npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

termxl

v1.1.0

Published

Terminal-native spreadsheet — Excel in your terminal. Full formula engine, real-time recalculation, premium TUI.

Readme


  termxl | Book1                              Sheet1 | * Unsaved
  A1        fx: =SUM(A1:A5)
  --------------------------------------------------------------
       |      A       |      B       |      C       |      D
  -----+--------------+--------------+--------------+----------
   1   |          120 |          200 |     [=A1+B1] |
   2   |           50 |           30 |          80  |
   3   |           75 |          100 |         175  |
   4   |              |              |              |
   5   |              |              |              |
  --------------------------------------------------------------
  Value: 320  Type: number  Mode: NAV  | Arrows:move Enter:edit

Quick Start

npm install -g termxl
termxl                    # New blank workbook
termxl data.csv           # Open CSV file
termxl budget.txl         # Open native format
cat report.csv | termxl   # Import from pipe

That's it. No config files, no setup, no browser. Just install and run.


What Makes termxl Different

| Feature | Excel | Google Sheets | VisiData | sc-im | termxl | |---------|-------|---------------|----------|-------|------------| | Formula engine | Yes | Yes | No | Partial | Yes (23 functions) | | Real-time recalculation | Yes | Yes | No | Yes | Yes | | Dependency tracking | Yes | Yes | No | No | Yes | | Cycle detection | Yes | Yes | No | No | Yes | | Terminal-native | No | No | Yes | Yes | Yes | | Zero dependencies | No | No | No | No | Yes | | npm installable | No | No | No | No | Yes | | CSV import/export | Yes | Yes | Yes | Yes | Yes | | Native save format | .xlsx | Cloud | No | .sc | .txl (JSON) | | Keyboard-first | Partial | No (mouse) | Yes | Yes | Yes | | Cross-platform | Windows | Browser | Yes | Unix | Yes (Node.js) | | Viewport virtualization | Yes | Yes | Yes | Yes | Yes | | No account required | Yes | No | Yes | Yes | Yes | | File size | 2 GB+ | N/A | 40 MB | 5 MB | < 100 KB |

termxl combines the formula power of desktop spreadsheets with the speed and simplicity of a terminal tool. No GUI, no Electron, no browser -- just your data and your keyboard.


Formula Engine

termxl includes a complete formula engine built from scratch. Every formula goes through a four-stage pipeline:

Input:  =SUM(A1:A5) + B1 * 2

  Tokenizer  -->  [IDENT:SUM, LPAREN, CELL:A1, COLON, CELL:A5, RPAREN, PLUS, CELL:B1, STAR, NUMBER:2]

  Parser     -->  BinaryOp(+)
                  ├── FunctionCall(SUM, [RangeRef(A1:A5)])
                  └── BinaryOp(*)
                      ├── CellRef(B1)
                      └── NumberLiteral(2)

  Evaluator  -->  320 + 200 * 2 = 720

  Display    -->  720

Operator Precedence

Operators are evaluated in strict precedence order, matching Excel behavior:

| Precedence | Operator | Description | |:---:|:---:|---| | 1 (highest) | ^ | Exponentiation (right-associative) | | 2 | + - (unary) | Unary plus, unary minus | | 3 | * / | Multiplication, division | | 4 | + - | Addition, subtraction | | 5 (lowest) | > < >= <= = <> | Comparison operators |

Parentheses override precedence: =(2+3)*4 evaluates to 20, not 14.

Built-in Functions

termxl ships with 23 built-in functions organized by category:

Math

| Function | Syntax | Description | |----------|--------|-------------| | SUM | =SUM(A1:A10) | Sum all numeric values in a range | | ABS | =ABS(A1) | Absolute value | | ROUND | =ROUND(A1, 2) | Round to N decimal places | | INT | =INT(3.7) | Floor to nearest integer | | MOD | =MOD(10, 3) | Modulo (remainder) | | POWER | =POWER(2, 8) | Raise base to exponent | | SQRT | =SQRT(144) | Square root | | PI | =PI() | Returns 3.14159... |

Statistics

| Function | Syntax | Description | |----------|--------|-------------| | AVERAGE | =AVERAGE(A1:A10) | Arithmetic mean (alias: AVG) | | COUNT | =COUNT(A1:A10) | Count cells containing numbers | | COUNTA | =COUNTA(A1:A10) | Count non-blank cells | | MIN | =MIN(A1:A10) | Smallest numeric value | | MAX | =MAX(A1:A10) | Largest numeric value |

Logic

| Function | Syntax | Description | |----------|--------|-------------| | IF | =IF(A1>10, "High", "Low") | Conditional evaluation | | AND | =AND(A1>0, B1>0) | Logical AND | | OR | =OR(A1>0, B1>0) | Logical OR | | NOT | =NOT(A1) | Logical negation |

Text

| Function | Syntax | Description | |----------|--------|-------------| | CONCAT | =CONCAT(A1, " ", B1) | Concatenate values (alias: CONCATENATE) | | LEN | =LEN(A1) | String length | | UPPER | =UPPER(A1) | Convert to uppercase | | LOWER | =LOWER(A1) | Convert to lowercase |

Formula Examples

=A1+B1                         # Basic arithmetic
=SUM(A1:A10)                   # Range aggregation
=AVERAGE(B2:B100)              # Statistical mean
=IF(A1>100, "Over", "Under")   # Conditional logic
=ROUND(A1/B1, 2)               # Division with rounding
=POWER(2, 10)                  # Exponentiation (1024)
=AND(A1>0, A1<100)             # Compound condition
=CONCAT(A1, " ", B1)           # String joining
=IF(MOD(A1,2)=0,"Even","Odd")  # Nested functions
=SQRT(POWER(A1,2)+POWER(B1,2)) # Pythagorean distance

Error System

When a formula cannot be evaluated, termxl returns a typed error code identical to Excel conventions:

| Error | Meaning | |-------|---------| | #REF! | Reference to an invalid cell | | #NAME? | Unknown function name | | #VALUE! | Wrong argument type (e.g., text where number expected) | | #DIV/0! | Division by zero | | #CYCLE! | Circular reference detected | | #PARSE! | Formula syntax error (unmatched parentheses, bad tokens) |


Keyboard Controls

termxl is designed for keyboard-first interaction. Every action is reachable without a mouse.

| Key | Navigation Mode | Edit Mode | |-----|-----------------|-----------| | Arrow keys | Move active cell | Commit and move (Up/Down) | | Enter | Start editing current cell | Commit value, move down | | Escape | -- | Cancel edit, return to navigation | | = | Enter formula mode | -- | | Delete / Backspace | Clear cell contents | Delete last character | | Tab | Move one cell right | Commit value, move right | | Shift+Tab | Move one cell left | -- | | Ctrl+S | Save workbook | Save workbook | | Ctrl+Q | Quit | Quit | | Ctrl+C | Quit | Quit | | Page Up | Scroll up one page | -- | | Page Down | Scroll down one page | -- | | Home | Go to cell A1 | -- | | End | Go to last cell with data | -- | | Any printable key | Start editing with that character | Append to edit buffer |

Mode System

termxl operates in three distinct modes, shown in the status bar:

  • NAV (Navigation) -- Arrow keys move between cells. Type to start editing. Press = to enter a formula.
  • EDIT -- Free-form text entry. Press Enter to commit, Escape to cancel. The edit buffer appears both in the cell and the formula bar.
  • FORMULA -- Formula entry mode. Starts with = pre-filled. Same commit/cancel behavior as edit mode.

Architecture

User Input (keyboard)
    |
    v
Mode Manager (NAV / EDIT / FORMULA)
    |
    v
Spreadsheet Engine
+-- Cell Storage (Map<key, Cell>)
+-- Formula Engine
|   +-- Tokenizer
|   +-- Parser (recursive descent)
|   +-- AST
|   +-- Evaluator (23 functions)
+-- Dependency Graph
+-- Recalculation Engine
+-- Viewport Manager
    |
    v
TUI Renderer (ANSI)
+-- Top Bar (app name, workbook, sheet, save status)
+-- Formula Bar (cell label, fx content)
+-- Column/Row Headers (dynamic, scrollable)
+-- Cell Grid (virtualized, colored by type)
+-- Status Bar (value, type, mode, key hints)

termxl uses zero npm runtime dependencies. Every component -- tokenizer, parser, evaluator, renderer, file I/O -- is built from scratch using only Node.js built-in modules (fs, path, process). This means:

  • No native bindings to compile
  • No node-gyp headaches
  • Works anywhere Node.js 18+ runs
  • Instant install, instant run
  • Total package size under 100 KB

Spreadsheet Engine

Cell Storage

Cells are stored in a Map<string, Cell> keyed by address label (e.g., "A1", "B2"). Each cell tracks:

  • raw -- the exact string the user typed
  • parsed -- the AST node (for formulas) or null (for literals)
  • value -- the computed RuntimeValue (number, string, boolean, blank, or error)
  • display -- the rendered text shown in the grid
  • dependencies -- set of cell keys this cell reads from
  • dependents -- set of cell keys that read from this cell

Dependency Tracking

When a formula is entered, termxl extracts all cell and range references from the AST and registers them as dependencies. The reverse mapping (dependents) is maintained simultaneously, forming a bidirectional dependency graph.

A1 = 100
B1 = 200
C1 = =A1+B1     -->  C1 depends on {A1, B1}
                      A1 has dependent {C1}
                      B1 has dependent {C1}
D1 = =C1*2      -->  D1 depends on {C1}
                      C1 has dependent {D1}

When A1 changes, the engine walks the dependent chain: A1 -> C1 -> D1, recalculating each cell in topological order.

Incremental Recalculation

termxl does not recalculate the entire sheet on every edit. When a cell changes:

  1. The cell's own value is recomputed
  2. The engine walks the dependents set recursively
  3. Only cells in the dependency chain are re-evaluated
  4. A visited-set prevents infinite loops

This keeps recalculation time proportional to the affected subgraph, not the total sheet size.

Cycle Detection

Circular references are detected at recalculation time. If the recalculation engine visits a cell that is already in the current walk path, it marks that cell with #CYCLE! and stops propagation. This prevents infinite loops while preserving all non-circular values.

A1 = =B1      A1 --> #CYCLE!
B1 = =A1      B1 --> #CYCLE!
C1 = =A1+1    C1 --> #CYCLE! (propagated from A1)
D1 = 42       D1 --> 42 (unaffected)

Viewport Virtualization

termxl only renders cells visible in the current terminal window. The viewport manager tracks:

  • startRow / startCol -- the top-left corner of the visible area
  • visibleRows / visibleCols -- computed dynamically from terminal dimensions
  • activeRow / activeCol -- the currently selected cell

When the active cell moves outside the visible area, the viewport scrolls to keep it on screen. Column count adjusts automatically on terminal resize. This means termxl can handle sheets with thousands of rows without any rendering overhead -- only the visible window is drawn each frame.


File Formats

CSV (Import/Export)

termxl reads and writes standard CSV files with full quoting support:

  • Comma-delimited fields
  • Double-quote escaping for fields containing commas, quotes, or newlines
  • Automatic type detection on import (numbers, booleans, strings)
termxl data.csv              # Open CSV in the TUI
cat data.csv | termxl        # Pipe CSV from stdin

CSV export writes computed values (not formulas) -- what you see is what you get.

.txl (Native Format)

The .txl format is a simple JSON file that preserves formulas, cell addresses, and workbook structure:

{
  "name": "Budget",
  "sheets": [
    {
      "name": "Sheet1",
      "cells": {
        "A1": "Revenue",
        "B1": "120000",
        "A2": "Expenses",
        "B2": "85000",
        "A3": "Profit",
        "B3": "=B1-B2"
      }
    }
  ]
}

Benefits of the .txl format:

  • Human-readable and version-control friendly
  • Preserves formulas (CSV exports only computed values)
  • Supports multiple sheets per workbook
  • Lightweight -- stores only non-empty cells

Project Structure

termxl/
├── src/
│   ├── index.ts                # CLI entry point, main loop, keypress handler
│   ├── formula/
│   │   ├── types.ts            # Token types, AST nodes, RuntimeValue, ErrorCode
│   │   ├── tokenizer.ts        # Lexer: string --> Token[]
│   │   ├── parser.ts           # Recursive-descent parser: Token[] --> AST
│   │   ├── evaluator.ts        # AST evaluator, 23 built-in functions
│   │   ├── functions.ts        # Function registry, isKnownFunction()
│   │   └── index.ts            # Barrel export
│   ├── spreadsheet/
│   │   ├── types.ts            # Cell, Sheet, Workbook, ViewportState interfaces
│   │   ├── sheet.ts            # Cell CRUD, dependency graph, recalculation
│   │   ├── workbook.ts         # Workbook/sheet management
│   │   ├── viewport.ts         # Viewport scrolling and navigation
│   │   └── index.ts            # Barrel export
│   ├── io/
│   │   ├── csv.ts              # CSV import/export with quote handling
│   │   └── txl.ts              # Native .txl JSON format read/write
│   └── tui/
│       └── renderer.ts         # ANSI TUI renderer (alt screen, grid, status bar)
├── dist/                       # Compiled output (tsup)
├── package.json
├── tsconfig.json
├── tsup.config.ts
├── LICENSE
└── README.md

Tech Stack

| Component | Technology | |-----------|-----------| | Language | TypeScript 5.5+ (strict mode) | | Runtime | Node.js 18+ | | Build | tsup (esbuild under the hood) | | Test | Vitest | | Type checking | tsc --noEmit | | Module format | CommonJS (for CLI compatibility) | | Terminal rendering | Raw ANSI escape sequences | | Formula parsing | Hand-written recursive-descent parser | | Cell storage | ES Map with string keys | | Dependencies | Zero runtime dependencies |


CLI Options

termxl                    # Interactive spreadsheet (default)
termxl <file.csv>         # Import CSV file
termxl <file.txl>         # Open native termxl workbook
cat data.csv | termxl     # Import CSV from stdin pipe
termxl --help             # Show help and keyboard reference
termxl -h                 # Short alias for --help
termxl --version          # Show version
termxl -v                 # Short alias for --version

Development

# Clone the repository
git clone https://github.com/Worth-Doing/termxl.git
cd termxl

# Install dev dependencies
npm install

# Build the project
npm run build

# Run the CLI
npm start

# Type check
npm run typecheck

# Run tests
npm test

Contributing

Contributions are welcome. termxl is built and maintained by WorthDoing AI.

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/your-feature)
  3. Commit your changes (git commit -m "Add your feature")
  4. Push to the branch (git push origin feature/your-feature)
  5. Open a Pull Request

Guidelines

  • All code must pass npm run typecheck with zero errors
  • Maintain zero runtime dependencies -- use only Node.js built-ins
  • Follow the existing code style (strict TypeScript, no any)
  • Add tests for new formula functions or engine features
  • Keep the formula engine Excel-compatible where possible

License

MIT -- Copyright (c) 2026 WorthDoing AI