add adjustWhitespace-flag to snippet controller, #57093

This commit is contained in:
Johannes Rieken 2018-08-24 10:07:48 +02:00
parent 8d72e849d3
commit 561f8d6b33
3 changed files with 53 additions and 39 deletions

View file

@ -5,22 +5,22 @@
'use strict';
import { RawContextKey, IContextKey, IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { registerEditorContribution, EditorCommand, registerEditorCommand } from 'vs/editor/browser/editorExtensions';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { SnippetSession } from './snippetSession';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { showSimpleSuggestions } from 'vs/editor/contrib/suggest/suggest';
import { ISuggestion } from 'vs/editor/common/modes';
import { Selection } from 'vs/editor/common/core/selection';
import { Range } from 'vs/editor/common/core/range';
import { Choice } from 'vs/editor/contrib/snippet/snippetParser';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { repeat } from 'vs/base/common/strings';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { EditorCommand, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { ISuggestion } from 'vs/editor/common/modes';
import { Choice } from 'vs/editor/contrib/snippet/snippetParser';
import { showSimpleSuggestions } from 'vs/editor/contrib/suggest/suggest';
import { ContextKeyExpr, IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { ILogService } from 'vs/platform/log/common/log';
import { SnippetSession } from './snippetSession';
export class SnippetController2 implements IEditorContribution {
@ -65,13 +65,14 @@ export class SnippetController2 implements IEditorContribution {
insert(
template: string,
overwriteBefore: number = 0, overwriteAfter: number = 0,
undoStopBefore: boolean = true, undoStopAfter: boolean = true
undoStopBefore: boolean = true, undoStopAfter: boolean = true,
adjustWhitespace: boolean = true,
): void {
// this is here to find out more about the yet-not-understood
// error that sometimes happens when we fail to inserted a nested
// snippet
try {
this._doInsert(template, overwriteBefore, overwriteAfter, undoStopBefore, undoStopAfter);
this._doInsert(template, overwriteBefore, overwriteAfter, undoStopBefore, undoStopAfter, adjustWhitespace);
} catch (e) {
this.cancel();
@ -85,7 +86,8 @@ export class SnippetController2 implements IEditorContribution {
private _doInsert(
template: string,
overwriteBefore: number = 0, overwriteAfter: number = 0,
undoStopBefore: boolean = true, undoStopAfter: boolean = true
undoStopBefore: boolean = true, undoStopAfter: boolean = true,
adjustWhitespace: boolean = true,
): void {
// don't listen while inserting the snippet
@ -98,10 +100,10 @@ export class SnippetController2 implements IEditorContribution {
if (!this._session) {
this._modelVersionId = this._editor.getModel().getAlternativeVersionId();
this._session = new SnippetSession(this._editor, template, overwriteBefore, overwriteAfter);
this._session = new SnippetSession(this._editor, template, overwriteBefore, overwriteAfter, adjustWhitespace);
this._session.insert();
} else {
this._session.merge(template, overwriteBefore, overwriteAfter);
this._session.merge(template, overwriteBefore, overwriteAfter, adjustWhitespace);
}
if (undoStopAfter) {

View file

@ -5,21 +5,21 @@
'use strict';
import 'vs/css!./snippetSession';
import { getLeadingWhitespace } from 'vs/base/common/strings';
import { ITextModel, TrackedRangeStickiness, IIdentifiedSingleEditOperation } from 'vs/editor/common/model';
import { EditOperation } from 'vs/editor/common/core/editOperation';
import { TextmateSnippet, Placeholder, Choice, Text, SnippetParser } from './snippetParser';
import { Selection } from 'vs/editor/common/core/selection';
import { Range } from 'vs/editor/common/core/range';
import { IPosition } from 'vs/editor/common/core/position';
import { groupBy } from 'vs/base/common/arrays';
import { dispose } from 'vs/base/common/lifecycle';
import { SelectionBasedVariableResolver, CompositeSnippetVariableResolver, ModelBasedVariableResolver, ClipboardBasedVariableResolver, TimeBasedVariableResolver } from './snippetVariables';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
import { getLeadingWhitespace } from 'vs/base/common/strings';
import 'vs/css!./snippetSession';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditOperation } from 'vs/editor/common/core/editOperation';
import { IPosition } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { IIdentifiedSingleEditOperation, ITextModel, TrackedRangeStickiness } from 'vs/editor/common/model';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { optional } from 'vs/platform/instantiation/common/instantiation';
import { Choice, Placeholder, SnippetParser, Text, TextmateSnippet } from './snippetParser';
import { ClipboardBasedVariableResolver, CompositeSnippetVariableResolver, ModelBasedVariableResolver, SelectionBasedVariableResolver, TimeBasedVariableResolver } from './snippetVariables';
export class OneSnippet {
@ -271,7 +271,7 @@ export class OneSnippet {
export class SnippetSession {
static adjustWhitespace2(model: ITextModel, position: IPosition, snippet: TextmateSnippet): void {
static adjustWhitespace(model: ITextModel, position: IPosition, snippet: TextmateSnippet): void {
const line = model.getLineContent(position.lineNumber);
const lineLeadingWhitespace = getLeadingWhitespace(line, 0, position.column - 1);
@ -317,7 +317,7 @@ export class SnippetSession {
return selection;
}
static createEditsAndSnippets(editor: ICodeEditor, template: string, overwriteBefore: number, overwriteAfter: number, enforceFinalTabstop: boolean): { edits: IIdentifiedSingleEditOperation[], snippets: OneSnippet[] } {
static createEditsAndSnippets(editor: ICodeEditor, template: string, overwriteBefore: number, overwriteAfter: number, enforceFinalTabstop: boolean, adjustWhitespace: boolean): { edits: IIdentifiedSingleEditOperation[], snippets: OneSnippet[] } {
const model = editor.getModel();
const edits: IIdentifiedSingleEditOperation[] = [];
@ -365,7 +365,9 @@ export class SnippetSession {
// adjust the template string to match the indentation and
// whitespace rules of this insert location (can be different for each cursor)
const start = snippetSelection.getStartPosition();
SnippetSession.adjustWhitespace2(model, start, snippet);
if (adjustWhitespace) {
SnippetSession.adjustWhitespace(model, start, snippet);
}
snippet.resolveVariables(new CompositeSnippetVariableResolver([
modelBasedVariableResolver,
@ -392,13 +394,15 @@ export class SnippetSession {
private readonly _templateMerges: [number, number, string][] = [];
private readonly _overwriteBefore: number;
private readonly _overwriteAfter: number;
private readonly _adjustWhitespace: boolean;
private _snippets: OneSnippet[] = [];
constructor(editor: ICodeEditor, template: string, overwriteBefore: number = 0, overwriteAfter: number = 0) {
constructor(editor: ICodeEditor, template: string, overwriteBefore: number = 0, overwriteAfter: number = 0, adjustWhitespace: boolean = true) {
this._editor = editor;
this._template = template;
this._overwriteBefore = overwriteBefore;
this._overwriteAfter = overwriteAfter;
this._adjustWhitespace = adjustWhitespace;
}
dispose(): void {
@ -414,7 +418,7 @@ export class SnippetSession {
const model = this._editor.getModel();
// make insert edit and start with first selections
const { edits, snippets } = SnippetSession.createEditsAndSnippets(this._editor, this._template, this._overwriteBefore, this._overwriteAfter, false);
const { edits, snippets } = SnippetSession.createEditsAndSnippets(this._editor, this._template, this._overwriteBefore, this._overwriteAfter, false, this._adjustWhitespace);
this._snippets = snippets;
const selections = model.pushEditOperations(this._editor.getSelections(), edits, undoEdits => {
@ -428,9 +432,9 @@ export class SnippetSession {
this._editor.revealRange(selections[0]);
}
merge(template: string, overwriteBefore: number = 0, overwriteAfter: number = 0): void {
merge(template: string, overwriteBefore: number = 0, overwriteAfter: number = 0, adjustWhitespace: boolean = true): void {
this._templateMerges.push([this._snippets[0]._nestingLevel, this._snippets[0]._placeholderGroupsIdx, template]);
const { edits, snippets } = SnippetSession.createEditsAndSnippets(this._editor, template, overwriteBefore, overwriteAfter, true);
const { edits, snippets } = SnippetSession.createEditsAndSnippets(this._editor, template, overwriteBefore, overwriteAfter, true, adjustWhitespace);
this._editor.setSelections(this._editor.getModel().pushEditOperations(this._editor.getSelections(), edits, undoEdits => {

View file

@ -5,14 +5,14 @@
'use strict';
import * as assert from 'assert';
import { Selection } from 'vs/editor/common/core/selection';
import { Range } from 'vs/editor/common/core/range';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IPosition, Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { TextModel } from 'vs/editor/common/model/textModel';
import { SnippetParser } from 'vs/editor/contrib/snippet/snippetParser';
import { SnippetSession } from 'vs/editor/contrib/snippet/snippetSession';
import { createTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
import { TextModel } from 'vs/editor/common/model/textModel';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { SnippetParser } from 'vs/editor/contrib/snippet/snippetParser';
suite('SnippetSession', function () {
@ -43,7 +43,7 @@ suite('SnippetSession', function () {
function assertNormalized(position: IPosition, input: string, expected: string): void {
const snippet = new SnippetParser().parse(input);
SnippetSession.adjustWhitespace2(model, position, snippet);
SnippetSession.adjustWhitespace(model, position, snippet);
assert.equal(snippet.toTextmateString(), expected);
}
@ -125,6 +125,14 @@ suite('SnippetSession', function () {
assertSelections(editor, new Selection(3, 1, 3, 1), new Selection(6, 5, 6, 5));
});
test('snippets, newline NO whitespace adjust', () => {
editor.setSelection(new Selection(2, 5, 2, 5));
const session = new SnippetSession(editor, 'abc\n foo\n bar\n$0', 0, 0, false);
session.insert();
assert.equal(editor.getModel().getValue(), 'function foo() {\n abc\n foo\n bar\nconsole.log(a);\n}');
});
test('snippets, selections -> next/prev', () => {
const session = new SnippetSession(editor, 'f$1oo${2:bar}foo$0');