Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor LSPConnection, ConnectionManager #165

Merged
merged 67 commits into from
Feb 9, 2020
Merged
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
a3a5ac5
(wip) only create one connection manager per app, one socket per lang…
bollwyvl Jan 16, 2020
afc45ac
more work on lazy loading
bollwyvl Jan 16, 2020
312c9e5
make highlight uri-aware
bollwyvl Jan 16, 2020
568234c
make hover uri-aware
bollwyvl Jan 16, 2020
48e0a94
mostly get highlighting to not duplicate in wrong editors
bollwyvl Jan 18, 2020
99752d3
Merge remote-tracking branch 'upstream/master' into add-one-socket-pe…
bollwyvl Jan 20, 2020
d8fb97f
start working on getting the unit tests back up
bollwyvl Jan 20, 2020
8b39f9d
fix connection test
bollwyvl Jan 20, 2020
e11a63f
add rename to lsp interface
bollwyvl Jan 20, 2020
ac82ff0
hide non-essential logging behind DEBUG
bollwyvl Jan 20, 2020
41c5b0c
wait for kernel before initializing notebook adapter to reduce log ou…
bollwyvl Jan 20, 2020
e5ec536
hide more logging
bollwyvl Jan 20, 2020
1ff5b32
squash react log errors
bollwyvl Jan 20, 2020
83c1dd8
squash more errors with checks on widget lifecycle
bollwyvl Jan 20, 2020
95eacdf
more log squashing
bollwyvl Jan 20, 2020
291e525
walk back expectation of kernel readiness, change log squashing approach
bollwyvl Jan 20, 2020
bd6442b
use solve_uris for document_info
bollwyvl Jan 20, 2020
32b6a64
rework document closing behavior
bollwyvl Jan 20, 2020
93c5067
linting
bollwyvl Jan 20, 2020
4ac60a6
handle some open doc issues when closing tabs
bollwyvl Jan 20, 2020
548998b
change connection constructor for searchability
bollwyvl Jan 20, 2020
273c9b6
remove todo on bash, since they are randomized now
bollwyvl Jan 20, 2020
74ebb52
work on behavior of foreign docs, diagnostics and singleton connectio…
bollwyvl Jan 20, 2020
b6df0b7
pyflakes and mypy can both claim the error
bollwyvl Jan 20, 2020
bbb50d4
start working on unit tests
bollwyvl Jan 20, 2020
505c8a6
more work on unit tests (down to 5 failing)
bollwyvl Jan 21, 2020
c6f9f36
temporarily ignore jest test fails on azure
bollwyvl Jan 21, 2020
69559b1
try linking in hot lsp-ws
bollwyvl Jan 21, 2020
79095e6
try entrypoints instead of pkg_resources
bollwyvl Jan 21, 2020
d9f2605
roll back zipp stuff
bollwyvl Jan 22, 2020
9c225e6
activeCell can be null
bollwyvl Jan 22, 2020
a995e11
fix up unit tests through PageConfig, other means
bollwyvl Jan 22, 2020
71fc0e7
uncomment unit tests
bollwyvl Jan 22, 2020
4d5b112
trailing quote
bollwyvl Jan 22, 2020
70d2d39
hide some more warnings from unready connections
bollwyvl Jan 22, 2020
5ee1427
refactor goto to use promises
bollwyvl Jan 22, 2020
949407d
refactor signature to use promises
bollwyvl Jan 22, 2020
1e03f43
more work on promises for signature, hover
bollwyvl Jan 22, 2020
792749e
rework on hover, completion
bollwyvl Jan 22, 2020
763aa6d
typeofpocalypse
bollwyvl Jan 22, 2020
c64556f
handle malformed end ranges
bollwyvl Jan 22, 2020
2be2b68
work on type defs
bollwyvl Jan 22, 2020
4450a0b
more initialization check into notebook setup
bollwyvl Jan 22, 2020
74991ec
restore verbose logging, remove DEBUG
bollwyvl Jan 22, 2020
2d470a1
it would appear server_root no longer does anything
bollwyvl Jan 23, 2020
bbbb4f9
substantially increase ready check interval (50 -> 200)
bollwyvl Jan 23, 2020
f0d38a1
don't react to document changes until connection is ready
bollwyvl Jan 23, 2020
3249d42
Merge remote-tracking branch 'upstream/master' into add-one-socket-pe…
bollwyvl Jan 23, 2020
29be129
some looking at memory profiling
bollwyvl Jan 24, 2020
5763fd4
Merge remote-tracking branch 'upstream/master' into add-one-socket-pe…
bollwyvl Jan 29, 2020
bcb4e65
significant memory leak investigation underway
bollwyvl Jan 30, 2020
2145c42
clear up some more memory leaks
bollwyvl Feb 2, 2020
55bb0d3
clobber debug stuff again
bollwyvl Feb 2, 2020
d384809
handle late cleanup of document vs update
bollwyvl Feb 2, 2020
e2a869c
rework screenshot strategy
bollwyvl Feb 2, 2020
f2a79d6
missing quote
bollwyvl Feb 2, 2020
3fa15ee
rework document closing (connection doesn't go away)
bollwyvl Feb 2, 2020
8ae1b9e
fix completion regression
bollwyvl Feb 2, 2020
36aa419
some cleanup of completion, document updating
bollwyvl Feb 2, 2020
832c7b5
hoist pathChanged concern to plugin level
bollwyvl Feb 2, 2020
87173e1
just bump the max listeners to something ridiculous
bollwyvl Feb 2, 2020
452969b
remove highlight and hover connection_handlers
bollwyvl Feb 2, 2020
33b1b04
restore py38/win tests
bollwyvl Feb 3, 2020
9e7337f
update CHANGELOG
bollwyvl Feb 4, 2020
02569d3
some docs and todos on connection manager
bollwyvl Feb 4, 2020
7e3bc34
merge master
bollwyvl Feb 8, 2020
3d45458
linting
bollwyvl Feb 8, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,4 @@ junit.xml
coverage/
.vscode/
_schema.d.ts
.virtual_documents/
6 changes: 2 additions & 4 deletions atest/01_Editor.robot
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ ${CM CURSORS} css:.CodeMirror-cursors:not([style='visibility: hidden'])

*** Test Cases ***
Bash
[Documentation] TODO: figure out why the first server is extra flaky
Wait Until Keyword Succeeds 6x 5s Editor Shows Features for Language Bash example.sh Diagnostics=Failed to parse expression
... Jump to Definition=fib
Editor Shows Features for Language Bash example.sh Diagnostics=Failed to parse expression Jump to Definition=fib

CSS
${def} = Set Variable xpath:(//span[contains(@class, 'cm-variable-2')][contains(text(), '--some-var')])[last()]
Expand Down Expand Up @@ -67,7 +65,7 @@ Editor Shows Features for Language
Set Tags language:${Language.lower()}
Set Screenshot Directory ${OUTPUT DIR}${/}screenshots${/}editor${/}${Language.lower()}
Copy File examples${/}${file} ${OUTPUT DIR}${/}home${/}${file}
Lab Command Close All Tabs
Try to Close All Tabs
Open ${file} in ${MENU EDITOR}
Capture Page Screenshot 00-opened.png
FOR ${f} IN @{features}
Expand Down
8 changes: 4 additions & 4 deletions atest/03_Notebook.robot
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
*** Settings ***
Suite Setup Setup Suite For Screenshots notebook
Test Setup Try to Close All Tabs
Resource Keywords.robot

*** Test Cases ***
Python
[Setup] Gently Reset Workspace
Setup Notebook Python Python.ipynb
Capture Page Screenshot 01-python.png
${diagnostic} = Set Variable W291 trailing whitespace (pycodestyle)
Expand All @@ -13,11 +13,11 @@ Python
Clean Up After Working With File Python.ipynb

Foregin Extractors
[Setup] Gently Reset Workspace
Setup Notebook Python Foreign extractors.ipynb
@{diagnostics} = Create List Failed to parse expression undefined name 'valid' (pyflakes) Trailing whitespace is superfluous. (lintr)
# if mypy and pyflakes will fight over `(N|n)ame 'valid'`, just hope for the best
@{diagnostics} = Create List Failed to parse expression ame 'valid' Trailing whitespace is superfluous. (lintr)
FOR ${diagnostic} IN @{diagnostics}
Wait Until Page Contains Element css:.cm-lsp-diagnostic[title="${diagnostic}"] timeout=35s
Wait Until Page Contains Element css:.cm-lsp-diagnostic[title*\="${diagnostic}"] timeout=35s
Capture Page Screenshot 0x-${diagnostic}.png
END
Clean Up After Working With File Foreign Extractors.ipynb
7 changes: 0 additions & 7 deletions atest/05_Features/Completion.robot
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ Works With Kernel Running
[Documentation] The suggestions from kernel and LSP should get integrated.
[Tags] language:python
Setup Notebook Python Completion.ipynb
Wait Until Fully Initialized
Enter Cell Editor 1 line=2
Capture Page Screenshot 01-entered-cell.png
Trigger Completer
Expand All @@ -31,7 +30,6 @@ Works With Kernel Running
Works When Kernel Is Shut Down
[Tags] language:python
Setup Notebook Python Completion.ipynb
Wait Until Fully Initialized
Lab Command Shut Down All Kernels…
Capture Page Screenshot 01-shutting-kernels.png
Accept Default Dialog Option
Expand Down Expand Up @@ -59,7 +57,6 @@ User Can Select Lowercase After Starting Uppercase
[Tags] language:python
Setup Notebook Python Completion.ipynb
# `from time import Tim<tab>` → `from time import time`
Wait Until Fully Initialized
Enter Cell Editor 5 line=1
Trigger Completer
Completer Should Suggest time
Expand All @@ -73,7 +70,6 @@ Mid Token Completions Do Not Overwrite
# `disp<tab>data` → `display_table<cursor>data`
Place Cursor In Cell Editor At 9 line=1 character=4
Capture Page Screenshot 01-cursor-placed.png
Wait Until Fully Initialized
Press Keys None TAB
Capture Page Screenshot 02-completed.png
Wait Until Keyword Succeeds 40x 0.5s Cell Editor Should Equal 9 display_tabledata
Expand All @@ -88,7 +84,6 @@ Completion Works For Tokens Separated By Space
Setup Notebook Python Completion.ipynb
# `from statistics <tab>` → `from statistics import<cursor>`
Enter Cell Editor 13 line=1
Wait Until Fully Initialized
Trigger Completer
Completer Should Suggest import
Press Keys None ENTER
Expand All @@ -102,7 +97,6 @@ Kernel And LSP Completions Merge Prefix Conflicts Are Resolved
# `import os.pat<tab>` → `import os.pathsep`
Setup Notebook Python Completion.ipynb
Enter Cell Editor 15 line=1
Wait Until Fully Initialized
Trigger Completer
Completer Should Suggest pathsep
Select Completer Suggestion pathsep
Expand All @@ -113,7 +107,6 @@ Triggers Completer On Dot
[Tags] language:python
Setup Notebook Python Completion.ipynb
Enter Cell Editor 2 line=1
Wait Until Fully Initialized
Press Keys None .
Wait Until Keyword Succeeds 10x 0.5s Cell Editor Should Equal 2 list.
Wait Until Page Contains Element ${COMPLETER_BOX} timeout=35s
Expand Down
1 change: 0 additions & 1 deletion atest/05_Features/Signature.robot
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ ${SIGNATURE_BOX} css:.lsp-signature-help
*** Test Cases ***
Triggers Signature Help After A Keystroke
Setup Notebook Python Signature.ipynb
Wait Until Fully Initialized
Enter Cell Editor 1 line=6
Capture Page Screenshot 01-entered-cell.png
Press Keys None (
Expand Down
18 changes: 14 additions & 4 deletions atest/Keywords.robot
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,17 @@ Open JupyterLab
Close JupyterLab
Close All Browsers

Reset Application State
Close All Tabs
Accept Default Dialog Option
Lab Command Close All Tabs
Accept Default Dialog Option

Try to Close All Tabs
Wait Until Keyword Succeeds 5x 50ms Close All Tabs

Reset Application State
Try to Close All Tabs
Accept Default Dialog Option
Ensure All Kernels Are Shut Down
Lab Command Reset Application State
Wait For Splash
Expand Down Expand Up @@ -174,9 +182,11 @@ Setup Notebook
Set Tags language:${Language.lower()}
Set Screenshot Directory ${OUTPUT DIR}${/}screenshots${/}notebook${/}${file.lower()}
Copy File examples${/}${file} ${OUTPUT DIR}${/}home${/}${file}
Lab Command Close All Tabs
Try to Close All Tabs
Open ${file} in ${MENU NOTEBOOK}
Wait Until Fully Initialized
Capture Page Screenshot 00-opened.png
Capture Page Screenshot 01-initialized.png

Open Diagnostics Panel
Lab Command Show Diagnostics Panel
Expand All @@ -194,7 +204,7 @@ Wait For Dialog
Wait Until Page Contains Element ${DIALOG WINDOW} timeout=180s

Gently Reset Workspace
Lab Command Close All Tabs
Try to Close All Tabs

Enter Cell Editor
[Arguments] ${cell_nr} ${line}=1
Expand All @@ -207,7 +217,7 @@ Place Cursor In Cell Editor At
Execute JavaScript return document.querySelector('.jp-Cell:nth-child(${cell_nr}) .CodeMirror').CodeMirror.setCursor({line: ${line} - 1, ch: ${character}})

Wait Until Fully Initialized
Wait Until Element Contains ${STATUSBAR} Fully initialized timeout=35s
Wait Until Element Contains ${STATUSBAR} Fully initialized timeout=60s
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seemed to reduce flake a fair amount: on a fresh browser load, the lazy load does make the first connection slower to start, so this time isn't getting rolled up into the aggressive up-front animation waiting.


Open Context Menu Over
[Arguments] ${sel}
Expand Down
3 changes: 3 additions & 0 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ variables:
THIRD_PARTY_LABEXTENSIONS: >-
@krassowski/jupyterlab_go_to_definition

LINKED_EXTENSIONS: >-
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should have done this ages ago

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not testing the as-built tarball, but what can you do? that would be an advantage of killing the intermediate layer, as the entire module would be:

export import { ConsoleLogger, listen, MessageConnection } from 'vscode-ws-jsonrpc';

...plus 10 files of boilerplate, and would only need to be updated once an upstream release (if then).

packages/lsp-ws-connection

jobs:
- template: ci/job.lint.yml
- template: ci/job.test.yml
Expand Down
4 changes: 4 additions & 0 deletions ci/job.test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ parameters:
spec: '>=3.8,<3.9.0a0'
lab: '>=1.2.4,<1.3.0a0'
env_update: conda env update -n jupyterlab-lsp --file env-test.yml --quiet
lab_link: jupyter labextension link --no-build $(LINKED_EXTENSIONS)
lab_ext: jupyter labextension install --no-build $(THIRD_PARTY_LABEXTENSIONS) $(FIRST_PARTY_LABEXTENSIONS)

jobs:
Expand Down Expand Up @@ -79,6 +80,9 @@ jobs:
- script: ${{ platform.activate }} jupyterlab-lsp && python scripts/utest.py --test-run-title="Pytest ${{ platform.name }}${{ python.name }}"
displayName: run python tests

- script: ${{ platform.activate }} jupyterlab-lsp && ${{ parameters.lab_link }} || ${{ parameters.lab_link }} || ${{ parameters.lab_link }}
displayName: install support packages

- script: ${{ platform.activate }} jupyterlab-lsp && ${{ parameters.lab_ext }} || ${{ parameters.lab_ext }} || ${{ parameters.lab_ext }}
displayName: install labextensions

Expand Down
23 changes: 16 additions & 7 deletions packages/jupyterlab-lsp/src/adapters/codemirror/cm_adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,28 @@ export class CodeMirrorAdapter {

public async updateAfterChange() {
this.jupyterlab_components.remove_tooltip();
await until_ready(() => this.last_change != null, 30, 22).catch(() => {
this.invalidateLastChange();
throw Error(

try {
await until_ready(() => this.last_change != null, 30, 22);
} catch (err) {
console.log(
'No change obtained from CodeMirror editor within the expected time of 0.66s'
);
});
return;
}

let change: CodeMirror.EditorChange = this.last_change;

let root_position: IRootPosition;

try {
const root_position = this.editor
.getDoc()
.getCursor('end') as IRootPosition;
root_position = this.editor.getDoc().getCursor('end') as IRootPosition;
} catch (err) {
console.log('LSP: Root positon not found');
return;
}

try {
let document = this.editor.document_at_root_position(root_position);

if (this.virtual_document !== document) {
Expand Down
16 changes: 10 additions & 6 deletions packages/jupyterlab-lsp/src/adapters/codemirror/feature.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { nbformat } from '@jupyterlab/coreutils';
import { language_specific_overrides } from '../../magics/defaults';
import { foreign_code_extractors } from '../../extractors/defaults';
import { NotebookModel } from '@jupyterlab/notebook';
import { PageConfig } from '@jupyterlab/coreutils';

const js_fib_code = `function fib(n) {
return n<2?n:fib(n-1)+fib(n-2);
Expand Down Expand Up @@ -94,6 +95,8 @@ const js_partial_edits = [
];

describe('Feature', () => {
PageConfig.setOption('rootUri', 'file://');

describe('apply_edit()', () => {
class EditApplyingFeature extends CodeMirrorLSPFeature {
name = 'EditApplyingFeature';
Expand Down Expand Up @@ -248,9 +251,9 @@ describe('Feature', () => {
'def a_function_2():\n pass\n\n\nx = a_function_2()\n';
expect(main_document.value).to.be.equal(old_virtual_source);

let result = await feature.do_apply_edit({
let outcome = await feature.do_apply_edit({
changes: {
['file://' + environment.path()]: [
[main_document.document_info.uri]: [
{
range: {
start: { line: 0, character: 0 },
Expand All @@ -261,6 +264,7 @@ describe('Feature', () => {
]
}
});

await synchronizeContent();

let value = main_document.value;
Expand All @@ -274,9 +278,9 @@ describe('Feature', () => {
);
expect(code_cells[1]).to.have.property('source', 'x = a_function_2()');

expect(result.appliedChanges).to.be.equal(null);
expect(result.wasGranular).to.be.equal(false);
expect(result.modifiedCells).to.be.equal(2);
expect(outcome.appliedChanges).to.be.equal(null);
expect(outcome.wasGranular).to.be.equal(false);
expect(outcome.modifiedCells).to.be.equal(2);
});

it('handles IPython magics', async () => {
Expand Down Expand Up @@ -317,7 +321,7 @@ print(x)""")

await feature.do_apply_edit({
changes: {
['file://' + environment.path()]: [
[main_document.document_info.uri]: [
{
range: {
start: { line: 0, character: 0 },
Expand Down
6 changes: 4 additions & 2 deletions packages/jupyterlab-lsp/src/adapters/codemirror/feature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ export abstract class CodeMirrorLSPFeature implements ILSPFeature {
let start = PositionConverter.lsp_to_cm(range.start) as IVirtualPosition;
let end = PositionConverter.lsp_to_cm(range.end) as IVirtualPosition;

if (typeof cm_editor === 'undefined') {
if (cm_editor == null) {
let start_in_root = this.transform_virtual_position_to_root_position(
start
);
Expand Down Expand Up @@ -278,7 +278,8 @@ export abstract class CodeMirrorLSPFeature implements ILSPFeature {
protected async apply_edit(
workspaceEdit: lsProtocol.WorkspaceEdit
): Promise<IEditOutcome> {
let current_uri = this.connection.getDocumentUri();
let current_uri = this.virtual_document.document_info.uri;

// Specs: documentChanges are preferred over changes
let changes = workspaceEdit.documentChanges
? workspaceEdit.documentChanges.map(
Expand All @@ -292,6 +293,7 @@ export abstract class CodeMirrorLSPFeature implements ILSPFeature {

for (let change of changes) {
let uri = change.textDocument.uri;

if (
decodeURI(uri) !== decodeURI(current_uri) &&
decodeURI(uri) !== '/' + decodeURI(current_uri)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export class Completion extends CodeMirrorLSPFeature {

get completionCharacters() {
if (
typeof this._completionCharacters === 'undefined' ||
this._completionCharacters == null ||
!this._completionCharacters.length
) {
this._completionCharacters = this.connection.getLanguageCompletionCharacters();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as CodeMirror from 'codemirror';
import * as lsProtocol from 'vscode-languageserver-protocol';
import { Menu } from '@phosphor/widgets';
import { PositionConverter } from '../../../converter';
import { IVirtualPosition } from '../../../positioning';
import { IVirtualPosition, IEditorPosition } from '../../../positioning';
import { diagnosticSeverityNames } from '../../../lsp';
import { DefaultMap } from '../../../utils';
import { CodeMirrorLSPFeature, IFeatureCommand } from '../feature';
Expand All @@ -14,7 +14,6 @@ import {
IEditorDiagnostic
} from './diagnostics_listing';
import { VirtualDocument } from '../../../virtual/document';
import { DocumentConnectionManager } from '../../../connection_manager';
import { VirtualEditor } from '../../../virtual/editor';

// TODO: settings
Expand Down Expand Up @@ -118,7 +117,6 @@ export class Diagnostics extends CodeMirrorLSPFeature {
}

if (!panel_widget.isAttached) {
console.warn(adapter.widget_id);
app.shell.add(panel_widget, 'main', {
ref: adapter.widget_id,
mode: 'split-bottom'
Expand Down Expand Up @@ -223,19 +221,13 @@ export class Diagnostics extends CodeMirrorLSPFeature {
}

public handleDiagnostic(response: lsProtocol.PublishDiagnosticsParams) {
if (response.uri !== this.virtual_document.document_info.uri) {
return;
}
/* TODO: gutters */
try {
let diagnostics_list: IEditorDiagnostic[] = [];

let my_uri = DocumentConnectionManager.solve_uris(
this.virtual_document,
''
).document;

if (response.uri !== my_uri) {
return;
}

// Note: no deep equal for Sets or Maps in JS
const markers_to_retain: Set<string> = new Set();

Expand Down Expand Up @@ -311,7 +303,16 @@ export class Diagnostics extends CodeMirrorLSPFeature {
let cm_editor = document.get_editor_at_virtual_line(start);

let start_in_editor = document.transform_virtual_to_editor(start);
let end_in_editor = document.transform_virtual_to_editor(end);
let end_in_editor: IEditorPosition;

// some servers return strange positions for ends
try {
end_in_editor = document.transform_virtual_to_editor(end);
} catch (err) {
console.warn('LSP: Malformed range for diagnostic', end);
end_in_editor = { ...start_in_editor, ch: start_in_editor.ch + 1 };
}

let range_in_editor = {
start: start_in_editor,
end: end_in_editor
Expand Down Expand Up @@ -408,7 +409,7 @@ export function message_without_code(diagnostic: lsProtocol.Diagnostic) {
let message = diagnostic.message;
let code_str = '' + diagnostic.code;
if (
typeof diagnostic.code !== 'undefined' &&
diagnostic.code != null &&
diagnostic.code !== '' &&
message.startsWith(code_str + '')
) {
Expand Down
Loading