Fixes #231: Restore snippet mode if not entering snippet mode

This commit is contained in:
Alex Dima 2015-12-10 15:29:55 +01:00
parent 7af75ebf56
commit fc26dad6cf
4 changed files with 131 additions and 40 deletions

View file

@ -243,18 +243,28 @@ export class ModelLine {
return NO_OP_MARKERS_ADJUSTER;
}
this._markers.sort(ModelLine._compareMarkers);
var markers = this._markers;
var markersLength = markers.length;
var markersIndex = 0;
var marker = markers[markersIndex];
// var printMarker = (m:ILineMarker) => {
// if (m.stickToPreviousCharacter) {
// return '|' + m.column;
// }
// return m.column + '|';
// }
// var printMarkers = () => {
// return '[' + markers.map( m => m.column).join(', ') + ']';
// return '[' + markers.map(printMarker).join(', ') + ']';
// };
let adjust = (toColumn:number, delta:number, minimumAllowedColumn:number, isReplace:boolean, forceMoveMarkers:boolean) => {
// console.log('------------- INITIAL MARKERS: ' + printMarkers());
let adjust = (toColumn:number, delta:number, minimumAllowedColumn:number, forceStickToPrevious:boolean, forceMoveMarkers:boolean) => {
// console.log('------------------------------');
// console.log('adjust called: toColumn: ' + toColumn + ', delta: ' + delta + ', minimumAllowedColumn: ' + minimumAllowedColumn + ', isReplace: ' + isReplace + ', forceMoveMarkers:' + forceMoveMarkers);
// console.log('adjust called: toColumn: ' + toColumn + ', delta: ' + delta + ', minimumAllowedColumn: ' + minimumAllowedColumn + ', forceStickToPrevious: ' + forceStickToPrevious + ', forceMoveMarkers:' + forceMoveMarkers);
// console.log('BEFORE::: markersIndex: ' + markersIndex + ' : ' + printMarkers());
while (
markersIndex < markersLength
@ -263,7 +273,7 @@ export class ModelLine {
|| (
!forceMoveMarkers
&& marker.column === toColumn
&& (isReplace || marker.stickToPreviousCharacter)
&& (forceStickToPrevious || marker.stickToPreviousCharacter)
)
)
) {
@ -287,6 +297,8 @@ export class ModelLine {
let finish = (delta:number, lineTextLength:number) => {
adjust(Number.MAX_VALUE, delta, 1, false, false);
// console.log('------------- FINAL MARKERS: ' + printMarkers());
};
return {
@ -296,39 +308,46 @@ export class ModelLine {
}
public applyEdits(changedMarkers: IChangedMarkers, edits:ILineEdit[]): number {
// console.log('--> applyEdits: ' + JSON.stringify(edits));
var deltaColumn = 0;
var resultText = this.text;
let deltaColumn = 0;
let resultText = this.text;
var tokensAdjuster = this._createTokensAdjuster();
var markersAdjuster = this._createMarkersAdjuster(changedMarkers);
let tokensAdjuster = this._createTokensAdjuster();
let markersAdjuster = this._createMarkersAdjuster(changedMarkers);
for (var i = 0, len = edits.length; i < len; i++) {
let _oldStartColumn = edits[i].startColumn;
let _oldEndColumn = edits[i].endColumn;
// console.log('_oldStartColumn: ' + _oldStartColumn + ', _oldEndColumn: ' + _oldEndColumn);
let startColumn = deltaColumn + edits[i].startColumn;
let endColumn = deltaColumn + edits[i].endColumn;
let text = edits[i].text;
for (let i = 0, len = edits.length; i < len; i++) {
let edit = edits[i];
// console.log();
// console.log('=============================');
// console.log('EDIT #' + i + ' [ ' + edit.startColumn + ' -> ' + edit.endColumn + ' ] : <<<' + edit.text + '>>>, forceMoveMarkers: ' + edit.forceMoveMarkers);
// console.log('deltaColumn: ' + deltaColumn);
let startColumn = deltaColumn + edit.startColumn;
let endColumn = deltaColumn + edit.endColumn;
let deletingCnt = endColumn - startColumn;
let insertingCnt = edit.text.length;
// Adjust tokens & markers before this edit
tokensAdjuster.adjust(_oldStartColumn - 1, deltaColumn, 1);
markersAdjuster.adjust(_oldStartColumn - 1 + 1, deltaColumn, 1, startColumn !== endColumn, edits[i].forceMoveMarkers);
// console.log('Adjust tokens & markers before this edit');
tokensAdjuster.adjust(edit.startColumn - 1, deltaColumn, 1);
markersAdjuster.adjust(edit.startColumn, deltaColumn, 1, deletingCnt > 0, edit.forceMoveMarkers);
// Adjust tokens & markers for the common part of this edit
let commonLength = Math.min(endColumn - startColumn, text.length);
let commonLength = Math.min(deletingCnt, insertingCnt);
if (commonLength > 0) {
tokensAdjuster.adjust(_oldStartColumn - 1 + commonLength, deltaColumn, startColumn);
markersAdjuster.adjust(_oldStartColumn - 1 + 1 + commonLength, deltaColumn, startColumn, true, edits[i].forceMoveMarkers);
// console.log('Adjust tokens & markers for the common part of this edit');
tokensAdjuster.adjust(edit.startColumn - 1 + commonLength, deltaColumn, startColumn);
markersAdjuster.adjust(edit.startColumn + commonLength, deltaColumn, startColumn, deletingCnt > insertingCnt, edit.forceMoveMarkers);
}
// Perform the edit & update `deltaColumn`
resultText = resultText.substring(0, startColumn - 1) + text + resultText.substring(endColumn - 1);
deltaColumn += text.length - (endColumn - startColumn);
resultText = resultText.substring(0, startColumn - 1) + edit.text + resultText.substring(endColumn - 1);
deltaColumn += insertingCnt - deletingCnt;
// Adjust tokens & markers inside this edit
tokensAdjuster.adjust(_oldEndColumn, deltaColumn, startColumn);
markersAdjuster.adjust(_oldEndColumn + 1, deltaColumn, startColumn, false, edits[i].forceMoveMarkers);
// console.log('Adjust tokens & markers inside this edit');
tokensAdjuster.adjust(edit.endColumn, deltaColumn, startColumn);
markersAdjuster.adjust(edit.endColumn, deltaColumn, startColumn, false, edit.forceMoveMarkers);
}
// Wrap up tokens & markers; adjust remaining if needed
@ -453,8 +472,6 @@ export class ModelLine {
} else {
this._markers.push(marker);
}
this._markers.sort(ModelLine._compareMarkers);
}
public addMarkers(markers:ILineMarker[]): void {
@ -474,8 +491,6 @@ export class ModelLine {
} else {
this._markers = this._markers.concat(markers);
}
this._markers.sort(ModelLine._compareMarkers);
}
private static _compareMarkers(a:ILineMarker, b:ILineMarker): number {

View file

@ -12,9 +12,9 @@ import EventEmitter = require('vs/base/common/eventEmitter');
import {CommonEditorRegistry} from 'vs/editor/common/editorCommonExtensions';
import {Range} from 'vs/editor/common/core/range';
import {Selection} from 'vs/editor/common/core/selection';
import {ReplaceCommand} from 'vs/editor/common/commands/replaceCommand';
import {IKeybindingService, IKeybindingContextKey} from 'vs/platform/keybinding/common/keybindingService';
import {KeyMod, KeyCode} from 'vs/base/common/keyCodes';
import {EditOperation} from 'vs/editor/common/core/editOperation';
interface IParsedLinePlaceHolderInfo {
id: string;
@ -735,7 +735,8 @@ class SnippetController implements ISnippetController {
}
public run(snippet:CodeSnippet, overwriteBefore:number, overwriteAfter:number): void {
this.dispose();
let prevController = this._currentController;
this._currentController = null;
if (snippet.placeHolders.length === 0) {
// No placeholders => execute for all editor selections
@ -743,6 +744,16 @@ class SnippetController implements ISnippetController {
} else {
this._runForPrimarySelection(snippet, overwriteBefore, overwriteAfter);
}
if (!this._currentController) {
// we didn't end up in snippet mode again => restore previous controller
this._currentController = prevController;
} else {
// we ended up in snippet mode => dispose previous controller if necessary
if (prevController) {
prevController.dispose();
}
}
}
private static _getTypeRangeForSelection(model:EditorCommon.IModel, selection:EditorCommon.IEditorSelection, overwriteBefore:number, overwriteAfter:number): EditorCommon.IEditorRange {
@ -764,16 +775,16 @@ class SnippetController implements ISnippetController {
return snippet.bind(model.getLineContent(typeRange.startLineNumber), typeRange.startLineNumber - 1, typeRange.startColumn - 1, editor);
}
private static _getCommandForSnippet(adaptedSnippet:ICodeSnippet, typeRange:EditorCommon.IEditorRange): EditorCommon.ICommand {
private static _getCommandForSnippet(adaptedSnippet:ICodeSnippet, typeRange:EditorCommon.IEditorRange): EditorCommon.IIdentifiedSingleEditOperation {
var insertText = adaptedSnippet.lines.join('\n');
return new ReplaceCommand(typeRange, insertText);
return EditOperation.replace(typeRange, insertText);
}
private _runForPrimarySelection(snippet: CodeSnippet, overwriteBefore: number, overwriteAfter: number): void {
var initialAlternativeVersionId = this._editor.getModel().getAlternativeVersionId();
var prepared = SnippetController._prepareSnippet(this._editor, this._editor.getSelection(), snippet, overwriteBefore, overwriteAfter);
this._editor.executeCommand('editor.contrib.insertSnippetHelper', SnippetController._getCommandForSnippet(prepared.adaptedSnippet, prepared.typeRange));
this._editor.executeEdits('editor.contrib.insertSnippetHelper', [SnippetController._getCommandForSnippet(prepared.adaptedSnippet, prepared.typeRange)]);
var cursorOnly = SnippetController._getSnippetCursorOnly(prepared.adaptedSnippet);
if (cursorOnly) {
@ -787,16 +798,15 @@ class SnippetController implements ISnippetController {
}
private _runForAllSelections(snippet:CodeSnippet, overwriteBefore:number, overwriteAfter:number): void {
var selections = this._editor.getSelections(),
i:number,
commands:EditorCommon.ICommand[] = [];
let selections = this._editor.getSelections(),
edits:EditorCommon.IIdentifiedSingleEditOperation[] = [];
for (i = 0; i < selections.length; i++) {
for (let i = 0; i < selections.length; i++) {
var prepared = SnippetController._prepareSnippet(this._editor, selections[i], snippet, overwriteBefore, overwriteAfter);
commands.push(SnippetController._getCommandForSnippet(prepared.adaptedSnippet, prepared.typeRange));
edits.push(SnippetController._getCommandForSnippet(prepared.adaptedSnippet, prepared.typeRange));
}
this._editor.executeCommands('editor.contrib.insertSnippetHelper', commands);
this._editor.executeEdits('editor.contrib.insertSnippetHelper', edits);
}
private static _prepareSnippet(editor:EditorCommon.ICommonCodeEditor, selection:EditorCommon.IEditorSelection, snippet:CodeSnippet, overwriteBefore:number, overwriteAfter:number): { typeRange: EditorCommon.IEditorRange; adaptedSnippet: ICodeSnippet; } {

View file

@ -77,6 +77,28 @@ suite('Editor Side Editing - collapsed selection', () => {
);
});
test('replace at selection 2', () => {
testCommand(
[
'first',
'second line',
'third line',
'fourth'
],
new Selection(1,1,1,6),
[
EditOperation.replace(new Selection(1,1,1,6), 'something')
],
[
'something',
'second line',
'third line',
'fourth'
],
new Selection(1,1,1,10)
);
});
test('ModelLine.applyEdits uses `isReplace`', () => {
testLineEditMarker('something', 1, true, { startColumn: 1, endColumn: 1, text: 'asd', forceMoveMarkers: false }, 1);
testLineEditMarker('something', 1, true, { startColumn: 1, endColumn: 1, text: 'asd', forceMoveMarkers: true }, 4);

View file

@ -1607,6 +1607,28 @@ suite('Editor Model - ModelLine.applyEdits text & markers', () => {
);
});
test('delete near markers', () => {
testLineEditMarkers(
'abcd',
[
marker(1, 3, true),
marker(2, 3, false)
],
[{
startColumn: 3,
endColumn: 4,
text: '',
forceMoveMarkers: false
}],
'abd',
[],
[
marker(1, 3, true),
marker(2, 3, false)
]
);
});
test('replace: updates markers 2', () => {
testLineEditMarkers(
'Hello world, how are you',
@ -1788,6 +1810,28 @@ suite('Editor Model - ModelLine.applyEdits text & markers', () => {
]
);
});
test('replace selection', () => {
testLineEditMarkers(
'first',
[
marker(1, 1, true),
marker(2, 6, false),
],
[{
startColumn: 1,
endColumn: 6,
text: 'something',
forceMoveMarkers: false
}],
'something',
[2],
[
marker(1, 1, true),
marker(2, 10, false),
]
);
});
});
suite('Editor Model - ModelLine.split text & markers', () => {