@@ -249,6 +249,52 @@ def _top_definition(self, definition):
249249 return d
250250 return definition
251251
252+ def _extract_range (self , definition ):
253+ """Provides the definition range of a given definition
254+
255+ For regular symbols it returns the start and end location of the
256+ characters making up the symbol.
257+
258+ For scoped containers it will return the entire definition of the
259+ scope.
260+
261+ The scope that jedi provides ends with the first character of the next
262+ scope so it's not ideal. For vscode we need the scope to end with the
263+ last character of actual code. That's why we extract the lines that
264+ make up our scope and trim the trailing whitespace.
265+ """
266+ from jedi import common
267+ from jedi .parser .utils import load_parser
268+ # get the scope range
269+ if definition .type in ['class' , 'function' , 'method' ]:
270+ scope = definition ._name .get_parent_scope ()
271+ start_line = scope .start_pos [0 ] - 1
272+ start_column = scope .start_pos [1 ]
273+ end_line = scope .end_pos [0 ] - 1
274+ end_column = scope .end_pos [1 ]
275+ # get the lines
276+ path = definition ._name .get_parent_until ().path
277+ parser = load_parser (path )
278+ lines = common .splitlines (parser .source )
279+ lines [end_line ] = lines [end_line ][:end_column ]
280+ # trim the lines
281+ lines = lines [start_line :end_line + 1 ]
282+ lines = '\n ' .join (lines ).rstrip ().split ('\n ' )
283+ end_line = start_line + len (lines ) - 1
284+ end_column = len (lines [- 1 ]) - 1
285+ else :
286+ symbol = definition ._name
287+ start_line = symbol .start_pos [0 ] - 1
288+ start_column = symbol .start_pos [1 ]
289+ end_line = symbol .end_pos [0 ] - 1
290+ end_column = symbol .end_pos [1 ]
291+ return {
292+ 'start_line' : start_line ,
293+ 'start_column' : start_column ,
294+ 'end_line' : end_line ,
295+ 'end_column' : end_column
296+ }
297+
252298 def _serialize_definitions (self , definitions , identifier = None ):
253299 """Serialize response to be read from VSCode.
254300
@@ -267,13 +313,18 @@ def _serialize_definitions(self, definitions, identifier=None):
267313 definition = self ._top_definition (definition )
268314 if not definition .module_path :
269315 continue
316+ try :
317+ parent = definition .parent ()
318+ container = parent .name if parent .type != 'module' else ''
319+ except Exception :
320+ container = ''
270321 _definition = {
271322 'text' : definition .name ,
272323 'type' : self ._get_definition_type (definition ),
273324 'raw_type' : definition .type ,
274325 'fileName' : definition .module_path ,
275- 'line ' : definition . line - 1 ,
276- 'column ' : definition . column
326+ 'container ' : container ,
327+ 'range ' : self . _extract_range ( definition )
277328 }
278329 _definitions .append (_definition )
279330 except Exception as e :
@@ -419,7 +470,7 @@ def watch(self):
419470 else :
420471 jediPath = os .path .join (os .path .dirname (__file__ ), 'release' )
421472 sys .path .insert (0 , jediPath )
422- import jedi
473+ import jedi
423474 if jediPreview :
424475 jedi .settings .cache_directory = os .path .join (
425476 jedi .settings .cache_directory , cachePrefix + jedi .__version__ .replace ('.' , '' ))
0 commit comments