rolfedh-doc-utils 0.1.27__tar.gz → 0.1.29__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.
Files changed (62) hide show
  1. {rolfedh_doc_utils-0.1.27/rolfedh_doc_utils.egg-info → rolfedh_doc_utils-0.1.29}/PKG-INFO +1 -1
  2. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/callout_lib/converter_bullets.py +2 -2
  3. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/callout_lib/converter_deflist.py +2 -2
  4. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/callout_lib/detector.py +16 -7
  5. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/callout_lib/table_parser.py +11 -0
  6. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/doc_utils/format_asciidoc_spacing.py +16 -5
  7. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/doc_utils/version.py +1 -1
  8. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/doc_utils/version_check.py +16 -5
  9. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/doc_utils_cli.py +6 -1
  10. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/pyproject.toml +1 -1
  11. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29/rolfedh_doc_utils.egg-info}/PKG-INFO +1 -1
  12. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/tests/test_version_check.py +6 -4
  13. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/LICENSE +0 -0
  14. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/README.md +0 -0
  15. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/archive_unused_files.py +0 -0
  16. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/archive_unused_images.py +0 -0
  17. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/callout_lib/__init__.py +0 -0
  18. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/callout_lib/converter_comments.py +0 -0
  19. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/check_scannability.py +0 -0
  20. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/convert_callouts_interactive.py +0 -0
  21. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/convert_callouts_to_deflist.py +0 -0
  22. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/doc_utils/__init__.py +0 -0
  23. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/doc_utils/extract_link_attributes.py +0 -0
  24. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/doc_utils/file_utils.py +0 -0
  25. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/doc_utils/replace_link_attributes.py +0 -0
  26. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/doc_utils/scannability.py +0 -0
  27. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/doc_utils/spinner.py +0 -0
  28. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/doc_utils/topic_map_parser.py +0 -0
  29. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/doc_utils/unused_adoc.py +0 -0
  30. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/doc_utils/unused_attributes.py +0 -0
  31. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/doc_utils/unused_images.py +0 -0
  32. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/doc_utils/validate_links.py +0 -0
  33. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/extract_link_attributes.py +0 -0
  34. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/find_unused_attributes.py +0 -0
  35. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/format_asciidoc_spacing.py +0 -0
  36. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/replace_link_attributes.py +0 -0
  37. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/rolfedh_doc_utils.egg-info/SOURCES.txt +0 -0
  38. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/rolfedh_doc_utils.egg-info/dependency_links.txt +0 -0
  39. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/rolfedh_doc_utils.egg-info/entry_points.txt +0 -0
  40. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/rolfedh_doc_utils.egg-info/requires.txt +0 -0
  41. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/rolfedh_doc_utils.egg-info/top_level.txt +0 -0
  42. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/setup.cfg +0 -0
  43. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/setup.py +0 -0
  44. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/tests/test_archive_unused_files.py +0 -0
  45. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/tests/test_archive_unused_images.py +0 -0
  46. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/tests/test_auto_discovery.py +0 -0
  47. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/tests/test_check_scannability.py +0 -0
  48. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/tests/test_cli_entry_points.py +0 -0
  49. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/tests/test_extract_link_attributes.py +0 -0
  50. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/tests/test_file_utils.py +0 -0
  51. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/tests/test_fixture_archive_unused_files.py +0 -0
  52. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/tests/test_fixture_archive_unused_images.py +0 -0
  53. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/tests/test_fixture_check_scannability.py +0 -0
  54. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/tests/test_parse_exclude_list.py +0 -0
  55. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/tests/test_replace_link_attributes.py +0 -0
  56. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/tests/test_symlink_handling.py +0 -0
  57. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/tests/test_table_callout_conversion.py +0 -0
  58. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/tests/test_table_parser.py +0 -0
  59. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/tests/test_topic_map_parser.py +0 -0
  60. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/tests/test_unused_attributes.py +0 -0
  61. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/tests/test_validate_links.py +0 -0
  62. {rolfedh_doc_utils-0.1.27 → rolfedh_doc_utils-0.1.29}/validate_links.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rolfedh-doc-utils
3
- Version: 0.1.27
3
+ Version: 0.1.29
4
4
  Summary: CLI tools for AsciiDoc documentation projects
5
5
  Author: Rolfe Dlugy-Hegwer
6
6
  License: MIT License
@@ -59,8 +59,8 @@ class BulletListConverter:
59
59
  user_value = f'{user_value}>'
60
60
  term = f'`{user_value}`'
61
61
  else:
62
- # This is a code line - use it as-is in backticks
63
- term = f'`{code_line}`'
62
+ # This is a code line - strip whitespace before wrapping in backticks
63
+ term = f'`{code_line.strip()}`'
64
64
 
65
65
  # Collect all explanations for this group
66
66
  all_explanation_lines = []
@@ -54,8 +54,8 @@ class DefListConverter:
54
54
  user_value = f'{user_value}>'
55
55
  term = f'`{user_value}`'
56
56
  else:
57
- # This is a code line - use it as-is in backticks
58
- term = f'`{code_line}`'
57
+ # This is a code line - strip whitespace before wrapping in backticks
58
+ term = f'`{code_line.strip()}`'
59
59
 
60
60
  # Add blank line before each term
61
61
  lines.append('')
@@ -45,6 +45,11 @@ class CalloutDetector:
45
45
  # Pattern for callout number in code block (can appear multiple times per line)
46
46
  CALLOUT_IN_CODE = re.compile(r'<(\d+)>')
47
47
 
48
+ # Pattern for callout with optional preceding comment syntax
49
+ # Matches common comment styles: //, #, --, ;, followed by optional whitespace and <number>
50
+ # The comment syntax must be preceded by whitespace to avoid matching code operators
51
+ CALLOUT_WITH_COMMENT = re.compile(r'\s*(?://|#|--|;)\s*<\d+>|\s*<\d+>')
52
+
48
53
  # Pattern for callout explanation line: <1> Explanation text
49
54
  CALLOUT_EXPLANATION = re.compile(r'^<(\d+)>\s+(.+)$')
50
55
 
@@ -130,8 +135,9 @@ class CalloutDetector:
130
135
  # Look for all callout numbers on this line
131
136
  callout_matches = list(self.CALLOUT_IN_CODE.finditer(line))
132
137
  if callout_matches:
133
- # Remove all callouts from the line to get the actual code
134
- line_without_callouts = self.CALLOUT_IN_CODE.sub('', line).strip()
138
+ # Remove callouts AND preceding comment syntax from the line
139
+ # Use CALLOUT_WITH_COMMENT to remove both comment syntax and callout
140
+ line_without_callouts = self.CALLOUT_WITH_COMMENT.sub('', line).rstrip()
135
141
 
136
142
  # Find all angle-bracket enclosed values
137
143
  user_values = self.USER_VALUE_PATTERN.findall(line_without_callouts)
@@ -216,11 +222,11 @@ class CalloutDetector:
216
222
 
217
223
  # Add value lines with context
218
224
  if value_lines:
219
- # Format: "Refers to `value`. Description..."
225
+ # Format: "`value`:"
220
226
  value_text = value_lines[0] if value_lines else ""
221
227
  # If value is code-like (contains backticks or special chars), keep it formatted
222
228
  if value_text:
223
- all_lines.append(f"Refers to {value_text}.")
229
+ all_lines.append(f"{value_text}:")
224
230
 
225
231
  # Add additional value lines if multi-line
226
232
  for line in value_lines[1:]:
@@ -290,11 +296,14 @@ class CalloutDetector:
290
296
  return explanations, i - 1
291
297
 
292
298
  def remove_callouts_from_code(self, content: List[str]) -> List[str]:
293
- """Remove callout numbers from code block content (handles multiple callouts per line)."""
299
+ """
300
+ Remove callout numbers and preceding comment syntax from code block content.
301
+ Handles multiple callouts per line and various comment styles (//, #, --, ;).
302
+ """
294
303
  cleaned = []
295
304
  for line in content:
296
- # Remove all callout numbers and trailing whitespace
297
- cleaned.append(self.CALLOUT_IN_CODE.sub('', line).rstrip())
305
+ # Remove all callout numbers with their preceding comment syntax
306
+ cleaned.append(self.CALLOUT_WITH_COMMENT.sub('', line).rstrip())
298
307
  return cleaned
299
308
 
300
309
  def validate_callouts(self, callout_groups: List[CalloutGroup], explanations: Dict[int, Callout]) -> Tuple[bool, set, set]:
@@ -200,6 +200,17 @@ class TableParser:
200
200
  content=[part],
201
201
  conditionals=[]
202
202
  ))
203
+
204
+ # Multi-cell line completes a row - finalize it
205
+ if current_row_cells:
206
+ rows.append(TableRow(
207
+ cells=current_row_cells.copy(),
208
+ conditionals_before=conditionals_before_row.copy(),
209
+ conditionals_after=conditionals_after_row.copy()
210
+ ))
211
+ current_row_cells = []
212
+ conditionals_before_row = []
213
+ conditionals_after_row = []
203
214
  else:
204
215
  # Single cell on this line
205
216
  if cell_content:
@@ -65,9 +65,16 @@ def process_file(file_path: Path, dry_run: bool = False, verbose: bool = False)
65
65
  new_lines.append(current_line)
66
66
  in_conditional = False
67
67
  # Add blank line after conditional if needed
68
+ # Don't add if next line is:
69
+ # - a list item (starts with *, -, ., .., or numbered)
70
+ # - list continuation (+)
71
+ # - another conditional
72
+ # - blank
68
73
  if (next_line and
69
74
  not re.match(r'^\s*$', next_line) and
70
- not re.match(r'^(ifdef::|ifndef::|endif::)', next_line)):
75
+ not re.match(r'^(ifdef::|ifndef::|endif::)', next_line) and
76
+ not re.match(r'^(\*|\-|\.|\.\.|\d+\.)\s', next_line) and # List items
77
+ not re.match(r'^\+\s*$', next_line)): # List continuation
71
78
  new_lines.append("")
72
79
  changes_made = True
73
80
  if verbose:
@@ -102,10 +109,13 @@ def process_file(file_path: Path, dry_run: bool = False, verbose: bool = False)
102
109
  # Check for block titles (.Title)
103
110
  elif not in_block and not in_comment_block and re.match(r'^\.[A-Z]', current_line):
104
111
  # Add blank line before block title if needed
105
- if (prev_line and
112
+ # Don't add if inside a conditional block or if previous line is a conditional directive
113
+ if (not in_conditional and
114
+ prev_line and
106
115
  not re.match(r'^\s*$', prev_line) and
107
116
  not re.match(r'^=+\s+', prev_line) and
108
- not re.match(r'^\[role=', prev_line)): # Don't add if previous is heading, empty, or role block
117
+ not re.match(r'^\[role=', prev_line) and
118
+ not re.match(r'^(ifdef::|ifndef::|endif::)', prev_line)): # Don't add if previous is conditional
109
119
  new_lines.append("")
110
120
  changes_made = True
111
121
  if verbose:
@@ -117,11 +127,12 @@ def process_file(file_path: Path, dry_run: bool = False, verbose: bool = False)
117
127
  elif not in_block and re.match(r'^=+\s+', current_line):
118
128
  new_lines.append(current_line)
119
129
 
120
- # Check if next line is not empty, not another heading, and not a comment block
130
+ # Check if next line is not empty, not another heading, not a comment block, and not a conditional
121
131
  if (next_line and
122
132
  not re.match(r'^=+\s+', next_line) and
123
133
  not re.match(r'^\s*$', next_line) and
124
- not re.match(r'^////+$', next_line)): # Don't add if next is comment block
134
+ not re.match(r'^////+$', next_line) and # Don't add if next is comment block
135
+ not re.match(r'^(ifdef::|ifndef::|endif::)', next_line)): # Don't add if next is conditional
125
136
  new_lines.append("")
126
137
  changes_made = True
127
138
  if verbose:
@@ -1,7 +1,7 @@
1
1
  """Version information for doc-utils."""
2
2
 
3
3
  # This should match the version in pyproject.toml
4
- __version__ = "0.1.21"
4
+ __version__ = "0.1.29"
5
5
 
6
6
  def get_version():
7
7
  """Return the current version string."""
@@ -141,10 +141,12 @@ def detect_install_method() -> str:
141
141
  Detect how the package was installed.
142
142
 
143
143
  Returns:
144
- 'pipx', 'pip', or 'unknown'
144
+ 'pipx' or 'pip'
145
+
146
+ Note: Defaults to 'pipx' as the recommended installation method.
145
147
  """
146
- # Check if running from pipx venv
147
- if 'pipx' in sys.prefix:
148
+ # Check if running from pipx venv (standard pipx install)
149
+ if 'pipx' in sys.prefix.lower():
148
150
  return 'pipx'
149
151
 
150
152
  # Check PIPX_HOME environment variable
@@ -152,8 +154,17 @@ def detect_install_method() -> str:
152
154
  if pipx_home and str(Path(sys.prefix)).startswith(str(Path(pipx_home))):
153
155
  return 'pipx'
154
156
 
155
- # Default to pip
156
- return 'pip'
157
+ # Check if executable is in typical pipx bin location
158
+ try:
159
+ exe_path = Path(sys.executable)
160
+ if '.local/pipx' in str(exe_path):
161
+ return 'pipx'
162
+ except Exception:
163
+ pass
164
+
165
+ # Default to pipx as the recommended method (per CLAUDE.md guidelines)
166
+ # This ensures users see the recommended upgrade command even for editable installs
167
+ return 'pipx'
157
168
 
158
169
 
159
170
  def show_update_notification(latest_version: str, current_version: str = None):
@@ -55,9 +55,14 @@ TOOLS = [
55
55
  },
56
56
  {
57
57
  'name': 'convert-callouts-to-deflist',
58
- 'description': 'Converts callout-style annotations to definition list format',
58
+ 'description': 'Converts callouts to definition lists (batch mode)',
59
59
  'example': 'convert-callouts-to-deflist --dry-run modules/'
60
60
  },
61
+ {
62
+ 'name': 'convert-callouts-interactive',
63
+ 'description': 'Interactively converts callouts with per-block format selection',
64
+ 'example': 'convert-callouts-interactive modules/'
65
+ },
61
66
  ]
62
67
 
63
68
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "rolfedh-doc-utils"
7
- version = "0.1.27"
7
+ version = "0.1.29"
8
8
  description = "CLI tools for AsciiDoc documentation projects"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rolfedh-doc-utils
3
- Version: 0.1.27
3
+ Version: 0.1.29
4
4
  Summary: CLI tools for AsciiDoc documentation projects
5
5
  Author: Rolfe Dlugy-Hegwer
6
6
  License: MIT License
@@ -26,20 +26,22 @@ class TestDetectInstallMethod:
26
26
  assert detect_install_method() == 'pipx'
27
27
 
28
28
  def test_detect_pip(self):
29
- """Test detection defaults to pip."""
29
+ """Test detection defaults to pipx (per project guidelines)."""
30
30
  with patch('sys.prefix', '/usr'):
31
31
  # Clear PIPX_HOME if set
32
32
  env = {k: v for k, v in os.environ.items() if k != 'PIPX_HOME'}
33
33
  with patch.dict(os.environ, env, clear=True):
34
- assert detect_install_method() == 'pip'
34
+ # Default is now pipx to align with installation recommendations
35
+ assert detect_install_method() == 'pipx'
35
36
 
36
37
  def test_detect_pip_user(self):
37
- """Test detection for pip --user installations."""
38
+ """Test detection for pip --user installations defaults to pipx."""
38
39
  with patch('sys.prefix', '/home/user/.local'):
39
40
  # Clear PIPX_HOME if set
40
41
  env = {k: v for k, v in os.environ.items() if k != 'PIPX_HOME'}
41
42
  with patch.dict(os.environ, env, clear=True):
42
- assert detect_install_method() == 'pip'
43
+ # Default is now pipx to align with installation recommendations
44
+ assert detect_install_method() == 'pipx'
43
45
 
44
46
 
45
47
  class TestParseVersion: