README.md

July 14, 2026 · View on GitHub

numr

CI

A text calculator for natural language expressions with a vim-style TUI.

Try it online →

numr TUI demo - calculations with variables, units, currencies, and continuation

Features

  • Natural language expressions: 20% of 150, $100 in euros, 2 hours + 30 min
  • Variables: tax = 15% then 100 + tax
  • Unit conversions: Length, weight, time, temperature, data sizes
  • Compound units: 5 m * 10 m = 50 m², 100 km / 2 h = 50 km/h
  • Currency conversions: USD, EUR, GBP, JPY, CHF, CNY, CAD, AUD, INR, KRW, RUB, ILS, PLN, UAH + crypto (BTC, ETH, SOL, and more)
  • Number base conversions: 22 to hex, 22 to bin
  • Math functions and constants: median(1, 3, 2), clamp(120, 0, 100), sin(90°), factorial(5)
  • Angle conversions: 90° to rad, 3.14159 rad to deg, rad(180), deg(pi)
  • Live exchange rates: Loaded and refreshed explicitly by each frontend, with a shared 1-hour cache
  • Dual keybinding modes: Vim (modal) or Standard (direct input) - toggle with Shift+Tab
  • Mouse support: Scroll with mouse wheel or trackpad
  • File persistence: Save with Ctrl+S, supports custom files
  • Syntax highlighting: Numbers, operators, variables, units, and currencies
  • Comments: Lines starting with # or // are treated as comments
  • Continuation: Start a line with an operator (+ 10, * 2) to continue from the previous result
  • Wrap mode: Toggle text wrapping; results follow the final expression row and ignore trailing comments
  • Grouped totals: Currencies and units summed separately in footer (respects exchange rates)

Installation

macOS (Homebrew)

brew tap nasedkinpv/tap
brew install numr

Installs both binaries: numr (opens the calculator file in the TUI) and numr-cli (CLI/REPL/server).

Arch Linux (AUR)

# Using yay
yay -S numr

# Using paru
paru -S numr

Installs both binaries: numr (opens the calculator file in the TUI) and numr-cli (CLI/REPL/server).

From source

# Install the TUI binary
cargo install --path crates/numr-tui

# Install the CLI binary
cargo install --path crates/numr-cli

# Or build both from source
cargo build --release

# Binaries will be available at target/release/numr and target/release/numr-cli

Release archives also contain both binaries: numr (opens the calculator file in the TUI) and numr-cli (CLI/REPL/server).

Usage

TUI Mode

# Open default file (stored in OS config directory)
numr

# Open specific file
numr example.numr

CLI Mode

# Single expression
numr-cli "20% of 150"

# Evaluate file (aligned "input = result" output)
numr-cli -f example.numr

# Interactive REPL
numr-cli -i

# Pipe mode
echo "100 + 200" | numr-cli

# Show running total
numr-cli -t -f example.numr

# Aligned output for any mode
numr-cli --verbose "20% of 150"

By default, numr-cli prints just the result. File mode (-f) uses aligned input = result output. Use --verbose to get aligned output in other modes. Use -t to show a running total at the end.

On Linux, use rlwrap numr-cli -i for readline-style history and editing in the REPL.

JSON-RPC Server Mode

Run numr as a backend for other tools (editors, launchers, scripts):

numr-cli --server

Send JSON-RPC 2.0 requests via stdin, receive responses via stdout:

echo '{"jsonrpc":"2.0","method":"eval","params":{"expr":"20% of 150"},"id":1}' | numr-cli --server
# {"jsonrpc":"2.0","result":{"type":"number","value":"30","display":"30"},"id":1}

The transport is newline-delimited JSON. It supports calls, notifications, null IDs, and JSON-RPC batches; each input frame is limited to 1 MiB. Notifications update server state but produce no response.

Available methods:

MethodParamsDescription
eval{"expr": "..."}Evaluate expression
eval_lines{"lines": [...]}Evaluate multiple lines
clearnoneClear state
get_totalsnoneGet grouped totals
get_variablesnoneList variables
reload_ratesnoneRefresh exchange rates

See docs/json-rpc.md for the complete protocol, result schema, limits, and error codes.

Keybindings (TUI)

The TUI supports two keybinding modes: Vim (default) and Standard. Press Shift+Tab to toggle between them.

Vim Mode

Normal Mode

KeyAction
i / aEnter Insert mode at/after cursor
I / AEnter Insert mode at line start/end
o / ONew line below/above and enter Insert mode
sSubstitute character (delete and insert)
CChange to end of line
h / j / k / lMove left/down/up/right
w / b / eWord forward/backward/end
0 / $Line start/end
gg / GFirst/last line
SpaceMove right
PageUp/DownScroll page
x / XDelete char forward/backward
ddDelete line
DDelete to end of line
JJoin lines
W / N / HToggle wrap/line numbers/header
? / F1Toggle help
Ctrl+sSave
Ctrl+rRefresh rates
F12Toggle debug
Shift+TabSwitch to Standard mode
qQuit

Insert Mode

KeyAction
EscReturn to Normal mode
TypeInsert text
Backspace / DeleteDelete char backward/forward
Option+Backspace / Ctrl+wDelete previous word
Cmd+Backspace / Ctrl+uDelete to line start
EnterNew line
Arrows / PageUp/DownNavigate
Home / EndLine start/end
Ctrl+sSave

Standard Mode

Direct input like traditional editors - no modal switching required.

KeyAction
TypeInsert text directly
Arrow keysMove cursor
Home / EndLine start/end
PageUp/DownScroll page
Ctrl+a / Ctrl+eLine start/end
Ctrl+gGo to first line
Backspace / DeleteDelete char
Option+Backspace / Ctrl+wDelete previous word
Cmd+Backspace / Ctrl+uDelete to line start
Ctrl+kDelete to line end
EnterNew line
Option+zToggle wrap
Ctrl+l / Ctrl+hToggle line numbers/header
? / F1Toggle help
Ctrl+sSave
Ctrl+rRefresh rates
Shift+TabSwitch to Vim mode
Ctrl+qQuit

Supported Operations

CategoryExamples
Arithmetic10 + 20, 6 * 7, 2 ^ 8
Percentages20% of 150, $50 - 10%, 100 + 15%
Variablestax = 8% then price + tax
Continuation$100+ \$50* 2 (chains from previous)
Functionssum(), avg(), min(), max(), median(), clamp(), sqrt(), abs(), round(), floor(), ceil(), sin(), cos(), tan(), rad(), deg(), ln(), log(), log_y(), factorial(), mod()
Base conversion22 to hex0x16, 22 to bin0b10110
Unit conversion5 km in miles, 22 C in F, 1 TB in GB
Compound units5 m * 10 m50 m², 100 km / 2 h50 km/h
Currency$100 in eur, 1 BTC in USD
Comments# comment or // comment
Reference previous_ or ANS for last result

Compound unit aliases: kph (km/h), mph (mi/h), mps (m/s), m2 (m²), km2 (km²), ft2 (ft²)

See example.numr for a complete, executable tour of arithmetic, variables, continuations, functions, currencies, angles, and compound units. Constants are pi, e, and phi.

Supported Units

CategoryUnits
Lengthkm, m, cm, mm, mi/miles, ft/feet, in/inches
Area/m2, km²/km2, ft²/ft2, acre, hectare/ha
Speedm/s/mps, km/h/kph, mph, knot
Weightkg, g, mg, lb/lbs, oz, ton
VolumeL, mL, gal, /m3
Timemonths/mo, weeks/wk, days/d, hours/hr/h, minutes/min, seconds/sec/s
EnergyJ, kJ, cal, kcal, kWh
PowerW, kW
TemperatureK/Kelvin, C/Celsius, F/Fahrenheit
DataTB, GB, MB, KB, bytes
Fiat$/USD, /EUR, £/GBP, ¥/JPY, CHF, CNY, CAD, AUD, /INR, /KRW, /RUB, /ILS, /PLN, /UAH
Crypto/BTC, Ξ/ETH, /SOL, /USDT, USDC, BNB, XRP, /ADA, Ð/DOGE, DOT, Ł/LTC, LINK, AVAX, MATIC, TON

Architecture

Calculation semantics live in the pure, WASM-compatible numr-core; numr-editor provides shared highlighting and UTF-8 primitives; CLI, TUI, web, and desktop remain thin I/O and presentation adapters. See docs/architecture.md for the complete component map, contracts, dependency direction, and rate data flow. The web frontend is maintained in the separate numr-web repository.

Config and cache are stored in the OS config directory (~/.config/numr/ on Linux, ~/Library/Application Support/numr/ on macOS). Settings persist automatically when toggled in the TUI.

Example config.toml:

[preferences]
keybinding_mode = "vim"   # "vim" or "standard"
wrap_mode = false
show_line_numbers = false
show_header = false

[files]
default_path = "~/Documents/calculations.numr"

[api]
fiat_rates_url = "https://open.er-api.com/v6/latest/USD"
crypto_rates_url = "https://api.coingecko.com/api/v3/simple/price"

[api.keys]
coingecko_api_key = "your-key-here"

CoinGecko API key header (demo vs pro) is selected automatically based on the URL host.

Exchange rates are cached to rates.json in the same config directory with 1-hour expiry. Cache I/O is explicit and writes use atomic replacement. The native adapters share this cache:

  • TUI: Starts a background refresh without blocking the event loop
  • CLI: Loads the cache, then fetches only if no usable cached rates exist
  • JSON-RPC server: Loads the cache at startup; network access occurs only through reload_rates

Rate sources:

Integrations

License

MIT