SkillAgentSearch skills...

Dial.nvim

enhanced increment/decrement plugin for Neovim.

Install / Use

/learn @monaqa/Dial.nvim
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

dial.nvim

Abstract

Extended increment/decrement plugin for Neovim. Written in Lua.

demo.gif

Features

  • Increment/decrement based on various type of rules
    • n-ary (2 <= n <= 36) integers
    • decimal Fractions
    • date and time
    • constants (an ordered set of specific strings, such as a keyword or operator)
      • truefalse
      • &&||
      • ab ⇄ ... ⇄ z
    • hex colors
    • semantic version
  • Support <C-a> / <C-x> / g<C-a> / g<C-x> in VISUAL mode
  • Flexible configuration of increment/decrement targets
    • Rules that are valid only in specific FileType
    • Rules that are valid only in VISUAL mode
  • Support counter
  • Support dot repeat (without overriding the behavior of .)

Similar plugins

Installation

dial.nvim requires Neovim >=0.11.0. You can install dial.nvim by following the instructions of your favorite package manager.

Usage

This plugin does not provide or override any default key-mappings. To use this plugin, you need to assign the plugin key-mapping to the key you like, as shown below:

nnoremap  <C-a> <Plug>(dial-increment)
nnoremap  <C-x> <Plug>(dial-decrement)
nnoremap g<C-a> <Plug>(dial-g-increment)
nnoremap g<C-x> <Plug>(dial-g-decrement)
xnoremap  <C-a> <Plug>(dial-increment)
xnoremap  <C-x> <Plug>(dial-decrement)
xnoremap g<C-a> <Plug>(dial-g-increment)
xnoremap g<C-x> <Plug>(dial-g-decrement)

Or you can configure it with Lua as follows:

vim.keymap.set("n", "<C-a>", function()
    require("dial.map").manipulate("increment", "normal")
end)
vim.keymap.set("n", "<C-x>", function()
    require("dial.map").manipulate("decrement", "normal")
end)
vim.keymap.set("n", "g<C-a>", function()
    require("dial.map").manipulate("increment", "gnormal")
end)
vim.keymap.set("n", "g<C-x>", function()
    require("dial.map").manipulate("decrement", "gnormal")
end)
vim.keymap.set("x", "<C-a>", function()
    require("dial.map").manipulate("increment", "visual")
end)
vim.keymap.set("x", "<C-x>", function()
    require("dial.map").manipulate("decrement", "visual")
end)
vim.keymap.set("x", "g<C-a>", function()
    require("dial.map").manipulate("increment", "gvisual")
end)
vim.keymap.set("x", "g<C-x>", function()
    require("dial.map").manipulate("decrement", "gvisual")
end)

Configuration

In this plugin, flexible increment/decrement rules can be set by using augend and group, where augend represents the target of the increment/decrement operation, and group represents a group of multiple augends.

local augend = require("dial.augend")
require("dial.config").augends:register_group{
  -- default augends used when no group name is specified
  default = {
    augend.integer.alias.decimal,   -- nonnegative decimal number (0, 1, 2, 3, ...)
    augend.integer.alias.hex,       -- nonnegative hex number  (0x01, 0x1a1f, etc.)
    augend.date.alias["%Y/%m/%d"],  -- date (2022/02/19, etc.)
  },

  -- augends used when group with name `mygroup` is specified
  mygroup = {
    augend.integer.alias.decimal,
    augend.constant.alias.bool,    -- boolean value (true <-> false)
    augend.date.alias["%m/%d/%Y"], -- date (02/19/2022, etc.)
  }
}
  • To define a group, use the augends:register_group function in the "dial.config" module. The arguments is a dictionary whose keys are the group names and whose values are the list of augends.
  • Various augends are defined "dial.augend" by default.

To specify the group of augends, you can use expression register (:h @=) as follows:

"=mygroup<CR><C-a>

If it is tedious to specify the expression register for each operation, you can "map" it:

nmap <Leader>a "=mygroup<CR><Plug>(dial-increment)

Alternatively, you can set the same mapping without expression register:

vim.keymap.set("n", "<Leader>a", require("dial.map").inc_normal("mygroup"))

When you don't specify any group name in the way described above, the addends in the default group is used instead.

Example Configuration

local augend = require("dial.augend")
require("dial.config").augends:register_group{
  default = {
    augend.integer.alias.decimal,
    augend.integer.alias.hex,
    augend.date.alias["%Y/%m/%d"],
  },
  only_in_visual = {
    augend.integer.alias.decimal,
    augend.integer.alias.hex,
    augend.date.alias["%Y/%m/%d"],
    augend.constant.alias.alpha,
    augend.constant.alias.Alpha,
  },
}

-- Use `only_in_visual` group only in VISUAL <C-a> / <C-x>
vim.keymap.set("x", "<C-a>", function()
    require("dial.map").manipulate("increment", "visual", "only_in_visual")
end)
vim.keymap.set("x", "<C-x>", function()
    require("dial.map").manipulate("decrement", "visual", "only_in_visual")
end)

require("dial.config").augends:on_filetype {
  typescript = {
    augend.integer.alias.decimal,
    augend.integer.alias.hex,
    augend.constant.new{ elements = {"let", "const"} },
  },
}

List of Augends

For simplicity, we define the variable augend as follows.

local augend = require("dial.augend")

integer

n-based integer (2 <= n <= 36). You can use this rule with augend.integer.new{ ...opts }.

require("dial.config").augends:register_group{
  default = {
    -- uppercase hex number (0x1A1A, 0xEEFE, etc.)
    augend.integer.new{
      radix = 16,
      prefix = "0x",
      natural = true,
      case = "upper",
    },
  },
}

date

Date and time.

require("dial.config").augends:register_group{
  default = {
    -- date with format `yyyy/mm/dd`
    augend.date.new{
        pattern = "%Y/%m/%d",
        default_kind = "day",
        -- if true, it does not match dates which does not exist, such as 2022/05/32
        only_valid = true,
        -- if true, it only matches dates with word boundary
        word = false,
    },
  },
}

In the pattern argument, you can use the following escape sequences:

|Sequence|Meaning | |-----|------------------------------------------------------------------------------| |%Y |4-digit year. (e.g. 2022) | |%y |Last 2 digits of year. The upper 2 digits are interpreted as 20. (e.g. 22)| |%m |2-digit month. (e.g. 09) | |%d |2-digit day. (e.g. 28) | |%H |2-digit hour, expressed in 24 hours. (e.g. 15) | |%I |2-digit hour, expressed in 12 hours. (e.g. 03) | |%M |2-digit minute. (e.g. 05) | |%S |2-digit second. (e.g. 08) | |%-y|1- or 2-digit year. (e.g. 9 represents 2009) | |%-m|1- or 2-digit month. (e.g. 9) | |%-d|1- or 2-digit day. (e.g. 28) | |%-H|1- or 2-digit hour, expressed in 24 hours. (e.g. 15) | |%-I|1- or 2-digit hour, expressed in 12 hours. (e.g. 3) | |%-M|1- or 2-digit minute. (e.g. 5) | |%-S|1- or 2-digit second. (e.g. 8) | |%a |English weekdays (Sun, Mon, ..., Sat) | |%A |English full weekdays (Sunday, Monday, ..., Saturday) | |%b |English month names (Jan, ..., Dec) | |%B |English month full names (January, ..., December) | |%p |AM or PM. | |%J |Japanese weekdays (, , ..., ) |

constant

Predefined sequence of strings. You can use this rule with augend.constant.new{ ...opts }.

require("dial.config").augends:register_group{
  default = {
    -- uppercase hex number (0x1A1A, 0xEEFE, etc.)
    augend.constant.new{
      elements = {"and", "or"},
      word = true, -- if false, "sand" is incremented into "sor", "doctor" into "doctand", etc.
      cyclic = true,  -- "or" is incremented into "and".
    },
    augend.constant.new{
      elements = {"&&", "||"},
      word = false,
      cyclic = true,
    },
  },
}

hexcolor

RGB color code such as #000000 and #ffffff.

require("dial.config").augends:register_group{
  default = {
    -- hex colors (e.g. #1A1A1A, #EEFEFE, etc.)
    augend.hexcolor.new{
      case = "upper", -- or "lower", "prefer_upper", "prefer_lower", see below
    },
  },
}

Supported options for case are:

  • upper: use uppercase letters A-F
  • lower: use lowercase letters a-f
  • prefer_upper: try to keep the case, use uppercase as fallback
    • #0a1bfe will be incremented to #0b1cff (keep existing case)
    • #0A1BFE will be incremented to #0B1CFF (keep existing case)
    • #059799 will be incremented to #06989A (no letter, use uppercase)
    • #0a1BFf will be incremented to #0B1CFF (mixed casing, use uppercase)
  • prefer_lower: try to keep the case, use lowercase as fallback
    • #0a1bfe will be incremented to #0b1cff (keep existing case)
    • #0A1BFE will be incremented to #0B1CFF (keep existing case)
    • #059799 will be incremented to #06989a (no letter, use lowercase)
    • #0a1BFf will be incremented to #0b1cff (mixed casing, use lowercase)

semver

Semantic versions. You can use this

View on GitHub
GitHub Stars1.1k
CategoryDevelopment
Updated2d ago
Forks25

Languages

Lua

Security Score

100/100

Audited on Apr 1, 2026

No findings