|
12 | 12 | from sphinx_codelinks.config import UNIX_NEWLINE, CommentCategory
|
13 | 13 | from sphinx_codelinks.source_discover.config import CommentType
|
14 | 14 |
|
| 15 | +# Language-specific node types for scope detection |
| 16 | +SCOPE_NODE_TYPES = { |
| 17 | + CommentType.python: {"function_definition", "class_definition"}, |
| 18 | + CommentType.cpp: {"function_definition", "class_definition"}, |
| 19 | + CommentType.cs: {"method_declaration", "class_declaration", "property_declaration"}, |
| 20 | +} |
| 21 | + |
15 | 22 | # initialize logger
|
16 | 23 | logger = logging.getLogger(__name__)
|
17 | 24 | logger.setLevel(logging.INFO)
|
|
35 | 42 | (class_definition (block (expression_statement (string)) @comment))
|
36 | 43 | """
|
37 | 44 | CPP_QUERY = """(comment) @comment"""
|
| 45 | +C_SHARP_QUERY = """(comment) @comment""" |
38 | 46 |
|
39 | 47 |
|
40 | 48 | def is_text_file(filepath: Path, sample_size: int = 2048) -> bool:
|
@@ -63,6 +71,11 @@ def init_tree_sitter(comment_type: CommentType) -> tuple[Parser, Query]:
|
63 | 71 |
|
64 | 72 | parsed_language = Language(tree_sitter_python.language())
|
65 | 73 | query = Query(parsed_language, PYTHON_QUERY)
|
| 74 | + elif comment_type == CommentType.cs: |
| 75 | + import tree_sitter_c_sharp # noqa: PLC0415 |
| 76 | + |
| 77 | + parsed_language = Language(tree_sitter_c_sharp.language()) |
| 78 | + query = Query(parsed_language, C_SHARP_QUERY) |
66 | 79 | else:
|
67 | 80 | raise ValueError(f"Unsupported comment style: {comment_type}")
|
68 | 81 | parser = Parser(parsed_language)
|
@@ -90,39 +103,47 @@ def extract_comments(
|
90 | 103 | return captures.get("comment")
|
91 | 104 |
|
92 | 105 |
|
93 |
| -def find_enclosing_scope(node: TreeSitterNode) -> TreeSitterNode | None: |
| 106 | +def find_enclosing_scope( |
| 107 | + node: TreeSitterNode, comment_type: CommentType = CommentType.cpp |
| 108 | +) -> TreeSitterNode | None: |
94 | 109 | """Find the enclosing scope of a comment."""
|
| 110 | + scope_types = SCOPE_NODE_TYPES.get(comment_type, SCOPE_NODE_TYPES[CommentType.cpp]) |
95 | 111 | current: TreeSitterNode = node
|
96 | 112 | while current:
|
97 |
| - if current.type in {"function_definition", "class_definition"}: |
| 113 | + if current.type in scope_types: |
98 | 114 | return current
|
99 | 115 | current: TreeSitterNode | None = current.parent # type: ignore[no-redef] # required for node traversal
|
100 | 116 | return None
|
101 | 117 |
|
102 | 118 |
|
103 |
| -def find_next_scope(node: TreeSitterNode) -> TreeSitterNode | None: |
| 119 | +def find_next_scope( |
| 120 | + node: TreeSitterNode, comment_type: CommentType = CommentType.cpp |
| 121 | +) -> TreeSitterNode | None: |
104 | 122 | """Find the next scope of a comment."""
|
| 123 | + scope_types = SCOPE_NODE_TYPES.get(comment_type, SCOPE_NODE_TYPES[CommentType.cpp]) |
105 | 124 | current: TreeSitterNode = node
|
106 | 125 | while current:
|
107 |
| - if current.type in {"function_definition", "class_definition"}: |
| 126 | + if current.type in scope_types: |
108 | 127 | return current
|
109 | 128 | current: TreeSitterNode | None = current.next_named_sibling # type: ignore[no-redef] # required for node traversal
|
110 | 129 | if current and current.type == "block":
|
111 | 130 | for child in current.named_children:
|
112 |
| - if child.type in {"function_definition", "class_definition"}: |
| 131 | + if child.type in scope_types: |
113 | 132 | return child
|
114 | 133 | return None
|
115 | 134 |
|
116 | 135 |
|
117 |
| -def find_associated_scope(node: TreeSitterNode) -> TreeSitterNode | None: |
| 136 | +def find_associated_scope( |
| 137 | + node: TreeSitterNode, comment_type: CommentType = CommentType.cpp |
| 138 | +) -> TreeSitterNode | None: |
118 | 139 | """Find the associated scope of a comment."""
|
119 | 140 | if node.type == CommentCategory.docstring:
|
120 | 141 | # Only for python's docstring
|
121 |
| - return find_enclosing_scope(node) |
| 142 | + return find_enclosing_scope(node, comment_type) |
122 | 143 | # General comments regardless of comment types
|
123 |
| - associated_scope = find_next_scope(node) |
| 144 | + associated_scope = find_next_scope(node, comment_type) |
124 | 145 | if not associated_scope:
|
125 |
| - associated_scope = find_enclosing_scope(node) |
| 146 | + associated_scope = find_enclosing_scope(node, comment_type) |
126 | 147 | return associated_scope
|
127 | 148 |
|
128 | 149 |
|
|
0 commit comments