A Calca-inspired TUI calculator/editor that combines vim-style text editing with live mathematical evaluation. Built in Rust using ratatui and powered by the Monkey programming language interpreter.
- Vim-style modal editing: Full vim modal editing support including normal, insert, visual, and command modes
- Live mathematical evaluation: Write expressions and see results update in real-time using the
=>operator - Unit conversions: Convert between common units (km to miles, kg to lbs, celsius to fahrenheit, etc.)
- Time functions: Built-in
now()andutc()functions for current time calculations - Variable support: Define and use variables throughout your document
- Function definitions: Create reusable functions using Monkey language syntax
- Persistent evaluation: Variables maintain their values throughout the document
- Split-pane interface: Editor on the left, calculation results on the right
- Rust (nightly toolchain recommended)
- Nix with flakes enabled (optional, for development environment)
- direnv (optional but recommended)
git clone https://github.com/JonnyWalker81/spread.git
cd spread
cargo build --releaseThe binary will be available at target/release/spread.
If you have Nix with flakes enabled:
git clone https://github.com/JonnyWalker81/spread.git
cd spread
direnv allow # If using direnv
just build # Or: cargo build --releasespread [file.spread]spread --eval file.spreadi- Enter insert modev- Enter visual mode:- Enter command modeh/j/k/l- Navigate (vim motions)w/b- Word navigation0/$- Line start/endgg/G- Document start/enddd- Delete lineyy- Yank linep- Pasteu- UndoCtrl+r- Redo
:w- Save file:q- Quit:wq- Save and quit:q!- Quit without saving
5 + 3 => 8
10 * 20 => 200
100 / 4 => 25
2^8 => 256
distance = 150
time = 2.5
speed = distance / time => 60
2km to miles => 1.242742
70kg to lbs => 154.3234
32f to c => 0
100c to f => 212
5 liters to gallons => 1.32086
# Define a function
calculate_tip = fn(bill, percent) { bill * percent / 100 }
bill_amount = 85.50
tip = calculate_tip(bill_amount, 20) => 17.1
total = bill_amount + tip => 102.6
# Using arrays
numbers = [1, 2, 3, 4, 5]
sum = fn(arr) {
if (len(arr) == 0) {
0
} else {
arr[0] + sum(rest(arr))
}
}
total = sum(numbers) => 15
current_time = now() => 2025-07-20 17:21:12
utc_time = utc() => 2025-07-21 00:21:12 UTC
# Time-based calculations
start_hour = 9
current_hour = 17
hours_worked = current_hour - start_hour => 8
hourly_rate = 25
pay = hours_worked * hourly_rate => 200
price = 150
discount = 20%
discount_amount = price * discount => 30
final_price = price - discount_amount => 120
Configuration is stored in ~/.config/spread/config.toml:
[editor]
tab_size = 4
use_spaces = true
line_numbers = true
wrap_lines = false
[ui]
theme = "default"
split_ratio = 0.6
show_line_numbers = true
[evaluator]
auto_evaluate = true
evaluation_delay_ms = 500
max_iterations = 1000
precision = 10This project uses a Nix flake for reproducible development environments.
# With just (task runner)
just build # Development build
just build-release # Release build
just run # Run application
just test # Run tests
just fmt # Format code
just lint # Run clippy
just watch # Watch for changes
# With cargo directly
cargo build
cargo run -- file.spread
cargo test
RUST_LOG=spread=debug cargo run # With debug logging- In eval mode:
RUST_LOG=spread=debug spread --eval file.spread - In TUI mode:
RUST_LOG=spread=debug spread(logs written tospread.log)
spread/
├── src/
│ ├── main.rs # Application entry point
│ ├── app.rs # Main application state and event loop
│ ├── editor/ # Vim-style editor implementation
│ ├── evaluator/ # Mathematical expression evaluation
│ ├── interpreter/ # Monkey language interpreter
│ ├── document/ # Document model and persistence
│ ├── ui/ # Terminal UI components
│ └── config.rs # Configuration management
├── flake.nix # Nix development environment
├── Cargo.toml # Rust dependencies
├── justfile # Development task automation
└── CLAUDE.md # AI assistant instructions
Contributions are welcome! Please feel free to submit a Pull Request.
MIT License