Skip to content

Commit

Permalink
Merge pull request #3 from gbprod/feat-ctrl-v-substitution
Browse files Browse the repository at this point in the history
feat: improve get_regions to select ctrl-v selections
  • Loading branch information
gbprod authored Jan 28, 2022
2 parents 17a60e7 + 1da04e1 commit a55ba9f
Show file tree
Hide file tree
Showing 10 changed files with 595 additions and 75 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/panvimdoc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: panvimdoc

on: [push]

jobs:
docs:
runs-on: ubuntu-latest
name: pandoc to vimdoc
steps:
- uses: actions/checkout@v2
- name: panvimdoc
uses: kdheepak/panvimdoc@main
with:
vimdoc: substitute-nvim
description: Neovim plugin introducing a new operator motions to quickly replace text.
version: 'NVIM v0.6.0'
- uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: 'chore: auto generate docs'
branch: ${{ github.head_ref }}
245 changes: 245 additions & 0 deletions doc/substitute-nvim.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
*substitute-nvim.txt*Neovim plugin introducing a new operator motions to quickly replace text.

==============================================================================
Table of Contents *substitute-nvim-table-of-contents*

1. substitute.nvim |substitute-nvim-substitute.nvim|
- Usage |substitute-nvim-usage|
- Substitute operator |substitute-nvim-substitute-operator|
- Substitute over range motion|substitute-nvim-substitute-over-range-motion|
- Credits |substitute-nvim-credits|

==============================================================================
1. substitute.nvim *substitute-nvim-substitute.nvim*

<img
src='https://github.com/gbprod/substitute.nvim/actions/workflows/integration.yml/badge.svg'
title=''/>
<https://github.com/gbprod/substitute.nvim/actions/workflows/integration.yml>

`substitute.nvim` aim is to provide new operator motions to make it very easy
to perform quick substitutions.

If you are familiar with svermeulen/vim-subversive
<https://github.com/svermeulen/vim-subversive>, this plugin does almost the
same but rewritten in `lua` (and I hope this will be more maintainable,
readable and efficient).

This is a beta version, expect bugs ;) (but I use it daily).

USAGE *substitute-nvim-usage*

Requires neovim > 0.6.0.

Using https://github.com/wbthomason/packer.nvim:

>
use({
"gbprod/substitute.nvim",
config = function()
require("substitute").setup()
end
})
<


SUBSTITUTE OPERATOR *substitute-nvim-substitute-operator*

It contains no default mappings and will have no effect until you add your own
maps to it.

>
vim.api.nvim_set_keymap("n", "s", "<cmd>lua require('substitute').operator()<cr>", { noremap = true })
vim.api.nvim_set_keymap("n", "ss", "<cmd>lua require('substitute').line()<cr>", { noremap = true })
vim.api.nvim_set_keymap("n", "S", "<cmd>lua require('substitute').eol()<cr>", { noremap = true })
vim.api.nvim_set_keymap("x", "s", "<cmd>lua require('substitute').visual()<cr>", { noremap = true })
<


Or

>
nnoremap s <cmd>lua require('substitute').operator()<cr>
nnoremap ss <cmd>lua require('substitute').line()<cr>
nnoremap S <cmd>lua require('substitute').eol()<cr>
xnoremap s <cmd>lua require('substitute').visual()<cr>
<


Then you can then execute `s<motion>` to substitute the text object provided by
the motion with the contents of the default register (or an explicit register
if provided). For example, you could execute siw to replace the current word
under the cursor with the current yank, or sip to replace the paragraph, etc.

This action is dot-repeatable.

Note: in this case you will be shadowing the change character key `s` so you
will have to use the longer form `cl`.

CONFIGURATION ~

*substitute-nvim-`on_substitute`*

`on_substitute` Default : `nil`


Function that will be called each times a substitution is made. This function
takes a `param` argument that contains the `register` used for substitution.

*substitute-nvim-`yank_substitued_text`*

`yank_substitued_text` Default : `false`


If `true`, when performing a substitution, substitued text is pushed into the
default register.

INTEGRATION ~

svermeulen/vim-yoink ~

To enable vim-yoink <https://github.com/svermeulen/vim-yoink> swap when
performing a substitution, you can add this to your setup:

>
require("substitute").setup({
on_substitute = function(_)
vim.cmd("call yoink#startUndoRepeatSwap()")
end,
})
<


vim-yoink <https://github.com/svermeulen/vim-yoink> does not support swapping
when doing paste in visual mode. With this plugin, you can add thoss mappings
to enable it :

>
vim.api.nvim_set_keymap("x", "p", "<cmd>lua require('substitute').visual()<cr>", {})
vim.api.nvim_set_keymap("x", "P", "<cmd>lua require('substitute').visual()<cr>", {})
<


or

>
xmap p <cmd>lua require('substitute').visual()<cr>
xmap P <cmd>lua require('substitute').visual()<cr>
<


SUBSTITUTE OVER RANGE MOTION *substitute-nvim-substitute-over-range-motion*

Another operator provided allows specifying both the text to replace and the
line range over which to apply the change by using multiple consecutive
motions.

>
vim.api.nvim_set_keymap("n", "<leader>s", "<cmd>lua require('substitute.range').operator()<cr>", { noremap = true })
vim.api.nvim_set_keymap("x", "<leader>s", "<cmd>lua require('substitute.range').visual()<cr>")
vim.api.nvim_set_keymap("n", "<leader>ss", "<cmd>lua require('substitute.range').word()<cr>")
<


or

>
nmap <leader>s <cmd>lua require('substitute.range').operator()<cr>
xmap <leader>s <cmd>lua require('substitute.range').visual()<cr>
nmap <leader>ss <cmd>lua require('substitute.range').word()<cr>
<


After adding this map, if you execute `<leader>s<motion1><motion2>` then the
command line will be filled with a substitute command that allow to replace the
text given by `motion1` by the text will enter in the command line for each
line provided by `motion2`.

Alternatively, we can also select `motion1` in visual mode and then hit
`<leader>s<motion2>` for the same effect.

For convenience, `<leader>ss<motion2>` can be used to select complete word
under the cursor as motion1 (complete word means that `complete_word` options
is override to `true` so is different from <leader>siwip which will not require
that there be word boundaries on each match).

You can override any default configuration (described later) by passing this to
the operator function. By example, this will use `S` as prefix of the
substitution command (and use tpope/vim-abolish
<https://github.com/tpope/vim-abolish>):

>
nmap <leader>S <cmd>lua require('substitute.range').operator({ prefix = 'S' })<cr>
<


CONFIGURATION ~

*substitute-nvim-`range.prefix`*

`range.prefix` Default : `s`


Substitution command that will be used (set it to `S` to use tpope/vim-abolish
<https://github.com/tpope/vim-abolish> substitution by default).

*substitute-nvim-`range.prompt_current_text`*

`range.prompt_current_text` Default : `false`


Substitution command replace part will be set to the current text. Eg. instead
of `s/pattern//g` you will have `s/pattern/pattern/g`.

*substitute-nvim-`range.confirm`*

`range.confirm` Default : `false`


Will ask for confirmation for each substitutions.

*substitute-nvim-`range.complete_word`*

`range.complete_word` Default : `false`


Will require that there be word boundaries on each match (eg: `\<word\>`
instead of `word`).

INTEGRATION ~

tpope/vim-abolish ~

You can use tpope/vim-abolish <https://github.com/tpope/vim-abolish>
substitution by default.

>
require("substitute").setup({
range = {
prefix = "S",
}
})
<


CONFIGURATION ~

*substitute-nvim-`range.prefix`*

`range.prefix` Default : `s`


Function that will be called each times a substitution is made. This function
takes a `param` argument that contains the `register` used for substitution.

CREDITS *substitute-nvim-credits*

This plugin is a lua version of svermeulen/vim-subversive
<https://github.com/svermeulen/vim-subversive> awesome plugin.

Thanks to m00qek lua plugin template
<https://github.com/m00qek/plugin-template.nvim>.

Generated by panvimdoc <https://github.com/kdheepak/panvimdoc>

vim:tw=78:ts=8:noet:ft=help:norl:
Empty file added doc/substitute.nvim.txt
Empty file.
24 changes: 11 additions & 13 deletions lua/substitute.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,21 @@ function substitute.operator()
vim.api.nvim_feedkeys("g@", "i", false)
end

local function do_substitution(start_row, start_col, end_row, end_col, register)
local function do_substitution(regions, register, vmode)
local replacement = vim.fn.getreg(register)

if config.options.yank_substitued_text then
vim.fn.setreg(
utils.get_default_register(),
table.concat(utils.nvim_buf_get_text(start_row, start_col, end_row, end_col), "\n")
table.concat(utils.get_text(regions), "\n"),
utils.get_register_type(vmode)
)
end

vim.api.nvim_buf_set_text(0, start_row, start_col, end_row, end_col, vim.split(replacement:gsub("\n$", ""), "\n"))
local text = vim.split(replacement:gsub("\n$", ""), "\n")
for _, region in ipairs(regions) do
vim.api.nvim_buf_set_text(0, region.start_row - 1, region.start_col, region.end_row - 1, region.end_col + 1, text)
end

if config.options.on_substitute ~= nil then
config.options.on_substitute({
Expand All @@ -37,14 +41,8 @@ local function do_substitution(start_row, start_col, end_row, end_col, register)
end

function substitute.operator_callback(vmode)
local region = utils.get_region(vmode)
do_substitution(
region.start_row - 1,
region.start_col,
region.end_row - 1,
region.end_col + 1,
substitute.state.register
)
local regions = utils.get_regions(vmode)
do_substitution(regions, substitute.state.register, vmode)
end

function substitute.line()
Expand All @@ -67,8 +65,8 @@ end

function substitute.visual()
substitute.state.register = vim.v.register
vim.o.operatorfunc = "v:lua.require'substitute'.operator_callback"
vim.api.nvim_feedkeys("g@`>", "i", false)
vim.cmd([[execute "normal! \<esc>"]])
substitute.operator_callback(vim.fn.visualmode())
end

return substitute
8 changes: 4 additions & 4 deletions lua/substitute/range.lua
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ function range.clear_match()
end

function range.operator_callback(vmode)
local region = utils.get_region(vmode)
if region.start_row ~= region.end_row then
local regions = utils.get_regions(vmode)
if vim.tbl_count(regions) ~= 1 or regions[1].start_row ~= regions[1].end_row then
vim.notify("Multiline is not supported by SubstituteRange", vim.log.levels.INFO)
return
end

local line = vim.api.nvim_buf_get_lines(0, region.start_row - 1, region.end_row, true)
range.state.subject = string.sub(line[1], region.start_col + 1, region.end_col + 1)
local line = vim.api.nvim_buf_get_lines(0, regions[1].start_row - 1, regions[1].end_row, true)
range.state.subject = string.sub(line[1], regions[1].start_col + 1, regions[1].end_col + 1)

create_match()

Expand Down
Loading

0 comments on commit a55ba9f

Please sign in to comment.