Compter.nvim provides an easy way to customize and power the ability of <C-a>
and <C-x>
.
By default, Neovim enable you to use <C-a>
and <C-x>
to increase and descrease value of numbers. But with support of compter.nvim, you can customize <C-a>
and <C-x>
to not only increase and decrease value of numbers but also to enable you to do more powerful things, such as increase and descrease alphabet value (e.g. increase from a to b) and increase and decrease date value (e.g. increase from 01/01/2020 to 02/01/2020).
Use any plugin managers you like, here is an example using lazy.nvim:
require("lazy").setup({
{ "RutaTang/compter.nvim", config = function()
require("compter").setup({})
end,
}
})
require("lazy").setup({
{ "RutaTang/compter.nvim", config = function()
require("compter").setup({
-- Provide and customize templates
templates = {
},
-- Whether fallback to nvim-built-in increase and decrease operation, default to false
fallback = false
})
end,
}
})
Compter.nvim does not embed built-in templates, you can choose and add provided templates from Useful template or Provide your own template
Note: You need either add at least one template or enable fallback to make it work.
Compter.nvim has already overrided <C-a>
and <C-x>
keymappings. What you need to do to use this plugin is just to use <C-a>
and <C-x>
as usual. Both <C-a>
and <C-x>
support intergation with count, which means you can use like 100<C-a>
and 100<C-x>
.
For example:
- Cursor is on 1
1
^
- Press
<C-a>
- The value increase to 2
2
^
You can use provided templates or add your own.
- Useful template: use provided template
- Provide your own template: provide your own template
After you choose or wirte templates, add templates to the templates
like this:
require("lazy").setup({
{ "RutaTang/compter.nvim", config=function()
require("compter").setup(
{
templates = {
-- example template
{
pattern = [[-\?\d\+]],
priority = 0,
increase = function(content)
content = tonumber(content)
return content + 1, true
end,
decrease = function(content)
content = tonumber(content)
return content - 1, true
end,
},
-- more templates
}
}
)
end
},
})
I may continuely add more templates later:
Show all templates
- For number:
{
pattern = [[-\?\d\+]],
priority = 0,
increase = function(content)
content = tonumber(content)
return content + 1, true
end,
decrease = function(content)
content = tonumber(content)
return content - 1, true
end,
}
- For alphabet:
-- for lowercase alphabet
{
pattern = [[\l]],
priority = 0,
increase = function(content)
local ansiCode = string.byte(content) + 1
if ansiCode > string.byte("z") then
ansiCode = string.byte("a")
end
local char = string.char(ansiCode)
return char, true
end,
decrease = function(content)
local ansiCode = string.byte(content) - 1
if ansiCode < string.byte("a") then
ansiCode = string.byte("z")
end
local char = string.char(ansiCode)
return char, true
end,
}
-- for uppercase alphabet
{
pattern = [[\u]],
priority = 0,
increase = function(content)
local ansiCode = string.byte(content) + 1
if ansiCode > string.byte("Z") then
ansiCode = string.byte("A")
end
local char = string.char(ansiCode)
return char, true
end,
decrease = function(content)
local ansiCode = string.byte(content) - 1
if ansiCode < string.byte("A") then
ansiCode = string.byte("Z")
end
local char = string.char(ansiCode)
return char, true
end,
}
- For date format, dd/mm/YYYY:
-- for date format: dd/mm/YYYY
{
pattern = [[\d\{2}/\d\{2}/\d\{4}]],
priority = 100,
increase = function(content)
local ts = vim.fn.strptime("%d/%m/%Y", content)
if ts == 0 then
return content, false
else
ts = ts + 24 * 60 * 60
return vim.fn.strftime("%d/%m/%Y", ts), true
end
end,
decrease = function(content)
local ts = vim.fn.strptime("%d/%m/%Y", content)
if ts == 0 then
return content, false
else
ts = ts - 24 * 60 * 60
return vim.fn.strftime("%d/%m/%Y", ts), true
end
end,
}
- For emoji ⭐:
-- for emoji ⭐
{
pattern = [[⭐\{1,5}]],
priority = 0,
increase = function(content)
local l = #content / 3 + 1
if l > 5 then
l = 1
end
return string.rep("⭐", l), true
end,
decrease = function(content)
local l = #content / 3 - 1
if l < 1 then
l = 5
end
return string.rep("⭐", l), true
end,
}
- For circle degree:
-- for circle degree
{
pattern = [[\d\{1,3}°]],
priority = 0,
increase = function(content)
local l = tonumber(content:sub(1, -3)) + 1
if l >= 360 then
l = 0
end
return string.format("%d°", l), true
end,
decrease = function(content)
local l = tonumber(content:sub(1, -3)) - 1
if l < 0 then
l = 359
end
return string.format("%d°", l), true
end,
}
- For boolean:
-- for boolean
{
pattern = [[\<\(true\|false\|TRUE\|FALSE\|True\|False\)\>]],
priority = 100,
increase = function(content)
local switch = {
["true"] = "false",
["false"] = "true",
["True"] = "False",
["False"] = "True",
["TRUE"] = "FALSE",
["FALSE"] = "TRUE",
}
return switch[content], true
end,
decrease = function(content)
local switch = {
["true"] = "false",
["false"] = "true",
["True"] = "False",
["False"] = "True",
["TRUE"] = "FALSE",
["FALSE"] = "TRUE",
}
return switch[content], true
end,
}
A template must be as following structure:
{
pattern = ..., -- regex pattern to be matched, e.g. [[\d]]
priority = 0, -- priority, template with higher priority will be matched first
-- How to increase content (<C-a>)
-- @param content: content is the matched text
-- @return newContent, handled: handled means whether continue to matche other templates
increase = function(content)
...
return newContent, true
end,
-- How to decrease content (<C-x>)
-- param and return is same as `increase` above
decrease = function(content)
...
return newContent, true
end,
},
A simple example is like:
-- this template match numbers
{
pattern = [[-\?\d\+]],
priority = 0,
increase = function(content)
content = tonumber(content)
return content + 1, true
end,
decrease = function(content)
content = tonumber(content)
return content - 1, true
end,
}
Since the plugin is in its very early stage, I do not accpet PRs to plugin codes and templates for now and still very appreciate for your willing to contribute. I may accpet PRs later when it's ready.
If you found any bugs or enhancements, please open an issue first and we can the discuss.