Compare commits

..
1 Commits
Author SHA1 Message Date
Jesse Duffield c5ff39ba5f new version 2020-03-04 09:41:04 +11:00
53 changed files with 500 additions and 667 deletions
+62
View File
@@ -0,0 +1,62 @@
version: 2
jobs:
build:
docker:
- image: circleci/golang:1.13
environment:
GO111MODULE: "on"
working_directory: /go/src/github.com/jesseduffield/lazygit
steps:
- checkout
- run:
name: Run gofmt -s
command: |
if [ $(find . ! -path "./vendor/*" -name "*.go" -exec gofmt -s -d {} \;|wc -l) -gt 0 ]; then
find . ! -path "./vendor/*" -name "*.go" -exec gofmt -s -d {} \;
exit 1;
fi
- restore_cache:
keys:
- pkg-cache-{{ checksum "go.sum" }}-v5
- run:
name: Run tests
command: |
./test.sh
- run:
name: Push on codecov result
command: |
bash <(curl -s https://codecov.io/bash)
- run:
name: Compile project on every platform
command: |
go get github.com/mitchellh/gox
GOFLAGS=-mod=vendor gox -parallel 10 -os "linux freebsd netbsd windows" -osarch "darwin/i386 darwin/amd64"
- save_cache:
key: pkg-cache-{{ checksum "go.sum" }}-v5
paths:
- ~/.cache/go-build
release:
docker:
- image: circleci/golang:1.13
working_directory: /go/src/github.com/jesseduffield/lazygit
steps:
- checkout
- run:
name: Run gorelease
command: |
curl -sL https://git.io/goreleaser | bash
workflows:
version: 2
build:
jobs:
- build
release:
jobs:
- release:
filters:
tags:
only: /v[0-9]+(\.[0-9]+)*/
branches:
ignore: /.*/
-34
View File
@@ -1,34 +0,0 @@
name: Continuous Delivery
on:
push:
tags:
- 'v*'
jobs:
cd:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v1
with:
go-version: 1.14.x
- name: Run goreleaser
uses: goreleaser/goreleaser-action@v1
with:
args: release --rm-dist
env:
GITHUB_TOKEN: ${{secrets.GITHUB_API_TOKEN}}
- name: Get tag
id: tag
run: echo "::set-output name=tag::${GITHUB_REF##*/}"
- name: Bump Homebrew
uses: dawidd6/action-homebrew-bump-formula@v1
with:
token: ${{secrets.GITHUB_API_TOKEN}}
formula: lazygit
url: "https://github.com/${{github.repository}}/archive/${{steps.tag.outputs.tag}}.tar.gz"
-37
View File
@@ -1,37 +0,0 @@
name: Continuous Integration
on: push
jobs:
ci:
runs-on: ubuntu-latest
env:
GOFLAGS: -mod=vendor
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Setup Go
uses: actions/setup-go@v1
with:
go-version: 1.14.x
- name: Cache build
uses: actions/cache@v1
with:
path: ~/.cache/go-build
key: ${{runner.os}}-go-${{hashFiles('**/go.sum')}}
restore-keys: |
${{runner.os}}-go-
- name: Format code
run: |
if [ $(find . ! -path "./vendor/*" -name "*.go" -exec gofmt -s -d {} \;|wc -l) -gt 0 ]; then
find . ! -path "./vendor/*" -name "*.go" -exec gofmt -s -d {} \;
exit 1
fi
- name: Test code
run: |
./test.sh
- name: Build binaries
run: |
go get github.com/mitchellh/gox
export PATH="$(go env GOPATH)/bin:$PATH"
gox -parallel 4 -os "linux freebsd netbsd windows" -osarch "darwin/i386 darwin/amd64"
+2 -2
View File
@@ -2,12 +2,12 @@
# docker build -t lazygit .
# docker run -it lazygit:latest /bin/sh -l
FROM golang:1.14-alpine3.11
FROM golang:1.13-alpine3.10
WORKDIR /go/src/github.com/jesseduffield/lazygit/
COPY ./ .
RUN CGO_ENABLED=0 GOOS=linux go build
FROM alpine:3.11
FROM alpine:3.10
RUN apk add -U git xdg-utils
WORKDIR /go/src/github.com/jesseduffield/lazygit/
COPY --from=0 /go/src/github.com/jesseduffield/lazygit /go/src/github.com/jesseduffield/lazygit
+1 -1
View File
@@ -1,4 +1,4 @@
# lazygit ![CI](https://github.com/jesseduffield/lazygit/workflows/Continuous%20Integration/badge.svg) [![codecov](https://codecov.io/gh/jesseduffield/lazygit/branch/master/graph/badge.svg)](https://codecov.io/gh/jesseduffield/lazygit) [![Go Report Card](https://goreportcard.com/badge/github.com/jesseduffield/lazygit)](https://goreportcard.com/report/github.com/jesseduffield/lazygit) [![GolangCI](https://golangci.com/badges/github.com/jesseduffield/lazygit.svg)](https://golangci.com) [![GoDoc](https://godoc.org/github.com/jesseduffield/lazygit?status.svg)](http://godoc.org/github.com/jesseduffield/lazygit) [![GitHub tag](https://img.shields.io/github/tag/jesseduffield/lazygit.svg)]() [![TODOs](https://badgen.net/https/api.tickgit.com/badgen/github.com/jesseduffield/lazygit)](https://www.tickgit.com/browse?repo=github.com/jesseduffield/lazygit)
# lazygit [![CircleCI](https://circleci.com/gh/jesseduffield/lazygit.svg?style=svg)](https://circleci.com/gh/jesseduffield/lazygit) [![codecov](https://codecov.io/gh/jesseduffield/lazygit/branch/master/graph/badge.svg)](https://codecov.io/gh/jesseduffield/lazygit) [![Go Report Card](https://goreportcard.com/badge/github.com/jesseduffield/lazygit)](https://goreportcard.com/report/github.com/jesseduffield/lazygit) [![GolangCI](https://golangci.com/badges/github.com/jesseduffield/lazygit.svg)](https://golangci.com) [![GoDoc](https://godoc.org/github.com/jesseduffield/lazygit?status.svg)](http://godoc.org/github.com/jesseduffield/lazygit) [![GitHub tag](https://img.shields.io/github/tag/jesseduffield/lazygit.svg)]() [![TODOs](https://badgen.net/https/api.tickgit.com/badgen/github.com/jesseduffield/lazygit)](https://www.tickgit.com/browse?repo=github.com/jesseduffield/lazygit)
A simple terminal UI for git commands, written in Go with the [gocui](https://github.com/jroimartin/gocui 'gocui') library.
-1
View File
@@ -128,7 +128,6 @@ Default path for the config file:
tagCommit: 'T'
toggleDiffCommit: 'i'
checkoutCommit: '<space>'
resetCherryPick: '<c-R>'
stash:
popStash: 'g'
commitFiles:
+4 -26
View File
@@ -10,7 +10,6 @@
<kbd>P</kbd>: push
<kbd>p</kbd>: pull
<kbd>R</kbd>: refresh
<kbd>x</kbd>: open menu
<kbd>+</kbd>: next screen mode (normal/half/fullscreen)
<kbd>_</kbd>: prev screen mode
<kbd>:</kbd>: execute custom command
@@ -30,8 +29,6 @@
<kbd>i</kbd>: show git-flow options
<kbd>f</kbd>: fast-forward this branch from its upstream
<kbd>g</kbd>: view reset options
<kbd>R</kbd>: rename branch
<kbd>/</kbd>: start search
</pre>
## Branches Panel (Remote Branches (in Remotes tab))
@@ -44,7 +41,6 @@
<kbd>d</kbd>: delete branch
<kbd>r</kbd>: rebase checked-out branch onto this branch
<kbd>u</kbd>: set as upstream of checked-out branch
<kbd>/</kbd>: start search
</pre>
## Branches Panel (Remotes Tab)
@@ -54,7 +50,6 @@
<kbd>n</kbd>: add new remote
<kbd>d</kbd>: remove remote
<kbd>e</kbd>: edit remote
<kbd>/</kbd>: start search
</pre>
## Branches Panel (Tags Tab)
@@ -65,7 +60,6 @@
<kbd>P</kbd>: push tag
<kbd>n</kbd>: create tag
<kbd>g</kbd>: view reset options
<kbd>/</kbd>: start search
</pre>
## Commit Files Panel
@@ -77,13 +71,6 @@
<kbd>o</kbd>: open file
<kbd>space</kbd>: toggle file included in patch
<kbd>enter</kbd>: enter file to add selected lines to the patch
<kbd>/</kbd>: start search
</pre>
## Commits Panel
<pre>
<kbd>/</kbd>: start search
</pre>
## Commits Panel (Commits Tab)
@@ -139,7 +126,6 @@
<kbd>enter</kbd>: stage individual hunks/lines
<kbd>f</kbd>: fetch
<kbd>g</kbd>: view upstream reset options
<kbd>/</kbd>: start search
</pre>
## Main Panel (Merging)
@@ -170,7 +156,8 @@
<kbd>▼</kbd>: select next line
<kbd>◄</kbd>: select previous hunk
<kbd>►</kbd>: select next hunk
<kbd>space</kbd>: add/remove line(s) to patch
<kbd>space</kbd>: stage selection
<kbd>d</kbd>: reset selection
<kbd>v</kbd>: toggle drag select
<kbd>V</kbd>: toggle drag select
<kbd>a</kbd>: toggle select hunk
@@ -180,8 +167,8 @@
<pre>
<kbd>esc</kbd>: return to files panel
<kbd>space</kbd>: toggle line staged / unstaged
<kbd>d</kbd>: delete change (git reset)
<kbd>space</kbd>: stage selection
<kbd>d</kbd>: reset selection
<kbd>tab</kbd>: switch to other panel
<kbd>▲</kbd>: select previous line
<kbd>▼</kbd>: select next line
@@ -197,21 +184,12 @@
<kbd>C</kbd>: commit changes using git editor
</pre>
## Menu Panel
<pre>
<kbd>esc</kbd>: close menu
<kbd>q</kbd>: close menu
<kbd>/</kbd>: start search
</pre>
## Stash Panel
<pre>
<kbd>space</kbd>: apply
<kbd>g</kbd>: pop
<kbd>d</kbd>: drop
<kbd>/</kbd>: start search
</pre>
## Status Panel
+4 -26
View File
@@ -10,7 +10,6 @@
<kbd>P</kbd>: push
<kbd>p</kbd>: pull
<kbd>R</kbd>: verversen
<kbd>x</kbd>: open menu
<kbd>+</kbd>: next screen mode (normal/half/fullscreen)
<kbd>_</kbd>: prev screen mode
<kbd>:</kbd>: voor aangepast commando uit
@@ -30,8 +29,6 @@
<kbd>i</kbd>: show git-flow options
<kbd>f</kbd>: fast-forward this branch from its upstream
<kbd>g</kbd>: bekijk reset opties
<kbd>R</kbd>: rename branch
<kbd>/</kbd>: start search
</pre>
## Branches Panel (Remote Branches (in Remotes tab))
@@ -44,7 +41,6 @@
<kbd>d</kbd>: verwijder branch
<kbd>r</kbd>: rebase branch
<kbd>u</kbd>: set as upstream of checked-out branch
<kbd>/</kbd>: start search
</pre>
## Branches Panel (Remotes Tab)
@@ -54,7 +50,6 @@
<kbd>n</kbd>: add new remote
<kbd>d</kbd>: remove remote
<kbd>e</kbd>: edit remote
<kbd>/</kbd>: start search
</pre>
## Branches Panel (Tags Tab)
@@ -65,7 +60,6 @@
<kbd>P</kbd>: push tag
<kbd>n</kbd>: create tag
<kbd>g</kbd>: bekijk reset opties
<kbd>/</kbd>: start search
</pre>
## Commit bestanden Panel
@@ -77,13 +71,6 @@
<kbd>o</kbd>: open bestand
<kbd>space</kbd>: toggle file included in patch
<kbd>enter</kbd>: enter file to add selected lines to the patch
<kbd>/</kbd>: start search
</pre>
## Commits Panel
<pre>
<kbd>/</kbd>: start search
</pre>
## Commits Panel (Commits Tab)
@@ -139,7 +126,6 @@
<kbd>enter</kbd>: stage individuele hunks/lijnen
<kbd>f</kbd>: fetch
<kbd>g</kbd>: view upstream reset options
<kbd>/</kbd>: start search
</pre>
## Hoofd Panel (Merging)
@@ -170,7 +156,8 @@
<kbd>▼</kbd>: selecteer de volgende lijn
<kbd>◄</kbd>: selecteer de vorige hunk
<kbd>►</kbd>: selecteer de volgende hunk
<kbd>space</kbd>: add/remove line(s) to patch
<kbd>space</kbd>: stage selection
<kbd>d</kbd>: reset selection
<kbd>v</kbd>: toggle drag select
<kbd>V</kbd>: toggle drag select
<kbd>a</kbd>: toggle select hunk
@@ -180,8 +167,8 @@
<pre>
<kbd>esc</kbd>: ga terug naar het bestanden paneel
<kbd>space</kbd>: toggle line staged / unstaged
<kbd>d</kbd>: delete change (git reset)
<kbd>space</kbd>: stage selection
<kbd>d</kbd>: reset selection
<kbd>tab</kbd>: switch to other panel
<kbd>▲</kbd>: selecteer de vorige lijn
<kbd>▼</kbd>: selecteer de volgende lijn
@@ -197,21 +184,12 @@
<kbd>C</kbd>: commit veranderingen met de git editor
</pre>
## Menu Panel
<pre>
<kbd>esc</kbd>: close menu
<kbd>q</kbd>: close menu
<kbd>/</kbd>: start search
</pre>
## Stash Panel
<pre>
<kbd>space</kbd>: toepassen
<kbd>g</kbd>: pop
<kbd>d</kbd>: drop
<kbd>/</kbd>: start search
</pre>
## Status Panel
+4 -26
View File
@@ -10,7 +10,6 @@
<kbd>P</kbd>: push
<kbd>p</kbd>: pull
<kbd>R</kbd>: odśwież
<kbd>x</kbd>: open menu
<kbd>+</kbd>: next screen mode (normal/half/fullscreen)
<kbd>_</kbd>: prev screen mode
<kbd>:</kbd>: execute custom command
@@ -30,8 +29,6 @@
<kbd>i</kbd>: show git-flow options
<kbd>f</kbd>: fast-forward this branch from its upstream
<kbd>g</kbd>: view reset options
<kbd>R</kbd>: rename branch
<kbd>/</kbd>: start search
</pre>
## Gałęzie Panel (Remote Branches (in Remotes tab))
@@ -44,7 +41,6 @@
<kbd>d</kbd>: usuń gałąź
<kbd>r</kbd>: rebase branch
<kbd>u</kbd>: set as upstream of checked-out branch
<kbd>/</kbd>: start search
</pre>
## Gałęzie Panel (Remotes Tab)
@@ -54,7 +50,6 @@
<kbd>n</kbd>: add new remote
<kbd>d</kbd>: remove remote
<kbd>e</kbd>: edit remote
<kbd>/</kbd>: start search
</pre>
## Gałęzie Panel (Tags Tab)
@@ -65,7 +60,6 @@
<kbd>P</kbd>: push tag
<kbd>n</kbd>: create tag
<kbd>g</kbd>: view reset options
<kbd>/</kbd>: start search
</pre>
## Commit files Panel
@@ -77,13 +71,6 @@
<kbd>o</kbd>: otwórz plik
<kbd>space</kbd>: toggle file included in patch
<kbd>enter</kbd>: enter file to add selected lines to the patch
<kbd>/</kbd>: start search
</pre>
## Commity Panel
<pre>
<kbd>/</kbd>: start search
</pre>
## Commity Panel (Commits Tab)
@@ -139,7 +126,6 @@
<kbd>enter</kbd>: zatwierdź pojedyncze linie
<kbd>f</kbd>: fetch
<kbd>g</kbd>: view upstream reset options
<kbd>/</kbd>: start search
</pre>
## Main Panel (Merging)
@@ -170,7 +156,8 @@
<kbd>▼</kbd>: select next line
<kbd>◄</kbd>: select previous hunk
<kbd>►</kbd>: select next hunk
<kbd>space</kbd>: add/remove line(s) to patch
<kbd>space</kbd>: stage selection
<kbd>d</kbd>: reset selection
<kbd>v</kbd>: toggle drag select
<kbd>V</kbd>: toggle drag select
<kbd>a</kbd>: toggle select hunk
@@ -180,8 +167,8 @@
<pre>
<kbd>esc</kbd>: wróć do panelu plików
<kbd>space</kbd>: toggle line staged / unstaged
<kbd>d</kbd>: delete change (git reset)
<kbd>space</kbd>: stage selection
<kbd>d</kbd>: reset selection
<kbd>tab</kbd>: switch to other panel
<kbd>▲</kbd>: select previous line
<kbd>▼</kbd>: select next line
@@ -197,21 +184,12 @@
<kbd>C</kbd>: commituj zmiany używając edytora z gita
</pre>
## Menu Panel
<pre>
<kbd>esc</kbd>: close menu
<kbd>q</kbd>: close menu
<kbd>/</kbd>: start search
</pre>
## Schowek Panel
<pre>
<kbd>space</kbd>: zastosuj
<kbd>g</kbd>: wyciągnij
<kbd>d</kbd>: porzuć
<kbd>/</kbd>: start search
</pre>
## Status Panel
+2 -3
View File
@@ -1,6 +1,6 @@
module github.com/jesseduffield/lazygit
go 1.14
go 1.13
require (
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
@@ -11,7 +11,7 @@ require (
github.com/golang/protobuf v1.3.2 // indirect
github.com/google/go-cmp v0.3.1 // indirect
github.com/integrii/flaggy v1.4.0
github.com/jesseduffield/gocui v0.3.1-0.20200309001002-7765949e1c8a
github.com/jesseduffield/gocui v0.3.1-0.20200301081700-d6e485450113
github.com/jesseduffield/pty v1.2.1
github.com/jesseduffield/termbox-go v0.0.0-20200130214842-1d31d1faa3c9 // indirect
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
@@ -20,7 +20,6 @@ require (
github.com/mattn/go-isatty v0.0.11 // indirect
github.com/mattn/go-runewidth v0.0.8
github.com/mgutz/str v1.2.0
github.com/mitchellh/gox v1.0.1 // indirect
github.com/nicksnyder/go-i18n/v2 v2.0.3
github.com/onsi/ginkgo v1.10.3 // indirect
github.com/onsi/gomega v1.7.1 // indirect
+2 -8
View File
@@ -68,8 +68,6 @@ github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoA
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/go-version v1.0.0 h1:21MVWPKDphxa7ineQQTrCU5brh7OuVVAzGOCnnCPtE8=
github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
@@ -78,10 +76,10 @@ github.com/integrii/flaggy v1.4.0 h1:A1x7SYx4jqu5NSrY14z8Z+0UyX2S5ygfJJrfolWR3zM
github.com/integrii/flaggy v1.4.0/go.mod h1:tnTxHeTJbah0gQ6/K0RW0J7fMUBk9MCF5blhm43LNpI=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jesseduffield/gocui v0.3.1-0.20200224201655-5024a02682ed h1:glGs+mzPZOl1iHiUsBW3918WeFwqsbQQ/jtLkkQXDi4=
github.com/jesseduffield/gocui v0.3.1-0.20200224201655-5024a02682ed/go.mod h1:2RtZznzYKt8RLRwvFiSkXjU0Ei8WwHdubgnlaYH47dw=
github.com/jesseduffield/gocui v0.3.1-0.20200301081700-d6e485450113 h1:jHZRVJUWsU8HaQ0crocz0i0BkpOqFLDJEO/AtBp+Ecs=
github.com/jesseduffield/gocui v0.3.1-0.20200301081700-d6e485450113/go.mod h1:2RtZznzYKt8RLRwvFiSkXjU0Ei8WwHdubgnlaYH47dw=
github.com/jesseduffield/gocui v0.3.1-0.20200309001002-7765949e1c8a h1:JSORQue6V4bMppr22dtUuYX+w79cgupo66PcGZ9ijlU=
github.com/jesseduffield/gocui v0.3.1-0.20200309001002-7765949e1c8a/go.mod h1:2RtZznzYKt8RLRwvFiSkXjU0Ei8WwHdubgnlaYH47dw=
github.com/jesseduffield/pty v1.2.1 h1:7xYBiwNH0PpWqC8JmvrPq1a/ksNqyCavzWu9pbBGYWI=
github.com/jesseduffield/pty v1.2.1/go.mod h1:7jlS40+UhOqkZJDIG1B/H21xnuET/+fvbbnHCa8wSIo=
github.com/jesseduffield/termbox-go v0.0.0-20200130214842-1d31d1faa3c9 h1:iBBk1lhFwjwJw//J2m1yyz9S368GeXQTpMVACTyQMh0=
@@ -121,10 +119,6 @@ github.com/mgutz/str v1.2.0 h1:4IzWSdIz9qPQWLfKZ0rJcV0jcUDpxvP4JVZ4GXQyvSw=
github.com/mgutz/str v1.2.0/go.mod h1:w1v0ofgLaJdoD0HpQ3fycxKD1WtxpjSo151pK/31q6w=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/gox v1.0.1 h1:x0jD3dcHk9a9xPSDN6YEL4xL6Qz0dvNYm8yZqui5chI=
github.com/mitchellh/gox v1.0.1/go.mod h1:ED6BioOGXMswlXa2zxfh/xdd5QhwYliBFn9V18Ap4z4=
github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+6
View File
@@ -4,6 +4,7 @@ import (
"fmt"
"log"
"os"
"path/filepath"
"runtime"
"github.com/go-errors/errors"
@@ -19,6 +20,11 @@ var (
buildSource = "unknown"
)
func projectPath(path string) string {
gopath := os.Getenv("GOPATH")
return filepath.FromSlash(gopath + "/src/github.com/jesseduffield/lazygit/" + path)
}
func main() {
flaggy.DefaultParser.ShowVersionWithVersionFlag = false
+4 -6
View File
@@ -3,10 +3,8 @@ package commands
// Branch : A git branch
// duplicating this for now
type Branch struct {
Name string
Recency string
Pushables string
Pullables string
UpstreamName string
Head bool
Name string
Recency string
Pushables string
Pullables string
}
+83 -100
View File
@@ -7,6 +7,8 @@ import (
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/sirupsen/logrus"
"gopkg.in/src-d/go-git.v4/plumbing"
)
// context:
@@ -34,105 +36,113 @@ func NewBranchListBuilder(log *logrus.Entry, gitCommand *GitCommand) (*BranchLis
}, nil
}
func (b *BranchListBuilder) obtainCurrentBranchName() string {
func (b *BranchListBuilder) obtainCurrentBranch() *Branch {
branchName, err := b.GitCommand.CurrentBranchName()
if err != nil {
panic(err.Error())
}
return branchName
return &Branch{Name: strings.TrimSpace(branchName)}
}
func (b *BranchListBuilder) obtainBranches() []*Branch {
cmdStr := `git branch --format="%(HEAD)|%(refname:short)|%(upstream:short)|%(upstream:track)"`
output, err := b.GitCommand.OSCommand.RunCommandWithOutput(cmdStr)
func (b *BranchListBuilder) obtainReflogBranches() []*Branch {
branches := make([]*Branch, 0)
// if we directly put this string in RunCommandWithOutput the compiler complains because it thinks it's a format string
unescaped := "git reflog --date=relative --pretty='%gd|%gs' --grep-reflog='checkout: moving' HEAD"
rawString, err := b.GitCommand.OSCommand.RunCommandWithOutput(unescaped)
if err != nil {
return branches
}
branchLines := utils.SplitLines(rawString)
for _, line := range branchLines {
recency, branchName := branchInfoFromLine(line)
if branchName == "" {
continue
}
branch := &Branch{Name: branchName, Recency: recency}
branches = append(branches, branch)
}
return uniqueByName(branches)
}
func (b *BranchListBuilder) obtainSafeBranches() []*Branch {
branches := make([]*Branch, 0)
bIter, err := b.GitCommand.Repo.Branches()
if err != nil {
panic(err)
}
trimmedOutput := strings.TrimSpace(output)
outputLines := strings.Split(trimmedOutput, "\n")
branches := make([]*Branch, len(outputLines))
for i, line := range outputLines {
split := strings.Split(line, SEPARATION_CHAR)
name := split[1]
branches[i] = &Branch{
Name: name,
Pullables: "?",
Pushables: "?",
Head: split[0] == "*",
}
upstreamName := split[2]
if upstreamName == "" {
continue
}
branches[i].UpstreamName = upstreamName
track := split[3]
re := regexp.MustCompile(`ahead (\d+)`)
match := re.FindStringSubmatch(track)
if len(match) > 1 {
branches[i].Pushables = match[1]
} else {
branches[i].Pushables = "0"
}
re = regexp.MustCompile(`behind (\d+)`)
match = re.FindStringSubmatch(track)
if len(match) > 1 {
branches[i].Pullables = match[1]
} else {
branches[i].Pullables = "0"
}
}
bIter.ForEach(func(b *plumbing.Reference) error {
name := b.Name().Short()
branches = append(branches, &Branch{Name: name})
return nil
})
return branches
}
func (b *BranchListBuilder) appendNewBranches(finalBranches, newBranches, existingBranches []*Branch, included bool) []*Branch {
for _, newBranch := range newBranches {
if included == branchIncluded(newBranch.Name, existingBranches) {
finalBranches = append(finalBranches, newBranch)
}
}
return finalBranches
}
func sanitisedReflogName(reflogBranch *Branch, safeBranches []*Branch) string {
for _, safeBranch := range safeBranches {
if strings.ToLower(safeBranch.Name) == strings.ToLower(reflogBranch.Name) {
return safeBranch.Name
}
}
return reflogBranch.Name
}
// Build the list of branches for the current repo
func (b *BranchListBuilder) Build() []*Branch {
currentBranchName := b.obtainCurrentBranchName()
branches := b.obtainBranches()
branches := make([]*Branch, 0)
head := b.obtainCurrentBranch()
safeBranches := b.obtainSafeBranches()
reflogBranches := b.obtainReflogBranches()
// loop through reflog branches. If there is a match, merge them, then remove it from the branches and keep it in the reflog branches
branchesWithRecency := make([]*Branch, 0)
outer:
for _, reflogBranch := range reflogBranches {
for j, branch := range branches {
if branch.Head {
continue
}
if strings.EqualFold(reflogBranch.Name, branch.Name) {
branch.Recency = reflogBranch.Recency
branchesWithRecency = append(branchesWithRecency, branch)
branches = append(branches[0:j], branches[j+1:]...)
continue outer
}
}
for i, reflogBranch := range reflogBranches {
reflogBranches[i].Name = sanitisedReflogName(reflogBranch, safeBranches)
}
branches = append(branchesWithRecency, branches...)
branches = b.appendNewBranches(branches, reflogBranches, safeBranches, true)
branches = b.appendNewBranches(branches, safeBranches, branches, false)
if len(branches) == 0 {
branches = append([]*Branch{{Name: currentBranchName}}, branches...)
if len(branches) == 0 || branches[0].Name != head.Name {
branches = append([]*Branch{head}, branches...)
}
for i, branch := range branches {
if branch.Head {
branch.Name = currentBranchName
branch.Recency = " *"
branches = append(branches[0:i], branches[i+1:]...)
branches = append([]*Branch{branch}, branches...)
break
}
}
branches[0].Recency = " *"
return branches
}
func branchIncluded(branchName string, branches []*Branch) bool {
for _, existingBranch := range branches {
if strings.ToLower(existingBranch.Name) == strings.ToLower(branchName) {
return true
}
}
return false
}
func uniqueByName(branches []*Branch) []*Branch {
finalBranches := make([]*Branch, 0)
for _, branch := range branches {
if branchIncluded(branch.Name, finalBranches) {
continue
}
finalBranches = append(finalBranches, branch)
}
return finalBranches
}
// A line will have the form '10 days ago master' so we need to strip out the
// useful information from that into timeNumber, timeUnit, and branchName
func branchInfoFromLine(line string) (string, string) {
@@ -162,30 +172,3 @@ func abbreviatedTimeUnit(timeUnit string) string {
}
return timeUnitMap[timeUnit]
}
func (b *BranchListBuilder) obtainReflogBranches() []*Branch {
branches := make([]*Branch, 0)
// if we directly put this string in RunCommandWithOutput the compiler complains because it thinks it's a format string
unescaped := "git reflog --date=relative --pretty='%gd|%gs' --grep-reflog='checkout: moving' HEAD"
rawString, err := b.GitCommand.OSCommand.RunCommandWithOutput(unescaped)
if err != nil {
return branches
}
branchNameMap := map[string]bool{}
branchLines := utils.SplitLines(rawString)
for _, line := range branchLines {
recency, branchName := branchInfoFromLine(line)
if branchName == "" {
continue
}
if _, ok := branchNameMap[branchName]; ok {
continue
}
branchNameMap[branchName] = true
branch := &Branch{Name: branchName, Recency: recency}
branches = append(branches, branch)
}
return branches
}
+4 -8
View File
@@ -327,8 +327,8 @@ func (c *GitCommand) ResetToCommit(sha string, strength string) error {
}
// NewBranch create new branch
func (c *GitCommand) NewBranch(name string, baseBranch string) error {
return c.OSCommand.RunCommand("git checkout -b %s %s", name, baseBranch)
func (c *GitCommand) NewBranch(name string) error {
return c.OSCommand.RunCommand("git checkout -b %s", name)
}
// CurrentBranchName is a function.
@@ -343,7 +343,7 @@ func (c *GitCommand) CurrentBranchName() (string, error) {
match := re.FindStringSubmatch(output)
branchName = match[1]
}
return strings.TrimSpace(branchName), nil
return utils.TrimTrailingNewline(branchName), nil
}
// DeleteBranch delete branch
@@ -563,7 +563,7 @@ func (c *GitCommand) ShowCmdStr(sha string) string {
}
func (c *GitCommand) GetBranchGraphCmdStr(branchName string) string {
return fmt.Sprintf("git log --graph --color=always --abbrev-commit --decorate --date=relative --pretty=medium %s --", branchName)
return fmt.Sprintf("git log --graph --color=always --abbrev-commit --decorate --date=relative --pretty=medium %s", branchName)
}
// GetRemoteURL returns current repo remote url
@@ -1163,7 +1163,3 @@ func (c *GitCommand) GetPager(width int) string {
func (c *GitCommand) colorArg() string {
return c.Config.GetUserConfig().GetString("git.paging.colorArg")
}
func (c *GitCommand) RenameBranch(oldName string, newName string) error {
return c.OSCommand.RunCommand("git branch --move %s %s", oldName, newName)
}
+4 -4
View File
@@ -636,12 +636,12 @@ func TestGitCommandNewBranch(t *testing.T) {
gitCmd := NewDummyGitCommand()
gitCmd.OSCommand.command = func(cmd string, args ...string) *exec.Cmd {
assert.EqualValues(t, "git", cmd)
assert.EqualValues(t, []string{"checkout", "-b", "test", "master"}, args)
assert.EqualValues(t, []string{"checkout", "-b", "test"}, args)
return exec.Command("echo")
}
assert.NoError(t, gitCmd.NewBranch("test", "master"))
assert.NoError(t, gitCmd.NewBranch("test"))
}
// TestGitCommandDeleteBranch is a function.
@@ -1449,7 +1449,7 @@ func TestGitCommandGetBranchGraph(t *testing.T) {
gitCmd := NewDummyGitCommand()
gitCmd.OSCommand.command = func(cmd string, args ...string) *exec.Cmd {
assert.EqualValues(t, "git", cmd)
assert.EqualValues(t, []string{"log", "--graph", "--color=always", "--abbrev-commit", "--decorate", "--date=relative", "--pretty=medium", "test", "--"}, args)
assert.EqualValues(t, []string{"log", "--graph", "--color=always", "--abbrev-commit", "--decorate", "--date=relative", "--pretty=medium", "test"}, args)
return exec.Command("echo")
}
@@ -2130,7 +2130,7 @@ func TestGitCommandSkipEditorCommand(t *testing.T) {
)
})
_ = cmd.RunSkipEditorCommand("true")
cmd.RunSkipEditorCommand("true")
}
func TestFindDotGitDir(t *testing.T) {
-2
View File
@@ -334,7 +334,6 @@ keybinding:
checkoutBranchByName: 'c'
forceCheckoutBranch: 'F'
rebaseBranch: 'r'
renameBranch: 'R'
mergeIntoCurrentBranch: 'M'
viewGitFlowOptions: 'i'
fastForward: 'f'
@@ -360,7 +359,6 @@ keybinding:
tagCommit: 'T'
toggleDiffCommit: 'i'
checkoutCommit: '<space>'
resetCherryPick: '<c-R>'
stash:
popStash: 'g'
commitFiles:
+3 -1
View File
@@ -66,7 +66,9 @@ func (gui *Gui) WithWaitingStatus(name string, f func() error) error {
if appStatus == "" {
return
}
gui.renderString(gui.g, "appStatus", appStatus)
if err := gui.renderString(gui.g, "appStatus", appStatus); err != nil {
gui.Log.Warn(err)
}
}
}()
+42 -63
View File
@@ -40,7 +40,12 @@ func (gui *Gui) handleBranchSelect(g *gocui.Gui, v *gocui.View) error {
return gui.newStringTask("main", gui.Tr.SLocalize("NoBranchesThisRepo"))
}
branch := gui.getSelectedBranch()
v.FocusPoint(0, gui.State.Panels.Branches.SelectedLine)
if err := gui.focusPoint(0, gui.State.Panels.Branches.SelectedLine, len(gui.State.Branches), v); err != nil {
return err
}
if err := gui.RenderSelectedBranchUpstreamDifferences(); err != nil {
return err
}
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.GetBranchGraphCmdStr(branch.Name),
@@ -51,6 +56,24 @@ func (gui *Gui) handleBranchSelect(g *gocui.Gui, v *gocui.View) error {
return nil
}
func (gui *Gui) RenderSelectedBranchUpstreamDifferences() error {
return gui.newTask("branches", func(stop chan struct{}) error {
branch := gui.getSelectedBranch()
branch.Pushables, branch.Pullables = gui.GitCommand.GetBranchUpstreamDifferenceCount(branch.Name)
select {
case <-stop:
return nil
default:
}
branchesView := gui.getBranchesView()
displayStrings := presentation.GetBranchListDisplayStrings(gui.State.Branches, gui.currentViewName() == "branches", gui.State.Panels.Branches.SelectedLine)
gui.renderDisplayStrings(branchesView, displayStrings)
return nil
})
}
// gui.refreshStatus is called at the end of this because that's when we can
// be sure there is a state.Branches array to pick the current branch from
func (gui *Gui) refreshBranches(g *gocui.Gui) error {
@@ -85,8 +108,9 @@ func (gui *Gui) renderLocalBranchesWithSelection() error {
branchesView := gui.getBranchesView()
gui.refreshSelectedLine(&gui.State.Panels.Branches.SelectedLine, len(gui.State.Branches))
displayStrings := presentation.GetBranchListDisplayStrings(gui.State.Branches, gui.State.ScreenMode != SCREEN_NORMAL)
gui.renderDisplayStrings(branchesView, displayStrings)
if err := gui.RenderSelectedBranchUpstreamDifferences(); err != nil {
return err
}
if gui.g.CurrentView() == branchesView {
if err := gui.handleBranchSelect(gui.g, branchesView); err != nil {
return err
@@ -137,7 +161,7 @@ func (gui *Gui) handleForceCheckout(g *gocui.Gui, v *gocui.View) error {
title := gui.Tr.SLocalize("ForceCheckoutBranch")
return gui.createConfirmationPanel(g, v, true, title, message, func(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.Checkout(branch.Name, true); err != nil {
_ = gui.createErrorPanel(g, err.Error())
gui.createErrorPanel(g, err.Error())
}
return gui.refreshSidePanels(g)
}, nil)
@@ -181,9 +205,10 @@ func (gui *Gui) handleCheckoutRef(ref string) error {
}
func (gui *Gui) handleCheckoutByName(g *gocui.Gui, v *gocui.View) error {
return gui.createPromptPanel(g, v, gui.Tr.SLocalize("BranchName")+":", "", func(g *gocui.Gui, v *gocui.View) error {
gui.createPromptPanel(g, v, gui.Tr.SLocalize("BranchName")+":", "", func(g *gocui.Gui, v *gocui.View) error {
return gui.handleCheckoutRef(gui.trimmedContent(v))
})
return nil
}
func (gui *Gui) getCheckedOutBranch() *commands.Branch {
@@ -195,31 +220,31 @@ func (gui *Gui) getCheckedOutBranch() *commands.Branch {
}
func (gui *Gui) handleNewBranch(g *gocui.Gui, v *gocui.View) error {
branch := gui.getSelectedBranch()
if branch == nil {
return nil
}
branch := gui.getCheckedOutBranch()
message := gui.Tr.TemplateLocalize(
"NewBranchNameBranchOff",
Teml{
"branchName": branch.Name,
},
)
return gui.createPromptPanel(g, v, message, "", func(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.NewBranch(gui.trimmedContent(v), branch.Name); err != nil {
return gui.createErrorPanel(g, err.Error())
}
if err := gui.refreshSidePanels(g); err != nil {
gui.createPromptPanel(g, v, message, "", func(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.NewBranch(gui.trimmedContent(v)); err != nil {
return gui.createErrorPanel(g, err.Error())
}
gui.refreshSidePanels(g)
return gui.handleBranchSelect(g, v)
})
return nil
}
func (gui *Gui) handleDeleteBranch(g *gocui.Gui, v *gocui.View) error {
return gui.deleteBranch(g, v, false)
}
func (gui *Gui) handleForceDeleteBranch(g *gocui.Gui, v *gocui.View) error {
return gui.deleteBranch(g, v, true)
}
func (gui *Gui) deleteBranch(g *gocui.Gui, v *gocui.View, force bool) error {
selectedBranch := gui.getSelectedBranch()
if selectedBranch == nil {
@@ -353,7 +378,7 @@ func (gui *Gui) handleFastForward(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.FastForward(branch.Name, remoteName, remoteBranchName); err != nil {
_ = gui.createErrorPanel(gui.g, err.Error())
}
_ = gui.refreshBranches(gui.g)
_ = gui.RenderSelectedBranchUpstreamDifferences()
}
_ = gui.closeConfirmationPrompt(gui.g, true)
@@ -372,9 +397,7 @@ func (gui *Gui) onBranchesTabClick(tabIndex int) error {
func (gui *Gui) switchBranchesPanelContext(context string) error {
branchesView := gui.getBranchesView()
branchesView.Context = context
if err := gui.onSearchEscape(); err != nil {
return err
}
gui.onSearchEscape()
contextTabIndexMap := map[string]int{
"local-branches": 0,
@@ -385,13 +408,7 @@ func (gui *Gui) switchBranchesPanelContext(context string) error {
branchesView.TabIndex = contextTabIndexMap[context]
return gui.refreshBranchesViewWithSelection()
}
func (gui *Gui) refreshBranchesViewWithSelection() error {
branchesView := gui.getBranchesView()
switch branchesView.Context {
switch context {
case "local-branches":
return gui.renderLocalBranchesWithSelection()
case "remotes":
@@ -441,41 +458,3 @@ func (gui *Gui) onBranchesPanelSearchSelect(selectedLine int) error {
}
return nil
}
func (gui *Gui) handleRenameBranch(g *gocui.Gui, v *gocui.View) error {
branch := gui.getSelectedBranch()
if branch == nil {
return nil
}
promptForNewName := func() error {
return gui.createPromptPanel(g, v, gui.Tr.SLocalize("NewBranchNamePrompt")+" "+branch.Name+":", "", func(g *gocui.Gui, v *gocui.View) error {
newName := gui.trimmedContent(v)
if err := gui.GitCommand.RenameBranch(branch.Name, newName); err != nil {
return gui.createErrorPanel(gui.g, err.Error())
}
// need to checkout so that the branch shows up in our reflog and therefore
// doesn't get lost among all the other branches when we switch to something else
if err := gui.GitCommand.Checkout(newName, false); err != nil {
return gui.createErrorPanel(gui.g, err.Error())
}
return gui.refreshBranches(gui.g)
})
}
// I could do an explicit check here for whether the branch is tracking a remote branch
// but if we've selected it we'll already know that via Pullables and Pullables.
// Bit of a hack but I'm lazy.
notTrackingRemote := branch.Pullables == "?"
if notTrackingRemote {
return promptForNewName()
}
return gui.createConfirmationPanel(gui.g, v, true, gui.Tr.SLocalize("renameBranch"), gui.Tr.SLocalize("RenameBranchWarning"), func(_g *gocui.Gui, _v *gocui.View) error {
return promptForNewName()
}, nil)
}
func (gui *Gui) currentBranch() *commands.Branch {
return gui.State.Branches[0]
}
+6 -7
View File
@@ -36,15 +36,16 @@ func (gui *Gui) handleCommitFileSelect(g *gocui.Gui, v *gocui.View) error {
commitFile := gui.getSelectedCommitFile(g)
if commitFile == nil {
gui.renderString(g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
return nil
return gui.renderString(g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
}
if err := gui.refreshSecondaryPatchPanel(); err != nil {
return err
}
v.FocusPoint(0, gui.State.Panels.CommitFiles.SelectedLine)
if err := gui.focusPoint(0, gui.State.Panels.CommitFiles.SelectedLine, len(gui.State.CommitFiles), v); err != nil {
return err
}
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.ShowCommitFileCmdStr(commitFile.Sha, commitFile.Name, false),
@@ -131,8 +132,7 @@ func (gui *Gui) handleToggleFileForPatch(g *gocui.Gui, v *gocui.View) error {
commitFile := gui.getSelectedCommitFile(g)
if commitFile == nil {
gui.renderString(g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
return nil
return gui.renderString(g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
}
toggleTheFile := func() error {
@@ -187,8 +187,7 @@ func (gui *Gui) enterCommitFile(selectedLineIdx int) error {
commitFile := gui.getSelectedCommitFile(gui.g)
if commitFile == nil {
gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
return nil
return gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
}
enterTheFile := func(selectedLineIdx int) error {
+2 -3
View File
@@ -52,7 +52,7 @@ func (gui *Gui) handleCommitConfirm(g *gocui.Gui, v *gocui.View) error {
}
func (gui *Gui) handleCommitClose(g *gocui.Gui, v *gocui.View) error {
_, _ = g.SetViewOnBottom("commitMessage")
g.SetViewOnBottom("commitMessage")
return gui.switchFocus(g, v, gui.getFilesView())
}
@@ -68,8 +68,7 @@ func (gui *Gui) handleCommitFocused(g *gocui.Gui, v *gocui.View) error {
"keyBindConfirm": "enter",
},
)
gui.renderString(g, "options", message)
return nil
return gui.renderString(g, "options", message)
}
func (gui *Gui) getBufferLength(view *gocui.View) string {
+59 -13
View File
@@ -3,6 +3,8 @@ package gui
import (
"strconv"
"github.com/go-errors/errors"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
@@ -53,7 +55,9 @@ func (gui *Gui) handleCommitSelect(g *gocui.Gui, v *gocui.View) error {
return gui.newStringTask("main", gui.Tr.SLocalize("NoCommitsThisBranch"))
}
v.FocusPoint(0, gui.State.Panels.Commits.SelectedLine)
if err := gui.focusPoint(0, gui.State.Panels.Commits.SelectedLine, len(gui.State.Commits), v); err != nil {
return err
}
// if specific diff mode is on, don't show diff
if gui.State.Panels.Commits.SpecificDiffMode {
@@ -73,7 +77,7 @@ func (gui *Gui) handleCommitSelect(g *gocui.Gui, v *gocui.View) error {
func (gui *Gui) refreshCommits(g *gocui.Gui) error {
g.Update(func(*gocui.Gui) error {
// I think this is here for the sake of some kind of rebasing thing
_ = gui.refreshStatus(g)
gui.refreshStatus(g)
if err := gui.refreshCommitsWithLimit(); err != nil {
return err
@@ -117,6 +121,28 @@ func (gui *Gui) refreshCommitsWithLimit() error {
// specific functions
func (gui *Gui) handleResetToCommit(g *gocui.Gui, commitView *gocui.View) error {
return gui.createConfirmationPanel(g, commitView, true, gui.Tr.SLocalize("ResetToCommit"), gui.Tr.SLocalize("SureResetThisCommit"), func(g *gocui.Gui, v *gocui.View) error {
commit := gui.getSelectedCommit(g)
if commit == nil {
panic(errors.New(gui.Tr.SLocalize("NoCommitsThisBranch")))
}
if err := gui.GitCommand.ResetToCommit(commit.Sha, "mixed"); err != nil {
return gui.createErrorPanel(g, err.Error())
}
if err := gui.refreshCommits(g); err != nil {
panic(err)
}
if err := gui.refreshFiles(); err != nil {
panic(err)
}
gui.resetOrigin(commitView)
gui.State.Panels.Commits.SelectedLine = 0
return gui.handleCommitSelect(g, commitView)
}, nil)
}
func (gui *Gui) handleCommitSquashDown(g *gocui.Gui, v *gocui.View) error {
if len(gui.State.Commits) <= 1 {
return gui.createErrorPanel(g, gui.Tr.SLocalize("YouNoCommitsToSquash"))
@@ -130,12 +156,23 @@ func (gui *Gui) handleCommitSquashDown(g *gocui.Gui, v *gocui.View) error {
return nil
}
return gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("Squash"), gui.Tr.SLocalize("SureSquashThisCommit"), func(g *gocui.Gui, v *gocui.View) error {
gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("Squash"), gui.Tr.SLocalize("SureSquashThisCommit"), func(g *gocui.Gui, v *gocui.View) error {
return gui.WithWaitingStatus(gui.Tr.SLocalize("SquashingStatus"), func() error {
err := gui.GitCommand.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLine, "squash")
return gui.handleGenericMergeCommandResult(err)
})
}, nil)
return nil
}
// TODO: move to files panel
func (gui *Gui) anyUnStagedChanges(files []*commands.File) bool {
for _, file := range files {
if file.Tracked && file.HasUnstagedChanges {
return true
}
}
return false
}
func (gui *Gui) handleCommitFixup(g *gocui.Gui, v *gocui.View) error {
@@ -151,12 +188,13 @@ func (gui *Gui) handleCommitFixup(g *gocui.Gui, v *gocui.View) error {
return nil
}
return gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("Fixup"), gui.Tr.SLocalize("SureFixupThisCommit"), func(g *gocui.Gui, v *gocui.View) error {
gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("Fixup"), gui.Tr.SLocalize("SureFixupThisCommit"), func(g *gocui.Gui, v *gocui.View) error {
return gui.WithWaitingStatus(gui.Tr.SLocalize("FixingStatus"), func() error {
err := gui.GitCommand.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLine, "fixup")
return gui.handleGenericMergeCommandResult(err)
})
}, nil)
return nil
}
func (gui *Gui) handleRenameCommit(g *gocui.Gui, v *gocui.View) error {
@@ -226,6 +264,21 @@ func (gui *Gui) handleMidRebaseCommand(action string) (bool, error) {
return true, gui.refreshCommits(gui.g)
}
// handleMoveTodoDown like handleMidRebaseCommand but for moving an item up in the todo list
func (gui *Gui) handleMoveTodoDown(index int) (bool, error) {
selectedCommit := gui.State.Commits[index]
if selectedCommit.Status != "rebasing" {
return false, nil
}
if gui.State.Commits[index+1].Status != "rebasing" {
return true, nil
}
if err := gui.GitCommand.MoveTodoDown(index); err != nil {
return true, gui.createErrorPanel(gui.g, err.Error())
}
return true, gui.refreshCommits(gui.g)
}
func (gui *Gui) handleCommitDelete(g *gocui.Gui, v *gocui.View) error {
applied, err := gui.handleMidRebaseCommand("drop")
if err != nil {
@@ -451,7 +504,7 @@ func (gui *Gui) setDiffMode() {
v.Title = gui.Tr.SLocalize("CommitsTitle")
}
_ = gui.refreshCommits(gui.g)
gui.refreshCommits(gui.g)
}
func (gui *Gui) hasCommit(commits []*commands.Commit, target string) (int, bool) {
@@ -570,9 +623,7 @@ func (gui *Gui) onCommitsTabClick(tabIndex int) error {
func (gui *Gui) switchCommitsPanelContext(context string) error {
commitsView := gui.getCommitsView()
commitsView.Context = context
if err := gui.onSearchEscape(); err != nil {
return err
}
gui.onSearchEscape()
contextTabIndexMap := map[string]int{
"branch-commits": 0,
@@ -642,8 +693,3 @@ func (gui *Gui) handleOpenSearchForCommitsPanel(g *gocui.Gui, v *gocui.View) err
return gui.handleOpenSearch(gui.g, v)
}
func (gui *Gui) handleResetCherryPick(g *gocui.Gui, v *gocui.View) error {
gui.State.CherryPickedCommits = []*commands.Commit{}
return gui.refreshCommits(gui.g)
}
+10 -2
View File
@@ -122,7 +122,9 @@ func (gui *Gui) createPopupPanel(g *gocui.Gui, currentView *gocui.View, title, p
}()
}
gui.renderString(g, "confirmation", prompt)
if err := gui.renderString(g, "confirmation", prompt); err != nil {
return err
}
return gui.setKeyBindings(g, handleConfirm, handleClose, returnFocusOnClose)
})
return nil
@@ -149,13 +151,19 @@ func (gui *Gui) setKeyBindings(g *gocui.Gui, handleConfirm, handleClose func(*go
"keyBindConfirm": "enter",
},
)
gui.renderString(g, "options", actions)
if err := gui.renderString(g, "options", actions); err != nil {
return err
}
if err := g.SetKeybinding("confirmation", nil, gocui.KeyEnter, gocui.ModNone, gui.wrappedConfirmationFunction(handleConfirm, returnFocusOnClose)); err != nil {
return err
}
return g.SetKeybinding("confirmation", nil, gocui.KeyEsc, gocui.ModNone, gui.wrappedConfirmationFunction(handleClose, returnFocusOnClose))
}
func (gui *Gui) createMessagePanel(g *gocui.Gui, currentView *gocui.View, title, prompt string) error {
return gui.createPopupPanel(g, currentView, title, prompt, false, true, false, nil, nil)
}
// createSpecificErrorPanel allows you to create an error popup, specifying the
// view to be focused when the user closes the popup, and a boolean specifying
// whether we will log the error. If the message may include a user password,
+1
View File
@@ -16,4 +16,5 @@ func (gui *Gui) changeMainViewsContext(context string) {
}
gui.State.MainContext = context
return
}
+1 -2
View File
@@ -82,8 +82,7 @@ func (gui *Gui) handleCredentialsViewFocused(g *gocui.Gui, v *gocui.View) error
"keyBindConfirm": "enter",
},
)
gui.renderString(g, "options", message)
return nil
return gui.renderString(g, "options", message)
}
// HandleCredentialsPopup handles the views after executing a command that might ask for credentials
+2 -4
View File
@@ -23,13 +23,11 @@ type fileWatcher struct {
}
func NewFileWatcher(log *logrus.Entry) *fileWatcher {
// TODO: get this going again, and ensure we don't see any crashes from it
watcher, err := fsnotify.NewWatcher()
log.Error(err)
return &fileWatcher{
Disabled: true,
}
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Error(err)
return &fileWatcher{
+36 -24
View File
@@ -37,7 +37,9 @@ func (gui *Gui) selectFile(alreadySelected bool) error {
return gui.newStringTask("main", gui.Tr.SLocalize("NoChangedFiles"))
}
gui.getFilesView().FocusPoint(0, gui.State.Panels.Files.SelectedLine)
if err := gui.focusPoint(0, gui.State.Panels.Files.SelectedLine, len(gui.State.Files), gui.getFilesView()); err != nil {
return err
}
if file.HasInlineMergeConflicts {
gui.getMainView().Title = gui.Tr.SLocalize("MergeConflictsTitle")
@@ -186,12 +188,9 @@ func (gui *Gui) handleFilePress(g *gocui.Gui, v *gocui.View) error {
}
if file.HasUnstagedChanges {
err = gui.GitCommand.StageFile(file.Name)
gui.GitCommand.StageFile(file.Name)
} else {
err = gui.GitCommand.UnStageFile(file.Name, file.Tracked)
}
if err != nil {
return gui.createErrorPanel(gui.g, err.Error())
gui.GitCommand.UnStageFile(file.Name, file.Tracked)
}
if err := gui.refreshFiles(); err != nil {
@@ -269,7 +268,9 @@ func (gui *Gui) handleWIPCommitPress(g *gocui.Gui, filesView *gocui.View) error
return gui.createErrorPanel(gui.g, gui.Tr.SLocalize("SkipHookPrefixNotConfigured"))
}
gui.renderString(g, "commitMessage", skipHookPreifx)
if err := gui.renderString(g, "commitMessage", skipHookPreifx); err != nil {
return err
}
if err := gui.getCommitMessageView().SetCursor(len(skipHookPreifx), 0); err != nil {
return err
}
@@ -283,14 +284,8 @@ func (gui *Gui) handleCommitPress(g *gocui.Gui, filesView *gocui.View) error {
}
commitMessageView := gui.getCommitMessageView()
g.Update(func(g *gocui.Gui) error {
if _, err := g.SetViewOnTop("commitMessage"); err != nil {
return err
}
if err := gui.switchFocus(g, filesView, commitMessageView); err != nil {
return err
}
g.SetViewOnTop("commitMessage")
gui.switchFocus(g, filesView, commitMessageView)
gui.RenderCommitLength()
return nil
})
@@ -399,20 +394,24 @@ func (gui *Gui) catSelectedFile(g *gocui.Gui) (string, error) {
func (gui *Gui) handlePullFiles(g *gocui.Gui, v *gocui.View) error {
// if we have no upstream branch we need to set that first
currentBranch := gui.currentBranch()
if currentBranch.Pullables == "?" {
_, pullables := gui.GitCommand.GetCurrentBranchUpstreamDifferenceCount()
currentBranchName, err := gui.GitCommand.CurrentBranchName()
if err != nil {
return err
}
if pullables == "?" {
// see if we have this branch in our config with an upstream
conf, err := gui.GitCommand.Repo.Config()
if err != nil {
return gui.createErrorPanel(gui.g, err.Error())
}
for branchName, branch := range conf.Branches {
if branchName == currentBranch.Name {
if branchName == currentBranchName {
return gui.pullFiles(v, fmt.Sprintf("%s %s", branch.Remote, branchName))
}
}
return gui.createPromptPanel(g, v, gui.Tr.SLocalize("EnterUpstream"), "origin/"+currentBranch.Name, func(g *gocui.Gui, v *gocui.View) error {
return gui.createPromptPanel(g, v, gui.Tr.SLocalize("EnterUpstream"), "origin/"+currentBranchName, func(g *gocui.Gui, v *gocui.View) error {
upstream := gui.trimmedContent(v)
if err := gui.GitCommand.SetUpstreamBranch(upstream); err != nil {
errorMessage := err.Error()
@@ -463,24 +462,28 @@ func (gui *Gui) pushWithForceFlag(g *gocui.Gui, v *gocui.View, force bool, upstr
func (gui *Gui) pushFiles(g *gocui.Gui, v *gocui.View) error {
// if we have pullables we'll ask if the user wants to force push
currentBranch := gui.currentBranch()
_, pullables := gui.GitCommand.GetCurrentBranchUpstreamDifferenceCount()
currentBranchName, err := gui.GitCommand.CurrentBranchName()
if err != nil {
return err
}
if currentBranch.Pullables == "?" {
if pullables == "?" {
// see if we have this branch in our config with an upstream
conf, err := gui.GitCommand.Repo.Config()
if err != nil {
return gui.createErrorPanel(gui.g, err.Error())
}
for branchName, branch := range conf.Branches {
if branchName == currentBranch.Name {
if branchName == currentBranchName {
return gui.pushWithForceFlag(g, v, false, "", fmt.Sprintf("%s %s", branch.Remote, branchName))
}
}
return gui.createPromptPanel(g, v, gui.Tr.SLocalize("EnterUpstream"), "origin "+currentBranch.Name, func(g *gocui.Gui, v *gocui.View) error {
return gui.createPromptPanel(g, v, gui.Tr.SLocalize("EnterUpstream"), "origin "+currentBranchName, func(g *gocui.Gui, v *gocui.View) error {
return gui.pushWithForceFlag(g, v, false, gui.trimmedContent(v), "")
})
} else if currentBranch.Pullables == "0" {
} else if pullables == "0" {
return gui.pushWithForceFlag(g, v, false, "", "")
}
return gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("ForcePush"), gui.Tr.SLocalize("ForcePushPrompt"), func(g *gocui.Gui, v *gocui.View) error {
@@ -506,6 +509,15 @@ func (gui *Gui) handleSwitchToMerge(g *gocui.Gui, v *gocui.View) error {
return gui.refreshMergePanel()
}
func (gui *Gui) handleAbortMerge(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.AbortMerge(); err != nil {
return gui.createErrorPanel(g, err.Error())
}
gui.createMessagePanel(g, v, "", gui.Tr.SLocalize("MergeAborted"))
gui.refreshStatus(g)
return gui.refreshFiles()
}
func (gui *Gui) openFile(filename string) error {
if err := gui.OSCommand.OpenFile(filename); err != nil {
return gui.createErrorPanel(gui.g, err.Error())
+27 -35
View File
@@ -24,6 +24,7 @@ import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
"github.com/jesseduffield/lazygit/pkg/i18n"
"github.com/jesseduffield/lazygit/pkg/tasks"
"github.com/jesseduffield/lazygit/pkg/theme"
@@ -80,7 +81,7 @@ type Gui struct {
GitCommand *commands.GitCommand
OSCommand *commands.OSCommand
SubProcess *exec.Cmd
State *guiState
State guiState
Config config.AppConfigurer
Tr *i18n.Localizer
Errors SentinelErrors
@@ -213,7 +214,6 @@ type guiState struct {
Ptmx *os.File
PrevMainWidth int
PrevMainHeight int
OldInformation string
}
// for now the split view will always be on
@@ -221,7 +221,7 @@ type guiState struct {
// NewGui builds a new gui handler
func NewGui(log *logrus.Entry, gitCommand *commands.GitCommand, oSCommand *commands.OSCommand, tr *i18n.Localizer, config config.AppConfigurer, updater *updates.Updater) (*Gui, error) {
initialState := &guiState{
initialState := guiState{
Files: make([]*commands.File, 0),
PreviousView: "files",
Commits: make([]*commands.Commit, 0),
@@ -278,10 +278,6 @@ func (gui *Gui) nextScreenMode(g *gocui.Gui, v *gocui.View) error {
if err := gui.refreshCommitsViewWithSelection(); err != nil {
return err
}
// same with branches
if err := gui.refreshBranchesViewWithSelection(); err != nil {
return err
}
return nil
}
@@ -292,10 +288,6 @@ func (gui *Gui) prevScreenMode(g *gocui.Gui, v *gocui.View) error {
if err := gui.refreshCommitsViewWithSelection(); err != nil {
return err
}
// same with branches
if err := gui.refreshBranchesViewWithSelection(); err != nil {
return err
}
return nil
}
@@ -389,11 +381,15 @@ func (gui *Gui) onFocusLost(v *gocui.View, newView *gocui.View) error {
return nil
}
if v.IsSearching() && newView.Name() != "search" {
if err := gui.onSearchEscape(); err != nil {
return err
}
gui.onSearchEscape()
}
switch v.Name() {
case "branches":
if v.Context == "local-branches" {
// This stops the branches panel from showing the upstream/downstream changes to the selected branch, when it loses focus
displayStrings := presentation.GetBranchListDisplayStrings(gui.State.Branches, false, -1)
gui.renderDisplayStrings(gui.getBranchesView(), displayStrings)
}
case "main":
// if we have lost focus to a first-class panel, we need to do some cleanup
gui.changeMainViewsContext("normal")
@@ -495,9 +491,6 @@ func (gui *Gui) layout(g *gocui.Gui) error {
donate := color.New(color.FgMagenta, color.Underline).Sprint(gui.Tr.SLocalize("Donate"))
information = donate + " " + information
}
if len(gui.State.CherryPickedCommits) > 0 {
information = utils.ColoredString(fmt.Sprintf("%d commits copied", len(gui.State.CherryPickedCommits)), color.FgCyan)
}
minimumHeight := 9
minimumWidth := 10
@@ -525,7 +518,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
}
_, _ = g.SetViewOnBottom("limit")
_ = g.DeleteView("limit")
g.DeleteView("limit")
sidePanelWidthRatio := gui.Config.GetUserConfig().GetFloat64("gui.sidePanelWidth")
@@ -545,6 +538,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
}
}
panelSplitX := width - 1
mainPanelLeft := leftSideWidth + 1
mainPanelRight := width - 1
secondaryPanelLeft := width - 1
@@ -553,7 +547,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
if gui.State.SplitMainPanel {
if gui.State.ScreenMode == SCREEN_FULL {
mainPanelLeft = 0
panelSplitX := width/2 - 4
panelSplitX = width/2 - 4
mainPanelRight = panelSplitX
secondaryPanelLeft = panelSplitX + 1
} else if width < 220 {
@@ -564,7 +558,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
units := 5
leftSideWidth = width / units
mainPanelLeft = leftSideWidth + 1
panelSplitX := (1 + ((units - 1) / 2)) * width / units
panelSplitX = (1 + ((units - 1) / 2)) * width / units
mainPanelRight = panelSplitX
secondaryPanelLeft = panelSplitX + 1
}
@@ -699,7 +693,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
if err.Error() != "unknown view" {
return err
}
_, _ = g.SetViewOnBottom("commitMessage")
g.SetViewOnBottom("commitMessage")
commitMessageView.Title = gui.Tr.SLocalize("CommitMessage")
commitMessageView.FgColor = textColor
commitMessageView.Editable = true
@@ -764,25 +758,22 @@ func (gui *Gui) layout(g *gocui.Gui) error {
}
}
informationView, err := g.SetView("information", optionsVersionBoundary-1, height-2, width, height, 0)
if err != nil {
if v, err := g.SetView("information", optionsVersionBoundary-1, height-2, width, height, 0); err != nil {
if err.Error() != "unknown view" {
return err
}
informationView.BgColor = gocui.ColorDefault
informationView.FgColor = gocui.ColorGreen
informationView.Frame = false
gui.renderString(g, "information", information)
v.BgColor = gocui.ColorDefault
v.FgColor = gocui.ColorGreen
v.Frame = false
if err := gui.renderString(g, "information", information); err != nil {
return err
}
// doing this here because it'll only happen once
if err := gui.onInitialViewsCreation(); err != nil {
return err
}
}
if gui.State.OldInformation != information {
gui.setViewContent(g, informationView, information)
gui.State.OldInformation = information
}
if gui.g.CurrentView() == nil {
if _, err := gui.g.SetCurrentView(gui.getFilesView().Name()); err != nil {
@@ -821,7 +812,9 @@ func (gui *Gui) layout(g *gocui.Gui) error {
continue
}
// check if the selected line is now out of view and if so refocus it
listView.view.FocusPoint(0, listView.selectedLine)
if err := gui.focusPoint(0, listView.selectedLine, listView.lineCount, listView.view); err != nil {
return err
}
}
mainViewWidth, mainViewHeight := gui.getMainView().Size()
@@ -916,8 +909,7 @@ func (gui *Gui) fetch(g *gocui.Gui, v *gocui.View, canAskForCredentials bool) (u
_ = gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("Error"), coloredMessage, close, close)
}
_ = gui.refreshStatus(g)
gui.refreshStatus(g)
return unamePassOpend, err
}
@@ -926,7 +918,7 @@ func (gui *Gui) renderGlobalOptions() error {
fmt.Sprintf("%s/%s", gui.getKeyDisplay("universal.scrollUpMain"), gui.getKeyDisplay("universal.scrollDownMain")): gui.Tr.SLocalize("scroll"),
fmt.Sprintf("%s %s %s %s", gui.getKeyDisplay("universal.prevBlock"), gui.getKeyDisplay("universal.nextBlock"), gui.getKeyDisplay("universal.prevItem"), gui.getKeyDisplay("universal.nextItem")): gui.Tr.SLocalize("navigate"),
fmt.Sprintf("%s/%s", gui.getKeyDisplay("universal.return"), gui.getKeyDisplay("universal.quit")): gui.Tr.SLocalize("close"),
gui.getKeyDisplay("universal.optionMenu"): gui.Tr.SLocalize("menu"),
fmt.Sprintf("%s", gui.getKeyDisplay("universal.optionMenu")): gui.Tr.SLocalize("menu"),
"1-5": gui.Tr.SLocalize("jump"),
})
}
+21 -41
View File
@@ -162,15 +162,15 @@ func (gui *Gui) getKeyDisplay(name string) string {
func GetKeyDisplay(key interface{}) string {
keyInt := 0
switch key := key.(type) {
switch key.(type) {
case rune:
keyInt = int(key)
keyInt = int(key.(rune))
case gocui.Key:
value, ok := keyMapReversed[key]
value, ok := keyMapReversed[key.(gocui.Key)]
if ok {
return value
}
keyInt = int(key)
keyInt = int(key.(gocui.Key))
}
return string(keyInt)
@@ -295,11 +295,10 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Description: gui.Tr.SLocalize("refresh"),
},
{
ViewName: "",
Key: gui.getKey("universal.optionMenu"),
Modifier: gocui.ModNone,
Handler: gui.handleCreateOptionsMenu,
Description: gui.Tr.SLocalize("openMenu"),
ViewName: "",
Key: gui.getKey("universal.optionMenu"),
Modifier: gocui.ModNone,
Handler: gui.handleCreateOptionsMenu,
},
{
ViewName: "",
@@ -569,14 +568,6 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Handler: gui.handleCreateResetToBranchMenu,
Description: gui.Tr.SLocalize("viewResetOptions"),
},
{
ViewName: "branches",
Contexts: []string{"local-branches"},
Key: gui.getKey("branches.renameBranch"),
Modifier: gocui.ModNone,
Handler: gui.handleRenameBranch,
Description: gui.Tr.SLocalize("renameBranch"),
},
{
ViewName: "branches",
Contexts: []string{"tags"},
@@ -666,11 +657,10 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Handler: gui.handlePrevCommitsTab,
},
{
ViewName: "commits",
Key: gui.getKey("universal.startSearch"),
Modifier: gocui.ModNone,
Handler: gui.handleOpenSearchForCommitsPanel,
Description: gui.Tr.SLocalize("startSearch"),
ViewName: "commits",
Key: gui.getKey("universal.startSearch"),
Modifier: gocui.ModNone,
Handler: gui.handleOpenSearchForCommitsPanel,
},
{
ViewName: "commits",
@@ -840,14 +830,6 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Handler: gui.handleTagCommit,
Description: gui.Tr.SLocalize("tagCommit"),
},
{
ViewName: "commits",
Contexts: []string{"branch-commits"},
Key: gui.getKey("commits.resetCherryPick"),
Modifier: gocui.ModNone,
Handler: gui.handleResetCherryPick,
Description: gui.Tr.SLocalize("resetCherryPick"),
},
{
ViewName: "commits",
Contexts: []string{"reflog-commits"},
@@ -910,18 +892,16 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Handler: gui.handleCloseCredentialsView,
},
{
ViewName: "menu",
Key: gui.getKey("universal.return"),
Modifier: gocui.ModNone,
Handler: gui.handleMenuClose,
Description: gui.Tr.SLocalize("closeMenu"),
ViewName: "menu",
Key: gui.getKey("universal.return"),
Modifier: gocui.ModNone,
Handler: gui.handleMenuClose,
},
{
ViewName: "menu",
Key: gui.getKey("universal.quit"),
Modifier: gocui.ModNone,
Handler: gui.handleMenuClose,
Description: gui.Tr.SLocalize("closeMenu"),
ViewName: "menu",
Key: gui.getKey("universal.quit"),
Modifier: gocui.ModNone,
Handler: gui.handleMenuClose,
},
{
ViewName: "information",
@@ -1474,7 +1454,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
// we need a specific keybinding for the commits panel beacuse it usually lazyloads commits
if listView.viewName != "commits" {
bindings = append(bindings, &Binding{ViewName: listView.viewName, Contexts: []string{listView.context}, Key: gui.getKey("universal.startSearch"), Modifier: gocui.ModNone, Handler: gui.handleOpenSearch, Description: gui.Tr.SLocalize("startSearch")})
bindings = append(bindings, &Binding{ViewName: listView.viewName, Contexts: []string{listView.context}, Key: gui.getKey("universal.startSearch"), Modifier: gocui.ModNone, Handler: gui.handleOpenSearch})
}
}
+2 -4
View File
@@ -88,8 +88,7 @@ func (gui *Gui) refreshLineByLinePanel(diff string, secondaryDiff string, second
}
gui.g.Update(func(*gocui.Gui) error {
gui.setViewContent(gui.g, gui.getSecondaryView(), secondaryPatchParser.Render(-1, -1, nil))
return nil
return gui.setViewContent(gui.g, gui.getSecondaryView(), secondaryPatchParser.Render(-1, -1, nil))
})
return false, nil
@@ -242,8 +241,7 @@ func (gui *Gui) refreshMainView() error {
mainView.Wrap = false
gui.g.Update(func(*gocui.Gui) error {
gui.setViewContent(gui.g, gui.getMainView(), colorDiff)
return nil
return gui.setViewContent(gui.g, gui.getMainView(), colorDiff)
})
return nil
+1 -2
View File
@@ -17,8 +17,7 @@ type menuItem struct {
// list panel functions
func (gui *Gui) handleMenuSelect(g *gocui.Gui, v *gocui.View) error {
v.FocusPoint(0, gui.State.Panels.Menu.SelectedLine)
return nil
return gui.focusPoint(0, gui.State.Panels.Menu.SelectedLine, gui.State.MenuItemCount, v)
}
// specific functions
+6 -12
View File
@@ -151,19 +151,13 @@ func (gui *Gui) handlePopFileSnapshot(g *gocui.Gui, v *gocui.View) error {
if err != nil {
return err
}
if err := ioutil.WriteFile(gitFile.Name, []byte(prevContent), 0644); err != nil {
return err
}
ioutil.WriteFile(gitFile.Name, []byte(prevContent), 0644)
return gui.refreshMergePanel()
}
func (gui *Gui) handlePickHunk(g *gocui.Gui, v *gocui.View) error {
conflict := gui.State.Panels.Merging.Conflicts[gui.State.Panels.Merging.ConflictIndex]
if err := gui.pushFileSnapshot(g); err != nil {
return err
}
gui.pushFileSnapshot(g)
pick := "bottom"
if gui.State.Panels.Merging.ConflictTop {
pick = "top"
@@ -184,9 +178,7 @@ func (gui *Gui) handlePickHunk(g *gocui.Gui, v *gocui.View) error {
func (gui *Gui) handlePickBothHunks(g *gocui.Gui, v *gocui.View) error {
conflict := gui.State.Panels.Merging.Conflicts[gui.State.Panels.Merging.ConflictIndex]
if err := gui.pushFileSnapshot(g); err != nil {
return err
}
gui.pushFileSnapshot(g)
err := gui.resolveConflict(g, conflict, "both")
if err != nil {
panic(err)
@@ -223,7 +215,9 @@ func (gui *Gui) refreshMergePanel() error {
mainView := gui.getMainView()
mainView.Wrap = false
gui.setViewContent(gui.g, mainView, content)
if err := gui.setViewContent(gui.g, mainView, content); err != nil {
return err
}
gui.Log.Warn("scrolling to conflict")
if err := gui.scrollToConflict(gui.g); err != nil {
return err
+3 -6
View File
@@ -18,8 +18,7 @@ func (gui *Gui) refreshPatchBuildingPanel(selectedLineIdx int) error {
// get diff from commit file that's currently selected
commitFile := gui.getSelectedCommitFile(gui.g)
if commitFile == nil {
gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
return nil
return gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
}
diff, err := gui.GitCommand.ShowCommitFile(commitFile.Sha, commitFile.Name, true)
@@ -58,8 +57,7 @@ func (gui *Gui) handleToggleSelectionForPatch(g *gocui.Gui, v *gocui.View) error
// add range of lines to those set for the file
commitFile := gui.getSelectedCommitFile(gui.g)
if commitFile == nil {
gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
return nil
return gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
}
toggleFunc(commitFile.Name, state.FirstLineIdx, state.LastLineIdx)
@@ -94,8 +92,7 @@ func (gui *Gui) refreshSecondaryPatchPanel() error {
secondaryView.Wrap = false
gui.g.Update(func(*gocui.Gui) error {
gui.setViewContent(gui.g, gui.getSecondaryView(), gui.GitCommand.PatchManager.RenderAggregatedPatchColored(false))
return nil
return gui.setViewContent(gui.g, gui.getSecondaryView(), gui.GitCommand.PatchManager.RenderAggregatedPatchColored(false))
})
} else {
gui.State.SplitMainPanel = false
+7 -20
View File
@@ -10,38 +10,25 @@ import (
"github.com/jesseduffield/lazygit/pkg/utils"
)
func GetBranchListDisplayStrings(branches []*commands.Branch, fullDescription bool) [][]string {
func GetBranchListDisplayStrings(branches []*commands.Branch, isFocused bool, selectedLine int) [][]string {
lines := make([][]string, len(branches))
for i := range branches {
lines[i] = getBranchDisplayStrings(branches[i], fullDescription)
showUpstreamDifferences := isFocused && i == selectedLine
lines[i] = getBranchDisplayStrings(branches[i], showUpstreamDifferences)
}
return lines
}
// getBranchDisplayStrings returns the display string of branch
func getBranchDisplayStrings(b *commands.Branch, fullDescription bool) []string {
func getBranchDisplayStrings(b *commands.Branch, showUpstreamDifferences bool) []string {
displayName := utils.ColoredString(b.Name, GetBranchColor(b.Name))
if b.Pushables != "" && b.Pullables != "" && b.Pushables != "?" && b.Pullables != "?" {
trackColor := color.FgYellow
if b.Pushables == "0" && b.Pullables == "0" {
trackColor = color.FgGreen
}
track := utils.ColoredString(fmt.Sprintf("↑%s↓%s", b.Pushables, b.Pullables), trackColor)
displayName = fmt.Sprintf("%s %s", displayName, track)
if showUpstreamDifferences && b.Pushables != "" && b.Pullables != "" {
displayName = fmt.Sprintf("%s ↑%s↓%s", displayName, b.Pushables, b.Pullables)
}
recencyColor := color.FgCyan
if b.Recency == " *" {
recencyColor = color.FgGreen
}
if fullDescription {
return []string{utils.ColoredString(b.Recency, recencyColor), displayName, utils.ColoredString(b.UpstreamName, color.FgYellow)}
}
return []string{utils.ColoredString(b.Recency, recencyColor), displayName}
return []string{b.Recency, displayName}
}
// GetBranchColor branch color
+3 -3
View File
@@ -17,11 +17,11 @@ func (gui *Gui) handleCreateRebaseOptionsMenu(g *gocui.Gui, v *gocui.View) error
menuItems := make([]*menuItem, len(options))
for i, option := range options {
// note to self. Never, EVER, close over loop variables in a function
option := option
innerOption := option
menuItems[i] = &menuItem{
displayString: option,
displayString: innerOption,
onPress: func() error {
return gui.genericMergeCommand(option)
return gui.genericMergeCommand(innerOption)
},
}
}
+3 -1
View File
@@ -34,7 +34,9 @@ func (gui *Gui) handleReflogCommitSelect(g *gocui.Gui, v *gocui.View) error {
if commit == nil {
return gui.newStringTask("main", "No reflog history")
}
v.FocusPoint(0, gui.State.Panels.ReflogCommits.SelectedLine)
if err := gui.focusPoint(0, gui.State.Panels.ReflogCommits.SelectedLine, len(gui.State.ReflogCommits), v); err != nil {
return err
}
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.ShowCmdStr(commit.Sha),
+4 -1
View File
@@ -38,7 +38,10 @@ func (gui *Gui) handleRemoteBranchSelect(g *gocui.Gui, v *gocui.View) error {
return gui.newStringTask("main", "No branches for this remote")
}
v.FocusPoint(0, gui.State.Panels.RemoteBranches.SelectedLine)
gui.focusPoint(0, gui.State.Panels.Menu.SelectedLine, gui.State.MenuItemCount, v)
if err := gui.focusPoint(0, gui.State.Panels.RemoteBranches.SelectedLine, len(gui.State.RemoteBranches), v); err != nil {
return err
}
branchName := fmt.Sprintf("%s/%s", remote.Name, remoteBranch.Name)
+3 -1
View File
@@ -39,7 +39,9 @@ func (gui *Gui) handleRemoteSelect(g *gocui.Gui, v *gocui.View) error {
if remote == nil {
return gui.newStringTask("main", "No remotes")
}
v.FocusPoint(0, gui.State.Panels.Remotes.SelectedLine)
if err := gui.focusPoint(0, gui.State.Panels.Remotes.SelectedLine, len(gui.State.Remotes), v); err != nil {
return err
}
return gui.newStringTask("main", fmt.Sprintf("%s\nUrls:\n%s", utils.ColoredString(remote.Name, color.FgGreen), strings.Join(remote.Urls, "\n")))
}
+1 -7
View File
@@ -23,10 +23,7 @@ func (gui *Gui) createResetMenu(ref string) error {
return gui.createErrorPanel(gui.g, err.Error())
}
if err := gui.switchCommitsPanelContext("branch-commits"); err != nil {
return err
}
gui.switchCommitsPanelContext("branch-commits")
gui.State.Panels.Commits.SelectedLine = 0
gui.State.Panels.ReflogCommits.SelectedLine = 0
@@ -36,9 +33,6 @@ func (gui *Gui) createResetMenu(ref string) error {
if err := gui.refreshFiles(); err != nil {
return err
}
if err := gui.refreshBranches(gui.g); err != nil {
return err
}
if err := gui.resetOrigin(gui.getCommitsView()); err != nil {
return err
}
+5 -8
View File
@@ -12,19 +12,14 @@ func (gui *Gui) handleOpenSearch(g *gocui.Gui, v *gocui.View) error {
gui.State.Searching.isSearching = true
gui.State.Searching.view = v
gui.renderString(gui.g, "search", "")
if err := gui.switchFocus(gui.g, v, gui.getSearchView()); err != nil {
return err
}
gui.switchFocus(gui.g, v, gui.getSearchView())
return nil
}
func (gui *Gui) handleSearch(g *gocui.Gui, v *gocui.View) error {
gui.State.Searching.searchString = gui.getSearchView().Buffer()
if err := gui.switchFocus(gui.g, nil, gui.State.Searching.view); err != nil {
return err
}
gui.switchFocus(gui.g, nil, gui.State.Searching.view)
if err := gui.State.Searching.view.Search(gui.State.Searching.searchString); err != nil {
return err
}
@@ -90,5 +85,7 @@ func (gui *Gui) handleSearchEscape(g *gocui.Gui, v *gocui.View) error {
return err
}
return gui.onSearchEscape()
gui.onSearchEscape()
return nil
}
+8
View File
@@ -159,3 +159,11 @@ func (gui *Gui) applySelection(reverse bool) error {
}
return nil
}
func (gui *Gui) handleMouseDownSecondaryWhileStaging(g *gocui.Gui, v *gocui.View) error {
state := gui.State.Panels.LineByLine
state.SecondaryFocused = !state.SecondaryFocused
return gui.refreshStagingPanel(false, -1)
}
+7 -9
View File
@@ -34,7 +34,9 @@ func (gui *Gui) handleStashEntrySelect(g *gocui.Gui, v *gocui.View) error {
if stashEntry == nil {
return gui.newStringTask("main", gui.Tr.SLocalize("NoStashEntries"))
}
v.FocusPoint(0, gui.State.Panels.Stash.SelectedLine)
if err := gui.focusPoint(0, gui.State.Panels.Stash.SelectedLine, len(gui.State.StashEntries), v); err != nil {
return err
}
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.ShowStashEntryCmdStr(stashEntry.Index),
@@ -95,11 +97,9 @@ func (gui *Gui) stashDo(g *gocui.Gui, v *gocui.View, method string) error {
return gui.createErrorPanel(g, errorMessage)
}
if err := gui.GitCommand.StashDo(stashEntry.Index, method); err != nil {
return gui.createErrorPanel(g, err.Error())
}
if err := gui.refreshStashEntries(g); err != nil {
return gui.createErrorPanel(g, err.Error())
gui.createErrorPanel(g, err.Error())
}
gui.refreshStashEntries(g)
return gui.refreshFiles()
}
@@ -109,11 +109,9 @@ func (gui *Gui) handleStashSave(stashFunc func(message string) error) error {
}
return gui.createPromptPanel(gui.g, gui.getFilesView(), gui.Tr.SLocalize("StashChanges"), "", func(g *gocui.Gui, v *gocui.View) error {
if err := stashFunc(gui.trimmedContent(v)); err != nil {
return gui.createErrorPanel(g, err.Error())
}
if err := gui.refreshStashEntries(g); err != nil {
return gui.createErrorPanel(g, err.Error())
gui.createErrorPanel(g, err.Error())
}
gui.refreshStashEntries(g)
return gui.refreshFiles()
})
}
+1 -10
View File
@@ -22,20 +22,11 @@ func (gui *Gui) refreshStatus(g *gocui.Gui) error {
// contents end up cleared
g.Update(func(*gocui.Gui) error {
v.Clear()
// TODO: base this off of the current branch
state.pushables, state.pullables = gui.GitCommand.GetCurrentBranchUpstreamDifferenceCount()
if err := gui.updateWorkTreeState(); err != nil {
return err
}
trackColor := color.FgYellow
if state.pushables == "0" && state.pullables == "0" {
trackColor = color.FgGreen
} else if state.pushables == "?" && state.pullables == "?" {
trackColor = color.FgRed
}
status := utils.ColoredString(fmt.Sprintf("↑%s↓%s", state.pushables, state.pullables), trackColor)
status := fmt.Sprintf("↑%s↓%s", state.pushables, state.pullables)
branches := gui.State.Branches
if gui.State.WorkingTreeState != "normal" {
+4 -2
View File
@@ -34,7 +34,9 @@ func (gui *Gui) handleTagSelect(g *gocui.Gui, v *gocui.View) error {
if tag == nil {
return gui.newStringTask("main", "No tags")
}
v.FocusPoint(0, gui.State.Panels.Tags.SelectedLine)
if err := gui.focusPoint(0, gui.State.Panels.Tags.SelectedLine, len(gui.State.Tags), v); err != nil {
return err
}
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.GetBranchGraphCmdStr(tag.Name),
@@ -55,7 +57,7 @@ func (gui *Gui) refreshTags() error {
gui.State.Tags = tags
if gui.getBranchesView().Context == "tags" {
return gui.renderTagsWithSelection()
gui.renderTagsWithSelection()
}
return nil
+1 -2
View File
@@ -59,8 +59,7 @@ func (gui *Gui) newStringTask(viewName string, str string) error {
manager := gui.getManager(view)
f := func(stop chan struct{}) error {
gui.renderString(gui.g, viewName, str)
return nil
return gui.renderString(gui.g, viewName, str)
}
if err := manager.NewTask(f); err != nil {
+3 -1
View File
@@ -47,7 +47,9 @@ func (gui *Gui) startUpdating(newVersion string) {
func (gui *Gui) onUpdateFinish(err error) error {
gui.State.Updating = false
gui.statusManager.removeStatus("updating")
gui.renderString(gui.g, "appStatus", "")
if err := gui.renderString(gui.g, "appStatus", ""); err != nil {
return err
}
if err != nil {
return gui.createErrorPanel(gui.g, "Update failed: "+err.Error())
}
+33 -6
View File
@@ -218,18 +218,25 @@ func (gui *Gui) resetOrigin(v *gocui.View) error {
return v.SetOrigin(0, 0)
}
// if the cursor down past the last item, move it to the last line
func (gui *Gui) focusPoint(cx int, cy int, lineCount int, v *gocui.View) error {
v.FocusPoint(cx, cy)
return nil
}
func (gui *Gui) cleanString(s string) string {
output := string(bom.Clean([]byte(s)))
return utils.NormalizeLinefeeds(output)
}
func (gui *Gui) setViewContent(g *gocui.Gui, v *gocui.View, s string) {
func (gui *Gui) setViewContent(g *gocui.Gui, v *gocui.View, s string) error {
v.Clear()
fmt.Fprint(v, gui.cleanString(s))
return nil
}
// renderString resets the origin of a view and sets its content
func (gui *Gui) renderString(g *gocui.Gui, viewName, s string) {
func (gui *Gui) renderString(g *gocui.Gui, viewName, s string) error {
g.Update(func(*gocui.Gui) error {
v, err := g.View(viewName)
if err != nil {
@@ -241,9 +248,9 @@ func (gui *Gui) renderString(g *gocui.Gui, viewName, s string) {
if err := v.SetCursor(0, 0); err != nil {
return err
}
gui.setViewContent(gui.g, v, s)
return nil
return gui.setViewContent(gui.g, v, s)
})
return nil
}
func (gui *Gui) optionsMapToString(optionsMap map[string]string) string {
@@ -256,8 +263,7 @@ func (gui *Gui) optionsMapToString(optionsMap map[string]string) string {
}
func (gui *Gui) renderOptionsMap(optionsMap map[string]string) error {
gui.renderString(gui.g, "options", gui.optionsMapToString(optionsMap))
return nil
return gui.renderString(gui.g, "options", gui.optionsMapToString(optionsMap))
}
// TODO: refactor properly
@@ -343,6 +349,22 @@ func (gui *Gui) resizePopupPanel(g *gocui.Gui, v *gocui.View) error {
return err
}
// generalFocusLine takes a lineNumber to focus, and a bottomLine to ensure we can see
func (gui *Gui) generalFocusLine(lineNumber int, bottomLine int, v *gocui.View) error {
_, height := v.Size()
overScroll := bottomLine - height + 1
if overScroll < 0 {
overScroll = 0
}
if err := v.SetOrigin(0, overScroll); err != nil {
return err
}
if err := v.SetCursor(0, lineNumber-overScroll); err != nil {
return err
}
return nil
}
func (gui *Gui) changeSelectedLine(line *int, total int, change int) {
// TODO: find out why we're doing this
if *line == -1 {
@@ -387,6 +409,11 @@ func (gui *Gui) renderPanelOptions() error {
return gui.renderGlobalOptions()
}
func (gui *Gui) handleFocusView(g *gocui.Gui, v *gocui.View) error {
_, err := gui.g.SetCurrentView(v.Name())
return err
}
func (gui *Gui) isPopupPanel(viewName string) bool {
return viewName == "commitMessage" || viewName == "credentials" || viewName == "confirmation" || viewName == "menu"
}
-21
View File
@@ -1008,33 +1008,12 @@ func addEnglish(i18nObject *i18n.Bundle) error {
}, &i18n.Message{
ID: "prevScreenMode",
Other: "prev screen mode",
}, &i18n.Message{
ID: "startSearch",
Other: "start search",
}, &i18n.Message{
ID: "Panel",
Other: "Panel",
}, &i18n.Message{
ID: "Keybindings",
Other: "Keybindings",
}, &i18n.Message{
ID: "renameBranch",
Other: "rename branch",
}, &i18n.Message{
ID: "NewBranchNamePrompt",
Other: "Enter new branch name for branch",
}, &i18n.Message{
ID: "RenameBranchWarning",
Other: "This branch is tracking a remote. This action will only rename the local branch name, not the name of the remote branch. Continue?",
}, &i18n.Message{
ID: "openMenu",
Other: "open menu",
}, &i18n.Message{
ID: "closeMenu",
Other: "close menu",
}, &i18n.Message{
ID: "resetCherryPick",
Other: "reset cherry-picked (copied) commits selection",
},
)
}
+4 -2
View File
@@ -23,6 +23,7 @@ type Task struct {
type ViewBufferManager struct {
writer io.Writer
waitingTask *Task
currentTask *Task
waitingMutex sync.Mutex
taskIDMutex sync.Mutex
@@ -78,7 +79,7 @@ func (m *ViewBufferManager) NewCmdTask(r io.Reader, cmd *exec.Cmd, linesToRead i
loadingMutex.Lock()
if !loaded {
m.beforeStart()
_, _ = m.writer.Write([]byte("loading..."))
m.writer.Write([]byte("loading..."))
m.refreshView()
}
loadingMutex.Unlock()
@@ -110,7 +111,7 @@ func (m *ViewBufferManager) NewCmdTask(r io.Reader, cmd *exec.Cmd, linesToRead i
m.refreshView()
break outer
}
_, _ = m.writer.Write(append(scanner.Bytes(), []byte("\n")...))
m.writer.Write(append(scanner.Bytes(), []byte("\n")...))
}
m.refreshView()
case <-stop:
@@ -222,4 +223,5 @@ func (t *Task) Stop() {
<-t.notifyStopped
t.Log.Info("received notifystopped message")
t.stopped = true
return
}
+2
View File
@@ -196,6 +196,8 @@ func TestDisplayArraysAligned(t *testing.T) {
}
}
type myStruct struct{}
// TestGetPaddedDisplayStrings is a function.
func TestGetPaddedDisplayStrings(t *testing.T) {
type scenario struct {
+3 -1
View File
@@ -83,7 +83,9 @@ func getBindingSections(mApp *app.App) []*bindingSection {
if len(binding.Contexts) == 0 {
contexts = append(contexts, "")
} else {
contexts = append(contexts, binding.Contexts...)
for _, context := range binding.Contexts {
contexts = append(contexts, context)
}
}
for _, context := range contexts {
+3 -24
View File
@@ -10,7 +10,6 @@ import (
"strings"
"sync"
"time"
"unicode"
"github.com/go-errors/errors"
@@ -467,38 +466,18 @@ func (v *View) Rewind() {
v.readOffset = 0
}
func containsUpcaseChar(str string) bool {
for _, ch := range str {
if unicode.IsUpper(ch) {
return true
}
}
return false
}
func (v *View) updateSearchPositions() {
if v.searcher.searchString != "" {
var normalizeRune func(r rune) rune
var normalizedSearchStr string
// if we have any uppercase characters we'll do a case-sensitive search
if containsUpcaseChar(v.searcher.searchString) {
normalizedSearchStr = v.searcher.searchString
normalizeRune = func(r rune) rune { return r }
} else {
normalizedSearchStr = strings.ToLower(v.searcher.searchString)
normalizeRune = unicode.ToLower
}
v.searcher.searchPositions = []cellPos{}
for y, line := range v.lines {
lineLoop:
for x, _ := range line {
if normalizeRune(line[x].chr) == rune(normalizedSearchStr[0]) {
for offset := 1; offset < len(normalizedSearchStr); offset++ {
if line[x].chr == rune(v.searcher.searchString[0]) {
for offset := 1; offset < len(v.searcher.searchString); offset++ {
if len(line)-1 < x+offset {
continue lineLoop
}
if normalizeRune(line[x+offset].chr) != rune(normalizedSearchStr[offset]) {
if line[x+offset].chr != rune(v.searcher.searchString[offset]) {
continue lineLoop
}
}
+1 -45
View File
@@ -1,5 +1,4 @@
# github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
## explicit
github.com/cloudfoundry/jibber_jabber
# github.com/davecgh/go-spew v1.1.1
github.com/davecgh/go-spew/spew
@@ -11,21 +10,13 @@ github.com/emirpasic/gods/trees
github.com/emirpasic/gods/trees/binaryheap
github.com/emirpasic/gods/utils
# github.com/fatih/color v1.7.0
## explicit
github.com/fatih/color
# github.com/fsnotify/fsnotify v1.4.7
## explicit
github.com/fsnotify/fsnotify
# github.com/go-errors/errors v1.0.1
## explicit
github.com/go-errors/errors
# github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
## explicit
github.com/golang-collections/collections/stack
# github.com/golang/protobuf v1.3.2
## explicit
# github.com/google/go-cmp v0.3.1
## explicit
# github.com/hashicorp/hcl v1.0.0
github.com/hashicorp/hcl
github.com/hashicorp/hcl/hcl/ast
@@ -38,86 +29,61 @@ github.com/hashicorp/hcl/json/parser
github.com/hashicorp/hcl/json/scanner
github.com/hashicorp/hcl/json/token
# github.com/integrii/flaggy v1.4.0
## explicit
github.com/integrii/flaggy
# github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99
github.com/jbenet/go-context/io
# github.com/jesseduffield/gocui v0.3.1-0.20200309001002-7765949e1c8a
## explicit
# github.com/jesseduffield/gocui v0.3.1-0.20200301081700-d6e485450113
github.com/jesseduffield/gocui
# github.com/jesseduffield/pty v1.2.1
## explicit
github.com/jesseduffield/pty
# github.com/jesseduffield/termbox-go v0.0.0-20200130214842-1d31d1faa3c9
## explicit
github.com/jesseduffield/termbox-go
# github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
## explicit
github.com/kardianos/osext
# github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd
github.com/kevinburke/ssh_config
# github.com/konsorten/go-windows-terminal-sequences v1.0.2
## explicit
github.com/konsorten/go-windows-terminal-sequences
# github.com/magiconair/properties v1.8.1
github.com/magiconair/properties
# github.com/mattn/go-colorable v0.1.4
## explicit
github.com/mattn/go-colorable
# github.com/mattn/go-isatty v0.0.11
## explicit
github.com/mattn/go-isatty
# github.com/mattn/go-runewidth v0.0.8
## explicit
github.com/mattn/go-runewidth
# github.com/mgutz/str v1.2.0
## explicit
github.com/mgutz/str
# github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/go-homedir
# github.com/mitchellh/gox v1.0.1
## explicit
# github.com/mitchellh/mapstructure v1.1.2
github.com/mitchellh/mapstructure
# github.com/nicksnyder/go-i18n/v2 v2.0.3
## explicit
github.com/nicksnyder/go-i18n/v2/i18n
github.com/nicksnyder/go-i18n/v2/internal
github.com/nicksnyder/go-i18n/v2/internal/plural
# github.com/onsi/ginkgo v1.10.3
## explicit
# github.com/onsi/gomega v1.7.1
## explicit
# github.com/pelletier/go-toml v1.6.0
## explicit
github.com/pelletier/go-toml
# github.com/pmezard/go-difflib v1.0.0
github.com/pmezard/go-difflib/difflib
# github.com/sergi/go-diff v1.0.0
github.com/sergi/go-diff/diffmatchpatch
# github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0
## explicit
github.com/shibukawa/configdir
# github.com/sirupsen/logrus v1.4.2
## explicit
github.com/sirupsen/logrus
# github.com/spf13/afero v1.2.2
## explicit
github.com/spf13/afero
github.com/spf13/afero/mem
# github.com/spf13/cast v1.3.0
github.com/spf13/cast
# github.com/spf13/jwalterweatherman v1.1.0
## explicit
github.com/spf13/jwalterweatherman
# github.com/spf13/pflag v1.0.5
## explicit
github.com/spf13/pflag
# github.com/spf13/viper v1.6.1
## explicit
github.com/spf13/viper
# github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad
## explicit
github.com/spkg/bom
# github.com/src-d/gcfg v1.4.0
github.com/src-d/gcfg
@@ -125,17 +91,14 @@ github.com/src-d/gcfg/scanner
github.com/src-d/gcfg/token
github.com/src-d/gcfg/types
# github.com/stretchr/testify v1.4.0
## explicit
github.com/stretchr/testify/assert
# github.com/subosito/gotenv v1.2.0
github.com/subosito/gotenv
# github.com/tcnksm/go-gitconfig v0.1.2
## explicit
github.com/tcnksm/go-gitconfig
# github.com/xanzy/ssh-agent v0.2.1
github.com/xanzy/ssh-agent
# golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413
## explicit
golang.org/x/crypto/cast5
golang.org/x/crypto/chacha20
golang.org/x/crypto/curve25519
@@ -153,25 +116,20 @@ golang.org/x/crypto/ssh
golang.org/x/crypto/ssh/agent
golang.org/x/crypto/ssh/knownhosts
# golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553
## explicit
golang.org/x/net/context
golang.org/x/net/internal/socks
golang.org/x/net/proxy
# golang.org/x/sys v0.0.0-20191210023423-ac6580df4449
## explicit
golang.org/x/sys/cpu
golang.org/x/sys/unix
golang.org/x/sys/windows
# golang.org/x/text v0.3.2
## explicit
golang.org/x/text/internal/language
golang.org/x/text/internal/language/compact
golang.org/x/text/internal/tag
golang.org/x/text/language
golang.org/x/text/transform
golang.org/x/text/unicode/norm
# gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15
## explicit
# gopkg.in/ini.v1 v1.51.0
gopkg.in/ini.v1
# gopkg.in/src-d/go-billy.v4 v4.3.2
@@ -181,7 +139,6 @@ gopkg.in/src-d/go-billy.v4/helper/polyfill
gopkg.in/src-d/go-billy.v4/osfs
gopkg.in/src-d/go-billy.v4/util
# gopkg.in/src-d/go-git.v4 v4.13.1
## explicit
gopkg.in/src-d/go-git.v4
gopkg.in/src-d/go-git.v4/config
gopkg.in/src-d/go-git.v4/internal/revision
@@ -226,5 +183,4 @@ gopkg.in/src-d/go-git.v4/utils/merkletrie/noder
# gopkg.in/warnings.v0 v0.1.2
gopkg.in/warnings.v0
# gopkg.in/yaml.v2 v2.2.7
## explicit
gopkg.in/yaml.v2