提交 403d7841 编写于 作者: J Johannes Rieken

be a little stricter and leave snippet mode when cursor move out of placeholders

上级 36f3b136
......@@ -57,11 +57,12 @@ export class SnippetController2 {
this.cancel();
}
this._snippet = new SnippetSession(this._editor, template, overwriteBefore, overwriteAfter);
this._snippet.insert();
this._snippetListener = [
this._editor.onDidChangeModel(() => this.cancel()),
this._editor.onDidChangeCursorSelection(() => this._updateState())
];
this._snippet.insert();
this._updateState();
}
private _updateState(): void {
......@@ -76,7 +77,7 @@ export class SnippetController2 {
return;
}
if (this._snippet.isAtFinalPlaceholder || !this._snippet.validateSelections()) {
if (this._snippet.isAtFinalPlaceholder || !this._snippet.isSelectionWithPlaceholders()) {
return this.cancel();
}
......
......@@ -21,7 +21,6 @@ class OneSnippet {
private readonly _snippet: TextmateSnippet;
private readonly _offset: number;
private _snippetDecoration: string;
private _placeholderDecorations: Map<Placeholder, string>;
private _placeholderGroups: Placeholder[][];
private _placeholderGroupsIdx: number;
......@@ -31,7 +30,6 @@ class OneSnippet {
inactive: <IModelDecorationOptions>{ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'snippet-placeholder' },
activeFinal: <IModelDecorationOptions>{ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'finish-snippet-placeholder' },
inactiveFinal: <IModelDecorationOptions>{ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'finish-snippet-placeholder' },
snippet: <IModelDecorationOptions>{ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges },
};
constructor(editor: ICommonCodeEditor, snippet: TextmateSnippet, offset: number) {
......@@ -60,13 +58,6 @@ class OneSnippet {
this._editor.changeDecorations(accessor => {
// create one decoration for the whole snippets
const range = Range.fromPositions(
model.getPositionAt(this._offset),
model.getPositionAt(this._offset + this._snippet.text.length)
);
this._snippetDecoration = accessor.addDecoration(range, OneSnippet._decor.snippet);
// create a decoration for each placeholder
for (const placeholder of this._snippet.placeholders) {
const placeholderOffset = this._snippet.offset(placeholder);
......@@ -151,8 +142,17 @@ class OneSnippet {
return this._snippet.placeholders.length > 0;
}
get range() {
return this._snippetDecoration !== undefined && this._editor.getModel().getDecorationRange(this._snippetDecoration);
get placeholderRanges() {
const ret: Range[] = [];
this._placeholderDecorations.forEach((id, placeholder) => {
if (!placeholder.isFinalTabstop) {
const range = this._editor.getModel().getDecorationRange(id);
if (range) {
ret.push(range);
}
}
});
return ret;
}
}
......@@ -307,27 +307,38 @@ export class SnippetSession {
return this._snippets[0].hasPlaceholder;
}
validateSelections(): boolean {
isSelectionWithPlaceholders(): boolean {
const selections = this._editor.getSelections();
if (selections.length < this._snippets.length) {
// this means we started snippet mode with N
// selections and have M (N > M) selections.
// So one snippet is without selection -> cancel
return false;
}
for (const selection of selections) {
let found = false;
for (const { range } of this._snippets) {
if (!range) {
// all deleted
return false;
}
const ranges: Range[] = [];
for (const snippet of this._snippets) {
ranges.push(...snippet.placeholderRanges);
}
if (selections.length > ranges.length) {
return false;
}
// sort selections and ranges by their start position
// and then make sure each selection is contained by
// a placeholder range
selections.sort(Range.compareRangesUsingStarts);
ranges.sort(Range.compareRangesUsingStarts);
outer: for (const selection of selections) {
let range: Range;
while (range = ranges.shift()) {
if (range.containsRange(selection)) {
found = true;
break;
continue outer;
}
}
if (!found) {
return false;
}
return false;
}
return true;
......
......@@ -299,28 +299,28 @@ suite('SnippetSession', function () {
assert.equal(model.getValue(), 'foofarboobarfunction foo() {\n foofarboobarconsole.log(a);\n}');
assertSelections(editor, new Selection(1, 1, 1, 4), new Selection(2, 5, 2, 8));
assert.equal(session.validateSelections(), true);
assert.equal(session.isSelectionWithPlaceholders(), true);
editor.setSelections([new Selection(1, 1, 1, 1)]);
assert.equal(session.validateSelections(), false);
assert.equal(session.isSelectionWithPlaceholders(), false);
editor.setSelections([new Selection(1, 6, 1, 6), new Selection(2, 10, 2, 10)]);
assert.equal(session.validateSelections(), true);
assert.equal(session.isSelectionWithPlaceholders(), false); // in snippet, outside placeholder
editor.setSelections([new Selection(1, 6, 1, 6), new Selection(2, 10, 2, 10), new Selection(1, 1, 1, 1)]);
assert.equal(session.validateSelections(), true);
assert.equal(session.isSelectionWithPlaceholders(), false); // in snippet, outside placeholder
editor.setSelections([new Selection(1, 6, 1, 6), new Selection(2, 10, 2, 10), new Selection(2, 20, 2, 21)]);
assert.equal(session.validateSelections(), false);
assert.equal(session.isSelectionWithPlaceholders(), false);
// reset selection to placeholder
session.next();
assert.equal(session.validateSelections(), true);
assert.equal(session.isSelectionWithPlaceholders(), true);
assertSelections(editor, new Selection(1, 10, 1, 13), new Selection(2, 14, 2, 17));
// reset selection to placeholder
session.next();
assert.equal(session.validateSelections(), true);
assert.equal(session.isSelectionWithPlaceholders(), true);
assert.equal(session.isAtFinalPlaceholder, true);
assertSelections(editor, new Selection(1, 13, 1, 13), new Selection(2, 17, 2, 17));
});
......@@ -354,10 +354,10 @@ suite('SnippetSession', function () {
const session = new SnippetSession(editor, 'farboo$0');
session.insert();
assert.equal(session.isAtFinalPlaceholder, true);
assert.equal(session.validateSelections(), true);
assert.equal(session.isSelectionWithPlaceholders(), false);
editor.trigger('test', 'type', { text: 'XXX' });
assert.equal(session.validateSelections(), false);
assert.equal(session.isSelectionWithPlaceholders(), false);
});
test('snippets, typing at beginning', function () {
......@@ -367,12 +367,12 @@ suite('SnippetSession', function () {
session.insert();
editor.setSelection(new Selection(1, 2, 1, 2));
assert.equal(session.validateSelections(), true);
assert.equal(session.isSelectionWithPlaceholders(), false);
assert.equal(session.isAtFinalPlaceholder, true);
editor.trigger('test', 'type', { text: 'XXX' });
assert.equal(model.getLineContent(1), 'fXXXfarboounction foo() {');
assert.equal(session.validateSelections(), true);
assert.equal(session.isSelectionWithPlaceholders(), false);
session.next();
assertSelections(editor, new Selection(1, 11, 1, 11));
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册