diff --git a/README.md b/README.md index 82bfbcd50e1..3ef058d0aa9 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ VSCodeVim is a [Visual Studio Code](https://code.visualstudio.com/) extension th * Multi-cursor support. Allows multiple simultaneous cursors to receive Vim commands (e.g. allows `/` search, each cursor has independent clipboards, etc.). * The [EasyMotion plugin](#how-to-use-easymotion)! * The [Surround.vim plugin](#how-to-use-surround)! +* The [Commentary plugin](#how-to-use-commentary). * And much more! Refer to the [roadmap](ROADMAP.md) or everything we support. Please [report missing features/bugs on GitHub](https://github.com/VSCodeVim/Vim/issues), which will help us get to them faster. @@ -329,6 +330,31 @@ Some examples: * `"test"` with cursor inside quotes type cs"t and enter 123> to end up with `<123>test` * `test` with cursor on word test type ysaw) to end up with `(test)` +#### How to use commentary + +Commentary in VSCodeVim works similarly to tpope's [vim-commentary] (https://github.com/tpope/vim-commentary) but uses the VSCode native "Toggle Line Comment" and "Toggle Block Comment" features. + +Because `gc` is already used in VSCodeVim the commentary operators are bound to `gb` for line comments and `gB` for block comments. + +Usage examples: +* `gb` - toggles line comment. For example `gbb` to toggle line comment for current line and `gb2j` to toggle line comments for the current line and the next line. +* `gB` - toggles block comment. For example `gBi)` to comment out everything within parenthesis. + +If you are use to using vim-commentary you are probably use to using `gc` instead of `gb`. This can be achieved by adding the following remapping to your VSCode settings: + +``` +"vim.otherModesKeyBindings": [ + { + "before": ["g", "c"], + "after": ["g", "b"] + }, + { + "before": ["g", "C"], + "after": ["g", "B"] + } +], +``` + ## Contributing This project is maintained by a group of awesome [people](https://github.com/VSCodeVim/Vim/graphs/contributors) and contributions are extremely welcome :heart:. For a quick tutorial on how you can help, see our [contributing guide](/.github/CONTRIBUTING.md). diff --git a/src/actions/actions.ts b/src/actions/actions.ts index 9cf34aa8aa2..3cb9d3e5595 100644 --- a/src/actions/actions.ts +++ b/src/actions/actions.ts @@ -7110,3 +7110,37 @@ class CommandSurroundAddToReplacement extends BaseCommand { return false; } } + +@RegisterAction +export class CommentOperator extends BaseOperator { + public keys = ["g", "b"]; + public modes = [ModeName.Normal, ModeName.Visual, ModeName.VisualLine]; + + public async run(vimState: VimState, start: Position, end: Position): Promise { + vimState.editor.selection = new vscode.Selection(start.getLineBegin(), end.getLineEnd()); + await vscode.commands.executeCommand("editor.action.commentLine"); + + vimState.cursorPosition = new Position(start.line, 0); + vimState.currentMode = ModeName.Normal; + + return vimState; + } +} + +@RegisterAction +export class CommentBlockOperator extends BaseOperator { + public keys = ["g", "B"]; + public modes = [ModeName.Normal, ModeName.Visual, ModeName.VisualLine]; + + public async run(vimState: VimState, start: Position, end: Position): Promise { + const endPosition = vimState.currentMode === ModeName.Normal ? end.getRight() : end; + vimState.editor.selection = new vscode.Selection(start, endPosition); + await vscode.commands.executeCommand("editor.action.blockComment"); + + vimState.cursorPosition = start; + vimState.currentMode = ModeName.Normal; + + return vimState; + } + +} \ No newline at end of file diff --git a/test/mode/modeHandler.test.ts b/test/mode/modeHandler.test.ts index 4673ff5e254..eedb608ed78 100644 --- a/test/mode/modeHandler.test.ts +++ b/test/mode/modeHandler.test.ts @@ -7,7 +7,9 @@ import { ModeHandler } from '../../src/mode/modeHandler'; suite("Mode Handler", () => { - setup(setupWorkspace); + setup(async () => { + await setupWorkspace(); + }); teardown(cleanUpWorkspace); diff --git a/test/operator/comment.test.ts b/test/operator/comment.test.ts new file mode 100644 index 00000000000..83353632f76 --- /dev/null +++ b/test/operator/comment.test.ts @@ -0,0 +1,74 @@ +"use strict"; + +import { setupWorkspace, setTextEditorOptions, cleanUpWorkspace } from './../testUtils'; +import { ModeName } from '../../src/mode/mode'; +import { ModeHandler } from '../../src/mode/modeHandler'; +import { getTestingFunctions } from '../testSimplifier'; + +suite("comment operator", () => { + let modeHandler: ModeHandler; + let { + newTest, + newTestOnly, + } = getTestingFunctions(); + + setup(async () => { + await setupWorkspace(".js"); + setTextEditorOptions(4, false); + modeHandler = new ModeHandler(); + }); + + teardown(cleanUpWorkspace); + + newTest({ + title: "gbb comments out current line", + start: [ + "first| line", + "second line" + ], + keysPressed: 'gbb', + end: [ + "|// first line", + "second line", + ], + }); + + newTest({ + title: "gbj comments in current and next line", + start: [ + "// first| line", + "// second line", + "third line" + ], + keysPressed: 'gbj', + end: [ + "|first line", + "second line", + "third line" + ], + }); + + newTest({ + title: "block comment with motion", + start: [ + "function myTestFunction(arg|1, arg2, arg3) {" + ], + keysPressed: 'gBi)', + end: [ + "function myTestFunction(|/*arg1, arg2, arg3*/) {" + ] + }); + + newTest({ + title: "block comment in Visual Mode", + start: [ + "blah |blah blah" + ], + keysPressed: 'vllllgB', + end: [ + "blah |/*blah*/ blah" + ], + endMode: ModeName.Normal + }); + +}); \ No newline at end of file diff --git a/test/testUtils.ts b/test/testUtils.ts index 34b4c708602..bbf7b2c34b8 100644 --- a/test/testUtils.ts +++ b/test/testUtils.ts @@ -12,8 +12,8 @@ function rndName() { return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 10); } -async function createRandomFile(contents: string): Promise { - const tmpFile = join(os.tmpdir(), rndName()); +async function createRandomFile(contents: string, fileExtension: string): Promise { + const tmpFile = join(os.tmpdir(), rndName() + fileExtension); try { fs.writeFileSync(tmpFile, contents); @@ -41,8 +41,8 @@ export function assertEqual(one: T, two: T, message: string = ""): void { assert.equal(one, two, message); } -export async function setupWorkspace(): Promise { - const file = await createRandomFile(""); +export async function setupWorkspace(fileExtension: string = ""): Promise { + const file = await createRandomFile("", fileExtension); const doc = await vscode.workspace.openTextDocument(file); await vscode.window.showTextDocument(doc); diff --git a/test/textEditor.test.ts b/test/textEditor.test.ts index b38ef3b95f7..c5ab1c87d48 100644 --- a/test/textEditor.test.ts +++ b/test/textEditor.test.ts @@ -6,7 +6,9 @@ import { TextEditor } from './../src/textEditor'; import { setupWorkspace, cleanUpWorkspace } from './testUtils'; suite("text editor", () => { - suiteSetup(setupWorkspace); + suiteSetup(async () => { + await setupWorkspace(); + }); suiteTeardown(cleanUpWorkspace);