1
1
# Copyright 2022- Python Language Server Contributors.
2
2
3
3
import logging
4
- from typing import Any , Dict , Generator , List , Set
4
+ from typing import Any , Dict , Generator , List , Optional , Set
5
5
6
6
import parso
7
7
from jedi import Script
15
15
from pylsp .config .config import Config
16
16
from pylsp .workspace import Document , Workspace
17
17
18
+ from ._rope_task_handle import PylspTaskHandle
19
+
18
20
log = logging .getLogger (__name__ )
19
21
20
22
_score_pow = 5
@@ -46,8 +48,10 @@ def _should_insert(expr: tree.BaseNode, word_node: tree.Leaf) -> bool: # pylint
46
48
if first_child == word_node :
47
49
return True # If the word is the first word then its fine
48
50
if len (expr .children ) > 1 :
49
- if any (node .type == "operator" and "." in node .value or
50
- node .type == "trailer" for node in expr .children ):
51
+ if any (
52
+ node .type == "operator" and "." in node .value or node .type == "trailer"
53
+ for node in expr .children
54
+ ):
51
55
return False # Check if we're on a method of a function
52
56
if isinstance (first_child , (tree .PythonErrorNode , tree .PythonNode )):
53
57
# The tree will often include error nodes like this to indicate errors
@@ -56,8 +60,7 @@ def _should_insert(expr: tree.BaseNode, word_node: tree.Leaf) -> bool: # pylint
56
60
return _handle_first_child (first_child , expr , word_node )
57
61
58
62
59
- def _handle_first_child (first_child : NodeOrLeaf , expr : tree .BaseNode ,
60
- word_node : tree .Leaf ) -> bool :
63
+ def _handle_first_child (first_child : NodeOrLeaf , expr : tree .BaseNode , word_node : tree .Leaf ) -> bool :
61
64
"""Check if we suggest imports given the following first child."""
62
65
if isinstance (first_child , tree .Import ):
63
66
return False
@@ -121,22 +124,16 @@ def _process_statements(
121
124
insert_line = autoimport .find_insertion_line (document .source ) - 1
122
125
start = {"line" : insert_line , "character" : 0 }
123
126
edit_range = {"start" : start , "end" : start }
124
- edit = {
125
- "range" : edit_range ,
126
- "newText" : suggestion .import_statement + "\n "
127
- }
128
- score = _get_score (suggestion .source , suggestion .import_statement ,
129
- suggestion .name , word )
127
+ edit = {"range" : edit_range , "newText" : suggestion .import_statement + "\n " }
128
+ score = _get_score (suggestion .source , suggestion .import_statement , suggestion .name , word )
130
129
if score > _score_max :
131
130
continue
132
131
# TODO make this markdown
133
132
yield {
134
133
"label" : suggestion .name ,
135
134
"kind" : suggestion .itemkind ,
136
135
"sortText" : _sort_import (score ),
137
- "data" : {
138
- "doc_uri" : doc_uri
139
- },
136
+ "data" : {"doc_uri" : doc_uri },
140
137
"detail" : _document (suggestion .import_statement ),
141
138
"additionalTextEdits" : [edit ],
142
139
}
@@ -150,8 +147,7 @@ def get_names(script: Script) -> Set[str]:
150
147
151
148
152
149
@hookimpl
153
- def pylsp_completions (config : Config , workspace : Workspace , document : Document ,
154
- position ):
150
+ def pylsp_completions (config : Config , workspace : Workspace , document : Document , position ):
155
151
"""Get autoimport suggestions."""
156
152
line = document .lines [position ["line" ]]
157
153
expr = parso .parse (line )
@@ -161,17 +157,15 @@ def pylsp_completions(config: Config, workspace: Workspace, document: Document,
161
157
word = word_node .value
162
158
log .debug (f"autoimport: searching for word: { word } " )
163
159
rope_config = config .settings (document_path = document .path ).get ("rope" , {})
164
- ignored_names : Set [str ] = get_names (
165
- document .jedi_script (use_document_path = True ))
160
+ ignored_names : Set [str ] = get_names (document .jedi_script (use_document_path = True ))
166
161
autoimport = workspace ._rope_autoimport (rope_config )
167
- suggestions = list (
168
- autoimport .search_full (word , ignored_names = ignored_names ))
162
+ suggestions = list (autoimport .search_full (word , ignored_names = ignored_names ))
169
163
results = list (
170
164
sorted (
171
- _process_statements (suggestions , document .uri , word , autoimport ,
172
- document ),
165
+ _process_statements (suggestions , document .uri , word , autoimport , document ),
173
166
key = lambda statement : statement ["sortText" ],
174
- ))
167
+ )
168
+ )
175
169
if len (results ) > MAX_RESULTS :
176
170
results = results [:MAX_RESULTS ]
177
171
return results
@@ -181,11 +175,10 @@ def _document(import_statement: str) -> str:
181
175
return """# Auto-Import\n """ + import_statement
182
176
183
177
184
- def _get_score (source : int , full_statement : str , suggested_name : str ,
185
- desired_name ) -> int :
178
+ def _get_score (source : int , full_statement : str , suggested_name : str , desired_name ) -> int :
186
179
import_length = len ("import" )
187
180
full_statement_score = len (full_statement ) - import_length
188
- suggested_name_score = ((len (suggested_name ) - len (desired_name )))** 2
181
+ suggested_name_score = ((len (suggested_name ) - len (desired_name ))) ** 2
189
182
source_score = 20 * source
190
183
return suggested_name_score + full_statement_score + source_score
191
184
@@ -198,24 +191,37 @@ def _sort_import(score: int) -> str:
198
191
return "[z" + str (score ).rjust (_score_pow , "0" )
199
192
200
193
201
- @hookimpl
202
- def pylsp_initialize (config : Config , workspace : Workspace ):
203
- """Initialize AutoImport. Generates the cache for local and global items."""
204
- memory : bool = config .plugin_settings ("rope_autoimport" ).get (
205
- "memory" , False )
194
+ def _reload_cache (config : Config , workspace : Workspace , files : Optional [List [Document ]] = None ):
195
+ memory : bool = config .plugin_settings ("rope_autoimport" ).get ("memory" , False )
206
196
rope_config = config .settings ().get ("rope" , {})
207
197
autoimport = workspace ._rope_autoimport (rope_config , memory )
208
- autoimport .generate_modules_cache ()
209
- autoimport .generate_cache ()
198
+ task_handle = PylspTaskHandle (workspace )
199
+ resources : Optional [List [Resource ]] = (
200
+ None if files is None else [document ._rope_resource (rope_config ) for document in files ]
201
+ )
202
+ autoimport .generate_cache (task_handle = task_handle , resources = resources )
203
+ autoimport .generate_modules_cache (task_handle = task_handle )
210
204
211
205
212
206
@hookimpl
213
- def pylsp_document_did_save (config : Config , workspace : Workspace ,
214
- document : Document ):
207
+ def pylsp_initialize (config : Config , workspace : Workspace ):
208
+ """Initialize AutoImport.
209
+
210
+ Generates the cache for local and global items.
211
+ """
212
+ _reload_cache (config , workspace )
213
+
214
+
215
+ @hookimpl
216
+ def pylsp_document_did_open (config : Config , workspace : Workspace ):
217
+ """Initialize AutoImport.
218
+
219
+ Generates the cache for local and global items.
220
+ """
221
+ _reload_cache (config , workspace )
222
+
223
+
224
+ @hookimpl
225
+ def pylsp_document_did_save (config : Config , workspace : Workspace , document : Document ):
215
226
"""Update the names associated with this document."""
216
- rope_config = config .settings ().get ("rope" , {})
217
- rope_doucment : Resource = document ._rope_resource (rope_config )
218
- autoimport = workspace ._rope_autoimport (rope_config )
219
- autoimport .generate_cache (resources = [rope_doucment ])
220
- # Might as well using saving the document as an indicator to regenerate the module cache
221
- autoimport .generate_modules_cache ()
227
+ _reload_cache (config , workspace , [document ])
0 commit comments