| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- import { KeyChord } from '../../../../base/common/keyCodes.js';
- import { CoreEditingCommands } from '../../../browser/coreCommands.js';
- import { EditorAction, registerEditorAction } from '../../../browser/editorExtensions.js';
- import { ReplaceCommand, ReplaceCommandThatPreservesSelection, ReplaceCommandThatSelectsText } from '../../../common/commands/replaceCommand.js';
- import { TrimTrailingWhitespaceCommand } from '../../../common/commands/trimTrailingWhitespaceCommand.js';
- import { TypeOperations } from '../../../common/cursor/cursorTypeOperations.js';
- import { EditOperation } from '../../../common/core/editOperation.js';
- import { Position } from '../../../common/core/position.js';
- import { Range } from '../../../common/core/range.js';
- import { Selection } from '../../../common/core/selection.js';
- import { EditorContextKeys } from '../../../common/editorContextKeys.js';
- import { CopyLinesCommand } from './copyLinesCommand.js';
- import { MoveLinesCommand } from './moveLinesCommand.js';
- import { SortLinesCommand } from './sortLinesCommand.js';
- import * as nls from '../../../../nls.js';
- import { MenuId } from '../../../../platform/actions/common/actions.js';
- import { ILanguageConfigurationService } from '../../../common/languages/languageConfigurationRegistry.js';
- // copy lines
- class AbstractCopyLinesAction extends EditorAction {
- constructor(down, opts) {
- super(opts);
- this.down = down;
- }
- run(_accessor, editor) {
- if (!editor.hasModel()) {
- return;
- }
- const selections = editor.getSelections().map((selection, index) => ({ selection, index, ignore: false }));
- selections.sort((a, b) => Range.compareRangesUsingStarts(a.selection, b.selection));
- // Remove selections that would result in copying the same line
- let prev = selections[0];
- for (let i = 1; i < selections.length; i++) {
- const curr = selections[i];
- if (prev.selection.endLineNumber === curr.selection.startLineNumber) {
- // these two selections would copy the same line
- if (prev.index < curr.index) {
- // prev wins
- curr.ignore = true;
- }
- else {
- // curr wins
- prev.ignore = true;
- prev = curr;
- }
- }
- }
- const commands = [];
- for (const selection of selections) {
- commands.push(new CopyLinesCommand(selection.selection, this.down, selection.ignore));
- }
- editor.pushUndoStop();
- editor.executeCommands(this.id, commands);
- editor.pushUndoStop();
- }
- }
- class CopyLinesUpAction extends AbstractCopyLinesAction {
- constructor() {
- super(false, {
- id: 'editor.action.copyLinesUpAction',
- label: nls.localize('lines.copyUp', "Copy Line Up"),
- alias: 'Copy Line Up',
- precondition: EditorContextKeys.writable,
- kbOpts: {
- kbExpr: EditorContextKeys.editorTextFocus,
- primary: 512 /* KeyMod.Alt */ | 1024 /* KeyMod.Shift */ | 16 /* KeyCode.UpArrow */,
- linux: { primary: 2048 /* KeyMod.CtrlCmd */ | 512 /* KeyMod.Alt */ | 1024 /* KeyMod.Shift */ | 16 /* KeyCode.UpArrow */ },
- weight: 100 /* KeybindingWeight.EditorContrib */
- },
- menuOpts: {
- menuId: MenuId.MenubarSelectionMenu,
- group: '2_line',
- title: nls.localize({ key: 'miCopyLinesUp', comment: ['&& denotes a mnemonic'] }, "&&Copy Line Up"),
- order: 1
- }
- });
- }
- }
- class CopyLinesDownAction extends AbstractCopyLinesAction {
- constructor() {
- super(true, {
- id: 'editor.action.copyLinesDownAction',
- label: nls.localize('lines.copyDown', "Copy Line Down"),
- alias: 'Copy Line Down',
- precondition: EditorContextKeys.writable,
- kbOpts: {
- kbExpr: EditorContextKeys.editorTextFocus,
- primary: 512 /* KeyMod.Alt */ | 1024 /* KeyMod.Shift */ | 18 /* KeyCode.DownArrow */,
- linux: { primary: 2048 /* KeyMod.CtrlCmd */ | 512 /* KeyMod.Alt */ | 1024 /* KeyMod.Shift */ | 18 /* KeyCode.DownArrow */ },
- weight: 100 /* KeybindingWeight.EditorContrib */
- },
- menuOpts: {
- menuId: MenuId.MenubarSelectionMenu,
- group: '2_line',
- title: nls.localize({ key: 'miCopyLinesDown', comment: ['&& denotes a mnemonic'] }, "Co&&py Line Down"),
- order: 2
- }
- });
- }
- }
- export class DuplicateSelectionAction extends EditorAction {
- constructor() {
- super({
- id: 'editor.action.duplicateSelection',
- label: nls.localize('duplicateSelection', "Duplicate Selection"),
- alias: 'Duplicate Selection',
- precondition: EditorContextKeys.writable,
- menuOpts: {
- menuId: MenuId.MenubarSelectionMenu,
- group: '2_line',
- title: nls.localize({ key: 'miDuplicateSelection', comment: ['&& denotes a mnemonic'] }, "&&Duplicate Selection"),
- order: 5
- }
- });
- }
- run(accessor, editor, args) {
- if (!editor.hasModel()) {
- return;
- }
- const commands = [];
- const selections = editor.getSelections();
- const model = editor.getModel();
- for (const selection of selections) {
- if (selection.isEmpty()) {
- commands.push(new CopyLinesCommand(selection, true));
- }
- else {
- const insertSelection = new Selection(selection.endLineNumber, selection.endColumn, selection.endLineNumber, selection.endColumn);
- commands.push(new ReplaceCommandThatSelectsText(insertSelection, model.getValueInRange(selection)));
- }
- }
- editor.pushUndoStop();
- editor.executeCommands(this.id, commands);
- editor.pushUndoStop();
- }
- }
- // move lines
- class AbstractMoveLinesAction extends EditorAction {
- constructor(down, opts) {
- super(opts);
- this.down = down;
- }
- run(accessor, editor) {
- const languageConfigurationService = accessor.get(ILanguageConfigurationService);
- const commands = [];
- const selections = editor.getSelections() || [];
- const autoIndent = editor.getOption(9 /* EditorOption.autoIndent */);
- for (const selection of selections) {
- commands.push(new MoveLinesCommand(selection, this.down, autoIndent, languageConfigurationService));
- }
- editor.pushUndoStop();
- editor.executeCommands(this.id, commands);
- editor.pushUndoStop();
- }
- }
- class MoveLinesUpAction extends AbstractMoveLinesAction {
- constructor() {
- super(false, {
- id: 'editor.action.moveLinesUpAction',
- label: nls.localize('lines.moveUp', "Move Line Up"),
- alias: 'Move Line Up',
- precondition: EditorContextKeys.writable,
- kbOpts: {
- kbExpr: EditorContextKeys.editorTextFocus,
- primary: 512 /* KeyMod.Alt */ | 16 /* KeyCode.UpArrow */,
- linux: { primary: 512 /* KeyMod.Alt */ | 16 /* KeyCode.UpArrow */ },
- weight: 100 /* KeybindingWeight.EditorContrib */
- },
- menuOpts: {
- menuId: MenuId.MenubarSelectionMenu,
- group: '2_line',
- title: nls.localize({ key: 'miMoveLinesUp', comment: ['&& denotes a mnemonic'] }, "Mo&&ve Line Up"),
- order: 3
- }
- });
- }
- }
- class MoveLinesDownAction extends AbstractMoveLinesAction {
- constructor() {
- super(true, {
- id: 'editor.action.moveLinesDownAction',
- label: nls.localize('lines.moveDown', "Move Line Down"),
- alias: 'Move Line Down',
- precondition: EditorContextKeys.writable,
- kbOpts: {
- kbExpr: EditorContextKeys.editorTextFocus,
- primary: 512 /* KeyMod.Alt */ | 18 /* KeyCode.DownArrow */,
- linux: { primary: 512 /* KeyMod.Alt */ | 18 /* KeyCode.DownArrow */ },
- weight: 100 /* KeybindingWeight.EditorContrib */
- },
- menuOpts: {
- menuId: MenuId.MenubarSelectionMenu,
- group: '2_line',
- title: nls.localize({ key: 'miMoveLinesDown', comment: ['&& denotes a mnemonic'] }, "Move &&Line Down"),
- order: 4
- }
- });
- }
- }
- export class AbstractSortLinesAction extends EditorAction {
- constructor(descending, opts) {
- super(opts);
- this.descending = descending;
- }
- run(_accessor, editor) {
- const selections = editor.getSelections() || [];
- for (const selection of selections) {
- if (!SortLinesCommand.canRun(editor.getModel(), selection, this.descending)) {
- return;
- }
- }
- const commands = [];
- for (let i = 0, len = selections.length; i < len; i++) {
- commands[i] = new SortLinesCommand(selections[i], this.descending);
- }
- editor.pushUndoStop();
- editor.executeCommands(this.id, commands);
- editor.pushUndoStop();
- }
- }
- export class SortLinesAscendingAction extends AbstractSortLinesAction {
- constructor() {
- super(false, {
- id: 'editor.action.sortLinesAscending',
- label: nls.localize('lines.sortAscending', "Sort Lines Ascending"),
- alias: 'Sort Lines Ascending',
- precondition: EditorContextKeys.writable
- });
- }
- }
- export class SortLinesDescendingAction extends AbstractSortLinesAction {
- constructor() {
- super(true, {
- id: 'editor.action.sortLinesDescending',
- label: nls.localize('lines.sortDescending', "Sort Lines Descending"),
- alias: 'Sort Lines Descending',
- precondition: EditorContextKeys.writable
- });
- }
- }
- export class DeleteDuplicateLinesAction extends EditorAction {
- constructor() {
- super({
- id: 'editor.action.removeDuplicateLines',
- label: nls.localize('lines.deleteDuplicates', "Delete Duplicate Lines"),
- alias: 'Delete Duplicate Lines',
- precondition: EditorContextKeys.writable
- });
- }
- run(_accessor, editor) {
- if (!editor.hasModel()) {
- return;
- }
- const model = editor.getModel();
- if (model.getLineCount() === 1 && model.getLineMaxColumn(1) === 1) {
- return;
- }
- const edits = [];
- const endCursorState = [];
- let linesDeleted = 0;
- for (const selection of editor.getSelections()) {
- const uniqueLines = new Set();
- const lines = [];
- for (let i = selection.startLineNumber; i <= selection.endLineNumber; i++) {
- const line = model.getLineContent(i);
- if (uniqueLines.has(line)) {
- continue;
- }
- lines.push(line);
- uniqueLines.add(line);
- }
- const selectionToReplace = new Selection(selection.startLineNumber, 1, selection.endLineNumber, model.getLineMaxColumn(selection.endLineNumber));
- const adjustedSelectionStart = selection.startLineNumber - linesDeleted;
- const finalSelection = new Selection(adjustedSelectionStart, 1, adjustedSelectionStart + lines.length - 1, lines[lines.length - 1].length);
- edits.push(EditOperation.replace(selectionToReplace, lines.join('\n')));
- endCursorState.push(finalSelection);
- linesDeleted += (selection.endLineNumber - selection.startLineNumber + 1) - lines.length;
- }
- editor.pushUndoStop();
- editor.executeEdits(this.id, edits, endCursorState);
- editor.pushUndoStop();
- }
- }
- export class TrimTrailingWhitespaceAction extends EditorAction {
- constructor() {
- super({
- id: TrimTrailingWhitespaceAction.ID,
- label: nls.localize('lines.trimTrailingWhitespace', "Trim Trailing Whitespace"),
- alias: 'Trim Trailing Whitespace',
- precondition: EditorContextKeys.writable,
- kbOpts: {
- kbExpr: EditorContextKeys.editorTextFocus,
- primary: KeyChord(2048 /* KeyMod.CtrlCmd */ | 41 /* KeyCode.KeyK */, 2048 /* KeyMod.CtrlCmd */ | 54 /* KeyCode.KeyX */),
- weight: 100 /* KeybindingWeight.EditorContrib */
- }
- });
- }
- run(_accessor, editor, args) {
- let cursors = [];
- if (args.reason === 'auto-save') {
- // See https://github.com/editorconfig/editorconfig-vscode/issues/47
- // It is very convenient for the editor config extension to invoke this action.
- // So, if we get a reason:'auto-save' passed in, let's preserve cursor positions.
- cursors = (editor.getSelections() || []).map(s => new Position(s.positionLineNumber, s.positionColumn));
- }
- const selection = editor.getSelection();
- if (selection === null) {
- return;
- }
- const command = new TrimTrailingWhitespaceCommand(selection, cursors);
- editor.pushUndoStop();
- editor.executeCommands(this.id, [command]);
- editor.pushUndoStop();
- }
- }
- TrimTrailingWhitespaceAction.ID = 'editor.action.trimTrailingWhitespace';
- export class DeleteLinesAction extends EditorAction {
- constructor() {
- super({
- id: 'editor.action.deleteLines',
- label: nls.localize('lines.delete', "Delete Line"),
- alias: 'Delete Line',
- precondition: EditorContextKeys.writable,
- kbOpts: {
- kbExpr: EditorContextKeys.textInputFocus,
- primary: 2048 /* KeyMod.CtrlCmd */ | 1024 /* KeyMod.Shift */ | 41 /* KeyCode.KeyK */,
- weight: 100 /* KeybindingWeight.EditorContrib */
- }
- });
- }
- run(_accessor, editor) {
- if (!editor.hasModel()) {
- return;
- }
- const ops = this._getLinesToRemove(editor);
- const model = editor.getModel();
- if (model.getLineCount() === 1 && model.getLineMaxColumn(1) === 1) {
- // Model is empty
- return;
- }
- let linesDeleted = 0;
- const edits = [];
- const cursorState = [];
- for (let i = 0, len = ops.length; i < len; i++) {
- const op = ops[i];
- let startLineNumber = op.startLineNumber;
- let endLineNumber = op.endLineNumber;
- let startColumn = 1;
- let endColumn = model.getLineMaxColumn(endLineNumber);
- if (endLineNumber < model.getLineCount()) {
- endLineNumber += 1;
- endColumn = 1;
- }
- else if (startLineNumber > 1) {
- startLineNumber -= 1;
- startColumn = model.getLineMaxColumn(startLineNumber);
- }
- edits.push(EditOperation.replace(new Selection(startLineNumber, startColumn, endLineNumber, endColumn), ''));
- cursorState.push(new Selection(startLineNumber - linesDeleted, op.positionColumn, startLineNumber - linesDeleted, op.positionColumn));
- linesDeleted += (op.endLineNumber - op.startLineNumber + 1);
- }
- editor.pushUndoStop();
- editor.executeEdits(this.id, edits, cursorState);
- editor.pushUndoStop();
- }
- _getLinesToRemove(editor) {
- // Construct delete operations
- const operations = editor.getSelections().map((s) => {
- let endLineNumber = s.endLineNumber;
- if (s.startLineNumber < s.endLineNumber && s.endColumn === 1) {
- endLineNumber -= 1;
- }
- return {
- startLineNumber: s.startLineNumber,
- selectionStartColumn: s.selectionStartColumn,
- endLineNumber: endLineNumber,
- positionColumn: s.positionColumn
- };
- });
- // Sort delete operations
- operations.sort((a, b) => {
- if (a.startLineNumber === b.startLineNumber) {
- return a.endLineNumber - b.endLineNumber;
- }
- return a.startLineNumber - b.startLineNumber;
- });
- // Merge delete operations which are adjacent or overlapping
- const mergedOperations = [];
- let previousOperation = operations[0];
- for (let i = 1; i < operations.length; i++) {
- if (previousOperation.endLineNumber + 1 >= operations[i].startLineNumber) {
- // Merge current operations into the previous one
- previousOperation.endLineNumber = operations[i].endLineNumber;
- }
- else {
- // Push previous operation
- mergedOperations.push(previousOperation);
- previousOperation = operations[i];
- }
- }
- // Push the last operation
- mergedOperations.push(previousOperation);
- return mergedOperations;
- }
- }
- export class IndentLinesAction extends EditorAction {
- constructor() {
- super({
- id: 'editor.action.indentLines',
- label: nls.localize('lines.indent', "Indent Line"),
- alias: 'Indent Line',
- precondition: EditorContextKeys.writable,
- kbOpts: {
- kbExpr: EditorContextKeys.editorTextFocus,
- primary: 2048 /* KeyMod.CtrlCmd */ | 89 /* KeyCode.BracketRight */,
- weight: 100 /* KeybindingWeight.EditorContrib */
- }
- });
- }
- run(_accessor, editor) {
- const viewModel = editor._getViewModel();
- if (!viewModel) {
- return;
- }
- editor.pushUndoStop();
- editor.executeCommands(this.id, TypeOperations.indent(viewModel.cursorConfig, editor.getModel(), editor.getSelections()));
- editor.pushUndoStop();
- }
- }
- class OutdentLinesAction extends EditorAction {
- constructor() {
- super({
- id: 'editor.action.outdentLines',
- label: nls.localize('lines.outdent', "Outdent Line"),
- alias: 'Outdent Line',
- precondition: EditorContextKeys.writable,
- kbOpts: {
- kbExpr: EditorContextKeys.editorTextFocus,
- primary: 2048 /* KeyMod.CtrlCmd */ | 87 /* KeyCode.BracketLeft */,
- weight: 100 /* KeybindingWeight.EditorContrib */
- }
- });
- }
- run(_accessor, editor) {
- CoreEditingCommands.Outdent.runEditorCommand(_accessor, editor, null);
- }
- }
- export class InsertLineBeforeAction extends EditorAction {
- constructor() {
- super({
- id: 'editor.action.insertLineBefore',
- label: nls.localize('lines.insertBefore', "Insert Line Above"),
- alias: 'Insert Line Above',
- precondition: EditorContextKeys.writable,
- kbOpts: {
- kbExpr: EditorContextKeys.editorTextFocus,
- primary: 2048 /* KeyMod.CtrlCmd */ | 1024 /* KeyMod.Shift */ | 3 /* KeyCode.Enter */,
- weight: 100 /* KeybindingWeight.EditorContrib */
- }
- });
- }
- run(_accessor, editor) {
- const viewModel = editor._getViewModel();
- if (!viewModel) {
- return;
- }
- editor.pushUndoStop();
- editor.executeCommands(this.id, TypeOperations.lineInsertBefore(viewModel.cursorConfig, editor.getModel(), editor.getSelections()));
- }
- }
- export class InsertLineAfterAction extends EditorAction {
- constructor() {
- super({
- id: 'editor.action.insertLineAfter',
- label: nls.localize('lines.insertAfter', "Insert Line Below"),
- alias: 'Insert Line Below',
- precondition: EditorContextKeys.writable,
- kbOpts: {
- kbExpr: EditorContextKeys.editorTextFocus,
- primary: 2048 /* KeyMod.CtrlCmd */ | 3 /* KeyCode.Enter */,
- weight: 100 /* KeybindingWeight.EditorContrib */
- }
- });
- }
- run(_accessor, editor) {
- const viewModel = editor._getViewModel();
- if (!viewModel) {
- return;
- }
- editor.pushUndoStop();
- editor.executeCommands(this.id, TypeOperations.lineInsertAfter(viewModel.cursorConfig, editor.getModel(), editor.getSelections()));
- }
- }
- export class AbstractDeleteAllToBoundaryAction extends EditorAction {
- run(_accessor, editor) {
- if (!editor.hasModel()) {
- return;
- }
- const primaryCursor = editor.getSelection();
- const rangesToDelete = this._getRangesToDelete(editor);
- // merge overlapping selections
- const effectiveRanges = [];
- for (let i = 0, count = rangesToDelete.length - 1; i < count; i++) {
- const range = rangesToDelete[i];
- const nextRange = rangesToDelete[i + 1];
- if (Range.intersectRanges(range, nextRange) === null) {
- effectiveRanges.push(range);
- }
- else {
- rangesToDelete[i + 1] = Range.plusRange(range, nextRange);
- }
- }
- effectiveRanges.push(rangesToDelete[rangesToDelete.length - 1]);
- const endCursorState = this._getEndCursorState(primaryCursor, effectiveRanges);
- const edits = effectiveRanges.map(range => {
- return EditOperation.replace(range, '');
- });
- editor.pushUndoStop();
- editor.executeEdits(this.id, edits, endCursorState);
- editor.pushUndoStop();
- }
- }
- 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.textInputFocus,
- primary: 0,
- mac: { primary: 2048 /* KeyMod.CtrlCmd */ | 1 /* KeyCode.Backspace */ },
- weight: 100 /* KeybindingWeight.EditorContrib */
- }
- });
- }
- _getEndCursorState(primaryCursor, rangesToDelete) {
- let endPrimaryCursor = null;
- const endCursorState = [];
- let deletedLines = 0;
- rangesToDelete.forEach(range => {
- let endCursor;
- if (range.endColumn === 1 && deletedLines > 0) {
- const newStartLine = range.startLineNumber - deletedLines;
- endCursor = new Selection(newStartLine, range.startColumn, newStartLine, range.startColumn);
- }
- else {
- endCursor = new Selection(range.startLineNumber, range.startColumn, range.startLineNumber, range.startColumn);
- }
- deletedLines += range.endLineNumber - range.startLineNumber;
- if (range.intersectRanges(primaryCursor)) {
- endPrimaryCursor = endCursor;
- }
- else {
- endCursorState.push(endCursor);
- }
- });
- if (endPrimaryCursor) {
- endCursorState.unshift(endPrimaryCursor);
- }
- return endCursorState;
- }
- _getRangesToDelete(editor) {
- const selections = editor.getSelections();
- if (selections === null) {
- return [];
- }
- let rangesToDelete = selections;
- const model = editor.getModel();
- if (model === null) {
- return [];
- }
- rangesToDelete.sort(Range.compareRangesUsingStarts);
- rangesToDelete = rangesToDelete.map(selection => {
- if (selection.isEmpty()) {
- if (selection.startColumn === 1) {
- const deleteFromLine = Math.max(1, selection.startLineNumber - 1);
- const deleteFromColumn = selection.startLineNumber === 1 ? 1 : model.getLineContent(deleteFromLine).length + 1;
- return new Range(deleteFromLine, deleteFromColumn, selection.startLineNumber, 1);
- }
- else {
- return new Range(selection.startLineNumber, 1, selection.startLineNumber, selection.startColumn);
- }
- }
- else {
- return new Range(selection.startLineNumber, 1, selection.endLineNumber, selection.endColumn);
- }
- });
- return rangesToDelete;
- }
- }
- 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.textInputFocus,
- primary: 0,
- mac: { primary: 256 /* KeyMod.WinCtrl */ | 41 /* KeyCode.KeyK */, secondary: [2048 /* KeyMod.CtrlCmd */ | 20 /* KeyCode.Delete */] },
- weight: 100 /* KeybindingWeight.EditorContrib */
- }
- });
- }
- _getEndCursorState(primaryCursor, rangesToDelete) {
- let endPrimaryCursor = null;
- const endCursorState = [];
- for (let i = 0, len = rangesToDelete.length, offset = 0; i < len; i++) {
- const range = rangesToDelete[i];
- const 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) {
- const model = editor.getModel();
- if (model === null) {
- return [];
- }
- const selections = editor.getSelections();
- if (selections === null) {
- return [];
- }
- const rangesToDelete = selections.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;
- }
- }
- export class JoinLinesAction extends EditorAction {
- constructor() {
- super({
- id: 'editor.action.joinLines',
- label: nls.localize('lines.joinLines', "Join Lines"),
- alias: 'Join Lines',
- precondition: EditorContextKeys.writable,
- kbOpts: {
- kbExpr: EditorContextKeys.editorTextFocus,
- primary: 0,
- mac: { primary: 256 /* KeyMod.WinCtrl */ | 40 /* KeyCode.KeyJ */ },
- weight: 100 /* KeybindingWeight.EditorContrib */
- }
- });
- }
- run(_accessor, editor) {
- const selections = editor.getSelections();
- if (selections === null) {
- return;
- }
- let primaryCursor = editor.getSelection();
- if (primaryCursor === null) {
- return;
- }
- selections.sort(Range.compareRangesUsingStarts);
- const reducedSelections = [];
- const lastSelection = selections.reduce((previousValue, currentValue) => {
- if (previousValue.isEmpty()) {
- if (previousValue.endLineNumber === currentValue.startLineNumber) {
- if (primaryCursor.equalsSelection(previousValue)) {
- primaryCursor = currentValue;
- }
- return currentValue;
- }
- if (currentValue.startLineNumber > previousValue.endLineNumber + 1) {
- reducedSelections.push(previousValue);
- return currentValue;
- }
- else {
- return new Selection(previousValue.startLineNumber, previousValue.startColumn, currentValue.endLineNumber, currentValue.endColumn);
- }
- }
- else {
- if (currentValue.startLineNumber > previousValue.endLineNumber) {
- reducedSelections.push(previousValue);
- return currentValue;
- }
- else {
- return new Selection(previousValue.startLineNumber, previousValue.startColumn, currentValue.endLineNumber, currentValue.endColumn);
- }
- }
- });
- reducedSelections.push(lastSelection);
- const model = editor.getModel();
- if (model === null) {
- return;
- }
- const edits = [];
- const endCursorState = [];
- let endPrimaryCursor = primaryCursor;
- let lineOffset = 0;
- for (let i = 0, len = reducedSelections.length; i < len; i++) {
- const selection = reducedSelections[i];
- const startLineNumber = selection.startLineNumber;
- const startColumn = 1;
- let columnDeltaOffset = 0;
- let endLineNumber, endColumn;
- const selectionEndPositionOffset = model.getLineContent(selection.endLineNumber).length - selection.endColumn;
- if (selection.isEmpty() || selection.startLineNumber === selection.endLineNumber) {
- const position = selection.getStartPosition();
- if (position.lineNumber < model.getLineCount()) {
- endLineNumber = startLineNumber + 1;
- endColumn = model.getLineMaxColumn(endLineNumber);
- }
- else {
- endLineNumber = position.lineNumber;
- endColumn = model.getLineMaxColumn(position.lineNumber);
- }
- }
- else {
- endLineNumber = selection.endLineNumber;
- endColumn = model.getLineMaxColumn(endLineNumber);
- }
- let trimmedLinesContent = model.getLineContent(startLineNumber);
- for (let i = startLineNumber + 1; i <= endLineNumber; i++) {
- const lineText = model.getLineContent(i);
- const firstNonWhitespaceIdx = model.getLineFirstNonWhitespaceColumn(i);
- if (firstNonWhitespaceIdx >= 1) {
- let insertSpace = true;
- if (trimmedLinesContent === '') {
- insertSpace = false;
- }
- if (insertSpace && (trimmedLinesContent.charAt(trimmedLinesContent.length - 1) === ' ' ||
- trimmedLinesContent.charAt(trimmedLinesContent.length - 1) === '\t')) {
- insertSpace = false;
- trimmedLinesContent = trimmedLinesContent.replace(/[\s\uFEFF\xA0]+$/g, ' ');
- }
- const lineTextWithoutIndent = lineText.substr(firstNonWhitespaceIdx - 1);
- trimmedLinesContent += (insertSpace ? ' ' : '') + lineTextWithoutIndent;
- if (insertSpace) {
- columnDeltaOffset = lineTextWithoutIndent.length + 1;
- }
- else {
- columnDeltaOffset = lineTextWithoutIndent.length;
- }
- }
- else {
- columnDeltaOffset = 0;
- }
- }
- const deleteSelection = new Range(startLineNumber, startColumn, endLineNumber, endColumn);
- if (!deleteSelection.isEmpty()) {
- let resultSelection;
- if (selection.isEmpty()) {
- edits.push(EditOperation.replace(deleteSelection, trimmedLinesContent));
- resultSelection = new Selection(deleteSelection.startLineNumber - lineOffset, trimmedLinesContent.length - columnDeltaOffset + 1, startLineNumber - lineOffset, trimmedLinesContent.length - columnDeltaOffset + 1);
- }
- else {
- if (selection.startLineNumber === selection.endLineNumber) {
- edits.push(EditOperation.replace(deleteSelection, trimmedLinesContent));
- resultSelection = new Selection(selection.startLineNumber - lineOffset, selection.startColumn, selection.endLineNumber - lineOffset, selection.endColumn);
- }
- else {
- edits.push(EditOperation.replace(deleteSelection, trimmedLinesContent));
- resultSelection = new Selection(selection.startLineNumber - lineOffset, selection.startColumn, selection.startLineNumber - lineOffset, trimmedLinesContent.length - selectionEndPositionOffset);
- }
- }
- if (Range.intersectRanges(deleteSelection, primaryCursor) !== null) {
- endPrimaryCursor = resultSelection;
- }
- else {
- endCursorState.push(resultSelection);
- }
- }
- lineOffset += deleteSelection.endLineNumber - deleteSelection.startLineNumber;
- }
- endCursorState.unshift(endPrimaryCursor);
- editor.pushUndoStop();
- editor.executeEdits(this.id, edits, endCursorState);
- editor.pushUndoStop();
- }
- }
- export class TransposeAction extends EditorAction {
- constructor() {
- super({
- id: 'editor.action.transpose',
- label: nls.localize('editor.transpose', "Transpose characters around the cursor"),
- alias: 'Transpose characters around the cursor',
- precondition: EditorContextKeys.writable
- });
- }
- run(_accessor, editor) {
- const selections = editor.getSelections();
- if (selections === null) {
- return;
- }
- const model = editor.getModel();
- if (model === null) {
- return;
- }
- const commands = [];
- for (let i = 0, len = selections.length; i < len; i++) {
- const selection = selections[i];
- if (!selection.isEmpty()) {
- continue;
- }
- const cursor = selection.getStartPosition();
- const maxColumn = model.getLineMaxColumn(cursor.lineNumber);
- if (cursor.column >= maxColumn) {
- if (cursor.lineNumber === model.getLineCount()) {
- continue;
- }
- // The cursor is at the end of current line and current line is not empty
- // then we transpose the character before the cursor and the line break if there is any following line.
- const deleteSelection = new Range(cursor.lineNumber, Math.max(1, cursor.column - 1), cursor.lineNumber + 1, 1);
- const chars = model.getValueInRange(deleteSelection).split('').reverse().join('');
- commands.push(new ReplaceCommand(new Selection(cursor.lineNumber, Math.max(1, cursor.column - 1), cursor.lineNumber + 1, 1), chars));
- }
- else {
- const deleteSelection = new Range(cursor.lineNumber, Math.max(1, cursor.column - 1), cursor.lineNumber, cursor.column + 1);
- const chars = model.getValueInRange(deleteSelection).split('').reverse().join('');
- commands.push(new ReplaceCommandThatPreservesSelection(deleteSelection, chars, new Selection(cursor.lineNumber, cursor.column + 1, cursor.lineNumber, cursor.column + 1)));
- }
- }
- editor.pushUndoStop();
- editor.executeCommands(this.id, commands);
- editor.pushUndoStop();
- }
- }
- export class AbstractCaseAction extends EditorAction {
- run(_accessor, editor) {
- const selections = editor.getSelections();
- if (selections === null) {
- return;
- }
- const model = editor.getModel();
- if (model === null) {
- return;
- }
- const wordSeparators = editor.getOption(119 /* EditorOption.wordSeparators */);
- const textEdits = [];
- for (const selection of selections) {
- if (selection.isEmpty()) {
- const cursor = selection.getStartPosition();
- const word = editor.getConfiguredWordAtPosition(cursor);
- if (!word) {
- continue;
- }
- const wordRange = new Range(cursor.lineNumber, word.startColumn, cursor.lineNumber, word.endColumn);
- const text = model.getValueInRange(wordRange);
- textEdits.push(EditOperation.replace(wordRange, this._modifyText(text, wordSeparators)));
- }
- else {
- const text = model.getValueInRange(selection);
- textEdits.push(EditOperation.replace(selection, this._modifyText(text, wordSeparators)));
- }
- }
- editor.pushUndoStop();
- editor.executeEdits(this.id, textEdits);
- editor.pushUndoStop();
- }
- }
- export class UpperCaseAction extends AbstractCaseAction {
- constructor() {
- super({
- id: 'editor.action.transformToUppercase',
- label: nls.localize('editor.transformToUppercase', "Transform to Uppercase"),
- alias: 'Transform to Uppercase',
- precondition: EditorContextKeys.writable
- });
- }
- _modifyText(text, wordSeparators) {
- return text.toLocaleUpperCase();
- }
- }
- export class LowerCaseAction extends AbstractCaseAction {
- constructor() {
- super({
- id: 'editor.action.transformToLowercase',
- label: nls.localize('editor.transformToLowercase', "Transform to Lowercase"),
- alias: 'Transform to Lowercase',
- precondition: EditorContextKeys.writable
- });
- }
- _modifyText(text, wordSeparators) {
- return text.toLocaleLowerCase();
- }
- }
- class BackwardsCompatibleRegExp {
- constructor(_pattern, _flags) {
- this._pattern = _pattern;
- this._flags = _flags;
- this._actual = null;
- this._evaluated = false;
- }
- get() {
- if (!this._evaluated) {
- this._evaluated = true;
- try {
- this._actual = new RegExp(this._pattern, this._flags);
- }
- catch (err) {
- // this browser does not support this regular expression
- }
- }
- return this._actual;
- }
- isSupported() {
- return (this.get() !== null);
- }
- }
- export class TitleCaseAction extends AbstractCaseAction {
- constructor() {
- super({
- id: 'editor.action.transformToTitlecase',
- label: nls.localize('editor.transformToTitlecase', "Transform to Title Case"),
- alias: 'Transform to Title Case',
- precondition: EditorContextKeys.writable
- });
- }
- _modifyText(text, wordSeparators) {
- const titleBoundary = TitleCaseAction.titleBoundary.get();
- if (!titleBoundary) {
- // cannot support this
- return text;
- }
- return text
- .toLocaleLowerCase()
- .replace(titleBoundary, (b) => b.toLocaleUpperCase());
- }
- }
- TitleCaseAction.titleBoundary = new BackwardsCompatibleRegExp('(^|[^\\p{L}\\p{N}\']|((^|\\P{L})\'))\\p{L}', 'gmu');
- export class SnakeCaseAction extends AbstractCaseAction {
- constructor() {
- super({
- id: 'editor.action.transformToSnakecase',
- label: nls.localize('editor.transformToSnakecase', "Transform to Snake Case"),
- alias: 'Transform to Snake Case',
- precondition: EditorContextKeys.writable
- });
- }
- _modifyText(text, wordSeparators) {
- const caseBoundary = SnakeCaseAction.caseBoundary.get();
- const singleLetters = SnakeCaseAction.singleLetters.get();
- if (!caseBoundary || !singleLetters) {
- // cannot support this
- return text;
- }
- return (text
- .replace(caseBoundary, '$1_$2')
- .replace(singleLetters, '$1_$2$3')
- .toLocaleLowerCase());
- }
- }
- SnakeCaseAction.caseBoundary = new BackwardsCompatibleRegExp('(\\p{Ll})(\\p{Lu})', 'gmu');
- SnakeCaseAction.singleLetters = new BackwardsCompatibleRegExp('(\\p{Lu}|\\p{N})(\\p{Lu})(\\p{Ll})', 'gmu');
- export class KebabCaseAction extends AbstractCaseAction {
- constructor() {
- super({
- id: 'editor.action.transformToKebabcase',
- label: nls.localize('editor.transformToKebabcase', 'Transform to Kebab Case'),
- alias: 'Transform to Kebab Case',
- precondition: EditorContextKeys.writable
- });
- }
- static isSupported() {
- const areAllRegexpsSupported = [
- this.caseBoundary,
- this.singleLetters,
- this.underscoreBoundary,
- ].every((regexp) => regexp.isSupported());
- return areAllRegexpsSupported;
- }
- _modifyText(text, _) {
- const caseBoundary = KebabCaseAction.caseBoundary.get();
- const singleLetters = KebabCaseAction.singleLetters.get();
- const underscoreBoundary = KebabCaseAction.underscoreBoundary.get();
- if (!caseBoundary || !singleLetters || !underscoreBoundary) {
- // one or more regexps aren't supported
- return text;
- }
- return text
- .replace(underscoreBoundary, '$1-$3')
- .replace(caseBoundary, '$1-$2')
- .replace(singleLetters, '$1-$2')
- .toLocaleLowerCase();
- }
- }
- KebabCaseAction.caseBoundary = new BackwardsCompatibleRegExp('(\\p{Ll})(\\p{Lu})', 'gmu');
- KebabCaseAction.singleLetters = new BackwardsCompatibleRegExp('(\\p{Lu}|\\p{N})(\\p{Lu}\\p{Ll})', 'gmu');
- KebabCaseAction.underscoreBoundary = new BackwardsCompatibleRegExp('(\\S)(_)(\\S)', 'gm');
- registerEditorAction(CopyLinesUpAction);
- registerEditorAction(CopyLinesDownAction);
- registerEditorAction(DuplicateSelectionAction);
- registerEditorAction(MoveLinesUpAction);
- registerEditorAction(MoveLinesDownAction);
- registerEditorAction(SortLinesAscendingAction);
- registerEditorAction(SortLinesDescendingAction);
- registerEditorAction(DeleteDuplicateLinesAction);
- registerEditorAction(TrimTrailingWhitespaceAction);
- registerEditorAction(DeleteLinesAction);
- registerEditorAction(IndentLinesAction);
- registerEditorAction(OutdentLinesAction);
- registerEditorAction(InsertLineBeforeAction);
- registerEditorAction(InsertLineAfterAction);
- registerEditorAction(DeleteAllLeftAction);
- registerEditorAction(DeleteAllRightAction);
- registerEditorAction(JoinLinesAction);
- registerEditorAction(TransposeAction);
- registerEditorAction(UpperCaseAction);
- registerEditorAction(LowerCaseAction);
- if (SnakeCaseAction.caseBoundary.isSupported() && SnakeCaseAction.singleLetters.isSupported()) {
- registerEditorAction(SnakeCaseAction);
- }
- if (TitleCaseAction.titleBoundary.isSupported()) {
- registerEditorAction(TitleCaseAction);
- }
- if (KebabCaseAction.isSupported()) {
- registerEditorAction(KebabCaseAction);
- }
|