nvumi is a Neovim plugin that integrates the numi natural language calculator with a scratch buffer. It lets you construct natural language expressions and see the results evaluated inline as you type.
{
"josephburgess/nvumi",
opts = {
virtual_text = "newline", -- or "inline"
prefix = " = ", -- prefix shown before the output
date_format = "iso", -- or: "uk", "us", "long"
keys = {
run = "<CR>", -- run/refresh calculations
reset = "R", -- reset buffer
yank = "<leader>y", -- yank output of current line
yank_all = "<leader>Y", -- yank all outputs
},
-- see below for more on custom conversions/functions
custom_conversions = {},
custom_functions = {}
}
}
numi-cliYou will also need numi-cli.
MacOS
brew install nikolaeu/numi/numi-cli
Linux & Windows
curl -sSL https://s.numi.app/cli | sh
nvumi does not have a default keybinding to open the scratch buffer. You can set one:
vim.keymap.set("n", "<leader>on", "<CMD>Nvumi<CR>", { desc = "Open nvumi" })
:Nvumi to open a scratch buffer.20 inches in cm).<CR> to refresh calculations.<leader>y to yank the current result (or <leader>Y for all results).nvumi supports variables for storing values and reusing them in subsequent expressions. Variable names must start with a letter or underscore, followed by letters, numbers, or underscores.
x = 20 inches in cm
y = 5000
x * y
x + 5
y meters in kilometers
x stores the result of 20 inches in cmy holds 5000x * y use the stored valuesPressing R to reset the buffer also clears all stored variables.
nvumi supports user-defined unit conversions beyond what numi-cli provides. This was inspired by the plugins that exist for the numi desktop app (those should be compatible with nvumi too).
base_unit (e.g., "speed", "volume"){
opts = {
custom_conversions = {
{
id = "kmh",
phrases = "kmh, kmph, klicks, kilometers per hour",
base_unit = "speed",
format = "km/h",
ratio = 1,
},
{
id = "mph",
phrases = "mph, miles per hour",
base_unit = "speed",
format = "mph",
ratio = 1.609344, -- 1 mph = 1.609344 km/h
},
},
}
}
| Input | Output |
|---|---|
10 gallons in liters |
37.8541 L |
5 kmh in mph |
3.10686 mph |
nvumi supports user-defined functions with aliases. Functions receive arguments (numbers or strings, or nothing) and return computed results. You can include error messages that will surface if something goes wrong.
{
opts = {
custom_functions = {
{
def = { phrases = "square, sqr" },
fn = function(args)
if #args < 1 or type(args[1]) ~= "number" then
return { error = "square requires a single numeric argument" }
end
return { result = args[1] * args[1] }
end,
},
{
def = { id = "greet", phrases = "hello, hi" },
fn = function(args)
local name = args[1] or "stranger"
return { result = "Hello, " .. name .. "!" }
end,
},
{
def = { phrases = "coinflip, flip" },
fn = function()
return { result = (math.random() > 0.5) and "Heads" or "Tails" }
end,
},
},
}
}
| Input | Output |
|---|---|
square(5) |
25 |
square("abc") |
"Error: square requires a single numeric argument" |
hello("Joe") |
"Hello, Joe!" |
flip() |
Heads / Tails |
{} EvaluationsExpressions inside {} are evaluated first and the result is substituted into the full line before processing. This is particularly useful with custom functions or conversions, where passing a raw expression as an argument would confuse the parser.
| Input | Step 1 - Evaluate {} |
Step 2 - Final Output |
|---|---|---|
log({10*10}, {5+5}) |
log(100, 10) |
2 |
{10+20} mph in kmh |
30 mph in kmh |
48.28032 km/h |
nvumi supports two virtual text modes:
| Format | Example Output |
|---|---|
"iso" |
2025-02-21 |
"us" |
02/21/2025 |
"uk" |
21/02/2025 |
"long" |
February 21, 2025 |
opts = {
date_format = "iso", -- or: "uk", "us", "long"
}
| Command | Description |
|---|---|
NvumiEvalLine |
Run nvumi on any line in any buffer |
NvumiEvalBuf |
Run nvumi on the entire buffer anywhere (this will probably be messy...) |
NvumiClear |
Clears the buffer's virtual text |
.nvumi filetypenvumi uses a custom filetype .nvumi so that the autocommands don't trigger on arbitrary buffers. As a side effect, you can create and save .nvumi files outside of the scratch buffer and they work exactly the same.
There is a Wiki with more detail, including a Recipes page with example custom conversions and functions.
This is my first attempt at a Neovim plugin, so contributions are more than welcome. If you encounter issues or have ideas for improvements, please open an issue or submit a pull request on GitHub.
MIT License. See LICENSE for details.