Path: blob/main/src/vs/editor/contrib/comment/browser/comment.ts
5241 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { KeyChord, KeyCode, KeyMod } from '../../../../base/common/keyCodes.js';6import * as nls from '../../../../nls.js';7import { MenuId } from '../../../../platform/actions/common/actions.js';8import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';9import { ICodeEditor } from '../../../browser/editorBrowser.js';10import { EditorAction, IActionOptions, registerEditorAction, ServicesAccessor } from '../../../browser/editorExtensions.js';11import { EditorOption } from '../../../common/config/editorOptions.js';12import { Range } from '../../../common/core/range.js';13import { ICommand } from '../../../common/editorCommon.js';14import { EditorContextKeys } from '../../../common/editorContextKeys.js';15import { ILanguageConfigurationService } from '../../../common/languages/languageConfigurationRegistry.js';16import { BlockCommentCommand } from './blockCommentCommand.js';17import { LineCommentCommand, Type } from './lineCommentCommand.js';1819abstract class CommentLineAction extends EditorAction {2021private readonly _type: Type;2223constructor(type: Type, opts: IActionOptions) {24super(opts);25this._type = type;26}2728public run(accessor: ServicesAccessor, editor: ICodeEditor): void {29const languageConfigurationService = accessor.get(ILanguageConfigurationService);3031if (!editor.hasModel()) {32return;33}3435const model = editor.getModel();36const commands: ICommand[] = [];37const modelOptions = model.getOptions();38const commentsOptions = editor.getOption(EditorOption.comments);3940const selections = editor.getSelections().map((selection, index) => ({ selection, index, ignoreFirstLine: false }));41selections.sort((a, b) => Range.compareRangesUsingStarts(a.selection, b.selection));4243// Remove selections that would result in copying the same line44let prev = selections[0];45for (let i = 1; i < selections.length; i++) {46const curr = selections[i];47if (prev.selection.endLineNumber === curr.selection.startLineNumber) {48// these two selections would copy the same line49if (prev.index < curr.index) {50// prev wins51curr.ignoreFirstLine = true;52} else {53// curr wins54prev.ignoreFirstLine = true;55prev = curr;56}57}58}596061for (const selection of selections) {62commands.push(new LineCommentCommand(63languageConfigurationService,64selection.selection,65modelOptions.indentSize,66this._type,67commentsOptions.insertSpace,68commentsOptions.ignoreEmptyLines,69selection.ignoreFirstLine70));71}7273editor.pushUndoStop();74editor.executeCommands(this.id, commands);75editor.pushUndoStop();76}7778}7980class ToggleCommentLineAction extends CommentLineAction {81constructor() {82super(Type.Toggle, {83id: 'editor.action.commentLine',84label: nls.localize2('comment.line', "Toggle Line Comment"),85precondition: EditorContextKeys.writable,86kbOpts: {87kbExpr: EditorContextKeys.editorTextFocus,88primary: KeyMod.CtrlCmd | KeyCode.Slash,89weight: KeybindingWeight.EditorContrib90},91menuOpts: {92menuId: MenuId.MenubarEditMenu,93group: '5_insert',94title: nls.localize({ key: 'miToggleLineComment', comment: ['&& denotes a mnemonic'] }, "&&Toggle Line Comment"),95order: 196},97canTriggerInlineEdits: true,98});99}100}101102class AddLineCommentAction extends CommentLineAction {103constructor() {104super(Type.ForceAdd, {105id: 'editor.action.addCommentLine',106label: nls.localize2('comment.line.add', "Add Line Comment"),107precondition: EditorContextKeys.writable,108kbOpts: {109kbExpr: EditorContextKeys.editorTextFocus,110primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyC),111weight: KeybindingWeight.EditorContrib112},113canTriggerInlineEdits: true,114});115}116}117118class RemoveLineCommentAction extends CommentLineAction {119constructor() {120super(Type.ForceRemove, {121id: 'editor.action.removeCommentLine',122label: nls.localize2('comment.line.remove', "Remove Line Comment"),123precondition: EditorContextKeys.writable,124kbOpts: {125kbExpr: EditorContextKeys.editorTextFocus,126primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyU),127weight: KeybindingWeight.EditorContrib128},129canTriggerInlineEdits: true,130});131}132}133134class BlockCommentAction extends EditorAction {135136constructor() {137super({138id: 'editor.action.blockComment',139label: nls.localize2('comment.block', "Toggle Block Comment"),140precondition: EditorContextKeys.writable,141kbOpts: {142kbExpr: EditorContextKeys.editorTextFocus,143primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KeyA,144linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyA },145weight: KeybindingWeight.EditorContrib146},147menuOpts: {148menuId: MenuId.MenubarEditMenu,149group: '5_insert',150title: nls.localize({ key: 'miToggleBlockComment', comment: ['&& denotes a mnemonic'] }, "Toggle &&Block Comment"),151order: 2152},153canTriggerInlineEdits: true,154});155}156157public run(accessor: ServicesAccessor, editor: ICodeEditor): void {158const languageConfigurationService = accessor.get(ILanguageConfigurationService);159160if (!editor.hasModel()) {161return;162}163164const commentsOptions = editor.getOption(EditorOption.comments);165const commands: ICommand[] = [];166const selections = editor.getSelections();167for (const selection of selections) {168commands.push(new BlockCommentCommand(selection, commentsOptions.insertSpace, languageConfigurationService));169}170171editor.pushUndoStop();172editor.executeCommands(this.id, commands);173editor.pushUndoStop();174}175}176177registerEditorAction(ToggleCommentLineAction);178registerEditorAction(AddLineCommentAction);179registerEditorAction(RemoveLineCommentAction);180registerEditorAction(BlockCommentAction);181182183