Merge pull request #2796 from martellaj/joem/sort-lines

Adds sort lines (ascending and descending) command
This commit is contained in:
Alex Dima
2016-03-17 22:18:08 +01:00
3 changed files with 282 additions and 2 deletions
@@ -7,6 +7,7 @@
import * as nls from 'vs/nls';
import {KeyCode, KeyMod} from 'vs/base/common/keyCodes';
import {TPromise} from 'vs/base/common/winjs.base';
import {SortLinesCommand} from 'vs/editor/contrib/linesOperations/common/sortLinesCommand';
import {TrimTrailingWhitespaceCommand} from 'vs/editor/common/commands/trimTrailingWhitespaceCommand';
import {EditorAction, HandlerEditorAction} from 'vs/editor/common/editorAction';
import {Handler, ICommand, ICommonCodeEditor, IEditorActionDescriptorData} from 'vs/editor/common/editorCommon';
@@ -100,6 +101,40 @@ class MoveLinesDownAction extends MoveLinesAction {
}
}
class SortLinesAction extends EditorAction {
private descending:boolean;
constructor(descriptor:IEditorActionDescriptorData, editor:ICommonCodeEditor, descending:boolean) {
super(descriptor, editor);
this.descending = descending;
}
public run():TPromise<boolean> {
var command = new SortLinesCommand(this.editor.getSelection(), this.descending);
this.editor.executeCommands(this.id, [command]);
return TPromise.as(true);
}
}
class SortLinesAscendingAction extends SortLinesAction {
static ID ='editor.action.sortLinesAscending';
constructor(descriptor:IEditorActionDescriptorData, editor:ICommonCodeEditor) {
super(descriptor, editor, false);
}
}
class SortLinesDescendingAction extends SortLinesAction {
static ID ='editor.action.sortLinesDescending';
constructor(descriptor:IEditorActionDescriptorData, editor:ICommonCodeEditor) {
super(descriptor, editor, true);
}
}
class TrimTrailingWhitespaceAction extends EditorAction {
static ID = 'editor.action.trimTrailingWhitespace';
@@ -234,6 +269,14 @@ CommonEditorRegistry.registerEditorAction(new EditorActionDescriptor(DeleteLines
context: ContextKey.EditorTextFocus,
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_K
}));
CommonEditorRegistry.registerEditorAction(new EditorActionDescriptor(SortLinesAscendingAction, SortLinesAscendingAction.ID, nls.localize('lines.sortAscending', "Sort Lines Ascending"), {
context: ContextKey.EditorTextFocus,
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_2
}));
CommonEditorRegistry.registerEditorAction(new EditorActionDescriptor(SortLinesDescendingAction, SortLinesDescendingAction.ID, nls.localize('lines.sortDescending', "Sort Lines Descending"), {
context: ContextKey.EditorTextFocus,
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_3
}));
CommonEditorRegistry.registerEditorAction(new EditorActionDescriptor(TrimTrailingWhitespaceAction, TrimTrailingWhitespaceAction.ID, nls.localize('lines.trimTrailingWhitespace', "Trim Trailing Whitespace"), {
context: ContextKey.EditorTextFocus,
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_X
@@ -274,5 +317,3 @@ CommonEditorRegistry.registerEditorAction(new EditorActionDescriptor(InsertLineA
context: ContextKey.EditorTextFocus,
primary: KeyMod.CtrlCmd | KeyCode.Enter
}));
@@ -0,0 +1,72 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {EditOperation} from 'vs/editor/common/core/editOperation';
import * as editorCommon from 'vs/editor/common/editorCommon';
import {Range} from 'vs/editor/common/core/range';
export class SortLinesCommand implements editorCommon.ICommand {
private selection:editorCommon.IEditorSelection;
private selectionId:string;
private descending:boolean;
constructor(selection:editorCommon.IEditorSelection, descending:boolean) {
this.selection = selection;
this.descending = descending;
}
public getEditOperations(model:editorCommon.ITokenizedModel, builder:editorCommon.IEditOperationBuilder):void {
let op = sortLines(model, this.selection, this.descending);
if (op) {
builder.addEditOperation(op.range, op.text);
}
this.selectionId = builder.trackSelection(this.selection);
}
public computeCursorState(model:editorCommon.ITokenizedModel, helper: editorCommon.ICursorStateComputerData):editorCommon.IEditorSelection {
return helper.getTrackedSelection(this.selectionId);
}
}
/**
* Generate commands for sorting lines on a model.
*/
export function sortLines(model:editorCommon.ITextModel, selection:editorCommon.IEditorSelection, descending:boolean): editorCommon.IIdentifiedSingleEditOperation {
let startLineNumber = selection.startLineNumber;
let endLineNumber = selection.endLineNumber;
if (selection.endColumn === 1) {
endLineNumber--;
}
// Nothing to sort if user didn't select anything.
if (startLineNumber >= endLineNumber) {
return null;
}
let linesToSort = [];
// Get the contents of the selection to be sorted.
for (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {
linesToSort.push(model.getLineContent(lineNumber));
}
let sorted = linesToSort.sort((a, b) => {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
// If descending, reverse the order.
if (descending === true) {
sorted = sorted.reverse();
}
return EditOperation.replace(
new Range(startLineNumber, 1, endLineNumber, model.getLineMaxColumn(endLineNumber)),
sorted.join('\n')
);
}
@@ -0,0 +1,167 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {Selection} from 'vs/editor/common/core/selection';
import {SortLinesCommand} from 'vs/editor/contrib/linesOperations/common/sortLinesCommand';
import {testCommand} from 'vs/editor/test/common/commands/commandTestUtils';
function testSortLinesAscendingCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
testCommand(lines, null, selection, (sel) => new SortLinesCommand(sel, false), expectedLines, expectedSelection);
}
function testSortLinesDescendingCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
testCommand(lines, null, selection, (sel) => new SortLinesCommand(sel, true), expectedLines, expectedSelection);
}
suite('Editor Contrib - Sort Lines Command', () => {
test('no op unless at least two lines selected 1', function () {
testSortLinesAscendingCommand(
[
'first',
'second line',
'third line',
'fourth line',
'fifth'
],
new Selection(1, 3, 1, 1),
[
'first',
'second line',
'third line',
'fourth line',
'fifth'
],
new Selection(1, 3, 1, 1)
);
});
test('no op unless at least two lines selected 2', function () {
testSortLinesAscendingCommand(
[
'first',
'second line',
'third line',
'fourth line',
'fifth'
],
new Selection(1, 3, 2, 1),
[
'first',
'second line',
'third line',
'fourth line',
'fifth'
],
new Selection(1, 3, 2, 1)
);
});
test('sorting two lines ascending', function () {
testSortLinesAscendingCommand(
[
'first',
'second line',
'third line',
'fourth line',
'fifth'
],
new Selection(3, 3, 4, 2),
[
'first',
'second line',
'fourth line',
'third line',
'fifth'
],
new Selection(3, 3, 4, 2)
);
});
test('sorting first 4 lines ascending', function () {
testSortLinesAscendingCommand(
[
'first',
'second line',
'third line',
'fourth line',
'fifth'
],
new Selection(1, 1, 5, 1),
[
'first',
'fourth line',
'second line',
'third line',
'fifth'
],
new Selection(1, 1, 5, 1)
);
});
test('sorting all lines ascending', function () {
testSortLinesAscendingCommand(
[
'first',
'second line',
'third line',
'fourth line',
'fifth'
],
new Selection(1, 1, 5, 6),
[
'fifth',
'first',
'fourth line',
'second line',
'third line',
],
new Selection(1, 1, 5, 6)
);
});
test('sorting first 4 lines desscending', function () {
testSortLinesDescendingCommand(
[
'first',
'second line',
'third line',
'fourth line',
'fifth'
],
new Selection(1, 1, 5, 1),
[
'third line',
'second line',
'fourth line',
'first',
'fifth'
],
new Selection(1, 1, 5, 1)
);
});
test('sorting all lines descending', function () {
testSortLinesDescendingCommand(
[
'first',
'second line',
'third line',
'fourth line',
'fifth'
],
new Selection(1, 1, 5, 6),
[
'third line',
'second line',
'fourth line',
'first',
'fifth',
],
new Selection(1, 1, 5, 6)
);
});
});