srgn/scoping/langs/
python.rs1use std::fmt::Debug;
2
3use clap::ValueEnum;
4use const_format::formatcp;
5
6use super::{Find, LanguageScoper, QuerySource, TSLanguage, TSQuery, TSQueryError};
7use crate::scoping::langs::IGNORE;
8
9#[derive(Debug)]
11pub struct CompiledQuery(super::CompiledQuery);
12
13impl TryFrom<QuerySource> for CompiledQuery {
14 type Error = TSQueryError;
15
16 fn try_from(query: QuerySource) -> Result<Self, Self::Error> {
22 let q = super::CompiledQuery::from_source(&tree_sitter_python::LANGUAGE.into(), &query)?;
23 Ok(Self(q))
24 }
25}
26
27impl From<PreparedQuery> for CompiledQuery {
28 fn from(query: PreparedQuery) -> Self {
29 Self(super::CompiledQuery::from_prepared_query(
30 &tree_sitter_python::LANGUAGE.into(),
31 query.as_str(),
32 ))
33 }
34}
35
36#[derive(Debug, Clone, Copy, ValueEnum)]
38pub enum PreparedQuery {
39 Comments,
41 Strings,
43 Imports,
45 DocStrings,
47 FunctionNames,
49 FunctionCalls,
51 Class,
53 Def,
55 AsyncDef,
57 Methods,
59 ClassMethods,
61 StaticMethods,
63 With,
65 Try,
67 Lambda,
69 Globals,
71 VariableIdentifiers,
73 Types,
75 Identifiers,
77}
78
79impl PreparedQuery {
80 #[expect(clippy::too_many_lines)]
81 const fn as_str(self) -> &'static str {
82 match self {
83 Self::Comments => "(comment) @comment",
84 Self::Strings => "(string_content) @string",
85 Self::Imports => {
86 r"[
87 (import_statement
88 name: (dotted_name) @dn)
89 (import_from_statement
90 module_name: (dotted_name) @dn)
91 (import_from_statement
92 module_name: (dotted_name) @dn
93 (wildcard_import))
94 (import_statement(
95 aliased_import
96 name: (dotted_name) @dn))
97 (import_from_statement
98 module_name: (relative_import) @ri)
99 ]"
100 }
101 Self::DocStrings => {
102 formatcp!(
106 "
107 (
108 (expression_statement
109 (string
110 (string_start) @{0}
111 (string_content) @string
112 (#match? @{0} \"\\^\\\"\\\"\\\"\")
113 )
114 )
115 )
116 ",
117 IGNORE
118 )
119 }
120 Self::FunctionNames => {
121 r"
122 (function_definition
123 name: (identifier) @function-name
124 )
125 "
126 }
127 Self::FunctionCalls => {
128 r"
129 (call
130 function: (identifier) @function-name
131 )
132 "
133 }
134 Self::Class => "(class_definition) @class",
135 Self::Def => "(function_definition) @def",
136 Self::AsyncDef => r#"((function_definition) @def (#match? @def "^async "))"#,
137 Self::Methods => {
138 r"
139 (class_definition
140 body: (block
141 [
142 (function_definition) @method
143 (decorated_definition definition: (function_definition)) @method
144 ]
145 )
146 )
147 "
148 }
149 Self::ClassMethods => {
150 formatcp!(
151 "
152 (class_definition
153 body: (block
154 (decorated_definition
155 (decorator (identifier) @{0})
156 definition: (function_definition) @method
157 (#eq? @{0} \"classmethod\")
158 )
159 )
160 )",
161 IGNORE
162 )
163 }
164 Self::StaticMethods => {
165 formatcp!(
166 "
167 (class_definition
168 body: (block
169 (decorated_definition
170 (decorator (identifier) @{0})
171 definition: (function_definition) @method
172 (#eq? @{0} \"staticmethod\")
173 )
174 )
175 )",
176 IGNORE
177 )
178 }
179 Self::With => "(with_statement) @with",
180 Self::Try => "(try_statement) @try",
181 Self::Lambda => "(lambda) @lambda",
182 Self::Globals => {
183 "(module (expression_statement (assignment left: (identifier) @global)))"
184 }
185 Self::VariableIdentifiers => "(assignment left: (identifier) @identifier)",
186 Self::Types => "(type) @type",
187 Self::Identifiers => "(identifier) @identifier",
188 }
189 }
190}
191
192impl LanguageScoper for CompiledQuery {
193 fn lang() -> TSLanguage {
194 tree_sitter_python::LANGUAGE.into()
195 }
196
197 fn pos_query(&self) -> &TSQuery {
198 &self.0.positive_query
199 }
200
201 fn neg_query(&self) -> Option<&TSQuery> {
202 self.0.negative_query.as_ref()
203 }
204}
205
206impl Find for CompiledQuery {
207 fn extensions(&self) -> &'static [&'static str] {
208 &["py"]
209 }
210
211 fn interpreters(&self) -> Option<&'static [&'static str]> {
212 Some(&["python", "python3"])
213 }
214}