Path: blob/main/src/vs/editor/contrib/comment/browser/comment.ts
3296 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 { ICodeEditor } from '../../../browser/editorBrowser.js';7import { EditorAction, IActionOptions, registerEditorAction, ServicesAccessor } from '../../../browser/editorExtensions.js';8import { EditorOption } from '../../../common/config/editorOptions.js';9import { Range } from '../../../common/core/range.js';10import { ICommand } from '../../../common/editorCommon.js';11import { EditorContextKeys } from '../../../common/editorContextKeys.js';12import { ILanguageConfigurationService } from '../../../common/languages/languageConfigurationRegistry.js';13import { BlockCommentCommand } from './blockCommentCommand.js';14import { LineCommentCommand, Type } from './lineCommentCommand.js';15import * as nls from '../../../../nls.js';16import { MenuId } from '../../../../platform/actions/common/actions.js';17import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.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}97});98}99}100101class AddLineCommentAction extends CommentLineAction {102constructor() {103super(Type.ForceAdd, {104id: 'editor.action.addCommentLine',105label: nls.localize2('comment.line.add', "Add Line Comment"),106precondition: EditorContextKeys.writable,107kbOpts: {108kbExpr: EditorContextKeys.editorTextFocus,109primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyC),110weight: KeybindingWeight.EditorContrib111}112});113}114}115116class RemoveLineCommentAction extends CommentLineAction {117constructor() {118super(Type.ForceRemove, {119id: 'editor.action.removeCommentLine',120label: nls.localize2('comment.line.remove', "Remove Line Comment"),121precondition: EditorContextKeys.writable,122kbOpts: {123kbExpr: EditorContextKeys.editorTextFocus,124primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyU),125weight: KeybindingWeight.EditorContrib126}127});128}129}130131class BlockCommentAction extends EditorAction {132133constructor() {134super({135id: 'editor.action.blockComment',136label: nls.localize2('comment.block', "Toggle Block Comment"),137precondition: EditorContextKeys.writable,138kbOpts: {139kbExpr: EditorContextKeys.editorTextFocus,140primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KeyA,141linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyA },142weight: KeybindingWeight.EditorContrib143},144menuOpts: {145menuId: MenuId.MenubarEditMenu,146group: '5_insert',147title: nls.localize({ key: 'miToggleBlockComment', comment: ['&& denotes a mnemonic'] }, "Toggle &&Block Comment"),148order: 2149}150});151}152153public run(accessor: ServicesAccessor, editor: ICodeEditor): void {154const languageConfigurationService = accessor.get(ILanguageConfigurationService);155156if (!editor.hasModel()) {157return;158}159160const commentsOptions = editor.getOption(EditorOption.comments);161const commands: ICommand[] = [];162const selections = editor.getSelections();163for (const selection of selections) {164commands.push(new BlockCommentCommand(selection, commentsOptions.insertSpace, languageConfigurationService));165}166167editor.pushUndoStop();168editor.executeCommands(this.id, commands);169editor.pushUndoStop();170}171}172173registerEditorAction(ToggleCommentLineAction);174registerEditorAction(AddLineCommentAction);175registerEditorAction(RemoveLineCommentAction);176registerEditorAction(BlockCommentAction);177178179