Skip to content

Commit 752149c

Browse files
committed
Fix cache, do not trigger: from key if already shown, line background,
add test for key-based trigger, removed unused variables, return early if possible, move unpacking before loop
1 parent 01aceff commit 752149c

File tree

3 files changed

+77
-34
lines changed

3 files changed

+77
-34
lines changed

atest/05_Features/Hover.robot

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Test Setup Setup Hover Test
44
Test Teardown Clean Up After Working With File Hover.ipynb
55
Force Tags feature:hover
66
Resource ../Keywords.robot
7-
Library ../mouse_over_with_modifier.py
7+
Library ../mouse_over_extension.py
88

99
*** Variables ***
1010
${HOVER_BOX} css:.lsp-hover
@@ -13,7 +13,7 @@ ${HOVER_SIGNAL} css:.cm-lsp-hover-available
1313
*** Test Cases ***
1414
Hover works in notebooks
1515
Enter Cell Editor 1
16-
Hover Over python_add
16+
Trigger Tooltip python_add
1717
Element Text Should Be ${HOVER_SIGNAL} python_add
1818
Capture Page Screenshot 02-hover-shown.png
1919
Element Should Contain ${HOVER_BOX} python_add(a: int, b: int)
@@ -24,9 +24,14 @@ Hover works in notebooks
2424
# it should be possible to move the mouse over the tooltip in order to copy/scroll
2525
Mouse Over ${HOVER_BOX}
2626

27+
Hover can be triggered via modifier key once cursor stopped moving
28+
Enter Cell Editor 1
29+
${element} = Last Occurrence python_add
30+
Wait Until Keyword Succeeds 4x 0.1 s Trigger Via Modifier Key Press ${element}
31+
2732
Hover works in foreign code (javascript)
2833
Enter Cell Editor 2
29-
Hover Over js_add
34+
Trigger Tooltip js_add
3035
Capture Page Screenshot 02-hover-shown.png
3136
Element Should Contain ${HOVER_BOX} function js_add(a: any, b: any): any
3237
Page Should Contain Element ${HOVER_BOX} code.language-typescript
@@ -36,23 +41,38 @@ Hover works in foreign code (javascript)
3641
Page Should Not Contain Element ${HOVER_SIGNAL}
3742
# also for multiple cells of the same document
3843
Enter Cell Editor 3
39-
Hover Over Math
44+
Trigger Tooltip Math
4045
Element Should Contain ${HOVER_BOX} const Math: Math
4146

4247
*** Keywords ***
43-
Hover Over
48+
Last Occurrence
4449
[Arguments] ${symbol}
4550
${sel} = Set Variable If "${symbol}".startswith(("xpath", "css")) ${symbol} xpath:(//span[@role="presentation"][contains(., "${symbol}")])[last()]
46-
Wait Until Keyword Succeeds 3x 0.1 s Trigger Tooltip ${sel}
51+
[Return] ${sel}
4752

48-
Trigger Tooltip
53+
Trigger Via Hover With Modifier
4954
[Arguments] ${sel}
5055
# bring the cursor to the element
5156
Mouse Over ${sel}
5257
# move it back and forth (wiggle) while hodling the ctrl modifier
5358
Mouse Over With Control ${sel} x_wiggle=5
5459
Wait Until Page Contains Element ${HOVER_SIGNAL}
55-
Wait Until Keyword Succeeds 3x 0.1s Page Should Contain Element ${HOVER_BOX}
60+
Wait Until Keyword Succeeds 4x 0.1s Page Should Contain Element ${HOVER_BOX}
61+
62+
Trigger Via Modifier Key Press
63+
[Arguments] ${sel}
64+
# bring the cursor to the element
65+
Mouse Over ${sel}
66+
Wait Until Page Contains Element ${HOVER_SIGNAL}
67+
Mouse Over And Wiggle ${sel} 5
68+
Press Keys ${sel} CTRL
69+
Wait Until Keyword Succeeds 4x 0.1s Page Should Contain Element ${HOVER_BOX}
70+
71+
Trigger Tooltip
72+
[Arguments] ${symbol}
73+
[Documentation] The default way to trigger the hover tooltip
74+
${sel} = Last Occurrence ${symbol}
75+
Wait Until Keyword Succeeds 4x 0.1 s Trigger Via Hover With Modifier ${sel}
5676

5777
Setup Hover Test
5878
Setup Notebook Python Hover.ipynb
Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,28 @@
1-
from robot.api import logger
21
from robot.libraries.BuiltIn import BuiltIn
32
from selenium.webdriver import ActionChains
43
from selenium.webdriver.common.keys import Keys
54
from SeleniumLibrary import SeleniumLibrary
65

76

7+
def wiggle(action_chains, x_wiggle):
8+
if x_wiggle:
9+
action_chains.move_by_offset(xoffset=x_wiggle, yoffset=0)
10+
action_chains.move_by_offset(xoffset=-x_wiggle, yoffset=0)
11+
12+
813
def mouse_over_with_control(locator, x_wiggle=0):
9-
logger.info("Getting currently open browser desired capabilities")
1014
sl: SeleniumLibrary = BuiltIn().get_library_instance("SeleniumLibrary")
1115
action_chains = ActionChains(sl.driver)
1216
action_chains.key_down(Keys.CONTROL)
1317
action_chains.move_to_element(sl.find_element(locator))
14-
if x_wiggle:
15-
action_chains.move_by_offset(xoffset=x_wiggle, yoffset=0)
16-
action_chains.move_by_offset(xoffset=-x_wiggle, yoffset=0)
18+
wiggle(action_chains, x_wiggle)
1719
action_chains.key_up(Keys.CONTROL)
1820
return action_chains.perform()
21+
22+
23+
def mouse_over_and_wiggle(locator, x_wiggle=5):
24+
sl: SeleniumLibrary = BuiltIn().get_library_instance("SeleniumLibrary")
25+
action_chains = ActionChains(sl.driver)
26+
action_chains.move_to_element(sl.find_element(locator))
27+
wiggle(action_chains, x_wiggle)
28+
return action_chains.perform()

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

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -93,23 +93,29 @@ export class HoverCM extends CodeMirrorIntegration {
9393
}
9494

9595
protected restore_from_cache(
96-
root_position: IRootPosition,
9796
document: VirtualDocument,
9897
virtual_position: IVirtualPosition
9998
): IResponseData | null {
99+
const { line, ch } = virtual_position;
100100
const matching_items = this.cache.data.filter(cache_item => {
101101
if (cache_item.document !== document) {
102102
return false;
103103
}
104104
let range = cache_item.response.range;
105-
let { line, ch } = virtual_position;
106105
return (
107106
line >= range.start.line &&
108107
line <= range.end.line &&
109108
(line != range.start.line || ch >= range.start.character) &&
110109
(line != range.end.line || ch <= range.end.character)
111110
);
112111
});
112+
if (matching_items.length > 1) {
113+
console.warn(
114+
'LSP: Potential hover cache malfunction: ',
115+
virtual_position,
116+
matching_items
117+
);
118+
}
113119
return matching_items.length != 0 ? matching_items[0] : null;
114120
}
115121

@@ -157,16 +163,16 @@ export class HoverCM extends CodeMirrorIntegration {
157163
getModifierState(event, this.modifierKey) &&
158164
typeof this.last_hover_character !== 'undefined'
159165
) {
166+
// does not need to be shown if it is already visible (otherwise we would be creating an identical tooltip again!)
167+
if (this.tooltip && this.tooltip.isVisible && !this.tooltip.isDisposed) {
168+
return;
169+
}
160170
const document = this.virtual_editor.document_at_root_position(
161171
this.last_hover_character
162172
);
163-
const virtual_position = this.virtual_editor.root_position_to_virtual_position(
164-
this.last_hover_character
165-
);
166173
let response_data = this.restore_from_cache(
167-
this.last_hover_character,
168174
document,
169-
virtual_position
175+
this.virtual_position
170176
);
171177
if (response_data == null) {
172178
return;
@@ -312,6 +318,13 @@ export class HoverCM extends CodeMirrorIntegration {
312318
protected async _updateUnderlineAndTooltip(
313319
event: MouseEvent
314320
): Promise<boolean> {
321+
const target = event.target as HTMLElement;
322+
323+
// if over an empty space in a line (and not over a token) then not worth checking
324+
if (target.classList.contains('CodeMirror-line')) {
325+
return;
326+
}
327+
315328
const show_tooltip = getModifierState(event, this.modifierKey);
316329

317330
// currently the events are coming from notebook panel; ideally these would be connected to individual cells,
@@ -330,9 +343,6 @@ export class HoverCM extends CodeMirrorIntegration {
330343
let token = this.virtual_editor.getTokenAt(root_position);
331344

332345
let document = this.virtual_editor.document_at_root_position(root_position);
333-
let virtual_position = this.virtual_editor.root_position_to_virtual_position(
334-
root_position
335-
);
336346

337347
if (
338348
this.is_token_empty(token) ||
@@ -344,14 +354,13 @@ export class HoverCM extends CodeMirrorIntegration {
344354
}
345355

346356
if (!is_equal(root_position, this.last_hover_character)) {
357+
let virtual_position = this.virtual_editor.root_position_to_virtual_position(
358+
root_position
359+
);
347360
this.virtual_position = virtual_position;
348361
this.last_hover_character = root_position;
349362

350-
let response_data = this.restore_from_cache(
351-
root_position,
352-
document,
353-
virtual_position
354-
);
363+
let response_data = this.restore_from_cache(document, virtual_position);
355364

356365
if (response_data == null) {
357366
let response = await this.debounced_get_hover.invoke();
@@ -470,15 +479,19 @@ export class HoverCM extends CodeMirrorIntegration {
470479
...response,
471480
range: {
472481
start: PositionConverter.cm_to_lsp(
473-
this.virtual_editor.transform_from_editor_to_root(
474-
ce_editor,
475-
editor_range.start
482+
this.virtual_editor.root_position_to_virtual_position(
483+
this.virtual_editor.transform_from_editor_to_root(
484+
ce_editor,
485+
editor_range.start
486+
)
476487
)
477488
),
478489
end: PositionConverter.cm_to_lsp(
479-
this.virtual_editor.transform_from_editor_to_root(
480-
ce_editor,
481-
editor_range.end
490+
this.virtual_editor.root_position_to_virtual_position(
491+
this.virtual_editor.transform_from_editor_to_root(
492+
ce_editor,
493+
editor_range.end
494+
)
482495
)
483496
)
484497
}

0 commit comments

Comments
 (0)