Skip to content

Commit 6a7a3f3

Browse files
committed
improvements to hover provider
1 parent 612478a commit 6a7a3f3

3 files changed

Lines changed: 95 additions & 34 deletions

File tree

pythonFiles/completion.py

Lines changed: 50 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import traceback
77

88
WORD_RE = re.compile(r'\w')
9+
jediPreview = False
910

1011

1112
class JediCompletion(object):
@@ -314,7 +315,7 @@ def _extract_range(self, definition):
314315
'end_line': definition.line - 1,
315316
'end_column': definition.column
316317
}
317-
def _get_definitions(self, definitions, identifier=None):
318+
def _get_definitionsx(self, definitions, identifier=None, ignoreNoModulePath=False):
318319
"""Serialize response to be read from VSCode.
319320
320321
Args:
@@ -327,25 +328,39 @@ def _get_definitions(self, definitions, identifier=None):
327328
_definitions = []
328329
for definition in definitions:
329330
try:
330-
if definition.module_path:
331-
if definition.type == 'import':
332-
definition = self._top_definition(definition)
333-
if not definition.module_path:
331+
if definition.type == 'import':
332+
definition = self._top_definition(definition)
333+
definitionRange = {
334+
'start_line': 0,
335+
'start_column': 0,
336+
'end_line': 0,
337+
'end_column': 0
338+
}
339+
module_path = ''
340+
if hasattr(definition, 'module_path') and definition.module_path:
341+
module_path = definition.module_path
342+
definitionRange = self._extract_range(definition)
343+
else:
344+
if not ignoreNoModulePath:
334345
continue
335-
try:
336-
parent = definition.parent()
337-
container = parent.name if parent.type != 'module' else ''
338-
except Exception:
339-
container = ''
340-
_definition = {
341-
'text': definition.name,
342-
'type': self._get_definition_type(definition),
343-
'raw_type': definition.type,
344-
'fileName': definition.module_path,
345-
'container': container,
346-
'range': self._extract_range(definition)
347-
}
348-
_definitions.append(_definition)
346+
try:
347+
parent = definition.parent()
348+
container = parent.name if parent.type != 'module' else ''
349+
except Exception:
350+
container = ''
351+
_definition = {
352+
'text': definition.name,
353+
'type': self._get_definition_type(definition),
354+
'raw_type': definition.type,
355+
'fileName': module_path,
356+
'container': container,
357+
'range': definitionRange,
358+
'description': definition.description,
359+
'docstring': definition.docstring(),
360+
'raw_docstring': definition.docstring(raw=True),
361+
'signature': self._generate_signature(definition)
362+
}
363+
_definitions.append(_definition)
349364
except Exception as e:
350365
pass
351366
return _definitions
@@ -379,7 +394,10 @@ def _serialize_definitions(self, definitions, identifier=None):
379394
'raw_type': definition.type,
380395
'fileName': definition.module_path,
381396
'container': container,
382-
'range': self._extract_range(definition)
397+
'range': self._extract_range(definition),
398+
'description': definition.description,
399+
'docstring': definition.docstring(),
400+
'raw_docstring': definition.docstring(raw=True)
383401
}
384402
_definitions.append(_definition)
385403
except Exception as e:
@@ -405,7 +423,9 @@ def _serialize_tooltip(self, definitions, identifier=None):
405423
description = definition.docstring().strip()
406424
_definition = {
407425
'type': self._get_definition_type(definition),
426+
'text': definition.name,
408427
'description': description,
428+
'docstring': description,
409429
'signature': signature
410430
}
411431
_definitions.append(_definition)
@@ -477,15 +497,20 @@ def _process_request(self, request):
477497
script = jedi.api.Script(
478498
source=request.get('source', None), line=request['line'] + 1,
479499
column=request['column'], path=request.get('path', ''))
480-
500+
481501
if lookup == 'definitions':
482-
defs = self._get_definitions(script.goto_definitions(), request['id'])
502+
defs = self._get_definitionsx(script.goto_definitions(), request['id'])
483503
if len(defs) == 0:
484-
defs = self._get_definitions(script.goto_assignments(), request['id'])
504+
defs = self._get_definitionsx(script.goto_assignments(), request['id'])
485505
return self._write_response(json.dumps({'id': request['id'], 'results': defs}))
486506
if lookup == 'tooltip':
487-
return self._write_response(self._serialize_tooltip(
488-
script.goto_definitions(), request['id']))
507+
if jediPreview:
508+
defs = self._get_definitionsx(script.goto_definitions(), request['id'], True)
509+
if len(defs) == 0:
510+
defs = self._get_definitionsx(script.goto_assignments(), request['id'], True)
511+
return self._write_response(json.dumps({'id': request['id'], 'results': defs}))
512+
else:
513+
return self._write_response(self._serialize_tooltip(script.goto_definitions(), request['id']))
489514
elif lookup == 'arguments':
490515
return self._write_response(self._serialize_arguments(
491516
script, request['id']))
@@ -514,7 +539,6 @@ def watch(self):
514539
sys.stderr.flush()
515540

516541
if __name__ == '__main__':
517-
jediPreview = False
518542
cachePrefix = 'v'
519543
if len(sys.argv) > 0 and sys.argv[1] == 'preview':
520544
jediPath = os.path.join(os.path.dirname(__file__), 'preview')

src/client/providers/hoverProvider.ts

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@ import * as vscode from 'vscode';
44
import * as proxy from './jediProxy';
55
import * as telemetryContracts from "../common/telemetryContracts";
66
import { highlightCode } from './jediHelpers';
7+
import { EOL } from 'os';
78

89
export class PythonHoverProvider implements vscode.HoverProvider {
910
private jediProxyHandler: proxy.JediProxyHandler<proxy.IHoverResult>;
1011

1112
public constructor(context: vscode.ExtensionContext, jediProxy: proxy.JediProxy = null) {
1213
this.jediProxyHandler = new proxy.JediProxyHandler(context, jediProxy);
1314
}
14-
private static parseData(data: proxy.IHoverResult): vscode.Hover {
15+
private static parseData(data: proxy.IHoverResult, currentWord: string): vscode.Hover {
1516
let results = [];
17+
let capturedInfo: string[] = [];
1618
data.items.forEach(item => {
1719
let { description, signature } = item;
1820
switch (item.kind) {
@@ -26,11 +28,42 @@ export class PythonHoverProvider implements vscode.HoverProvider {
2628
signature = 'class ' + signature;
2729
break;
2830
}
31+
default: {
32+
signature = typeof item.text === 'string' && item.text.length > 0 ? item.text : currentWord;
33+
}
34+
}
35+
if (item.docstring) {
36+
let lines = item.docstring.split(EOL);
37+
if (lines.length > 0 && lines[0] === item.signature) {
38+
lines.shift();
39+
}
40+
if (lines.length > 0 && item.signature.startsWith(currentWord) && lines[0].startsWith(currentWord) && lines[0].endsWith(')')) {
41+
lines.shift();
42+
}
43+
let descriptionWithHighlightedCode = highlightCode(lines.join(EOL));
44+
let hoverInfo = '```python' + EOL + signature + EOL + '```' + EOL + descriptionWithHighlightedCode;
45+
let key = signature + lines.join('');
46+
// Sometimes we have duplicate documentation, one with a period at the end
47+
if (capturedInfo.indexOf(key) >= 0 || capturedInfo.indexOf(key + '.') >= 0) {
48+
return;
49+
}
50+
capturedInfo.push(key);
51+
capturedInfo.push(key + '.');
52+
results.push(hoverInfo);
53+
return;
2954
}
30-
results.push({ language: 'python', value: signature });
3155
if (item.description) {
32-
var descriptionWithHighlightedCode = highlightCode(item.description);
33-
results.push(descriptionWithHighlightedCode);
56+
let descriptionWithHighlightedCode = highlightCode(item.description);
57+
let hoverInfo = '```python' + EOL + signature + EOL + '```' + EOL + descriptionWithHighlightedCode;
58+
let lines = item.description.split(EOL);
59+
let key = signature + lines.join('');
60+
// Sometimes we have duplicate documentation, one with a period at the end
61+
if (capturedInfo.indexOf(key) >= 0 || capturedInfo.indexOf(key + '.') >= 0) {
62+
return;
63+
}
64+
capturedInfo.push(key);
65+
capturedInfo.push(key + '.');
66+
results.push(hoverInfo);
3467
}
3568
});
3669
return new vscode.Hover(results);
@@ -48,7 +81,7 @@ export class PythonHoverProvider implements vscode.HoverProvider {
4881
if (!range || range.isEmpty) {
4982
return null;
5083
}
51-
84+
let word = document.getText(range);
5285
var cmd: proxy.ICommand<proxy.IDefinitionResult> = {
5386
command: proxy.CommandType.Hover,
5487
fileName: filename,
@@ -64,6 +97,6 @@ export class PythonHoverProvider implements vscode.HoverProvider {
6497
return;
6598
}
6699

67-
return PythonHoverProvider.parseData(data);
100+
return PythonHoverProvider.parseData(data, word);
68101
}
69102
}

src/client/providers/jediProxy.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -342,8 +342,10 @@ function spawnProcess(dir: string) {
342342
return {
343343
kind: getMappedVSCodeSymbol(def.type),
344344
description: def.description,
345-
signature: def.signature
346-
}
345+
signature: def.signature,
346+
docstring: def.docstring,
347+
text: def.text
348+
};
347349
})
348350
};
349351

@@ -651,7 +653,9 @@ export interface IDefinition {
651653

652654
export interface IHoverItem {
653655
kind: vscode.SymbolKind;
656+
text: string;
654657
description: string;
658+
docstring: string;
655659
signature: string;
656660
}
657661

0 commit comments

Comments
 (0)