A fully-functional terminal-based spreadsheet application inspired by the legendary Lotus 1-2-3. Built with Python and the Textual TUI framework.
This entire application was 100% coded by Claude Opus 4.5 using Claude Code CLI, vibe coded over a weekend.
Note: This project is provided as a reference implementation and educational resource. It is not intended for active development or production use. See Disclaimer below.
- Features
- Installation
- Quick Start Guide
- Keyboard Shortcuts
- Menu System
- Working with Formulas
- Creating Charts
- Data Operations
- File Formats
- Themes
- Architecture
- Running Tests
- Disclaimer
- License
- Large Grid: 256 columns (A-IV) × 65,536 rows
- Cell References: A1 notation with absolute/relative support (
$A$1,A1,$A1,A$1) - Range References: Multi-cell ranges (
A1:B10) - Named Ranges: Create and use named ranges in formulas
- 180+ Formula Functions: Comprehensive function library across 9 categories
- Dual Syntax: Both
=SUM(...)and Lotus-style@SUM(...)supported
| Prefix | Alignment | Example |
|---|---|---|
' |
Left | 'Hello |
" |
Right | "Hello |
^ |
Center | ^Title |
\ |
Repeat/Fill | \- (fills cell with -) |
Numbers are right-aligned by default, text is left-aligned.
- Sort (ascending/descending by column)
- Query with criteria ranges
- Fill (down, right, with series)
- Find and replace
| Format | Extension | Description |
|---|---|---|
| JSON | .json |
Native format with full feature support |
| XLSX/XLS | .xlsx, .xls |
Microsoft Excel format (import/export) |
| WK1/WKS | .wk1, .wks |
Lotus 1-2-3 binary format (import only) |
| CSV | .csv |
Comma-separated values |
| TSV | .tsv |
Tab-separated values |
Text-based charts rendered in the terminal:
- Line charts
- Bar charts (vertical and horizontal)
- Stacked bar charts
- XY Scatter plots
- Pie charts
- Area charts
- Lotus-style
/Menu: Hierarchical menu system - Multiple Themes: Classic Lotus blue, Tomorrow Night, Mocha
- Full Keyboard Navigation: Vim-like efficiency
- Range Selection: Shift+Arrow or mouse drag
- Undo/Redo: Full history support
- Copy/Cut/Paste: Internal and OS clipboard integration
Requires Python 3.11+ and uv.
# Clone the repository
git clone https://github.com/mdemirhan/pylotus123.git
cd pylotus123
# Install dependencies
uv sync# Start with empty spreadsheet
uv run python main.py
# Open an existing file
uv run python main.py samples/sales_dashboard.json
uv run python main.py samples/sample1.json- Move around: Use arrow keys to navigate between cells
- Jump to a cell: Press
Ctrl+GorF5, then type a cell reference likeA1orZ100 - Scroll quickly: Use
Page Up/Page Downfor vertical scrolling - Go to start: Press
Hometo go to column A, orCtrl+Hometo go to cell A1
- Type directly: Just start typing - the cell will enter edit mode automatically
- Edit existing cell: Press
EnterorF2to edit the current cell - Confirm entry: Press
Enterto save your input - Cancel editing: Press
Escapeto discard changes
123 → Stored as number, right-aligned
Hello → Stored as text, left-aligned
'123 → Stored as text (apostrophe prefix), left-aligned
^Title → Centered text
"Right → Right-aligned text
\- → Repeating character (fills cell with dashes)
Formulas start with = or the Lotus-style @:
=A1+B1 → Add two cells
=SUM(A1:A10) → Sum a range
@SUM(A1:A10) → Lotus-style syntax
=A1*1.1 → Multiply by constant
- With keyboard: Hold
Shiftand use arrow keys to extend selection - With mouse: Click and drag to select a range
- View selection: Selected cells are highlighted
- Select a range of cells
- Press
Ctrl+Cto copy orCtrl+Xto cut - Navigate to the destination
- Press
Ctrl+Vto paste
- Save: Press
Ctrl+S(saves to current file, or prompts for filename) - Save As: Use menu
/→File→Save - Open: Press
Ctrl+Oor use menu/→File→Retrieve - New: Press
Ctrl+Nfor a blank spreadsheet
Press / to open the Lotus-style menu bar. Navigate with arrow keys and press Enter to select.
| Key | Action |
|---|---|
| Arrow keys | Move cursor |
Page Up/Down |
Scroll vertically |
Home |
First column |
End |
Last used column |
Ctrl+Home |
Cell A1 |
Ctrl+G / F5 |
Go to cell |
| Key | Action |
|---|---|
Enter / F2 |
Edit cell |
Delete |
Clear cell |
Escape |
Cancel edit |
F4 |
Toggle absolute reference ($) |
F9 |
Recalculate all |
| Key | Action |
|---|---|
Shift+Arrow |
Extend selection |
Ctrl+Shift+End |
Select to last cell |
| Key | Action |
|---|---|
Ctrl+C |
Copy |
Ctrl+X |
Cut |
Ctrl+V |
Paste |
| Key | Action |
|---|---|
Ctrl+S |
Save |
Ctrl+O |
Open |
Ctrl+N |
New |
Ctrl+Q |
Quit |
| Key | Action |
|---|---|
/ |
Open menu |
Ctrl+Z |
Undo |
Ctrl+Y |
Redo |
Ctrl+T |
Change theme |
F3 |
Find |
Press / to access the Lotus-style menu:
┌─ Worksheet ─┬─ Range ─┬─ Copy ─┬─ Move ─┬─ File ─┬─ Print ─┬─ Graph ─┬─ Data ─┬─ System ─┬─ Quit ─┐
- Worksheet: Insert/delete rows/columns, column width, global settings, erase
- Range: Format cells, set labels, name ranges, justify text
- Copy: Copy cells to new location (Lotus-style: prompts for destination)
- Move: Move cells to new location
- File: New, open, save, import/export (XLSX, CSV, TSV, WK1)
- Graph: Create and view charts (line, bar, pie, etc.)
- Data: Sort, query, fill operations
- Quit: Exit application
=A1+B1 # Addition
=A1-B1 # Subtraction
=A1*B1 # Multiplication
=A1/B1 # Division
=A1^2 # Power (A1 squared)
=(A1+B1)*C1 # Parentheses for order of operations
Functions can use = or Lotus-style @ prefix:
=SUM(A1:A10) # Sum of range
@AVG(B1:B20) # Average (Lotus-style)
=MAX(A1:A100) # Maximum value
=MIN(A1:A100) # Minimum value
=COUNT(A1:A50) # Count of numbers
=COUNTA(A1:A50) # Count of non-empty cells
=IF(A1>100,"High","Low") # Simple IF
=IF(A1>100,"High",IF(A1>50,"Med","Low")) # Nested IF
=AND(A1>0,A1<100) # Logical AND
=OR(A1="Yes",A1="Y") # Logical OR
=LEFT(A1,3) # First 3 characters
=RIGHT(A1,2) # Last 2 characters
=MID(A1,2,4) # 4 chars starting at position 2
=LEN(A1) # Length of text
=UPPER(A1) # Convert to uppercase
=LOWER(A1) # Convert to lowercase
=TRIM(A1) # Remove extra spaces
=CONCATENATE(A1," ",B1) # Join text
=A1&" "&B1 # Join text (alternative)
=VLOOKUP(A1,D1:E100,2) # Vertical lookup
=HLOOKUP(A1,A1:Z2,2) # Horizontal lookup
=INDEX(A1:C10,3,2) # Value at row 3, col 2
=MATCH(100,A1:A50,0) # Find position of value
=TODAY() # Current date
=NOW() # Current date and time
=DATE(2024,12,25) # Create date
=YEAR(A1) # Extract year
=MONTH(A1) # Extract month
=DAY(A1) # Extract day
=PMT(0.05/12,360,200000) # Monthly payment (5% APR, 30yr, $200k)
=PV(0.08,10,1000) # Present value
=FV(0.06,5,0,1000) # Future value
=NPV(0.1,A1:A5) # Net present value
=IRR(A1:A10) # Internal rate of return
A1 # Relative reference (adjusts when copied)
$A$1 # Absolute reference (never adjusts)
$A1 # Mixed: column absolute, row relative
A$1 # Mixed: column relative, row absolute
Tip: Press F4 while editing to cycle through reference types.
- Select a range of cells
- Press
/→Range→Name - Enter a name (e.g.,
SALES) - Use in formulas:
=SUM(SALES)
-
Enter your data in a tabular format:
A B C D 1 Category Q1 Q2 Q3 2 North 1000 1200 1100 3 South 800 900 950 4 East 1200 1300 1400 -
Open the Graph menu: Press
/→Graph -
Set the chart type: Select
Typeand choose:Line- Line chartBar- Vertical bar chartStacked-Bar- Stacked bar chartXY- Scatter plotPie- Pie chart
-
Set the X-axis range (labels):
- Select
Xfrom the menu - Select the range containing your labels (e.g.,
A2:A4)
- Select
-
Set the data series (A through F):
- Select
Afrom the menu - Select your first data series (e.g.,
B2:B4) - Repeat for series B, C, etc. as needed
- Select
Tip: If you select a range in the spreadsheet before opening the Graph menu and choosing X, A, B, etc., the selected range will automatically be used as the series input without prompting you to enter it again.
-
View the chart: Select
Viewto display the chart -
Optional - Set titles:
- Use
Options→Titlesto add chart title and axis labels
- Use
1. Enter data:
A1: Month B1: Sales
A2: Jan B2: 5000
A3: Feb B3: 6200
A4: Mar B4: 5800
A5: Apr B5: 7100
2. Press / → Graph → Type → Bar
3. Press / → Graph → X
Select A2:A5 (month labels)
4. Press / → Graph → A
Select B2:B5 (sales data)
5. Press / → Graph → View
| Type | Best For |
|---|---|
| Line | Trends over time |
| Bar | Comparing categories |
| Stacked Bar | Part-to-whole comparisons |
| XY Scatter | Correlation between variables |
| Pie | Proportions of a whole |
Charts can be saved to separate .chart files and loaded later. This is useful for:
- Reusing chart configurations across different spreadsheets
- Creating chart templates with predefined settings
- Backing up complex chart setups
To Save a Chart:
- Configure your chart (set type, X range, data series A-F, titles, etc.)
- Press
/→Graph→Save - Enter a filename (
.chartextension added automatically)
To Load a Chart:
- Press
/→Graph→Load - Select the
.chartfile
What is saved in a .chart file:
- Chart type (line, bar, pie, etc.)
- X-axis range reference (e.g.,
A1:A10) - Data series (A through F) with their range references
- Axis settings (titles, min/max values, scale type, grid lines)
- Chart options (title, subtitle, legend position)
Important Notes:
- Chart files store range references, not actual data values
- When you load a chart, it reads data from the current spreadsheet using the saved range references
- This means you can create a "chart template" and apply it to different spreadsheets with similar data layouts
- To reset a chart configuration, use
/→Graph→Reset
- Select your data range (including headers if present)
- Press
/→Data→Sort - Set the primary sort column:
- Enter the column letter to sort by
- Choose order: Ascending (A) or Descending (D)
- Optional: Set secondary sort column
Example: Sort a list by column B in descending order:
1. Select A1:C100 (your data range)
2. / → Data → Sort
3. Primary key: B
4. Order: D (descending)
Copy the top cell's value/formula down through a selected range:
- Enter a value or formula in the first cell
- Select the range to fill (including the source cell)
- Press
/→Data→Fill→Down
Same as Fill Down, but copies rightward:
- Enter a value in the leftmost cell
- Select the range
- Press
/→Data→Fill→Right
Create a sequence of numbers or dates:
- Select the range to fill
- Press
/→Data→Fill→Series - Enter start value, step, and stop value
Set up a database query to find and extract records:
-
Set up your database range (your data with headers):
A1: Name B1: Dept C1: Salary A2: John B2: Sales C2: 50000 A3: Jane B3: IT C3: 65000 ... -
Create a criteria range (headers + conditions):
E1: Dept F1: Salary E2: Sales F2: >40000 -
Set up the query:
- Press
/→Data→Query Input: Select your database range (A1:C100)Criteria: Select your criteria range (E1:F2)Output: Select where to put results
- Press
-
Execute:
Find: Find matching recordsExtract: Copy matching records to output range
Use these functions to calculate values based on criteria:
=DSUM(A1:C100,C1,E1:F2) # Sum of Salary where criteria match
=DAVG(A1:C100,C1,E1:F2) # Average Salary where criteria match
=DCOUNT(A1:C100,C1,E1:F2) # Count matching records
=DMAX(A1:C100,C1,E1:F2) # Maximum matching value
=DMIN(A1:C100,C1,E1:F2) # Minimum matching value
The default format with full feature support:
- All formulas preserved
- Column widths and formatting saved
- Named ranges included
- Chart definitions saved
# Save/open JSON files
uv run python main.py myfile.jsonImport and export Excel files via the menu:
- Press
/→File→Import→XLSX - Press
/→File→Export→XLSX
Or open XLSX files directly from the command line:
uv run python main.py spreadsheet.xlsxWhat is preserved in XLSX:
- Cell values (numbers, text, dates)
- Formulas (converted to Excel syntax)
- Column widths
- Text alignment (left, right, center)
- Basic number formatting
What is NOT preserved in XLSX:
- Named ranges
- Charts (not embedded in XLSX)
- Lotus-style label prefixes (converted to alignment)
- Complex conditional formatting
Note on WK1 Support: The WK1 file format support was implemented to help preserve knowledge of this historical file format. The WK1 format was the native binary format used by Lotus 1-2-3 versions 1.x and 2.x, and represents an important piece of computing history.
Accuracy Disclaimer: While we've made best efforts to implement the WK1 format correctly based on available documentation, results may not be 100% accurate. Some features may not be fully supported, and edge cases may exist. If you're working with important WK1 files, please verify the imported data carefully.
Import via menu:
- Press
/→File→Import→WK1
Or open WK1/WKS files directly from the command line:
uv run python main.py spreadsheet.wk1What is imported from WK1:
- Cell values (numbers, strings, formulas)
- Formulas (converted from WK1 bytecode format)
- Column widths
- Named ranges
- Cell format codes (fixed, scientific, currency, percent, comma, date/time)
WK1 Format Limitations:
- Maximum grid size: 256 columns × 8,192 rows (original Lotus 1-2-3 limits)
- Some complex formula expressions may not import perfectly
For data exchange with other applications:
Import:
- Press
/→File→Import - Select
Text - Choose delimiter (Comma, Tab, or custom)
- Select the file
Export:
- Press
/→File→Export - Select
Text - Choose format (CSV or TSV)
- Enter filename
Important: When exporting to CSV or TSV, formulas are converted to their calculated values. The exported file contains only the results, not the original formulas. This is standard behavior for data interchange formats.
What is preserved in CSV/TSV:
- All cell values (as calculated results)
- Text content
What is NOT preserved in CSV/TSV:
- Formulas (converted to values)
- Cell formatting and alignment
- Column widths
- Named ranges
- Charts
Three built-in color themes:
| Theme | Description |
|---|---|
| Lotus 1-2-3 | Classic blue theme faithful to the original |
| Tomorrow Night | Modern dark theme with muted colors |
| Mocha | Catppuccin Mocha color palette |
Switch themes with Ctrl+T or via the menu.
lotus123/
├── app.py # Main TUI application
├── core/ # Data model (cell, spreadsheet, formatting)
├── formula/ # Formula engine (parser, evaluator, functions)
├── ui/ # UI components (grid, menus, dialogs, themes)
├── data/ # Data operations (sort, query, fill)
├── io/ # File I/O (JSON, XLSX, CSV, TSV, WK1)
├── charting/ # Chart renderers
├── handlers/ # Application event handlers
└── utils/ # Utilities (undo/redo, clipboard)
SUM, ABS, INT, ROUND, MOD, SQRT, POWER, SIGN, TRUNC, CEILING, FLOOR, FACT, GCD, LCM, EXP, LN, LOG, SIN, COS, TAN, ASIN, ACOS, ATAN, ATAN2, DEGREES, RADIANS, PI, RAND
AVG, AVERAGE, COUNT, COUNTA, COUNTBLANK, MIN, MAX, MEDIAN, STD, STDEV, VAR, MODE, LARGE, SMALL, RANK, PERCENTILE, QUARTILE, GEOMEAN, HARMEAN, PRODUCT, SUMPRODUCT, SUMSQ, COMBIN, PERMUT
LEFT, RIGHT, MID, LENGTH, LEN, FIND, SEARCH, REPLACE, SUBSTITUTE, UPPER, LOWER, PROPER, TRIM, CLEAN, VALUE, STRING, CHAR, CODE, CONCAT, CONCATENATE, EXACT, REPEAT, REPT, TEXT
IF, TRUE, FALSE, AND, OR, NOT, XOR, ISERR, ISERROR, ISNA, ISNUMBER, ISSTRING, ISTEXT, ISBLANK, ISLOGICAL, ISEVEN, ISODD, NA, ERR, IFERROR, IFNA, SWITCH, CHOOSE
VLOOKUP, HLOOKUP, INDEX, LOOKUP, MATCH, ADDRESS, INDIRECT, COLUMNS, COLS, COLUMN, ROWS, ROW, OFFSET, TRANSPOSE
DATE, DATEVALUE, DAY, MONTH, YEAR, TIME, TIMEVALUE, HOUR, MINUTE, SECOND, NOW, TODAY, WEEKDAY, DAYS, EDATE, EOMONTH, YEARFRAC
PMT, PV, FV, NPV, IRR, RATE, NPER, CTERM, SLN, SYD, DDB, IPMT, PPMT, TERM
DSUM, DAVG, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DSTD, DSTDEV, DVAR
TYPE, CELL, ISNUMBER, ISSTRING, ISERR, ISNA, INFO, ISFORMULA
# Run all tests
uv run pytest
# Run with coverage
uv run pytest --cov=lotus123
# Run specific test file
uv run pytest tests/core/test_spreadsheet.py
# Run specific test
uv run pytest tests/core/test_spreadsheet.py::TestCellAlignment -vThe samples/ directory contains example spreadsheets:
sales_dashboard.json- Sales report with formatting examplessample1.json- Sample spreadsheet with various data typessample1.xlsx/sales_dashboard.xlsx- Excel format examplessample1.wk1- Lotus 1-2-3 WK1 format examplesample1.csv/sample1.tsv- Delimited text format examples
THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
Reference Implementation: This project is provided as a reference implementation and educational resource. It is not intended for active development or production use.
-
No Support: This is a hobby project created over a weekend. No ongoing support, maintenance, or updates should be expected.
-
Data Accuracy: While efforts have been made to implement calculations correctly, do not rely on this software for critical calculations. Always verify important results with established spreadsheet software.
-
WK1 Format: The WK1 file format support is provided to help preserve historical knowledge. Results may not be 100% accurate, and some features may not be fully supported.
-
AI-Generated Code: This entire application was generated by Claude (AI). While it has been tested, AI-generated code may contain unexpected behaviors or bugs.
Use at your own risk.
MIT License - See LICENSE file for details.
- Inspired by Lotus 1-2-3, the spreadsheet that defined an industry
- Built with Textual - a fantastic TUI framework for Python
- 100% coded by Claude using Claude Code CLI


