@adecore/lsp 0.22.1 → 0.23.1

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.
@@ -0,0 +1,4 @@
1
+ import type { CompletionItem, CompletionList } from './protocol.ts';
2
+ export declare function applyCompletionDefaults(item: CompletionItem, defaults?: CompletionList['itemDefaults'], options?: {
3
+ onInvalidRange?: (error: RangeError) => void;
4
+ }): CompletionItem;
@@ -0,0 +1,83 @@
1
+ function validRange(range, singleLine = true) {
2
+ if (range === null || typeof range !== 'object') {
3
+ return false;
4
+ }
5
+ const { start, end } = range;
6
+ return (start !== undefined &&
7
+ start !== null &&
8
+ typeof start === 'object' &&
9
+ end !== undefined &&
10
+ end !== null &&
11
+ typeof end === 'object' &&
12
+ [start.line, start.character, end.line, end.character].every((value) => Number.isSafeInteger(value) && value >= 0) &&
13
+ (!singleLine || start.line === end.line) &&
14
+ (start.line < end.line || (start.line === end.line && start.character <= end.character)));
15
+ }
16
+ function validEditRange(range, singleLine = true) {
17
+ if (range === null || typeof range !== 'object' || Array.isArray(range)) {
18
+ return false;
19
+ }
20
+ if ('start' in range) {
21
+ return validRange(range, singleLine);
22
+ }
23
+ return (validRange(range.insert) &&
24
+ validRange(range.replace) &&
25
+ range.insert.start.line === range.replace.start.line &&
26
+ range.insert.start.character === range.replace.start.character &&
27
+ range.insert.end.character <= range.replace.end.character);
28
+ }
29
+ export function applyCompletionDefaults(item, defaults, options) {
30
+ if (typeof item?.label !== 'string') {
31
+ throw new TypeError('A completion item must have a string label.');
32
+ }
33
+ for (const value of [item.filterText, item.sortText, item.insertText, item.textEditText]) {
34
+ if (value !== undefined && typeof value !== 'string') {
35
+ throw new TypeError('Completion ranking and insertion text must be strings.');
36
+ }
37
+ }
38
+ if (item.textEdit !== undefined) {
39
+ const edit = item.textEdit;
40
+ if (edit === null ||
41
+ typeof edit !== 'object' ||
42
+ typeof edit.newText !== 'string' ||
43
+ !('range' in edit ? validEditRange(edit.range, false) : validEditRange(edit))) {
44
+ throw new RangeError('Invalid completion item edit.');
45
+ }
46
+ }
47
+ if (defaults === undefined) {
48
+ return item;
49
+ }
50
+ const next = { ...item };
51
+ if (next.commitCharacters === undefined && defaults.commitCharacters !== undefined) {
52
+ next.commitCharacters = defaults.commitCharacters;
53
+ }
54
+ if (next.insertTextFormat === undefined && defaults.insertTextFormat !== undefined) {
55
+ next.insertTextFormat = defaults.insertTextFormat;
56
+ }
57
+ if (next.insertTextMode === undefined && defaults.insertTextMode !== undefined) {
58
+ next.insertTextMode = defaults.insertTextMode;
59
+ }
60
+ if (next.data === undefined && defaults.data !== undefined) {
61
+ next.data = defaults.data;
62
+ }
63
+ if (next.textEdit === undefined && defaults.editRange !== undefined) {
64
+ const range = defaults.editRange;
65
+ const newText = item.textEditText ?? item.label;
66
+ if (typeof newText !== 'string') {
67
+ throw new TypeError('Completion edit text must be a string.');
68
+ }
69
+ const invalid = (message) => {
70
+ const error = new RangeError(message);
71
+ if (options?.onInvalidRange === undefined) {
72
+ throw error;
73
+ }
74
+ options.onInvalidRange(error);
75
+ return next;
76
+ };
77
+ if (!validEditRange(range)) {
78
+ return invalid('Invalid completion default edit range.');
79
+ }
80
+ next.textEdit = 'start' in range ? { range, newText } : { insert: range.insert, replace: range.replace, newText };
81
+ }
82
+ return next;
83
+ }
@@ -1,5 +1,5 @@
1
1
  import type { LspSession } from './session.ts';
2
- import type { CodeAction, CodeActionContext, CodeLens, Command, CompletionContext, CompletionItem, CompletionResult, ContentChange, DocumentDiagnosticReport, DocumentHighlight, DocumentItem, DocumentRequestOptions, DocumentSymbolResult, FoldingRange, FormattingOptions, Hover, InlayHint, Location, NavigationResult, Position, PrepareRenameResult, Range, SelectionRange, SemanticTokens, SemanticTokensDelta, SignatureHelp, SignatureHelpContext, TextEdit, WorkspaceEdit } from './protocol.ts';
2
+ import type { CallHierarchyIncomingCall, CallHierarchyItem, CallHierarchyOutgoingCall, CodeAction, CodeActionContext, CodeLens, Command, CompletionContext, CompletionItem, CompletionResult, ContentChange, DocumentDiagnosticReport, DocumentHighlight, DocumentItem, DocumentRequestOptions, DocumentSymbolResult, FoldingRange, FormattingOptions, Hover, InlayHint, Location, NavigationResult, Position, PrepareRenameResult, Range, SelectionRange, SemanticTokens, SemanticTokensDelta, SignatureHelp, SignatureHelpContext, TextEdit, WorkspaceEdit } from './protocol.ts';
3
3
  export declare class LspDocument {
4
4
  readonly session: LspSession;
5
5
  readonly uri: string;
@@ -39,6 +39,7 @@ export declare class LspDocument {
39
39
  resolveCodeLens(lens: CodeLens, options?: DocumentRequestOptions): Promise<CodeLens>;
40
40
  formatting(formatting: FormattingOptions, options?: DocumentRequestOptions): Promise<TextEdit[] | null>;
41
41
  rangeFormatting(range: Range, formatting: FormattingOptions, options?: DocumentRequestOptions): Promise<TextEdit[] | null>;
42
+ onTypeFormatting(position: Position, ch: string, formatting: FormattingOptions, options?: DocumentRequestOptions): Promise<TextEdit[] | null>;
42
43
  foldingRanges(options?: DocumentRequestOptions): Promise<FoldingRange[] | null>;
43
44
  selectionRanges(positions: readonly Position[], options?: DocumentRequestOptions): Promise<SelectionRange[] | null>;
44
45
  semanticTokens(options?: DocumentRequestOptions): Promise<SemanticTokens | null>;
@@ -46,6 +47,9 @@ export declare class LspDocument {
46
47
  semanticTokensRange(range: Range, options?: DocumentRequestOptions): Promise<SemanticTokens | null>;
47
48
  inlayHints(range: Range, options?: DocumentRequestOptions): Promise<InlayHint[] | null>;
48
49
  resolveInlayHint(hint: InlayHint, options?: DocumentRequestOptions): Promise<InlayHint>;
50
+ prepareCallHierarchy(position: Position, options?: DocumentRequestOptions): Promise<CallHierarchyItem[] | null>;
51
+ incomingCalls(item: CallHierarchyItem, options?: DocumentRequestOptions): Promise<CallHierarchyIncomingCall[] | null>;
52
+ outgoingCalls(item: CallHierarchyItem, options?: DocumentRequestOptions): Promise<CallHierarchyOutgoingCall[] | null>;
49
53
  diagnostics(previousResultId?: string, identifier?: string, options?: DocumentRequestOptions): Promise<DocumentDiagnosticReport>;
50
54
  request<T = unknown>(method: string, params: object, options?: DocumentRequestOptions): Promise<T>;
51
55
  close(): Promise<void>;
package/dist/document.js CHANGED
@@ -149,6 +149,10 @@ export class LspDocument {
149
149
  rangeFormatting(range, formatting, options) {
150
150
  return this.feature('textDocument/rangeFormatting', { range, options: formatting }, options);
151
151
  }
152
+ /* `ch` is the character that was typed; `position` is where the caret is after it. */
153
+ onTypeFormatting(position, ch, formatting, options) {
154
+ return this.feature('textDocument/onTypeFormatting', { position, ch, options: formatting }, options);
155
+ }
152
156
  foldingRanges(options) {
153
157
  return this.feature('textDocument/foldingRange', {}, options);
154
158
  }
@@ -170,6 +174,16 @@ export class LspDocument {
170
174
  resolveInlayHint(hint, options) {
171
175
  return this.resolve('inlayHint/resolve', hint, options);
172
176
  }
177
+ prepareCallHierarchy(position, options) {
178
+ return this.feature('textDocument/prepareCallHierarchy', { position }, options);
179
+ }
180
+ /* The callers of an item the server gave. Neighbouring expansions run beside each other, so a newer one does not cancel an older unless `cancelPrevious` says so. */
181
+ incomingCalls(item, options) {
182
+ return this.perform('callHierarchy/incomingCalls', { item }, { cancelPrevious: false, ...options });
183
+ }
184
+ outgoingCalls(item, options) {
185
+ return this.perform('callHierarchy/outgoingCalls', { item }, { cancelPrevious: false, ...options });
186
+ }
173
187
  diagnostics(previousResultId, identifier, options) {
174
188
  return this.feature('textDocument/diagnostic', { previousResultId, identifier }, options);
175
189
  }
@@ -1,5 +1,13 @@
1
- import type { FileOperationFilter, FileRename } from './protocol.ts';
1
+ import type { FileCreate, FileDelete, FileOperationFilter, FileRename } from './protocol.ts';
2
2
  export interface RenamedFile extends FileRename {
3
3
  directory: boolean;
4
4
  }
5
+ export interface CreatedFile extends FileCreate {
6
+ directory: boolean;
7
+ }
8
+ export interface DeletedFile extends FileDelete {
9
+ directory: boolean;
10
+ }
5
11
  export declare function renamesTaken(filters: readonly FileOperationFilter[], files: readonly RenamedFile[]): FileRename[];
12
+ export declare function createsTaken(filters: readonly FileOperationFilter[], files: readonly CreatedFile[]): FileCreate[];
13
+ export declare function deletesTaken(filters: readonly FileOperationFilter[], files: readonly DeletedFile[]): FileDelete[];
@@ -1,12 +1,12 @@
1
1
  import { globMatch } from './glob.js';
2
- function filterTakes(filter, file) {
2
+ function filterTakes(filter, uri, directory) {
3
3
  const { matches, glob, options } = filter.pattern;
4
- if (matches !== undefined && (matches === 'folder') !== file.directory) {
4
+ if (matches !== undefined && (matches === 'folder') !== directory) {
5
5
  return false;
6
6
  }
7
7
  let url;
8
8
  try {
9
- url = new URL(file.oldUri);
9
+ url = new URL(uri);
10
10
  }
11
11
  catch {
12
12
  return false;
@@ -19,5 +19,13 @@ function filterTakes(filter, file) {
19
19
  }
20
20
  /* The renames a server asked to hear about, by the filters it registered. A rename is matched on the place it leaves. */
21
21
  export function renamesTaken(filters, files) {
22
- return files.filter((file) => filters.some((filter) => filterTakes(filter, file))).map(({ oldUri, newUri }) => ({ oldUri, newUri }));
22
+ return files.filter((file) => filters.some((filter) => filterTakes(filter, file.oldUri, file.directory))).map(({ oldUri, newUri }) => ({ oldUri, newUri }));
23
+ }
24
+ /* The files made that a server asked to hear about, by the filters it registered. */
25
+ export function createsTaken(filters, files) {
26
+ return files.filter((file) => filters.some((filter) => filterTakes(filter, file.uri, file.directory))).map(({ uri }) => ({ uri }));
27
+ }
28
+ /* The files deleted that a server asked to hear about, by the filters it registered. A folder is matched as one, not by what was in it. */
29
+ export function deletesTaken(filters, files) {
30
+ return files.filter((file) => filters.some((filter) => filterTakes(filter, file.uri, file.directory))).map(({ uri }) => ({ uri }));
23
31
  }
package/dist/index.d.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  export { ErrorCodes, JsonRpcConnection, LspError, StaleResultError, type RequestHandler } from './connection.ts';
2
+ export { applyCompletionDefaults } from './completion-defaults.ts';
2
3
  export { LspDocument } from './document.ts';
3
4
  export { applyContentChanges, applyTextEdits, endPosition, minimalChange, offsetAt, planWorkspaceEdit, positionAt, type DocumentSnapshot, type PlannedDocumentEdit } from './edits.ts';
4
- export { renamesTaken, type RenamedFile } from './file-operations.ts';
5
+ export { planWorkspaceOperations, type PlannedCreateStep, type PlannedDeleteStep, type PlannedRenameStep, type PlannedTextStep, type ResourceOperationKind, type WorkspaceEditPlan, type WorkspaceEditSource, type WorkspaceEditStep, type WorkspaceEditText } from './workspace-operations.ts';
6
+ export { createsTaken, deletesTaken, renamesTaken, type CreatedFile, type DeletedFile, type RenamedFile } from './file-operations.ts';
5
7
  export { watchesFile, type FileChangeType } from './watched-files.ts';
6
8
  export { LspSession, type LspSessionOptions, type SessionState } from './session.ts';
7
9
  export type { DiagnosticsReport, LanguageDocument, LanguageRequestOptions, LanguageService } from './service.ts';
package/dist/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  export { ErrorCodes, JsonRpcConnection, LspError, StaleResultError } from './connection.js';
2
+ export { applyCompletionDefaults } from './completion-defaults.js';
2
3
  export { LspDocument } from './document.js';
3
4
  export { applyContentChanges, applyTextEdits, endPosition, minimalChange, offsetAt, planWorkspaceEdit, positionAt } from './edits.js';
4
- export { renamesTaken } from './file-operations.js';
5
+ export { planWorkspaceOperations } from './workspace-operations.js';
6
+ export { createsTaken, deletesTaken, renamesTaken } from './file-operations.js';
5
7
  export { watchesFile } from './watched-files.js';
6
8
  export { LspSession } from './session.js';
7
9
  export { ContentLengthDecoder, connectWebSocket, createMemoryTransportPair, createStreamTransport, encodeMessage } from './transport.js';
@@ -185,6 +185,24 @@ export interface WorkspaceSymbol {
185
185
  };
186
186
  data?: unknown;
187
187
  }
188
+ export interface CallHierarchyItem {
189
+ name: string;
190
+ kind: SymbolKind;
191
+ tags?: 1[];
192
+ detail?: string;
193
+ uri: string;
194
+ range: Range;
195
+ selectionRange: Range;
196
+ data?: unknown;
197
+ }
198
+ export interface CallHierarchyIncomingCall {
199
+ from: CallHierarchyItem;
200
+ fromRanges: Range[];
201
+ }
202
+ export interface CallHierarchyOutgoingCall {
203
+ to: CallHierarchyItem;
204
+ fromRanges: Range[];
205
+ }
188
206
  export type DocumentSymbolResult = DocumentSymbol[] | SymbolInformation[] | null;
189
207
  export type WorkspaceSymbolResult = SymbolInformation[] | WorkspaceSymbol[] | null;
190
208
  export interface ParameterInformation {
@@ -262,6 +280,13 @@ export interface FileRename {
262
280
  oldUri: string;
263
281
  newUri: string;
264
282
  }
283
+ export interface FileCreate {
284
+ uri: string;
285
+ }
286
+ export interface FileDelete {
287
+ uri: string;
288
+ }
289
+ export type FileOperation = 'willRename' | 'didRename' | 'willCreate' | 'didCreate' | 'willDelete' | 'didDelete';
265
290
  export interface FileOperationFilter {
266
291
  scheme?: string;
267
292
  pattern: {
@@ -393,6 +418,8 @@ export interface ProviderOptions {
393
418
  resolveProvider?: boolean;
394
419
  prepareProvider?: boolean;
395
420
  triggerCharacters?: string[];
421
+ firstTriggerCharacter?: string;
422
+ moreTriggerCharacter?: string[];
396
423
  retriggerCharacters?: string[];
397
424
  commands?: string[];
398
425
  watchers?: FileSystemWatcher[];
@@ -440,6 +467,8 @@ export interface ServerCapabilities {
440
467
  legend: SemanticTokensLegend;
441
468
  };
442
469
  inlayHintProvider?: boolean | ProviderOptions;
470
+ callHierarchyProvider?: boolean | ProviderOptions;
471
+ documentOnTypeFormattingProvider?: ProviderOptions;
443
472
  diagnosticProvider?: ProviderOptions;
444
473
  [capability: string]: unknown;
445
474
  }
package/dist/service.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import type { CodeAction, CodeActionContext, CodeLens, Command, CompletionContext, CompletionItem, CompletionResult, ContentChange, Diagnostic, Disposable, DocumentHighlight, DocumentSymbolResult, FoldingRange, FormattingOptions, Hover, InlayHint, Location, NavigationResult, Position, PrepareRenameResult, ProviderOptions, Range, SelectionRange, SemanticTokens, SemanticTokensDelta, SignatureHelp, SignatureHelpContext, TextEdit, WorkspaceEdit, WorkspaceSymbolResult } from './protocol.ts';
1
+ import type { CallHierarchyIncomingCall, CallHierarchyItem, CallHierarchyOutgoingCall, CodeAction, CodeActionContext, CodeLens, Command, CompletionContext, CompletionItem, CompletionResult, ContentChange, Diagnostic, Disposable, DocumentHighlight, DocumentSymbolResult, FoldingRange, FormattingOptions, Hover, InlayHint, Location, NavigationResult, Position, PrepareRenameResult, ProviderOptions, Range, SelectionRange, SemanticTokens, SemanticTokensDelta, SignatureHelp, SignatureHelpContext, TextEdit, WorkspaceEdit, WorkspaceSymbolResult } from './protocol.ts';
2
+ import type { CreatedFile, DeletedFile } from './file-operations.ts';
2
3
  export interface LanguageDocument {
3
4
  uri: string;
4
5
  languageId: string;
@@ -18,6 +19,7 @@ export interface LanguageService {
18
19
  openDocument(document: LanguageDocument): Promise<void>;
19
20
  changeDocument(uri: string, changes: readonly ContentChange[]): Promise<void>;
20
21
  closeDocument(uri: string): Promise<void>;
22
+ versionOf?(uri: string): number | null;
21
23
  supports(method: string, uri: string): boolean;
22
24
  providerOptions(method: string, uri: string): ProviderOptions | undefined;
23
25
  onProvidersChanged(listener: (uri: string) => void): Disposable;
@@ -40,6 +42,7 @@ export interface LanguageService {
40
42
  executeCommand(uri: string, command: Command, options?: LanguageRequestOptions): Promise<unknown>;
41
43
  formatting(uri: string, formatting: FormattingOptions, options?: LanguageRequestOptions): Promise<TextEdit[] | null>;
42
44
  rangeFormatting(uri: string, range: Range, formatting: FormattingOptions, options?: LanguageRequestOptions): Promise<TextEdit[] | null>;
45
+ onTypeFormatting?(uri: string, position: Position, ch: string, formatting: FormattingOptions, options?: LanguageRequestOptions): Promise<TextEdit[] | null>;
43
46
  semanticTokens(uri: string, options?: LanguageRequestOptions): Promise<SemanticTokens | null>;
44
47
  semanticTokensDelta(uri: string, previousResultId: string, options?: LanguageRequestOptions): Promise<SemanticTokens | SemanticTokensDelta | null>;
45
48
  semanticTokensRange(uri: string, range: Range, options?: LanguageRequestOptions): Promise<SemanticTokens | null>;
@@ -48,6 +51,13 @@ export interface LanguageService {
48
51
  workspaceSymbols(uri: string, query: string, options?: LanguageRequestOptions): Promise<WorkspaceSymbolResult>;
49
52
  foldingRanges(uri: string, options?: LanguageRequestOptions): Promise<FoldingRange[] | null>;
50
53
  selectionRanges(uri: string, positions: readonly Position[], options?: LanguageRequestOptions): Promise<SelectionRange[] | null>;
54
+ prepareCallHierarchy?(uri: string, position: Position, options?: LanguageRequestOptions): Promise<CallHierarchyItem[] | null>;
55
+ incomingCalls?(uri: string, item: CallHierarchyItem, options?: LanguageRequestOptions): Promise<CallHierarchyIncomingCall[] | null>;
56
+ outgoingCalls?(uri: string, item: CallHierarchyItem, options?: LanguageRequestOptions): Promise<CallHierarchyOutgoingCall[] | null>;
57
+ willCreateFiles?(files: readonly CreatedFile[], options?: LanguageRequestOptions): Promise<WorkspaceEdit | null>;
58
+ didCreateFiles?(files: readonly CreatedFile[]): Promise<void>;
59
+ willDeleteFiles?(files: readonly DeletedFile[], options?: LanguageRequestOptions): Promise<WorkspaceEdit | null>;
60
+ didDeleteFiles?(files: readonly DeletedFile[]): Promise<void>;
51
61
  codeLenses(uri: string, options?: LanguageRequestOptions): Promise<CodeLens[] | null>;
52
62
  resolveCodeLens(uri: string, lens: CodeLens, options?: LanguageRequestOptions): Promise<CodeLens>;
53
63
  }
package/dist/session.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { JsonRpcConnection, type RequestHandler } from './connection.ts';
2
2
  import { LspDocument } from './document.ts';
3
- import { type RenamedFile } from './file-operations.ts';
4
- import type { ApplyWorkspaceEditParams, ApplyWorkspaceEditResult, Command, ConfigurationItem, Disposable, DocumentItem, FileEvent, FileOperationFilter, FileSystemWatcher, InitializeResult, LspTransport, ProgressParams, ProviderOptions, PublishDiagnosticsParams, RequestOptions, ServerCapabilities, TextDocumentSyncOptions, WorkspaceEdit, WorkspaceFolder, WorkspaceSymbol, WorkspaceSymbolResult } from './protocol.ts';
3
+ import { type CreatedFile, type DeletedFile, type RenamedFile } from './file-operations.ts';
4
+ import type { ResourceOperationKind } from './workspace-operations.ts';
5
+ import type { ApplyWorkspaceEditParams, ApplyWorkspaceEditResult, Command, ConfigurationItem, Disposable, DocumentItem, FileEvent, FileOperation, FileOperationFilter, FileSystemWatcher, InitializeResult, LspTransport, ProgressParams, ProviderOptions, PublishDiagnosticsParams, RequestOptions, ServerCapabilities, TextDocumentSyncOptions, WorkspaceEdit, WorkspaceFolder, WorkspaceSymbol, WorkspaceSymbolResult } from './protocol.ts';
5
6
  export type SessionState = 'new' | 'initializing' | 'ready' | 'closing' | 'closed';
6
7
  export interface LspSessionOptions {
7
8
  rootUri?: string | null;
@@ -14,6 +15,9 @@ export interface LspSessionOptions {
14
15
  };
15
16
  timeoutMs?: number;
16
17
  snippetSupport?: boolean;
18
+ insertTextModes?: readonly (1 | 2)[];
19
+ completionItemDefaults?: readonly string[];
20
+ resourceOperations?: readonly ResourceOperationKind[];
17
21
  onConfiguration?: (item: ConfigurationItem) => unknown | Promise<unknown>;
18
22
  onApplyEdit?: (params: ApplyWorkspaceEditParams) => ApplyWorkspaceEditResult | Promise<ApplyWorkspaceEditResult>;
19
23
  onShowMessage?: (params: {
@@ -64,9 +68,13 @@ export declare class LspSession {
64
68
  onDiagnostics(listener: (params: PublishDiagnosticsParams) => void): Disposable;
65
69
  watchedFiles(): FileSystemWatcher[];
66
70
  didChangeWatchedFiles(changes: readonly FileEvent[]): Promise<void>;
67
- fileOperationFilters(operation: 'willRename' | 'didRename'): FileOperationFilter[];
71
+ fileOperationFilters(operation: FileOperation): FileOperationFilter[];
68
72
  willRenameFiles(files: readonly RenamedFile[], options?: RequestOptions): Promise<WorkspaceEdit | null>;
69
73
  didRenameFiles(files: readonly RenamedFile[]): Promise<void>;
74
+ willCreateFiles(files: readonly CreatedFile[], options?: RequestOptions): Promise<WorkspaceEdit | null>;
75
+ didCreateFiles(files: readonly CreatedFile[]): Promise<void>;
76
+ willDeleteFiles(files: readonly DeletedFile[], options?: RequestOptions): Promise<WorkspaceEdit | null>;
77
+ didDeleteFiles(files: readonly DeletedFile[]): Promise<void>;
70
78
  onCapabilitiesChanged(listener: () => void): Disposable;
71
79
  shutdown(): Promise<void>;
72
80
  forgetDocument(document: LspDocument): void;
package/dist/session.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ErrorCodes, JsonRpcConnection, LspError } from './connection.js';
2
2
  import { LspDocument } from './document.js';
3
- import { renamesTaken } from './file-operations.js';
3
+ import { createsTaken, deletesTaken, renamesTaken } from './file-operations.js';
4
4
  import { globMatch } from './glob.js';
5
5
  /* The capability that advertises each method statically. */
6
6
  const PROVIDERS = {
@@ -26,6 +26,7 @@ const PROVIDERS = {
26
26
  'workspace/executeCommand': 'executeCommandProvider',
27
27
  'textDocument/formatting': 'documentFormattingProvider',
28
28
  'textDocument/rangeFormatting': 'documentRangeFormattingProvider',
29
+ 'textDocument/onTypeFormatting': 'documentOnTypeFormattingProvider',
29
30
  'textDocument/foldingRange': 'foldingRangeProvider',
30
31
  'textDocument/selectionRange': 'selectionRangeProvider',
31
32
  'textDocument/semanticTokens/full': 'semanticTokensProvider',
@@ -33,6 +34,9 @@ const PROVIDERS = {
33
34
  'textDocument/semanticTokens/range': 'semanticTokensProvider',
34
35
  'textDocument/inlayHint': 'inlayHintProvider',
35
36
  'inlayHint/resolve': 'inlayHintProvider',
37
+ 'textDocument/prepareCallHierarchy': 'callHierarchyProvider',
38
+ 'callHierarchy/incomingCalls': 'callHierarchyProvider',
39
+ 'callHierarchy/outgoingCalls': 'callHierarchyProvider',
36
40
  'textDocument/diagnostic': 'diagnosticProvider'
37
41
  };
38
42
  /* A method whose dynamic registration is made under the name of another. */
@@ -41,6 +45,8 @@ const REGISTRATION_METHODS = {
41
45
  'codeAction/resolve': 'textDocument/codeAction',
42
46
  'codeLens/resolve': 'textDocument/codeLens',
43
47
  'inlayHint/resolve': 'textDocument/inlayHint',
48
+ 'callHierarchy/incomingCalls': 'textDocument/prepareCallHierarchy',
49
+ 'callHierarchy/outgoingCalls': 'textDocument/prepareCallHierarchy',
44
50
  'textDocument/prepareRename': 'textDocument/rename',
45
51
  'workspaceSymbol/resolve': 'workspace/symbol',
46
52
  'textDocument/semanticTokens/full': 'textDocument/semanticTokens',
@@ -287,7 +293,7 @@ export class LspSession {
287
293
  didChangeWatchedFiles(changes) {
288
294
  return this.notify('workspace/didChangeWatchedFiles', { changes });
289
295
  }
290
- /* The files a server asked to hear about when they are renamed, from its capabilities and its registrations. */
296
+ /* The files a server asked to hear about when they are renamed, created or deleted, from its capabilities and its registrations. */
291
297
  fileOperationFilters(operation) {
292
298
  const fileOperations = this.serverCapabilities.workspace?.fileOperations;
293
299
  const method = `workspace/${operation}Files`;
@@ -310,6 +316,30 @@ export class LspSession {
310
316
  await this.notify('workspace/didRenameFiles', { files: taken });
311
317
  }
312
318
  }
319
+ /* What the server would change before these files are made, or null when it takes none of them or has nothing to say. */
320
+ async willCreateFiles(files, options) {
321
+ const taken = createsTaken(this.fileOperationFilters('willCreate'), files);
322
+ return taken.length === 0 || this.phase !== 'ready' ? null : this.request('workspace/willCreateFiles', { files: taken }, options);
323
+ }
324
+ /* Tells the server which of these files were made, those its filters take. */
325
+ async didCreateFiles(files) {
326
+ const taken = createsTaken(this.fileOperationFilters('didCreate'), files);
327
+ if (taken.length > 0 && this.phase === 'ready') {
328
+ await this.notify('workspace/didCreateFiles', { files: taken });
329
+ }
330
+ }
331
+ /* What the server would change before these files are deleted, or null when it takes none of them or has nothing to say. */
332
+ async willDeleteFiles(files, options) {
333
+ const taken = deletesTaken(this.fileOperationFilters('willDelete'), files);
334
+ return taken.length === 0 || this.phase !== 'ready' ? null : this.request('workspace/willDeleteFiles', { files: taken }, options);
335
+ }
336
+ /* Tells the server which of these files were deleted, those its filters take. */
337
+ async didDeleteFiles(files) {
338
+ const taken = deletesTaken(this.fileOperationFilters('didDelete'), files);
339
+ if (taken.length > 0 && this.phase === 'ready') {
340
+ await this.notify('workspace/didDeleteFiles', { files: taken });
341
+ }
342
+ }
313
343
  /* Registrations and the refresh requests of the server both land here, since each can change what a document may ask. */
314
344
  onCapabilitiesChanged(listener) {
315
345
  this.capabilityListeners.add(listener);
@@ -394,8 +424,16 @@ function clientCapabilities(options) {
394
424
  general: { positionEncodings: ['utf-16'] },
395
425
  workspace: {
396
426
  applyEdit: !!options.onApplyEdit,
397
- workspaceEdit: { documentChanges: true, resourceOperations: ['create', 'rename'], failureHandling: 'abort' },
398
- fileOperations: { dynamicRegistration: true, willRename: true, didRename: true },
427
+ workspaceEdit: { documentChanges: true, resourceOperations: [...(options.resourceOperations ?? ['create', 'rename'])], failureHandling: 'abort' },
428
+ fileOperations: {
429
+ dynamicRegistration: true,
430
+ willRename: true,
431
+ didRename: true,
432
+ willCreate: true,
433
+ didCreate: true,
434
+ willDelete: true,
435
+ didDelete: true
436
+ },
399
437
  configuration: true,
400
438
  workspaceFolders: true,
401
439
  executeCommand: dynamic,
@@ -419,8 +457,11 @@ function clientCapabilities(options) {
419
457
  completion: {
420
458
  ...dynamic,
421
459
  contextSupport: true,
460
+ insertTextMode: 1,
461
+ ...(options.completionItemDefaults?.length ? { completionList: { itemDefaults: [...options.completionItemDefaults] } } : {}),
422
462
  completionItem: {
423
463
  snippetSupport: options.snippetSupport ?? false,
464
+ ...(options.insertTextModes?.length ? { insertTextModeSupport: { valueSet: [...options.insertTextModes] } } : {}),
424
465
  commitCharactersSupport: true,
425
466
  documentationFormat: ['markdown', 'plaintext'],
426
467
  deprecatedSupport: true,
@@ -474,6 +515,7 @@ function clientCapabilities(options) {
474
515
  codeLens: dynamic,
475
516
  formatting: dynamic,
476
517
  rangeFormatting: dynamic,
518
+ onTypeFormatting: dynamic,
477
519
  foldingRange: { ...dynamic, lineFoldingOnly: false, foldingRange: { collapsedText: false } },
478
520
  selectionRange: dynamic,
479
521
  semanticTokens: {
@@ -521,6 +563,7 @@ function clientCapabilities(options) {
521
563
  multilineTokenSupport: false
522
564
  },
523
565
  inlayHint: { ...dynamic, resolveSupport: { properties: ['tooltip', 'textEdits', 'label.tooltip', 'label.location', 'label.command'] } },
566
+ callHierarchy: { dynamicRegistration: false },
524
567
  diagnostic: { ...dynamic, relatedDocumentSupport: true }
525
568
  }
526
569
  };
@@ -0,0 +1,45 @@
1
+ import type { TextEdit, WorkspaceEdit } from './protocol.ts';
2
+ export type ResourceOperationKind = 'create' | 'rename' | 'delete';
3
+ export interface WorkspaceEditText {
4
+ readonly text: string;
5
+ readonly version: number | null;
6
+ readonly open: boolean;
7
+ }
8
+ export interface WorkspaceEditSource {
9
+ read(uri: string): Promise<WorkspaceEditText | null>;
10
+ exists?(uri: string): Promise<boolean>;
11
+ isFolder?(uri: string): Promise<boolean>;
12
+ readonly operations: readonly ResourceOperationKind[];
13
+ }
14
+ export interface PlannedTextStep {
15
+ readonly kind: 'edits';
16
+ readonly uri: string;
17
+ readonly readUri: string;
18
+ readonly edits: readonly TextEdit[];
19
+ readonly before: string;
20
+ readonly after: string;
21
+ readonly version: number | null;
22
+ readonly open: boolean;
23
+ }
24
+ export interface PlannedCreateStep {
25
+ readonly kind: 'create';
26
+ readonly uri: string;
27
+ readonly text: string;
28
+ readonly overwrite: boolean;
29
+ }
30
+ export interface PlannedRenameStep {
31
+ readonly kind: 'rename';
32
+ readonly oldUri: string;
33
+ readonly newUri: string;
34
+ readonly overwrite: boolean;
35
+ }
36
+ export interface PlannedDeleteStep {
37
+ readonly kind: 'delete';
38
+ readonly uri: string;
39
+ readonly recursive: boolean;
40
+ }
41
+ export type WorkspaceEditStep = PlannedTextStep | PlannedCreateStep | PlannedRenameStep | PlannedDeleteStep;
42
+ export interface WorkspaceEditPlan {
43
+ readonly steps: readonly WorkspaceEditStep[];
44
+ }
45
+ export declare function planWorkspaceOperations(edit: WorkspaceEdit, source: WorkspaceEditSource): Promise<WorkspaceEditPlan>;