Skip to content

Commit 48637de

Browse files
authored
Merge branch 'master' into backend-status
2 parents f32b49d + 0a0d5c9 commit 48637de

File tree

7 files changed

+97
-20
lines changed

7 files changed

+97
-20
lines changed

CHANGELOG.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,28 @@
99

1010
- bug fixes:
1111

12-
- fix completions with R double and triple colon prefix ([#449])
13-
- fix contrast on status icon when status item is active ([#465])
14-
- fix connection manager loosing track of notebooks when multiple were open ([#474])
12+
- namespace completions in R (after double and triple colon) now work properly ([#449])
13+
- improved status icon contrast when status item is active ([#465])
14+
- connection manager now properly keeps track of notebooks when multiple notebooks are open ([#474])
15+
- new cells added after kernel restart now work properly; kernel changes are handled correctly ([#478])
1516

1617
[#449]: https://github.com/krassowski/jupyterlab-lsp/pull/449
1718
[#465]: https://github.com/krassowski/jupyterlab-lsp/pull/465
1819
[#474]: https://github.com/krassowski/jupyterlab-lsp/pull/474
1920
[#476]: https://github.com/krassowski/jupyterlab-lsp/pull/476
21+
[#478]: https://github.com/krassowski/jupyterlab-lsp/pull/478
2022

2123
### `jupyter-lsp 1.0.1` (unreleased)
2224

2325
- bug fixes:
2426

2527
- send periodic pings on websocket channels to maintain connection ([#459], thanks @franckchen)
2628
- R languageserver is no longer incorrectly shown as available when not installed ([#463])
29+
- fix completion of very large namespaces (e.g. in R's base or in JavaScript) due to truncated message relay ([#477])
2730

2831
[#459]: https://github.com/krassowski/jupyterlab-lsp/pull/459
2932
[#463]: https://github.com/krassowski/jupyterlab-lsp/pull/463
33+
[#477]: https://github.com/krassowski/jupyterlab-lsp/pull/477
3034

3135
### `@krassowski/jupyterlab-lsp 3.0.0` (2021-01-06)
3236

atest/05_Features/Completion.robot

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Works With Kernel Running
2828

2929
Works When Kernel Is Shut Down
3030
Lab Command Shut Down All Kernels…
31+
Wait For Dialog
3132
Capture Page Screenshot 01-shutting-kernels.png
3233
Accept Default Dialog Option
3334
Capture Page Screenshot 02-kernels-shut.png
@@ -39,6 +40,21 @@ Works When Kernel Is Shut Down
3940
# this comes from kernel:
4041
Completer Should Not Suggest %%timeit
4142

43+
Works After Kernel Restart In New Cells
44+
Lab Command Restart Kernel…
45+
Wait For Dialog
46+
Accept Default Dialog Option
47+
Enter Cell Editor 1 line=2
48+
# works in old cells
49+
Trigger Completer
50+
Completer Should Suggest test
51+
Lab Command Insert Cell Below
52+
Enter Cell Editor 2 line=1
53+
# works in new cells
54+
Press Keys None lis
55+
Trigger Completer
56+
Completer Should Suggest list
57+
4258
Works In File Editor
4359
[Setup] Prepare File for Editing Python completion completion.py
4460
Place Cursor In File Editor At 9 2
@@ -203,6 +219,14 @@ Completes Correctly With R Double And Triple Colon
203219
Wait Until Keyword Succeeds 40x 0.5s File Editor Line Should Equal 3 datasets:::.packageName
204220
[Teardown] Clean Up After Working With File completion.R
205221

222+
Completes Large Namespaces
223+
[Setup] Prepare File for Editing R completion completion.R
224+
Place Cursor In File Editor At 6 7
225+
Wait Until Fully Initialized
226+
Trigger Completer
227+
Completer Should Suggest abs timeout=30s
228+
[Teardown] Clean Up After Working With File completion.R
229+
206230
*** Keywords ***
207231
Setup Completion Test
208232
Setup Notebook Python Completion.ipynb
@@ -235,8 +259,8 @@ Select Completer Suggestion
235259
Click Element ${suggestion} code
236260

237261
Completer Should Suggest
238-
[Arguments] ${text}
239-
Wait Until Page Contains Element ${COMPLETER_BOX} .jp-Completer-item[data-value="${text}"] timeout=10s
262+
[Arguments] ${text} ${timeout}=10s
263+
Wait Until Page Contains Element ${COMPLETER_BOX} .jp-Completer-item[data-value="${text}"] timeout=${timeout}
240264
Capture Page Screenshot ${text.replace(' ', '_')}.png
241265

242266
Completer Should Include Icon

atest/examples/completion.R

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@
22
tools::
33
# `datasets:::<tab>` → select `.packageName` → `datasets:::.packageName`
44
datasets:::
5+
# `base:::<tab>` → works
6+
base:::

docs/Configuring.ipynb

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,9 @@
210210
},
211211
{
212212
"cell_type": "markdown",
213+
"metadata": {
214+
"collapsed": false
215+
},
213216
"source": [
214217
"### Example: Scala Language Server (metals) integration with jupyterlab-lsp\n",
215218
"\n",
@@ -225,11 +228,13 @@
225228
"$ ./coursier launch --fork almond -- --install\n",
226229
"$ rm -f coursier\n",
227230
"```\n",
231+
"\n",
228232
"Spark Magic kernel:\n",
229233
"\n",
230234
"```bash\n",
231235
"pip install sparkmagic\n",
232236
"```\n",
237+
"\n",
233238
"Now, install the spark kernel:\n",
234239
"\n",
235240
"```bash\n",
@@ -247,7 +252,8 @@
247252
"\n",
248253
"(Might need to use the --force-fetch flag if you are getting dependency issues.)\n",
249254
"\n",
250-
"Step 3: Configure the metals server in jupyterlab-lsp. Enter the following in the jupyter_server_config.json:\n",
255+
"Step 3: Configure the metals server in jupyterlab-lsp. Enter the following in\n",
256+
"the jupyter_server_config.json:\n",
251257
"\n",
252258
"```python\n",
253259
"{\n",
@@ -264,11 +270,10 @@
264270
"}\n",
265271
"```\n",
266272
"\n",
267-
"You are good to go now! Just start `jupyter lab` and create a notebook with either the Spark or the Scala kernel and you should be able to see the metals server initialised from the bottom left corner."
268-
],
269-
"metadata": {
270-
"collapsed": false
271-
}
273+
"You are good to go now! Just start `jupyter lab` and create a notebook with\n",
274+
"either the Spark or the Scala kernel and you should be able to see the metals\n",
275+
"server initialised from the bottom left corner."
276+
]
272277
}
273278
],
274279
"metadata": {

packages/jupyterlab-lsp/src/adapters/adapter.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,17 @@ export abstract class WidgetAdapter<T extends IDocumentWidget> {
236236
);
237237

238238
// recreate virtual document using current path and language
239-
let virtual_document = this.create_virtual_document();
240-
this.virtual_editor.virtual_document = virtual_document;
239+
// as virtual editor assumes it gets the virtual document at init,
240+
// just dispose virtual editor (which disposes virtual document too)
241+
// and re-initialize both virtual editor and document
242+
this.virtual_editor.dispose();
243+
244+
this.init_virtual();
245+
241246
// reconnect
242-
this.connect_document(virtual_document, true).catch(console.warn);
247+
this.connect_document(this.virtual_editor.virtual_document, true).catch(
248+
console.warn
249+
);
243250
}
244251

245252
protected on_save_state(context: any, state: DocumentRegistry.SaveState) {

python_packages/jupyter_lsp/jupyter_lsp/specs/utils.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,12 @@ def __call__(self, mgr: LanguageServerManagerAPI) -> KeyedLanguageServerSpecs:
6767
if cmd:
6868
break
6969

70-
if not cmd and BUILDING_DOCS: # pragma: no cover
71-
cmd = self.cmd
72-
7370
if not self.is_installed(cmd): # pragma: no cover
7471
return {}
7572

73+
if not cmd and BUILDING_DOCS: # pragma: no cover
74+
cmd = self.cmd
75+
7676
return {
7777
self.key: {
7878
"argv": [cmd, *self.args],

python_packages/jupyter_lsp/jupyter_lsp/stdio.py

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import io
1313
import os
1414
from concurrent.futures import ThreadPoolExecutor
15-
from typing import Text
15+
from typing import List, Optional, Text
1616

1717
from tornado.concurrent import run_on_executor
1818
from tornado.gen import convert_yielded
@@ -30,7 +30,9 @@ class LspStdIoBase(LoggingConfigurable):
3030

3131
executor = None
3232

33-
stream = Instance(io.BufferedIOBase, help="the stream to read/write")
33+
stream = Instance(
34+
io.BufferedIOBase, help="the stream to read/write"
35+
) # type: io.BufferedIOBase
3436
queue = Instance(Queue, help="queue to get/put")
3537

3638
def __repr__(self): # pragma: no cover
@@ -95,6 +97,39 @@ async def read(self) -> None:
9597
self.log.exception("%s couldn't enqueue message: %s", self, message)
9698
await self.sleep()
9799

100+
def _read_content(self, length: int, max_parts=1000) -> Optional[bytes]:
101+
"""Read the full length of the message unless exceeding max_parts.
102+
103+
See https://github.com/krassowski/jupyterlab-lsp/issues/450
104+
105+
Crucial docs or read():
106+
"If the argument is positive, and the underlying raw
107+
stream is not interactive, multiple raw reads may be issued
108+
to satisfy the byte count (unless EOF is reached first)"
109+
110+
Args:
111+
- length: the content length
112+
- max_parts: prevent absurdly long messages (1000 parts is several MBs):
113+
1 part is usually sufficent but not enough for some long
114+
messages 2 or 3 parts are often needed.
115+
"""
116+
raw_parts: List[bytes] = []
117+
received_size = 0
118+
while received_size < length and len(raw_parts) < max_parts:
119+
part = self.stream.read(length)
120+
if part is None:
121+
break # pragma: no cover
122+
received_size += len(part)
123+
raw_parts.append(part)
124+
125+
if raw_parts:
126+
raw = b"".join(raw_parts)
127+
if len(raw) != length: # pragma: no cover
128+
self.log.warning(
129+
f"Readout and content-length mismatch:" f" {len(raw)} vs {length}"
130+
)
131+
return raw
132+
98133
async def read_one(self) -> Text:
99134
"""Read a single message"""
100135
message = ""
@@ -114,7 +149,7 @@ async def read_one(self) -> Text:
114149
retries = 5
115150
while raw is None and retries:
116151
try:
117-
raw = self.stream.read(content_length)
152+
raw = self._read_content(length=content_length)
118153
except OSError: # pragma: no cover
119154
raw = None
120155
if raw is None: # pragma: no cover

0 commit comments

Comments
 (0)