Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

https://github.com/chrisgrieser/nvim-alt-substitute

A substitute of vim's :substitute that uses lua patterns instead of vim regex. Supports incremental preview.
https://github.com/chrisgrieser/nvim-alt-substitute

editing-support lua-pattern-matching nvim-plugin search-and-replace substitute

Last synced: about 2 months ago
JSON representation

A substitute of vim's :substitute that uses lua patterns instead of vim regex. Supports incremental preview.

Lists

README

        

# nvim-alt-substitute

A substitute of vim's `:substitute` that uses lua patterns instead of vim regex. Since you really don't want to learn a whole new flavor of regex just to be able to make search-and-replace operations in your editor.

https://user-images.githubusercontent.com/73286100/231134276-e33b4ee8-611c-4b27-9c57-031ae13fc268.mp4

*Colorscheme: dawnfox variant of nightfox.nvim*

- [Motivation](#motivation)
- [Features](#features)
- [Installation](#installation)
- [Configuration](#configuration)
- [Usage](#usage)
- [Flags](#flags)
- [Ranges](#ranges)
- [Escaping](#escaping)
- [Advanced Usage](#advanced-usage)
- [Lua Pattern Tricks](#lua-pattern-tricks)
- [Appearance](#appearance)
- [Command Line Completion](#command-line-completion)
- [Current Limitations](#current-limitations)
- [Add Support for more Regex Flavors](#add-support-for-more-regex-flavors)
- [Other Search-and-Replace Plugins](#other-search-and-replace-plugins)
- [Credits](#credits)

## Motivation

Many people like me have only started using nvim after the introduction of lua as configuration language. While almost everything about neovim can be done with lua by now, search-and-replace via `:substitute` is one of few areas remaining where you still have to use vimscript. Regardless whether you like vimscript or not, learning vim's flavor of regex *just* for search-and-replace-operations feels somewhat unproductive.

Vim's `:smagic` does help a bit, but still requires additional backslashes where common regex syntax does not require them. Using `verymagic` gets you closest to common regex, [but requires rather convoluted syntax](https://stackoverflow.com/questions/3760444/in-vim-is-there-a-way-to-set-very-magic-permanently-and-globally/23021259#23021259) that can make the command line hard to read in my view. And even if using `magic` or `verymagic`, vim's regex still differs from common regex syntax in various ways, [like the the the way non-greedy quantifiers are written](https://vi.stackexchange.com/questions/196/how-to-make-regex-matchers-non-greedy).

So for those of us who have never used neovim with anything other than lua, why not work with lua patterns for search-and-replace as well to drop the need to learn yet another regex flavor? For people already well-versed in vim regex, this plugin is indeed of little use, but for newcomers it may lower the barrier by removing the need to learn yet another regex flavor.

## Features
- Use `:AltSubstitute` (short form `:S`) to perform search-and-replace
operations using lua patterns.
- Incremental preview of the substitution.
- Supports ranges, with `%` as default.
- The `g` flag is supported and works like with `:substitute`.
- New flags: `i` for case-insensitive search and `f` for fixed strings (literal strings).

```text
:%s /\(\a\+\)\d\+/\1/g -- :substitute
:S /(%a+)%d+/%1/g -- :AltSubstitute
deviceModel2020 -> deviceModel -- effect
```

## Installation

```lua
-- lazy.nvim
{
"chrisgrieser/nvim-alt-substitute",
opts = true,
-- lazy-loading with `cmd =` does not work well with incremental preview
event = "CmdlineEnter",
},

-- packer
use {
"chrisgrieser/nvim-alt-substitute",
config = function() require("alt-substitute").setup({}) end,
}
```

> __Note__
> This plugin requires at least __nvim 0.8__, which introduced the incremental
> command preview feature.

## Configuration

```lua
-- default values
opts = {
showNotification = true, -- whether to show the "x replacements made" notification
}
```

The plugin uses ex-commands and comes without keymaps. You can set some of your own though. (Remember *not* to add `` at the end.)

```lua
-- prefill commandline with Substitution Syntax
vim.keymap.set({ "n", "x" }, "s", [[:S ///g]], { desc = "󱗘 :AltSubstitute" })

-- prefill commandline with Substitution Syntax and word under cursor
vim.keymap.set(
{ "n", "x" },
"S",
function() return ":S /" .. vim.fn.expand("") .. "//g" end,
{ desc = "󱗘 :AltSubstitute (word under cursor)", expr = true }
)
```

## Usage
The plugin registers the Ex-commands `:AltSubstitue` and `:S` as short form.

### Flags
- `g`: works the same as the `g` flag from `:substitute`: Without the `g` flag, only the first match in a line is replaced. With it, every occurrence in a line is replaced.
- `f`: the search query and replace value are treated as __fixed strings__,
meaning lua magic characters are treated as literal strings.
- `i`: the search query is __case insensitive__. The `i` flag is ignored when the `f` flag is also used. (Also note that as opposed to `:substitute`, this plugin ignores the `ignorecase` and `smartcase` setting – case sensitivity is solely determined by whether this flag is present.)

### Ranges
- Ranges are line-based and work [like all other vim command](https://neovim.io/doc/user/cmdline.html#cmdline-ranges).
- However, as opposed to `:substitute`, `:AltSubstitute` works on the whole buffer when no range is given. (In other words, `%` is the default range.)

### Escaping
- Like with `:substitute`, slashes (`/`) delimit search query, replace
value, and flags. Therefore, to search for or replace a `/` you need to escape it with a backslash: `\/`.

## Advanced Usage

### Lua Pattern Tricks
- The frontier pattern`%f[set]`[^1] can be used as a replacement for `\b`:
`%f[%w]`
- The balanced match `%bxy` can be used to deal conveniently with nested brackets.
- [Read more about lua patterns in the lua reference manual](https://www.lua.org/manual/5.4/manual.html#6.4.1).

### Appearance
The incremental preview uses the same highlight group as `:substitute`, namely `Substitition`.

### Command Line Completion
You can use [cmp-cmdline-history](https://github.com/dmitmel/cmp-cmdline-history) to get suggestions of previous substitutions you made. If you find them not helpful, and do not want the suggestions to obfuscate your view of the buffer, then you can disable command suggestions for this plugin:

```lua
cmp.setup.cmdline(":", {
sources = { --[[ your sources ]]
},
enabled = function()
-- Set of commands where cmp will be disabled
local disabled = {
AltSubstitute = true,
S = true,
}
-- Get first word of cmdline
local cmd = vim.fn.getcmdline():match("%S+")
-- Return true if cmd isn't disabled
-- else call/return cmp.close(), which returns false
return not disabled[cmd] or cmp.close()
end,
})
```

### Interactive Lua Pattern Evaluation
While unintended, I found this plugin's incremental preview to also be very useful for interactive testing of lua patterns. Without a replacement value, the plugin evaluates `string.find()` and with a replacement value, it evaluates `string.gsub()`.

## Current Limitations
- `:substitution` flags other than `g` are not supported.
- The `ignorecase` and the `smartcase` option are ignored. Instead, case sensitivity is termined by the presence or absense of the `i` flag.
- `inccommand=split` is not supported, please use `inccommand=unsplit` instead.
- Line breaks in the search or the replacement value are not supported.
- Delimiters other than `/` are not supported yet. (You can make a PR to add
them, the relevant functions are in the [process-parameters module](./lua/alt-substitute/process-parameters.lua))

## Add Support for more Regex Flavors
PRs adding support for more regex flavors, like for example javascript regex, are welcome. The plugin has been specifically built with extensibility in mind, so other regex flavors can be added by writing just one search function and one replace function. However, the bridging to other languages necessitates some tricky escaping. Also performance was an issue in my brief attempts, since the incremental preview basically runs the substitution on every keystroke.

Have a look this plugin's [regex module](./lua/alt-substitute/regex.lua) to see want needs to be implemented, if you wanna give it a try.

## Other Search-and-Replace Plugins
- [nvim-spectre](https://github.com/windwp/nvim-spectre)
- [serch-replace.nvim](https://github.com/roobert/search-replace.nvim)
- [replacer.nvim](https://github.com/gabrielpoca/replacer.nvim)
- [nvim-search-and-replace](https://github.com/s1n7ax/nvim-search-and-replace)

## Credits

__About Me__
In my day job, I am a sociologist studying the social mechanisms underlying the digital economy. For my PhD project, I investigate the governance of the app economy and how software ecosystems manage the tension between innovation and compatibility. If you are interested in this subject, feel free to get in touch.

__Profiles__
- [reddit](https://www.reddit.com/user/pseudometapseudo)
- [Discord](https://discordapp.com/users/462774483044794368/)
- [Academic Website](https://chris-grieser.de/)
- [Twitter](https://twitter.com/pseudo_meta)
- [ResearchGate](https://www.researchgate.net/profile/Christopher-Grieser)
- [LinkedIn](https://www.linkedin.com/in/christopher-grieser-ba693b17a/)

__Buy Me a Coffee__


Buy Me a Coffee at ko-fi.com

[^1]: Frontier patterns are not mentioned in [neovim's respective section for lua patterns](https://neovim.io/doc/user/luaref.html#luaref-patterns). This is likely due to neovim using LuaJit, which itself is based on Lua 5.1, where [frontier patterns were still an undocumented feature](http://lua-users.org/lists/lua-l/2006-12/msg00536.html). But since frontier patterns are [officially documented in the most recent lua version](https://www.lua.org/manual/5.4/manual.html#6.4.1), it should be safe to assume that they are here to stay, so using them should not be an issue.