An efficient, lightweight terminal-based spreadsheet application built in Rust. TSHTS brings the power of spreadsheet calculations to your command line with an intuitive interface, comprehensive formula support, and robust data management capabilities.

# Clone the repository
git clone https://github.com/SamuelSchlesinger/tshts.git
cd tshts
# Build and run
cargo run --release
# Or build for installation
cargo build --release
# Binary will be available at target/release/tshts
TSHTS uses vim-style modes. The status bar shows your current mode
(-- NORMAL --, -- INSERT --, -- VISUAL --, etc.).
hjkl move between cells. Counts work: 5j, 10G.i / a / I / A / s / Enter enter Insert mode. o / O open a new row.= for formulas (e.g., =A1+B1, =SUM(A1:A10))v (cells), V (whole row), Ctrl+V (block). Then y yank / d delete / c change / p paste.Ctrl+S saves; :w / :wq / :q! work from the command palette (:).Ctrl+E (CSV export), Ctrl+L (CSV import), or :export <file> / :import <file>./ searches across cells and formulas; n / N cycle results.F1 or ? opens help. Press 0 to jump to Vim Mode reference; / searches help.+, -, *, /, ** / ^ (power), % (modulo)& (concatenation), string literals with "quotes"<, >, <=, >=, =, <>SUM, AVERAGE, MIN, MAX, ABS, SQRT, ROUND,
CEILING, FLOOR, INT, MOD, POWER, SIGN, LOG, LN, EXP, PI, RAND, RANDBETWEENSUMIF, COUNTIF, AVERAGEIF (">5", wildcards)VLOOKUP, INDEX, MATCHCONCAT, LEN, UPPER, LOWER, PROPER, TRIM,
LEFT, RIGHT, MID, FIND, SUBSTITUTE, REPLACE, REPT, EXACT,
CLEAN, CHAR, CODE, TEXT, VALUE, NUMBERVALUETODAY, NOW, DATE, YEAR, MONTH, DAY (Excel
serial-day numbers)GET(url) — non-blocking, cached for 5 min; first call
returns "Loading…" and the cell auto-refreshes when the background fetch
completesIF, AND, OR, NOT, TRUE, FALSEISBLANK, ISNUMBER, ISTEXT, TYPE, COUNT, COUNTASPARKLINE(range) — unicode bar chartA1, AA123 — and absolute markers $A$1, $A1, A$1A1:C3 for any range-aware functionCtrl+Z / Ctrl+YShift+Arrow keysCtrl+D — copies formulas with relative-ref adjustment,
preserving $-anchored parts+ for all columns, -/_ for individual column adjustment.tshts files in JSON formatCtrl+S to save, Ctrl+O to load spreadsheet filesCtrl+E to export CSV, Ctrl+I/Ctrl+L to import CSVPerformance: Built in Rust for excellent performance and memory efficiency. Handles large spreadsheets smoothly in terminal environments.
Portability: Cross-platform support (Linux, macOS, Windows) with no GUI dependencies. Perfect for servers, remote work, and headless environments.
Developer-Friendly: Clean architecture following domain-driven design principles. Comprehensive documentation, extensive test coverage, and modular structure make it easy to extend.
Modern Workflow: Git-friendly JSON format, command-line integration, and automation support. Works seamlessly with CI/CD pipelines and version control.
Rich Feature Set: Advanced formula engine with web functions (GET), string manipulation, logical operations, and mathematical functions. Real-time search, undo/redo, and smart autofill capabilities.
TSHTS provides a comprehensive spreadsheet experience with:
GET function for fetching data from URLs and APIsUPPER, LOWER, TRIM, FIND, MID, etc.SUM, AVERAGE, MIN, MAX, ABS, SQRT, ROUND, and moreIF, AND, OR, NOT with full boolean logic supportA1:C3) in all applicable functions.tshts format and CSV import/exportUpcoming features:
INDIRECT / OFFSET, conditional
formatting, multi-column VLOOKUP, DATEDIFWant to contribute? Check our issues for good first contributions. We welcome: - Bug reports and feature requests - Documentation improvements - Performance optimizations - New formula functions - Platform-specific enhancements
TSHTS supports a powerful multi-type formula system that handles both numbers and strings seamlessly.
=2+3 → 5
=10-4 → 6
=A1*B1 → Multiplies values in A1 and B1
=15/3 → 5
=2**3 → 8 (2 to the power of 3)
=10%3 → 1 (10 modulo 3)
=SUM(A1,B1,C1) → Sum of individual cells
=SUM(A1:A10) → Sum of range A1 through A10
=AVERAGE(A1:A10) → Average of range
=MIN(A1:C3) → Minimum value in range
=MAX(A1:C3) → Maximum value in range
=ABS(-5) → 5 (absolute value)
=SQRT(16) → 4 (square root)
=ROUND(3.14159) → 3 (round to integer)
=ROUND(3.14159, 2) → 3.14 (round to 2 decimal places)
="Hello World" → Hello World
="" → (empty string)
="Hello" & " " & "World" → Hello World
="Number: " & 42 → Number: 42
="Result: " & (2+3) → Result: 5
=LEN("Hello") → 5 (string length)
=UPPER("hello") → HELLO (convert to uppercase)
=LOWER("WORLD") → world (convert to lowercase)
=TRIM(" spaces ") → spaces (remove leading/trailing spaces)
=LEFT("Hello World", 5) → Hello (first 5 characters)
=RIGHT("Hello World", 5) → World (last 5 characters)
=MID("Hello World", 6, 5) → World (5 chars starting at position 6)
=FIND("lo", "Hello") → 3 (position of "lo" in "Hello")
=FIND("World", "Hello World") → 6 (position of "World")
=CONCAT("A", "B", "C") → ABC (concatenate multiple values)
=CONCAT("Number: ", 123) → Number: 123
=FIND("text", A1, 3) → Find "text" in A1 starting from position 3
=GET("https://api.example.com/data") → Fetch raw content from API
=GET("https://jsonplaceholder.typicode.com/posts/1") → Get JSON data
=GET("https://raw.githubusercontent.com/user/repo/main/data.csv") → Fetch CSV
=LEN(GET("https://example.com")) → Get length of web content
=UPPER(GET("https://api.service.com")) → Convert fetched content to uppercase
=5<10 → 1 (true)
=A1>=B1 → 1 if A1 ≥ B1, 0 otherwise
="Hello"="Hello" → 1 (string equality)
="Hello"<>"World" → 1 (string inequality)
=A1<>B1 → 1 if values are different
=IF(A1>10, "High", "Low") → Conditional with string results
=IF(A1="Hello", "Found", "Not Found") → String condition
=AND(A1>0, B1<10) → 1 if both conditions true
=OR(A1=0, B1=0) → 1 if either condition true
=NOT(A1>5) → 1 if A1 ≤ 5
=A1 → Value from cell A1 (auto-detects number vs string)
=A1+B1 → Sum if numeric, concatenation if mixed types
=SUM(A1:A10) → Sum of range A1 through A10
=AVERAGE(B1:B5) → Average of range B1 through B5
=CONCAT(A1:A3) → Concatenate all values in range A1:A3
TSHTS automatically handles type conversion: - Numeric operations: Strings are converted to numbers (empty/invalid = 0) - String operations: Numbers are converted to strings - Comparisons: Like types compared directly, mixed types compared as strings - Cell values: Auto-detected based on content
=UPPER(A1) & " - " & LOWER(B1) → Combine formatted strings
=IF(LEN(A1)>0, A1, "Empty") → Check for non-empty strings
=LEFT(A1, FIND(" ", A1)-1) → Extract first word
=MID(A1, FIND(" ", A1)+1, LEN(A1)) → Extract everything after first space
=IF(AND(LEN(A1)>3, A1<>""), "Valid", "Invalid") → Validate string length
=IF(OR(A1="", A1="N/A"), "Missing", A1) → Handle missing data
=SUM(A1:A10) & " total items" → Numeric result with description
=IF(AVERAGE(A1:A10)>50, "PASS", "FAIL") → Grade based on average
=CONCAT("Hello ", A1, ", you scored ", B1, "%") → Dynamic messages
#ERROR"" is considered different from empty cells"Quote""Test" → Quote"Testtshts foo.tshts opens at startupn / N for next / previous:regex on, :case on: search-option togglesTSHTS uses sensible defaults but can be customized:
spreadsheet.tshtsTSHTS saves files in a clean JSON format that's both human-readable and version-control friendly:
{
"cells": [
[0, 0, {"value": "Hello", "formula": null}],
[1, 1, {"value": "42", "formula": "=6*7"}]
],
"rows": 100,
"cols": 26,
"column_widths": {"0": 15},
"default_column_width": 8
}
TSHTS follows clean architecture and domain-driven design principles:
``` src/ ├── domain/ # Core business logic (no external dependencies) │ ├── models.rs # Data structures (Spreadsheet, CellData) │ ├── services.rs # Formula evaluation engine and CSV operations │ └── parser.rs # Expression parser with formal BNF grammar ├── application/ # Application orchestration │ └── state.r
$ claude mcp add tshts \
-- python -m otcore.mcp_server <graph>