mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-04-09 07:24:03 +02:00
Merge branch 'master' into feature/auto-updates
This commit is contained in:
commit
f24c95aede
.circleci
.github/ISSUE_TEMPLATE
.gitignoreGopkg.lockGopkg.tomlREADME.mddocs
pkg
app
commands
config
git
gui
i18n
test
updates
utils
test/repos
vendor/github.com
@ -1,26 +1,42 @@
|
|||||||
# Golang CircleCI 2.0 configuration file
|
|
||||||
#
|
|
||||||
# Check https://circleci.com/docs/2.0/language-go/ for more details
|
|
||||||
version: 2
|
version: 2
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
docker:
|
docker:
|
||||||
# specify the version
|
- image: circleci/golang:1.10
|
||||||
- image: circleci/golang:1.9
|
|
||||||
|
|
||||||
# Specify service dependencies here if necessary
|
|
||||||
# CircleCI maintains a library of pre-built images
|
|
||||||
# documented at https://circleci.com/docs/2.0/circleci-images/
|
|
||||||
# - image: circleci/postgres:9.4
|
|
||||||
|
|
||||||
#### TEMPLATE_NOTE: go expects specific checkout path representing url
|
|
||||||
#### expecting it in the form of
|
|
||||||
#### /go/src/github.com/circleci/go-tool
|
|
||||||
#### /go/src/bitbucket.org/circleci/go-tool
|
|
||||||
working_directory: /go/src/github.com/jesseduffield/lazygit
|
working_directory: /go/src/github.com/jesseduffield/lazygit
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
|
- run:
|
||||||
|
name: Run tests
|
||||||
|
command: |
|
||||||
|
./test.sh
|
||||||
|
- run:
|
||||||
|
name: Push on codecov result
|
||||||
|
command: |
|
||||||
|
bash <(curl -s https://codecov.io/bash)
|
||||||
|
|
||||||
# specify any bash command here prefixed with `run: `
|
release:
|
||||||
- run: go test -v ./...
|
docker:
|
||||||
- run: bash <(curl -s https://codecov.io/bash)
|
- image: circleci/golang:1.10
|
||||||
|
working_directory: /go/src/github.com/jesseduffield/lazygit
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run:
|
||||||
|
name: Run gorelease
|
||||||
|
command: |
|
||||||
|
curl -sL https://git.io/goreleaser | bash
|
||||||
|
|
||||||
|
workflows:
|
||||||
|
version: 2
|
||||||
|
build:
|
||||||
|
jobs:
|
||||||
|
- build
|
||||||
|
release:
|
||||||
|
jobs:
|
||||||
|
- release:
|
||||||
|
filters:
|
||||||
|
tags:
|
||||||
|
only: /v[0-9]+(\.[0-9]+)*/
|
||||||
|
branches:
|
||||||
|
ignore: /.*/
|
||||||
|
1
.github/ISSUE_TEMPLATE/bug_report.md
vendored
1
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -23,6 +23,7 @@ If applicable, add screenshots to help explain your problem.
|
|||||||
**Desktop (please complete the following information):**
|
**Desktop (please complete the following information):**
|
||||||
- OS: [e.g. Windows]
|
- OS: [e.g. Windows]
|
||||||
- Lazygit Version [e.g. v0.1.45]
|
- Lazygit Version [e.g. v0.1.45]
|
||||||
|
- The last commit id if you built project from sources (run : ```git-rev parse HEAD```)
|
||||||
|
|
||||||
**Additional context**
|
**Additional context**
|
||||||
Add any other context about the problem here.
|
Add any other context about the problem here.
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -13,6 +13,7 @@ TODO.md
|
|||||||
|
|
||||||
# Tests
|
# Tests
|
||||||
test/repos/repo
|
test/repos/repo
|
||||||
|
coverage.txt
|
||||||
|
|
||||||
# Binaries
|
# Binaries
|
||||||
lazygit
|
lazygit
|
||||||
|
32
Gopkg.lock
generated
32
Gopkg.lock
generated
@ -1,14 +1,6 @@
|
|||||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||||
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:b2339e83ce9b5c4f79405f949429a7f68a9a904fed903c672aac1e7ceb7f5f02"
|
|
||||||
name = "github.com/Sirupsen/logrus"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "NUT"
|
|
||||||
revision = "3e01752db0189b9157070a0e1668a620f9a85da2"
|
|
||||||
version = "v1.0.6"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:cd7ba2b29e93e2a8384e813dfc80ebb0f85d9214762e6ca89bb55a58092eab87"
|
digest = "1:cd7ba2b29e93e2a8384e813dfc80ebb0f85d9214762e6ca89bb55a58092eab87"
|
||||||
@ -93,11 +85,11 @@
|
|||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:c9a848b0484a72da2dae28957b4f67501fe27fa38bc73f4713e454353c0a4a60"
|
digest = "1:f774b11ae458cae2d10b94ef66ef00ba1c57f1971dd0e5534ac743cbe574f6d4"
|
||||||
name = "github.com/jesseduffield/gocui"
|
name = "github.com/jesseduffield/gocui"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = "NUT"
|
pruneopts = "NUT"
|
||||||
revision = "432b7f6215f81ef1aaa1b2d9b69887822923cf79"
|
revision = "7818a0f93387d1037cbd06f69323d9f8d068af7c"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:8021af4dcbd531ae89433c8c3a6520e51064114aaf8eb1724c3cf911c497c9ba"
|
digest = "1:8021af4dcbd531ae89433c8c3a6520e51064114aaf8eb1724c3cf911c497c9ba"
|
||||||
@ -216,13 +208,20 @@
|
|||||||
version = "v1.0.0"
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
|
||||||
digest = "1:41618aee8828e62dfe62d44f579c06892d0e98907d1c6d5bcd83bfe8536ec5a3"
|
digest = "1:41618aee8828e62dfe62d44f579c06892d0e98907d1c6d5bcd83bfe8536ec5a3"
|
||||||
name = "github.com/shibukawa/configdir"
|
name = "github.com/shibukawa/configdir"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = "NUT"
|
pruneopts = "NUT"
|
||||||
revision = "e180dbdc8da04c4fa04272e875ce64949f38bd3e"
|
revision = "e180dbdc8da04c4fa04272e875ce64949f38bd3e"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:b2339e83ce9b5c4f79405f949429a7f68a9a904fed903c672aac1e7ceb7f5f02"
|
||||||
|
name = "github.com/sirupsen/logrus"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = "NUT"
|
||||||
|
revision = "3e01752db0189b9157070a0e1668a620f9a85da2"
|
||||||
|
version = "v1.0.6"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:330e9062b308ac597e28485699c02223bd052437a6eed32a173c9227dcb9d95a"
|
digest = "1:330e9062b308ac597e28485699c02223bd052437a6eed32a173c9227dcb9d95a"
|
||||||
name = "github.com/spf13/afero"
|
name = "github.com/spf13/afero"
|
||||||
@ -266,6 +265,14 @@
|
|||||||
revision = "907c19d40d9a6c9bb55f040ff4ae45271a4754b9"
|
revision = "907c19d40d9a6c9bb55f040ff4ae45271a4754b9"
|
||||||
version = "v1.1.0"
|
version = "v1.1.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:0e9a5ac14bcc11f205031a671b28c7e05cb88b2ebbe06f383c1ab0b2c12c7cb5"
|
||||||
|
name = "github.com/spkg/bom"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = "NUT"
|
||||||
|
revision = "59b7046e48ad6bac800c5e1dd5142282cbfcf154"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:ccca1dcd18bc54e23b517a3c5babeff2e3924a7d8fc1932162225876cfe4bfb0"
|
digest = "1:ccca1dcd18bc54e23b517a3c5babeff2e3924a7d8fc1932162225876cfe4bfb0"
|
||||||
name = "github.com/src-d/gcfg"
|
name = "github.com/src-d/gcfg"
|
||||||
@ -447,7 +454,6 @@
|
|||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
input-imports = [
|
input-imports = [
|
||||||
"github.com/Sirupsen/logrus",
|
|
||||||
"github.com/cloudfoundry/jibber_jabber",
|
"github.com/cloudfoundry/jibber_jabber",
|
||||||
"github.com/davecgh/go-spew/spew",
|
"github.com/davecgh/go-spew/spew",
|
||||||
"github.com/fatih/color",
|
"github.com/fatih/color",
|
||||||
@ -456,7 +462,9 @@
|
|||||||
"github.com/mgutz/str",
|
"github.com/mgutz/str",
|
||||||
"github.com/nicksnyder/go-i18n/v2/i18n",
|
"github.com/nicksnyder/go-i18n/v2/i18n",
|
||||||
"github.com/shibukawa/configdir",
|
"github.com/shibukawa/configdir",
|
||||||
|
"github.com/sirupsen/logrus",
|
||||||
"github.com/spf13/viper",
|
"github.com/spf13/viper",
|
||||||
|
"github.com/spkg/bom",
|
||||||
"github.com/stretchr/testify/assert",
|
"github.com/stretchr/testify/assert",
|
||||||
"github.com/tcnksm/go-gitconfig",
|
"github.com/tcnksm/go-gitconfig",
|
||||||
"golang.org/x/text/language",
|
"golang.org/x/text/language",
|
||||||
|
@ -40,3 +40,7 @@
|
|||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "gopkg.in/src-d/go-git.v4"
|
name = "gopkg.in/src-d/go-git.v4"
|
||||||
revision = "43d17e14b714665ab5bc2ecc220b6740779d733f"
|
revision = "43d17e14b714665ab5bc2ecc220b6740779d733f"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/spkg/bom"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# lazygit [](https://goreportcard.com/report/github.com/jesseduffield/lazygit)
|
# lazygit [](https://circleci.com/gh/jesseduffield/lazygit) [](https://codecov.io/gh/jesseduffield/lazygit) [](https://goreportcard.com/report/github.com/jesseduffield/lazygit) [](https://golangci.com) [](http://godoc.org/github.com/jesseduffield/lazygit) []()
|
||||||
|
|
||||||
A simple terminal UI for git commands, written in Go with the [gocui](https://github.com/jroimartin/gocui "gocui") library.
|
A simple terminal UI for git commands, written in Go with the [gocui](https://github.com/jroimartin/gocui "gocui") library.
|
||||||
|
|
||||||
|
@ -37,3 +37,7 @@ The available attributes are:
|
|||||||
- bold
|
- bold
|
||||||
- reverse # useful for high-contrast
|
- reverse # useful for high-contrast
|
||||||
- underline
|
- underline
|
||||||
|
|
||||||
|
## Example Coloring:
|
||||||
|
|
||||||
|

|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
<kbd>c</kbd>: checkout by name
|
<kbd>c</kbd>: checkout by name
|
||||||
<kbd>n</kbd>: new branch
|
<kbd>n</kbd>: new branch
|
||||||
<kbd>d</kbd>: delete branch
|
<kbd>d</kbd>: delete branch
|
||||||
|
<kbd>D</kbd>: force delete branch
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Commits Panel:
|
## Commits Panel:
|
||||||
|
BIN
docs/resources/colored-border-example.png
Normal file
BIN
docs/resources/colored-border-example.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 88 KiB |
@ -5,7 +5,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/config"
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui"
|
"github.com/jesseduffield/lazygit/pkg/gui"
|
||||||
@ -53,10 +53,7 @@ func NewApp(config config.AppConfigurer) (*App, error) {
|
|||||||
return app, err
|
return app, err
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Tr, err = i18n.NewLocalizer(app.Log)
|
app.Tr = i18n.NewLocalizer(app.Log)
|
||||||
if err != nil {
|
|
||||||
return app, err
|
|
||||||
}
|
|
||||||
|
|
||||||
app.GitCommand, err = commands.NewGitCommand(app.Log, app.OSCommand)
|
app.GitCommand, err = commands.NewGitCommand(app.Log, app.OSCommand)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
gitconfig "github.com/tcnksm/go-gitconfig"
|
gitconfig "github.com/tcnksm/go-gitconfig"
|
||||||
@ -223,8 +223,14 @@ func (c *GitCommand) NewBranch(name string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeleteBranch delete branch
|
// DeleteBranch delete branch
|
||||||
func (c *GitCommand) DeleteBranch(branch string) error {
|
func (c *GitCommand) DeleteBranch(branch string, force bool) error {
|
||||||
return c.OSCommand.RunCommand("git branch -d " + branch)
|
var command string
|
||||||
|
if force {
|
||||||
|
command = "git branch -D "
|
||||||
|
} else {
|
||||||
|
command = "git branch -d "
|
||||||
|
}
|
||||||
|
return c.OSCommand.RunCommand(command + branch)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListStash list stash
|
// ListStash list stash
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/jesseduffield/lazygit/pkg/test"
|
"github.com/jesseduffield/lazygit/pkg/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/mgutz/str"
|
"github.com/mgutz/str"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
gitconfig "github.com/tcnksm/go-gitconfig"
|
gitconfig "github.com/tcnksm/go-gitconfig"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -175,7 +175,8 @@ func (c *OSCommand) Unquote(message string) string {
|
|||||||
return message
|
return message
|
||||||
}
|
}
|
||||||
|
|
||||||
func (C *OSCommand) AppendLineToFile(filename, line string) error {
|
// AppendLineToFile adds a new line in file
|
||||||
|
func (c *OSCommand) AppendLineToFile(filename, line string) error {
|
||||||
f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
|
f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -121,10 +121,7 @@ func LoadUserConfigFromFile(v *viper.Viper) error {
|
|||||||
folder = configDirs.QueryFolderContainsFile("config.yml")
|
folder = configDirs.QueryFolderContainsFile("config.yml")
|
||||||
}
|
}
|
||||||
v.AddConfigPath(folder.Path)
|
v.AddConfigPath(folder.Path)
|
||||||
if err := v.MergeInConfig(); err != nil {
|
return v.MergeInConfig()
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertToUserConfig adds a key/value pair to the user's config and saves it
|
// InsertToUserConfig adds a key/value pair to the user's config and saves it
|
||||||
@ -139,10 +136,7 @@ func (c *AppConfig) InsertToUserConfig(key, value string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
v.Set(key, value)
|
v.Set(key, value)
|
||||||
if err := v.WriteConfig(); err != nil {
|
return v.WriteConfig()
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDefaultConfig() []byte {
|
func getDefaultConfig() []byte {
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"gopkg.in/src-d/go-git.v4/plumbing"
|
"gopkg.in/src-d/go-git.v4/plumbing"
|
||||||
)
|
)
|
||||||
|
@ -62,20 +62,34 @@ func (gui *Gui) handleNewBranch(g *gocui.Gui, v *gocui.View) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleDeleteBranch(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleDeleteBranch(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
return gui.deleteBranch(g, v, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleForceDeleteBranch(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
return gui.deleteBranch(g, v, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) deleteBranch(g *gocui.Gui, v *gocui.View, force bool) error {
|
||||||
checkedOutBranch := gui.State.Branches[0]
|
checkedOutBranch := gui.State.Branches[0]
|
||||||
selectedBranch := gui.getSelectedBranch(v)
|
selectedBranch := gui.getSelectedBranch(v)
|
||||||
if checkedOutBranch.Name == selectedBranch.Name {
|
if checkedOutBranch.Name == selectedBranch.Name {
|
||||||
return gui.createErrorPanel(g, gui.Tr.SLocalize("CantDeleteCheckOutBranch"))
|
return gui.createErrorPanel(g, gui.Tr.SLocalize("CantDeleteCheckOutBranch"))
|
||||||
}
|
}
|
||||||
|
title := gui.Tr.SLocalize("DeleteBranch")
|
||||||
|
var messageId string
|
||||||
|
if force {
|
||||||
|
messageId = "ForceDeleteBranchMessage"
|
||||||
|
} else {
|
||||||
|
messageId = "DeleteBranchMessage"
|
||||||
|
}
|
||||||
message := gui.Tr.TemplateLocalize(
|
message := gui.Tr.TemplateLocalize(
|
||||||
"DeleteBranchMessage",
|
messageId,
|
||||||
Teml{
|
Teml{
|
||||||
"selectedBranchName": selectedBranch.Name,
|
"selectedBranchName": selectedBranch.Name,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
title := gui.Tr.SLocalize("DeleteBranch")
|
|
||||||
return gui.createConfirmationPanel(g, v, title, message, func(g *gocui.Gui, v *gocui.View) error {
|
return gui.createConfirmationPanel(g, v, title, message, func(g *gocui.Gui, v *gocui.View) error {
|
||||||
if err := gui.GitCommand.DeleteBranch(selectedBranch.Name); err != nil {
|
if err := gui.GitCommand.DeleteBranch(selectedBranch.Name, force); err != nil {
|
||||||
return gui.createErrorPanel(g, err.Error())
|
return gui.createErrorPanel(g, err.Error())
|
||||||
}
|
}
|
||||||
return gui.refreshSidePanels(g)
|
return gui.refreshSidePanels(g)
|
||||||
@ -108,6 +122,7 @@ func (gui *Gui) renderBranchesOptions(g *gocui.Gui) error {
|
|||||||
"c": gui.Tr.SLocalize("checkoutByName"),
|
"c": gui.Tr.SLocalize("checkoutByName"),
|
||||||
"n": gui.Tr.SLocalize("newBranch"),
|
"n": gui.Tr.SLocalize("newBranch"),
|
||||||
"d": gui.Tr.SLocalize("deleteBranch"),
|
"d": gui.Tr.SLocalize("deleteBranch"),
|
||||||
|
"D": gui.Tr.SLocalize("forceDeleteBranch"),
|
||||||
"← → ↑ ↓": gui.Tr.SLocalize("navigate"),
|
"← → ↑ ↓": gui.Tr.SLocalize("navigate"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -251,14 +251,6 @@ func (gui *Gui) handleFileEdit(g *gocui.Gui, v *gocui.View) error {
|
|||||||
return gui.genericFileOpen(g, v, file.Name, gui.OSCommand.EditFile)
|
return gui.genericFileOpen(g, v, file.Name, gui.OSCommand.EditFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) openFile(filename string) error {
|
|
||||||
err := gui.OSCommand.OpenFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
return gui.createErrorPanel(gui.g, err.Error())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) handleFileOpen(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleFileOpen(g *gocui.Gui, v *gocui.View) error {
|
||||||
file, err := gui.getSelectedFile(g)
|
file, err := gui.getSelectedFile(g)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -15,13 +15,13 @@ import (
|
|||||||
|
|
||||||
// "strings"
|
// "strings"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/golang-collections/collections/stack"
|
"github.com/golang-collections/collections/stack"
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/config"
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
"github.com/jesseduffield/lazygit/pkg/i18n"
|
"github.com/jesseduffield/lazygit/pkg/i18n"
|
||||||
"github.com/jesseduffield/lazygit/pkg/updates"
|
"github.com/jesseduffield/lazygit/pkg/updates"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OverlappingEdges determines if panel edges overlap
|
// OverlappingEdges determines if panel edges overlap
|
||||||
@ -152,14 +152,15 @@ func (gui *Gui) setAppStatus(status string) error {
|
|||||||
func (gui *Gui) layout(g *gocui.Gui) error {
|
func (gui *Gui) layout(g *gocui.Gui) error {
|
||||||
g.Highlight = true
|
g.Highlight = true
|
||||||
width, height := g.Size()
|
width, height := g.Size()
|
||||||
|
version := gui.Config.GetVersion()
|
||||||
leftSideWidth := width / 3
|
leftSideWidth := width / 3
|
||||||
statusFilesBoundary := 2
|
statusFilesBoundary := 2
|
||||||
filesBranchesBoundary := 2 * height / 5 // height - 20
|
filesBranchesBoundary := 2 * height / 5 // height - 20
|
||||||
commitsBranchesBoundary := 3 * height / 5 // height - 10
|
commitsBranchesBoundary := 3 * height / 5 // height - 10
|
||||||
commitsStashBoundary := height - 5 // height - 5
|
commitsStashBoundary := height - 5 // height - 5
|
||||||
|
optionsVersionBoundary := width - max(len(version), 1)
|
||||||
minimumHeight := 16
|
minimumHeight := 16
|
||||||
minimumWidth := 10
|
minimumWidth := 10
|
||||||
version := gui.Config.GetVersion()
|
|
||||||
|
|
||||||
appStatusView, _ := g.View("appStatus")
|
appStatusView, _ := g.View("appStatus")
|
||||||
appStatusOptionsBoundary := -2
|
appStatusOptionsBoundary := -2
|
||||||
@ -244,7 +245,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
|
|||||||
v.FgColor = gocui.ColorWhite
|
v.FgColor = gocui.ColorWhite
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := g.SetView("options", appStatusOptionsBoundary-1, optionsTop, width-len(version)-2, optionsTop+2, 0); err != nil {
|
if v, err := g.SetView("options", appStatusOptionsBoundary-1, optionsTop, optionsVersionBoundary-1, optionsTop+2, 0); err != nil {
|
||||||
if err != gocui.ErrUnknownView {
|
if err != gocui.ErrUnknownView {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -281,7 +282,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
|
|||||||
v.Frame = false
|
v.Frame = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := g.SetView("version", width-len(version)-1, optionsTop, width, optionsTop+2, 0); err != nil {
|
if v, err := g.SetView("version", optionsVersionBoundary-1, optionsTop, width, optionsTop+2, 0); err != nil {
|
||||||
if err != gocui.ErrUnknownView {
|
if err != gocui.ErrUnknownView {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ func (gui *Gui) keybindings(g *gocui.Gui) error {
|
|||||||
bindings := []Binding{
|
bindings := []Binding{
|
||||||
{ViewName: "", Key: 'q', Modifier: gocui.ModNone, Handler: gui.quit},
|
{ViewName: "", Key: 'q', Modifier: gocui.ModNone, Handler: gui.quit},
|
||||||
{ViewName: "", Key: gocui.KeyCtrlC, Modifier: gocui.ModNone, Handler: gui.quit},
|
{ViewName: "", Key: gocui.KeyCtrlC, Modifier: gocui.ModNone, Handler: gui.quit},
|
||||||
|
{ViewName: "", Key: gocui.KeyEsc, Modifier: gocui.ModNone, Handler: gui.quit},
|
||||||
{ViewName: "", Key: gocui.KeyPgup, Modifier: gocui.ModNone, Handler: gui.scrollUpMain},
|
{ViewName: "", Key: gocui.KeyPgup, Modifier: gocui.ModNone, Handler: gui.scrollUpMain},
|
||||||
{ViewName: "", Key: gocui.KeyPgdn, Modifier: gocui.ModNone, Handler: gui.scrollDownMain},
|
{ViewName: "", Key: gocui.KeyPgdn, Modifier: gocui.ModNone, Handler: gui.scrollDownMain},
|
||||||
{ViewName: "", Key: gocui.KeyCtrlU, Modifier: gocui.ModNone, Handler: gui.scrollUpMain},
|
{ViewName: "", Key: gocui.KeyCtrlU, Modifier: gocui.ModNone, Handler: gui.scrollUpMain},
|
||||||
@ -57,6 +58,7 @@ func (gui *Gui) keybindings(g *gocui.Gui) error {
|
|||||||
{ViewName: "branches", Key: 'F', Modifier: gocui.ModNone, Handler: gui.handleForceCheckout},
|
{ViewName: "branches", Key: 'F', Modifier: gocui.ModNone, Handler: gui.handleForceCheckout},
|
||||||
{ViewName: "branches", Key: 'n', Modifier: gocui.ModNone, Handler: gui.handleNewBranch},
|
{ViewName: "branches", Key: 'n', Modifier: gocui.ModNone, Handler: gui.handleNewBranch},
|
||||||
{ViewName: "branches", Key: 'd', Modifier: gocui.ModNone, Handler: gui.handleDeleteBranch},
|
{ViewName: "branches", Key: 'd', Modifier: gocui.ModNone, Handler: gui.handleDeleteBranch},
|
||||||
|
{ViewName: "branches", Key: 'D', Modifier: gocui.ModNone, Handler: gui.handleForceDeleteBranch},
|
||||||
{ViewName: "branches", Key: 'm', Modifier: gocui.ModNone, Handler: gui.handleMerge},
|
{ViewName: "branches", Key: 'm', Modifier: gocui.ModNone, Handler: gui.handleMerge},
|
||||||
{ViewName: "commits", Key: 's', Modifier: gocui.ModNone, Handler: gui.handleCommitSquashDown},
|
{ViewName: "commits", Key: 's', Modifier: gocui.ModNone, Handler: gui.handleCommitSquashDown},
|
||||||
{ViewName: "commits", Key: 'r', Modifier: gocui.ModNone, Handler: gui.handleRenameCommit},
|
{ViewName: "commits", Key: 'r', Modifier: gocui.ModNone, Handler: gui.handleRenameCommit},
|
||||||
|
@ -7,6 +7,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
|
"github.com/spkg/bom"
|
||||||
)
|
)
|
||||||
|
|
||||||
var cyclableViews = []string{"status", "files", "branches", "commits", "stash"}
|
var cyclableViews = []string{"status", "files", "branches", "commits", "stash"}
|
||||||
@ -224,7 +226,9 @@ func (gui *Gui) renderString(g *gocui.Gui, viewName, s string) error {
|
|||||||
gui.Log.Info(s)
|
gui.Log.Info(s)
|
||||||
}
|
}
|
||||||
v.Clear()
|
v.Clear()
|
||||||
fmt.Fprint(v, s)
|
output := string(bom.Clean([]byte(s)))
|
||||||
|
output = utils.NormalizeLinefeeds(output)
|
||||||
|
fmt.Fprint(v, output)
|
||||||
v.Wrap = true
|
v.Wrap = true
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
@ -132,7 +132,10 @@ func addDutch(i18nObject *i18n.Bundle) error {
|
|||||||
Other: "Verwijder branch",
|
Other: "Verwijder branch",
|
||||||
}, &i18n.Message{
|
}, &i18n.Message{
|
||||||
ID: "DeleteBranchMessage",
|
ID: "DeleteBranchMessage",
|
||||||
Other: "Weet je zeker dat je {{.selectedBranchName}} branch wil verwijderen?",
|
Other: "Weet je zeker dat je branch {{.selectedBranchName}} wil verwijderen?",
|
||||||
|
}, &i18n.Message{
|
||||||
|
ID: "ForceDeleteBranchMessage",
|
||||||
|
Other: "Weet je zeker dat je branch {{.selectedBranchName}} geforceerd wil verwijderen?",
|
||||||
}, &i18n.Message{
|
}, &i18n.Message{
|
||||||
ID: "CantMergeBranchIntoItself",
|
ID: "CantMergeBranchIntoItself",
|
||||||
Other: "Je kan niet een branch in zichzelf mergen",
|
Other: "Je kan niet een branch in zichzelf mergen",
|
||||||
@ -151,6 +154,9 @@ func addDutch(i18nObject *i18n.Bundle) error {
|
|||||||
}, &i18n.Message{
|
}, &i18n.Message{
|
||||||
ID: "deleteBranch",
|
ID: "deleteBranch",
|
||||||
Other: "verwijder branch",
|
Other: "verwijder branch",
|
||||||
|
}, &i18n.Message{
|
||||||
|
ID: "forceDeleteBranch",
|
||||||
|
Other: "verwijder branch (forceer)",
|
||||||
}, &i18n.Message{
|
}, &i18n.Message{
|
||||||
ID: "NoBranchesThisRepo",
|
ID: "NoBranchesThisRepo",
|
||||||
Other: "Geen branches voor deze repo",
|
Other: "Geen branches voor deze repo",
|
||||||
|
@ -140,7 +140,10 @@ func addEnglish(i18nObject *i18n.Bundle) error {
|
|||||||
Other: "Delete Branch",
|
Other: "Delete Branch",
|
||||||
}, &i18n.Message{
|
}, &i18n.Message{
|
||||||
ID: "DeleteBranchMessage",
|
ID: "DeleteBranchMessage",
|
||||||
Other: "Are you sure you want delete the branch {{.selectedBranchName}} ?",
|
Other: "Are you sure you want to delete the branch {{.selectedBranchName}}?",
|
||||||
|
}, &i18n.Message{
|
||||||
|
ID: "ForceDeleteBranchMessage",
|
||||||
|
Other: "Are you sure you want to force delete the branch {{.selectedBranchName}}?",
|
||||||
}, &i18n.Message{
|
}, &i18n.Message{
|
||||||
ID: "CantMergeBranchIntoItself",
|
ID: "CantMergeBranchIntoItself",
|
||||||
Other: "You cannot merge a branch into itself",
|
Other: "You cannot merge a branch into itself",
|
||||||
@ -159,6 +162,9 @@ func addEnglish(i18nObject *i18n.Bundle) error {
|
|||||||
}, &i18n.Message{
|
}, &i18n.Message{
|
||||||
ID: "deleteBranch",
|
ID: "deleteBranch",
|
||||||
Other: "delete branch",
|
Other: "delete branch",
|
||||||
|
}, &i18n.Message{
|
||||||
|
ID: "forceDeleteBranch",
|
||||||
|
Other: "delete branch (force)",
|
||||||
}, &i18n.Message{
|
}, &i18n.Message{
|
||||||
ID: "NoBranchesThisRepo",
|
ID: "NoBranchesThisRepo",
|
||||||
Other: "No branches for this repo",
|
Other: "No branches for this repo",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package i18n
|
package i18n
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/cloudfoundry/jibber_jabber"
|
"github.com/cloudfoundry/jibber_jabber"
|
||||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||||
"golang.org/x/text/language"
|
"golang.org/x/text/language"
|
||||||
@ -18,33 +18,12 @@ type Localizer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewLocalizer creates a new Localizer
|
// NewLocalizer creates a new Localizer
|
||||||
func NewLocalizer(log *logrus.Logger) (*Localizer, error) {
|
func NewLocalizer(log *logrus.Logger) *Localizer {
|
||||||
|
userLang := detectLanguage(jibber_jabber.DetectLanguage)
|
||||||
|
|
||||||
// detect the user's language
|
|
||||||
userLang, err := jibber_jabber.DetectLanguage()
|
|
||||||
if err != nil {
|
|
||||||
if err.Error() != "Could not detect Language" {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
userLang = "C"
|
|
||||||
}
|
|
||||||
log.Info("language: " + userLang)
|
log.Info("language: " + userLang)
|
||||||
|
|
||||||
// create a i18n bundle that can be used to add translations and other things
|
return setupLocalizer(log, userLang)
|
||||||
i18nBundle := &i18n.Bundle{DefaultLanguage: language.English}
|
|
||||||
|
|
||||||
addBundles(log, i18nBundle)
|
|
||||||
|
|
||||||
// return the new localizer that can be used to translate text
|
|
||||||
i18nLocalizer := i18n.NewLocalizer(i18nBundle, userLang)
|
|
||||||
|
|
||||||
localizer := &Localizer{
|
|
||||||
i18nLocalizer: i18nLocalizer,
|
|
||||||
language: userLang,
|
|
||||||
Log: log,
|
|
||||||
}
|
|
||||||
|
|
||||||
return localizer, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Localize handels the translations
|
// Localize handels the translations
|
||||||
@ -82,17 +61,42 @@ func (l *Localizer) GetLanguage() string {
|
|||||||
|
|
||||||
// add translation file(s)
|
// add translation file(s)
|
||||||
func addBundles(log *logrus.Logger, i18nBundle *i18n.Bundle) {
|
func addBundles(log *logrus.Logger, i18nBundle *i18n.Bundle) {
|
||||||
err := addPolish(i18nBundle)
|
fs := []func(*i18n.Bundle) error{
|
||||||
if err != nil {
|
addPolish,
|
||||||
log.Fatal(err)
|
addDutch,
|
||||||
}
|
addEnglish,
|
||||||
err = addDutch(i18nBundle)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
err = addEnglish(i18nBundle)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, f := range fs {
|
||||||
|
if err := f(i18nBundle); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// detectLanguage extracts user language from environment
|
||||||
|
func detectLanguage(langDetector func() (string, error)) string {
|
||||||
|
if userLang, err := langDetector(); err == nil {
|
||||||
|
return userLang
|
||||||
|
}
|
||||||
|
|
||||||
|
return "C"
|
||||||
|
}
|
||||||
|
|
||||||
|
// setupLocalizer creates a new localizer using given userLang
|
||||||
|
func setupLocalizer(log *logrus.Logger, userLang string) *Localizer {
|
||||||
|
// create a i18n bundle that can be used to add translations and other things
|
||||||
|
i18nBundle := &i18n.Bundle{DefaultLanguage: language.English}
|
||||||
|
|
||||||
|
addBundles(log, i18nBundle)
|
||||||
|
|
||||||
|
// return the new localizer that can be used to translate text
|
||||||
|
i18nLocalizer := i18n.NewLocalizer(i18nBundle, userLang)
|
||||||
|
|
||||||
|
return &Localizer{
|
||||||
|
i18nLocalizer: i18nLocalizer,
|
||||||
|
language: userLang,
|
||||||
|
Log: log,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
81
pkg/i18n/i18n_test.go
Normal file
81
pkg/i18n/i18n_test.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package i18n
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewLocalizer(t *testing.T) {
|
||||||
|
assert.NotNil(t, NewLocalizer(logrus.New()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDetectLanguage(t *testing.T) {
|
||||||
|
type scenario struct {
|
||||||
|
langDetector func() (string, error)
|
||||||
|
expected string
|
||||||
|
}
|
||||||
|
|
||||||
|
scenarios := []scenario{
|
||||||
|
{
|
||||||
|
func() (string, error) {
|
||||||
|
return "", fmt.Errorf("An error occurred")
|
||||||
|
},
|
||||||
|
"C",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
func() (string, error) {
|
||||||
|
return "en", nil
|
||||||
|
},
|
||||||
|
"en",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
assert.EqualValues(t, s.expected, detectLanguage(s.langDetector))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLocalizer(t *testing.T) {
|
||||||
|
type scenario struct {
|
||||||
|
userLang string
|
||||||
|
test func(*Localizer)
|
||||||
|
}
|
||||||
|
|
||||||
|
scenarios := []scenario{
|
||||||
|
{
|
||||||
|
"C",
|
||||||
|
func(l *Localizer) {
|
||||||
|
assert.EqualValues(t, "C", l.GetLanguage())
|
||||||
|
assert.Equal(t, "Diff", l.Localize(&i18n.LocalizeConfig{
|
||||||
|
DefaultMessage: &i18n.Message{
|
||||||
|
ID: "DiffTitle",
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
assert.Equal(t, "Diff", l.SLocalize("DiffTitle"))
|
||||||
|
assert.Equal(t, "Are you sure you want to delete the branch test?", l.TemplateLocalize("DeleteBranchMessage", Teml{"selectedBranchName": "test"}))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nl",
|
||||||
|
func(l *Localizer) {
|
||||||
|
assert.EqualValues(t, "nl", l.GetLanguage())
|
||||||
|
assert.Equal(t, "Diff", l.Localize(&i18n.LocalizeConfig{
|
||||||
|
DefaultMessage: &i18n.Message{
|
||||||
|
ID: "DiffTitle",
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
assert.Equal(t, "Diff", l.SLocalize("DiffTitle"))
|
||||||
|
assert.Equal(t, "Weet je zeker dat je branch test wil verwijderen?", l.TemplateLocalize("DeleteBranchMessage", Teml{"selectedBranchName": "test"}))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
s.test(setupLocalizer(logrus.New(), s.userLang))
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
)
|
)
|
||||||
@ -11,15 +12,20 @@ import (
|
|||||||
// GenerateRepo generates a repo from test/repos and changes the directory to be
|
// GenerateRepo generates a repo from test/repos and changes the directory to be
|
||||||
// inside the newly made repo
|
// inside the newly made repo
|
||||||
func GenerateRepo(filename string) error {
|
func GenerateRepo(filename string) error {
|
||||||
testPath := utils.GetProjectRoot() + "/test/repos/"
|
reposDir := "/test/repos/"
|
||||||
|
testPath := utils.GetProjectRoot() + reposDir
|
||||||
|
|
||||||
|
// workaround for debian packaging
|
||||||
|
if _, err := os.Stat(testPath); os.IsNotExist(err) {
|
||||||
|
cwd, _ := os.Getwd()
|
||||||
|
testPath = filepath.Dir(filepath.Dir(cwd)) + reposDir
|
||||||
|
}
|
||||||
if err := os.Chdir(testPath); err != nil {
|
if err := os.Chdir(testPath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if output, err := exec.Command("bash", filename).CombinedOutput(); err != nil {
|
if output, err := exec.Command("bash", filename).CombinedOutput(); err != nil {
|
||||||
return errors.New(string(output))
|
return errors.New(string(output))
|
||||||
}
|
}
|
||||||
if err := os.Chdir(testPath + "repo"); err != nil {
|
|
||||||
return err
|
return os.Chdir(testPath + "repo")
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -13,10 +13,10 @@ import (
|
|||||||
|
|
||||||
"github.com/kardianos/osext"
|
"github.com/kardianos/osext"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
getter "github.com/jesseduffield/go-getter"
|
getter "github.com/jesseduffield/go-getter"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/config"
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Update checks for updates and does updates
|
// Update checks for updates and does updates
|
||||||
|
@ -64,6 +64,13 @@ func TrimTrailingNewline(str string) string {
|
|||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NormalizeLinefeeds - Removes all Windows and Mac style line feeds
|
||||||
|
func NormalizeLinefeeds(str string) string {
|
||||||
|
str = strings.Replace(str, "\r\n", "\n", -1)
|
||||||
|
str = strings.Replace(str, "\r", "", -1)
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
// GetProjectRoot returns the path to the root of the project. Only to be used
|
// GetProjectRoot returns the path to the root of the project. Only to be used
|
||||||
// in testing contexts, as with binaries it's unlikely this path will exist on
|
// in testing contexts, as with binaries it's unlikely this path will exist on
|
||||||
// the machine
|
// the machine
|
||||||
|
@ -81,3 +81,36 @@ func TestTrimTrailingNewline(t *testing.T) {
|
|||||||
assert.EqualValues(t, s.expected, TrimTrailingNewline(s.str))
|
assert.EqualValues(t, s.expected, TrimTrailingNewline(s.str))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNormalizeLinefeeds(t *testing.T) {
|
||||||
|
type scenario struct {
|
||||||
|
byteArray []byte
|
||||||
|
expected []byte
|
||||||
|
}
|
||||||
|
var scenarios = []scenario{
|
||||||
|
{
|
||||||
|
// \r\n
|
||||||
|
[]byte{97, 115, 100, 102, 13, 10},
|
||||||
|
[]byte{97, 115, 100, 102, 10},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// bash\r\nblah
|
||||||
|
[]byte{97, 115, 100, 102, 13, 10, 97, 115, 100, 102},
|
||||||
|
[]byte{97, 115, 100, 102, 10, 97, 115, 100, 102},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// \r
|
||||||
|
[]byte{97, 115, 100, 102, 13},
|
||||||
|
[]byte{97, 115, 100, 102},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// \n
|
||||||
|
[]byte{97, 115, 100, 102, 10},
|
||||||
|
[]byte{97, 115, 100, 102, 10},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
assert.EqualValues(t, string(s.expected), NormalizeLinefeeds(string(s.byteArray)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
14
test.sh
Executable file
14
test.sh
Executable file
@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
echo "" > coverage.txt
|
||||||
|
|
||||||
|
for d in $( find ./* -maxdepth 10 ! -path "./vendor*" ! -path "./.git*" -type d); do
|
||||||
|
if ls $d/*.go &> /dev/null; then
|
||||||
|
go test -v -race -coverprofile=profile.out -covermode=atomic $d
|
||||||
|
if [ -f profile.out ]; then
|
||||||
|
cat profile.out >> coverage.txt
|
||||||
|
rm profile.out
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
23
test/repos/bom.sh
Executable file
23
test/repos/bom.sh
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -ex; rm -rf repo; mkdir repo; cd repo
|
||||||
|
|
||||||
|
git init
|
||||||
|
|
||||||
|
cat <<EOT >> windowslf.txt
|
||||||
|
asdf
|
||||||
|
asdf
|
||||||
|
EOT
|
||||||
|
|
||||||
|
cat <<EOT >> linuxlf.txt
|
||||||
|
asdf
|
||||||
|
asdf
|
||||||
|
EOT
|
||||||
|
|
||||||
|
cat <<EOT >> bomtest.txt
|
||||||
|
A,B,C,D,E
|
||||||
|
F,G,H,I,J
|
||||||
|
K,L,M,N,O
|
||||||
|
P,Q,R,S,T
|
||||||
|
U,V,W,X,Y
|
||||||
|
Z,1,2,3,4
|
||||||
|
EOT
|
28
vendor/github.com/jesseduffield/gocui/gui.go
generated
vendored
28
vendor/github.com/jesseduffield/gocui/gui.go
generated
vendored
@ -653,17 +653,31 @@ func (g *Gui) onKey(ev *termbox.Event) error {
|
|||||||
// execKeybindings executes the keybinding handlers that match the passed view
|
// execKeybindings executes the keybinding handlers that match the passed view
|
||||||
// and event. The value of matched is true if there is a match and no errors.
|
// and event. The value of matched is true if there is a match and no errors.
|
||||||
func (g *Gui) execKeybindings(v *View, ev *termbox.Event) (matched bool, err error) {
|
func (g *Gui) execKeybindings(v *View, ev *termbox.Event) (matched bool, err error) {
|
||||||
matched = false
|
var globalKb *keybinding
|
||||||
for _, kb := range g.keybindings {
|
for _, kb := range g.keybindings {
|
||||||
if kb.handler == nil {
|
if kb.handler == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if kb.matchKeypress(Key(ev.Key), ev.Ch, Modifier(ev.Mod)) && kb.matchView(v) {
|
if !kb.matchKeypress(Key(ev.Key), ev.Ch, Modifier(ev.Mod)) {
|
||||||
if err := kb.handler(g, v); err != nil {
|
continue
|
||||||
return false, err
|
}
|
||||||
}
|
if kb.matchView(v) {
|
||||||
matched = true
|
return g.execKeybinding(v, kb)
|
||||||
|
}
|
||||||
|
if kb.viewName == "" && (!v.Editable || kb.ch == 0) {
|
||||||
|
globalKb = kb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return matched, nil
|
if globalKb != nil {
|
||||||
|
return g.execKeybinding(v, globalKb)
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// execKeybinding executes a given keybinding
|
||||||
|
func (g *Gui) execKeybinding(v *View, kb *keybinding) (bool, error) {
|
||||||
|
if err := kb.handler(g, v); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
|
3
vendor/github.com/jesseduffield/gocui/keybinding.go
generated
vendored
3
vendor/github.com/jesseduffield/gocui/keybinding.go
generated
vendored
@ -38,9 +38,6 @@ func (kb *keybinding) matchView(v *View) bool {
|
|||||||
if v.Editable == true && kb.ch != 0 {
|
if v.Editable == true && kb.ch != 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if kb.viewName == "" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return v != nil && kb.viewName == v.name
|
return v != nil && kb.viewName == v.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
0
vendor/github.com/Sirupsen/logrus/LICENSE → vendor/github.com/sirupsen/logrus/LICENSE
generated
vendored
0
vendor/github.com/Sirupsen/logrus/LICENSE → vendor/github.com/sirupsen/logrus/LICENSE
generated
vendored
0
vendor/github.com/Sirupsen/logrus/alt_exit.go → vendor/github.com/sirupsen/logrus/alt_exit.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/alt_exit.go → vendor/github.com/sirupsen/logrus/alt_exit.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/doc.go → vendor/github.com/sirupsen/logrus/doc.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/doc.go → vendor/github.com/sirupsen/logrus/doc.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/entry.go → vendor/github.com/sirupsen/logrus/entry.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/entry.go → vendor/github.com/sirupsen/logrus/entry.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/exported.go → vendor/github.com/sirupsen/logrus/exported.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/exported.go → vendor/github.com/sirupsen/logrus/exported.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/formatter.go → vendor/github.com/sirupsen/logrus/formatter.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/formatter.go → vendor/github.com/sirupsen/logrus/formatter.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/hooks.go → vendor/github.com/sirupsen/logrus/hooks.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/hooks.go → vendor/github.com/sirupsen/logrus/hooks.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/json_formatter.go → vendor/github.com/sirupsen/logrus/json_formatter.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/json_formatter.go → vendor/github.com/sirupsen/logrus/json_formatter.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/logger.go → vendor/github.com/sirupsen/logrus/logger.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/logger.go → vendor/github.com/sirupsen/logrus/logger.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/logrus.go → vendor/github.com/sirupsen/logrus/logrus.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/logrus.go → vendor/github.com/sirupsen/logrus/logrus.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/terminal_bsd.go → vendor/github.com/sirupsen/logrus/terminal_bsd.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/terminal_bsd.go → vendor/github.com/sirupsen/logrus/terminal_bsd.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/terminal_check_appengine.go → vendor/github.com/sirupsen/logrus/terminal_check_appengine.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/terminal_check_appengine.go → vendor/github.com/sirupsen/logrus/terminal_check_appengine.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/terminal_check_notappengine.go → vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/terminal_check_notappengine.go → vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/terminal_linux.go → vendor/github.com/sirupsen/logrus/terminal_linux.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/terminal_linux.go → vendor/github.com/sirupsen/logrus/terminal_linux.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/text_formatter.go → vendor/github.com/sirupsen/logrus/text_formatter.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/text_formatter.go → vendor/github.com/sirupsen/logrus/text_formatter.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/writer.go → vendor/github.com/sirupsen/logrus/writer.go
generated
vendored
0
vendor/github.com/Sirupsen/logrus/writer.go → vendor/github.com/sirupsen/logrus/writer.go
generated
vendored
21
vendor/github.com/spkg/bom/LICENSE.md
generated
vendored
Normal file
21
vendor/github.com/spkg/bom/LICENSE.md
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 John Jeffery
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
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 OR COPYRIGHT HOLDERS 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.
|
39
vendor/github.com/spkg/bom/bom.go
generated
vendored
Normal file
39
vendor/github.com/spkg/bom/bom.go
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// Package bom is used to clean up UTF-8 Byte Order Marks.
|
||||||
|
package bom
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
bom0 = 0xef
|
||||||
|
bom1 = 0xbb
|
||||||
|
bom2 = 0xbf
|
||||||
|
)
|
||||||
|
|
||||||
|
// Clean returns b with the 3 byte BOM stripped off the front if it is present.
|
||||||
|
// If the BOM is not present, then b is returned.
|
||||||
|
func Clean(b []byte) []byte {
|
||||||
|
if len(b) >= 3 &&
|
||||||
|
b[0] == bom0 &&
|
||||||
|
b[1] == bom1 &&
|
||||||
|
b[2] == bom2 {
|
||||||
|
return b[3:]
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewReader returns an io.Reader that will skip over initial UTF-8 byte order marks.
|
||||||
|
func NewReader(r io.Reader) io.Reader {
|
||||||
|
buf := bufio.NewReader(r)
|
||||||
|
b, err := buf.Peek(3)
|
||||||
|
if err != nil {
|
||||||
|
// not enough bytes
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
if b[0] == bom0 && b[1] == bom1 && b[2] == bom2 {
|
||||||
|
discardBytes(buf, 3)
|
||||||
|
}
|
||||||
|
return buf
|
||||||
|
}
|
12
vendor/github.com/spkg/bom/discard_go14.go
generated
vendored
Normal file
12
vendor/github.com/spkg/bom/discard_go14.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// +build !go1.5
|
||||||
|
|
||||||
|
package bom
|
||||||
|
|
||||||
|
import "bufio"
|
||||||
|
|
||||||
|
func discardBytes(buf *bufio.Reader, n int) {
|
||||||
|
// cannot use the buf.Discard method as it was introduced in Go 1.5
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
buf.ReadByte()
|
||||||
|
}
|
||||||
|
}
|
10
vendor/github.com/spkg/bom/discard_go15.go
generated
vendored
Normal file
10
vendor/github.com/spkg/bom/discard_go15.go
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// +build go1.5
|
||||||
|
|
||||||
|
package bom
|
||||||
|
|
||||||
|
import "bufio"
|
||||||
|
|
||||||
|
func discardBytes(buf *bufio.Reader, n int) {
|
||||||
|
// the Discard method was introduced in Go 1.5
|
||||||
|
buf.Discard(n)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user