Repository: terrortylor/nvim-comment Branch: main Commit: e9ac16ab0566 Files: 10 Total size: 35.3 KB Directory structure: gitextract_xu0egi6i/ ├── .github/ │ └── workflows/ │ └── make.yml ├── .luacheckrc ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── lua/ │ ├── nvim_comment.lua │ └── spec/ │ └── nvim_comment_spec.lua └── tests/ ├── comment_spec.lua └── minimal_init.vim ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/make.yml ================================================ name: Run Tests on: [push, pull_request] jobs: Tests: name: Linting and Test runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - name: Prepare run: | # sudo apt-get update sudo apt-get install lua-check mkdir -p ~/.local/share/nvim/site/pack/vendor/start git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary.nvim ln -s $(pwd) ~/.local/share/nvim/site/pack/vendor/start mkdir -p build wget https://github.com/neovim/neovim/releases/download/nightly/nvim.appimage chmod +x nvim.appimage mv nvim.appimage ./build/nvim - name: Run Lint run: make lint - name: Run unit tests run: | export PATH="${PWD}/build/:${PATH}" make unit echo "exit code $?" - name: Run tests run: | export PATH="${PWD}/build/:${PATH}" make gh-integration echo "exit code $?" ================================================ FILE: .luacheckrc ================================================ globals = {"Snake", "Cell", "vim", "_TEST", "LOG_LEVEL"} read_globals = { print = { fields = { revert = {} } }, os = { fields = { execute = { fields = { revert = {} } }, } } } ================================================ FILE: CHANGELOG.md ================================================ Changelog ====================== 2021-07-10 - Add hook function to be called before reading `commentstring` 2021-02-16 - Fix issue with `gv` causing entire buffer range to be acted on 2021-02-12 - Fix issue with motion acting on last visual selection ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2021 Alex Tylor Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Makefile ================================================ all: lint test lint: @echo "Linting..." luacheck --no-color . @echo unit: @echo "Run unit tests..." nvim --headless --noplugin -c 'packadd plenary.nvim' -c "PlenaryBustedDirectory lua/spec" @echo gh-integration: @echo "Run integration tests..." nvim --headless --noplugin -u tests/minimal_init.vim -c "PlenaryBustedDirectory tests { minimal_init = './tests/minimal_init.vim' }" @echo integration: @echo "Run integration tests..." nvim --headless --noplugin -c 'packadd plenary.nvim' -c "PlenaryBustedDirectory tests" @echo test: unit integration ================================================ FILE: README.md ================================================ # nvim-comment Toggle comments in Neovim, using built in `commentstring` filetype option; written in Lua. Without a doubt this plugin **is not required** and is a rip off of [TPope's Commentary](https://github.com/tpope/vim-commentary) with less features! What makes this plugin stand out over the numerous other comment plugins written in Lua are: - Comments each line, rather than adds block comments; making it easier to toggle code when debugging - Uses the built in `commentstring` buffer option to define comment markers - Where a marker doesn't have a **space** character as padding this is added, configurable (this can be disabled in the options, see below but is useful when working with numerous linters) - Supports motions - Dot `.` repeatable When the plugin is called it works out the range to comment/uncomment; if all lines in the given range are commented then it uncomments, otherwise it comments the range. This is useful when commenting a block out for testing with a real like comment in it; as for the plugin a comment is a comment. ## Usage Either use the command `CommentToggle`, e.g.: - `CommentToggle` comment/uncomment current line - `67,69CommentToggle` comment/uncomment a range - `'<,'>CommentToggle` comment/uncomment a visual selection Or use the default mappings: - `gcc` comment/uncomment current line, this does not take a count, if you want a count use the `gc{count}{motion}` - `gc{motion}` comment/uncomment selection defined by a motion (as lines are commented, any comment toggling actions will default to a linewise): - `gcip` comment/uncomment a paragraph - `gc4w` comment/uncomment current line - `gc4j` comment/uncomment 4 lines below the current line - `dic` delete comment block - `gcic` uncomment commented block ### Configure The comment plugin needs to be initialised using: ```lua require('nvim_comment').setup() ``` However you can pass in some config options, the defaults are: ```lua { -- Linters prefer comment and line to have a space in between markers marker_padding = true, -- should comment out empty or whitespace only lines comment_empty = true, -- trim empty comment whitespace comment_empty_trim_whitespace = true, -- Should key mappings be created create_mappings = true, -- Normal mode mapping left hand side line_mapping = "gcc", -- Visual/Operator mapping left hand side operator_mapping = "gc", -- text object mapping, comment chunk,, comment_chunk_text_object = "ic", -- Hook function to call before commenting takes place hook = nil } ``` - Ignore Empty Lines ```lua require('nvim_comment').setup({comment_empty = false}) ``` - Don't trim trailing comment whitespace when commenting empty line ```lua require('nvim_comment').setup({comment_empty_trim_whitespace = false}) ``` The default for this is `true`, meaning that a commented empty line will not contain any whitespace. Most `commentstring` comment prefixes have some whitespace padding, disable this to keep that padding on empty lines. - Disable mappings ```lua require('nvim_comment').setup({create_mappings = false}) ``` - Custom mappings ```lua require('nvim_comment').setup({line_mapping = "cl", operator_mapping = "c", comment_chunk_text_object = "ic"}) ``` - Disable marker padding ```lua require('nvim_comment').setup({marker_padding = false}) ``` - Hook function called before reading `commentstring` You can run arbitrary function which will be called before plugin reads value of `commentstring`. This can be used to integrate with [JoosepAlviste/nvim-ts-context-commentstring](https://github.com/JoosepAlviste/nvim-ts-context-commentstring): ```lua require('nvim_comment').setup({ hook = function() if vim.api.nvim_buf_get_option(0, "filetype") == "vue" then require("ts_context_commentstring.internal").update_commentstring() end end }) ``` - Changing/Setting `commentstring` If you want to override the comment markers or add a new filetype just set the `commentstring` options: ```lua -- Assumes this is being run in the context of the filetype... vim.api.nvim_buf_set_option(0, "commentstring", "# %s") ``` You can also use an autocommand to automatically load your `commentstring` for certain file types: ```vim " when you enter a (new) buffer augroup set-commentstring-ag autocmd! autocmd BufEnter *.cpp,*.h :lua vim.api.nvim_buf_set_option(0, "commentstring", "// %s") " when you've changed the name of a file opened in a buffer, the file type may have changed autocmd BufFilePost *.cpp,*.h :lua vim.api.nvim_buf_set_option(0, "commentstring", "// %s") augroup END ``` Or add the comment string option in the relevant `filetype` file: ```vim let commentstring="# %s" ``` ```lua vim.api.nvim_buf_set_option(0, "commentstring", "# %s") ``` ## Installation Install just as you would a normal plugin, here are some options: ### Built in package manager ```bash mkdir -p ~/.local/share/nvim/site/pack/plugins/start cd ~/.local/share/nvim/site/pack/plugins/start git clone https://github.com/terrortylor/nvim-comment ``` ### Via a plugin manager Using [packer.nvim](https://github.com/wbthomason/packer.nvim): ```lua use "terrortylor/nvim-comment" require('nvim_comment').setup() ``` ================================================ FILE: lua/nvim_comment.lua ================================================ local api = vim.api local M = {} M.config = { -- Linters prefer comment and line to have a space in between marker_padding = true, -- should comment out empty or whitespace only lines comment_empty = true, -- trim empty comment whitespace comment_empty_trim_whitespace = true, -- Should key mappings be created create_mappings = true, -- Normal mode mapping left hand side line_mapping = "gcc", -- Visual/Operator mapping left hand side operator_mapping = "gc", -- text object mapping, comment chunk comment_chunk_text_object = "ic", -- Hook function to call before commenting takes place hook = nil, } function M.get_comment_wrapper() local cs = api.nvim_buf_get_option(0, "commentstring") -- make sure comment string is understood if cs:find("%%s") then local left, right = cs:match("^(.*)%%s(.*)") if right == "" then right = nil end -- left comment markers should have padding as linterers preffer if M.config.marker_padding then if not left:match("%s$") then left = left .. " " end if right and not right:match("^%s") then right = " " .. right end end return left, right else api.nvim_command('echom "Commentstring not understood: ' .. cs .. '"') end end function M.comment_line(l, indent, left, right, comment_empty, comment_empty_trim_whitespace) if not comment_empty and l:match("^%s*$") then return l end local line_empty = l:match("^%s*$") -- standarise indentation before adding local line = l:gsub("^" .. indent, "") if right then line = line .. right end local ret_line = indent .. left .. line if comment_empty_trim_whitespace and line_empty then return ret_line:gsub("^(.*)%s+$", "%1") end return ret_line end function M.uncomment_line(l, left, right, comment_empty_trim_whitespace) local line = l if right and right ~= "" then line = line:gsub(vim.pesc(right) .. "$", "") return line:gsub(vim.pesc(left), "", 1) end if comment_empty_trim_whitespace and left:match("%s+$") then local left_nw = left:match("^(%S+)%s+$") if line:match("^%s*" .. left_nw .. "$") then return line:gsub(vim.pesc(left_nw), "", 1) end end return line:gsub(vim.pesc(left), "", 1) end function M.operator(mode) local line1, line2 if not mode then line1 = api.nvim_win_get_cursor(0)[1] line2 = line1 elseif mode:match("[vV]") then line1 = api.nvim_buf_get_mark(0, "<")[1] line2 = api.nvim_buf_get_mark(0, ">")[1] else line1 = api.nvim_buf_get_mark(0, "[")[1] line2 = api.nvim_buf_get_mark(0, "]")[1] end M.comment_toggle(line1, line2) end function M.comment_toggle(line_start, line_end) if type(M.config.hook) == "function" then M.config.hook() end local left, right = M.get_comment_wrapper() if not left or (not left and not right) then return end local lines = api.nvim_buf_get_lines(0, line_start - 1, line_end, false) if not lines then return end -- check if any lines commented, capture indent local esc_left = vim.pesc(left) if M.config.comment_empty_trim_whitespace and left:match("%s+$") then local left_nw = left:match("^(%S+)%s+$") esc_left = vim.pesc(left_nw) .. "%s*" end local commented_lines_counter = 0 local empty_counter = 0 local indent for _, v in pairs(lines) do if v:find("^%s*" .. esc_left) then commented_lines_counter = commented_lines_counter + 1 elseif v:match("^%s*$") then empty_counter = empty_counter + 1 end if not v:match("^%s*$") then local line_indent = v:match("^%s+") or "" if not indent or string.len(line_indent) < string.len(indent) then indent = line_indent end end end for i, v in pairs(lines) do if commented_lines_counter ~= (#lines - empty_counter) then lines[i] = M.comment_line( v, indent, left, right, M.config.comment_empty, M.config.comment_empty_trim_whitespace ) else lines[i] = M.uncomment_line(v, left, right, M.config.comment_empty_trim_whitespace) end end -- the LUA API doesn't seem to keep marks for lines that are changes with -- nvim_buf_set_lines api.nvim_call_function("setline", {line_start, lines}) -- The lua call seems to clear the visual selection so reset it -- 2147483647 is vimL built in api.nvim_call_function("setpos", { "'<", { 0, line_start, 1, 0 } }) api.nvim_call_function("setpos", { "'>", { 0, line_end, 2147483647, 0 } }) end function M.select_comment_chunk() vim.cmd([[execute "normal! \"]]) local up = vim.fn.search("\\v^(\\s*--)@!", "Wbcn") up = up + 1 local down = vim.fn.search("\\v^(\\s*--)@!", "Wzn") if down ~= 0 then down = down - 1 end local lines = vim.api.nvim_buf_line_count(0) local pos = vim.api.nvim_win_get_cursor(0)[1] if down == 0 then down = lines end if up <= down and up <= pos and down >= pos then vim.api.nvim_buf_set_mark(0, "<", up, 1, {}) vim.api.nvim_buf_set_mark(0, ">", down, 1, {}) vim.cmd("normal! `") end end function M.setup(user_opts) M.config = vim.tbl_extend("force", M.config, user_opts or {}) -- Messy, change with nvim_exec once merged local vim_func = [[ function! CommentOperator(type) abort let reg_save = @@ execute "lua require('nvim_comment').operator('" . a:type. "')" let @@ = reg_save endfunction ]] vim.api.nvim_call_function("execute", { vim_func }) vim.api.nvim_command("command! -range CommentToggle lua require('nvim_comment').comment_toggle(, )") if M.config.create_mappings then local opts = { noremap = true } api.nvim_set_keymap("n", M.config.line_mapping, "set operatorfunc=CommentOperatorg@l", opts) api.nvim_set_keymap("n", M.config.operator_mapping, "set operatorfunc=CommentOperatorg@", opts) api.nvim_set_keymap("x", M.config.operator_mapping, ":call CommentOperator(visualmode())", opts) api.nvim_set_keymap( "x", M.config.comment_chunk_text_object, "lua require('nvim_comment').select_comment_chunk()", opts ) api.nvim_set_keymap( "o", M.config.comment_chunk_text_object, "lua require('nvim_comment').select_comment_chunk()", opts ) end end return M ================================================ FILE: lua/spec/nvim_comment_spec.lua ================================================ local testModule local mock = require('luassert.mock') local api_mock describe('nvim-comment', function() before_each(function() testModule = require('nvim_comment') api_mock = mock(vim.api, true) -- reset config to default testModule.config = { marker_padding = true } end) after_each(function() mock.revert(api_mock) end) describe('get_comment_wrapper', function() local commentstrings = { ['COMMENT %s'] = {'COMMENT ', nil}, ['{% comment %}%s{% endcomment %}'] = {'{% comment %}', '{% endcomment %}'}, ['c# %s'] = {'c# ', nil}, ['dnl %s'] = {'dnl ', nil}, ['NB. %s'] = {'NB. ', nil}, ['! %s'] = {'! ', nil}, ['#%s'] = {'#', nil}, ['# %s'] = {'# ', nil}, ['%%s'] = {'%', nil}, ['% %s'] = {'% ', nil}, ['(*%s*)'] = {'(*', '*)'}, ['(;%s;)'] = {'(;', ';)'}, ['**%s'] = {'**', nil}, ['-# %s'] = {'-# ', nil}, ['-- %s'] = {'-- ', nil}, ['-- %s'] = {'-- ', nil}, ['.. %s'] = {'.. ', nil}, ['.\\"%s'] = {'.\\"', nil}, ['/*%s*/'] = {'/*', '*/'}, ['/* %s */'] = {'/* ', ' */'}, ['//%s'] = {'//', nil}, ['// %s'] = {'// ', nil}, [':: %s'] = {':: ', nil}, [';%s'] = {';', nil}, ['; %s'] = {'; ', nil}, ['; // %s'] = {'; // ', nil}, [''] = {''}, ['<%#%s%>'] = {'<%#', '%>'}, ['> %s'] = {'> ', nil}, [' *%s'] = {' *', nil}, ['"%s'] = {'"', nil}, } for string,expected in pairs(commentstrings) do it('Should return comment wrapper(s) for: ' .. string .. ' no left marker padding', function() testModule.config.marker_padding = false api_mock.nvim_buf_get_option.on_call_with(0, 'commentstring').returns(string) local left, right = testModule.get_comment_wrapper(string) assert.equals(left, expected[1]) assert.equals(right, expected[2]) end) end local padded_commentstrings = { ['COMMENT %s'] = {'COMMENT ', nil}, ['{% comment %}%s{% endcomment %}'] = {'{% comment %} ', ' {% endcomment %}'}, ['c# %s'] = {'c# ', nil}, ['dnl %s'] = {'dnl ', nil}, ['NB. %s'] = {'NB. ', nil}, ['! %s'] = {'! ', nil}, ['#%s'] = {'# ', nil}, ['# %s'] = {'# ', nil}, ['%%s'] = {'% ', nil}, ['% %s'] = {'% ', nil}, ['(*%s*)'] = {'(* ', ' *)'}, ['(;%s;)'] = {'(; ', ' ;)'}, ['**%s'] = {'** ', nil}, ['-# %s'] = {'-# ', nil}, ['-- %s'] = {'-- ', nil}, ['-- %s'] = {'-- ', nil}, ['.. %s'] = {'.. ', nil}, ['.\\"%s'] = {'.\\" ', nil}, ['/*%s*/'] = {'/* ', ' */'}, ['/* %s */'] = {'/* ', ' */'}, ['//%s'] = {'// ', nil}, ['// %s'] = {'// ', nil}, [':: %s'] = {':: ', nil}, [';%s'] = {'; ', nil}, ['; %s'] = {'; ', nil}, ['; // %s'] = {'; // ', nil}, [''] = {''}, ['<%#%s%>'] = {'<%# ', ' %>'}, ['> %s'] = {'> ', nil}, [' *%s'] = {' * ', nil}, ['"%s'] = {'" ', nil}, } for string,expected in pairs(padded_commentstrings) do it('Should return comment wrapper(s) for: ' .. string .. ' with marker padding', function() api_mock.nvim_buf_get_option.on_call_with(0, 'commentstring').returns(string) local left, right = testModule.get_comment_wrapper(string) assert.equals(left, expected[1]) assert.equals(right, expected[2]) end) end it('Should return nil,nil if unsuported commentstring', function() api_mock.nvim_buf_get_option.on_call_with(0, 'commentstring').returns('something here') local left, right = testModule.get_comment_wrapper('something here') assert.equals(left, nil) assert.equals(right, nil) end) end) describe('comment_line', function() local commentstrings = { ['COMMENT line'] = {'COMMENT ', ''}, ['{% comment %}line{% endcomment %}'] = {'{% comment %}', '{% endcomment %}'}, ['c# line'] = {'c# ', ''}, ['dnl line'] = {'dnl ', ''}, ['NB. line'] = {'NB. ', ''}, ['! line'] = {'! ', ''}, ['#line'] = {'#', ''}, ['# line'] = {'# ', ''}, ['%line'] = {'%', ''}, ['% line'] = {'% ', ''}, ['(*line*)'] = {'(*', '*)'}, ['(;line;)'] = {'(;', ';)'}, ['**line'] = {'**', ''}, ['-# line'] = {'-# ', ''}, ['-- line'] = {'-- ', ''}, ['-- line'] = {'-- ', ''}, ['.. line'] = {'.. ', ''}, ['.\\"line'] = {'.\\"', ''}, ['/*line*/'] = {'/*', '*/'}, ['/* line */'] = {'/* ', ' */'}, ['//line'] = {'//', ''}, ['// line'] = {'// ', ''}, [':: line'] = {':: ', ''}, [';line'] = {';', ''}, ['; line'] = {'; ', ''}, ['; // line'] = {'; // ', ''}, [''] = {''}, ['<%#line%>'] = {'<%#', '%>'}, ['> line'] = {'> ', ''}, [' *line'] = {' *', ''}, ['"line'] = {'"', ''}, } for expected,comment_parts in pairs(commentstrings) do it('Should comment line as expected, with no padding: ' .. expected, function() local actual = testModule.comment_line('line', "", comment_parts[1], comment_parts[2], true, true) assert.equals(expected, actual) end) end it("Should add comment after any whitespace, with padding", function() local actual = testModule.comment_line(" line", " ", "-- ", "", true, true) assert.equals(" -- line", actual) end) it("Should add comment after any whitespace, with extra padding", function() local actual = testModule.comment_line(" line", " ", "-- ", "", true, true) assert.equals(" -- line", actual) end) it("Should trim whitespace", function() local actual = testModule.comment_line("", " ", "-- ", "", true, true) assert.equals(" --", actual) end) it("Should not trim whitespace", function() local actual = testModule.comment_line("", " ", "-- ", "", true, false) assert.equals(" -- ", actual) end) it("Should ignore line if empty or just whitespace", function() local actual = testModule.comment_line(" line", " ", "-- ", "", false, true) assert.equals(" -- line", actual) actual = testModule.comment_line("", " ", "-- ", "", false, true) assert.equals("", actual) -- spaces actual = testModule.comment_line(" ", " ", "-- ", "", false, true) assert.equals(" ", actual) -- Tabs actual = testModule.comment_line(" ", " ", "-- ", "", false, true) assert.equals(" ", actual) end) end) describe('uncomment_line', function() local commentstrings = { ['COMMENT line'] = {'COMMENT ', ''}, ['{% comment %}line{% endcomment %}'] = {'{% comment %}', '{% endcomment %}'}, ['c# line'] = {'c# ', ''}, ['dnl line'] = {'dnl ', ''}, ['NB. line'] = {'NB. ', ''}, ['! line'] = {'! ', ''}, ['#line'] = {'#', ''}, ['# line'] = {'# ', ''}, ['%line'] = {'%', ''}, ['% line'] = {'% ', ''}, ['(*line*)'] = {'(*', '*)'}, ['(;line;)'] = {'(;', ';)'}, ['**line'] = {'**', ''}, ['-# line'] = {'-# ', ''}, ['-- line'] = {'-- ', ''}, ['-- line'] = {'-- ', ''}, ['.. line'] = {'.. ', ''}, ['.\\"line'] = {'.\\"', ''}, ['/*line*/'] = {'/*', '*/'}, ['/* line */'] = {'/* ', ' */'}, ['//line'] = {'//', ''}, ['// line'] = {'// ', ''}, [':: line'] = {':: ', ''}, [';line'] = {';', ''}, ['; line'] = {'; ', ''}, ['; // line'] = {'; // ', ''}, [''] = {''}, ['<%#line%>'] = {'<%#', '%>'}, ['> line'] = {'> ', ''}, -- [' *line'] = {' *', ''}, ['"line'] = {'"', ''}, } for input,comment_parts in pairs(commentstrings) do it('Should uncomment line as expected: ' .. input, function() local actual = testModule.uncomment_line(input, comment_parts[1], comment_parts[2], false) assert.equals('line', actual) end) end it('Should uncomment if trailing whitespace in left hand side removed, no right hand side', function() local actual = testModule.uncomment_line("--", "-- ", "", true) assert.equals('', actual) end) it('Should uncomment and not leave padding when comment_empty_trim_whitespace false, no right hand side', function() local actual = testModule.uncomment_line("-- test", "-- ", "", true) assert.equals('test', actual) end) end) describe('comment_toggle', function() it('Should add left hand side comments only on entire range', function() api_mock.nvim_buf_get_option.on_call_with(0, 'commentstring').returns('-- %s') api_mock.nvim_buf_get_lines.on_call_with(0, 0, 3, false).returns({ "line1", "line2", "line3", }) testModule.comment_toggle(1, 3) assert.stub(api_mock.nvim_call_function).was_called_with("setline", {1, { "-- line1", "-- line2", "-- line3", }}) assert.stub(api_mock.nvim_call_function).was_called_with('setpos', {"'<", {0, 1, 1, 0}}) assert.stub(api_mock.nvim_call_function).was_called_with('setpos', {"'>", {0, 3, 2147483647, 0}}) end) it('Should remove left hand side comments only on entire range', function() api_mock.nvim_buf_get_option.on_call_with(0, 'commentstring').returns('-- %s') api_mock.nvim_buf_get_lines.on_call_with(0, 0, 3, false).returns({ "-- line1", "-- line2", "-- line3", }) testModule.comment_toggle(1, 3) assert.stub(api_mock.nvim_call_function).was_called_with("setline", {1, { "line1", "line2", "line3", }}) assert.stub(api_mock.nvim_call_function).was_called_with('setpos', {"'<", {0, 1, 1, 0}}) assert.stub(api_mock.nvim_call_function).was_called_with('setpos', {"'>", {0, 3, 2147483647, 0}}) end) it('Should add comments on uncommented lines to entire range', function() api_mock.nvim_buf_get_option.on_call_with(0, 'commentstring').returns('-- %s') api_mock.nvim_buf_get_lines.on_call_with(0, 0, 3, false).returns({ "line1", "-- line2", "line3", }) testModule.comment_toggle(1, 3) assert.stub(api_mock.nvim_call_function).was_called_with("setline", {1, { "-- line1", "-- -- line2", "-- line3", }}) assert.stub(api_mock.nvim_call_function).was_called_with('setpos', {"'<", {0, 1, 1, 0}}) assert.stub(api_mock.nvim_call_function).was_called_with('setpos', {"'>", {0, 3, 2147483647, 0}}) end) it('Should add left and right hand side comments to entire range', function() api_mock.nvim_buf_get_option.on_call_with(0, 'commentstring').returns('(*%s*)') api_mock.nvim_buf_get_lines.on_call_with(0, 0, 3, false).returns({ "line1", "line2", "line3", }) testModule.comment_toggle(1, 3) assert.stub(api_mock.nvim_call_function).was_called_with("setline", {1, { "(* line1 *)", "(* line2 *)", "(* line3 *)", }}) assert.stub(api_mock.nvim_call_function).was_called_with('setpos', {"'<", {0, 1, 1, 0}}) assert.stub(api_mock.nvim_call_function).was_called_with('setpos', {"'>", {0, 3, 2147483647, 0}}) end) it('Should remove left and right hand side comments to entire range', function() api_mock.nvim_buf_get_option.on_call_with(0, 'commentstring').returns('(*%s*)') api_mock.nvim_buf_get_lines.on_call_with(0, 0, 3, false).returns({ "(* line1 *)", "(* line2 *)", "(* line3 *)", }) testModule.comment_toggle(1, 3) assert.stub(api_mock.nvim_call_function).was_called_with("setline", {1, { "line1", "line2", "line3", }}) assert.stub(api_mock.nvim_call_function).was_called_with('setpos', {"'<", {0, 1, 1, 0}}) assert.stub(api_mock.nvim_call_function).was_called_with('setpos', {"'>", {0, 3, 2147483647, 0}}) end) it('Should not do anything if commentstring not supported', function() api_mock.nvim_buf_get_option.on_call_with(0, 'commentstring').returns('whatwhat') testModule.comment_toggle(1, 3) assert.stub(api_mock.nvim_buf_get_lines).was_not_called() assert.stub(api_mock.nvim_buf_set_lines).was_not_called() end) end) end) ================================================ FILE: tests/comment_spec.lua ================================================ local function setUpBuffer(input, filetype) local buf = vim.api.nvim_create_buf(false, true) vim.api.nvim_buf_set_option(buf, "filetype", filetype) vim.api.nvim_command("buffer " .. buf) vim.api.nvim_buf_set_lines(0, 0, -1, true, vim.split(input, "\n")) end local function goToLineRunKeys(line, feedkeys) vim.api.nvim_win_set_cursor(0, { line, 0 }) local keys = vim.api.nvim_replace_termcodes(feedkeys, true, false, true) vim.api.nvim_feedkeys(keys, "x", false) end local function getBufLines() local result = vim.api.nvim_buf_get_lines(0, 0, vim.api.nvim_buf_line_count(0), false) return result end local function runCommandAndAssert(line, feedkeys, expected) goToLineRunKeys(line, feedkeys) local result = getBufLines() assert.are.same(vim.split(expected, "\n"), result) end describe("comment/uncomment", function() local input = [[ local function dummy_func() print("This is a dummy func") end local function another_dummy_func() print("This is a another dummy func") end ]] before_each(function() local testModule = require("nvim_comment") testModule.setup({ marker_padding = true, }) end) after_each(function() end) it("Should comment/uncomment line with dot repeatable", function() local expected = [[ -- local function dummy_func() print("This is a dummy func") end local function another_dummy_func() print("This is a another dummy func") end ]] setUpBuffer(input, "lua") -- comment runCommandAndAssert(1, "gcc", expected) -- uncomment runCommandAndAssert(1, "gcc", input) -- comment, via dot runCommandAndAssert(1, ".", expected) end) it("Should comment/uncomment via motion and dot", function() local expected = [[ -- local function dummy_func() print("This is a dummy func") end local function another_dummy_func() print("This is a another dummy func") end ]] setUpBuffer(input, "lua") -- comment runCommandAndAssert(1, "gcl", expected) -- uncomment runCommandAndAssert(1, "gcl", input) -- comment, via dot runCommandAndAssert(1, ".", expected) end) it("Should comment/uncomment motion with count and dot", function() local expected = [[ -- local function dummy_func() -- print("This is a dummy func") -- end local function another_dummy_func() print("This is a another dummy func") end ]] setUpBuffer(input, "lua") -- comment runCommandAndAssert(1, "gc2j", expected) -- uncomment runCommandAndAssert(1, "gc2j", input) -- comment, via dot runCommandAndAssert(1, ".", expected) end) it("Should comment out another pararaph via dot", function() local first_expected = [[ -- local function dummy_func() -- print("This is a dummy func") -- end local function another_dummy_func() print("This is a another dummy func") end ]] local second_expected = [[ -- local function dummy_func() -- print("This is a dummy func") -- end -- local function another_dummy_func() -- print("This is a another dummy func") -- end ]] setUpBuffer(input, "lua") -- comment runCommandAndAssert(2, "gcip", first_expected) -- comment, via dot runCommandAndAssert(7, ".", second_expected) -- uncomment, via dot runCommandAndAssert(7, "gcip", first_expected) end) end) describe("padding flag", function() local input = [[ Tove Jani ]] it("Should add padding", function() require("nvim_comment").setup({ marker_padding = true }) local expected = [[ Tove ]] setUpBuffer(input, "xml") -- comment runCommandAndAssert(3, "gcl", expected) end) it("Should not add padding", function() require("nvim_comment").setup({ marker_padding = false }) local expected = [[ Tove ]] setUpBuffer(input, "xml") -- comment runCommandAndAssert(3, "gcl", expected) end) end) describe("mapping with leader as space", function() local input = [[ Tove Jani ]] it("Should toggle comment with line mapping", function() require("nvim_comment").setup({ line_mapping = " cc", operator_mapping = " c", }) local expected = [[ Tove ]] setUpBuffer(input, "xml") -- comment runCommandAndAssert(3, " cc", expected) end) it("Should toggle comment with operator mapping", function() require("nvim_comment").setup({ line_mapping = " cc", operator_mapping = " c", }) local expected = [[ Tove ]] setUpBuffer(input, "xml") -- comment runCommandAndAssert(3, " c1j", expected) end) end) describe("comment empty flag", function() local input = [[ local function dummy_func() print("This is a dummy func") end local function another_dummy_func() print("This is a another dummy func") end]] it("Should comment empty lines", function() require("nvim_comment").setup({ marker_padding = true, comment_empty = true, }) -- luacheck: ignore local expected = [[ -- local function dummy_func() -- print("This is a dummy func") -- end -- -- local function another_dummy_func() -- print("This is a another dummy func") -- end]] setUpBuffer(input, "lua") -- comment runCommandAndAssert(1, "vGgc", expected) -- uncomment runCommandAndAssert(1, "vGgc", input) end) it("Should not comment empty lines", function() require("nvim_comment").setup({ marker_padding = true, comment_empty = false, }) local expected = [[ -- local function dummy_func() -- print("This is a dummy func") -- end -- local function another_dummy_func() -- print("This is a another dummy func") -- end]] setUpBuffer(input, "lua") -- comment runCommandAndAssert(1, "vGgc", expected) -- comment, via dot runCommandAndAssert(1, "vGgc", input) end) end) describe("comment chunks", function() before_each(function() local testModule = require("nvim_comment") testModule.setup({ marker_padding = true, comment_empty = true, }) end) local input = [[ -- local foo = 'foo' -- local bar = 'bar' -- local baz = 'baz' local foo = 'foo' local baz = 'baz' -- local foo = 'foo' local baz = 'baz' -- local foo = 'foo' -- local foo = 'foo' local bar = 'bar' local baz = 'baz' -- local foo = 'foo' -- local bar = 'bar']] it("Should handle text obeject at top of buffer", function() local expected = [[ local foo = 'foo' local bar = 'bar' local baz = 'baz' local foo = 'foo' local baz = 'baz' -- local foo = 'foo' local baz = 'baz' -- local foo = 'foo' -- local foo = 'foo' local bar = 'bar' local baz = 'baz' -- local foo = 'foo' -- local bar = 'bar']] setUpBuffer(input, "lua") runCommandAndAssert(1, "gcic", expected) end) it("Should handle text obeject at botton of buffer", function() local expected = [[ -- local foo = 'foo' -- local bar = 'bar' -- local baz = 'baz' local foo = 'foo' local baz = 'baz' -- local foo = 'foo' local baz = 'baz' -- local foo = 'foo' -- local foo = 'foo' local bar = 'bar' local baz = 'baz' local foo = 'foo' local bar = 'bar']] setUpBuffer(input, "lua") runCommandAndAssert(1, "Ggcic", expected) end) it("Should handle single line text object", function() local expected = [[ -- local foo = 'foo' -- local bar = 'bar' -- local baz = 'baz' local foo = 'foo' local baz = 'baz' local baz = 'baz' -- local foo = 'foo' -- local foo = 'foo' local bar = 'bar' local baz = 'baz' -- local foo = 'foo' -- local bar = 'bar']] setUpBuffer(input, "lua") runCommandAndAssert(6, "dic", expected) end) it("Should handle multi line text object", function() local expected = [[ -- local foo = 'foo' -- local bar = 'bar' -- local baz = 'baz' local foo = 'foo' local baz = 'baz' -- local foo = 'foo' local baz = 'baz' local bar = 'bar' local baz = 'baz' -- local foo = 'foo' -- local bar = 'bar']] setUpBuffer(input, "lua") runCommandAndAssert(9, "dic", expected) end) end) describe("issues", function() before_each(function() local testModule = require("nvim_comment") testModule.setup({ marker_padding = true, comment_empty = true, }) end) it("issue 22", function() local input = [[ local foo = 'foo' local bar = 'bar' local baz = 'baz' local foo = 'foo' local bar = 'bar' local baz = 'baz' ]] local expected = [[ -- local foo = 'foo' -- local bar = 'bar' -- local baz = 'baz' local foo = 'foo' local bar = 'bar' local baz = 'baz' ]] setUpBuffer(input, "lua") runCommandAndAssert(1, "gg0jjgc", expected) end) it("issue 31", function() local input = [[ this is some block of idented text with empty lines yeah]] local expected = [[ this is some block -- of idented text -- with empty lines yeah]] setUpBuffer(input, "lua") runCommandAndAssert(1, "ggjVjgc", expected) end) end) ================================================ FILE: tests/minimal_init.vim ================================================ set rtp+=. set rtp+=../plenary.nvim/ set hidden runtime! plugin/plenary.vim