feat: add integration with vim-fugitive

This commit is contained in:
Tommy Guo 2026-02-06 17:01:06 -05:00
parent c1db02c04e
commit d67be9d25b
2 changed files with 44 additions and 18 deletions

View File

@ -1,4 +1,5 @@
<a id="readme-top"></a> <a id="readme-top"></a>
<h1 align="center"><code>difi</code></h1> <h1 align="center"><code>difi</code></h1>
<p align="center"><em>Review and refine Git diffs before you push</em></p> <p align="center"><em>Review and refine Git diffs before you push</em></p>
@ -14,7 +15,7 @@
## Why difi? ## Why difi?
**git diff** shows changes. **difi** helps you *review* them. **git diff** shows changes. **difi** helps you _review_ them.
- ⚡️ **Instant** — Built in Go. Launches immediately with no daemon or indexing. - ⚡️ **Instant** — Built in Go. Launches immediately with no daemon or indexing.
- 🎨 **Structured** — A clean file tree and focused diffs for fast mental parsing. - 🎨 **Structured** — A clean file tree and focused diffs for fast mental parsing.
@ -71,7 +72,25 @@ difi
## Integrations ## Integrations
#### Neovim #### vim-fugitive
- **The "Unix philosophy" approach:** Uses the industry-standard Git wrapper to provide a robust, side-by-side editing experience.
- **Side-by-Side Editing:** Instantly opens a vertical split (:Gvdiffsplit!) against the index.
- **Merge Conflicts:** Automatically detects conflicts and opens a 3-way merge view for resolution.
- **Config**: Add the line below to if using **lazy.nvim**.
```lua
{
"tpope/vim-fugitive",
cmd = { "Gvdiffsplit", "Git" }, -- Add this line
}
```
<p align="left">
<img src="https://img.shields.io/badge/Supports-vim--fugitive-4d4d4d?style=for-the-badge&logo=vim&logoColor=white" alt="Supports vim-fugitive" />
</p>
#### difi.nvim
Get the ultimate review experience with **[difi.nvim](https://github.com/oug-t/difi.nvim)**. Get the ultimate review experience with **[difi.nvim](https://github.com/oug-t/difi.nvim)**.
@ -86,6 +105,8 @@ Get the ultimate review experience with **[difi.nvim](https://github.com/oug-t/d
</a> </a>
</p> </p>
<p align="right">(<a href="#readme-top">back to top</a>)</p>
## Contributing ## Contributing
```bash ```bash
@ -95,6 +116,7 @@ go run cmd/difi/main.go
``` ```
Contributions are especially welcome in: Contributions are especially welcome in:
- diff.nvim rendering edge cases - diff.nvim rendering edge cases
- UI polish and accessibility - UI polish and accessibility
- Windows support - Windows support
@ -117,11 +139,3 @@ Contributions are especially welcome in:
--- ---
<p align="center"> Made with ❤️ by <a href="https://github.com/oug-t">oug-t</a> </p> <p align="center"> Made with ❤️ by <a href="https://github.com/oug-t">oug-t</a> </p>

View File

@ -3,6 +3,8 @@ package ui
import ( import (
"fmt" "fmt"
"math" "math"
"os"
"os/exec"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
@ -224,13 +226,14 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
} }
} }
if m.selectedPath != "" { if m.selectedPath != "" {
if i, ok := m.fileList.SelectedItem().(tree.TreeItem); ok && !i.IsDir { line := 0
// proceed if m.focus == FocusDiff {
line = git.CalculateFileLine(m.diffContent, m.diffCursor)
} else { } else {
return m, nil line = git.CalculateFileLine(m.diffContent, 0)
} }
return m, openFugitive(m.selectedPath, line)
} }
fallthrough
case "e": case "e":
if m.selectedPath != "" { if m.selectedPath != "" {
@ -245,7 +248,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
line = git.CalculateFileLine(m.diffContent, 0) line = git.CalculateFileLine(m.diffContent, 0)
} }
m.inputBuffer = "" m.inputBuffer = ""
return m, git.OpenEditorCmd(m.selectedPath, line, m.targetBranch) return m, openFugitive(m.selectedPath, line)
} }
case "z": case "z":
@ -369,6 +372,17 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, tea.Batch(cmds...) return m, tea.Batch(cmds...)
} }
func openFugitive(path string, line int) tea.Cmd {
lineArg := fmt.Sprintf("+%d", line)
c := exec.Command("nvim", lineArg, "-c", "Gvdiffsplit!", path)
c.Stdin = os.Stdin
c.Stdout = os.Stdout
c.Stderr = os.Stderr
return tea.ExecProcess(c, func(err error) tea.Msg {
return git.EditorFinishedMsg{}
})
}
func (m *Model) centerDiffCursor() { func (m *Model) centerDiffCursor() {
halfScreen := m.diffViewport.Height / 2 halfScreen := m.diffViewport.Height / 2
targetOffset := m.diffCursor - halfScreen targetOffset := m.diffCursor - halfScreen
@ -571,7 +585,7 @@ func (m Model) renderHelpDrawer() string {
) )
col4 := lipgloss.JoinVertical(lipgloss.Left, col4 := lipgloss.JoinVertical(lipgloss.Left,
HelpTextStyle.Render("H/M/L Move Cursor"), HelpTextStyle.Render("H/M/L Move Cursor"),
HelpTextStyle.Render("e Edit File"), HelpTextStyle.Render("e Edit File"),
) )
return HelpDrawerStyle.Copy(). return HelpDrawerStyle.Copy().
@ -654,8 +668,6 @@ func (m Model) renderEmptyState(w, h int, statusMsg string) string {
guides, guides,
) )
// Use lipgloss.Place to center the content in the available space
// This automatically handles vertical and horizontal centering.
return lipgloss.Place(w, h, lipgloss.Center, lipgloss.Center, content) return lipgloss.Place(w, h, lipgloss.Center, lipgloss.Center, content)
} }