A programmer's calculator that lives in a Neovim buffer.
Decimal, hex, octal and a 64-bit bit grid all at once, updating as you type.
Stop alt-tabbing to GNOME Calculator to check what 1 << 40 | 0x3C looks like
in hex. progcalc.nvim brings the programmer-mode panel into Neovim and
unlike a quick :lua print(), it stays exact at 64 bits.
Set bits are highlighted and clear bits dimmed, so a register mask is readable at a glance. Colours come from your colourscheme nothing is hard-coded.
Because most of them are quietly wrong above 32 bits.
Lua numbers are IEEE doubles, exact only to 53 bits. Lua's bitwise operations are documented as 32-bit. Any calculator built on either will silently hand you a wrong answer for a 64-bit mask precisely the case you opened a programmer's calculator to solve.
progcalc.nvim evaluates on uint64_t cdata from end to end, including
literal parsing. tonumber('FFFFFFFFFFFFFFFF', 16) routes through a double
and loses the low bits, so digits are accumulated into a uint64_t instead.
| Expression | progcalc | Plain Lua + bit |
|---|---|---|
0xFFFFFFFFFFFFFFFF |
18446744073709551615 |
1.844674407371e+19 |
0xFFFFFFFFFFFFFFFF + 1 |
0 |
1.844674407371e+19 (unchanged) |
1 << 40 |
1099511627776 |
256 (32-bit wrap) |
1 << 64 |
0 |
1 (shift count wraps) |
0x123456789ABCDEF0 >> 32 |
0x12345678 |
0x789ABCDF |
Every value in that right-hand column was produced by running the expression in Neovim, not assumed. The first row is the sharpest: the literal cannot even be stored the nearest double is 264, one greater than the number written, so adding 1 to it changes nothing at all.
- Every base at once decimal, hex, octal and binary, no mode switching
- Correct 64-bit arithmetic on
uint64_t, including literals - Bit grid with an index ruler at every byte boundary, GNOME-style
- Word sizes 8 / 16 / 32 / 64, cycled with a keystroke
- Signed view shown automatically when two's complement differs
- ASCII of the low byte when printable
- C operator precedence paste an expression from source and it evaluates the way the compiler reads it
- Evaluate a visual selection straight out of your code
- Yank any representation in a paste-ready form
- Zero dependencies, no
setup()required
Neovim 0.10+ (developed and tested on 0.11.6). No external tools, no other plugins. LuaJIT's FFI ships with Neovim, so 64-bit support needs nothing extra.
lazy.nvim
{
'SafaeOuajih/progcalc.nvim',
cmd = 'ProgCalc',
keys = {
{ '<leader>cc', '<cmd>ProgCalc<cr>', desc = 'Programmer calculator' },
{ '<leader>cc', ":'<,'>ProgCalc<cr>", mode = 'v', desc = 'Calculate selection' },
},
}packer.nvim
use { 'SafaeOuajih/progcalc.nvim', cmd = 'ProgCalc' }vim-plug
Plug 'SafaeOuajih/progcalc.nvim'Calling setup() is optional the plugin works as soon as it is on the
runtimepath.
| Command | Does |
|---|---|
:ProgCalc |
Open the panel |
:ProgCalc 1 << 12 |
Open with an expression already evaluated |
:'<,'>ProgCalc |
Evaluate the current visual selection |
Inside the panel:
| Key | Does |
|---|---|
<C-b> |
Cycle word size: 8 → 16 → 32 → 64 |
yh |
Yank hex |
yd |
Yank decimal |
yo |
Yank octal |
yb |
Yank binary |
q / <Esc> |
Close |
Yanked values are ungrouped and prefixed, so 0000 0100 0000 003C yanks as
0x000001000000003C and pastes straight into code.
Input in any base, with _ or ' as digit separators:
42 0x2A 0b101010 0o52
0xDEAD_BEEF 1'000'000Operators follow C precedence, loosest to tightest:
| Level | Operators |
|---|---|
| or | | |
| xor | ^ |
| and | & |
| shift | << >> |
| additive | + - |
| multiplicative | * / % |
| unary | - ~ |
Important
^ is xor, not exponentiation. This is a programmer's calculator, so C
semantics win over Lua's.
Division is integer division. Arithmetic wraps at 64 bits, and shifts of 64 or
more yield 0 rather than the wrapped count that C leaves undefined.
require('progcalc').setup {
word = 64, -- word size the panel opens with: 8, 16, 32 or 64
}require('progcalc').open { expression = '1 << 12' }
require('progcalc').toggle()
require('progcalc').close()
-- Evaluate without opening the panel; returns uint64_t cdata.
local value, err = require('progcalc').eval '0xFF & 0x0F'The evaluator and formatter have no Neovim API dependencies, so the tests run without a framework:
nvim -l tests/eval_spec.lua # 37 assertions
nvim -l tests/format_spec.lua # 30 assertionsLayout:
lua/progcalc/eval.lua tokenizer + recursive-descent parser, uint64 math
lua/progcalc/format.lua base conversion, bit grid, signed interpretation
lua/progcalc/ui.lua floating panel, virtual-line rendering
lua/progcalc/init.lua public API
plugin/progcalc.lua :ProgCalc, with visual-range support
The panel's buffer holds exactly one real line your expression. Every readout is a virtual line, so there is no output text to accidentally edit.
Issues and pull requests are welcome. If you are reporting a wrong result,
please include the expression and the word size; if you are adding an operator,
please add a case to tests/eval_spec.lua alongside it.
MIT
The layout follows GNOME Calculator's programmer mode, which got the ergonomics right long before this existed.
