|
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