mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 13:00:58 +00:00
Merge pull request #17152 from rebornix/MultiCursorState
Compute cursor/s state after edits were applied
This commit is contained in:
commit
84e23b5182
|
@ -600,7 +600,7 @@ export abstract class CommonCodeEditor extends EventEmitter implements editorCom
|
|||
return true;
|
||||
}
|
||||
|
||||
public executeEdits(source: string, edits: editorCommon.IIdentifiedSingleEditOperation[]): boolean {
|
||||
public executeEdits(source: string, edits: editorCommon.IIdentifiedSingleEditOperation[], endCursorState?: Selection[]): boolean {
|
||||
if (!this.cursor) {
|
||||
// no view, no cursor
|
||||
return false;
|
||||
|
@ -611,9 +611,13 @@ export abstract class CommonCodeEditor extends EventEmitter implements editorCom
|
|||
}
|
||||
|
||||
this.model.pushEditOperations(this.cursor.getSelections(), edits, () => {
|
||||
return this.cursor.getSelections();
|
||||
return endCursorState ? endCursorState : this.cursor.getSelections();
|
||||
});
|
||||
|
||||
if (endCursorState) {
|
||||
this.cursor.setSelections(source, endCursorState);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -3939,11 +3939,12 @@ export interface ICommonCodeEditor extends IEditor {
|
|||
pushUndoStop(): boolean;
|
||||
|
||||
/**
|
||||
* Execute a command on the editor.
|
||||
* Execute edits on the editor.
|
||||
* @param source The source of the call.
|
||||
* @param command The command to execute
|
||||
* @param edits The edits to execute.
|
||||
* @param endCursoState Cursor state after the edits were applied.
|
||||
*/
|
||||
executeEdits(source: string, edits: IIdentifiedSingleEditOperation[]): boolean;
|
||||
executeEdits(source: string, edits: IIdentifiedSingleEditOperation[], endCursoState?: Selection[]): boolean;
|
||||
|
||||
/**
|
||||
* Execute multiple (concommitent) commands on the editor.
|
||||
|
|
|
@ -351,92 +351,10 @@ class InsertLineAfterAction extends HandlerEditorAction {
|
|||
}
|
||||
}
|
||||
|
||||
@editorAction
|
||||
export class DeleteAllLeftAction extends EditorAction {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'deleteAllLeft',
|
||||
label: nls.localize('lines.deleteAllLeft', "Delete All Left"),
|
||||
alias: 'Delete All Left',
|
||||
precondition: EditorContextKeys.Writable,
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.TextFocus,
|
||||
primary: null,
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyCode.Backspace }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export abstract class AbstractDeleteAllToBoundaryAction extends EditorAction {
|
||||
public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void {
|
||||
let selections: Range[] = editor.getSelections();
|
||||
|
||||
selections.sort(Range.compareRangesUsingStarts);
|
||||
selections = selections.map(selection => {
|
||||
if (selection.isEmpty()) {
|
||||
return new Selection(selection.startLineNumber, 1, selection.startLineNumber, selection.startColumn);
|
||||
} else {
|
||||
return selection;
|
||||
}
|
||||
});
|
||||
|
||||
// merge overlapping selections
|
||||
let effectiveRanges: Range[] = [];
|
||||
|
||||
for (let i = 0, count = selections.length - 1; i < count; i++) {
|
||||
let range = selections[i];
|
||||
let nextRange = selections[i + 1];
|
||||
|
||||
if (Range.intersectRanges(range, nextRange) === null) {
|
||||
effectiveRanges.push(range);
|
||||
} else {
|
||||
selections[i + 1] = Range.plusRange(range, nextRange);
|
||||
}
|
||||
}
|
||||
|
||||
effectiveRanges.push(selections[selections.length - 1]);
|
||||
|
||||
let edits: IIdentifiedSingleEditOperation[] = effectiveRanges.map(range => {
|
||||
return EditOperation.replace(range, '');
|
||||
});
|
||||
|
||||
editor.executeEdits(this.id, edits);
|
||||
}
|
||||
}
|
||||
|
||||
@editorAction
|
||||
export class DeleteAllRightAction extends EditorAction {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'deleteAllRight',
|
||||
label: nls.localize('lines.deleteAllRight', "Delete All Right"),
|
||||
alias: 'Delete All Right',
|
||||
precondition: EditorContextKeys.Writable,
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.TextFocus,
|
||||
primary: null,
|
||||
mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_K, secondary: [KeyMod.CtrlCmd | KeyCode.Delete] }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void {
|
||||
let model = editor.getModel();
|
||||
|
||||
let rangesToDelete: Range[] = editor.getSelections().map((sel) => {
|
||||
if (sel.isEmpty()) {
|
||||
const maxColumn = model.getLineMaxColumn(sel.startLineNumber);
|
||||
|
||||
if (sel.startColumn === maxColumn) {
|
||||
return new Range(sel.startLineNumber, sel.startColumn, sel.startLineNumber + 1, 1);
|
||||
} else {
|
||||
return new Range(sel.startLineNumber, sel.startColumn, sel.startLineNumber, maxColumn);
|
||||
}
|
||||
}
|
||||
return sel;
|
||||
});
|
||||
|
||||
rangesToDelete.sort(Range.compareRangesUsingStarts);
|
||||
|
||||
const primaryCursor = editor.getSelection();
|
||||
let rangesToDelete = this._getRangesToDelete(editor);
|
||||
// merge overlapping selections
|
||||
let effectiveRanges: Range[] = [];
|
||||
|
||||
|
@ -453,12 +371,132 @@ export class DeleteAllRightAction extends EditorAction {
|
|||
|
||||
effectiveRanges.push(rangesToDelete[rangesToDelete.length - 1]);
|
||||
|
||||
let endCursorState = this._getEndCursorState(primaryCursor, effectiveRanges);
|
||||
let edits: IIdentifiedSingleEditOperation[] = effectiveRanges.map(range => {
|
||||
endCursorState.push(new Selection(range.startLineNumber, range.startColumn, range.startLineNumber, range.startColumn));
|
||||
return EditOperation.replace(range, '');
|
||||
});
|
||||
|
||||
editor.executeEdits(this.id, edits);
|
||||
editor.pushUndoStop();
|
||||
editor.executeEdits(this.id, edits, endCursorState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the cursor state after the edit operations were applied.
|
||||
*/
|
||||
protected abstract _getEndCursorState(primaryCursor: Range, rangesToDelete: Range[]): Selection[];
|
||||
|
||||
protected abstract _getRangesToDelete(editor: ICommonCodeEditor): Range[];
|
||||
}
|
||||
|
||||
@editorAction
|
||||
export class DeleteAllLeftAction extends AbstractDeleteAllToBoundaryAction {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'deleteAllLeft',
|
||||
label: nls.localize('lines.deleteAllLeft', "Delete All Left"),
|
||||
alias: 'Delete All Left',
|
||||
precondition: EditorContextKeys.Writable,
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.TextFocus,
|
||||
primary: null,
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyCode.Backspace }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_getEndCursorState(primaryCursor: Range, rangesToDelete: Range[]): Selection[] {
|
||||
let endPrimaryCursor: Range;
|
||||
let endCursorState = [];
|
||||
|
||||
for (let i = 0, len = rangesToDelete.length; i < len; i++) {
|
||||
let range = rangesToDelete[i];
|
||||
let endCursor = new Selection(rangesToDelete[i].startLineNumber, rangesToDelete[i].startColumn, rangesToDelete[i].startLineNumber, rangesToDelete[i].startColumn);
|
||||
|
||||
if (range.intersectRanges(primaryCursor)) {
|
||||
endPrimaryCursor = endCursor;
|
||||
} else {
|
||||
endCursorState.push(endCursor);
|
||||
}
|
||||
}
|
||||
|
||||
if (endPrimaryCursor) {
|
||||
endCursorState.unshift(endPrimaryCursor);
|
||||
}
|
||||
|
||||
return endCursorState;
|
||||
}
|
||||
|
||||
_getRangesToDelete(editor: ICommonCodeEditor): Range[] {
|
||||
let rangesToDelete: Range[] = editor.getSelections();
|
||||
|
||||
rangesToDelete.sort(Range.compareRangesUsingStarts);
|
||||
rangesToDelete = rangesToDelete.map(selection => {
|
||||
if (selection.isEmpty()) {
|
||||
return new Range(selection.startLineNumber, 1, selection.startLineNumber, selection.startColumn);
|
||||
} else {
|
||||
return selection;
|
||||
}
|
||||
});
|
||||
|
||||
return rangesToDelete;
|
||||
}
|
||||
}
|
||||
|
||||
@editorAction
|
||||
export class DeleteAllRightAction extends AbstractDeleteAllToBoundaryAction {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'deleteAllRight',
|
||||
label: nls.localize('lines.deleteAllRight', "Delete All Right"),
|
||||
alias: 'Delete All Right',
|
||||
precondition: EditorContextKeys.Writable,
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.TextFocus,
|
||||
primary: null,
|
||||
mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_K, secondary: [KeyMod.CtrlCmd | KeyCode.Delete] }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_getEndCursorState(primaryCursor: Range, rangesToDelete: Range[]): Selection[] {
|
||||
let endPrimaryCursor: Range;
|
||||
let endCursorState = [];
|
||||
for (let i = 0, len = rangesToDelete.length, offset = 0; i < len; i++) {
|
||||
let range = rangesToDelete[i];
|
||||
let endCursor = new Selection(range.startLineNumber - offset, range.startColumn, range.startLineNumber - offset, range.startColumn);
|
||||
|
||||
if (range.intersectRanges(primaryCursor)) {
|
||||
endPrimaryCursor = endCursor;
|
||||
} else {
|
||||
endCursorState.push(endCursor);
|
||||
}
|
||||
}
|
||||
|
||||
if (endPrimaryCursor) {
|
||||
endCursorState.unshift(endPrimaryCursor);
|
||||
}
|
||||
|
||||
return endCursorState;
|
||||
}
|
||||
|
||||
_getRangesToDelete(editor: ICommonCodeEditor): Range[] {
|
||||
let model = editor.getModel();
|
||||
|
||||
let rangesToDelete: Range[] = editor.getSelections().map((sel) => {
|
||||
if (sel.isEmpty()) {
|
||||
const maxColumn = model.getLineMaxColumn(sel.startLineNumber);
|
||||
|
||||
if (sel.startColumn === maxColumn) {
|
||||
return new Range(sel.startLineNumber, sel.startColumn, sel.startLineNumber + 1, 1);
|
||||
} else {
|
||||
return new Range(sel.startLineNumber, sel.startColumn, sel.startLineNumber, maxColumn);
|
||||
}
|
||||
}
|
||||
return sel;
|
||||
});
|
||||
|
||||
rangesToDelete.sort(Range.compareRangesUsingStarts);
|
||||
return rangesToDelete;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -480,7 +518,7 @@ export class JoinLinesAction extends EditorAction {
|
|||
|
||||
public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void {
|
||||
let selections = editor.getSelections();
|
||||
let primarySelection = editor.getSelection();
|
||||
let primaryCursor = editor.getSelection();
|
||||
|
||||
selections.sort(Range.compareRangesUsingStarts);
|
||||
let reducedSelections: Selection[] = [];
|
||||
|
@ -488,8 +526,8 @@ export class JoinLinesAction extends EditorAction {
|
|||
let lastSelection = selections.reduce((previousValue, currentValue) => {
|
||||
if (previousValue.isEmpty()) {
|
||||
if (previousValue.endLineNumber === currentValue.startLineNumber) {
|
||||
if (primarySelection.equalsSelection(previousValue)) {
|
||||
primarySelection = currentValue;
|
||||
if (primaryCursor.equalsSelection(previousValue)) {
|
||||
primaryCursor = currentValue;
|
||||
}
|
||||
return currentValue;
|
||||
}
|
||||
|
@ -514,8 +552,8 @@ export class JoinLinesAction extends EditorAction {
|
|||
|
||||
let model = editor.getModel();
|
||||
let edits = [];
|
||||
let resultSelections = [];
|
||||
let resultPrimarySelection = primarySelection;
|
||||
let endCursorState = [];
|
||||
let endPrimaryCursor = primaryCursor;
|
||||
let lineOffset = 0;
|
||||
|
||||
for (let i = 0, len = reducedSelections.length; i < len; i++) {
|
||||
|
@ -594,19 +632,19 @@ export class JoinLinesAction extends EditorAction {
|
|||
}
|
||||
}
|
||||
|
||||
if (Range.intersectRanges(deleteSelection, primarySelection) !== null) {
|
||||
resultPrimarySelection = resultSelection;
|
||||
if (Range.intersectRanges(deleteSelection, primaryCursor) !== null) {
|
||||
endPrimaryCursor = resultSelection;
|
||||
} else {
|
||||
resultSelections.push(resultSelection);
|
||||
endCursorState.push(resultSelection);
|
||||
}
|
||||
}
|
||||
|
||||
lineOffset += deleteSelection.endLineNumber - deleteSelection.startLineNumber;
|
||||
}
|
||||
|
||||
editor.executeEdits(this.id, edits);
|
||||
resultSelections.unshift(resultPrimarySelection);
|
||||
editor.setSelections(resultSelections);
|
||||
endCursorState.unshift(endPrimaryCursor);
|
||||
editor.executeEdits(this.id, edits, endCursorState);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,155 +6,160 @@
|
|||
|
||||
import * as assert from 'assert';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { Handler } from 'vs/editor/common/editorCommon';
|
||||
import { withMockCodeEditor } from 'vs/editor/test/common/mocks/mockCodeEditor';
|
||||
import { DeleteAllLeftAction, JoinLinesAction, TransposeAction, UpperCaseAction, LowerCaseAction, DeleteAllRightAction } from 'vs/editor/contrib/linesOperations/common/linesOperations';
|
||||
|
||||
suite('Editor Contrib - Line Operations', () => {
|
||||
test('delete all left', function () {
|
||||
withMockCodeEditor(
|
||||
[
|
||||
'one',
|
||||
'two',
|
||||
'three'
|
||||
], {}, (editor, cursor) => {
|
||||
let model = editor.getModel();
|
||||
let deleteAllLeftAction = new DeleteAllLeftAction();
|
||||
suite('DeleteAllLeftAction', () => {
|
||||
test('should delete to the left of the cursor', function () {
|
||||
withMockCodeEditor(
|
||||
[
|
||||
'one',
|
||||
'two',
|
||||
'three'
|
||||
], {}, (editor, cursor) => {
|
||||
let model = editor.getModel();
|
||||
let deleteAllLeftAction = new DeleteAllLeftAction();
|
||||
|
||||
editor.setSelection(new Selection(1, 2, 1, 2));
|
||||
deleteAllLeftAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(1), 'ne', '001');
|
||||
editor.setSelection(new Selection(1, 2, 1, 2));
|
||||
deleteAllLeftAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(1), 'ne', '001');
|
||||
|
||||
editor.setSelections([new Selection(2, 2, 2, 2), new Selection(3, 2, 3, 2)]);
|
||||
deleteAllLeftAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(2), 'wo', '002');
|
||||
assert.equal(model.getLineContent(3), 'hree', '003');
|
||||
});
|
||||
editor.setSelections([new Selection(2, 2, 2, 2), new Selection(3, 2, 3, 2)]);
|
||||
deleteAllLeftAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(2), 'wo', '002');
|
||||
assert.equal(model.getLineContent(3), 'hree', '003');
|
||||
});
|
||||
});
|
||||
|
||||
test('should work in multi cursor mode', function () {
|
||||
withMockCodeEditor(
|
||||
[
|
||||
'hello',
|
||||
'world',
|
||||
'hello world',
|
||||
'hello',
|
||||
'bonjour',
|
||||
'hola',
|
||||
'world',
|
||||
'hello world',
|
||||
], {}, (editor, cursor) => {
|
||||
let model = editor.getModel();
|
||||
let deleteAllLeftAction = new DeleteAllLeftAction();
|
||||
|
||||
editor.setSelections([new Selection(1, 2, 1, 2), new Selection(1, 4, 1, 4)]);
|
||||
deleteAllLeftAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(1), 'lo', '001');
|
||||
|
||||
editor.setSelections([new Selection(2, 2, 2, 2), new Selection(2, 4, 2, 5)]);
|
||||
deleteAllLeftAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(2), 'ord', '002');
|
||||
|
||||
editor.setSelections([new Selection(3, 2, 3, 5), new Selection(3, 7, 3, 7)]);
|
||||
deleteAllLeftAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(3), 'world', '003');
|
||||
|
||||
editor.setSelections([new Selection(4, 3, 4, 3), new Selection(4, 5, 5, 4)]);
|
||||
deleteAllLeftAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(4), 'lljour', '004');
|
||||
|
||||
editor.setSelections([new Selection(5, 3, 6, 3), new Selection(6, 5, 7, 5), new Selection(7, 7, 7, 7)]);
|
||||
deleteAllLeftAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(5), 'horlworld', '005');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('delete all left in multi cursor mode', function () {
|
||||
withMockCodeEditor(
|
||||
[
|
||||
'hello',
|
||||
'world',
|
||||
'hello world',
|
||||
'hello',
|
||||
'bonjour',
|
||||
'hola',
|
||||
'world',
|
||||
'hello world',
|
||||
], {}, (editor, cursor) => {
|
||||
let model = editor.getModel();
|
||||
let deleteAllLeftAction = new DeleteAllLeftAction();
|
||||
suite('JoinLinesAction', () => {
|
||||
test('should join lines and insert space if necessary', function () {
|
||||
withMockCodeEditor(
|
||||
[
|
||||
'hello',
|
||||
'world',
|
||||
'hello ',
|
||||
'world',
|
||||
'hello ',
|
||||
' world',
|
||||
'hello ',
|
||||
' world',
|
||||
'',
|
||||
'',
|
||||
'hello world'
|
||||
], {}, (editor, cursor) => {
|
||||
let model = editor.getModel();
|
||||
let joinLinesAction = new JoinLinesAction();
|
||||
|
||||
editor.setSelections([new Selection(1, 2, 1, 2), new Selection(1, 4, 1, 4)]);
|
||||
deleteAllLeftAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(1), 'lo', '001');
|
||||
editor.setSelection(new Selection(1, 2, 1, 2));
|
||||
joinLinesAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(1), 'hello world', '001');
|
||||
assert.deepEqual(editor.getSelection().toString(), new Selection(1, 6, 1, 6).toString(), '002');
|
||||
|
||||
editor.setSelections([new Selection(2, 2, 2, 2), new Selection(2, 4, 2, 5)]);
|
||||
deleteAllLeftAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(2), 'ord', '002');
|
||||
editor.setSelection(new Selection(2, 2, 2, 2));
|
||||
joinLinesAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(2), 'hello world', '003');
|
||||
assert.deepEqual(editor.getSelection().toString(), new Selection(2, 7, 2, 7).toString(), '004');
|
||||
|
||||
editor.setSelections([new Selection(3, 2, 3, 5), new Selection(3, 7, 3, 7)]);
|
||||
deleteAllLeftAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(3), 'world', '003');
|
||||
editor.setSelection(new Selection(3, 2, 3, 2));
|
||||
joinLinesAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(3), 'hello world', '005');
|
||||
assert.deepEqual(editor.getSelection().toString(), new Selection(3, 7, 3, 7).toString(), '006');
|
||||
|
||||
editor.setSelections([new Selection(4, 3, 4, 3), new Selection(4, 5, 5, 4)]);
|
||||
deleteAllLeftAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(4), 'lljour', '004');
|
||||
editor.setSelection(new Selection(4, 2, 5, 3));
|
||||
joinLinesAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(4), 'hello world', '007');
|
||||
assert.deepEqual(editor.getSelection().toString(), new Selection(4, 2, 4, 8).toString(), '008');
|
||||
|
||||
editor.setSelections([new Selection(5, 3, 6, 3), new Selection(6, 5, 7, 5), new Selection(7, 7, 7, 7)]);
|
||||
deleteAllLeftAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(5), 'horlworld', '005');
|
||||
});
|
||||
});
|
||||
editor.setSelection(new Selection(5, 1, 7, 3));
|
||||
joinLinesAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(5), 'hello world', '009');
|
||||
assert.deepEqual(editor.getSelection().toString(), new Selection(5, 1, 5, 3).toString(), '010');
|
||||
});
|
||||
});
|
||||
|
||||
test('join lines', function () {
|
||||
withMockCodeEditor(
|
||||
[
|
||||
'hello',
|
||||
'world',
|
||||
'hello ',
|
||||
'world',
|
||||
'hello ',
|
||||
' world',
|
||||
'hello ',
|
||||
' world',
|
||||
'',
|
||||
'',
|
||||
'hello world'
|
||||
], {}, (editor, cursor) => {
|
||||
let model = editor.getModel();
|
||||
let joinLinesAction = new JoinLinesAction();
|
||||
test('should work in multi cursor mode', function () {
|
||||
withMockCodeEditor(
|
||||
[
|
||||
'hello',
|
||||
'world',
|
||||
'hello ',
|
||||
'world',
|
||||
'hello ',
|
||||
' world',
|
||||
'hello ',
|
||||
' world',
|
||||
'',
|
||||
'',
|
||||
'hello world'
|
||||
], {}, (editor, cursor) => {
|
||||
let model = editor.getModel();
|
||||
let joinLinesAction = new JoinLinesAction();
|
||||
|
||||
editor.setSelection(new Selection(1, 2, 1, 2));
|
||||
joinLinesAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(1), 'hello world', '001');
|
||||
assert.deepEqual(editor.getSelection().toString(), new Selection(1, 6, 1, 6).toString(), '002');
|
||||
editor.setSelections([
|
||||
/** primary cursor */
|
||||
new Selection(5, 2, 5, 2),
|
||||
new Selection(1, 2, 1, 2),
|
||||
new Selection(3, 2, 4, 2),
|
||||
new Selection(5, 4, 6, 3),
|
||||
new Selection(7, 5, 8, 4),
|
||||
new Selection(10, 1, 10, 1)
|
||||
]);
|
||||
|
||||
editor.setSelection(new Selection(2, 2, 2, 2));
|
||||
joinLinesAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(2), 'hello world', '003');
|
||||
assert.deepEqual(editor.getSelection().toString(), new Selection(2, 7, 2, 7).toString(), '004');
|
||||
joinLinesAction.run(null, editor);
|
||||
assert.equal(model.getLinesContent().join('\n'), 'hello world\nhello world\nhello world\nhello world\n\nhello world', '001');
|
||||
assert.deepEqual(editor.getSelections().toString(), [
|
||||
/** primary cursor */
|
||||
new Selection(3, 4, 3, 8),
|
||||
new Selection(1, 6, 1, 6),
|
||||
new Selection(2, 2, 2, 8),
|
||||
new Selection(4, 5, 4, 9),
|
||||
new Selection(6, 1, 6, 1)
|
||||
].toString(), '002');
|
||||
|
||||
editor.setSelection(new Selection(3, 2, 3, 2));
|
||||
joinLinesAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(3), 'hello world', '005');
|
||||
assert.deepEqual(editor.getSelection().toString(), new Selection(3, 7, 3, 7).toString(), '006');
|
||||
|
||||
editor.setSelection(new Selection(4, 2, 5, 3));
|
||||
joinLinesAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(4), 'hello world', '007');
|
||||
assert.deepEqual(editor.getSelection().toString(), new Selection(4, 2, 4, 8).toString(), '008');
|
||||
|
||||
editor.setSelection(new Selection(5, 1, 7, 3));
|
||||
joinLinesAction.run(null, editor);
|
||||
assert.equal(model.getLineContent(5), 'hello world', '009');
|
||||
assert.deepEqual(editor.getSelection().toString(), new Selection(5, 1, 5, 3).toString(), '010');
|
||||
});
|
||||
});
|
||||
|
||||
test('join lines in multi cursor mode', function () {
|
||||
withMockCodeEditor(
|
||||
[
|
||||
'hello',
|
||||
'world',
|
||||
'hello ',
|
||||
'world',
|
||||
'hello ',
|
||||
' world',
|
||||
'hello ',
|
||||
' world',
|
||||
'',
|
||||
'',
|
||||
'hello world'
|
||||
], {}, (editor, cursor) => {
|
||||
let model = editor.getModel();
|
||||
let joinLinesAction = new JoinLinesAction();
|
||||
|
||||
editor.setSelections([
|
||||
/** primary cursor */
|
||||
new Selection(5, 2, 5, 2),
|
||||
new Selection(1, 2, 1, 2),
|
||||
new Selection(3, 2, 4, 2),
|
||||
new Selection(5, 4, 6, 3),
|
||||
new Selection(7, 5, 8, 4),
|
||||
new Selection(10, 1, 10, 1)
|
||||
]);
|
||||
|
||||
joinLinesAction.run(null, editor);
|
||||
assert.equal(model.getLinesContent().join('\n'), 'hello world\nhello world\nhello world\nhello world\n\nhello world', '001');
|
||||
assert.deepEqual(editor.getSelections().toString(), [
|
||||
/** primary cursor */
|
||||
new Selection(3, 4, 3, 8),
|
||||
new Selection(1, 6, 1, 6),
|
||||
new Selection(2, 2, 2, 8),
|
||||
new Selection(4, 5, 4, 9),
|
||||
new Selection(6, 1, 6, 1)
|
||||
].toString(), '002');
|
||||
|
||||
/** primary cursor */
|
||||
assert.deepEqual(editor.getSelection().toString(), new Selection(3, 4, 3, 8).toString(), '003');
|
||||
});
|
||||
assert.deepEqual(editor.getSelection().toString(), new Selection(3, 4, 3, 8).toString(), '003');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('transpose', function () {
|
||||
|
@ -447,5 +452,40 @@ suite('Editor Contrib - Line Operations', () => {
|
|||
]);
|
||||
});
|
||||
});
|
||||
|
||||
test('should work with undo/redo', () => {
|
||||
withMockCodeEditor([
|
||||
'hello',
|
||||
'there',
|
||||
'world'
|
||||
], {}, (editor, cursor) => {
|
||||
const model = editor.getModel();
|
||||
const action = new DeleteAllRightAction();
|
||||
|
||||
editor.setSelections([
|
||||
new Selection(1, 3, 1, 3),
|
||||
new Selection(1, 6, 1, 6),
|
||||
new Selection(3, 4, 3, 4),
|
||||
]);
|
||||
action.run(null, editor);
|
||||
assert.deepEqual(model.getLinesContent(), ['hethere', 'wor']);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
new Selection(1, 3, 1, 3),
|
||||
new Selection(2, 4, 2, 4)
|
||||
]);
|
||||
|
||||
cursor.trigger('tests', Handler.Undo, {});
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
new Selection(1, 3, 1, 3),
|
||||
new Selection(1, 6, 1, 6),
|
||||
new Selection(3, 4, 3, 4)
|
||||
]);
|
||||
cursor.trigger('tests', Handler.Redo, {});
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
new Selection(1, 3, 1, 3),
|
||||
new Selection(2, 4, 2, 4)
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
7
src/vs/monaco.d.ts
vendored
7
src/vs/monaco.d.ts
vendored
|
@ -3163,11 +3163,12 @@ declare module monaco.editor {
|
|||
*/
|
||||
pushUndoStop(): boolean;
|
||||
/**
|
||||
* Execute a command on the editor.
|
||||
* Execute edits on the editor.
|
||||
* @param source The source of the call.
|
||||
* @param command The command to execute
|
||||
* @param edits The edits to execute.
|
||||
* @param endCursoState Cursor state after the edits were applied.
|
||||
*/
|
||||
executeEdits(source: string, edits: IIdentifiedSingleEditOperation[]): boolean;
|
||||
executeEdits(source: string, edits: IIdentifiedSingleEditOperation[], endCursoState?: Selection[]): boolean;
|
||||
/**
|
||||
* Execute multiple (concommitent) commands on the editor.
|
||||
* @param source The source of the call.
|
||||
|
|
Loading…
Reference in a new issue