A powerful neovim plugin to easily convert between various formats
Find a file
2026-06-07 12:49:08 +02:00
lua/convy feat(init): register opts.formats in setup 2026-06-05 11:10:05 +02:00
plugin chore: replace depreacted api calls 2026-06-03 07:50:30 +02:00
LICENSE docs: add LICENSE 2025-11-04 19:18:28 +01:00
README.md docs: remove ROADMAP 2026-06-05 11:10:05 +02:00

🧮 convy.nvim

A powerful Neovim plugin to convert between various formats

showcase

Features

  • 🔄 Multiple Formats: from ASCII to binary, Morse and Freedom Units
    • Encoding: ascii, bin, dec, hex, oct, b64, sha256, md5, morse, braille, nato
    • Data size: B, KB, MB, GB, TB (SI), KiB, MiB, GiB, TiB (IEC)
    • Data rate: bps, kbps, mbps, gbps, tbps
    • Length: px, em, rem, pt, pica, mm, cm, m, km, in, ft, yd, mi, barleycorn, bolt, cable, chain, clothyard, cubit, ell, fathom, finger, furlong, hand, league, line, link, megalithicyard, nail, nmi, palm, poppyseed, pyramidinch, rod, shackle, span, thou, angstrom, ls, au, ly, pc
    • Area: mm2, cm2, m2, km2, in2, ft2, yd2, mi2, ha, acre
    • Volume: ml, cl, dl, l, m3, tsp, tbsp, floz, cup, pint, qt, gal
    • Angle: deg, rad, grad, turn
    • Time: ns, us, ms, s, min, h, day, week, fortnight
    • Speed: mps, kmh, mph, fps, kn
    • Mass: mg, g, kg, t, oz, lb, st
    • Pressure: Pa, kPa, bar, atm, psi, mmHg, torr
    • Energy: J, kJ, cal, kcal, Wh, kWh, BTU
    • Power: W, kW, MW, GW, hp
    • Temperature: celsius, fahrenheit, kelvin
    • Frequency: Hz, kHz, MHz, GHz, THz
    • Color: hex, rgb, hsl, tailwind
  • 🤖 Auto-detection of input format
  • 🎯 Smart selection: works with visual selection or word-under-cursor
  • 🌳 Interactive split-window tree UI with search and live result preview
  • 🧩 Custom formats: add your own units or conversions from your config

📦 Installation

{
  "necrom4/convy.nvim",
  cmd = { "Convy", "ConvySeparator" },
  opts = {}
}

⚙️ Configuration

{
  opts = {
    -- default configuration
    notifications = true,
    separator = " ",
    window = {
      position = "left", -- "left" or "right"
      width = 36,
    },
    formats = {
      -- custom formats, see section below
    },
  },
  keys = {
    -- example keymaps
    {
      "<leader>cc",
      ":Convy<CR>",
      desc = "Convert (interactive selection)",
      mode = { "n", "v" },
      silent = true,
    },
    {
      "<leader>cd",
      ":Convy auto dec<CR>",
      desc = "Convert to decimal",
      mode = { "n", "v" },
      silent = true,
    },
    {
      "<leader>cs",
      ":ConvySeparator<CR>",
      desc = "Set conversion separator (visual selection)",
      mode = { "v" },
      silent = true,
    },
  }
}

🚀 Usage

:Convy <input_format> <output_format>
:Convy " open interactive selection window
:'<,'>Convy <<input_format> <output_format>> " visual selection as string to work on
lua require("convy").convert("auto", "<output_format>") -- `auto` guesses the format of the input
lua require("convy").convert("<input_format>", "<output_format>", true) -- boolean indicates use of visual selection
lua require("convy").show_selector() -- open interactive selection window
:ConvySeparator ", " " sets the separator to `, `
:ConvySeparator \", \" " sets the separator to `", "`
:ConvySeparator | - | " spaces are not ignored, this sets the separator to `| - |`
:'<,'>ConvySeparator " visual selection as selector
lua require("convy.utils").set_separator(", ") -- sets the separator to `, `

Interactive window keymaps:

  • Navigation: Up/Down/j/k/Tab/gg/G
  • Select unit: Enter/Space/Right/l
  • Deselect unit: Esc/BS
  • Open/collapse group: Enter/Space
  • Toggle all groups: za
  • Search: /
  • Modify input value: i

Examples:

| represents the cursor's position, [ ... ] represents a visual selection.

" 72 1|01 108 108 111
:Convy auto ascii
" Converts hovered word from decimal to ascii
" Result: 72 e 108 108 111

" [72 101 108 108 111]
:Convy auto ascii
" Converts selection from decimal to ascii
" Result: Hello

" [Hello]
:Convy
" Opens the split-window selector
" Navigate the tree with `j/k`, open a group with `l`/`right`, search with `/`
" Select the input format (or `auto`) with `<CR>`/`<Space>`
" Then select a compatible output format to apply and close
" Result: 72 101 108 108 111

🧩 Custom formats

Add your own units or conversions through setup({ formats = { ... } }). Each entry either extends a built-in group or defines a new key/kind group. New formats appear in the selector, tab-completion and :Convy.

Add a unit to an existing group

length is a linear group, so a new unit is just a suffix and a factor relative to the group's base (meters):

require("convy").setup({
  formats = {
    { extend = "length", formats = {
      { name = "smoot", suffix = "smoot", factor = 1.7018 },
    }},
  },
})
-- :Convy smoot m -> 1smoot becomes 1.7018m

Define a new group with custom conversions

A custom group converts through a shared base: each format provides decode(text) -> base and encode(base) -> text. Conversion is out.encode(in.decode(text)), so N formats only need N function pairs.

This example treats a uint32 as a Unix timestamp (epoch seconds) and converts between the raw integer, hex, and an ISO 8601 UTC date:

require("convy").setup({
  formats = {
    {
      key = "epoch",
      label = "Epoch Date",
      kind = "custom",
      formats = {
        {
          name = "unix",
          decode = function(text) return tonumber(text) end,
          encode = function(secs) return tostring(math.floor(secs)) end,
        },
        {
          name = "hex32",
          decode = function(text) return tonumber(text, 16) end,
          encode = function(secs) return string.format("%08X", secs) end,
        },
        {
          name = "iso",
          display = "ISO date",
          -- optional: makes `auto` recognise ISO dates
          detect = function(text) return text:match("^%d%d%d%d%-%d%d%-%d%dT") ~= nil end,
          decode = function(text)
            local y, mo, d, h, mi, s = text:match("(%d+)-(%d+)-(%d+)T(%d+):(%d+):(%d+)")
            if not y then return nil end
            local utc_offset = os.time(os.date("!*t", 0))
            return os.time({
              year = tonumber(y), month = tonumber(mo), day = tonumber(d),
              hour = tonumber(h), min = tonumber(mi), sec = tonumber(s), isdst = false,
            }) - utc_offset
          end,
          encode = function(secs) return os.date("!%Y-%m-%dT%H:%M:%SZ", secs) end,
        },
      },
    },
  },
})
-- :Convy unix iso     ->  1700000000 becomes 2023-11-14T22:13:20Z
-- :Convy auto unix    ->  2023-11-14T22:13:20Z becomes 1700000000