@difizen/libro-lsp 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +0 -0
- package/es/adapters/adapter.d.ts +255 -0
- package/es/adapters/adapter.d.ts.map +1 -0
- package/es/adapters/adapter.js +647 -0
- package/es/adapters/notebook-adapter.d.ts +150 -0
- package/es/adapters/notebook-adapter.d.ts.map +1 -0
- package/es/adapters/notebook-adapter.js +588 -0
- package/es/adapters/status-message.d.ts +48 -0
- package/es/adapters/status-message.d.ts.map +1 -0
- package/es/adapters/status-message.js +110 -0
- package/es/connection-manager.d.ts +199 -0
- package/es/connection-manager.d.ts.map +1 -0
- package/es/connection-manager.js +685 -0
- package/es/connection.d.ts +149 -0
- package/es/connection.d.ts.map +1 -0
- package/es/connection.js +591 -0
- package/es/extractors/index.d.ts +4 -0
- package/es/extractors/index.d.ts.map +1 -0
- package/es/extractors/index.js +6 -0
- package/es/extractors/manager.d.ts +31 -0
- package/es/extractors/manager.d.ts.map +1 -0
- package/es/extractors/manager.js +90 -0
- package/es/extractors/text-extractor.d.ts +56 -0
- package/es/extractors/text-extractor.d.ts.map +1 -0
- package/es/extractors/text-extractor.js +72 -0
- package/es/extractors/types.d.ts +68 -0
- package/es/extractors/types.d.ts.map +1 -0
- package/es/extractors/types.js +1 -0
- package/es/feature.d.ts +29 -0
- package/es/feature.d.ts.map +1 -0
- package/es/feature.js +85 -0
- package/es/index.d.ts +19 -0
- package/es/index.d.ts.map +1 -0
- package/es/index.js +21 -0
- package/es/lsp-app-contribution.d.ts +19 -0
- package/es/lsp-app-contribution.d.ts.map +1 -0
- package/es/lsp-app-contribution.js +155 -0
- package/es/lsp-protocol.d.ts +10 -0
- package/es/lsp-protocol.d.ts.map +1 -0
- package/es/lsp-protocol.js +1 -0
- package/es/lsp.d.ts +136 -0
- package/es/lsp.d.ts.map +1 -0
- package/es/lsp.js +141 -0
- package/es/manager.d.ts +142 -0
- package/es/manager.d.ts.map +1 -0
- package/es/manager.js +423 -0
- package/es/module.d.ts +3 -0
- package/es/module.d.ts.map +1 -0
- package/es/module.js +21 -0
- package/es/plugin.d.ts +56 -0
- package/es/plugin.d.ts.map +1 -0
- package/es/plugin.js +0 -0
- package/es/positioning.d.ts +66 -0
- package/es/positioning.d.ts.map +1 -0
- package/es/positioning.js +96 -0
- package/es/schema.d.ts +240 -0
- package/es/schema.d.ts.map +1 -0
- package/es/schema.js +0 -0
- package/es/tokens.d.ts +677 -0
- package/es/tokens.d.ts.map +1 -0
- package/es/tokens.js +183 -0
- package/es/utils.d.ts +33 -0
- package/es/utils.d.ts.map +1 -0
- package/es/utils.js +168 -0
- package/es/virtual/document.d.ts +546 -0
- package/es/virtual/document.d.ts.map +1 -0
- package/es/virtual/document.js +1263 -0
- package/es/ws-connection/server-capability-registration.d.ts +19 -0
- package/es/ws-connection/server-capability-registration.d.ts.map +1 -0
- package/es/ws-connection/server-capability-registration.js +51 -0
- package/es/ws-connection/types.d.ts +76 -0
- package/es/ws-connection/types.d.ts.map +1 -0
- package/es/ws-connection/types.js +1 -0
- package/es/ws-connection/ws-connection.d.ts +105 -0
- package/es/ws-connection/ws-connection.d.ts.map +1 -0
- package/es/ws-connection/ws-connection.js +301 -0
- package/package.json +67 -0
- package/src/adapters/adapter.ts +611 -0
- package/src/adapters/notebook-adapter.ts +463 -0
- package/src/adapters/status-message.ts +93 -0
- package/src/connection-manager.ts +626 -0
- package/src/connection.ts +570 -0
- package/src/extractors/index.ts +6 -0
- package/src/extractors/manager.ts +82 -0
- package/src/extractors/text-extractor.ts +94 -0
- package/src/extractors/types.ts +78 -0
- package/src/feature.ts +60 -0
- package/src/index.spec.ts +10 -0
- package/src/index.ts +21 -0
- package/src/lsp-app-contribution.ts +83 -0
- package/src/lsp-protocol.ts +10 -0
- package/src/lsp.ts +160 -0
- package/src/manager.ts +358 -0
- package/src/module.ts +32 -0
- package/src/plugin.ts +62 -0
- package/src/positioning.ts +121 -0
- package/src/schema.ts +249 -0
- package/src/tokens.ts +843 -0
- package/src/utils.ts +109 -0
- package/src/virtual/document.ts +1250 -0
- package/src/ws-connection/server-capability-registration.ts +77 -0
- package/src/ws-connection/types.ts +102 -0
- package/src/ws-connection/ws-connection.ts +320 -0
package/src/manager.ts
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
// Copyright (c) Jupyter Development Team.
|
|
2
|
+
// Distributed under the terms of the Modified BSD License.
|
|
3
|
+
|
|
4
|
+
import { URL } from '@difizen/libro-common';
|
|
5
|
+
import type { ISettings } from '@difizen/libro-kernel';
|
|
6
|
+
import { PageConfig, ServerConnection, ServerManager } from '@difizen/libro-kernel';
|
|
7
|
+
import type { Event } from '@difizen/mana-app';
|
|
8
|
+
import { Deferred, Emitter } from '@difizen/mana-app';
|
|
9
|
+
import { inject, postConstruct, transient } from '@difizen/mana-app';
|
|
10
|
+
|
|
11
|
+
import type { ServerSpecProperties } from './schema.js';
|
|
12
|
+
import { ILanguageServerManagerOptions, URL_NS } from './tokens.js';
|
|
13
|
+
import type {
|
|
14
|
+
IGetServerIdOptions,
|
|
15
|
+
ILanguageServerManager,
|
|
16
|
+
TLanguageServerConfigurations,
|
|
17
|
+
TLanguageServerId,
|
|
18
|
+
TSessionMap,
|
|
19
|
+
TSpecsMap,
|
|
20
|
+
} from './tokens.js';
|
|
21
|
+
|
|
22
|
+
@transient()
|
|
23
|
+
export class LanguageServerManager implements ILanguageServerManager {
|
|
24
|
+
@inject(ServerConnection) serverConnection!: ServerConnection;
|
|
25
|
+
@inject(ServerManager) serverManager!: ServerManager;
|
|
26
|
+
constructor(
|
|
27
|
+
@inject(ILanguageServerManagerOptions) options: ILanguageServerManagerOptions,
|
|
28
|
+
) {
|
|
29
|
+
this._baseUrl = options.baseUrl || PageConfig.getBaseUrl();
|
|
30
|
+
this._retries = options.retries || 2;
|
|
31
|
+
this._retriesInterval = options.retriesInterval || 10000;
|
|
32
|
+
this._statusCode = -1;
|
|
33
|
+
this._configuration = {};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@postConstruct()
|
|
37
|
+
init() {
|
|
38
|
+
this.serverManager.ready
|
|
39
|
+
.then(() => {
|
|
40
|
+
this.fetchSessions();
|
|
41
|
+
return;
|
|
42
|
+
})
|
|
43
|
+
.catch(console.error);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Check if the manager is enabled or disabled
|
|
48
|
+
*/
|
|
49
|
+
get isEnabled(): boolean {
|
|
50
|
+
return this._enabled;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Check if the manager is disposed.
|
|
54
|
+
*/
|
|
55
|
+
get isDisposed(): boolean {
|
|
56
|
+
return this._isDisposed;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Get the language server specs.
|
|
61
|
+
*/
|
|
62
|
+
get specs(): TSpecsMap {
|
|
63
|
+
return this._specs;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Get the status end point.
|
|
68
|
+
*/
|
|
69
|
+
get statusUrl(): string {
|
|
70
|
+
const baseUrl = this.serverConnection.settings.baseUrl ?? this._baseUrl;
|
|
71
|
+
return URL.join(baseUrl, URL_NS, 'status');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Signal emitted when a language server session is changed
|
|
76
|
+
*/
|
|
77
|
+
get sessionsChanged(): Event<void> {
|
|
78
|
+
return this._sessionsChanged.event;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Get the map of language server sessions.
|
|
83
|
+
*/
|
|
84
|
+
get sessions(): TSessionMap {
|
|
85
|
+
return this._sessions;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* A promise resolved when this server manager is ready.
|
|
90
|
+
*/
|
|
91
|
+
get ready(): Promise<void> {
|
|
92
|
+
return this._ready.promise;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get the status code of server's responses.
|
|
97
|
+
*/
|
|
98
|
+
get statusCode(): number {
|
|
99
|
+
return this._statusCode;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Enable the language server services
|
|
104
|
+
*/
|
|
105
|
+
async enable(): Promise<void> {
|
|
106
|
+
this._enabled = true;
|
|
107
|
+
await this.fetchSessions();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Disable the language server services
|
|
112
|
+
*/
|
|
113
|
+
disable(): void {
|
|
114
|
+
this._enabled = false;
|
|
115
|
+
this._sessions = new Map();
|
|
116
|
+
this._sessionsChanged.fire(void 0);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Dispose the manager.
|
|
121
|
+
*/
|
|
122
|
+
dispose(): void {
|
|
123
|
+
if (this._isDisposed) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
this._isDisposed = true;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Update the language server configuration.
|
|
131
|
+
*/
|
|
132
|
+
setConfiguration(configuration: TLanguageServerConfigurations): void {
|
|
133
|
+
this._configuration = configuration;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Get matching language server for input language option.
|
|
138
|
+
*
|
|
139
|
+
* modify lsp server rank on ~/.jupyter/lab/user-settings/@jupyterlab/lsp-extension
|
|
140
|
+
*/
|
|
141
|
+
getMatchingServers(options: IGetServerIdOptions): TLanguageServerId[] {
|
|
142
|
+
if (!options.language) {
|
|
143
|
+
console.error(
|
|
144
|
+
'Cannot match server by language: language not available; ensure that kernel and specs provide language and MIME type',
|
|
145
|
+
);
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const matchingSessionsKeys: TLanguageServerId[] = [];
|
|
150
|
+
|
|
151
|
+
for (const [key, session] of this._sessions.entries()) {
|
|
152
|
+
if (this.isMatchingSpec(options, session.spec)) {
|
|
153
|
+
matchingSessionsKeys.push(key);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return matchingSessionsKeys.sort(this.compareRanks.bind(this));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Get matching language server spec for input language option.
|
|
162
|
+
*/
|
|
163
|
+
getMatchingSpecs(options: IGetServerIdOptions): TSpecsMap {
|
|
164
|
+
const result: TSpecsMap = new Map();
|
|
165
|
+
|
|
166
|
+
for (const [key, specification] of this._specs.entries()) {
|
|
167
|
+
if (this.isMatchingSpec(options, specification)) {
|
|
168
|
+
result.set(key, specification);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return result;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Fetch the server session list from the status endpoint. The server
|
|
176
|
+
* manager is ready once this method finishes.
|
|
177
|
+
*/
|
|
178
|
+
async fetchSessions(): Promise<void> {
|
|
179
|
+
if (!this._enabled) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
let sessions: Record<string, any>;
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
const response = await this.serverConnection.makeRequest(this.statusUrl, {});
|
|
187
|
+
|
|
188
|
+
this._statusCode = response.status;
|
|
189
|
+
if (!response.ok) {
|
|
190
|
+
if (this._retries > 0) {
|
|
191
|
+
this._retries -= 1;
|
|
192
|
+
setTimeout(this.fetchSessions.bind(this), this._retriesInterval);
|
|
193
|
+
} else {
|
|
194
|
+
this._ready.resolve(undefined);
|
|
195
|
+
console.warn('Missing jupyter_lsp server extension, skipping.');
|
|
196
|
+
}
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
const data = await response.json();
|
|
200
|
+
sessions = data.sessions;
|
|
201
|
+
try {
|
|
202
|
+
this.version = data.version;
|
|
203
|
+
this._specs = new Map(Object.entries(data.specs)) as TSpecsMap;
|
|
204
|
+
} catch (err) {
|
|
205
|
+
console.warn(err);
|
|
206
|
+
}
|
|
207
|
+
} catch (err) {
|
|
208
|
+
console.warn(err);
|
|
209
|
+
this._ready.resolve(undefined);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
for (const key of Object.keys(sessions)) {
|
|
214
|
+
const id: TLanguageServerId = key as TLanguageServerId;
|
|
215
|
+
if (this._sessions.has(id)) {
|
|
216
|
+
Object.assign(this._sessions.get(id)!, sessions[key]);
|
|
217
|
+
} else {
|
|
218
|
+
this._sessions.set(id, sessions[key]);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const oldKeys = this._sessions.keys();
|
|
223
|
+
|
|
224
|
+
for (const oldKey in oldKeys) {
|
|
225
|
+
if (!sessions[oldKey]) {
|
|
226
|
+
const oldId = oldKey as TLanguageServerId;
|
|
227
|
+
this._sessions.delete(oldId);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
this._sessionsChanged.fire(void 0);
|
|
231
|
+
this._ready.resolve(undefined);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Version number of sever session.
|
|
236
|
+
*/
|
|
237
|
+
protected version: number;
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Check if input language option maths the language server spec.
|
|
241
|
+
*/
|
|
242
|
+
protected isMatchingSpec(
|
|
243
|
+
options: IGetServerIdOptions,
|
|
244
|
+
spec: ServerSpecProperties,
|
|
245
|
+
): boolean {
|
|
246
|
+
// most things speak language
|
|
247
|
+
// if language is not known, it is guessed based on MIME type earlier
|
|
248
|
+
// so some language should be available by now (which can be not so obvious, e.g. "plain" for txt documents)
|
|
249
|
+
const lowerCaseLanguage = options.language!.toLocaleLowerCase();
|
|
250
|
+
return spec.languages!.some(
|
|
251
|
+
(language: string) => language.toLocaleLowerCase() === lowerCaseLanguage,
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Helper function to warn a message only once.
|
|
257
|
+
*/
|
|
258
|
+
protected warnOnce(arg: string): void {
|
|
259
|
+
if (!this._warningsEmitted.has(arg)) {
|
|
260
|
+
this._warningsEmitted.add(arg);
|
|
261
|
+
console.warn(arg);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Compare the rank of two servers with the same language.
|
|
267
|
+
*/
|
|
268
|
+
protected compareRanks(a: TLanguageServerId, b: TLanguageServerId): number {
|
|
269
|
+
const DEFAULT_RANK = 50;
|
|
270
|
+
const defaultServerRank: Record<TLanguageServerId, number> = {
|
|
271
|
+
'pyright-extended': DEFAULT_RANK + 3,
|
|
272
|
+
pyright: DEFAULT_RANK + 2,
|
|
273
|
+
pylsp: DEFAULT_RANK + 1,
|
|
274
|
+
'bash-language-server': DEFAULT_RANK,
|
|
275
|
+
'dockerfile-language-server-nodejs': DEFAULT_RANK,
|
|
276
|
+
'javascript-typescript-langserver': DEFAULT_RANK,
|
|
277
|
+
'unified-language-server': DEFAULT_RANK,
|
|
278
|
+
'vscode-css-languageserver-bin': DEFAULT_RANK,
|
|
279
|
+
'vscode-html-languageserver-bin': DEFAULT_RANK,
|
|
280
|
+
'vscode-json-languageserver-bin': DEFAULT_RANK,
|
|
281
|
+
'yaml-language-server': DEFAULT_RANK,
|
|
282
|
+
'r-languageserver': DEFAULT_RANK,
|
|
283
|
+
} as const;
|
|
284
|
+
const aRank = this._configuration[a]?.rank ?? defaultServerRank[a] ?? DEFAULT_RANK;
|
|
285
|
+
const bRank = this._configuration[b]?.rank ?? defaultServerRank[b] ?? DEFAULT_RANK;
|
|
286
|
+
|
|
287
|
+
if (aRank === bRank) {
|
|
288
|
+
this.warnOnce(
|
|
289
|
+
`Two matching servers: ${a} and ${b} have the same rank; choose which one to use by changing the rank in Advanced Settings Editor`,
|
|
290
|
+
);
|
|
291
|
+
return a.localeCompare(b);
|
|
292
|
+
}
|
|
293
|
+
// higher rank = higher in the list (descending order)
|
|
294
|
+
return bRank - aRank;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* map of language server sessions.
|
|
299
|
+
*/
|
|
300
|
+
protected _sessions: TSessionMap = new Map();
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Map of language server specs.
|
|
304
|
+
*/
|
|
305
|
+
protected _specs: TSpecsMap = new Map();
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Server connection setting.
|
|
309
|
+
*/
|
|
310
|
+
protected _settings: ISettings;
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Base URL to connect to the language server handler.
|
|
314
|
+
*/
|
|
315
|
+
protected _baseUrl: string;
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Status code of server response
|
|
319
|
+
*/
|
|
320
|
+
protected _statusCode: number;
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Number of connection retry, default to 2.
|
|
324
|
+
*/
|
|
325
|
+
protected _retries: number;
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Interval between each retry, default to 10s.
|
|
329
|
+
*/
|
|
330
|
+
protected _retriesInterval: number;
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Language server configuration.
|
|
334
|
+
*/
|
|
335
|
+
protected _configuration: TLanguageServerConfigurations;
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Set of emitted warning message, message in this set will not be warned again.
|
|
339
|
+
*/
|
|
340
|
+
protected _warningsEmitted = new Set<string>();
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* A promise resolved when this server manager is ready.
|
|
344
|
+
*/
|
|
345
|
+
protected _ready = new Deferred<void>();
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Signal emitted when a language server session is changed
|
|
349
|
+
*/
|
|
350
|
+
protected _sessionsChanged = new Emitter<void>();
|
|
351
|
+
|
|
352
|
+
protected _isDisposed = false;
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Check if the manager is enabled or disabled
|
|
356
|
+
*/
|
|
357
|
+
protected _enabled = true;
|
|
358
|
+
}
|
package/src/module.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { LibroServerModule } from '@difizen/libro-kernel';
|
|
2
|
+
import { ManaModule } from '@difizen/mana-app';
|
|
3
|
+
|
|
4
|
+
import { DocumentConnectionManager } from './connection-manager.js';
|
|
5
|
+
import { CodeExtractorsManager } from './extractors/index.js';
|
|
6
|
+
import { FeatureManager } from './feature.js';
|
|
7
|
+
import { LSPAppContribution } from './lsp-app-contribution.js';
|
|
8
|
+
import { LanguageServerManager } from './manager.js';
|
|
9
|
+
import {
|
|
10
|
+
ILanguageServerManagerFactory,
|
|
11
|
+
ILanguageServerManagerOptions,
|
|
12
|
+
} from './tokens.js';
|
|
13
|
+
|
|
14
|
+
export const LibroLSPModule = ManaModule.create()
|
|
15
|
+
.register(
|
|
16
|
+
LSPAppContribution,
|
|
17
|
+
DocumentConnectionManager,
|
|
18
|
+
FeatureManager,
|
|
19
|
+
CodeExtractorsManager,
|
|
20
|
+
LanguageServerManager,
|
|
21
|
+
{
|
|
22
|
+
token: ILanguageServerManagerFactory,
|
|
23
|
+
useFactory: (ctx) => {
|
|
24
|
+
return (option: ILanguageServerManagerOptions) => {
|
|
25
|
+
const child = ctx.container.createChild();
|
|
26
|
+
child.register({ token: ILanguageServerManagerOptions, useValue: option });
|
|
27
|
+
return child.get(LanguageServerManager);
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
)
|
|
32
|
+
.dependOn(LibroServerModule);
|
package/src/plugin.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Copyright (c) Jupyter Development Team.
|
|
2
|
+
// Distributed under the terms of the Modified BSD License.
|
|
3
|
+
|
|
4
|
+
/* eslint-disable */
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* This file was automatically generated by json-schema-to-typescript.
|
|
8
|
+
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
|
|
9
|
+
* and run jlpm build:schema to regenerate this file.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Enable or disable the language server services.
|
|
14
|
+
*/
|
|
15
|
+
export type Activate = 'off' | 'on';
|
|
16
|
+
/**
|
|
17
|
+
* When multiple servers match specific document/language, the server with the highest rank will be used
|
|
18
|
+
*/
|
|
19
|
+
export type RankOfTheServer = number;
|
|
20
|
+
/**
|
|
21
|
+
* Whether to ask server to send logs with execution trace (for debugging). Accepted values are: "off", "messages", "verbose". Servers are allowed to ignore this request.
|
|
22
|
+
*/
|
|
23
|
+
export type AskServersToSendTraceNotifications = 'off' | 'messages' | 'verbose';
|
|
24
|
+
/**
|
|
25
|
+
* Enable or disable the logging feature of the language servers.
|
|
26
|
+
*/
|
|
27
|
+
export type LogCommunication = boolean;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Language Server Protocol settings.
|
|
31
|
+
*/
|
|
32
|
+
export interface LanguageServersExperimental {
|
|
33
|
+
activate?: Activate;
|
|
34
|
+
languageServers?: LanguageServer;
|
|
35
|
+
setTrace?: AskServersToSendTraceNotifications;
|
|
36
|
+
logAllCommunication?: LogCommunication;
|
|
37
|
+
[k: string]: any;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Language-server specific configuration, keyed by implementation
|
|
41
|
+
*/
|
|
42
|
+
export interface LanguageServer {
|
|
43
|
+
[k: string]: LanguageServer1;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* This interface was referenced by `LanguageServer`'s JSON-Schema definition
|
|
47
|
+
* via the `patternProperty` ".*".
|
|
48
|
+
*
|
|
49
|
+
* This interface was referenced by `LanguageServersExperimental`'s JSON-Schema
|
|
50
|
+
* via the `definition` "languageServer".
|
|
51
|
+
*/
|
|
52
|
+
export interface LanguageServer1 {
|
|
53
|
+
configuration?: LanguageServerConfigurations;
|
|
54
|
+
rank?: RankOfTheServer;
|
|
55
|
+
[k: string]: any;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Configuration to be sent to language server over LSP when initialized: see the specific language server's documentation for more
|
|
59
|
+
*/
|
|
60
|
+
export interface LanguageServerConfigurations {
|
|
61
|
+
[k: string]: any;
|
|
62
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/* eslint-disable no-param-reassign */
|
|
2
|
+
// Copyright (c) Jupyter Development Team.
|
|
3
|
+
// Distributed under the terms of the Modified BSD License.
|
|
4
|
+
|
|
5
|
+
import type { IPosition as CodeEditorPosition } from '@difizen/libro-code-editor';
|
|
6
|
+
import type * as lsp from 'vscode-languageserver-protocol';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* CM5 position interface.
|
|
10
|
+
*
|
|
11
|
+
* TODO: Migrate to offset-only mode once `CodeEditor.IPosition`
|
|
12
|
+
* is migrated.
|
|
13
|
+
*/
|
|
14
|
+
export interface Position {
|
|
15
|
+
/**
|
|
16
|
+
* Line number
|
|
17
|
+
*/
|
|
18
|
+
line: number;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Position of character in line
|
|
22
|
+
*/
|
|
23
|
+
ch: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* is_* attributes are there only to enforce strict interface type checking
|
|
28
|
+
*/
|
|
29
|
+
export interface ISourcePosition extends Position {
|
|
30
|
+
isSource: true;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface IEditorPosition extends Position {
|
|
34
|
+
isEditor: true;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface IVirtualPosition extends Position {
|
|
38
|
+
isVirtual: true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface IRootPosition extends ISourcePosition {
|
|
42
|
+
isRoot: true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Compare two `Position` variable.
|
|
47
|
+
*
|
|
48
|
+
*/
|
|
49
|
+
export function isEqual(self: Position, other: Position): boolean {
|
|
50
|
+
return other && self.line === other.line && self.ch === other.ch;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Given a list of line and an offset from the start, compute the corresponding
|
|
55
|
+
* position in form of line and column number
|
|
56
|
+
*
|
|
57
|
+
* @param offset - number of spaces counted from the start of first line
|
|
58
|
+
* @param lines - list of lines to compute the position
|
|
59
|
+
* @return - the position of cursor
|
|
60
|
+
*/
|
|
61
|
+
export function positionAtOffset(offset: number, lines: string[]): CodeEditorPosition {
|
|
62
|
+
let line = 0;
|
|
63
|
+
let column = 0;
|
|
64
|
+
for (const textLine of lines) {
|
|
65
|
+
// each line has a new line symbol which is accounted for in offset!
|
|
66
|
+
if (textLine.length + 1 <= offset) {
|
|
67
|
+
offset -= textLine.length + 1;
|
|
68
|
+
line += 1;
|
|
69
|
+
} else {
|
|
70
|
+
column = offset;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return { line, column };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Given a list of line and position in form of line and column number,
|
|
79
|
+
* compute the offset from the start of first line.
|
|
80
|
+
* @param position - postion of cursor
|
|
81
|
+
* @param lines - list of lines to compute the position
|
|
82
|
+
* @param linesIncludeBreaks - should count the line break as space?
|
|
83
|
+
* return - offset number
|
|
84
|
+
*/
|
|
85
|
+
export function offsetAtPosition(
|
|
86
|
+
position: CodeEditorPosition,
|
|
87
|
+
lines: string[],
|
|
88
|
+
linesIncludeBreaks = false,
|
|
89
|
+
): number {
|
|
90
|
+
const breakIncrement = linesIncludeBreaks ? 0 : 1;
|
|
91
|
+
let offset = 0;
|
|
92
|
+
for (let i = 0; i < lines.length; i++) {
|
|
93
|
+
const textLine = lines[i];
|
|
94
|
+
if (position.line > i) {
|
|
95
|
+
offset += textLine.length + breakIncrement;
|
|
96
|
+
} else {
|
|
97
|
+
offset += position.column;
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return offset;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export namespace ProtocolCoordinates {
|
|
105
|
+
/**
|
|
106
|
+
* Check if the position is in the input range
|
|
107
|
+
*
|
|
108
|
+
* @param position - position in form of line and character number.
|
|
109
|
+
* @param range - range in from of start and end position.
|
|
110
|
+
*/
|
|
111
|
+
export function isWithinRange(position: lsp.Position, range: lsp.Range): boolean {
|
|
112
|
+
const { line, character } = position;
|
|
113
|
+
return (
|
|
114
|
+
line >= range.start.line &&
|
|
115
|
+
line <= range.end.line &&
|
|
116
|
+
// need to be non-overlapping see https://github.com/jupyter-lsp/jupyterlab-lsp/issues/628
|
|
117
|
+
(line !== range.start.line || character > range.start.character) &&
|
|
118
|
+
(line !== range.end.line || character <= range.end.character)
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
}
|