rolfedh-doc-utils 0.1.22__tar.gz → 0.1.24__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rolfedh_doc_utils-0.1.22/rolfedh_doc_utils.egg-info → rolfedh_doc_utils-0.1.24}/PKG-INFO +1 -1
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/convert_callouts_to_deflist.py +226 -67
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/pyproject.toml +1 -1
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24/rolfedh_doc_utils.egg-info}/PKG-INFO +1 -1
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/LICENSE +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/README.md +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/archive_unused_files.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/archive_unused_images.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/check_scannability.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/doc_utils/__init__.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/doc_utils/extract_link_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/doc_utils/file_utils.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/doc_utils/format_asciidoc_spacing.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/doc_utils/replace_link_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/doc_utils/scannability.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/doc_utils/spinner.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/doc_utils/topic_map_parser.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/doc_utils/unused_adoc.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/doc_utils/unused_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/doc_utils/unused_images.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/doc_utils/validate_links.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/doc_utils/version.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/doc_utils/version_check.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/doc_utils_cli.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/extract_link_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/find_unused_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/format_asciidoc_spacing.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/replace_link_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/rolfedh_doc_utils.egg-info/SOURCES.txt +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/rolfedh_doc_utils.egg-info/dependency_links.txt +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/rolfedh_doc_utils.egg-info/entry_points.txt +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/rolfedh_doc_utils.egg-info/requires.txt +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/rolfedh_doc_utils.egg-info/top_level.txt +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/setup.cfg +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/setup.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/tests/test_archive_unused_files.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/tests/test_archive_unused_images.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/tests/test_auto_discovery.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/tests/test_check_scannability.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/tests/test_cli_entry_points.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/tests/test_extract_link_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/tests/test_file_utils.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/tests/test_fixture_archive_unused_files.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/tests/test_fixture_archive_unused_images.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/tests/test_fixture_check_scannability.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/tests/test_parse_exclude_list.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/tests/test_replace_link_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/tests/test_symlink_handling.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/tests/test_topic_map_parser.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/tests/test_unused_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/tests/test_validate_links.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/tests/test_version_check.py +0 -0
- {rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/validate_links.py +0 -0
|
@@ -34,10 +34,17 @@ def print_colored(message: str, color: str = Colors.NC) -> None:
|
|
|
34
34
|
class Callout:
|
|
35
35
|
"""Represents a callout with its number and explanation text."""
|
|
36
36
|
number: int
|
|
37
|
-
|
|
37
|
+
lines: List[str] # List of lines to preserve formatting
|
|
38
38
|
is_optional: bool = False
|
|
39
39
|
|
|
40
40
|
|
|
41
|
+
@dataclass
|
|
42
|
+
class CalloutGroup:
|
|
43
|
+
"""Represents one or more callouts that share the same code line."""
|
|
44
|
+
code_line: str # The actual code line (without callouts)
|
|
45
|
+
callout_numbers: List[int] # List of callout numbers on this line
|
|
46
|
+
|
|
47
|
+
|
|
41
48
|
@dataclass
|
|
42
49
|
class CodeBlock:
|
|
43
50
|
"""Represents a code block with its content and metadata."""
|
|
@@ -51,11 +58,12 @@ class CodeBlock:
|
|
|
51
58
|
class CalloutConverter:
|
|
52
59
|
"""Converts callout-style documentation to definition list format."""
|
|
53
60
|
|
|
54
|
-
# Pattern for code block start: [source,language] or [source]
|
|
55
|
-
|
|
61
|
+
# Pattern for code block start: [source,language] or [source] with optional attributes
|
|
62
|
+
# Matches: [source], [source,java], [source,java,subs="..."], [source,java,options="..."], etc.
|
|
63
|
+
CODE_BLOCK_START = re.compile(r'^\[source(?:,\s*(\w+))?(?:[,\s]+[^\]]+)?\]')
|
|
56
64
|
|
|
57
|
-
# Pattern for callout number
|
|
58
|
-
CALLOUT_IN_CODE = re.compile(r'<(\d+)
|
|
65
|
+
# Pattern for callout number in code block (can appear multiple times per line)
|
|
66
|
+
CALLOUT_IN_CODE = re.compile(r'<(\d+)>')
|
|
59
67
|
|
|
60
68
|
# Pattern for callout explanation line: <1> Explanation text
|
|
61
69
|
CALLOUT_EXPLANATION = re.compile(r'^<(\d+)>\s+(.+)$')
|
|
@@ -64,9 +72,10 @@ class CalloutConverter:
|
|
|
64
72
|
# Excludes heredoc syntax (<<) and comparison operators
|
|
65
73
|
USER_VALUE_PATTERN = re.compile(r'(?<!<)<([a-zA-Z][^>]*)>')
|
|
66
74
|
|
|
67
|
-
def __init__(self, dry_run: bool = False, verbose: bool = False):
|
|
75
|
+
def __init__(self, dry_run: bool = False, verbose: bool = False, output_format: str = 'deflist'):
|
|
68
76
|
self.dry_run = dry_run
|
|
69
77
|
self.verbose = verbose
|
|
78
|
+
self.output_format = output_format # 'deflist' or 'bullets'
|
|
70
79
|
self.changes_made = 0
|
|
71
80
|
self.warnings = [] # Collect warnings for summary
|
|
72
81
|
|
|
@@ -81,6 +90,7 @@ class CalloutConverter:
|
|
|
81
90
|
i = 0
|
|
82
91
|
|
|
83
92
|
while i < len(lines):
|
|
93
|
+
# Check for [source] prefix first
|
|
84
94
|
match = self.CODE_BLOCK_START.match(lines[i])
|
|
85
95
|
if match:
|
|
86
96
|
language = match.group(1)
|
|
@@ -106,44 +116,71 @@ class CalloutConverter:
|
|
|
106
116
|
))
|
|
107
117
|
break
|
|
108
118
|
i += 1
|
|
119
|
+
# Check for plain delimited blocks without [source] prefix
|
|
120
|
+
elif lines[i].strip() in ['----', '....']:
|
|
121
|
+
delimiter = lines[i].strip()
|
|
122
|
+
start = i
|
|
123
|
+
i += 1
|
|
124
|
+
content_start = i
|
|
125
|
+
|
|
126
|
+
# Find the closing delimiter
|
|
127
|
+
while i < len(lines):
|
|
128
|
+
if lines[i].strip() == delimiter:
|
|
129
|
+
content = lines[content_start:i]
|
|
130
|
+
# Only add if block contains callouts
|
|
131
|
+
if any(self.CALLOUT_IN_CODE.search(line) for line in content):
|
|
132
|
+
blocks.append(CodeBlock(
|
|
133
|
+
start_line=start,
|
|
134
|
+
end_line=i,
|
|
135
|
+
delimiter=delimiter,
|
|
136
|
+
content=content,
|
|
137
|
+
language=None
|
|
138
|
+
))
|
|
139
|
+
break
|
|
140
|
+
i += 1
|
|
109
141
|
i += 1
|
|
110
142
|
|
|
111
143
|
return blocks
|
|
112
144
|
|
|
113
|
-
def extract_callouts_from_code(self, content: List[str]) ->
|
|
145
|
+
def extract_callouts_from_code(self, content: List[str]) -> List[CalloutGroup]:
|
|
114
146
|
"""
|
|
115
147
|
Extract callout numbers from code block content.
|
|
116
|
-
Returns
|
|
117
|
-
- The user-replaceable value
|
|
118
|
-
-
|
|
148
|
+
Returns list of CalloutGroups, where each group contains:
|
|
149
|
+
- The code line (with user-replaceable value if found, or full line)
|
|
150
|
+
- List of callout numbers on that line
|
|
119
151
|
|
|
120
|
-
|
|
121
|
-
|
|
152
|
+
Multiple callouts on the same line are grouped together to be merged
|
|
153
|
+
in the definition list.
|
|
122
154
|
"""
|
|
123
|
-
|
|
155
|
+
groups = []
|
|
124
156
|
|
|
125
157
|
for line in content:
|
|
126
|
-
# Look for callout
|
|
127
|
-
|
|
128
|
-
if
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
# Extract the user-replaceable value (content in angle brackets)
|
|
132
|
-
# Remove the callout number first
|
|
133
|
-
line_without_callout = self.CALLOUT_IN_CODE.sub('', line).strip()
|
|
158
|
+
# Look for all callout numbers on this line
|
|
159
|
+
callout_matches = list(self.CALLOUT_IN_CODE.finditer(line))
|
|
160
|
+
if callout_matches:
|
|
161
|
+
# Remove all callouts from the line to get the actual code
|
|
162
|
+
line_without_callouts = self.CALLOUT_IN_CODE.sub('', line).strip()
|
|
134
163
|
|
|
135
164
|
# Find all angle-bracket enclosed values
|
|
136
|
-
user_values = self.USER_VALUE_PATTERN.findall(
|
|
165
|
+
user_values = self.USER_VALUE_PATTERN.findall(line_without_callouts)
|
|
137
166
|
|
|
167
|
+
# Determine what to use as the code line term
|
|
138
168
|
if user_values:
|
|
139
169
|
# Use the rightmost (closest to the callout) user value
|
|
140
|
-
|
|
170
|
+
code_line = user_values[-1]
|
|
141
171
|
else:
|
|
142
|
-
# No angle-bracket value found -
|
|
143
|
-
|
|
144
|
-
|
|
172
|
+
# No angle-bracket value found - use the actual code line
|
|
173
|
+
code_line = line_without_callouts
|
|
174
|
+
|
|
175
|
+
# Collect all callout numbers on this line
|
|
176
|
+
callout_nums = [int(m.group(1)) for m in callout_matches]
|
|
145
177
|
|
|
146
|
-
|
|
178
|
+
groups.append(CalloutGroup(
|
|
179
|
+
code_line=code_line,
|
|
180
|
+
callout_numbers=callout_nums
|
|
181
|
+
))
|
|
182
|
+
|
|
183
|
+
return groups
|
|
147
184
|
|
|
148
185
|
def extract_callout_explanations(self, lines: List[str], start_line: int) -> Tuple[Dict[int, Callout], int]:
|
|
149
186
|
"""
|
|
@@ -153,8 +190,8 @@ class CalloutConverter:
|
|
|
153
190
|
explanations = {}
|
|
154
191
|
i = start_line + 1 # Start after the closing delimiter
|
|
155
192
|
|
|
156
|
-
# Skip blank lines
|
|
157
|
-
while i < len(lines) and not lines[i].strip():
|
|
193
|
+
# Skip blank lines and continuation markers (+)
|
|
194
|
+
while i < len(lines) and (not lines[i].strip() or lines[i].strip() == '+'):
|
|
158
195
|
i += 1
|
|
159
196
|
|
|
160
197
|
# Collect consecutive callout explanation lines
|
|
@@ -162,31 +199,48 @@ class CalloutConverter:
|
|
|
162
199
|
match = self.CALLOUT_EXPLANATION.match(lines[i])
|
|
163
200
|
if match:
|
|
164
201
|
num = int(match.group(1))
|
|
165
|
-
|
|
202
|
+
first_line = match.group(2).strip()
|
|
203
|
+
explanation_lines = [first_line]
|
|
204
|
+
i += 1
|
|
166
205
|
|
|
167
|
-
#
|
|
206
|
+
# Collect continuation lines (lines that don't start with a new callout)
|
|
207
|
+
# Continue until we hit a blank line, a new callout, or certain patterns
|
|
208
|
+
while i < len(lines):
|
|
209
|
+
line = lines[i]
|
|
210
|
+
# Stop if we hit a blank line, new callout, or list start marker
|
|
211
|
+
if not line.strip() or self.CALLOUT_EXPLANATION.match(line) or line.startswith('[start='):
|
|
212
|
+
break
|
|
213
|
+
# Add continuation line preserving original formatting
|
|
214
|
+
explanation_lines.append(line)
|
|
215
|
+
i += 1
|
|
216
|
+
|
|
217
|
+
# Check if marked as optional (only in first line)
|
|
168
218
|
is_optional = False
|
|
169
|
-
if
|
|
219
|
+
if first_line.lower().startswith('optional.') or first_line.lower().startswith('optional:'):
|
|
170
220
|
is_optional = True
|
|
171
|
-
|
|
172
|
-
|
|
221
|
+
# Remove "Optional." or "Optional:" from first line
|
|
222
|
+
explanation_lines[0] = first_line[9:].strip()
|
|
223
|
+
elif '(Optional)' in first_line or '(optional)' in first_line:
|
|
173
224
|
is_optional = True
|
|
174
|
-
|
|
225
|
+
explanation_lines[0] = re.sub(r'\s*\(optional\)\s*', ' ', first_line, flags=re.IGNORECASE).strip()
|
|
175
226
|
|
|
176
|
-
explanations[num] = Callout(num,
|
|
177
|
-
i += 1
|
|
227
|
+
explanations[num] = Callout(num, explanation_lines, is_optional)
|
|
178
228
|
else:
|
|
179
229
|
break
|
|
180
230
|
|
|
181
231
|
return explanations, i - 1
|
|
182
232
|
|
|
183
|
-
def validate_callouts(self,
|
|
233
|
+
def validate_callouts(self, callout_groups: List[CalloutGroup], explanations: Dict[int, Callout],
|
|
184
234
|
input_file: Path = None, block_start: int = None, block_end: int = None) -> bool:
|
|
185
235
|
"""
|
|
186
236
|
Validate that callout numbers in code match explanation numbers.
|
|
187
237
|
Returns True if valid, False otherwise.
|
|
188
238
|
"""
|
|
189
|
-
|
|
239
|
+
# Extract all callout numbers from groups
|
|
240
|
+
code_nums = set()
|
|
241
|
+
for group in callout_groups:
|
|
242
|
+
code_nums.update(group.callout_numbers)
|
|
243
|
+
|
|
190
244
|
explanation_nums = set(explanations.keys())
|
|
191
245
|
|
|
192
246
|
if code_nums != explanation_nums:
|
|
@@ -208,31 +262,35 @@ class CalloutConverter:
|
|
|
208
262
|
return True
|
|
209
263
|
|
|
210
264
|
def remove_callouts_from_code(self, content: List[str]) -> List[str]:
|
|
211
|
-
"""Remove callout numbers from code block content."""
|
|
265
|
+
"""Remove callout numbers from code block content (handles multiple callouts per line)."""
|
|
212
266
|
cleaned = []
|
|
213
267
|
for line in content:
|
|
214
|
-
|
|
268
|
+
# Remove all callout numbers and trailing whitespace
|
|
269
|
+
cleaned.append(self.CALLOUT_IN_CODE.sub('', line).rstrip())
|
|
215
270
|
return cleaned
|
|
216
271
|
|
|
217
|
-
def create_definition_list(self,
|
|
272
|
+
def create_definition_list(self, callout_groups: List[CalloutGroup], explanations: Dict[int, Callout]) -> List[str]:
|
|
218
273
|
"""
|
|
219
|
-
Create definition list from
|
|
274
|
+
Create definition list from callout groups and explanations.
|
|
220
275
|
|
|
221
276
|
For callouts with user-replaceable values in angle brackets, uses those.
|
|
222
277
|
For callouts without values, uses the actual code line as the term.
|
|
278
|
+
|
|
279
|
+
When multiple callouts share the same code line (same group), their
|
|
280
|
+
explanations are merged using AsciiDoc list continuation (+).
|
|
223
281
|
"""
|
|
224
|
-
lines = ['\nwhere
|
|
282
|
+
lines = ['\nwhere:']
|
|
225
283
|
|
|
226
|
-
#
|
|
227
|
-
for
|
|
228
|
-
|
|
229
|
-
|
|
284
|
+
# Process each group (which may contain one or more callouts)
|
|
285
|
+
for group in callout_groups:
|
|
286
|
+
code_line = group.code_line
|
|
287
|
+
callout_nums = group.callout_numbers
|
|
230
288
|
|
|
231
289
|
# Check if this is a user-replaceable value (contains angle brackets but not heredoc)
|
|
232
290
|
# User values are single words/phrases in angle brackets like <my-value>
|
|
233
|
-
user_values = self.USER_VALUE_PATTERN.findall(
|
|
291
|
+
user_values = self.USER_VALUE_PATTERN.findall(code_line)
|
|
234
292
|
|
|
235
|
-
if user_values and len(user_values) == 1 and len(
|
|
293
|
+
if user_values and len(user_values) == 1 and len(code_line) < 100:
|
|
236
294
|
# This looks like a user-replaceable value placeholder
|
|
237
295
|
# Format the value (ensure it has angle brackets)
|
|
238
296
|
user_value = user_values[0]
|
|
@@ -243,15 +301,97 @@ class CalloutConverter:
|
|
|
243
301
|
term = f'`{user_value}`'
|
|
244
302
|
else:
|
|
245
303
|
# This is a code line - use it as-is in backticks
|
|
246
|
-
term = f'`{
|
|
304
|
+
term = f'`{code_line}`'
|
|
305
|
+
|
|
306
|
+
# Add blank line before each term
|
|
307
|
+
lines.append('')
|
|
308
|
+
lines.append(f'{term}::')
|
|
247
309
|
|
|
248
|
-
#
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
explanation_text = f'Optional. {explanation_text}'
|
|
310
|
+
# Add explanations for all callouts in this group
|
|
311
|
+
for idx, callout_num in enumerate(callout_nums):
|
|
312
|
+
explanation = explanations[callout_num]
|
|
252
313
|
|
|
253
|
-
|
|
254
|
-
|
|
314
|
+
# If this is not the first explanation in the group, add continuation marker
|
|
315
|
+
if idx > 0:
|
|
316
|
+
lines.append('+')
|
|
317
|
+
|
|
318
|
+
# Add explanation lines, prepending "Optional. " to first line if needed
|
|
319
|
+
for line_idx, line in enumerate(explanation.lines):
|
|
320
|
+
if line_idx == 0 and explanation.is_optional:
|
|
321
|
+
lines.append(f'Optional. {line}')
|
|
322
|
+
else:
|
|
323
|
+
lines.append(line)
|
|
324
|
+
|
|
325
|
+
return lines
|
|
326
|
+
|
|
327
|
+
def create_bulleted_list(self, callout_groups: List[CalloutGroup], explanations: Dict[int, Callout]) -> List[str]:
|
|
328
|
+
"""
|
|
329
|
+
Create bulleted list from callout groups and explanations.
|
|
330
|
+
|
|
331
|
+
Follows Red Hat style guide format:
|
|
332
|
+
- Each bullet starts with `*` followed by backticked code element
|
|
333
|
+
- Colon separates element from explanation
|
|
334
|
+
- Blank line between each bullet point
|
|
335
|
+
|
|
336
|
+
For callouts with user-replaceable values in angle brackets, uses those.
|
|
337
|
+
For callouts without values, uses the actual code line as the term.
|
|
338
|
+
|
|
339
|
+
When multiple callouts share the same code line (same group), their
|
|
340
|
+
explanations are merged with line breaks.
|
|
341
|
+
"""
|
|
342
|
+
lines = [''] # Start with blank line before list
|
|
343
|
+
|
|
344
|
+
# Process each group (which may contain one or more callouts)
|
|
345
|
+
for group in callout_groups:
|
|
346
|
+
code_line = group.code_line
|
|
347
|
+
callout_nums = group.callout_numbers
|
|
348
|
+
|
|
349
|
+
# Check if this is a user-replaceable value (contains angle brackets but not heredoc)
|
|
350
|
+
# User values are single words/phrases in angle brackets like <my-value>
|
|
351
|
+
user_values = self.USER_VALUE_PATTERN.findall(code_line)
|
|
352
|
+
|
|
353
|
+
if user_values and len(user_values) == 1 and len(code_line) < 100:
|
|
354
|
+
# This looks like a user-replaceable value placeholder
|
|
355
|
+
# Format the value (ensure it has angle brackets)
|
|
356
|
+
user_value = user_values[0]
|
|
357
|
+
if not user_value.startswith('<'):
|
|
358
|
+
user_value = f'<{user_value}>'
|
|
359
|
+
if not user_value.endswith('>'):
|
|
360
|
+
user_value = f'{user_value}>'
|
|
361
|
+
term = f'`{user_value}`'
|
|
362
|
+
else:
|
|
363
|
+
# This is a code line - use it as-is in backticks
|
|
364
|
+
term = f'`{code_line}`'
|
|
365
|
+
|
|
366
|
+
# Collect all explanations for this group
|
|
367
|
+
all_explanation_lines = []
|
|
368
|
+
for idx, callout_num in enumerate(callout_nums):
|
|
369
|
+
explanation = explanations[callout_num]
|
|
370
|
+
|
|
371
|
+
# Add explanation lines, prepending "Optional. " to first line if needed
|
|
372
|
+
for line_idx, line in enumerate(explanation.lines):
|
|
373
|
+
if line_idx == 0 and explanation.is_optional:
|
|
374
|
+
all_explanation_lines.append(f'Optional. {line}')
|
|
375
|
+
else:
|
|
376
|
+
all_explanation_lines.append(line)
|
|
377
|
+
|
|
378
|
+
# If there are more callouts in this group, add a line break
|
|
379
|
+
if idx < len(callout_nums) - 1:
|
|
380
|
+
all_explanation_lines.append('')
|
|
381
|
+
|
|
382
|
+
# Format as bullet point: * `term`: explanation
|
|
383
|
+
# First line uses the bullet marker
|
|
384
|
+
lines.append(f'* {term}: {all_explanation_lines[0]}')
|
|
385
|
+
|
|
386
|
+
# Continuation lines (if any) are indented to align with first line
|
|
387
|
+
for continuation_line in all_explanation_lines[1:]:
|
|
388
|
+
if continuation_line: # Skip empty lines for now
|
|
389
|
+
lines.append(f' {continuation_line}')
|
|
390
|
+
else:
|
|
391
|
+
lines.append('')
|
|
392
|
+
|
|
393
|
+
# Add blank line after each bullet point
|
|
394
|
+
lines.append('')
|
|
255
395
|
|
|
256
396
|
return lines
|
|
257
397
|
|
|
@@ -282,14 +422,19 @@ class CalloutConverter:
|
|
|
282
422
|
conversions = 0
|
|
283
423
|
|
|
284
424
|
for block in reversed(blocks):
|
|
285
|
-
# Extract callouts from code
|
|
286
|
-
|
|
425
|
+
# Extract callouts from code (returns list of CalloutGroups)
|
|
426
|
+
callout_groups = self.extract_callouts_from_code(block.content)
|
|
287
427
|
|
|
288
|
-
if not
|
|
428
|
+
if not callout_groups:
|
|
289
429
|
self.log(f"No callouts in block at line {block.start_line + 1}")
|
|
290
430
|
continue
|
|
291
431
|
|
|
292
|
-
|
|
432
|
+
# Extract all callout numbers for logging
|
|
433
|
+
all_callout_nums = []
|
|
434
|
+
for group in callout_groups:
|
|
435
|
+
all_callout_nums.extend(group.callout_numbers)
|
|
436
|
+
|
|
437
|
+
self.log(f"Block at line {block.start_line + 1} has callouts: {all_callout_nums}")
|
|
293
438
|
|
|
294
439
|
# Extract explanations
|
|
295
440
|
explanations, explanation_end = self.extract_callout_explanations(new_lines, block.end_line)
|
|
@@ -299,7 +444,7 @@ class CalloutConverter:
|
|
|
299
444
|
continue
|
|
300
445
|
|
|
301
446
|
# Validate callouts match
|
|
302
|
-
if not self.validate_callouts(
|
|
447
|
+
if not self.validate_callouts(callout_groups, explanations, input_file, block.start_line, block.end_line):
|
|
303
448
|
continue
|
|
304
449
|
|
|
305
450
|
self.log(f"Converting block at line {block.start_line + 1}")
|
|
@@ -307,12 +452,20 @@ class CalloutConverter:
|
|
|
307
452
|
# Remove callouts from code
|
|
308
453
|
cleaned_content = self.remove_callouts_from_code(block.content)
|
|
309
454
|
|
|
310
|
-
# Create definition list
|
|
311
|
-
|
|
455
|
+
# Create output list (definition list or bulleted list based on format option)
|
|
456
|
+
if self.output_format == 'bullets':
|
|
457
|
+
output_list = self.create_bulleted_list(callout_groups, explanations)
|
|
458
|
+
else: # default to 'deflist'
|
|
459
|
+
output_list = self.create_definition_list(callout_groups, explanations)
|
|
312
460
|
|
|
313
461
|
# Replace in document
|
|
314
462
|
# 1. Update code block content
|
|
315
|
-
|
|
463
|
+
# Check if block has [source] prefix by checking if start_line contains [source]
|
|
464
|
+
has_source_prefix = self.CODE_BLOCK_START.match(new_lines[block.start_line])
|
|
465
|
+
if has_source_prefix:
|
|
466
|
+
content_start = block.start_line + 2 # After [source] and ----
|
|
467
|
+
else:
|
|
468
|
+
content_start = block.start_line + 1 # After ---- only
|
|
316
469
|
content_end = block.end_line
|
|
317
470
|
|
|
318
471
|
# 2. Remove old callout explanations
|
|
@@ -325,7 +478,7 @@ class CalloutConverter:
|
|
|
325
478
|
new_lines[:content_start] +
|
|
326
479
|
cleaned_content +
|
|
327
480
|
[new_lines[content_end]] + # Keep closing delimiter
|
|
328
|
-
|
|
481
|
+
output_list +
|
|
329
482
|
new_lines[explanation_end + 1:]
|
|
330
483
|
)
|
|
331
484
|
|
|
@@ -478,6 +631,12 @@ Example transformation:
|
|
|
478
631
|
action='store_true',
|
|
479
632
|
help='Enable verbose output'
|
|
480
633
|
)
|
|
634
|
+
parser.add_argument(
|
|
635
|
+
'-f', '--format',
|
|
636
|
+
choices=['deflist', 'bullets'],
|
|
637
|
+
default='deflist',
|
|
638
|
+
help='Output format: "deflist" for definition list with "where:" (default), "bullets" for bulleted list'
|
|
639
|
+
)
|
|
481
640
|
parser.add_argument(
|
|
482
641
|
'--exclude-dir',
|
|
483
642
|
action='append',
|
|
@@ -535,7 +694,7 @@ Example transformation:
|
|
|
535
694
|
print(f"Found {len(adoc_files)} AsciiDoc file(s) to process")
|
|
536
695
|
|
|
537
696
|
# Create converter
|
|
538
|
-
converter = CalloutConverter(dry_run=args.dry_run, verbose=args.verbose)
|
|
697
|
+
converter = CalloutConverter(dry_run=args.dry_run, verbose=args.verbose, output_format=args.format)
|
|
539
698
|
|
|
540
699
|
# Process each file
|
|
541
700
|
files_processed = 0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/rolfedh_doc_utils.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/rolfedh_doc_utils.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/rolfedh_doc_utils.egg-info/requires.txt
RENAMED
|
File without changes
|
{rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/rolfedh_doc_utils.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/tests/test_fixture_archive_unused_files.py
RENAMED
|
File without changes
|
{rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/tests/test_fixture_archive_unused_images.py
RENAMED
|
File without changes
|
{rolfedh_doc_utils-0.1.22 → rolfedh_doc_utils-0.1.24}/tests/test_fixture_check_scannability.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|