0
# Comment Handling System
1
2
REUSE provides an extensible comment processing system that supports 25+ file types for adding and parsing copyright headers. The system automatically detects comment styles and provides utilities for managing comment-based REUSE information.
3
4
## Capabilities
5
6
### Comment Style Detection
7
8
Automatically detect and retrieve appropriate comment styles for files.
9
10
```python { .api }
11
def get_comment_style(path: StrPath) -> Optional[Type[CommentStyle]]:
12
"""
13
Detect comment style for file path.
14
15
Args:
16
path: File path to analyze (accepts str or Path-like)
17
18
Returns:
19
CommentStyle class appropriate for the file type, or None if unsupported
20
21
Note:
22
Detection is based on file extension and content analysis.
23
Returns the most appropriate comment style class for the file.
24
"""
25
26
def is_uncommentable(path: Path) -> bool:
27
"""
28
Check if file cannot have comments added.
29
30
Args:
31
path: File path to check
32
33
Returns:
34
True if file type doesn't support comments (e.g., binary files)
35
"""
36
37
def has_style(path: Path) -> bool:
38
"""
39
Check if path has a known comment style.
40
41
Args:
42
path: File path to check
43
44
Returns:
45
True if a comment style exists for this file type
46
"""
47
```
48
49
**Usage Examples:**
50
51
```python
52
from reuse.comment import get_comment_style, is_uncommentable, has_style
53
from pathlib import Path
54
55
# Detect comment style for different file types
56
python_file = Path("example.py")
57
c_file = Path("example.c")
58
html_file = Path("example.html")
59
60
# Get comment styles
61
python_style = get_comment_style(python_file)
62
c_style = get_comment_style(c_file)
63
html_style = get_comment_style(html_file)
64
65
print(f"Python style: {python_style.__name__ if python_style else 'None'}")
66
print(f"C style: {c_style.__name__ if c_style else 'None'}")
67
print(f"HTML style: {html_style.__name__ if html_style else 'None'}")
68
69
# Check if files can be commented
70
print(f"Can comment Python: {not is_uncommentable(python_file)}")
71
print(f"Python has style: {has_style(python_file)}")
72
73
# Check binary file
74
binary_file = Path("example.png")
75
print(f"Can comment PNG: {not is_uncommentable(binary_file)}")
76
```
77
78
### Base Comment Style Class
79
80
The foundation class for all comment style implementations.
81
82
```python { .api }
83
class CommentStyle:
84
"""
85
Base class for different file comment styles.
86
87
Subclasses implement specific comment syntax for different file types.
88
Each style defines how to create single-line and multi-line comments
89
appropriate for the file format.
90
"""
91
92
# Class attributes defined by subclasses:
93
SHORTHAND: str = "" # Short identifier for the style
94
SINGLE_LINE: str = "" # Single-line comment prefix
95
SINGLE_LINE_REGEXP: Optional[re.Pattern] = None # Regex for parsing single-line comments
96
INDENT_AFTER_SINGLE: str = "" # Indentation after single-line prefix
97
MULTI_LINE: MultiLineSegments = MultiLineSegments("", "", "") # Multi-line comment structure
98
INDENT_BEFORE_MIDDLE: str = "" # Indentation before middle marker
99
INDENT_AFTER_MIDDLE: str = "" # Indentation after middle marker
100
INDENT_BEFORE_END: str = "" # Indentation before end marker
101
SHEBANGS: list[str] = [] # Supported shebang patterns
102
103
@classmethod
104
def can_handle_single(cls) -> bool:
105
"""Whether the CommentStyle can handle single-line comments."""
106
107
@classmethod
108
def can_handle_multi(cls) -> bool:
109
"""Whether the CommentStyle can handle multi-line comments."""
110
111
@classmethod
112
def create_comment(cls, text: str, force_multi: bool = False) -> str:
113
"""Comment all lines in text. Single-line comments are preferred unless force_multi is True.
114
115
Raises:
116
CommentCreateError: if text could not be commented.
117
"""
118
119
@classmethod
120
def parse_comment(cls, text: str) -> str:
121
"""Parse and extract comment content from commented text.
122
123
Raises:
124
CommentParseError: if text could not be parsed.
125
"""
126
127
@classmethod
128
def comment_at_first_character(cls, text: str) -> str:
129
"""Create comment starting at the first character of text."""
130
```
131
132
### Multi-line Comment Structure
133
134
Data structure for multi-line comment formatting.
135
136
```python { .api }
137
class MultiLineSegments(NamedTuple):
138
"""
139
Structure for multi-line comment formatting.
140
141
Attributes:
142
start: str - Start marker for multi-line comment
143
middle: str - Middle prefix for each line in multi-line comment
144
end: str - End marker for multi-line comment
145
"""
146
start: str
147
middle: str
148
end: str
149
```
150
151
**Usage Examples:**
152
153
```python
154
from reuse.comment import MultiLineSegments, CommentStyle
155
156
# Example multi-line segments for C-style comments
157
c_multiline = MultiLineSegments(
158
start="/*",
159
middle=" *",
160
end=" */"
161
)
162
163
print(f"C comment start: {c_multiline.start}")
164
print(f"C comment middle: {c_multiline.middle}")
165
print(f"C comment end: {c_multiline.end}")
166
```
167
168
### Supported Comment Styles
169
170
The system provides built-in support for 25+ file types through specialized comment style classes.
171
172
```python { .api }
173
# Programming Languages
174
class PythonCommentStyle(CommentStyle):
175
"""Python files (.py) - # single-line comments"""
176
pass
177
178
class CCommentStyle(CommentStyle):
179
"""C files (.c, .h) - /* multi-line */ comments"""
180
pass
181
182
class CppCommentStyle(CommentStyle):
183
"""C++ files (.cpp, .hpp) - /* multi-line */ comments"""
184
pass
185
186
class CppSingleCommentStyle(CommentStyle):
187
"""C++ files - // single-line comments"""
188
pass
189
190
class JavaCommentStyle(CommentStyle):
191
"""Java files (.java) - /* multi-line */ and // single-line"""
192
pass
193
194
class HaskellCommentStyle(CommentStyle):
195
"""Haskell files (.hs) - -- single-line comments"""
196
pass
197
198
class JuliaCommentStyle(CommentStyle):
199
"""Julia files (.jl) - # single-line comments"""
200
pass
201
202
class FortranCommentStyle(CommentStyle):
203
"""Fortran files (.f, .for) - C or * in column 1"""
204
pass
205
206
class ModernFortranCommentStyle(CommentStyle):
207
"""Modern Fortran files (.f90, .f95) - ! single-line comments"""
208
pass
209
210
class LispCommentStyle(CommentStyle):
211
"""Lisp files (.lisp, .cl) - ; single-line comments"""
212
pass
213
214
class MlCommentStyle(CommentStyle):
215
"""ML files (.ml, .mli) - (* multi-line *) comments"""
216
pass
217
218
class LeanCommentStyle(CommentStyle):
219
"""Lean files (.lean) - -- single-line comments"""
220
pass
221
222
# Markup and Templates
223
class HtmlCommentStyle(CommentStyle):
224
"""HTML files (.html, .htm) - <!-- multi-line --> comments"""
225
pass
226
227
class JinjaCommentStyle(CommentStyle):
228
"""Jinja templates (.j2, .jinja) - {# multi-line #} comments"""
229
pass
230
231
class HandlebarsCommentStyle(CommentStyle):
232
"""Handlebars templates (.hbs) - {{! multi-line }} comments"""
233
pass
234
235
class VelocityCommentStyle(CommentStyle):
236
"""Velocity templates (.vm) - ## single-line comments"""
237
pass
238
239
class TexCommentStyle(CommentStyle):
240
"""TeX/LaTeX files (.tex, .sty) - % single-line comments"""
241
pass
242
243
class ReStructedTextCommentStyle(CommentStyle):
244
"""reStructuredText files (.rst) - .. single-line comments"""
245
pass
246
247
# Configuration and Data
248
class BibTexCommentStyle(CommentStyle):
249
"""BibTeX files (.bib) - % single-line comments"""
250
pass
251
252
class M4CommentStyle(CommentStyle):
253
"""M4 files (.m4) - dnl single-line comments"""
254
pass
255
256
class FtlCommentStyle(CommentStyle):
257
"""FTL files (.ftl) - <#-- multi-line --> comments"""
258
pass
259
260
# Scripting and System
261
class BatchFileCommentStyle(CommentStyle):
262
"""Batch files (.bat, .cmd) - REM single-line comments"""
263
pass
264
265
class AppleScriptCommentStyle(CommentStyle):
266
"""AppleScript files (.scpt) - -- single-line comments"""
267
pass
268
269
class VimCommentStyle(CommentStyle):
270
"""Vim script files (.vim) - \" single-line comments"""
271
pass
272
273
class UnixManCommentStyle(CommentStyle):
274
"""Unix manual pages (.1, .2, etc.) - .\\\" single-line comments"""
275
pass
276
277
# Other Formats
278
class AspxCommentStyle(CommentStyle):
279
"""ASPX files (.aspx) - <%-- multi-line --%> comments"""
280
pass
281
282
class XQueryCommentStyle(CommentStyle):
283
"""XQuery files (.xq, .xquery) - (: multi-line :) comments"""
284
pass
285
286
class PlantUmlCommentStyle(CommentStyle):
287
"""PlantUML files (.puml) - ' single-line comments"""
288
pass
289
290
class SemicolonCommentStyle(CommentStyle):
291
"""Files using semicolon comments - ; single-line comments"""
292
pass
293
294
# Special Cases
295
class EmptyCommentStyle(CommentStyle):
296
"""Files that support comments but with empty prefix"""
297
pass
298
299
class UncommentableCommentStyle(CommentStyle):
300
"""Files that cannot have comments (binary files, etc.)"""
301
pass
302
```
303
304
### Comment Style Registry
305
306
Access the mapping between style names and comment style classes.
307
308
```python { .api }
309
NAME_STYLE_MAP: dict[str, Type[CommentStyle]]
310
"""Dictionary mapping style names to comment style classes."""
311
```
312
313
**Usage Examples:**
314
315
```python
316
from reuse.comment import NAME_STYLE_MAP
317
318
# List all available comment styles
319
print("Available comment styles:")
320
for name, style_class in NAME_STYLE_MAP.items():
321
print(f" {name}: {style_class.__name__}")
322
323
# Get specific style by name
324
python_style = NAME_STYLE_MAP.get("python")
325
if python_style:
326
print(f"Python style class: {python_style.__name__}")
327
328
# Check if style exists
329
has_rust_style = "rust" in NAME_STYLE_MAP
330
print(f"Has Rust style: {has_rust_style}")
331
```
332
333
## Comment Style Usage Examples
334
335
### Working with Different Comment Styles
336
337
```python
338
from reuse.comment import get_comment_style, PythonCommentStyle, CCommentStyle
339
from pathlib import Path
340
341
def demonstrate_comment_styles():
342
"""Demonstrate comment style detection and usage."""
343
344
# File type detection
345
files = [
346
Path("example.py"),
347
Path("example.c"),
348
Path("example.html"),
349
Path("example.js"),
350
Path("example.tex")
351
]
352
353
for file_path in files:
354
style_class = get_comment_style(file_path)
355
if style_class:
356
print(f"\n{file_path.suffix} files use: {style_class.__name__}")
357
358
# Create style instance
359
style = style_class()
360
361
# Show single-line comment prefix
362
if hasattr(style, 'SINGLE_LINE') and style.SINGLE_LINE:
363
print(f" Single-line: '{style.SINGLE_LINE}'")
364
365
# Show multi-line comment structure
366
if hasattr(style, 'MULTI_LINE') and style.MULTI_LINE:
367
ml = style.MULTI_LINE
368
print(f" Multi-line: '{ml.start}' ... '{ml.middle}' ... '{ml.end}'")
369
370
demonstrate_comment_styles()
371
```
372
373
### Creating Custom Comment Headers
374
375
```python
376
from reuse.comment import get_comment_style, MultiLineSegments
377
from pathlib import Path
378
379
def create_comment_header(file_path: Path, copyright_text: str, license_id: str) -> str:
380
"""Create a properly formatted comment header for a file."""
381
382
style_class = get_comment_style(file_path)
383
if not style_class:
384
return ""
385
386
style = style_class()
387
388
# Prepare header content
389
header_lines = [
390
f"SPDX-FileCopyrightText: {copyright_text}",
391
f"SPDX-License-Identifier: {license_id}"
392
]
393
394
# Format based on comment style
395
if hasattr(style, 'MULTI_LINE') and style.MULTI_LINE:
396
# Use multi-line comment format
397
ml = style.MULTI_LINE
398
formatted_lines = [ml.start]
399
for line in header_lines:
400
formatted_lines.append(f"{ml.middle} {line}")
401
formatted_lines.append(ml.end)
402
return "\n".join(formatted_lines)
403
404
elif hasattr(style, 'SINGLE_LINE') and style.SINGLE_LINE:
405
# Use single-line comment format
406
prefix = style.SINGLE_LINE
407
indent = getattr(style, 'INDENT_AFTER_SINGLE', ' ')
408
formatted_lines = []
409
for line in header_lines:
410
formatted_lines.append(f"{prefix}{indent}{line}")
411
return "\n".join(formatted_lines)
412
413
return ""
414
415
# Usage examples
416
python_header = create_comment_header(
417
Path("example.py"),
418
"2023 Jane Doe <jane@example.com>",
419
"MIT"
420
)
421
print("Python header:")
422
print(python_header)
423
424
c_header = create_comment_header(
425
Path("example.c"),
426
"2023 Jane Doe <jane@example.com>",
427
"GPL-3.0-or-later"
428
)
429
print("\nC header:")
430
print(c_header)
431
```
432
433
### File Type Comment Style Reference
434
435
```python
436
from reuse.comment import get_comment_style
437
from pathlib import Path
438
439
def show_comment_reference():
440
"""Show comment styles for common file types."""
441
442
file_extensions = [
443
".py", ".c", ".cpp", ".java", ".rs", ".go", ".js", ".ts",
444
".html", ".css", ".scss", ".php", ".rb", ".pl", ".sh",
445
".tex", ".md", ".rst", ".yaml", ".json", ".xml", ".sql"
446
]
447
448
print("File Type Comment Style Reference:")
449
print("=" * 50)
450
451
for ext in file_extensions:
452
test_file = Path(f"test{ext}")
453
style_class = get_comment_style(test_file)
454
455
if style_class:
456
style = style_class()
457
comment_info = []
458
459
if hasattr(style, 'SINGLE_LINE') and style.SINGLE_LINE:
460
comment_info.append(f"single: '{style.SINGLE_LINE}'")
461
462
if hasattr(style, 'MULTI_LINE') and style.MULTI_LINE:
463
ml = style.MULTI_LINE
464
comment_info.append(f"multi: '{ml.start}...{ml.end}'")
465
466
print(f"{ext:8} -> {style_class.__name__:25} ({', '.join(comment_info)})")
467
else:
468
print(f"{ext:8} -> No comment style available")
469
470
show_comment_reference()
471
```