Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

progcalc.nvim

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.

Neovim 0.10+ Lua No dependencies License MIT


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.

progcalc.nvim: typing an expression and cycling word sizes

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.

Why another calculator plugin?

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.

Features

  • 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

Requirements

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.

Installation

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.

Usage

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.

Expression syntax

Input in any base, with _ or ' as digit separators:

42          0x2A        0b101010      0o52
0xDEAD_BEEF             1'000'000

Operators 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.

Configuration

require('progcalc').setup {
  word = 64, -- word size the panel opens with: 8, 16, 32 or 64
}

API

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'

Development

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 assertions

Layout:

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.

Contributing

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.

License

MIT

Acknowledgements

The layout follows GNOME Calculator's programmer mode, which got the ergonomics right long before this existed.

About

GNOME Calculator's programmer mode, in a Neovim buffer. Decimal, hex, octal and a live 64-bit bit grid, with exact uint64 arithmetic.

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages