diff --git a/.github/workflows/job.test.yml b/.github/workflows/job.test.yml index 1221ab3bc..2a8af681a 100644 --- a/.github/workflows/job.test.yml +++ b/.github/workflows/job.test.yml @@ -44,7 +44,7 @@ jobs: matrix: os: [ubuntu] nodejs: ['>=16,<17.0.0a0'] - lab: ['>=4.0.5,<5.0.0a0'] + lab: ['>=4.0.6,<5.0.0a0'] r: ['>=4'] steps: - uses: actions/checkout@v3 diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fafb1295..2124f4ae7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ ## Changelog +### `@jupyter-lsp/jupyterlab-lsp 5.0.0-rc.0` + +- fixes diagnostics not showing up in text editor in certain circumstances +- fixes signature hover box not being clickable +- improves performance by not creating a temporary editor to setup linter underline style +- JSON overrides work again +- fixes issue with syntax highlighting breaking when pasting multiple cells + +Requires JupyterLab `>=4.0.6,<5.0.0a0` + ### `@jupyter-lsp/jupyterlab-lsp 5.0.0-beta.1` - fix highlights conflict with selection diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 94571c134..01eaee9eb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,7 +33,7 @@ Development requires, at a minimum: - `nodejs >=16,!=17,<19` - `python >=3.8,<3.11.0a0` -- `jupyterlab >=4.0.5,<5.0.0a0` +- `jupyterlab >=4.0.6,<5.0.0a0` It is recommended to use a virtual environment (e.g. `virtualenv` or `conda env`) for development. diff --git a/README.md b/README.md index beaf2ebd6..130faa2e8 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ Use context menu on rows in the panel to filter out diagnostics or copy their me You will need to have both of the following installed: -- JupyterLab >=4.0.5,<5.0.0a0 +- JupyterLab >=4.0.6,<5.0.0a0 - Python 3.8+ In addition, if you wish to use javascript, html, markdown or any other NodeJS-based language server you will need to have appropriate NodeJS version installed. diff --git a/atest/01_Editor.robot b/atest/01_Editor.robot index 8162206e5..541f4c63d 100644 --- a/atest/01_Editor.robot +++ b/atest/01_Editor.robot @@ -9,7 +9,7 @@ Test Tags ui:editor aspect:ls:features *** Test Cases *** Bash - ${def} = Set Variable xpath:(//div[contains(@class, 'cm-line')]//text()[contains(., 'HelloWorld')])[last()] + ${def} = Set Variable lastToken:fib Editor Shows Features for Language ... Bash ... example.sh @@ -17,19 +17,18 @@ Bash ... Jump to Definition=${def} CSS - ${def} = Set Variable - ... xpath:(//div[contains(@class, 'cm-line')]//text()[contains(., '--some-var')])[last()] + ${def} = Set Variable lastToken:--some-var Editor Shows Features for Language CSS example.css Diagnostics=Do not use empty rulesets ... Jump to Definition=${def} Rename=${def} Docker - ${def} = Set Variable xpath://div[contains(@class, 'cm-line')]//text()[contains(., 'PLANET')] + ${def} = Set Variable lastToken:PLANET Wait Until Keyword Succeeds 3x 100ms Editor Shows Features for Language Docker Dockerfile ... Diagnostics=Instructions should be written in uppercase letters Jump to Definition=${def} ... Rename=${def} JS - ${def} = Set Variable xpath:(//div[contains(@class, 'cm-line')]//text()[contains(., 'fib')])[last()] + ${def} = Set Variable lastToken:fib Editor Shows Features for Language JS example.js Diagnostics=Expression expected ... Jump to Definition=${def} Rename=${def} @@ -37,20 +36,20 @@ JSON Editor Shows Features for Language JSON example.json Diagnostics=Duplicate object key JSX - ${def} = Set Variable xpath:(//div[contains(@class, 'cm-line')]//text()[contains(., 'hello')])[last()] + ${def} = Set Variable lastToken:hello Editor Shows Features for Language JSX example.jsx Diagnostics=Expression expected ... Jump to Definition=${def} Rename=${def} # Julia -# ${def} = Set Variable xpath:(//div[contains(@class, 'cm-line')]//text()[contains(., 'add_together')])[last()] +# ${def} = Set Variable lastToken:add_together # Editor Shows Features for Language Julia example.jl Jump to Definition=${def} Rename=${def} LaTeX [Tags] language:latex - ${def} = Set Variable xpath:(//div[contains(@class, 'cm-line')]//span[contains(text(), 'foo')])[last()] + ${def} = Set Variable lastToken:foo Editor Shows Features for Language LaTeX example.tex Jump to Definition=${def} Rename=${def} Less - ${def} = Set Variable xpath:(//div[contains(@class, 'cm-line')]//text()[contains(., '@width')])[last()] + ${def} = Set Variable lastToken:@width Editor Shows Features for Language Less example.less Diagnostics=Do not use empty rulesets ... Jump to Definition=${def} @@ -58,7 +57,7 @@ Markdown Editor Shows Features for Language Markdown example.md Diagnostics=`Color` is misspelt Python (pylsp) - ${def} = Set Variable xpath:(//div[contains(@class, 'cm-line')]//text()[contains(., 'fib')])[last()] + ${def} = Set Variable lastToken:fib Editor Shows Features for Server ... pylsp ... Python @@ -68,35 +67,33 @@ Python (pylsp) ... Rename=${def} Python (pyright) - ${def} = Set Variable xpath:(//div[contains(@class, 'cm-line')]//text()[contains(., 'fib')])[last()] + ${def} = Set Variable lastToken:fib Editor Shows Features for Server pyright Python example.py Diagnostics=is not defined (Pyright) ... Jump to Definition=${def} R - ${def} = Set Variable xpath:(//div[contains(@class, 'cm-line')]//text()[contains(., 'fib')])[last()] + ${def} = Set Variable lastToken:fib Editor Shows Features for Language R example.R Diagnostics=Put spaces around all infix operators ... Jump to Definition=${def} Robot Framework [Tags] gh:332 - ${def} = Set Variable - ... xpath:(//div[contains(@class, 'cm-line')]//text()[contains(., 'Special Log')])[last()] + ${def} = Set Variable lastToken:Special Log Editor Shows Features for Language Robot Framework example.robot Diagnostics=Undefined keyword ... Jump to Definition=${def} SCSS - ${def} = Set Variable - ... xpath:(//div[contains(@class, 'cm-line')]//text()[contains(., 'primary-color')])[last()] + ${def} = Set Variable lastToken:primary-color Editor Shows Features for Language SCSS example.scss Diagnostics=Do not use empty rulesets ... Jump to Definition=${def} TSX - ${def} = Set Variable xpath:(//div[contains(@class, 'cm-line')]//text()[contains(., 'HelloWorld')])[last()] + ${def} = Set Variable lastToken:HelloWorld Editor Shows Features for Language TSX example.tsx ... Diagnostics='hello' is declared but its value is never read. Jump to Definition=${def} Rename=${def} TypeScript - ${def} = Set Variable xpath:(//div[contains(@class, 'cm-line')]//text()[contains(., 'inc')])[last()] + ${def} = Set Variable lastToken:inc Editor Shows Features for Language TypeScript example.ts Diagnostics=The left-hand side of an arithmetic ... Jump to Definition=${def} Rename=${def} @@ -155,9 +152,7 @@ Editor Content Changed Editor Should Rename [Arguments] ${symbol} Set Tags feature:rename - ${sel} = Set Variable If "${symbol}".startswith(("xpath", "css")) ${symbol} - ... xpath:(//span[@role="presentation"][contains(., "${symbol}")])[last()] - Open Context Menu Over ${sel} + Open Context Menu Over Token ${symbol} ${old_content} = Get Editor Content Capture Page Screenshot 03-rename-0.png Mouse Over ${MENU RENAME} diff --git a/atest/04_Interface/DiagnosticsPanel.robot b/atest/04_Interface/DiagnosticsPanel.robot index 25fbb3975..42a7b1cf8 100644 --- a/atest/04_Interface/DiagnosticsPanel.robot +++ b/atest/04_Interface/DiagnosticsPanel.robot @@ -14,7 +14,6 @@ ${DIAGNOSTIC MESSAGE} trailing whitespace ${DIAGNOSTIC} W291 trailing whitespace (pycodestyle) ${EXPECTED_COUNT} 4 ${MENU COLUMNS} xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(text(), "columns")] -${R CELL} %%R\n{} *** Test Cases *** @@ -79,9 +78,8 @@ Diagnostics Can Be Ignored By Code Open Context Menu Over W291 Expand Menu Entry Ignore diagnostics Select Menu Entry code - Open in Advanced Settings ${DIAGNOSTICS PLUGIN ID} - Capture Page Screenshot 02-code-pressed.png Wait Until Keyword Succeeds 10 x 1s Should Have Expected Rows Count ${EXPECTED_AFTER} + Configure JupyterLab Plugin {} plugin id=${DIAGNOSTICS PLUGIN ID} Diagnostics Can Be Ignored By Message Wait Until Keyword Succeeds 10 x 1s Should Have Expected Rows Count ${EXPECTED_COUNT} @@ -91,9 +89,8 @@ Diagnostics Can Be Ignored By Message Expand Menu Entry Ignore diagnostics Capture Page Screenshot 02-menu-visible.png Select Menu Entry Ignore diagnostics with "W291 trailing whitespace" message - Open in Advanced Settings ${DIAGNOSTICS PLUGIN ID} - Capture Page Screenshot 02-message-pressed.png Wait Until Keyword Succeeds 10 x 1s Should Have Expected Rows Count ${EXPECTED_AFTER} + Configure JupyterLab Plugin {} plugin id=${DIAGNOSTICS PLUGIN ID} Diagnostic Message Can Be Copied Wait Until Keyword Succeeds 10 x 1s Element Should Contain ${DIAGNOSTICS PANEL} @@ -101,28 +98,39 @@ Diagnostic Message Can Be Copied Open Context Menu Over css:.lsp-diagnostics-listing tbody tr Select Menu Entry Copy diagnostic Close Diagnostics Panel - Wait Until Element Contains css:.lsp-statusbar-item Successfully copied timeout=10s + Wait Until Element Contains css:.jp-toast-message Successfully copied timeout=10s Diagnostics Panel Works After Removing Foreign Document Enter Cell Editor 2 Lab Command Insert Cell Below Enter Cell Editor 3 - Press Keys None ${R CELL} + Press Keys None %%R\n + # these two steps ideally would not be needed (they show that for slow-starting server + # update may not be triggered until user manually makes another action). + Wait Until Fully Initialized + Press Keys None {} Wait Until Keyword Succeeds 10 x 1s Element Should Contain ${DIAGNOSTICS PANEL} ... ${DIAGNOSTIC MESSAGE} Wait Until Keyword Succeeds 10 x 1s Element Should Contain ${DIAGNOSTICS PANEL} ... ${DIAGNOSTIC MESSAGE R} - Lab Command Delete Cells + Lab Command Delete Cell # regain focus by entering cell Enter Cell Editor 2 # trigger 7 document updates to trigger the garbage collector that removes unused documents - # (search for VirtualDocument.remainining_lifetime for more) + # (search for VirtualDocument.remainingLifetime for more) Press Keys None 1234567 Wait Until Keyword Succeeds 10 x 1s Element Should Contain ${DIAGNOSTICS PANEL} ... ${DIAGNOSTIC MESSAGE} Wait Until Keyword Succeeds 10 x 1s Element Should Not Contain ${DIAGNOSTICS PANEL} ... ${DIAGNOSTIC MESSAGE R} - + # it should be possible to get the diagnostic back after re-creatign the cell + Lab Command Insert Cell Below + Enter Cell Editor 3 + Press Keys None %%R\n{} + Wait Until Keyword Succeeds 10 x 1s Element Should Contain ${DIAGNOSTICS PANEL} + ... ${DIAGNOSTIC MESSAGE} + Wait Until Keyword Succeeds 10 x 1s Element Should Contain ${DIAGNOSTICS PANEL} + ... ${DIAGNOSTIC MESSAGE R} *** Keywords *** Open Context Menu Over W291 @@ -134,7 +142,7 @@ Open Context Menu Over W291 Open Notebook And Panel [Arguments] ${notebook} Setup Notebook Python ${notebook} - Capture Page Screenshot 00-notebook-and-panel-openeing.png + Capture Page Screenshot 00-notebook-and-panel-opening.png Wait Until Page Contains Diagnostic [title*="${DIAGNOSTIC}"] timeout=20s Open Diagnostics Panel Capture Page Screenshot 00-notebook-and-panel-opened.png diff --git a/atest/05_Features/Completion.robot b/atest/05_Features/Completion.robot index 3ae35b818..0081daa02 100644 --- a/atest/05_Features/Completion.robot +++ b/atest/05_Features/Completion.robot @@ -85,7 +85,7 @@ Invalidates On Focus Loss Completer Should Not Suggest test Enter Cell Editor 1 line=2 -Uses LSP Completions When Kernel Resoponse Times Out +Uses LSP Completions When Kernel Response Times Out [Tags] requires:busy-indicator Configure JupyterLab Plugin {"kernelResponseTimeout": 1, "waitForBusyKernel": true} ... plugin id=${COMPLETION PLUGIN ID} @@ -150,7 +150,7 @@ Continuous Hinting Works [Setup] Prepare File for Editing Python completion completion.py Configure JupyterLab Plugin {"continuousHinting": true} plugin id=${COMPLETION PLUGIN ID} # TODO: remove once we resolve https://github.com/jupyterlab/jupyterlab/issues/15022 - Configure JupyterLab Plugin {"autoCompletion": true} plugin id=${MANAGER PLUGIN ID} + Configure JupyterLab Plugin {"autoCompletion": true, "providerTimeout": 2500} plugin id=${MANAGER PLUGIN ID} Place Cursor In File Editor At 9 2 Wait For Ready State Press Keys None d @@ -373,6 +373,8 @@ Completes Paths In Strings *** Keywords *** Setup Completion Test Setup Notebook Python Completion.ipynb + # TODO: this should be per-provider (upstream issue) + Configure JupyterLab Plugin {"providerTimeout": 2500} plugin id=${MANAGER PLUGIN ID} Get Cell Editor Content [Arguments] ${cell_nr} @@ -470,4 +472,4 @@ Should Complete While Kernel Is Busy Page Should Contain Element ${KERNEL_BUSY_INDICATOR} Wait For Our Completer To Initialize - Wait Until Page Contains Element css:.body[data-lsp-completer-layout] + Wait Until Page Contains Element css:body[data-lsp-completer-layout] diff --git a/atest/05_Features/Hover.robot b/atest/05_Features/Hover.robot index 6430f3e9d..7c7117e30 100644 --- a/atest/05_Features/Hover.robot +++ b/atest/05_Features/Hover.robot @@ -17,7 +17,7 @@ ${HOVER_SIGNAL} css:.cm-lsp-hover-available *** Test Cases *** Hover Does Not Trigger Automatically Enter Cell Editor 1 - ${sel} = Last Occurrence python_add + ${sel} = Set Variable lastToken:python_add Configure JupyterLab Plugin {"autoActivate": false} ... plugin id=${HOVER PLUGIN ID} Trigger Automatically By Hover ${sel} @@ -27,7 +27,7 @@ Hover Does Not Trigger Automatically Hover Triggers Automatically Enter Cell Editor 1 - ${sel} = Last Occurrence python_add + ${sel} = Set Variable lastToken:python_add Configure JupyterLab Plugin {"delay": 100, "autoActivate": true} ... plugin id=${HOVER PLUGIN ID} Trigger Automatically By Hover ${sel} @@ -48,7 +48,7 @@ Hover works in notebooks Hover can be triggered via modifier key once cursor stopped moving Enter Cell Editor 1 - ${element} = Last Occurrence python_add + ${element} = Set Variable lastToken:python_add Wait Until Keyword Succeeds 5x 0.1 s Trigger Via Modifier Key Press ${element} Hover works in foreign code (javascript) @@ -70,60 +70,46 @@ Update hover after character deletion Enter Cell Editor 4 Trigger Tooltip atan2 Element Text Should Be ${HOVER_SIGNAL} atan2 - Capture Page Screenshot 01-hover-before-delection.png + Capture Page Screenshot 01-hover-before-deletion.png Element Should Contain ${HOVER_BOX} atan2(y: SupportsFloat, x: SupportsFloat, /) Place Cursor In Cell Editor At 4 line=2 character=13 Press Keys None DELETE Trigger Tooltip atan Element Text Should Be ${HOVER_SIGNAL} atan - Capture Page Screenshot 02-hover-after-delection.png + Capture Page Screenshot 02-hover-after-deletion.png Element Should Contain ${HOVER_BOX} atan(x: SupportsFloat, /) *** Keywords *** -Last Occurrence - [Arguments] ${symbol} - ${sel} = Set Variable If "${symbol}".startswith(("xpath", "css")) ${symbol} - ... xpath:(//div[@class="cm-content"]//text()[contains(., "${symbol}")])[last()] - RETURN ${sel} - Trigger Automatically By Hover [Arguments] ${sel} # bring the cursor to the element - Wokraround Visibility Problem ${sel} - Mouse Over ${sel} + Mouse Over Token ${sel} Wait Until Page Contains Element ${HOVER_SIGNAL} timeout=10s - Mouse Over And Wiggle ${sel} 5 + Mouse Over Token And Wiggle ${sel} 5 Trigger Via Hover With Modifier [Arguments] ${sel} # bring the cursor to the element - Wokraround Visibility Problem ${sel} - Mouse Over ${sel} - # move it back and forth (wiggle) while hodling the ctrl modifier - Mouse Over With Control ${sel} x_wiggle=5 + Mouse Over Token ${sel} + # move it back and forth (wiggle) while holding the ctrl modifier + Mouse Over Token With Control ${sel} x_wiggle=5 Wait Until Keyword Succeeds 4x 0.1s Page Should Contain Element ${HOVER_BOX} Trigger Via Modifier Key Press [Arguments] ${sel} # bring the cursor to the element - Wokraround Visibility Problem ${sel} - Mouse Over ${sel} + Mouse Over Token ${sel} Wait Until Page Contains Element ${HOVER_SIGNAL} timeout=10s - Mouse Over And Wiggle ${sel} 5 - Press Keys ${sel} CTRL + Mouse Over Token And Wiggle ${sel} 5 + Press Keys None CTRL Wait Until Keyword Succeeds 4x 0.1s Page Should Contain Element ${HOVER_BOX} Trigger Tooltip [Documentation] The default way to trigger the hover tooltip [Arguments] ${symbol} - ${sel} = Last Occurrence ${symbol} + ${sel} = Set Variable lastToken:${symbol} Wait Until Keyword Succeeds 4x 0.1 s Trigger Via Hover With Modifier ${sel} Setup Hover Test Setup Notebook Python Hover.ipynb - -Wokraround Visibility Problem - [Arguments] ${sel} - ${width} ${height} = Get Element Size ${sel} - IF ${width} == 0 Cover Element ${sel} diff --git a/atest/05_Features/Jump.robot b/atest/05_Features/Jump.robot index 69ddf2cfa..2145aa3a7 100644 --- a/atest/05_Features/Jump.robot +++ b/atest/05_Features/Jump.robot @@ -15,8 +15,7 @@ Python Jumps Between Files Copy Files to Folder With Spaces jump_a.py jump_b.py Open ${FOLDER WITH SPACE}/jump_b.py in ${MENU EDITOR} Wait Until Fully Initialized - ${sel} = Select Token Occurrence a_function_definition - Jump To Definition ${sel} + Jump To Definition lastToken:a_function_definition Wait Until Page Contains ANOTHER_CONSTANT Capture Page Screenshot 10-jumped.png [Teardown] Clean Up Folder With Spaces jump_a.py jump_b.py diff --git a/atest/Keywords.resource b/atest/Keywords.resource index a02563c19..57e911768 100644 --- a/atest/Keywords.resource +++ b/atest/Keywords.resource @@ -10,6 +10,7 @@ Library ./ports.py Library ./config.py Library ./paths.py Library ./diagnostics.py +Library ./mouse_over_extension.py *** Keywords *** @@ -80,6 +81,7 @@ Read Page Config Set Global Variable ${PAGE CONFIG} ${config} Set Global Variable ${LAB VERSION} ${config["appVersion"]} + Setup Suite For Screenshots [Arguments] ${folder} Set Screenshot Directory ${SCREENSHOTS DIR}${/}${folder} @@ -324,6 +326,11 @@ Enter Cell Editor [Arguments] ${cell_nr} ${line}=1 Click Element css:.jp-Cell:nth-child(${cell_nr}) .cm-line:nth-child(${line}) Wait Until Page Contains Element css:.jp-Cell:nth-child(${cell_nr}) .cm-focused + # clicking on line does not appear sufficient in CM6 (but still useful because it ensures we have it in view + Execute JavaScript + ... var view = document.querySelector('.jp-Cell:nth-child(${cell_nr}) .cm-content').cmView.view; + ... var pos = view.state.doc.line(${line}).to; + ... return view.dispatch({selection: {anchor: pos, head: pos}}); Open Context Menu Over Cell Editor [Arguments] ${cell_nr} ${line}=1 @@ -391,11 +398,7 @@ Open File Open in Advanced Settings [Arguments] ${plugin id} - IF '${LAB VERSION}'.startswith('3.') - Lab Command Advanced JSON Settings Editor - ELSE - Lab Command Advanced Settings Editor - END + Lab Command Advanced Settings Editor ${sel} = Set Variable css:[data-id="${plugin id}"] Wait Until Page Contains Element ${sel} timeout=10s Click Element ${sel} @@ -433,11 +436,9 @@ Clean Up After Working with File and Settings Jump To Definition [Arguments] ${symbol} - ${sel} = Set Variable If "${symbol}".startswith(("xpath", "css")) ${symbol} - ... xpath:(//span[@role="presentation"][contains(., "${symbol}")])[last()] - Click Element ${sel} + Click Token ${symbol} ${cursor} = Measure Cursor Position - Open Context Menu Over ${sel} + Open Context Menu Over Token ${symbol} Capture Page Screenshot 02-jump-to-definition-0.png Wait Until Element Is Visible ${MENU JUMP} timeout=5s Mouse Over ${MENU JUMP} diff --git a/atest/diagnostics.py b/atest/diagnostics.py index 4bd37cd24..85224491d 100644 --- a/atest/diagnostics.py +++ b/atest/diagnostics.py @@ -27,7 +27,7 @@ def page_contains_diagnostic(driver: WebDriver, selector, negate=False): return False if negate else True -def wait_until_page_contains_diagnostic(selector, timeout='3s'): +def wait_until_page_contains_diagnostic(selector, timeout='5s'): sl: SeleniumLibrary = BuiltIn().get_library_instance("SeleniumLibrary") wait = WebDriverWait(sl.driver, timestr_to_secs(timeout)) try: @@ -50,7 +50,7 @@ def wait_until_page_contains_diagnostic(selector, timeout='3s'): ) -def wait_until_page_does_not_contain_diagnostic(selector, timeout='3s'): +def wait_until_page_does_not_contain_diagnostic(selector, timeout='5s'): sl: SeleniumLibrary = BuiltIn().get_library_instance("SeleniumLibrary") wait = WebDriverWait(sl.driver, timestr_to_secs(timeout)) return wait.until( diff --git a/atest/examples/Hover.ipynb b/atest/examples/Hover.ipynb index e68905259..4c77b42cd 100644 --- a/atest/examples/Hover.ipynb +++ b/atest/examples/Hover.ipynb @@ -35,7 +35,9 @@ "outputs": [], "source": [ "%%javascript\n", - "Math" + "function range(x) {\n", + " Math.max(x) - Math.min(x)\n", + "}" ] }, { @@ -51,7 +53,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -65,7 +67,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.9" + "version": "3.11.4" } }, "nbformat": 4, diff --git a/atest/fixtures/overrides.json b/atest/fixtures/overrides.json index c4cb73ca9..726fe9625 100644 --- a/atest/fixtures/overrides.json +++ b/atest/fixtures/overrides.json @@ -9,12 +9,6 @@ "pylsp.plugins.flake8.enabled": true, "pylsp.plugins.pyflakes.enabled": false } - }, - "pyright": { - "priority": 500, - "serverSettings": { - "python.analysis.useLibraryCodeForTypes": false - } } } } diff --git a/atest/mouse_over_extension.py b/atest/mouse_over_extension.py index cfb867454..0c18125be 100644 --- a/atest/mouse_over_extension.py +++ b/atest/mouse_over_extension.py @@ -1,28 +1,121 @@ from robot.libraries.BuiltIn import BuiltIn -from selenium.webdriver import ActionChains +from selenium.webdriver.common.actions.action_builder import ActionBuilder from selenium.webdriver.common.keys import Keys from SeleniumLibrary import SeleniumLibrary -def wiggle(action_chains, x_wiggle): +def wiggle(action, x_wiggle): if x_wiggle: - action_chains.move_by_offset(xoffset=x_wiggle, yoffset=0) - action_chains.move_by_offset(xoffset=-x_wiggle, yoffset=0) + action.pointer_action.move_by(x_wiggle, 0) + action.pointer_action.move_by(-x_wiggle, 0) -def mouse_over_with_control(locator, x_wiggle=0): +def mouse_over_token_with_control(token_locator, x_wiggle=0): sl: SeleniumLibrary = BuiltIn().get_library_instance("SeleniumLibrary") - action_chains = ActionChains(sl.driver) - action_chains.key_down(Keys.CONTROL) - action_chains.move_to_element(sl.find_element(locator)) - wiggle(action_chains, x_wiggle) - action_chains.key_up(Keys.CONTROL) - return action_chains.perform() + location = _find_text_in_line(token_locator) + action = ActionBuilder(sl.driver) + action.key_action.key_down(Keys.CONTROL) -def mouse_over_and_wiggle(locator, x_wiggle=5): + action.pointer_action.move_to_location(location['x'], location['y']) + wiggle(action, x_wiggle) + action.key_action.key_up(Keys.CONTROL) + + return action.perform() + + +def mouse_over_token_and_wiggle(token_locator, x_wiggle=5): + sl: SeleniumLibrary = BuiltIn().get_library_instance("SeleniumLibrary") + action = ActionBuilder(sl.driver) + location = _find_text_in_line(token_locator) + action.pointer_action.move_to_location(location['x'], location['y']) + wiggle(action, x_wiggle) + return action.perform() + + +def _find_text_in_line(token_locator: str): + which, text = token_locator.split(':', maxsplit=1) + assert which == 'lastToken' + sl: SeleniumLibrary = BuiltIn().get_library_instance("SeleniumLibrary") + sl.driver.execute_script( + """ + window.breadthFirstSearchReverse = function (nodes, text) { + for (let n of nodes.toReversed()) { + if (n.childNodes.length) { + var result = window.breadthFirstSearchReverse( + [...n.childNodes], + text + ); + if (result) { + return result + } + } else if (n.textContent.includes(text) && n.nodeType === 3) { + return n; + } + } + } + """ + ) + return sl.driver.execute_script( + """ + const text = arguments[0]; + + const textNode = window.breadthFirstSearchReverse( + [...document.querySelectorAll('.cm-line')], + text + ); + + const offset = textNode.textContent.indexOf(text); + const subNode = ( + textNode + .splitText(offset) + .splitText(text.length) + .previousSibling + ); + const range = document.createRange(); + range.selectNode(subNode); + const rect = range.getBoundingClientRect(); + + return { + // selenium does not allow passing bare nodes, only elements + parentElement: subNode.parentElement, + x: (rect.left + rect.right) / 2, + y: (rect.top + rect.bottom) / 2 + } + """, + text + ) + +def _emit_over_text_in_line(token_locator: str, event: str): + sl: SeleniumLibrary = BuiltIn().get_library_instance("SeleniumLibrary") + location = _find_text_in_line(token_locator) + sl.driver.execute_script( + """ + const location = arguments[0]; + const eventType = arguments[1]; + + const e = new Event(eventType, {bubbles: true}); + e.clientX = location.x; + e.clientY = location.y; + + location.parentElement.dispatchEvent(e); + """, + location, + event + ) + + +def mouse_over_token(token_locator: str): sl: SeleniumLibrary = BuiltIn().get_library_instance("SeleniumLibrary") - action_chains = ActionChains(sl.driver) - action_chains.move_to_element(sl.find_element(locator)) - wiggle(action_chains, x_wiggle) - return action_chains.perform() + action = ActionBuilder(sl.driver) + location = _find_text_in_line(token_locator) + action.pointer_action.move_to_location(location['x'], location['y']) + return action.perform() + + +def click_token(token_locator: str): + return _emit_over_text_in_line(token_locator, event='click') + + +def open_context_menu_over_token(token_locator: str): + return _emit_over_text_in_line(token_locator, event='contextmenu') diff --git a/binder/environment.yml b/binder/environment.yml index dcb621bdf..0284add73 100644 --- a/binder/environment.yml +++ b/binder/environment.yml @@ -7,7 +7,7 @@ channels: dependencies: # runtime dependencies - python >=3.8,<3.11.0a0 - - jupyterlab >=4.0.5,<5.0.0a0 + - jupyterlab >=4.0.6,<5.0.0a0 - jupyter_server >=1.1.2 # TODO: uncomment once Notebook 7 is released #- notebook >= 7.0 diff --git a/docs/rtd.yml b/docs/rtd.yml index 3748c5101..d0e56f53e 100644 --- a/docs/rtd.yml +++ b/docs/rtd.yml @@ -7,7 +7,7 @@ channels: dependencies: - importlib_metadata - - jupyterlab >=4.0.5,<5.0.0a0 + - jupyterlab >=4.0.6,<5.0.0a0 - myst-nb - nodejs >=16,!=17,<19 - pandas diff --git a/packages/_example-extractor/package.json b/packages/_example-extractor/package.json index e7baa12a4..9af538354 100644 --- a/packages/_example-extractor/package.json +++ b/packages/_example-extractor/package.json @@ -14,8 +14,8 @@ "@jupyter-lsp/jupyterlab-lsp": "^5.0.0-alpha.0" }, "devDependencies": { - "@jupyterlab/application": "^4.0.5", - "@jupyterlab/testing": "^4.0.5", + "@jupyterlab/application": "^4.0.6", + "@jupyterlab/testing": "^4.0.6", "@types/jest": "^29.5.4", "jest": "^29.2.0", "rimraf": "^3.0.0", diff --git a/packages/_klingon-integration/package.json b/packages/_klingon-integration/package.json index bb7d42ca9..f6d8c6003 100644 --- a/packages/_klingon-integration/package.json +++ b/packages/_klingon-integration/package.json @@ -11,11 +11,11 @@ "LICENSE" ], "dependencies": { - "@jupyterlab/application": "^4.0.5" + "@jupyterlab/application": "^4.0.6" }, "devDependencies": { - "@jupyterlab/application": "^4.0.5", - "@jupyterlab/builder": "^4.0.5", + "@jupyterlab/application": "^4.0.6", + "@jupyterlab/builder": "^4.0.6", "typescript": "~5.0.4" }, "jupyterlab": { diff --git a/packages/code-jumpers/package.json b/packages/code-jumpers/package.json index ff1faed19..67181e195 100644 --- a/packages/code-jumpers/package.json +++ b/packages/code-jumpers/package.json @@ -1,6 +1,6 @@ { "name": "@jupyter-lsp/code-jumpers", - "version": "1.2.0", + "version": "2.0.0-rc.0", "description": "Implementation underlying the jump to definition functionality in JupyterLab-LSP", "keywords": [ "jupyter", @@ -41,16 +41,16 @@ "@jupyterlab/translation": "^4.0.0" }, "devDependencies": { - "@jupyterlab/apputils": "^4.1.5", - "@jupyterlab/codeeditor": "^4.0.5", - "@jupyterlab/coreutils": "^6.0.5", - "@jupyterlab/docmanager": "^4.0.5", - "@jupyterlab/docregistry": "^4.0.5", - "@jupyterlab/fileeditor": "^4.0.5", - "@jupyterlab/notebook": "^4.0.5", - "@jupyterlab/observables": "^5.0.5", - "@jupyterlab/testing": "^4.0.5", - "@jupyterlab/translation": "^4.0.5", + "@jupyterlab/apputils": "^4.1.6", + "@jupyterlab/codeeditor": "^4.0.6", + "@jupyterlab/coreutils": "^6.0.6", + "@jupyterlab/docmanager": "^4.0.6", + "@jupyterlab/docregistry": "^4.0.6", + "@jupyterlab/fileeditor": "^4.0.6", + "@jupyterlab/notebook": "^4.0.6", + "@jupyterlab/observables": "^5.0.6", + "@jupyterlab/testing": "^4.0.6", + "@jupyterlab/translation": "^4.0.6", "rimraf": "^3.0.0", "typescript": "~5.0.4" }, diff --git a/packages/completion-theme/package.json b/packages/completion-theme/package.json index a693cc0f1..b679d7352 100644 --- a/packages/completion-theme/package.json +++ b/packages/completion-theme/package.json @@ -1,6 +1,6 @@ { "name": "@jupyter-lsp/completion-theme", - "version": "3.3.0", + "version": "4.0.0-rc.0", "description": "Completion theme manager for JupyterLab-LSP", "keywords": [ "jupyter", @@ -33,8 +33,8 @@ "clean": "rimraf lib" }, "devDependencies": { - "@jupyterlab/builder": "^4.0.5", - "@jupyterlab/ui-components": "^4.0.5", + "@jupyterlab/builder": "^4.0.6", + "@jupyterlab/ui-components": "^4.0.6", "react": "^18.2.0", "rimraf": "^3.0.0", "typescript": "~5.0.4" diff --git a/packages/jupyterlab-lsp/package.json b/packages/jupyterlab-lsp/package.json index 2d9333ff8..4b1306814 100644 --- a/packages/jupyterlab-lsp/package.json +++ b/packages/jupyterlab-lsp/package.json @@ -1,6 +1,6 @@ { "name": "@jupyter-lsp/jupyterlab-lsp", - "version": "5.0.0-beta.1", + "version": "5.0.0-rc.0", "description": "Language Server Protocol integration for JupyterLab", "keywords": [ "jupyter", @@ -60,36 +60,36 @@ "watch:src": "tsc -w" }, "dependencies": { - "@jupyter-lsp/code-jumpers": "~1.2.0", - "@jupyter-lsp/completion-theme": "~3.3.0", - "@jupyter-lsp/theme-material": "~2.1.1", - "@jupyter-lsp/theme-vscode": "~2.1.1", - "@jupyterlab/lsp": "^4.0.5", + "@jupyter-lsp/code-jumpers": "~2.0.0-rc.0", + "@jupyter-lsp/completion-theme": "~4.0.0-rc.0", + "@jupyter-lsp/theme-material": "~3.0.0-rc.0", + "@jupyter-lsp/theme-vscode": "~3.0.0-rc.0", + "@jupyterlab/lsp": "^4.0.6", "@rjsf/validator-ajv8": "^5.12.1", "lodash.mergewith": "^4.6.1" }, "devDependencies": { "@codemirror/lint": "^6.4.0", - "@jupyter-notebook/application": "^7.0.2", - "@jupyterlab/application": "^4.0.5", - "@jupyterlab/apputils": "^4.1.5", - "@jupyterlab/builder": "^4.0.5", - "@jupyterlab/cells": "^4.0.5", - "@jupyterlab/codeeditor": "^4.0.5", - "@jupyterlab/codemirror": "^4.0.5", - "@jupyterlab/completer": "^4.0.5", - "@jupyterlab/coreutils": "^6.0.5", - "@jupyterlab/docmanager": "^4.0.5", - "@jupyterlab/docregistry": "^4.0.5", - "@jupyterlab/fileeditor": "^4.0.5", - "@jupyterlab/logconsole": "^4.0.5", - "@jupyterlab/notebook": "^4.0.5", - "@jupyterlab/rendermime": "^4.0.5", - "@jupyterlab/services": "^7.0.5", - "@jupyterlab/statusbar": "^4.0.5", - "@jupyterlab/testing": "^4.0.5", - "@jupyterlab/tooltip": "^4.0.5", - "@jupyterlab/ui-components": "^4.0.5", + "@jupyter-notebook/application": "^7.0.3", + "@jupyterlab/application": "^4.0.6", + "@jupyterlab/apputils": "^4.1.6", + "@jupyterlab/builder": "^4.0.6", + "@jupyterlab/cells": "^4.0.6", + "@jupyterlab/codeeditor": "^4.0.6", + "@jupyterlab/codemirror": "^4.0.6", + "@jupyterlab/completer": "^4.0.6", + "@jupyterlab/coreutils": "^6.0.6", + "@jupyterlab/docmanager": "^4.0.6", + "@jupyterlab/docregistry": "^4.0.6", + "@jupyterlab/fileeditor": "^4.0.6", + "@jupyterlab/logconsole": "^4.0.6", + "@jupyterlab/notebook": "^4.0.6", + "@jupyterlab/rendermime": "^4.0.6", + "@jupyterlab/services": "^7.0.6", + "@jupyterlab/statusbar": "^4.0.6", + "@jupyterlab/testing": "^4.0.6", + "@jupyterlab/tooltip": "^4.0.6", + "@jupyterlab/ui-components": "^4.0.6", "@lumino/algorithm": "*", "@lumino/widgets": "^2.3.0", "@types/jest": "^29.5.4", diff --git a/packages/jupyterlab-lsp/src/adapters/notebook.ts b/packages/jupyterlab-lsp/src/adapters/notebook.ts index 89723263f..e76ee1d0a 100644 --- a/packages/jupyterlab-lsp/src/adapters/notebook.ts +++ b/packages/jupyterlab-lsp/src/adapters/notebook.ts @@ -48,21 +48,23 @@ export class NotebookAdapter extends UpstreamNotebookAdapter { } protected async onForeignDocumentOpened( - _: VirtualDocument, + virtualDocument: VirtualDocument, context: Document.IForeignContext ): Promise { /* - Opening a standalone foreign document can result in an inifnite loop, + Opening a standalone foreign document can result in an infinite loop, as a new connection gets opened for these, and once that is ready `updateDocuments()` gets called. To avoid the problem, `updateDocuments()` gets suppressed for standalone documents. It does not affect non-standalone documents, because no new connection gets opened for these. + + https://github.com/jupyter-lsp/jupyterlab-lsp/issues/959 */ try { this._blockUpdates = true; - await super.onForeignDocumentOpened(_, context); + await super.onForeignDocumentOpened(virtualDocument, context); } finally { this._blockUpdates = false; } diff --git a/packages/jupyterlab-lsp/src/converter.ts b/packages/jupyterlab-lsp/src/converter.ts index 7149114fd..d357582ab 100644 --- a/packages/jupyterlab-lsp/src/converter.ts +++ b/packages/jupyterlab-lsp/src/converter.ts @@ -10,7 +10,7 @@ import type { } from '@jupyterlab/lsp'; import type * as lsProtocol from 'vscode-languageserver-protocol'; -import type { VirtualDocument } from './virtual/document'; +import { VirtualDocument } from './virtual/document'; export class PositionConverter { static lsp_to_cm(position: lsProtocol.Position): IPosition { @@ -86,18 +86,6 @@ export function rootPositionToVirtualPosition( return adapter.virtualDocument!.virtualPositionAtDocument(rootAsSource); } -export function virtualPositionToRootPosition( - adapter: WidgetLSPAdapter, - position: IVirtualPosition -): IRootPosition | null { - if (!adapter.virtualDocument) { - throw Error('Virtual document of adapter disposed!'); - } - return (adapter.virtualDocument as VirtualDocument).transformVirtualToRoot( - position - ); -} - export function rootPositionToEditorPosition( adapter: WidgetLSPAdapter, position: IRootPosition @@ -126,12 +114,20 @@ export function editorPositionToRootPosition( export function rangeToEditorRange( adapter: WidgetLSPAdapter, range: lsProtocol.Range, - editor: CodeEditor.IEditor | null + editor: CodeEditor.IEditor | null, + virtualDocument: VirtualDocument ): IEditorRange { let start = PositionConverter.lsp_to_cm(range.start) as IVirtualPosition; let end = PositionConverter.lsp_to_cm(range.end) as IVirtualPosition; - let startInRoot = virtualPositionToRootPosition(adapter, start); + // because `openForeign()` does not use new this.constructor, we need to workaround it for now: + // const startInRoot = virtualDocument.transformVirtualToRoot(start); + // https://github.com/jupyterlab/jupyterlab/issues/15126 + const startInRoot = VirtualDocument.prototype.transformVirtualToRoot.call( + virtualDocument, + start + ); + if (!startInRoot) { throw Error('Could not determine position in root'); } diff --git a/packages/jupyterlab-lsp/src/features/completion/item.ts b/packages/jupyterlab-lsp/src/features/completion/item.ts index 0de5fde1b..a68757b46 100644 --- a/packages/jupyterlab-lsp/src/features/completion/item.ts +++ b/packages/jupyterlab-lsp/src/features/completion/item.ts @@ -30,10 +30,6 @@ namespace CompletionItem { } export class CompletionItem implements IExtendedCompletionItem { - private _detail: string | undefined; - private _documentation: string | undefined; - private _isDocumentationMarkdown: boolean; - private _resolved: boolean; /** * Self-reference to make sure that the instance for will remain accessible * after any copy operation (whether via spread syntax or Object.assign) @@ -42,7 +38,6 @@ export class CompletionItem implements IExtendedCompletionItem { public self: CompletionItem; public element: HTMLLIElement; public source: string; - private _currentInsertText: string; get isDocumentationMarkdown(): boolean { return this._isDocumentationMarkdown; @@ -55,7 +50,6 @@ export class CompletionItem implements IExtendedCompletionItem { public label: string; icon: LabIcon | undefined; - private match: lsProtocol.CompletionItem; constructor(protected options: CompletionItem.IOptions) { const match = options.match; @@ -63,52 +57,49 @@ export class CompletionItem implements IExtendedCompletionItem { this._setDocumentation(match.documentation); this._resolved = false; this._detail = match.detail; - this.match = match; + this._match = match; this.self = this; this.source = options.source; this.icon = options.icon ? options.icon : undefined; + + // Upstream is sometimes using spread operator to copy the object (in reconciliator), + // which does not copy getters because these are not enumerable; we should use + // `Object.assign` upstream, but them, but for now marking relevant properties as enumerable is enough + // Ideally this would be fixed and tested e2e in JupyterLab 4.0.7. + // https://github.com/jupyterlab/jupyterlab/issues/15125 + makeGetterEnumerable(this, 'insertText'); + makeGetterEnumerable(this, 'sortText'); + makeGetterEnumerable(this, 'filterText'); } get type() { return this.options.type; } - private _setDocumentation( - documentation: string | lsProtocol.MarkupContent | undefined - ) { - if (lsProtocol.MarkupContent.is(documentation)) { - this._documentation = documentation.value; - this._isDocumentationMarkdown = documentation.kind === 'markdown'; - } else { - this._documentation = documentation; - this._isDocumentationMarkdown = false; - } - } - /** * Completion to be inserted. */ get insertText(): string { - return this._currentInsertText || this.match.insertText || this.match.label; + return ( + this._currentInsertText || this._match.insertText || this._match.label + ); } - set insertText(text: string) { this._currentInsertText = text; } get sortText(): string { - return this.match.sortText || this.match.label; + return this._currentSortText || this._match.sortText || this._match.label; + } + set sortText(text: string) { + this._currentSortText = text; } get filterText(): string | undefined { - return this.match.filterText; + return this._match.filterText; } - - private _supportsResolution(): boolean { - const connection = this.options.connection; - return ( - connection.serverCapabilities.completionProvider?.resolveProvider ?? false - ); + set filterText(text: string | undefined) { + this._match.filterText = text; } get detail(): string | undefined { @@ -146,7 +137,7 @@ export class CompletionItem implements IExtendedCompletionItem { const resolvedCompletionItem = await connection.clientRequests[ 'completionItem/resolve' - ].request(this.match); + ].request(this._match); if (resolvedCompletionItem === null) { return this; @@ -174,14 +165,61 @@ export class CompletionItem implements IExtendedCompletionItem { * Indicates if the item is deprecated. */ get deprecated(): boolean { - if (this.match.deprecated) { - return this.match.deprecated; + if (this._match.deprecated) { + return this._match.deprecated; } return ( - this.match.tags != null && - this.match.tags.some( + this._match.tags != null && + this._match.tags.some( tag => tag == lsProtocol.CompletionItemTag.Deprecated ) ); } + + private _setDocumentation( + documentation: string | lsProtocol.MarkupContent | undefined + ) { + if (lsProtocol.MarkupContent.is(documentation)) { + this._documentation = documentation.value; + this._isDocumentationMarkdown = documentation.kind === 'markdown'; + } else { + this._documentation = documentation; + this._isDocumentationMarkdown = false; + } + } + + private _supportsResolution(): boolean { + const connection = this.options.connection; + return ( + connection.serverCapabilities.completionProvider?.resolveProvider ?? false + ); + } + + private _detail: string | undefined; + private _documentation: string | undefined; + private _isDocumentationMarkdown: boolean; + private _resolved: boolean; + private _currentInsertText: string; + private _currentSortText: string; + private _match: lsProtocol.CompletionItem; +} + +function makeGetterEnumerable(instance: object, name: string) { + const generatedDescriptor = findDescriptor(instance, name); + Object.defineProperty(instance, name, { + enumerable: true, + get: generatedDescriptor.get, + set: generatedDescriptor.set + }); +} + +function findDescriptor(instance: object, name: string) { + while (instance) { + const desc = Object.getOwnPropertyDescriptor(instance, name); + if (desc) { + return desc; + } + instance = Object.getPrototypeOf(instance); + } + throw Error(`No ${name} descriptor found.`); } diff --git a/packages/jupyterlab-lsp/src/features/completion/model.spec.ts b/packages/jupyterlab-lsp/src/features/completion/model.spec.ts index 3cf2ae073..19e4189f0 100644 --- a/packages/jupyterlab-lsp/src/features/completion/model.spec.ts +++ b/packages/jupyterlab-lsp/src/features/completion/model.spec.ts @@ -8,14 +8,15 @@ describe('LSPCompleterModel', () => { function createDummyItem( match: lsProtocol.CompletionItem, - type: string = 'dummy' + type: string = 'dummy', + source: string = 'lsp' ) { return new CompletionItem({ type, icon: null as any, match, connection: null as any, - source: 'lsp' + source: source }); } @@ -79,6 +80,68 @@ describe('LSPCompleterModel', () => { expect(sortedItems.map(item => item.sortText)).toEqual(['a', 'b', 'c']); }); + describe('sorting by source', () => { + const testCompletionA = createDummyItem( + { + label: 'test' + }, + 'a', + 'LSP' + ); + const testCompletionB = createDummyItem( + { + label: 'test' + }, + 'b', + 'kernel' + ); + const testCompletionC = createDummyItem( + { + label: 'test' + }, + 'c', + 'context' + ); + const testCompletionD = createDummyItem( + { + label: 'test' + }, + 'd', + 'unknown' + ); + const completionsFromDifferentSources = [ + testCompletionA, + testCompletionC, + testCompletionB + ]; + + it('completions are sorted by source', () => { + model.setCompletionItems(completionsFromDifferentSources); + model.query = 'test'; + let sortedItems = model.completionItems(); + expect(sortedItems.map(item => item.type)).toEqual(['a', 'b', 'c']); + }); + + it('kernel completions can be prioritised', () => { + model.setCompletionItems(completionsFromDifferentSources); + model.query = 'test'; + model.settings.kernelCompletionsFirst = true; + let sortedItems = model.completionItems(); + expect(sortedItems.map(item => item.type)).toEqual(['b', 'a', 'c']); + }); + + it('completions from unknown source land at the end', () => { + model.setCompletionItems([ + testCompletionD, + ...completionsFromDifferentSources + ]); + model.query = 'test'; + let sortedItems = model.completionItems(); + const types = sortedItems.map(item => item.type); + expect(types[types.length - 1]).toEqual('d'); + }); + }); + it('ignores perfect matches when asked', () => { model = new LSPCompleterModel({ includePerfectMatches: false diff --git a/packages/jupyterlab-lsp/src/features/completion/model.ts b/packages/jupyterlab-lsp/src/features/completion/model.ts index 90b485359..b2c0981ff 100644 --- a/packages/jupyterlab-lsp/src/features/completion/model.ts +++ b/packages/jupyterlab-lsp/src/features/completion/model.ts @@ -38,14 +38,16 @@ export class GenericCompleterModel< completionItems(): T[] { let query = this.query; - // TODO: make use of `processedItemsCache` when made available upstream, - // see https://github.com/jupyterlab/jupyterlab/pull/15025 // (setting query is bad because it resets the cache; ideally we would // modify the sorting and filtering algorithm upstream). + + // TODO processedItemsCache this.query = ''; + let unfilteredItems = ( super.completionItems() as CompletionHandler.ICompletionItem[] ).map(this.harmoniseItem); + this.query = query; // always want to sort @@ -60,19 +62,44 @@ export class GenericCompleterModel< setCompletionItems(newValue: T[]) { super.setCompletionItems(newValue); - if (this.settings.preFilterMatches && this.current && this.cursor) { + if (this.current && this.cursor) { // set initial query to pre-filter items; in future we should use: // https://github.com/jupyterlab/jupyterlab/issues/9763#issuecomment-1001603348 + + // note: start/end from cursor are not ideal because these get populated from fetch + // reply which will vary depending on what providers decide to return; we want the + // actual position in token, the same as passed in request to fetch. We can get it + // by searching for longest common prefix as seen below (or by counting characters). + // Maybe upstream should expose it directly? const { start, end } = this.cursor; - let query = this.current.text.substring(start, end).trim(); + const { text, line, column } = this.original!; + + const queryRange = text.substring(start, end).trim(); + const linePrefix = text.split('\n')[line].substring(0, column).trim(); + let query = ''; + for (let i = queryRange.length; i > 0; i--) { + if (queryRange.slice(0, i) == linePrefix.slice(-i)) { + query = linePrefix.slice(-i); + break; + } + } + if (!query) { + return; + } + + let trimmedQuotes = false; // special case for "Completes Paths In Strings" test case if (query.startsWith('"') || query.startsWith("'")) { query = query.substring(1); + trimmedQuotes = true; } if (query.endsWith('"') || query.endsWith("'")) { query = query.substring(0, -1); + trimmedQuotes = true; + } + if (this.settings.preFilterMatches || trimmedQuotes) { + this.query = query; } - this.query = query; } } @@ -97,6 +124,20 @@ export class GenericCompleterModel< return index > -1 ? item.label.substring(0, index) : item.label; } + createPatch(patch: string) { + if (this.subsetMatch) { + // Prevent insertion code path when auto-populating subset on tab, to avoid problems with + // prefix which is a subset of token incorrectly replacing a string with file system path. + // - Q: Which code path is being blocked? + // A: The code path (b) discussed in https://github.com/jupyterlab/jupyterlab/issues/15130. + // - Q: Why are we short- circuiting here? + // A: we want to prevent `onCompletionSelected()` from proceeding with text insertion, + // but direct extension of Completer handler is difficult. + return undefined; + } + return super.createPatch(patch); + } + private _sortAndFilter(query: string, items: T[]): T[] { let results: ICompletionMatch[] = []; @@ -178,7 +219,7 @@ export class GenericCompleterModel< } } - results.sort(this.compareMatches); + results.sort(this.compareMatches.bind(this)); return results.map(x => x.item); } @@ -206,14 +247,19 @@ export namespace GenericCompleterModel { */ includePerfectMatches?: boolean; /** - * Wheteher matches should be pre-filtered (default = true) + * Whether matches should be pre-filtered (default = true) */ preFilterMatches?: boolean; + /** + * Whether kernel completions should be shown first. + */ + kernelCompletionsFirst?: boolean; } export const defaultOptions: IOptions = { caseSensitive: true, includePerfectMatches: true, - preFilterMatches: true + preFilterMatches: true, + kernelCompletionsFirst: false }; } @@ -230,7 +276,10 @@ export class LSPCompleterModel extends GenericCompleterModel, b: ICompletionMatch ): number { - const delta = a.score - b.score; - if (delta !== 0) { - return delta; - } - // solve ties using sortText - - // note: locale compare is case-insensitive - return (a.item.sortText ?? 'z').localeCompare(b.item.sortText ?? 'z'); + // TODO: take source order from provider ranks, upstream this code + const sourceOrder = { + LSP: 1, + kernel: this.settings.kernelCompletionsFirst ? 0 : 2, + context: 3 + }; + const aRank = a.item.source + ? sourceOrder[a.item.source as keyof typeof sourceOrder] ?? 4 + : 4; + const bRank = b.item.source + ? sourceOrder[b.item.source as keyof typeof sourceOrder] ?? 4 + : 4; + return ( + aRank - bRank || + (a.item.sortText ?? 'z').localeCompare(b.item.sortText ?? 'z') || + a.score - b.score + ); } } diff --git a/packages/jupyterlab-lsp/src/features/completion/overrides.ts b/packages/jupyterlab-lsp/src/features/completion/overrides.ts index 42fe44ad9..d1a267c42 100644 --- a/packages/jupyterlab-lsp/src/features/completion/overrides.ts +++ b/packages/jupyterlab-lsp/src/features/completion/overrides.ts @@ -36,21 +36,17 @@ export class EnhancedContextCompleterProvider extends ContextCompleterProvider { super(); } - private get _kernelCompletionsFirst(): boolean { - return this.options.settings.composite.kernelCompletionsFirst; - } - async fetch( request: CompletionHandler.IRequest, context: ICompletionContext ): Promise { const result = await super.fetch(request, context); - result.items = result.items.map(i => { + result.items = result.items.map((item, order) => { return { - ...i, - icon: this.iconFor(i.type ?? 'Text') ?? this.iconFor('Text'), - type: i.type === '' ? undefined : (i.type as string), - sortText: this._kernelCompletionsFirst ? 'a' : 'z', + ...item, + icon: this.iconFor(item.type ?? 'Text') ?? this.iconFor('Text'), + type: item.type === '' ? undefined : (item.type as string), + sortText: String.fromCharCode(order), source: this.label }; }); @@ -75,11 +71,11 @@ export class EnhancedKernelCompleterProvider extends KernelCompleterProvider { context: ICompletionContext ): Promise { const result = await super.fetch(request, context); - result.items = result.items.map(i => { + result.items = result.items.map((item, order) => { return { - ...i, - icon: this.iconFor(i.type ?? KernelKind) ?? this.iconFor(KernelKind), - sortText: 'z', + ...item, + icon: this.iconFor(item.type ?? KernelKind) ?? this.iconFor(KernelKind), + sortText: String.fromCharCode(order), source: this.label }; }); @@ -88,7 +84,7 @@ export class EnhancedKernelCompleterProvider extends KernelCompleterProvider { async isApplicable(context: ICompletionContext): Promise { // Note: this method logs errors instead of throwing to ensure we do not ever - // break the upstream kernel completer, even if there is an error elsehwere. + // break the upstream kernel completer, even if there is an error elsewhere. const upstream = await super.isApplicable(context); if (upstream === false) { diff --git a/packages/jupyterlab-lsp/src/features/completion/provider.ts b/packages/jupyterlab-lsp/src/features/completion/provider.ts index dbd136fcc..6ecc90863 100644 --- a/packages/jupyterlab-lsp/src/features/completion/provider.ts +++ b/packages/jupyterlab-lsp/src/features/completion/provider.ts @@ -42,6 +42,7 @@ interface IOptions { export class CompletionProvider implements ICompletionProvider { readonly identifier = 'lsp'; readonly label = 'LSP'; + readonly rank = 1000; protected console = new BrowserConsole().scope('Completion provider'); constructor(protected options: IOptions) { @@ -65,13 +66,15 @@ export class CompletionProvider implements ICompletionProvider { const model = new LSPCompleterModel({ caseSensitive: composite.caseSensitive, preFilterMatches: composite.preFilterMatches, - includePerfectMatches: composite.includePerfectMatches + includePerfectMatches: composite.includePerfectMatches, + kernelCompletionsFirst: composite.kernelCompletionsFirst }); this.options.settings.changed.connect(() => { const composite = this.options.settings.composite; model.settings.caseSensitive = composite.caseSensitive; model.settings.preFilterMatches = composite.preFilterMatches; model.settings.includePerfectMatches = composite.includePerfectMatches; + model.settings.kernelCompletionsFirst = composite.kernelCompletionsFirst; }); return model; }; @@ -213,9 +216,9 @@ export class CompletionProvider implements ICompletionProvider { editor.getPositionAt(request.offset)! ) as IEditorPosition; const token = editor.getTokenAt(request.offset); - const positionInToken = token.offset - request.offset; + const positionInToken = request.offset - token.offset; // TODO: (typedCharacter can serve as a proxy for triggerCharacter) - const typedCharacter = token.value[positionInToken + 1]; + const typedCharacter = token.value[positionInToken - 1]; // TODO: direct mapping // because we need editorAccessor, not the editor itself we perform this rather sad dance: @@ -296,20 +299,22 @@ export class CompletionProvider implements ICompletionProvider { if (this.options.settings.composite.disable) { return false; } - /* - // Disabled due to the result being effectively cached until user changes - // cells which can lead to bad UX; upstream issue: - // https://github.com/jupyterlab/jupyterlab/issues/15016 const manager = this.options.connectionManager; const widget = context.widget as IDocumentWidget; const adapter = manager.adapters.get(widget.context.path); if (!adapter) { return false; } - */ return true; } } + +function stripQuotes(path: string): string { + return path.slice( + path.startsWith("'") || path.startsWith('"') ? 1 : 0, + path.endsWith("'") || path.endsWith('"') ? -1 : path.length + ); +} export function transformLSPCompletions( token: CodeEditor.IToken, positionInToken: number, @@ -317,47 +322,67 @@ export function transformLSPCompletions( createCompletionItem: (kind: string, match: lsProtocol.CompletionItem) => T, console: ILSPLogConsole ) { - let prefix = token.value.slice(0, positionInToken + 1); - let allNonPrefixed = true; + let prefix = token.value.slice(0, positionInToken); + let suffix = token.value.slice(positionInToken, token.value.length); let items: T[] = []; + // If there are no prefixes, we will just insert the text without replacing the token, + // which is the case for example in R for `stats::` which returns module members + // without `::` prefix. + // If there are prefixes, we will replace the token so we may need to prepend/append to, + // or otherwise modify the insert text of individual completion items. + let anyPrefixed = false; + lspCompletionItems.forEach(match => { let kind = match.kind ? CompletionItemKind[match.kind] : ''; - // Update prefix values let text = match.insertText ? match.insertText : match.label; + let intendedText = match.insertText ? match.insertText : match.label; - // declare prefix presence if needed and update it - if (text.toLowerCase().startsWith(prefix.toLowerCase())) { - allNonPrefixed = false; - if (prefix !== token.value) { - if (text.toLowerCase().startsWith(token.value.toLowerCase())) { - // given a completion insert text "display_table" and two test cases: - // dispdata → display_tabledata - // display → display_table - // we have to adjust the prefix for the latter (otherwise we would get display_tablelay), - // as we are constrained NOT to replace after the prefix (which would be "disp" otherwise) - prefix = token.value; - } + if (intendedText.toLowerCase().startsWith(prefix.toLowerCase())) { + anyPrefixed = true; + } + + // Add overlap with token prefix + if (intendedText.startsWith(token.value)) { + anyPrefixed = true; + // remove overlap with prefix before expanding it + if (intendedText.startsWith(prefix)) { + text = text.substring(prefix.length, text.length); + match.insertText = text; } + text = token.value + text; + match.insertText = text; } - // add prefix if needed - else if (token.type === 'string' && prefix.includes('/')) { - // special case for path completion in strings, ensuring that: - // '/Com → '/Completion.ipynb - // when the returned insert text is `Completion.ipynb` (the token here is `'/Com`) - // developed against pyls and pylsp server, may not work well in other cases - const parts = prefix.split('/'); + + // special handling for paths + if (token.type === 'String' && prefix.includes('/')) { + const parts = stripQuotes(prefix).split('/'); if ( text.toLowerCase().startsWith(parts[parts.length - 1].toLowerCase()) ) { let pathPrefix = parts.slice(0, -1).join('/') + '/'; - match.insertText = pathPrefix + text; - // for label removing the prefix quote if present - if (pathPrefix.startsWith("'") || pathPrefix.startsWith('"')) { - pathPrefix = pathPrefix.substr(1); - } + text = + (prefix.startsWith("'") || prefix.startsWith('"') ? prefix[0] : '') + + pathPrefix + + text + + (suffix.startsWith("'") || suffix.startsWith('"') ? suffix[0] : ''); + match.insertText = text; + // for label without quotes match.label = pathPrefix + match.label; - allNonPrefixed = false; + anyPrefixed = true; + } + } else { + // harmonise end to token + if (text.toLowerCase().endsWith(suffix.toLowerCase())) { + text = text.substring(0, text.length - suffix.length); + match.insertText = text; + } else if (token.type === 'String') { + // special case for completion in strings to preserve the closing quote; + // there is an issue that this gives opposing results in Notebook vs File editor + // probably due to reconciliator logic + if (suffix.startsWith("'") || suffix.startsWith('"')) { + match.insertText = text + suffix[0]; + } } } @@ -366,29 +391,17 @@ export function transformLSPCompletions( items.push(completionItem); }); console.debug('Transformed'); - // required to make the repetitive trigger characters like :: or ::: work for R with R languageserver, - // see https://github.com/jupyter-lsp/jupyterlab-lsp/issues/436 - let prefixOffset = token.value.length; - // completion of dictionaries for Python with jedi-language-server was - // causing an issue for dic[''] case; to avoid this let's make - // sure that prefix.length >= prefix.offset - if (allNonPrefixed && prefixOffset > prefix.length) { - prefixOffset = prefix.length; + + let start = token.offset; + let end = token.offset + token.value.length; + if (!anyPrefixed) { + start = end; } let response = { - // note in the ContextCompleter it was: - // start: token.offset, - // end: token.offset + token.value.length, - // which does not work with "from statistics import " as the last token ends at "t" of "import", - // so the completer would append "mean" as "from statistics importmean" (without space!); - // (in such a case the typedCharacters is undefined as we are out of range) - // a different workaround would be to prepend the token.value prefix: - // text = token.value + text; - // but it did not work for "from statistics " and lead to "from statisticsimport" (no space) - start: token.offset + (allNonPrefixed ? prefixOffset : 0), - end: token.offset + prefix.length, - items: items, + start, + end, + items, source: 'LSP' }; if (response.start > response.end) { diff --git a/packages/jupyterlab-lsp/src/features/completion/renderer.ts b/packages/jupyterlab-lsp/src/features/completion/renderer.ts index 204be004e..358e41407 100644 --- a/packages/jupyterlab-lsp/src/features/completion/renderer.ts +++ b/packages/jupyterlab-lsp/src/features/completion/renderer.ts @@ -3,7 +3,6 @@ import { Completer } from '@jupyterlab/completer'; import { IRenderMime } from '@jupyterlab/rendermime'; -import { Signal } from '@lumino/signaling'; import { CodeCompletion as LSPCompletionSettings } from '../../_completion'; import { FeatureSettings } from '../../feature'; @@ -20,15 +19,10 @@ export class LSPCompletionRenderer extends Completer.Renderer implements Completer.IRenderer { - // signals - public activeChanged: Signal; - public itemShown: Signal; // observers private visibilityObserver: IntersectionObserver; - private activityObserver: MutationObserver; // element data maps (with weak references for better GC) private elementToItem: WeakMap; - private wasActivated: WeakMap; protected ITEM_PLACEHOLDER_CLASS = 'lsp-detail-placeholder'; protected EXTRA_INFO_CLASS = 'jp-Completer-typeExtended'; @@ -36,10 +30,7 @@ export class LSPCompletionRenderer constructor(protected options: LSPCompletionRenderer.IOptions) { super(); - this.activeChanged = new Signal(this); - this.itemShown = new Signal(this); this.elementToItem = new WeakMap(); - this.wasActivated = new WeakMap(); this.visibilityObserver = new IntersectionObserver( entries => { @@ -49,41 +40,13 @@ export class LSPCompletionRenderer } let li = entry.target as HTMLLIElement; let item = this.elementToItem.get(li)!; - this.itemShown.emit({ - item: item, - element: li - }); + item.resolve().catch(console.error); }); }, { threshold: 0.25 } ); - - // note: there should be no need to unobserve deleted elements as per: - // https://stackoverflow.com/a/51106262/6646912 - this.activityObserver = new MutationObserver(mutations => { - mutations.forEach(mutation => { - let li = mutation.target; - if (!(li instanceof HTMLLIElement)) { - return; - } - let inactive = !this.wasActivated.get(li); - - if (li.classList.contains('jp-mod-active')) { - if (inactive) { - this.wasActivated.set(li, true); - let item = this.elementToItem.get(li)!; - this.activeChanged.emit({ - item: item, - element: li - }); - } - } else { - this.wasActivated.set(li, false); - } - }); - }); } protected getExtraInfo(item: CompletionItem): string { @@ -132,10 +95,6 @@ export class LSPCompletionRenderer if (lspItem) { lspItem.element = li; this.elementToItem.set(li, lspItem); - this.activityObserver.observe(li, { - attributes: true, - attributeFilter: ['class'] - }); this.visibilityObserver.observe(li); // TODO: build custom li from ground up this.updateExtraInfo(lspItem, li); @@ -161,14 +120,14 @@ export class LSPCompletionRenderer const originalHTMLLabel = labelElement.childNodes; let hasMark = false; for (const node of originalHTMLLabel) { - if (node.nodeType === Node.ELEMENT_NODE) { - const element = node as Element; + if (node instanceof HTMLElement) { + const element = node as HTMLElement; const text = element.textContent; - if (element.tagName === 'MARK' && text) { + if (element.tagName === 'MARK' && text && text.length > 3) { const elidableElement = document.createElement('bdo'); elidableElement.setAttribute('dir', 'ltr'); elidableElement.textContent = text; - elidableElement.title = text; + element.title = text; element.replaceChildren(elidableElement); element.classList.add('lsp-elide'); hasMark = true; @@ -213,6 +172,9 @@ export class LSPCompletionRenderer }) .catch(this.options.console.warn); return this.options.markdownRenderer.node; + } else if (item.source != 'LSP') { + // fallback to default implementation for non-LSP completions + return super.createDocumentationNode(item); } else { let node = document.createElement('pre'); if (item.documentation) { @@ -223,7 +185,7 @@ export class LSPCompletionRenderer } itemWidthHeuristic(item: CompletionItem): number { - const labelSize = item.label.replace(/<\?mark>/g, '').length; + const labelSize = item.label.replace(/<(\/)?mark>/g, '').length; const extraTextSize = this.getExtraInfo(item).length; if (this.options.settings.composite.layout === 'side-by-side') { // in 'side-by-side' take the sum diff --git a/packages/jupyterlab-lsp/src/features/diagnostics/feature.ts b/packages/jupyterlab-lsp/src/features/diagnostics/feature.ts index 8a36c2418..fa102f6eb 100644 --- a/packages/jupyterlab-lsp/src/features/diagnostics/feature.ts +++ b/packages/jupyterlab-lsp/src/features/diagnostics/feature.ts @@ -18,6 +18,7 @@ import { } from '@jupyterlab/lsp'; import { TranslationBundle } from '@jupyterlab/translation'; import { PromiseDelegate } from '@lumino/coreutils'; +import { StyleModule } from 'style-mod'; import * as lsProtocol from 'vscode-languageserver-protocol'; import { CodeDiagnostics as LSPDiagnosticsSettings } from '../../_diagnostics'; @@ -56,7 +57,6 @@ export class DiagnosticsFeature extends Feature implements IDiagnosticsFeature { }; protected settings: IFeatureSettings; protected console = new BrowserConsole().scope('Diagnostics'); - private _responseReceived: PromiseDelegate = new PromiseDelegate(); private _firstResponseReceived: PromiseDelegate = new PromiseDelegate(); private _diagnosticsDatabases = new WeakMap< WidgetLSPAdapter, @@ -101,12 +101,38 @@ export class DiagnosticsFeature extends Feature implements IDiagnosticsFeature { const connectionManager = options.connectionManager; // https://github.com/jupyterlab/jupyterlab/issues/14783 options.shell.currentChanged.connect(shell => { + if (shell.currentWidget == diagnosticsPanel.widget) { + // allow focusing on the panel + return; + } + const adapter = [...connectionManager.adapters.values()].find( adapter => adapter.widget == shell.currentWidget ); if (!adapter) { - this.console.debug('No adapter'); + this.switchDiagnosticsPanelSource(null); + // this dance should not be needed once https://github.com/jupyterlab/jupyterlab/pull/14920 is in, + // but we will need to continue listening to `currentChanged` signal anyways to make sure we show + // empty indicator in launcher or other widget which does not support linting. + let attemptsLeft = 3; + const retry = () => { + const adapter = [...connectionManager.adapters.values()].find( + adapter => adapter.widget == shell.currentWidget + ); + attemptsLeft -= 1; + if (adapter) { + this.switchDiagnosticsPanelSource(adapter); + attemptsLeft = 0; + } + if (attemptsLeft == 0) { + connectionManager.connected.disconnect(retry); + } + }; + connectionManager.connected.connect(retry); + this.console.debug( + 'No adapter (yet?), will retry on next connected document' + ); } else { this.switchDiagnosticsPanelSource(adapter); } @@ -151,13 +177,12 @@ export class DiagnosticsFeature extends Feature implements IDiagnosticsFeature { // do not wait for next update, show what we already know. // TODO: this still fails when scrolling down fast and then - // scrolling up to the skipped cells because the state invlidation + // scrolling up to the skipped cells because the state invalidation // counter kicks in but diagnostics does not get rendered yet before // we leave.. await this._firstResponseReceived.promise; } else { await adapter.updateFinished; - await this._responseReceived.promise; } const database = this.getDiagnosticsDB(adapter); @@ -242,29 +267,29 @@ export class DiagnosticsFeature extends Feature implements IDiagnosticsFeature { private _reconfigureTheme() { const style = getComputedStyle(document.body); - const baseTheme = EditorView.baseTheme({ - '.cm-lintRange-error': { + const lintTheme = new StyleModule({ + '.cm-editor .cm-lintRange-error': { backgroundImage: underline( style.getPropertyValue( '--jp-editor-mirror-lsp-diagnostic-error-decoration-color' ) ) }, - '.cm-lintRange-warning': { + '.cm-editor .cm-lintRange-warning': { backgroundImage: underline( style.getPropertyValue( '--jp-editor-mirror-lsp-diagnostic-warning-decoration-color' ) ) }, - '.cm-lintRange-info': { + '.cm-editor .cm-lintRange-info': { backgroundImage: underline( style.getPropertyValue( '--jp-editor-mirror-lsp-diagnostic-information-decoration-color' ) ) }, - '.cm-lintRange-hint': { + '.cm-editor .cm-lintRange-hint': { backgroundImage: underline( style.getPropertyValue( '--jp-editor-mirror-lsp-diagnostic-hint-decoration-color' @@ -272,13 +297,7 @@ export class DiagnosticsFeature extends Feature implements IDiagnosticsFeature { ) } }); - const tempEditor = new EditorView({ extensions: baseTheme }); - const styleModules = tempEditor.state.facet(EditorView.styleModule); - const ourRules = styleModules.find(styleModule => { - const rules = styleModule.getRules().split('\n'); - return rules.every(rule => rule.includes('cm-lintRange')); - })!; - this._styleElement.innerHTML = ourRules.getRules(); + this._styleElement.innerHTML = lintTheme.getRules(); } clearDocumentDiagnostics( @@ -305,16 +324,20 @@ export class DiagnosticsFeature extends Feature implements IDiagnosticsFeature { return this._diagnosticsDatabases.get(adapter)!; } - switchDiagnosticsPanelSource = (adapter: WidgetLSPAdapter) => { + switchDiagnosticsPanelSource = (adapter: WidgetLSPAdapter | null) => { diagnosticsPanel.trans = this._trans; - const diagnostics = this.getDiagnosticsDB(adapter); - if (diagnosticsPanel.content.model.diagnostics == diagnostics) { - return; + if (adapter !== null) { + const diagnostics = this.getDiagnosticsDB(adapter); + if (diagnosticsPanel.content.model.diagnostics == diagnostics) { + return; + } + diagnosticsPanel.content.model.diagnostics = diagnostics; + diagnosticsPanel.content.model.settings = this.settings; + diagnosticsPanel.feature = this; + } else { + diagnosticsPanel.content.model.diagnostics = null; } - diagnosticsPanel.content.model.diagnostics = diagnostics; diagnosticsPanel.content.model.adapter = adapter; - diagnosticsPanel.content.model.settings = this.settings; - diagnosticsPanel.feature = this; diagnosticsPanel.update(); }; @@ -568,8 +591,6 @@ export class DiagnosticsFeature extends Feature implements IDiagnosticsFeature { const done = new Promise(resolve => { setTimeout(() => { this._firstResponseReceived.resolve(); - this._responseReceived.resolve(); - this._responseReceived = new PromiseDelegate(); resolve(); }, 0); }); diff --git a/packages/jupyterlab-lsp/src/features/diagnostics/listing.tsx b/packages/jupyterlab-lsp/src/features/diagnostics/listing.tsx index 0cda4d357..651efc6aa 100644 --- a/packages/jupyterlab-lsp/src/features/diagnostics/listing.tsx +++ b/packages/jupyterlab-lsp/src/features/diagnostics/listing.tsx @@ -265,7 +265,10 @@ export class DiagnosticsListing extends VDomRenderer { if (diagnosticsDatabase == null || !adapter) { return (
- {this.trans.__('Diagnostics are not available')} +

No diagnostics

+ {this.trans.__( + 'Diagnostics panel shows linting results in notebooks and files connected to a language server.' + )}
); } diff --git a/packages/jupyterlab-lsp/src/features/highlights.ts b/packages/jupyterlab-lsp/src/features/highlights.ts index 558a083fc..66abc37df 100644 --- a/packages/jupyterlab-lsp/src/features/highlights.ts +++ b/packages/jupyterlab-lsp/src/features/highlights.ts @@ -14,8 +14,7 @@ import { ILSPFeatureManager, IEditorPosition, ILSPDocumentConnectionManager, - WidgetLSPAdapter, - VirtualDocument + WidgetLSPAdapter } from '@jupyterlab/lsp'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; import { LabIcon } from '@jupyterlab/ui-components'; @@ -37,6 +36,7 @@ import { DocumentHighlightKind } from '../lsp'; import { createMarkManager, ISimpleMarkManager } from '../marks'; import { PLUGIN_ID } from '../tokens'; import { BrowserConsole } from '../virtual/console'; +import { VirtualDocument } from '../virtual/document'; export const highlightIcon = new LabIcon({ name: 'lsp:highlight', @@ -70,7 +70,10 @@ export class HighlightsFeature extends Feature { >; private _virtualPosition: IVirtualPosition; private _versionSent: number; - private _lastToken: CodeEditor.IToken | null = null; + private _lastToken: { + token: CodeEditor.IToken; + adapter: WidgetLSPAdapter; + } | null = null; constructor(options: HighlightsFeature.IOptions) { super(options); @@ -160,7 +163,8 @@ export class HighlightsFeature extends Feature { protected handleHighlight( items: lsProtocol.DocumentHighlight[] | null, - adapter: WidgetLSPAdapter + adapter: WidgetLSPAdapter, + document: VirtualDocument ) { this.markManager.clearAllMarks(); @@ -174,7 +178,7 @@ export class HighlightsFeature extends Feature { >(); for (let item of items) { - let range = rangeToEditorRange(adapter, item.range, null); + let range = rangeToEditorRange(adapter, item.range, null, document); const editor = range.editor; let optionsList = highlightsByEditor.get(editor); @@ -296,10 +300,12 @@ export class HighlightsFeature extends Feature { const token = editor.getTokenAt(offset); // if token has not changed, no need to update highlight, unless it is an empty token - // which would indicate that the cursor is at the first character + // which would indicate that the cursor is at the first character; we also need to check + // adapter in case if user switched between documents/notebooks. if ( this._lastToken && - token.value === this._lastToken.value && + token.value === this._lastToken.token.value && + adapter === this._lastToken.adapter && token.value !== '' ) { this.console.log( @@ -350,8 +356,11 @@ export class HighlightsFeature extends Feature { return; } - this.handleHighlight(highlights, adapter); - this._lastToken = token; + this.handleHighlight(highlights, adapter, document); + this._lastToken = { + token, + adapter + }; } catch (e) { this.console.warn('Could not get highlights:', e); } diff --git a/packages/jupyterlab-lsp/src/features/hover.ts b/packages/jupyterlab-lsp/src/features/hover.ts index 86f205d52..bc223688d 100644 --- a/packages/jupyterlab-lsp/src/features/hover.ts +++ b/packages/jupyterlab-lsp/src/features/hover.ts @@ -18,7 +18,6 @@ import { isEqual, ILSPDocumentConnectionManager, WidgetLSPAdapter, - VirtualDocument, Document } from '@jupyterlab/lsp'; import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; @@ -45,6 +44,7 @@ import { createMarkManager, ISimpleMarkManager } from '../marks'; import { PLUGIN_ID } from '../tokens'; import { getModifierState } from '../utils'; import { BrowserConsole } from '../virtual/console'; +import { VirtualDocument } from '../virtual/document'; export const hoverIcon = new LabIcon({ name: 'lsp:hover', @@ -365,7 +365,8 @@ export class HoverFeature extends Feature { context.adapter, response, context.token, - context.editor + context.editor, + virtualDocument ); return this._addRange( context.adapter, @@ -619,7 +620,8 @@ export class HoverFeature extends Feature { adapter, response, token, - editor + editor, + document ); responseData = { response: response, @@ -689,10 +691,11 @@ export class HoverFeature extends Feature { adapter: WidgetLSPAdapter, response: lsProtocol.Hover, token: CodeEditor.IToken, - editor: CodeEditor.IEditor + editor: CodeEditor.IEditor, + document: VirtualDocument ): IEditorRange { if (typeof response.range !== 'undefined') { - return rangeToEditorRange(adapter, response.range, editor); + return rangeToEditorRange(adapter, response.range, editor, document); } const startInEditor = editor.getPositionAt(token.offset); diff --git a/packages/jupyterlab-lsp/src/features/jump_to.ts b/packages/jupyterlab-lsp/src/features/jump_to.ts index a143f0d02..2d9748de8 100644 --- a/packages/jupyterlab-lsp/src/features/jump_to.ts +++ b/packages/jupyterlab-lsp/src/features/jump_to.ts @@ -48,13 +48,13 @@ import { documentAtRootPosition, editorAtRootPosition, rootPositionToVirtualPosition, - rootPositionToEditorPosition, - virtualPositionToRootPosition + rootPositionToEditorPosition } from '../converter'; import { FeatureSettings, Feature } from '../feature'; import { PLUGIN_ID } from '../tokens'; import { getModifierState, uriToContentsPath, urisEqual } from '../utils'; import { BrowserConsole } from '../virtual/console'; +import { VirtualDocument } from '../virtual/document'; export const jumpToIcon = new LabIcon({ name: 'lsp:jump-to', @@ -245,7 +245,7 @@ export class NavigationFeature extends Feature { connection.clientRequests['textDocument/definition'] .request(positionParams) .then(targets => { - this.handleJump(targets, positionParams, adapter) + this.handleJump(targets, positionParams, adapter, document) .then((result: JumpResult | undefined) => { if ( result === JumpResult.NoTargetsFound || @@ -259,7 +259,7 @@ export class NavigationFeature extends Feature { }) .then(targets => // TODO: explain that we are now presenting references? - this.handleJump(targets, positionParams, adapter) + this.handleJump(targets, positionParams, adapter, document) ) .catch(this.console.warn); } @@ -312,7 +312,7 @@ export class NavigationFeature extends Feature { return path + ', line: ' + location.range.start.line; }); - // TODO: use selector with preview, basically needes the ui-component + // TODO: use selector with preview, basically needs the ui-component // from jupyterlab-citation-manager; let's try to move it to JupyterLab core // (and re-implement command palette with it) // the preview should use this.jumper.document_manager.services.contents @@ -361,7 +361,8 @@ export class NavigationFeature extends Feature { async handleJump( locationData: AnyLocation, positionParams: lsp.TextDocumentPositionParams, - adapter: WidgetLSPAdapter + adapter: WidgetLSPAdapter, + document: VirtualDocument ) { const locations = this._harmonizeLocations(locationData); const targetInfo = await this._chooseTarget(locations); @@ -382,10 +383,16 @@ export class NavigationFeature extends Feature { if (urisEqual(uri, positionParams.textDocument.uri)) { // if in current file, transform from the position within virtual document to the editor position: - const rootPosition = virtualPositionToRootPosition( - adapter, - virtualPosition - ); + + // because `openForeign()` does not use new this.constructor, we need to workaround it for now: + // const rootPosition = document.transformVirtualToRoot(virtualPosition); + // https://github.com/jupyterlab/jupyterlab/issues/15126 + const rootPosition = + VirtualDocument.prototype.transformVirtualToRoot.call( + document, + virtualPosition + ); + if (rootPosition === null) { this.console.warn( 'Could not jump: conversion from virtual position to editor position failed', @@ -581,7 +588,7 @@ export const JUMP_PLUGIN: JupyterFrontEndPlugin = { const targets = await connection.clientRequests[ 'textDocument/definition' ].request(positionParams); - await feature.handleJump(targets, positionParams, adapter); + await feature.handleJump(targets, positionParams, adapter, document); }, label: trans.__('Jump to definition'), icon: jumpToIcon, @@ -627,7 +634,7 @@ export const JUMP_PLUGIN: JupyterFrontEndPlugin = { ...positionParams, context: { includeDeclaration: false } }); - await feature.handleJump(targets, positionParams, adapter); + await feature.handleJump(targets, positionParams, adapter, document); }, label: trans.__('Jump to references'), icon: jumpToIcon, diff --git a/packages/jupyterlab-lsp/src/features/signature.ts b/packages/jupyterlab-lsp/src/features/signature.ts index c511fc9d7..e6084d042 100644 --- a/packages/jupyterlab-lsp/src/features/signature.ts +++ b/packages/jupyterlab-lsp/src/features/signature.ts @@ -193,7 +193,7 @@ export function highlightCode( language, (token: string, className: string, from: number, to: number) => { let populated = false; - // In CodeMirror6 variables are not necessairly tokenized, + // In CodeMirror6 variables are not necessarily tokenized, // we need to split them manually if (from <= end && start <= to) { const a = Math.max(start, from); @@ -313,7 +313,13 @@ export class SignatureFeature extends Feature { // TODO: the assumption that updated editor = active editor will fail on RTC. How to get `CodeEditor.IEditor` and `Document.IEditor` from `EditorView`? we got `CodeEditor.IModel` from `options.model` but may need more context here. const editorAccessor = adapter.activeEditor; - const editor = editorAccessor!.getEditor()!; + const editor = editorAccessor!.getEditor(); + + if (!editor) { + // see https://github.com/jupyter-lsp/jupyterlab-lsp/issues/984 + // TODO: should not be needed once https://github.com/jupyterlab/jupyterlab/pull/14920 is in + return; + } // TODO: or should it come from viewUpdate instead?! // especially on copy paste this can be problematic. @@ -326,13 +332,16 @@ export class SignatureFeature extends Feature { // Delay handling by moving on top of the stack // so that virtual document is updated. setTimeout(() => { + // be careful: updateListener also fires after blur, so we + // need to carefully check what changed to avoid invalidating + // user clicking on the hover box. if (viewUpdate.docChanged) { this.afterChange( viewUpdate.changes, adapter, editorPosition ).catch(this.console.warn); - } else { + } else if (viewUpdate.selectionSet) { this.onCursorActivity(adapter, editorPosition).catch( this.console.warn ); @@ -564,7 +573,7 @@ export class SignatureFeature extends Feature { response ); if (displayPosition === null) { - // try to find last occurrance of trigger character to position the tooltip + // try to find last occurrence of trigger character to position the tooltip const content = editor.model.sharedModel.getSource(); const lines = content.split('\n'); const offset = offsetAtPosition( @@ -595,7 +604,7 @@ export class SignatureFeature extends Feature { tooltip: { privilege: 'forceAbove', // do not move the tooltip to match the token to avoid drift of the - // tooltip due the simplicty of token matching rules; instead we keep + // tooltip due the simplicity of token matching rules; instead we keep // the position constant manually via `displayPosition`. alignment: undefined, hideOnKeyPress: false diff --git a/packages/jupyterlab-lsp/src/features/syntax_highlighting.ts b/packages/jupyterlab-lsp/src/features/syntax_highlighting.ts index fc3bad706..bbba89d87 100644 --- a/packages/jupyterlab-lsp/src/features/syntax_highlighting.ts +++ b/packages/jupyterlab-lsp/src/features/syntax_highlighting.ts @@ -138,6 +138,12 @@ export class SyntaxHighlightingFeature extends Feature { return; } + if (Array.isArray(mimetype)) { + // Contrarily to what types say, mimetype can be an array. + // https://github.com/jupyterlab/jupyterlab/issues/15100 + return mimetype[0]; + } + return mimetype; } diff --git a/packages/jupyterlab-lsp/src/index.ts b/packages/jupyterlab-lsp/src/index.ts index 51e482ab4..f004be14d 100644 --- a/packages/jupyterlab-lsp/src/index.ts +++ b/packages/jupyterlab-lsp/src/index.ts @@ -156,13 +156,16 @@ export class LSPExtension { {}) as TLanguageServerConfigurations; // Add `configuration` as a copy of `serverSettings` to work with changed name upstream + // Add `rank` as a copy of priority for the same reason. languageServerSettings = Object.fromEntries( Object.entries(languageServerSettings).map(([key, value]) => { value.configuration = value.serverSettings; + value.rank = value.priority; return [key, value]; }) ); + const previousInitialConfig = this._connectionManager.initialConfigurations; this._connectionManager.initialConfigurations = languageServerSettings; // TODO: if priorities changed reset connections @@ -170,6 +173,26 @@ export class LSPExtension { this.connectionManager.updateConfiguration(languageServerSettings); if (afterInitialization) { this.connectionManager.updateServerConfigurations(languageServerSettings); + } else { + // This would not be needed if we controlled the connection manager, but because + // it is now an independent plugin it may have started and finished initialization + // earlier, so it potentially sent wrong `initialConfigurations` and we have no way + // to avoid this, so we need to send a reconfiguration request instead. + // + // TODO: this is comparing objects which is always false, + // we should have a proper comparison to avoid redundant calls, + // but in practice because upstream never populates defaults and + // we always do, this means it would be false anyways, + // so for now the comparison serves more as a comment than logic. + if (previousInitialConfig != languageServerSettings) { + this.connectionManager.ready + .then(() => { + this.connectionManager.updateServerConfigurations( + languageServerSettings + ); + }) + .catch(console.error); + } } this._connectionManager.updateLogging( options.logAllCommunication, diff --git a/packages/jupyterlab-lsp/src/settings.ts b/packages/jupyterlab-lsp/src/settings.ts index 4f382ad5b..6da7ba0c2 100644 --- a/packages/jupyterlab-lsp/src/settings.ts +++ b/packages/jupyterlab-lsp/src/settings.ts @@ -8,7 +8,8 @@ import { TranslationBundle } from '@jupyterlab/translation'; import { JSONExt, ReadonlyPartialJSONObject, - ReadonlyJSONObject + ReadonlyJSONObject, + PromiseDelegate } from '@lumino/coreutils'; import { Signal, ISignal } from '@lumino/signaling'; import { FieldProps } from '@rjsf/utils'; @@ -77,9 +78,9 @@ interface IValidationData { } /** - * Conflicts encounteredn when dot-collapsing settings + * Conflicts encountered when dot-collapsing settings * organised by server ID, and then as a mapping between - * (dotted) setting ID and list of encoutnered values. + * (dotted) setting ID and list of encountered values. * The last encountered values is preferred for use. */ type SettingsMergeConflicts = Record>; @@ -145,18 +146,9 @@ export class SettingsSchemaManager { this._lastValidation = null; this._lastUserServerSettings = null; this._lastUserServerSettingsDoted = null; - this._defaultsPopulated = this._createDefaultsPromise(); this._validationErrors = []; } - private _defaultsPopulated: Promise; - private _populatedAccept: (value: unknown) => void; - private _createDefaultsPromise(): Promise { - return new Promise(accept => { - this._populatedAccept = accept; - }); - } - get schemaValidated(): ISignal< SettingsSchemaManager, ISchemaValidator.IError[] @@ -175,6 +167,9 @@ export class SettingsSchemaManager { */ async setupSchemaTransform(pluginId: string): Promise { const languageServerManager = this.options.languageServerManager; + // To populate defaults we require specs to be available, so we need to + // wait for until after the `languageServerManager` is ready. + await languageServerManager.ready; // Transform the plugin object to return different schema than the default. this.options.settingRegistry.transform(pluginId, { @@ -187,7 +182,7 @@ export class SettingsSchemaManager { // 1.8% spent on `deepCopy()` // 1.79% spend on other tasks in `populate()` // There is a limit on the transformation time, and failing to transform - // in the default 1 second means that no settigns whatsoever are available. + // in the default 1 second means that no settings whatsoever are available. // Therefore validation in `populate()` was moved into an async function; // this means that we need to trigger re-load of settings // if there validation errors. @@ -200,7 +195,7 @@ export class SettingsSchemaManager { if (!this._canonical) { this._canonical = JSONExt.deepCopy(plugin.schema); this._populate(plugin, this._canonical); - this._populatedAccept(void 0); + this._defaultsPopulated.resolve(void 0); } return { @@ -219,7 +214,7 @@ export class SettingsSchemaManager { // race condition, see https://github.com/jupyterlab/jupyterlab/issues/12978 languageServerManager.sessionsChanged.connect(async () => { this._canonical = null; - this._defaultsPopulated = this._createDefaultsPromise(); + this._defaultsPopulated = new PromiseDelegate(); await this.options.settingRegistry.reload(pluginId); }); } @@ -272,7 +267,7 @@ export class SettingsSchemaManager { } if (!configSchema.properties) { this.console.warn( - 'No properites in config schema - skipping transformation for', + 'No properties in config schema - skipping transformation for', serverKey ); continue; @@ -333,7 +328,7 @@ export class SettingsSchemaManager { configSchema.properties[key].default = value; } } - // add server-speficic default overrides from overrides.json (and pre-defined in schema) + // add server-specific default overrides from overrides.json (and pre-defined in schema) const serverDefaultsOverrides = defaultsOverrides && defaultsOverrides.hasOwnProperty(serverKey) ? defaultsOverrides[serverKey] @@ -373,10 +368,13 @@ export class SettingsSchemaManager { this._defaults = defaults; } + /** + * Normalize settings by dotted and nested specs, and merging with defaults. + */ async normalizeSettings( composite: Required ): Promise> { - await this._defaultsPopulated; + await this._defaultsPopulated.promise; // Cache collapsed settings for speed and to only show dialog once. // Note that JupyterLab attempts to transform in "preload" step (before splash screen end) // and then again for deferred extensions if the initial transform in preload timed out. @@ -449,7 +447,7 @@ export class SettingsSchemaManager { /** * Validate user settings from plugin against provided schema, * asynchronously to avoid blocking the main thread. - * Stores validation reult in `this._validationErrors`. + * Stores validation result in `this._validationErrors`. */ private async _validateSchemaLater( plugin: ISettingRegistry.IPlugin, @@ -583,6 +581,7 @@ export class SettingsSchemaManager { } private _defaults: LanguageServerSettings; + private _defaultsPopulated = new PromiseDelegate(); private _validationErrors: ISchemaValidator.IError[]; private _schemaValidated: Signal< SettingsSchemaManager, diff --git a/packages/jupyterlab-lsp/src/virtual/document.ts b/packages/jupyterlab-lsp/src/virtual/document.ts index f42ddae55..29f8e643d 100644 --- a/packages/jupyterlab-lsp/src/virtual/document.ts +++ b/packages/jupyterlab-lsp/src/virtual/document.ts @@ -141,15 +141,53 @@ export class VirtualDocument extends VirtualDocumentBase { this.lastSourceLine += sourceCellLines.length; } + /** + * Close all expired documents. + */ + closeExpiredDocuments(): void { + // TODO: remove once https://github.com/jupyterlab/jupyterlab/pull/15105 is in + const usedDocuments = new Set(); + for (const line of this.sourceLines.values()) { + for (const block of line.foreignDocumentsMap.values()) { + usedDocuments.add(block.virtualDocument as VirtualDocument); + } + } + + const documentIDs = new Map(); + for (const [id, document] of ( + this.foreignDocuments as Map + ).entries()) { + const ids = documentIDs.get(document); + if (typeof ids !== 'undefined') { + documentIDs.set(document, [...ids, id]); + } + documentIDs.set(document, [id]); + } + const allDocuments = new Set(documentIDs.keys()); + const unusedVirtualDocuments = new Set( + [...allDocuments].filter(x => !usedDocuments.has(x)) + ); + + for (let document of unusedVirtualDocuments.values()) { + document.remainingLifetime -= 1; + if (document.remainingLifetime <= 0) { + document.dispose(); + const ids = documentIDs.get(document)!; + for (const id of ids) { + this.foreignDocuments.delete(id); + } + } + } + } + /** * @experimental */ transformVirtualToRoot(position: IVirtualPosition): IRootPosition | null { - // a method which was previously implemented in CodeMirrorIntegration - // but probably should have been in VirtualDocument all along let editor = this.virtualLines.get(position.line)!.editor; let editorPosition = this.transformVirtualToEditor(position); - return this.transformFromEditorToRoot(editor, editorPosition!); + // only root holds the full editor mapping + return this.root.transformFromEditorToRoot(editor, editorPosition!); } /** diff --git a/packages/jupyterlab-lsp/style/diagnostics_listing.css b/packages/jupyterlab-lsp/style/diagnostics_listing.css index 841fb5410..ddc46e19d 100644 --- a/packages/jupyterlab-lsp/style/diagnostics_listing.css +++ b/packages/jupyterlab-lsp/style/diagnostics_listing.css @@ -2,6 +2,16 @@ overflow-y: auto; } +.lsp-diagnostics-placeholder { + padding: 8px; + color: var(--jp-content-font-color2); + text-align: center; +} + +.lsp-diagnostics-placeholder > h3 { + margin-bottom: var(--jp-content-heading-margin-bottom); +} + .lsp-diagnostics-listing { color: var(--jp-ui-font-color1); background: var(--jp-layout-color1); diff --git a/packages/metapackage/package.json b/packages/metapackage/package.json index 4a94698ac..520219f66 100644 --- a/packages/metapackage/package.json +++ b/packages/metapackage/package.json @@ -1,6 +1,6 @@ { "name": "@jupyter-lsp/jupyterlab-lsp-metapackage", - "version": "5.0.0-beta.1", + "version": "5.0.0-rc.0", "description": "JupyterLab LSP - Meta Package. All of the packages used by JupyterLab LSP", "homepage": "https://github.com/jupyter-lsp/jupyterlab-lsp", "bugs": { diff --git a/packages/theme-material/package.json b/packages/theme-material/package.json index cc448da90..15413edee 100644 --- a/packages/theme-material/package.json +++ b/packages/theme-material/package.json @@ -1,6 +1,6 @@ { "name": "@jupyter-lsp/theme-material", - "version": "2.1.1", + "version": "3.0.0-rc.0", "description": "Material theme for JupyterLab-LSP", "keywords": [ "jupyter", @@ -34,7 +34,7 @@ "clean": "rimraf lib" }, "dependencies": { - "@jupyter-lsp/completion-theme": "^3.0.0" + "@jupyter-lsp/completion-theme": "^4.0.0-rc.0" }, "jupyterlab": { "extension": true, diff --git a/packages/theme-vscode/package.json b/packages/theme-vscode/package.json index 613f48437..f12d713a2 100644 --- a/packages/theme-vscode/package.json +++ b/packages/theme-vscode/package.json @@ -1,6 +1,6 @@ { "name": "@jupyter-lsp/theme-vscode", - "version": "2.1.1", + "version": "3.0.0-rc.0", "description": "VSCode theme for JupyterLab-LSP", "keywords": [ "jupyter", @@ -34,7 +34,7 @@ "clean": "rimraf lib" }, "dependencies": { - "@jupyter-lsp/completion-theme": "^3.0.0" + "@jupyter-lsp/completion-theme": "^4.0.0-rc.0" }, "jupyterlab": { "extension": true, diff --git a/python_packages/jupyter_lsp/jupyter_lsp/handlers.py b/python_packages/jupyter_lsp/jupyter_lsp/handlers.py index a7312f4a4..704852916 100644 --- a/python_packages/jupyter_lsp/jupyter_lsp/handlers.py +++ b/python_packages/jupyter_lsp/jupyter_lsp/handlers.py @@ -23,7 +23,7 @@ class LanguageServerWebSocketHandler( # type: ignore ): """Setup tornado websocket to route to language server sessions""" - language_server = None # type: Optional[Text] + language_server: Optional[Text] = None async def open(self, language_server): await self.manager.ready() diff --git a/python_packages/jupyter_lsp/jupyter_lsp/manager.py b/python_packages/jupyter_lsp/jupyter_lsp/manager.py index 28e05eb05..c847e8c4d 100644 --- a/python_packages/jupyter_lsp/jupyter_lsp/manager.py +++ b/python_packages/jupyter_lsp/jupyter_lsp/manager.py @@ -61,17 +61,17 @@ class LanguageServerManager(LanguageServerManagerAPI): config=True ) # type: KeyedLanguageServerSpecs - autodetect = Bool( + autodetect: bool = Bool( # type:ignore[assignment] True, help=_("try to find known language servers in sys.prefix (and elsewhere)") ).tag( config=True - ) # type: bool + ) - sessions = Dict_( # type:ignore[assignment] + sessions: Dict[Tuple[Text], LanguageServerSession] = Dict_( # type:ignore[assignment] trait=Instance(LanguageServerSession), default_value={}, help="sessions keyed by language server name", - ) # type: Dict[Tuple[Text], LanguageServerSession] + ) virtual_documents_dir = Unicode( help="""Path to virtual documents relative to the content manager root @@ -99,8 +99,8 @@ def _default_virtual_documents_dir(self): return os.getenv("JP_LSP_VIRTUAL_DIR", ".virtual_documents") @default("conf_d_language_servers") - def _default_conf_d_language_servers(self): - language_servers = {} # type: KeyedLanguageServerSpecs + def _default_conf_d_language_servers(self) -> KeyedLanguageServerSpecs: + language_servers: KeyedLanguageServerSpecs = {} manager = ConfigManager(read_config_path=jupyter_config_path()) @@ -113,10 +113,10 @@ def _default_conf_d_language_servers(self): return language_servers - def __init__(self, **kwargs): + def __init__(self, **kwargs: Dict): """Before starting, perform all necessary configuration""" self.all_language_servers: KeyedLanguageServerSpecs = {} - self._language_servers_from_config = {} + self._language_servers_from_config: KeyedLanguageServerSpecs = {} super().__init__(**kwargs) def initialize(self, *args, **kwargs): @@ -253,7 +253,7 @@ def _autodetect_language_servers(self, only_installed: bool): for ep in _entry_points or []: try: - spec_finder = ep.load() # type: SpecMaker + spec_finder: SpecMaker = ep.load() except Exception as err: # pragma: no cover self.log.warning( _("Failed to load language server spec finder `{}`: \n{}").format( diff --git a/python_packages/jupyter_lsp/jupyter_lsp/types.py b/python_packages/jupyter_lsp/jupyter_lsp/types.py index d9581f809..ea10592f6 100644 --- a/python_packages/jupyter_lsp/jupyter_lsp/types.py +++ b/python_packages/jupyter_lsp/jupyter_lsp/types.py @@ -72,9 +72,8 @@ class MessageScope(enum.Enum): class MessageListener(object): """A base listener implementation""" - listener = None # type: HandlerListenerCallback - language_server = None # type: Optional[Pattern[Text]] - method = None # type: Optional[Pattern[Text]] + language_server: Optional[Pattern[Text]] = None + method: Optional[Pattern[Text]] = None def __init__( self, diff --git a/python_packages/jupyterlab_lsp/setup.cfg b/python_packages/jupyterlab_lsp/setup.cfg index e1af2c659..90b7d42db 100644 --- a/python_packages/jupyterlab_lsp/setup.cfg +++ b/python_packages/jupyterlab_lsp/setup.cfg @@ -37,4 +37,4 @@ python_requires = >=3.8 install_requires = jupyter_lsp >=2.0.0 - jupyterlab >=4.0.5,<5.0.0a0 + jupyterlab >=4.0.6,<5.0.0a0 diff --git a/requirements/github-actions.yml b/requirements/github-actions.yml index e01cfff56..fadbd4f90 100644 --- a/requirements/github-actions.yml +++ b/requirements/github-actions.yml @@ -12,9 +12,10 @@ dependencies: - pip - nodejs {nodejs} # for python language server (and development) - - python-lsp-server - - flake8 >=3.5 - - autopep8 <1.6.0 + - python-lsp-server >=1.7.4 + - flake8 + - autopep8 + - pyflakes # robotframework for testing and language server - jupyterlab_robotmode - robotframework >=4 @@ -36,12 +37,8 @@ dependencies: # test tools - pytest-asyncio - pytest-cov - # temporary pin added on 2022-12-28, if editing this file try to remove it: - # pytoolconfig 1.2.4 depends on packaging>=22.0 which breaks `pip check` - - pytoolconfig <1.2.4 - # see https://github.com/conda-forge/pytest-flake8-feedstock/issues/20 - # and https://github.com/tholo/pytest-flake8/issues/86 - - pytest-flake8 <1.1.1 + - pytoolconfig + - pytest-flake8 - pytest-runner - ruamel_yaml - pytest-github-actions-annotate-failures diff --git a/requirements/lab.txt b/requirements/lab.txt index a2d2631aa..85771d5af 100644 --- a/requirements/lab.txt +++ b/requirements/lab.txt @@ -1,3 +1,3 @@ # the version of jupyterlab -r ./prod.txt -jupyterlab >=4.0.5,<5.0.0a0 +jupyterlab >=4.0.6,<5.0.0a0 diff --git a/yarn.lock b/yarn.lock index fc4d344db..89faf36b0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2090,20 +2090,20 @@ __metadata: languageName: node linkType: hard -"@jupyter-lsp/code-jumpers@workspace:*, @jupyter-lsp/code-jumpers@workspace:packages/code-jumpers, @jupyter-lsp/code-jumpers@~1.2.0": +"@jupyter-lsp/code-jumpers@workspace:*, @jupyter-lsp/code-jumpers@workspace:packages/code-jumpers, @jupyter-lsp/code-jumpers@~2.0.0-rc.0": version: 0.0.0-use.local resolution: "@jupyter-lsp/code-jumpers@workspace:packages/code-jumpers" dependencies: - "@jupyterlab/apputils": ^4.1.5 - "@jupyterlab/codeeditor": ^4.0.5 - "@jupyterlab/coreutils": ^6.0.5 - "@jupyterlab/docmanager": ^4.0.5 - "@jupyterlab/docregistry": ^4.0.5 - "@jupyterlab/fileeditor": ^4.0.5 - "@jupyterlab/notebook": ^4.0.5 - "@jupyterlab/observables": ^5.0.5 - "@jupyterlab/testing": ^4.0.5 - "@jupyterlab/translation": ^4.0.5 + "@jupyterlab/apputils": ^4.1.6 + "@jupyterlab/codeeditor": ^4.0.6 + "@jupyterlab/coreutils": ^6.0.6 + "@jupyterlab/docmanager": ^4.0.6 + "@jupyterlab/docregistry": ^4.0.6 + "@jupyterlab/fileeditor": ^4.0.6 + "@jupyterlab/notebook": ^4.0.6 + "@jupyterlab/observables": ^5.0.6 + "@jupyterlab/testing": ^4.0.6 + "@jupyterlab/translation": ^4.0.6 rimraf: ^3.0.0 typescript: ~5.0.4 peerDependencies: @@ -2119,12 +2119,12 @@ __metadata: languageName: unknown linkType: soft -"@jupyter-lsp/completion-theme@^3.0.0, @jupyter-lsp/completion-theme@workspace:*, @jupyter-lsp/completion-theme@workspace:packages/completion-theme, @jupyter-lsp/completion-theme@~3.3.0": +"@jupyter-lsp/completion-theme@^4.0.0-rc.0, @jupyter-lsp/completion-theme@workspace:*, @jupyter-lsp/completion-theme@workspace:packages/completion-theme, @jupyter-lsp/completion-theme@~4.0.0-rc.0": version: 0.0.0-use.local resolution: "@jupyter-lsp/completion-theme@workspace:packages/completion-theme" dependencies: - "@jupyterlab/builder": ^4.0.5 - "@jupyterlab/ui-components": ^4.0.5 + "@jupyterlab/builder": ^4.0.6 + "@jupyterlab/ui-components": ^4.0.6 react: ^18.2.0 rimraf: ^3.0.0 typescript: ~5.0.4 @@ -2136,8 +2136,8 @@ __metadata: resolution: "@jupyter-lsp/jupyterlab-lsp-example-extractor@workspace:packages/_example-extractor" dependencies: "@jupyter-lsp/jupyterlab-lsp": ^5.0.0-alpha.0 - "@jupyterlab/application": ^4.0.5 - "@jupyterlab/testing": ^4.0.5 + "@jupyterlab/application": ^4.0.6 + "@jupyterlab/testing": ^4.0.6 "@types/jest": ^29.5.4 jest: ^29.2.0 rimraf: ^3.0.0 @@ -2149,8 +2149,8 @@ __metadata: version: 0.0.0-use.local resolution: "@jupyter-lsp/jupyterlab-lsp-klingon-integration@workspace:packages/_klingon-integration" dependencies: - "@jupyterlab/application": ^4.0.5 - "@jupyterlab/builder": ^4.0.5 + "@jupyterlab/application": ^4.0.6 + "@jupyterlab/builder": ^4.0.6 typescript: ~5.0.4 languageName: unknown linkType: soft @@ -2176,31 +2176,31 @@ __metadata: resolution: "@jupyter-lsp/jupyterlab-lsp@workspace:packages/jupyterlab-lsp" dependencies: "@codemirror/lint": ^6.4.0 - "@jupyter-lsp/code-jumpers": ~1.2.0 - "@jupyter-lsp/completion-theme": ~3.3.0 - "@jupyter-lsp/theme-material": ~2.1.1 - "@jupyter-lsp/theme-vscode": ~2.1.1 - "@jupyter-notebook/application": ^7.0.2 - "@jupyterlab/application": ^4.0.5 - "@jupyterlab/apputils": ^4.1.5 - "@jupyterlab/builder": ^4.0.5 - "@jupyterlab/cells": ^4.0.5 - "@jupyterlab/codeeditor": ^4.0.5 - "@jupyterlab/codemirror": ^4.0.5 - "@jupyterlab/completer": ^4.0.5 - "@jupyterlab/coreutils": ^6.0.5 - "@jupyterlab/docmanager": ^4.0.5 - "@jupyterlab/docregistry": ^4.0.5 - "@jupyterlab/fileeditor": ^4.0.5 - "@jupyterlab/logconsole": ^4.0.5 - "@jupyterlab/lsp": ^4.0.5 - "@jupyterlab/notebook": ^4.0.5 - "@jupyterlab/rendermime": ^4.0.5 - "@jupyterlab/services": ^7.0.5 - "@jupyterlab/statusbar": ^4.0.5 - "@jupyterlab/testing": ^4.0.5 - "@jupyterlab/tooltip": ^4.0.5 - "@jupyterlab/ui-components": ^4.0.5 + "@jupyter-lsp/code-jumpers": ~2.0.0-rc.0 + "@jupyter-lsp/completion-theme": ~4.0.0-rc.0 + "@jupyter-lsp/theme-material": ~3.0.0-rc.0 + "@jupyter-lsp/theme-vscode": ~3.0.0-rc.0 + "@jupyter-notebook/application": ^7.0.3 + "@jupyterlab/application": ^4.0.6 + "@jupyterlab/apputils": ^4.1.6 + "@jupyterlab/builder": ^4.0.6 + "@jupyterlab/cells": ^4.0.6 + "@jupyterlab/codeeditor": ^4.0.6 + "@jupyterlab/codemirror": ^4.0.6 + "@jupyterlab/completer": ^4.0.6 + "@jupyterlab/coreutils": ^6.0.6 + "@jupyterlab/docmanager": ^4.0.6 + "@jupyterlab/docregistry": ^4.0.6 + "@jupyterlab/fileeditor": ^4.0.6 + "@jupyterlab/logconsole": ^4.0.6 + "@jupyterlab/lsp": ^4.0.6 + "@jupyterlab/notebook": ^4.0.6 + "@jupyterlab/rendermime": ^4.0.6 + "@jupyterlab/services": ^7.0.6 + "@jupyterlab/statusbar": ^4.0.6 + "@jupyterlab/testing": ^4.0.6 + "@jupyterlab/tooltip": ^4.0.6 + "@jupyterlab/ui-components": ^4.0.6 "@lumino/algorithm": "*" "@lumino/widgets": ^2.3.0 "@rjsf/validator-ajv8": ^5.12.1 @@ -2241,38 +2241,38 @@ __metadata: languageName: unknown linkType: soft -"@jupyter-lsp/theme-material@workspace:*, @jupyter-lsp/theme-material@workspace:packages/theme-material, @jupyter-lsp/theme-material@~2.1.1": +"@jupyter-lsp/theme-material@workspace:*, @jupyter-lsp/theme-material@workspace:packages/theme-material, @jupyter-lsp/theme-material@~3.0.0-rc.0": version: 0.0.0-use.local resolution: "@jupyter-lsp/theme-material@workspace:packages/theme-material" dependencies: - "@jupyter-lsp/completion-theme": ^3.0.0 + "@jupyter-lsp/completion-theme": ^4.0.0-rc.0 languageName: unknown linkType: soft -"@jupyter-lsp/theme-vscode@workspace:*, @jupyter-lsp/theme-vscode@workspace:packages/theme-vscode, @jupyter-lsp/theme-vscode@~2.1.1": +"@jupyter-lsp/theme-vscode@workspace:*, @jupyter-lsp/theme-vscode@workspace:packages/theme-vscode, @jupyter-lsp/theme-vscode@~3.0.0-rc.0": version: 0.0.0-use.local resolution: "@jupyter-lsp/theme-vscode@workspace:packages/theme-vscode" dependencies: - "@jupyter-lsp/completion-theme": ^3.0.0 + "@jupyter-lsp/completion-theme": ^4.0.0-rc.0 languageName: unknown linkType: soft -"@jupyter-notebook/application@npm:^7.0.2": - version: 7.0.2 - resolution: "@jupyter-notebook/application@npm:7.0.2" +"@jupyter-notebook/application@npm:^7.0.3": + version: 7.0.3 + resolution: "@jupyter-notebook/application@npm:7.0.3" dependencies: - "@jupyterlab/application": ^4.0.4 - "@jupyterlab/coreutils": ^6.0.4 - "@jupyterlab/docregistry": ^4.0.4 - "@jupyterlab/rendermime-interfaces": ^3.8.4 - "@jupyterlab/ui-components": ^4.0.4 - "@lumino/algorithm": ^2.0.0 - "@lumino/coreutils": ^2.1.1 - "@lumino/messaging": ^2.0.0 - "@lumino/polling": ^2.1.1 - "@lumino/signaling": ^2.1.1 - "@lumino/widgets": ^2.1.1 - checksum: dd3d2592baa458881265107b8c985a02a8d137a2e6fcd362c4ff43500ed99144c46f9871bfb8d44e7a23168298a440a830f87431177dd954674f89ff944ca148 + "@jupyterlab/application": ^4.0.5 + "@jupyterlab/coreutils": ^6.0.5 + "@jupyterlab/docregistry": ^4.0.5 + "@jupyterlab/rendermime-interfaces": ^3.8.5 + "@jupyterlab/ui-components": ^4.0.5 + "@lumino/algorithm": ^2.0.1 + "@lumino/coreutils": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/polling": ^2.1.2 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + checksum: 0f24dbac34b6008360609d1d2fc2637739d2897c695591385bfb8b5f505a179dc195dbbbe55e64e351d4d2c56120c1e0928eb67575ced47fd1ae794526a9a77b languageName: node linkType: hard @@ -2290,7 +2290,7 @@ __metadata: languageName: node linkType: hard -"@jupyterlab/application@npm:^4.0.4, @jupyterlab/application@npm:^4.0.5": +"@jupyterlab/application@npm:^4.0.5": version: 4.0.5 resolution: "@jupyterlab/application@npm:4.0.5" dependencies: @@ -2318,6 +2318,34 @@ __metadata: languageName: node linkType: hard +"@jupyterlab/application@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/application@npm:4.0.6" + dependencies: + "@fortawesome/fontawesome-free": ^5.12.0 + "@jupyterlab/apputils": ^4.1.6 + "@jupyterlab/coreutils": ^6.0.6 + "@jupyterlab/docregistry": ^4.0.6 + "@jupyterlab/rendermime": ^4.0.6 + "@jupyterlab/rendermime-interfaces": ^3.8.6 + "@jupyterlab/services": ^7.0.6 + "@jupyterlab/statedb": ^4.0.6 + "@jupyterlab/translation": ^4.0.6 + "@jupyterlab/ui-components": ^4.0.6 + "@lumino/algorithm": ^2.0.1 + "@lumino/application": ^2.2.1 + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/polling": ^2.1.2 + "@lumino/properties": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + checksum: 1212b71d3717bc02543b3eee74e69be799634421bd9b291b7adf07ba27bf6f9c7db860c423c824eaced9c2524db2f6b58de2c58e7edd5de2f0d7fabbb2c94b8c + languageName: node + linkType: hard + "@jupyterlab/apputils@npm:^4.1.5": version: 4.1.5 resolution: "@jupyterlab/apputils@npm:4.1.5" @@ -2347,23 +2375,52 @@ __metadata: languageName: node linkType: hard -"@jupyterlab/attachments@npm:^4.0.5": - version: 4.0.5 - resolution: "@jupyterlab/attachments@npm:4.0.5" +"@jupyterlab/apputils@npm:^4.1.6": + version: 4.1.6 + resolution: "@jupyterlab/apputils@npm:4.1.6" + dependencies: + "@jupyterlab/coreutils": ^6.0.6 + "@jupyterlab/observables": ^5.0.6 + "@jupyterlab/rendermime-interfaces": ^3.8.6 + "@jupyterlab/services": ^7.0.6 + "@jupyterlab/settingregistry": ^4.0.6 + "@jupyterlab/statedb": ^4.0.6 + "@jupyterlab/statusbar": ^4.0.6 + "@jupyterlab/translation": ^4.0.6 + "@jupyterlab/ui-components": ^4.0.6 + "@lumino/algorithm": ^2.0.1 + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/domutils": ^2.0.1 + "@lumino/messaging": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/virtualdom": ^2.0.1 + "@lumino/widgets": ^2.3.0 + "@types/react": ^18.0.26 + react: ^18.2.0 + sanitize-html: ~2.7.3 + checksum: 40fb43f5a6464c665f1b941d164f3366ab8ea906fed72894ccf026ebeebf0734409edb6546a151ac267cbd4f945e23474251aed644f7f0f0dbf2548b9230ae22 + languageName: node + linkType: hard + +"@jupyterlab/attachments@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/attachments@npm:4.0.6" dependencies: - "@jupyterlab/nbformat": ^4.0.5 - "@jupyterlab/observables": ^5.0.5 - "@jupyterlab/rendermime": ^4.0.5 - "@jupyterlab/rendermime-interfaces": ^3.8.5 + "@jupyterlab/nbformat": ^4.0.6 + "@jupyterlab/observables": ^5.0.6 + "@jupyterlab/rendermime": ^4.0.6 + "@jupyterlab/rendermime-interfaces": ^3.8.6 "@lumino/disposable": ^2.1.2 "@lumino/signaling": ^2.1.2 - checksum: bb0a5dc7e830fc42824743cc817cf59a43c43b6f3979b3d6214619baf69f77bb70606241b39a92da21788348eb1144a0914e3683f0b2b8d01a530e8aeaf6f01e + checksum: b7efd01d6a0b7f28a4ee8114723cdc33267f1c1f84763b71a04e783024a87f639e442be74eda5afecff7eea5750d094f4da8a46ee711ec1298645eb92252c7ee languageName: node linkType: hard -"@jupyterlab/builder@npm:^4.0.5": - version: 4.0.5 - resolution: "@jupyterlab/builder@npm:4.0.5" +"@jupyterlab/builder@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/builder@npm:4.0.6" dependencies: "@lumino/algorithm": ^2.0.1 "@lumino/application": ^2.2.1 @@ -2398,32 +2455,32 @@ __metadata: worker-loader: ^3.0.2 bin: build-labextension: lib/build-labextension.js - checksum: 60b12e784881a16a3d2c794b0edfaea85e5da0b84f1a751564741df665c0bfcea8baabb91e5c061461fc431a8a5570e837cbf7692b39935b0df7fe87e1c0f213 + checksum: 8ee8db483e07bcc99c45133616a60f57eb2f323898217961cecf82ef875343879327ad7e74adaa860577742d946e8325f16dfcb54845930db41faa9f4bdad70c languageName: node linkType: hard -"@jupyterlab/cells@npm:^4.0.5": - version: 4.0.5 - resolution: "@jupyterlab/cells@npm:4.0.5" +"@jupyterlab/cells@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/cells@npm:4.0.6" dependencies: "@codemirror/state": ^6.2.0 "@codemirror/view": ^6.9.6 "@jupyter/ydoc": ^1.0.2 - "@jupyterlab/apputils": ^4.1.5 - "@jupyterlab/attachments": ^4.0.5 - "@jupyterlab/codeeditor": ^4.0.5 - "@jupyterlab/codemirror": ^4.0.5 - "@jupyterlab/coreutils": ^6.0.5 - "@jupyterlab/documentsearch": ^4.0.5 - "@jupyterlab/filebrowser": ^4.0.5 - "@jupyterlab/nbformat": ^4.0.5 - "@jupyterlab/observables": ^5.0.5 - "@jupyterlab/outputarea": ^4.0.5 - "@jupyterlab/rendermime": ^4.0.5 - "@jupyterlab/services": ^7.0.5 - "@jupyterlab/toc": ^6.0.5 - "@jupyterlab/translation": ^4.0.5 - "@jupyterlab/ui-components": ^4.0.5 + "@jupyterlab/apputils": ^4.1.6 + "@jupyterlab/attachments": ^4.0.6 + "@jupyterlab/codeeditor": ^4.0.6 + "@jupyterlab/codemirror": ^4.0.6 + "@jupyterlab/coreutils": ^6.0.6 + "@jupyterlab/documentsearch": ^4.0.6 + "@jupyterlab/filebrowser": ^4.0.6 + "@jupyterlab/nbformat": ^4.0.6 + "@jupyterlab/observables": ^5.0.6 + "@jupyterlab/outputarea": ^4.0.6 + "@jupyterlab/rendermime": ^4.0.6 + "@jupyterlab/services": ^7.0.6 + "@jupyterlab/toc": ^6.0.6 + "@jupyterlab/translation": ^4.0.6 + "@jupyterlab/ui-components": ^4.0.6 "@lumino/algorithm": ^2.0.1 "@lumino/coreutils": ^2.1.2 "@lumino/domutils": ^2.0.1 @@ -2434,7 +2491,7 @@ __metadata: "@lumino/virtualdom": ^2.0.1 "@lumino/widgets": ^2.3.0 react: ^18.2.0 - checksum: d674a15ddf870bea876d8b40ec598bbe9ba6d59b653223b381beec7e4e1e18c1b2c623585a9edc24e186dc666d73c63c55cee76ec83f975183f17bb5a56a8573 + checksum: b0bb039c05ee0d83f40b5ccb0efa27d90723808c50821f8b8abedc8770387916bbc46d8a886102bf353b58e434cf33849981f782f1dbb3658835cce219940f33 languageName: node linkType: hard @@ -2461,9 +2518,32 @@ __metadata: languageName: node linkType: hard -"@jupyterlab/codemirror@npm:^4.0.5": - version: 4.0.5 - resolution: "@jupyterlab/codemirror@npm:4.0.5" +"@jupyterlab/codeeditor@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/codeeditor@npm:4.0.6" + dependencies: + "@codemirror/state": ^6.2.0 + "@jupyter/ydoc": ^1.0.2 + "@jupyterlab/coreutils": ^6.0.6 + "@jupyterlab/nbformat": ^4.0.6 + "@jupyterlab/observables": ^5.0.6 + "@jupyterlab/statusbar": ^4.0.6 + "@jupyterlab/translation": ^4.0.6 + "@jupyterlab/ui-components": ^4.0.6 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/dragdrop": ^2.1.3 + "@lumino/messaging": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + react: ^18.2.0 + checksum: 831d330273280781dbdc223325d575ac373c0db17fab208f327bce4e1c2286c62f8264d1d612da1a762bc006cd81dfb0eb5108dd3bd8f8298f9be8ecac98b2ca + languageName: node + linkType: hard + +"@jupyterlab/codemirror@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/codemirror@npm:4.0.6" dependencies: "@codemirror/autocomplete": ^6.5.1 "@codemirror/commands": ^6.2.3 @@ -2486,11 +2566,11 @@ __metadata: "@codemirror/state": ^6.2.0 "@codemirror/view": ^6.9.6 "@jupyter/ydoc": ^1.0.2 - "@jupyterlab/codeeditor": ^4.0.5 - "@jupyterlab/coreutils": ^6.0.5 - "@jupyterlab/documentsearch": ^4.0.5 - "@jupyterlab/nbformat": ^4.0.5 - "@jupyterlab/translation": ^4.0.5 + "@jupyterlab/codeeditor": ^4.0.6 + "@jupyterlab/coreutils": ^6.0.6 + "@jupyterlab/documentsearch": ^4.0.6 + "@jupyterlab/nbformat": ^4.0.6 + "@jupyterlab/translation": ^4.0.6 "@lezer/common": ^1.0.2 "@lezer/generator": ^1.2.2 "@lezer/highlight": ^1.1.4 @@ -2499,22 +2579,22 @@ __metadata: "@lumino/disposable": ^2.1.2 "@lumino/signaling": ^2.1.2 yjs: ^13.5.40 - checksum: 840d9abd7c34ce7fb09446eff235e056e2d04da290f83380c020a9c3e2a1a27c0d3fc7ffcbd54a1f6de6325a57cc18d350d30c61a0f27d9810d8d2ec32aa5cf2 + checksum: fdd0c4655e8597b1beb985b84b82dcfe29b4c8d0ae7e7ff3b0aecdbc94bc2b94ec0b617b3d59d7739e271e76433b2e624672d94ec64cfa4efc628cab92418175 languageName: node linkType: hard -"@jupyterlab/completer@npm:^4.0.5": - version: 4.0.5 - resolution: "@jupyterlab/completer@npm:4.0.5" +"@jupyterlab/completer@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/completer@npm:4.0.6" dependencies: "@jupyter/ydoc": ^1.0.2 - "@jupyterlab/apputils": ^4.1.5 - "@jupyterlab/codeeditor": ^4.0.5 - "@jupyterlab/coreutils": ^6.0.5 - "@jupyterlab/rendermime": ^4.0.5 - "@jupyterlab/services": ^7.0.5 - "@jupyterlab/statedb": ^4.0.5 - "@jupyterlab/ui-components": ^4.0.5 + "@jupyterlab/apputils": ^4.1.6 + "@jupyterlab/codeeditor": ^4.0.6 + "@jupyterlab/coreutils": ^6.0.6 + "@jupyterlab/rendermime": ^4.0.6 + "@jupyterlab/services": ^7.0.6 + "@jupyterlab/statedb": ^4.0.6 + "@jupyterlab/ui-components": ^4.0.6 "@lumino/algorithm": ^2.0.1 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 @@ -2522,11 +2602,11 @@ __metadata: "@lumino/messaging": ^2.0.1 "@lumino/signaling": ^2.1.2 "@lumino/widgets": ^2.3.0 - checksum: bca52950049bfad7a03a2a36d8ed0ac0c430bb4b7cbd833be5ece0d03293edd474349ff462dfe25a5dd76c9de77dd1c68d42d1444f43faec6dd4d1f79cefb162 + checksum: 3fcd07e52a753a0e8e4cc3a27220fb8a8d64167097a73f76343fbbb40ce69681a7be4244b8c7f21f826dab91af4e25591d15245b2f41237d56d83d3aab3db39e languageName: node linkType: hard -"@jupyterlab/coreutils@npm:^6.0.4, @jupyterlab/coreutils@npm:^6.0.5": +"@jupyterlab/coreutils@npm:^6.0.5": version: 6.0.5 resolution: "@jupyterlab/coreutils@npm:6.0.5" dependencies: @@ -2540,17 +2620,31 @@ __metadata: languageName: node linkType: hard -"@jupyterlab/docmanager@npm:^4.0.5": - version: 4.0.5 - resolution: "@jupyterlab/docmanager@npm:4.0.5" +"@jupyterlab/coreutils@npm:^6.0.6": + version: 6.0.6 + resolution: "@jupyterlab/coreutils@npm:6.0.6" dependencies: - "@jupyterlab/apputils": ^4.1.5 - "@jupyterlab/coreutils": ^6.0.5 - "@jupyterlab/docregistry": ^4.0.5 - "@jupyterlab/services": ^7.0.5 - "@jupyterlab/statusbar": ^4.0.5 - "@jupyterlab/translation": ^4.0.5 - "@jupyterlab/ui-components": ^4.0.5 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/signaling": ^2.1.2 + minimist: ~1.2.0 + path-browserify: ^1.0.0 + url-parse: ~1.5.4 + checksum: cf3cfbc7c48cae20549f5514a949b253c2f9d67c79db107ab0a81c2b7a9c08e28f9fd264e3d944a05a8cb1bbb9676c6b4163b75c28788d1cb3a3cc523d44d802 + languageName: node + linkType: hard + +"@jupyterlab/docmanager@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/docmanager@npm:4.0.6" + dependencies: + "@jupyterlab/apputils": ^4.1.6 + "@jupyterlab/coreutils": ^6.0.6 + "@jupyterlab/docregistry": ^4.0.6 + "@jupyterlab/services": ^7.0.6 + "@jupyterlab/statusbar": ^4.0.6 + "@jupyterlab/translation": ^4.0.6 + "@jupyterlab/ui-components": ^4.0.6 "@lumino/algorithm": ^2.0.1 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 @@ -2559,11 +2653,11 @@ __metadata: "@lumino/signaling": ^2.1.2 "@lumino/widgets": ^2.3.0 react: ^18.2.0 - checksum: 16627833d9d540e9569bd27e3464c6c9a5cf9f628265b5018a4f63e05f351c4891494b8c731f83bb279da3bb42d0da23cb1d1b536c0b1b4422e4f6f250377ca5 + checksum: 25d3f694ae8664ca6c54bfcd36d8913caba9455fea68ed3df23963ce9723254c1f2c38fb6a93e267187f095392507d40cd2a4181c30173306c1c0b962e001b93 languageName: node linkType: hard -"@jupyterlab/docregistry@npm:^4.0.4, @jupyterlab/docregistry@npm:^4.0.5": +"@jupyterlab/docregistry@npm:^4.0.5": version: 4.0.5 resolution: "@jupyterlab/docregistry@npm:4.0.5" dependencies: @@ -2588,13 +2682,38 @@ __metadata: languageName: node linkType: hard -"@jupyterlab/documentsearch@npm:^4.0.5": - version: 4.0.5 - resolution: "@jupyterlab/documentsearch@npm:4.0.5" +"@jupyterlab/docregistry@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/docregistry@npm:4.0.6" dependencies: - "@jupyterlab/apputils": ^4.1.5 - "@jupyterlab/translation": ^4.0.5 - "@jupyterlab/ui-components": ^4.0.5 + "@jupyter/ydoc": ^1.0.2 + "@jupyterlab/apputils": ^4.1.6 + "@jupyterlab/codeeditor": ^4.0.6 + "@jupyterlab/coreutils": ^6.0.6 + "@jupyterlab/observables": ^5.0.6 + "@jupyterlab/rendermime": ^4.0.6 + "@jupyterlab/rendermime-interfaces": ^3.8.6 + "@jupyterlab/services": ^7.0.6 + "@jupyterlab/translation": ^4.0.6 + "@jupyterlab/ui-components": ^4.0.6 + "@lumino/algorithm": ^2.0.1 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/properties": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + checksum: 57de3751ea04037f27596ffe782392fb4840f3fba1776a64bb7b0dc5936a3cee4de115b2133147cda23a697d3da7802daaec0effae10be329d6c774f102091ee + languageName: node + linkType: hard + +"@jupyterlab/documentsearch@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/documentsearch@npm:4.0.6" + dependencies: + "@jupyterlab/apputils": ^4.1.6 + "@jupyterlab/translation": ^4.0.6 + "@jupyterlab/ui-components": ^4.0.6 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 "@lumino/messaging": ^2.0.1 @@ -2602,23 +2721,23 @@ __metadata: "@lumino/signaling": ^2.1.2 "@lumino/widgets": ^2.3.0 react: ^18.2.0 - checksum: d7fe83a57562e9f90555c8b938f77edff21f7204b52a7cdd4a0cd21f5382fd5a7906e5d7c2ec661802b5d9bada42f80fcaa5d129931aeac949e8655d290d9adf + checksum: e6cf3533cdae29ca2f81147b26b056718df16998f6d89274d90cffcc70eab705634a7e36d353e9dcaea38640b490315b4ae683e937755547f42b8a5623bc914a languageName: node linkType: hard -"@jupyterlab/filebrowser@npm:^4.0.5": - version: 4.0.5 - resolution: "@jupyterlab/filebrowser@npm:4.0.5" +"@jupyterlab/filebrowser@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/filebrowser@npm:4.0.6" dependencies: - "@jupyterlab/apputils": ^4.1.5 - "@jupyterlab/coreutils": ^6.0.5 - "@jupyterlab/docmanager": ^4.0.5 - "@jupyterlab/docregistry": ^4.0.5 - "@jupyterlab/services": ^7.0.5 - "@jupyterlab/statedb": ^4.0.5 - "@jupyterlab/statusbar": ^4.0.5 - "@jupyterlab/translation": ^4.0.5 - "@jupyterlab/ui-components": ^4.0.5 + "@jupyterlab/apputils": ^4.1.6 + "@jupyterlab/coreutils": ^6.0.6 + "@jupyterlab/docmanager": ^4.0.6 + "@jupyterlab/docregistry": ^4.0.6 + "@jupyterlab/services": ^7.0.6 + "@jupyterlab/statedb": ^4.0.6 + "@jupyterlab/statusbar": ^4.0.6 + "@jupyterlab/translation": ^4.0.6 + "@jupyterlab/ui-components": ^4.0.6 "@lumino/algorithm": ^2.0.1 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 @@ -2630,64 +2749,64 @@ __metadata: "@lumino/virtualdom": ^2.0.1 "@lumino/widgets": ^2.3.0 react: ^18.2.0 - checksum: f47d55cc8ff246efe65fdbf1f0fc09e227eca9bafcf0f1e45e1973612ad13e0853f1393882decddc2f1df015f11097b6d751bdbcdc255ed438adc96598b376a8 + checksum: abe7eca4072a9c3d1f7a756840d0ad209403928b958fe09dfd81fbb693cb18c91c64027157babe1e7353a556b11c070716326b16ee2eb629089399906a3467be languageName: node linkType: hard -"@jupyterlab/fileeditor@npm:^4.0.5": - version: 4.0.5 - resolution: "@jupyterlab/fileeditor@npm:4.0.5" +"@jupyterlab/fileeditor@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/fileeditor@npm:4.0.6" dependencies: - "@jupyterlab/apputils": ^4.1.5 - "@jupyterlab/codeeditor": ^4.0.5 - "@jupyterlab/codemirror": ^4.0.5 - "@jupyterlab/coreutils": ^6.0.5 - "@jupyterlab/docregistry": ^4.0.5 - "@jupyterlab/documentsearch": ^4.0.5 - "@jupyterlab/lsp": ^4.0.5 - "@jupyterlab/statusbar": ^4.0.5 - "@jupyterlab/toc": ^6.0.5 - "@jupyterlab/translation": ^4.0.5 - "@jupyterlab/ui-components": ^4.0.5 + "@jupyterlab/apputils": ^4.1.6 + "@jupyterlab/codeeditor": ^4.0.6 + "@jupyterlab/codemirror": ^4.0.6 + "@jupyterlab/coreutils": ^6.0.6 + "@jupyterlab/docregistry": ^4.0.6 + "@jupyterlab/documentsearch": ^4.0.6 + "@jupyterlab/lsp": ^4.0.6 + "@jupyterlab/statusbar": ^4.0.6 + "@jupyterlab/toc": ^6.0.6 + "@jupyterlab/translation": ^4.0.6 + "@jupyterlab/ui-components": ^4.0.6 "@lumino/commands": ^2.1.3 "@lumino/coreutils": ^2.1.2 "@lumino/messaging": ^2.0.1 "@lumino/widgets": ^2.3.0 react: ^18.2.0 regexp-match-indices: ^1.0.2 - checksum: 7598dec866704fb664223b805a3fa7db4eb6506f10b4c59a831404d1462e2d993955b259095ea7d35258bb1be9147860d261f11e48c493331bb77746807565ac + checksum: cc70beea6dffe131574a73106e9381c80fe05b440f00f37312e4c12a0995dd22989f414916f4b450d455db20bf28d9ea3c2ef339e5ecfd45e61ce433c0bb8a0a languageName: node linkType: hard -"@jupyterlab/logconsole@npm:^4.0.5": - version: 4.0.5 - resolution: "@jupyterlab/logconsole@npm:4.0.5" +"@jupyterlab/logconsole@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/logconsole@npm:4.0.6" dependencies: - "@jupyterlab/coreutils": ^6.0.5 - "@jupyterlab/nbformat": ^4.0.5 - "@jupyterlab/outputarea": ^4.0.5 - "@jupyterlab/rendermime": ^4.0.5 - "@jupyterlab/services": ^7.0.5 - "@jupyterlab/translation": ^4.0.5 + "@jupyterlab/coreutils": ^6.0.6 + "@jupyterlab/nbformat": ^4.0.6 + "@jupyterlab/outputarea": ^4.0.6 + "@jupyterlab/rendermime": ^4.0.6 + "@jupyterlab/services": ^7.0.6 + "@jupyterlab/translation": ^4.0.6 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 "@lumino/messaging": ^2.0.1 "@lumino/signaling": ^2.1.2 "@lumino/widgets": ^2.3.0 - checksum: e18e395e38ce3994c2a5ccc637a6a2bf2beeb3e8b727f0aa5d8c816e47a1ffbb681af592596e55fb67cf2e66f7d05ce6e969cf7983d9d41d5a98832dcfed2ec5 + checksum: 7d6e56c019819452a4fadbacdc02eef3a4ca2192c96d40f49b2336fffa9f00a3fd0981ee9b0498ce8e7609619221e20f0bf9e5bd4c05e16228c3c5524eccfcd0 languageName: node linkType: hard -"@jupyterlab/lsp@npm:^4.0.5": - version: 4.0.5 - resolution: "@jupyterlab/lsp@npm:4.0.5" +"@jupyterlab/lsp@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/lsp@npm:4.0.6" dependencies: - "@jupyterlab/apputils": ^4.1.5 - "@jupyterlab/codeeditor": ^4.0.5 - "@jupyterlab/coreutils": ^6.0.5 - "@jupyterlab/docregistry": ^4.0.5 - "@jupyterlab/services": ^7.0.5 - "@jupyterlab/translation": ^4.0.5 + "@jupyterlab/apputils": ^4.1.6 + "@jupyterlab/codeeditor": ^4.0.6 + "@jupyterlab/coreutils": ^6.0.6 + "@jupyterlab/docregistry": ^4.0.6 + "@jupyterlab/services": ^7.0.6 + "@jupyterlab/translation": ^4.0.6 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 "@lumino/signaling": ^2.1.2 @@ -2695,7 +2814,7 @@ __metadata: vscode-jsonrpc: ^6.0.0 vscode-languageserver-protocol: ^3.17.0 vscode-ws-jsonrpc: ~1.0.2 - checksum: b59d21c9df84963c354422134e525acabab7f7fe2930e4bb5b5b81edd3e8397772ce5c395bc1faa7c79cddb6bfefc9e1c41edfd939241681da483ae3238be00d + checksum: 7a20f402bd2777e5ec36efe3193357ae59a8d619516ccf34bb569afe68d32df2af2c77479216826a08fd6dc16952e1430f2465e1fd9878bf092ca8773e5e2d1e languageName: node linkType: hard @@ -2708,28 +2827,37 @@ __metadata: languageName: node linkType: hard -"@jupyterlab/notebook@npm:^4.0.5": - version: 4.0.5 - resolution: "@jupyterlab/notebook@npm:4.0.5" +"@jupyterlab/nbformat@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/nbformat@npm:4.0.6" + dependencies: + "@lumino/coreutils": ^2.1.2 + checksum: 43ace863be98a82875a55a947828b9b987cff35bb484e6cb6474c97f60aadbf31027c5f2fdf81b4ee2d108dc735b92c15c9b35cded765b0e476ebf0c8fd670f6 + languageName: node + linkType: hard + +"@jupyterlab/notebook@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/notebook@npm:4.0.6" dependencies: "@jupyter/ydoc": ^1.0.2 - "@jupyterlab/apputils": ^4.1.5 - "@jupyterlab/cells": ^4.0.5 - "@jupyterlab/codeeditor": ^4.0.5 - "@jupyterlab/codemirror": ^4.0.5 - "@jupyterlab/coreutils": ^6.0.5 - "@jupyterlab/docregistry": ^4.0.5 - "@jupyterlab/documentsearch": ^4.0.5 - "@jupyterlab/lsp": ^4.0.5 - "@jupyterlab/nbformat": ^4.0.5 - "@jupyterlab/observables": ^5.0.5 - "@jupyterlab/rendermime": ^4.0.5 - "@jupyterlab/services": ^7.0.5 - "@jupyterlab/settingregistry": ^4.0.5 - "@jupyterlab/statusbar": ^4.0.5 - "@jupyterlab/toc": ^6.0.5 - "@jupyterlab/translation": ^4.0.5 - "@jupyterlab/ui-components": ^4.0.5 + "@jupyterlab/apputils": ^4.1.6 + "@jupyterlab/cells": ^4.0.6 + "@jupyterlab/codeeditor": ^4.0.6 + "@jupyterlab/codemirror": ^4.0.6 + "@jupyterlab/coreutils": ^6.0.6 + "@jupyterlab/docregistry": ^4.0.6 + "@jupyterlab/documentsearch": ^4.0.6 + "@jupyterlab/lsp": ^4.0.6 + "@jupyterlab/nbformat": ^4.0.6 + "@jupyterlab/observables": ^5.0.6 + "@jupyterlab/rendermime": ^4.0.6 + "@jupyterlab/services": ^7.0.6 + "@jupyterlab/settingregistry": ^4.0.6 + "@jupyterlab/statusbar": ^4.0.6 + "@jupyterlab/toc": ^6.0.6 + "@jupyterlab/translation": ^4.0.6 + "@jupyterlab/ui-components": ^4.0.6 "@lumino/algorithm": ^2.0.1 "@lumino/coreutils": ^2.1.2 "@lumino/domutils": ^2.0.1 @@ -2740,7 +2868,7 @@ __metadata: "@lumino/virtualdom": ^2.0.1 "@lumino/widgets": ^2.3.0 react: ^18.2.0 - checksum: c6979a1b3cc1a6e4eb82176d97bc2109f8f3bcf6b281853a6fb8d350e66fa443dcd34981d46b0aebb03356e6533956dd4ad233e6dee9198acbd62b9c6f027bcd + checksum: 9ffb5f39b5e6d34fc2df2662c790121fda3880a271f0606bd56f3bcff416b43b1697640d43f0a30231fcf24a935e193ca9b5bf016d34675ede0e02e1185afffb languageName: node linkType: hard @@ -2757,17 +2885,30 @@ __metadata: languageName: node linkType: hard -"@jupyterlab/outputarea@npm:^4.0.5": - version: 4.0.5 - resolution: "@jupyterlab/outputarea@npm:4.0.5" +"@jupyterlab/observables@npm:^5.0.6": + version: 5.0.6 + resolution: "@jupyterlab/observables@npm:5.0.6" dependencies: - "@jupyterlab/apputils": ^4.1.5 - "@jupyterlab/nbformat": ^4.0.5 - "@jupyterlab/observables": ^5.0.5 - "@jupyterlab/rendermime": ^4.0.5 - "@jupyterlab/rendermime-interfaces": ^3.8.5 - "@jupyterlab/services": ^7.0.5 - "@jupyterlab/translation": ^4.0.5 + "@lumino/algorithm": ^2.0.1 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/signaling": ^2.1.2 + checksum: 23232972e6a049b2addeae1d445bc3a10bb6c9a3dd4794225a0344aaa1ff62421ee300ef8803a19a3f068d2bba2de8b9a8dec719a7f47019fbd77c8d5dafb7a0 + languageName: node + linkType: hard + +"@jupyterlab/outputarea@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/outputarea@npm:4.0.6" + dependencies: + "@jupyterlab/apputils": ^4.1.6 + "@jupyterlab/nbformat": ^4.0.6 + "@jupyterlab/observables": ^5.0.6 + "@jupyterlab/rendermime": ^4.0.6 + "@jupyterlab/rendermime-interfaces": ^3.8.6 + "@jupyterlab/services": ^7.0.6 + "@jupyterlab/translation": ^4.0.6 "@lumino/algorithm": ^2.0.1 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 @@ -2775,11 +2916,11 @@ __metadata: "@lumino/properties": ^2.0.1 "@lumino/signaling": ^2.1.2 "@lumino/widgets": ^2.3.0 - checksum: fc7f49b09ad8104fd0ac022366877eee228beb63f237afa76e785e170cb17e9ae18a686e7ac09f5f74bf25735ebc089812ea9374cc7920f4a0a641b9d565a046 + checksum: 2691fe7e4bdff895c821e970edbc19867107dbd8150aa7f32c7f3a4a7608f9ae9c7862dc5887fdca6983b9d6a947e05f23bbf5160c7c99eef93a0abf20d085a4 languageName: node linkType: hard -"@jupyterlab/rendermime-interfaces@npm:^3.8.4, @jupyterlab/rendermime-interfaces@npm:^3.8.5": +"@jupyterlab/rendermime-interfaces@npm:^3.8.5": version: 3.8.5 resolution: "@jupyterlab/rendermime-interfaces@npm:3.8.5" dependencies: @@ -2789,6 +2930,16 @@ __metadata: languageName: node linkType: hard +"@jupyterlab/rendermime-interfaces@npm:^3.8.6": + version: 3.8.6 + resolution: "@jupyterlab/rendermime-interfaces@npm:3.8.6" + dependencies: + "@lumino/coreutils": ^1.11.0 || ^2.1.2 + "@lumino/widgets": ^1.37.2 || ^2.3.0 + checksum: 84ba0c3979e6ace6246e00248d1248075afb112f55be202257bb89a553b235d36ca82879c56f46f58285a5fc6d39914e93fea203c53245e0ac8d1b5ef838bb50 + languageName: node + linkType: hard + "@jupyterlab/rendermime@npm:^4.0.5": version: 4.0.5 resolution: "@jupyterlab/rendermime@npm:4.0.5" @@ -2809,6 +2960,26 @@ __metadata: languageName: node linkType: hard +"@jupyterlab/rendermime@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/rendermime@npm:4.0.6" + dependencies: + "@jupyterlab/apputils": ^4.1.6 + "@jupyterlab/coreutils": ^6.0.6 + "@jupyterlab/nbformat": ^4.0.6 + "@jupyterlab/observables": ^5.0.6 + "@jupyterlab/rendermime-interfaces": ^3.8.6 + "@jupyterlab/services": ^7.0.6 + "@jupyterlab/translation": ^4.0.6 + "@lumino/coreutils": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + lodash.escape: ^4.0.1 + checksum: 8f44601ccd6abe9985f8f713dcabf48ae38246b8b5a17a3963ebfe298dc2a03cc49d1f99c6d3bfeadbe1eb74803d0b3138c01347693a99166d7d70cb832c400b + languageName: node + linkType: hard + "@jupyterlab/services@npm:^7.0.5": version: 7.0.5 resolution: "@jupyterlab/services@npm:7.0.5" @@ -2828,6 +2999,25 @@ __metadata: languageName: node linkType: hard +"@jupyterlab/services@npm:^7.0.6": + version: 7.0.6 + resolution: "@jupyterlab/services@npm:7.0.6" + dependencies: + "@jupyter/ydoc": ^1.0.2 + "@jupyterlab/coreutils": ^6.0.6 + "@jupyterlab/nbformat": ^4.0.6 + "@jupyterlab/settingregistry": ^4.0.6 + "@jupyterlab/statedb": ^4.0.6 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/polling": ^2.1.2 + "@lumino/properties": ^2.0.1 + "@lumino/signaling": ^2.1.2 + ws: ^8.11.0 + checksum: 6e12ef309559977209e61ce3ec8ca74aa486d54f50d8f38211b684055fb2335a21c2ae6e846d2863e48524bffd7d6ac4d36dfc9f7ca610ae4b1c60752fa6c3a8 + languageName: node + linkType: hard + "@jupyterlab/settingregistry@npm:^4.0.5": version: 4.0.5 resolution: "@jupyterlab/settingregistry@npm:4.0.5" @@ -2847,6 +3037,25 @@ __metadata: languageName: node linkType: hard +"@jupyterlab/settingregistry@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/settingregistry@npm:4.0.6" + dependencies: + "@jupyterlab/nbformat": ^4.0.6 + "@jupyterlab/statedb": ^4.0.6 + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/signaling": ^2.1.2 + "@rjsf/utils": ^5.1.0 + ajv: ^8.12.0 + json5: ^2.2.3 + peerDependencies: + react: ">=16" + checksum: 70b6fc44a25e0d4ec36501c1418fe2764b9a9415f892df0901c43480b608a1621141ec8045183dfbca5aedf11ebaf1518dd76e2e96373b9ebe0efa6586ce856d + languageName: node + linkType: hard + "@jupyterlab/statedb@npm:^4.0.5": version: 4.0.5 resolution: "@jupyterlab/statedb@npm:4.0.5" @@ -2860,6 +3069,19 @@ __metadata: languageName: node linkType: hard +"@jupyterlab/statedb@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/statedb@npm:4.0.6" + dependencies: + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/properties": ^2.0.1 + "@lumino/signaling": ^2.1.2 + checksum: de507d094afcce7f7d12f9dc846788765616140b2f75ea22997f780056baaaadae0cf9683471a1d96c61d448b38860640c823302aeef0d5e5d7c9cf598074328 + languageName: node + linkType: hard + "@jupyterlab/statusbar@npm:^4.0.5": version: 4.0.5 resolution: "@jupyterlab/statusbar@npm:4.0.5" @@ -2876,13 +3098,29 @@ __metadata: languageName: node linkType: hard -"@jupyterlab/testing@npm:^4.0.5": - version: 4.0.5 - resolution: "@jupyterlab/testing@npm:4.0.5" +"@jupyterlab/statusbar@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/statusbar@npm:4.0.6" + dependencies: + "@jupyterlab/ui-components": ^4.0.6 + "@lumino/algorithm": ^2.0.1 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.0 + react: ^18.2.0 + checksum: c5d579b101e19670182d87de0d601fc9c73c40b5a81120e18e6cd7853ee9fd744fa31524f24b2c92cb587bb2d6aa54c08f6e257d868426a73d968e48b1101b7c + languageName: node + linkType: hard + +"@jupyterlab/testing@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/testing@npm:4.0.6" dependencies: "@babel/core": ^7.10.2 "@babel/preset-env": ^7.10.2 - "@jupyterlab/coreutils": ^6.0.5 + "@jupyterlab/coreutils": ^6.0.6 "@lumino/coreutils": ^2.1.2 "@lumino/signaling": ^2.1.2 child_process: ~1.0.2 @@ -2897,43 +3135,43 @@ __metadata: ts-jest: ^29.1.0 peerDependencies: typescript: ">=4.3" - checksum: 5f242263f879bb075db6ff5125dbdb495589703ae2e287c171b7680954db16eb6fd3ab66d09d77ca27686a1d1ec3a0736c78f86808dd222949c834ebd13910fb + checksum: b6e7326d90ca2a7d36a825ea32557f2ce4436dc4c8965f3603fa430aad138b703f0e206c432509c48c72294a959ab47881a81c8c88b1e378b53fe9108861791e languageName: node linkType: hard -"@jupyterlab/toc@npm:^6.0.5": - version: 6.0.5 - resolution: "@jupyterlab/toc@npm:6.0.5" - dependencies: - "@jupyterlab/apputils": ^4.1.5 - "@jupyterlab/coreutils": ^6.0.5 - "@jupyterlab/docregistry": ^4.0.5 - "@jupyterlab/observables": ^5.0.5 - "@jupyterlab/rendermime": ^4.0.5 - "@jupyterlab/translation": ^4.0.5 - "@jupyterlab/ui-components": ^4.0.5 +"@jupyterlab/toc@npm:^6.0.6": + version: 6.0.6 + resolution: "@jupyterlab/toc@npm:6.0.6" + dependencies: + "@jupyterlab/apputils": ^4.1.6 + "@jupyterlab/coreutils": ^6.0.6 + "@jupyterlab/docregistry": ^4.0.6 + "@jupyterlab/observables": ^5.0.6 + "@jupyterlab/rendermime": ^4.0.6 + "@jupyterlab/translation": ^4.0.6 + "@jupyterlab/ui-components": ^4.0.6 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 "@lumino/messaging": ^2.0.1 "@lumino/signaling": ^2.1.2 "@lumino/widgets": ^2.3.0 react: ^18.2.0 - checksum: 4b688fdd2aa0d14db02394bafcbae5e0ce632681e8541ff3ca6153ba0e219dc20cb99f03ef4ac25f849b4b7b23f3e168e50a450bf952f42b0418e2e42aaeb546 + checksum: d8d955a00e6678c50f73f18205dd79d77c752c3b0d33699554cdb77c3501657708c699642889975c97b58a85704c3bca40de01019ce087f188681bb843f35c3a languageName: node linkType: hard -"@jupyterlab/tooltip@npm:^4.0.5": - version: 4.0.5 - resolution: "@jupyterlab/tooltip@npm:4.0.5" +"@jupyterlab/tooltip@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/tooltip@npm:4.0.6" dependencies: - "@jupyterlab/codeeditor": ^4.0.5 - "@jupyterlab/rendermime": ^4.0.5 - "@jupyterlab/services": ^7.0.5 - "@jupyterlab/ui-components": ^4.0.5 + "@jupyterlab/codeeditor": ^4.0.6 + "@jupyterlab/rendermime": ^4.0.6 + "@jupyterlab/services": ^7.0.6 + "@jupyterlab/ui-components": ^4.0.6 "@lumino/coreutils": ^2.1.2 "@lumino/messaging": ^2.0.1 "@lumino/widgets": ^2.3.0 - checksum: 8a096fe65fb6887e47f12f20109b83f71249bb435eb552341958fd78a3f2d8d0979b900f143a4889e361ba722cb6f7cbd6831ac49d8ad17ce0710b5bea2c921e + checksum: ba65f9bda2ce1ecada6d977779ee422bdbaadc7e4fbfc314d5910bf512fd85f99f74af02a5d330fb5cddf2d36f0c9585a4faf4fe09dd63d9b136465536ba66ef languageName: node linkType: hard @@ -2950,7 +3188,20 @@ __metadata: languageName: node linkType: hard -"@jupyterlab/ui-components@npm:^4.0.4, @jupyterlab/ui-components@npm:^4.0.5": +"@jupyterlab/translation@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/translation@npm:4.0.6" + dependencies: + "@jupyterlab/coreutils": ^6.0.6 + "@jupyterlab/rendermime-interfaces": ^3.8.6 + "@jupyterlab/services": ^7.0.6 + "@jupyterlab/statedb": ^4.0.6 + "@lumino/coreutils": ^2.1.2 + checksum: 490243a26898bbdcc1909e8e1649be90580c6d4502417590fd1b3ca24db5aeff2323e567dbfb1d528c56df89ed2e7717753ece784134f9e409d14df92bf25682 + languageName: node + linkType: hard + +"@jupyterlab/ui-components@npm:^4.0.5": version: 4.0.5 resolution: "@jupyterlab/ui-components@npm:4.0.5" dependencies: @@ -2979,6 +3230,35 @@ __metadata: languageName: node linkType: hard +"@jupyterlab/ui-components@npm:^4.0.6": + version: 4.0.6 + resolution: "@jupyterlab/ui-components@npm:4.0.6" + dependencies: + "@jupyterlab/coreutils": ^6.0.6 + "@jupyterlab/observables": ^5.0.6 + "@jupyterlab/rendermime-interfaces": ^3.8.6 + "@jupyterlab/translation": ^4.0.6 + "@lumino/algorithm": ^2.0.1 + "@lumino/commands": ^2.1.3 + "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 + "@lumino/messaging": ^2.0.1 + "@lumino/polling": ^2.1.2 + "@lumino/properties": ^2.0.1 + "@lumino/signaling": ^2.1.2 + "@lumino/virtualdom": ^2.0.1 + "@lumino/widgets": ^2.3.0 + "@rjsf/core": ^5.1.0 + "@rjsf/utils": ^5.1.0 + react: ^18.2.0 + react-dom: ^18.2.0 + typestyle: ^2.0.4 + peerDependencies: + react: ^18.2.0 + checksum: 02997c3c35c15c0eda6a0d49fe9cfd12a3c5194c026b2ae8d8e53c7af80b769ba1598e7c24283450bacae7b8fab838d18f6c614d686c98d3d43e68f1f00b2528 + languageName: node + linkType: hard + "@lerna/child-process@npm:6.5.1": version: 6.5.1 resolution: "@lerna/child-process@npm:6.5.1" @@ -3159,7 +3439,7 @@ __metadata: languageName: node linkType: hard -"@lumino/algorithm@npm:*, @lumino/algorithm@npm:^2.0.0, @lumino/algorithm@npm:^2.0.1": +"@lumino/algorithm@npm:*, @lumino/algorithm@npm:^2.0.1": version: 2.0.1 resolution: "@lumino/algorithm@npm:2.0.1" checksum: cbf7fcf6ee6b785ea502cdfddc53d61f9d353dcb9659343511d5cd4b4030be2ff2ca4c08daec42f84417ab0318a3d9972a17319fa5231693e109ab112dcf8000 @@ -3201,7 +3481,7 @@ __metadata: languageName: node linkType: hard -"@lumino/coreutils@npm:^1.11.0 || ^2.0.0, @lumino/coreutils@npm:^1.11.0 || ^2.1.2, @lumino/coreutils@npm:^2.1.1, @lumino/coreutils@npm:^2.1.2": +"@lumino/coreutils@npm:^1.11.0 || ^2.0.0, @lumino/coreutils@npm:^1.11.0 || ^2.1.2, @lumino/coreutils@npm:^2.1.2": version: 2.1.2 resolution: "@lumino/coreutils@npm:2.1.2" checksum: 7865317ac0676b448d108eb57ab5d8b2a17c101995c0f7a7106662d9fe6c859570104525f83ee3cda12ae2e326803372206d6f4c1f415a5b59e4158a7b81066f @@ -3241,7 +3521,7 @@ __metadata: languageName: node linkType: hard -"@lumino/messaging@npm:^2.0.0, @lumino/messaging@npm:^2.0.1": +"@lumino/messaging@npm:^2.0.1": version: 2.0.1 resolution: "@lumino/messaging@npm:2.0.1" dependencies: @@ -3251,7 +3531,7 @@ __metadata: languageName: node linkType: hard -"@lumino/polling@npm:^2.1.1, @lumino/polling@npm:^2.1.2": +"@lumino/polling@npm:^2.1.2": version: 2.1.2 resolution: "@lumino/polling@npm:2.1.2" dependencies: @@ -3269,7 +3549,7 @@ __metadata: languageName: node linkType: hard -"@lumino/signaling@npm:^1.10.0 || ^2.0.0, @lumino/signaling@npm:^2.1.1, @lumino/signaling@npm:^2.1.2": +"@lumino/signaling@npm:^1.10.0 || ^2.0.0, @lumino/signaling@npm:^2.1.2": version: 2.1.2 resolution: "@lumino/signaling@npm:2.1.2" dependencies: @@ -3288,7 +3568,7 @@ __metadata: languageName: node linkType: hard -"@lumino/widgets@npm:^1.37.2 || ^2.3.0, @lumino/widgets@npm:^2.1.1, @lumino/widgets@npm:^2.3.0": +"@lumino/widgets@npm:^1.37.2 || ^2.3.0, @lumino/widgets@npm:^2.3.0": version: 2.3.0 resolution: "@lumino/widgets@npm:2.3.0" dependencies: