Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
name: build

on: [push, pull_request]
on:
push:
branches: [main]
pull_request:

jobs:
stylua:
Expand Down Expand Up @@ -36,7 +39,8 @@ jobs:
toc: true
treesitter: true
docmappingprojectname: false
- uses: stefanzweifel/git-auto-commit-action@v4
- uses: stefanzweifel/git-auto-commit-action@v5
if: github.ref == 'refs/heads/main'
with:
commit_message: "build(docs): auto generate vim documentation"
commit_user_name: "github-actions[bot]"
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ The following example shows the installation process using [lazy.nvim](https://g

> [!TIP]
> The word(s) being replaced during substitution are available in the replacement text using `&`.
>

> [!NOTE]
> The search pattern uses Vim's very magic mode (`\v`), so characters like `.`, `+`, `*`, and `()` are treated as regex operators. This lets you use regex in your search patterns without extra escaping. If you need to match these characters literally, escape them with `\` (e.g. `\.` to match a period).
>
## Acknowledgments

This project was inspired by [Scalpel](https://github.com/wincent/scalpel), a Vimscript plugin I've used for many years. **scalpel.nvim** is my version, which was reimagined and implemented in Lua for fun.
3 changes: 2 additions & 1 deletion lua/scalpel/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ function M.substitute()
elseif is_blank(word) then
vim.notify('Selection is blank, cannot substitute', vim.log.levels.INFO)
else
local pattern = ':%s/\\v' .. word .. '//gc'
local escaped = vim.fn.escape(word, '/\\')
local pattern = ':%s/\\v' .. escaped .. '//gc'
local cursor_move = vim.api.nvim_replace_termcodes('<Left><Left><Left>', true, false, true)
vim.api.nvim_feedkeys(pattern .. cursor_move, 'n', true)
end
Expand Down
25 changes: 25 additions & 0 deletions tests/scalpel_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,31 @@ describe('scalpel', function()
end)
end)

describe('escaping', function()
it('escapes forward slashes in visual selection', function()
helpers.set_mode('v')
helpers.set_visual_marks({ 1, 0 }, { 1, 6 })
helpers.set_buffer_lines({ 'foo/bar baz' })

scalpel.substitute()

local call = helpers.feedkeys_calls[2]
assert.truthy(call.keys:find('foo\\/bar'))
assert.truthy(call.keys:find('//gc'))
end)

it('escapes backslashes in visual selection', function()
helpers.set_mode('v')
helpers.set_visual_marks({ 1, 0 }, { 1, 6 })
helpers.set_buffer_lines({ 'foo\\bar baz' })

scalpel.substitute()

local call = helpers.feedkeys_calls[2]
assert.truthy(call.keys:find('foo\\\\bar'))
end)
end)

describe('visual mode', function()
-- Note: get_visual_range() calls nvim_feedkeys with <Esc> first,
-- so visual mode tests have an extra feedkeys call at index 1.
Expand Down