Skip to content

Commit 84121b4

Browse files
authored
Merge pull request #739 from jupyter-lsp/jump-to-references
Implement jump target selector and jump to references
2 parents f4d42d1 + 2ee8375 commit 84121b4

File tree

17 files changed

+397
-186
lines changed

17 files changed

+397
-186
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ over the underlined code to see a more detailed message
2828

2929
![inspections](https://raw.githubusercontent.com/jupyter-lsp/jupyterlab-lsp/master/examples/screenshots/inspections.png)
3030

31-
### Jump to Definition
31+
### Jump to Definition and References
3232

33-
Use the context menu entry, or <kbd>Alt</kbd> + :computer_mouse: to jump to definitions (you can change it to <kbd>Ctrl</kbd>/<kbd>⌘</kbd> in settings); use <kbd>Alt</kbd> + <kbd>o</kbd> to jump back
33+
Use the context menu entry, or <kbd>Alt</kbd> + :computer_mouse: to jump to definitions/references (you can change it to <kbd>Ctrl</kbd>/<kbd>⌘</kbd> in settings); use <kbd>Alt</kbd> + <kbd>o</kbd> to jump back.
3434

3535
![jump](https://raw.githubusercontent.com/jupyter-lsp/jupyterlab-lsp/master/examples/screenshots/jump_to_definition.png)
3636

atest/04_Interface/DiagnosticsPanel.robot

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ ${DIAGNOSTIC MESSAGE} trailing whitespace
1212
${DIAGNOSTIC MESSAGE R} Closing curly-braces should always be on their own line
1313
${R CELL} %%R\n{}
1414
${MENU COLUMNS} xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(text(), "columns")]
15-
${LAB MENU} css:.lm-Menu
1615

1716
*** Test Cases ***
1817
Diagnostics Panel Opens
@@ -119,28 +118,6 @@ Open Context Menu Over W291
119118
Table Cell Should Equal W291 row=-1 column=2
120119
Open Context Menu Over css:.lsp-diagnostics-listing tbody > tr:last-child
121120

122-
Expand Menu Entry
123-
[Arguments] ${label}
124-
${entry} = Set Variable xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(text(), "${label}")]
125-
Wait Until Page Contains Element ${entry} timeout=10s
126-
${menus before} = Get Element Count ${LAB MENU}
127-
Mouse Over ${entry}
128-
${expected menus} = Evaluate ${menus before} + 1
129-
Wait Until Keyword Succeeds 10 x 1s Menus Count Equal ${expected menus}
130-
131-
Menus Count Equal
132-
[Arguments] ${count}
133-
${menus count} = Get Element Count ${LAB MENU}
134-
Should Be Equal ${menus count} ${count}
135-
136-
Select Menu Entry
137-
[Arguments] ${label}
138-
${entry} Set Variable xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(text(), '${label}')]
139-
Wait Until Page Contains Element ${entry} timeout=10s
140-
Mouse Over ${entry}
141-
Click Element ${entry}
142-
Wait Until Page Does Not Contain Element ${entry} timeout=10s
143-
144121
Open Notebook And Panel
145122
[Arguments] ${notebook}
146123
Setup Notebook Python ${notebook}

atest/05_Features/Jump.robot

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,60 @@ Force Tags feature:jump-to-definition gh:403
44
Resource ../Keywords.robot
55

66
*** Variables ***
7-
${FOLDER WITH SPACE} a földer
7+
${FOLDER WITH SPACE} a föl@der
88

99
*** Test Cases ***
10-
Python Jumps between Files
10+
Python Jumps Between Files
1111
Copy Files to Folder With Spaces jump_a.py jump_b.py
12-
${def} = Set Variable a_function_definition
1312
Open ${FOLDER WITH SPACE}/jump_b.py in ${MENU EDITOR}
1413
Wait Until Fully Initialized
15-
${sel} = Set Variable xpath:(//span[contains(@class, 'cm-variable')][contains(text(), '${def}')])[last()]
14+
${sel} = Select Token Occurrence a_function_definition
1615
Jump To Definition ${sel}
1716
Wait Until Page Contains ANOTHER_CONSTANT
1817
Capture Page Screenshot 10-jumped.png
1918
Clean Up After Working With File jump_b.py
2019

20+
Jumps To References With Modifier Click
21+
[Setup] Prepare File for Editing Python editor jump_references.py
22+
Configure JupyterLab Plugin {"modifierKey": "Accel"} plugin id=${JUMP PLUGIN ID}
23+
Wait Until Fully Initialized
24+
${token} = Select Token Occurrence func type=def
25+
Click Element ${token}
26+
${original} = Measure Cursor Position
27+
Ctrl Click Element ${token}
28+
Wait Until Page Contains Choose the jump target
29+
${references_count} = Get Element Count css:.jp-Dialog select option
30+
Should Be True ${references_count} == ${3}
31+
Select From List By Index css:.jp-Dialog select 2
32+
Click Element css:.jp-Dialog-button.jp-mod-accept
33+
Wait Until Keyword Succeeds 10 x 1 s Cursor Should Jump ${original}
34+
Clean Up After Working With File jump_references.py
35+
36+
Jumps To References From Context Menu
37+
[Setup] Prepare File for Editing Python editor jump_references.py
38+
Wait Until Fully Initialized
39+
${token} = Select Token Occurrence func type=def
40+
Click Element ${token}
41+
${original} = Measure Cursor Position
42+
Open Context Menu Over ${token}
43+
Select Menu Entry Jump to references
44+
Wait Until Page Contains Choose the jump target
45+
${references_count} = Get Element Count css:.jp-Dialog select option
46+
Should Be True ${references_count} == ${3}
47+
Select From List By Index css:.jp-Dialog select 2
48+
Click Element css:.jp-Dialog-button.jp-mod-accept
49+
Wait Until Keyword Succeeds 10 x 1 s Cursor Should Jump ${original}
50+
Clean Up After Working With File jump_references.py
51+
2152
Ctrl Click And Jumping Back Works
2253
[Setup] Prepare File for Editing Python editor jump.py
2354
Configure JupyterLab Plugin {"modifierKey": "Accel"} plugin id=${JUMP PLUGIN ID}
2455
Wait Until Fully Initialized
25-
${usage} = Set Variable a_variable
26-
${sel} = Set Variable xpath:(//span[contains(@class, 'cm-variable')][contains(text(), '${usage}')])[last()]
56+
${sel} = Select Token Occurrence a_variable
2757
Click Element ${sel}
2858
${original} = Measure Cursor Position
2959
Capture Page Screenshot 01-ready-to-jump.png
30-
${key} = Evaluate 'COMMAND' if platform.system() == 'Darwin' else 'CTRL' platform
31-
Click Element ${sel} modifier=${key}
60+
Ctrl Click Element ${sel}
3261
Capture Page Screenshot 02-jumped.png
3362
Wait Until Keyword Succeeds 10 x 1 s Cursor Should Jump ${original}
3463
${new} = Measure Cursor Position
@@ -47,3 +76,16 @@ Copy Files to Folder With Spaces
4776
FOR ${file} IN @{files}
4877
Copy File examples${/}${file} ${NOTEBOOK DIR}${/}${FOLDER WITH SPACE}${/}${file}
4978
END
79+
80+
Select Token Occurrence
81+
[Arguments] ${token} ${type}=variable ${which}=last
82+
[Return] xpath:(//span[contains(@class, 'cm-${type}')][contains(text(), '${token}')])[${which}()]
83+
84+
Ctrl Click Element
85+
[Arguments] ${element}
86+
${key} = Evaluate 'COMMAND' if platform.system() == 'Darwin' else 'CTRL' platform
87+
Click Element ${element} modifier=${key}
88+
89+
Should Have Expected Count
90+
[Arguments] ${expected_count}
91+
${count} = Count Diagnostics In Panel

atest/Keywords.robot

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,3 +434,25 @@ Restart Kernel
434434
Lab Command Restart Kernel…
435435
Wait For Dialog
436436
Accept Default Dialog Option
437+
438+
Expand Menu Entry
439+
[Arguments] ${label}
440+
${entry} = Set Variable xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(text(), "${label}")]
441+
Wait Until Page Contains Element ${entry} timeout=10s
442+
${menus before} = Get Element Count ${LAB MENU}
443+
Mouse Over ${entry}
444+
${expected menus} = Evaluate ${menus before} + 1
445+
Wait Until Keyword Succeeds 10 x 1s Menus Count Equal ${expected menus}
446+
447+
Menus Count Equal
448+
[Arguments] ${count}
449+
${menus count} = Get Element Count ${LAB MENU}
450+
Should Be Equal ${menus count} ${count}
451+
452+
Select Menu Entry
453+
[Arguments] ${label}
454+
${entry} Set Variable xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(text(), '${label}')]
455+
Wait Until Page Contains Element ${entry} timeout=10s
456+
Mouse Over ${entry}
457+
Click Element ${entry}
458+
Wait Until Page Does Not Contain Element ${entry} timeout=10s

atest/Variables.robot

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ ${MENU EDITOR} xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(.,
4040
${MENU JUMP} xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(text(), "Jump to definition")]
4141
${MENU SETTINGS} xpath://div[contains(@class, 'lm-MenuBar-itemLabel')][contains(text(), "Settings")]
4242
${MENU EDITOR THEME} xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(text(), "Text Editor Theme")]
43+
${LAB MENU} css:.lm-Menu
4344
${CM CURSOR} css:.CodeMirror-cursor
4445
${CM CURSORS} css:.jp-MainAreaWidget:not(.lm-mod-hidden) .CodeMirror-cursors:not([style='visibility: hidden'])
4546
# settings

atest/examples/jump_references.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
def func():
2+
pass
3+
4+
5+
x = func()
6+
y = func()
-3.87 KB
Loading

packages/jupyterlab-lsp/src/connection.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,10 @@ export interface IClientResult {
129129
[Method.ClientRequest.DEFINITION]: AnyLocation;
130130
[Method.ClientRequest.DOCUMENT_HIGHLIGHT]: lsp.DocumentHighlight[];
131131
[Method.ClientRequest.DOCUMENT_SYMBOL]: lsp.DocumentSymbol[];
132-
[Method.ClientRequest.HOVER]: lsp.Hover;
132+
[Method.ClientRequest.HOVER]: lsp.Hover | null;
133133
[Method.ClientRequest.IMPLEMENTATION]: AnyLocation;
134134
[Method.ClientRequest.INITIALIZE]: lsp.InitializeResult;
135-
[Method.ClientRequest.REFERENCES]: Location[];
135+
[Method.ClientRequest.REFERENCES]: lsp.Location[] | null;
136136
[Method.ClientRequest.RENAME]: lsp.WorkspaceEdit;
137137
[Method.ClientRequest.SIGNATURE_HELP]: lsp.SignatureHelp;
138138
[Method.ClientRequest.TYPE_DEFINITION]: AnyLocation;

packages/jupyterlab-lsp/src/editor_integration/codemirror.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ export abstract class CodeMirrorIntegration
9898
protected virtual_document: VirtualDocument;
9999
protected connection: LSPConnection;
100100

101+
/** @deprecated: use `setStatusMessage()` instead */
101102
protected status_message: StatusMessage;
102103
protected adapter: WidgetAdapter<IDocumentWidget>;
103104
protected console: ILSPLogConsole;
@@ -128,6 +129,17 @@ export abstract class CodeMirrorIntegration
128129
this.is_registered = false;
129130
}
130131

132+
/**
133+
* Set the text message and (optionally) the timeout to remove it.
134+
* @param message
135+
* @param timeout - number of ms to until the message is cleaned;
136+
* -1 if the message should stay up indefinitely;
137+
* defaults to 3000ms (3 seconds)
138+
*/
139+
setStatusMessage(message: string, timeout?: number): void {
140+
this.status_message.set(message, timeout);
141+
}
142+
131143
register(): void {
132144
// register editor handlers
133145
for (let [event_name, handler] of this.editor_handlers) {

packages/jupyterlab-lsp/src/features/highlights.ts

Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,15 @@ import {
44
} from '@jupyterlab/application';
55
import { CodeEditor } from '@jupyterlab/codeeditor';
66
import { ISettingRegistry } from '@jupyterlab/settingregistry';
7-
import { ITranslator, TranslationBundle } from '@jupyterlab/translation';
87
import { LabIcon } from '@jupyterlab/ui-components';
98
import { Debouncer } from '@lumino/polling';
109
import type * as CodeMirror from 'codemirror';
1110
import type * as lsProtocol from 'vscode-languageserver-protocol';
1211

13-
import highlightTypeSvg from '../../style/icons/highlight-type.svg';
1412
import highlightSvg from '../../style/icons/highlight.svg';
1513
import { CodeHighlights as LSPHighlightsSettings } from '../_highlights';
1614
import { CodeMirrorIntegration } from '../editor_integration/codemirror';
17-
import { FeatureSettings, IFeatureCommand } from '../feature';
15+
import { FeatureSettings } from '../feature';
1816
import { DocumentHighlightKind } from '../lsp';
1917
import { IRootPosition, IVirtualPosition } from '../positioning';
2018
import { ILSPFeatureManager, PLUGIN_ID } from '../tokens';
@@ -25,32 +23,6 @@ export const highlightIcon = new LabIcon({
2523
svgstr: highlightSvg
2624
});
2725

28-
export const highlightTypeIcon = new LabIcon({
29-
name: 'lsp:highlight-type',
30-
svgstr: highlightTypeSvg
31-
});
32-
33-
const COMMANDS = (trans: TranslationBundle): IFeatureCommand[] => [
34-
{
35-
id: 'highlight-references',
36-
execute: ({ connection, virtual_position, document }) =>
37-
connection?.getReferences(virtual_position, document.document_info),
38-
is_enabled: ({ connection }) =>
39-
connection ? connection.isReferencesSupported() : false,
40-
label: trans.__('Highlight references'),
41-
icon: highlightIcon
42-
},
43-
{
44-
id: 'highlight-type-definition',
45-
execute: ({ connection, virtual_position, document }) =>
46-
connection?.getTypeDefinition(virtual_position, document.document_info),
47-
is_enabled: ({ connection }) =>
48-
connection ? connection.isTypeDefinitionSupported() : false,
49-
label: trans.__('Highlight type definition'),
50-
icon: highlightTypeIcon
51-
}
52-
];
53-
5426
export class HighlightsCM extends CodeMirrorIntegration {
5527
protected highlight_markers: CodeMirror.TextMarker[] = [];
5628
private debounced_get_highlight: Debouncer<
@@ -240,24 +212,21 @@ const FEATURE_ID = PLUGIN_ID + ':highlights';
240212

241213
export const HIGHLIGHTS_PLUGIN: JupyterFrontEndPlugin<void> = {
242214
id: FEATURE_ID,
243-
requires: [ILSPFeatureManager, ISettingRegistry, ITranslator],
215+
requires: [ILSPFeatureManager, ISettingRegistry],
244216
autoStart: true,
245217
activate: (
246218
app: JupyterFrontEnd,
247219
featureManager: ILSPFeatureManager,
248-
settingRegistry: ISettingRegistry,
249-
translator: ITranslator
220+
settingRegistry: ISettingRegistry
250221
) => {
251222
const settings = new FeatureSettings(settingRegistry, FEATURE_ID);
252-
const trans = translator.load('jupyterlab_lsp');
253223

254224
featureManager.register({
255225
feature: {
256226
editorIntegrationFactory: new Map([['CodeMirrorEditor', HighlightsCM]]),
257227
id: FEATURE_ID,
258228
name: 'LSP Highlights',
259-
settings: settings,
260-
commands: COMMANDS(trans)
229+
settings: settings
261230
}
262231
});
263232
}

0 commit comments

Comments
 (0)