QCodeSitter 0.1.0__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.
- QCodeSitter/__init__.py +38 -0
- QCodeSitter/behaviors/__init__.py +115 -0
- QCodeSitter/behaviors/auto_bracket.py +141 -0
- QCodeSitter/behaviors/code_folding.py +530 -0
- QCodeSitter/behaviors/comment_toggle.py +71 -0
- QCodeSitter/behaviors/highlight_matching_brackets.py +181 -0
- QCodeSitter/behaviors/highlight_matching_selection.py +59 -0
- QCodeSitter/behaviors/line_numbers.py +49 -0
- QCodeSitter/behaviors/multi_cursor_paint.py +131 -0
- QCodeSitter/behaviors/overscroll.py +104 -0
- QCodeSitter/behaviors/smart_indent.py +191 -0
- QCodeSitter/behaviors/syntax_highlighting.py +181 -0
- QCodeSitter/behaviors/tab_completion/__init__.py +257 -0
- QCodeSitter/behaviors/tab_completion/popup.py +123 -0
- QCodeSitter/behaviors/tab_completion/providers.py +66 -0
- QCodeSitter/behaviors/tab_completion/types.py +55 -0
- QCodeSitter/code_editor.py +540 -0
- QCodeSitter/cursors/__init__.py +8 -0
- QCodeSitter/cursors/clipboard.py +51 -0
- QCodeSitter/cursors/iterator.py +141 -0
- QCodeSitter/cursors/line_edits.py +128 -0
- QCodeSitter/cursors/multi.py +240 -0
- QCodeSitter/cursors/state.py +55 -0
- QCodeSitter/cursors/tracked.py +97 -0
- QCodeSitter/defaults.py +93 -0
- QCodeSitter/editing_keys.py +150 -0
- QCodeSitter/editor_options.py +246 -0
- QCodeSitter/gui_colors.py +51 -0
- QCodeSitter/gutters.py +141 -0
- QCodeSitter/integrations/__init__.py +1 -0
- QCodeSitter/integrations/preditor_interface.py +390 -0
- QCodeSitter/languages/__init__.py +99 -0
- QCodeSitter/languages/base.py +60 -0
- QCodeSitter/languages/python.py +146 -0
- QCodeSitter/languages/python_highlights.py +444 -0
- QCodeSitter/py.typed +0 -0
- QCodeSitter/queries/__init__.py +73 -0
- QCodeSitter/queries/predicates.py +172 -0
- QCodeSitter/syntax_specs.py +65 -0
- QCodeSitter/themes.py +271 -0
- QCodeSitter/tracked_document.py +107 -0
- QCodeSitter/tree_manager.py +180 -0
- QCodeSitter/utils.py +84 -0
- qcodesitter-0.1.0.dist-info/METADATA +255 -0
- qcodesitter-0.1.0.dist-info/RECORD +49 -0
- qcodesitter-0.1.0.dist-info/WHEEL +5 -0
- qcodesitter-0.1.0.dist-info/entry_points.txt +2 -0
- qcodesitter-0.1.0.dist-info/licenses/LICENSE.txt +7 -0
- qcodesitter-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Collection
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from ..utils import leading_whitespace
|
|
7
|
+
from .base import IndentRules, LanguageSpec
|
|
8
|
+
from .python_highlights import HIGHLIGHT_QUERY
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from tree_sitter import Node
|
|
12
|
+
|
|
13
|
+
# Statements whose body starts after a colon
|
|
14
|
+
_BLOCK_TYPES = frozenset(
|
|
15
|
+
{
|
|
16
|
+
"if_statement",
|
|
17
|
+
"for_statement",
|
|
18
|
+
"while_statement",
|
|
19
|
+
"function_definition",
|
|
20
|
+
"class_definition",
|
|
21
|
+
"with_statement",
|
|
22
|
+
"try_statement",
|
|
23
|
+
"except_clause",
|
|
24
|
+
"finally_clause",
|
|
25
|
+
"elif_clause",
|
|
26
|
+
"else_clause",
|
|
27
|
+
"match_statement",
|
|
28
|
+
"case_clause",
|
|
29
|
+
}
|
|
30
|
+
)
|
|
31
|
+
_COLLECTION_TYPES = frozenset(
|
|
32
|
+
{"list", "dictionary", "set", "tuple", "argument_list", "parameters"}
|
|
33
|
+
)
|
|
34
|
+
# Statements that end their block, so the next line dedents
|
|
35
|
+
_TERMINAL_TYPES = frozenset(
|
|
36
|
+
{
|
|
37
|
+
"return_statement",
|
|
38
|
+
"break_statement",
|
|
39
|
+
"continue_statement",
|
|
40
|
+
"pass_statement",
|
|
41
|
+
"raise_statement",
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
_OPEN_BRACKETS = frozenset("([{")
|
|
45
|
+
_CLOSE_BRACKETS = frozenset(")]}")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _child_of_type(node: Node, types: Collection[str]) -> Node | None:
|
|
49
|
+
for child in node.children:
|
|
50
|
+
if child.type in types:
|
|
51
|
+
return child
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _opens_block(node: Node, row: int) -> bool:
|
|
56
|
+
"""Whether this node starts an indented block or open bracket on the row"""
|
|
57
|
+
if node.type in _BLOCK_TYPES:
|
|
58
|
+
# The colon can be followed by a comment, like "def foo(): # comment"
|
|
59
|
+
colon = _child_of_type(node, (":",))
|
|
60
|
+
return colon is not None and colon.start_point.row == row
|
|
61
|
+
if node.type in _OPEN_BRACKETS:
|
|
62
|
+
# Incomplete code can leave a bare bracket in an ERROR node
|
|
63
|
+
return node.start_point.row == row
|
|
64
|
+
if node.type in _COLLECTION_TYPES:
|
|
65
|
+
opening = _child_of_type(node, _OPEN_BRACKETS)
|
|
66
|
+
closing = _child_of_type(node, _CLOSE_BRACKETS)
|
|
67
|
+
if opening is None or opening.start_point.row != row:
|
|
68
|
+
return False
|
|
69
|
+
return closing is None or closing.start_point.row != row
|
|
70
|
+
return False
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class PythonIndentRules(IndentRules):
|
|
74
|
+
def should_indent_after(self, row: int, col: int) -> bool:
|
|
75
|
+
node = self.node_at(row, col)
|
|
76
|
+
while node is not None:
|
|
77
|
+
if _opens_block(node, row):
|
|
78
|
+
return True
|
|
79
|
+
node = node.parent
|
|
80
|
+
return False
|
|
81
|
+
|
|
82
|
+
def should_dedent_after(self, row: int, col: int) -> bool:
|
|
83
|
+
node = self.node_at(row, col)
|
|
84
|
+
if node is None:
|
|
85
|
+
return False
|
|
86
|
+
if self._closes_earlier_bracket(row, col):
|
|
87
|
+
return True
|
|
88
|
+
while node is not None:
|
|
89
|
+
if node.type in _TERMINAL_TYPES:
|
|
90
|
+
return True
|
|
91
|
+
node = node.parent
|
|
92
|
+
return False
|
|
93
|
+
|
|
94
|
+
def _closes_earlier_bracket(self, row: int, col: int) -> bool:
|
|
95
|
+
"""Whether the line starts with a bracket, after the column, that closes
|
|
96
|
+
a bracket opened on an earlier line
|
|
97
|
+
"""
|
|
98
|
+
line_text = self.document.findBlockByNumber(row).text()
|
|
99
|
+
# The indent is all whitespace, so its length is also its UTF-16 length
|
|
100
|
+
bracket_col = len(leading_whitespace(line_text))
|
|
101
|
+
if line_text[bracket_col : bracket_col + 1] not in _CLOSE_BRACKETS:
|
|
102
|
+
return False
|
|
103
|
+
# Enter after the bracket keeps the indent of the closing line
|
|
104
|
+
if col >= bracket_col:
|
|
105
|
+
return False
|
|
106
|
+
bracket = self.node_at(row, bracket_col)
|
|
107
|
+
if bracket is None or bracket.parent is None:
|
|
108
|
+
return False
|
|
109
|
+
opening = _child_of_type(bracket.parent, _OPEN_BRACKETS)
|
|
110
|
+
return opening is not None and opening.start_point.row < row
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
IDENTIFIER_QUERY = """
|
|
114
|
+
(function_definition name: (identifier) @function)
|
|
115
|
+
(class_definition name: (identifier) @class)
|
|
116
|
+
(assignment left: (identifier) @variable)
|
|
117
|
+
(parameters (identifier) @parameter)
|
|
118
|
+
(import_statement name: (dotted_name (identifier) @import))
|
|
119
|
+
(import_from_statement name: (dotted_name (identifier) @import))
|
|
120
|
+
(aliased_import name: (dotted_name (identifier) @import))
|
|
121
|
+
(aliased_import alias: (identifier) @import)
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
PYTHON = LanguageSpec(
|
|
125
|
+
name="python",
|
|
126
|
+
comment_prefix="# ",
|
|
127
|
+
highlight_query=HIGHLIGHT_QUERY,
|
|
128
|
+
identifier_query=IDENTIFIER_QUERY,
|
|
129
|
+
fold_hide_last_line=frozenset(
|
|
130
|
+
{
|
|
131
|
+
"class_definition",
|
|
132
|
+
"for_statement",
|
|
133
|
+
"function_definition",
|
|
134
|
+
"if_statement",
|
|
135
|
+
"match_statement",
|
|
136
|
+
"try_statement",
|
|
137
|
+
"while_statement",
|
|
138
|
+
"with_statement",
|
|
139
|
+
}
|
|
140
|
+
),
|
|
141
|
+
fold_keep_last_line=frozenset({"argument_list", "dictionary", "list", "tuple"}),
|
|
142
|
+
indent_rules=PythonIndentRules,
|
|
143
|
+
no_completion_types=frozenset({"string", "comment", "string_start", "string_end"}),
|
|
144
|
+
string_type="string",
|
|
145
|
+
string_delimiter_types=("string_start", "string_end"),
|
|
146
|
+
)
|
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
HIGHLIGHT_QUERY = """
|
|
2
|
+
; From tree-sitter-python licensed under MIT License
|
|
3
|
+
; Copyright (c) 2016 Max Brunsfeld
|
|
4
|
+
; Variables
|
|
5
|
+
(identifier) @variable
|
|
6
|
+
|
|
7
|
+
; Reset highlighting in f-string interpolations
|
|
8
|
+
(interpolation) @none
|
|
9
|
+
|
|
10
|
+
; Identifier naming conventions
|
|
11
|
+
((identifier) @type
|
|
12
|
+
(#match? @type "^[A-Z].*[a-z]"))
|
|
13
|
+
|
|
14
|
+
((identifier) @constant
|
|
15
|
+
(#match? @constant "^[A-Z][A-Z_0-9]*$"))
|
|
16
|
+
|
|
17
|
+
((identifier) @constant.builtin
|
|
18
|
+
(#match? @constant.builtin "^__[a-zA-Z0-9_]*__$"))
|
|
19
|
+
|
|
20
|
+
((identifier) @constant.builtin
|
|
21
|
+
(#any-of? @constant.builtin
|
|
22
|
+
; https://docs.python.org/3/library/constants.html
|
|
23
|
+
"NotImplemented" "Ellipsis" "quit" "exit" "copyright" "credits" "license"))
|
|
24
|
+
|
|
25
|
+
"_" @character.special ; match wildcard
|
|
26
|
+
|
|
27
|
+
((assignment
|
|
28
|
+
left: (identifier) @type.definition
|
|
29
|
+
(type
|
|
30
|
+
(identifier) @_annotation))
|
|
31
|
+
(#eq? @_annotation "TypeAlias"))
|
|
32
|
+
|
|
33
|
+
((assignment
|
|
34
|
+
left: (identifier) @type.definition
|
|
35
|
+
right: (call
|
|
36
|
+
function: (identifier) @_func))
|
|
37
|
+
(#any-of? @_func "TypeVar" "NewType"))
|
|
38
|
+
|
|
39
|
+
; Function definitions
|
|
40
|
+
(function_definition
|
|
41
|
+
name: (identifier) @function)
|
|
42
|
+
|
|
43
|
+
(type
|
|
44
|
+
(identifier) @type)
|
|
45
|
+
|
|
46
|
+
(type
|
|
47
|
+
(subscript
|
|
48
|
+
(identifier) @type)) ; type subscript: Tuple[int]
|
|
49
|
+
|
|
50
|
+
((call
|
|
51
|
+
function: (identifier) @_isinstance
|
|
52
|
+
arguments: (argument_list
|
|
53
|
+
(_)
|
|
54
|
+
(identifier) @type))
|
|
55
|
+
(#eq? @_isinstance "isinstance"))
|
|
56
|
+
|
|
57
|
+
; Literals
|
|
58
|
+
(none) @constant.builtin
|
|
59
|
+
|
|
60
|
+
[
|
|
61
|
+
(true)
|
|
62
|
+
(false)
|
|
63
|
+
] @boolean
|
|
64
|
+
|
|
65
|
+
(integer) @number
|
|
66
|
+
|
|
67
|
+
(float) @number.float
|
|
68
|
+
|
|
69
|
+
(comment) @comment @spell
|
|
70
|
+
|
|
71
|
+
((module
|
|
72
|
+
.
|
|
73
|
+
(comment) @keyword.directive @nospell)
|
|
74
|
+
(#match? @keyword.directive "^#!/"))
|
|
75
|
+
|
|
76
|
+
(string) @string
|
|
77
|
+
|
|
78
|
+
[
|
|
79
|
+
(escape_sequence)
|
|
80
|
+
(escape_interpolation)
|
|
81
|
+
] @string.escape
|
|
82
|
+
|
|
83
|
+
; doc-strings
|
|
84
|
+
(expression_statement
|
|
85
|
+
(string
|
|
86
|
+
(string_content) @spell) @string.documentation)
|
|
87
|
+
|
|
88
|
+
; Tokens
|
|
89
|
+
[
|
|
90
|
+
"-"
|
|
91
|
+
"-="
|
|
92
|
+
":="
|
|
93
|
+
"!="
|
|
94
|
+
"*"
|
|
95
|
+
"**"
|
|
96
|
+
"**="
|
|
97
|
+
"*="
|
|
98
|
+
"/"
|
|
99
|
+
"//"
|
|
100
|
+
"//="
|
|
101
|
+
"/="
|
|
102
|
+
"&"
|
|
103
|
+
"&="
|
|
104
|
+
"%"
|
|
105
|
+
"%="
|
|
106
|
+
"^"
|
|
107
|
+
"^="
|
|
108
|
+
"+"
|
|
109
|
+
"+="
|
|
110
|
+
"<"
|
|
111
|
+
"<<"
|
|
112
|
+
"<<="
|
|
113
|
+
"<="
|
|
114
|
+
"<>"
|
|
115
|
+
"="
|
|
116
|
+
"=="
|
|
117
|
+
">"
|
|
118
|
+
">="
|
|
119
|
+
">>"
|
|
120
|
+
">>="
|
|
121
|
+
"@"
|
|
122
|
+
"@="
|
|
123
|
+
"|"
|
|
124
|
+
"|="
|
|
125
|
+
"~"
|
|
126
|
+
"->"
|
|
127
|
+
] @operator
|
|
128
|
+
|
|
129
|
+
; Keywords
|
|
130
|
+
[
|
|
131
|
+
"and"
|
|
132
|
+
"in"
|
|
133
|
+
"is"
|
|
134
|
+
"not"
|
|
135
|
+
"or"
|
|
136
|
+
"is not"
|
|
137
|
+
"not in"
|
|
138
|
+
"del"
|
|
139
|
+
] @keyword.operator
|
|
140
|
+
|
|
141
|
+
[
|
|
142
|
+
"def"
|
|
143
|
+
"lambda"
|
|
144
|
+
] @keyword.function
|
|
145
|
+
|
|
146
|
+
[
|
|
147
|
+
"assert"
|
|
148
|
+
"exec"
|
|
149
|
+
"global"
|
|
150
|
+
"nonlocal"
|
|
151
|
+
"pass"
|
|
152
|
+
"print"
|
|
153
|
+
"with"
|
|
154
|
+
"as"
|
|
155
|
+
] @keyword
|
|
156
|
+
|
|
157
|
+
[
|
|
158
|
+
"type"
|
|
159
|
+
"class"
|
|
160
|
+
] @keyword.type
|
|
161
|
+
|
|
162
|
+
[
|
|
163
|
+
"async"
|
|
164
|
+
"await"
|
|
165
|
+
] @keyword.coroutine
|
|
166
|
+
|
|
167
|
+
[
|
|
168
|
+
"return"
|
|
169
|
+
"yield"
|
|
170
|
+
] @keyword.return
|
|
171
|
+
|
|
172
|
+
(yield
|
|
173
|
+
"from" @keyword.return)
|
|
174
|
+
|
|
175
|
+
(future_import_statement
|
|
176
|
+
"from" @keyword.import
|
|
177
|
+
"__future__" @module.builtin)
|
|
178
|
+
|
|
179
|
+
(import_from_statement
|
|
180
|
+
"from" @keyword.import)
|
|
181
|
+
|
|
182
|
+
"import" @keyword.import
|
|
183
|
+
|
|
184
|
+
(aliased_import
|
|
185
|
+
"as" @keyword.import)
|
|
186
|
+
|
|
187
|
+
(wildcard_import
|
|
188
|
+
"*" @character.special)
|
|
189
|
+
|
|
190
|
+
(import_statement
|
|
191
|
+
name: (dotted_name
|
|
192
|
+
(identifier) @module))
|
|
193
|
+
|
|
194
|
+
(import_statement
|
|
195
|
+
name: (aliased_import
|
|
196
|
+
name: (dotted_name
|
|
197
|
+
(identifier) @module)
|
|
198
|
+
alias: (identifier) @module))
|
|
199
|
+
|
|
200
|
+
(import_from_statement
|
|
201
|
+
module_name: (dotted_name
|
|
202
|
+
(identifier) @module))
|
|
203
|
+
|
|
204
|
+
(import_from_statement
|
|
205
|
+
module_name: (relative_import
|
|
206
|
+
(dotted_name
|
|
207
|
+
(identifier) @module)))
|
|
208
|
+
|
|
209
|
+
[
|
|
210
|
+
"if"
|
|
211
|
+
"elif"
|
|
212
|
+
"else"
|
|
213
|
+
"match"
|
|
214
|
+
"case"
|
|
215
|
+
] @keyword.conditional
|
|
216
|
+
|
|
217
|
+
[
|
|
218
|
+
"for"
|
|
219
|
+
"while"
|
|
220
|
+
"break"
|
|
221
|
+
"continue"
|
|
222
|
+
] @keyword.repeat
|
|
223
|
+
|
|
224
|
+
[
|
|
225
|
+
"try"
|
|
226
|
+
"except"
|
|
227
|
+
"raise"
|
|
228
|
+
"finally"
|
|
229
|
+
] @keyword.exception
|
|
230
|
+
|
|
231
|
+
(raise_statement
|
|
232
|
+
"from" @keyword.exception)
|
|
233
|
+
|
|
234
|
+
(try_statement
|
|
235
|
+
(else_clause
|
|
236
|
+
"else" @keyword.exception))
|
|
237
|
+
|
|
238
|
+
[
|
|
239
|
+
"("
|
|
240
|
+
")"
|
|
241
|
+
"["
|
|
242
|
+
"]"
|
|
243
|
+
"{"
|
|
244
|
+
"}"
|
|
245
|
+
] @punctuation.bracket
|
|
246
|
+
|
|
247
|
+
(interpolation
|
|
248
|
+
"{" @punctuation.special
|
|
249
|
+
"}" @punctuation.special)
|
|
250
|
+
|
|
251
|
+
(type_conversion) @function.macro
|
|
252
|
+
|
|
253
|
+
[
|
|
254
|
+
","
|
|
255
|
+
"."
|
|
256
|
+
":"
|
|
257
|
+
";"
|
|
258
|
+
(ellipsis)
|
|
259
|
+
] @punctuation.delimiter
|
|
260
|
+
|
|
261
|
+
((identifier) @type.builtin
|
|
262
|
+
(#any-of? @type.builtin
|
|
263
|
+
; https://docs.python.org/3/library/exceptions.html
|
|
264
|
+
"BaseException" "Exception" "ArithmeticError" "BufferError" "LookupError" "AssertionError"
|
|
265
|
+
"AttributeError" "EOFError" "FloatingPointError" "GeneratorExit" "ImportError"
|
|
266
|
+
"ModuleNotFoundError" "IndexError" "KeyError" "KeyboardInterrupt" "MemoryError" "NameError"
|
|
267
|
+
"NotImplementedError" "OSError" "OverflowError" "RecursionError" "ReferenceError" "RuntimeError"
|
|
268
|
+
"StopIteration" "StopAsyncIteration" "SyntaxError" "IndentationError" "TabError" "SystemError"
|
|
269
|
+
"SystemExit" "TypeError" "UnboundLocalError" "UnicodeError" "UnicodeEncodeError"
|
|
270
|
+
"UnicodeDecodeError" "UnicodeTranslateError" "ValueError" "ZeroDivisionError" "EnvironmentError"
|
|
271
|
+
"IOError" "WindowsError" "BlockingIOError" "ChildProcessError" "ConnectionError"
|
|
272
|
+
"BrokenPipeError" "ConnectionAbortedError" "ConnectionRefusedError" "ConnectionResetError"
|
|
273
|
+
"FileExistsError" "FileNotFoundError" "InterruptedError" "IsADirectoryError"
|
|
274
|
+
"NotADirectoryError" "PermissionError" "ProcessLookupError" "TimeoutError" "Warning"
|
|
275
|
+
"UserWarning" "DeprecationWarning" "PendingDeprecationWarning" "SyntaxWarning" "RuntimeWarning"
|
|
276
|
+
"FutureWarning" "ImportWarning" "UnicodeWarning" "BytesWarning" "ResourceWarning"
|
|
277
|
+
; https://docs.python.org/3/library/stdtypes.html
|
|
278
|
+
"bool" "int" "float" "complex" "list" "tuple" "range" "str" "bytes" "bytearray" "memoryview"
|
|
279
|
+
"set" "frozenset" "dict" "type" "object"))
|
|
280
|
+
|
|
281
|
+
; Normal parameters
|
|
282
|
+
(parameters
|
|
283
|
+
(identifier) @variable.parameter)
|
|
284
|
+
|
|
285
|
+
; Lambda parameters
|
|
286
|
+
(lambda_parameters
|
|
287
|
+
(identifier) @variable.parameter)
|
|
288
|
+
|
|
289
|
+
(lambda_parameters
|
|
290
|
+
(tuple_pattern
|
|
291
|
+
(identifier) @variable.parameter))
|
|
292
|
+
|
|
293
|
+
; Default parameters
|
|
294
|
+
(keyword_argument
|
|
295
|
+
name: (identifier) @variable.parameter)
|
|
296
|
+
|
|
297
|
+
; Naming parameters on call-site
|
|
298
|
+
(default_parameter
|
|
299
|
+
name: (identifier) @variable.parameter)
|
|
300
|
+
|
|
301
|
+
(typed_parameter
|
|
302
|
+
(identifier) @variable.parameter)
|
|
303
|
+
|
|
304
|
+
(typed_default_parameter
|
|
305
|
+
name: (identifier) @variable.parameter)
|
|
306
|
+
|
|
307
|
+
; Variadic parameters *args, **kwargs
|
|
308
|
+
(parameters
|
|
309
|
+
(list_splat_pattern ; *args
|
|
310
|
+
(identifier) @variable.parameter))
|
|
311
|
+
|
|
312
|
+
(parameters
|
|
313
|
+
(dictionary_splat_pattern ; **kwargs
|
|
314
|
+
(identifier) @variable.parameter))
|
|
315
|
+
|
|
316
|
+
; Typed variadic parameters
|
|
317
|
+
(parameters
|
|
318
|
+
(typed_parameter
|
|
319
|
+
(list_splat_pattern ; *args: type
|
|
320
|
+
(identifier) @variable.parameter)))
|
|
321
|
+
|
|
322
|
+
(parameters
|
|
323
|
+
(typed_parameter
|
|
324
|
+
(dictionary_splat_pattern ; *kwargs: type
|
|
325
|
+
(identifier) @variable.parameter)))
|
|
326
|
+
|
|
327
|
+
; Lambda parameters
|
|
328
|
+
(lambda_parameters
|
|
329
|
+
(list_splat_pattern
|
|
330
|
+
(identifier) @variable.parameter))
|
|
331
|
+
|
|
332
|
+
(lambda_parameters
|
|
333
|
+
(dictionary_splat_pattern
|
|
334
|
+
(identifier) @variable.parameter))
|
|
335
|
+
|
|
336
|
+
((identifier) @variable.builtin
|
|
337
|
+
(#eq? @variable.builtin "self"))
|
|
338
|
+
|
|
339
|
+
((identifier) @variable.builtin
|
|
340
|
+
(#eq? @variable.builtin "cls"))
|
|
341
|
+
|
|
342
|
+
; After @type.builtin bacause builtins (such as `type`) are valid as attribute name
|
|
343
|
+
((attribute
|
|
344
|
+
attribute: (identifier) @variable.member)
|
|
345
|
+
(#match? @variable.member "^[%l_].*$"))
|
|
346
|
+
|
|
347
|
+
; Class definitions
|
|
348
|
+
(class_definition
|
|
349
|
+
name: (identifier) @type)
|
|
350
|
+
|
|
351
|
+
(class_definition
|
|
352
|
+
body: (block
|
|
353
|
+
(function_definition
|
|
354
|
+
name: (identifier) @function.method)))
|
|
355
|
+
|
|
356
|
+
(class_definition
|
|
357
|
+
superclasses: (argument_list
|
|
358
|
+
(identifier) @type))
|
|
359
|
+
|
|
360
|
+
((class_definition
|
|
361
|
+
body: (block
|
|
362
|
+
(expression_statement
|
|
363
|
+
(assignment
|
|
364
|
+
left: (identifier) @variable.member))))
|
|
365
|
+
(#match? @variable.member "^[%l_].*$"))
|
|
366
|
+
|
|
367
|
+
((class_definition
|
|
368
|
+
body: (block
|
|
369
|
+
(expression_statement
|
|
370
|
+
(assignment
|
|
371
|
+
left: (_
|
|
372
|
+
(identifier) @variable.member)))))
|
|
373
|
+
(#match? @variable.member "^[%l_].*$"))
|
|
374
|
+
|
|
375
|
+
((class_definition
|
|
376
|
+
(block
|
|
377
|
+
(function_definition
|
|
378
|
+
name: (identifier) @constructor)))
|
|
379
|
+
(#any-of? @constructor "__new__" "__init__"))
|
|
380
|
+
|
|
381
|
+
; Function calls
|
|
382
|
+
(call
|
|
383
|
+
function: (identifier) @function.call)
|
|
384
|
+
|
|
385
|
+
(call
|
|
386
|
+
function: (attribute
|
|
387
|
+
attribute: (identifier) @function.method.call))
|
|
388
|
+
|
|
389
|
+
((call
|
|
390
|
+
function: (identifier) @constructor)
|
|
391
|
+
(#match? @constructor "^%u"))
|
|
392
|
+
|
|
393
|
+
((call
|
|
394
|
+
function: (attribute
|
|
395
|
+
attribute: (identifier) @constructor))
|
|
396
|
+
(#match? @constructor "^%u"))
|
|
397
|
+
|
|
398
|
+
; Builtin functions
|
|
399
|
+
((call
|
|
400
|
+
function: (identifier) @function.builtin)
|
|
401
|
+
(#any-of? @function.builtin
|
|
402
|
+
"abs" "all" "any" "ascii" "bin" "bool" "breakpoint" "bytearray" "bytes" "callable" "chr"
|
|
403
|
+
"classmethod" "compile" "complex" "delattr" "dict" "dir" "divmod" "enumerate" "eval" "exec"
|
|
404
|
+
"filter" "float" "format" "frozenset" "getattr" "globals" "hasattr" "hash" "help" "hex" "id"
|
|
405
|
+
"input" "int" "isinstance" "issubclass" "iter" "len" "list" "locals" "map" "max" "memoryview"
|
|
406
|
+
"min" "next" "object" "oct" "open" "ord" "pow" "print" "property" "range" "repr" "reversed"
|
|
407
|
+
"round" "set" "setattr" "slice" "sorted" "staticmethod" "str" "sum" "super" "tuple" "type"
|
|
408
|
+
"vars" "zip" "__import__"))
|
|
409
|
+
|
|
410
|
+
; Regex from the `re` module
|
|
411
|
+
(call
|
|
412
|
+
function: (attribute
|
|
413
|
+
object: (identifier) @_re)
|
|
414
|
+
arguments: (argument_list
|
|
415
|
+
.
|
|
416
|
+
(string
|
|
417
|
+
(string_content) @string.regexp))
|
|
418
|
+
(#eq? @_re "re"))
|
|
419
|
+
|
|
420
|
+
; Decorators
|
|
421
|
+
((decorator
|
|
422
|
+
"@" @attribute)
|
|
423
|
+
(#set! priority 101))
|
|
424
|
+
|
|
425
|
+
(decorator
|
|
426
|
+
(identifier) @attribute)
|
|
427
|
+
|
|
428
|
+
(decorator
|
|
429
|
+
(attribute
|
|
430
|
+
attribute: (identifier) @attribute))
|
|
431
|
+
|
|
432
|
+
(decorator
|
|
433
|
+
(call
|
|
434
|
+
(identifier) @attribute))
|
|
435
|
+
|
|
436
|
+
(decorator
|
|
437
|
+
(call
|
|
438
|
+
(attribute
|
|
439
|
+
attribute: (identifier) @attribute)))
|
|
440
|
+
|
|
441
|
+
((decorator
|
|
442
|
+
(identifier) @attribute.builtin)
|
|
443
|
+
(#any-of? @attribute.builtin "classmethod" "property" "staticmethod"))
|
|
444
|
+
"""
|
QCodeSitter/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Compiling and running tree-sitter queries
|
|
2
|
+
|
|
3
|
+
Every query is compiled with `compile_query` and run with `query_byte_range`.
|
|
4
|
+
Tree-sitter can't evaluate text predicates like #eq? on our UTF-16 trees, so
|
|
5
|
+
compile_query renames them and query_byte_range evaluates them against the
|
|
6
|
+
document text. predicates.py has the details
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import functools
|
|
12
|
+
import warnings
|
|
13
|
+
from collections.abc import Callable
|
|
14
|
+
from typing import Literal
|
|
15
|
+
|
|
16
|
+
from tree_sitter import Language, Node, Query, QueryCursor, QueryError
|
|
17
|
+
|
|
18
|
+
from .predicates import QueryPredicates, prepare_query_source
|
|
19
|
+
|
|
20
|
+
# A predicate argument is (value, "capture" or "string")
|
|
21
|
+
PredicateArgs = list[tuple[str, Literal["capture", "string"]]]
|
|
22
|
+
# Capture name -> the nodes it captured
|
|
23
|
+
Captures = dict[str, list[Node]]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@functools.lru_cache(maxsize=64)
|
|
27
|
+
def compile_query(language: Language, source: str) -> Query | None:
|
|
28
|
+
"""Compile a query once, and share it between every editor and behavior
|
|
29
|
+
|
|
30
|
+
A query with an error warns once, and gives None so the behavior that
|
|
31
|
+
uses it does nothing, like an invalid #match? pattern matches nothing
|
|
32
|
+
"""
|
|
33
|
+
try:
|
|
34
|
+
return Query(language, prepare_query_source(source))
|
|
35
|
+
except QueryError as err:
|
|
36
|
+
warnings.warn(
|
|
37
|
+
f"Invalid tree-sitter query for {language.name}: {err}", stacklevel=2
|
|
38
|
+
)
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def query_byte_range(
|
|
43
|
+
query: Query,
|
|
44
|
+
root: Node,
|
|
45
|
+
start_byte: int,
|
|
46
|
+
end_byte: int,
|
|
47
|
+
get_text: Callable[[Node], str] | None = None,
|
|
48
|
+
) -> Captures:
|
|
49
|
+
"""Run a query over a byte range of a tree, returning nodes by capture name
|
|
50
|
+
|
|
51
|
+
A byte range that ends before it starts warns once and returns no
|
|
52
|
+
captures.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
get_text: Returns a node's source text, to evaluate the query's text
|
|
56
|
+
predicates with. Without it, the text predicates match everything.
|
|
57
|
+
Errors it raises propagate
|
|
58
|
+
"""
|
|
59
|
+
cursor = QueryCursor(query)
|
|
60
|
+
try:
|
|
61
|
+
cursor.set_byte_range(start_byte, end_byte)
|
|
62
|
+
except ValueError:
|
|
63
|
+
# Tree-sitter rejects a range that ends before it starts
|
|
64
|
+
warnings.warn(
|
|
65
|
+
f"Skipped a tree-sitter query over the reversed byte range "
|
|
66
|
+
f"{start_byte}..{end_byte}",
|
|
67
|
+
stacklevel=2,
|
|
68
|
+
)
|
|
69
|
+
return {}
|
|
70
|
+
if get_text is None:
|
|
71
|
+
# Tree-sitter doesn't accept predicate=None
|
|
72
|
+
return cursor.captures(root)
|
|
73
|
+
return cursor.captures(root, QueryPredicates(get_text))
|