mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 09:08:48 +01:00
Insert snippet API changes.
This commit is contained in:
@@ -6,7 +6,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import { workspace, window, Position, Range, commands, TextEditor, TextDocument, TextEditorCursorStyle, TextEditorLineNumbersStyle, SnippetString } from 'vscode';
|
import { workspace, window, Position, Range, commands, TextEditor, TextDocument, TextEditorCursorStyle, TextEditorLineNumbersStyle, SnippetString, Selection } from 'vscode';
|
||||||
import { createRandomFile, deleteFile, cleanUp } from './utils';
|
import { createRandomFile, deleteFile, cleanUp } from './utils';
|
||||||
|
|
||||||
suite('editor tests', () => {
|
suite('editor tests', () => {
|
||||||
@@ -41,7 +41,7 @@ suite('editor tests', () => {
|
|||||||
.appendText(' snippet');
|
.appendText(' snippet');
|
||||||
|
|
||||||
return withRandomFileEditor('', (editor, doc) => {
|
return withRandomFileEditor('', (editor, doc) => {
|
||||||
return editor.insertSnippet(snippetString.value, new Position(0, 0)).then(inserted => {
|
return editor.edit(snippetString).then(inserted => {
|
||||||
assert.ok(inserted);
|
assert.ok(inserted);
|
||||||
assert.equal(doc.getText(), 'This is a placeholder snippet');
|
assert.equal(doc.getText(), 'This is a placeholder snippet');
|
||||||
assert.ok(doc.isDirty);
|
assert.ok(doc.isDirty);
|
||||||
@@ -54,7 +54,12 @@ suite('editor tests', () => {
|
|||||||
.appendText('has been');
|
.appendText('has been');
|
||||||
|
|
||||||
return withRandomFileEditor('This will be replaced', (editor, doc) => {
|
return withRandomFileEditor('This will be replaced', (editor, doc) => {
|
||||||
return editor.insertSnippet(snippetString.value, new Range(0, 5, 0, 12)).then(inserted => {
|
editor.selection = new Selection(
|
||||||
|
new Position(0, 4),
|
||||||
|
new Position(0, 12)
|
||||||
|
);
|
||||||
|
|
||||||
|
return editor.edit(snippetString).then(inserted => {
|
||||||
assert.ok(inserted);
|
assert.ok(inserted);
|
||||||
assert.equal(doc.getText(), 'This has been replaced');
|
assert.equal(doc.getText(), 'This has been replaced');
|
||||||
assert.ok(doc.isDirty);
|
assert.ok(doc.isDirty);
|
||||||
|
|||||||
@@ -476,11 +476,6 @@ export class SnippetController {
|
|||||||
this.run(snippet, overwriteBefore, overwriteAfter);
|
this.run(snippet, overwriteBefore, overwriteAfter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public insertSnippetWithReplaceRange(template: string, replaceRange: Range): void {
|
|
||||||
const snippet = CodeSnippet.fromTextmate(template, this._variableResolver);
|
|
||||||
this.runWithReplaceRange(snippet, replaceRange);
|
|
||||||
}
|
|
||||||
|
|
||||||
public run(snippet: CodeSnippet, overwriteBefore: number, overwriteAfter: number, stripPrefix?: boolean): void {
|
public run(snippet: CodeSnippet, overwriteBefore: number, overwriteAfter: number, stripPrefix?: boolean): void {
|
||||||
this._runAndRestoreController(() => {
|
this._runAndRestoreController(() => {
|
||||||
if (snippet.isInsertOnly || snippet.isSingleTabstopOnly) {
|
if (snippet.isInsertOnly || snippet.isSingleTabstopOnly) {
|
||||||
|
|||||||
Vendored
+5
-7
@@ -937,15 +937,13 @@ declare module 'vscode' {
|
|||||||
edit(callback: (editBuilder: TextEditorEdit) => void, options?: { undoStopBefore: boolean; undoStopAfter: boolean; }): Thenable<boolean>;
|
edit(callback: (editBuilder: TextEditorEdit) => void, options?: { undoStopBefore: boolean; undoStopAfter: boolean; }): Thenable<boolean>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts the given snippet template and enters snippet mode.
|
* Enters snippet mode in the editor with the specified snippet.
|
||||||
*
|
*
|
||||||
* If the editor is already in snippet mode, insertion fails and the returned promise resolves to false.
|
* @param snippet The snippet to insert
|
||||||
*
|
* @param options The undo/redo behaviour around this edit. By default, undo stops will be created before and after this edit.
|
||||||
* @param template The snippet template to insert
|
* @return A promise that resolves with a value indicating if the editor entered snippet mode.
|
||||||
* @param posOrRange The position or replacement range representing the location of the insertion.
|
|
||||||
* @return A promise that resolves with a value indicating if the snippet could be inserted.
|
|
||||||
*/
|
*/
|
||||||
insertSnippet(template: string, posOrRange: Position | Range): Thenable<boolean>;
|
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
|
* Adds a set of decorations to the text editor. If a set of decorations already exists with
|
||||||
|
|||||||
Vendored
+5
-7
@@ -110,15 +110,13 @@ declare module 'vscode' {
|
|||||||
|
|
||||||
export interface TextEditor {
|
export interface TextEditor {
|
||||||
/**
|
/**
|
||||||
* Inserts the given snippet template and enters snippet mode.
|
* Enters snippet mode in the editor with the specified snippet.
|
||||||
*
|
*
|
||||||
* If the editor is already in snippet mode, insertion fails and the returned promise resolves to false.
|
* @param snippet The snippet to insert
|
||||||
*
|
* @param options The undo/redo behaviour around this edit. By default, undo stops will be created before and after this edit.
|
||||||
* @param template The snippet template to insert
|
* @return A promise that resolves with a value indicating if the editor entered snippet mode.
|
||||||
* @param posOrRange The position or replacement range representing the location of the insertion.
|
|
||||||
* @return A promise that resolves with a value indicating if the snippet could be inserted.
|
|
||||||
*/
|
*/
|
||||||
insertSnippet(template: string, posOrRange: Position | Range): Thenable<boolean>;
|
edit(snippet: SnippetString, options?: { undoStopBefore: boolean; undoStopAfter: boolean; }): Thenable<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SCMResourceThemableDecorations {
|
export interface SCMResourceThemableDecorations {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import { IWorkspaceConfigurationValues } from 'vs/workbench/services/configurati
|
|||||||
import { IPickOpenEntry, IPickOptions } from 'vs/platform/quickOpen/common/quickOpen';
|
import { IPickOpenEntry, IPickOptions } from 'vs/platform/quickOpen/common/quickOpen';
|
||||||
import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
|
import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
import { IWorkspaceSymbol } from 'vs/workbench/parts/search/common/search';
|
import { IWorkspaceSymbol } from 'vs/workbench/parts/search/common/search';
|
||||||
import { IApplyEditsOptions, TextEditorRevealType, ITextEditorConfigurationUpdate, IResolvedTextEditorConfiguration, ISelectionChangeEvent } from './mainThreadEditorsTracker';
|
import { IApplyEditsOptions, IInsertSnippetOptions, TextEditorRevealType, ITextEditorConfigurationUpdate, IResolvedTextEditorConfiguration, ISelectionChangeEvent } from './mainThreadEditorsTracker';
|
||||||
|
|
||||||
import { InternalTreeExplorerNodeContent } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel';
|
import { InternalTreeExplorerNodeContent } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel';
|
||||||
|
|
||||||
@@ -137,7 +137,7 @@ export abstract class MainThreadEditorsShape {
|
|||||||
$tryRevealRange(id: string, range: editorCommon.IRange, revealType: TextEditorRevealType): TPromise<any> { throw ni(); }
|
$tryRevealRange(id: string, range: editorCommon.IRange, revealType: TextEditorRevealType): TPromise<any> { throw ni(); }
|
||||||
$trySetSelections(id: string, selections: editorCommon.ISelection[]): 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(); }
|
$tryApplyEdits(id: string, modelVersionId: number, edits: editorCommon.ISingleEditOperation[], opts: IApplyEditsOptions): TPromise<boolean> { throw ni(); }
|
||||||
$tryInsertSnippet(id: string, template: string, posOrRange: editorCommon.IPosition | editorCommon.IRange): TPromise<boolean> { throw ni(); }
|
$tryInsertSnippet(id: string, template: string, opts: IInsertSnippetOptions): TPromise<boolean> { throw ni(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class MainThreadTreeExplorersShape {
|
export abstract class MainThreadTreeExplorersShape {
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import Event, { Emitter } from 'vs/base/common/event';
|
|||||||
import { TPromise } from 'vs/base/common/winjs.base';
|
import { TPromise } from 'vs/base/common/winjs.base';
|
||||||
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
|
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
|
||||||
import { ExtHostDocuments, ExtHostDocumentData } from 'vs/workbench/api/node/extHostDocuments';
|
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, IPosition, IRange } from 'vs/editor/common/editorCommon';
|
import { ISingleEditOperation, TextEditorCursorStyle } from 'vs/editor/common/editorCommon';
|
||||||
import { IResolvedTextEditorConfiguration, ISelectionChangeEvent, ITextEditorConfigurationUpdate } from 'vs/workbench/api/node/mainThreadEditorsTracker';
|
import { IResolvedTextEditorConfiguration, ISelectionChangeEvent, ITextEditorConfigurationUpdate } from 'vs/workbench/api/node/mainThreadEditorsTracker';
|
||||||
import * as TypeConverters from './extHostTypeConverters';
|
import * as TypeConverters from './extHostTypeConverters';
|
||||||
import { MainContext, MainThreadEditorsShape, ExtHostEditorsShape, ITextEditorAddData, ITextEditorPositionData } from './extHost.protocol';
|
import { MainContext, MainThreadEditorsShape, ExtHostEditorsShape, ITextEditorAddData, ITextEditorPositionData } from './extHost.protocol';
|
||||||
@@ -595,10 +595,17 @@ class ExtHostTextEditor implements vscode.TextEditor {
|
|||||||
|
|
||||||
// ---- editing
|
// ---- editing
|
||||||
|
|
||||||
edit(callback: (edit: TextEditorEdit) => void, options: { undoStopBefore: boolean; undoStopAfter: boolean; } = { undoStopBefore: true, undoStopAfter: true }): Thenable<boolean> {
|
edit(callback: (edit: TextEditorEdit) => void, options: { undoStopBefore: boolean; undoStopAfter: boolean; }): Thenable<boolean>;
|
||||||
let edit = new TextEditorEdit(this._documentData.document, options);
|
edit(snippet: SnippetString, options: { undoStopBefore: boolean; undoStopAfter: boolean; }): Thenable<boolean>;
|
||||||
callback(edit);
|
|
||||||
return this._applyEdit(edit);
|
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> {
|
_applyEdit(editBuilder: TextEditorEdit): TPromise<boolean> {
|
||||||
@@ -620,22 +627,6 @@ class ExtHostTextEditor implements vscode.TextEditor {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
insertSnippet(template: string, posOrRange: Position | Range) {
|
|
||||||
let convertedPosOrRange: IPosition | IRange;
|
|
||||||
|
|
||||||
if (Position.isPosition(posOrRange)) {
|
|
||||||
convertedPosOrRange = TypeConverters.fromPosition(posOrRange);
|
|
||||||
}
|
|
||||||
else if (Range.isRange(posOrRange)) {
|
|
||||||
convertedPosOrRange = TypeConverters.fromRange(posOrRange);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return TPromise.wrapError(new Error('Unrecognized value for posOrRange'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return this._proxy.$tryInsertSnippet(this._id, template, convertedPosOrRange);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- util
|
// ---- util
|
||||||
|
|
||||||
private _runOnProxy(callback: () => TPromise<any>, silent: boolean): TPromise<ExtHostTextEditor> {
|
private _runOnProxy(callback: () => TPromise<any>, silent: boolean): TPromise<ExtHostTextEditor> {
|
||||||
|
|||||||
@@ -519,6 +519,16 @@ export class WorkspaceEdit {
|
|||||||
|
|
||||||
export class SnippetString {
|
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 {
|
private static _escape(value: string): string {
|
||||||
return value.replace(/\$|}|\\/g, '\\$&');
|
return value.replace(/\$|}|\\/g, '\\$&');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ import URI from 'vs/base/common/uri';
|
|||||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||||
import { TPromise } from 'vs/base/common/winjs.base';
|
import { TPromise } from 'vs/base/common/winjs.base';
|
||||||
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
|
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
|
||||||
import { ISingleEditOperation, ISelection, IPosition, IRange, IEditor, EditorType, ICommonCodeEditor, ICommonDiffEditor, IDecorationRenderOptions, IDecorationOptions } from 'vs/editor/common/editorCommon';
|
import { ISingleEditOperation, ISelection, IRange, IEditor, EditorType, ICommonCodeEditor, ICommonDiffEditor, IDecorationRenderOptions, IDecorationOptions } from 'vs/editor/common/editorCommon';
|
||||||
import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService';
|
import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService';
|
||||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
|
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
|
||||||
import { Position as EditorPosition } from 'vs/platform/editor/common/editor';
|
import { Position as EditorPosition } from 'vs/platform/editor/common/editor';
|
||||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
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, IInsertSnippetOptions, ITextEditorConfigurationUpdate } from 'vs/workbench/api/node/mainThreadEditorsTracker';
|
||||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
import { equals as arrayEquals } from 'vs/base/common/arrays';
|
import { equals as arrayEquals } from 'vs/base/common/arrays';
|
||||||
import { equals as objectEquals } from 'vs/base/common/objects';
|
import { equals as objectEquals } from 'vs/base/common/objects';
|
||||||
@@ -293,11 +293,11 @@ export class MainThreadEditors extends MainThreadEditorsShape {
|
|||||||
return TPromise.as(this._textEditorsMap[id].applyEdits(modelVersionId, edits, opts));
|
return TPromise.as(this._textEditorsMap[id].applyEdits(modelVersionId, edits, opts));
|
||||||
}
|
}
|
||||||
|
|
||||||
$tryInsertSnippet(id: string, template: string, posOrRange: IPosition | IRange): TPromise<boolean> {
|
$tryInsertSnippet(id: string, template: string, opts: IInsertSnippetOptions): TPromise<boolean> {
|
||||||
if (!this._textEditorsMap[id]) {
|
if (!this._textEditorsMap[id]) {
|
||||||
return TPromise.wrapError('TextEditor disposed');
|
return TPromise.wrapError('TextEditor disposed');
|
||||||
}
|
}
|
||||||
return TPromise.as(this._textEditorsMap[id].insertSnippet(template, posOrRange));
|
return TPromise.as(this._textEditorsMap[id].insertSnippet(template, opts));
|
||||||
}
|
}
|
||||||
|
|
||||||
$registerTextEditorDecorationType(key: string, options: IDecorationRenderOptions): void {
|
$registerTextEditorDecorationType(key: string, options: IDecorationRenderOptions): void {
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import { IModelService } from 'vs/editor/common/services/modelService';
|
|||||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||||
import { IdGenerator } from 'vs/base/common/idGenerator';
|
import { IdGenerator } from 'vs/base/common/idGenerator';
|
||||||
import { Position } from 'vs/editor/common/core/position';
|
|
||||||
import { Range } from 'vs/editor/common/core/range';
|
import { Range } from 'vs/editor/common/core/range';
|
||||||
import { Selection } from 'vs/editor/common/core/selection';
|
import { Selection } from 'vs/editor/common/core/selection';
|
||||||
import { SnippetController } from 'vs/editor/contrib/snippet/common/snippetController';
|
import { SnippetController } from 'vs/editor/contrib/snippet/common/snippetController';
|
||||||
@@ -60,12 +59,19 @@ export enum TextEditorRevealType {
|
|||||||
InCenterIfOutsideViewport = 2
|
InCenterIfOutsideViewport = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IApplyEditsOptions {
|
export interface IUndoStopOptions {
|
||||||
undoStopBefore: boolean;
|
undoStopBefore: boolean;
|
||||||
undoStopAfter: boolean;
|
undoStopAfter: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IApplyEditsOptions extends IUndoStopOptions {
|
||||||
setEndOfLine: EndOfLine;
|
setEndOfLine: EndOfLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IInsertSnippetOptions extends IUndoStopOptions {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Text Editor that is permanently bound to the same model.
|
* Text Editor that is permanently bound to the same model.
|
||||||
* It can be bound or not to a CodeEditor.
|
* It can be bound or not to a CodeEditor.
|
||||||
@@ -386,24 +392,22 @@ export class MainThreadTextEditor {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
insertSnippet(template: string, posOrRange: EditorCommon.IPosition | EditorCommon.IRange) {
|
insertSnippet(template: string, opts: IInsertSnippetOptions) {
|
||||||
const snippetController = SnippetController.get(this._codeEditor);
|
const snippetController = SnippetController.get(this._codeEditor);
|
||||||
if (snippetController.inSnippetMode) {
|
if (snippetController.inSnippetMode) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const range = Range.isIRange(posOrRange) ? Range.lift(posOrRange) : null;
|
|
||||||
const position = Position.isIPosition(posOrRange) ? Position.lift(posOrRange) : range.getStartPosition();
|
|
||||||
|
|
||||||
this._codeEditor.setPosition(position);
|
|
||||||
this._codeEditor.revealLine(position.lineNumber);
|
|
||||||
this._codeEditor.focus();
|
this._codeEditor.focus();
|
||||||
|
|
||||||
if (range) {
|
if (opts.undoStopBefore) {
|
||||||
snippetController.insertSnippetWithReplaceRange(template, range);
|
this._codeEditor.pushUndoStop();
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
snippetController.insertSnippet(template, 0, 0);
|
snippetController.insertSnippet(template, 0, 0);
|
||||||
|
|
||||||
|
if (opts.undoStopAfter) {
|
||||||
|
this._codeEditor.pushUndoStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
Reference in New Issue
Block a user