420 lines
13 KiB
Markdown
420 lines
13 KiB
Markdown
<p align="center">
|
||
<img src="https://raw.githubusercontent.com/charmbracelet/vhs/main/examples/neofetch/out.gif" width="0" height="0" />
|
||
</p>
|
||
|
||
<h1 align="center">
|
||
<br>
|
||
<pre>
|
||
██████╗ ██╗███╗ ███╗
|
||
██╔════╝ ██║████╗ ████║
|
||
██║ ███╗██║██╔████╔██║
|
||
██║ ██║██║██║╚██╔╝██║
|
||
╚██████╔╝██║██║ ╚═╝ ██║
|
||
╚═════╝ ╚═╝╚═╝ ╚═╝
|
||
</pre>
|
||
<br>
|
||
<em>Go + Vim = Gim</em>
|
||
<br>
|
||
</h1>
|
||
|
||
<p align="center">
|
||
<strong>A blazingly fast, terminal-based text editor with vim-style keybindings</strong>
|
||
</p>
|
||
|
||
<p align="center">
|
||
<a href="#-features">Features</a> •
|
||
<a href="#-installation">Installation</a> •
|
||
<a href="#-keybindings">Keybindings</a> •
|
||
<a href="#-architecture">Architecture</a> •
|
||
<a href="#-roadmap">Roadmap</a>
|
||
</p>
|
||
|
||
<p align="center">
|
||
<img src="https://img.shields.io/badge/Go-1.25-00ADD8?style=for-the-badge&logo=go&logoColor=white" alt="Go Version" />
|
||
<img src="https://img.shields.io/badge/Built_with-BubbleTea-FF69B4?style=for-the-badge" alt="BubbleTea" />
|
||
<img src="https://img.shields.io/badge/Styled_with-Lipgloss-9B59B6?style=for-the-badge" alt="Lipgloss" />
|
||
<img src="https://img.shields.io/badge/License-MIT-green?style=for-the-badge" alt="License" />
|
||
</p>
|
||
|
||
---
|
||
|
||
## ✨ What is Gim?
|
||
|
||
**Gim** is a modern, lightweight text editor written in Go that brings the power of vim-style modal editing to your terminal. Built on the excellent [Charm](https://charm.sh) stack, it combines the speed of Go with the elegance of functional UI patterns.
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────┐
|
||
│ Why Gim? │
|
||
├──────────────────────────────────────────────────────────────┤
|
||
│ 🚀 Fast - Native Go performance │
|
||
│ 🎨 Beautiful - Lipgloss-powered terminal styling │
|
||
│ 🧠 Vim-like - Modal editing for efficiency │
|
||
│ 🧪 Well-tested - Comprehensive integration test suite │
|
||
│ 📦 Single binary - No dependencies, just run │
|
||
└──────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## Trade Offs
|
||
|
||
#### Undo Tree vs. Undo Stack
|
||
|
||
While the undo tree method that vim uses is powerful, I rarely find myself using it. A stack terminal-based
|
||
approach is more natural to "non-vim" users and much simpler to implement. Implementing a feature similar
|
||
to Vims undo tree would many times longer than a simple stack.
|
||
|
||
---
|
||
|
||
## TODO List
|
||
|
||
- Ops like change, and substitute and such should add to paste reg
|
||
- Delete op should also add to paste reg
|
||
- Gap buffer implementation (this shouldn't be TOO hard)
|
||
- Alternate buffer handling and implementation
|
||
- Scroll in X direction
|
||
|
||
---
|
||
|
||
## 🎯 Features
|
||
|
||
### 🎭 Six Editor Modes
|
||
|
||
| Mode | Key | Description |
|
||
|------|-----|-------------|
|
||
| **Normal** | `Esc` | Navigate and command - your home base |
|
||
| **Insert** | `i/a/o` | Type and create |
|
||
| **Visual** | `v` | Select characters |
|
||
| **Visual Line** | `V` | Select whole lines |
|
||
| **Visual Block** | `Ctrl+V` | Select rectangular regions |
|
||
| **Command** | `:` | Execute commands *(coming soon)* |
|
||
|
||
### ⌨️ Full Motion System
|
||
|
||
```
|
||
gg
|
||
↑
|
||
b ←── · ──→ w/e
|
||
↓
|
||
G
|
||
|
||
0 ──────── $
|
||
│ _ │
|
||
└──┴───────┘
|
||
line
|
||
```
|
||
|
||
- **Character motions**: `h` `j` `k` `l` - The classics
|
||
- **Word motions**: `w` `e` `b` - Jump by word boundaries
|
||
- **Line motions**: `0` `$` `_` - Start, end, first non-whitespace
|
||
- **File motions**: `gg` `G` - Top and bottom of file
|
||
|
||
### 🔧 Powerful Operators
|
||
|
||
| Operator | Action | Examples |
|
||
|----------|--------|----------|
|
||
| `d` | Delete | `dd` `dw` `d$` `dG` |
|
||
| `x` | Delete char | `x` `3x` |
|
||
|
||
*Operators compose with motions and counts!*
|
||
|
||
```
|
||
3 d 2w
|
||
↓ ↓ ↓
|
||
count op motion
|
||
|
||
= Delete 6 words (3 × 2)
|
||
```
|
||
|
||
### 🎪 Visual Mode Magic
|
||
|
||
Select text visually, then operate on it:
|
||
|
||
```
|
||
┌─────────────────────────────────┐
|
||
│ Hello, [world! How] are you? │ ← v + motion + d
|
||
│ Hello, are you? │ ← Result
|
||
└─────────────────────────────────┘
|
||
|
||
┌─────────────────────────────────┐
|
||
│ [Line one ] │
|
||
│ [Line two ] │ ← V + j + d
|
||
│ [Line three ] │
|
||
│ │ ← All lines deleted
|
||
└─────────────────────────────────┘
|
||
```
|
||
|
||
### 🔢 Count Everything
|
||
|
||
Prefix any command with a number:
|
||
|
||
| Input | Action |
|
||
|-------|--------|
|
||
| `5j` | Move down 5 lines |
|
||
| `3dd` | Delete 3 lines |
|
||
| `10i=Esc` | Insert `==========` |
|
||
| `2d3w` | Delete 6 words |
|
||
|
||
### 🪟 Smart Scrolling
|
||
|
||
- Automatic viewport following
|
||
- `scrollOff` margin keeps context visible
|
||
- Smooth cursor tracking
|
||
|
||
---
|
||
|
||
## 📦 Installation
|
||
|
||
### From Source
|
||
|
||
```bash
|
||
# Clone the repository
|
||
git clone https://git.gophernest.net/azpect/TextEditor.git
|
||
cd TextEditor
|
||
|
||
# Build
|
||
go build -o gim ./cmd/gim
|
||
|
||
# Run
|
||
./gim [filename]
|
||
```
|
||
|
||
### Quick Run
|
||
|
||
```bash
|
||
go run ./cmd/gim [filename]
|
||
```
|
||
|
||
---
|
||
|
||
## ⌨️ Keybindings
|
||
|
||
### Normal Mode
|
||
|
||
<details>
|
||
<summary><strong>🧭 Navigation</strong></summary>
|
||
|
||
| Key | Action |
|
||
|-----|--------|
|
||
| `h` | Move left |
|
||
| `j` | Move down |
|
||
| `k` | Move up |
|
||
| `l` | Move right |
|
||
| `w` | Next word start |
|
||
| `e` | Next word end |
|
||
| `b` | Previous word start |
|
||
| `0` | Line start |
|
||
| `$` | Line end |
|
||
| `_` | First non-whitespace |
|
||
| `gg` | File start |
|
||
| `G` | File end |
|
||
|
||
</details>
|
||
|
||
<details>
|
||
<summary><strong>✏️ Entering Insert Mode</strong></summary>
|
||
|
||
| Key | Action |
|
||
|-----|--------|
|
||
| `i` | Insert before cursor |
|
||
| `a` | Insert after cursor |
|
||
| `I` | Insert at line start |
|
||
| `A` | Insert at line end |
|
||
| `o` | Open line below |
|
||
| `O` | Open line above |
|
||
|
||
</details>
|
||
|
||
<details>
|
||
<summary><strong>🗑️ Deletion</strong></summary>
|
||
|
||
| Key | Action |
|
||
|-----|--------|
|
||
| `x` | Delete character |
|
||
| `dd` | Delete line |
|
||
| `d{motion}` | Delete to motion |
|
||
| `D` | Delete to end of line |
|
||
|
||
</details>
|
||
|
||
<details>
|
||
<summary><strong>👁️ Visual Mode</strong></summary>
|
||
|
||
| Key | Action |
|
||
|-----|--------|
|
||
| `v` | Character visual |
|
||
| `V` | Line visual |
|
||
| `Ctrl+V` | Block visual |
|
||
|
||
</details>
|
||
|
||
### Insert Mode
|
||
|
||
| Key | Action |
|
||
|-----|--------|
|
||
| `Esc` | Return to normal |
|
||
| `Backspace` | Delete previous char |
|
||
| `Delete` | Delete next char |
|
||
| `Ctrl+W` | Delete previous word |
|
||
| `Tab` | Insert tab (2 spaces) |
|
||
| `Enter` | New line |
|
||
| `↑↓←→` | Navigate |
|
||
|
||
### Visual Mode
|
||
|
||
All normal mode navigation keys work, plus:
|
||
|
||
| Key | Action |
|
||
|-----|--------|
|
||
| `d` | Delete selection |
|
||
| `Esc` | Return to normal |
|
||
|
||
---
|
||
|
||
## 🏗️ Architecture
|
||
|
||
Gim follows a clean, modular architecture inspired by the Elm Architecture (Model-Update-View):
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ cmd/gim/ │
|
||
│ Entry Point │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ internal/editor/ │
|
||
│ Model • Update • View • Style │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
│ │ │
|
||
▼ ▼ ▼
|
||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||
│ internal/input/ │ │ internal/motion/│ │internal/operator│
|
||
│ Handler │ │ h j k l w e │ │ d (delete) │
|
||
│ Keymap │ │ b 0 $ gg G │ │ │
|
||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||
│ │ │
|
||
└───────────────────┴────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ internal/action/ │
|
||
│ Action • Motion • Operator • Position │
|
||
│ (Core Interfaces) │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### Key Design Patterns
|
||
|
||
- **🔌 Interface-based**: Actions/motions use a `Model` interface, enabling clean testing
|
||
- **🎭 State Machine**: Input handler manages mode transitions and pending operations
|
||
- **📐 Motion Types**: Linewise vs Charwise motions for proper operator behavior
|
||
- **🔄 Composition**: Operators compose with motions (e.g., `d` + `w` = delete word)
|
||
|
||
---
|
||
|
||
## 🧪 Testing
|
||
|
||
Gim has comprehensive integration tests using the `teatest` library:
|
||
|
||
```bash
|
||
# Run all tests
|
||
go test ./...
|
||
|
||
# Run with verbose output
|
||
go test -v ./internal/editor/
|
||
|
||
# Run specific test
|
||
go test -v -run TestDeleteOperator ./internal/editor/
|
||
```
|
||
|
||
**Test Coverage Areas:**
|
||
- ✅ Basic motions (hjkl)
|
||
- ✅ Jump motions (gg, G, 0, $, _)
|
||
- ✅ Word motions (w, e, b)
|
||
- ✅ Delete operator with all motions
|
||
- ✅ Insert mode (all entry points, recording, replay)
|
||
- ✅ Visual mode (all three types)
|
||
- ✅ Scrolling behavior
|
||
|
||
---
|
||
|
||
## 🗺️ Roadmap
|
||
|
||
### ✅ Implemented
|
||
|
||
- [x] Modal editing (Normal, Insert, Visual, Visual Line, Visual Block)
|
||
- [x] Basic motions (hjkl, word motions, line motions)
|
||
- [x] Delete operator with motion composition
|
||
- [x] Count prefixes for all commands
|
||
- [x] Insert mode with recording/replay
|
||
- [x] Visual selection with operators
|
||
- [x] Smart scrolling with scrollOff
|
||
- [x] Relative line numbers
|
||
|
||
### 🚧 In Progress
|
||
|
||
- [ ] Command mode (`:` commands)
|
||
- [ ] File I/O (save/load)
|
||
|
||
### 🔮 Future
|
||
|
||
- [ ] **Operators**: `y` (yank), `c` (change), `p` (paste)
|
||
- [ ] **Motions**: `f`/`F`/`t`/`T` (find char), `/`/`?` (search), `{`/`}` (paragraph)
|
||
- [ ] **Features**:
|
||
- Undo/redo system
|
||
- Multiple buffers/tabs
|
||
- Syntax highlighting
|
||
- Configuration file
|
||
- Clipboard integration
|
||
- Macros (`q` recording)
|
||
- Marks (`m` and `'`)
|
||
- Registers (`"`)
|
||
- Text objects (`iw`, `a"`, etc.)
|
||
- Plugins system
|
||
|
||
---
|
||
|
||
## 🎨 Built With
|
||
|
||
<p align="center">
|
||
<a href="https://github.com/charmbracelet/bubbletea">
|
||
<img src="https://stuff.charm.sh/bubbletea/bubbletea-github-header-simple.png" width="400" alt="BubbleTea" />
|
||
</a>
|
||
</p>
|
||
|
||
- **[BubbleTea](https://github.com/charmbracelet/bubbletea)** - The fun, functional TUI framework
|
||
- **[Lipgloss](https://github.com/charmbracelet/lipgloss)** - Style definitions for terminal apps
|
||
- **[Go](https://go.dev)** - The language that makes it all possible
|
||
|
||
---
|
||
|
||
## 🤝 Contributing
|
||
|
||
Contributions are welcome! Whether it's:
|
||
|
||
- 🐛 Bug fixes
|
||
- ✨ New features
|
||
- 📖 Documentation improvements
|
||
- 🧪 Test coverage
|
||
|
||
Feel free to open issues and pull requests!
|
||
|
||
---
|
||
|
||
## 📜 License
|
||
|
||
This project is open source. See [LICENSE](LICENSE) for details.
|
||
|
||
---
|
||
|
||
<p align="center">
|
||
<sub>Made with 💜 and lots of ☕</sub>
|
||
</p>
|
||
|
||
<p align="center">
|
||
<sub>
|
||
<em>"Because sometimes you just want to build your own vim"</em>
|
||
</sub>
|
||
</p>
|