rolfedh-doc-utils 0.1.24__py3-none-any.whl → 0.1.26__py3-none-any.whl

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.
@@ -3,18 +3,24 @@
3
3
  convert-callouts-to-deflist - Convert AsciiDoc callouts to definition list format
4
4
 
5
5
  Converts code blocks with callout-style annotations (<1>, <2>, etc.) to cleaner
6
- definition list format with "where:" prefix.
6
+ definition list format with "where:" prefix, bulleted list format, or inline comments.
7
7
 
8
8
  This tool automatically scans all .adoc files in the current directory (recursively)
9
9
  by default, or you can specify a specific file or directory.
10
10
  """
11
11
 
12
- import re
13
12
  import sys
14
13
  import argparse
15
14
  from pathlib import Path
16
- from typing import List, Dict, Tuple, Optional
17
- from dataclasses import dataclass
15
+ from typing import List, Tuple
16
+
17
+ # Import from callout_lib
18
+ from callout_lib import (
19
+ CalloutDetector,
20
+ DefListConverter,
21
+ BulletListConverter,
22
+ CommentConverter,
23
+ )
18
24
 
19
25
 
20
26
  # Colors for output
@@ -30,374 +36,30 @@ def print_colored(message: str, color: str = Colors.NC) -> None:
30
36
  print(f"{color}{message}{Colors.NC}")
31
37
 
32
38
 
33
- @dataclass
34
- class Callout:
35
- """Represents a callout with its number and explanation text."""
36
- number: int
37
- lines: List[str] # List of lines to preserve formatting
38
- is_optional: bool = False
39
-
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
-
48
- @dataclass
49
- class CodeBlock:
50
- """Represents a code block with its content and metadata."""
51
- start_line: int
52
- end_line: int
53
- delimiter: str
54
- content: List[str]
55
- language: Optional[str] = None
56
-
57
-
58
39
  class CalloutConverter:
59
- """Converts callout-style documentation to definition list format."""
60
-
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]+[^\]]+)?\]')
64
-
65
- # Pattern for callout number in code block (can appear multiple times per line)
66
- CALLOUT_IN_CODE = re.compile(r'<(\d+)>')
67
-
68
- # Pattern for callout explanation line: <1> Explanation text
69
- CALLOUT_EXPLANATION = re.compile(r'^<(\d+)>\s+(.+)$')
40
+ """Converts callout-style documentation to various formats."""
70
41
 
71
- # Pattern to detect user-replaceable values in angle brackets
72
- # Excludes heredoc syntax (<<) and comparison operators
73
- USER_VALUE_PATTERN = re.compile(r'(?<!<)<([a-zA-Z][^>]*)>')
74
-
75
- def __init__(self, dry_run: bool = False, verbose: bool = False, output_format: str = 'deflist'):
42
+ def __init__(self, dry_run: bool = False, verbose: bool = False, output_format: str = 'deflist',
43
+ max_comment_length: int = 120):
76
44
  self.dry_run = dry_run
77
45
  self.verbose = verbose
78
- self.output_format = output_format # 'deflist' or 'bullets'
46
+ self.output_format = output_format # 'deflist', 'bullets', or 'comments'
47
+ self.max_comment_length = max_comment_length # Max length for inline comments
79
48
  self.changes_made = 0
80
49
  self.warnings = [] # Collect warnings for summary
50
+ self.long_comment_warnings = [] # Warnings for comments exceeding max length
51
+
52
+ # Initialize detector and converters
53
+ self.detector = CalloutDetector()
81
54
 
82
55
  def log(self, message: str):
83
56
  """Print message if verbose mode is enabled."""
84
57
  if self.verbose:
85
58
  print(f"[INFO] {message}")
86
59
 
87
- def find_code_blocks(self, lines: List[str]) -> List[CodeBlock]:
88
- """Find all code blocks in the document."""
89
- blocks = []
90
- i = 0
91
-
92
- while i < len(lines):
93
- # Check for [source] prefix first
94
- match = self.CODE_BLOCK_START.match(lines[i])
95
- if match:
96
- language = match.group(1)
97
- start = i
98
- i += 1
99
-
100
- # Find the delimiter line (---- or ....)
101
- if i < len(lines) and lines[i].strip() in ['----', '....']:
102
- delimiter = lines[i].strip()
103
- i += 1
104
- content_start = i
105
-
106
- # Find the closing delimiter
107
- while i < len(lines):
108
- if lines[i].strip() == delimiter:
109
- content = lines[content_start:i]
110
- blocks.append(CodeBlock(
111
- start_line=start,
112
- end_line=i,
113
- delimiter=delimiter,
114
- content=content,
115
- language=language
116
- ))
117
- break
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
141
- i += 1
142
-
143
- return blocks
144
-
145
- def extract_callouts_from_code(self, content: List[str]) -> List[CalloutGroup]:
146
- """
147
- Extract callout numbers from code block content.
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
151
-
152
- Multiple callouts on the same line are grouped together to be merged
153
- in the definition list.
154
- """
155
- groups = []
156
-
157
- for line in content:
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()
163
-
164
- # Find all angle-bracket enclosed values
165
- user_values = self.USER_VALUE_PATTERN.findall(line_without_callouts)
166
-
167
- # Determine what to use as the code line term
168
- if user_values:
169
- # Use the rightmost (closest to the callout) user value
170
- code_line = user_values[-1]
171
- else:
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]
177
-
178
- groups.append(CalloutGroup(
179
- code_line=code_line,
180
- callout_numbers=callout_nums
181
- ))
182
-
183
- return groups
184
-
185
- def extract_callout_explanations(self, lines: List[str], start_line: int) -> Tuple[Dict[int, Callout], int]:
186
- """
187
- Extract callout explanations following a code block.
188
- Returns dict of callouts and the line number where explanations end.
189
- """
190
- explanations = {}
191
- i = start_line + 1 # Start after the closing delimiter
192
-
193
- # Skip blank lines and continuation markers (+)
194
- while i < len(lines) and (not lines[i].strip() or lines[i].strip() == '+'):
195
- i += 1
196
-
197
- # Collect consecutive callout explanation lines
198
- while i < len(lines):
199
- match = self.CALLOUT_EXPLANATION.match(lines[i])
200
- if match:
201
- num = int(match.group(1))
202
- first_line = match.group(2).strip()
203
- explanation_lines = [first_line]
204
- i += 1
205
-
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)
218
- is_optional = False
219
- if first_line.lower().startswith('optional.') or first_line.lower().startswith('optional:'):
220
- is_optional = True
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:
224
- is_optional = True
225
- explanation_lines[0] = re.sub(r'\s*\(optional\)\s*', ' ', first_line, flags=re.IGNORECASE).strip()
226
-
227
- explanations[num] = Callout(num, explanation_lines, is_optional)
228
- else:
229
- break
230
-
231
- return explanations, i - 1
232
-
233
- def validate_callouts(self, callout_groups: List[CalloutGroup], explanations: Dict[int, Callout],
234
- input_file: Path = None, block_start: int = None, block_end: int = None) -> bool:
235
- """
236
- Validate that callout numbers in code match explanation numbers.
237
- Returns True if valid, False otherwise.
238
- """
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
-
244
- explanation_nums = set(explanations.keys())
245
-
246
- if code_nums != explanation_nums:
247
- # Format warning message with file and line numbers
248
- if input_file and block_start is not None and block_end is not None:
249
- # Line numbers are 1-indexed for display
250
- line_range = f"{block_start + 1}-{block_end + 1}"
251
- warning_msg = (
252
- f"WARNING: {input_file.name} lines {line_range}: Callout mismatch: "
253
- f"code has {sorted(code_nums)}, explanations have {sorted(explanation_nums)}"
254
- )
255
- print_colored(warning_msg, Colors.YELLOW)
256
- # Store warning for summary
257
- self.warnings.append(warning_msg)
258
- else:
259
- self.log(f"Callout mismatch: code has {code_nums}, explanations have {explanation_nums}")
260
- return False
261
-
262
- return True
263
-
264
- def remove_callouts_from_code(self, content: List[str]) -> List[str]:
265
- """Remove callout numbers from code block content (handles multiple callouts per line)."""
266
- cleaned = []
267
- for line in content:
268
- # Remove all callout numbers and trailing whitespace
269
- cleaned.append(self.CALLOUT_IN_CODE.sub('', line).rstrip())
270
- return cleaned
271
-
272
- def create_definition_list(self, callout_groups: List[CalloutGroup], explanations: Dict[int, Callout]) -> List[str]:
273
- """
274
- Create definition list from callout groups and explanations.
275
-
276
- For callouts with user-replaceable values in angle brackets, uses those.
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 (+).
281
- """
282
- lines = ['\nwhere:']
283
-
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
288
-
289
- # Check if this is a user-replaceable value (contains angle brackets but not heredoc)
290
- # User values are single words/phrases in angle brackets like <my-value>
291
- user_values = self.USER_VALUE_PATTERN.findall(code_line)
292
-
293
- if user_values and len(user_values) == 1 and len(code_line) < 100:
294
- # This looks like a user-replaceable value placeholder
295
- # Format the value (ensure it has angle brackets)
296
- user_value = user_values[0]
297
- if not user_value.startswith('<'):
298
- user_value = f'<{user_value}>'
299
- if not user_value.endswith('>'):
300
- user_value = f'{user_value}>'
301
- term = f'`{user_value}`'
302
- else:
303
- # This is a code line - use it as-is in backticks
304
- term = f'`{code_line}`'
305
-
306
- # Add blank line before each term
307
- lines.append('')
308
- lines.append(f'{term}::')
309
-
310
- # Add explanations for all callouts in this group
311
- for idx, callout_num in enumerate(callout_nums):
312
- explanation = explanations[callout_num]
313
-
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('')
395
-
396
- return lines
397
-
398
60
  def convert_file(self, input_file: Path) -> Tuple[int, bool]:
399
61
  """
400
- Convert callouts in a file to definition list format.
62
+ Convert callouts in a file to the specified output format.
401
63
  Returns tuple of (number of conversions, whether file was modified).
402
64
  """
403
65
  # Read input file
@@ -411,7 +73,7 @@ class CalloutConverter:
411
73
  self.log(f"Processing {input_file} ({len(lines)} lines)")
412
74
 
413
75
  # Find all code blocks
414
- blocks = self.find_code_blocks(lines)
76
+ blocks = self.detector.find_code_blocks(lines)
415
77
  self.log(f"Found {len(blocks)} code blocks")
416
78
 
417
79
  if not blocks:
@@ -423,7 +85,7 @@ class CalloutConverter:
423
85
 
424
86
  for block in reversed(blocks):
425
87
  # Extract callouts from code (returns list of CalloutGroups)
426
- callout_groups = self.extract_callouts_from_code(block.content)
88
+ callout_groups = self.detector.extract_callouts_from_code(block.content)
427
89
 
428
90
  if not callout_groups:
429
91
  self.log(f"No callouts in block at line {block.start_line + 1}")
@@ -437,50 +99,96 @@ class CalloutConverter:
437
99
  self.log(f"Block at line {block.start_line + 1} has callouts: {all_callout_nums}")
438
100
 
439
101
  # Extract explanations
440
- explanations, explanation_end = self.extract_callout_explanations(new_lines, block.end_line)
102
+ explanations, explanation_end = self.detector.extract_callout_explanations(new_lines, block.end_line)
441
103
 
442
104
  if not explanations:
443
105
  self.log(f"No explanations found after block at line {block.start_line + 1}")
444
106
  continue
445
107
 
446
108
  # Validate callouts match
447
- if not self.validate_callouts(callout_groups, explanations, input_file, block.start_line, block.end_line):
109
+ is_valid, code_nums, explanation_nums = self.detector.validate_callouts(callout_groups, explanations)
110
+ if not is_valid:
111
+ # Format warning message with file and line numbers
112
+ line_range = f"{block.start_line + 1}-{block.end_line + 1}"
113
+ warning_msg = (
114
+ f"WARNING: {input_file.name} lines {line_range}: Callout mismatch: "
115
+ f"code has {sorted(code_nums)}, explanations have {sorted(explanation_nums)}"
116
+ )
117
+ print_colored(warning_msg, Colors.YELLOW)
118
+ self.warnings.append(warning_msg)
448
119
  continue
449
120
 
450
121
  self.log(f"Converting block at line {block.start_line + 1}")
451
122
 
452
- # Remove callouts from code
453
- cleaned_content = self.remove_callouts_from_code(block.content)
123
+ # Convert based on format option
124
+ use_deflist_fallback = False
125
+ if self.output_format == 'comments':
126
+ # For comments format, replace callouts inline in the code
127
+ converted_content, long_warnings = CommentConverter.convert(
128
+ block.content, callout_groups, explanations, block.language,
129
+ max_length=self.max_comment_length, shorten_long=False
130
+ )
131
+
132
+ # If there are long comment warnings, fall back to definition list
133
+ if long_warnings:
134
+ for lw in long_warnings:
135
+ warning_msg = (
136
+ f"WARNING: {input_file.name} lines {block.start_line + 1}-{block.end_line + 1}: "
137
+ f"Callout <{lw.callout_num}> explanation too long ({lw.length} chars) "
138
+ f"for inline comment (max: {self.max_comment_length}). Falling back to definition list format."
139
+ )
140
+ print_colored(warning_msg, Colors.YELLOW)
141
+ self.warnings.append(warning_msg)
142
+ self.long_comment_warnings.append((input_file.name, block.start_line + 1, lw))
143
+
144
+ # Fall back to definition list
145
+ self.log(f"Falling back to definition list for block at line {block.start_line + 1}")
146
+ converted_content = self.detector.remove_callouts_from_code(block.content)
147
+ output_list = DefListConverter.convert(callout_groups, explanations)
148
+ use_deflist_fallback = True
149
+ else:
150
+ output_list = [] # No separate list after code block for comments
151
+ else:
152
+ # For deflist and bullets, remove callouts from code and create separate list
153
+ converted_content = self.detector.remove_callouts_from_code(block.content)
454
154
 
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)
155
+ if self.output_format == 'bullets':
156
+ output_list = BulletListConverter.convert(callout_groups, explanations)
157
+ else: # default to 'deflist'
158
+ output_list = DefListConverter.convert(callout_groups, explanations)
460
159
 
461
160
  # Replace in document
462
- # 1. Update code block content
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])
161
+ # Check if block has [source] prefix
162
+ has_source_prefix = self.detector.CODE_BLOCK_START.match(new_lines[block.start_line])
465
163
  if has_source_prefix:
466
164
  content_start = block.start_line + 2 # After [source] and ----
467
165
  else:
468
166
  content_start = block.start_line + 1 # After ---- only
469
167
  content_end = block.end_line
470
168
 
471
- # 2. Remove old callout explanations
472
- explanation_start = block.end_line + 1
473
- while explanation_start < len(new_lines) and not new_lines[explanation_start].strip():
474
- explanation_start += 1
475
-
476
- # Build the new section
477
- new_section = (
478
- new_lines[:content_start] +
479
- cleaned_content +
480
- [new_lines[content_end]] + # Keep closing delimiter
481
- output_list +
482
- new_lines[explanation_end + 1:]
483
- )
169
+ # For comments format (without fallback), we keep the explanations section
170
+ # For deflist/bullets format, we remove old explanations and add new list
171
+ if self.output_format == 'comments' and not use_deflist_fallback:
172
+ # Keep everything as-is, just replace code content
173
+ new_section = (
174
+ new_lines[:content_start] +
175
+ converted_content +
176
+ new_lines[content_end:]
177
+ )
178
+ else:
179
+ # Remove old callout explanations and add new list
180
+ explanation_start = block.end_line + 1
181
+ while explanation_start < len(new_lines) and not new_lines[explanation_start].strip():
182
+ explanation_start += 1
183
+
184
+ # Build the new section
185
+ new_section = (
186
+ new_lines[:content_start] +
187
+ converted_content +
188
+ [new_lines[content_end]] + # Keep closing delimiter
189
+ output_list +
190
+ new_lines[explanation_end + 1:]
191
+ )
484
192
 
485
193
  new_lines = new_section
486
194
  conversions += 1
@@ -572,23 +280,29 @@ def load_exclusion_list(exclusion_file: Path) -> Tuple[List[str], List[str]]:
572
280
  def main():
573
281
  """Main entry point"""
574
282
  parser = argparse.ArgumentParser(
575
- description='Convert AsciiDoc callouts to definition list format',
283
+ description='Convert AsciiDoc callouts to various formats',
576
284
  formatter_class=argparse.RawDescriptionHelpFormatter,
577
285
  epilog="""
578
- Convert AsciiDoc callout-style documentation to definition list format.
286
+ Convert AsciiDoc callout-style documentation to various formats.
579
287
 
580
288
  This script identifies code blocks with callout numbers (<1>, <2>, etc.) and their
581
- corresponding explanation lines, then converts them to a cleaner definition list format
582
- with "where:" prefix.
289
+ corresponding explanation lines, then converts them to your chosen format.
290
+
291
+ Formats:
292
+ deflist - Definition list with "where:" prefix (default)
293
+ bullets - Bulleted list format
294
+ comments - Inline comments within code (removes separate explanations)
583
295
 
584
296
  Examples:
585
297
  %(prog)s # Process all .adoc files in current directory
586
298
  %(prog)s modules/ # Process all .adoc files in modules/
587
299
  %(prog)s assemblies/my-guide.adoc # Process single file
588
300
  %(prog)s --dry-run modules/ # Preview changes without modifying
301
+ %(prog)s --format bullets modules/ # Convert to bulleted list format
302
+ %(prog)s --format comments src/ # Convert to inline comments
589
303
  %(prog)s --exclude-dir .vale modules/ # Exclude .vale directory
590
304
 
591
- Example transformation:
305
+ Example transformation (deflist format):
592
306
  FROM:
593
307
  [source,yaml]
594
308
  ----
@@ -633,9 +347,15 @@ Example transformation:
633
347
  )
634
348
  parser.add_argument(
635
349
  '-f', '--format',
636
- choices=['deflist', 'bullets'],
350
+ choices=['deflist', 'bullets', 'comments'],
637
351
  default='deflist',
638
- help='Output format: "deflist" for definition list with "where:" (default), "bullets" for bulleted list'
352
+ help='Output format: "deflist" for definition list (default), "bullets" for bulleted list, "comments" for inline comments'
353
+ )
354
+ parser.add_argument(
355
+ '--max-comment-length',
356
+ type=int,
357
+ default=120,
358
+ help='Maximum length for inline comments before falling back to definition list (default: 120 characters)'
639
359
  )
640
360
  parser.add_argument(
641
361
  '--exclude-dir',
@@ -694,7 +414,8 @@ Example transformation:
694
414
  print(f"Found {len(adoc_files)} AsciiDoc file(s) to process")
695
415
 
696
416
  # Create converter
697
- converter = CalloutConverter(dry_run=args.dry_run, verbose=args.verbose, output_format=args.format)
417
+ converter = CalloutConverter(dry_run=args.dry_run, verbose=args.verbose, output_format=args.format,
418
+ max_comment_length=args.max_comment_length)
698
419
 
699
420
  # Process each file
700
421
  files_processed = 0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rolfedh-doc-utils
3
- Version: 0.1.24
3
+ Version: 0.1.26
4
4
  Summary: CLI tools for AsciiDoc documentation projects
5
5
  Author: Rolfe Dlugy-Hegwer
6
6
  License: MIT License
@@ -1,13 +1,20 @@
1
1
  archive_unused_files.py,sha256=OJZrkqn70hiOXED218jMYPFNFWnsDpjsCYOmBRxYnHU,2274
2
2
  archive_unused_images.py,sha256=fZeyEZtTd72Gbd3YBXTy5xoshAAM9qb4qFPMjhHL1Fg,1864
3
3
  check_scannability.py,sha256=O6ROr-e624jVPvPpASpsWo0gTfuCFpA2mTSX61BjAEI,5478
4
- convert_callouts_to_deflist.py,sha256=XBcQ5oUjpSsv9VM4ldh_2fFH33-ZQaIQ1Gj6SyEW5b0,28954
4
+ convert_callouts_interactive.py,sha256=hoDKff3jqyJiGZ3IqjcWF7AXM4XUQE-vVg2NpJYECs4,21066
5
+ convert_callouts_to_deflist.py,sha256=WRpHmD3DWs7G7qEcL6c9WLYpX4uaPzlMKrWXnPlHQ_s,17720
5
6
  doc_utils_cli.py,sha256=dsMYrkAriYdZUF0_cSPh5DAPrJMPiecuY26xN-p0UJ0,4911
6
7
  extract_link_attributes.py,sha256=wR2SmR2la-jR6DzDbas2PoNONgRZ4dZ6aqwzkwEv8Gs,3516
7
8
  find_unused_attributes.py,sha256=77CxFdm72wj6SO81w-auMdDjnvF83jWy_qaM7DsAtBw,4263
8
9
  format_asciidoc_spacing.py,sha256=nmWpw2dgwhd81LXyznq0rT8w6Z7cNRyGtPJGRyKFRdc,4212
9
10
  replace_link_attributes.py,sha256=Cpc4E-j9j-4_y0LOstAKYOPl02Ln_2bGNIeqp3ZVCdA,7624
10
11
  validate_links.py,sha256=lWuK8sgfiFdfcUdSVAt_5U9JHVde_oa6peSUlBQtsac,6145
12
+ callout_lib/__init__.py,sha256=8B82N_z4D1LaZVYgd5jZR53QAabtgPzADOyGlnvihj0,665
13
+ callout_lib/converter_bullets.py,sha256=8P92QZ0PylrKRE7V-D3TVZCDH0ct3GRIonc7W5AK5uU,3898
14
+ callout_lib/converter_comments.py,sha256=do0dH8uOyNFpn5CDEzR0jYYCMIPP3oPFM8cEB-Fp22c,9767
15
+ callout_lib/converter_deflist.py,sha256=mQ17Y8gJLv0MzzJscpUL7ujuDRyEVcrb9lcPdUNkIX4,3117
16
+ callout_lib/detector.py,sha256=qMFb8MZGYWhEXqV-Bn9BW0qXlYgJcVwKyPI-50oYl5U,10937
17
+ callout_lib/table_parser.py,sha256=0sngxSXdVxc9vs6umeV6hgOIP2ETC7I_RbrEuSntB6k,15505
11
18
  doc_utils/__init__.py,sha256=qqZR3lohzkP63soymrEZPBGzzk6-nFzi4_tSffjmu_0,74
12
19
  doc_utils/extract_link_attributes.py,sha256=U0EvPZReJQigNfbT-icBsVT6Li64hYki5W7MQz6qqbc,22743
13
20
  doc_utils/file_utils.py,sha256=fpTh3xx759sF8sNocdn_arsP3KAv8XA6cTQTAVIZiZg,4247
@@ -22,9 +29,9 @@ doc_utils/unused_images.py,sha256=nqn36Bbrmon2KlGlcaruNjJJvTQ8_9H0WU9GvCW7rW8,14
22
29
  doc_utils/validate_links.py,sha256=iBGXnwdeLlgIT3fo3v01ApT5k0X2FtctsvkrE6E3VMk,19610
23
30
  doc_utils/version.py,sha256=5Uc0sAUOkXA6R_PvDGjw2MBYptEKdav5XmeRqukMTo0,203
24
31
  doc_utils/version_check.py,sha256=eHJnZmBTbdhhY2fJQW9KnnyD0rWEvCZpMg6oSr0fOmI,7090
25
- rolfedh_doc_utils-0.1.24.dist-info/licenses/LICENSE,sha256=vLxtwMVOJA_hEy8b77niTkdmQI9kNJskXHq0dBS36e0,1075
26
- rolfedh_doc_utils-0.1.24.dist-info/METADATA,sha256=1IJI_6eS9NzQnW6oJfzrevLrwDoOjurisURUMUNgyaQ,8325
27
- rolfedh_doc_utils-0.1.24.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
28
- rolfedh_doc_utils-0.1.24.dist-info/entry_points.txt,sha256=uoZFRyvDmJfz-0M6cKyB2WjxH0WCmeRrDq0Os1R1wd8,512
29
- rolfedh_doc_utils-0.1.24.dist-info/top_level.txt,sha256=O13H7Ibk6HKNC32hpcqK8Cq13jiIqRP6A_bB66Zib1Q,224
30
- rolfedh_doc_utils-0.1.24.dist-info/RECORD,,
32
+ rolfedh_doc_utils-0.1.26.dist-info/licenses/LICENSE,sha256=vLxtwMVOJA_hEy8b77niTkdmQI9kNJskXHq0dBS36e0,1075
33
+ rolfedh_doc_utils-0.1.26.dist-info/METADATA,sha256=ni6hzbVbd9CcWp73tFf688p7g5xaWXqsASphw0Bb4kA,8325
34
+ rolfedh_doc_utils-0.1.26.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
35
+ rolfedh_doc_utils-0.1.26.dist-info/entry_points.txt,sha256=vL_LlLKOiurRzchrq8iRUQG19Xi9lSAFVZGjO-xyErk,577
36
+ rolfedh_doc_utils-0.1.26.dist-info/top_level.txt,sha256=J4xtr3zoyCip27b3GnticFVZoyz5HHtgGqHQ-SZONCA,265
37
+ rolfedh_doc_utils-0.1.26.dist-info/RECORD,,
@@ -2,6 +2,7 @@
2
2
  archive-unused-files = archive_unused_files:main
3
3
  archive-unused-images = archive_unused_images:main
4
4
  check-scannability = check_scannability:main
5
+ convert-callouts-interactive = convert_callouts_interactive:main
5
6
  convert-callouts-to-deflist = convert_callouts_to_deflist:main
6
7
  doc-utils = doc_utils_cli:main
7
8
  extract-link-attributes = extract_link_attributes:main