Compare commits
121 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1c6619401 | ||
|
|
3524f6baa9 | ||
|
|
ac5cbc1d2c | ||
|
|
a045313e08 | ||
|
|
9bd2dc3050 | ||
|
|
02fef3136f | ||
|
|
8fe0e00cd9 | ||
|
|
f7f19bbc02 | ||
|
|
95ae806e09 | ||
|
|
d8a6f173c3 | ||
|
|
431f1aa766 | ||
|
|
379dcf0972 | ||
|
|
0d25d113c9 | ||
|
|
7c70913e8d | ||
|
|
1c5858c515 | ||
|
|
c3767bb3b3 | ||
|
|
b92d27ee7f | ||
|
|
6eff139c40 | ||
|
|
07462303ab | ||
|
|
d12f81b44e | ||
|
|
600112780c | ||
|
|
4c73c8889f | ||
|
|
68d5c2bc10 | ||
|
|
7db1fee877 | ||
|
|
8f786e3fd9 | ||
|
|
1c704e11f2 | ||
|
|
e0dd1cb29d | ||
|
|
827837b0b9 | ||
|
|
e83ef9858b | ||
|
|
504d506575 | ||
|
|
823b436b53 | ||
|
|
212327d746 | ||
|
|
cc138fc70e | ||
|
|
d953712377 | ||
|
|
69ac0036e6 | ||
|
|
975a5315b0 | ||
|
|
8f734b11e3 | ||
|
|
17b4cabc71 | ||
|
|
75db4faf69 | ||
|
|
e1f5601d4b | ||
|
|
b60ecdaa24 | ||
|
|
9fb9962ce7 | ||
|
|
25c93c678d | ||
|
|
b8baef7b8f | ||
|
|
235a47bb80 | ||
|
|
c107eed890 | ||
|
|
abddea060e | ||
|
|
3e40369fd2 | ||
|
|
0f0fda1660 | ||
|
|
bd2170a99c | ||
|
|
c039e5bed0 | ||
|
|
527c025a0c | ||
|
|
53cded77f1 | ||
|
|
4a4dc676fc | ||
|
|
c61bfbdd4c | ||
|
|
e38d9d5f22 | ||
|
|
97f060d38d | ||
|
|
357b8fa98f | ||
|
|
8754d766e2 | ||
|
|
2388c3ee9a | ||
|
|
61890cb9de | ||
|
|
5a0d0bb299 | ||
|
|
2746b1bd38 | ||
|
|
e09aac6450 | ||
|
|
19a6368377 | ||
|
|
e6122122e9 | ||
|
|
492614ebc7 | ||
|
|
d31f0ed39b | ||
|
|
b505c295d2 | ||
|
|
0b9d7edd47 | ||
|
|
e9fbb608a8 | ||
|
|
6ba05c94ea | ||
|
|
07fec6d00e | ||
|
|
a69b985086 | ||
|
|
471733fe03 | ||
|
|
0d3a193ab5 | ||
|
|
ab9fa291a8 | ||
|
|
cadc74eeec | ||
|
|
fc3a57b5e2 | ||
|
|
7ff07e1454 | ||
|
|
3e779bca8d | ||
|
|
0f1abcb10c | ||
|
|
55538a3695 | ||
|
|
878a15aff4 | ||
|
|
60e33f5d8c | ||
|
|
b422692746 | ||
|
|
f34be1896a | ||
|
|
c350cdba43 | ||
|
|
1a933eaa73 | ||
|
|
bd46e9c5b0 | ||
|
|
09b7ae21bc | ||
|
|
acfc961909 | ||
|
|
f502f75e1f | ||
|
|
ff97ef7b94 | ||
|
|
a2c780b085 | ||
|
|
b99305c909 | ||
|
|
d84dfc23e7 | ||
|
|
9d8fd3594e | ||
|
|
e68dbeb7eb | ||
|
|
32ddf0c296 | ||
|
|
c453bfeb32 | ||
|
|
f6ca450d36 | ||
|
|
d5f617ec92 | ||
|
|
6d104bfa91 | ||
|
|
e583cc2519 | ||
|
|
0d208b7957 | ||
|
|
43e5c042a2 | ||
|
|
39844ffef9 | ||
|
|
f5c8aac97d | ||
|
|
b6447ebdbb | ||
|
|
466fc4227e | ||
|
|
c034c88be4 | ||
|
|
72830efc45 | ||
|
|
c98eddc185 | ||
|
|
3b2353b5ae | ||
|
|
3f567c952c | ||
|
|
4f7f6a073c | ||
|
|
0e008cc15f | ||
|
|
1ad9c6faac | ||
|
|
06fe726ee7 | ||
|
|
1b6e46973e |
@@ -3,22 +3,11 @@ jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: circleci/golang:1.12
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
working_directory: /go/src/github.com/jesseduffield/lazygit
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Ensure go.mod file is up to date
|
||||
command: |
|
||||
export GO111MODULE=on
|
||||
rm go.sum
|
||||
mv go.mod /tmp/
|
||||
go mod init
|
||||
export GO111MODULE=auto
|
||||
|
||||
if [ $(diff /tmp/go.mod go.mod|wc -l) -gt 0 ]; then
|
||||
diff /tmp/go.mod go.mod
|
||||
exit 1;
|
||||
fi
|
||||
- run:
|
||||
name: Run gofmt -s
|
||||
command: |
|
||||
@@ -28,28 +17,28 @@ jobs:
|
||||
fi
|
||||
- restore_cache:
|
||||
keys:
|
||||
- pkg-cache-{{ checksum "Gopkg.lock" }}-v4
|
||||
- pkg-cache-{{ checksum "go.sum" }}-v5
|
||||
- run:
|
||||
name: Run tests
|
||||
command: |
|
||||
./test.sh
|
||||
- run:
|
||||
name: Compile project on every platform
|
||||
command: |
|
||||
go get github.com/mitchellh/gox
|
||||
gox -parallel 10 -os "linux freebsd netbsd windows" -osarch "darwin/i386 darwin/amd64"
|
||||
- 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 "Gopkg.lock" }}-v4
|
||||
key: pkg-cache-{{ checksum "go.sum" }}-v5
|
||||
paths:
|
||||
- ~/.cache/go-build
|
||||
|
||||
release:
|
||||
docker:
|
||||
- image: circleci/golang:1.10
|
||||
- image: circleci/golang:1.12
|
||||
working_directory: /go/src/github.com/jesseduffield/lazygit
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
4
.github/FUNDING.yml
vendored
Normal file
4
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
ko_fi: jesseduffield
|
||||
custom: ['https://donorbox.org/lazygit']
|
||||
3
.github/ISSUE_TEMPLATE/bug_report.md
vendored
3
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,6 +1,9 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
||||
14
.github/ISSUE_TEMPLATE/discussion.md
vendored
Normal file
14
.github/ISSUE_TEMPLATE/discussion.md
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: Discussion
|
||||
about: Begin a discussion
|
||||
title: ''
|
||||
labels: discussion
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Topic**
|
||||
A clear and concise description of what you want to discuss
|
||||
|
||||
**Your thoughts**
|
||||
What you have to say about the topic
|
||||
3
.github/ISSUE_TEMPLATE/feature_request.md
vendored
3
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,6 +1,9 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
FROM golang:alpine
|
||||
WORKDIR /go/src/github.com/jesseduffield/lazygit/
|
||||
COPY ./ .
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -o lazygit .
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build
|
||||
|
||||
FROM alpine:latest
|
||||
RUN apk add -U git xdg-utils
|
||||
|
||||
652
Gopkg.lock
generated
652
Gopkg.lock
generated
@@ -1,652 +0,0 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e24ea5dbc89fbab51635ee32e5be4f61a9267cae20788efcae4c07efb4abec99"
|
||||
name = "github.com/aws/aws-sdk-go"
|
||||
packages = [
|
||||
"aws",
|
||||
"aws/awserr",
|
||||
"aws/awsutil",
|
||||
"aws/client",
|
||||
"aws/client/metadata",
|
||||
"aws/corehandlers",
|
||||
"aws/credentials",
|
||||
"aws/credentials/ec2rolecreds",
|
||||
"aws/credentials/endpointcreds",
|
||||
"aws/credentials/stscreds",
|
||||
"aws/csm",
|
||||
"aws/defaults",
|
||||
"aws/ec2metadata",
|
||||
"aws/endpoints",
|
||||
"aws/request",
|
||||
"aws/session",
|
||||
"aws/signer/v4",
|
||||
"internal/sdkio",
|
||||
"internal/sdkrand",
|
||||
"internal/sdkuri",
|
||||
"internal/shareddefaults",
|
||||
"private/protocol",
|
||||
"private/protocol/eventstream",
|
||||
"private/protocol/eventstream/eventstreamapi",
|
||||
"private/protocol/query",
|
||||
"private/protocol/query/queryutil",
|
||||
"private/protocol/rest",
|
||||
"private/protocol/restxml",
|
||||
"private/protocol/xml/xmlutil",
|
||||
"service/s3",
|
||||
"service/sts",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "4324bc9d8865bdb3e6aa86ec7772ca1272d2750e"
|
||||
version = "v1.15.21"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:37011b20a70e205b93ebea5287e1afa5618db54bf3998c36ff5a8e4b146a170a"
|
||||
name = "github.com/bgentry/go-netrc"
|
||||
packages = ["netrc"]
|
||||
pruneopts = "NUT"
|
||||
revision = "9fd32a8b3d3d3f9d43c341bfe098430e07609480"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:cd7ba2b29e93e2a8384e813dfc80ebb0f85d9214762e6ca89bb55a58092eab87"
|
||||
name = "github.com/cloudfoundry/jibber_jabber"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "bcc4c8345a21301bf47c032ff42dd1aae2fe3027"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a2c1d0e43bd3baaa071d1b9ed72c27d78169b2b269f71c105ac4ba34b1be4a39"
|
||||
name = "github.com/davecgh/go-spew"
|
||||
packages = ["spew"]
|
||||
pruneopts = "NUT"
|
||||
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:de4a74b504df31145ffa8ca0c4edbffa2f3eb7f466753962184611b618fa5981"
|
||||
name = "github.com/emirpasic/gods"
|
||||
packages = [
|
||||
"containers",
|
||||
"lists",
|
||||
"lists/arraylist",
|
||||
"trees",
|
||||
"trees/binaryheap",
|
||||
"utils",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "f6c17b524822278a87e3b3bd809fec33b51f5b46"
|
||||
version = "v1.9.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ade392a843b2035effb4b4a2efa2c3bab3eb29b992e98bacf9c898b0ecb54e45"
|
||||
name = "github.com/fatih/color"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "5b77d2a35fb0ede96d138fc9a99f5c9b6aef11b4"
|
||||
version = "v1.7.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:1b91ae0dc69a41d4c2ed23ea5cffb721ea63f5037ca4b81e6d6771fbb8f45129"
|
||||
name = "github.com/fsnotify/fsnotify"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
|
||||
version = "v1.4.7"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ea1d5bfdb4ec5c2ee48c97865e6de1a28fa8c4849a3f56b27d521aa619038e06"
|
||||
name = "github.com/go-errors/errors"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "a6af135bd4e28680facf08a3d206b454abc877a4"
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:74d9b0a7b4107b41e0ade759fac64502876f82d29fb23d77b3dd24b194ee3dd5"
|
||||
name = "github.com/go-ini/ini"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "5cf292cae48347c2490ac1a58fe36735fb78df7e"
|
||||
version = "v1.38.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:4a8ed9b8cf22bd03bee5d74179fa06a282e4a73b6de949f7a865ff56cd2537e0"
|
||||
name = "github.com/golang-collections/collections"
|
||||
packages = ["stack"]
|
||||
pruneopts = "NUT"
|
||||
revision = "604e922904d35e97f98a774db7881f049cd8d970"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:a5d940c38bf56f121721bfa747c66356df387cb9d5318c570c6d4170aab62862"
|
||||
name = "github.com/hashicorp/go-cleanhttp"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "d5fe4b57a186c716b0e00b8c301cbd9b4182694d"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:b634d733abf079dc191d359e5a8d31479f1795d00e656f8a018a459571046266"
|
||||
name = "github.com/hashicorp/go-getter"
|
||||
packages = ["helper/url"]
|
||||
pruneopts = "NUT"
|
||||
revision = "4bda8fa99001c61db3cad96b421d4c12a81f256d"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:fbab03227343a0285fc74a68dd2ff46cda7edecbbe5a3e98d2cecd00cc67b217"
|
||||
name = "github.com/hashicorp/go-safetemp"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "b1a1dbde6fdc11e3ae79efd9039009e22d4ae240"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0b06ffe0c0764e413a6738e3f045d6bb14117359aef80a09f8c60fbff2ecad6b"
|
||||
name = "github.com/hashicorp/go-version"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "b5a281d3160aa11950a6182bd9a9dc2cb1e02d50"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:11c6c696067d3127ecf332b10f89394d386d9083f82baf71f40f2da31841a009"
|
||||
name = "github.com/hashicorp/hcl"
|
||||
packages = [
|
||||
".",
|
||||
"hcl/ast",
|
||||
"hcl/parser",
|
||||
"hcl/printer",
|
||||
"hcl/scanner",
|
||||
"hcl/strconv",
|
||||
"hcl/token",
|
||||
"json/parser",
|
||||
"json/scanner",
|
||||
"json/token",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "ef8a98b0bbce4a65b5aa4c368430a80ddc533168"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:d457d39e88f678ed14ac29517c3d74927a48dbc6a9f073fa241cf364a68cbe5c"
|
||||
name = "github.com/heroku/rollrus"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "fc0cef2ff331aebb24cd4e9ded7e20650f3d7006"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:62fe3a7ea2050ecbd753a71889026f83d73329337ada66325cbafd5dea5f713d"
|
||||
name = "github.com/jbenet/go-context"
|
||||
packages = ["io"]
|
||||
pruneopts = "NUT"
|
||||
revision = "d14ea06fba99483203c19d92cfcd13ebe73135f4"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:490643e333b848f3d6ab772c21082d706663dcf4a3c0fbe9a4b4ef7b205ce6c7"
|
||||
name = "github.com/jesseduffield/go-getter"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "906e15686e6309ff310c1c10463ab53287c3a678"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:831819e8726b6b19e90079bce76d3048e2be3595359ee912d63d560e0db89b97"
|
||||
name = "github.com/jesseduffield/gocui"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "f0f0ab442e6c8e42650a7e38a45122bba2e11f3f"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:a46c2f4863e5284ddb255c28750298e04bc8c0fc896bed6056e947673168b7be"
|
||||
name = "github.com/jesseduffield/pty"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "02db52c7e406c7abec44c717a173c7715e4c1b62"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:3ab130f65766f5b7cc944d557df31c6a007ec017151705ec1e1b8719f2689021"
|
||||
name = "github.com/jesseduffield/termbox-go"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "1e272ff78dcb4c448870f464fda1cdcf2bf0b3dd"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ac6d01547ec4f7f673311b4663909269bfb8249952de3279799289467837c3cc"
|
||||
name = "github.com/jmespath/go-jmespath"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "0b12d6b5"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:263f9b0a0bcbfff9d5e7d9f2aa11f53995d98214fe0fb97e429e7a5f4534a0f9"
|
||||
name = "github.com/kardianos/osext"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "ae77be60afb1dcacde03767a8c37337fad28ac14"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:8021af4dcbd531ae89433c8c3a6520e51064114aaf8eb1724c3cf911c497c9ba"
|
||||
name = "github.com/kevinburke/ssh_config"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "9fc7bb800b555d63157c65a904c86a2cc7b4e795"
|
||||
version = "0.4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:d244f8666a838fe6ad70ec8fe77f50ebc29fdc3331a2729ba5886bef8435d10d"
|
||||
name = "github.com/magiconair/properties"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "c2353362d570a7bfa228149c62842019201cfb71"
|
||||
version = "v1.8.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:08c231ec84231a7e23d67e4b58f975e1423695a32467a362ee55a803f9de8061"
|
||||
name = "github.com/mattn/go-colorable"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
|
||||
version = "v0.0.9"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:bc4f7eec3b7be8c6cb1f0af6c1e3333d5bb71072951aaaae2f05067b0803f287"
|
||||
name = "github.com/mattn/go-isatty"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:cb591533458f6eb6e2c1065ff3eac6b50263d7847deb23fc9f79b25bc608970e"
|
||||
name = "github.com/mattn/go-runewidth"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "9e777a8366cce605130a531d2cd6363d07ad7317"
|
||||
version = "v0.0.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a25c9a6b41e100f4ce164db80260f2b687095ba9d8b46a1d6072d3686cc020db"
|
||||
name = "github.com/mgutz/str"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "968bf66e3da857419e4f6e71b2d5c9ae95682dc4"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:a4df73029d2c42fabcb6b41e327d2f87e685284ec03edf76921c267d9cfc9c23"
|
||||
name = "github.com/mitchellh/go-homedir"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "58046073cbffe2f25d425fe1331102f55cf719de"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:18b773b92ac82a451c1276bd2776c1e55ce057ee202691ab33c8d6690efcc048"
|
||||
name = "github.com/mitchellh/go-testing-interface"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "a61a99592b77c9ba629d254a693acffaeb4b7e28"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:5fe20cfe4ef484c237cec9f947b2a6fa90bad4b8610fd014f0e4211e13d82d5d"
|
||||
name = "github.com/mitchellh/mapstructure"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "f15292f7a699fcc1a38a80977f80a046874ba8ac"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:2c34c77bf3ec848da26e48af58fc511ed52750961fa848399d122882b8890928"
|
||||
name = "github.com/nicksnyder/go-i18n"
|
||||
packages = [
|
||||
"v2/i18n",
|
||||
"v2/internal",
|
||||
"v2/internal/plural",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "a16b91a3ba80db3a2301c70d1d302d42251c9079"
|
||||
version = "v2.0.0-beta.5"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:cf254277d898b713195cc6b4a3fac8bf738b9f1121625df27843b52b267eec6c"
|
||||
name = "github.com/pelletier/go-buffruneio"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "c37440a7cf42ac63b919c752ca73a85067e05992"
|
||||
version = "v0.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:51ea800cff51752ff68e12e04106f5887b4daec6f9356721238c28019f0b42db"
|
||||
name = "github.com/pelletier/go-toml"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:5cf3f025cbee5951a4ee961de067c8a89fc95a5adabead774f82822efabab121"
|
||||
name = "github.com/pkg/errors"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
||||
version = "v0.8.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe"
|
||||
name = "github.com/pmezard/go-difflib"
|
||||
packages = ["difflib"]
|
||||
pruneopts = "NUT"
|
||||
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:d917313f309bda80d27274d53985bc65651f81a5b66b820749ac7f8ef061fd04"
|
||||
name = "github.com/sergi/go-diff"
|
||||
packages = ["diffmatchpatch"]
|
||||
pruneopts = "NUT"
|
||||
revision = "1744e2970ca51c86172c8190fadad617561ed6e7"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:41618aee8828e62dfe62d44f579c06892d0e98907d1c6d5bcd83bfe8536ec5a3"
|
||||
name = "github.com/shibukawa/configdir"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "e180dbdc8da04c4fa04272e875ce64949f38bd3e"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b2339e83ce9b5c4f79405f949429a7f68a9a904fed903c672aac1e7ceb7f5f02"
|
||||
name = "github.com/sirupsen/logrus"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "3e01752db0189b9157070a0e1668a620f9a85da2"
|
||||
version = "v1.0.6"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:330e9062b308ac597e28485699c02223bd052437a6eed32a173c9227dcb9d95a"
|
||||
name = "github.com/spf13/afero"
|
||||
packages = [
|
||||
".",
|
||||
"mem",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "787d034dfe70e44075ccc060d346146ef53270ad"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:3fa7947ca83b98ae553590d993886e845a4bff19b7b007e869c6e0dd3b9da9cd"
|
||||
name = "github.com/spf13/cast"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "8965335b8c7107321228e3e3702cab9832751bac"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:f29f83301ed096daed24a90f4af591b7560cb14b9cc3e1827abbf04db7269ab5"
|
||||
name = "github.com/spf13/jwalterweatherman"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "14d3d4c518341bea657dd8a226f5121c0ff8c9f2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e3707aeaccd2adc89eba6c062fec72116fe1fc1ba71097da85b4d8ae1668a675"
|
||||
name = "github.com/spf13/pflag"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "9a97c102cda95a86cec2345a6f09f55a939babf5"
|
||||
version = "v1.0.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:454979540e2a1582f375a17c106cf4e11e3bcac4baffb4af23e515c87f87de13"
|
||||
name = "github.com/spf13/viper"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "907c19d40d9a6c9bb55f040ff4ae45271a4754b9"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:0e9a5ac14bcc11f205031a671b28c7e05cb88b2ebbe06f383c1ab0b2c12c7cb5"
|
||||
name = "github.com/spkg/bom"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "59b7046e48ad6bac800c5e1dd5142282cbfcf154"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ccca1dcd18bc54e23b517a3c5babeff2e3924a7d8fc1932162225876cfe4bfb0"
|
||||
name = "github.com/src-d/gcfg"
|
||||
packages = [
|
||||
".",
|
||||
"scanner",
|
||||
"token",
|
||||
"types",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "f187355171c936ac84a82793659ebb4936bc1c23"
|
||||
version = "v1.3.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:bacb8b590716ab7c33f2277240972c9582d389593ee8d66fc10074e0508b8126"
|
||||
name = "github.com/stretchr/testify"
|
||||
packages = ["assert"]
|
||||
pruneopts = "NUT"
|
||||
revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686"
|
||||
version = "v1.2.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:e42372d3f4921ec35df07f9b23239631e9d28580f7c1edcca212bc6daddc68fe"
|
||||
name = "github.com/stvp/roll"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "3627a5cbeaeaa68023abd02bb8687925265f2f63"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:cd5ffc5bda4e0296ab3e4de90dbb415259c78e45e7fab13694b14cde8ab74541"
|
||||
name = "github.com/tcnksm/go-gitconfig"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "d154598bacbf4501c095a309753c5d4af66caa81"
|
||||
version = "v0.1.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:07e8742c479bab0066149ad02a710024154e76874fd0a2dba002d87702725825"
|
||||
name = "github.com/ulikunitz/xz"
|
||||
packages = [
|
||||
".",
|
||||
"internal/hash",
|
||||
"internal/xlog",
|
||||
"lzma",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "0c6b41e72360850ca4f98dc341fd999726ea007f"
|
||||
version = "v0.5.4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:3148cb3478c26a92b4c1a18abb9428234b281e278af6267840721a24b6cbc6a3"
|
||||
name = "github.com/xanzy/ssh-agent"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "640f0ab560aeb89d523bb6ac322b1244d5c3796c"
|
||||
version = "v0.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:dfcb1b2db354cafa48fc3cdafe4905a08bec4a9757919ab07155db0ca23855b4"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = [
|
||||
"cast5",
|
||||
"curve25519",
|
||||
"ed25519",
|
||||
"ed25519/internal/edwards25519",
|
||||
"internal/chacha20",
|
||||
"internal/subtle",
|
||||
"openpgp",
|
||||
"openpgp/armor",
|
||||
"openpgp/elgamal",
|
||||
"openpgp/errors",
|
||||
"openpgp/packet",
|
||||
"openpgp/s2k",
|
||||
"poly1305",
|
||||
"ssh",
|
||||
"ssh/agent",
|
||||
"ssh/knownhosts",
|
||||
"ssh/terminal",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "de0752318171da717af4ce24d0a2e8626afaeb11"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:76ee51c3f468493aff39dbacc401e8831fbb765104cbf613b89bef01cf4bad70"
|
||||
name = "golang.org/x/net"
|
||||
packages = ["context"]
|
||||
pruneopts = "NUT"
|
||||
revision = "c39426892332e1bb5ec0a434a079bf82f5d30c54"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:ec76a40fbfda0c329ee58f4e3b14b4279a939efce89eca020e934e2e5234eddd"
|
||||
name = "golang.org/x/sys"
|
||||
packages = [
|
||||
"unix",
|
||||
"windows",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "98c5dad5d1a0e8a73845ecc8897d0bd56586511d"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a95288ef1ef4dfad6cba7fe30843e1683f71bc28c912ca1ba3f6a539d44db739"
|
||||
name = "golang.org/x/text"
|
||||
packages = [
|
||||
"internal/gen",
|
||||
"internal/tag",
|
||||
"internal/triegen",
|
||||
"internal/ucd",
|
||||
"language",
|
||||
"transform",
|
||||
"unicode/cldr",
|
||||
"unicode/norm",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:47a697b155f5214ff14e68e39ce9c2e8d93e1fb035ae5ba7e247d044e0ce64e3"
|
||||
name = "gopkg.in/src-d/go-billy.v4"
|
||||
packages = [
|
||||
".",
|
||||
"helper/chroot",
|
||||
"helper/polyfill",
|
||||
"osfs",
|
||||
"util",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "83cf655d40b15b427014d7875d10850f96edba14"
|
||||
version = "v4.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e66078da2bd6e53c72518d7f6ae0c3c8c7f34c0df12c39435ce34a6bce165525"
|
||||
name = "gopkg.in/src-d/go-git.v4"
|
||||
packages = [
|
||||
".",
|
||||
"config",
|
||||
"internal/revision",
|
||||
"plumbing",
|
||||
"plumbing/cache",
|
||||
"plumbing/filemode",
|
||||
"plumbing/format/config",
|
||||
"plumbing/format/diff",
|
||||
"plumbing/format/gitignore",
|
||||
"plumbing/format/idxfile",
|
||||
"plumbing/format/index",
|
||||
"plumbing/format/objfile",
|
||||
"plumbing/format/packfile",
|
||||
"plumbing/format/pktline",
|
||||
"plumbing/object",
|
||||
"plumbing/protocol/packp",
|
||||
"plumbing/protocol/packp/capability",
|
||||
"plumbing/protocol/packp/sideband",
|
||||
"plumbing/revlist",
|
||||
"plumbing/storer",
|
||||
"plumbing/transport",
|
||||
"plumbing/transport/client",
|
||||
"plumbing/transport/file",
|
||||
"plumbing/transport/git",
|
||||
"plumbing/transport/http",
|
||||
"plumbing/transport/internal/common",
|
||||
"plumbing/transport/server",
|
||||
"plumbing/transport/ssh",
|
||||
"storage",
|
||||
"storage/filesystem",
|
||||
"storage/filesystem/dotgit",
|
||||
"storage/memory",
|
||||
"utils/binary",
|
||||
"utils/diff",
|
||||
"utils/ioutil",
|
||||
"utils/merkletrie",
|
||||
"utils/merkletrie/filesystem",
|
||||
"utils/merkletrie/index",
|
||||
"utils/merkletrie/internal/frame",
|
||||
"utils/merkletrie/noder",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "43d17e14b714665ab5bc2ecc220b6740779d733f"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b233ad4ec87ac916e7bf5e678e98a2cb9e8b52f6de6ad3e11834fc7a71b8e3bf"
|
||||
name = "gopkg.in/warnings.v0"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "ec4a0fea49c7b46c2aeb0b51aac55779c607e52b"
|
||||
version = "v0.1.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7c95b35057a0ff2e19f707173cc1a947fa43a6eb5c4d300d196ece0334046082"
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
||||
version = "v2.2.1"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
input-imports = [
|
||||
"github.com/cloudfoundry/jibber_jabber",
|
||||
"github.com/fatih/color",
|
||||
"github.com/go-errors/errors",
|
||||
"github.com/golang-collections/collections/stack",
|
||||
"github.com/heroku/rollrus",
|
||||
"github.com/jesseduffield/go-getter",
|
||||
"github.com/jesseduffield/gocui",
|
||||
"github.com/jesseduffield/pty",
|
||||
"github.com/kardianos/osext",
|
||||
"github.com/mgutz/str",
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n",
|
||||
"github.com/shibukawa/configdir",
|
||||
"github.com/sirupsen/logrus",
|
||||
"github.com/spf13/viper",
|
||||
"github.com/spkg/bom",
|
||||
"github.com/stretchr/testify/assert",
|
||||
"github.com/tcnksm/go-gitconfig",
|
||||
"golang.org/x/text/language",
|
||||
"gopkg.in/src-d/go-git.v4",
|
||||
"gopkg.in/src-d/go-git.v4/plumbing",
|
||||
"gopkg.in/yaml.v2",
|
||||
]
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
50
Gopkg.toml
50
Gopkg.toml
@@ -1,50 +0,0 @@
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
#
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
non-go = true
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/fatih/color"
|
||||
version = "1.7.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/golang-collections/collections"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/jesseduffield/gocui"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/jesseduffield/pty"
|
||||
|
||||
[[constraint]]
|
||||
name = "gopkg.in/src-d/go-git.v4"
|
||||
revision = "43d17e14b714665ab5bc2ecc220b6740779d733f"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/spkg/bom"
|
||||
@@ -10,7 +10,7 @@ Jira? This is the app for you!
|
||||
|
||||
- [Installation](https://github.com/jesseduffield/lazygit#installation)
|
||||
- [Usage](https://github.com/jesseduffield/lazygit#usage),
|
||||
[Keybindings](https://github.com/jesseduffield/lazygit/blob/master/docs/Keybindings_en.md)
|
||||
[Keybindings](/docs/keybindings)
|
||||
- [Cool Features](https://github.com/jesseduffield/lazygit#cool-features)
|
||||
- [Contributing](https://github.com/jesseduffield/lazygit#contributing)
|
||||
- [Video Tutorial](https://youtu.be/VDXvbHZYeKY)
|
||||
@@ -21,7 +21,6 @@ Jira? This is the app for you!
|
||||
### Homebrew
|
||||
|
||||
```sh
|
||||
brew tap jesseduffield/lazygit
|
||||
brew install lazygit
|
||||
```
|
||||
|
||||
@@ -104,7 +103,7 @@ whichever rc file you're using).
|
||||
|
||||
- Basic video tutorial [here](https://youtu.be/VDXvbHZYeKY).
|
||||
- List of keybindings
|
||||
[here](/docs/Keybindings_en.md).
|
||||
[here](/docs/keybindings).
|
||||
|
||||
## Cool features
|
||||
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
|
||||
## Default:
|
||||
|
||||
```
|
||||
```yaml
|
||||
gui:
|
||||
# stuff relating to the UI
|
||||
scrollHeight: 2 # how many lines you scroll by
|
||||
scrollPastBottom: true # enable scrolling past the bottom
|
||||
theme:
|
||||
lightTheme: false # For terminals with a light background
|
||||
activeBorderColor:
|
||||
- white
|
||||
- bold
|
||||
@@ -21,6 +22,8 @@
|
||||
merging:
|
||||
# only applicable to unix users
|
||||
manualCommit: false
|
||||
skipHookPrefix: WIP
|
||||
autoFetch: true
|
||||
update:
|
||||
method: prompt # can be: prompt | background | never
|
||||
days: 14 # how often an update is checked for
|
||||
@@ -32,21 +35,21 @@
|
||||
|
||||
### Windows:
|
||||
|
||||
```
|
||||
```yaml
|
||||
os:
|
||||
openCommand: 'cmd /c "start "" {{filename}}"'
|
||||
```
|
||||
|
||||
### Linux:
|
||||
|
||||
```
|
||||
```yaml
|
||||
os:
|
||||
openCommand: 'sh -c "xdg-open {{filename}} >/dev/null"'
|
||||
```
|
||||
|
||||
### OSX:
|
||||
|
||||
```
|
||||
```yaml
|
||||
os:
|
||||
openCommand: 'open {{filename}}'
|
||||
```
|
||||
@@ -55,7 +58,7 @@
|
||||
|
||||
for users of VSCode
|
||||
|
||||
```
|
||||
```yaml
|
||||
os:
|
||||
openCommand: 'code -r {{filename}}'
|
||||
```
|
||||
@@ -78,6 +81,21 @@ The available attributes are:
|
||||
- reverse # useful for high-contrast
|
||||
- underline
|
||||
|
||||
## Light terminal theme:
|
||||
|
||||
If you have issues with a light terminal theme where you can't read / see the text add these settings
|
||||
|
||||
```yaml
|
||||
gui:
|
||||
theme:
|
||||
lightTheme: true
|
||||
activeBorderColor:
|
||||
- black
|
||||
- bold
|
||||
inactiveBorderColor:
|
||||
- black
|
||||
```
|
||||
|
||||
## Example Coloring:
|
||||
|
||||

|
||||
|
||||
@@ -22,21 +22,22 @@
|
||||
|
||||
<pre>
|
||||
<kbd>c</kbd>: commit changes
|
||||
<kbd>w</kbd>: commit changes without pre-commit hook
|
||||
<kbd>A</kbd>: amend last commit
|
||||
<kbd>C</kbd>: commit changes using git editor
|
||||
<kbd>space</kbd>: toggle staged
|
||||
<kbd>d</kbd>: delete if untracked / checkout if tracked
|
||||
<kbd>d</kbd>: view 'discard changes' options
|
||||
<kbd>e</kbd>: edit file
|
||||
<kbd>o</kbd>: open file
|
||||
<kbd>i</kbd>: add to .gitignore
|
||||
<kbd>r</kbd>: refresh files
|
||||
<kbd>S</kbd>: stash files
|
||||
<kbd>s</kbd>: soft reset to last commit
|
||||
<kbd>a</kbd>: stage/unstage all
|
||||
<kbd>t</kbd>: add patch
|
||||
<kbd>D</kbd>: reset hard and remove untracked files
|
||||
<kbd>D</kbd>: view reset options
|
||||
<kbd>enter</kbd>: stage individual hunks/lines
|
||||
<kbd>f</kbd>: fetch
|
||||
<kbd>X</kbd>: execute custom command
|
||||
</pre>
|
||||
|
||||
## Branches
|
||||
@@ -61,9 +62,11 @@
|
||||
<kbd>R</kbd>: rename commit with editor
|
||||
<kbd>g</kbd>: reset to this commit
|
||||
<kbd>f</kbd>: fixup commit
|
||||
<kbd>F</kbd>: create fixup commit for this commit
|
||||
<kbd>S</kbd>: squash above commits
|
||||
<kbd>d</kbd>: delete commit
|
||||
<kbd>J</kbd>: move commit down one
|
||||
<kbd>K</kbd>: move commit up one
|
||||
<kbd>ctrl+j</kbd>: move commit down one
|
||||
<kbd>ctrl+k</kbd>: move commit up one
|
||||
<kbd>e</kbd>: edit commit
|
||||
<kbd>A</kbd>: amend commit with staged changes
|
||||
<kbd>p</kbd>: pick commit (when mid-rebase)
|
||||
@@ -71,6 +74,8 @@
|
||||
<kbd>c</kbd>: copy commit (cherry-pick)
|
||||
<kbd>C</kbd>: copy commit range (cherry-pick)
|
||||
<kbd>v</kbd>: paste commits (cherry-pick)
|
||||
<kbd>enter</kbd>: view commit's files
|
||||
<kbd>space</kbd>: select commit to diff with another commit
|
||||
</pre>
|
||||
|
||||
## Stash
|
||||
@@ -81,11 +86,20 @@
|
||||
<kbd>d</kbd>: drop
|
||||
</pre>
|
||||
|
||||
## Commit files
|
||||
|
||||
<pre>
|
||||
<kbd>esc</kbd>: go back
|
||||
<kbd>c</kbd>: checkout file
|
||||
<kbd>d</kbd>: discard this commit's changes to this file
|
||||
<kbd>o</kbd>: open file
|
||||
</pre>
|
||||
|
||||
## Main (Normal)
|
||||
|
||||
<pre>
|
||||
<kbd>PgDn</kbd>: scroll down
|
||||
<kbd>PgUp</kbd>: scroll up
|
||||
<kbd>PgDn</kbd>: scroll down (fn+up)
|
||||
<kbd>PgUp</kbd>: scroll up (fn+down)
|
||||
</pre>
|
||||
|
||||
## Main (Staging)
|
||||
128
docs/keybindings/Keybindings_nl.md
Normal file
128
docs/keybindings/Keybindings_nl.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# Lazygit menu
|
||||
|
||||
## Global
|
||||
|
||||
<pre>
|
||||
<kbd>m</kbd>: bekijk merge/rebase opties
|
||||
<kbd>P</kbd>: push
|
||||
<kbd>p</kbd>: pull
|
||||
<kbd>R</kbd>: verversen
|
||||
</pre>
|
||||
|
||||
## Status
|
||||
|
||||
<pre>
|
||||
<kbd>e</kbd>: verander config file
|
||||
<kbd>o</kbd>: open config file
|
||||
<kbd>u</kbd>: check voor updates
|
||||
<kbd>s</kbd>: wissel naar een recente repo
|
||||
</pre>
|
||||
|
||||
## Bestanden
|
||||
|
||||
<pre>
|
||||
<kbd>c</kbd>: Commit veranderingen
|
||||
<kbd>w</kbd>: commit veranderingen zonder pre-commit hook
|
||||
<kbd>A</kbd>: wijzig laatste commit
|
||||
<kbd>C</kbd>: commit veranderingen met de git editor
|
||||
<kbd>space</kbd>: toggle staged
|
||||
<kbd>d</kbd>: bekijk 'veranderingen ongedaan maken' opties
|
||||
<kbd>e</kbd>: verander bestand
|
||||
<kbd>o</kbd>: open bestand
|
||||
<kbd>i</kbd>: voeg toe aan .gitignore
|
||||
<kbd>r</kbd>: refresh bestanden
|
||||
<kbd>S</kbd>: stash-bestanden
|
||||
<kbd>a</kbd>: toggle staged alle
|
||||
<kbd>t</kbd>: bewerkingen toevoegen
|
||||
<kbd>D</kbd>: bekijk reset opties
|
||||
<kbd>enter</kbd>: stage individuele hunks/lijnen
|
||||
<kbd>f</kbd>: fetch
|
||||
<kbd>X</kbd>: voor aangepast commando uit
|
||||
</pre>
|
||||
|
||||
## Branches
|
||||
|
||||
<pre>
|
||||
<kbd>space</kbd>: uitchecken
|
||||
<kbd>o</kbd>: maak een pull-aanvraag
|
||||
<kbd>c</kbd>: uitchecken bij naam
|
||||
<kbd>F</kbd>: forceer checkout
|
||||
<kbd>n</kbd>: nieuwe branch
|
||||
<kbd>d</kbd>: verwijder branch
|
||||
<kbd>r</kbd>: rebase branch
|
||||
<kbd>M</kbd>: merge in met huidige checked out branch
|
||||
<kbd>f</kbd>: fast-forward this branch from its upstream
|
||||
</pre>
|
||||
|
||||
## Commits
|
||||
|
||||
<pre>
|
||||
<kbd>s</kbd>: squash beneden
|
||||
<kbd>r</kbd>: hernoem commit
|
||||
<kbd>R</kbd>: rename commit with editor
|
||||
<kbd>g</kbd>: reset naar deze commit
|
||||
<kbd>f</kbd>: Fixup commit
|
||||
<kbd>F</kbd>: creëer fixup commit voor deze commit
|
||||
<kbd>S</kbd>: squash bovenstaande commits
|
||||
<kbd>d</kbd>: verwijder commit
|
||||
<kbd>ctrl+j</kbd>: verplaats commit 1 omlaag
|
||||
<kbd>ctrl+k</kbd>: verplaats commit 1 omhoog
|
||||
<kbd>e</kbd>: verander commit
|
||||
<kbd>A</kbd>: wijzig commit met staged veranderingen
|
||||
<kbd>p</kbd>: pick commit (when mid-rebase)
|
||||
<kbd>t</kbd>: commit omgedaan maken
|
||||
<kbd>c</kbd>: kopiëer commit (cherry-pick)
|
||||
<kbd>C</kbd>: kopiëer commit reeks (cherry-pick)
|
||||
<kbd>v</kbd>: plak commits (cherry-pick)
|
||||
<kbd>enter</kbd>: bekijk gecommite bestanden
|
||||
<kbd>space</kbd>: select commit to diff with another commit
|
||||
</pre>
|
||||
|
||||
## Stash
|
||||
|
||||
<pre>
|
||||
<kbd>space</kbd>: toepassen
|
||||
<kbd>g</kbd>: pop
|
||||
<kbd>d</kbd>: drop
|
||||
</pre>
|
||||
|
||||
## Commit bestanden
|
||||
|
||||
<pre>
|
||||
<kbd>esc</kbd>: ga terug
|
||||
<kbd>c</kbd>: bestand uitchecken
|
||||
<kbd>d</kbd>: uitsluit deze commit zijn veranderingen aan dit bestand
|
||||
<kbd>o</kbd>: open bestand
|
||||
</pre>
|
||||
|
||||
## Hoofd (Stage Lines/Hunks)
|
||||
|
||||
<pre>
|
||||
<kbd>esc</kbd>: ga terug naar het bestanden paneel
|
||||
<kbd>▲</kbd>: selecteer de vorige lijn
|
||||
<kbd>▼</kbd>: selecteer de volgende lijn
|
||||
<kbd>◄</kbd>: selecteer de vorige hunk
|
||||
<kbd>►</kbd>: selecteer de volgende hunk
|
||||
<kbd>space</kbd>: stage lijn
|
||||
<kbd>a</kbd>: stage hunk
|
||||
</pre>
|
||||
|
||||
## Hoofd (Merging)
|
||||
|
||||
<pre>
|
||||
<kbd>esc</kbd>: ga terug naar het bestanden paneel
|
||||
<kbd>space</kbd>: pick hunk
|
||||
<kbd>b</kbd>: pick beide hunks
|
||||
<kbd>◄</kbd>: selecteer voorgaand conflict
|
||||
<kbd>►</kbd>: selecteer volgende conflict
|
||||
<kbd>▲</kbd>: selecteer bovenste hunk
|
||||
<kbd>▼</kbd>: selecteer onderste hunk
|
||||
<kbd>z</kbd>: ongedaan maken
|
||||
</pre>
|
||||
|
||||
## Hoofd (Normaal)
|
||||
|
||||
<pre>
|
||||
<kbd>PgDn</kbd>: scroll omlaag (fn+up)
|
||||
<kbd>PgUp</kbd>: scroll omhoog (fn+down)
|
||||
</pre>
|
||||
128
docs/keybindings/Keybindings_pl.md
Normal file
128
docs/keybindings/Keybindings_pl.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# Lazygit menu
|
||||
|
||||
## Globalne
|
||||
|
||||
<pre>
|
||||
<kbd>m</kbd>: view merge/rebase options
|
||||
<kbd>P</kbd>: push
|
||||
<kbd>p</kbd>: pull
|
||||
<kbd>R</kbd>: odśwież
|
||||
</pre>
|
||||
|
||||
## Status
|
||||
|
||||
<pre>
|
||||
<kbd>e</kbd>: edytuj plik konfiguracyjny
|
||||
<kbd>o</kbd>: otwórz plik konfiguracyjny
|
||||
<kbd>u</kbd>: sprawdź aktualizacje
|
||||
<kbd>s</kbd>: switch to a recent repo
|
||||
</pre>
|
||||
|
||||
## Pliki
|
||||
|
||||
<pre>
|
||||
<kbd>c</kbd>: commituj zmiany
|
||||
<kbd>w</kbd>: commit changes without pre-commit hook
|
||||
<kbd>A</kbd>: zmień ostatnie zatwierdzenie
|
||||
<kbd>C</kbd>: commituj zmiany używając edytora z gita
|
||||
<kbd>space</kbd>: przełącz zatwierdzenie
|
||||
<kbd>d</kbd>: view 'discard changes' options
|
||||
<kbd>e</kbd>: edytuj plik
|
||||
<kbd>o</kbd>: otwórz plik
|
||||
<kbd>i</kbd>: dodaj do .gitignore
|
||||
<kbd>r</kbd>: odśwież pliki
|
||||
<kbd>S</kbd>: przechowaj pliki
|
||||
<kbd>a</kbd>: przełącz wszystkie zatwierdzenia
|
||||
<kbd>t</kbd>: dodaj łatkę
|
||||
<kbd>D</kbd>: view reset options
|
||||
<kbd>enter</kbd>: zatwierdź pojedyncze linie
|
||||
<kbd>f</kbd>: fetch
|
||||
<kbd>X</kbd>: execute custom command
|
||||
</pre>
|
||||
|
||||
## Gałęzie
|
||||
|
||||
<pre>
|
||||
<kbd>space</kbd>: przełącz
|
||||
<kbd>o</kbd>: utwórz żądanie wyciągnięcia
|
||||
<kbd>c</kbd>: przełącz używając nazwy
|
||||
<kbd>F</kbd>: wymuś przełączenie
|
||||
<kbd>n</kbd>: nowa gałąź
|
||||
<kbd>d</kbd>: usuń gałąź
|
||||
<kbd>r</kbd>: rebase branch
|
||||
<kbd>M</kbd>: scal do obecnej gałęzi
|
||||
<kbd>f</kbd>: fast-forward this branch from its upstream
|
||||
</pre>
|
||||
|
||||
## Commity
|
||||
|
||||
<pre>
|
||||
<kbd>s</kbd>: ściśnij w dół
|
||||
<kbd>r</kbd>: przemianuj commit
|
||||
<kbd>R</kbd>: przemianuj commit w edytorze
|
||||
<kbd>g</kbd>: zresetuj do tego commita
|
||||
<kbd>f</kbd>: napraw commit
|
||||
<kbd>F</kbd>: create fixup commit for this commit
|
||||
<kbd>S</kbd>: squash above commits
|
||||
<kbd>d</kbd>: delete commit
|
||||
<kbd>ctrl+j</kbd>: move commit down one
|
||||
<kbd>ctrl+k</kbd>: move commit up one
|
||||
<kbd>e</kbd>: edit commit
|
||||
<kbd>A</kbd>: amend commit with staged changes
|
||||
<kbd>p</kbd>: pick commit (when mid-rebase)
|
||||
<kbd>t</kbd>: revert commit
|
||||
<kbd>c</kbd>: copy commit (cherry-pick)
|
||||
<kbd>C</kbd>: copy commit range (cherry-pick)
|
||||
<kbd>v</kbd>: paste commits (cherry-pick)
|
||||
<kbd>enter</kbd>: view commit's files
|
||||
<kbd>space</kbd>: select commit to diff with another commit
|
||||
</pre>
|
||||
|
||||
## Schowek
|
||||
|
||||
<pre>
|
||||
<kbd>space</kbd>: zastosuj
|
||||
<kbd>g</kbd>: wyciągnij
|
||||
<kbd>d</kbd>: porzuć
|
||||
</pre>
|
||||
|
||||
## Commit files
|
||||
|
||||
<pre>
|
||||
<kbd>esc</kbd>: go back
|
||||
<kbd>c</kbd>: checkout file
|
||||
<kbd>d</kbd>: discard this commit's changes to this file
|
||||
<kbd>o</kbd>: otwórz plik
|
||||
</pre>
|
||||
|
||||
## Main (Normal)
|
||||
|
||||
<pre>
|
||||
<kbd>PgDn</kbd>: scroll down (fn+up)
|
||||
<kbd>PgUp</kbd>: scroll up (fn+down)
|
||||
</pre>
|
||||
|
||||
## Main (Zatwierdzanie)
|
||||
|
||||
<pre>
|
||||
<kbd>esc</kbd>: wróć do panelu plików
|
||||
<kbd>▲</kbd>: select previous line
|
||||
<kbd>▼</kbd>: select next line
|
||||
<kbd>◄</kbd>: select previous hunk
|
||||
<kbd>►</kbd>: select next hunk
|
||||
<kbd>space</kbd>: zatwierdź linię
|
||||
<kbd>a</kbd>: zatwierdź kawałek
|
||||
</pre>
|
||||
|
||||
## Main (Merging)
|
||||
|
||||
<pre>
|
||||
<kbd>esc</kbd>: wróć do panelu plików
|
||||
<kbd>space</kbd>: pick hunk
|
||||
<kbd>b</kbd>: pick both hunks
|
||||
<kbd>◄</kbd>: select previous conflict
|
||||
<kbd>►</kbd>: select next conflict
|
||||
<kbd>▲</kbd>: select top hunk
|
||||
<kbd>▼</kbd>: select bottom hunk
|
||||
<kbd>z</kbd>: undo
|
||||
</pre>
|
||||
93
go.mod
93
go.mod
@@ -3,64 +3,67 @@ module github.com/jesseduffield/lazygit
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/aws/aws-sdk-go v1.15.21
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d
|
||||
github.com/BurntSushi/toml v0.3.1 // indirect
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 // indirect
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 // indirect
|
||||
github.com/aws/aws-sdk-go v1.15.21 // indirect
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
|
||||
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
|
||||
github.com/davecgh/go-spew v1.1.0
|
||||
github.com/emirpasic/gods v1.9.0
|
||||
github.com/emirpasic/gods v1.9.0 // indirect
|
||||
github.com/fatih/color v1.7.0
|
||||
github.com/fsnotify/fsnotify v1.4.7
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
|
||||
github.com/gliderlabs/ssh v0.2.2 // indirect
|
||||
github.com/go-errors/errors v1.0.1
|
||||
github.com/go-ini/ini v1.38.2
|
||||
github.com/go-ini/ini v1.38.2 // indirect
|
||||
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
|
||||
github.com/hashicorp/go-cleanhttp v0.0.0-20171218145408-d5fe4b57a186
|
||||
github.com/hashicorp/go-getter v0.0.0-20180809191950-4bda8fa99001
|
||||
github.com/hashicorp/go-safetemp v0.0.0-20180326211150-b1a1dbde6fdc
|
||||
github.com/hashicorp/go-version v1.0.0
|
||||
github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce
|
||||
github.com/heroku/rollrus v0.0.0-20180515183152-fc0cef2ff331
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99
|
||||
github.com/google/go-cmp v0.3.1 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.0.0-20171218145408-d5fe4b57a186 // indirect
|
||||
github.com/hashicorp/go-getter v0.0.0-20180809191950-4bda8fa99001 // indirect
|
||||
github.com/hashicorp/go-safetemp v0.0.0-20180326211150-b1a1dbde6fdc // indirect
|
||||
github.com/hashicorp/go-version v1.0.0 // indirect
|
||||
github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce // indirect
|
||||
github.com/integrii/flaggy v1.2.2
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jesseduffield/go-getter v0.0.0-20180822080847-906e15686e63
|
||||
github.com/jesseduffield/gocui v0.0.0-20190305102456-f0f0ab442e6c
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20190908012510-092b2290ee54
|
||||
github.com/jesseduffield/pty v0.0.0-20181218102224-02db52c7e406
|
||||
github.com/jesseduffield/termbox-go v0.0.0-20180919093808-1e272ff78dcb
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8
|
||||
github.com/jesseduffield/rollrus v0.0.0-20190701125922-dd028cb0bfd7
|
||||
github.com/jesseduffield/termbox-go v0.0.0-20180919093808-1e272ff78dcb // indirect
|
||||
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1
|
||||
github.com/kevinburke/ssh_config v0.0.0-20180317175531-9fc7bb800b55
|
||||
github.com/magiconair/properties v1.8.0
|
||||
github.com/mattn/go-colorable v0.0.9
|
||||
github.com/mattn/go-isatty v0.0.3
|
||||
github.com/mattn/go-runewidth v0.0.2
|
||||
github.com/kevinburke/ssh_config v0.0.0-20180317175531-9fc7bb800b55 // indirect
|
||||
github.com/magiconair/properties v1.8.0 // indirect
|
||||
github.com/mattn/go-colorable v0.0.9 // indirect
|
||||
github.com/mattn/go-isatty v0.0.3 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.2 // indirect
|
||||
github.com/mgutz/str v1.2.0
|
||||
github.com/mitchellh/go-homedir v0.0.0-20180801233206-58046073cbff
|
||||
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77
|
||||
github.com/mitchellh/mapstructure v0.0.0-20180715050151-f15292f7a699
|
||||
github.com/nicksnyder/go-i18n v0.0.0-20180803040939-a16b91a3ba80
|
||||
github.com/pelletier/go-buffruneio v0.2.0
|
||||
github.com/pelletier/go-toml v1.2.0
|
||||
github.com/pkg/errors v0.8.0
|
||||
github.com/pmezard/go-difflib v1.0.0
|
||||
github.com/sergi/go-diff v1.0.0
|
||||
github.com/mitchellh/go-homedir v0.0.0-20180801233206-58046073cbff // indirect
|
||||
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 // indirect
|
||||
github.com/mitchellh/mapstructure v0.0.0-20180715050151-f15292f7a699 // indirect
|
||||
github.com/nicksnyder/go-i18n/v2 v2.0.2
|
||||
github.com/onsi/ginkgo v1.9.0 // indirect
|
||||
github.com/onsi/gomega v1.6.0 // indirect
|
||||
github.com/pelletier/go-buffruneio v0.2.0 // indirect
|
||||
github.com/pelletier/go-toml v1.2.0 // indirect
|
||||
github.com/sergi/go-diff v1.0.0 // indirect
|
||||
github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0
|
||||
github.com/sirupsen/logrus v1.0.6
|
||||
github.com/spf13/afero v1.1.1
|
||||
github.com/spf13/cast v1.2.0
|
||||
github.com/spf13/jwalterweatherman v0.0.0-20180814060501-14d3d4c51834
|
||||
github.com/spf13/pflag v1.0.2
|
||||
github.com/sirupsen/logrus v1.3.0
|
||||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 // indirect
|
||||
github.com/spf13/afero v1.1.1 // indirect
|
||||
github.com/spf13/cast v1.2.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v0.0.0-20180814060501-14d3d4c51834 // indirect
|
||||
github.com/spf13/pflag v1.0.2 // indirect
|
||||
github.com/spf13/viper v1.1.0
|
||||
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad
|
||||
github.com/src-d/gcfg v1.3.0
|
||||
github.com/src-d/gcfg v1.3.0 // indirect
|
||||
github.com/stretchr/testify v1.2.2
|
||||
github.com/stvp/roll v0.0.0-20170522205222-3627a5cbeaea
|
||||
github.com/tcnksm/go-gitconfig v0.1.2
|
||||
github.com/ulikunitz/xz v0.5.4
|
||||
github.com/xanzy/ssh-agent v0.2.0
|
||||
golang.org/x/crypto v0.0.0-20180808211826-de0752318171
|
||||
golang.org/x/net v0.0.0-20180811021610-c39426892332
|
||||
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0
|
||||
golang.org/x/text v0.3.0
|
||||
gopkg.in/src-d/go-billy.v4 v4.2.0
|
||||
github.com/ulikunitz/xz v0.5.4 // indirect
|
||||
github.com/xanzy/ssh-agent v0.2.0 // indirect
|
||||
golang.org/x/text v0.3.2
|
||||
gopkg.in/ini.v1 v1.46.0 // indirect
|
||||
gopkg.in/src-d/go-billy.v4 v4.2.0 // indirect
|
||||
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 // indirect
|
||||
gopkg.in/src-d/go-git.v4 v4.0.0-20180807092216-43d17e14b714
|
||||
gopkg.in/warnings.v0 v0.1.2
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.1
|
||||
)
|
||||
|
||||
109
go.sum
109
go.sum
@@ -1,17 +1,28 @@
|
||||
github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/aws/aws-sdk-go v1.15.21 h1:STLvc6RrpycslC1NRtTvt/YSgDkIGCTrB9K9vE5R2oQ=
|
||||
github.com/aws/aws-sdk-go v1.15.21/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
|
||||
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:tuijfIjZyjZaHq9xDUh0tNitwXshJpbLkqMOJv4H3do=
|
||||
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:po7NpZ/QiTKzBKyrsEAxwnTamCoh8uDk/egRpQ7siIc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/emirpasic/gods v1.9.0 h1:rUF4PuzEjMChMiNsVjdI+SyLu7rEqpQ5reNFnhC7oFo=
|
||||
github.com/emirpasic/gods v1.9.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
|
||||
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
@@ -19,9 +30,15 @@ github.com/go-ini/ini v1.38.2 h1:6Hl/z3p3iFkA0dlDfzYxuFuUGD+kaweypF6btsR2/Q4=
|
||||
github.com/go-ini/ini v1.38.2/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 h1:zN2lZNZRflqFyxVaTIU61KNKQ9C0055u9CAfpmqUvo4=
|
||||
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3/go.mod h1:nPpo7qLxd6XL3hWJG/O60sR8ZKfMCiIoNap5GvD12KU=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/hashicorp/go-cleanhttp v0.0.0-20171218145408-d5fe4b57a186 h1:URgjUo+bs1KwatoNbwG0uCO4dHN4r1jsp4a5AGgHRjo=
|
||||
github.com/hashicorp/go-cleanhttp v0.0.0-20171218145408-d5fe4b57a186/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-getter v0.0.0-20180809191950-4bda8fa99001 h1:MFPzqpPED05pFyGjNPJEC2sXM6EHTzFyvX+0s0JoZ48=
|
||||
github.com/hashicorp/go-getter v0.0.0-20180809191950-4bda8fa99001 h1:qC+3MHkvfCXb1cA9YDpWZ7np8tPOXZceLrW+xyqOgmk=
|
||||
github.com/hashicorp/go-getter v0.0.0-20180809191950-4bda8fa99001/go.mod h1:6rdJFnhkXnzGOJbvkrdv4t9nLwKcVA+tmbQeUlkIzrU=
|
||||
github.com/hashicorp/go-safetemp v0.0.0-20180326211150-b1a1dbde6fdc h1:wAa9fGALVHfjYxZuXRnmuJG2CnwRpJYOTvY6YdErAh0=
|
||||
github.com/hashicorp/go-safetemp v0.0.0-20180326211150-b1a1dbde6fdc/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
|
||||
@@ -29,24 +46,34 @@ github.com/hashicorp/go-version v1.0.0 h1:21MVWPKDphxa7ineQQTrCU5brh7OuVVAzGOCnn
|
||||
github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce h1:xdsDDbiBDQTKASoGEZ+pEmF1OnWuu8AQ9I8iNbHNeno=
|
||||
github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
|
||||
github.com/heroku/rollrus v0.0.0-20180515183152-fc0cef2ff331 h1:qio0y/sQdhbHRA3cmgczo04MaSV2zw+n46G1owvgWIk=
|
||||
github.com/heroku/rollrus v0.0.0-20180515183152-fc0cef2ff331/go.mod h1:BT+PgT529opmb6mcUY+Fg0IwVRRmwqFyavEMU17GnBg=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/integrii/flaggy v1.2.2 h1:SzL5kyEaW+Cb3RLxGG1ch9FFDLQPB6QuMdYoNu5JIo0=
|
||||
github.com/integrii/flaggy v1.2.2/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/go-getter v0.0.0-20180822080847-906e15686e63 h1:Nrr/yUxNjXWYK0B3IqcFlYh1ICnesJDB4ogcfOVc5Ns=
|
||||
github.com/jesseduffield/go-getter v0.0.0-20180822080847-906e15686e63 h1:tbm85YuPi3d1LFAUr6yZyzZ4vR96ygV98rezZZ+ywbg=
|
||||
github.com/jesseduffield/go-getter v0.0.0-20180822080847-906e15686e63/go.mod h1:fNqjRf+4XnTo2PrGN1JRb79b/BeoHwP4lU00f39SQY0=
|
||||
github.com/jesseduffield/gocui v0.0.0-20190305102456-f0f0ab442e6c h1:ZmCZFQukfddcISnY8R5YYMCYJX0mc1Wfmq/MhEQViUE=
|
||||
github.com/jesseduffield/gocui v0.0.0-20190305102456-f0f0ab442e6c/go.mod h1:2RtZznzYKt8RLRwvFiSkXjU0Ei8WwHdubgnlaYH47dw=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20190908012510-092b2290ee54 h1:zK8KCB55hNdBadw5iJll46xQL6WXEwEXbt9B+QyYswo=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20190908012510-092b2290ee54/go.mod h1:2RtZznzYKt8RLRwvFiSkXjU0Ei8WwHdubgnlaYH47dw=
|
||||
github.com/jesseduffield/pty v0.0.0-20181218102224-02db52c7e406 h1:iYMH6h6SuWuBkIzRtymosE8NpSgTK0oRMfyTdVWgxzc=
|
||||
github.com/jesseduffield/pty v0.0.0-20181218102224-02db52c7e406/go.mod h1:7jlS40+UhOqkZJDIG1B/H21xnuET/+fvbbnHCa8wSIo=
|
||||
github.com/jesseduffield/roll v0.0.0-20190629104057-695be2e62b00 h1:+JaOkfBNYQYlGD7dgru8mCwYNEc5tRRI8mThlVANhSM=
|
||||
github.com/jesseduffield/roll v0.0.0-20190629104057-695be2e62b00/go.mod h1:cWNQljQAWYBp4wchyGfql4q2jRNZXxiE1KhVQgz+JaM=
|
||||
github.com/jesseduffield/rollrus v0.0.0-20190701125922-dd028cb0bfd7 h1:CRD7bVjlGIiV+M0jlsa+XWpneW0KY0e7Y4z3GWb5S4o=
|
||||
github.com/jesseduffield/rollrus v0.0.0-20190701125922-dd028cb0bfd7/go.mod h1:VspA3aTkEo0Q7TPCLmX1uHNP+Wb4iSDX09hmTRo1QYc=
|
||||
github.com/jesseduffield/termbox-go v0.0.0-20180919093808-1e272ff78dcb h1:cFHYEWpQEfzFZVKiKZytCUX4UwQixKSw0kd3WhluPsY=
|
||||
github.com/jesseduffield/termbox-go v0.0.0-20180919093808-1e272ff78dcb/go.mod h1:anMibpZtqNxjDbxrcDEAwSdaJ37vyUeM1f/M4uekib4=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8 h1:12VvqtR6Aowv3l/EQUlocDHW2Cp4G9WJVH7uyH8QFJE=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro=
|
||||
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20180317175531-9fc7bb800b55 h1:S38dC4mEwxdw/U41+97VWdbun8mTcTjwg5Ujfg8QPME=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20180317175531-9fc7bb800b55/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
|
||||
@@ -63,23 +90,31 @@ github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 h1:
|
||||
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20180715050151-f15292f7a699 h1:KXZJFdun9knAVAR8tg/aHJEr5DgtcbqyvzacK+CDCaI=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20180715050151-f15292f7a699/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/nicksnyder/go-i18n v0.0.0-20180803040939-a16b91a3ba80 h1:7ory6RlsEkeK89iyV7Imz3sVz8YHeSw29w3PehpCWC0=
|
||||
github.com/nicksnyder/go-i18n v0.0.0-20180803040939-a16b91a3ba80/go.mod h1:e4Di5xjP9oTVrC6y3C7C0HoSYXjSbhh/dU0eUV32nB4=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.0.0-beta.6 h1:SooTCzUOOs899x/M7gmSS+dgL+AUfSWqAcHLN3auCic=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.0.0-beta.6/go.mod h1:4Opqa6/HIv0lhG3WRAkqzO0afezkRhxXI0P8EJkqeRU=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.0.2 h1:KsHGcTByIM0mHZKQGy0nlJLOjPNjQ6MVib/3PvsBDNY=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.0.2/go.mod h1:JXS4+OKhbcwDoVTEj0sLFWL1vOwec2g/YBAxZ9owJqY=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.9.0 h1:SZjF721BByVj8QH636/8S2DnX4n0Re3SteMmw3N+tzc=
|
||||
github.com/onsi/ginkgo v1.9.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.6.0 h1:8XTW0fcJZEq9q+Upcyws4JSGua2MFysCL5xkaSgHc+M=
|
||||
github.com/onsi/gomega v1.6.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/pelletier/go-buffruneio v0.2.0 h1:U4t4R6YkofJ5xHm3dJzuRpPZ0mr5MMCoAWooScCR7aA=
|
||||
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
|
||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0 h1:Xuk8ma/ibJ1fOy4Ee11vHhUFHQNpHhrBneOCNHVXS5w=
|
||||
github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0/go.mod h1:7AwjWCpdPhkSmNAgUv5C7EJ4AbmjEB3r047r3DXWu3Y=
|
||||
github.com/sirupsen/logrus v1.0.6 h1:hcP1GmhGigz/O7h1WVUM5KklBp1JoNS9FggWKdj/j3s=
|
||||
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||
github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME=
|
||||
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/spf13/afero v1.1.1 h1:Lt3ihYMlE+lreX1GS4Qw4ZsNpYQLxIXKBTEOXm3nt6I=
|
||||
github.com/spf13/afero v1.1.1/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.2.0 h1:HHl1DSRbEQN2i8tJmtS6ViPyHx35+p51amrdsiTCrkg=
|
||||
@@ -94,29 +129,53 @@ github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad h1:fiWzISvDn0Csy5H0iwgAuJ
|
||||
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
|
||||
github.com/src-d/gcfg v1.3.0 h1:2BEDr8r0I0b8h/fOqwtxCEiq2HJu8n2JGZJQFGXWLjg=
|
||||
github.com/src-d/gcfg v1.3.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stvp/roll v0.0.0-20170522205222-3627a5cbeaea h1:jysxIKov/4GJ33wI2aRvuIK7yBwB28E5almlgDLPRpM=
|
||||
github.com/stvp/roll v0.0.0-20170522205222-3627a5cbeaea/go.mod h1:Ffmqrj3nXIMIjeA4uW3Qjj0Ud9eDoTG0fu4JxyAr/tE=
|
||||
github.com/tcnksm/go-gitconfig v0.1.2 h1:iiDhRitByXAEyjgBqsKi9QU4o2TNtv9kPP3RgPgXBPw=
|
||||
github.com/tcnksm/go-gitconfig v0.1.2/go.mod h1:/8EhP4H7oJZdIPyT+/UIsG87kTzrzM4UsLGSItWYCpE=
|
||||
github.com/ulikunitz/xz v0.5.4 h1:zATC2OoZ8H1TZll3FpbX+ikwmadbO699PE06cIkm9oU=
|
||||
github.com/ulikunitz/xz v0.5.4/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||
github.com/xanzy/ssh-agent v0.2.0 h1:Adglfbi5p9Z0BmK2oKU9nTG+zKfniSfnaMYB+ULd+Ro=
|
||||
github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8=
|
||||
golang.org/x/crypto v0.0.0-20180808211826-de0752318171 h1:vYogbvSFj2YXcjQxFHu/rASSOt9sLytpCaSkiwQ135I=
|
||||
golang.org/x/crypto v0.0.0-20180808211826-de0752318171/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/net v0.0.0-20180811021610-c39426892332 h1:efGso+ep0DjyCBJPjvoz0HI6UldX4Md2F1rZFe1ir0E=
|
||||
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0 h1:8H8QZJ30plJyIVj60H3lr8TZGIq2Fh3Cyrs/ZNg1foU=
|
||||
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.0.0-20171214130843-f21a4dfb5e38/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284 h1:rlLehGeYg6jfoyz/eDqDU1iRXLKfR42nnNh57ytKEWo=
|
||||
golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/ini.v1 v1.46.0 h1:VeDZbLYGaupuvIrsYCEOe/L/2Pcs5n7hdO1ZTjporag=
|
||||
gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/src-d/go-billy.v4 v4.2.0 h1:VGbrP1EsYxtvVPEiHui+4//imr4E5MGEFLx66bQtusg=
|
||||
gopkg.in/src-d/go-billy.v4 v4.2.0/go.mod h1:ZHSF0JP+7oD97194otDUCD7Ofbk63+xFcfWP5bT6h+Q=
|
||||
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg=
|
||||
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
|
||||
gopkg.in/src-d/go-git.v4 v4.0.0-20180807092216-43d17e14b714 h1:+wM2BGgQ1znCKBexOB4OrGVSDw8mtKNUSq3wqxZhi/k=
|
||||
gopkg.in/src-d/go-git.v4 v4.0.0-20180807092216-43d17e14b714/go.mod h1:CzbUWqMn4pvmvndg3gnh5iZFmSsbhyhUWdI0IQ60AQo=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
||||
|
||||
43
main.go
43
main.go
@@ -1,7 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
@@ -9,6 +8,7 @@ import (
|
||||
"runtime"
|
||||
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/integrii/flaggy"
|
||||
"github.com/jesseduffield/lazygit/pkg/app"
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
)
|
||||
@@ -18,10 +18,6 @@ var (
|
||||
version = "unversioned"
|
||||
date string
|
||||
buildSource = "unknown"
|
||||
|
||||
configFlag = flag.Bool("config", false, "Print the current default config")
|
||||
debuggingFlag = flag.Bool("debug", false, "a boolean")
|
||||
versionFlag = flag.Bool("v", false, "Print the current version")
|
||||
)
|
||||
|
||||
func projectPath(path string) string {
|
||||
@@ -30,17 +26,43 @@ func projectPath(path string) string {
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
if *versionFlag {
|
||||
flaggy.DefaultParser.ShowVersionWithVersionFlag = false
|
||||
|
||||
repoPath := "."
|
||||
flaggy.String(&repoPath, "p", "path", "Path of git repo")
|
||||
|
||||
dump := ""
|
||||
flaggy.AddPositionalValue(&dump, "gitargs", 1, false, "Todo file")
|
||||
flaggy.DefaultParser.PositionalFlags[0].Hidden = true
|
||||
|
||||
versionFlag := false
|
||||
flaggy.Bool(&versionFlag, "v", "version", "Print the current version")
|
||||
|
||||
debuggingFlag := false
|
||||
flaggy.Bool(&debuggingFlag, "d", "debug", "Run in debug mode with logging")
|
||||
|
||||
configFlag := false
|
||||
flaggy.Bool(&configFlag, "c", "config", "Print the current default config")
|
||||
|
||||
flaggy.Parse()
|
||||
|
||||
if versionFlag {
|
||||
fmt.Printf("commit=%s, build date=%s, build source=%s, version=%s, os=%s, arch=%s\n", commit, date, buildSource, version, runtime.GOOS, runtime.GOARCH)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if *configFlag {
|
||||
if configFlag {
|
||||
fmt.Printf("%s\n", config.GetDefaultConfig())
|
||||
os.Exit(0)
|
||||
}
|
||||
appConfig, err := config.NewAppConfig("lazygit", version, commit, date, buildSource, *debuggingFlag)
|
||||
|
||||
if repoPath != "." {
|
||||
if err := os.Chdir(repoPath); err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
appConfig, err := config.NewAppConfig("lazygit", version, commit, date, buildSource, debuggingFlag)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
@@ -52,6 +74,9 @@ func main() {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if errorMessage, known := app.KnownError(err); known {
|
||||
log.Fatal(errorMessage)
|
||||
}
|
||||
newErr := errors.Wrap(err, 0)
|
||||
stackTrace := newErr.ErrorStack()
|
||||
app.Log.Error(stackTrace)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
@@ -8,12 +9,12 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/heroku/rollrus"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui"
|
||||
"github.com/jesseduffield/lazygit/pkg/i18n"
|
||||
"github.com/jesseduffield/lazygit/pkg/updates"
|
||||
"github.com/jesseduffield/rollrus"
|
||||
"github.com/shibukawa/configdir"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -32,9 +33,15 @@ type App struct {
|
||||
ClientContext string
|
||||
}
|
||||
|
||||
type errorMapping struct {
|
||||
originalError string
|
||||
newError string
|
||||
}
|
||||
|
||||
func newProductionLogger(config config.AppConfigurer) *logrus.Logger {
|
||||
log := logrus.New()
|
||||
log.Out = ioutil.Discard
|
||||
log.SetLevel(logrus.ErrorLevel)
|
||||
return log
|
||||
}
|
||||
|
||||
@@ -44,8 +51,18 @@ func globalConfigDir() string {
|
||||
return configDir.Path
|
||||
}
|
||||
|
||||
func getLogLevel() logrus.Level {
|
||||
strLevel := os.Getenv("LOG_LEVEL")
|
||||
level, err := logrus.ParseLevel(strLevel)
|
||||
if err != nil {
|
||||
return logrus.DebugLevel
|
||||
}
|
||||
return level
|
||||
}
|
||||
|
||||
func newDevelopmentLogger(config config.AppConfigurer) *logrus.Logger {
|
||||
log := logrus.New()
|
||||
log.SetLevel(getLogLevel())
|
||||
file, err := os.OpenFile(filepath.Join(globalConfigDir(), "development.log"), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
panic("unable to log to file") // TODO: don't panic (also, remove this call to the `panic` function)
|
||||
@@ -103,12 +120,13 @@ func NewApp(config config.AppConfigurer) (*App, error) {
|
||||
if err != nil {
|
||||
return app, err
|
||||
}
|
||||
|
||||
if err := app.setupRepo(); err != nil {
|
||||
return app, err
|
||||
}
|
||||
|
||||
app.GitCommand, err = commands.NewGitCommand(app.Log, app.OSCommand, app.Tr, app.Config)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "Not a git repository") {
|
||||
fmt.Println("Not in a git repository. Use `git init` to create a new one")
|
||||
os.Exit(1)
|
||||
}
|
||||
return app, err
|
||||
}
|
||||
app.Gui, err = gui.NewGui(app.Log, app.GitCommand, app.OSCommand, app.Tr, config, app.Updater)
|
||||
@@ -118,6 +136,24 @@ func NewApp(config config.AppConfigurer) (*App, error) {
|
||||
return app, nil
|
||||
}
|
||||
|
||||
func (app *App) setupRepo() error {
|
||||
// if we are not in a git repo, we ask if we want to `git init`
|
||||
if err := app.OSCommand.RunCommand("git status"); err != nil {
|
||||
if !strings.Contains(err.Error(), "Not a git repository") {
|
||||
return err
|
||||
}
|
||||
fmt.Print(app.Tr.SLocalize("CreateRepo"))
|
||||
response, _ := bufio.NewReader(os.Stdin).ReadString('\n')
|
||||
if strings.Trim(response, " \n") != "y" {
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := app.OSCommand.RunCommand("git init"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (app *App) Run() error {
|
||||
if app.ClientContext == "INTERACTIVE_REBASE" {
|
||||
return app.Rebase()
|
||||
@@ -127,7 +163,8 @@ func (app *App) Run() error {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
return app.Gui.RunWithSubprocesses()
|
||||
err := app.Gui.RunWithSubprocesses()
|
||||
return err
|
||||
}
|
||||
|
||||
// Rebase contains logic for when we've been run in demon mode, meaning we've
|
||||
@@ -161,3 +198,22 @@ func (app *App) Close() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// KnownError takes an error and tells us whether it's an error that we know about where we can print a nicely formatted version of it rather than panicking with a stack trace
|
||||
func (app *App) KnownError(err error) (string, bool) {
|
||||
errorMessage := err.Error()
|
||||
|
||||
mappings := []errorMapping{
|
||||
{
|
||||
originalError: "fatal: not a git repository (or any of the parent directories): .git",
|
||||
newError: app.Tr.SLocalize("notARepository"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, mapping := range mappings {
|
||||
if strings.Contains(errorMessage, mapping.originalError) {
|
||||
return mapping.newError, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/theme"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
@@ -18,7 +20,7 @@ type Branch struct {
|
||||
Selected bool
|
||||
}
|
||||
|
||||
// GetDisplayStrings returns the dispaly string of branch
|
||||
// GetDisplayStrings returns the display string of branch
|
||||
func (b *Branch) GetDisplayStrings(isFocused bool) []string {
|
||||
displayName := utils.ColoredString(b.Name, b.GetColor())
|
||||
if isFocused && b.Selected && b.Pushables != "" && b.Pullables != "" {
|
||||
@@ -38,7 +40,7 @@ func (b *Branch) GetColor() color.Attribute {
|
||||
case "hotfix":
|
||||
return color.FgRed
|
||||
default:
|
||||
return color.FgWhite
|
||||
return theme.DefaultTextColor
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package commands
|
||||
|
||||
import (
|
||||
"github.com/fatih/color"
|
||||
"github.com/jesseduffield/lazygit/pkg/theme"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
|
||||
@@ -9,7 +10,7 @@ import (
|
||||
type Commit struct {
|
||||
Sha string
|
||||
Name string
|
||||
Status string // one of "unpushed", "pushed", "merged", or "rebasing"
|
||||
Status string // one of "unpushed", "pushed", "merged", "rebasing" or "selected"
|
||||
DisplayString string
|
||||
Action string // one of "", "pick", "edit", "squash", "reword", "drop", "fixup"
|
||||
Copied bool // to know if this commit is ready to be cherry-picked somewhere
|
||||
@@ -22,7 +23,8 @@ func (c *Commit) GetDisplayStrings(isFocused bool) []string {
|
||||
green := color.New(color.FgGreen)
|
||||
blue := color.New(color.FgBlue)
|
||||
cyan := color.New(color.FgCyan)
|
||||
white := color.New(color.FgWhite)
|
||||
defaultColor := color.New(theme.DefaultTextColor)
|
||||
magenta := color.New(color.FgMagenta)
|
||||
|
||||
// for some reason, setting the background to blue pads out the other commits
|
||||
// horizontally. For the sake of accessibility I'm considering this a feature,
|
||||
@@ -39,8 +41,10 @@ func (c *Commit) GetDisplayStrings(isFocused bool) []string {
|
||||
shaColor = green
|
||||
case "rebasing":
|
||||
shaColor = blue
|
||||
case "selected":
|
||||
shaColor = magenta
|
||||
default:
|
||||
shaColor = white
|
||||
shaColor = defaultColor
|
||||
}
|
||||
|
||||
if c.Copied {
|
||||
@@ -52,5 +56,5 @@ func (c *Commit) GetDisplayStrings(isFocused bool) []string {
|
||||
actionString = cyan.Sprint(utils.WithPadding(c.Action, 7)) + " "
|
||||
}
|
||||
|
||||
return []string{shaColor.Sprint(c.Sha), actionString + white.Sprint(c.Name)}
|
||||
return []string{shaColor.Sprint(c.Sha), actionString + defaultColor.Sprint(c.Name)}
|
||||
}
|
||||
|
||||
13
pkg/commands/commit_file.go
Normal file
13
pkg/commands/commit_file.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package commands
|
||||
|
||||
// CommitFile : A git commit file
|
||||
type CommitFile struct {
|
||||
Sha string
|
||||
Name string
|
||||
DisplayString string
|
||||
}
|
||||
|
||||
// GetDisplayStrings is a function.
|
||||
func (f *CommitFile) GetDisplayStrings(isFocused bool) []string {
|
||||
return []string{f.DisplayString}
|
||||
}
|
||||
14
pkg/commands/errors.go
Normal file
14
pkg/commands/errors.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package commands
|
||||
|
||||
import "github.com/go-errors/errors"
|
||||
|
||||
// WrapError wraps an error for the sake of showing a stack trace at the top level
|
||||
// the go-errors package, for some reason, does not return nil when you try to wrap
|
||||
// a non-error, so we're just doing it here
|
||||
func WrapError(err error) error {
|
||||
if err == nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return errors.Wrap(err, 0)
|
||||
}
|
||||
@@ -5,14 +5,12 @@ package commands
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/go-errors/errors"
|
||||
|
||||
"github.com/jesseduffield/pty"
|
||||
"github.com/mgutz/str"
|
||||
)
|
||||
|
||||
// RunCommandWithOutputLiveWrapper runs a command and return every word that gets written in stdout
|
||||
@@ -20,10 +18,7 @@ import (
|
||||
// As return of output you need to give a string that will be written to stdin
|
||||
// NOTE: If the return data is empty it won't written anything to stdin
|
||||
func RunCommandWithOutputLiveWrapper(c *OSCommand, command string, output func(string) string) error {
|
||||
splitCmd := str.ToArgv(command)
|
||||
cmd := c.command(splitCmd[0], splitCmd[1:]...)
|
||||
|
||||
cmd.Env = os.Environ()
|
||||
cmd := c.ExecutableFromString(command)
|
||||
cmd.Env = append(cmd.Env, "LANG=en_US.UTF-8", "LC_ALL=en_US.UTF-8")
|
||||
|
||||
var stderr bytes.Buffer
|
||||
|
||||
@@ -14,6 +14,7 @@ type File struct {
|
||||
HasInlineMergeConflicts bool
|
||||
DisplayString string
|
||||
Type string // one of 'file', 'directory', and 'other'
|
||||
ShortStatus string // e.g. 'AD', ' A', 'M ', '??'
|
||||
}
|
||||
|
||||
// GetDisplayStrings returns the display string of a file
|
||||
|
||||
@@ -25,18 +25,18 @@ func verifyInGitRepo(runCmd func(string) error) error {
|
||||
|
||||
func navigateToRepoRootDirectory(stat func(string) (os.FileInfo, error), chdir func(string) error) error {
|
||||
for {
|
||||
f, err := stat(".git")
|
||||
_, err := stat(".git")
|
||||
|
||||
if err == nil && f.IsDir() {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !os.IsNotExist(err) {
|
||||
return errors.Wrap(err, 0)
|
||||
return WrapError(err)
|
||||
}
|
||||
|
||||
if err = chdir(".."); err != nil {
|
||||
return errors.Wrap(err, 0)
|
||||
return WrapError(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,6 +72,7 @@ type GitCommand struct {
|
||||
getGlobalGitConfig func(string) (string, error)
|
||||
getLocalGitConfig func(string) (string, error)
|
||||
removeFile func(string) error
|
||||
DotGitDir string
|
||||
}
|
||||
|
||||
// NewGitCommand it runs git commands
|
||||
@@ -99,6 +100,11 @@ func NewGitCommand(log *logrus.Entry, osCommand *OSCommand, tr *i18n.Localizer,
|
||||
}
|
||||
}
|
||||
|
||||
dotGitDir, err := findDotGitDir(os.Stat, ioutil.ReadFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &GitCommand{
|
||||
Log: log,
|
||||
OSCommand: osCommand,
|
||||
@@ -109,10 +115,32 @@ func NewGitCommand(log *logrus.Entry, osCommand *OSCommand, tr *i18n.Localizer,
|
||||
getGlobalGitConfig: gitconfig.Global,
|
||||
getLocalGitConfig: gitconfig.Local,
|
||||
removeFile: os.RemoveAll,
|
||||
DotGitDir: dotGitDir,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetStashEntries stash entryies
|
||||
func findDotGitDir(stat func(string) (os.FileInfo, error), readFile func(filename string) ([]byte, error)) (string, error) {
|
||||
f, err := stat(".git")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if f.IsDir() {
|
||||
return ".git", nil
|
||||
}
|
||||
|
||||
fileBytes, err := readFile(".git")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
fileContent := string(fileBytes)
|
||||
if !strings.HasPrefix(fileContent, "gitdir: ") {
|
||||
return "", errors.New(".git is a file which suggests we are in a submodule but the file's contents do not contain a gitdir pointing to the actual .git directory")
|
||||
}
|
||||
return strings.TrimSpace(strings.TrimPrefix(fileContent, "gitdir: ")), nil
|
||||
}
|
||||
|
||||
// GetStashEntries stash entries
|
||||
func (c *GitCommand) GetStashEntries() []*StashEntry {
|
||||
rawString, _ := c.OSCommand.RunCommandWithOutput("git stash list --pretty='%gs'")
|
||||
stashEntries := []*StashEntry{}
|
||||
@@ -148,6 +176,8 @@ func (c *GitCommand) GetStatusFiles() []*File {
|
||||
filename := c.OSCommand.Unquote(statusString[3:])
|
||||
_, untracked := map[string]bool{"??": true, "A ": true, "AM": true}[change]
|
||||
_, hasNoStagedChanges := map[string]bool{" ": true, "U": true, "?": true}[stagedChange]
|
||||
hasMergeConflicts := change == "UU" || change == "AA" || change == "DU"
|
||||
hasInlineMergeConflicts := change == "UU" || change == "AA"
|
||||
|
||||
file := &File{
|
||||
Name: filename,
|
||||
@@ -156,9 +186,10 @@ func (c *GitCommand) GetStatusFiles() []*File {
|
||||
HasUnstagedChanges: unstagedChange != " ",
|
||||
Tracked: !untracked,
|
||||
Deleted: unstagedChange == "D" || stagedChange == "D",
|
||||
HasMergeConflicts: change == "UU" || change == "AA" || change == "DU",
|
||||
HasInlineMergeConflicts: change == "UU" || change == "AA",
|
||||
HasMergeConflicts: hasMergeConflicts,
|
||||
HasInlineMergeConflicts: hasInlineMergeConflicts,
|
||||
Type: c.OSCommand.FileType(filename),
|
||||
ShortStatus: change,
|
||||
}
|
||||
files = append(files, file)
|
||||
}
|
||||
@@ -217,11 +248,11 @@ func includesInt(list []int, a int) bool {
|
||||
|
||||
// ResetAndClean removes all unstaged changes and removes all untracked files
|
||||
func (c *GitCommand) ResetAndClean() error {
|
||||
if err := c.OSCommand.RunCommand("git reset --hard HEAD"); err != nil {
|
||||
if err := c.ResetHardHead(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.OSCommand.RunCommand("git clean -fd")
|
||||
return c.RemoveUntrackedFiles()
|
||||
}
|
||||
|
||||
func (c *GitCommand) GetCurrentBranchUpstreamDifferenceCount() (string, string) {
|
||||
@@ -274,8 +305,8 @@ func (c *GitCommand) Fetch(unamePassQuestion func(string) string, canAskForCrede
|
||||
}
|
||||
|
||||
// ResetToCommit reset to commit
|
||||
func (c *GitCommand) ResetToCommit(sha string) error {
|
||||
return c.OSCommand.RunCommand(fmt.Sprintf("git reset %s", sha))
|
||||
func (c *GitCommand) ResetToCommit(sha string, strength string) error {
|
||||
return c.OSCommand.RunCommand(fmt.Sprintf("git reset --%s %s", strength, sha))
|
||||
}
|
||||
|
||||
// NewBranch create new branch
|
||||
@@ -334,8 +365,8 @@ func (c *GitCommand) usingGpg() bool {
|
||||
}
|
||||
|
||||
// Commit commits to git
|
||||
func (c *GitCommand) Commit(message string) (*exec.Cmd, error) {
|
||||
command := fmt.Sprintf("git commit -m %s", c.OSCommand.Quote(message))
|
||||
func (c *GitCommand) Commit(message string, flags string) (*exec.Cmd, error) {
|
||||
command := fmt.Sprintf("git commit %s -m %s", flags, c.OSCommand.Quote(message))
|
||||
if c.usingGpg() {
|
||||
return c.OSCommand.PrepareSubProcess(c.OSCommand.Platform.shell, c.OSCommand.Platform.shellArg, command), nil
|
||||
}
|
||||
@@ -408,7 +439,7 @@ func (c *GitCommand) UnStageFile(fileName string, tracked bool) error {
|
||||
|
||||
// GitStatus returns the plaintext short status of the repo
|
||||
func (c *GitCommand) GitStatus() (string, error) {
|
||||
return c.OSCommand.RunCommandWithOutput("git status --untracked-files=all --short")
|
||||
return c.OSCommand.RunCommandWithOutput("git status --untracked-files=all --porcelain")
|
||||
}
|
||||
|
||||
// IsInMergeState states whether we are still mid-merge
|
||||
@@ -423,14 +454,14 @@ func (c *GitCommand) IsInMergeState() (bool, error) {
|
||||
// RebaseMode returns "" for non-rebase mode, "normal" for normal rebase
|
||||
// and "interactive" for interactive rebase
|
||||
func (c *GitCommand) RebaseMode() (string, error) {
|
||||
exists, err := c.OSCommand.FileExists(".git/rebase-apply")
|
||||
exists, err := c.OSCommand.FileExists(fmt.Sprintf("%s/rebase-apply", c.DotGitDir))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if exists {
|
||||
return "normal", nil
|
||||
}
|
||||
exists, err = c.OSCommand.FileExists(".git/rebase-merge")
|
||||
exists, err = c.OSCommand.FileExists(fmt.Sprintf("%s/rebase-merge", c.DotGitDir))
|
||||
if exists {
|
||||
return "interactive", err
|
||||
} else {
|
||||
@@ -438,19 +469,25 @@ func (c *GitCommand) RebaseMode() (string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveFile directly
|
||||
func (c *GitCommand) RemoveFile(file *File) error {
|
||||
// DiscardAllFileChanges directly
|
||||
func (c *GitCommand) DiscardAllFileChanges(file *File) error {
|
||||
// if the file isn't tracked, we assume you want to delete it
|
||||
quotedFileName := c.OSCommand.Quote(file.Name)
|
||||
if file.HasStagedChanges {
|
||||
if file.HasStagedChanges || file.HasMergeConflicts {
|
||||
if err := c.OSCommand.RunCommand(fmt.Sprintf("git reset -- %s", quotedFileName)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !file.Tracked {
|
||||
return c.removeFile(file.Name)
|
||||
}
|
||||
// if the file is tracked, we assume you want to just check it out
|
||||
return c.DiscardUnstagedFileChanges(file)
|
||||
}
|
||||
|
||||
// DiscardUnstagedFileChanges directly
|
||||
func (c *GitCommand) DiscardUnstagedFileChanges(file *File) error {
|
||||
quotedFileName := c.OSCommand.Quote(file.Name)
|
||||
return c.OSCommand.RunCommand(fmt.Sprintf("git checkout -- %s", quotedFileName))
|
||||
}
|
||||
|
||||
@@ -575,7 +612,7 @@ func (c *GitCommand) ApplyPatch(patch string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
defer func() { _ = c.OSCommand.RemoveFile(filename) }()
|
||||
defer func() { _ = c.OSCommand.Remove(filename) }()
|
||||
|
||||
return c.OSCommand.RunCommandWithOutput(fmt.Sprintf("git apply --cached %s", c.OSCommand.Quote(filename)))
|
||||
}
|
||||
@@ -588,7 +625,7 @@ func (c *GitCommand) FastForward(branchName string) error {
|
||||
func (c *GitCommand) RunSkipEditorCommand(command string) error {
|
||||
cmd := c.OSCommand.ExecutableFromString(command)
|
||||
cmd.Env = append(
|
||||
os.Environ(),
|
||||
cmd.Env,
|
||||
"LAZYGIT_CLIENT_COMMAND=EXIT_IMMEDIATELY",
|
||||
"EDITOR="+c.OSCommand.GetLazygitPath(),
|
||||
)
|
||||
@@ -608,12 +645,12 @@ func (c *GitCommand) GenericMerge(commandType string, command string) error {
|
||||
}
|
||||
|
||||
func (c *GitCommand) RewordCommit(commits []*Commit, index int) (*exec.Cmd, error) {
|
||||
todo, err := c.GenerateGenericRebaseTodo(commits, index, "reword")
|
||||
todo, sha, err := c.GenerateGenericRebaseTodo(commits, index, "reword")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c.PrepareInteractiveRebaseCommand(commits[index+1].Sha, todo, false)
|
||||
return c.PrepareInteractiveRebaseCommand(sha, todo, false)
|
||||
}
|
||||
|
||||
func (c *GitCommand) MoveCommitDown(commits []*Commit, index int) error {
|
||||
@@ -638,12 +675,12 @@ func (c *GitCommand) MoveCommitDown(commits []*Commit, index int) error {
|
||||
}
|
||||
|
||||
func (c *GitCommand) InteractiveRebase(commits []*Commit, index int, action string) error {
|
||||
todo, err := c.GenerateGenericRebaseTodo(commits, index, action)
|
||||
todo, sha, err := c.GenerateGenericRebaseTodo(commits, index, action)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd, err := c.PrepareInteractiveRebaseCommand(commits[index+1].Sha, todo, true)
|
||||
cmd, err := c.PrepareInteractiveRebaseCommand(sha, todo, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -658,7 +695,7 @@ func (c *GitCommand) PrepareInteractiveRebaseCommand(baseSha string, todo string
|
||||
ex := c.OSCommand.GetLazygitPath()
|
||||
|
||||
debug := "FALSE"
|
||||
if c.OSCommand.Config.GetDebug() == true {
|
||||
if c.OSCommand.Config.GetDebug() {
|
||||
debug = "TRUE"
|
||||
}
|
||||
|
||||
@@ -697,38 +734,45 @@ func (c *GitCommand) SoftReset(baseSha string) error {
|
||||
return c.OSCommand.RunCommand("git reset --soft " + baseSha)
|
||||
}
|
||||
|
||||
func (c *GitCommand) GenerateGenericRebaseTodo(commits []*Commit, index int, action string) (string, error) {
|
||||
if len(commits) <= index+1 {
|
||||
// assuming they aren't picking the bottom commit
|
||||
return "", errors.New(c.Tr.SLocalize("CannotRebaseOntoFirstCommit"))
|
||||
func (c *GitCommand) GenerateGenericRebaseTodo(commits []*Commit, actionIndex int, action string) (string, string, error) {
|
||||
baseIndex := actionIndex + 1
|
||||
|
||||
if len(commits) <= baseIndex {
|
||||
return "", "", errors.New(c.Tr.SLocalize("CannotRebaseOntoFirstCommit"))
|
||||
}
|
||||
|
||||
if action == "squash" || action == "fixup" {
|
||||
baseIndex++
|
||||
|
||||
if len(commits) <= baseIndex {
|
||||
return "", "", errors.New(c.Tr.SLocalize("CannotSquashOntoSecondCommit"))
|
||||
}
|
||||
}
|
||||
|
||||
todo := ""
|
||||
for i, commit := range commits[0 : index+1] {
|
||||
for i, commit := range commits[0:baseIndex] {
|
||||
a := "pick"
|
||||
if i == index {
|
||||
if i == actionIndex {
|
||||
a = action
|
||||
}
|
||||
todo = a + " " + commit.Sha + " " + commit.Name + "\n" + todo
|
||||
}
|
||||
return todo, nil
|
||||
|
||||
return todo, commits[baseIndex].Sha, nil
|
||||
}
|
||||
|
||||
// AmendTo amends the given commit with whatever files are staged
|
||||
func (c *GitCommand) AmendTo(sha string) error {
|
||||
if err := c.OSCommand.RunCommand(fmt.Sprintf("git commit --fixup=%s", sha)); err != nil {
|
||||
if err := c.CreateFixupCommit(sha); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.RunSkipEditorCommand(
|
||||
fmt.Sprintf(
|
||||
"git rebase --interactive --autostash --autosquash %s^", sha,
|
||||
),
|
||||
)
|
||||
|
||||
return c.SquashAllAboveFixupCommits(sha)
|
||||
}
|
||||
|
||||
// EditRebaseTodo sets the action at a given index in the git-rebase-todo file
|
||||
func (c *GitCommand) EditRebaseTodo(index int, action string) error {
|
||||
fileName := ".git/rebase-merge/git-rebase-todo"
|
||||
fileName := fmt.Sprintf("%s/rebase-merge/git-rebase-todo", c.DotGitDir)
|
||||
bytes, err := ioutil.ReadFile(fileName)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -760,7 +804,7 @@ func (c *GitCommand) getTodoCommitCount(content []string) int {
|
||||
|
||||
// MoveTodoDown moves a rebase todo item down by one position
|
||||
func (c *GitCommand) MoveTodoDown(index int) error {
|
||||
fileName := ".git/rebase-merge/git-rebase-todo"
|
||||
fileName := fmt.Sprintf("%s/rebase-merge/git-rebase-todo", c.DotGitDir)
|
||||
bytes, err := ioutil.ReadFile(fileName)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -796,3 +840,169 @@ func (c *GitCommand) CherryPickCommits(commits []*Commit) error {
|
||||
|
||||
return c.OSCommand.RunPreparedCommand(cmd)
|
||||
}
|
||||
|
||||
// GetCommitFiles get the specified commit files
|
||||
func (c *GitCommand) GetCommitFiles(commitSha string) ([]*CommitFile, error) {
|
||||
cmd := fmt.Sprintf("git show --pretty= --name-only %s", commitSha)
|
||||
files, err := c.OSCommand.RunCommandWithOutput(cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
commitFiles := make([]*CommitFile, 0)
|
||||
|
||||
for _, file := range strings.Split(strings.TrimRight(files, "\n"), "\n") {
|
||||
commitFiles = append(commitFiles, &CommitFile{
|
||||
Sha: commitSha,
|
||||
Name: file,
|
||||
DisplayString: file,
|
||||
})
|
||||
}
|
||||
|
||||
return commitFiles, nil
|
||||
}
|
||||
|
||||
// ShowCommitFile get the diff of specified commit file
|
||||
func (c *GitCommand) ShowCommitFile(commitSha, fileName string) (string, error) {
|
||||
cmd := fmt.Sprintf("git show --color %s -- %s", commitSha, fileName)
|
||||
return c.OSCommand.RunCommandWithOutput(cmd)
|
||||
}
|
||||
|
||||
// CheckoutFile checks out the file for the given commit
|
||||
func (c *GitCommand) CheckoutFile(commitSha, fileName string) error {
|
||||
cmd := fmt.Sprintf("git checkout %s %s", commitSha, fileName)
|
||||
return c.OSCommand.RunCommand(cmd)
|
||||
}
|
||||
|
||||
// DiscardOldFileChanges discards changes to a file from an old commit
|
||||
func (c *GitCommand) DiscardOldFileChanges(commits []*Commit, commitIndex int, fileName string) error {
|
||||
if len(commits)-1 < commitIndex {
|
||||
return errors.New("index outside of range of commits")
|
||||
}
|
||||
|
||||
// we can make this GPG thing possible it just means we need to do this in two parts:
|
||||
// one where we handle the possibility of a credential request, and the other
|
||||
// where we continue the rebase
|
||||
if c.usingGpg() {
|
||||
return errors.New(c.Tr.SLocalize("DisabledForGPG"))
|
||||
}
|
||||
|
||||
todo, sha, err := c.GenerateGenericRebaseTodo(commits, commitIndex, "edit")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd, err := c.PrepareInteractiveRebaseCommand(sha, todo, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.OSCommand.RunPreparedCommand(cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if file exists in previous commit (this command returns an error if the file doesn't exist)
|
||||
if err := c.OSCommand.RunCommand(fmt.Sprintf("git cat-file -e HEAD^:%s", fileName)); err != nil {
|
||||
if err := c.OSCommand.Remove(fileName); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.StageFile(fileName); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err := c.CheckoutFile("HEAD^", fileName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// amend the commit
|
||||
cmd, err = c.AmendHead()
|
||||
if cmd != nil {
|
||||
return errors.New("received unexpected pointer to cmd")
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// continue
|
||||
return c.GenericMerge("rebase", "continue")
|
||||
}
|
||||
|
||||
// DiscardAnyUnstagedFileChanges discards any unstages file changes via `git checkout -- .`
|
||||
func (c *GitCommand) DiscardAnyUnstagedFileChanges() error {
|
||||
return c.OSCommand.RunCommand("git checkout -- .")
|
||||
}
|
||||
|
||||
// RemoveUntrackedFiles runs `git clean -fd`
|
||||
func (c *GitCommand) RemoveUntrackedFiles() error {
|
||||
return c.OSCommand.RunCommand("git clean -fd")
|
||||
}
|
||||
|
||||
// ResetHardHead runs `git reset --hard HEAD`
|
||||
func (c *GitCommand) ResetHardHead() error {
|
||||
return c.OSCommand.RunCommand("git reset --hard HEAD")
|
||||
}
|
||||
|
||||
// ResetSoftHead runs `git reset --soft HEAD`
|
||||
func (c *GitCommand) ResetSoftHead() error {
|
||||
return c.OSCommand.RunCommand("git reset --soft HEAD")
|
||||
}
|
||||
|
||||
// DiffCommits show diff between commits
|
||||
func (c *GitCommand) DiffCommits(sha1, sha2 string) (string, error) {
|
||||
cmd := fmt.Sprintf("git diff --color %s %s", sha1, sha2)
|
||||
return c.OSCommand.RunCommandWithOutput(cmd)
|
||||
}
|
||||
|
||||
// CreateFixupCommit creates a commit that fixes up a previous commit
|
||||
func (c *GitCommand) CreateFixupCommit(sha string) error {
|
||||
cmd := fmt.Sprintf("git commit --fixup=%s", sha)
|
||||
return c.OSCommand.RunCommand(cmd)
|
||||
}
|
||||
|
||||
// SquashAllAboveFixupCommits squashes all fixup! commits above the given one
|
||||
func (c *GitCommand) SquashAllAboveFixupCommits(sha string) error {
|
||||
return c.RunSkipEditorCommand(
|
||||
fmt.Sprintf(
|
||||
"git rebase --interactive --autostash --autosquash %s^",
|
||||
sha,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// StashSaveStagedChanges stashes only the currently staged changes. This takes a few steps
|
||||
// shoutouts to Joe on https://stackoverflow.com/questions/14759748/stashing-only-staged-changes-in-git-is-it-possible
|
||||
func (c *GitCommand) StashSaveStagedChanges(message string) error {
|
||||
|
||||
if err := c.OSCommand.RunCommand("git stash --keep-index"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.StashSave(message); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.OSCommand.RunCommand("git stash apply stash@{1}"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.OSCommand.PipeCommands("git stash show -p", "git apply -R"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.OSCommand.RunCommand("git stash drop stash@{1}"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if you had staged an untracked file, that will now appear as 'AD' in git status
|
||||
// meaning it's deleted in your working tree but added in your index. Given that it's
|
||||
// now safely stashed, we need to remove it.
|
||||
files := c.GetStatusFiles()
|
||||
for _, file := range files {
|
||||
if file.ShortStatus == "AD" {
|
||||
if err := c.UnStageFile(file.Name, false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/jesseduffield/lazygit/pkg/i18n"
|
||||
"github.com/jesseduffield/lazygit/pkg/test"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -355,52 +356,72 @@ func TestGitCommandGetStatusFiles(t *testing.T) {
|
||||
func(cmd string, args ...string) *exec.Cmd {
|
||||
return exec.Command(
|
||||
"echo",
|
||||
"MM file1.txt\nA file3.txt\nAM file2.txt\n?? file4.txt",
|
||||
"MM file1.txt\nA file3.txt\nAM file2.txt\n?? file4.txt\nUU file5.txt",
|
||||
)
|
||||
},
|
||||
func(files []*File) {
|
||||
assert.Len(t, files, 4)
|
||||
assert.Len(t, files, 5)
|
||||
|
||||
expected := []*File{
|
||||
{
|
||||
Name: "file1.txt",
|
||||
HasStagedChanges: true,
|
||||
HasUnstagedChanges: true,
|
||||
Tracked: true,
|
||||
Deleted: false,
|
||||
HasMergeConflicts: false,
|
||||
DisplayString: "MM file1.txt",
|
||||
Type: "other",
|
||||
Name: "file1.txt",
|
||||
HasStagedChanges: true,
|
||||
HasUnstagedChanges: true,
|
||||
Tracked: true,
|
||||
Deleted: false,
|
||||
HasMergeConflicts: false,
|
||||
HasInlineMergeConflicts: false,
|
||||
DisplayString: "MM file1.txt",
|
||||
Type: "other",
|
||||
ShortStatus: "MM",
|
||||
},
|
||||
{
|
||||
Name: "file3.txt",
|
||||
HasStagedChanges: true,
|
||||
HasUnstagedChanges: false,
|
||||
Tracked: false,
|
||||
Deleted: false,
|
||||
HasMergeConflicts: false,
|
||||
DisplayString: "A file3.txt",
|
||||
Type: "other",
|
||||
Name: "file3.txt",
|
||||
HasStagedChanges: true,
|
||||
HasUnstagedChanges: false,
|
||||
Tracked: false,
|
||||
Deleted: false,
|
||||
HasMergeConflicts: false,
|
||||
HasInlineMergeConflicts: false,
|
||||
DisplayString: "A file3.txt",
|
||||
Type: "other",
|
||||
ShortStatus: "A ",
|
||||
},
|
||||
{
|
||||
Name: "file2.txt",
|
||||
HasStagedChanges: true,
|
||||
HasUnstagedChanges: true,
|
||||
Tracked: false,
|
||||
Deleted: false,
|
||||
HasMergeConflicts: false,
|
||||
DisplayString: "AM file2.txt",
|
||||
Type: "other",
|
||||
Name: "file2.txt",
|
||||
HasStagedChanges: true,
|
||||
HasUnstagedChanges: true,
|
||||
Tracked: false,
|
||||
Deleted: false,
|
||||
HasMergeConflicts: false,
|
||||
HasInlineMergeConflicts: false,
|
||||
DisplayString: "AM file2.txt",
|
||||
Type: "other",
|
||||
ShortStatus: "AM",
|
||||
},
|
||||
{
|
||||
Name: "file4.txt",
|
||||
HasStagedChanges: false,
|
||||
HasUnstagedChanges: true,
|
||||
Tracked: false,
|
||||
Deleted: false,
|
||||
HasMergeConflicts: false,
|
||||
DisplayString: "?? file4.txt",
|
||||
Type: "other",
|
||||
Name: "file4.txt",
|
||||
HasStagedChanges: false,
|
||||
HasUnstagedChanges: true,
|
||||
Tracked: false,
|
||||
Deleted: false,
|
||||
HasMergeConflicts: false,
|
||||
HasInlineMergeConflicts: false,
|
||||
DisplayString: "?? file4.txt",
|
||||
Type: "other",
|
||||
ShortStatus: "??",
|
||||
},
|
||||
{
|
||||
Name: "file5.txt",
|
||||
HasStagedChanges: false,
|
||||
HasUnstagedChanges: true,
|
||||
Tracked: true,
|
||||
Deleted: false,
|
||||
HasMergeConflicts: true,
|
||||
HasInlineMergeConflicts: true,
|
||||
DisplayString: "UU file5.txt",
|
||||
Type: "other",
|
||||
ShortStatus: "UU",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -616,12 +637,12 @@ func TestGitCommandResetToCommit(t *testing.T) {
|
||||
gitCmd := NewDummyGitCommand()
|
||||
gitCmd.OSCommand.command = func(cmd string, args ...string) *exec.Cmd {
|
||||
assert.EqualValues(t, "git", cmd)
|
||||
assert.EqualValues(t, []string{"reset", "78976bc"}, args)
|
||||
assert.EqualValues(t, []string{"reset", "--hard", "78976bc"}, args)
|
||||
|
||||
return exec.Command("echo")
|
||||
}
|
||||
|
||||
assert.NoError(t, gitCmd.ResetToCommit("78976bc"))
|
||||
assert.NoError(t, gitCmd.ResetToCommit("78976bc", "hard"))
|
||||
}
|
||||
|
||||
// TestGitCommandNewBranch is a function.
|
||||
@@ -801,6 +822,7 @@ func TestGitCommandCommit(t *testing.T) {
|
||||
command func(string, ...string) *exec.Cmd
|
||||
getGlobalGitConfig func(string) (string, error)
|
||||
test func(*exec.Cmd, error)
|
||||
flags string
|
||||
}
|
||||
|
||||
scenarios := []scenario{
|
||||
@@ -808,7 +830,7 @@ func TestGitCommandCommit(t *testing.T) {
|
||||
"Commit using gpg",
|
||||
func(cmd string, args ...string) *exec.Cmd {
|
||||
assert.EqualValues(t, "bash", cmd)
|
||||
assert.EqualValues(t, []string{"-c", `git commit -m 'test'`}, args)
|
||||
assert.EqualValues(t, []string{"-c", `git commit -m 'test'`}, args)
|
||||
|
||||
return exec.Command("echo")
|
||||
},
|
||||
@@ -819,6 +841,7 @@ func TestGitCommandCommit(t *testing.T) {
|
||||
assert.NotNil(t, cmd)
|
||||
assert.Nil(t, err)
|
||||
},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"Commit without using gpg",
|
||||
@@ -835,6 +858,24 @@ func TestGitCommandCommit(t *testing.T) {
|
||||
assert.Nil(t, cmd)
|
||||
assert.Nil(t, err)
|
||||
},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"Commit with --no-verify flag",
|
||||
func(cmd string, args ...string) *exec.Cmd {
|
||||
assert.EqualValues(t, "git", cmd)
|
||||
assert.EqualValues(t, []string{"commit", "--no-verify", "-m", "test"}, args)
|
||||
|
||||
return exec.Command("echo")
|
||||
},
|
||||
func(string) (string, error) {
|
||||
return "false", nil
|
||||
},
|
||||
func(cmd *exec.Cmd, err error) {
|
||||
assert.Nil(t, cmd)
|
||||
assert.Nil(t, err)
|
||||
},
|
||||
"--no-verify",
|
||||
},
|
||||
{
|
||||
"Commit without using gpg with an error",
|
||||
@@ -851,6 +892,7 @@ func TestGitCommandCommit(t *testing.T) {
|
||||
assert.Nil(t, cmd)
|
||||
assert.Error(t, err)
|
||||
},
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -859,7 +901,7 @@ func TestGitCommandCommit(t *testing.T) {
|
||||
gitCmd := NewDummyGitCommand()
|
||||
gitCmd.getGlobalGitConfig = s.getGlobalGitConfig
|
||||
gitCmd.OSCommand.command = s.command
|
||||
s.test(gitCmd.Commit("test"))
|
||||
s.test(gitCmd.Commit("test", s.flags))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1140,8 +1182,8 @@ func TestGitCommandIsInMergeState(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestGitCommandRemoveFile is a function.
|
||||
func TestGitCommandRemoveFile(t *testing.T) {
|
||||
// TestGitCommandDiscardAllFileChanges is a function.
|
||||
func TestGitCommandDiscardAllFileChanges(t *testing.T) {
|
||||
type scenario struct {
|
||||
testName string
|
||||
command func() (func(string, ...string) *exec.Cmd, *[][]string)
|
||||
@@ -1252,7 +1294,7 @@ func TestGitCommandRemoveFile(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
"Reset and checkout",
|
||||
"Reset and checkout staged changes",
|
||||
func() (func(string, ...string) *exec.Cmd, *[][]string) {
|
||||
cmdsCalled := [][]string{}
|
||||
return func(cmd string, args ...string) *exec.Cmd {
|
||||
@@ -1278,6 +1320,33 @@ func TestGitCommandRemoveFile(t *testing.T) {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
"Reset and checkout merge conflicts",
|
||||
func() (func(string, ...string) *exec.Cmd, *[][]string) {
|
||||
cmdsCalled := [][]string{}
|
||||
return func(cmd string, args ...string) *exec.Cmd {
|
||||
cmdsCalled = append(cmdsCalled, args)
|
||||
|
||||
return exec.Command("echo")
|
||||
}, &cmdsCalled
|
||||
},
|
||||
func(cmdsCalled *[][]string, err error) {
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, *cmdsCalled, 2)
|
||||
assert.EqualValues(t, *cmdsCalled, [][]string{
|
||||
{"reset", "--", "test"},
|
||||
{"checkout", "--", "test"},
|
||||
})
|
||||
},
|
||||
&File{
|
||||
Name: "test",
|
||||
Tracked: true,
|
||||
HasMergeConflicts: true,
|
||||
},
|
||||
func(string) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
"Reset and remove",
|
||||
func() (func(string, ...string) *exec.Cmd, *[][]string) {
|
||||
@@ -1337,7 +1406,7 @@ func TestGitCommandRemoveFile(t *testing.T) {
|
||||
gitCmd := NewDummyGitCommand()
|
||||
gitCmd.OSCommand.command, cmdsCalled = s.command()
|
||||
gitCmd.removeFile = s.removeFile
|
||||
s.test(cmdsCalled, gitCmd.RemoveFile(s.file))
|
||||
s.test(cmdsCalled, gitCmd.DiscardAllFileChanges(s.file))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1707,7 +1776,472 @@ func TestGitCommandRebaseBranch(t *testing.T) {
|
||||
gitCmd := NewDummyGitCommand()
|
||||
|
||||
for _, s := range scenarios {
|
||||
gitCmd.OSCommand.command = s.command
|
||||
s.test(gitCmd.RebaseBranch(s.arg))
|
||||
t.Run(s.testName, func(t *testing.T) {
|
||||
gitCmd.OSCommand.command = s.command
|
||||
s.test(gitCmd.RebaseBranch(s.arg))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestGitCommandCheckoutFile is a function.
|
||||
func TestGitCommandCheckoutFile(t *testing.T) {
|
||||
type scenario struct {
|
||||
testName string
|
||||
commitSha string
|
||||
fileName string
|
||||
command func(string, ...string) *exec.Cmd
|
||||
test func(error)
|
||||
}
|
||||
|
||||
scenarios := []scenario{
|
||||
{
|
||||
"typical case",
|
||||
"11af912",
|
||||
"test999.txt",
|
||||
test.CreateMockCommand(t, []*test.CommandSwapper{
|
||||
{
|
||||
Expect: "git checkout 11af912 test999.txt",
|
||||
Replace: "echo",
|
||||
},
|
||||
}),
|
||||
func(err error) {
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
},
|
||||
{
|
||||
"returns error if there is one",
|
||||
"11af912",
|
||||
"test999.txt",
|
||||
test.CreateMockCommand(t, []*test.CommandSwapper{
|
||||
{
|
||||
Expect: "git checkout 11af912 test999.txt",
|
||||
Replace: "test",
|
||||
},
|
||||
}),
|
||||
func(err error) {
|
||||
assert.Error(t, err)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
gitCmd := NewDummyGitCommand()
|
||||
|
||||
for _, s := range scenarios {
|
||||
t.Run(s.testName, func(t *testing.T) {
|
||||
gitCmd.OSCommand.command = s.command
|
||||
s.test(gitCmd.CheckoutFile(s.commitSha, s.fileName))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestGitCommandDiscardOldFileChanges is a function.
|
||||
func TestGitCommandDiscardOldFileChanges(t *testing.T) {
|
||||
type scenario struct {
|
||||
testName string
|
||||
getLocalGitConfig func(string) (string, error)
|
||||
commits []*Commit
|
||||
commitIndex int
|
||||
fileName string
|
||||
command func(string, ...string) *exec.Cmd
|
||||
test func(error)
|
||||
}
|
||||
|
||||
scenarios := []scenario{
|
||||
{
|
||||
"returns error when index outside of range of commits",
|
||||
func(string) (string, error) {
|
||||
return "", nil
|
||||
},
|
||||
[]*Commit{},
|
||||
0,
|
||||
"test999.txt",
|
||||
nil,
|
||||
func(err error) {
|
||||
assert.Error(t, err)
|
||||
},
|
||||
},
|
||||
{
|
||||
"returns error when using gpg",
|
||||
func(string) (string, error) {
|
||||
return "true", nil
|
||||
},
|
||||
[]*Commit{{Name: "commit", Sha: "123456"}},
|
||||
0,
|
||||
"test999.txt",
|
||||
nil,
|
||||
func(err error) {
|
||||
assert.Error(t, err)
|
||||
},
|
||||
},
|
||||
{
|
||||
"checks out file if it already existed",
|
||||
func(string) (string, error) {
|
||||
return "", nil
|
||||
},
|
||||
[]*Commit{
|
||||
{Name: "commit", Sha: "123456"},
|
||||
{Name: "commit2", Sha: "abcdef"},
|
||||
},
|
||||
0,
|
||||
"test999.txt",
|
||||
test.CreateMockCommand(t, []*test.CommandSwapper{
|
||||
{
|
||||
Expect: "git rebase --interactive --autostash abcdef",
|
||||
Replace: "echo",
|
||||
},
|
||||
{
|
||||
Expect: "git cat-file -e HEAD^:test999.txt",
|
||||
Replace: "echo",
|
||||
},
|
||||
{
|
||||
Expect: "git checkout HEAD^ test999.txt",
|
||||
Replace: "echo",
|
||||
},
|
||||
{
|
||||
Expect: "git commit --amend --no-edit",
|
||||
Replace: "echo",
|
||||
},
|
||||
{
|
||||
Expect: "git rebase --continue",
|
||||
Replace: "echo",
|
||||
},
|
||||
}),
|
||||
func(err error) {
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
},
|
||||
// test for when the file was created within the commit requires a refactor to support proper mocks
|
||||
// currently we'd need to mock out the os.Remove function and that's gonna introduce tech debt
|
||||
}
|
||||
|
||||
gitCmd := NewDummyGitCommand()
|
||||
|
||||
for _, s := range scenarios {
|
||||
t.Run(s.testName, func(t *testing.T) {
|
||||
gitCmd.OSCommand.command = s.command
|
||||
gitCmd.getLocalGitConfig = s.getLocalGitConfig
|
||||
s.test(gitCmd.DiscardOldFileChanges(s.commits, s.commitIndex, s.fileName))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestGitCommandShowCommitFile is a function.
|
||||
func TestGitCommandShowCommitFile(t *testing.T) {
|
||||
type scenario struct {
|
||||
testName string
|
||||
commitSha string
|
||||
fileName string
|
||||
command func(string, ...string) *exec.Cmd
|
||||
test func(string, error)
|
||||
}
|
||||
|
||||
scenarios := []scenario{
|
||||
{
|
||||
"valid case",
|
||||
"123456",
|
||||
"hello.txt",
|
||||
test.CreateMockCommand(t, []*test.CommandSwapper{
|
||||
{
|
||||
Expect: "git show --color 123456 -- hello.txt",
|
||||
Replace: "echo -n hello",
|
||||
},
|
||||
}),
|
||||
func(str string, err error) {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "hello", str)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
gitCmd := NewDummyGitCommand()
|
||||
|
||||
for _, s := range scenarios {
|
||||
t.Run(s.testName, func(t *testing.T) {
|
||||
gitCmd.OSCommand.command = s.command
|
||||
s.test(gitCmd.ShowCommitFile(s.commitSha, s.fileName))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestGitCommandGetCommitFiles is a function.
|
||||
func TestGitCommandGetCommitFiles(t *testing.T) {
|
||||
type scenario struct {
|
||||
testName string
|
||||
commitSha string
|
||||
command func(string, ...string) *exec.Cmd
|
||||
test func([]*CommitFile, error)
|
||||
}
|
||||
|
||||
scenarios := []scenario{
|
||||
{
|
||||
"valid case",
|
||||
"123456",
|
||||
test.CreateMockCommand(t, []*test.CommandSwapper{
|
||||
{
|
||||
Expect: "git show --pretty= --name-only 123456",
|
||||
Replace: "echo 'hello\nworld'",
|
||||
},
|
||||
}),
|
||||
func(commitFiles []*CommitFile, err error) {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []*CommitFile{
|
||||
{Sha: "123456", Name: "hello", DisplayString: "hello"},
|
||||
{Sha: "123456", Name: "world", DisplayString: "world"},
|
||||
}, commitFiles)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
gitCmd := NewDummyGitCommand()
|
||||
|
||||
for _, s := range scenarios {
|
||||
t.Run(s.testName, func(t *testing.T) {
|
||||
gitCmd.OSCommand.command = s.command
|
||||
s.test(gitCmd.GetCommitFiles(s.commitSha))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestGitCommandDiscardUnstagedFileChanges is a function.
|
||||
func TestGitCommandDiscardUnstagedFileChanges(t *testing.T) {
|
||||
type scenario struct {
|
||||
testName string
|
||||
file *File
|
||||
command func(string, ...string) *exec.Cmd
|
||||
test func(error)
|
||||
}
|
||||
|
||||
scenarios := []scenario{
|
||||
{
|
||||
"valid case",
|
||||
&File{Name: "test.txt"},
|
||||
test.CreateMockCommand(t, []*test.CommandSwapper{
|
||||
{
|
||||
Expect: `git checkout -- "test.txt"`,
|
||||
Replace: "echo",
|
||||
},
|
||||
}),
|
||||
func(err error) {
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
gitCmd := NewDummyGitCommand()
|
||||
|
||||
for _, s := range scenarios {
|
||||
t.Run(s.testName, func(t *testing.T) {
|
||||
gitCmd.OSCommand.command = s.command
|
||||
s.test(gitCmd.DiscardUnstagedFileChanges(s.file))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestGitCommandDiscardAnyUnstagedFileChanges is a function.
|
||||
func TestGitCommandDiscardAnyUnstagedFileChanges(t *testing.T) {
|
||||
type scenario struct {
|
||||
testName string
|
||||
command func(string, ...string) *exec.Cmd
|
||||
test func(error)
|
||||
}
|
||||
|
||||
scenarios := []scenario{
|
||||
{
|
||||
"valid case",
|
||||
test.CreateMockCommand(t, []*test.CommandSwapper{
|
||||
{
|
||||
Expect: `git checkout -- .`,
|
||||
Replace: "echo",
|
||||
},
|
||||
}),
|
||||
func(err error) {
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
gitCmd := NewDummyGitCommand()
|
||||
|
||||
for _, s := range scenarios {
|
||||
t.Run(s.testName, func(t *testing.T) {
|
||||
gitCmd.OSCommand.command = s.command
|
||||
s.test(gitCmd.DiscardAnyUnstagedFileChanges())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestGitCommandRemoveUntrackedFiles is a function.
|
||||
func TestGitCommandRemoveUntrackedFiles(t *testing.T) {
|
||||
type scenario struct {
|
||||
testName string
|
||||
command func(string, ...string) *exec.Cmd
|
||||
test func(error)
|
||||
}
|
||||
|
||||
scenarios := []scenario{
|
||||
{
|
||||
"valid case",
|
||||
test.CreateMockCommand(t, []*test.CommandSwapper{
|
||||
{
|
||||
Expect: `git clean -fd`,
|
||||
Replace: "echo",
|
||||
},
|
||||
}),
|
||||
func(err error) {
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
gitCmd := NewDummyGitCommand()
|
||||
|
||||
for _, s := range scenarios {
|
||||
t.Run(s.testName, func(t *testing.T) {
|
||||
gitCmd.OSCommand.command = s.command
|
||||
s.test(gitCmd.RemoveUntrackedFiles())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestGitCommandResetHardHead is a function.
|
||||
func TestGitCommandResetHardHead(t *testing.T) {
|
||||
type scenario struct {
|
||||
testName string
|
||||
command func(string, ...string) *exec.Cmd
|
||||
test func(error)
|
||||
}
|
||||
|
||||
scenarios := []scenario{
|
||||
{
|
||||
"valid case",
|
||||
test.CreateMockCommand(t, []*test.CommandSwapper{
|
||||
{
|
||||
Expect: `git reset --hard HEAD`,
|
||||
Replace: "echo",
|
||||
},
|
||||
}),
|
||||
func(err error) {
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
gitCmd := NewDummyGitCommand()
|
||||
|
||||
for _, s := range scenarios {
|
||||
t.Run(s.testName, func(t *testing.T) {
|
||||
gitCmd.OSCommand.command = s.command
|
||||
s.test(gitCmd.ResetHardHead())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestGitCommandCreateFixupCommit is a function.
|
||||
func TestGitCommandCreateFixupCommit(t *testing.T) {
|
||||
type scenario struct {
|
||||
testName string
|
||||
sha string
|
||||
command func(string, ...string) *exec.Cmd
|
||||
test func(error)
|
||||
}
|
||||
|
||||
scenarios := []scenario{
|
||||
{
|
||||
"valid case",
|
||||
"12345",
|
||||
test.CreateMockCommand(t, []*test.CommandSwapper{
|
||||
{
|
||||
Expect: `git commit --fixup=12345`,
|
||||
Replace: "echo",
|
||||
},
|
||||
}),
|
||||
func(err error) {
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
gitCmd := NewDummyGitCommand()
|
||||
|
||||
for _, s := range scenarios {
|
||||
t.Run(s.testName, func(t *testing.T) {
|
||||
gitCmd.OSCommand.command = s.command
|
||||
s.test(gitCmd.CreateFixupCommit(s.sha))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFindDotGitDir(t *testing.T) {
|
||||
type scenario struct {
|
||||
testName string
|
||||
stat func(string) (os.FileInfo, error)
|
||||
readFile func(filename string) ([]byte, error)
|
||||
test func(string, error)
|
||||
}
|
||||
|
||||
scenarios := []scenario{
|
||||
{
|
||||
".git is a directory",
|
||||
func(dotGit string) (os.FileInfo, error) {
|
||||
assert.Equal(t, ".git", dotGit)
|
||||
return os.Stat("testdata/a_dir")
|
||||
},
|
||||
func(dotGit string) ([]byte, error) {
|
||||
assert.Fail(t, "readFile should not be called if .git is a directory")
|
||||
return nil, nil
|
||||
},
|
||||
func(gitDir string, err error) {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, ".git", gitDir)
|
||||
},
|
||||
},
|
||||
{
|
||||
".git is a file",
|
||||
func(dotGit string) (os.FileInfo, error) {
|
||||
assert.Equal(t, ".git", dotGit)
|
||||
return os.Stat("testdata/a_file")
|
||||
},
|
||||
func(dotGit string) ([]byte, error) {
|
||||
assert.Equal(t, ".git", dotGit)
|
||||
return []byte("gitdir: blah\n"), nil
|
||||
},
|
||||
func(gitDir string, err error) {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "blah", gitDir)
|
||||
},
|
||||
},
|
||||
{
|
||||
"os.Stat returns an error",
|
||||
func(dotGit string) (os.FileInfo, error) {
|
||||
assert.Equal(t, ".git", dotGit)
|
||||
return nil, errors.New("error")
|
||||
},
|
||||
func(dotGit string) ([]byte, error) {
|
||||
assert.Fail(t, "readFile should not be called os.Stat returns an error")
|
||||
return nil, nil
|
||||
},
|
||||
func(gitDir string, err error) {
|
||||
assert.Error(t, err)
|
||||
},
|
||||
},
|
||||
{
|
||||
"readFile returns an error",
|
||||
func(dotGit string) (os.FileInfo, error) {
|
||||
assert.Equal(t, ".git", dotGit)
|
||||
return os.Stat("testdata/a_file")
|
||||
},
|
||||
func(dotGit string) ([]byte, error) {
|
||||
return nil, errors.New("error")
|
||||
},
|
||||
func(gitDir string, err error) {
|
||||
assert.Error(t, err)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, s := range scenarios {
|
||||
t.Run(s.testName, func(t *testing.T) {
|
||||
s.test(findDotGitDir(s.stat, s.readFile))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/go-errors/errors"
|
||||
|
||||
@@ -77,8 +78,9 @@ func (c *OSCommand) RunExecutable(cmd *exec.Cmd) error {
|
||||
// ExecutableFromString takes a string like `git status` and returns an executable command for it
|
||||
func (c *OSCommand) ExecutableFromString(commandStr string) *exec.Cmd {
|
||||
splitCmd := str.ToArgv(commandStr)
|
||||
c.Log.Info(splitCmd)
|
||||
return c.command(splitCmd[0], splitCmd[1:]...)
|
||||
cmd := c.command(splitCmd[0], splitCmd[1:]...)
|
||||
cmd.Env = append(os.Environ(), "GIT_OPTIONAL_LOCKS=0")
|
||||
return cmd
|
||||
}
|
||||
|
||||
// RunCommandWithOutputLive runs RunCommandWithOutputLiveWrapper
|
||||
@@ -145,7 +147,7 @@ func sanitisedCommandOutput(output []byte, err error) (string, error) {
|
||||
// errors like 'exit status 1' are not very useful so we'll create an error
|
||||
// from the combined output
|
||||
if outputString == "" {
|
||||
return "", errors.Wrap(err, 0)
|
||||
return "", WrapError(err)
|
||||
}
|
||||
return outputString, errors.New(outputString)
|
||||
}
|
||||
@@ -200,8 +202,13 @@ func (c *OSCommand) EditFile(filename string) (*exec.Cmd, error) {
|
||||
}
|
||||
|
||||
// PrepareSubProcess iniPrepareSubProcessrocess then tells the Gui to switch to it
|
||||
// TODO: see if this needs to exist, given that ExecutableFromString does the same things
|
||||
func (c *OSCommand) PrepareSubProcess(cmdName string, commandArgs ...string) *exec.Cmd {
|
||||
return c.command(cmdName, commandArgs...)
|
||||
cmd := c.command(cmdName, commandArgs...)
|
||||
if cmd != nil {
|
||||
cmd.Env = append(os.Environ(), "GIT_OPTIONAL_LOCKS=0")
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
// Quote wraps a message in platform-specific quotation marks
|
||||
@@ -224,13 +231,13 @@ func (c *OSCommand) Unquote(message string) string {
|
||||
func (c *OSCommand) AppendLineToFile(filename, line string) error {
|
||||
f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, 0)
|
||||
return WrapError(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, err = f.WriteString("\n" + line)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, 0)
|
||||
return WrapError(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -240,25 +247,25 @@ func (c *OSCommand) CreateTempFile(filename, content string) (string, error) {
|
||||
tmpfile, err := ioutil.TempFile("", filename)
|
||||
if err != nil {
|
||||
c.Log.Error(err)
|
||||
return "", errors.Wrap(err, 0)
|
||||
return "", WrapError(err)
|
||||
}
|
||||
|
||||
if _, err := tmpfile.WriteString(content); err != nil {
|
||||
c.Log.Error(err)
|
||||
return "", errors.Wrap(err, 0)
|
||||
return "", WrapError(err)
|
||||
}
|
||||
if err := tmpfile.Close(); err != nil {
|
||||
c.Log.Error(err)
|
||||
return "", errors.Wrap(err, 0)
|
||||
return "", WrapError(err)
|
||||
}
|
||||
|
||||
return tmpfile.Name(), nil
|
||||
}
|
||||
|
||||
// RemoveFile removes a file at the specified path
|
||||
func (c *OSCommand) RemoveFile(filename string) error {
|
||||
err := os.Remove(filename)
|
||||
return errors.Wrap(err, 0)
|
||||
// Remove removes a file or directory at the specified path
|
||||
func (c *OSCommand) Remove(filename string) error {
|
||||
err := os.RemoveAll(filename)
|
||||
return WrapError(err)
|
||||
}
|
||||
|
||||
// FileExists checks whether a file exists at the specified path
|
||||
@@ -296,3 +303,68 @@ func (c *OSCommand) GetLazygitPath() string {
|
||||
}
|
||||
return filepath.ToSlash(ex)
|
||||
}
|
||||
|
||||
// RunCustomCommand returns the pointer to a custom command
|
||||
func (c *OSCommand) RunCustomCommand(command string) *exec.Cmd {
|
||||
return c.PrepareSubProcess(c.Platform.shell, c.Platform.shellArg, command)
|
||||
}
|
||||
|
||||
// PipeCommands runs a heap of commands and pipes their inputs/outputs together like A | B | C
|
||||
func (c *OSCommand) PipeCommands(commandStrings ...string) error {
|
||||
|
||||
cmds := make([]*exec.Cmd, len(commandStrings))
|
||||
|
||||
for i, str := range commandStrings {
|
||||
cmds[i] = c.ExecutableFromString(str)
|
||||
}
|
||||
|
||||
for i := 0; i < len(cmds)-1; i++ {
|
||||
stdout, err := cmds[i].StdoutPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmds[i+1].Stdin = stdout
|
||||
}
|
||||
|
||||
// keeping this here in case I adapt this code for some other purpose in the future
|
||||
// cmds[len(cmds)-1].Stdout = os.Stdout
|
||||
|
||||
finalErrors := []string{}
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(len(cmds))
|
||||
|
||||
for _, cmd := range cmds {
|
||||
currentCmd := cmd
|
||||
go func() {
|
||||
stderr, err := currentCmd.StderrPipe()
|
||||
if err != nil {
|
||||
c.Log.Error(err)
|
||||
}
|
||||
|
||||
if err := currentCmd.Start(); err != nil {
|
||||
c.Log.Error(err)
|
||||
}
|
||||
|
||||
if b, err := ioutil.ReadAll(stderr); err == nil {
|
||||
if len(b) > 0 {
|
||||
finalErrors = append(finalErrors, string(b))
|
||||
}
|
||||
}
|
||||
|
||||
if err := currentCmd.Wait(); err != nil {
|
||||
c.Log.Error(err)
|
||||
}
|
||||
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
if len(finalErrors) > 0 {
|
||||
return errors.New(strings.Join(finalErrors, "\n"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ func getServices() []*Service {
|
||||
},
|
||||
{
|
||||
Name: "bitbucket.org",
|
||||
PullRequestURL: "https://bitbucket.org/%s/%s/pull-requests/new?t=%s",
|
||||
PullRequestURL: "https://bitbucket.org/%s/%s/pull-requests/new?source=%s&t=1",
|
||||
},
|
||||
{
|
||||
Name: "gitlab.com",
|
||||
|
||||
@@ -64,7 +64,7 @@ func TestCreatePullRequest(t *testing.T) {
|
||||
}
|
||||
|
||||
assert.Equal(t, cmd, "open")
|
||||
assert.Equal(t, args, []string{"https://bitbucket.org/johndoe/social_network/pull-requests/new?t=feature/profile-page"})
|
||||
assert.Equal(t, args, []string{"https://bitbucket.org/johndoe/social_network/pull-requests/new?source=feature/profile-page&t=1"})
|
||||
return exec.Command("echo")
|
||||
},
|
||||
func(err error) {
|
||||
@@ -83,7 +83,7 @@ func TestCreatePullRequest(t *testing.T) {
|
||||
}
|
||||
|
||||
assert.Equal(t, cmd, "open")
|
||||
assert.Equal(t, args, []string{"https://bitbucket.org/johndoe/social_network/pull-requests/new?t=feature/events"})
|
||||
assert.Equal(t, args, []string{"https://bitbucket.org/johndoe/social_network/pull-requests/new?source=feature/events&t=1"})
|
||||
return exec.Command("echo")
|
||||
},
|
||||
func(err error) {
|
||||
|
||||
@@ -7,7 +7,7 @@ type StashEntry struct {
|
||||
DisplayString string
|
||||
}
|
||||
|
||||
// GetDisplayStrings returns the dispaly string of branch
|
||||
// GetDisplayStrings returns the display string of branch
|
||||
func (s *StashEntry) GetDisplayStrings(isFocused bool) []string {
|
||||
return []string{s.DisplayString}
|
||||
}
|
||||
|
||||
0
pkg/commands/testdata/a_dir/file
vendored
Normal file
0
pkg/commands/testdata/a_dir/file
vendored
Normal file
0
pkg/commands/testdata/a_file
vendored
Normal file
0
pkg/commands/testdata/a_file
vendored
Normal file
@@ -13,15 +13,16 @@ import (
|
||||
|
||||
// AppConfig contains the base configuration fields required for lazygit.
|
||||
type AppConfig struct {
|
||||
Debug bool `long:"debug" env:"DEBUG" default:"false"`
|
||||
Version string `long:"version" env:"VERSION" default:"unversioned"`
|
||||
Commit string `long:"commit" env:"COMMIT"`
|
||||
BuildDate string `long:"build-date" env:"BUILD_DATE"`
|
||||
Name string `long:"name" env:"NAME" default:"lazygit"`
|
||||
BuildSource string `long:"build-source" env:"BUILD_SOURCE" default:""`
|
||||
UserConfig *viper.Viper
|
||||
AppState *AppState
|
||||
IsNewRepo bool
|
||||
Debug bool `long:"debug" env:"DEBUG" default:"false"`
|
||||
Version string `long:"version" env:"VERSION" default:"unversioned"`
|
||||
Commit string `long:"commit" env:"COMMIT"`
|
||||
BuildDate string `long:"build-date" env:"BUILD_DATE"`
|
||||
Name string `long:"name" env:"NAME" default:"lazygit"`
|
||||
BuildSource string `long:"build-source" env:"BUILD_SOURCE" default:""`
|
||||
UserConfig *viper.Viper
|
||||
UserConfigDir string
|
||||
AppState *AppState
|
||||
IsNewRepo bool
|
||||
}
|
||||
|
||||
// AppConfigurer interface allows individual app config structs to inherit Fields
|
||||
@@ -34,6 +35,7 @@ type AppConfigurer interface {
|
||||
GetName() string
|
||||
GetBuildSource() string
|
||||
GetUserConfig() *viper.Viper
|
||||
GetUserConfigDir() string
|
||||
GetAppState() *AppState
|
||||
WriteToUserConfig(string, string) error
|
||||
SaveAppState() error
|
||||
@@ -44,7 +46,7 @@ type AppConfigurer interface {
|
||||
|
||||
// NewAppConfig makes a new app config
|
||||
func NewAppConfig(name, version, commit, date string, buildSource string, debuggingFlag bool) (*AppConfig, error) {
|
||||
userConfig, err := LoadConfig("config", true)
|
||||
userConfig, userConfigPath, err := LoadConfig("config", true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -54,15 +56,16 @@ func NewAppConfig(name, version, commit, date string, buildSource string, debugg
|
||||
}
|
||||
|
||||
appConfig := &AppConfig{
|
||||
Name: "lazygit",
|
||||
Version: version,
|
||||
Commit: commit,
|
||||
BuildDate: date,
|
||||
Debug: debuggingFlag,
|
||||
BuildSource: buildSource,
|
||||
UserConfig: userConfig,
|
||||
AppState: &AppState{},
|
||||
IsNewRepo: false,
|
||||
Name: "lazygit",
|
||||
Version: version,
|
||||
Commit: commit,
|
||||
BuildDate: date,
|
||||
Debug: debuggingFlag,
|
||||
BuildSource: buildSource,
|
||||
UserConfig: userConfig,
|
||||
UserConfigDir: filepath.Dir(userConfigPath),
|
||||
AppState: &AppState{},
|
||||
IsNewRepo: false,
|
||||
}
|
||||
|
||||
if err := appConfig.LoadAppState(); err != nil {
|
||||
@@ -123,6 +126,10 @@ func (c *AppConfig) GetAppState() *AppState {
|
||||
return c.AppState
|
||||
}
|
||||
|
||||
func (c *AppConfig) GetUserConfigDir() string {
|
||||
return c.UserConfigDir
|
||||
}
|
||||
|
||||
func newViper(filename string) (*viper.Viper, error) {
|
||||
v := viper.New()
|
||||
v.SetConfigType("yaml")
|
||||
@@ -131,23 +138,24 @@ func newViper(filename string) (*viper.Viper, error) {
|
||||
}
|
||||
|
||||
// LoadConfig gets the user's config
|
||||
func LoadConfig(filename string, withDefaults bool) (*viper.Viper, error) {
|
||||
func LoadConfig(filename string, withDefaults bool) (*viper.Viper, string, error) {
|
||||
v, err := newViper(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, "", err
|
||||
}
|
||||
if withDefaults {
|
||||
if err = LoadDefaults(v, GetDefaultConfig()); err != nil {
|
||||
return nil, err
|
||||
return nil, "", err
|
||||
}
|
||||
if err = LoadDefaults(v, GetPlatformDefaultConfig()); err != nil {
|
||||
return nil, err
|
||||
return nil, "", err
|
||||
}
|
||||
}
|
||||
if err = LoadAndMergeFile(v, filename+".yml"); err != nil {
|
||||
return nil, err
|
||||
configPath, err := LoadAndMergeFile(v, filename+".yml")
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
return v, nil
|
||||
return v, configPath, nil
|
||||
}
|
||||
|
||||
// LoadDefaults loads in the defaults defined in this file
|
||||
@@ -173,21 +181,21 @@ func prepareConfigFile(filename string) (string, error) {
|
||||
|
||||
// LoadAndMergeFile Loads the config/state file, creating
|
||||
// the file has an empty one if it does not exist
|
||||
func LoadAndMergeFile(v *viper.Viper, filename string) error {
|
||||
func LoadAndMergeFile(v *viper.Viper, filename string) (string, error) {
|
||||
configPath, err := prepareConfigFile(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
|
||||
v.AddConfigPath(filepath.Dir(configPath))
|
||||
return v.MergeInConfig()
|
||||
return configPath, v.MergeInConfig()
|
||||
}
|
||||
|
||||
// WriteToUserConfig adds a key/value pair to the user's config and saves it
|
||||
func (c *AppConfig) WriteToUserConfig(key, value string) error {
|
||||
// reloading the user config directly (without defaults) so that we're not
|
||||
// writing any defaults back to the user's config
|
||||
v, err := LoadConfig("config", false)
|
||||
v, _, err := LoadConfig("config", false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -196,7 +204,7 @@ func (c *AppConfig) WriteToUserConfig(key, value string) error {
|
||||
return v.WriteConfig()
|
||||
}
|
||||
|
||||
// SaveAppState marhsalls the AppState struct and writes it to the disk
|
||||
// SaveAppState marshalls the AppState struct and writes it to the disk
|
||||
func (c *AppConfig) SaveAppState() error {
|
||||
marshalledAppState, err := yaml.Marshal(c.AppState)
|
||||
if err != nil {
|
||||
@@ -236,6 +244,7 @@ func GetDefaultConfig() []byte {
|
||||
scrollPastBottom: true
|
||||
mouseEvents: false # will default to true when the feature is complete
|
||||
theme:
|
||||
lightTheme: false
|
||||
activeBorderColor:
|
||||
- white
|
||||
- bold
|
||||
@@ -245,9 +254,11 @@ func GetDefaultConfig() []byte {
|
||||
- blue
|
||||
commitLength:
|
||||
show: true
|
||||
git:
|
||||
merging:
|
||||
manualCommit: false
|
||||
git:
|
||||
merging:
|
||||
manualCommit: false
|
||||
skipHookPrefix: 'WIP'
|
||||
autoFetch: true
|
||||
update:
|
||||
method: prompt # can be: prompt | background | never
|
||||
days: 14 # how often a update is checked for
|
||||
|
||||
@@ -70,7 +70,7 @@ func (b *BranchListBuilder) obtainSafeBranches() []*commands.Branch {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = bIter.ForEach(func(b *plumbing.Reference) error {
|
||||
bIter.ForEach(func(b *plumbing.Reference) error {
|
||||
name := b.Name().Short()
|
||||
branches = append(branches, &commands.Branch{Name: name})
|
||||
return nil
|
||||
|
||||
@@ -31,16 +31,18 @@ type CommitListBuilder struct {
|
||||
OSCommand *commands.OSCommand
|
||||
Tr *i18n.Localizer
|
||||
CherryPickedCommits []*commands.Commit
|
||||
DiffEntries []*commands.Commit
|
||||
}
|
||||
|
||||
// NewCommitListBuilder builds a new commit list builder
|
||||
func NewCommitListBuilder(log *logrus.Entry, gitCommand *commands.GitCommand, osCommand *commands.OSCommand, tr *i18n.Localizer, cherryPickedCommits []*commands.Commit) (*CommitListBuilder, error) {
|
||||
func NewCommitListBuilder(log *logrus.Entry, gitCommand *commands.GitCommand, osCommand *commands.OSCommand, tr *i18n.Localizer, cherryPickedCommits []*commands.Commit, diffEntries []*commands.Commit) (*CommitListBuilder, error) {
|
||||
return &CommitListBuilder{
|
||||
Log: log,
|
||||
GitCommand: gitCommand,
|
||||
OSCommand: osCommand,
|
||||
Tr: tr,
|
||||
CherryPickedCommits: cherryPickedCommits,
|
||||
DiffEntries: diffEntries,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -96,6 +98,14 @@ func (c *CommitListBuilder) GetCommits() ([]*commands.Commit, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, commit := range commits {
|
||||
for _, entry := range c.DiffEntries {
|
||||
if entry.Sha == commit.Sha {
|
||||
commit.Status = "selected"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return commits, nil
|
||||
}
|
||||
|
||||
@@ -113,7 +123,7 @@ func (c *CommitListBuilder) getRebasingCommits(rebaseMode string) ([]*commands.C
|
||||
|
||||
func (c *CommitListBuilder) getNormalRebasingCommits() ([]*commands.Commit, error) {
|
||||
rewrittenCount := 0
|
||||
bytesContent, err := ioutil.ReadFile(".git/rebase-apply/rewritten")
|
||||
bytesContent, err := ioutil.ReadFile(fmt.Sprintf("%s/rebase-apply/rewritten", c.GitCommand.DotGitDir))
|
||||
if err == nil {
|
||||
content := string(bytesContent)
|
||||
rewrittenCount = len(strings.Split(content, "\n"))
|
||||
@@ -121,7 +131,7 @@ func (c *CommitListBuilder) getNormalRebasingCommits() ([]*commands.Commit, erro
|
||||
|
||||
// we know we're rebasing, so lets get all the files whose names have numbers
|
||||
commits := []*commands.Commit{}
|
||||
err = filepath.Walk(".git/rebase-apply", func(path string, f os.FileInfo, err error) error {
|
||||
err = filepath.Walk(fmt.Sprintf("%s/rebase-apply", c.GitCommand.DotGitDir), func(path string, f os.FileInfo, err error) error {
|
||||
if rewrittenCount > 0 {
|
||||
rewrittenCount--
|
||||
return nil
|
||||
@@ -165,9 +175,9 @@ func (c *CommitListBuilder) getNormalRebasingCommits() ([]*commands.Commit, erro
|
||||
// and extracts out the sha and names of commits that we still have to go
|
||||
// in the rebase:
|
||||
func (c *CommitListBuilder) getInteractiveRebasingCommits() ([]*commands.Commit, error) {
|
||||
bytesContent, err := ioutil.ReadFile(".git/rebase-merge/git-rebase-todo")
|
||||
bytesContent, err := ioutil.ReadFile(fmt.Sprintf("%s/rebase-merge/git-rebase-todo", c.GitCommand.DotGitDir))
|
||||
if err != nil {
|
||||
c.Log.Info(fmt.Sprintf("error occured reading git-rebase-todo: %s", err.Error()))
|
||||
c.Log.Info(fmt.Sprintf("error occurred reading git-rebase-todo: %s", err.Error()))
|
||||
// we assume an error means the file doesn't exist so we just return
|
||||
return nil, nil
|
||||
}
|
||||
@@ -251,10 +261,8 @@ func (c *CommitListBuilder) getMergeBase() (string, error) {
|
||||
baseBranch = "develop"
|
||||
}
|
||||
|
||||
output, err := c.OSCommand.RunCommandWithOutput(fmt.Sprintf("git merge-base HEAD %s", baseBranch))
|
||||
if err != nil {
|
||||
// swallowing error because it's not a big deal; probably because there are no commits yet
|
||||
}
|
||||
// swallowing error because it's not a big deal; probably because there are no commits yet
|
||||
output, _ := c.OSCommand.RunCommandWithOutput(fmt.Sprintf("git merge-base HEAD %s", baseBranch))
|
||||
return output, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ func (gui *Gui) handleBranchSelect(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.renderString(g, "main", gui.Tr.SLocalize("NoBranchesThisRepo"))
|
||||
}
|
||||
branch := gui.getSelectedBranch()
|
||||
if err := gui.focusPoint(0, gui.State.Panels.Branches.SelectedLine, v); err != nil {
|
||||
if err := gui.focusPoint(0, gui.State.Panels.Branches.SelectedLine, len(gui.State.Branches), v); err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
@@ -121,15 +121,7 @@ func (gui *Gui) handleBranchPress(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.createErrorPanel(g, gui.Tr.SLocalize("AlreadyCheckedOutBranch"))
|
||||
}
|
||||
branch := gui.getSelectedBranch()
|
||||
if err := gui.GitCommand.Checkout(branch.Name, false); err != nil {
|
||||
if err := gui.createErrorPanel(g, err.Error()); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
gui.State.Panels.Branches.SelectedLine = 0
|
||||
}
|
||||
|
||||
return gui.refreshSidePanels(g)
|
||||
return gui.handleCheckoutBranch(branch.Name)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleCreatePullRequestPress(g *gocui.Gui, v *gocui.View) error {
|
||||
@@ -166,12 +158,45 @@ func (gui *Gui) handleForceCheckout(g *gocui.Gui, v *gocui.View) error {
|
||||
}, nil)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleCheckoutBranch(branchName string) error {
|
||||
if err := gui.GitCommand.Checkout(branchName, false); err != nil {
|
||||
// note, this will only work for english-language git commands. If we force git to use english, and the error isn't this one, then the user will receive an english command they may not understand. I'm not sure what the best solution to this is. Running the command once in english and a second time in the native language is one option
|
||||
|
||||
if strings.Contains(err.Error(), "Please commit your changes or stash them before you switch branch") {
|
||||
// offer to autostash changes
|
||||
return gui.createConfirmationPanel(gui.g, gui.getBranchesView(), gui.Tr.SLocalize("AutoStashTitle"), gui.Tr.SLocalize("AutoStashPrompt"), func(g *gocui.Gui, v *gocui.View) error {
|
||||
if err := gui.GitCommand.StashSave(gui.Tr.SLocalize("StashPrefix") + branchName); err != nil {
|
||||
return gui.createErrorPanel(g, err.Error())
|
||||
}
|
||||
if err := gui.GitCommand.Checkout(branchName, false); err != nil {
|
||||
return gui.createErrorPanel(g, err.Error())
|
||||
}
|
||||
|
||||
// checkout successful so we select the new branch
|
||||
gui.State.Panels.Branches.SelectedLine = 0
|
||||
|
||||
if err := gui.GitCommand.StashDo(0, "pop"); err != nil {
|
||||
if err := gui.refreshSidePanels(g); err != nil {
|
||||
return err
|
||||
}
|
||||
return gui.createErrorPanel(g, err.Error())
|
||||
}
|
||||
return gui.refreshSidePanels(g)
|
||||
}, nil)
|
||||
}
|
||||
|
||||
if err := gui.createErrorPanel(gui.g, err.Error()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
gui.State.Panels.Branches.SelectedLine = 0
|
||||
return gui.refreshSidePanels(gui.g)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleCheckoutByName(g *gocui.Gui, v *gocui.View) error {
|
||||
gui.createPromptPanel(g, v, gui.Tr.SLocalize("BranchName")+":", func(g *gocui.Gui, v *gocui.View) error {
|
||||
if err := gui.GitCommand.Checkout(gui.trimmedContent(v), false); err != nil {
|
||||
return gui.createErrorPanel(g, err.Error())
|
||||
}
|
||||
return gui.refreshSidePanels(g)
|
||||
return gui.handleCheckoutBranch(gui.trimmedContent(v))
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
106
pkg/gui/commit_files_panel.go
Normal file
106
pkg/gui/commit_files_panel.go
Normal file
@@ -0,0 +1,106 @@
|
||||
package gui
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||
)
|
||||
|
||||
func (gui *Gui) getSelectedCommitFile(g *gocui.Gui) *commands.CommitFile {
|
||||
selectedLine := gui.State.Panels.CommitFiles.SelectedLine
|
||||
if selectedLine == -1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return gui.State.CommitFiles[selectedLine]
|
||||
}
|
||||
|
||||
func (gui *Gui) handleCommitFileSelect(g *gocui.Gui, v *gocui.View) error {
|
||||
commitFile := gui.getSelectedCommitFile(g)
|
||||
if commitFile == nil {
|
||||
return gui.renderString(g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
|
||||
}
|
||||
|
||||
if err := gui.focusPoint(0, gui.State.Panels.CommitFiles.SelectedLine, len(gui.State.CommitFiles), v); err != nil {
|
||||
return err
|
||||
}
|
||||
commitText, err := gui.GitCommand.ShowCommitFile(commitFile.Sha, commitFile.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return gui.renderString(g, "main", commitText)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleCommitFilesNextLine(g *gocui.Gui, v *gocui.View) error {
|
||||
panelState := gui.State.Panels.CommitFiles
|
||||
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.CommitFiles), false)
|
||||
|
||||
return gui.handleCommitFileSelect(gui.g, v)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleCommitFilesPrevLine(g *gocui.Gui, v *gocui.View) error {
|
||||
panelState := gui.State.Panels.CommitFiles
|
||||
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.CommitFiles), true)
|
||||
|
||||
return gui.handleCommitFileSelect(gui.g, v)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleSwitchToCommitsPanel(g *gocui.Gui, v *gocui.View) error {
|
||||
commitsView, err := g.View("commits")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return gui.switchFocus(g, v, commitsView)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleCheckoutCommitFile(g *gocui.Gui, v *gocui.View) error {
|
||||
file := gui.State.CommitFiles[gui.State.Panels.CommitFiles.SelectedLine]
|
||||
|
||||
if err := gui.GitCommand.CheckoutFile(file.Sha, file.Name); err != nil {
|
||||
return gui.createErrorPanel(gui.g, err.Error())
|
||||
}
|
||||
|
||||
return gui.refreshFiles()
|
||||
}
|
||||
|
||||
func (gui *Gui) handleDiscardOldFileChange(g *gocui.Gui, v *gocui.View) error {
|
||||
fileName := gui.State.CommitFiles[gui.State.Panels.CommitFiles.SelectedLine].Name
|
||||
|
||||
return gui.createConfirmationPanel(gui.g, v, gui.Tr.SLocalize("DiscardFileChangesTitle"), gui.Tr.SLocalize("DiscardFileChangesPrompt"), func(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.WithWaitingStatus(gui.Tr.SLocalize("RebasingStatus"), func() error {
|
||||
if err := gui.GitCommand.DiscardOldFileChanges(gui.State.Commits, gui.State.Panels.Commits.SelectedLine, fileName); err != nil {
|
||||
if err := gui.handleGenericMergeCommandResult(err); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return gui.refreshSidePanels(gui.g)
|
||||
})
|
||||
}, nil)
|
||||
}
|
||||
|
||||
func (gui *Gui) refreshCommitFilesView() error {
|
||||
commit := gui.getSelectedCommit(gui.g)
|
||||
if commit == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
files, err := gui.GitCommand.GetCommitFiles(commit.Sha)
|
||||
if err != nil {
|
||||
return gui.createErrorPanel(gui.g, err.Error())
|
||||
}
|
||||
|
||||
gui.State.CommitFiles = files
|
||||
|
||||
gui.refreshSelectedLine(&gui.State.Panels.CommitFiles.SelectedLine, len(gui.State.CommitFiles))
|
||||
|
||||
if err := gui.renderListPanel(gui.getCommitFilesView(), gui.State.CommitFiles); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return gui.handleCommitFileSelect(gui.g, gui.getCommitFilesView())
|
||||
}
|
||||
|
||||
func (gui *Gui) handleOpenOldCommitFile(g *gocui.Gui, v *gocui.View) error {
|
||||
file := gui.getSelectedCommitFile(g)
|
||||
return gui.openFile(file.Name)
|
||||
}
|
||||
@@ -11,17 +11,18 @@ import (
|
||||
// runSyncOrAsyncCommand takes the output of a command that may have returned
|
||||
// either no error, an error, or a subprocess to execute, and if a subprocess
|
||||
// needs to be set on the gui object, it does so, and then returns the error
|
||||
func (gui *Gui) runSyncOrAsyncCommand(sub *exec.Cmd, err error) error {
|
||||
// the bool returned tells us whether the calling code should continue
|
||||
func (gui *Gui) runSyncOrAsyncCommand(sub *exec.Cmd, err error) (bool, error) {
|
||||
if err != nil {
|
||||
if err != gui.Errors.ErrSubProcess {
|
||||
return gui.createErrorPanel(gui.g, err.Error())
|
||||
return false, gui.createErrorPanel(gui.g, err.Error())
|
||||
}
|
||||
}
|
||||
if sub != nil {
|
||||
gui.SubProcess = sub
|
||||
return gui.Errors.ErrSubProcess
|
||||
return false, gui.Errors.ErrSubProcess
|
||||
}
|
||||
return nil
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (gui *Gui) handleCommitConfirm(g *gocui.Gui, v *gocui.View) error {
|
||||
@@ -29,9 +30,18 @@ func (gui *Gui) handleCommitConfirm(g *gocui.Gui, v *gocui.View) error {
|
||||
if message == "" {
|
||||
return gui.createErrorPanel(g, gui.Tr.SLocalize("CommitWithoutMessageErr"))
|
||||
}
|
||||
if err := gui.runSyncOrAsyncCommand(gui.GitCommand.Commit(message)); err != nil {
|
||||
flags := ""
|
||||
skipHookPrefix := gui.Config.GetUserConfig().GetString("git.skipHookPrefix")
|
||||
if skipHookPrefix != "" && strings.HasPrefix(message, skipHookPrefix) {
|
||||
flags = "--no-verify"
|
||||
}
|
||||
ok, err := gui.runSyncOrAsyncCommand(gui.GitCommand.Commit(message, flags))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
v.Clear()
|
||||
_ = v.SetCursor(0, 0)
|
||||
@@ -61,33 +71,6 @@ func (gui *Gui) handleCommitFocused(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.renderString(g, "options", message)
|
||||
}
|
||||
|
||||
func (gui *Gui) simpleEditor(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
|
||||
switch {
|
||||
case key == gocui.KeyBackspace || key == gocui.KeyBackspace2:
|
||||
v.EditDelete(true)
|
||||
case key == gocui.KeyDelete:
|
||||
v.EditDelete(false)
|
||||
case key == gocui.KeyArrowDown:
|
||||
v.MoveCursor(0, 1, false)
|
||||
case key == gocui.KeyArrowUp:
|
||||
v.MoveCursor(0, -1, false)
|
||||
case key == gocui.KeyArrowLeft:
|
||||
v.MoveCursor(-1, 0, false)
|
||||
case key == gocui.KeyArrowRight:
|
||||
v.MoveCursor(1, 0, false)
|
||||
case key == gocui.KeyTab:
|
||||
v.EditNewLine()
|
||||
case key == gocui.KeySpace:
|
||||
v.EditWrite(' ')
|
||||
case key == gocui.KeyInsert:
|
||||
v.Overwrite = !v.Overwrite
|
||||
default:
|
||||
v.EditWrite(ch)
|
||||
}
|
||||
|
||||
gui.RenderCommitLength()
|
||||
}
|
||||
|
||||
func (gui *Gui) getBufferLength(view *gocui.View) string {
|
||||
return " " + strconv.Itoa(strings.Count(view.Buffer(), "")-1) + " "
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/go-errors/errors"
|
||||
|
||||
"github.com/jesseduffield/gocui"
|
||||
@@ -36,9 +37,15 @@ func (gui *Gui) handleCommitSelect(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.renderString(g, "main", gui.Tr.SLocalize("NoCommitsThisBranch"))
|
||||
}
|
||||
|
||||
if err := gui.focusPoint(0, gui.State.Panels.Commits.SelectedLine, v); err != nil {
|
||||
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 {
|
||||
return nil
|
||||
}
|
||||
|
||||
commitText, err := gui.GitCommand.Show(commit.Sha)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -48,7 +55,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 {
|
||||
builder, err := git.NewCommitListBuilder(gui.Log, gui.GitCommand, gui.OSCommand, gui.Tr, gui.State.CherryPickedCommits)
|
||||
builder, err := git.NewCommitListBuilder(gui.Log, gui.GitCommand, gui.OSCommand, gui.Tr, gui.State.CherryPickedCommits, gui.State.DiffEntries)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -71,9 +78,12 @@ func (gui *Gui) refreshCommits(g *gocui.Gui) error {
|
||||
fmt.Fprint(v, list)
|
||||
|
||||
gui.refreshStatus(g)
|
||||
if v == g.CurrentView() {
|
||||
if g.CurrentView() == v {
|
||||
gui.handleCommitSelect(g, v)
|
||||
}
|
||||
if g.CurrentView() == gui.getCommitFilesView() {
|
||||
return gui.refreshCommitFilesView()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return nil
|
||||
@@ -115,7 +125,8 @@ func (gui *Gui) handleResetToCommit(g *gocui.Gui, commitView *gocui.View) error
|
||||
if commit == nil {
|
||||
panic(errors.New(gui.Tr.SLocalize("NoCommitsThisBranch")))
|
||||
}
|
||||
if err := gui.GitCommand.ResetToCommit(commit.Sha); err != nil {
|
||||
|
||||
if err := gui.GitCommand.ResetToCommit(commit.Sha, "mixed"); err != nil {
|
||||
return gui.createErrorPanel(g, err.Error())
|
||||
}
|
||||
if err := gui.refreshCommits(g); err != nil {
|
||||
@@ -437,3 +448,158 @@ func (gui *Gui) HandlePasteCommits(g *gocui.Gui, v *gocui.View) error {
|
||||
})
|
||||
}, nil)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleSwitchToCommitFilesPanel(g *gocui.Gui, v *gocui.View) error {
|
||||
if err := gui.refreshCommitFilesView(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return gui.switchFocus(g, v, gui.getCommitFilesView())
|
||||
}
|
||||
|
||||
func (gui *Gui) handleToggleDiffCommit(g *gocui.Gui, v *gocui.View) error {
|
||||
selectLimit := 2
|
||||
|
||||
// get selected commit
|
||||
commit := gui.getSelectedCommit(g)
|
||||
if commit == nil {
|
||||
return gui.renderString(g, "main", gui.Tr.SLocalize("NoCommitsThisBranch"))
|
||||
}
|
||||
|
||||
// if already selected commit delete
|
||||
if idx, has := gui.hasCommit(gui.State.DiffEntries, commit.Sha); has {
|
||||
gui.State.DiffEntries = gui.unchooseCommit(gui.State.DiffEntries, idx)
|
||||
} else {
|
||||
if len(gui.State.DiffEntries) == selectLimit {
|
||||
gui.State.DiffEntries = gui.unchooseCommit(gui.State.DiffEntries, 0)
|
||||
}
|
||||
gui.State.DiffEntries = append(gui.State.DiffEntries, commit)
|
||||
}
|
||||
|
||||
gui.setDiffMode()
|
||||
|
||||
// if selected two commits, display diff between
|
||||
if len(gui.State.DiffEntries) == selectLimit {
|
||||
commitText, err := gui.GitCommand.DiffCommits(gui.State.DiffEntries[0].Sha, gui.State.DiffEntries[1].Sha)
|
||||
|
||||
if err != nil {
|
||||
return gui.createErrorPanel(gui.g, err.Error())
|
||||
}
|
||||
|
||||
return gui.renderString(g, "main", commitText)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) setDiffMode() {
|
||||
v := gui.getCommitsView()
|
||||
if len(gui.State.DiffEntries) != 0 {
|
||||
gui.State.Panels.Commits.SpecificDiffMode = true
|
||||
v.Title = gui.Tr.SLocalize("CommitsDiffTitle")
|
||||
} else {
|
||||
gui.State.Panels.Commits.SpecificDiffMode = false
|
||||
v.Title = gui.Tr.SLocalize("CommitsTitle")
|
||||
}
|
||||
|
||||
gui.refreshCommits(gui.g)
|
||||
}
|
||||
|
||||
func (gui *Gui) hasCommit(commits []*commands.Commit, target string) (int, bool) {
|
||||
for idx, commit := range commits {
|
||||
if commit.Sha == target {
|
||||
return idx, true
|
||||
}
|
||||
}
|
||||
return -1, false
|
||||
}
|
||||
|
||||
func (gui *Gui) unchooseCommit(commits []*commands.Commit, i int) []*commands.Commit {
|
||||
return append(commits[:i], commits[i+1:]...)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleCreateFixupCommit(g *gocui.Gui, v *gocui.View) error {
|
||||
commit := gui.getSelectedCommit(g)
|
||||
if commit == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return gui.createConfirmationPanel(g, v, gui.Tr.SLocalize("CreateFixupCommit"), gui.Tr.TemplateLocalize(
|
||||
"SureCreateFixupCommit",
|
||||
Teml{
|
||||
"commit": commit.Sha,
|
||||
},
|
||||
), func(g *gocui.Gui, v *gocui.View) error {
|
||||
if err := gui.GitCommand.CreateFixupCommit(commit.Sha); err != nil {
|
||||
return gui.createErrorPanel(g, err.Error())
|
||||
}
|
||||
|
||||
return gui.refreshSidePanels(gui.g)
|
||||
}, nil)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleSquashAllAboveFixupCommits(g *gocui.Gui, v *gocui.View) error {
|
||||
commit := gui.getSelectedCommit(g)
|
||||
if commit == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return gui.createConfirmationPanel(g, v, gui.Tr.SLocalize("SquashAboveCommits"), gui.Tr.TemplateLocalize(
|
||||
"SureSquashAboveCommits",
|
||||
Teml{
|
||||
"commit": commit.Sha,
|
||||
},
|
||||
), func(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.WithWaitingStatus(gui.Tr.SLocalize("SquashingStatus"), func() error {
|
||||
err := gui.GitCommand.SquashAllAboveFixupCommits(commit.Sha)
|
||||
return gui.handleGenericMergeCommandResult(err)
|
||||
})
|
||||
}, nil)
|
||||
}
|
||||
|
||||
type resetOption struct {
|
||||
description string
|
||||
command string
|
||||
}
|
||||
|
||||
// GetDisplayStrings is a function.
|
||||
func (r *resetOption) GetDisplayStrings(isFocused bool) []string {
|
||||
return []string{r.description, color.New(color.FgRed).Sprint(r.command)}
|
||||
}
|
||||
|
||||
func (gui *Gui) handleCreateCommitResetMenu(g *gocui.Gui, v *gocui.View) error {
|
||||
commit := gui.getSelectedCommit(g)
|
||||
if commit == nil {
|
||||
return gui.createErrorPanel(gui.g, gui.Tr.SLocalize("NoCommitsThisBranch"))
|
||||
}
|
||||
|
||||
strengths := []string{"soft", "mixed", "hard"}
|
||||
options := make([]*resetOption, len(strengths))
|
||||
for i, strength := range strengths {
|
||||
options[i] = &resetOption{
|
||||
description: fmt.Sprintf("%s reset", strength),
|
||||
command: fmt.Sprintf("reset --%s %s", strength, commit.Sha),
|
||||
}
|
||||
}
|
||||
|
||||
handleMenuPress := func(index int) error {
|
||||
if err := gui.GitCommand.ResetToCommit(commit.Sha, strengths[index]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := gui.refreshCommits(g); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gui.refreshFiles(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gui.resetOrigin(gui.getCommitsView()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gui.State.Panels.Commits.SelectedLine = 0
|
||||
return gui.handleCommitSelect(g, gui.getCommitsView())
|
||||
}
|
||||
|
||||
return gui.createMenu(fmt.Sprintf("%s %s", gui.Tr.SLocalize("resetTo"), commit.Sha), options, len(options), handleMenuPress)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/theme"
|
||||
)
|
||||
|
||||
func (gui *Gui) wrappedConfirmationFunction(function func(*gocui.Gui, *gocui.View) error) func(*gocui.Gui, *gocui.View) error {
|
||||
@@ -81,7 +82,7 @@ func (gui *Gui) prepareConfirmationPanel(currentView *gocui.View, title, prompt
|
||||
confirmationView.HasLoader = hasLoader
|
||||
confirmationView.Title = title
|
||||
confirmationView.Wrap = true
|
||||
confirmationView.FgColor = gocui.ColorWhite
|
||||
confirmationView.FgColor = theme.GocuiDefaultTextColor
|
||||
}
|
||||
gui.g.Update(func(g *gocui.Gui) error {
|
||||
return gui.switchFocus(gui.g, currentView, confirmationView)
|
||||
|
||||
@@ -21,7 +21,11 @@ func (gui *Gui) contextTitleMap() map[string]map[string]string {
|
||||
}
|
||||
|
||||
func (gui *Gui) setMainTitle() error {
|
||||
currentViewName := gui.g.CurrentView().Name()
|
||||
currentView := gui.g.CurrentView()
|
||||
if currentView == nil {
|
||||
return nil
|
||||
}
|
||||
currentViewName := currentView.Name()
|
||||
var newTitle string
|
||||
if context, ok := gui.State.Contexts[currentViewName]; ok {
|
||||
newTitle = gui.contextTitleMap()[currentViewName][context]
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
@@ -63,7 +64,7 @@ func (gui *Gui) handleFileSelect(g *gocui.Gui, v *gocui.View, alreadySelected bo
|
||||
return gui.renderString(g, "main", gui.Tr.SLocalize("NoChangedFiles"))
|
||||
}
|
||||
|
||||
if err := gui.focusPoint(0, gui.State.Panels.Files.SelectedLine, v); err != nil {
|
||||
if err := gui.focusPoint(0, gui.State.Panels.Files.SelectedLine, len(gui.State.Files), v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -85,6 +86,10 @@ func (gui *Gui) refreshFiles() error {
|
||||
selectedFile, _ := gui.getSelectedFile(gui.g)
|
||||
|
||||
filesView := gui.getFilesView()
|
||||
if filesView == nil {
|
||||
// if the filesView hasn't been instantiated yet we just return
|
||||
return nil
|
||||
}
|
||||
if err := gui.refreshStateFiles(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -259,35 +264,6 @@ func (gui *Gui) handleAddPatch(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.Errors.ErrSubProcess
|
||||
}
|
||||
|
||||
func (gui *Gui) handleFileRemove(g *gocui.Gui, v *gocui.View) error {
|
||||
file, err := gui.getSelectedFile(g)
|
||||
if err != nil {
|
||||
if err == gui.Errors.ErrNoFiles {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
var deleteVerb string
|
||||
if file.Tracked {
|
||||
deleteVerb = gui.Tr.SLocalize("checkout")
|
||||
} else {
|
||||
deleteVerb = gui.Tr.SLocalize("delete")
|
||||
}
|
||||
message := gui.Tr.TemplateLocalize(
|
||||
"SureTo",
|
||||
Teml{
|
||||
"deleteVerb": deleteVerb,
|
||||
"fileName": file.Name,
|
||||
},
|
||||
)
|
||||
return gui.createConfirmationPanel(g, v, strings.Title(deleteVerb)+" file", message, func(g *gocui.Gui, v *gocui.View) error {
|
||||
if err := gui.GitCommand.RemoveFile(file); err != nil {
|
||||
return err
|
||||
}
|
||||
return gui.refreshFiles()
|
||||
}, nil)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleIgnoreFile(g *gocui.Gui, v *gocui.View) error {
|
||||
file, err := gui.getSelectedFile(g)
|
||||
if err != nil {
|
||||
@@ -302,6 +278,22 @@ func (gui *Gui) handleIgnoreFile(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.refreshFiles()
|
||||
}
|
||||
|
||||
func (gui *Gui) handleWIPCommitPress(g *gocui.Gui, filesView *gocui.View) error {
|
||||
skipHookPreifx := gui.Config.GetUserConfig().GetString("git.skipHookPrefix")
|
||||
if skipHookPreifx == "" {
|
||||
return gui.createErrorPanel(gui.g, gui.Tr.SLocalize("SkipHookPrefixNotConfigured"))
|
||||
}
|
||||
|
||||
if err := gui.renderString(g, "commitMessage", skipHookPreifx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gui.getCommitMessageView().SetCursor(len(skipHookPreifx), 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return gui.handleCommitPress(g, filesView)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleCommitPress(g *gocui.Gui, filesView *gocui.View) error {
|
||||
if len(gui.stagedFiles()) == 0 && gui.State.WorkingTreeState == "normal" {
|
||||
return gui.createErrorPanel(g, gui.Tr.SLocalize("NoStagedFilesToCommit"))
|
||||
@@ -328,9 +320,13 @@ func (gui *Gui) handleAmendCommitPress(g *gocui.Gui, filesView *gocui.View) erro
|
||||
question := gui.Tr.SLocalize("SureToAmend")
|
||||
|
||||
return gui.createConfirmationPanel(g, filesView, title, question, func(g *gocui.Gui, v *gocui.View) error {
|
||||
if err := gui.runSyncOrAsyncCommand(gui.GitCommand.AmendHead()); err != nil {
|
||||
ok, err := gui.runSyncOrAsyncCommand(gui.GitCommand.AmendHead())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return gui.refreshSidePanels(g)
|
||||
}, nil)
|
||||
@@ -355,13 +351,14 @@ func (gui *Gui) PrepareSubProcess(g *gocui.Gui, commands ...string) {
|
||||
}
|
||||
|
||||
func (gui *Gui) editFile(filename string) error {
|
||||
return gui.runSyncOrAsyncCommand(gui.OSCommand.EditFile(filename))
|
||||
_, err := gui.runSyncOrAsyncCommand(gui.OSCommand.EditFile(filename))
|
||||
return err
|
||||
}
|
||||
|
||||
func (gui *Gui) handleFileEdit(g *gocui.Gui, v *gocui.View) error {
|
||||
file, err := gui.getSelectedFile(g)
|
||||
if err != nil {
|
||||
return err
|
||||
return gui.createErrorPanel(gui.g, err.Error())
|
||||
}
|
||||
|
||||
return gui.editFile(file.Name)
|
||||
@@ -370,7 +367,7 @@ func (gui *Gui) handleFileEdit(g *gocui.Gui, v *gocui.View) error {
|
||||
func (gui *Gui) handleFileOpen(g *gocui.Gui, v *gocui.View) error {
|
||||
file, err := gui.getSelectedFile(g)
|
||||
if err != nil {
|
||||
return err
|
||||
return gui.createErrorPanel(gui.g, err.Error())
|
||||
}
|
||||
return gui.openFile(file.Name)
|
||||
}
|
||||
@@ -454,7 +451,7 @@ func (gui *Gui) handleSwitchToMerge(g *gocui.Gui, v *gocui.View) error {
|
||||
file, err := gui.getSelectedFile(g)
|
||||
if err != nil {
|
||||
if err != gui.Errors.ErrNoFiles {
|
||||
return err
|
||||
return gui.createErrorPanel(gui.g, err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -479,15 +476,6 @@ func (gui *Gui) handleAbortMerge(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.refreshFiles()
|
||||
}
|
||||
|
||||
func (gui *Gui) handleResetAndClean(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.createConfirmationPanel(g, v, gui.Tr.SLocalize("ClearFilePanel"), gui.Tr.SLocalize("SureResetHardHead"), func(g *gocui.Gui, v *gocui.View) error {
|
||||
if err := gui.GitCommand.ResetAndClean(); err != nil {
|
||||
gui.createErrorPanel(g, err.Error())
|
||||
}
|
||||
return gui.refreshFiles()
|
||||
}, nil)
|
||||
}
|
||||
|
||||
func (gui *Gui) openFile(filename string) error {
|
||||
if err := gui.OSCommand.OpenFile(filename); err != nil {
|
||||
return gui.createErrorPanel(gui.g, err.Error())
|
||||
@@ -504,15 +492,181 @@ func (gui *Gui) anyFilesWithMergeConflicts() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (gui *Gui) handleSoftReset(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.createConfirmationPanel(g, v, gui.Tr.SLocalize("SoftReset"), gui.Tr.SLocalize("ConfirmSoftReset"), func(g *gocui.Gui, v *gocui.View) error {
|
||||
if err := gui.GitCommand.SoftReset("HEAD^"); err != nil {
|
||||
return gui.createErrorPanel(g, err.Error())
|
||||
}
|
||||
type discardOption struct {
|
||||
handler func(fileName *commands.File) error
|
||||
description string
|
||||
}
|
||||
|
||||
if err := gui.refreshCommits(gui.g); err != nil {
|
||||
type discardAllOption struct {
|
||||
handler func() error
|
||||
description string
|
||||
command string
|
||||
}
|
||||
|
||||
// GetDisplayStrings is a function.
|
||||
func (r *discardOption) GetDisplayStrings(isFocused bool) []string {
|
||||
return []string{r.description}
|
||||
}
|
||||
|
||||
// GetDisplayStrings is a function.
|
||||
func (r *discardAllOption) GetDisplayStrings(isFocused bool) []string {
|
||||
return []string{r.description, color.New(color.FgRed).Sprint(r.command)}
|
||||
}
|
||||
|
||||
func (gui *Gui) handleCreateDiscardMenu(g *gocui.Gui, v *gocui.View) error {
|
||||
file, err := gui.getSelectedFile(g)
|
||||
if err != nil {
|
||||
if err != gui.Errors.ErrNoFiles {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
options := []*discardOption{
|
||||
{
|
||||
description: gui.Tr.SLocalize("discardAllChanges"),
|
||||
handler: func(file *commands.File) error {
|
||||
return gui.GitCommand.DiscardAllFileChanges(file)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: gui.Tr.SLocalize("cancel"),
|
||||
handler: func(file *commands.File) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if file.HasStagedChanges && file.HasUnstagedChanges {
|
||||
discardUnstagedChanges := &discardOption{
|
||||
description: gui.Tr.SLocalize("discardUnstagedChanges"),
|
||||
handler: func(file *commands.File) error {
|
||||
return gui.GitCommand.DiscardUnstagedFileChanges(file)
|
||||
},
|
||||
}
|
||||
|
||||
options = append(options[:1], append([]*discardOption{discardUnstagedChanges}, options[1:]...)...)
|
||||
}
|
||||
|
||||
handleMenuPress := func(index int) error {
|
||||
file, err := gui.getSelectedFile(g)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := options[index].handler(file); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return gui.refreshFiles()
|
||||
}, nil)
|
||||
}
|
||||
|
||||
return gui.createMenu(file.Name, options, len(options), handleMenuPress)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleCreateResetMenu(g *gocui.Gui, v *gocui.View) error {
|
||||
options := []*discardAllOption{
|
||||
{
|
||||
description: gui.Tr.SLocalize("discardAllChangesToAllFiles"),
|
||||
command: "reset --hard HEAD && git clean -fd",
|
||||
handler: func() error {
|
||||
return gui.GitCommand.ResetAndClean()
|
||||
},
|
||||
},
|
||||
{
|
||||
description: gui.Tr.SLocalize("discardAnyUnstagedChanges"),
|
||||
command: "git checkout -- .",
|
||||
handler: func() error {
|
||||
return gui.GitCommand.DiscardAnyUnstagedFileChanges()
|
||||
},
|
||||
},
|
||||
{
|
||||
description: gui.Tr.SLocalize("discardUntrackedFiles"),
|
||||
command: "git clean -fd",
|
||||
handler: func() error {
|
||||
return gui.GitCommand.RemoveUntrackedFiles()
|
||||
},
|
||||
},
|
||||
{
|
||||
description: gui.Tr.SLocalize("softReset"),
|
||||
command: "git reset --soft HEAD",
|
||||
handler: func() error {
|
||||
return gui.GitCommand.ResetSoftHead()
|
||||
},
|
||||
},
|
||||
{
|
||||
description: gui.Tr.SLocalize("hardReset"),
|
||||
command: "git reset --hard HEAD",
|
||||
handler: func() error {
|
||||
return gui.GitCommand.ResetHardHead()
|
||||
},
|
||||
},
|
||||
{
|
||||
description: gui.Tr.SLocalize("cancel"),
|
||||
handler: func() error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
handleMenuPress := func(index int) error {
|
||||
if err := options[index].handler(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return gui.refreshFiles()
|
||||
}
|
||||
|
||||
return gui.createMenu("", options, len(options), handleMenuPress)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleCustomCommand(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.createPromptPanel(g, v, gui.Tr.SLocalize("CustomCommand"), func(g *gocui.Gui, v *gocui.View) error {
|
||||
command := gui.trimmedContent(v)
|
||||
gui.SubProcess = gui.OSCommand.RunCustomCommand(command)
|
||||
return gui.Errors.ErrSubProcess
|
||||
})
|
||||
}
|
||||
|
||||
type stashOption struct {
|
||||
description string
|
||||
handler func() error
|
||||
}
|
||||
|
||||
// GetDisplayStrings is a function.
|
||||
func (o *stashOption) GetDisplayStrings(isFocused bool) []string {
|
||||
return []string{o.description}
|
||||
}
|
||||
|
||||
func (gui *Gui) handleCreateStashMenu(g *gocui.Gui, v *gocui.View) error {
|
||||
options := []*stashOption{
|
||||
{
|
||||
description: gui.Tr.SLocalize("stashAllChanges"),
|
||||
handler: func() error {
|
||||
return gui.handleStashSave(gui.GitCommand.StashSave)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: gui.Tr.SLocalize("stashStagedChanges"),
|
||||
handler: func() error {
|
||||
return gui.handleStashSave(gui.GitCommand.StashSaveStagedChanges)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: gui.Tr.SLocalize("cancel"),
|
||||
handler: func() error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
handleMenuPress := func(index int) error {
|
||||
return options[index].handler()
|
||||
}
|
||||
|
||||
return gui.createMenu(gui.Tr.SLocalize("stashOptions"), options, len(options), handleMenuPress)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleStashChanges(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.handleStashSave(gui.GitCommand.StashSave)
|
||||
}
|
||||
|
||||
372
pkg/gui/gui.go
372
pkg/gui/gui.go
@@ -1,14 +1,15 @@
|
||||
package gui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
// "io"
|
||||
// "io/ioutil"
|
||||
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -23,6 +24,7 @@ import (
|
||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
"github.com/jesseduffield/lazygit/pkg/i18n"
|
||||
"github.com/jesseduffield/lazygit/pkg/theme"
|
||||
"github.com/jesseduffield/lazygit/pkg/updates"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -103,7 +105,8 @@ type branchPanelState struct {
|
||||
}
|
||||
|
||||
type commitPanelState struct {
|
||||
SelectedLine int
|
||||
SelectedLine int
|
||||
SpecificDiffMode bool
|
||||
}
|
||||
|
||||
type stashPanelState struct {
|
||||
@@ -114,14 +117,19 @@ type menuPanelState struct {
|
||||
SelectedLine int
|
||||
}
|
||||
|
||||
type commitFilesPanelState struct {
|
||||
SelectedLine int
|
||||
}
|
||||
|
||||
type panelStates struct {
|
||||
Files *filePanelState
|
||||
Branches *branchPanelState
|
||||
Commits *commitPanelState
|
||||
Stash *stashPanelState
|
||||
Menu *menuPanelState
|
||||
Staging *stagingPanelState
|
||||
Merging *mergingPanelState
|
||||
Files *filePanelState
|
||||
Branches *branchPanelState
|
||||
Commits *commitPanelState
|
||||
Stash *stashPanelState
|
||||
Menu *menuPanelState
|
||||
Staging *stagingPanelState
|
||||
Merging *mergingPanelState
|
||||
CommitFiles *commitFilesPanelState
|
||||
}
|
||||
|
||||
type guiState struct {
|
||||
@@ -129,6 +137,9 @@ type guiState struct {
|
||||
Branches []*commands.Branch
|
||||
Commits []*commands.Commit
|
||||
StashEntries []*commands.StashEntry
|
||||
CommitFiles []*commands.CommitFile
|
||||
DiffEntries []*commands.Commit
|
||||
MenuItemCount int // can't store the actual list because it's of interface{} type
|
||||
PreviousView string
|
||||
Platform commands.Platform
|
||||
Updating bool
|
||||
@@ -147,13 +158,15 @@ func NewGui(log *logrus.Entry, gitCommand *commands.GitCommand, oSCommand *comma
|
||||
Commits: make([]*commands.Commit, 0),
|
||||
CherryPickedCommits: make([]*commands.Commit, 0),
|
||||
StashEntries: make([]*commands.StashEntry, 0),
|
||||
DiffEntries: make([]*commands.Commit, 0),
|
||||
Platform: *oSCommand.Platform,
|
||||
Panels: &panelStates{
|
||||
Files: &filePanelState{SelectedLine: -1},
|
||||
Branches: &branchPanelState{SelectedLine: 0},
|
||||
Commits: &commitPanelState{SelectedLine: -1},
|
||||
Stash: &stashPanelState{SelectedLine: -1},
|
||||
Menu: &menuPanelState{SelectedLine: 0},
|
||||
Files: &filePanelState{SelectedLine: -1},
|
||||
Branches: &branchPanelState{SelectedLine: 0},
|
||||
Commits: &commitPanelState{SelectedLine: -1},
|
||||
CommitFiles: &commitFilesPanelState{SelectedLine: -1},
|
||||
Stash: &stashPanelState{SelectedLine: -1},
|
||||
Menu: &menuPanelState{SelectedLine: 0},
|
||||
Merging: &mergingPanelState{
|
||||
ConflictIndex: 0,
|
||||
ConflictTop: true,
|
||||
@@ -213,20 +226,21 @@ func max(a, b int) int {
|
||||
|
||||
// getFocusLayout returns a manager function for when view gain and lose focus
|
||||
func (gui *Gui) getFocusLayout() func(g *gocui.Gui) error {
|
||||
var focusedView *gocui.View
|
||||
var previousView *gocui.View
|
||||
return func(g *gocui.Gui) error {
|
||||
v := gui.g.CurrentView()
|
||||
if v != focusedView {
|
||||
if err := gui.onFocusChange(); err != nil {
|
||||
newView := gui.g.CurrentView()
|
||||
if err := gui.onFocusChange(); err != nil {
|
||||
return err
|
||||
}
|
||||
// for now we don't consider losing focus to a popup panel as actually losing focus
|
||||
if newView != previousView && !gui.isPopupPanel(newView.Name()) {
|
||||
if err := gui.onFocusLost(previousView, newView); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gui.onFocusLost(focusedView); err != nil {
|
||||
if err := gui.onFocus(newView); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gui.onFocus(v); err != nil {
|
||||
return err
|
||||
}
|
||||
focusedView = v
|
||||
previousView = newView
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -240,21 +254,24 @@ func (gui *Gui) onFocusChange() error {
|
||||
return gui.setMainTitle()
|
||||
}
|
||||
|
||||
func (gui *Gui) onFocusLost(v *gocui.View) error {
|
||||
func (gui *Gui) onFocusLost(v *gocui.View, newView *gocui.View) error {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
if v.Name() == "branches" {
|
||||
// This stops the branches panel from showing the upstream/downstream changes to the selected branch, when it loses focus
|
||||
// inside renderListPanel it checks to see if the panel has focus
|
||||
if err := gui.renderListPanel(gui.getBranchesView(), gui.State.Branches); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if v.Name() == "main" {
|
||||
// if we have lost focus to a popup panel, that's okay
|
||||
if gui.popupPanelFocused() {
|
||||
return nil
|
||||
// if we have lost focus to a first-class panel, we need to do some cleanup
|
||||
if err := gui.changeContext("main", "normal"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := gui.changeContext("main", "normal"); err != nil {
|
||||
} else if v.Name() == "commitFiles" {
|
||||
if _, err := gui.g.SetViewOnBottom(v.Name()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -274,20 +291,75 @@ func (gui *Gui) onFocus(v *gocui.View) error {
|
||||
func (gui *Gui) layout(g *gocui.Gui) error {
|
||||
g.Highlight = true
|
||||
width, height := g.Size()
|
||||
|
||||
information := gui.Config.GetVersion()
|
||||
if gui.g.Mouse {
|
||||
donate := color.New(color.FgMagenta, color.Underline).Sprint(gui.Tr.SLocalize("Donate"))
|
||||
information = donate + " " + information
|
||||
}
|
||||
leftSideWidth := width / 3
|
||||
statusFilesBoundary := 2
|
||||
filesBranchesBoundary := 2 * height / 5
|
||||
commitsBranchesBoundary := 3 * height / 5
|
||||
optionsTop := height - 2
|
||||
commitsStashBoundary := optionsTop - 3
|
||||
optionsVersionBoundary := width - max(len(utils.Decolorise(information)), 1)
|
||||
minimumHeight := 18
|
||||
|
||||
minimumHeight := 9
|
||||
minimumWidth := 10
|
||||
if height < minimumHeight || width < minimumWidth {
|
||||
v, err := g.SetView("limit", 0, 0, width-1, height-1, 0)
|
||||
if err != nil {
|
||||
if err.Error() != "unknown view" {
|
||||
return err
|
||||
}
|
||||
v.Title = gui.Tr.SLocalize("NotEnoughSpace")
|
||||
v.Wrap = true
|
||||
_, _ = g.SetViewOnTop("limit")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
currView := gui.g.CurrentView()
|
||||
currentCyclebleView := gui.State.PreviousView
|
||||
if currView != nil {
|
||||
viewName := currView.Name()
|
||||
usePreviouseView := true
|
||||
for _, view := range cyclableViews {
|
||||
if view == viewName {
|
||||
currentCyclebleView = viewName
|
||||
usePreviouseView = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if usePreviouseView {
|
||||
currentCyclebleView = gui.State.PreviousView
|
||||
}
|
||||
}
|
||||
|
||||
usableSpace := height - 7
|
||||
extraSpace := usableSpace - (usableSpace/3)*3
|
||||
|
||||
vHeights := map[string]int{
|
||||
"status": 3,
|
||||
"files": (usableSpace / 3) + extraSpace,
|
||||
"branches": usableSpace / 3,
|
||||
"commits": usableSpace / 3,
|
||||
"stash": 3,
|
||||
"options": 1,
|
||||
}
|
||||
|
||||
if height < 28 {
|
||||
defaultHeight := 3
|
||||
if height < 21 {
|
||||
defaultHeight = 1
|
||||
}
|
||||
vHeights = map[string]int{
|
||||
"status": defaultHeight,
|
||||
"files": defaultHeight,
|
||||
"branches": defaultHeight,
|
||||
"commits": defaultHeight,
|
||||
"stash": defaultHeight,
|
||||
"options": defaultHeight,
|
||||
}
|
||||
vHeights[currentCyclebleView] = height - defaultHeight*4 - 1
|
||||
}
|
||||
|
||||
optionsVersionBoundary := width - max(len(utils.Decolorise(information)), 1)
|
||||
leftSideWidth := width / 3
|
||||
|
||||
appStatus := gui.statusManager.getStatusString()
|
||||
appStatusOptionsBoundary := 0
|
||||
@@ -300,103 +372,98 @@ func (gui *Gui) layout(g *gocui.Gui) error {
|
||||
panelSpacing = 0
|
||||
}
|
||||
|
||||
if height < minimumHeight || width < minimumWidth {
|
||||
v, err := g.SetView("limit", 0, 0, max(width-1, 2), max(height-1, 2), 0)
|
||||
if err != nil {
|
||||
if err.Error() != "unknown view" {
|
||||
return err
|
||||
}
|
||||
v.Title = gui.Tr.SLocalize("NotEnoughSpace")
|
||||
v.Wrap = true
|
||||
g.SetViewOnTop("limit")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
_, _ = g.SetViewOnBottom("limit")
|
||||
g.DeleteView("limit")
|
||||
|
||||
v, err := g.SetView("main", leftSideWidth+panelSpacing, 0, width-1, optionsTop, gocui.LEFT)
|
||||
textColor := theme.GocuiDefaultTextColor
|
||||
v, err := g.SetView("main", leftSideWidth+panelSpacing, 0, width-1, height-2, gocui.LEFT)
|
||||
if err != nil {
|
||||
if err.Error() != "unknown view" {
|
||||
return err
|
||||
}
|
||||
v.Title = gui.Tr.SLocalize("DiffTitle")
|
||||
v.Wrap = true
|
||||
v.FgColor = gocui.ColorWhite
|
||||
v.FgColor = textColor
|
||||
}
|
||||
|
||||
if v, err := g.SetView("status", 0, 0, leftSideWidth, statusFilesBoundary, gocui.BOTTOM|gocui.RIGHT); err != nil {
|
||||
if v, err := g.SetView("status", 0, 0, leftSideWidth, vHeights["status"]-1, gocui.BOTTOM|gocui.RIGHT); err != nil {
|
||||
if err.Error() != "unknown view" {
|
||||
return err
|
||||
}
|
||||
v.Title = gui.Tr.SLocalize("StatusTitle")
|
||||
v.FgColor = gocui.ColorWhite
|
||||
v.FgColor = textColor
|
||||
}
|
||||
|
||||
filesView, err := g.SetView("files", 0, statusFilesBoundary+panelSpacing, leftSideWidth, filesBranchesBoundary, gocui.TOP|gocui.BOTTOM)
|
||||
filesView, err := g.SetViewBeneath("files", "status", vHeights["files"])
|
||||
if err != nil {
|
||||
if err.Error() != "unknown view" {
|
||||
return err
|
||||
}
|
||||
filesView.Highlight = true
|
||||
filesView.Title = gui.Tr.SLocalize("FilesTitle")
|
||||
v.FgColor = gocui.ColorWhite
|
||||
v.FgColor = textColor
|
||||
}
|
||||
|
||||
branchesView, err := g.SetView("branches", 0, filesBranchesBoundary+panelSpacing, leftSideWidth, commitsBranchesBoundary, gocui.TOP|gocui.BOTTOM)
|
||||
branchesView, err := g.SetViewBeneath("branches", "files", vHeights["branches"])
|
||||
if err != nil {
|
||||
if err.Error() != "unknown view" {
|
||||
return err
|
||||
}
|
||||
branchesView.Title = gui.Tr.SLocalize("BranchesTitle")
|
||||
branchesView.FgColor = gocui.ColorWhite
|
||||
branchesView.FgColor = textColor
|
||||
}
|
||||
|
||||
commitsView, err := g.SetView("commits", 0, commitsBranchesBoundary+panelSpacing, leftSideWidth, commitsStashBoundary, gocui.TOP|gocui.BOTTOM)
|
||||
if v, err := g.SetViewBeneath("commitFiles", "branches", vHeights["commits"]); err != nil {
|
||||
if err.Error() != "unknown view" {
|
||||
return err
|
||||
}
|
||||
v.Title = gui.Tr.SLocalize("CommitFiles")
|
||||
v.FgColor = textColor
|
||||
}
|
||||
|
||||
commitsView, err := g.SetViewBeneath("commits", "branches", vHeights["commits"])
|
||||
if err != nil {
|
||||
if err.Error() != "unknown view" {
|
||||
return err
|
||||
}
|
||||
commitsView.Title = gui.Tr.SLocalize("CommitsTitle")
|
||||
commitsView.FgColor = gocui.ColorWhite
|
||||
commitsView.FgColor = textColor
|
||||
}
|
||||
|
||||
stashView, err := g.SetView("stash", 0, commitsStashBoundary+panelSpacing, leftSideWidth, optionsTop, gocui.TOP|gocui.RIGHT)
|
||||
stashView, err := g.SetViewBeneath("stash", "commits", vHeights["stash"])
|
||||
if err != nil {
|
||||
if err.Error() != "unknown view" {
|
||||
return err
|
||||
}
|
||||
stashView.Title = gui.Tr.SLocalize("StashTitle")
|
||||
stashView.FgColor = gocui.ColorWhite
|
||||
stashView.FgColor = textColor
|
||||
}
|
||||
|
||||
if v, err := g.SetView("options", appStatusOptionsBoundary-1, optionsTop, optionsVersionBoundary-1, optionsTop+2, 0); err != nil {
|
||||
if v, err := g.SetView("options", appStatusOptionsBoundary-1, height-2, optionsVersionBoundary-1, height, 0); err != nil {
|
||||
if err.Error() != "unknown view" {
|
||||
return err
|
||||
}
|
||||
v.Frame = false
|
||||
if v.FgColor, err = gui.GetOptionsPanelTextColor(); err != nil {
|
||||
return err
|
||||
}
|
||||
userConfig := gui.Config.GetUserConfig()
|
||||
v.FgColor = theme.GetColor(userConfig.GetStringSlice("gui.theme.optionsTextColor"))
|
||||
}
|
||||
|
||||
if gui.getCommitMessageView() == nil {
|
||||
// doesn't matter where this view starts because it will be hidden
|
||||
if commitMessageView, err := g.SetView("commitMessage", 0, 0, width/2, height/2, 0); err != nil {
|
||||
if commitMessageView, err := g.SetView("commitMessage", width, height, width*2, height*2, 0); err != nil {
|
||||
if err.Error() != "unknown view" {
|
||||
return err
|
||||
}
|
||||
g.SetViewOnBottom("commitMessage")
|
||||
commitMessageView.Title = gui.Tr.SLocalize("CommitMessage")
|
||||
commitMessageView.FgColor = gocui.ColorWhite
|
||||
commitMessageView.FgColor = textColor
|
||||
commitMessageView.Editable = true
|
||||
commitMessageView.Editor = gocui.EditorFunc(gui.simpleEditor)
|
||||
}
|
||||
}
|
||||
|
||||
if check, _ := g.View("credentials"); check == nil {
|
||||
// doesn't matter where this view starts because it will be hidden
|
||||
if credentialsView, err := g.SetView("credentials", 0, 0, width/2, height/2, 0); err != nil {
|
||||
if credentialsView, err := g.SetView("credentials", width, height, width*2, height*2, 0); err != nil {
|
||||
if err.Error() != "unknown view" {
|
||||
return err
|
||||
}
|
||||
@@ -405,13 +472,12 @@ func (gui *Gui) layout(g *gocui.Gui) error {
|
||||
return err
|
||||
}
|
||||
credentialsView.Title = gui.Tr.SLocalize("CredentialsUsername")
|
||||
credentialsView.FgColor = gocui.ColorWhite
|
||||
credentialsView.FgColor = textColor
|
||||
credentialsView.Editable = true
|
||||
credentialsView.Editor = gocui.EditorFunc(gui.simpleEditor)
|
||||
}
|
||||
}
|
||||
|
||||
if appStatusView, err := g.SetView("appStatus", -1, optionsTop, width, optionsTop+2, 0); err != nil {
|
||||
if appStatusView, err := g.SetView("appStatus", -1, height-2, width, height, 0); err != nil {
|
||||
if err.Error() != "unknown view" {
|
||||
return err
|
||||
}
|
||||
@@ -423,7 +489,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
|
||||
}
|
||||
}
|
||||
|
||||
if v, err := g.SetView("information", optionsVersionBoundary-1, optionsTop, width, optionsTop+2, 0); err != nil {
|
||||
if v, err := g.SetView("information", optionsVersionBoundary-1, height-2, width, height, 0); err != nil {
|
||||
if err.Error() != "unknown view" {
|
||||
return err
|
||||
}
|
||||
@@ -434,47 +500,41 @@ func (gui *Gui) layout(g *gocui.Gui) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// these are only called once (it's a place to put all the things you want
|
||||
// to happen on startup after the screen is first rendered)
|
||||
gui.Updater.CheckForNewUpdate(gui.onBackgroundUpdateCheckFinish, false)
|
||||
if err := gui.updateRecentRepoList(); err != nil {
|
||||
// doing this here because it'll only happen once
|
||||
if err := gui.loadNewRepo(); err != nil {
|
||||
return err
|
||||
}
|
||||
gui.waitForIntro.Done()
|
||||
|
||||
if _, err := gui.g.SetCurrentView(filesView.Name()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := gui.refreshSidePanels(gui.g); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := gui.switchFocus(g, nil, filesView); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if gui.Config.GetUserConfig().GetString("reporting") == "undetermined" {
|
||||
if err := gui.promptAnonymousReporting(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
listViews := map[*gocui.View]int{
|
||||
filesView: gui.State.Panels.Files.SelectedLine,
|
||||
branchesView: gui.State.Panels.Branches.SelectedLine,
|
||||
commitsView: gui.State.Panels.Commits.SelectedLine,
|
||||
stashView: gui.State.Panels.Stash.SelectedLine,
|
||||
if gui.g.CurrentView() == nil {
|
||||
if _, err := gui.g.SetCurrentView(gui.getFilesView().Name()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := gui.switchFocus(gui.g, nil, gui.getFilesView()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
type listViewState struct {
|
||||
selectedLine int
|
||||
lineCount int
|
||||
}
|
||||
|
||||
listViews := map[*gocui.View]listViewState{
|
||||
filesView: {selectedLine: gui.State.Panels.Files.SelectedLine, lineCount: len(gui.State.Files)},
|
||||
branchesView: {selectedLine: gui.State.Panels.Branches.SelectedLine, lineCount: len(gui.State.Branches)},
|
||||
commitsView: {selectedLine: gui.State.Panels.Commits.SelectedLine, lineCount: len(gui.State.Commits)},
|
||||
stashView: {selectedLine: gui.State.Panels.Stash.SelectedLine, lineCount: len(gui.State.StashEntries)},
|
||||
}
|
||||
|
||||
// menu view might not exist so we check to be safe
|
||||
if menuView, err := gui.g.View("menu"); err == nil {
|
||||
listViews[menuView] = gui.State.Panels.Menu.SelectedLine
|
||||
listViews[menuView] = listViewState{selectedLine: gui.State.Panels.Menu.SelectedLine, lineCount: gui.State.MenuItemCount}
|
||||
}
|
||||
for view, selectedLine := range listViews {
|
||||
for view, state := range listViews {
|
||||
// check if the selected line is now out of view and if so refocus it
|
||||
if err := gui.focusPoint(0, selectedLine, view); err != nil {
|
||||
if err := gui.focusPoint(0, state.selectedLine, state.lineCount, view); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -486,6 +546,25 @@ func (gui *Gui) layout(g *gocui.Gui) error {
|
||||
return gui.resizeCurrentPopupPanel(g)
|
||||
}
|
||||
|
||||
func (gui *Gui) loadNewRepo() error {
|
||||
gui.Updater.CheckForNewUpdate(gui.onBackgroundUpdateCheckFinish, false)
|
||||
if err := gui.updateRecentRepoList(); err != nil {
|
||||
return err
|
||||
}
|
||||
gui.waitForIntro.Done()
|
||||
|
||||
if err := gui.refreshSidePanels(gui.g); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if gui.Config.GetUserConfig().GetString("reporting") == "undetermined" {
|
||||
if err := gui.promptAnonymousReporting(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) promptAnonymousReporting() error {
|
||||
return gui.createConfirmationPanel(gui.g, nil, gui.Tr.SLocalize("AnonymousReportingTitle"), gui.Tr.SLocalize("AnonymousReportingPrompt"), func(g *gocui.Gui, v *gocui.View) error {
|
||||
gui.waitForIntro.Done()
|
||||
@@ -530,6 +609,7 @@ func (gui *Gui) renderGlobalOptions() error {
|
||||
"← → ↑ ↓": gui.Tr.SLocalize("navigate"),
|
||||
"esc/q": gui.Tr.SLocalize("close"),
|
||||
"x": gui.Tr.SLocalize("menu"),
|
||||
"1-5": gui.Tr.SLocalize("jump"),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -541,6 +621,23 @@ func (gui *Gui) goEvery(interval time.Duration, function func() error) {
|
||||
}()
|
||||
}
|
||||
|
||||
func (gui *Gui) startBackgroundFetch() {
|
||||
gui.waitForIntro.Wait()
|
||||
isNew := gui.Config.GetIsNewRepo()
|
||||
if !isNew {
|
||||
time.After(60 * time.Second)
|
||||
}
|
||||
_, err := gui.fetch(gui.g, gui.g.CurrentView(), false)
|
||||
if err != nil && strings.Contains(err.Error(), "exit status 128") && isNew {
|
||||
_ = gui.createConfirmationPanel(gui.g, gui.g.CurrentView(), gui.Tr.SLocalize("NoAutomaticGitFetchTitle"), gui.Tr.SLocalize("NoAutomaticGitFetchBody"), nil, nil)
|
||||
} else {
|
||||
gui.goEvery(time.Second*60, func() error {
|
||||
_, err := gui.fetch(gui.g, gui.g.CurrentView(), false)
|
||||
return err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Run setup the gui with keybindings and start the mainloop
|
||||
func (gui *Gui) Run() error {
|
||||
g, err := gocui.NewGui(gocui.OutputNormal, OverlappingEdges)
|
||||
@@ -555,7 +652,7 @@ func (gui *Gui) Run() error {
|
||||
|
||||
gui.g = g // TODO: always use gui.g rather than passing g around everywhere
|
||||
|
||||
if err := gui.SetColorScheme(); err != nil {
|
||||
if err := gui.setColorScheme(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -565,22 +662,9 @@ func (gui *Gui) Run() error {
|
||||
gui.waitForIntro.Add(1)
|
||||
}
|
||||
|
||||
go func() {
|
||||
gui.waitForIntro.Wait()
|
||||
isNew := gui.Config.GetIsNewRepo()
|
||||
if !isNew {
|
||||
time.After(60 * time.Second)
|
||||
}
|
||||
_, err := gui.fetch(g, g.CurrentView(), false)
|
||||
if err != nil && strings.Contains(err.Error(), "exit status 128") && isNew {
|
||||
_ = gui.createConfirmationPanel(g, g.CurrentView(), gui.Tr.SLocalize("NoAutomaticGitFetchTitle"), gui.Tr.SLocalize("NoAutomaticGitFetchBody"), nil, nil)
|
||||
} else {
|
||||
gui.goEvery(time.Second*60, func() error {
|
||||
_, err := gui.fetch(gui.g, gui.g.CurrentView(), false)
|
||||
return err
|
||||
})
|
||||
}
|
||||
}()
|
||||
if gui.Config.GetUserConfig().GetBool("git.autoFetch") {
|
||||
go gui.startBackgroundFetch()
|
||||
}
|
||||
gui.goEvery(time.Second*10, gui.refreshFiles)
|
||||
gui.goEvery(time.Millisecond*50, gui.renderAppStatus)
|
||||
|
||||
@@ -605,14 +689,9 @@ func (gui *Gui) RunWithSubprocesses() error {
|
||||
} else if err == gui.Errors.ErrSwitchRepo {
|
||||
continue
|
||||
} else if err == gui.Errors.ErrSubProcess {
|
||||
gui.SubProcess.Stdin = os.Stdin
|
||||
gui.SubProcess.Stdout = os.Stdout
|
||||
gui.SubProcess.Stderr = os.Stderr
|
||||
gui.SubProcess.Run()
|
||||
gui.SubProcess.Stdout = ioutil.Discard
|
||||
gui.SubProcess.Stderr = ioutil.Discard
|
||||
gui.SubProcess.Stdin = nil
|
||||
gui.SubProcess = nil
|
||||
if err := gui.runCommand(); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
@@ -621,6 +700,30 @@ func (gui *Gui) RunWithSubprocesses() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) runCommand() error {
|
||||
gui.SubProcess.Stdout = os.Stdout
|
||||
gui.SubProcess.Stderr = os.Stdout
|
||||
gui.SubProcess.Stdin = os.Stdin
|
||||
|
||||
fmt.Fprintf(os.Stdout, "\n%s\n\n", utils.ColoredString("+ "+strings.Join(gui.SubProcess.Args, " "), color.FgBlue))
|
||||
|
||||
if err := gui.SubProcess.Run(); err != nil {
|
||||
// not handling the error explicitly because usually we're going to see it
|
||||
// in the output anyway
|
||||
gui.Log.Error(err)
|
||||
}
|
||||
|
||||
gui.SubProcess.Stdout = ioutil.Discard
|
||||
gui.SubProcess.Stderr = ioutil.Discard
|
||||
gui.SubProcess.Stdin = nil
|
||||
gui.SubProcess = nil
|
||||
|
||||
fmt.Fprintf(os.Stdout, "\n%s", utils.ColoredString(gui.Tr.SLocalize("pressEnterToReturn"), color.FgGreen))
|
||||
fmt.Scanln() // wait for enter press
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) quit(g *gocui.Gui, v *gocui.View) error {
|
||||
if gui.State.Updating {
|
||||
return gui.createUpdateQuitConfirmation(g, v)
|
||||
@@ -644,3 +747,14 @@ func (gui *Gui) handleDonate(g *gocui.Gui, v *gocui.View) error {
|
||||
}
|
||||
return gui.OSCommand.OpenLink("https://donorbox.org/lazygit")
|
||||
}
|
||||
|
||||
// setColorScheme sets the color scheme for the app based on the user config
|
||||
func (gui *Gui) setColorScheme() error {
|
||||
userConfig := gui.Config.GetUserConfig()
|
||||
theme.UpdateTheme(userConfig)
|
||||
|
||||
gui.g.FgColor = theme.InactiveBorderColor
|
||||
gui.g.SelFgColor = theme.ActiveBorderColor
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ type Binding struct {
|
||||
Key interface{} // FIXME: find out how to get `gocui.Key | rune`
|
||||
Modifier gocui.Modifier
|
||||
Description string
|
||||
Alternative string
|
||||
}
|
||||
|
||||
// GetDisplayStrings returns the display string of a file
|
||||
@@ -28,6 +29,12 @@ func (b *Binding) GetKey() string {
|
||||
case rune:
|
||||
key = int(b.Key.(rune))
|
||||
case gocui.Key:
|
||||
if b.Key.(gocui.Key) == gocui.KeyCtrlJ {
|
||||
return "ctrl+j"
|
||||
}
|
||||
if b.Key.(gocui.Key) == gocui.KeyCtrlK {
|
||||
return "ctrl+k"
|
||||
}
|
||||
key = int(b.Key.(gocui.Key))
|
||||
}
|
||||
|
||||
@@ -74,14 +81,26 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||
Key: gocui.KeyEsc,
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.quit,
|
||||
}, {
|
||||
ViewName: "",
|
||||
Key: gocui.KeyPgup,
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.scrollUpMain,
|
||||
Alternative: "fn+up",
|
||||
}, {
|
||||
ViewName: "",
|
||||
Key: gocui.KeyPgdn,
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.scrollDownMain,
|
||||
Alternative: "fn+down",
|
||||
}, {
|
||||
ViewName: "",
|
||||
Key: gocui.KeyPgup,
|
||||
Key: 'K',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.scrollUpMain,
|
||||
}, {
|
||||
ViewName: "",
|
||||
Key: gocui.KeyPgdn,
|
||||
Key: 'J',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.scrollDownMain,
|
||||
}, {
|
||||
@@ -154,6 +173,13 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleCommitPress,
|
||||
Description: gui.Tr.SLocalize("CommitChanges"),
|
||||
},
|
||||
{
|
||||
ViewName: "files",
|
||||
Key: 'w',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleWIPCommitPress,
|
||||
Description: gui.Tr.SLocalize("commitChangesWithoutHook"),
|
||||
}, {
|
||||
ViewName: "files",
|
||||
Key: 'A',
|
||||
@@ -176,8 +202,8 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||
ViewName: "files",
|
||||
Key: 'd',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleFileRemove,
|
||||
Description: gui.Tr.SLocalize("removeFile"),
|
||||
Handler: gui.handleCreateDiscardMenu,
|
||||
Description: gui.Tr.SLocalize("viewDiscardOptions"),
|
||||
}, {
|
||||
ViewName: "files",
|
||||
Key: 'e',
|
||||
@@ -202,18 +228,18 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleRefreshFiles,
|
||||
Description: gui.Tr.SLocalize("refreshFiles"),
|
||||
}, {
|
||||
ViewName: "files",
|
||||
Key: 'S',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleStashSave,
|
||||
Description: gui.Tr.SLocalize("stashFiles"),
|
||||
}, {
|
||||
ViewName: "files",
|
||||
Key: 's',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleSoftReset,
|
||||
Description: gui.Tr.SLocalize("softReset"),
|
||||
Handler: gui.handleStashChanges,
|
||||
Description: gui.Tr.SLocalize("stashAllChanges"),
|
||||
}, {
|
||||
ViewName: "files",
|
||||
Key: 'S',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleCreateStashMenu,
|
||||
Description: gui.Tr.SLocalize("viewStashOptions"),
|
||||
}, {
|
||||
ViewName: "files",
|
||||
Key: 'a',
|
||||
@@ -230,8 +256,8 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||
ViewName: "files",
|
||||
Key: 'D',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleResetAndClean,
|
||||
Description: gui.Tr.SLocalize("resetHard"),
|
||||
Handler: gui.handleCreateResetMenu,
|
||||
Description: gui.Tr.SLocalize("viewResetOptions"),
|
||||
}, {
|
||||
ViewName: "files",
|
||||
Key: gocui.KeyEnter,
|
||||
@@ -244,6 +270,12 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleGitFetch,
|
||||
Description: gui.Tr.SLocalize("fetch"),
|
||||
}, {
|
||||
ViewName: "files",
|
||||
Key: 'X',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleCustomCommand,
|
||||
Description: gui.Tr.SLocalize("executeCustomCommand"),
|
||||
}, {
|
||||
ViewName: "branches",
|
||||
Key: gocui.KeySpace,
|
||||
@@ -320,7 +352,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||
ViewName: "commits",
|
||||
Key: 'g',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleResetToCommit,
|
||||
Handler: gui.handleCreateCommitResetMenu,
|
||||
Description: gui.Tr.SLocalize("resetToThisCommit"),
|
||||
}, {
|
||||
ViewName: "commits",
|
||||
@@ -328,6 +360,18 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleCommitFixup,
|
||||
Description: gui.Tr.SLocalize("fixupCommit"),
|
||||
}, {
|
||||
ViewName: "commits",
|
||||
Key: 'F',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleCreateFixupCommit,
|
||||
Description: gui.Tr.SLocalize("createFixupCommit"),
|
||||
}, {
|
||||
ViewName: "commits",
|
||||
Key: 'S',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleSquashAllAboveFixupCommits,
|
||||
Description: gui.Tr.SLocalize("squashAboveCommits"),
|
||||
}, {
|
||||
ViewName: "commits",
|
||||
Key: 'd',
|
||||
@@ -336,13 +380,13 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||
Description: gui.Tr.SLocalize("deleteCommit"),
|
||||
}, {
|
||||
ViewName: "commits",
|
||||
Key: 'J',
|
||||
Key: gocui.KeyCtrlJ,
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleCommitMoveDown,
|
||||
Description: gui.Tr.SLocalize("moveDownCommit"),
|
||||
}, {
|
||||
ViewName: "commits",
|
||||
Key: 'K',
|
||||
Key: gocui.KeyCtrlK,
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleCommitMoveUp,
|
||||
Description: gui.Tr.SLocalize("moveUpCommit"),
|
||||
@@ -388,6 +432,18 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.HandlePasteCommits,
|
||||
Description: gui.Tr.SLocalize("pasteCommits"),
|
||||
}, {
|
||||
ViewName: "commits",
|
||||
Key: gocui.KeyEnter,
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleSwitchToCommitFilesPanel,
|
||||
Description: gui.Tr.SLocalize("viewCommitFiles"),
|
||||
}, {
|
||||
ViewName: "commits",
|
||||
Key: gocui.KeySpace,
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleToggleDiffCommit,
|
||||
Description: gui.Tr.SLocalize("CommitsDiff"),
|
||||
}, {
|
||||
ViewName: "stash",
|
||||
Key: gocui.KeySpace,
|
||||
@@ -441,10 +497,35 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||
Key: gocui.MouseLeft,
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleDonate,
|
||||
}, {
|
||||
ViewName: "commitFiles",
|
||||
Key: gocui.KeyEsc,
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleSwitchToCommitsPanel,
|
||||
Description: gui.Tr.SLocalize("goBack"),
|
||||
}, {
|
||||
ViewName: "commitFiles",
|
||||
Key: 'c',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleCheckoutCommitFile,
|
||||
Description: gui.Tr.SLocalize("checkoutCommitFile"),
|
||||
}, {
|
||||
ViewName: "commitFiles",
|
||||
Key: 'd',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleDiscardOldFileChange,
|
||||
Description: gui.Tr.SLocalize("discardOldFileChange"),
|
||||
},
|
||||
{
|
||||
ViewName: "commitFiles",
|
||||
Key: 'o',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleOpenOldCommitFile,
|
||||
Description: gui.Tr.SLocalize("openFile"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, viewName := range []string{"status", "branches", "files", "commits", "stash", "menu"} {
|
||||
for _, viewName := range []string{"status", "branches", "files", "commits", "commitFiles", "stash", "menu"} {
|
||||
bindings = append(bindings, []*Binding{
|
||||
{ViewName: viewName, Key: gocui.KeyTab, Modifier: gocui.ModNone, Handler: gui.nextView},
|
||||
{ViewName: viewName, Key: gocui.KeyArrowLeft, Modifier: gocui.ModNone, Handler: gui.previousView},
|
||||
@@ -454,17 +535,23 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||
}...)
|
||||
}
|
||||
|
||||
// Appends keybindings to jump to a particular sideView using numbers
|
||||
for i, viewName := range []string{"status", "files", "branches", "commits", "stash"} {
|
||||
bindings = append(bindings, &Binding{ViewName: "", Key: rune(i+1) + '0', Modifier: gocui.ModNone, Handler: gui.goToSideView(viewName)})
|
||||
}
|
||||
|
||||
listPanelMap := map[string]struct {
|
||||
prevLine func(*gocui.Gui, *gocui.View) error
|
||||
nextLine func(*gocui.Gui, *gocui.View) error
|
||||
focus func(*gocui.Gui, *gocui.View) error
|
||||
}{
|
||||
"menu": {prevLine: gui.handleMenuPrevLine, nextLine: gui.handleMenuNextLine, focus: gui.handleMenuSelect},
|
||||
"files": {prevLine: gui.handleFilesPrevLine, nextLine: gui.handleFilesNextLine, focus: gui.handleFilesFocus},
|
||||
"branches": {prevLine: gui.handleBranchesPrevLine, nextLine: gui.handleBranchesNextLine, focus: gui.handleBranchSelect},
|
||||
"commits": {prevLine: gui.handleCommitsPrevLine, nextLine: gui.handleCommitsNextLine, focus: gui.handleCommitSelect},
|
||||
"stash": {prevLine: gui.handleStashPrevLine, nextLine: gui.handleStashNextLine, focus: gui.handleStashEntrySelect},
|
||||
"status": {focus: gui.handleStatusSelect},
|
||||
"menu": {prevLine: gui.handleMenuPrevLine, nextLine: gui.handleMenuNextLine, focus: gui.handleMenuSelect},
|
||||
"files": {prevLine: gui.handleFilesPrevLine, nextLine: gui.handleFilesNextLine, focus: gui.handleFilesFocus},
|
||||
"branches": {prevLine: gui.handleBranchesPrevLine, nextLine: gui.handleBranchesNextLine, focus: gui.handleBranchSelect},
|
||||
"commits": {prevLine: gui.handleCommitsPrevLine, nextLine: gui.handleCommitsNextLine, focus: gui.handleCommitSelect},
|
||||
"stash": {prevLine: gui.handleStashPrevLine, nextLine: gui.handleStashNextLine, focus: gui.handleStashEntrySelect},
|
||||
"status": {focus: gui.handleStatusSelect},
|
||||
"commitFiles": {prevLine: gui.handleCommitFilesPrevLine, nextLine: gui.handleCommitFilesNextLine, focus: gui.handleCommitFileSelect},
|
||||
}
|
||||
|
||||
for viewName, functions := range listPanelMap {
|
||||
@@ -516,12 +603,14 @@ func (gui *Gui) GetContextMap() map[string]map[string][]*Binding {
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.scrollDownMain,
|
||||
Description: gui.Tr.SLocalize("ScrollDown"),
|
||||
Alternative: "fn+up",
|
||||
}, {
|
||||
ViewName: "main",
|
||||
Key: gocui.MouseWheelUp,
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.scrollUpMain,
|
||||
Description: gui.Tr.SLocalize("ScrollUp"),
|
||||
Alternative: "fn+down",
|
||||
},
|
||||
},
|
||||
"staging": {
|
||||
|
||||
@@ -4,13 +4,14 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/theme"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
|
||||
// list panel functions
|
||||
|
||||
func (gui *Gui) handleMenuSelect(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.focusPoint(0, gui.State.Panels.Menu.SelectedLine, v)
|
||||
return gui.focusPoint(0, gui.State.Panels.Menu.SelectedLine, gui.State.MenuItemCount, v)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleMenuNextLine(g *gocui.Gui, v *gocui.View) error {
|
||||
@@ -51,8 +52,9 @@ func (gui *Gui) handleMenuClose(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.returnFocus(g, v)
|
||||
}
|
||||
|
||||
func (gui *Gui) createMenu(title string, items interface{}, handlePress func(int) error) error {
|
||||
func (gui *Gui) createMenu(title string, items interface{}, itemCount int, handlePress func(int) error) error {
|
||||
isFocused := gui.g.CurrentView().Name() == "menu"
|
||||
gui.State.MenuItemCount = itemCount
|
||||
list, err := utils.RenderList(items, isFocused)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -61,7 +63,7 @@ func (gui *Gui) createMenu(title string, items interface{}, handlePress func(int
|
||||
x0, y0, x1, y1 := gui.getConfirmationPanelDimensions(gui.g, false, list)
|
||||
menuView, _ := gui.g.SetView("menu", x0, y0, x1, y1, 0)
|
||||
menuView.Title = title
|
||||
menuView.FgColor = gocui.ColorWhite
|
||||
menuView.FgColor = theme.GocuiDefaultTextColor
|
||||
menuView.Clear()
|
||||
fmt.Fprint(menuView, list)
|
||||
gui.State.Panels.Menu.SelectedLine = 0
|
||||
@@ -81,6 +83,8 @@ func (gui *Gui) createMenu(title string, items interface{}, handlePress func(int
|
||||
}
|
||||
|
||||
for _, key := range []gocui.Key{gocui.KeySpace, gocui.KeyEnter} {
|
||||
_ = gui.g.DeleteKeybinding("menu", key, gocui.ModNone)
|
||||
|
||||
if err := gui.g.SetKeybinding("menu", key, gocui.ModNone, wrappedHandlePress); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/golang-collections/collections/stack"
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/theme"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
|
||||
@@ -50,7 +51,7 @@ func (gui *Gui) coloredConflictFile(content string, conflicts []commands.Conflic
|
||||
conflict, remainingConflicts := gui.shiftConflict(conflicts)
|
||||
var outputBuffer bytes.Buffer
|
||||
for i, line := range utils.SplitLines(content) {
|
||||
colourAttr := color.FgWhite
|
||||
colourAttr := theme.DefaultTextColor
|
||||
if i == conflict.Start || i == conflict.Middle || i == conflict.End {
|
||||
colourAttr = color.FgRed
|
||||
}
|
||||
|
||||
@@ -49,5 +49,5 @@ func (gui *Gui) handleCreateOptionsMenu(g *gocui.Gui, v *gocui.View) error {
|
||||
return bindings[index].Handler(g, v)
|
||||
}
|
||||
|
||||
return gui.createMenu(strings.Title(gui.Tr.SLocalize("menu")), bindings, handleMenuPress)
|
||||
return gui.createMenu(strings.Title(gui.Tr.SLocalize("menu")), bindings, len(bindings), handleMenuPress)
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ func (gui *Gui) handleCreateRebaseOptionsMenu(g *gocui.Gui, v *gocui.View) error
|
||||
title = gui.Tr.SLocalize("RebaseOptionsTitle")
|
||||
}
|
||||
|
||||
return gui.createMenu(title, options, handleMenuPress)
|
||||
return gui.createMenu(title, options, len(options), handleMenuPress)
|
||||
}
|
||||
|
||||
func (gui *Gui) genericMergeCommand(command string) error {
|
||||
|
||||
@@ -44,7 +44,7 @@ func (gui *Gui) handleCreateRecentReposMenu(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.Errors.ErrSwitchRepo
|
||||
}
|
||||
|
||||
return gui.createMenu(gui.Tr.SLocalize("RecentRepos"), recentRepos, handleMenuPress)
|
||||
return gui.createMenu(gui.Tr.SLocalize("RecentRepos"), recentRepos, len(recentRepos), handleMenuPress)
|
||||
}
|
||||
|
||||
// updateRecentRepoList registers the fact that we opened lazygit in this repo,
|
||||
|
||||
@@ -31,7 +31,7 @@ func (gui *Gui) handleStashEntrySelect(g *gocui.Gui, v *gocui.View) error {
|
||||
if stashEntry == nil {
|
||||
return gui.renderString(g, "main", gui.Tr.SLocalize("NoStashEntries"))
|
||||
}
|
||||
if err := gui.focusPoint(0, gui.State.Panels.Stash.SelectedLine, v); err != nil {
|
||||
if err := gui.focusPoint(0, gui.State.Panels.Stash.SelectedLine, len(gui.State.StashEntries), v); err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
@@ -130,16 +130,15 @@ func (gui *Gui) stashDo(g *gocui.Gui, v *gocui.View, method string) error {
|
||||
return gui.refreshFiles()
|
||||
}
|
||||
|
||||
func (gui *Gui) handleStashSave(g *gocui.Gui, filesView *gocui.View) error {
|
||||
func (gui *Gui) handleStashSave(stashFunc func(message string) error) error {
|
||||
if len(gui.trackedFiles()) == 0 && len(gui.stagedFiles()) == 0 {
|
||||
return gui.createErrorPanel(g, gui.Tr.SLocalize("NoTrackedStagedFilesStash"))
|
||||
return gui.createErrorPanel(gui.g, gui.Tr.SLocalize("NoTrackedStagedFilesStash"))
|
||||
}
|
||||
gui.createPromptPanel(g, filesView, gui.Tr.SLocalize("StashChanges"), func(g *gocui.Gui, v *gocui.View) error {
|
||||
if err := gui.GitCommand.StashSave(gui.trimmedContent(v)); err != nil {
|
||||
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 {
|
||||
gui.createErrorPanel(g, err.Error())
|
||||
}
|
||||
gui.refreshStashEntries(g)
|
||||
return gui.refreshFiles()
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ func (gui *Gui) handleStatusSelect(g *gocui.Gui, v *gocui.View) error {
|
||||
[]string{
|
||||
lazygitTitle(),
|
||||
"Copyright (c) 2018 Jesse Duffield",
|
||||
"Keybindings: https://github.com/jesseduffield/lazygit/blob/master/docs/Keybindings.md",
|
||||
"Keybindings: https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings",
|
||||
"Config Options: https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md",
|
||||
"Tutorial: https://youtu.be/VDXvbHZYeKY",
|
||||
"Raise an Issue: https://github.com/jesseduffield/lazygit/issues",
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
package gui
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/gocui"
|
||||
)
|
||||
|
||||
// GetAttribute gets the gocui color attribute from the string
|
||||
func (gui *Gui) GetAttribute(key string) gocui.Attribute {
|
||||
colorMap := map[string]gocui.Attribute{
|
||||
"default": gocui.ColorDefault,
|
||||
"black": gocui.ColorBlack,
|
||||
"red": gocui.ColorRed,
|
||||
"green": gocui.ColorGreen,
|
||||
"yellow": gocui.ColorYellow,
|
||||
"blue": gocui.ColorBlue,
|
||||
"magenta": gocui.ColorMagenta,
|
||||
"cyan": gocui.ColorCyan,
|
||||
"white": gocui.ColorWhite,
|
||||
"bold": gocui.AttrBold,
|
||||
"reverse": gocui.AttrReverse,
|
||||
"underline": gocui.AttrUnderline,
|
||||
}
|
||||
value, present := colorMap[key]
|
||||
if present {
|
||||
return value
|
||||
}
|
||||
return gocui.ColorWhite
|
||||
}
|
||||
|
||||
// GetColor bitwise OR's a list of attributes obtained via the given keys
|
||||
func (gui *Gui) GetColor(keys []string) gocui.Attribute {
|
||||
var attribute gocui.Attribute
|
||||
for _, key := range keys {
|
||||
attribute = attribute | gui.GetAttribute(key)
|
||||
}
|
||||
return attribute
|
||||
}
|
||||
|
||||
// GetOptionsPanelTextColor gets the color of the options panel text
|
||||
func (gui *Gui) GetOptionsPanelTextColor() (gocui.Attribute, error) {
|
||||
userConfig := gui.Config.GetUserConfig()
|
||||
optionsColor := userConfig.GetStringSlice("gui.theme.optionsTextColor")
|
||||
return gui.GetColor(optionsColor), nil
|
||||
}
|
||||
|
||||
// SetColorScheme sets the color scheme for the app based on the user config
|
||||
func (gui *Gui) SetColorScheme() error {
|
||||
userConfig := gui.Config.GetUserConfig()
|
||||
activeBorderColor := userConfig.GetStringSlice("gui.theme.activeBorderColor")
|
||||
inactiveBorderColor := userConfig.GetStringSlice("gui.theme.inactiveBorderColor")
|
||||
gui.g.FgColor = gui.GetColor(inactiveBorderColor)
|
||||
gui.g.SelFgColor = gui.GetColor(activeBorderColor)
|
||||
return nil
|
||||
}
|
||||
@@ -22,6 +22,7 @@ func (gui *Gui) refreshSidePanels(g *gocui.Gui) error {
|
||||
if err := gui.refreshCommits(g); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return gui.refreshStashEntries(g)
|
||||
}
|
||||
|
||||
@@ -30,8 +31,13 @@ func (gui *Gui) nextView(g *gocui.Gui, v *gocui.View) error {
|
||||
if v == nil || v.Name() == cyclableViews[len(cyclableViews)-1] {
|
||||
focusedViewName = cyclableViews[0]
|
||||
} else {
|
||||
// if we're in the commitFiles view we'll act like we're in the commits view
|
||||
viewName := v.Name()
|
||||
if viewName == "commitFiles" {
|
||||
viewName = "commits"
|
||||
}
|
||||
for i := range cyclableViews {
|
||||
if v.Name() == cyclableViews[i] {
|
||||
if viewName == cyclableViews[i] {
|
||||
focusedViewName = cyclableViews[i+1]
|
||||
break
|
||||
}
|
||||
@@ -39,7 +45,7 @@ func (gui *Gui) nextView(g *gocui.Gui, v *gocui.View) error {
|
||||
message := gui.Tr.TemplateLocalize(
|
||||
"IssntListOfViews",
|
||||
Teml{
|
||||
"name": v.Name(),
|
||||
"name": viewName,
|
||||
},
|
||||
)
|
||||
gui.Log.Info(message)
|
||||
@@ -59,8 +65,13 @@ func (gui *Gui) previousView(g *gocui.Gui, v *gocui.View) error {
|
||||
if v == nil || v.Name() == cyclableViews[0] {
|
||||
focusedViewName = cyclableViews[len(cyclableViews)-1]
|
||||
} else {
|
||||
// if we're in the commitFiles view we'll act like we're in the commits view
|
||||
viewName := v.Name()
|
||||
if viewName == "commitFiles" {
|
||||
viewName = "commits"
|
||||
}
|
||||
for i := range cyclableViews {
|
||||
if v.Name() == cyclableViews[i] {
|
||||
if viewName == cyclableViews[i] {
|
||||
focusedViewName = cyclableViews[i-1] // TODO: make this work properly
|
||||
break
|
||||
}
|
||||
@@ -68,7 +79,7 @@ func (gui *Gui) previousView(g *gocui.Gui, v *gocui.View) error {
|
||||
message := gui.Tr.TemplateLocalize(
|
||||
"IssntListOfViews",
|
||||
Teml{
|
||||
"name": v.Name(),
|
||||
"name": viewName,
|
||||
},
|
||||
)
|
||||
gui.Log.Info(message)
|
||||
@@ -95,6 +106,8 @@ func (gui *Gui) newLineFocused(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.handleBranchSelect(g, v)
|
||||
case "commits":
|
||||
return gui.handleCommitSelect(g, v)
|
||||
case "commitFiles":
|
||||
return gui.handleCommitFileSelect(g, v)
|
||||
case "stash":
|
||||
return gui.handleStashEntrySelect(g, v)
|
||||
case "confirmation":
|
||||
@@ -126,18 +139,39 @@ func (gui *Gui) returnFocus(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.switchFocus(g, v, previousView)
|
||||
}
|
||||
|
||||
func (gui *Gui) goToSideView(sideViewName string) func(g *gocui.Gui, v *gocui.View) error {
|
||||
return func(g *gocui.Gui, v *gocui.View) error {
|
||||
view, err := g.View(sideViewName)
|
||||
if err != nil {
|
||||
gui.Log.Error(err)
|
||||
return nil
|
||||
}
|
||||
err = gui.closePopupPanels()
|
||||
if err != nil {
|
||||
gui.Log.Error(err)
|
||||
return nil
|
||||
}
|
||||
return gui.switchFocus(g, nil, view)
|
||||
}
|
||||
}
|
||||
|
||||
func (gui *Gui) closePopupPanels() error {
|
||||
gui.onNewPopupPanel()
|
||||
err := gui.closeConfirmationPrompt(gui.g)
|
||||
if err != nil {
|
||||
gui.Log.Error(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// pass in oldView = nil if you don't want to be able to return to your old view
|
||||
// TODO: move some of this logic into our onFocusLost and onFocus hooks
|
||||
func (gui *Gui) switchFocus(g *gocui.Gui, oldView, newView *gocui.View) error {
|
||||
// we assume we'll never want to return focus to a confirmation panel i.e.
|
||||
// we should never stack confirmation panels
|
||||
if oldView != nil && oldView.Name() != "confirmation" {
|
||||
// second class panels should never have focus restored to them because
|
||||
// once they lose focus they are effectively 'destroyed'
|
||||
secondClassPanels := []string{"confirmation", "menu"}
|
||||
if !utils.IncludesString(secondClassPanels, oldView.Name()) {
|
||||
gui.State.PreviousView = oldView.Name()
|
||||
}
|
||||
// we assume we'll never want to return focus to a popup panel i.e.
|
||||
// we should never stack popup panels
|
||||
if oldView != nil && !gui.isPopupPanel(oldView.Name()) {
|
||||
gui.State.PreviousView = oldView.Name()
|
||||
}
|
||||
|
||||
gui.Log.Info("setting highlight to true for view" + newView.Name())
|
||||
@@ -165,49 +199,37 @@ func (gui *Gui) switchFocus(g *gocui.Gui, oldView, newView *gocui.View) error {
|
||||
}
|
||||
|
||||
func (gui *Gui) resetOrigin(v *gocui.View) error {
|
||||
if err := v.SetCursor(0, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = v.SetCursor(0, 0)
|
||||
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, v *gocui.View) error {
|
||||
if cy < 0 {
|
||||
func (gui *Gui) focusPoint(cx int, cy int, lineCount int, v *gocui.View) error {
|
||||
if cy < 0 || cy > lineCount {
|
||||
return nil
|
||||
}
|
||||
ox, oy := v.Origin()
|
||||
_, height := v.Size()
|
||||
|
||||
ly := height - 1
|
||||
if ly == -1 {
|
||||
ly = 0
|
||||
}
|
||||
|
||||
// if line is above origin, move origin and set cursor to zero
|
||||
// if line is below origin + height, move origin and set cursor to max
|
||||
// otherwise set cursor to value - origin
|
||||
if ly > v.LinesHeight() {
|
||||
if err := v.SetCursor(cx, cy); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v.SetOrigin(ox, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if ly > lineCount {
|
||||
_ = v.SetCursor(cx, cy)
|
||||
_ = v.SetOrigin(ox, 0)
|
||||
} else if cy < oy {
|
||||
if err := v.SetCursor(cx, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v.SetOrigin(ox, cy); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = v.SetCursor(cx, 0)
|
||||
_ = v.SetOrigin(ox, cy)
|
||||
} else if cy > oy+ly {
|
||||
if err := v.SetCursor(cx, ly); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v.SetOrigin(ox, cy-ly); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = v.SetCursor(cx, ly)
|
||||
_ = v.SetOrigin(ox, cy-ly)
|
||||
} else {
|
||||
if err := v.SetCursor(cx, cy-oy); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = v.SetCursor(cx, cy-oy)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -283,6 +305,11 @@ func (gui *Gui) getStashView() *gocui.View {
|
||||
return v
|
||||
}
|
||||
|
||||
func (gui *Gui) getCommitFilesView() *gocui.View {
|
||||
v, _ := gui.g.View("commitFiles")
|
||||
return v
|
||||
}
|
||||
|
||||
func (gui *Gui) trimmedContent(v *gocui.View) string {
|
||||
return strings.TrimSpace(v.Buffer())
|
||||
}
|
||||
@@ -294,7 +321,7 @@ func (gui *Gui) currentViewName() string {
|
||||
|
||||
func (gui *Gui) resizeCurrentPopupPanel(g *gocui.Gui) error {
|
||||
v := g.CurrentView()
|
||||
if v.Name() == "commitMessage" || v.Name() == "credentials" || v.Name() == "confirmation" {
|
||||
if gui.isPopupPanel(v.Name()) {
|
||||
return gui.resizePopupPanel(g, v)
|
||||
}
|
||||
return nil
|
||||
@@ -386,14 +413,10 @@ func (gui *Gui) handleFocusView(g *gocui.Gui, v *gocui.View) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (gui *Gui) popupPanelFocused() bool {
|
||||
viewNames := []string{"commitMessage",
|
||||
"credentials",
|
||||
"menu"}
|
||||
for _, viewName := range viewNames {
|
||||
if gui.currentViewName() == viewName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
func (gui *Gui) isPopupPanel(viewName string) bool {
|
||||
return viewName == "commitMessage" || viewName == "credentials" || viewName == "confirmation" || viewName == "menu"
|
||||
}
|
||||
|
||||
func (gui *Gui) popupPanelFocused() bool {
|
||||
return gui.isPopupPanel(gui.currentViewName())
|
||||
}
|
||||
|
||||
@@ -28,6 +28,12 @@ func addDutch(i18nObject *i18n.Bundle) error {
|
||||
}, &i18n.Message{
|
||||
ID: "CommitsTitle",
|
||||
Other: "Commits",
|
||||
}, &i18n.Message{
|
||||
ID: "CommitsDiffTitle",
|
||||
Other: "Commits (specific diff mode)",
|
||||
}, &i18n.Message{
|
||||
ID: "CommitsDiff",
|
||||
Other: "select commit to diff with another commit",
|
||||
}, &i18n.Message{
|
||||
ID: "StashTitle",
|
||||
Other: "Stash",
|
||||
@@ -79,9 +85,6 @@ func addDutch(i18nObject *i18n.Bundle) error {
|
||||
}, &i18n.Message{
|
||||
ID: "execute",
|
||||
Other: "uitvoeren",
|
||||
}, &i18n.Message{
|
||||
ID: "stashFiles",
|
||||
Other: "stash-bestanden",
|
||||
}, &i18n.Message{
|
||||
ID: "open",
|
||||
Other: "open",
|
||||
@@ -157,9 +160,6 @@ func addDutch(i18nObject *i18n.Bundle) error {
|
||||
}, &i18n.Message{
|
||||
ID: "FileNoMergeCons",
|
||||
Other: "Dit bestand heeft geen merge conflicten",
|
||||
}, &i18n.Message{
|
||||
ID: "SureResetHardHead",
|
||||
Other: "Weet je het zeker dat je `reset --hard HEAD` en `clean -fd` wil uitvoeren? Het kan dat je hierdoor bestanden verliest",
|
||||
}, &i18n.Message{
|
||||
ID: "SureTo",
|
||||
Other: "Weet je het zeker dat je {{.fileName}} wilt {{.deleteVerb}} (je veranderingen zullen worden verwijderd)",
|
||||
@@ -340,9 +340,6 @@ func addDutch(i18nObject *i18n.Bundle) error {
|
||||
}, &i18n.Message{
|
||||
ID: "CantCloseConfirmationPrompt",
|
||||
Other: "Kon de bevestiging prompt niet sluiten: {{.error}}",
|
||||
}, &i18n.Message{
|
||||
ID: "ClearFilePanel",
|
||||
Other: "maak bestandsvenster leeg",
|
||||
}, &i18n.Message{
|
||||
ID: "MergeAborted",
|
||||
Other: "Merge afgebroken",
|
||||
@@ -382,9 +379,6 @@ func addDutch(i18nObject *i18n.Bundle) error {
|
||||
}, &i18n.Message{
|
||||
ID: "GitconfigParseErr",
|
||||
Other: `Gogit kon je gitconfig bestand niet goed parsen door de aanwezigheid van losstaande '\' tekens. Het weghalen van deze tekens zou het probleem moeten oplossen. `,
|
||||
}, &i18n.Message{
|
||||
ID: "removeFile",
|
||||
Other: `Verwijder als untracked / uitchecken wordt gevolgd (ga weg)`,
|
||||
}, &i18n.Message{
|
||||
ID: "editFile",
|
||||
Other: `verander bestand`,
|
||||
@@ -397,9 +391,6 @@ func addDutch(i18nObject *i18n.Bundle) error {
|
||||
}, &i18n.Message{
|
||||
ID: "refreshFiles",
|
||||
Other: `refresh bestanden`,
|
||||
}, &i18n.Message{
|
||||
ID: "resetHard",
|
||||
Other: `harde reset and verwijderen ongevolgde bestanden`,
|
||||
}, &i18n.Message{
|
||||
ID: "mergeIntoCurrentBranch",
|
||||
Other: `merge in met huidige checked out branch`,
|
||||
@@ -423,7 +414,7 @@ func addDutch(i18nObject *i18n.Bundle) error {
|
||||
Other: `fetch`,
|
||||
}, &i18n.Message{
|
||||
ID: "NoAutomaticGitFetchTitle",
|
||||
Other: `Geen automatiese git fetch`,
|
||||
Other: `Geen automatische git fetch`,
|
||||
}, &i18n.Message{
|
||||
ID: "NoAutomaticGitFetchBody",
|
||||
Other: `Lazygit kan niet "git fetch" uitvoeren in een privé repository, gebruik f in het branches paneel om "git fetch" manueel uit te voeren`,
|
||||
@@ -459,40 +450,34 @@ func addDutch(i18nObject *i18n.Bundle) error {
|
||||
Other: "Merging",
|
||||
}, &i18n.Message{
|
||||
ID: "ConfirmRebase",
|
||||
Other: "Are you sure you want to rebase {{.checkedOutBranch}} onto {{.selectedBranch}}?",
|
||||
Other: "Weet je zeker dat je {{.checkedOutBranch}} op {{.selectedBranch}} wil rebasen?",
|
||||
}, &i18n.Message{
|
||||
ID: "ConfirmMerge",
|
||||
Other: "Are you sure you want to merge {{.selectedBranch}} into {{.checkedOutBranch}}?",
|
||||
Other: "Weet je zeker dat je {{.selectedBranch}} in {{.checkedOutBranch}} wil mergen?",
|
||||
}, &i18n.Message{
|
||||
ID: "FwdNoUpstream",
|
||||
Other: "Cannot fast-forward a branch with no upstream",
|
||||
Other: "Kan niet de branch vooruitspoelen zonder upstream",
|
||||
}, &i18n.Message{
|
||||
ID: "ErrorOccurred",
|
||||
Other: "An error occurred! Please create an issue at https://github.com/jesseduffield/lazygit/issues",
|
||||
Other: "Er is iets fout gegaan! Zou je hier een issue aan willen maken: https://github.com/jesseduffield/lazygit/issues",
|
||||
}, &i18n.Message{
|
||||
ID: "FwdCommitsToPush",
|
||||
Other: "Cannot fast-forward a branch with commits to push",
|
||||
Other: "Je kan niet vooruitspoelen als de branch geen nieuwe commits heeft",
|
||||
}, &i18n.Message{
|
||||
ID: "MainTitle",
|
||||
Other: "Main",
|
||||
Other: "Hoofd",
|
||||
}, &i18n.Message{
|
||||
ID: "NormalTitle",
|
||||
Other: "Normal",
|
||||
Other: "Normaal",
|
||||
}, &i18n.Message{
|
||||
ID: "softReset",
|
||||
Other: "soft reset to last commit",
|
||||
}, &i18n.Message{
|
||||
ID: "SoftReset",
|
||||
Other: "Soft reset",
|
||||
}, &i18n.Message{
|
||||
ID: "ConfirmSoftReset",
|
||||
Other: "Are you sure you want to `reset --soft HEAD^`? The changes in your topmost commit will be placed in your working tree",
|
||||
Other: "zacht reset",
|
||||
}, &i18n.Message{
|
||||
ID: "CantRebaseOntoSelf",
|
||||
Other: "You cannot rebase a branch onto itself",
|
||||
Other: "Je kan niet een branch rebasen op zichzelf",
|
||||
}, &i18n.Message{
|
||||
ID: "SureSquashThisCommit",
|
||||
Other: "Are you sure you want to squash this commit into the commit below?",
|
||||
Other: "Weet je zeker dat je deze commit wil samenvoegen met de commit hieronder?",
|
||||
}, &i18n.Message{
|
||||
ID: "Squash",
|
||||
Other: "Squash",
|
||||
@@ -501,127 +486,130 @@ func addDutch(i18nObject *i18n.Bundle) error {
|
||||
Other: "pick commit (when mid-rebase)",
|
||||
}, &i18n.Message{
|
||||
ID: "revertCommit",
|
||||
Other: "revert commit",
|
||||
Other: "commit omgedaan maken",
|
||||
}, &i18n.Message{
|
||||
ID: "deleteCommit",
|
||||
Other: "delete commit",
|
||||
Other: "verwijder commit",
|
||||
}, &i18n.Message{
|
||||
ID: "moveDownCommit",
|
||||
Other: "move commit down one",
|
||||
Other: "verplaats commit 1 omlaag",
|
||||
}, &i18n.Message{
|
||||
ID: "moveUpCommit",
|
||||
Other: "move commit up one",
|
||||
Other: "verplaats commit 1 omhoog",
|
||||
}, &i18n.Message{
|
||||
ID: "editCommit",
|
||||
Other: "edit commit",
|
||||
Other: "verander commit",
|
||||
}, &i18n.Message{
|
||||
ID: "amendToCommit",
|
||||
Other: "amend commit with staged changes",
|
||||
Other: "wijzig commit met staged veranderingen",
|
||||
}, &i18n.Message{
|
||||
ID: "FoundConflicts",
|
||||
Other: "Damn, conflicts! To abort press 'esc', otherwise press 'enter'",
|
||||
Other: "Conflicten!, Om af te breken druk 'esc', anders druk op 'enter'",
|
||||
}, &i18n.Message{
|
||||
ID: "FoundConflictsTitle",
|
||||
Other: "Auto-merge failed",
|
||||
Other: "Auto-merge mislukt",
|
||||
}, &i18n.Message{
|
||||
ID: "Undo",
|
||||
Other: "undo",
|
||||
Other: "ongedaan maken",
|
||||
}, &i18n.Message{
|
||||
ID: "PickHunk",
|
||||
Other: "pick hunk",
|
||||
}, &i18n.Message{
|
||||
ID: "PickBothHunks",
|
||||
Other: "pick both hunks",
|
||||
Other: "pick beide hunks",
|
||||
}, &i18n.Message{
|
||||
ID: "ViewMergeRebaseOptions",
|
||||
Other: "view merge/rebase options",
|
||||
Other: "bekijk merge/rebase opties",
|
||||
}, &i18n.Message{
|
||||
ID: "NotMergingOrRebasing",
|
||||
Other: "You are currently neither rebasing nor merging",
|
||||
Other: "Je bent momenteel niet aan het rebasen of mergen",
|
||||
}, &i18n.Message{
|
||||
ID: "RecentRepos",
|
||||
Other: "recent repositories",
|
||||
}, &i18n.Message{
|
||||
ID: "MergeOptionsTitle",
|
||||
Other: "Merge Options",
|
||||
Other: "Merge Opties",
|
||||
}, &i18n.Message{
|
||||
ID: "RebaseOptionsTitle",
|
||||
Other: "Rebase Options",
|
||||
Other: "Rebase Opties",
|
||||
}, &i18n.Message{
|
||||
ID: "ConflictsResolved",
|
||||
Other: "all merge conflicts resolved. Continue?",
|
||||
Other: "alle merge conflicten zijn opgelost. Wilt je verder gaan?",
|
||||
}, &i18n.Message{
|
||||
ID: "NoRoom",
|
||||
Other: "Not enough room",
|
||||
Other: "Niet genoeg ruimte",
|
||||
}, &i18n.Message{
|
||||
ID: "YouAreHere",
|
||||
Other: "YOU ARE HERE",
|
||||
Other: "JE BENT HIER",
|
||||
}, &i18n.Message{
|
||||
ID: "rewordNotSupported",
|
||||
Other: "rewording commits while interactively rebasing is not currently supported",
|
||||
Other: "herformatteren van commits in interactief rebasen is nog niet ondersteund",
|
||||
}, &i18n.Message{
|
||||
ID: "cherryPickCopy",
|
||||
Other: "copy commit (cherry-pick)",
|
||||
Other: "kopiëer commit (cherry-pick)",
|
||||
}, &i18n.Message{
|
||||
ID: "cherryPickCopyRange",
|
||||
Other: "copy commit range (cherry-pick)",
|
||||
Other: "kopiëer commit reeks (cherry-pick)",
|
||||
}, &i18n.Message{
|
||||
ID: "pasteCommits",
|
||||
Other: "paste commits (cherry-pick)",
|
||||
Other: "plak commits (cherry-pick)",
|
||||
}, &i18n.Message{
|
||||
ID: "SureCherryPick",
|
||||
Other: "Are you sure you want to cherry-pick the copied commits onto this branch?",
|
||||
Other: "Weet je zeker dat je de gekopieerde commits naar deze branch wil cherry-picken?",
|
||||
}, &i18n.Message{
|
||||
ID: "CherryPick",
|
||||
Other: "Cherry-Pick",
|
||||
}, &i18n.Message{
|
||||
ID: "CannotRebaseOntoFirstCommit",
|
||||
Other: "You cannot interactive rebase onto the first commit",
|
||||
Other: "Je kan niet interactief rebasen naar de eerste commit",
|
||||
}, &i18n.Message{
|
||||
ID: "CannotSquashOntoSecondCommit",
|
||||
Other: "Je kan niet een squash/fixup doen naar de 2de commit",
|
||||
}, &i18n.Message{
|
||||
ID: "Donate",
|
||||
Other: "Donate",
|
||||
Other: "Doneer",
|
||||
}, &i18n.Message{
|
||||
ID: "PrevLine",
|
||||
Other: "select previous line",
|
||||
Other: "selecteer de vorige lijn",
|
||||
}, &i18n.Message{
|
||||
ID: "NextLine",
|
||||
Other: "select next line",
|
||||
Other: "selecteer de volgende lijn",
|
||||
}, &i18n.Message{
|
||||
ID: "PrevHunk",
|
||||
Other: "select previous hunk",
|
||||
Other: "selecteer de vorige hunk",
|
||||
}, &i18n.Message{
|
||||
ID: "NextHunk",
|
||||
Other: "select next hunk",
|
||||
Other: "selecteer de volgende hunk",
|
||||
}, &i18n.Message{
|
||||
ID: "PrevConflict",
|
||||
Other: "select previous conflict",
|
||||
Other: "selecteer voorgaand conflict",
|
||||
}, &i18n.Message{
|
||||
ID: "NextConflict",
|
||||
Other: "select next conflict",
|
||||
Other: "selecteer volgende conflict",
|
||||
}, &i18n.Message{
|
||||
ID: "SelectTop",
|
||||
Other: "select top hunk",
|
||||
Other: "selecteer bovenste hunk",
|
||||
}, &i18n.Message{
|
||||
ID: "SelectBottom",
|
||||
Other: "select bottom hunk",
|
||||
Other: "selecteer onderste hunk",
|
||||
}, &i18n.Message{
|
||||
ID: "ScrollDown",
|
||||
Other: "scroll down",
|
||||
Other: "scroll omlaag",
|
||||
}, &i18n.Message{
|
||||
ID: "ScrollUp",
|
||||
Other: "scroll up",
|
||||
Other: "scroll omhoog",
|
||||
}, &i18n.Message{
|
||||
ID: "AmendCommitTitle",
|
||||
Other: "Amend Commit",
|
||||
Other: "Commit wijzigen",
|
||||
}, &i18n.Message{
|
||||
ID: "AmendCommitPrompt",
|
||||
Other: "Are you sure you want to amend this commit with your staged files?",
|
||||
Other: "Weet je zeker dat je deze commit wil wijzigen met de vorige staged bestanden?",
|
||||
}, &i18n.Message{
|
||||
ID: "DeleteCommitTitle",
|
||||
Other: "Delete Commit",
|
||||
Other: "Verwijder Commit",
|
||||
}, &i18n.Message{
|
||||
ID: "DeleteCommitPrompt",
|
||||
Other: "Are you sure you want to delete this commit?",
|
||||
Other: "Weet je zeker dat je deze commit wil verwijderen?",
|
||||
}, &i18n.Message{
|
||||
ID: "SquashingStatus",
|
||||
Other: "squashing",
|
||||
@@ -630,19 +618,142 @@ func addDutch(i18nObject *i18n.Bundle) error {
|
||||
Other: "fixing up",
|
||||
}, &i18n.Message{
|
||||
ID: "DeletingStatus",
|
||||
Other: "deleting",
|
||||
Other: "verwijderen",
|
||||
}, &i18n.Message{
|
||||
ID: "MovingStatus",
|
||||
Other: "moving",
|
||||
Other: "verplaatsen",
|
||||
}, &i18n.Message{
|
||||
ID: "RebasingStatus",
|
||||
Other: "rebasing",
|
||||
}, &i18n.Message{
|
||||
ID: "AmendingStatus",
|
||||
Other: "amending",
|
||||
Other: "wijzigen",
|
||||
}, &i18n.Message{
|
||||
ID: "CherryPickingStatus",
|
||||
Other: "cherry-picking",
|
||||
}, &i18n.Message{
|
||||
ID: "CommitFiles",
|
||||
Other: "Commit bestanden",
|
||||
}, &i18n.Message{
|
||||
ID: "viewCommitFiles",
|
||||
Other: "bekijk gecommite bestanden",
|
||||
}, &i18n.Message{
|
||||
ID: "CommitFilesTitle",
|
||||
Other: "Commit bestanden",
|
||||
}, &i18n.Message{
|
||||
ID: "goBack",
|
||||
Other: "ga terug",
|
||||
}, &i18n.Message{
|
||||
ID: "NoCommiteFiles",
|
||||
Other: "Geen bestanden voor deze commit",
|
||||
}, &i18n.Message{
|
||||
ID: "checkoutCommitFile",
|
||||
Other: "bestand uitchecken",
|
||||
}, &i18n.Message{
|
||||
ID: "discardOldFileChange",
|
||||
Other: "uitsluit deze commit zijn veranderingen aan dit bestand",
|
||||
}, &i18n.Message{
|
||||
ID: "DiscardFileChangesTitle",
|
||||
Other: "uitsluit bestand zijn veranderingen",
|
||||
}, &i18n.Message{
|
||||
ID: "DiscardFileChangesPrompt",
|
||||
Other: "Weet je zeker dat je de wijzigingen van deze commit in dit bestand wilt weggooien? Als dit bestand is gecreëerd in deze commit dan zal dit bestand worden verwijdert",
|
||||
}, &i18n.Message{
|
||||
ID: "DisabledForGPG",
|
||||
Other: "Onderdelen niet beschikbaar voor gebruikers die GPG gebruiken",
|
||||
}, &i18n.Message{
|
||||
ID: "CreateRepo",
|
||||
Other: "Niet in een git repository. Creëer een nieuwe git repository? (y/n): ",
|
||||
}, &i18n.Message{
|
||||
ID: "AutoStashTitle",
|
||||
Other: "Autostash?",
|
||||
}, &i18n.Message{
|
||||
ID: "AutoStashPrompt",
|
||||
Other: "Je moet je veranderingen stashen en poppen om ze over te bregen. Dit automatisch doen? (enter/esc)",
|
||||
}, &i18n.Message{
|
||||
ID: "StashPrefix",
|
||||
Other: "Auto-stashing veranderingen voor ",
|
||||
}, &i18n.Message{
|
||||
ID: "viewDiscardOptions",
|
||||
Other: "bekijk 'veranderingen ongedaan maken' opties",
|
||||
}, &i18n.Message{
|
||||
ID: "cancel",
|
||||
Other: "anuleren",
|
||||
}, &i18n.Message{
|
||||
ID: "discardAllChanges",
|
||||
Other: "negeer alle wijzigingen",
|
||||
}, &i18n.Message{
|
||||
ID: "discardUnstagedChanges",
|
||||
Other: "negeer unstaged wijzigingen",
|
||||
}, &i18n.Message{
|
||||
ID: "discardAllChangesToAllFiles",
|
||||
Other: "verwijder werkende tree",
|
||||
}, &i18n.Message{
|
||||
ID: "discardAnyUnstagedChanges",
|
||||
Other: "discard unstaged changes",
|
||||
}, &i18n.Message{
|
||||
ID: "discardUntrackedFiles",
|
||||
Other: "negeer niet-gevonden bestanden",
|
||||
}, &i18n.Message{
|
||||
ID: "viewResetOptions",
|
||||
Other: `bekijk reset opties`,
|
||||
}, &i18n.Message{
|
||||
ID: "hardReset",
|
||||
Other: "harde reset",
|
||||
}, &i18n.Message{
|
||||
ID: "createFixupCommit",
|
||||
Other: `creëer fixup commit voor deze commit`,
|
||||
}, &i18n.Message{
|
||||
ID: "squashAboveCommits",
|
||||
Other: `squash bovenstaande commits`,
|
||||
}, &i18n.Message{
|
||||
ID: "SquashAboveCommits",
|
||||
Other: `Squash bovenstaande commits`,
|
||||
}, &i18n.Message{
|
||||
ID: "SureSquashAboveCommits",
|
||||
Other: `Weet je zeker dat je alles wil squash/fixup! voor de bovenstaand commits {{.commit}}?`,
|
||||
}, &i18n.Message{
|
||||
ID: "CreateFixupCommit",
|
||||
Other: `Creëer fixup commit`,
|
||||
}, &i18n.Message{
|
||||
ID: "SureCreateFixupCommit",
|
||||
Other: `Weet je zeker dat je een fixup wil maken! commit voor commit {{.commit}}?`,
|
||||
}, &i18n.Message{
|
||||
ID: "executeCustomCommand",
|
||||
Other: "voor aangepast commando uit",
|
||||
}, &i18n.Message{
|
||||
ID: "CustomCommand",
|
||||
Other: "Aangepast commando:",
|
||||
}, &i18n.Message{
|
||||
ID: "commitChangesWithoutHook",
|
||||
Other: "commit veranderingen zonder pre-commit hook",
|
||||
}, &i18n.Message{
|
||||
ID: "SkipHookPrefixNotConfigured",
|
||||
Other: "Je hebt nog niet een commit bericht voorvoegsel ingesteld voor het overslaan van hooks. Set `git.skipHookPrefix = 'WIP'` in je config",
|
||||
}, &i18n.Message{
|
||||
ID: "resetTo",
|
||||
Other: `reset to`,
|
||||
}, &i18n.Message{
|
||||
ID: "pressEnterToReturn",
|
||||
Other: "Press enter to return to lazygit",
|
||||
}, &i18n.Message{
|
||||
ID: "viewStashOptions",
|
||||
Other: "view stash options",
|
||||
}, &i18n.Message{
|
||||
ID: "stashAllChanges",
|
||||
Other: "stash-bestanden",
|
||||
}, &i18n.Message{
|
||||
ID: "stashStagedChanges",
|
||||
Other: "stash staged changes",
|
||||
}, &i18n.Message{
|
||||
ID: "stashOptions",
|
||||
Other: "Stash options",
|
||||
}, &i18n.Message{
|
||||
ID: "notARepository",
|
||||
Other: "Error: must be run inside a git repository",
|
||||
}, &i18n.Message{
|
||||
ID: "jump",
|
||||
Other: "jump to panel",
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -36,6 +36,12 @@ func addEnglish(i18nObject *i18n.Bundle) error {
|
||||
}, &i18n.Message{
|
||||
ID: "CommitsTitle",
|
||||
Other: "Commits",
|
||||
}, &i18n.Message{
|
||||
ID: "CommitsDiffTitle",
|
||||
Other: "Commits (specific diff mode)",
|
||||
}, &i18n.Message{
|
||||
ID: "CommitsDiff",
|
||||
Other: "select commit to diff with another commit",
|
||||
}, &i18n.Message{
|
||||
ID: "StashTitle",
|
||||
Other: "Stash",
|
||||
@@ -99,12 +105,6 @@ func addEnglish(i18nObject *i18n.Bundle) error {
|
||||
}, &i18n.Message{
|
||||
ID: "execute",
|
||||
Other: "execute",
|
||||
}, &i18n.Message{
|
||||
ID: "stashFiles",
|
||||
Other: "stash files",
|
||||
}, &i18n.Message{
|
||||
ID: "softReset",
|
||||
Other: "soft reset to last commit",
|
||||
}, &i18n.Message{
|
||||
ID: "open",
|
||||
Other: "open",
|
||||
@@ -181,14 +181,8 @@ func addEnglish(i18nObject *i18n.Bundle) error {
|
||||
ID: "FileNoMergeCons",
|
||||
Other: "This file has no inline merge conflicts",
|
||||
}, &i18n.Message{
|
||||
ID: "SureResetHardHead",
|
||||
Other: "Are you sure you want to `reset --hard HEAD` and `clean -fd`? You may lose changes",
|
||||
}, &i18n.Message{
|
||||
ID: "SoftReset",
|
||||
Other: "Soft reset",
|
||||
}, &i18n.Message{
|
||||
ID: "ConfirmSoftReset",
|
||||
Other: "Are you sure you want to `reset --soft HEAD^`? The changes in your topmost commit will be placed in your working tree",
|
||||
ID: "softReset",
|
||||
Other: "soft reset",
|
||||
}, &i18n.Message{
|
||||
ID: "SureTo",
|
||||
Other: "Are you sure you want to {{.deleteVerb}} {{.fileName}} (you will lose your changes)?",
|
||||
@@ -405,9 +399,6 @@ func addEnglish(i18nObject *i18n.Bundle) error {
|
||||
}, &i18n.Message{
|
||||
ID: "NoChangedFiles",
|
||||
Other: "No changed files",
|
||||
}, &i18n.Message{
|
||||
ID: "ClearFilePanel",
|
||||
Other: "Clear file panel",
|
||||
}, &i18n.Message{
|
||||
ID: "MergeAborted",
|
||||
Other: "Merge aborted",
|
||||
@@ -447,9 +438,6 @@ func addEnglish(i18nObject *i18n.Bundle) error {
|
||||
}, &i18n.Message{
|
||||
ID: "GitconfigParseErr",
|
||||
Other: `Gogit failed to parse your gitconfig file due to the presence of unquoted '\' characters. Removing these should fix the issue.`,
|
||||
}, &i18n.Message{
|
||||
ID: "removeFile",
|
||||
Other: `delete if untracked / checkout if tracked`,
|
||||
}, &i18n.Message{
|
||||
ID: "editFile",
|
||||
Other: `edit file`,
|
||||
@@ -462,9 +450,6 @@ func addEnglish(i18nObject *i18n.Bundle) error {
|
||||
}, &i18n.Message{
|
||||
ID: "refreshFiles",
|
||||
Other: `refresh files`,
|
||||
}, &i18n.Message{
|
||||
ID: "resetHard",
|
||||
Other: `reset hard and remove untracked files`,
|
||||
}, &i18n.Message{
|
||||
ID: "mergeIntoCurrentBranch",
|
||||
Other: `merge into currently checked out branch`,
|
||||
@@ -521,7 +506,7 @@ func addEnglish(i18nObject *i18n.Bundle) error {
|
||||
Other: "fetching and fast-forwarding {{.from}} -> {{.to}} ...",
|
||||
}, &i18n.Message{
|
||||
ID: "FoundConflicts",
|
||||
Other: "Damn, conflicts! To abort press 'esc', otherwise press 'enter'",
|
||||
Other: "Conflicts! To abort press 'esc', otherwise press 'enter'",
|
||||
}, &i18n.Message{
|
||||
ID: "FoundConflictsTitle",
|
||||
Other: "Auto-merge failed",
|
||||
@@ -600,6 +585,9 @@ func addEnglish(i18nObject *i18n.Bundle) error {
|
||||
}, &i18n.Message{
|
||||
ID: "CannotRebaseOntoFirstCommit",
|
||||
Other: "You cannot interactive rebase onto the first commit",
|
||||
}, &i18n.Message{
|
||||
ID: "CannotSquashOntoSecondCommit",
|
||||
Other: "You cannot squash/fixup onto the second commit",
|
||||
}, &i18n.Message{
|
||||
ID: "Donate",
|
||||
Other: "Donate",
|
||||
@@ -666,6 +654,129 @@ func addEnglish(i18nObject *i18n.Bundle) error {
|
||||
}, &i18n.Message{
|
||||
ID: "CherryPickingStatus",
|
||||
Other: "cherry-picking",
|
||||
}, &i18n.Message{
|
||||
ID: "CommitFiles",
|
||||
Other: "Commit files",
|
||||
}, &i18n.Message{
|
||||
ID: "viewCommitFiles",
|
||||
Other: "view commit's files",
|
||||
}, &i18n.Message{
|
||||
ID: "CommitFilesTitle",
|
||||
Other: "Commit files",
|
||||
}, &i18n.Message{
|
||||
ID: "goBack",
|
||||
Other: "go back",
|
||||
}, &i18n.Message{
|
||||
ID: "NoCommiteFiles",
|
||||
Other: "No files for this commit",
|
||||
}, &i18n.Message{
|
||||
ID: "checkoutCommitFile",
|
||||
Other: "checkout file",
|
||||
}, &i18n.Message{
|
||||
ID: "discardOldFileChange",
|
||||
Other: "discard this commit's changes to this file",
|
||||
}, &i18n.Message{
|
||||
ID: "DiscardFileChangesTitle",
|
||||
Other: "Discard file changes",
|
||||
}, &i18n.Message{
|
||||
ID: "DiscardFileChangesPrompt",
|
||||
Other: "Are you sure you want to discard this commit's changes to this file? If this file was created in this commit, it will be deleted",
|
||||
}, &i18n.Message{
|
||||
ID: "DisabledForGPG",
|
||||
Other: "Feature not available for users using GPG",
|
||||
}, &i18n.Message{
|
||||
ID: "CreateRepo",
|
||||
Other: "Not in a git repository. Create a new git repository? (y/n): ",
|
||||
}, &i18n.Message{
|
||||
ID: "AutoStashTitle",
|
||||
Other: "Autostash?",
|
||||
}, &i18n.Message{
|
||||
ID: "AutoStashPrompt",
|
||||
Other: "You must stash and pop your changes to bring them across. Do this automatically? (enter/esc)",
|
||||
}, &i18n.Message{
|
||||
ID: "StashPrefix",
|
||||
Other: "Auto-stashing changes for ",
|
||||
}, &i18n.Message{
|
||||
ID: "viewDiscardOptions",
|
||||
Other: "view 'discard changes' options",
|
||||
}, &i18n.Message{
|
||||
ID: "cancel",
|
||||
Other: "cancel",
|
||||
}, &i18n.Message{
|
||||
ID: "discardAllChanges",
|
||||
Other: "discard all changes",
|
||||
}, &i18n.Message{
|
||||
ID: "discardUnstagedChanges",
|
||||
Other: "discard unstaged changes",
|
||||
}, &i18n.Message{
|
||||
ID: "discardAllChangesToAllFiles",
|
||||
Other: "nuke working tree",
|
||||
}, &i18n.Message{
|
||||
ID: "discardAnyUnstagedChanges",
|
||||
Other: "discard unstaged changes",
|
||||
}, &i18n.Message{
|
||||
ID: "discardUntrackedFiles",
|
||||
Other: "discard untracked files",
|
||||
}, &i18n.Message{
|
||||
ID: "hardReset",
|
||||
Other: "hard reset",
|
||||
}, &i18n.Message{
|
||||
ID: "viewResetOptions",
|
||||
Other: `view reset options`,
|
||||
}, &i18n.Message{
|
||||
ID: "createFixupCommit",
|
||||
Other: `create fixup commit for this commit`,
|
||||
}, &i18n.Message{
|
||||
ID: "squashAboveCommits",
|
||||
Other: `squash above commits`,
|
||||
}, &i18n.Message{
|
||||
ID: "SquashAboveCommits",
|
||||
Other: `Squash above commits`,
|
||||
}, &i18n.Message{
|
||||
ID: "SureSquashAboveCommits",
|
||||
Other: `Are you sure you want to squash all fixup! commits above {{.commit}}?`,
|
||||
}, &i18n.Message{
|
||||
ID: "CreateFixupCommit",
|
||||
Other: `Create fixup commit`,
|
||||
}, &i18n.Message{
|
||||
ID: "SureCreateFixupCommit",
|
||||
Other: `Are you sure you want to create a fixup! commit for commit {{.commit}}?`,
|
||||
}, &i18n.Message{
|
||||
ID: "executeCustomCommand",
|
||||
Other: "execute custom command",
|
||||
}, &i18n.Message{
|
||||
ID: "CustomCommand",
|
||||
Other: "Custom Command:",
|
||||
}, &i18n.Message{
|
||||
ID: "commitChangesWithoutHook",
|
||||
Other: "commit changes without pre-commit hook",
|
||||
}, &i18n.Message{
|
||||
ID: "SkipHookPrefixNotConfigured",
|
||||
Other: "You have not configured a commit message prefix for skipping hooks. Set `git.skipHookPrefix = 'WIP'` in your config",
|
||||
}, &i18n.Message{
|
||||
ID: "resetTo",
|
||||
Other: `reset to`,
|
||||
}, &i18n.Message{
|
||||
ID: "pressEnterToReturn",
|
||||
Other: "Press enter to return to lazygit",
|
||||
}, &i18n.Message{
|
||||
ID: "viewStashOptions",
|
||||
Other: "view stash options",
|
||||
}, &i18n.Message{
|
||||
ID: "stashAllChanges",
|
||||
Other: "stash changes",
|
||||
}, &i18n.Message{
|
||||
ID: "stashStagedChanges",
|
||||
Other: "stash staged changes",
|
||||
}, &i18n.Message{
|
||||
ID: "stashOptions",
|
||||
Other: "Stash options",
|
||||
}, &i18n.Message{
|
||||
ID: "notARepository",
|
||||
Other: "Error: must be run inside a git repository",
|
||||
}, &i18n.Message{
|
||||
ID: "jump",
|
||||
Other: "jump to panel",
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ func detectLanguage(langDetector func() (string, error)) string {
|
||||
// setupLocalizer creates a new localizer using given userLang
|
||||
func setupLocalizer(log *logrus.Entry, userLang string) *Localizer {
|
||||
// create a i18n bundle that can be used to add translations and other things
|
||||
i18nBundle := &i18n.Bundle{DefaultLanguage: language.English}
|
||||
i18nBundle := i18n.NewBundle(language.English)
|
||||
|
||||
addBundles(log, i18nBundle)
|
||||
|
||||
|
||||
@@ -26,6 +26,12 @@ func addPolish(i18nObject *i18n.Bundle) error {
|
||||
}, &i18n.Message{
|
||||
ID: "CommitsTitle",
|
||||
Other: "Commity",
|
||||
}, &i18n.Message{
|
||||
ID: "CommitsDiffTitle",
|
||||
Other: "Commits (specific diff mode)",
|
||||
}, &i18n.Message{
|
||||
ID: "CommitsDiff",
|
||||
Other: "select commit to diff with another commit",
|
||||
}, &i18n.Message{
|
||||
ID: "StashTitle",
|
||||
Other: "Schowek",
|
||||
@@ -77,9 +83,6 @@ func addPolish(i18nObject *i18n.Bundle) error {
|
||||
}, &i18n.Message{
|
||||
ID: "execute",
|
||||
Other: "wykonaj",
|
||||
}, &i18n.Message{
|
||||
ID: "stashFiles",
|
||||
Other: "przechowaj pliki",
|
||||
}, &i18n.Message{
|
||||
ID: "open",
|
||||
Other: "otwórz",
|
||||
@@ -146,9 +149,6 @@ func addPolish(i18nObject *i18n.Bundle) error {
|
||||
}, &i18n.Message{
|
||||
ID: "FileNoMergeCons",
|
||||
Other: "Ten plik nie powoduje konfliktów scalania",
|
||||
}, &i18n.Message{
|
||||
ID: "SureResetHardHead",
|
||||
Other: "Jesteś pewny, że chcesz wykonać `reset --hard HEAD` i `clean -fd`? Możesz stracić wprowadzone zmiany",
|
||||
}, &i18n.Message{
|
||||
ID: "SureTo",
|
||||
Other: "Jesteś pewny, że chcesz {{.deleteVerb}} {{.fileName}} (stracisz swoje wprowadzone zmiany)?",
|
||||
@@ -332,9 +332,6 @@ func addPolish(i18nObject *i18n.Bundle) error {
|
||||
}, &i18n.Message{
|
||||
ID: "CantCloseConfirmationPrompt",
|
||||
Other: "Nie można zamknąć monitu potwierdzenia: {{.error}}",
|
||||
}, &i18n.Message{
|
||||
ID: "ClearFilePanel",
|
||||
Other: "Wyczyść panel plików",
|
||||
}, &i18n.Message{
|
||||
ID: "MergeAborted",
|
||||
Other: "Scalanie anulowane",
|
||||
@@ -371,9 +368,6 @@ func addPolish(i18nObject *i18n.Bundle) error {
|
||||
}, &i18n.Message{
|
||||
ID: "AnonymousReportingPrompt",
|
||||
Other: "Włączyć anonimowe raportowanie błędów w celu pomocy w usprawnianiu lazygita (enter/esc)?",
|
||||
}, &i18n.Message{
|
||||
ID: "removeFile",
|
||||
Other: `usuń jeśli nie śledzony / przełącz jeśli śledzony`,
|
||||
}, &i18n.Message{
|
||||
ID: "editFile",
|
||||
Other: `edytuj plik`,
|
||||
@@ -386,9 +380,6 @@ func addPolish(i18nObject *i18n.Bundle) error {
|
||||
}, &i18n.Message{
|
||||
ID: "refreshFiles",
|
||||
Other: `odśwież pliki`,
|
||||
}, &i18n.Message{
|
||||
ID: "resetHard",
|
||||
Other: `zresetuj twardo i usuń niepotwierdzone pliki`,
|
||||
}, &i18n.Message{
|
||||
ID: "mergeIntoCurrentBranch",
|
||||
Other: `scal do obecnej gałęzi`,
|
||||
@@ -466,13 +457,7 @@ func addPolish(i18nObject *i18n.Bundle) error {
|
||||
Other: "Normal",
|
||||
}, &i18n.Message{
|
||||
ID: "softReset",
|
||||
Other: "soft reset to last commit",
|
||||
}, &i18n.Message{
|
||||
ID: "SoftReset",
|
||||
Other: "Soft reset",
|
||||
}, &i18n.Message{
|
||||
ID: "ConfirmSoftReset",
|
||||
Other: "Are you sure you want to `reset --soft HEAD^`? The changes in your topmost commit will be placed in your working tree",
|
||||
Other: "soft reset",
|
||||
}, &i18n.Message{
|
||||
ID: "SureSquashThisCommit",
|
||||
Other: "Are you sure you want to squash this commit into the commit below?",
|
||||
@@ -502,7 +487,7 @@ func addPolish(i18nObject *i18n.Bundle) error {
|
||||
Other: "amend commit with staged changes",
|
||||
}, &i18n.Message{
|
||||
ID: "FoundConflicts",
|
||||
Other: "Damn, conflicts! To abort press 'esc', otherwise press 'enter'",
|
||||
Other: "Conflicts! To abort press 'esc', otherwise press 'enter'",
|
||||
}, &i18n.Message{
|
||||
ID: "FoundConflictsTitle",
|
||||
Other: "Auto-merge failed",
|
||||
@@ -560,6 +545,9 @@ func addPolish(i18nObject *i18n.Bundle) error {
|
||||
}, &i18n.Message{
|
||||
ID: "CannotRebaseOntoFirstCommit",
|
||||
Other: "You cannot interactive rebase onto the first commit",
|
||||
}, &i18n.Message{
|
||||
ID: "CannotSquashOntoSecondCommit",
|
||||
Other: "You cannot squash/fixup onto the second commit",
|
||||
}, &i18n.Message{
|
||||
ID: "Donate",
|
||||
Other: "Donate",
|
||||
@@ -626,6 +614,129 @@ func addPolish(i18nObject *i18n.Bundle) error {
|
||||
}, &i18n.Message{
|
||||
ID: "CherryPickingStatus",
|
||||
Other: "cherry-picking",
|
||||
}, &i18n.Message{
|
||||
ID: "CommitFiles",
|
||||
Other: "Commit files",
|
||||
}, &i18n.Message{
|
||||
ID: "viewCommitFiles",
|
||||
Other: "view commit's files",
|
||||
}, &i18n.Message{
|
||||
ID: "CommitFilesTitle",
|
||||
Other: "Commit files",
|
||||
}, &i18n.Message{
|
||||
ID: "goBack",
|
||||
Other: "go back",
|
||||
}, &i18n.Message{
|
||||
ID: "NoCommiteFiles",
|
||||
Other: "No files for this commit",
|
||||
}, &i18n.Message{
|
||||
ID: "checkoutCommitFile",
|
||||
Other: "checkout file",
|
||||
}, &i18n.Message{
|
||||
ID: "discardOldFileChange",
|
||||
Other: "discard this commit's changes to this file",
|
||||
}, &i18n.Message{
|
||||
ID: "DiscardFileChangesTitle",
|
||||
Other: "Discard file changes",
|
||||
}, &i18n.Message{
|
||||
ID: "DiscardFileChangesPrompt",
|
||||
Other: "Are you sure you want to discard this commit's changes to this file? If this file was created in this commit, it will be deleted",
|
||||
}, &i18n.Message{
|
||||
ID: "DisabledForGPG",
|
||||
Other: "Feature not available for users using GPG",
|
||||
}, &i18n.Message{
|
||||
ID: "CreateRepo",
|
||||
Other: "Not in a git repository. Create a new git repository? (y/n): ",
|
||||
}, &i18n.Message{
|
||||
ID: "AutoStashTitle",
|
||||
Other: "Autostash?",
|
||||
}, &i18n.Message{
|
||||
ID: "AutoStashPrompt",
|
||||
Other: "You must stash and pop your changes to bring them across. Do this automatically? (enter/esc)",
|
||||
}, &i18n.Message{
|
||||
ID: "StashPrefix",
|
||||
Other: "Auto-stashing changes for ",
|
||||
}, &i18n.Message{
|
||||
ID: "viewDiscardOptions",
|
||||
Other: "view 'discard changes' options",
|
||||
}, &i18n.Message{
|
||||
ID: "cancel",
|
||||
Other: "cancel",
|
||||
}, &i18n.Message{
|
||||
ID: "discardAllChanges",
|
||||
Other: "discard all changes",
|
||||
}, &i18n.Message{
|
||||
ID: "discardUnstagedChanges",
|
||||
Other: "discard unstaged changes",
|
||||
}, &i18n.Message{
|
||||
ID: "discardAllChangesToAllFiles",
|
||||
Other: "nuke working tree",
|
||||
}, &i18n.Message{
|
||||
ID: "discardAnyUnstagedChanges",
|
||||
Other: "discard unstaged changes",
|
||||
}, &i18n.Message{
|
||||
ID: "discardUntrackedFiles",
|
||||
Other: "discard untracked files",
|
||||
}, &i18n.Message{
|
||||
ID: "hardReset",
|
||||
Other: "hard reset",
|
||||
}, &i18n.Message{
|
||||
ID: "viewResetOptions",
|
||||
Other: `view reset options`,
|
||||
}, &i18n.Message{
|
||||
ID: "createFixupCommit",
|
||||
Other: `create fixup commit for this commit`,
|
||||
}, &i18n.Message{
|
||||
ID: "squashAboveCommits",
|
||||
Other: `squash above commits`,
|
||||
}, &i18n.Message{
|
||||
ID: "SquashAboveCommits",
|
||||
Other: `Squash above commits`,
|
||||
}, &i18n.Message{
|
||||
ID: "SureSquashAboveCommits",
|
||||
Other: `Are you sure you want to squash all fixup! commits above {{.commit}}?`,
|
||||
}, &i18n.Message{
|
||||
ID: "CreateFixupCommit",
|
||||
Other: `Create fixup commit`,
|
||||
}, &i18n.Message{
|
||||
ID: "SureCreateFixupCommit",
|
||||
Other: `Are you sure you want to create a fixup! commit for commit {{.commit}}?`,
|
||||
}, &i18n.Message{
|
||||
ID: "executeCustomCommand",
|
||||
Other: "execute custom command",
|
||||
}, &i18n.Message{
|
||||
ID: "CustomCommand",
|
||||
Other: "Custom Command:",
|
||||
}, &i18n.Message{
|
||||
ID: "commitChangesWithoutHook",
|
||||
Other: "commit changes without pre-commit hook",
|
||||
}, &i18n.Message{
|
||||
ID: "SkipHookPrefixNotConfigured",
|
||||
Other: "You have not configured a commit message prefix for skipping hooks. Set `git.skipHookPrefix = 'WIP'` in your config",
|
||||
}, &i18n.Message{
|
||||
ID: "resetTo",
|
||||
Other: `reset to`,
|
||||
}, &i18n.Message{
|
||||
ID: "pressEnterToReturn",
|
||||
Other: "Press enter to return to lazygit",
|
||||
}, &i18n.Message{
|
||||
ID: "viewStashOptions",
|
||||
Other: "view stash options",
|
||||
}, &i18n.Message{
|
||||
ID: "stashAllChanges",
|
||||
Other: "przechowaj pliki",
|
||||
}, &i18n.Message{
|
||||
ID: "stashStagedChanges",
|
||||
Other: "stash staged changes",
|
||||
}, &i18n.Message{
|
||||
ID: "stashOptions",
|
||||
Other: "Stash options",
|
||||
}, &i18n.Message{
|
||||
ID: "notARepository",
|
||||
Other: "Error: must be run inside a git repository",
|
||||
}, &i18n.Message{
|
||||
ID: "jump",
|
||||
Other: "jump to panel",
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
100
pkg/theme/theme.go
Normal file
100
pkg/theme/theme.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package theme
|
||||
|
||||
import (
|
||||
"github.com/fatih/color"
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultTextColor is the default text color
|
||||
DefaultTextColor = color.FgWhite
|
||||
|
||||
// GocuiDefaultTextColor does the same as DefaultTextColor but this one only colors gocui default text colors
|
||||
GocuiDefaultTextColor gocui.Attribute
|
||||
|
||||
// ActiveBorderColor is the border color of the active frame
|
||||
ActiveBorderColor gocui.Attribute
|
||||
|
||||
// InactiveBorderColor is the border color of the inactive active frames
|
||||
InactiveBorderColor gocui.Attribute
|
||||
)
|
||||
|
||||
// UpdateTheme updates all theme variables
|
||||
func UpdateTheme(userConfig *viper.Viper) {
|
||||
ActiveBorderColor = getColor(userConfig.GetStringSlice("gui.theme.activeBorderColor"))
|
||||
InactiveBorderColor = getColor(userConfig.GetStringSlice("gui.theme.inactiveBorderColor"))
|
||||
|
||||
isLightTheme := userConfig.GetBool("gui.theme.lightTheme")
|
||||
if isLightTheme {
|
||||
DefaultTextColor = color.FgBlack
|
||||
GocuiDefaultTextColor = gocui.ColorBlack
|
||||
} else {
|
||||
DefaultTextColor = color.FgWhite
|
||||
GocuiDefaultTextColor = gocui.ColorWhite
|
||||
}
|
||||
}
|
||||
|
||||
// getAttribute gets the gocui color attribute from the string
|
||||
func getAttribute(key string) gocui.Attribute {
|
||||
colorMap := map[string]gocui.Attribute{
|
||||
"default": gocui.ColorDefault,
|
||||
"black": gocui.ColorBlack,
|
||||
"red": gocui.ColorRed,
|
||||
"green": gocui.ColorGreen,
|
||||
"yellow": gocui.ColorYellow,
|
||||
"blue": gocui.ColorBlue,
|
||||
"magenta": gocui.ColorMagenta,
|
||||
"cyan": gocui.ColorCyan,
|
||||
"white": gocui.ColorWhite,
|
||||
"bold": gocui.AttrBold,
|
||||
"reverse": gocui.AttrReverse,
|
||||
"underline": gocui.AttrUnderline,
|
||||
}
|
||||
value, present := colorMap[key]
|
||||
if present {
|
||||
return value
|
||||
}
|
||||
return gocui.ColorWhite
|
||||
}
|
||||
|
||||
// getColor bitwise OR's a list of attributes obtained via the given keys
|
||||
func getColor(keys []string) gocui.Attribute {
|
||||
var attribute gocui.Attribute
|
||||
for _, key := range keys {
|
||||
attribute |= getAttribute(key)
|
||||
}
|
||||
return attribute
|
||||
}
|
||||
|
||||
// GetAttribute gets the gocui color attribute from the string
|
||||
func GetAttribute(key string) gocui.Attribute {
|
||||
colorMap := map[string]gocui.Attribute{
|
||||
"default": gocui.ColorDefault,
|
||||
"black": gocui.ColorBlack,
|
||||
"red": gocui.ColorRed,
|
||||
"green": gocui.ColorGreen,
|
||||
"yellow": gocui.ColorYellow,
|
||||
"blue": gocui.ColorBlue,
|
||||
"magenta": gocui.ColorMagenta,
|
||||
"cyan": gocui.ColorCyan,
|
||||
"white": gocui.ColorWhite,
|
||||
"bold": gocui.AttrBold,
|
||||
"reverse": gocui.AttrReverse,
|
||||
"underline": gocui.AttrUnderline,
|
||||
}
|
||||
value, present := colorMap[key]
|
||||
if present {
|
||||
return value
|
||||
}
|
||||
return gocui.ColorWhite
|
||||
}
|
||||
|
||||
// GetColor bitwise OR's a list of attributes obtained via the given keys
|
||||
func GetColor(keys []string) gocui.Attribute {
|
||||
var attribute gocui.Attribute
|
||||
for _, key := range keys {
|
||||
attribute |= GetAttribute(key)
|
||||
}
|
||||
return attribute
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package updates
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -16,7 +15,7 @@ import (
|
||||
|
||||
"github.com/kardianos/osext"
|
||||
|
||||
getter "github.com/jesseduffield/go-getter"
|
||||
"github.com/jesseduffield/go-getter"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
"github.com/jesseduffield/lazygit/pkg/i18n"
|
||||
@@ -261,15 +260,11 @@ func (u *Updater) downloadAndInstall(rawUrl string) error {
|
||||
}
|
||||
|
||||
g := new(getter.HttpGetter)
|
||||
tempDir, err := ioutil.TempDir("", "lazygit")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
u.Log.Info("Temp directory is " + tempDir)
|
||||
configDir := u.Config.GetUserConfigDir()
|
||||
u.Log.Info("Download directory is " + configDir)
|
||||
|
||||
// Get it!
|
||||
if err := g.Get(tempDir, url); err != nil {
|
||||
if err := g.Get(configDir, url); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -284,7 +279,7 @@ func (u *Updater) downloadAndInstall(rawUrl string) error {
|
||||
u.Log.Info("Binary name is " + binaryName)
|
||||
|
||||
// Verify the main file exists
|
||||
tempPath := filepath.Join(tempDir, binaryName)
|
||||
tempPath := filepath.Join(configDir, binaryName)
|
||||
u.Log.Info("Temp path to binary is " + tempPath)
|
||||
if _, err := os.Stat(tempPath); err != nil {
|
||||
return err
|
||||
|
||||
@@ -33,10 +33,11 @@ func SplitLines(multilineString string) []string {
|
||||
|
||||
// WithPadding pads a string as much as you want
|
||||
func WithPadding(str string, padding int) string {
|
||||
if padding-len(str) < 0 {
|
||||
uncoloredStr := Decolorise(str)
|
||||
if padding < len(uncoloredStr) {
|
||||
return str
|
||||
}
|
||||
return str + strings.Repeat(" ", padding-len(str))
|
||||
return str + strings.Repeat(" ", padding-len(uncoloredStr))
|
||||
}
|
||||
|
||||
// ColoredString takes a string and a colour attribute and returns a colored
|
||||
|
||||
@@ -169,7 +169,7 @@ func TestResolvePlaceholderString(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, s := range scenarios {
|
||||
assert.EqualValues(t, string(s.expected), ResolvePlaceholderString(s.templateString, s.arguments))
|
||||
assert.EqualValues(t, s.expected, ResolvePlaceholderString(s.templateString, s.arguments))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,16 +25,21 @@ type bindingSection struct {
|
||||
}
|
||||
|
||||
func main() {
|
||||
langs := []string{"pl", "nl", "en"}
|
||||
mConfig, _ := config.NewAppConfig("", "", "", "", "", true)
|
||||
mApp, _ := app.NewApp(mConfig)
|
||||
lang := mApp.Tr.GetLanguage()
|
||||
file, _ := os.Create("Keybindings_" + lang + ".md")
|
||||
|
||||
bindingSections := getBindingSections(mApp)
|
||||
for _, lang := range langs {
|
||||
os.Setenv("LC_ALL", lang)
|
||||
mApp, _ := app.NewApp(mConfig)
|
||||
file, err := os.Create(getProjectRoot() + "/docs/keybindings/Keybindings_" + lang + ".md")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
content := formatSections(mApp, bindingSections)
|
||||
|
||||
writeString(file, content)
|
||||
bindingSections := getBindingSections(mApp)
|
||||
content := formatSections(mApp, bindingSections)
|
||||
writeString(file, content)
|
||||
}
|
||||
}
|
||||
|
||||
func writeString(file *os.File, str string) {
|
||||
@@ -54,6 +59,9 @@ func formatTitle(title string) string {
|
||||
}
|
||||
|
||||
func formatBinding(binding *gui.Binding) string {
|
||||
if binding.Alternative != "" {
|
||||
return fmt.Sprintf(" <kbd>%s</kbd>: %s (%s)\n", binding.GetKey(), binding.Description, binding.Alternative)
|
||||
}
|
||||
return fmt.Sprintf(" <kbd>%s</kbd>: %s\n", binding.GetKey(), binding.Description)
|
||||
}
|
||||
|
||||
@@ -91,7 +99,7 @@ func getBindingSections(mApp *app.App) []*bindingSection {
|
||||
}
|
||||
|
||||
func addBinding(title string, bindingSections []*bindingSection, binding *gui.Binding) []*bindingSection {
|
||||
if binding.Description == "" {
|
||||
if binding.Description == "" && binding.Alternative == "" {
|
||||
return bindingSections
|
||||
}
|
||||
|
||||
@@ -124,3 +132,11 @@ func formatSections(mApp *app.App, bindingSections []*bindingSection) string {
|
||||
|
||||
return content
|
||||
}
|
||||
|
||||
func getProjectRoot() string {
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return strings.Split(dir, "lazygit")[0] + "lazygit"
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ func main() {
|
||||
|
||||
splitVersion := strings.Split(stringVersion, ".")
|
||||
patch := splitVersion[len(splitVersion)-1]
|
||||
newPatch, err := strconv.Atoi(patch)
|
||||
newPatch, _ := strconv.Atoi(patch)
|
||||
splitVersion[len(splitVersion)-1] = strconv.FormatInt(int64(newPatch)+1, 10)
|
||||
newVersion := strings.Join(splitVersion, ".")
|
||||
|
||||
|
||||
4
test.sh
4
test.sh
@@ -3,6 +3,8 @@
|
||||
set -e
|
||||
echo "" > coverage.txt
|
||||
|
||||
export GOFLAGS=-mod=vendor
|
||||
|
||||
use_go_test=false
|
||||
if command -v gotest; then
|
||||
use_go_test=true
|
||||
@@ -10,7 +12,7 @@ fi
|
||||
|
||||
for d in $( find ./* -maxdepth 10 ! -path "./vendor*" ! -path "./.git*" ! -path "./scripts*" -type d); do
|
||||
if ls $d/*.go &> /dev/null; then
|
||||
args="-v -race -coverprofile=profile.out -covermode=atomic $d"
|
||||
args="-race -coverprofile=profile.out -covermode=atomic $d"
|
||||
if [ "$use_go_test" == true ]; then
|
||||
gotest $args
|
||||
else
|
||||
|
||||
@@ -133,4 +133,23 @@ echo "once upon a time there was a horse" >> file5
|
||||
git add file5
|
||||
git commit -m "fourth commit on master"
|
||||
|
||||
# git merge develop # should have a merge conflict here
|
||||
|
||||
# this is for the autostash feature
|
||||
|
||||
git checkout -b base_branch
|
||||
|
||||
echo "original1\noriginal2\noriginal3" > file
|
||||
git add file
|
||||
git commit -m "file"
|
||||
|
||||
git checkout -b other_branch
|
||||
|
||||
git checkout base_branch
|
||||
|
||||
echo "new1\noriginal2\noriginal3" > file
|
||||
git add file
|
||||
git commit -m "file changed"
|
||||
|
||||
git checkout other_branch
|
||||
|
||||
echo "new2\noriginal2\noriginal3" > file
|
||||
|
||||
12
vendor/github.com/aws/aws-sdk-go/aws/credentials/example.ini
generated
vendored
Normal file
12
vendor/github.com/aws/aws-sdk-go/aws/credentials/example.ini
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
[default]
|
||||
aws_access_key_id = accessKey
|
||||
aws_secret_access_key = secret
|
||||
aws_session_token = token
|
||||
|
||||
[no_token]
|
||||
aws_access_key_id = accessKey
|
||||
aws_secret_access_key = secret
|
||||
|
||||
[with_colon]
|
||||
aws_access_key_id: accessKey
|
||||
aws_secret_access_key: secret
|
||||
44
vendor/github.com/cloudfoundry/jibber_jabber/README.md
generated
vendored
Normal file
44
vendor/github.com/cloudfoundry/jibber_jabber/README.md
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
# Jibber Jabber [](https://travis-ci.org/cloudfoundry/jibber_jabber)
|
||||
Jibber Jabber is a GoLang Library that can be used to detect an operating system's current language.
|
||||
|
||||
### OS Support
|
||||
|
||||
OSX and Linux via the `LC_ALL` and `LANG` environment variables. These are standard variables that are used in ALL versions of UNIX for language detection.
|
||||
|
||||
Windows via [GetUserDefaultLocaleName](http://msdn.microsoft.com/en-us/library/windows/desktop/dd318136.aspx) and [GetSystemDefaultLocaleName](http://msdn.microsoft.com/en-us/library/windows/desktop/dd318122.aspx) system calls. These calls are supported in Windows Vista and up.
|
||||
|
||||
# Usage
|
||||
Add the following line to your go `import`:
|
||||
|
||||
```
|
||||
"github.com/cloudfoundry/jibber_jabber"
|
||||
```
|
||||
|
||||
### DetectIETF
|
||||
`DetectIETF` will return the current locale as a string. The format of the locale will be the [ISO 639](http://en.wikipedia.org/wiki/ISO_639) two-letter language code, a DASH, then an [ISO 3166](http://en.wikipedia.org/wiki/ISO_3166-1) two-letter country code.
|
||||
|
||||
```
|
||||
userLocale, err := jibber_jabber.DetectIETF()
|
||||
println("Locale:", userLocale)
|
||||
```
|
||||
|
||||
### DetectLanguage
|
||||
`DetectLanguage` will return the current languge as a string. The format will be the [ISO 639](http://en.wikipedia.org/wiki/ISO_639) two-letter language code.
|
||||
|
||||
```
|
||||
userLanguage, err := jibber_jabber.DetectLanguage()
|
||||
println("Language:", userLanguage)
|
||||
```
|
||||
|
||||
### DetectTerritory
|
||||
`DetectTerritory` will return the current locale territory as a string. The format will be the [ISO 3166](http://en.wikipedia.org/wiki/ISO_3166-1) two-letter country code.
|
||||
|
||||
```
|
||||
localeTerritory, err := jibber_jabber.DetectTerritory()
|
||||
println("Territory:", localeTerritory)
|
||||
```
|
||||
|
||||
### Errors
|
||||
All the Detect commands will return an error if they are unable to read the Locale from the system.
|
||||
|
||||
For Windows, additional error information is provided due to the nature of the system call being used.
|
||||
2
vendor/github.com/davecgh/go-spew/LICENSE
generated
vendored
2
vendor/github.com/davecgh/go-spew/LICENSE
generated
vendored
@@ -2,7 +2,7 @@ ISC License
|
||||
|
||||
Copyright (c) 2012-2016 Dave Collins <dave@davec.name>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
|
||||
187
vendor/github.com/davecgh/go-spew/spew/bypass.go
generated
vendored
187
vendor/github.com/davecgh/go-spew/spew/bypass.go
generated
vendored
@@ -16,7 +16,9 @@
|
||||
// when the code is not running on Google App Engine, compiled by GopherJS, and
|
||||
// "-tags safe" is not added to the go build command line. The "disableunsafe"
|
||||
// tag is deprecated and thus should not be used.
|
||||
// +build !js,!appengine,!safe,!disableunsafe
|
||||
// Go versions prior to 1.4 are disabled because they use a different layout
|
||||
// for interfaces which make the implementation of unsafeReflectValue more complex.
|
||||
// +build !js,!appengine,!safe,!disableunsafe,go1.4
|
||||
|
||||
package spew
|
||||
|
||||
@@ -34,80 +36,49 @@ const (
|
||||
ptrSize = unsafe.Sizeof((*byte)(nil))
|
||||
)
|
||||
|
||||
var (
|
||||
// offsetPtr, offsetScalar, and offsetFlag are the offsets for the
|
||||
// internal reflect.Value fields. These values are valid before golang
|
||||
// commit ecccf07e7f9d which changed the format. The are also valid
|
||||
// after commit 82f48826c6c7 which changed the format again to mirror
|
||||
// the original format. Code in the init function updates these offsets
|
||||
// as necessary.
|
||||
offsetPtr = uintptr(ptrSize)
|
||||
offsetScalar = uintptr(0)
|
||||
offsetFlag = uintptr(ptrSize * 2)
|
||||
type flag uintptr
|
||||
|
||||
// flagKindWidth and flagKindShift indicate various bits that the
|
||||
// reflect package uses internally to track kind information.
|
||||
//
|
||||
// flagRO indicates whether or not the value field of a reflect.Value is
|
||||
// read-only.
|
||||
//
|
||||
// flagIndir indicates whether the value field of a reflect.Value is
|
||||
// the actual data or a pointer to the data.
|
||||
//
|
||||
// These values are valid before golang commit 90a7c3c86944 which
|
||||
// changed their positions. Code in the init function updates these
|
||||
// flags as necessary.
|
||||
flagKindWidth = uintptr(5)
|
||||
flagKindShift = uintptr(flagKindWidth - 1)
|
||||
flagRO = uintptr(1 << 0)
|
||||
flagIndir = uintptr(1 << 1)
|
||||
var (
|
||||
// flagRO indicates whether the value field of a reflect.Value
|
||||
// is read-only.
|
||||
flagRO flag
|
||||
|
||||
// flagAddr indicates whether the address of the reflect.Value's
|
||||
// value may be taken.
|
||||
flagAddr flag
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Older versions of reflect.Value stored small integers directly in the
|
||||
// ptr field (which is named val in the older versions). Versions
|
||||
// between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
|
||||
// scalar for this purpose which unfortunately came before the flag
|
||||
// field, so the offset of the flag field is different for those
|
||||
// versions.
|
||||
//
|
||||
// This code constructs a new reflect.Value from a known small integer
|
||||
// and checks if the size of the reflect.Value struct indicates it has
|
||||
// the scalar field. When it does, the offsets are updated accordingly.
|
||||
vv := reflect.ValueOf(0xf00)
|
||||
if unsafe.Sizeof(vv) == (ptrSize * 4) {
|
||||
offsetScalar = ptrSize * 2
|
||||
offsetFlag = ptrSize * 3
|
||||
}
|
||||
// flagKindMask holds the bits that make up the kind
|
||||
// part of the flags field. In all the supported versions,
|
||||
// it is in the lower 5 bits.
|
||||
const flagKindMask = flag(0x1f)
|
||||
|
||||
// Commit 90a7c3c86944 changed the flag positions such that the low
|
||||
// order bits are the kind. This code extracts the kind from the flags
|
||||
// field and ensures it's the correct type. When it's not, the flag
|
||||
// order has been changed to the newer format, so the flags are updated
|
||||
// accordingly.
|
||||
upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
|
||||
upfv := *(*uintptr)(upf)
|
||||
flagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift)
|
||||
if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {
|
||||
flagKindShift = 0
|
||||
flagRO = 1 << 5
|
||||
flagIndir = 1 << 6
|
||||
// Different versions of Go have used different
|
||||
// bit layouts for the flags type. This table
|
||||
// records the known combinations.
|
||||
var okFlags = []struct {
|
||||
ro, addr flag
|
||||
}{{
|
||||
// From Go 1.4 to 1.5
|
||||
ro: 1 << 5,
|
||||
addr: 1 << 7,
|
||||
}, {
|
||||
// Up to Go tip.
|
||||
ro: 1<<5 | 1<<6,
|
||||
addr: 1 << 8,
|
||||
}}
|
||||
|
||||
// Commit adf9b30e5594 modified the flags to separate the
|
||||
// flagRO flag into two bits which specifies whether or not the
|
||||
// field is embedded. This causes flagIndir to move over a bit
|
||||
// and means that flagRO is the combination of either of the
|
||||
// original flagRO bit and the new bit.
|
||||
//
|
||||
// This code detects the change by extracting what used to be
|
||||
// the indirect bit to ensure it's set. When it's not, the flag
|
||||
// order has been changed to the newer format, so the flags are
|
||||
// updated accordingly.
|
||||
if upfv&flagIndir == 0 {
|
||||
flagRO = 3 << 5
|
||||
flagIndir = 1 << 7
|
||||
}
|
||||
var flagValOffset = func() uintptr {
|
||||
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
|
||||
if !ok {
|
||||
panic("reflect.Value has no flag field")
|
||||
}
|
||||
return field.Offset
|
||||
}()
|
||||
|
||||
// flagField returns a pointer to the flag field of a reflect.Value.
|
||||
func flagField(v *reflect.Value) *flag {
|
||||
return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset))
|
||||
}
|
||||
|
||||
// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
|
||||
@@ -119,34 +90,56 @@ func init() {
|
||||
// This allows us to check for implementations of the Stringer and error
|
||||
// interfaces to be used for pretty printing ordinarily unaddressable and
|
||||
// inaccessible values such as unexported struct fields.
|
||||
func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
|
||||
indirects := 1
|
||||
vt := v.Type()
|
||||
upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
|
||||
rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
|
||||
if rvf&flagIndir != 0 {
|
||||
vt = reflect.PtrTo(v.Type())
|
||||
indirects++
|
||||
} else if offsetScalar != 0 {
|
||||
// The value is in the scalar field when it's not one of the
|
||||
// reference types.
|
||||
switch vt.Kind() {
|
||||
case reflect.Uintptr:
|
||||
case reflect.Chan:
|
||||
case reflect.Func:
|
||||
case reflect.Map:
|
||||
case reflect.Ptr:
|
||||
case reflect.UnsafePointer:
|
||||
default:
|
||||
upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
|
||||
offsetScalar)
|
||||
func unsafeReflectValue(v reflect.Value) reflect.Value {
|
||||
if !v.IsValid() || (v.CanInterface() && v.CanAddr()) {
|
||||
return v
|
||||
}
|
||||
flagFieldPtr := flagField(&v)
|
||||
*flagFieldPtr &^= flagRO
|
||||
*flagFieldPtr |= flagAddr
|
||||
return v
|
||||
}
|
||||
|
||||
// Sanity checks against future reflect package changes
|
||||
// to the type or semantics of the Value.flag field.
|
||||
func init() {
|
||||
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
|
||||
if !ok {
|
||||
panic("reflect.Value has no flag field")
|
||||
}
|
||||
if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() {
|
||||
panic("reflect.Value flag field has changed kind")
|
||||
}
|
||||
type t0 int
|
||||
var t struct {
|
||||
A t0
|
||||
// t0 will have flagEmbedRO set.
|
||||
t0
|
||||
// a will have flagStickyRO set
|
||||
a t0
|
||||
}
|
||||
vA := reflect.ValueOf(t).FieldByName("A")
|
||||
va := reflect.ValueOf(t).FieldByName("a")
|
||||
vt0 := reflect.ValueOf(t).FieldByName("t0")
|
||||
|
||||
// Infer flagRO from the difference between the flags
|
||||
// for the (otherwise identical) fields in t.
|
||||
flagPublic := *flagField(&vA)
|
||||
flagWithRO := *flagField(&va) | *flagField(&vt0)
|
||||
flagRO = flagPublic ^ flagWithRO
|
||||
|
||||
// Infer flagAddr from the difference between a value
|
||||
// taken from a pointer and not.
|
||||
vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A")
|
||||
flagNoPtr := *flagField(&vA)
|
||||
flagPtr := *flagField(&vPtrA)
|
||||
flagAddr = flagNoPtr ^ flagPtr
|
||||
|
||||
// Check that the inferred flags tally with one of the known versions.
|
||||
for _, f := range okFlags {
|
||||
if flagRO == f.ro && flagAddr == f.addr {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
pv := reflect.NewAt(vt, upv)
|
||||
rv = pv
|
||||
for i := 0; i < indirects; i++ {
|
||||
rv = rv.Elem()
|
||||
}
|
||||
return rv
|
||||
panic("reflect.Value read-only flag has changed semantics")
|
||||
}
|
||||
|
||||
2
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
generated
vendored
2
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
generated
vendored
@@ -16,7 +16,7 @@
|
||||
// when the code is running on Google App Engine, compiled by GopherJS, or
|
||||
// "-tags safe" is added to the go build command line. The "disableunsafe"
|
||||
// tag is deprecated and thus should not be used.
|
||||
// +build js appengine safe disableunsafe
|
||||
// +build js appengine safe disableunsafe !go1.4
|
||||
|
||||
package spew
|
||||
|
||||
|
||||
2
vendor/github.com/davecgh/go-spew/spew/common.go
generated
vendored
2
vendor/github.com/davecgh/go-spew/spew/common.go
generated
vendored
@@ -180,7 +180,7 @@ func printComplex(w io.Writer, c complex128, floatPrecision int) {
|
||||
w.Write(closeParenBytes)
|
||||
}
|
||||
|
||||
// printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x'
|
||||
// printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x'
|
||||
// prefix to Writer w.
|
||||
func printHexPtr(w io.Writer, p uintptr) {
|
||||
// Null pointer.
|
||||
|
||||
10
vendor/github.com/davecgh/go-spew/spew/dump.go
generated
vendored
10
vendor/github.com/davecgh/go-spew/spew/dump.go
generated
vendored
@@ -35,16 +35,16 @@ var (
|
||||
|
||||
// cCharRE is a regular expression that matches a cgo char.
|
||||
// It is used to detect character arrays to hexdump them.
|
||||
cCharRE = regexp.MustCompile("^.*\\._Ctype_char$")
|
||||
cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`)
|
||||
|
||||
// cUnsignedCharRE is a regular expression that matches a cgo unsigned
|
||||
// char. It is used to detect unsigned character arrays to hexdump
|
||||
// them.
|
||||
cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$")
|
||||
cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`)
|
||||
|
||||
// cUint8tCharRE is a regular expression that matches a cgo uint8_t.
|
||||
// It is used to detect uint8_t arrays to hexdump them.
|
||||
cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$")
|
||||
cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`)
|
||||
)
|
||||
|
||||
// dumpState contains information about the state of a dump operation.
|
||||
@@ -143,10 +143,10 @@ func (d *dumpState) dumpPtr(v reflect.Value) {
|
||||
// Display dereferenced value.
|
||||
d.w.Write(openParenBytes)
|
||||
switch {
|
||||
case nilFound == true:
|
||||
case nilFound:
|
||||
d.w.Write(nilAngleBytes)
|
||||
|
||||
case cycleFound == true:
|
||||
case cycleFound:
|
||||
d.w.Write(circularBytes)
|
||||
|
||||
default:
|
||||
|
||||
4
vendor/github.com/davecgh/go-spew/spew/format.go
generated
vendored
4
vendor/github.com/davecgh/go-spew/spew/format.go
generated
vendored
@@ -182,10 +182,10 @@ func (f *formatState) formatPtr(v reflect.Value) {
|
||||
|
||||
// Display dereferenced value.
|
||||
switch {
|
||||
case nilFound == true:
|
||||
case nilFound:
|
||||
f.fs.Write(nilAngleBytes)
|
||||
|
||||
case cycleFound == true:
|
||||
case cycleFound:
|
||||
f.fs.Write(circularShortBytes)
|
||||
|
||||
default:
|
||||
|
||||
27
vendor/github.com/fatih/color/Gopkg.lock
generated
vendored
Normal file
27
vendor/github.com/fatih/color/Gopkg.lock
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-colorable"
|
||||
packages = ["."]
|
||||
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
|
||||
version = "v0.0.9"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-isatty"
|
||||
packages = ["."]
|
||||
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
revision = "37707fdb30a5b38865cfb95e5aab41707daec7fd"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "e8a50671c3cb93ea935bf210b1cd20702876b9d9226129be581ef646d1565cdc"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
30
vendor/github.com/fatih/color/Gopkg.toml
generated
vendored
Normal file
30
vendor/github.com/fatih/color/Gopkg.toml
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/mattn/go-colorable"
|
||||
version = "0.0.9"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/mattn/go-isatty"
|
||||
version = "0.0.3"
|
||||
179
vendor/github.com/fatih/color/README.md
generated
vendored
Normal file
179
vendor/github.com/fatih/color/README.md
generated
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
# Color [](https://godoc.org/github.com/fatih/color) [](https://travis-ci.org/fatih/color)
|
||||
|
||||
|
||||
|
||||
Color lets you use colorized outputs in terms of [ANSI Escape
|
||||
Codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors) in Go (Golang). It
|
||||
has support for Windows too! The API can be used in several ways, pick one that
|
||||
suits you.
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
go get github.com/fatih/color
|
||||
```
|
||||
|
||||
Note that the `vendor` folder is here for stability. Remove the folder if you
|
||||
already have the dependencies in your GOPATH.
|
||||
|
||||
## Examples
|
||||
|
||||
### Standard colors
|
||||
|
||||
```go
|
||||
// Print with default helper functions
|
||||
color.Cyan("Prints text in cyan.")
|
||||
|
||||
// A newline will be appended automatically
|
||||
color.Blue("Prints %s in blue.", "text")
|
||||
|
||||
// These are using the default foreground colors
|
||||
color.Red("We have red")
|
||||
color.Magenta("And many others ..")
|
||||
|
||||
```
|
||||
|
||||
### Mix and reuse colors
|
||||
|
||||
```go
|
||||
// Create a new color object
|
||||
c := color.New(color.FgCyan).Add(color.Underline)
|
||||
c.Println("Prints cyan text with an underline.")
|
||||
|
||||
// Or just add them to New()
|
||||
d := color.New(color.FgCyan, color.Bold)
|
||||
d.Printf("This prints bold cyan %s\n", "too!.")
|
||||
|
||||
// Mix up foreground and background colors, create new mixes!
|
||||
red := color.New(color.FgRed)
|
||||
|
||||
boldRed := red.Add(color.Bold)
|
||||
boldRed.Println("This will print text in bold red.")
|
||||
|
||||
whiteBackground := red.Add(color.BgWhite)
|
||||
whiteBackground.Println("Red text with white background.")
|
||||
```
|
||||
|
||||
### Use your own output (io.Writer)
|
||||
|
||||
```go
|
||||
// Use your own io.Writer output
|
||||
color.New(color.FgBlue).Fprintln(myWriter, "blue color!")
|
||||
|
||||
blue := color.New(color.FgBlue)
|
||||
blue.Fprint(writer, "This will print text in blue.")
|
||||
```
|
||||
|
||||
### Custom print functions (PrintFunc)
|
||||
|
||||
```go
|
||||
// Create a custom print function for convenience
|
||||
red := color.New(color.FgRed).PrintfFunc()
|
||||
red("Warning")
|
||||
red("Error: %s", err)
|
||||
|
||||
// Mix up multiple attributes
|
||||
notice := color.New(color.Bold, color.FgGreen).PrintlnFunc()
|
||||
notice("Don't forget this...")
|
||||
```
|
||||
|
||||
### Custom fprint functions (FprintFunc)
|
||||
|
||||
```go
|
||||
blue := color.New(FgBlue).FprintfFunc()
|
||||
blue(myWriter, "important notice: %s", stars)
|
||||
|
||||
// Mix up with multiple attributes
|
||||
success := color.New(color.Bold, color.FgGreen).FprintlnFunc()
|
||||
success(myWriter, "Don't forget this...")
|
||||
```
|
||||
|
||||
### Insert into noncolor strings (SprintFunc)
|
||||
|
||||
```go
|
||||
// Create SprintXxx functions to mix strings with other non-colorized strings:
|
||||
yellow := color.New(color.FgYellow).SprintFunc()
|
||||
red := color.New(color.FgRed).SprintFunc()
|
||||
fmt.Printf("This is a %s and this is %s.\n", yellow("warning"), red("error"))
|
||||
|
||||
info := color.New(color.FgWhite, color.BgGreen).SprintFunc()
|
||||
fmt.Printf("This %s rocks!\n", info("package"))
|
||||
|
||||
// Use helper functions
|
||||
fmt.Println("This", color.RedString("warning"), "should be not neglected.")
|
||||
fmt.Printf("%v %v\n", color.GreenString("Info:"), "an important message.")
|
||||
|
||||
// Windows supported too! Just don't forget to change the output to color.Output
|
||||
fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS"))
|
||||
```
|
||||
|
||||
### Plug into existing code
|
||||
|
||||
```go
|
||||
// Use handy standard colors
|
||||
color.Set(color.FgYellow)
|
||||
|
||||
fmt.Println("Existing text will now be in yellow")
|
||||
fmt.Printf("This one %s\n", "too")
|
||||
|
||||
color.Unset() // Don't forget to unset
|
||||
|
||||
// You can mix up parameters
|
||||
color.Set(color.FgMagenta, color.Bold)
|
||||
defer color.Unset() // Use it in your function
|
||||
|
||||
fmt.Println("All text will now be bold magenta.")
|
||||
```
|
||||
|
||||
### Disable/Enable color
|
||||
|
||||
There might be a case where you want to explicitly disable/enable color output. the
|
||||
`go-isatty` package will automatically disable color output for non-tty output streams
|
||||
(for example if the output were piped directly to `less`)
|
||||
|
||||
`Color` has support to disable/enable colors both globally and for single color
|
||||
definitions. For example suppose you have a CLI app and a `--no-color` bool flag. You
|
||||
can easily disable the color output with:
|
||||
|
||||
```go
|
||||
|
||||
var flagNoColor = flag.Bool("no-color", false, "Disable color output")
|
||||
|
||||
if *flagNoColor {
|
||||
color.NoColor = true // disables colorized output
|
||||
}
|
||||
```
|
||||
|
||||
It also has support for single color definitions (local). You can
|
||||
disable/enable color output on the fly:
|
||||
|
||||
```go
|
||||
c := color.New(color.FgCyan)
|
||||
c.Println("Prints cyan text")
|
||||
|
||||
c.DisableColor()
|
||||
c.Println("This is printed without any color")
|
||||
|
||||
c.EnableColor()
|
||||
c.Println("This prints again cyan...")
|
||||
```
|
||||
|
||||
## Todo
|
||||
|
||||
* Save/Return previous values
|
||||
* Evaluate fmt.Formatter interface
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
* [Fatih Arslan](https://github.com/fatih)
|
||||
* Windows support via @mattn: [colorable](https://github.com/mattn/go-colorable)
|
||||
|
||||
## License
|
||||
|
||||
The MIT License (MIT) - see [`LICENSE.md`](https://github.com/fatih/color/blob/master/LICENSE.md) for more details
|
||||
|
||||
6
vendor/github.com/fsnotify/fsnotify/.gitignore
generated
vendored
Normal file
6
vendor/github.com/fsnotify/fsnotify/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
# Setup a Global .gitignore for OS and editor generated files:
|
||||
# https://help.github.com/articles/ignoring-files
|
||||
# git config --global core.excludesfile ~/.gitignore_global
|
||||
|
||||
.vagrant
|
||||
*.sublime-project
|
||||
317
vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
generated
vendored
Normal file
317
vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,317 @@
|
||||
# Changelog
|
||||
|
||||
## v1.4.7 / 2018-01-09
|
||||
|
||||
* BSD/macOS: Fix possible deadlock on closing the watcher on kqueue (thanks @nhooyr and @glycerine)
|
||||
* Tests: Fix missing verb on format string (thanks @rchiossi)
|
||||
* Linux: Fix deadlock in Remove (thanks @aarondl)
|
||||
* Linux: Watch.Add improvements (avoid race, fix consistency, reduce garbage) (thanks @twpayne)
|
||||
* Docs: Moved FAQ into the README (thanks @vahe)
|
||||
* Linux: Properly handle inotify's IN_Q_OVERFLOW event (thanks @zeldovich)
|
||||
* Docs: replace references to OS X with macOS
|
||||
|
||||
## v1.4.2 / 2016-10-10
|
||||
|
||||
* Linux: use InotifyInit1 with IN_CLOEXEC to stop leaking a file descriptor to a child process when using fork/exec [#178](https://github.com/fsnotify/fsnotify/pull/178) (thanks @pattyshack)
|
||||
|
||||
## v1.4.1 / 2016-10-04
|
||||
|
||||
* Fix flaky inotify stress test on Linux [#177](https://github.com/fsnotify/fsnotify/pull/177) (thanks @pattyshack)
|
||||
|
||||
## v1.4.0 / 2016-10-01
|
||||
|
||||
* add a String() method to Event.Op [#165](https://github.com/fsnotify/fsnotify/pull/165) (thanks @oozie)
|
||||
|
||||
## v1.3.1 / 2016-06-28
|
||||
|
||||
* Windows: fix for double backslash when watching the root of a drive [#151](https://github.com/fsnotify/fsnotify/issues/151) (thanks @brunoqc)
|
||||
|
||||
## v1.3.0 / 2016-04-19
|
||||
|
||||
* Support linux/arm64 by [patching](https://go-review.googlesource.com/#/c/21971/) x/sys/unix and switching to to it from syscall (thanks @suihkulokki) [#135](https://github.com/fsnotify/fsnotify/pull/135)
|
||||
|
||||
## v1.2.10 / 2016-03-02
|
||||
|
||||
* Fix golint errors in windows.go [#121](https://github.com/fsnotify/fsnotify/pull/121) (thanks @tiffanyfj)
|
||||
|
||||
## v1.2.9 / 2016-01-13
|
||||
|
||||
kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsnotify/pull/111) (thanks @bep)
|
||||
|
||||
## v1.2.8 / 2015-12-17
|
||||
|
||||
* kqueue: fix race condition in Close [#105](https://github.com/fsnotify/fsnotify/pull/105) (thanks @djui for reporting the issue and @ppknap for writing a failing test)
|
||||
* inotify: fix race in test
|
||||
* enable race detection for continuous integration (Linux, Mac, Windows)
|
||||
|
||||
## v1.2.5 / 2015-10-17
|
||||
|
||||
* inotify: use epoll_create1 for arm64 support (requires Linux 2.6.27 or later) [#100](https://github.com/fsnotify/fsnotify/pull/100) (thanks @suihkulokki)
|
||||
* inotify: fix path leaks [#73](https://github.com/fsnotify/fsnotify/pull/73) (thanks @chamaken)
|
||||
* kqueue: watch for rename events on subdirectories [#83](https://github.com/fsnotify/fsnotify/pull/83) (thanks @guotie)
|
||||
* kqueue: avoid infinite loops from symlinks cycles [#101](https://github.com/fsnotify/fsnotify/pull/101) (thanks @illicitonion)
|
||||
|
||||
## v1.2.1 / 2015-10-14
|
||||
|
||||
* kqueue: don't watch named pipes [#98](https://github.com/fsnotify/fsnotify/pull/98) (thanks @evanphx)
|
||||
|
||||
## v1.2.0 / 2015-02-08
|
||||
|
||||
* inotify: use epoll to wake up readEvents [#66](https://github.com/fsnotify/fsnotify/pull/66) (thanks @PieterD)
|
||||
* inotify: closing watcher should now always shut down goroutine [#63](https://github.com/fsnotify/fsnotify/pull/63) (thanks @PieterD)
|
||||
* kqueue: close kqueue after removing watches, fixes [#59](https://github.com/fsnotify/fsnotify/issues/59)
|
||||
|
||||
## v1.1.1 / 2015-02-05
|
||||
|
||||
* inotify: Retry read on EINTR [#61](https://github.com/fsnotify/fsnotify/issues/61) (thanks @PieterD)
|
||||
|
||||
## v1.1.0 / 2014-12-12
|
||||
|
||||
* kqueue: rework internals [#43](https://github.com/fsnotify/fsnotify/pull/43)
|
||||
* add low-level functions
|
||||
* only need to store flags on directories
|
||||
* less mutexes [#13](https://github.com/fsnotify/fsnotify/issues/13)
|
||||
* done can be an unbuffered channel
|
||||
* remove calls to os.NewSyscallError
|
||||
* More efficient string concatenation for Event.String() [#52](https://github.com/fsnotify/fsnotify/pull/52) (thanks @mdlayher)
|
||||
* kqueue: fix regression in rework causing subdirectories to be watched [#48](https://github.com/fsnotify/fsnotify/issues/48)
|
||||
* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51)
|
||||
|
||||
## v1.0.4 / 2014-09-07
|
||||
|
||||
* kqueue: add dragonfly to the build tags.
|
||||
* Rename source code files, rearrange code so exported APIs are at the top.
|
||||
* Add done channel to example code. [#37](https://github.com/fsnotify/fsnotify/pull/37) (thanks @chenyukang)
|
||||
|
||||
## v1.0.3 / 2014-08-19
|
||||
|
||||
* [Fix] Windows MOVED_TO now translates to Create like on BSD and Linux. [#36](https://github.com/fsnotify/fsnotify/issues/36)
|
||||
|
||||
## v1.0.2 / 2014-08-17
|
||||
|
||||
* [Fix] Missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso)
|
||||
* [Fix] Make ./path and path equivalent. (thanks @zhsso)
|
||||
|
||||
## v1.0.0 / 2014-08-15
|
||||
|
||||
* [API] Remove AddWatch on Windows, use Add.
|
||||
* Improve documentation for exported identifiers. [#30](https://github.com/fsnotify/fsnotify/issues/30)
|
||||
* Minor updates based on feedback from golint.
|
||||
|
||||
## dev / 2014-07-09
|
||||
|
||||
* Moved to [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify).
|
||||
* Use os.NewSyscallError instead of returning errno (thanks @hariharan-uno)
|
||||
|
||||
## dev / 2014-07-04
|
||||
|
||||
* kqueue: fix incorrect mutex used in Close()
|
||||
* Update example to demonstrate usage of Op.
|
||||
|
||||
## dev / 2014-06-28
|
||||
|
||||
* [API] Don't set the Write Op for attribute notifications [#4](https://github.com/fsnotify/fsnotify/issues/4)
|
||||
* Fix for String() method on Event (thanks Alex Brainman)
|
||||
* Don't build on Plan 9 or Solaris (thanks @4ad)
|
||||
|
||||
## dev / 2014-06-21
|
||||
|
||||
* Events channel of type Event rather than *Event.
|
||||
* [internal] use syscall constants directly for inotify and kqueue.
|
||||
* [internal] kqueue: rename events to kevents and fileEvent to event.
|
||||
|
||||
## dev / 2014-06-19
|
||||
|
||||
* Go 1.3+ required on Windows (uses syscall.ERROR_MORE_DATA internally).
|
||||
* [internal] remove cookie from Event struct (unused).
|
||||
* [internal] Event struct has the same definition across every OS.
|
||||
* [internal] remove internal watch and removeWatch methods.
|
||||
|
||||
## dev / 2014-06-12
|
||||
|
||||
* [API] Renamed Watch() to Add() and RemoveWatch() to Remove().
|
||||
* [API] Pluralized channel names: Events and Errors.
|
||||
* [API] Renamed FileEvent struct to Event.
|
||||
* [API] Op constants replace methods like IsCreate().
|
||||
|
||||
## dev / 2014-06-12
|
||||
|
||||
* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98)
|
||||
|
||||
## dev / 2014-05-23
|
||||
|
||||
* [API] Remove current implementation of WatchFlags.
|
||||
* current implementation doesn't take advantage of OS for efficiency
|
||||
* provides little benefit over filtering events as they are received, but has extra bookkeeping and mutexes
|
||||
* no tests for the current implementation
|
||||
* not fully implemented on Windows [#93](https://github.com/howeyc/fsnotify/issues/93#issuecomment-39285195)
|
||||
|
||||
## v0.9.3 / 2014-12-31
|
||||
|
||||
* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51)
|
||||
|
||||
## v0.9.2 / 2014-08-17
|
||||
|
||||
* [Backport] Fix missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso)
|
||||
|
||||
## v0.9.1 / 2014-06-12
|
||||
|
||||
* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98)
|
||||
|
||||
## v0.9.0 / 2014-01-17
|
||||
|
||||
* IsAttrib() for events that only concern a file's metadata [#79][] (thanks @abustany)
|
||||
* [Fix] kqueue: fix deadlock [#77][] (thanks @cespare)
|
||||
* [NOTICE] Development has moved to `code.google.com/p/go.exp/fsnotify` in preparation for inclusion in the Go standard library.
|
||||
|
||||
## v0.8.12 / 2013-11-13
|
||||
|
||||
* [API] Remove FD_SET and friends from Linux adapter
|
||||
|
||||
## v0.8.11 / 2013-11-02
|
||||
|
||||
* [Doc] Add Changelog [#72][] (thanks @nathany)
|
||||
* [Doc] Spotlight and double modify events on macOS [#62][] (reported by @paulhammond)
|
||||
|
||||
## v0.8.10 / 2013-10-19
|
||||
|
||||
* [Fix] kqueue: remove file watches when parent directory is removed [#71][] (reported by @mdwhatcott)
|
||||
* [Fix] kqueue: race between Close and readEvents [#70][] (reported by @bernerdschaefer)
|
||||
* [Doc] specify OS-specific limits in README (thanks @debrando)
|
||||
|
||||
## v0.8.9 / 2013-09-08
|
||||
|
||||
* [Doc] Contributing (thanks @nathany)
|
||||
* [Doc] update package path in example code [#63][] (thanks @paulhammond)
|
||||
* [Doc] GoCI badge in README (Linux only) [#60][]
|
||||
* [Doc] Cross-platform testing with Vagrant [#59][] (thanks @nathany)
|
||||
|
||||
## v0.8.8 / 2013-06-17
|
||||
|
||||
* [Fix] Windows: handle `ERROR_MORE_DATA` on Windows [#49][] (thanks @jbowtie)
|
||||
|
||||
## v0.8.7 / 2013-06-03
|
||||
|
||||
* [API] Make syscall flags internal
|
||||
* [Fix] inotify: ignore event changes
|
||||
* [Fix] race in symlink test [#45][] (reported by @srid)
|
||||
* [Fix] tests on Windows
|
||||
* lower case error messages
|
||||
|
||||
## v0.8.6 / 2013-05-23
|
||||
|
||||
* kqueue: Use EVT_ONLY flag on Darwin
|
||||
* [Doc] Update README with full example
|
||||
|
||||
## v0.8.5 / 2013-05-09
|
||||
|
||||
* [Fix] inotify: allow monitoring of "broken" symlinks (thanks @tsg)
|
||||
|
||||
## v0.8.4 / 2013-04-07
|
||||
|
||||
* [Fix] kqueue: watch all file events [#40][] (thanks @ChrisBuchholz)
|
||||
|
||||
## v0.8.3 / 2013-03-13
|
||||
|
||||
* [Fix] inoitfy/kqueue memory leak [#36][] (reported by @nbkolchin)
|
||||
* [Fix] kqueue: use fsnFlags for watching a directory [#33][] (reported by @nbkolchin)
|
||||
|
||||
## v0.8.2 / 2013-02-07
|
||||
|
||||
* [Doc] add Authors
|
||||
* [Fix] fix data races for map access [#29][] (thanks @fsouza)
|
||||
|
||||
## v0.8.1 / 2013-01-09
|
||||
|
||||
* [Fix] Windows path separators
|
||||
* [Doc] BSD License
|
||||
|
||||
## v0.8.0 / 2012-11-09
|
||||
|
||||
* kqueue: directory watching improvements (thanks @vmirage)
|
||||
* inotify: add `IN_MOVED_TO` [#25][] (requested by @cpisto)
|
||||
* [Fix] kqueue: deleting watched directory [#24][] (reported by @jakerr)
|
||||
|
||||
## v0.7.4 / 2012-10-09
|
||||
|
||||
* [Fix] inotify: fixes from https://codereview.appspot.com/5418045/ (ugorji)
|
||||
* [Fix] kqueue: preserve watch flags when watching for delete [#21][] (reported by @robfig)
|
||||
* [Fix] kqueue: watch the directory even if it isn't a new watch (thanks @robfig)
|
||||
* [Fix] kqueue: modify after recreation of file
|
||||
|
||||
## v0.7.3 / 2012-09-27
|
||||
|
||||
* [Fix] kqueue: watch with an existing folder inside the watched folder (thanks @vmirage)
|
||||
* [Fix] kqueue: no longer get duplicate CREATE events
|
||||
|
||||
## v0.7.2 / 2012-09-01
|
||||
|
||||
* kqueue: events for created directories
|
||||
|
||||
## v0.7.1 / 2012-07-14
|
||||
|
||||
* [Fix] for renaming files
|
||||
|
||||
## v0.7.0 / 2012-07-02
|
||||
|
||||
* [Feature] FSNotify flags
|
||||
* [Fix] inotify: Added file name back to event path
|
||||
|
||||
## v0.6.0 / 2012-06-06
|
||||
|
||||
* kqueue: watch files after directory created (thanks @tmc)
|
||||
|
||||
## v0.5.1 / 2012-05-22
|
||||
|
||||
* [Fix] inotify: remove all watches before Close()
|
||||
|
||||
## v0.5.0 / 2012-05-03
|
||||
|
||||
* [API] kqueue: return errors during watch instead of sending over channel
|
||||
* kqueue: match symlink behavior on Linux
|
||||
* inotify: add `DELETE_SELF` (requested by @taralx)
|
||||
* [Fix] kqueue: handle EINTR (reported by @robfig)
|
||||
* [Doc] Godoc example [#1][] (thanks @davecheney)
|
||||
|
||||
## v0.4.0 / 2012-03-30
|
||||
|
||||
* Go 1 released: build with go tool
|
||||
* [Feature] Windows support using winfsnotify
|
||||
* Windows does not have attribute change notifications
|
||||
* Roll attribute notifications into IsModify
|
||||
|
||||
## v0.3.0 / 2012-02-19
|
||||
|
||||
* kqueue: add files when watch directory
|
||||
|
||||
## v0.2.0 / 2011-12-30
|
||||
|
||||
* update to latest Go weekly code
|
||||
|
||||
## v0.1.0 / 2011-10-19
|
||||
|
||||
* kqueue: add watch on file creation to match inotify
|
||||
* kqueue: create file event
|
||||
* inotify: ignore `IN_IGNORED` events
|
||||
* event String()
|
||||
* linux: common FileEvent functions
|
||||
* initial commit
|
||||
|
||||
[#79]: https://github.com/howeyc/fsnotify/pull/79
|
||||
[#77]: https://github.com/howeyc/fsnotify/pull/77
|
||||
[#72]: https://github.com/howeyc/fsnotify/issues/72
|
||||
[#71]: https://github.com/howeyc/fsnotify/issues/71
|
||||
[#70]: https://github.com/howeyc/fsnotify/issues/70
|
||||
[#63]: https://github.com/howeyc/fsnotify/issues/63
|
||||
[#62]: https://github.com/howeyc/fsnotify/issues/62
|
||||
[#60]: https://github.com/howeyc/fsnotify/issues/60
|
||||
[#59]: https://github.com/howeyc/fsnotify/issues/59
|
||||
[#49]: https://github.com/howeyc/fsnotify/issues/49
|
||||
[#45]: https://github.com/howeyc/fsnotify/issues/45
|
||||
[#40]: https://github.com/howeyc/fsnotify/issues/40
|
||||
[#36]: https://github.com/howeyc/fsnotify/issues/36
|
||||
[#33]: https://github.com/howeyc/fsnotify/issues/33
|
||||
[#29]: https://github.com/howeyc/fsnotify/issues/29
|
||||
[#25]: https://github.com/howeyc/fsnotify/issues/25
|
||||
[#24]: https://github.com/howeyc/fsnotify/issues/24
|
||||
[#21]: https://github.com/howeyc/fsnotify/issues/21
|
||||
77
vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
generated
vendored
Normal file
77
vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
# Contributing
|
||||
|
||||
## Issues
|
||||
|
||||
* Request features and report bugs using the [GitHub Issue Tracker](https://github.com/fsnotify/fsnotify/issues).
|
||||
* Please indicate the platform you are using fsnotify on.
|
||||
* A code example to reproduce the problem is appreciated.
|
||||
|
||||
## Pull Requests
|
||||
|
||||
### Contributor License Agreement
|
||||
|
||||
fsnotify is derived from code in the [golang.org/x/exp](https://godoc.org/golang.org/x/exp) package and it may be included [in the standard library](https://github.com/fsnotify/fsnotify/issues/1) in the future. Therefore fsnotify carries the same [LICENSE](https://github.com/fsnotify/fsnotify/blob/master/LICENSE) as Go. Contributors retain their copyright, so you need to fill out a short form before we can accept your contribution: [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual).
|
||||
|
||||
Please indicate that you have signed the CLA in your pull request.
|
||||
|
||||
### How fsnotify is Developed
|
||||
|
||||
* Development is done on feature branches.
|
||||
* Tests are run on BSD, Linux, macOS and Windows.
|
||||
* Pull requests are reviewed and [applied to master][am] using [hub][].
|
||||
* Maintainers may modify or squash commits rather than asking contributors to.
|
||||
* To issue a new release, the maintainers will:
|
||||
* Update the CHANGELOG
|
||||
* Tag a version, which will become available through gopkg.in.
|
||||
|
||||
### How to Fork
|
||||
|
||||
For smooth sailing, always use the original import path. Installing with `go get` makes this easy.
|
||||
|
||||
1. Install from GitHub (`go get -u github.com/fsnotify/fsnotify`)
|
||||
2. Create your feature branch (`git checkout -b my-new-feature`)
|
||||
3. Ensure everything works and the tests pass (see below)
|
||||
4. Commit your changes (`git commit -am 'Add some feature'`)
|
||||
|
||||
Contribute upstream:
|
||||
|
||||
1. Fork fsnotify on GitHub
|
||||
2. Add your remote (`git remote add fork git@github.com:mycompany/repo.git`)
|
||||
3. Push to the branch (`git push fork my-new-feature`)
|
||||
4. Create a new Pull Request on GitHub
|
||||
|
||||
This workflow is [thoroughly explained by Katrina Owen](https://splice.com/blog/contributing-open-source-git-repositories-go/).
|
||||
|
||||
### Testing
|
||||
|
||||
fsnotify uses build tags to compile different code on Linux, BSD, macOS, and Windows.
|
||||
|
||||
Before doing a pull request, please do your best to test your changes on multiple platforms, and list which platforms you were able/unable to test on.
|
||||
|
||||
To aid in cross-platform testing there is a Vagrantfile for Linux and BSD.
|
||||
|
||||
* Install [Vagrant](http://www.vagrantup.com/) and [VirtualBox](https://www.virtualbox.org/)
|
||||
* Setup [Vagrant Gopher](https://github.com/nathany/vagrant-gopher) in your `src` folder.
|
||||
* Run `vagrant up` from the project folder. You can also setup just one box with `vagrant up linux` or `vagrant up bsd` (note: the BSD box doesn't support Windows hosts at this time, and NFS may prompt for your host OS password)
|
||||
* Once setup, you can run the test suite on a given OS with a single command `vagrant ssh linux -c 'cd fsnotify/fsnotify; go test'`.
|
||||
* When you're done, you will want to halt or destroy the Vagrant boxes.
|
||||
|
||||
Notice: fsnotify file system events won't trigger in shared folders. The tests get around this limitation by using the /tmp directory.
|
||||
|
||||
Right now there is no equivalent solution for Windows and macOS, but there are Windows VMs [freely available from Microsoft](http://www.modern.ie/en-us/virtualization-tools#downloads).
|
||||
|
||||
### Maintainers
|
||||
|
||||
Help maintaining fsnotify is welcome. To be a maintainer:
|
||||
|
||||
* Submit a pull request and sign the CLA as above.
|
||||
* You must be able to run the test suite on Mac, Windows, Linux and BSD.
|
||||
|
||||
To keep master clean, the fsnotify project uses the "apply mail" workflow outlined in Nathaniel Talbott's post ["Merge pull request" Considered Harmful][am]. This requires installing [hub][].
|
||||
|
||||
All code changes should be internal pull requests.
|
||||
|
||||
Releases are tagged using [Semantic Versioning](http://semver.org/).
|
||||
|
||||
[hub]: https://github.com/github/hub
|
||||
[am]: http://blog.spreedly.com/2014/06/24/merge-pull-request-considered-harmful/#.VGa5yZPF_Zs
|
||||
79
vendor/github.com/fsnotify/fsnotify/README.md
generated
vendored
Normal file
79
vendor/github.com/fsnotify/fsnotify/README.md
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
# File system notifications for Go
|
||||
|
||||
[](https://godoc.org/github.com/fsnotify/fsnotify) [](https://goreportcard.com/report/github.com/fsnotify/fsnotify)
|
||||
|
||||
fsnotify utilizes [golang.org/x/sys](https://godoc.org/golang.org/x/sys) rather than `syscall` from the standard library. Ensure you have the latest version installed by running:
|
||||
|
||||
```console
|
||||
go get -u golang.org/x/sys/...
|
||||
```
|
||||
|
||||
Cross platform: Windows, Linux, BSD and macOS.
|
||||
|
||||
|Adapter |OS |Status |
|
||||
|----------|----------|----------|
|
||||
|inotify |Linux 2.6.27 or later, Android\*|Supported [](https://travis-ci.org/fsnotify/fsnotify)|
|
||||
|kqueue |BSD, macOS, iOS\*|Supported [](https://travis-ci.org/fsnotify/fsnotify)|
|
||||
|ReadDirectoryChangesW|Windows|Supported [](https://ci.appveyor.com/project/NathanYoungman/fsnotify/branch/master)|
|
||||
|FSEvents |macOS |[Planned](https://github.com/fsnotify/fsnotify/issues/11)|
|
||||
|FEN |Solaris 11 |[In Progress](https://github.com/fsnotify/fsnotify/issues/12)|
|
||||
|fanotify |Linux 2.6.37+ | |
|
||||
|USN Journals |Windows |[Maybe](https://github.com/fsnotify/fsnotify/issues/53)|
|
||||
|Polling |*All* |[Maybe](https://github.com/fsnotify/fsnotify/issues/9)|
|
||||
|
||||
\* Android and iOS are untested.
|
||||
|
||||
Please see [the documentation](https://godoc.org/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information.
|
||||
|
||||
## API stability
|
||||
|
||||
fsnotify is a fork of [howeyc/fsnotify](https://godoc.org/github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA).
|
||||
|
||||
All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/). Further API changes are [planned](https://github.com/fsnotify/fsnotify/milestones), and will be tagged with a new major revision number.
|
||||
|
||||
Go 1.6 supports dependencies located in the `vendor/` folder. Unless you are creating a library, it is recommended that you copy fsnotify into `vendor/github.com/fsnotify/fsnotify` within your project, and likewise for `golang.org/x/sys`.
|
||||
|
||||
## Contributing
|
||||
|
||||
Please refer to [CONTRIBUTING][] before opening an issue or pull request.
|
||||
|
||||
## Example
|
||||
|
||||
See [example_test.go](https://github.com/fsnotify/fsnotify/blob/master/example_test.go).
|
||||
|
||||
## FAQ
|
||||
|
||||
**When a file is moved to another directory is it still being watched?**
|
||||
|
||||
No (it shouldn't be, unless you are watching where it was moved to).
|
||||
|
||||
**When I watch a directory, are all subdirectories watched as well?**
|
||||
|
||||
No, you must add watches for any directory you want to watch (a recursive watcher is on the roadmap [#18][]).
|
||||
|
||||
**Do I have to watch the Error and Event channels in a separate goroutine?**
|
||||
|
||||
As of now, yes. Looking into making this single-thread friendly (see [howeyc #7][#7])
|
||||
|
||||
**Why am I receiving multiple events for the same file on OS X?**
|
||||
|
||||
Spotlight indexing on OS X can result in multiple events (see [howeyc #62][#62]). A temporary workaround is to add your folder(s) to the *Spotlight Privacy settings* until we have a native FSEvents implementation (see [#11][]).
|
||||
|
||||
**How many files can be watched at once?**
|
||||
|
||||
There are OS-specific limits as to how many watches can be created:
|
||||
* Linux: /proc/sys/fs/inotify/max_user_watches contains the limit, reaching this limit results in a "no space left on device" error.
|
||||
* BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error.
|
||||
|
||||
[#62]: https://github.com/howeyc/fsnotify/issues/62
|
||||
[#18]: https://github.com/fsnotify/fsnotify/issues/18
|
||||
[#11]: https://github.com/fsnotify/fsnotify/issues/11
|
||||
[#7]: https://github.com/howeyc/fsnotify/issues/7
|
||||
|
||||
[contributing]: https://github.com/fsnotify/fsnotify/blob/master/CONTRIBUTING.md
|
||||
|
||||
## Related Projects
|
||||
|
||||
* [notify](https://github.com/rjeczalik/notify)
|
||||
* [fsevents](https://github.com/fsnotify/fsevents)
|
||||
|
||||
66
vendor/github.com/go-errors/errors/README.md
generated
vendored
Normal file
66
vendor/github.com/go-errors/errors/README.md
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
go-errors/errors
|
||||
================
|
||||
|
||||
[](https://travis-ci.org/go-errors/errors)
|
||||
|
||||
Package errors adds stacktrace support to errors in go.
|
||||
|
||||
This is particularly useful when you want to understand the state of execution
|
||||
when an error was returned unexpectedly.
|
||||
|
||||
It provides the type \*Error which implements the standard golang error
|
||||
interface, so you can use this library interchangably with code that is
|
||||
expecting a normal error return.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Full documentation is available on
|
||||
[godoc](https://godoc.org/github.com/go-errors/errors), but here's a simple
|
||||
example:
|
||||
|
||||
```go
|
||||
package crashy
|
||||
|
||||
import "github.com/go-errors/errors"
|
||||
|
||||
var Crashed = errors.Errorf("oh dear")
|
||||
|
||||
func Crash() error {
|
||||
return errors.New(Crashed)
|
||||
}
|
||||
```
|
||||
|
||||
This can be called as follows:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"crashy"
|
||||
"fmt"
|
||||
"github.com/go-errors/errors"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := crashy.Crash()
|
||||
if err != nil {
|
||||
if errors.Is(err, crashy.Crashed) {
|
||||
fmt.Println(err.(*errors.Error).ErrorStack())
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Meta-fu
|
||||
-------
|
||||
|
||||
This package was original written to allow reporting to
|
||||
[Bugsnag](https://bugsnag.com/) from
|
||||
[bugsnag-go](https://github.com/bugsnag/bugsnag-go), but after I found similar
|
||||
packages by Facebook and Dropbox, it was moved to one canonical location so
|
||||
everyone can benefit.
|
||||
|
||||
This package is licensed under the MIT license, see LICENSE.MIT for details.
|
||||
89
vendor/github.com/go-errors/errors/cover.out
generated
vendored
Normal file
89
vendor/github.com/go-errors/errors/cover.out
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
mode: set
|
||||
github.com/go-errors/errors/stackframe.go:27.51,30.25 2 1
|
||||
github.com/go-errors/errors/stackframe.go:33.2,38.8 3 1
|
||||
github.com/go-errors/errors/stackframe.go:30.25,32.3 1 0
|
||||
github.com/go-errors/errors/stackframe.go:43.47,44.31 1 1
|
||||
github.com/go-errors/errors/stackframe.go:47.2,47.48 1 1
|
||||
github.com/go-errors/errors/stackframe.go:44.31,46.3 1 1
|
||||
github.com/go-errors/errors/stackframe.go:52.42,56.16 3 1
|
||||
github.com/go-errors/errors/stackframe.go:60.2,60.60 1 1
|
||||
github.com/go-errors/errors/stackframe.go:56.16,58.3 1 0
|
||||
github.com/go-errors/errors/stackframe.go:64.55,67.16 2 1
|
||||
github.com/go-errors/errors/stackframe.go:71.2,72.61 2 1
|
||||
github.com/go-errors/errors/stackframe.go:76.2,76.66 1 1
|
||||
github.com/go-errors/errors/stackframe.go:67.16,69.3 1 0
|
||||
github.com/go-errors/errors/stackframe.go:72.61,74.3 1 0
|
||||
github.com/go-errors/errors/stackframe.go:79.56,91.63 3 1
|
||||
github.com/go-errors/errors/stackframe.go:95.2,95.53 1 1
|
||||
github.com/go-errors/errors/stackframe.go:100.2,101.18 2 1
|
||||
github.com/go-errors/errors/stackframe.go:91.63,94.3 2 1
|
||||
github.com/go-errors/errors/stackframe.go:95.53,98.3 2 1
|
||||
github.com/go-errors/errors/error.go:70.32,73.23 2 1
|
||||
github.com/go-errors/errors/error.go:80.2,85.3 3 1
|
||||
github.com/go-errors/errors/error.go:74.2,75.10 1 1
|
||||
github.com/go-errors/errors/error.go:76.2,77.28 1 1
|
||||
github.com/go-errors/errors/error.go:92.43,95.23 2 1
|
||||
github.com/go-errors/errors/error.go:104.2,109.3 3 1
|
||||
github.com/go-errors/errors/error.go:96.2,97.11 1 1
|
||||
github.com/go-errors/errors/error.go:98.2,99.10 1 1
|
||||
github.com/go-errors/errors/error.go:100.2,101.28 1 1
|
||||
github.com/go-errors/errors/error.go:115.39,117.19 1 1
|
||||
github.com/go-errors/errors/error.go:121.2,121.29 1 1
|
||||
github.com/go-errors/errors/error.go:125.2,125.43 1 1
|
||||
github.com/go-errors/errors/error.go:129.2,129.14 1 1
|
||||
github.com/go-errors/errors/error.go:117.19,119.3 1 1
|
||||
github.com/go-errors/errors/error.go:121.29,123.3 1 1
|
||||
github.com/go-errors/errors/error.go:125.43,127.3 1 1
|
||||
github.com/go-errors/errors/error.go:135.53,137.2 1 1
|
||||
github.com/go-errors/errors/error.go:140.34,142.2 1 1
|
||||
github.com/go-errors/errors/error.go:146.34,149.42 2 1
|
||||
github.com/go-errors/errors/error.go:153.2,153.20 1 1
|
||||
github.com/go-errors/errors/error.go:149.42,151.3 1 1
|
||||
github.com/go-errors/errors/error.go:158.39,160.2 1 1
|
||||
github.com/go-errors/errors/error.go:164.46,165.23 1 1
|
||||
github.com/go-errors/errors/error.go:173.2,173.19 1 1
|
||||
github.com/go-errors/errors/error.go:165.23,168.32 2 1
|
||||
github.com/go-errors/errors/error.go:168.32,170.4 1 1
|
||||
github.com/go-errors/errors/error.go:177.37,178.42 1 1
|
||||
github.com/go-errors/errors/error.go:181.2,181.41 1 1
|
||||
github.com/go-errors/errors/error.go:178.42,180.3 1 1
|
||||
github.com/go-errors/errors/parse_panic.go:10.39,12.2 1 1
|
||||
github.com/go-errors/errors/parse_panic.go:16.46,24.34 5 1
|
||||
github.com/go-errors/errors/parse_panic.go:70.2,70.43 1 1
|
||||
github.com/go-errors/errors/parse_panic.go:73.2,73.55 1 0
|
||||
github.com/go-errors/errors/parse_panic.go:24.34,27.23 2 1
|
||||
github.com/go-errors/errors/parse_panic.go:27.23,28.42 1 1
|
||||
github.com/go-errors/errors/parse_panic.go:28.42,31.5 2 1
|
||||
github.com/go-errors/errors/parse_panic.go:31.6,33.5 1 0
|
||||
github.com/go-errors/errors/parse_panic.go:35.5,35.29 1 1
|
||||
github.com/go-errors/errors/parse_panic.go:35.29,36.86 1 1
|
||||
github.com/go-errors/errors/parse_panic.go:36.86,38.5 1 1
|
||||
github.com/go-errors/errors/parse_panic.go:40.5,40.32 1 1
|
||||
github.com/go-errors/errors/parse_panic.go:40.32,41.18 1 1
|
||||
github.com/go-errors/errors/parse_panic.go:45.4,46.46 2 1
|
||||
github.com/go-errors/errors/parse_panic.go:51.4,53.23 2 1
|
||||
github.com/go-errors/errors/parse_panic.go:57.4,58.18 2 1
|
||||
github.com/go-errors/errors/parse_panic.go:62.4,63.17 2 1
|
||||
github.com/go-errors/errors/parse_panic.go:41.18,43.10 2 1
|
||||
github.com/go-errors/errors/parse_panic.go:46.46,49.5 2 1
|
||||
github.com/go-errors/errors/parse_panic.go:53.23,55.5 1 0
|
||||
github.com/go-errors/errors/parse_panic.go:58.18,60.5 1 0
|
||||
github.com/go-errors/errors/parse_panic.go:63.17,65.10 2 1
|
||||
github.com/go-errors/errors/parse_panic.go:70.43,72.3 1 1
|
||||
github.com/go-errors/errors/parse_panic.go:80.85,82.29 2 1
|
||||
github.com/go-errors/errors/parse_panic.go:85.2,85.15 1 1
|
||||
github.com/go-errors/errors/parse_panic.go:88.2,90.63 2 1
|
||||
github.com/go-errors/errors/parse_panic.go:94.2,94.53 1 1
|
||||
github.com/go-errors/errors/parse_panic.go:99.2,101.36 2 1
|
||||
github.com/go-errors/errors/parse_panic.go:105.2,106.15 2 1
|
||||
github.com/go-errors/errors/parse_panic.go:109.2,112.49 3 1
|
||||
github.com/go-errors/errors/parse_panic.go:116.2,117.16 2 1
|
||||
github.com/go-errors/errors/parse_panic.go:121.2,126.8 1 1
|
||||
github.com/go-errors/errors/parse_panic.go:82.29,84.3 1 0
|
||||
github.com/go-errors/errors/parse_panic.go:85.15,87.3 1 1
|
||||
github.com/go-errors/errors/parse_panic.go:90.63,93.3 2 1
|
||||
github.com/go-errors/errors/parse_panic.go:94.53,97.3 2 1
|
||||
github.com/go-errors/errors/parse_panic.go:101.36,103.3 1 0
|
||||
github.com/go-errors/errors/parse_panic.go:106.15,108.3 1 0
|
||||
github.com/go-errors/errors/parse_panic.go:112.49,114.3 1 1
|
||||
github.com/go-errors/errors/parse_panic.go:117.16,119.3 1 0
|
||||
6
vendor/github.com/go-ini/ini/.gitignore
generated
vendored
Normal file
6
vendor/github.com/go-ini/ini/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
testdata/conf_out.ini
|
||||
ini.sublime-project
|
||||
ini.sublime-workspace
|
||||
testdata/conf_reflect.ini
|
||||
.idea
|
||||
/.vscode
|
||||
15
vendor/github.com/go-ini/ini/Makefile
generated
vendored
Normal file
15
vendor/github.com/go-ini/ini/Makefile
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
.PHONY: build test bench vet coverage
|
||||
|
||||
build: vet bench
|
||||
|
||||
test:
|
||||
go test -v -cover -race
|
||||
|
||||
bench:
|
||||
go test -v -cover -race -test.bench=. -test.benchmem
|
||||
|
||||
vet:
|
||||
go vet
|
||||
|
||||
coverage:
|
||||
go test -coverprofile=c.out && go tool cover -html=c.out && rm c.out
|
||||
44
vendor/github.com/go-ini/ini/README.md
generated
vendored
Normal file
44
vendor/github.com/go-ini/ini/README.md
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
INI [](https://travis-ci.org/go-ini/ini) [](https://sourcegraph.com/github.com/go-ini/ini)
|
||||
===
|
||||
|
||||

|
||||
|
||||
Package ini provides INI file read and write functionality in Go.
|
||||
|
||||
## Features
|
||||
|
||||
- Load from multiple data sources(`[]byte`, file and `io.ReadCloser`) with overwrites.
|
||||
- Read with recursion values.
|
||||
- Read with parent-child sections.
|
||||
- Read with auto-increment key names.
|
||||
- Read with multiple-line values.
|
||||
- Read with tons of helper methods.
|
||||
- Read and convert values to Go types.
|
||||
- Read and **WRITE** comments of sections and keys.
|
||||
- Manipulate sections, keys and comments with ease.
|
||||
- Keep sections and keys in order as you parse and save.
|
||||
|
||||
## Installation
|
||||
|
||||
To use a tagged revision:
|
||||
|
||||
```sh
|
||||
$ go get gopkg.in/ini.v1
|
||||
```
|
||||
|
||||
To use with latest changes:
|
||||
|
||||
```sh
|
||||
$ go get github.com/go-ini/ini
|
||||
```
|
||||
|
||||
Please add `-u` flag to update in the future.
|
||||
|
||||
## Getting Help
|
||||
|
||||
- [Getting Started](https://ini.unknwon.io/docs/intro/getting_started)
|
||||
- [API Documentation](https://gowalker.org/gopkg.in/ini.v1)
|
||||
|
||||
## License
|
||||
|
||||
This project is under Apache v2 License. See the [LICENSE](LICENSE) file for the full license text.
|
||||
30
vendor/github.com/hashicorp/go-cleanhttp/README.md
generated
vendored
Normal file
30
vendor/github.com/hashicorp/go-cleanhttp/README.md
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
# cleanhttp
|
||||
|
||||
Functions for accessing "clean" Go http.Client values
|
||||
|
||||
-------------
|
||||
|
||||
The Go standard library contains a default `http.Client` called
|
||||
`http.DefaultClient`. It is a common idiom in Go code to start with
|
||||
`http.DefaultClient` and tweak it as necessary, and in fact, this is
|
||||
encouraged; from the `http` package documentation:
|
||||
|
||||
> The Client's Transport typically has internal state (cached TCP connections),
|
||||
so Clients should be reused instead of created as needed. Clients are safe for
|
||||
concurrent use by multiple goroutines.
|
||||
|
||||
Unfortunately, this is a shared value, and it is not uncommon for libraries to
|
||||
assume that they are free to modify it at will. With enough dependencies, it
|
||||
can be very easy to encounter strange problems and race conditions due to
|
||||
manipulation of this shared value across libraries and goroutines (clients are
|
||||
safe for concurrent use, but writing values to the client struct itself is not
|
||||
protected).
|
||||
|
||||
Making things worse is the fact that a bare `http.Client` will use a default
|
||||
`http.Transport` called `http.DefaultTransport`, which is another global value
|
||||
that behaves the same way. So it is not simply enough to replace
|
||||
`http.DefaultClient` with `&http.Client{}`.
|
||||
|
||||
This repository provides some simple functions to get a "clean" `http.Client`
|
||||
-- one that uses the same default values as the Go standard library, but
|
||||
returns a client that does not share any state with other clients.
|
||||
1
vendor/github.com/hashicorp/go-getter/test-fixtures/detect-file-symlink-pwd/syml/pwd
generated
vendored
1
vendor/github.com/hashicorp/go-getter/test-fixtures/detect-file-symlink-pwd/syml/pwd
generated
vendored
@@ -1 +0,0 @@
|
||||
../real
|
||||
10
vendor/github.com/hashicorp/go-safetemp/README.md
generated
vendored
Normal file
10
vendor/github.com/hashicorp/go-safetemp/README.md
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# go-safetemp
|
||||
[](https://godoc.org/github.com/hashicorp/go-safetemp)
|
||||
|
||||
Functions for safely working with temporary directories and files.
|
||||
|
||||
## Why?
|
||||
|
||||
The Go standard library provides the excellent `ioutil` package for
|
||||
working with temporary directories and files. This library builds on top
|
||||
of that to provide safe abstractions above that.
|
||||
65
vendor/github.com/hashicorp/go-version/README.md
generated
vendored
Normal file
65
vendor/github.com/hashicorp/go-version/README.md
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
# Versioning Library for Go
|
||||
[](https://travis-ci.org/hashicorp/go-version)
|
||||
|
||||
go-version is a library for parsing versions and version constraints,
|
||||
and verifying versions against a set of constraints. go-version
|
||||
can sort a collection of versions properly, handles prerelease/beta
|
||||
versions, can increment versions, etc.
|
||||
|
||||
Versions used with go-version must follow [SemVer](http://semver.org/).
|
||||
|
||||
## Installation and Usage
|
||||
|
||||
Package documentation can be found on
|
||||
[GoDoc](http://godoc.org/github.com/hashicorp/go-version).
|
||||
|
||||
Installation can be done with a normal `go get`:
|
||||
|
||||
```
|
||||
$ go get github.com/hashicorp/go-version
|
||||
```
|
||||
|
||||
#### Version Parsing and Comparison
|
||||
|
||||
```go
|
||||
v1, err := version.NewVersion("1.2")
|
||||
v2, err := version.NewVersion("1.5+metadata")
|
||||
|
||||
// Comparison example. There is also GreaterThan, Equal, and just
|
||||
// a simple Compare that returns an int allowing easy >=, <=, etc.
|
||||
if v1.LessThan(v2) {
|
||||
fmt.Printf("%s is less than %s", v1, v2)
|
||||
}
|
||||
```
|
||||
|
||||
#### Version Constraints
|
||||
|
||||
```go
|
||||
v1, err := version.NewVersion("1.2")
|
||||
|
||||
// Constraints example.
|
||||
constraints, err := version.NewConstraint(">= 1.0, < 1.4")
|
||||
if constraints.Check(v1) {
|
||||
fmt.Printf("%s satisfies constraints %s", v1, constraints)
|
||||
}
|
||||
```
|
||||
|
||||
#### Version Sorting
|
||||
|
||||
```go
|
||||
versionsRaw := []string{"1.1", "0.7.1", "1.4-beta", "1.4", "2"}
|
||||
versions := make([]*version.Version, len(versionsRaw))
|
||||
for i, raw := range versionsRaw {
|
||||
v, _ := version.NewVersion(raw)
|
||||
versions[i] = v
|
||||
}
|
||||
|
||||
// After this, the versions are properly sorted
|
||||
sort.Sort(version.Collection(versions))
|
||||
```
|
||||
|
||||
## Issues and Contributing
|
||||
|
||||
If you find an issue with this library, please report an issue. If you'd
|
||||
like, we welcome any contributions. Fork this library and submit a pull
|
||||
request.
|
||||
1
vendor/github.com/hashicorp/go-version/go.mod
generated
vendored
Normal file
1
vendor/github.com/hashicorp/go-version/go.mod
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module github.com/hashicorp/go-version
|
||||
9
vendor/github.com/hashicorp/hcl/.gitignore
generated
vendored
Normal file
9
vendor/github.com/hashicorp/hcl/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
y.output
|
||||
|
||||
# ignore intellij files
|
||||
.idea
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
*.test
|
||||
18
vendor/github.com/hashicorp/hcl/Makefile
generated
vendored
Normal file
18
vendor/github.com/hashicorp/hcl/Makefile
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
TEST?=./...
|
||||
|
||||
default: test
|
||||
|
||||
fmt: generate
|
||||
go fmt ./...
|
||||
|
||||
test: generate
|
||||
go get -t ./...
|
||||
go test $(TEST) $(TESTARGS)
|
||||
|
||||
generate:
|
||||
go generate ./...
|
||||
|
||||
updatedeps:
|
||||
go get -u golang.org/x/tools/cmd/stringer
|
||||
|
||||
.PHONY: default generate test updatedeps
|
||||
125
vendor/github.com/hashicorp/hcl/README.md
generated
vendored
Normal file
125
vendor/github.com/hashicorp/hcl/README.md
generated
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
# HCL
|
||||
|
||||
[](https://godoc.org/github.com/hashicorp/hcl) [](https://travis-ci.org/hashicorp/hcl)
|
||||
|
||||
HCL (HashiCorp Configuration Language) is a configuration language built
|
||||
by HashiCorp. The goal of HCL is to build a structured configuration language
|
||||
that is both human and machine friendly for use with command-line tools, but
|
||||
specifically targeted towards DevOps tools, servers, etc.
|
||||
|
||||
HCL is also fully JSON compatible. That is, JSON can be used as completely
|
||||
valid input to a system expecting HCL. This helps makes systems
|
||||
interoperable with other systems.
|
||||
|
||||
HCL is heavily inspired by
|
||||
[libucl](https://github.com/vstakhov/libucl),
|
||||
nginx configuration, and others similar.
|
||||
|
||||
## Why?
|
||||
|
||||
A common question when viewing HCL is to ask the question: why not
|
||||
JSON, YAML, etc.?
|
||||
|
||||
Prior to HCL, the tools we built at [HashiCorp](http://www.hashicorp.com)
|
||||
used a variety of configuration languages from full programming languages
|
||||
such as Ruby to complete data structure languages such as JSON. What we
|
||||
learned is that some people wanted human-friendly configuration languages
|
||||
and some people wanted machine-friendly languages.
|
||||
|
||||
JSON fits a nice balance in this, but is fairly verbose and most
|
||||
importantly doesn't support comments. With YAML, we found that beginners
|
||||
had a really hard time determining what the actual structure was, and
|
||||
ended up guessing more often than not whether to use a hyphen, colon, etc.
|
||||
in order to represent some configuration key.
|
||||
|
||||
Full programming languages such as Ruby enable complex behavior
|
||||
a configuration language shouldn't usually allow, and also forces
|
||||
people to learn some set of Ruby.
|
||||
|
||||
Because of this, we decided to create our own configuration language
|
||||
that is JSON-compatible. Our configuration language (HCL) is designed
|
||||
to be written and modified by humans. The API for HCL allows JSON
|
||||
as an input so that it is also machine-friendly (machines can generate
|
||||
JSON instead of trying to generate HCL).
|
||||
|
||||
Our goal with HCL is not to alienate other configuration languages.
|
||||
It is instead to provide HCL as a specialized language for our tools,
|
||||
and JSON as the interoperability layer.
|
||||
|
||||
## Syntax
|
||||
|
||||
For a complete grammar, please see the parser itself. A high-level overview
|
||||
of the syntax and grammar is listed here.
|
||||
|
||||
* Single line comments start with `#` or `//`
|
||||
|
||||
* Multi-line comments are wrapped in `/*` and `*/`. Nested block comments
|
||||
are not allowed. A multi-line comment (also known as a block comment)
|
||||
terminates at the first `*/` found.
|
||||
|
||||
* Values are assigned with the syntax `key = value` (whitespace doesn't
|
||||
matter). The value can be any primitive: a string, number, boolean,
|
||||
object, or list.
|
||||
|
||||
* Strings are double-quoted and can contain any UTF-8 characters.
|
||||
Example: `"Hello, World"`
|
||||
|
||||
* Multi-line strings start with `<<EOF` at the end of a line, and end
|
||||
with `EOF` on its own line ([here documents](https://en.wikipedia.org/wiki/Here_document)).
|
||||
Any text may be used in place of `EOF`. Example:
|
||||
```
|
||||
<<FOO
|
||||
hello
|
||||
world
|
||||
FOO
|
||||
```
|
||||
|
||||
* Numbers are assumed to be base 10. If you prefix a number with 0x,
|
||||
it is treated as a hexadecimal. If it is prefixed with 0, it is
|
||||
treated as an octal. Numbers can be in scientific notation: "1e10".
|
||||
|
||||
* Boolean values: `true`, `false`
|
||||
|
||||
* Arrays can be made by wrapping it in `[]`. Example:
|
||||
`["foo", "bar", 42]`. Arrays can contain primitives,
|
||||
other arrays, and objects. As an alternative, lists
|
||||
of objects can be created with repeated blocks, using
|
||||
this structure:
|
||||
|
||||
```hcl
|
||||
service {
|
||||
key = "value"
|
||||
}
|
||||
|
||||
service {
|
||||
key = "value"
|
||||
}
|
||||
```
|
||||
|
||||
Objects and nested objects are created using the structure shown below:
|
||||
|
||||
```
|
||||
variable "ami" {
|
||||
description = "the AMI to use"
|
||||
}
|
||||
```
|
||||
This would be equivalent to the following json:
|
||||
``` json
|
||||
{
|
||||
"variable": {
|
||||
"ami": {
|
||||
"description": "the AMI to use"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Thanks
|
||||
|
||||
Thanks to:
|
||||
|
||||
* [@vstakhov](https://github.com/vstakhov) - The original libucl parser
|
||||
and syntax that HCL was based off of.
|
||||
|
||||
* [@fatih](https://github.com/fatih) - The rewritten HCL parser
|
||||
in pure Go (no goyacc) and support for a printer.
|
||||
19
vendor/github.com/hashicorp/hcl/appveyor.yml
generated
vendored
Normal file
19
vendor/github.com/hashicorp/hcl/appveyor.yml
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
version: "build-{branch}-{build}"
|
||||
image: Visual Studio 2015
|
||||
clone_folder: c:\gopath\src\github.com\hashicorp\hcl
|
||||
environment:
|
||||
GOPATH: c:\gopath
|
||||
init:
|
||||
- git config --global core.autocrlf false
|
||||
install:
|
||||
- cmd: >-
|
||||
echo %Path%
|
||||
|
||||
go version
|
||||
|
||||
go env
|
||||
|
||||
go get -t ./...
|
||||
|
||||
build_script:
|
||||
- cmd: go test -v ./...
|
||||
14
vendor/github.com/integrii/flaggy/.gitignore
generated
vendored
Normal file
14
vendor/github.com/integrii/flaggy/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
||||
.glide/
|
||||
24
vendor/github.com/integrii/flaggy/LICENSE
generated
vendored
Normal file
24
vendor/github.com/integrii/flaggy/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org>
|
||||
252
vendor/github.com/integrii/flaggy/README.md
generated
vendored
Normal file
252
vendor/github.com/integrii/flaggy/README.md
generated
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
<p align="center">
|
||||
|
||||
<img src="/logo.png" />
|
||||
<br />
|
||||
<a href="https://goreportcard.com/report/github.com/integrii/flaggy"><img src="https://goreportcard.com/badge/github.com/integrii/flaggy"></a>
|
||||
<a href="https://travis-ci.org/integrii/flaggy"><img src="https://travis-ci.org/integrii/flaggy.svg?branch=master"></a>
|
||||
<a href="http://godoc.org/github.com/integrii/flaggy"><img src="https://camo.githubusercontent.com/d48cccd1ce67ddf8ba7fc356ec1087f3f7aa6d12/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f6c696c65696f2f6c696c653f7374617475732e737667"></a>
|
||||
<a href="http://unlicense.org/"><img src="https://img.shields.io/badge/license-Unlicense-blue.svg"></a>
|
||||
<a href="https://cover.run/go?repo=github.com%2Fintegrii%2Fflaggy&tag=golang-1.10"><img src="https://cover.run/go/github.com/integrii/flaggy.svg?style=flat&tag=golang-1.10"></a>
|
||||
<a href="https://github.com/avelino/awesome-go"><img src="https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg"></a>
|
||||
</p>
|
||||
|
||||
Sensible and _fast_ command-line flag parsing with excellent support for **subcommands** and **positional values**. Flags can be at any position. Flaggy has no required project or package layout like [Cobra requires](https://github.com/spf13/cobra/issues/641), and **no external dependencies**!
|
||||
|
||||
Check out the [godoc](http://godoc.org/github.com/integrii/flaggy), [examples directory](https://github.com/integrii/flaggy/tree/master/examples), and [examples in this readme](https://github.com/integrii/flaggy#super-simple-example) to get started quickly. You can also read the Flaggy introduction post with helpful examples [on my weblog](https://ericgreer.info/post/a-better-flags-package-for-go/).
|
||||
|
||||
# Installation
|
||||
|
||||
`go get -u github.com/integrii/flaggy`
|
||||
|
||||
# Key Features
|
||||
|
||||
- Very easy to use ([see examples below](https://github.com/integrii/flaggy#super-simple-example))
|
||||
- 35 different flag types supported
|
||||
- Any flag can be at any position
|
||||
- Pretty and readable help output by default
|
||||
- Positional subcommands
|
||||
- Positional parameters
|
||||
- Suggested subcommands when a subcommand is typo'd
|
||||
- Nested subcommands
|
||||
- Both global and subcommand specific flags
|
||||
- Both global and subcommand specific positional parameters
|
||||
- Customizable help templates for both the global command and subcommands
|
||||
- Customizable appended/prepended help messages for both the global command and subcommands
|
||||
- Simple function that displays help followed by a custom message string
|
||||
- Flags and subcommands may have both a short and long name
|
||||
- Unlimited trailing arguments after a `--`
|
||||
- Flags can use a single dash or double dash (`--flag`, `-flag`, `-f`, `--f`)
|
||||
- Flags can have `=` assignment operators, or use a space (`--flag=value`, `--flag value`)
|
||||
- Flags support single quote globs with spaces (`--flag 'this is all one value'`)
|
||||
- Flags of slice types can be passed multiple times (`-f one -f two -f three`)
|
||||
- Optional but default version output with `--version`
|
||||
- Optional but default help output with `-h` or `--help`
|
||||
- Optional but default help output when any invalid or unknown parameter is passed
|
||||
- It's _fast_. All flag and subcommand parsing takes less than `1ms` in most programs.
|
||||
|
||||
|
||||
# Example Help Output
|
||||
|
||||
```
|
||||
testCommand - Description goes here. Get more information at http://flaggy.
|
||||
This is a prepend for help
|
||||
|
||||
Usage:
|
||||
testCommand [subcommandA|subcommandB|subcommandC] [testPositionalA] [testPositionalB]
|
||||
|
||||
Positional Variables:
|
||||
testPositionalA - (Required) Test positional A does some things with a positional value. (default: defaultValue)
|
||||
testPositionalB - Test positional B does some less than serious things with a positional value.
|
||||
|
||||
Subcommands:
|
||||
subcommandA (a) - Subcommand A is a command that does stuff
|
||||
subcommandB (b) - Subcommand B is a command that does other stuff
|
||||
subcommandC (c) - Subcommand C is a command that does SERIOUS stuff
|
||||
|
||||
Flags:
|
||||
--version Displays the program version string.
|
||||
-h --help Displays help with available flag, subcommand, and positional value parameters.
|
||||
-s --stringFlag This is a test string flag that does some stringy string stuff.
|
||||
-i --intFlg This is a test int flag that does some interesting int stuff. (default: 5)
|
||||
-b --boolFlag This is a test bool flag that does some booly bool stuff. (default: true)
|
||||
-d --durationFlag This is a test duration flag that does some untimely stuff. (default: 1h23s)
|
||||
|
||||
This is an append for help
|
||||
This is a help add-on message
|
||||
```
|
||||
|
||||
# Super Simple Example
|
||||
|
||||
`./yourApp -f test`
|
||||
|
||||
```go
|
||||
// Declare variables and their defaults
|
||||
var stringFlag = "defaultValue"
|
||||
|
||||
// Add a flag
|
||||
flaggy.String(&stringFlag, "f", "flag", "A test string flag")
|
||||
|
||||
// Parse the flag
|
||||
flaggy.Parse()
|
||||
|
||||
// Use the flag
|
||||
print(stringFlag)
|
||||
```
|
||||
|
||||
|
||||
# Example with Subcommand
|
||||
|
||||
`./yourApp subcommandExample -f test`
|
||||
|
||||
```go
|
||||
// Declare variables and their defaults
|
||||
var stringFlag = "defaultValue"
|
||||
|
||||
// Create the subcommand
|
||||
subcommand := flaggy.NewSubcommand("subcommandExample")
|
||||
|
||||
// Add a flag to the subcommand
|
||||
subcommand.String(&stringFlag, "f", "flag", "A test string flag")
|
||||
|
||||
// Add the subcommand to the parser at position 1
|
||||
flaggy.AttachSubcommand(subcommand, 1)
|
||||
|
||||
// Parse the subcommand and all flags
|
||||
flaggy.Parse()
|
||||
|
||||
// Use the flag
|
||||
print(stringFlag)
|
||||
```
|
||||
|
||||
# Example with Nested Subcommands, Various Flags and Trailing Arguments
|
||||
|
||||
`./yourApp subcommandExample --flag=5 nestedSubcommand -t test -y -- trailingArg`
|
||||
|
||||
```go
|
||||
// Declare variables and their defaults
|
||||
var stringFlagF = "defaultValueF"
|
||||
var intFlagT = 3
|
||||
var boolFlagB bool
|
||||
|
||||
// Create the subcommands
|
||||
subcommandExample := flaggy.NewSubcommand("subcommandExample")
|
||||
nestedSubcommand := flaggy.NewSubcommand("nestedSubcommand")
|
||||
|
||||
// Add a flag to both subcommands
|
||||
subcommandExample.String(&stringFlagF, "t", "testFlag", "A test string flag")
|
||||
nestedSubcommand.Int(&intFlagT, "f", "flag", "A test int flag")
|
||||
|
||||
// add a global bool flag for fun
|
||||
flaggy.Bool(&boolFlagB, "y", "yes", "A sample boolean flag")
|
||||
|
||||
// attach the nested subcommand to the parent subcommand at position 1
|
||||
subcommandExample.AttachSubcommand(nestedSubcommand, 1)
|
||||
// attach the base subcommand to the parser at position 1
|
||||
flaggy.AttachSubcommand(subcommandExample, 1)
|
||||
|
||||
// Parse everything, then use the flags and trailing arguments
|
||||
flaggy.Parse()
|
||||
print(stringFlagF)
|
||||
print(intFlagT)
|
||||
print(boolFlagB)
|
||||
print(flaggy.TrailingArguments[0])
|
||||
```
|
||||
|
||||
# Supported Flag Types:
|
||||
|
||||
- string
|
||||
- []string
|
||||
- bool
|
||||
- []bool
|
||||
- time.Duration
|
||||
- []time.Duration
|
||||
- float32
|
||||
- []float32
|
||||
- float64
|
||||
- []float64
|
||||
- uint
|
||||
- uint64
|
||||
- []uint64
|
||||
- uint32
|
||||
- []uint32
|
||||
- uint16
|
||||
- []uint16
|
||||
- uint8
|
||||
- []uint8
|
||||
- []byte
|
||||
- int
|
||||
- []int
|
||||
- int64
|
||||
- []int64
|
||||
- int32
|
||||
- []int32
|
||||
- int16
|
||||
- []int16
|
||||
- int8
|
||||
- []int8
|
||||
- net.IP
|
||||
- []net.IP
|
||||
- net.HardwareAddr
|
||||
- []net.HardwareAddr
|
||||
- net.IPMask
|
||||
- []net.IPMask
|
||||
|
||||
|
||||
# Recommended Program Structure
|
||||
|
||||
Best practice when using flaggy includes setting your program's name, description, and version (at build time).
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import "github.com/integrii/flaggy"
|
||||
|
||||
// make a variable for the version which will be set at build time
|
||||
var version = "unknown"
|
||||
|
||||
// keep subcommands as globals so you can easily check if they were used later on
|
||||
var mySubcommand *flaggy.Subcommand
|
||||
|
||||
func init() {
|
||||
// Set your program's name and description. These appear in help output.
|
||||
flaggy.SetName("Test Program")
|
||||
flaggy.SetDescription("A little example program")
|
||||
|
||||
// you can disable various things by changing bools on the default parser
|
||||
// (or your own parser if you have created one)
|
||||
flaggy.DefaultParser.ShowHelpOnUnexpected = false
|
||||
|
||||
// you can set a help prepend or append on the default parser
|
||||
flaggy.DefaultParser.AdditionalHelpPrepend = "http://github.com/integrii/flaggy"
|
||||
|
||||
// create any subcommands and set their parameters
|
||||
mySubcommand = flaggy.NewSubcommand("mySubcommand")
|
||||
mySubcommand.Description = "My great subcommand!"
|
||||
|
||||
// set the version and parse all inputs into variables
|
||||
flaggy.SetVersion(version)
|
||||
flaggy.Parse()
|
||||
}
|
||||
func main(){
|
||||
if mySubcommand.Used {
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then, you can use the following build command to set the `version` variable in the above program at build time.
|
||||
|
||||
```bash
|
||||
# build your app and set the version string
|
||||
$ go build -ldflags='-X main.version=1.0.3-a3db3'
|
||||
$ ./yourApp version
|
||||
Version: 1.0.3-a3db3
|
||||
$ ./yourApp --help
|
||||
Test Program - A little example program
|
||||
http://github.com/integrii/flaggy
|
||||
```
|
||||
|
||||
|
||||
# Contributions
|
||||
|
||||
Please feel free to open an issue if you find any bugs or see any features that make sense. Pull requests will be reviewed and accepted if they make sense, but it is always wise to submit a proposal issue before any major changes.
|
||||
29
vendor/github.com/integrii/flaggy/argumentParser.go
generated
vendored
Normal file
29
vendor/github.com/integrii/flaggy/argumentParser.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
package flaggy
|
||||
|
||||
// setValueForParsers sets the value for a specified key in the
|
||||
// specified parsers (which normally include a Parser and Subcommand).
|
||||
// The return values represent the key being set, and any errors
|
||||
// returned when setting the key, such as failures to convert the string
|
||||
// into the appropriate flag value. We stop assigning values as soon
|
||||
// as we find a parser that accepts it.
|
||||
func setValueForParsers(key string, value string, parsers ...ArgumentParser) (bool, error) {
|
||||
|
||||
var valueWasSet bool
|
||||
|
||||
for _, p := range parsers {
|
||||
valueWasSet, err := p.SetValueForKey(key, value)
|
||||
if err != nil {
|
||||
return valueWasSet, err
|
||||
}
|
||||
if valueWasSet {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return valueWasSet, nil
|
||||
}
|
||||
|
||||
// ArgumentParser represents a parser or subcommand
|
||||
type ArgumentParser interface {
|
||||
SetValueForKey(key string, value string) (bool, error)
|
||||
}
|
||||
622
vendor/github.com/integrii/flaggy/flag.go
generated
vendored
Normal file
622
vendor/github.com/integrii/flaggy/flag.go
generated
vendored
Normal file
@@ -0,0 +1,622 @@
|
||||
package flaggy
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Flag holds the base methods for all flag types
|
||||
type Flag struct {
|
||||
ShortName string
|
||||
LongName string
|
||||
Description string
|
||||
rawValue string // the value as a string before being parsed
|
||||
Hidden bool // indicates this flag should be hidden from help and suggestions
|
||||
AssignmentVar interface{}
|
||||
defaultValue string // the value (as a string), that was set by default before any parsing and assignment
|
||||
parsed bool // indicates that this flag has already been parsed
|
||||
}
|
||||
|
||||
// HasName indicates that this flag's short or long name matches the
|
||||
// supplied name string
|
||||
func (f *Flag) HasName(name string) bool {
|
||||
name = strings.TrimSpace(name)
|
||||
if f.ShortName == name || f.LongName == name {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// identifyAndAssignValue identifies the type of the incoming value
|
||||
// and assigns it to the AssignmentVar pointer's target value. If
|
||||
// the value is a type that needs parsing, that is performed as well.
|
||||
func (f *Flag) identifyAndAssignValue(value string) error {
|
||||
|
||||
var err error
|
||||
|
||||
// Only parse this flag default value once. This keeps us from
|
||||
// overwriting the default value in help output
|
||||
if !f.parsed {
|
||||
f.parsed = true
|
||||
// parse the default value as a string and remember it for help output
|
||||
f.defaultValue, err = f.returnAssignmentVarValueAsString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
debugPrint("attempting to assign value", value, "to flag", f.LongName)
|
||||
f.rawValue = value // remember the raw value
|
||||
|
||||
// depending on the type of the assignment variable, we convert the
|
||||
// incoming string and assign it. We only use pointers to variables
|
||||
// in flagy. No returning vars by value.
|
||||
switch f.AssignmentVar.(type) {
|
||||
case *string:
|
||||
v, _ := (f.AssignmentVar).(*string)
|
||||
*v = value
|
||||
case *[]string:
|
||||
v := f.AssignmentVar.(*[]string)
|
||||
splitString := strings.Split(value, ",")
|
||||
new := append(*v, splitString...)
|
||||
*v = new
|
||||
case *bool:
|
||||
v, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a, _ := (f.AssignmentVar).(*bool)
|
||||
*a = v
|
||||
case *[]bool:
|
||||
// parse the incoming bool
|
||||
b, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// cast the assignment var
|
||||
existing := f.AssignmentVar.(*[]bool)
|
||||
// deref the assignment var and append to it
|
||||
v := append(*existing, b)
|
||||
// pointer the new value and assign it
|
||||
a, _ := (f.AssignmentVar).(*[]bool)
|
||||
*a = v
|
||||
case *time.Duration:
|
||||
v, err := time.ParseDuration(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a, _ := (f.AssignmentVar).(*time.Duration)
|
||||
*a = v
|
||||
case *[]time.Duration:
|
||||
t, err := time.ParseDuration(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existing := f.AssignmentVar.(*[]time.Duration)
|
||||
// deref the assignment var and append to it
|
||||
v := append(*existing, t)
|
||||
// pointer the new value and assign it
|
||||
a, _ := (f.AssignmentVar).(*[]time.Duration)
|
||||
*a = v
|
||||
case *float32:
|
||||
v, err := strconv.ParseFloat(value, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
float := float32(v)
|
||||
a, _ := (f.AssignmentVar).(*float32)
|
||||
*a = float
|
||||
case *[]float32:
|
||||
v, err := strconv.ParseFloat(value, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
float := float32(v)
|
||||
existing := f.AssignmentVar.(*[]float32)
|
||||
new := append(*existing, float)
|
||||
*existing = new
|
||||
case *float64:
|
||||
v, err := strconv.ParseFloat(value, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a, _ := (f.AssignmentVar).(*float64)
|
||||
*a = v
|
||||
case *[]float64:
|
||||
v, err := strconv.ParseFloat(value, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existing := f.AssignmentVar.(*[]float64)
|
||||
new := append(*existing, v)
|
||||
|
||||
*existing = new
|
||||
case *int:
|
||||
v, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e := f.AssignmentVar.(*int)
|
||||
*e = v
|
||||
case *[]int:
|
||||
v, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existing := f.AssignmentVar.(*[]int)
|
||||
new := append(*existing, v)
|
||||
*existing = new
|
||||
case *uint:
|
||||
v, err := strconv.ParseUint(value, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existing := f.AssignmentVar.(*uint)
|
||||
*existing = uint(v)
|
||||
case *[]uint:
|
||||
v, err := strconv.ParseUint(value, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existing := f.AssignmentVar.(*[]uint)
|
||||
new := append(*existing, uint(v))
|
||||
*existing = new
|
||||
case *uint64:
|
||||
v, err := strconv.ParseUint(value, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existing := f.AssignmentVar.(*uint64)
|
||||
*existing = v
|
||||
case *[]uint64:
|
||||
v, err := strconv.ParseUint(value, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existing := f.AssignmentVar.(*[]uint64)
|
||||
new := append(*existing, v)
|
||||
*existing = new
|
||||
case *uint32:
|
||||
v, err := strconv.ParseUint(value, 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existing := f.AssignmentVar.(*uint32)
|
||||
*existing = uint32(v)
|
||||
case *[]uint32:
|
||||
v, err := strconv.ParseUint(value, 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existing := f.AssignmentVar.(*[]uint32)
|
||||
new := append(*existing, uint32(v))
|
||||
*existing = new
|
||||
case *uint16:
|
||||
v, err := strconv.ParseUint(value, 10, 16)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
val := uint16(v)
|
||||
existing := f.AssignmentVar.(*uint16)
|
||||
*existing = val
|
||||
case *[]uint16:
|
||||
v, err := strconv.ParseUint(value, 10, 16)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existing := f.AssignmentVar.(*[]uint16)
|
||||
new := append(*existing, uint16(v))
|
||||
*existing = new
|
||||
case *uint8:
|
||||
v, err := strconv.ParseUint(value, 10, 8)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
val := uint8(v)
|
||||
existing := f.AssignmentVar.(*uint8)
|
||||
*existing = val
|
||||
case *[]uint8:
|
||||
var newSlice []uint8
|
||||
|
||||
v, err := strconv.ParseUint(value, 10, 8)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newV := uint8(v)
|
||||
existing := f.AssignmentVar.(*[]uint8)
|
||||
newSlice = append(*existing, newV)
|
||||
*existing = newSlice
|
||||
case *int64:
|
||||
v, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existing := f.AssignmentVar.(*int64)
|
||||
*existing = v
|
||||
case *[]int64:
|
||||
v, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existingSlice := f.AssignmentVar.(*[]int64)
|
||||
newSlice := append(*existingSlice, v)
|
||||
*existingSlice = newSlice
|
||||
case *int32:
|
||||
v, err := strconv.ParseInt(value, 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
converted := int32(v)
|
||||
existing := f.AssignmentVar.(*int32)
|
||||
*existing = converted
|
||||
case *[]int32:
|
||||
v, err := strconv.ParseInt(value, 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existingSlice := f.AssignmentVar.(*[]int32)
|
||||
newSlice := append(*existingSlice, int32(v))
|
||||
*existingSlice = newSlice
|
||||
case *int16:
|
||||
v, err := strconv.ParseInt(value, 10, 16)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
converted := int16(v)
|
||||
existing := f.AssignmentVar.(*int16)
|
||||
*existing = converted
|
||||
case *[]int16:
|
||||
v, err := strconv.ParseInt(value, 10, 16)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existingSlice := f.AssignmentVar.(*[]int16)
|
||||
newSlice := append(*existingSlice, int16(v))
|
||||
*existingSlice = newSlice
|
||||
case *int8:
|
||||
v, err := strconv.ParseInt(value, 10, 8)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
converted := int8(v)
|
||||
existing := f.AssignmentVar.(*int8)
|
||||
*existing = converted
|
||||
case *[]int8:
|
||||
v, err := strconv.ParseInt(value, 10, 8)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existingSlice := f.AssignmentVar.(*[]int8)
|
||||
newSlice := append(*existingSlice, int8(v))
|
||||
*existingSlice = newSlice
|
||||
case *net.IP:
|
||||
v := net.ParseIP(value)
|
||||
existing := f.AssignmentVar.(*net.IP)
|
||||
*existing = v
|
||||
case *[]net.IP:
|
||||
v := net.ParseIP(value)
|
||||
existing := f.AssignmentVar.(*[]net.IP)
|
||||
new := append(*existing, v)
|
||||
*existing = new
|
||||
case *net.HardwareAddr:
|
||||
v, err := net.ParseMAC(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existing := f.AssignmentVar.(*net.HardwareAddr)
|
||||
*existing = v
|
||||
case *[]net.HardwareAddr:
|
||||
v, err := net.ParseMAC(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existing := f.AssignmentVar.(*[]net.HardwareAddr)
|
||||
new := append(*existing, v)
|
||||
*existing = new
|
||||
case *net.IPMask:
|
||||
v := net.IPMask(net.ParseIP(value).To4())
|
||||
existing := f.AssignmentVar.(*net.IPMask)
|
||||
*existing = v
|
||||
case *[]net.IPMask:
|
||||
v := net.IPMask(net.ParseIP(value).To4())
|
||||
existing := f.AssignmentVar.(*[]net.IPMask)
|
||||
new := append(*existing, v)
|
||||
*existing = new
|
||||
default:
|
||||
return errors.New("Unknown flag assignmentVar supplied in flag " + f.LongName + " " + f.ShortName)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
const argIsPositional = "positional" // subcommand or positional value
|
||||
const argIsFlagWithSpace = "flagWithSpace" // -f path or --file path
|
||||
const argIsFlagWithValue = "flagWithValue" // -f=path or --file=path
|
||||
const argIsFinal = "final" // the final argument only '--'
|
||||
|
||||
// determineArgType determines if the specified arg is a flag with space
|
||||
// separated value, a flag with a connected value, or neither (positional)
|
||||
func determineArgType(arg string) string {
|
||||
|
||||
// if the arg is --, then its the final arg
|
||||
if arg == "--" {
|
||||
return argIsFinal
|
||||
}
|
||||
|
||||
// if it has the prefix --, then its a long flag
|
||||
if strings.HasPrefix(arg, "--") {
|
||||
// if it contains an equals, it is a joined value
|
||||
if strings.Contains(arg, "=") {
|
||||
return argIsFlagWithValue
|
||||
}
|
||||
return argIsFlagWithSpace
|
||||
}
|
||||
|
||||
// if it has the prefix -, then its a short flag
|
||||
if strings.HasPrefix(arg, "-") {
|
||||
// if it contains an equals, it is a joined value
|
||||
if strings.Contains(arg, "=") {
|
||||
return argIsFlagWithValue
|
||||
}
|
||||
return argIsFlagWithSpace
|
||||
}
|
||||
|
||||
return argIsPositional
|
||||
}
|
||||
|
||||
// parseArgWithValue parses a key=value concatenated argument into a key and
|
||||
// value
|
||||
func parseArgWithValue(arg string) (key string, value string) {
|
||||
|
||||
// remove up to two minuses from start of flag
|
||||
arg = strings.TrimPrefix(arg, "-")
|
||||
arg = strings.TrimPrefix(arg, "-")
|
||||
|
||||
// debugPrint("parseArgWithValue parsing", arg)
|
||||
|
||||
// break at the equals
|
||||
args := strings.SplitN(arg, "=", 2)
|
||||
|
||||
// if its a bool arg, with no explicit value, we return a blank
|
||||
if len(args) == 1 {
|
||||
return args[0], ""
|
||||
}
|
||||
|
||||
// if its a key and value pair, we return those
|
||||
if len(args) == 2 {
|
||||
// debugPrint("parseArgWithValue parsed", args[0], args[1])
|
||||
return args[0], args[1]
|
||||
}
|
||||
|
||||
fmt.Println("Warning: attempted to parseArgWithValue but did not have correct parameter count.", arg, "->", args)
|
||||
return "", ""
|
||||
}
|
||||
|
||||
// parseFlagToName parses a flag with space value down to a key name:
|
||||
// --path -> path
|
||||
// -p -> p
|
||||
func parseFlagToName(arg string) string {
|
||||
// remove minus from start
|
||||
arg = strings.TrimLeft(arg, "-")
|
||||
arg = strings.TrimLeft(arg, "-")
|
||||
return arg
|
||||
}
|
||||
|
||||
// flagIsBool determines if the flag is a bool within the specified parser
|
||||
// and subcommand's context
|
||||
func flagIsBool(sc *Subcommand, p *Parser, key string) bool {
|
||||
for _, f := range append(sc.Flags, p.Flags...) {
|
||||
if f.HasName(key) {
|
||||
_, isBool := f.AssignmentVar.(*bool)
|
||||
_, isBoolSlice := f.AssignmentVar.(*[]bool)
|
||||
if isBool || isBoolSlice {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// by default, the answer is false
|
||||
return false
|
||||
}
|
||||
|
||||
// returnAssignmentVarValueAsString returns the value of the flag's
|
||||
// assignment variable as a string. This is used to display the
|
||||
// default value of flags before they are assigned (like when help is output).
|
||||
func (f *Flag) returnAssignmentVarValueAsString() (string, error) {
|
||||
|
||||
debugPrint("returning current value of assignment var of flag", f.LongName)
|
||||
|
||||
var err error
|
||||
|
||||
// depending on the type of the assignment variable, we convert the
|
||||
// incoming string and assign it. We only use pointers to variables
|
||||
// in flagy. No returning vars by value.
|
||||
switch f.AssignmentVar.(type) {
|
||||
case *string:
|
||||
v, _ := (f.AssignmentVar).(*string)
|
||||
return *v, err
|
||||
case *[]string:
|
||||
v := f.AssignmentVar.(*[]string)
|
||||
return strings.Join(*v, ","), err
|
||||
case *bool:
|
||||
a, _ := (f.AssignmentVar).(*bool)
|
||||
return strconv.FormatBool(*a), err
|
||||
case *[]bool:
|
||||
value := f.AssignmentVar.(*[]bool)
|
||||
var ss []string
|
||||
for _, b := range *value {
|
||||
ss = append(ss, strconv.FormatBool(b))
|
||||
}
|
||||
return strings.Join(ss, ","), err
|
||||
case *time.Duration:
|
||||
a := f.AssignmentVar.(*time.Duration)
|
||||
return (*a).String(), err
|
||||
case *[]time.Duration:
|
||||
tds := f.AssignmentVar.(*[]time.Duration)
|
||||
var asSlice []string
|
||||
for _, td := range *tds {
|
||||
asSlice = append(asSlice, td.String())
|
||||
}
|
||||
return strings.Join(asSlice, ","), err
|
||||
case *float32:
|
||||
a := f.AssignmentVar.(*float32)
|
||||
return strconv.FormatFloat(float64(*a), 'f', 2, 32), err
|
||||
case *[]float32:
|
||||
v := f.AssignmentVar.(*[]float32)
|
||||
var strSlice []string
|
||||
for _, f := range *v {
|
||||
formatted := strconv.FormatFloat(float64(f), 'f', 2, 32)
|
||||
strSlice = append(strSlice, formatted)
|
||||
}
|
||||
return strings.Join(strSlice, ","), err
|
||||
case *float64:
|
||||
a := f.AssignmentVar.(*float64)
|
||||
return strconv.FormatFloat(float64(*a), 'f', 2, 64), err
|
||||
case *[]float64:
|
||||
v := f.AssignmentVar.(*[]float64)
|
||||
var strSlice []string
|
||||
for _, f := range *v {
|
||||
formatted := strconv.FormatFloat(float64(f), 'f', 2, 64)
|
||||
strSlice = append(strSlice, formatted)
|
||||
}
|
||||
return strings.Join(strSlice, ","), err
|
||||
case *int:
|
||||
a := f.AssignmentVar.(*int)
|
||||
return strconv.Itoa(*a), err
|
||||
case *[]int:
|
||||
val := f.AssignmentVar.(*[]int)
|
||||
var strSlice []string
|
||||
for _, i := range *val {
|
||||
str := strconv.Itoa(i)
|
||||
strSlice = append(strSlice, str)
|
||||
}
|
||||
return strings.Join(strSlice, ","), err
|
||||
case *uint:
|
||||
v := f.AssignmentVar.(*uint)
|
||||
return strconv.FormatUint(uint64(*v), 10), err
|
||||
case *[]uint:
|
||||
values := f.AssignmentVar.(*[]uint)
|
||||
var strVars []string
|
||||
for _, i := range *values {
|
||||
strVars = append(strVars, strconv.FormatUint(uint64(i), 10))
|
||||
}
|
||||
return strings.Join(strVars, ","), err
|
||||
case *uint64:
|
||||
v := f.AssignmentVar.(*uint64)
|
||||
return strconv.FormatUint(*v, 10), err
|
||||
case *[]uint64:
|
||||
values := f.AssignmentVar.(*[]uint64)
|
||||
var strVars []string
|
||||
for _, i := range *values {
|
||||
strVars = append(strVars, strconv.FormatUint(i, 10))
|
||||
}
|
||||
return strings.Join(strVars, ","), err
|
||||
case *uint32:
|
||||
v := f.AssignmentVar.(*uint32)
|
||||
return strconv.FormatUint(uint64(*v), 10), err
|
||||
case *[]uint32:
|
||||
values := f.AssignmentVar.(*[]uint32)
|
||||
var strVars []string
|
||||
for _, i := range *values {
|
||||
strVars = append(strVars, strconv.FormatUint(uint64(i), 10))
|
||||
}
|
||||
return strings.Join(strVars, ","), err
|
||||
case *uint16:
|
||||
v := f.AssignmentVar.(*uint16)
|
||||
return strconv.FormatUint(uint64(*v), 10), err
|
||||
case *[]uint16:
|
||||
values := f.AssignmentVar.(*[]uint16)
|
||||
var strVars []string
|
||||
for _, i := range *values {
|
||||
strVars = append(strVars, strconv.FormatUint(uint64(i), 10))
|
||||
}
|
||||
return strings.Join(strVars, ","), err
|
||||
case *uint8:
|
||||
v := f.AssignmentVar.(*uint8)
|
||||
return strconv.FormatUint(uint64(*v), 10), err
|
||||
case *[]uint8:
|
||||
values := f.AssignmentVar.(*[]uint8)
|
||||
var strVars []string
|
||||
for _, i := range *values {
|
||||
strVars = append(strVars, strconv.FormatUint(uint64(i), 10))
|
||||
}
|
||||
return strings.Join(strVars, ","), err
|
||||
case *int64:
|
||||
v := f.AssignmentVar.(*int64)
|
||||
return strconv.FormatInt(int64(*v), 10), err
|
||||
case *[]int64:
|
||||
values := f.AssignmentVar.(*[]int64)
|
||||
var strVars []string
|
||||
for _, i := range *values {
|
||||
strVars = append(strVars, strconv.FormatInt(i, 10))
|
||||
}
|
||||
return strings.Join(strVars, ","), err
|
||||
case *int32:
|
||||
v := f.AssignmentVar.(*int32)
|
||||
return strconv.FormatInt(int64(*v), 10), err
|
||||
case *[]int32:
|
||||
values := f.AssignmentVar.(*[]int32)
|
||||
var strVars []string
|
||||
for _, i := range *values {
|
||||
strVars = append(strVars, strconv.FormatInt(int64(i), 10))
|
||||
}
|
||||
return strings.Join(strVars, ","), err
|
||||
case *int16:
|
||||
v := f.AssignmentVar.(*int16)
|
||||
return strconv.FormatInt(int64(*v), 10), err
|
||||
case *[]int16:
|
||||
values := f.AssignmentVar.(*[]int16)
|
||||
var strVars []string
|
||||
for _, i := range *values {
|
||||
strVars = append(strVars, strconv.FormatInt(int64(i), 10))
|
||||
}
|
||||
return strings.Join(strVars, ","), err
|
||||
case *int8:
|
||||
v := f.AssignmentVar.(*int8)
|
||||
return strconv.FormatInt(int64(*v), 10), err
|
||||
case *[]int8:
|
||||
values := f.AssignmentVar.(*[]int8)
|
||||
var strVars []string
|
||||
for _, i := range *values {
|
||||
strVars = append(strVars, strconv.FormatInt(int64(i), 10))
|
||||
}
|
||||
return strings.Join(strVars, ","), err
|
||||
case *net.IP:
|
||||
val := f.AssignmentVar.(*net.IP)
|
||||
return val.String(), err
|
||||
case *[]net.IP:
|
||||
val := f.AssignmentVar.(*[]net.IP)
|
||||
var strSlice []string
|
||||
for _, ip := range *val {
|
||||
strSlice = append(strSlice, ip.String())
|
||||
}
|
||||
return strings.Join(strSlice, ","), err
|
||||
case *net.HardwareAddr:
|
||||
val := f.AssignmentVar.(*net.HardwareAddr)
|
||||
return val.String(), err
|
||||
case *[]net.HardwareAddr:
|
||||
val := f.AssignmentVar.(*[]net.HardwareAddr)
|
||||
var strSlice []string
|
||||
for _, mac := range *val {
|
||||
strSlice = append(strSlice, mac.String())
|
||||
}
|
||||
return strings.Join(strSlice, ","), err
|
||||
case *net.IPMask:
|
||||
val := f.AssignmentVar.(*net.IPMask)
|
||||
return val.String(), err
|
||||
case *[]net.IPMask:
|
||||
val := f.AssignmentVar.(*[]net.IPMask)
|
||||
var strSlice []string
|
||||
for _, m := range *val {
|
||||
strSlice = append(strSlice, m.String())
|
||||
}
|
||||
return strings.Join(strSlice, ","), err
|
||||
default:
|
||||
return "", errors.New("Unknown flag assignmentVar found in flag " + f.LongName + " " + f.ShortName + ". Type not supported: " + reflect.TypeOf(f.AssignmentVar).String())
|
||||
}
|
||||
}
|
||||
3
vendor/github.com/integrii/flaggy/go.mod
generated
vendored
Normal file
3
vendor/github.com/integrii/flaggy/go.mod
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
module github.com/integrii/flaggy
|
||||
|
||||
go 1.12
|
||||
23
vendor/github.com/integrii/flaggy/help.go
generated
vendored
Normal file
23
vendor/github.com/integrii/flaggy/help.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
package flaggy
|
||||
|
||||
// defaultHelpTemplate is the help template used by default
|
||||
// {{if (or (or (gt (len .StringFlags) 0) (gt (len .IntFlags) 0)) (gt (len .BoolFlags) 0))}}
|
||||
// {{if (or (gt (len .StringFlags) 0) (gt (len .BoolFlags) 0))}}
|
||||
const defaultHelpTemplate = `{{.CommandName}}{{if .Description}} - {{.Description}}{{end}}{{if .PrependMessage}}
|
||||
{{.PrependMessage}}{{end}}
|
||||
{{if .UsageString}}
|
||||
Usage:
|
||||
{{.UsageString}}{{end}}{{if .Positionals}}
|
||||
|
||||
Positional Variables: {{range .Positionals}}
|
||||
{{.Name}}{{if .Required}} (Required){{end}}{{if .Description}} - {{.Description}}{{end}}{{if .DefaultValue}} (default: {{.DefaultValue}}){{end}}{{end}}{{end}}{{if .Subcommands}}
|
||||
|
||||
Subcommands: {{range .Subcommands}}
|
||||
{{.LongName}}{{if .ShortName}} ({{.ShortName}}){{end}}{{if .Position}}{{if gt .Position 1}} (position {{.Position}}){{end}}{{end}}{{if .Description}} - {{.Description}}{{end}}{{end}}
|
||||
{{end}}{{if (gt (len .Flags) 0)}}
|
||||
Flags: {{if .Flags}}{{range .Flags}}
|
||||
{{if .ShortName}}-{{.ShortName}} {{else}} {{end}}{{if .LongName}}--{{.LongName}} {{end}}{{if .Description}} {{.Description}}{{if .DefaultValue}} (default: {{.DefaultValue}}){{end}}{{end}}{{end}}{{end}}
|
||||
{{end}}{{if .AppendMessage}}{{.AppendMessage}}
|
||||
{{end}}{{if .Message}}
|
||||
{{.Message}}{{end}}
|
||||
`
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user