6.5 KiB
6.5 KiB
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 startto launch the application,bb testfor 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:e2eto 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.mdfor 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
(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
{: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
;; 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"]
:flexkeyword 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:
{:index \M :worktree \space :path "file.txt"}
Diff Coloring
+lines: green (additions)-lines: red (deletions)@@lines: cyan (hunk headers)diff/commitlines: 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)