Skip to content

feat: add git gutter markers, tree syncing and diff preview#42

Open
Queaxtra wants to merge 8 commits into
cloudmanic:mainfrom
Queaxtra:feature/git-gutter
Open

feat: add git gutter markers, tree syncing and diff preview#42
Queaxtra wants to merge 8 commits into
cloudmanic:mainfrom
Queaxtra:feature/git-gutter

Conversation

@Queaxtra

Copy link
Copy Markdown

This PR introduces line-level git change tracking with colored gutter markers in the editor, enabling users to see modified, added, and deleted lines at a glance. It adds bidirectional sync between the active tab and the file tree sidebar, and automatically reveals and scrolls to files opened via the finder or CLI. Dirty file paths are normalized relative to the repo root, and folder-level change summaries are recalculated accordingly. It also adds a diff preview panel that opens when clicking a gutter marker, colorizing the output in the info modal. Additionally, tokenization and cursor highlighting are now limited to the visible viewport for better performance. Comprehensive tests are included for all new functionality.

Copilot AI review requested due to automatic review settings June 21, 2026 19:46
@Queaxtra

Copy link
Copy Markdown
Author

@cloudmanic

@Queaxtra

Copy link
Copy Markdown
Author
image image image

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends SpiceEdit’s UI/editor integration with Git-aware visuals and tighter sidebar/editor synchronization, adding per-line change markers (with clickable diff previews) and a new tree reveal/sync behavior to keep the file tree aligned with the active tab.

Changes:

  • Added Git-themed colors and filetree git-status kinds for richer “dirty” rendering (added/modified/deleted/renamed/mixed).
  • Implemented file tree active-file syncing plus Reveal() to expand ancestors and scroll opened files into view.
  • Limited syntax highlighting computation to the visible viewport and added gutter git markers + diff preview coloring in the info modal.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
internal/theme/theme.go Adds theme colors for git states used by gutter/tree/modal diff rendering.
internal/filetree/filetree.go Adds git change kinds, active-file tracking, per-kind coloring, and Reveal() scrolling/expansion.
internal/filetree/filetree_test.go Updates/extends tree tests for active-file highlighting, root dirty color, and reveal behavior.
internal/editor/tab.go Adds gutter git markers and switches highlighting to viewport-limited rendering.
internal/editor/highlight.go Adds HighlightVisible and refactors highlighting internals.
internal/editor/highlight_test.go Adds coverage for viewport-limited highlighting behavior.
internal/app/modals.go Colorizes diff preview lines in the info modal.
internal/app/modals_test.go Tests diff preview line coloring and includes a small formatting tweak.
internal/app/gitstatus.go Expands git status parsing to typed kinds; adds diff parsing and hunk preview extraction.
internal/app/gitstatus_test.go Extends tests for status kinds, diff-line parsing, hunk preview selection, and path rebasing.
internal/app/finder_test.go Adds an integration-style test asserting finder-open reveals the file in the tree.
internal/app/app.go Wires tree active-file syncing, reveal-on-open, gutter click-to-preview, and git line marker refresh.
internal/app/app_test.go Adds tests for gutter-marker click behavior opening the info modal.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/app/gitstatus.go
Comment on lines +250 to +259
func loadGitLineChanges(rootDir, path string) map[int]editor.GitLineChange {
if rootDir == "" || path == "" {
return nil
}
out, err := exec.Command("git", "-C", rootDir, "diff", "--unified=0", "--", path).Output()
if err != nil || len(out) == 0 {
return nil
}
return parseGitDiffLines(out)
}
Comment thread internal/app/gitstatus.go
Comment on lines +262 to +271
func loadGitHunkPreview(rootDir, path string, line int) []string {
if rootDir == "" || path == "" || line < 0 {
return nil
}
out, err := exec.Command("git", "-C", rootDir, "diff", "--unified=3", "--", path).Output()
if err != nil || len(out) == 0 {
return nil
}
return parseGitHunkPreview(out, line)
}
Comment thread internal/app/gitstatus.go
Comment on lines +323 to +332
if newCount == 0 {
mark := newStart
if mark < 0 {
mark = 0
}
changes[mark] = editor.GitLineDeleted
_ = oldStart
_ = oldCount
continue
}
Comment on lines +32 to +56
// HighlightVisible returns a style grid for the current viewport. Only visible
// rows are tokenised so keystroke cost follows terminal height, not file size.
func HighlightVisible(filename string, lines []string, startLine, height int, t theme.Theme) [][]tcell.Style {
styles := make([][]tcell.Style, len(lines))
if height <= 0 || startLine >= len(lines) {
return styles
}
if startLine < 0 {
startLine = 0
}
endLine := startLine + height
if endLine > len(lines) {
endLine = len(lines)
}
visible := strings.Join(lines[startLine:endLine], "\n")
visibleStyles := highlightSource(filename, visible, t)
for i, row := range visibleStyles {
lineIdx := startLine + i
if lineIdx >= endLine || lineIdx >= len(styles) {
break
}
styles[lineIdx] = row
}
return styles
}
Comment thread internal/editor/tab.go
Comment on lines 571 to 585
// Gutter / line number, right-aligned with one trailing space.
numStr := fmt.Sprintf("%*d", gutterWidth-1, lineIdx+1)
gutterStyle := tcell.StyleDefault.Background(lineBg).Foreground(th.Muted)
if isCursorLine {
gutterStyle = gutterStyle.Foreground(th.AccentSoft)
}
if marker, ok := t.GitLines[lineIdx]; ok && marker != GitLineNone {
scr.SetContent(x, cy, gitLineMarkerRune(marker), nil, gutterStyle.Foreground(gitLineMarkerColor(th, marker)))
}
for i, r := range numStr {
if i == 0 && t.GitLines[lineIdx] != GitLineNone {
continue
}
scr.SetContent(x+i, cy, r, nil, gutterStyle)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants