180 lines
6.5 KiB
Markdown
180 lines
6.5 KiB
Markdown
# Claude Code Instructions for lazygitclj
|
|
|
|
## Clojure Development
|
|
|
|
- Use Clojure skills (nREPL evaluation) when editing code to verify changes compile and work correctly
|
|
- Evaluate code in the REPL to test functions before committing changes
|
|
- Run `bb start` to launch the application, `bb test` for unit tests
|
|
|
|
## Local TUI Library
|
|
|
|
- The TUI library is at `../clojure-tui/` (local dependency in bb.edn)
|
|
- You have access to edit the local TUI library in conjunction with this repo
|
|
- Use this access to debug issues, support new features, and simplify code
|
|
- Look for opportunities to create better abstraction primitives for TUI layout
|
|
|
|
## Testing with VHS
|
|
|
|
- Use VHS to test all changes and verify behavior before finishing any task
|
|
- Run `bb test:e2e` to run VHS tape tests
|
|
- Run VHS tape files to capture terminal recordings and validate UI behavior
|
|
- Do not consider a task complete until changes have been verified with VHS
|
|
|
|
## Understanding Expected Behavior
|
|
|
|
- Reference the lazygit repository and documentation to understand expected behaviors
|
|
- Use VHS locally with lazygit to compare and verify that lazygitclj matches expected interaction patterns
|
|
- When implementing features, check how lazygit handles the same functionality
|
|
- See `PRD.md` for detailed lazygit behavior documentation
|
|
|
|
---
|
|
|
|
## Project Overview
|
|
|
|
lazygitclj is a lazygit-inspired TUI for Git written in Clojure, targeting Babashka for fast startup. It follows the Elm Architecture pattern (Model-Update-View).
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
src/lazygitclj/
|
|
├── core.clj # Main TUI app: views, update logic, keybindings (883 lines)
|
|
├── git.clj # Git operations wrapper via shell commands (478 lines)
|
|
└── debug_tui.clj # Layout debugging utility
|
|
test/
|
|
├── lazygitclj/
|
|
│ ├── core_test.clj # Model/update function tests
|
|
│ └── git_test.clj # Git operations tests (uses temp repo fixture)
|
|
└── run-tests.clj # Test runner
|
|
```
|
|
|
|
## Build Commands
|
|
|
|
| Command | Purpose |
|
|
|---------|---------|
|
|
| `bb start` | Run lazygitclj TUI |
|
|
| `bb debug` | Debug TUI layout issues |
|
|
| `bb test` | Run unit tests |
|
|
| `bb test:e2e` | Run VHS tape tests |
|
|
|
|
## Architecture: Elm Pattern
|
|
|
|
```clojure
|
|
(tui/run {:init (initial-model)
|
|
:update update-model
|
|
:view view})
|
|
```
|
|
|
|
- **Model**: Application state as a map
|
|
- **Update**: Pure functions returning `[new-model command]` tuples
|
|
- **View**: Pure functions rendering hiccup-style VDom
|
|
|
|
## Model Structure
|
|
|
|
```clojure
|
|
{:panel :files ;; Current panel: :files, :branches, :commits, :stash
|
|
:cursor 0 ;; Cursor position in current panel
|
|
:message nil ;; Transient message display
|
|
:input-mode nil ;; :commit, :new-branch, :rename-branch, etc.
|
|
:input-buffer "" ;; Text input during modal entry
|
|
:menu-mode nil ;; :stash-options, :reset-options, :help
|
|
:commits-tab :commits ;; :commits or :reflog
|
|
:branches-tab :local ;; :local, :remotes, or :tags
|
|
:branch "main" ;; Current branch
|
|
:sha "abc1234" ;; HEAD SHA
|
|
:ahead-behind [0 0] ;; [ahead, behind] upstream
|
|
:staged [...] ;; Staged files
|
|
:unstaged [...] ;; Unstaged/untracked files
|
|
:commits [...] ;; Recent commits
|
|
:branches [...] ;; Local branches
|
|
:remote-branches [...] ;; Remote branches
|
|
:tags [...] ;; Tags
|
|
:stashes [...] ;; Stash entries
|
|
:reflog [...] ;; Reflog for undo/redo
|
|
:diff nil} ;; Currently displayed diff
|
|
```
|
|
|
|
## Key Functions in core.clj
|
|
|
|
| Function | Purpose |
|
|
|----------|---------|
|
|
| `initial-model` | Create initial application state |
|
|
| `load-git-data` | Load all git state via git.clj |
|
|
| `refresh` | Reload git data and update diff |
|
|
| `update-model` | Main dispatcher for keyboard input |
|
|
| `update-files` | Handle files panel (stage, unstage, commit) |
|
|
| `update-commits` | Handle commits panel (checkout, cherry-pick, revert) |
|
|
| `update-branches` | Handle branches panel (checkout, create, delete, merge) |
|
|
| `update-stash` | Handle stash panel (apply, pop, drop) |
|
|
| `file-items` | Combine staged/unstaged files with type metadata |
|
|
| `current-items` | Get items for current panel |
|
|
| `view` | Render UI based on state and dimensions |
|
|
|
|
## Keybindings
|
|
|
|
**Global**: `q` quit, `?` help, `r` refresh, `h/l` panel nav, `j/k` cursor, `z/Z` undo/redo, `p/P` pull/push, `D` reset menu
|
|
|
|
**Files**: `space` stage/unstage, `a` stage all, `c` commit, `d` discard, `s/S` stash
|
|
|
|
**Commits**: `space` checkout, `g` reset to, `C` cherry-pick, `t` revert, `r` reword, `[/]` tabs
|
|
|
|
**Branches**: `enter` checkout, `n` new, `d` delete, `R` rename, `M` merge, `f` fast-forward, `[/]` tabs
|
|
|
|
**Stash**: `space` apply, `g` pop, `d` drop, `n` branch from stash
|
|
|
|
## Git Operations (git.clj)
|
|
|
|
All git operations wrap `babashka.process/shell` and return `nil` on error.
|
|
|
|
**Categories**:
|
|
- Status: `current-branch`, `head-sha`, `ahead-behind`
|
|
- Files: `status-files`, `staged-files`, `unstaged-files`
|
|
- Staging: `stage-file`, `unstage-file`, `stage-all`
|
|
- Diff: `diff-file`, `diff-staged`, `show-commit`, `diff-branch`
|
|
- Actions: `commit`, `discard-file`, `pull`, `push`
|
|
- Stash: `stash-list`, `stash-push`, `stash-pop`, `stash-apply`, `stash-drop`
|
|
- Reset: `reset-soft`, `reset-mixed`, `reset-hard`
|
|
- Branches: `create-branch`, `checkout-branch`, `delete-branch`, `merge-branch`
|
|
- Tags: `list-tags`, `create-tag`, `delete-tag`
|
|
|
|
## TUI Library Primitives
|
|
|
|
```clojure
|
|
;; Containers
|
|
[:row {:widths [30 :flex] :gap 1} left right]
|
|
[:col {:heights [3 :flex :flex 4]} top mid1 mid2 bottom]
|
|
[:box {:border :double :title "Title"} content]
|
|
|
|
;; Text with styling
|
|
[:text {:fg :green :bold true} "content"]
|
|
```
|
|
|
|
- `:flex` keyword items share remaining space equally
|
|
- Borders: `:single`, `:double`, `:rounded`
|
|
- Colors: `:red`, `:green`, `:yellow`, `:blue`, `:magenta`, `:cyan`, `:white`
|
|
|
|
## Responsive Layout
|
|
|
|
- **Narrow (< 70 cols)**: Single-column stacked layout
|
|
- **Wide (>= 70 cols)**: Two-column (left panels 30 cols, right diff flex)
|
|
|
|
## File Status Format
|
|
|
|
Files parsed from `git status --porcelain`:
|
|
```clojure
|
|
{:index \M :worktree \space :path "file.txt"}
|
|
```
|
|
|
|
## Diff Coloring
|
|
|
|
- `+` lines: green (additions)
|
|
- `-` lines: red (deletions)
|
|
- `@@` lines: cyan (hunk headers)
|
|
- `diff`/`commit` lines: yellow (headers)
|
|
|
|
## Conventions
|
|
|
|
- Predicates end with `?` (e.g., `can-fast-forward?`)
|
|
- Private functions prefixed with `-` (e.g., `-sh`, `-parse-status-line`)
|
|
- Update functions return `[new-model command]` tuples
|
|
- Messages are transient (cleared on next refresh)
|