Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support VSCode API: SnippetTextEdit #4154

Merged
merged 3 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions packages/extension/src/common/vscode/converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,16 @@ export namespace TextEdit {
}
}

export namespace SnippetTextEdit {
export function from(edit: vscode.SnippetTextEdit): model.TextEdit & { insertAsSnippet?: boolean } {
return {
text: edit.snippet.value,
range: fromRange(edit.range),
insertAsSnippet: true,
};
}
}

export function fromTextEdit(edit: vscode.TextEdit): model.SingleEditOperation {
return {
text: edit.newText,
Expand Down Expand Up @@ -841,6 +851,16 @@ export namespace WorkspaceEdit {
versionId: doc?.version,
metadata: entry.metadata,
} as model.ResourceTextEditDto);
} else if (entry._type === types.WorkspaceEditType.Snippet) {
// snippet edits
const doc = documents?.getDocument(entry.uri);
result.edits.push({
_type: types.WorkspaceEditType.Text,
resource: entry.uri,
textEdit: SnippetTextEdit.from(entry.edit),
versionId: doc?.version,
metadata: entry.metadata,
} as model.ResourceTextEditDto);
}
}
return result;
Expand Down
77 changes: 69 additions & 8 deletions packages/extension/src/common/vscode/ext-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
arrays,
es5ClassCompat,
isNumber,
isObject,
isString,
isStringArray,
isTextStreamMime,
Expand Down Expand Up @@ -1285,12 +1286,48 @@ export interface FileTextEdit {
metadata?: vscode.WorkspaceEditEntryMetadata;
}

type WorkspaceEditEntry = FileOperation | FileTextEdit;
export interface FileSnippetTextEdit {
readonly _type: WorkspaceEditType.Snippet;
readonly uri: Uri;
readonly range: Range;
readonly edit: SnippetTextEdit;
readonly metadata?: vscode.WorkspaceEditEntryMetadata;
}

type WorkspaceEditEntry = FileOperation | FileTextEdit | FileSnippetTextEdit;

export const enum WorkspaceEditType {
export enum WorkspaceEditType {
File = 1,
Text = 2,
// Cell = 3, // not supported yet
Snippet = 6,
}

export class SnippetTextEdit implements vscode.SnippetTextEdit {
range: Range;
snippet: SnippetString;

static isSnippetTextEdit(thing: unknown): thing is SnippetTextEdit {
return (
thing instanceof SnippetTextEdit ||
(isObject(thing) &&
Range.isRange((thing as SnippetTextEdit).range) &&
SnippetString.isSnippetString((thing as SnippetTextEdit).snippet))
);
}

static replace(range: Range, snippet: SnippetString): SnippetTextEdit {
return new SnippetTextEdit(range, snippet);
}

static insert(position: Position, snippet: SnippetString): SnippetTextEdit {
return SnippetTextEdit.replace(new Range(position, position), snippet);
}

constructor(range: Range, snippet: SnippetString) {
this.range = range;
this.snippet = snippet;
}
}

@es5ClassCompat
Expand Down Expand Up @@ -1343,18 +1380,42 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit {
return false;
}

set(uri: Uri, edits: TextEdit[]): void {
set(uri: Uri, edits: ReadonlyArray<TextEdit | SnippetTextEdit>): void;
// eslint-disable-next-line @typescript-eslint/unified-signatures
set(uri: Uri, edits: ReadonlyArray<[TextEdit | SnippetTextEdit, vscode.WorkspaceEditEntryMetadata]>): void;
set(
uri: Uri,
edits: ReadonlyArray<TextEdit | SnippetTextEdit | [TextEdit | SnippetTextEdit, vscode.WorkspaceEditEntryMetadata]>,
): void {
if (!edits) {
// remove all text edits for `uri`
this._edits = this._edits.filter(
(element) =>
!(element && element._type === WorkspaceEditType.Text && element.uri.toString() === uri.toString()),
!(
element &&
(element._type === WorkspaceEditType.Text || element._type === WorkspaceEditType.Snippet) &&
element.uri.toString() === uri.toString()
),
);
} else {
// append edit to the end
for (const edit of edits) {
if (edit) {
this._edits.push({ _type: WorkspaceEditType.Text, uri, edit });
for (const editOrTuple of edits) {
if (editOrTuple) {
let edit: TextEdit | SnippetTextEdit;
let metadata: vscode.WorkspaceEditEntryMetadata | undefined;

if (Array.isArray(editOrTuple)) {
edit = editOrTuple[0];
metadata = editOrTuple[1];
} else {
edit = editOrTuple;
}

if (SnippetTextEdit.isSnippetTextEdit(edit)) {
this._edits.push({ _type: WorkspaceEditType.Snippet, uri, range: edit.range, edit, metadata });
} else {
this._edits.push({ _type: WorkspaceEditType.Text, uri, edit });
}
bk1012 marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Expand Down Expand Up @@ -1385,7 +1446,7 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit {
return [...textEdits.values()];
}

allEntries(): ReadonlyArray<FileOperation | FileTextEdit> {
allEntries(): ReadonlyArray<WorkspaceEditEntry> {
return this._edits;
}

Expand Down
20 changes: 14 additions & 6 deletions packages/types/vscode/typings/vscode.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1538,12 +1538,20 @@ declare module 'vscode' {
has(uri: Uri): boolean;

/**
* Set (and replace) text edits for a resource.
*
* @param uri A resource identifier.
* @param edits An array of text edits.
*/
set(uri: Uri, edits: TextEdit[]): void;
* Set (and replace) text edits or snippet edits for a resource.
*
* @param uri A resource identifier.
* @param edits An array of edits.
*/
set(uri: Uri, edits: ReadonlyArray<TextEdit | SnippetTextEdit>): void;
bk1012 marked this conversation as resolved.
Show resolved Hide resolved

/**
* Set (and replace) text edits or snippet edits with metadata for a resource.
*
* @param uri A resource identifier.
* @param edits An array of edits.
*/
set(uri: Uri, edits: ReadonlyArray<[TextEdit | SnippetTextEdit, WorkspaceEditEntryMetadata | undefined]>): void;

/**
* Get the text edits for a resource.
Expand Down
48 changes: 48 additions & 0 deletions packages/types/vscode/typings/vscode.editor.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,54 @@ declare module 'vscode' {
constructor(range: Range, newText: string);
}

/**
* A snippet edit represents an interactive edit that is performed by
* the editor.
*
* *Note* that a snippet edit can always be performed as a normal {@link TextEdit text edit}.
* This will happen when no matching editor is open or when a {@link WorkspaceEdit workspace edit}
* contains snippet edits for multiple files. In that case only those that match the active editor
* will be performed as snippet edits and the others as normal text edits.
*/
export class SnippetTextEdit {

/**
* Utility to create a replace snippet edit.
*
* @param range A range.
* @param snippet A snippet string.
* @returns A new snippet edit object.
*/
static replace(range: Range, snippet: SnippetString): SnippetTextEdit;

/**
* Utility to create an insert snippet edit.
*
* @param position A position, will become an empty range.
* @param snippet A snippet string.
* @returns A new snippet edit object.
*/
static insert(position: Position, snippet: SnippetString): SnippetTextEdit;

/**
* The range this edit applies to.
*/
range: Range;

/**
* The {@link SnippetString snippet} this edit will perform.
*/
snippet: SnippetString;

/**
* Create a new snippet edit.
*
* @param range A range.
* @param snippet A snippet string.
*/
constructor(range: Range, snippet: SnippetString);
}

/**
* Provider for text based custom editors.
*
Expand Down
Loading