mirror of
https://github.com/jesseduffield/lazygit.git
synced 2024-11-24 08:52:21 +02:00
update
This commit is contained in:
parent
f465a5fe48
commit
7d70ed5be1
@ -56,8 +56,10 @@ func mergeGitStatusFiles(oldGitFiles, newGitFiles []GitFile) []GitFile {
|
||||
return result
|
||||
}
|
||||
|
||||
func getGitBranchOutput() (string, error) {
|
||||
cmdOut, err := exec.Command("bash", "-c", getBranchesCommand).Output()
|
||||
func runDirectCommand(command string) (string, error) {
|
||||
cmdOut, err := exec.Command("bash", "-c", command).Output()
|
||||
devLog(string(cmdOut))
|
||||
devLog(fmt.Sprint(err))
|
||||
return string(cmdOut), err
|
||||
}
|
||||
|
||||
@ -70,7 +72,7 @@ func branchNameFromString(branchString string) string {
|
||||
|
||||
func getGitBranches() []Branch {
|
||||
branches := make([]Branch, 0)
|
||||
rawString, _ := getGitBranchOutput()
|
||||
rawString, _ := runDirectCommand(getBranchesCommand)
|
||||
branchLines := splitLines(rawString)
|
||||
for _, line := range branchLines {
|
||||
name := branchNameFromString(line)
|
||||
@ -136,7 +138,7 @@ func runCommand(cmd string) (string, error) {
|
||||
splitCmd := strings.Split(cmd, " ")
|
||||
cmdOut, err := exec.Command(splitCmd[0], splitCmd[1:]...).Output()
|
||||
devLog(cmd)
|
||||
devLog(string(cmdOut))
|
||||
devLog(string(cmdOut[:]))
|
||||
return string(cmdOut), err
|
||||
}
|
||||
|
||||
@ -150,10 +152,14 @@ func getDiff(file GitFile) string {
|
||||
cachedArg = "--cached "
|
||||
}
|
||||
deletedArg := ""
|
||||
if file.Deleted || !file.Tracked {
|
||||
deletedArg = "--no-index /dev/null "
|
||||
if file.Deleted {
|
||||
deletedArg = "-- "
|
||||
}
|
||||
command := "git diff --color " + cachedArg + deletedArg + file.Name
|
||||
trackedArg := ""
|
||||
if !file.Tracked {
|
||||
trackedArg = "--no-index /dev/null "
|
||||
}
|
||||
command := "git diff --color " + cachedArg + deletedArg + trackedArg + file.Name
|
||||
s, err := runCommand(command)
|
||||
if err != nil {
|
||||
// for now we assume an error means the file was deleted
|
||||
@ -176,6 +182,22 @@ func getGitStatus() (string, error) {
|
||||
return runCommand("git status --untracked-files=all --short")
|
||||
}
|
||||
|
||||
func removeFile(file GitFile) error {
|
||||
// if the file isn't tracked, we assume you want to delete it
|
||||
if !file.Tracked {
|
||||
_, err := runCommand("rm -rf ./" + file.Name)
|
||||
return err
|
||||
}
|
||||
// if the file is tracked, we assume you want to just check it out
|
||||
_, err := runCommand("git checkout " + file.Name)
|
||||
return err
|
||||
}
|
||||
|
||||
func gitCommit(message string) error {
|
||||
_, err := runDirectCommand("git commit -m \"" + message + "\"")
|
||||
return err
|
||||
}
|
||||
|
||||
const getBranchesCommand = `set -e
|
||||
git reflog -n100 --pretty='%cr|%gs' --grep-reflog='checkout: moving' HEAD | {
|
||||
seen=":"
|
||||
|
184
gui.go
184
gui.go
@ -28,6 +28,16 @@ var state = stateType{GitFiles: make([]GitFile, 0)}
|
||||
|
||||
var cyclableViews = []string{"files", "branches"}
|
||||
|
||||
func stagedFiles(files []GitFile) []GitFile {
|
||||
result := make([]GitFile, 0)
|
||||
for _, file := range files {
|
||||
if file.HasStagedChanges {
|
||||
result = append(result, file)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func nextView(g *gocui.Gui, v *gocui.View) error {
|
||||
var focusedViewName string
|
||||
if v == nil || v.Name() == cyclableViews[len(cyclableViews)-1] {
|
||||
@ -48,21 +58,27 @@ func nextView(g *gocui.Gui, v *gocui.View) error {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
if v != nil {
|
||||
v.Highlight = false
|
||||
return switchFocus(g, v, focusedView)
|
||||
}
|
||||
|
||||
func switchFocus(g *gocui.Gui, oldView, newView *gocui.View) error {
|
||||
if oldView != nil {
|
||||
oldView.Highlight = false
|
||||
}
|
||||
focusedView.Highlight = true
|
||||
devLog(focusedViewName)
|
||||
_, err = g.SetCurrentView(focusedViewName)
|
||||
itemSelected(g, focusedView)
|
||||
showViewOptions(g, focusedViewName)
|
||||
newView.Highlight = true
|
||||
devLog(newView.Name())
|
||||
_, err := g.SetCurrentView(newView.Name()) // not mega proud of the delayed
|
||||
// return of err
|
||||
itemSelected(g, newView)
|
||||
showViewOptions(g, newView.Name())
|
||||
return err
|
||||
}
|
||||
|
||||
func showViewOptions(g *gocui.Gui, viewName string) error {
|
||||
optionsMap := map[string]string{
|
||||
"files": "space: toggle staged, c: commit changes",
|
||||
"files": "space: toggle staged, c: commit changes, shift+d: remove",
|
||||
"branches": "space: checkout",
|
||||
"prompt": "esc: cancel, enter: commit",
|
||||
}
|
||||
g.Update(func(*gocui.Gui) error {
|
||||
v, err := g.View("options")
|
||||
@ -133,6 +149,8 @@ func itemSelected(g *gocui.Gui, v *gocui.View) error {
|
||||
return handleFileSelect(g, v)
|
||||
case "branches":
|
||||
return handleBranchSelect(g, v)
|
||||
case "prompt":
|
||||
return nil
|
||||
default:
|
||||
panic("No view matching itemSelected switch statement")
|
||||
}
|
||||
@ -166,7 +184,7 @@ func devLog(s string) {
|
||||
func handleBranchPress(g *gocui.Gui, v *gocui.View) error {
|
||||
branch := getSelectedBranch(v)
|
||||
if err := gitCheckout(branch.Name, false); err != nil {
|
||||
return err
|
||||
panic(err)
|
||||
}
|
||||
refreshBranches(v)
|
||||
refreshFiles(g)
|
||||
@ -192,8 +210,67 @@ func handleFilePress(g *gocui.Gui, v *gocui.View) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleCommitPrompt(g *gocui.Gui, currentView *gocui.View) error {
|
||||
devLog(fmt.Sprint(stagedFiles(state.GitFiles)))
|
||||
if len(stagedFiles(state.GitFiles)) == 0 {
|
||||
return nil
|
||||
}
|
||||
maxX, maxY := g.Size()
|
||||
// var v *gocui.View
|
||||
if v, err := g.SetView("prompt", maxX/2-30, maxY/2-1, maxX/2+30, maxY/2+1); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
return err
|
||||
}
|
||||
v.Title = "Commit Message: "
|
||||
v.Editable = true
|
||||
v.Highlight = true
|
||||
v.Autoscroll = true
|
||||
v.Wrap = true
|
||||
v.Overwrite = true
|
||||
v.Caret = true
|
||||
// fmt.Fprintln(v, "commit message: ")
|
||||
if _, err := g.SetCurrentView("prompt"); err != nil {
|
||||
return err
|
||||
}
|
||||
switchFocus(g, currentView, v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleCommitSubmit(g *gocui.Gui, v *gocui.View) error {
|
||||
if len(v.BufferLines()) == 0 {
|
||||
return closePrompt(g, v)
|
||||
}
|
||||
message := fmt.Sprint(v.BufferLines()[0])
|
||||
// for whatever reason, a successful commit returns an error, so we're not
|
||||
// going to check for an error here
|
||||
if err := gitCommit(message); err != nil {
|
||||
devLog(fmt.Sprint(err))
|
||||
panic(err)
|
||||
}
|
||||
refreshFiles(g)
|
||||
return closePrompt(g, v)
|
||||
}
|
||||
|
||||
func handleFileRemove(g *gocui.Gui, v *gocui.View) error {
|
||||
file := getSelectedFile(v)
|
||||
removeFile(file)
|
||||
refreshFiles(g)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getSelectedFile(v *gocui.View) GitFile {
|
||||
lineNumber := getItemPosition(v)
|
||||
if len(state.GitFiles) == 0 {
|
||||
return GitFile{
|
||||
Name: "noFile",
|
||||
DisplayString: "none",
|
||||
HasStagedChanges: false,
|
||||
HasUnstagedChanges: false,
|
||||
Tracked: false,
|
||||
Deleted: false,
|
||||
}
|
||||
}
|
||||
return state.GitFiles[lineNumber]
|
||||
}
|
||||
|
||||
@ -215,25 +292,14 @@ func handleBranchSelect(g *gocui.Gui, v *gocui.View) error {
|
||||
func handleFileSelect(g *gocui.Gui, v *gocui.View) error {
|
||||
item := getSelectedFile(v)
|
||||
diff := getDiff(item)
|
||||
if err := renderString(g, diff); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// maxX, maxY := g.Size()
|
||||
// if v, err := g.SetView("msg", maxX/2-30, maxY/2, maxX/2+30, maxY/2+2); err != nil {
|
||||
// if err != gocui.ErrUnknownView {
|
||||
// return errkjhgkhj
|
||||
// }
|
||||
// fmt.Fprintln(v, l)
|
||||
// if _, err := g.SetCurrentView("msg"); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
return nil
|
||||
return renderString(g, diff)
|
||||
}
|
||||
|
||||
func delMsg(g *gocui.Gui, v *gocui.View) error {
|
||||
if err := g.DeleteView("msg"); err != nil {
|
||||
func closePrompt(g *gocui.Gui, v *gocui.View) error {
|
||||
filesView, _ := g.View("files")
|
||||
switchFocus(g, v, filesView)
|
||||
devLog("test prompt close")
|
||||
if err := g.DeleteView("prompt"); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := g.SetCurrentView("files"); err != nil {
|
||||
@ -247,32 +313,42 @@ func quit(g *gocui.Gui, v *gocui.View) error {
|
||||
}
|
||||
|
||||
func keybindings(g *gocui.Gui) error {
|
||||
for _, view := range cyclableViews {
|
||||
if err := g.SetKeybinding(view, gocui.KeyTab, gocui.ModNone, nextView); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.SetKeybinding(view, 'q', gocui.ModNone, quit); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.SetKeybinding(view, gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.SetKeybinding(view, gocui.KeyArrowDown, gocui.ModNone, cursorDown); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.SetKeybinding(view, gocui.KeyArrowUp, gocui.ModNone, cursorUp); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.SetKeybinding(view, gocui.KeyPgup, gocui.ModNone, scrollUp); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.SetKeybinding(view, gocui.KeyPgdn, gocui.ModNone, scrollDown); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.SetKeybinding("", gocui.KeyTab, gocui.ModNone, nextView); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.SetKeybinding("", 'q', gocui.ModNone, quit); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.SetKeybinding("", gocui.KeyArrowDown, gocui.ModNone, cursorDown); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.SetKeybinding("", gocui.KeyArrowUp, gocui.ModNone, cursorUp); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.SetKeybinding("", gocui.KeyPgup, gocui.ModNone, scrollUp); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.SetKeybinding("", gocui.KeyPgdn, gocui.ModNone, scrollDown); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.SetKeybinding("", 'C', gocui.ModNone, handleCommitPrompt); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.SetKeybinding("files", gocui.KeySpace, gocui.ModNone, handleFilePress); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.SetKeybinding("files", 'D', gocui.ModNone, handleFileRemove); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.SetKeybinding("prompt", gocui.KeyEsc, gocui.ModNone, closePrompt); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.SetKeybinding("prompt", gocui.KeyEnter, gocui.ModNone, handleCommitSubmit); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.SetKeybinding("branches", gocui.KeySpace, gocui.ModNone, handleBranchPress); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -317,6 +393,17 @@ func refreshBranches(v *gocui.View) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// if the cursor down past the last item, move it up one
|
||||
func correctCursor(v *gocui.View) error {
|
||||
cx, cy := v.Cursor()
|
||||
_, oy := v.Origin()
|
||||
lineCount := len(v.BufferLines()) - 2
|
||||
if cy >= lineCount-oy {
|
||||
return v.SetCursor(cx, lineCount-oy)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func refreshFiles(g *gocui.Gui) error {
|
||||
filesView, err := g.View("files")
|
||||
if err != nil {
|
||||
@ -343,6 +430,7 @@ func refreshFiles(g *gocui.Gui) error {
|
||||
green.Fprintln(filesView, gitFile.Name)
|
||||
}
|
||||
}
|
||||
correctCursor(filesView)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user