@kerebron/extension-lsp 0.4.26 → 0.4.27

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kerebron/extension-lsp",
3
- "version": "0.4.26",
3
+ "version": "0.4.27",
4
4
  "license": "MIT",
5
5
  "module": "./esm/mod.js",
6
6
  "exports": {
@@ -15,10 +15,11 @@
15
15
  }
16
16
  },
17
17
  "scripts": {},
18
+ "files": [],
18
19
  "dependencies": {
19
- "@kerebron/editor": "0.4.26",
20
- "@kerebron/extension-autocomplete": "0.4.26",
21
- "@kerebron/extension-markdown": "0.4.26",
20
+ "@kerebron/editor": "0.4.27",
21
+ "@kerebron/extension-autocomplete": "0.4.27",
22
+ "@kerebron/extension-markdown": "0.4.27",
22
23
  "prosemirror-state": "1.4.3",
23
24
  "prosemirror-view": "1.40.0",
24
25
  "vscode-languageserver-protocol": "3.17.5"
@@ -1,32 +0,0 @@
1
- import { Plugin } from 'prosemirror-state';
2
- import { ExtensionLsp } from './ExtensionLsp.js';
3
- import { PositionMapper } from '@kerebron/extension-markdown/PositionMapper';
4
- interface LspRange {
5
- line: number;
6
- character: number;
7
- }
8
- interface DiagnosticsItem {
9
- severity: number;
10
- range: {
11
- start: LspRange;
12
- end: LspRange;
13
- };
14
- message: string;
15
- source: string;
16
- code: string;
17
- data: any;
18
- }
19
- interface DiagnosticPluginState {
20
- diagnostics: DiagnosticsItem[];
21
- mapper?: PositionMapper;
22
- }
23
- interface DiagnosticConfig {
24
- }
25
- export declare class DiagnosticPlugin extends Plugin<DiagnosticPluginState> {
26
- diagListener: ((event: Event) => void) | undefined;
27
- listenerDisconnect: ((event: Event) => void) | undefined;
28
- listenerChange: ((event: Event) => void) | undefined;
29
- constructor(config: DiagnosticConfig, extension: ExtensionLsp);
30
- }
31
- export {};
32
- //# sourceMappingURL=DiagnosticPlugin.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DiagnosticPlugin.d.ts","sourceRoot":"","sources":["../src/DiagnosticPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAA0B,MAAM,mBAAmB,CAAC;AAEnE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,6CAA6C,CAAC;AAE7E,UAAU,QAAQ;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,eAAe;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE;QACL,KAAK,EAAE,QAAQ,CAAC;QAChB,GAAG,EAAE,QAAQ,CAAC;KACf,CAAC;IACF,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,GAAG,CAAC;CACX;AAED,UAAU,qBAAqB;IAC7B,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB;AAED,UAAU,gBAAgB;CACzB;AAID,qBAAa,gBAAiB,SAAQ,MAAM,CAAC,qBAAqB,CAAC;IACjE,YAAY,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACnD,kBAAkB,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACzD,cAAc,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;gBAEzC,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAE,YAAY;CA8J9D"}
@@ -1,116 +0,0 @@
1
- import { Plugin, PluginKey } from 'prosemirror-state';
2
- import { Decoration, DecorationSet } from 'prosemirror-view';
3
- const DiagnosticPluginKey = new PluginKey('lsp-diagnostic');
4
- export class DiagnosticPlugin extends Plugin {
5
- diagListener;
6
- listenerDisconnect;
7
- listenerChange;
8
- constructor(config, extension) {
9
- super({
10
- key: DiagnosticPluginKey,
11
- view(view) {
12
- return {
13
- destroy: () => {
14
- const client = extension.getClient(extension.mainLang);
15
- if (this.listener && client) {
16
- client.removeEventListener('textDocument/publishDiagnostics', this.listener);
17
- }
18
- if (this.listenerDisconnect && client) {
19
- client.removeEventListener('close', this.listenerDisconnect);
20
- }
21
- if (this.changeListener) {
22
- extension.getEditor().removeEventListener('change', this.changeListener);
23
- }
24
- },
25
- };
26
- },
27
- state: {
28
- init() {
29
- return {
30
- diagnostics: [],
31
- };
32
- },
33
- apply(tr, prev, oldState, newState) {
34
- const next = { ...prev };
35
- const meta = tr.getMeta(DiagnosticPluginKey);
36
- if (meta?.diagnostics) {
37
- next.diagnostics = meta.diagnostics;
38
- }
39
- if (meta?.mapper) {
40
- next.mapper = meta.mapper;
41
- }
42
- return next;
43
- },
44
- },
45
- props: {
46
- decorations(state) {
47
- const decorations = [];
48
- const pluginState = this.getState(state);
49
- if (pluginState) {
50
- const { diagnostics, mapper } = pluginState;
51
- if (mapper) {
52
- for (const diag of diagnostics) {
53
- const from = mapper.fromLineChar(diag.range.start.line, diag.range.start.character);
54
- const end = mapper.fromLineChar(diag.range.end.line, diag.range.end.character);
55
- if (from > -1 && end > -1) {
56
- const decoration = Decoration.inline(from, end, { class: 'kb-lsp__error', title: diag.message });
57
- decorations.push(decoration);
58
- }
59
- }
60
- }
61
- }
62
- return DecorationSet.create(state.doc, decorations);
63
- },
64
- },
65
- });
66
- let lastDiag = 0;
67
- const editor = extension.getEditor();
68
- const uri = editor.config.uri;
69
- if (uri) {
70
- const client = extension.getClient(extension.mainLang);
71
- this.diagListener = (event) => {
72
- const detail = event.detail;
73
- if (detail.params.uri !== uri) {
74
- return;
75
- }
76
- event.preventDefault();
77
- lastDiag = +Date();
78
- if (client) {
79
- const file = client.workspace.getFile(uri);
80
- if (file) {
81
- const { mapper } = file;
82
- const tr = editor.view.state.tr.setMeta(DiagnosticPluginKey, {
83
- diagnostics: detail.params.diagnostics,
84
- mapper,
85
- });
86
- editor.view.dispatch(tr);
87
- }
88
- }
89
- };
90
- if (client) {
91
- client.addEventListener('textDocument/publishDiagnostics', this.diagListener);
92
- }
93
- this.listenerDisconnect = (event) => {
94
- const tr = editor.view.state.tr.setMeta(DiagnosticPluginKey, {
95
- diagnostics: [],
96
- mapper: undefined,
97
- });
98
- editor.view.dispatch(tr);
99
- };
100
- if (client) {
101
- client.addEventListener('close', this.listenerDisconnect);
102
- }
103
- this.listenerChange = (event) => {
104
- if (lastDiag === 0 && +Date() - lastDiag > 10_1000) {
105
- return;
106
- }
107
- const tr = editor.view.state.tr.setMeta(DiagnosticPluginKey, {
108
- diagnostics: [],
109
- mapper: undefined,
110
- });
111
- editor.view.dispatch(tr);
112
- };
113
- // extension.getEditor().addEventListener('changed', this.listenerChange);
114
- }
115
- }
116
- }
@@ -1,25 +0,0 @@
1
- import { Plugin } from 'prosemirror-state';
2
- import { Extension } from '@kerebron/editor';
3
- import { type ExtensionMarkdown } from '@kerebron/extension-markdown';
4
- import { type ExtensionAutocomplete } from '@kerebron/extension-autocomplete';
5
- import { LSPClient, Transport } from './LSPClient.js';
6
- import { LspSource } from './workspace.js';
7
- export type LspTransportGetter = (lang: string) => Transport | undefined;
8
- export interface LspConfig {
9
- getLspTransport: LspTransportGetter;
10
- }
11
- export declare class ExtensionLsp extends Extension {
12
- protected config: LspConfig;
13
- name: string;
14
- clients: Record<string, LSPClient>;
15
- uri: string | undefined;
16
- extensionMarkdown: ExtensionMarkdown;
17
- extensionAutocomplete: ExtensionAutocomplete;
18
- mainLang: string;
19
- source: LspSource;
20
- constructor(config: LspConfig);
21
- getProseMirrorPlugins(): Plugin[];
22
- created(): void;
23
- getClient(lang: string): LSPClient | undefined;
24
- }
25
- //# sourceMappingURL=ExtensionLsp.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ExtensionLsp.d.ts","sourceRoot":"","sources":["../src/ExtensionLsp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAG9E,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAItD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,MAAM,MAAM,kBAAkB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,GAAG,SAAS,CAAC;AAEzE,MAAM,WAAW,SAAS;IACxB,eAAe,EAAE,kBAAkB,CAAC;CACrC;AAED,qBAAa,YAAa,SAAQ,SAAS;cASV,MAAM,EAAE,SAAS;IARhD,IAAI,SAAS;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAM;IACxC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,iBAAiB,EAAG,iBAAiB,CAAC;IACtC,qBAAqB,EAAG,qBAAqB,CAAC;IAC9C,QAAQ,EAAE,MAAM,CAAc;IAC9B,MAAM,EAAG,SAAS,CAAC;gBAEY,MAAM,EAAE,SAAS;IAIvC,qBAAqB,IAAI,MAAM,EAAE;IAWjC,OAAO;IA+DhB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;CAW/C"}
@@ -1,87 +0,0 @@
1
- import { Extension } from '@kerebron/editor';
2
- import { PositionMapper } from '@kerebron/extension-markdown/PositionMapper';
3
- import { LSPClient } from './LSPClient.js';
4
- import { AutocompletePlugin } from '@kerebron/extension-autocomplete/AutocompletePlugin';
5
- import { DiagnosticPlugin } from './DiagnosticPlugin.js';
6
- import { createLspAutocomplete } from './createLspAutocomplete.js';
7
- export class ExtensionLsp extends Extension {
8
- config;
9
- name = 'lsp';
10
- clients = {};
11
- uri;
12
- extensionMarkdown;
13
- extensionAutocomplete;
14
- mainLang = 'markdown';
15
- source;
16
- constructor(config) {
17
- super(config);
18
- this.config = config;
19
- }
20
- getProseMirrorPlugins() {
21
- const plugins = [];
22
- const { autocompleteConfig } = createLspAutocomplete(this);
23
- plugins.push(new AutocompletePlugin(autocompleteConfig, this.editor));
24
- plugins.push(new DiagnosticPlugin({}, this));
25
- return plugins;
26
- }
27
- created() {
28
- this.mainLang = this.editor.config.languageID || 'markdown';
29
- this.source = {
30
- ui: this.editor.ui,
31
- getMappedContent: async () => {
32
- const editor = this.editor;
33
- const result = await this.extensionMarkdown.toMarkdown(editor.state.doc);
34
- const mapper = new PositionMapper(editor, result.rawTextMap);
35
- return {
36
- ...result,
37
- mapper,
38
- };
39
- },
40
- };
41
- const extensionMarkdown = this.editor
42
- .getExtension('markdown');
43
- if (!extensionMarkdown) {
44
- throw new Error('No markdown extension');
45
- }
46
- this.extensionMarkdown = extensionMarkdown;
47
- this.editor.addEventListener('doc:loaded', async () => {
48
- const languageID = this.mainLang;
49
- this.uri = this.editor.config.uri;
50
- if (this.uri) {
51
- const client = this.getClient(this.mainLang);
52
- if (client) {
53
- client.connect(this.uri, this.source);
54
- await client.restart();
55
- client.workspace.openFile(this.uri, languageID, this.source);
56
- }
57
- }
58
- });
59
- this.editor.addEventListener('changed', () => {
60
- if (this.editor.config.uri) {
61
- const client = this.getClient(this.mainLang);
62
- if (client) {
63
- client.workspace.changedFile(this.editor.config.uri);
64
- }
65
- }
66
- });
67
- this.editor.addEventListener('beforeDestroy', () => {
68
- if (this.uri) {
69
- const client = this.getClient(this.mainLang);
70
- if (client) {
71
- client.disconnect(this.uri);
72
- }
73
- }
74
- });
75
- }
76
- getClient(lang) {
77
- if (!this.clients[lang]) {
78
- const transport = this.config.getLspTransport(lang);
79
- if (!transport) {
80
- console.warn(`No lsp transport for ${lang}`);
81
- return undefined;
82
- }
83
- this.clients[lang] = new LSPClient(transport, { rootUri: 'file:///' });
84
- }
85
- return this.clients[lang];
86
- }
87
- }
@@ -1,56 +0,0 @@
1
- import type * as lsp from 'vscode-languageserver-protocol';
2
- import { TextDocumentSyncKind } from 'vscode-languageserver-protocol';
3
- import { LspSource, Workspace, WorkspaceFile } from './workspace.js';
4
- export type Transport = {
5
- connect(): void;
6
- disconnect(): void;
7
- send(message: string): void;
8
- addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
9
- removeEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: EventListenerOptions | boolean): void;
10
- isConnected(): boolean;
11
- isInitialized(): boolean;
12
- };
13
- export type LSPClientConfig = {
14
- rootUri?: string;
15
- workspace?: (client: LSPClient) => Workspace;
16
- timeout?: number;
17
- sanitizeHTML?: (html: string) => string;
18
- unhandledNotification?: (client: LSPClient, method: string, params: any) => void;
19
- };
20
- export declare class LSPError extends Error {
21
- isTimeout: boolean;
22
- readonly isLSP = true;
23
- static createTimeout(): LSPError;
24
- }
25
- export declare class LSPClient extends EventTarget {
26
- private readonly transport;
27
- readonly config: LSPClientConfig;
28
- sources: Record<string, LspSource>;
29
- workspace: Workspace;
30
- private nextReqID;
31
- private requests;
32
- serverCapabilities: lsp.ServerCapabilities | null;
33
- supportSync: TextDocumentSyncKind;
34
- private readonly timeout;
35
- private initializing;
36
- private readonly receiveListener;
37
- active: boolean;
38
- constructor(transport: Transport, config?: LSPClientConfig);
39
- startInitializing(): void;
40
- stopInitializing(): void;
41
- restart(): Promise<void>;
42
- onInitialized(): void;
43
- connect(uri: string, source: LspSource): void;
44
- disconnect(uri: string): void;
45
- didOpen(file: WorkspaceFile): Promise<boolean>;
46
- didClose(uri: string): void;
47
- private receiveMessage;
48
- request<Params, Result>(method: string, params: Params): Promise<Result>;
49
- private requestInner;
50
- notification<Params>(method: string, params: Params): Promise<boolean>;
51
- cancelRequest(params: any): void;
52
- hasCapability(name: keyof lsp.ServerCapabilities): boolean | null;
53
- sync(): void;
54
- private timeoutRequest;
55
- }
56
- //# sourceMappingURL=LSPClient.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"LSPClient.d.ts","sourceRoot":"","sources":["../src/LSPClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,GAAG,MAAM,gCAAgC,CAAC;AAC3D,OAAO,EAEL,oBAAoB,EACrB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAEL,SAAS,EACT,SAAS,EACT,aAAa,EACd,MAAM,gBAAgB,CAAC;AA0BxB,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,IAAI,IAAI,CAAC;IAChB,UAAU,IAAI,IAAI,CAAC;IACnB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,gBAAgB,CACd,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,kCAAkC,EAC5C,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAC1C,IAAI,CAAC;IACR,mBAAmB,CACjB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,kCAAkC,GAAG,IAAI,EACnD,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,GACvC,IAAI,CAAC;IACR,WAAW,IAAI,OAAO,CAAC;IACvB,aAAa,IAAI,OAAO,CAAC;CAC1B,CAAC;AAiEF,MAAM,MAAM,eAAe,GAAG;IAE5B,OAAO,CAAC,EAAE,MAAM,CAAC;IAMjB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,SAAS,CAAC;IAG7C,OAAO,CAAC,EAAE,MAAM,CAAC;IAOjB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAGxC,qBAAqB,CAAC,EAAE,CACtB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,GAAG,KACR,IAAI,CAAC;CACX,CAAC;AAEF,qBAAa,QAAS,SAAQ,KAAK;IACjC,SAAS,UAAS;IAClB,QAAQ,CAAC,KAAK,QAAQ;IAEtB,MAAM,CAAC,aAAa;CAKrB;AAED,qBAAa,SAAU,SAAQ,WAAW;IAiBtC,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,QAAQ,CAAC,MAAM,EAAE,eAAe;IAjBlC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAM;IAExC,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,QAAQ,CAAsB;IAEtC,kBAAkB,EAAE,GAAG,CAAC,kBAAkB,GAAG,IAAI,CAAQ;IAClD,WAAW,EAAE,oBAAoB,CAA6B;IAErE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,YAAY,CAA6C;IAEjE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqC;IACrE,MAAM,EAAE,OAAO,CAAS;gBAGL,SAAS,EAAE,SAAS,EAC5B,MAAM,GAAE,eAAoB;IAuCvC,iBAAiB;IAoCjB,gBAAgB;IAOV,OAAO;IASb,aAAa;IAQb,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS;IAWtC,UAAU,CAAC,GAAG,EAAE,MAAM;IAahB,OAAO,CAAC,IAAI,EAAE,aAAa;IAmBjC,QAAQ,CAAC,GAAG,EAAE,MAAM;IASpB,OAAO,CAAC,cAAc;IA+ChB,OAAO,CAAC,MAAM,EAAE,MAAM,EAC1B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC;IAalB,OAAO,CAAC,YAAY;IA8Cd,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAoB5E,aAAa,CAAC,MAAM,EAAE,GAAG;IAOzB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,kBAAkB;IAIhD,IAAI;IAIJ,OAAO,CAAC,cAAc;CAcvB"}
package/esm/LSPClient.js DELETED
@@ -1,361 +0,0 @@
1
- import { MessageType, TextDocumentSyncKind, } from 'vscode-languageserver-protocol';
2
- import { DefaultWorkspace, } from './workspace.js';
3
- const defaultNotificationHandlers = {
4
- 'window/logMessage': (client, params) => {
5
- if (params.type == MessageType.Error) {
6
- console.error('[lsp] ' + params.message);
7
- }
8
- else if (params.type == MessageType.Warning) {
9
- console.warn('[lsp] ' + params.message);
10
- }
11
- else if (params.type == MessageType.Info) {
12
- console.info('[lsp] ' + params.message);
13
- }
14
- else if (params.type == MessageType.Log) {
15
- console.log('[lsp] ' + params.message);
16
- }
17
- },
18
- 'window/showMessage': (client, params) => {
19
- if (params.type > MessageType.Info)
20
- return;
21
- for (const f of client.workspace.files) {
22
- const ui = f.getUi();
23
- if (!ui)
24
- continue;
25
- ui.showMessage(params.message);
26
- }
27
- },
28
- };
29
- class Request {
30
- id;
31
- params;
32
- timeout;
33
- promise;
34
- constructor(id, params, timeout) {
35
- this.id = id;
36
- this.params = params;
37
- this.timeout = timeout;
38
- this.promise = new Promise((resolve, reject) => {
39
- this.resolve = resolve;
40
- this.reject = reject;
41
- });
42
- }
43
- }
44
- const clientCapabilities = {
45
- general: {
46
- markdown: {
47
- parser: 'marked',
48
- },
49
- },
50
- textDocument: {
51
- publishDiagnostics: { versionSupport: true },
52
- completion: {
53
- completionItem: {
54
- snippetSupport: true,
55
- documentationFormat: ['plaintext', 'markdown'],
56
- insertReplaceSupport: false,
57
- },
58
- completionList: {
59
- itemDefaults: ['commitCharacters', 'editRange', 'insertTextFormat'],
60
- },
61
- completionItemKind: { valueSet: [] },
62
- contextSupport: true,
63
- },
64
- hover: {
65
- contentFormat: ['markdown', 'plaintext'],
66
- },
67
- // formatting: {},
68
- // rename: {},
69
- signatureHelp: {
70
- contextSupport: true,
71
- signatureInformation: {
72
- documentationFormat: ['markdown', 'plaintext'],
73
- parameterInformation: { labelOffsetSupport: true },
74
- activeParameterSupport: true,
75
- },
76
- },
77
- definition: {},
78
- declaration: {},
79
- implementation: {},
80
- typeDefinition: {},
81
- references: {},
82
- diagnostic: {},
83
- },
84
- window: {
85
- showMessage: {},
86
- },
87
- };
88
- export class LSPError extends Error {
89
- isTimeout = false;
90
- isLSP = true;
91
- static createTimeout() {
92
- const err = new LSPError('Request timed out');
93
- err.isTimeout = true;
94
- return err;
95
- }
96
- }
97
- export class LSPClient extends EventTarget {
98
- transport;
99
- config;
100
- sources = {};
101
- workspace;
102
- nextReqID = 0;
103
- requests = [];
104
- serverCapabilities = null;
105
- supportSync = TextDocumentSyncKind.None;
106
- timeout;
107
- initializing;
108
- receiveListener;
109
- active = false;
110
- constructor(transport, config = {}) {
111
- super();
112
- this.transport = transport;
113
- this.config = config;
114
- this.timeout = config.timeout ?? 3000;
115
- this.receiveListener = (event) => this.receiveMessage(event);
116
- transport.addEventListener('message', this.receiveListener);
117
- transport.addEventListener('initialized', () => {
118
- try {
119
- console.info('LSP initialized');
120
- this.onInitialized();
121
- }
122
- catch (err) {
123
- if (err.isLSP) {
124
- console.error('Timeout as client.onConnected()', err.message, this.onInitialized);
125
- }
126
- else {
127
- throw err;
128
- }
129
- }
130
- });
131
- transport.addEventListener('open', () => {
132
- this.startInitializing();
133
- });
134
- transport.addEventListener('close', (event) => {
135
- this.active = false;
136
- this.serverCapabilities = null;
137
- this.dispatchEvent(new CloseEvent('close'));
138
- });
139
- this.workspace = config.workspace
140
- ? config.workspace(this)
141
- : new DefaultWorkspace(this);
142
- }
143
- startInitializing() {
144
- if (this.initializing) {
145
- return;
146
- }
147
- this.initializing = setInterval(async () => {
148
- const capabilities = clientCapabilities;
149
- try {
150
- const resp = await this.requestInner('initialize', {
151
- processId: null,
152
- clientInfo: { name: '@kerebron/lsp-client' },
153
- rootUri: this.config.rootUri || null,
154
- capabilities,
155
- }).promise;
156
- this.stopInitializing();
157
- this.serverCapabilities = resp.capabilities;
158
- const sync = this.serverCapabilities.textDocumentSync;
159
- this.supportSync = TextDocumentSyncKind.None;
160
- if (sync) {
161
- this.supportSync = typeof sync == 'number'
162
- ? sync
163
- : sync.change ?? TextDocumentSyncKind.None;
164
- }
165
- // deno-lint-ignore no-empty
166
- }
167
- catch (ignoreConnectErrors) { }
168
- }, this.timeout);
169
- }
170
- stopInitializing() {
171
- if (this.initializing) {
172
- clearInterval(this.initializing);
173
- this.initializing = undefined;
174
- }
175
- }
176
- async restart() {
177
- this.active = true;
178
- if (!this.transport.isConnected()) {
179
- this.transport.connect();
180
- }
181
- else {
182
- this.startInitializing();
183
- }
184
- }
185
- onInitialized() {
186
- this.transport.send(JSON.stringify({ jsonrpc: '2.0', method: 'initialized', params: {} }));
187
- this.workspace.connected();
188
- }
189
- connect(uri, source) {
190
- if (this.sources[uri] && this.sources[uri] !== source) {
191
- throw new Error(`Source for ${uri} already connected`);
192
- }
193
- this.sources[uri] = source;
194
- this.active = true;
195
- if (!this.transport.isConnected()) {
196
- this.transport.connect();
197
- }
198
- }
199
- disconnect(uri) {
200
- delete this.sources[uri];
201
- this.workspace.closeFile(uri);
202
- if (Object.keys(this.sources).length === 0) {
203
- this.active = false;
204
- this.serverCapabilities = null;
205
- this.transport.removeEventListener('data', this.receiveListener);
206
- this.workspace.disconnected();
207
- this.dispatchEvent(new CloseEvent('close'));
208
- }
209
- }
210
- /// Send a `textDocument/didOpen` notification to the server.
211
- async didOpen(file) {
212
- if (!this.transport.isInitialized()) {
213
- return false;
214
- }
215
- await this.notification('textDocument/didOpen', {
216
- textDocument: {
217
- uri: file.uri,
218
- languageId: file.languageId,
219
- text: file.content,
220
- version: file.version,
221
- },
222
- });
223
- return true;
224
- }
225
- /// Send a `textDocument/didClose` notification to the server.
226
- didClose(uri) {
227
- if (!this.transport.isInitialized()) {
228
- return;
229
- }
230
- this.notification('textDocument/didClose', {
231
- textDocument: { uri },
232
- });
233
- }
234
- receiveMessage(event) {
235
- const msg = event.data;
236
- const value = JSON.parse(msg);
237
- if ('id' in value && !('method' in value)) {
238
- const index = this.requests.findIndex((r) => r.id == value.id);
239
- if (index < 0) {
240
- console.warn(`[lsp] Received a response for non-existent request ${value.id}`);
241
- }
242
- else {
243
- const req = this.requests[index];
244
- clearTimeout(req.timeout);
245
- this.requests.splice(index, 1);
246
- if (value.error)
247
- req.reject(value.error);
248
- else
249
- req.resolve(value.result);
250
- }
251
- }
252
- else if (!('id' in value)) {
253
- const event = new CustomEvent(value.method, {
254
- detail: { params: value.params },
255
- });
256
- if (this.dispatchEvent(event)) {
257
- if (this.config.unhandledNotification) {
258
- this.config.unhandledNotification(this, value.method, value.params);
259
- }
260
- else {
261
- if (defaultNotificationHandlers[value.method]) {
262
- defaultNotificationHandlers[value.method](this, value.params);
263
- }
264
- }
265
- }
266
- }
267
- else {
268
- const resp = {
269
- jsonrpc: '2.0',
270
- id: value.id,
271
- error: {
272
- code: -32601, /* MethodNotFound */
273
- message: 'Method not implemented',
274
- },
275
- };
276
- this.transport.send(JSON.stringify(resp));
277
- }
278
- }
279
- async request(method, params) {
280
- if (!this.transport.isConnected()) {
281
- if (this.active) {
282
- this.transport.connect();
283
- }
284
- throw new LSPError('Not connected');
285
- }
286
- const retVal = await this.requestInner(method, params)
287
- .promise;
288
- return retVal;
289
- }
290
- requestInner(method, params, mapped = false) {
291
- if (!this.transport) {
292
- throw new Error('No transport');
293
- }
294
- if (!this.transport.isConnected()) {
295
- if (this.active) {
296
- this.transport.connect();
297
- }
298
- throw new Error('Transport not connected');
299
- }
300
- const id = ++this.nextReqID, data = {
301
- jsonrpc: '2.0',
302
- id,
303
- method,
304
- params: params,
305
- };
306
- const req = new Request(id, params, setTimeout(() => this.timeoutRequest(req, method, id, params), this.timeout));
307
- try {
308
- if (!this.transport) {
309
- throw new LSPError('No transport');
310
- }
311
- this.transport.send(JSON.stringify(data));
312
- this.requests.push(req);
313
- }
314
- catch (e) {
315
- console.error(e);
316
- clearTimeout(req.timeout);
317
- req.reject(e);
318
- }
319
- return req;
320
- }
321
- async notification(method, params) {
322
- if (!this.transport)
323
- return false;
324
- if (!this.transport.isConnected()) {
325
- if (this.active) {
326
- this.transport.connect();
327
- }
328
- return false;
329
- }
330
- if (!this.transport.isInitialized()) {
331
- return false;
332
- }
333
- const data = {
334
- jsonrpc: '2.0',
335
- method,
336
- params: params,
337
- };
338
- this.transport.send(JSON.stringify(data));
339
- return true;
340
- }
341
- cancelRequest(params) {
342
- const found = this.requests.find((r) => r.params === params);
343
- if (found) {
344
- this.notification('$/cancelRequest', found.id);
345
- }
346
- }
347
- hasCapability(name) {
348
- return this.serverCapabilities ? !!this.serverCapabilities[name] : null;
349
- }
350
- sync() {
351
- this.workspace.syncFiles();
352
- }
353
- timeoutRequest(req, method, id, params) {
354
- console.error('this.timeoutRequest', this.timeout, method, id, params);
355
- const index = this.requests.indexOf(req);
356
- if (index > -1) {
357
- req.reject(LSPError.createTimeout());
358
- this.requests.splice(index, 1);
359
- }
360
- }
361
- }
@@ -1,19 +0,0 @@
1
- import { type Transport } from './LSPClient.js';
2
- export declare class LspWebSocketTransport extends EventTarget implements Transport {
3
- readonly uri: string;
4
- socket: WebSocket | undefined;
5
- private reconnectAttempts;
6
- private maxAttempts;
7
- private readonly baseDelay;
8
- isConnecting: boolean;
9
- initialized: boolean;
10
- constructor(uri: string);
11
- isConnected(): boolean;
12
- isInitialized(): boolean;
13
- connect(): void;
14
- disconnect(): void;
15
- bindEvents(socket: WebSocket): void;
16
- scheduleReconnect(): void;
17
- send(message: string): void;
18
- }
19
- //# sourceMappingURL=LspWebSocketTransport.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"LspWebSocketTransport.d.ts","sourceRoot":"","sources":["../src/LspWebSocketTransport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAShD,qBAAa,qBAAsB,SAAQ,WAAY,YAAW,SAAS;aAQ7C,GAAG,EAAE,MAAM;IAPvC,MAAM,EAAE,SAAS,GAAG,SAAS,CAAC;IAC9B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,WAAW,CAAM;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;IAClC,YAAY,EAAE,OAAO,CAAS;IAC9B,WAAW,UAAS;gBAEQ,GAAG,EAAE,MAAM;IAIvC,WAAW;IAIX,aAAa;IAIb,OAAO;IAWP,UAAU,IAAI,IAAI;IAQlB,UAAU,CAAC,MAAM,EAAE,SAAS;IAqC5B,iBAAiB;IAiBjB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;CAW5B"}
@@ -1,102 +0,0 @@
1
- function shouldReconnectOnCode(code) {
2
- // https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent/code
3
- // Reconnect on server going away (1001), but NOT on normal close (1000)
4
- const reconnectCodes = [1001, 1005, 1006, 1011, 1012, 1013];
5
- return reconnectCodes.includes(code);
6
- }
7
- export class LspWebSocketTransport extends EventTarget {
8
- uri;
9
- socket;
10
- reconnectAttempts = 0;
11
- maxAttempts = 10;
12
- baseDelay = 1000;
13
- isConnecting = false;
14
- initialized = false;
15
- constructor(uri) {
16
- super();
17
- this.uri = uri;
18
- }
19
- isConnected() {
20
- return this.socket?.readyState === WebSocket.OPEN;
21
- }
22
- isInitialized() {
23
- return this.initialized;
24
- }
25
- connect() {
26
- if (this.isConnecting) {
27
- return;
28
- }
29
- this.isConnecting = true;
30
- this.socket?.close();
31
- const socket = new WebSocket(this.uri);
32
- this.bindEvents(socket);
33
- this.socket = socket;
34
- }
35
- disconnect() {
36
- console.info('LSP transport disconnect()');
37
- this.socket?.close();
38
- this.socket = undefined;
39
- this.initialized = false;
40
- this.reconnectAttempts = 0;
41
- }
42
- bindEvents(socket) {
43
- socket.addEventListener('message', (event) => {
44
- try {
45
- const json = JSON.parse(event.data);
46
- if (json?.result?.capabilities) {
47
- this.reconnectAttempts = 0;
48
- this.initialized = true;
49
- this.dispatchEvent(new Event('initialized'));
50
- }
51
- // deno-lint-ignore no-empty
52
- }
53
- catch (ignoredError) { }
54
- this.dispatchEvent(new MessageEvent('message', { data: event.data }));
55
- });
56
- socket.addEventListener('open', (event) => {
57
- this.isConnecting = false;
58
- this.dispatchEvent(new CustomEvent('open'));
59
- });
60
- socket.addEventListener('error', (event) => {
61
- console.error(event);
62
- this.dispatchEvent(event);
63
- });
64
- socket.addEventListener('close', (event) => {
65
- this.isConnecting = false;
66
- this.dispatchEvent(new CloseEvent('close', {
67
- code: event.code,
68
- }));
69
- this.socket = undefined;
70
- if (!event.wasClean || shouldReconnectOnCode(event.code)) {
71
- this.scheduleReconnect();
72
- }
73
- else {
74
- console.info('Clean close — no reconnect');
75
- }
76
- });
77
- }
78
- scheduleReconnect() {
79
- if (this.reconnectAttempts >= this.maxAttempts) {
80
- console.error('Max reconnect attempts reached');
81
- return;
82
- }
83
- const delay = this.baseDelay * Math.pow(2, this.reconnectAttempts);
84
- this.reconnectAttempts++;
85
- console.info(`Reconnecting in ${delay}ms... (attempt ${this.reconnectAttempts})`);
86
- setTimeout(() => {
87
- this.connect();
88
- }, delay);
89
- }
90
- send(message) {
91
- if (!this.socket) {
92
- console.warn('Socket disconnected');
93
- return;
94
- }
95
- if (this.socket.readyState === WebSocket.OPEN) {
96
- this.socket.send(message);
97
- }
98
- else {
99
- console.warn('WebSocket not open: ' + this.socket.readyState);
100
- }
101
- }
102
- }
@@ -1,8 +0,0 @@
1
- import * as lsp from 'vscode-languageserver-protocol';
2
- /**
3
- * Compares two strings and computes the minimal set of text changes
4
- * using a diff-based approach (simple line-by-line + character diff for simplicity).
5
- * Returns an array of TextEdit-like changes that transform `previous` into `current`.
6
- */
7
- export declare function computeIncrementalChanges(previous: string, current: string): lsp.TextDocumentContentChangeEvent[];
8
- //# sourceMappingURL=computeIncrementalChanges.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"computeIncrementalChanges.d.ts","sourceRoot":"","sources":["../src/computeIncrementalChanges.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,gCAAgC,CAAC;AAEtD;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,GAAG,CAAC,8BAA8B,EAAE,CA0FtC"}
@@ -1,82 +0,0 @@
1
- /**
2
- * Compares two strings and computes the minimal set of text changes
3
- * using a diff-based approach (simple line-by-line + character diff for simplicity).
4
- * Returns an array of TextEdit-like changes that transform `previous` into `current`.
5
- */
6
- export function computeIncrementalChanges(previous, current) {
7
- if (previous.length === 0) {
8
- return [
9
- {
10
- text: current,
11
- },
12
- ];
13
- }
14
- const prevLines = previous.split(/\r\n|\r|\n/);
15
- const currLines = current.split(/\r\n|\r|\n/);
16
- const changes = [];
17
- let startLine = 0;
18
- let insertedText = '';
19
- // Find common prefix
20
- while (startLine < prevLines.length && startLine < currLines.length) {
21
- if (prevLines[startLine] === currLines[startLine]) {
22
- startLine++;
23
- }
24
- else {
25
- break;
26
- }
27
- }
28
- // If entire document is the same
29
- if (startLine === prevLines.length &&
30
- startLine === currLines.length) {
31
- return changes; // No changes
32
- }
33
- // Find common suffix starting from the end
34
- let endLinePrev = prevLines.length - 1;
35
- let endLineCurr = currLines.length - 1;
36
- while (endLinePrev >= startLine &&
37
- endLineCurr >= startLine &&
38
- prevLines[endLinePrev] === currLines[endLineCurr]) {
39
- endLinePrev--;
40
- endLineCurr--;
41
- }
42
- // Region to replace: from startLine to endLinePrev (inclusive)
43
- const replaceStart = { line: startLine, character: 0 };
44
- let replaceEnd;
45
- if (endLinePrev >= startLine) {
46
- const lastDeletedLine = prevLines[endLinePrev];
47
- replaceEnd = {
48
- line: endLinePrev,
49
- character: lastDeletedLine.length,
50
- };
51
- }
52
- else {
53
- // Deletion ends at the start of the next line
54
- replaceEnd = { line: startLine, character: 0 };
55
- }
56
- // Build inserted text: lines from startLine to endLineCurr
57
- const insertedLines = currLines.slice(startLine, endLineCurr + 1);
58
- insertedText = insertedLines.join('\n');
59
- // If we're inserting at the end of the file, adjust range
60
- if (startLine === prevLines.length) {
61
- // Inserting after last line
62
- replaceEnd = {
63
- line: prevLines.length - 1,
64
- character: prevLines[prevLines.length - 1].length,
65
- };
66
- if (insertedLines.length === 0) {
67
- // Inserting empty at EOF
68
- insertedText = '\n';
69
- }
70
- }
71
- // Create the range for deletion
72
- const range = {
73
- start: replaceStart,
74
- end: replaceEnd,
75
- };
76
- // Push the incremental change
77
- changes.push({
78
- range,
79
- text: insertedText,
80
- });
81
- return changes;
82
- }
@@ -1,23 +0,0 @@
1
- import { DefaultRenderer } from '@kerebron/extension-autocomplete/DefaultRenderer';
2
- import { TextRange } from '@kerebron/editor';
3
- import { type AutocompleteProps } from '@kerebron/extension-autocomplete';
4
- import { ExtensionLsp } from './ExtensionLsp.js';
5
- interface CompletionItem {
6
- label: string;
7
- detail: string;
8
- insertText: string;
9
- }
10
- export declare class CustomRenderer extends DefaultRenderer<CompletionItem> {
11
- createListItem(item: CompletionItem, cnt: number): any;
12
- }
13
- export declare function cleanPlaceholders(input: string): string;
14
- export declare function createLspAutocomplete(extensionLsp: ExtensionLsp): {
15
- autocompleteConfig: {
16
- renderer: CustomRenderer;
17
- matchers: any[];
18
- getItems: (query: string, props: AutocompleteProps) => Promise<CompletionItem[]>;
19
- onSelect: (selected: CompletionItem, range: TextRange) => Promise<void>;
20
- };
21
- };
22
- export {};
23
- //# sourceMappingURL=createLspAutocomplete.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createLspAutocomplete.d.ts","sourceRoot":"","sources":["../src/createLspAutocomplete.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,kDAAkD,CAAC;AACnF,OAAO,EAAmB,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE9D,OAAO,EACL,KAAK,iBAAiB,EAEvB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,UAAU,cAAc;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,cAAe,SAAQ,eAAe,CAAC,cAAc,CAAC;IACxD,cAAc,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM;CAa1D;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGvD;AAED,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,YAAY;;;;0BAOpC,MAAM,SAAS,iBAAiB;6BAiC7B,cAAc,SAAS,SAAS;;EAiB9D"}
@@ -1,68 +0,0 @@
1
- import { DefaultRenderer } from '@kerebron/extension-autocomplete/DefaultRenderer';
2
- import { createRegexMatcher, } from '@kerebron/extension-autocomplete';
3
- export class CustomRenderer extends DefaultRenderer {
4
- createListItem(item, cnt) {
5
- const li = document.createElement('li');
6
- if (cnt === this.pos) {
7
- li.classList.add('active');
8
- }
9
- li.innerText = item.label;
10
- li.title = item.detail;
11
- li.style.cursor = 'pointer';
12
- li.addEventListener('click', () => {
13
- this.command(item);
14
- });
15
- return li;
16
- }
17
- }
18
- export function cleanPlaceholders(input) {
19
- const regex = /\$\{\d+:([^}]+)}/g;
20
- return input.replace(regex, '$1');
21
- }
22
- export function createLspAutocomplete(extensionLsp) {
23
- const editor = extensionLsp.getEditor();
24
- const renderer = new CustomRenderer(editor);
25
- const config = {
26
- renderer,
27
- matchers: [createRegexMatcher([/\w+/, /(^|\s)@\w*/, /^#\w*/])],
28
- getItems: async (query, props) => {
29
- const { mapper } = await extensionLsp.source.getMappedContent();
30
- const lspPos = mapper.toRawTextLspPos(props.range.from);
31
- const client = extensionLsp.getClient(extensionLsp.mainLang);
32
- if (client) {
33
- client.sync();
34
- try {
35
- const completions = await client.request('textDocument/completion', {
36
- textDocument: { uri: extensionLsp.uri },
37
- position: lspPos,
38
- context: { triggerKind: 2, triggerCharacter: query },
39
- });
40
- if (Array.isArray(completions)) {
41
- return completions;
42
- }
43
- return completions.items;
44
- }
45
- catch (err) {
46
- console.error(err.message);
47
- return [];
48
- }
49
- }
50
- else {
51
- return [];
52
- }
53
- },
54
- onSelect: async (selected, range) => {
55
- const rawText = cleanPlaceholders(selected.insertText);
56
- const slice = await extensionLsp.extensionMarkdown.fromMarkdown(rawText);
57
- if (slice.content.content.length === 1) {
58
- const first = slice.content.content[0];
59
- if (first.isBlock) {
60
- editor.chain().insertBlockSmart(range.from, first).run();
61
- return;
62
- }
63
- }
64
- editor.chain().replaceRangeSlice(range, slice).run();
65
- },
66
- };
67
- return { autocompleteConfig: config };
68
- }
package/esm/mod.d.ts DELETED
@@ -1,4 +0,0 @@
1
- export * from './ExtensionLsp.js';
2
- export * from './LSPClient.js';
3
- export * from './workspace.js';
4
- //# sourceMappingURL=mod.d.ts.map
package/esm/mod.d.ts.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC"}
package/esm/mod.js DELETED
@@ -1,3 +0,0 @@
1
- export * from './ExtensionLsp.js';
2
- export * from './LSPClient.js';
3
- export * from './workspace.js';
package/esm/package.json DELETED
@@ -1,3 +0,0 @@
1
- {
2
- "type": "module"
3
- }
package/esm/types.d.ts DELETED
@@ -1,19 +0,0 @@
1
- export type LspPosition = {
2
- line: number;
3
- character: number;
4
- };
5
- export type LspRange = {
6
- start: LspPosition;
7
- end: LspPosition;
8
- };
9
- export interface Diagnostic {
10
- range: LspRange;
11
- severity?: number;
12
- source?: string;
13
- message: string;
14
- }
15
- export interface PublishDiagnosticsParams {
16
- uri: string;
17
- diagnostics: Diagnostic[];
18
- }
19
- //# sourceMappingURL=types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAC9D,MAAM,MAAM,QAAQ,GAAG;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,GAAG,EAAE,WAAW,CAAA;CAAE,CAAC;AAEhE,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,QAAQ,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B"}
package/esm/types.js DELETED
@@ -1 +0,0 @@
1
- export {};
@@ -1,62 +0,0 @@
1
- import type * as lsp from 'vscode-languageserver-protocol';
2
- import type { EditorUi } from '@kerebron/editor';
3
- import { LSPClient } from './LSPClient.js';
4
- import { PositionMapper } from '@kerebron/extension-markdown/PositionMapper';
5
- export interface LspSource {
6
- ui: EditorUi;
7
- getMappedContent(): Promise<{
8
- content: string;
9
- mapper: PositionMapper;
10
- }>;
11
- }
12
- export interface WorkspaceFile {
13
- uri: string;
14
- languageId: string;
15
- version: number;
16
- content: string;
17
- source: LspSource;
18
- getUi(): EditorUi | undefined;
19
- mapper: PositionMapper;
20
- }
21
- interface WorkspaceFileUpdate {
22
- file: WorkspaceFile;
23
- prevDoc: string;
24
- changes: lsp.TextDocumentContentChangeEvent[];
25
- }
26
- export declare abstract class Workspace {
27
- readonly client: LSPClient;
28
- abstract files: WorkspaceFile[];
29
- protected isConnected: boolean;
30
- constructor(client: LSPClient);
31
- getFile(uri: string): WorkspaceFile | null;
32
- abstract syncFiles(): readonly WorkspaceFileUpdate[];
33
- requestFile(uri: string): Promise<WorkspaceFile | null>;
34
- abstract openFile(uri: string, languageId: string, source: LspSource): void;
35
- abstract changedFile(uri: string): void;
36
- abstract closeFile(uri: string): void;
37
- connected(): Promise<void>;
38
- disconnected(): void;
39
- getUi(uri: string): Promise<EditorUi | undefined>;
40
- }
41
- declare class DefaultWorkspaceFile implements WorkspaceFile {
42
- readonly uri: string;
43
- readonly languageId: string;
44
- version: number;
45
- content: string;
46
- mapper: PositionMapper;
47
- source: LspSource;
48
- syncedContent: string;
49
- constructor(uri: string, languageId: string, version: number, content: string, mapper: PositionMapper, source: LspSource);
50
- getUi(): EditorUi;
51
- }
52
- export declare class DefaultWorkspace extends Workspace {
53
- files: DefaultWorkspaceFile[];
54
- private fileVersions;
55
- nextFileVersion(uri: string): number;
56
- syncFiles(): WorkspaceFileUpdate[];
57
- changedFile(uri: string): Promise<void>;
58
- openFile(uri: string, languageId: string, source: LspSource): Promise<void>;
59
- closeFile(uri: string): void;
60
- }
61
- export {};
62
- //# sourceMappingURL=workspace.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,GAAG,MAAM,gCAAgC,CAAC;AAG3D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,6CAA6C,CAAC;AAG7E,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,QAAQ,CAAC;IACb,gBAAgB,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,cAAc,CAAA;KAAE,CAAC,CAAC;CAC1E;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,IAAI,QAAQ,GAAG,SAAS,CAAC;IAC9B,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,UAAU,mBAAmB;IAC3B,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,GAAG,CAAC,8BAA8B,EAAE,CAAC;CAC/C;AAED,8BAAsB,SAAS;IAK3B,QAAQ,CAAC,MAAM,EAAE,SAAS;IAJ5B,QAAQ,CAAC,KAAK,EAAE,aAAa,EAAE,CAAC;IAChC,SAAS,CAAC,WAAW,UAAS;gBAGnB,MAAM,EAAE,SAAS;IAG5B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAI1C,QAAQ,CAAC,SAAS,IAAI,SAAS,mBAAmB,EAAE;IAEpD,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAIvD,QAAQ,CAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,IAAI;IAC3E,QAAQ,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IACvC,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAE/B,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAOhC,YAAY,IAAI,IAAI;IAOpB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;CAIlD;AAED,cAAM,oBAAqB,YAAW,aAAa;IAG/C,QAAQ,CAAC,GAAG,EAAE,MAAM;IACpB,QAAQ,CAAC,UAAU,EAAE,MAAM;IACpB,OAAO,EAAE,MAAM;IACf,OAAO,EAAE,MAAM;IACf,MAAM,EAAE,cAAc;IACtB,MAAM,EAAE,SAAS;IAPnB,aAAa,EAAE,MAAM,CAAM;gBAEvB,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,SAAS;IAI1B,KAAK;CAGN;AAED,qBAAa,gBAAiB,SAAQ,SAAS;IAC7C,KAAK,EAAE,oBAAoB,EAAE,CAAM;IACnC,OAAO,CAAC,YAAY,CAAkD;IAEtE,eAAe,CAAC,GAAG,EAAE,MAAM;IAI3B,SAAS;IAaH,WAAW,CAAC,GAAG,EAAE,MAAM;IAkCvB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS;IAsBjE,SAAS,CAAC,GAAG,EAAE,MAAM;CAOtB"}
package/esm/workspace.js DELETED
@@ -1,117 +0,0 @@
1
- import { TextDocumentSyncKind } from 'vscode-languageserver-protocol';
2
- import { computeIncrementalChanges } from './computeIncrementalChanges.js';
3
- export class Workspace {
4
- client;
5
- isConnected = false;
6
- constructor(client) {
7
- this.client = client;
8
- }
9
- getFile(uri) {
10
- return this.files.find((f) => f.uri == uri) || null;
11
- }
12
- requestFile(uri) {
13
- return Promise.resolve(this.getFile(uri));
14
- }
15
- async connected() {
16
- this.isConnected = true;
17
- for await (const file of this.files) {
18
- const result = await this.client.didOpen(file);
19
- }
20
- }
21
- disconnected() {
22
- for (const file of this.files) {
23
- this.client.workspace.closeFile(file.uri);
24
- }
25
- this.isConnected = false;
26
- }
27
- getUi(uri) {
28
- const file = this.getFile(uri);
29
- return Promise.resolve(file ? file.getUi() : undefined);
30
- }
31
- }
32
- class DefaultWorkspaceFile {
33
- uri;
34
- languageId;
35
- version;
36
- content;
37
- mapper;
38
- source;
39
- syncedContent = '';
40
- constructor(uri, languageId, version, content, mapper, source) {
41
- this.uri = uri;
42
- this.languageId = languageId;
43
- this.version = version;
44
- this.content = content;
45
- this.mapper = mapper;
46
- this.source = source;
47
- }
48
- getUi() {
49
- return this.source.ui;
50
- }
51
- }
52
- export class DefaultWorkspace extends Workspace {
53
- files = [];
54
- fileVersions = Object.create(null);
55
- nextFileVersion(uri) {
56
- return this.fileVersions[uri] = (this.fileVersions[uri] ?? -1) + 1;
57
- }
58
- syncFiles() {
59
- if (!this.client.supportSync) {
60
- return [];
61
- }
62
- const result = [];
63
- for (const file of this.files) {
64
- this.changedFile(file.uri);
65
- }
66
- return result;
67
- }
68
- async changedFile(uri) {
69
- const file = this.files.find((f) => f.uri == uri) || null;
70
- if (file) {
71
- const { content, mapper } = await file.source.getMappedContent();
72
- if (!this.isConnected) {
73
- file.content = content;
74
- file.mapper = mapper;
75
- return;
76
- }
77
- if (await this.client.notification('textDocument/didChange', {
78
- textDocument: { uri: file.uri, version: file.version },
79
- contentChanges: contentChangesFor(file, content, mapper, this.client.supportSync == TextDocumentSyncKind.Incremental),
80
- })) {
81
- file.syncedContent = file.content;
82
- file.content = content;
83
- file.mapper = mapper;
84
- file.version = this.nextFileVersion(file.uri);
85
- }
86
- }
87
- }
88
- async openFile(uri, languageId, source) {
89
- // if (uri) {}
90
- if (this.getFile(uri)) {
91
- this.closeFile(uri);
92
- }
93
- const mappedContent = await source.getMappedContent();
94
- const { content, mapper } = mappedContent;
95
- const file = new DefaultWorkspaceFile(uri, languageId, this.nextFileVersion(uri), content, mapper, source);
96
- this.files.push(file);
97
- this.client.didOpen(file);
98
- }
99
- closeFile(uri) {
100
- const file = this.getFile(uri);
101
- if (file) {
102
- this.files = this.files.filter((f) => f.uri !== uri);
103
- this.client.didClose(uri);
104
- }
105
- }
106
- }
107
- var Sync;
108
- (function (Sync) {
109
- Sync[Sync["AlwaysIfSmaller"] = 1024] = "AlwaysIfSmaller";
110
- })(Sync || (Sync = {}));
111
- function contentChangesFor(file, newContent, mapper, supportInc) {
112
- if (!supportInc || newContent.length < Sync.AlwaysIfSmaller) {
113
- return [{ text: newContent }];
114
- }
115
- const changes = computeIncrementalChanges(file.content, newContent);
116
- return changes.reverse();
117
- }