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

Adding an overload to TextEditor.edit for insertion of a SnippetString #17628

Merged
merged 13 commits into from
Jan 20, 2017
Merged
36 changes: 35 additions & 1 deletion extensions/vscode-api-tests/src/editor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
'use strict';

import * as assert from 'assert';
import { workspace, window, Position, Range, commands, TextEditor, TextDocument, TextEditorCursorStyle, TextEditorLineNumbersStyle } from 'vscode';
import { workspace, window, Position, Range, commands, TextEditor, TextDocument, TextEditorCursorStyle, TextEditorLineNumbersStyle, SnippetString, Selection } from 'vscode';
import { createRandomFile, deleteFile, cleanUp } from './utils';

suite('editor tests', () => {
Expand All @@ -33,6 +33,40 @@ suite('editor tests', () => {
});
}

test('insert snippet', () => {
const snippetString = new SnippetString()
.appendText('This is a ')
.appendTabstop()
.appendPlaceholder('placeholder')
.appendText(' snippet');

return withRandomFileEditor('', (editor, doc) => {
return editor.edit(snippetString).then(inserted => {
assert.ok(inserted);
assert.equal(doc.getText(), 'This is a placeholder snippet');
assert.ok(doc.isDirty);
});
});
});

test('insert snippet with replacement', () => {
const snippetString = new SnippetString()
.appendText('has been');

return withRandomFileEditor('This will be replaced', (editor, doc) => {
editor.selection = new Selection(
new Position(0, 5),
new Position(0, 12)
);

return editor.edit(snippetString).then(inserted => {
assert.ok(inserted);
assert.equal(doc.getText(), 'This has been replaced');
assert.ok(doc.isDirty);
});
});
});

test('make edit', () => {
return withRandomFileEditor('', (editor, doc) => {
return editor.edit((builder) => {
Expand Down
9 changes: 9 additions & 0 deletions src/vs/vscode.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -936,6 +936,15 @@ declare module 'vscode' {
*/
edit(callback: (editBuilder: TextEditorEdit) => void, options?: { undoStopBefore: boolean; undoStopAfter: boolean; }): Thenable<boolean>;

/**
* Enters snippet mode in the editor with the specified snippet.
*
* @param snippet The snippet to insert in this edit.
* @param options The undo/redo behaviour around this edit. By default, undo stops will be created before and after this edit.
* @return A promise that resolves with a value indicating if the snippet could be inserted.
*/
edit(snippet: SnippetString, options?: { undoStopBefore: boolean; undoStopAfter: boolean; }): Thenable<boolean>;

/**
* Adds a set of decorations to the text editor. If a set of decorations already exists with
* the given [decoration type](#TextEditorDecorationType), they will be replaced.
Expand Down
3 changes: 2 additions & 1 deletion src/vs/workbench/api/node/extHost.protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { IWorkspaceConfigurationValues } from 'vs/workbench/services/configurati
import { IPickOpenEntry, IPickOptions } from 'vs/platform/quickOpen/common/quickOpen';
import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
import { IWorkspaceSymbol } from 'vs/workbench/parts/search/common/search';
import { IApplyEditsOptions, TextEditorRevealType, ITextEditorConfigurationUpdate, IResolvedTextEditorConfiguration, ISelectionChangeEvent } from './mainThreadEditorsTracker';
import { IApplyEditsOptions, IUndoStopOptions, TextEditorRevealType, ITextEditorConfigurationUpdate, IResolvedTextEditorConfiguration, ISelectionChangeEvent } from './mainThreadEditorsTracker';

import { InternalTreeExplorerNodeContent } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel';

Expand Down Expand Up @@ -137,6 +137,7 @@ export abstract class MainThreadEditorsShape {
$tryRevealRange(id: string, range: editorCommon.IRange, revealType: TextEditorRevealType): TPromise<any> { throw ni(); }
$trySetSelections(id: string, selections: editorCommon.ISelection[]): TPromise<any> { throw ni(); }
$tryApplyEdits(id: string, modelVersionId: number, edits: editorCommon.ISingleEditOperation[], opts: IApplyEditsOptions): TPromise<boolean> { throw ni(); }
$tryInsertSnippet(id: string, template: string, opts: IUndoStopOptions): TPromise<any> { throw ni(); }
}

export abstract class MainThreadTreeExplorersShape {
Expand Down
17 changes: 12 additions & 5 deletions src/vs/workbench/api/node/extHostEditors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import Event, { Emitter } from 'vs/base/common/event';
import { TPromise } from 'vs/base/common/winjs.base';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { ExtHostDocuments, ExtHostDocumentData } from 'vs/workbench/api/node/extHostDocuments';
import { Selection, Range, Position, EndOfLine, TextEditorRevealType, TextEditorSelectionChangeKind, TextEditorLineNumbersStyle } from './extHostTypes';
import { Selection, Range, Position, EndOfLine, TextEditorRevealType, TextEditorSelectionChangeKind, TextEditorLineNumbersStyle, SnippetString } from './extHostTypes';
import { ISingleEditOperation, TextEditorCursorStyle } from 'vs/editor/common/editorCommon';
import { IResolvedTextEditorConfiguration, ISelectionChangeEvent, ITextEditorConfigurationUpdate } from 'vs/workbench/api/node/mainThreadEditorsTracker';
import * as TypeConverters from './extHostTypeConverters';
Expand Down Expand Up @@ -595,10 +595,17 @@ class ExtHostTextEditor implements vscode.TextEditor {

// ---- editing

edit(callback: (edit: TextEditorEdit) => void, options: { undoStopBefore: boolean; undoStopAfter: boolean; } = { undoStopBefore: true, undoStopAfter: true }): Thenable<boolean> {
let edit = new TextEditorEdit(this._documentData.document, options);
callback(edit);
return this._applyEdit(edit);
edit(callback: (edit: TextEditorEdit) => void, options: { undoStopBefore: boolean; undoStopAfter: boolean; }): Thenable<boolean>;
edit(snippet: SnippetString, options: { undoStopBefore: boolean; undoStopAfter: boolean; }): Thenable<boolean>;

edit(callbackOrSnippet: ((edit: TextEditorEdit) => void) | SnippetString, options: { undoStopBefore: boolean; undoStopAfter: boolean; } = { undoStopBefore: true, undoStopAfter: true }): Thenable<boolean> {
if (SnippetString.isSnippetString(callbackOrSnippet)) {
return this._proxy.$tryInsertSnippet(this._id, callbackOrSnippet.value, options);
} else {
let edit = new TextEditorEdit(this._documentData.document, options);
callbackOrSnippet(edit);
return this._applyEdit(edit);
}
}

_applyEdit(editBuilder: TextEditorEdit): TPromise<boolean> {
Expand Down
10 changes: 10 additions & 0 deletions src/vs/workbench/api/node/extHostTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,16 @@ export class WorkspaceEdit {

export class SnippetString {

static isSnippetString(thing: any): thing is SnippetString {
if (thing instanceof SnippetString) {
return true;
}
if (!thing) {
return false;
}
return typeof (<SnippetString>thing).value === 'string';
}

private static _escape(value: string): string {
return value.replace(/\$|}|\\/g, '\\$&');
}
Expand Down
9 changes: 8 additions & 1 deletion src/vs/workbench/api/node/mainThreadEditors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
import { Position as EditorPosition } from 'vs/platform/editor/common/editor';
import { IModelService } from 'vs/editor/common/services/modelService';
import { MainThreadEditorsTracker, TextEditorRevealType, MainThreadTextEditor, IApplyEditsOptions, ITextEditorConfigurationUpdate } from 'vs/workbench/api/node/mainThreadEditorsTracker';
import { MainThreadEditorsTracker, TextEditorRevealType, MainThreadTextEditor, IApplyEditsOptions, IUndoStopOptions, ITextEditorConfigurationUpdate } from 'vs/workbench/api/node/mainThreadEditorsTracker';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { equals as arrayEquals } from 'vs/base/common/arrays';
import { equals as objectEquals } from 'vs/base/common/objects';
Expand Down Expand Up @@ -293,6 +293,13 @@ export class MainThreadEditors extends MainThreadEditorsShape {
return TPromise.as(this._textEditorsMap[id].applyEdits(modelVersionId, edits, opts));
}

$tryInsertSnippet(id: string, template: string, opts: IUndoStopOptions): TPromise<boolean> {
if (!this._textEditorsMap[id]) {
return TPromise.wrapError('TextEditor disposed');
}
return TPromise.as(this._textEditorsMap[id].insertSnippet(template, opts));
}

$registerTextEditorDecorationType(key: string, options: IDecorationRenderOptions): void {
this._editorTracker.registerTextEditorDecorationType(key, options);
}
Expand Down
28 changes: 27 additions & 1 deletion src/vs/workbench/api/node/mainThreadEditorsTracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { RunOnceScheduler } from 'vs/base/common/async';
import { IdGenerator } from 'vs/base/common/idGenerator';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { SnippetController } from 'vs/editor/contrib/snippet/common/snippetController';
import { EndOfLine, TextEditorLineNumbersStyle } from 'vs/workbench/api/node/extHostTypes';

export interface ITextEditorConfigurationUpdate {
Expand Down Expand Up @@ -58,9 +59,12 @@ export enum TextEditorRevealType {
InCenterIfOutsideViewport = 2
}

export interface IApplyEditsOptions {
export interface IUndoStopOptions {
undoStopBefore: boolean;
undoStopAfter: boolean;
}

export interface IApplyEditsOptions extends IUndoStopOptions {
setEndOfLine: EndOfLine;
}

Expand Down Expand Up @@ -383,6 +387,28 @@ export class MainThreadTextEditor {
console.warn('applyEdits on invisible editor');
return false;
}

insertSnippet(template: string, opts: IUndoStopOptions) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jrieken Should console.warn('applyEdits on invisible editor'); be added to insertSnippet?

const snippetController = SnippetController.get(this._codeEditor);

if (!this._codeEditor) {
return false;
}

this._codeEditor.focus();

if (opts.undoStopBefore) {
this._codeEditor.pushUndoStop();
}

snippetController.insertSnippet(template, 0, 0);

if (opts.undoStopAfter) {
this._codeEditor.pushUndoStop();
}

return true;
}
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/vs/workbench/test/node/api/extHostEditors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ suite('ExtHostTextEditorOptions', () => {
$tryRevealRange: undefined,
$trySetSelections: undefined,
$tryApplyEdits: undefined,
$tryInsertSnippet: undefined
};
opts = new ExtHostTextEditorOptions(mockProxy, '1', {
tabSize: 4,
Expand Down