gridline 0.1.5

Terminal spreadsheet with Rhai-powered formulas.
Documentation

Gridline ✨

Gridline is a proof-of-concept terminal spreadsheet with Rhai support. Cells can contain numbers, text, or formulas powered by the Rhai scripting language. Your sheet lives in a plain text file, and your reusable logic can live in a separate .rhai functions file.

What you get (today):

  • TUI grid with a formula bar and command mode
  • A1-style references in formulas (=A1 + B2) and range functions (=SUM(A1:B5))
  • Dependency tracking and recalculation
  • Load/reload user functions from a .rhai file (-f at startup, :source at runtime)
  • Vim keybindings by default, optional Emacs keymap
  • Custom keymaps via TOML (optional override)
  • Plain text storage format (one cell per line)
  • Simple plotting in a modal (bar/line/scatter)

Project status: this is a POC. Expect rough edges (especially around plotting and any non-trivial spreadsheet ergonomics).

Why it's fun:

  • 🧾 Plain-text sheets you can diff and version
  • 🧠 Formulas are real Rhai scripts (with spreadsheet sugar)
  • πŸ“ˆ Quick plots right in the terminal

Screenshots

Quick Start πŸš€

Build and run:

cargo run

Open an example file:

cargo run -- examples/plot.grid

Load custom Rhai functions at startup (can specify multiple files):

cargo run -- -f examples/functions.rhai examples/plot.grid
cargo run -- -f lib1.rhai -f lib2.rhai examples/plot.grid

Auto-load a default functions file if present:

  • config directory gridline/default.rhai (platform-specific)
    • Linux: ~/.config/gridline/default.rhai
    • macOS: ~/Library/Application Support/gridline/default.rhai
    • Windows: %APPDATA%\\gridline\\default.rhai

Load or reload functions at runtime:

:source examples/functions.rhai
:so                                 # reload all loaded files

Cell Input Rules 🧾

Gridline interprets cell input like this:

  • empty / whitespace => empty cell
  • leading = => formula (Rhai script; stored without the =)
  • quoted "text" => text (quotes stripped)
  • otherwise, parseable as f64 => number
  • else => text

Examples:

A1: 10
A2: "hello"
A3: =A1 * 2
A4: =SUM(A1:A3)

Formulas (Rhai + Spreadsheet Sugar) 🧠

Inside formulas:

  • A1 becomes cell(0, 0) (0-indexed internally)
  • @A1 becomes value(0, 0) (typed access: numbers/text/bools)
  • SUM(A1:B5) becomes sum_range(0, 0, 4, 1)

Arrays "spill" down the column. If you need to do an in-place operation that returns () (like Rhai's Array.sort()), use OUTPUT:

A1: 30
A2: 10
A3: 20
B1: =OUTPUT(VEC(A1:A3), |v| { v.sort(); v })

Typed refs are useful when a referenced cell contains text (or a formula that returns text):

B1: =if C1 > 100 { "expensive" } else { "cheap" }
A1: =len(@B1)

Built-in range functions (ALL CAPS):

  • SUM, AVG, COUNT, MIN, MAX
  • SUMIF(range, |x| condition) - sum values where predicate is true
  • COUNTIF(range, |x| condition) - count cells where predicate is true
  • BARCHART, LINECHART, SCATTER
  • VEC (convert a range to an array; respects direction: VEC(A3:A1) returns [A3, A2, A1])

Other built-ins:

  • ROW() - current cell's row (1-indexed)
  • COL() - current cell's column (1-indexed)
  • RAND() - random float in [0.0, 1.0)
  • RANDINT(min, max) - random integer in [min, max] inclusive

Custom Functions Example 🧩

Create a .rhai file:

fn fib(n) {
  if n < 2 { n } else { fib(n - 1) + fib(n - 2) }
}

Load it (either -f or :source), then use it in a cell:

A1: "Fibonacci"
B1: 10
C1: =fib(B1)

Plotting πŸ“ˆ

Plotting works by making a formula cell return a tagged plot spec. The grid shows a placeholder (e.g. <BAR>), and you can open the plot modal.

Example (examples/plot.grid):

C1: =SCATTER(A1:B5, "title", "xaxis", "yaxis")
D1: =BARCHART(B1:B5)

Open the plot modal:

  • Vim keymap: P
  • Emacs keymap: M-p

Commands ⌨️

Command mode:

  • Vim: :
  • Emacs: M-x

Useful commands:

  • :w or :w <path> save
  • :q quit (warns if modified)
  • :q! force quit
  • :wq save and quit
  • :e <path> open file
  • :goto A100 (alias :g A100) jump to a cell
  • :colwidth 15 set current column width
  • :colwidth A 15 set a specific column width
  • :source <file.rhai> (alias :so) load functions; :so reloads the last functions file

Keymaps πŸ—ΊοΈ

Select keybindings:

gridline --keymap vim
gridline --keymap emacs
gridline --keymap vim --keymap-file /path/to/keymaps.toml

Keymap files (optional):

  • Default location: config directory gridline/keymaps.toml (platform-specific)
  • Override with --keymap-file <path>
  • If a keymap name is not found in the file, Gridline falls back to the built-in map (vim or emacs)
    • Linux: ~/.config/gridline/keymaps.toml
    • macOS: ~/Library/Application Support/gridline/keymaps.toml
    • Windows: %APPDATA%\\gridline\\keymaps.toml

Sample keymap file:

  • docs/keymaps.toml

Status bar has an always-on cheat sheet, but the core controls are:

Vim:

  • hjkl move, i/Enter edit, Esc cancel
  • v visual select, y yank, p paste
  • :w save, :q quit

Emacs:

  • C-n/p/f/b move, Enter edit, C-g cancel
  • C-SPC set mark (visual), M-w copy, C-y paste
  • M-x command mode, :w save, :q quit

File Format πŸ“

Gridline files are plain text. Non-empty, non-comment lines look like:

CELLREF: VALUE

Comments start with #. Values follow the same input rules as interactive editing.

Development πŸ”§

cargo fmt
cargo clippy --all-targets -- -D warnings
cargo test

License πŸ“œ

Licensed under either of:

  • Apache License, Version 2.0 (LICENSE-APACHE)
  • MIT license (LICENSE-MIT)