@adecore/lsp 0.17.0-beta.2 → 0.17.0
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/dist/edits.d.ts +1 -0
- package/dist/edits.js +32 -10
- package/dist/session.js +1 -1
- package/package.json +1 -1
- package/src/edits.ts +35 -11
- package/src/session.ts +1 -1
package/dist/edits.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export interface PlannedDocumentEdit {
|
|
|
8
8
|
version: number | null;
|
|
9
9
|
before: string;
|
|
10
10
|
text: string;
|
|
11
|
+
created?: true;
|
|
11
12
|
}
|
|
12
13
|
export declare function offsetAt(text: string, position: Position): number;
|
|
13
14
|
export declare function positionAt(text: string, offset: number): Position;
|
package/dist/edits.js
CHANGED
|
@@ -137,25 +137,47 @@ export function minimalChange(before, after) {
|
|
|
137
137
|
text: after.slice(start, after.length - end)
|
|
138
138
|
};
|
|
139
139
|
}
|
|
140
|
-
|
|
140
|
+
function snapshotEdit(uri, snapshots) {
|
|
141
|
+
const snapshot = snapshots.get(uri);
|
|
142
|
+
if (!snapshot) {
|
|
143
|
+
throw new LspError(`Missing workspace snapshot: ${uri}`);
|
|
144
|
+
}
|
|
145
|
+
return { uri, version: snapshot.version, before: snapshot.text, text: snapshot.text };
|
|
146
|
+
}
|
|
147
|
+
/* A file that is there already is refused, unless the create says to empty it or to leave it as it is. */
|
|
148
|
+
function planCreate(change, snapshots, planned) {
|
|
149
|
+
const existing = planned.get(change.uri) ?? (snapshots.has(change.uri) ? snapshotEdit(change.uri, snapshots) : null);
|
|
150
|
+
if (existing === null) {
|
|
151
|
+
planned.set(change.uri, { uri: change.uri, version: null, before: '', text: '', created: true });
|
|
152
|
+
}
|
|
153
|
+
else if (change.options?.overwrite) {
|
|
154
|
+
planned.set(change.uri, { ...existing, text: '' });
|
|
155
|
+
}
|
|
156
|
+
else if (!change.options?.ignoreIfExists) {
|
|
157
|
+
throw new LspError(`${change.uri} already exists`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/*
|
|
161
|
+
* Plans text edits and created files in memory, in the order the edit gives them. `snapshots` holds the
|
|
162
|
+
* files that are there; a file the edit creates is absent from it. A rename or delete needs the host's own handling and is refused.
|
|
163
|
+
*/
|
|
141
164
|
export function planWorkspaceEdit(edit, snapshots) {
|
|
142
165
|
const planned = new Map();
|
|
143
166
|
const changes = edit.documentChanges ?? Object.entries(edit.changes ?? {}).map(([uri, edits]) => ({ textDocument: { uri, version: null }, edits }));
|
|
144
167
|
for (const change of changes) {
|
|
145
168
|
if ('kind' in change) {
|
|
146
|
-
|
|
169
|
+
if (change.kind !== 'create') {
|
|
170
|
+
throw new LspError(`A host file-operation handler is required for ${change.kind}`);
|
|
171
|
+
}
|
|
172
|
+
planCreate(change, snapshots, planned);
|
|
173
|
+
continue;
|
|
147
174
|
}
|
|
148
175
|
const { uri, version } = change.textDocument;
|
|
149
|
-
const
|
|
150
|
-
if (
|
|
151
|
-
throw new LspError(`Missing workspace snapshot: ${uri}`);
|
|
152
|
-
}
|
|
153
|
-
if (version !== null && snapshot.version !== version) {
|
|
176
|
+
const current = planned.get(uri) ?? snapshotEdit(uri, snapshots);
|
|
177
|
+
if (version !== null && current.version !== version) {
|
|
154
178
|
throw new LspError(`Workspace edit version mismatch: ${uri}`, ErrorCodes.ContentModified);
|
|
155
179
|
}
|
|
156
|
-
|
|
157
|
-
const text = applyTextEdits(before, change.edits);
|
|
158
|
-
planned.set(uri, { uri, version: snapshot.version, before: snapshot.text, text });
|
|
180
|
+
planned.set(uri, { ...current, text: applyTextEdits(current.text, change.edits) });
|
|
159
181
|
}
|
|
160
182
|
return [...planned.values()];
|
|
161
183
|
}
|
package/dist/session.js
CHANGED
|
@@ -395,7 +395,7 @@ function clientCapabilities(options) {
|
|
|
395
395
|
general: { positionEncodings: ['utf-16'] },
|
|
396
396
|
workspace: {
|
|
397
397
|
applyEdit: !!options.onApplyEdit,
|
|
398
|
-
workspaceEdit: { documentChanges: true, resourceOperations: ['rename'], failureHandling: 'abort' },
|
|
398
|
+
workspaceEdit: { documentChanges: true, resourceOperations: ['create', 'rename'], failureHandling: 'abort' },
|
|
399
399
|
fileOperations: { dynamicRegistration: true, willRename: true, didRename: true },
|
|
400
400
|
configuration: true,
|
|
401
401
|
workspaceFolders: true,
|
package/package.json
CHANGED
package/src/edits.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ErrorCodes, LspError } from './connection.ts';
|
|
2
|
-
import type { ContentChange, Position, TextEdit, WorkspaceEdit } from './protocol.ts';
|
|
2
|
+
import type { ContentChange, CreateFile, Position, TextEdit, WorkspaceEdit } from './protocol.ts';
|
|
3
3
|
|
|
4
4
|
export interface DocumentSnapshot {
|
|
5
5
|
text: string;
|
|
@@ -11,6 +11,8 @@ export interface PlannedDocumentEdit {
|
|
|
11
11
|
version: number | null;
|
|
12
12
|
before: string;
|
|
13
13
|
text: string;
|
|
14
|
+
/* A file the edit creates, which was not there: the host makes it with `text` and fails when it is there by then. */
|
|
15
|
+
created?: true;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
/* A line ends at `\n`, `\r\n` or a lone `\r`, which is how the protocol counts lines. */
|
|
@@ -158,25 +160,47 @@ export function minimalChange(before: string, after: string): ContentChange {
|
|
|
158
160
|
};
|
|
159
161
|
}
|
|
160
162
|
|
|
161
|
-
|
|
163
|
+
function snapshotEdit(uri: string, snapshots: ReadonlyMap<string, DocumentSnapshot>): PlannedDocumentEdit {
|
|
164
|
+
const snapshot = snapshots.get(uri);
|
|
165
|
+
if (!snapshot) {
|
|
166
|
+
throw new LspError(`Missing workspace snapshot: ${uri}`);
|
|
167
|
+
}
|
|
168
|
+
return { uri, version: snapshot.version, before: snapshot.text, text: snapshot.text };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* A file that is there already is refused, unless the create says to empty it or to leave it as it is. */
|
|
172
|
+
function planCreate(change: CreateFile, snapshots: ReadonlyMap<string, DocumentSnapshot>, planned: Map<string, PlannedDocumentEdit>): void {
|
|
173
|
+
const existing = planned.get(change.uri) ?? (snapshots.has(change.uri) ? snapshotEdit(change.uri, snapshots) : null);
|
|
174
|
+
if (existing === null) {
|
|
175
|
+
planned.set(change.uri, { uri: change.uri, version: null, before: '', text: '', created: true });
|
|
176
|
+
} else if (change.options?.overwrite) {
|
|
177
|
+
planned.set(change.uri, { ...existing, text: '' });
|
|
178
|
+
} else if (!change.options?.ignoreIfExists) {
|
|
179
|
+
throw new LspError(`${change.uri} already exists`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/*
|
|
184
|
+
* Plans text edits and created files in memory, in the order the edit gives them. `snapshots` holds the
|
|
185
|
+
* files that are there; a file the edit creates is absent from it. A rename or delete needs the host's own handling and is refused.
|
|
186
|
+
*/
|
|
162
187
|
export function planWorkspaceEdit(edit: WorkspaceEdit, snapshots: ReadonlyMap<string, DocumentSnapshot>): PlannedDocumentEdit[] {
|
|
163
188
|
const planned = new Map<string, PlannedDocumentEdit>();
|
|
164
189
|
const changes = edit.documentChanges ?? Object.entries(edit.changes ?? {}).map(([uri, edits]) => ({ textDocument: { uri, version: null }, edits }));
|
|
165
190
|
for (const change of changes) {
|
|
166
191
|
if ('kind' in change) {
|
|
167
|
-
|
|
192
|
+
if (change.kind !== 'create') {
|
|
193
|
+
throw new LspError(`A host file-operation handler is required for ${change.kind}`);
|
|
194
|
+
}
|
|
195
|
+
planCreate(change, snapshots, planned);
|
|
196
|
+
continue;
|
|
168
197
|
}
|
|
169
198
|
const { uri, version } = change.textDocument;
|
|
170
|
-
const
|
|
171
|
-
if (
|
|
172
|
-
throw new LspError(`Missing workspace snapshot: ${uri}`);
|
|
173
|
-
}
|
|
174
|
-
if (version !== null && snapshot.version !== version) {
|
|
199
|
+
const current = planned.get(uri) ?? snapshotEdit(uri, snapshots);
|
|
200
|
+
if (version !== null && current.version !== version) {
|
|
175
201
|
throw new LspError(`Workspace edit version mismatch: ${uri}`, ErrorCodes.ContentModified);
|
|
176
202
|
}
|
|
177
|
-
|
|
178
|
-
const text = applyTextEdits(before, change.edits);
|
|
179
|
-
planned.set(uri, { uri, version: snapshot.version, before: snapshot.text, text });
|
|
203
|
+
planned.set(uri, { ...current, text: applyTextEdits(current.text, change.edits) });
|
|
180
204
|
}
|
|
181
205
|
return [...planned.values()];
|
|
182
206
|
}
|
package/src/session.ts
CHANGED
|
@@ -480,7 +480,7 @@ function clientCapabilities(options: LspSessionOptions): object {
|
|
|
480
480
|
general: { positionEncodings: ['utf-16'] },
|
|
481
481
|
workspace: {
|
|
482
482
|
applyEdit: !!options.onApplyEdit,
|
|
483
|
-
workspaceEdit: { documentChanges: true, resourceOperations: ['rename'], failureHandling: 'abort' },
|
|
483
|
+
workspaceEdit: { documentChanges: true, resourceOperations: ['create', 'rename'], failureHandling: 'abort' },
|
|
484
484
|
fileOperations: { dynamicRegistration: true, willRename: true, didRename: true },
|
|
485
485
|
configuration: true,
|
|
486
486
|
workspaceFolders: true,
|