# e3po

**E3 Python Option** - A terminal-based text editor written in Python, inspired by the E, E3, E1, and E2 editors.

## Features

- **2D cursor space** - cursor can move anywhere, not bounded by line length
- **Block marking system** - LINE (Alt-L), BLOCK (Alt-B), CHAR (Alt-Z), WORD (Alt-W)
- **Mark operations** - Copy (Alt-C), Move (Alt-M), Delete (Alt-D), Overlay (Alt-O)
- **Undo/Redo** - F9 to undo, Ctrl-Y or Ctrl-R to redo
- **Search & Replace** - `/pattern` to search, `c/old/new/` to replace with Y/N/Q/G prompts
- **Clipboard support** - Paste via terminal, Alt-K to copy to system clipboard
- **Function keys** - F1 Help, F2 Save, F3 Quit, F4 Save+Quit, F7/F8 Shift mark
- **Syntax highlighting** - Optional tree-sitter based highlighting for Python, C, C++ and more
- **Encryption** - age encryption for sensitive files (passphrase-based)

## Requirements

- Python 3.7 or higher
- A terminal with curses support (standard on macOS and Linux)
- No external dependencies for core editor

## Installation

```bash
pip install e3po-editor
```

Or from source:

```bash
git clone https://github.com/BlakeGFitch/e3po.git
cd e3po
pip install -e .
```

## Usage

### Terminal Version (curses)
```bash
# Edit a file
e3po myfile.txt

# Create new file
e3po

# Run as module (alternative)
python -m e3po myfile.txt
```

### GUI Version (pygame)
The GUI version provides full keyboard access including Ctrl+Delete which doesn't work reliably in terminals.

```bash
# Install with GUI support
pip install e3po-editor[gui]

# Run the GUI editor
e3po-gui myfile.txt

# With custom font size
e3po-gui -s 18 myfile.txt

# With specific font
e3po-gui -f "Monaco" -s 16 myfile.txt
```

## Key Bindings

### Function Keys
| Key | Action |
|-----|--------|
| F1 | Help |
| F2 | Save |
| F3 | Quit (no save) |
| F4 | Save and quit |
| F7 | Shift mark left |
| F8 | Shift mark right |
| F9 | Undo |
| F10 | Next file (not yet implemented) |

### Undo/Redo
| Key | Action |
|-----|--------|
| F9 | Undo |
| Ctrl-Y | Redo |
| Ctrl-R | Redo (alternative) |

### Alt Keys (Mark Operations)
| Key | Action |
|-----|--------|
| Alt-L | Mark line(s) |
| Alt-B | Mark block (rectangular) |
| Alt-Z | Mark characters |
| Alt-W | Mark word |
| Alt-U | Unmark |
| Alt-C | Copy block to cursor |
| Alt-M | Move block to cursor |
| Alt-D | Delete marked region |
| Alt-F | Fill marked region with character |
| Alt-O | Overlay block at cursor |
| Alt-K | Copy mark to system clipboard |
| Alt-Y | Go to mark start |
| Alt-E | Go to mark end |
| Alt-S | Split line |
| Alt-J | Join lines |

### Ctrl Keys
| Key | Action |
|-----|--------|
| Ctrl-B | Toggle bookmark on line |
| Ctrl-Up/Down | Navigate bookmarks |
| Ctrl-N | Next file |
| Ctrl-P | Previous file |
| Ctrl-C | Copy mark to clipboard |
| Ctrl-K | Delete current line (most reliable) |
| Ctrl-Delete | Delete current line (terminal-dependent) |
| Ctrl-Backspace | Delete current line (terminal-dependent) |
| Ctrl-F | Repeat last search |
| Ctrl-E | Erase to end of line |
| Ctrl-S | Toggle spell check mode |
| Ctrl-Y | Redo |
| Ctrl-R | Redo |
| Ctrl-Home | Top of file |
| Ctrl-End | End of file |
| Ctrl-Left | Previous word |
| Ctrl-Right | Next word |

### Visual Indicators
- **Modified line markers** - Orange/yellow bar on left edge shows lines changed since last save
- **Minimap** (GUI only) - Shows file overview on right edge. Click to navigate. Shows marks, bookmarks (green), modified lines (orange). Toggle with `minimap` command. Auto-disabled for files >5000 lines.

**Note:** Ctrl+Delete/Backspace support varies by terminal:
- **macOS Terminal.app**: e3po auto-launches in iTerm2 (if installed) for proper support. iTerm2 is free: `brew install --cask iterm2`
- **Linux**: Many terminals (GNOME Terminal, Konsole) don't send distinct codes for Ctrl+Delete. Use **Ctrl-K** instead, which always works.

### Command Line (press ESC to enter)
| Command | Action |
|---------|--------|
| `123` | Go to line 123 |
| `/pattern` | Search forward |
| `/pattern/c` | Search (case insensitive) |
| `c/old/new/` | Replace (interactive Y/N/Q/G) |
| `c/old/new/*` | Replace all |
| `t` or `top` | Go to top of file |
| `b` or `bot` | Go to bottom of file |
| `s` or `save` | Save file |
| `q` or `quit` | Quit |
| `n filename` | Set filename |
| `e filename` | Edit file |

### Text Processing Commands
| Command | Action |
|---------|--------|
| `sort` | Sort lines (use with mark for partial sort) |
| `sort -r` | Sort in reverse |
| `sort -n` | Numeric sort |
| `sort -k2` | Sort by field 2 |
| `uniq` | Remove adjacent duplicate lines |
| `uniq -i` | Case-insensitive uniq |
| `grep pattern` | Keep only matching lines |
| `grep -v pattern` | Delete matching lines |
| `grep -i pattern` | Case-insensitive grep |

### Spell Check
| Command/Key | Action |
|-------------|--------|
| `spell` | Toggle spell check mode |
| `n` | Next misspelled word |
| `p` | Previous misspelled word |
| `1-9` | Replace with suggestion |
| `s` | Skip word (this session) |
| `a` | Add word to dictionary |
| `o` | Turn off spell mode |

## Development

### Project Structure

```
e3po/
├── src/e3po/
│   ├── __init__.py
│   ├── editor.py          # Terminal editor (curses)
│   ├── editor_pygame.py   # GUI editor (pygame)
│   └── syntax/            # Syntax highlighting
│       ├── highlighter.py
│       └── queries/       # Tree-sitter queries
├── tests/
│   ├── test_buffer.py
│   ├── test_marks.py
│   ├── test_undo_redo.py
│   ├── test_pygame_editor.py  # GUI editor tests
│   └── ...
├── pyproject.toml
├── README.md
└── SPEC.md
```

### Setting Up Development Environment

```bash
git clone https://github.com/bgf/e3po.git
cd e3po
python3 -m venv venv
source venv/bin/activate
pip install -e ".[dev]"
```

### Running Tests

```bash
# Run all tests
pytest tests/ -v

# Run specific test file
pytest tests/test_buffer.py -v

# Run with coverage (if installed)
pytest tests/ --cov=e3po
```

### Adding Tests

Tests use pytest and a mock screen object. Example:

```python
from e3po.editor import Buffer, Editor

def test_my_feature():
    editor = make_editor(["line1", "line2"])
    # ... test code ...
    assert editor.buffer.lines == ["expected"]
```

## Syntax Highlighting

e3po supports optional syntax highlighting using tree-sitter.

### Quick Start

```bash
pip install e3po-editor[syntax]
```

### Supported Languages

| Language | Package | File Extensions |
|----------|---------|-----------------|
| Python | tree-sitter-python | .py, .pyw, .pyi |
| C | tree-sitter-c | .c, .h |
| C++ | tree-sitter-cpp | .cpp, .cc, .cxx, .hpp |
| Bash | tree-sitter-bash | .sh, .bash |
| JSON | tree-sitter-json | .json |
| YAML | tree-sitter-yaml | .yaml, .yml |
| JavaScript | tree-sitter-javascript | .js, .mjs |
| Rust | tree-sitter-rust | .rs |
| Go | tree-sitter-go | .go |

### Installing Additional Languages

```bash
pip install tree-sitter-<language>
```

## Encryption

e3po supports age encryption for sensitive files. Encrypted files are detected automatically by magic bytes.

### Encrypting a File

1. Open a plaintext file: `e3po secrets.txt`
2. Press `ESC`, type `encrypt`, press Enter
3. Enter passphrase twice
4. Save with `F2` (file is now encrypted in place)

### Opening Encrypted Files

```bash
e3po secrets.txt  # Prompts for passphrase if encrypted
```

### Commands

| Command | Action |
|---------|--------|
| `encrypt` | Encrypt current file with passphrase |
| `passwd` | Change passphrase for encrypted file |

### Notes

- Encrypted files are detected by magic bytes, not file extension
- Passphrase is cached in memory for the session, cleared on close
- Plaintext never touches disk once encrypted
- Uses [age](https://age-encryption.org/) encryption via pyrage library

## License

MIT License. Based on the E, E3, E1, and E2 editors.
