diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fb3fe8f50..99ea11280 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -169,9 +169,9 @@ jobs: with: go-version: 1.24.x - name: Lint - uses: golangci/golangci-lint-action@v6.5.0 + uses: golangci/golangci-lint-action@v8 with: - version: v1.64.6 + version: v2.2.1 - name: errors run: golangci-lint run if: ${{ failure() }} diff --git a/.golangci.yml b/.golangci.yml index 209e79c5c..6a02b1dc5 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,36 +1,114 @@ -linters: - enable: - - gofumpt - - thelper - - goimports - - tparallel - - wastedassign - - unparam - - prealloc - - unconvert - - exhaustive - - makezero - - nakedret - - copyloopvar - fast: false - -linters-settings: - copyloopvar: - # Check all assigning the loop variable to another variable. - # Default: false - # If true, an assignment like `a := x` will be detected as an error. - check-alias: true - exhaustive: - default-signifies-exhaustive: true - staticcheck: - # SA1019 is for checking that we're not using fields marked as deprecated - # in a comment. It decides this in a loose way so I'm silencing it. Also because - # it's tripping on our own structs. - checks: ["all", "-SA1019"] - nakedret: - # the gods will judge me but I just don't like naked returns at all - max-func-lines: 0 - +version: "2" run: go: "1.24" - timeout: 10m +linters: + enable: + - copyloopvar + - errorlint + - exhaustive + - intrange + - makezero + - nakedret + - nolintlint + - prealloc + - revive + - thelper + - tparallel + - unconvert + - unparam + - wastedassign + settings: + copyloopvar: + check-alias: true + exhaustive: + default-signifies-exhaustive: true + nakedret: + # the gods will judge me but I just don't like naked returns at all + max-func-lines: 0 + staticcheck: + checks: + - all + + # SA1019 is for checking that we're not using fields marked as + # deprecated in a comment. It decides this in a loose way so I'm + # silencing it. Also because it's tripping on our own structs. + - -SA1019 + + # ST1003 complains about names like remoteUrl or itemId (should be + # remoteURL and itemID). While I like these suggestions, it also + # complains about enum constants that are all caps, and we use these and + # I like them, and also about camelCase identifiers that contain an + # underscore, which we also use in a few places. Since it can't be + # configured to ignore specific cases, and I don't want to use nolint + # comments in the code, we have to disable it altogether. + - -ST1003 # Poorly chosen identifier + + # Probably a good idea, but we first have to review our error reporting + # strategy to be able to use it everywhere. + - -ST1005 # Error strings should not be capitalized + + # Many of our classes use self as a receiver name, and we think that's fine. + - -ST1006 # Use of self or this as receiver name + + # De Morgan's law suggests to replace `!(a && b)` with `!a || !b`; but + # sometimes I find one more readable than the other, so I want to decide + # that myself. + - -QF1001 # De Morgan's law + + # QF1003 is about using a tagged switch instead of an if-else chain. In + # many cases this is a useful suggestion; however, sometimes the change + # is only possible by adding a default case to the switch (when there + # was no `else` block in the original code), in which case I don't find + # it to be an improvement. + - -QF1003 # Could replace with tagged switch + + # We need to review our use of embedded fields. I suspect that in some + # cases the fix is not to remove the selector for the embedded field, + # but to turn the embedded field into a named field. + - -QF1008 # Could remove embedded field from selector + + # The following checks are all disabled by default in golangci-lint, but + # we disable them again explicitly here to make it easier to keep this + # list in sync with the gopls config in .vscode/settings.json. + - -ST1000, # At least one file in a package should have a package comment + - -ST1020, # The documentation of an exported function should start with the function's name + - -ST1021, # The documentation of an exported type should start with type's name + - -ST1022, # The documentation of an exported variable or constant should start with variable's name + + dot-import-whitelist: + - github.com/jesseduffield/lazygit/pkg/integration/components + revive: + severity: warning + rules: + - name: atomic + - name: context-as-argument + - name: context-keys-type + - name: error-naming + - name: var-declaration + - name: package-comments + - name: range + - name: time-naming + - name: indent-error-flow + - name: errorf + - name: superfluous-else + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + paths: + - third_party$ + - builtin$ + - examples$ +formatters: + enable: + - gofumpt + - goimports + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/.vscode/settings.json b/.vscode/settings.json index 219c87aea..23a0e524b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,29 @@ { "gopls": { "formatting.gofumpt": true, + "ui.diagnostic.staticcheck": true, + "ui.diagnostic.analyses": { + // This list must match the one in .golangci.yml + "SA1019": false, + "ST1003": false, + "ST1005": false, + "ST1006": false, + "QF1001": false, + "QF1003": false, + "QF1008": false, + "ST1000": false, + "ST1020": false, + "ST1021": false, + "ST1022": false, + // Dot imports; this warning is enabled in .golangci.yml, but with an + // extra dot-import-whitelist config. Because I couldn't figure out how to + // specify that extra config for gopls, I'm disabling the check altogether + // here. + "ST1001": false, + }, }, + "go.alternateTools": { + "golangci-lint-v2": "${workspaceFolder}/.bin/golangci-lint", + }, + "go.lintTool": "golangci-lint-v2", } diff --git a/Makefile b/Makefile index ca490a94a..f972100a1 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ format: .PHONY: lint lint: - golangci-lint run + ./scripts/lint.sh # For more details about integration test, see https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md. .PHONY: integration-test-tui diff --git a/pkg/app/app.go b/pkg/app/app.go index 8d1d1568c..ad0d487ec 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -86,9 +86,9 @@ func newLogger(cfg config.AppConfigurer) *logrus.Entry { log.Fatal(err) } return logs.NewDevelopmentLogger(logPath) - } else { - return logs.NewProductionLogger() } + + return logs.NewProductionLogger() } // NewApp bootstrap a new application diff --git a/pkg/app/daemon/rebase.go b/pkg/app/daemon/rebase.go index 30740d09c..1cb3b844f 100644 --- a/pkg/app/daemon/rebase.go +++ b/pkg/app/daemon/rebase.go @@ -21,9 +21,8 @@ type TodoLine struct { func (self *TodoLine) ToString() string { if self.Action == "break" { return self.Action + "\n" - } else { - return self.Action + " " + self.Commit.Hash() + " " + self.Commit.Name + "\n" } + return self.Action + " " + self.Commit.Hash() + " " + self.Commit.Name + "\n" } func TodoLinesToString(todoLines []TodoLine) string { diff --git a/pkg/commands/git_cmd_obj_runner.go b/pkg/commands/git_cmd_obj_runner.go index 302547d41..fd98bc84f 100644 --- a/pkg/commands/git_cmd_obj_runner.go +++ b/pkg/commands/git_cmd_obj_runner.go @@ -28,7 +28,7 @@ func (self *gitCmdObjRunner) Run(cmdObj *oscommands.CmdObj) error { func (self *gitCmdObjRunner) RunWithOutput(cmdObj *oscommands.CmdObj) (string, error) { var output string var err error - for i := 0; i < RetryCount; i++ { + for range RetryCount { newCmdObj := cmdObj.Clone() output, err = self.innerRunner.RunWithOutput(newCmdObj) @@ -47,7 +47,7 @@ func (self *gitCmdObjRunner) RunWithOutput(cmdObj *oscommands.CmdObj) (string, e func (self *gitCmdObjRunner) RunWithOutputs(cmdObj *oscommands.CmdObj) (string, string, error) { var stdout, stderr string var err error - for i := 0; i < RetryCount; i++ { + for range RetryCount { newCmdObj := cmdObj.Clone() stdout, stderr, err = self.innerRunner.RunWithOutputs(newCmdObj) diff --git a/pkg/commands/git_commands/branch_loader.go b/pkg/commands/git_commands/branch_loader.go index 798a2ebef..73127ae63 100644 --- a/pkg/commands/git_commands/branch_loader.go +++ b/pkg/commands/git_commands/branch_loader.go @@ -356,9 +356,8 @@ func parseDifference(track string, regexStr string) string { match := re.FindStringSubmatch(track) if len(match) > 1 { return match[1] - } else { - return "0" } + return "0" } // TODO: only look at the new reflog commits, and otherwise store the recencies in diff --git a/pkg/commands/git_commands/commit.go b/pkg/commands/git_commands/commit.go index adf7dcf19..3568dbb33 100644 --- a/pkg/commands/git_commands/commit.go +++ b/pkg/commands/git_commands/commit.go @@ -149,9 +149,8 @@ func (self *CommitCommands) CommitEditorCmdObj() *oscommands.CmdObj { func (self *CommitCommands) signoffFlag() string { if self.UserConfig().Git.Commit.SignOff { return "--signoff" - } else { - return "" } + return "" } func (self *CommitCommands) GetCommitMessage(commitHash string) (string, error) { diff --git a/pkg/commands/git_commands/commit_loader_test.go b/pkg/commands/git_commands/commit_loader_test.go index cc959b4ea..fcbc825d9 100644 --- a/pkg/commands/git_commands/commit_loader_test.go +++ b/pkg/commands/git_commands/commit_loader_test.go @@ -16,16 +16,16 @@ import ( "github.com/stretchr/testify/assert" ) -var commitsOutput = strings.Replace(`0eea75e8c631fba6b58135697835d58ba4c18dbc|1640826609|Jesse Duffield|jessedduffield@gmail.com|HEAD -> better-tests|b21997d6b4cbdf84b149|>|better typing for rebase mode +var commitsOutput = strings.ReplaceAll(`0eea75e8c631fba6b58135697835d58ba4c18dbc|1640826609|Jesse Duffield|jessedduffield@gmail.com|HEAD -> better-tests|b21997d6b4cbdf84b149|>|better typing for rebase mode b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164|1640824515|Jesse Duffield|jessedduffield@gmail.com|origin/better-tests|e94e8fc5b6fab4cb755f|>|fix logging e94e8fc5b6fab4cb755f29f1bdb3ee5e001df35c|1640823749|Jesse Duffield|jessedduffield@gmail.com|tag: 123, tag: 456|d8084cd558925eb7c9c3|>|refactor d8084cd558925eb7c9c38afeed5725c21653ab90|1640821426|Jesse Duffield|jessedduffield@gmail.com||65f910ebd85283b5cce9|>|WIP 65f910ebd85283b5cce9bf67d03d3f1a9ea3813a|1640821275|Jesse Duffield|jessedduffield@gmail.com||26c07b1ab33860a1a759|>|WIP 26c07b1ab33860a1a7591a0638f9925ccf497ffa|1640750752|Jesse Duffield|jessedduffield@gmail.com||3d4470a6c072208722e5|>|WIP 3d4470a6c072208722e5ae9a54bcb9634959a1c5|1640748818|Jesse Duffield|jessedduffield@gmail.com||053a66a7be3da43aacdc|>|WIP -053a66a7be3da43aacdc7aa78e1fe757b82c4dd2|1640739815|Jesse Duffield|jessedduffield@gmail.com||985fe482e806b172aea4|>|refactoring the config struct`, "|", "\x00", -1) +053a66a7be3da43aacdc7aa78e1fe757b82c4dd2|1640739815|Jesse Duffield|jessedduffield@gmail.com||985fe482e806b172aea4|>|refactoring the config struct`, "|", "\x00") -var singleCommitOutput = strings.Replace(`0eea75e8c631fba6b58135697835d58ba4c18dbc|1640826609|Jesse Duffield|jessedduffield@gmail.com|HEAD -> better-tests|b21997d6b4cbdf84b149|>|better typing for rebase mode`, "|", "\x00", -1) +var singleCommitOutput = strings.ReplaceAll(`0eea75e8c631fba6b58135697835d58ba4c18dbc|1640826609|Jesse Duffield|jessedduffield@gmail.com|HEAD -> better-tests|b21997d6b4cbdf84b149|>|better typing for rebase mode`, "|", "\x00") func TestGetCommits(t *testing.T) { type scenario struct { diff --git a/pkg/commands/git_commands/deps_test.go b/pkg/commands/git_commands/deps_test.go index bb079c063..a8fff5edd 100644 --- a/pkg/commands/git_commands/deps_test.go +++ b/pkg/commands/git_commands/deps_test.go @@ -97,7 +97,7 @@ func buildGitCommon(deps commonDeps) *GitCommon { func buildRepo() *gogit.Repository { // TODO: think of a way to actually mock this out - var repo *gogit.Repository = nil + var repo *gogit.Repository return repo } diff --git a/pkg/commands/git_commands/file_loader.go b/pkg/commands/git_commands/file_loader.go index bb898d06a..92a011f63 100644 --- a/pkg/commands/git_commands/file_loader.go +++ b/pkg/commands/git_commands/file_loader.go @@ -110,8 +110,8 @@ type FileDiff struct { LinesDeleted int } -func (fileLoader *FileLoader) getFileDiffs() (map[string]FileDiff, error) { - diffs, err := fileLoader.gitDiffNumStat() +func (self *FileLoader) getFileDiffs() (map[string]FileDiff, error) { + diffs, err := self.gitDiffNumStat() if err != nil { return nil, err } @@ -157,8 +157,8 @@ type FileStatus struct { PreviousPath string } -func (fileLoader *FileLoader) gitDiffNumStat() (string, error) { - return fileLoader.cmd.New( +func (self *FileLoader) gitDiffNumStat() (string, error) { + return self.cmd.New( NewGitCmd("diff"). Arg("--numstat"). Arg("-z"). diff --git a/pkg/commands/git_commands/git_command_builder.go b/pkg/commands/git_commands/git_command_builder.go index a7edc144c..5e9c3b258 100644 --- a/pkg/commands/git_commands/git_command_builder.go +++ b/pkg/commands/git_commands/git_command_builder.go @@ -32,9 +32,8 @@ func (self *GitCommandBuilder) ArgIf(condition bool, ifTrue ...string) *GitComma func (self *GitCommandBuilder) ArgIfElse(condition bool, ifTrue string, ifFalse string) *GitCommandBuilder { if condition { return self.Arg(ifTrue) - } else { - return self.Arg(ifFalse) } + return self.Arg(ifFalse) } func (self *GitCommandBuilder) Config(value string) *GitCommandBuilder { diff --git a/pkg/commands/git_commands/rebase.go b/pkg/commands/git_commands/rebase.go index f6302fc28..8c52dc62f 100644 --- a/pkg/commands/git_commands/rebase.go +++ b/pkg/commands/git_commands/rebase.go @@ -327,9 +327,8 @@ func (self *RebaseCommands) MoveFixupCommitDown(commits []*models.Commit, target func todoFromCommit(commit *models.Commit) utils.Todo { if commit.Action == todo.UpdateRef { return utils.Todo{Ref: commit.Name} - } else { - return utils.Todo{Hash: commit.Hash()} } + return utils.Todo{Hash: commit.Hash()} } // Sets the action for the given commits in the git-rebase-todo file @@ -412,9 +411,9 @@ func (self *RebaseCommands) BeginInteractiveRebaseForCommit( instruction: daemon.NewInsertBreakInstruction(), keepCommitsThatBecomeEmpty: keepCommitsThatBecomeEmpty, }).Run() - } else { - return self.BeginInteractiveRebaseForCommitRange(commits, commitIndex, commitIndex, keepCommitsThatBecomeEmpty) } + + return self.BeginInteractiveRebaseForCommitRange(commits, commitIndex, commitIndex, keepCommitsThatBecomeEmpty) } func (self *RebaseCommands) BeginInteractiveRebaseForCommitRange( @@ -574,7 +573,7 @@ func getBaseHashOrRoot(commits []*models.Commit, index int) string { // at time of writing) if index < len(commits) { return commits[index].Hash() - } else { - return "--root" } + + return "--root" } diff --git a/pkg/commands/git_commands/reflog_commit_loader_test.go b/pkg/commands/git_commands/reflog_commit_loader_test.go index 5cc7395c0..01e479e5c 100644 --- a/pkg/commands/git_commands/reflog_commit_loader_test.go +++ b/pkg/commands/git_commands/reflog_commit_loader_test.go @@ -14,12 +14,12 @@ import ( "github.com/stretchr/testify/assert" ) -var reflogOutput = strings.Replace(`c3c4b66b64c97ffeecde|1643150483|checkout: moving from A to B|51baa8c1 +var reflogOutput = strings.ReplaceAll(`c3c4b66b64c97ffeecde|1643150483|checkout: moving from A to B|51baa8c1 c3c4b66b64c97ffeecde|1643150483|checkout: moving from B to A|51baa8c1 c3c4b66b64c97ffeecde|1643150483|checkout: moving from A to B|51baa8c1 c3c4b66b64c97ffeecde|1643150483|checkout: moving from master to A|51baa8c1 f4ddf2f0d4be4ccc7efa|1643149435|checkout: moving from A to master|51baa8c1 -`, "|", "\x00", -1) +`, "|", "\x00") func TestGetReflogCommits(t *testing.T) { type scenario struct { diff --git a/pkg/commands/git_commands/repo_paths.go b/pkg/commands/git_commands/repo_paths.go index a355a45ba..543ab5cd0 100644 --- a/pkg/commands/git_commands/repo_paths.go +++ b/pkg/commands/git_commands/repo_paths.go @@ -21,7 +21,7 @@ type RepoPaths struct { isBareRepo bool } -var gitPathFormatVersion GitVersion = GitVersion{2, 31, 0, ""} +var gitPathFormatVersion = GitVersion{2, 31, 0, ""} // Path to the current worktree. If we're in the main worktree, this will // be the same as RepoPath() diff --git a/pkg/commands/git_commands/repo_paths_test.go b/pkg/commands/git_commands/repo_paths_test.go index 77f451671..2d02a9ed3 100644 --- a/pkg/commands/git_commands/repo_paths_test.go +++ b/pkg/commands/git_commands/repo_paths_test.go @@ -184,9 +184,7 @@ func TestGetRepoPaths(t *testing.T) { Expected: nil, Err: func(getRevParseArgs argFn) error { args := strings.Join(getRevParseArgs(), " ") - return errors.New( - fmt.Sprintf("'git %v --show-toplevel --absolute-git-dir --git-common-dir --is-bare-repository --show-superproject-working-tree' failed: fatal: invalid gitfile format: /path/to/repo/worktree2/.git", args), - ) + return fmt.Errorf("'git %v --show-toplevel --absolute-git-dir --git-common-dir --is-bare-repository --show-superproject-working-tree' failed: fatal: invalid gitfile format: /path/to/repo/worktree2/.git", args) }, }, } diff --git a/pkg/commands/git_commands/stash_loader.go b/pkg/commands/git_commands/stash_loader.go index f97cc718a..d0a290507 100644 --- a/pkg/commands/git_commands/stash_loader.go +++ b/pkg/commands/git_commands/stash_loader.go @@ -53,7 +53,7 @@ outer: if err != nil { return self.getUnfilteredStashEntries() } - currentStashEntry = self.stashEntryFromLine(lines[i], idx) + currentStashEntry = stashEntryFromLine(lines[i], idx) for i+1 < len(lines) && !isAStash(lines[i+1]) { i++ if lines[i] == filterPath { @@ -70,11 +70,11 @@ func (self *StashLoader) getUnfilteredStashEntries() []*models.StashEntry { rawString, _ := self.cmd.New(cmdArgs).DontLog().RunWithOutput() return lo.Map(utils.SplitNul(rawString), func(line string, index int) *models.StashEntry { - return self.stashEntryFromLine(line, index) + return stashEntryFromLine(line, index) }) } -func (c *StashLoader) stashEntryFromLine(line string, index int) *models.StashEntry { +func stashEntryFromLine(line string, index int) *models.StashEntry { model := &models.StashEntry{ Name: line, Index: index, diff --git a/pkg/commands/git_commands/submodule.go b/pkg/commands/git_commands/submodule.go index fbe4802c4..f06e10134 100644 --- a/pkg/commands/git_commands/submodule.go +++ b/pkg/commands/git_commands/submodule.go @@ -49,9 +49,8 @@ func (self *SubmoduleCommands) GetConfigs(parentModule *models.SubmoduleConfig) if len(matches) > 0 { return matches[1], true - } else { - return "", false } + return "", false } configs := []*models.SubmoduleConfig{} diff --git a/pkg/commands/git_commands/working_tree.go b/pkg/commands/git_commands/working_tree.go index 8ba9b196d..a5faa801b 100644 --- a/pkg/commands/git_commands/working_tree.go +++ b/pkg/commands/git_commands/working_tree.go @@ -66,9 +66,8 @@ func (self *WorkingTreeCommands) UnstageAll() error { func (self *WorkingTreeCommands) UnStageFile(paths []string, tracked bool) error { if tracked { return self.UnstageTrackedFiles(paths) - } else { - return self.UnstageUntrackedFiles(paths) } + return self.UnstageUntrackedFiles(paths) } func (self *WorkingTreeCommands) UnstageTrackedFiles(paths []string) error { diff --git a/pkg/commands/git_config/get_key.go b/pkg/commands/git_config/get_key.go index cd5a678ef..7369fa08e 100644 --- a/pkg/commands/git_config/get_key.go +++ b/pkg/commands/git_config/get_key.go @@ -2,6 +2,7 @@ package git_config import ( "bytes" + "errors" "fmt" "io" "os/exec" @@ -39,7 +40,8 @@ func runGitConfigCmd(cmd *exec.Cmd) (string, error) { cmd.Stderr = io.Discard err := cmd.Run() - if exitError, ok := err.(*exec.ExitError); ok { + var exitError *exec.ExitError + if errors.As(err, &exitError) { if waitStatus, ok := exitError.Sys().(syscall.WaitStatus); ok { if waitStatus.ExitStatus() == 1 { return "", fmt.Errorf("the key is not found for %s", cmd.Args) diff --git a/pkg/commands/hosting_service/hosting_service.go b/pkg/commands/hosting_service/hosting_service.go index 2e913b654..1c328fd0d 100644 --- a/pkg/commands/hosting_service/hosting_service.go +++ b/pkg/commands/hosting_service/hosting_service.go @@ -46,9 +46,8 @@ func (self *HostingServiceMgr) GetPullRequestURL(from string, to string) (string if to == "" { return gitService.getPullRequestURLIntoDefaultBranch(url.QueryEscape(from)), nil - } else { - return gitService.getPullRequestURLIntoTargetBranch(url.QueryEscape(from), url.QueryEscape(to)), nil } + return gitService.getPullRequestURLIntoTargetBranch(url.QueryEscape(from), url.QueryEscape(to)), nil } func (self *HostingServiceMgr) GetCommitURL(commitHash string) (string, error) { diff --git a/pkg/commands/oscommands/os.go b/pkg/commands/oscommands/os.go index 042af3f92..53e4f3c3d 100644 --- a/pkg/commands/oscommands/os.go +++ b/pkg/commands/oscommands/os.go @@ -222,7 +222,7 @@ func (c *OSCommand) PipeCommands(cmdObjs ...*CmdObj) error { c.LogCommand(logCmdStr, true) - for i := 0; i < len(cmds)-1; i++ { + for i := range len(cmds) - 1 { stdout, err := cmds[i].StdoutPipe() if err != nil { return err @@ -283,7 +283,7 @@ func PrepareForChildren(cmd *exec.Cmd) { } func (c *OSCommand) CopyToClipboard(str string) error { - escaped := strings.Replace(str, "\n", "\\n", -1) + escaped := strings.ReplaceAll(str, "\n", "\\n") truncated := utils.TruncateWithEllipsis(escaped, 40) msg := utils.ResolvePlaceholderString( diff --git a/pkg/commands/patch/patch.go b/pkg/commands/patch/patch.go index 5e4f9a846..f5efe95da 100644 --- a/pkg/commands/patch/patch.go +++ b/pkg/commands/patch/patch.go @@ -56,7 +56,7 @@ func (self *Patch) HunkStartIdx(hunkIndex int) int { hunkIndex = lo.Clamp(hunkIndex, 0, len(self.hunks)-1) result := len(self.header) - for i := 0; i < hunkIndex; i++ { + for i := range hunkIndex { result += self.hunks[i].lineCount() } return result diff --git a/pkg/commands/patch/patch_builder.go b/pkg/commands/patch/patch_builder.go index 5ef81c72e..3fc8ebcf7 100644 --- a/pkg/commands/patch/patch_builder.go +++ b/pkg/commands/patch/patch_builder.go @@ -91,7 +91,7 @@ func (p *PatchBuilder) addFileWhole(info *fileInfo) { // add every line index // TODO: add tests and then use lo.Range to simplify info.includedLineIndices = make([]int, lineCount) - for i := 0; i < lineCount; i++ { + for i := range lineCount { info.includedLineIndices[i] = i } } @@ -211,9 +211,8 @@ func (p *PatchBuilder) RenderPatchForFile(opts RenderPatchForFileOpts) string { if opts.Plain { return patch.FormatPlain() - } else { - return patch.FormatView(FormatViewOpts{}) } + return patch.FormatView(FormatViewOpts{}) } func (p *PatchBuilder) renderEachFilePatch(plain bool) []string { diff --git a/pkg/commands/patch/transform.go b/pkg/commands/patch/transform.go index db35bb4a1..4cd4c0207 100644 --- a/pkg/commands/patch/transform.go +++ b/pkg/commands/patch/transform.go @@ -84,9 +84,9 @@ func (self *patchTransformer) transformHeader() []string { result = append(result, line) } return result - } else { - return self.patch.header } + + return self.patch.header } func (self *patchTransformer) transformHunks() []*Hunk { diff --git a/pkg/config/app_config.go b/pkg/config/app_config.go index 5d6b5e219..90c6c1013 100644 --- a/pkg/config/app_config.go +++ b/pkg/config/app_config.go @@ -288,7 +288,7 @@ func computeMigratedConfig(path string, content []byte, changes *ChangesSet) ([] for _, pathToReplace := range pathsToReplace { err, didReplace := yaml_utils.RenameYamlKey(&rootNode, pathToReplace.oldPath, pathToReplace.newName) if err != nil { - return nil, false, fmt.Errorf("Couldn't migrate config file at `%s` for key %s: %s", path, strings.Join(pathToReplace.oldPath, "."), err) + return nil, false, fmt.Errorf("Couldn't migrate config file at `%s` for key %s: %w", path, strings.Join(pathToReplace.oldPath, "."), err) } if didReplace { changes.Add(fmt.Sprintf("Renamed '%s' to '%s'", strings.Join(pathToReplace.oldPath, "."), pathToReplace.newName)) @@ -297,27 +297,27 @@ func computeMigratedConfig(path string, content []byte, changes *ChangesSet) ([] err = changeNullKeybindingsToDisabled(&rootNode, changes) if err != nil { - return nil, false, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err) + return nil, false, fmt.Errorf("Couldn't migrate config file at `%s`: %w", path, err) } err = changeElementToSequence(&rootNode, []string{"git", "commitPrefix"}, changes) if err != nil { - return nil, false, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err) + return nil, false, fmt.Errorf("Couldn't migrate config file at `%s`: %w", path, err) } err = changeCommitPrefixesMap(&rootNode, changes) if err != nil { - return nil, false, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err) + return nil, false, fmt.Errorf("Couldn't migrate config file at `%s`: %w", path, err) } err = changeCustomCommandStreamAndOutputToOutputEnum(&rootNode, changes) if err != nil { - return nil, false, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err) + return nil, false, fmt.Errorf("Couldn't migrate config file at `%s`: %w", path, err) } err = migrateAllBranchesLogCmd(&rootNode, changes) if err != nil { - return nil, false, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err) + return nil, false, fmt.Errorf("Couldn't migrate config file at `%s`: %w", path, err) } // Add more migrations here... diff --git a/pkg/config/user_config_validation.go b/pkg/config/user_config_validation.go index a84b70aa7..f46dfca9a 100644 --- a/pkg/config/user_config_validation.go +++ b/pkg/config/user_config_validation.go @@ -56,7 +56,7 @@ func validateKeybindingsRecurse(path string, node any) error { } } } else if value.Kind() == reflect.Slice { - for i := 0; i < value.Len(); i++ { + for i := range value.Len() { if err := validateKeybindingsRecurse( fmt.Sprintf("%s[%d]", path, i), value.Index(i).Interface()); err != nil { return err diff --git a/pkg/gui/command_log_panel.go b/pkg/gui/command_log_panel.go index 8c1daa4c7..c0319f5c0 100644 --- a/pkg/gui/command_log_panel.go +++ b/pkg/gui/command_log_panel.go @@ -48,7 +48,7 @@ func (gui *Gui) LogCommand(cmdStr string, commandLine bool) { textStyle = style.FgMagenta } gui.GuiLog = append(gui.GuiLog, cmdStr) - indentedCmdStr := " " + strings.Replace(cmdStr, "\n", "\n ", -1) + indentedCmdStr := " " + strings.ReplaceAll(cmdStr, "\n", "\n ") fmt.Fprint(gui.Views.Extras, "\n"+textStyle.Sprint(indentedCmdStr)) } diff --git a/pkg/gui/context/list_renderer_test.go b/pkg/gui/context/list_renderer_test.go index 9ed47d03f..08af680ff 100644 --- a/pkg/gui/context/list_renderer_test.go +++ b/pkg/gui/context/list_renderer_test.go @@ -257,11 +257,11 @@ func TestListRenderer_ModelIndexToViewIndex_and_back(t *testing.T) { // Need to render first so that it knows the non-model items self.renderLines(-1, -1) - for i := 0; i < len(s.modelIndices); i++ { + for i := range len(s.modelIndices) { assert.Equal(t, s.expectedViewIndices[i], self.ModelIndexToViewIndex(s.modelIndices[i])) } - for i := 0; i < len(s.viewIndices); i++ { + for i := range len(s.viewIndices) { assert.Equal(t, s.expectedModelIndices[i], self.ViewIndexToModelIndex(s.viewIndices[i])) } }) diff --git a/pkg/gui/context/menu_context.go b/pkg/gui/context/menu_context.go index 26425af3d..3d5937a9d 100644 --- a/pkg/gui/context/menu_context.go +++ b/pkg/gui/context/menu_context.go @@ -144,7 +144,7 @@ func (self *MenuViewModel) GetNonModelItems() []*NonModelItem { } menuItems := self.FilteredListViewModel.GetItems() - var prevSection *types.MenuSection = nil + var prevSection *types.MenuSection for i, menuItem := range menuItems { if menuItem.Section != nil && menuItem.Section != prevSection { if prevSection != nil { diff --git a/pkg/gui/context/suggestions_context.go b/pkg/gui/context/suggestions_context.go index 9e3b8ba95..45364b3b5 100644 --- a/pkg/gui/context/suggestions_context.go +++ b/pkg/gui/context/suggestions_context.go @@ -79,9 +79,8 @@ func (self *SuggestionsContext) RefreshSuggestions() { if findSuggestionsFn != nil { suggestions := findSuggestionsFn(self.c.GetPromptInput()) return func() { self.SetSuggestions(suggestions) } - } else { - return func() {} } + return func() {} }) } diff --git a/pkg/gui/context/traits/list_cursor.go b/pkg/gui/context/traits/list_cursor.go index a8ff89716..c471d9a0f 100644 --- a/pkg/gui/context/traits/list_cursor.go +++ b/pkg/gui/context/traits/list_cursor.go @@ -77,9 +77,8 @@ func (self *ListCursor) SetSelectionRangeAndMode(selectedIdx, rangeStartIdx int, func (self *ListCursor) GetSelectionRangeAndMode() (int, int, RangeSelectMode) { if self.IsSelectingRange() { return self.selectedIdx, self.rangeStartIdx, self.rangeSelectMode - } else { - return self.selectedIdx, self.selectedIdx, self.rangeSelectMode } + return self.selectedIdx, self.selectedIdx, self.rangeSelectMode } func (self *ListCursor) clampValue(value int) int { diff --git a/pkg/gui/context_config.go b/pkg/gui/context_config.go index 748482a35..e1b35c492 100644 --- a/pkg/gui/context_config.go +++ b/pkg/gui/context_config.go @@ -24,7 +24,7 @@ func OnFocusWrapper(f func() error) func(opts types.OnFocusOpts) error { func (gui *Gui) defaultSideContext() types.Context { if gui.State.Modes.Filtering.Active() { return gui.State.Contexts.LocalCommits - } else { - return gui.State.Contexts.Files } + + return gui.State.Contexts.Files } diff --git a/pkg/gui/controllers/bisect_controller.go b/pkg/gui/controllers/bisect_controller.go index 0cd8d1d0b..401550c98 100644 --- a/pkg/gui/controllers/bisect_controller.go +++ b/pkg/gui/controllers/bisect_controller.go @@ -54,9 +54,8 @@ func (self *BisectController) openMenu(commit *models.Commit) error { info := self.c.Git().Bisect.GetInfo() if info.Started() { return self.openMidBisectMenu(info, commit) - } else { - return self.openStartBisectMenu(info, commit) } + return self.openStartBisectMenu(info, commit) } func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, commit *models.Commit) error { @@ -280,11 +279,11 @@ func (self *BisectController) afterBisectMarkRefresh(selectCurrent bool, waitToR if waitToReselect { return self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{}, Then: selectFn}) - } else { - _ = selectFn() - - return self.c.Helpers().Bisect.PostBisectCommandRefresh() } + + _ = selectFn() + + return self.c.Helpers().Bisect.PostBisectCommandRefresh() } func (self *BisectController) selectCurrentBisectCommit() { diff --git a/pkg/gui/controllers/branches_controller.go b/pkg/gui/controllers/branches_controller.go index 4b5318dcb..528bfcf49 100644 --- a/pkg/gui/controllers/branches_controller.go +++ b/pkg/gui/controllers/branches_controller.go @@ -657,15 +657,15 @@ func (self *BranchesController) fastForward(branch *models.Branch) error { ) _ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) return err - } else { - self.c.LogAction(action) - - err := self.c.Git().Sync.FastForward( - task, branch.Name, branch.UpstreamRemote, branch.UpstreamBranch, - ) - _ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}}) - return err } + + self.c.LogAction(action) + + err := self.c.Git().Sync.FastForward( + task, branch.Name, branch.UpstreamRemote, branch.UpstreamBranch, + ) + _ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}}) + return err }) } diff --git a/pkg/gui/controllers/commit_message_controller.go b/pkg/gui/controllers/commit_message_controller.go index b72d5d45a..6f96cdd21 100644 --- a/pkg/gui/controllers/commit_message_controller.go +++ b/pkg/gui/controllers/commit_message_controller.go @@ -153,7 +153,7 @@ func (self *CommitMessageController) handleCommitIndexChange(value int) error { func (self *CommitMessageController) setCommitMessageAtIndex(index int) (bool, error) { commitMessage, err := self.c.Git().Commit.GetCommitMessageFromHistory(index) if err != nil { - if err == git_commands.ErrInvalidCommitIndex { + if errors.Is(err, git_commands.ErrInvalidCommitIndex) { return false, nil } return false, errors.New(self.c.Tr.CommitWithoutMessageErr) diff --git a/pkg/gui/controllers/custom_patch_options_menu_action.go b/pkg/gui/controllers/custom_patch_options_menu_action.go index 92b77f514..d83228793 100644 --- a/pkg/gui/controllers/custom_patch_options_menu_action.go +++ b/pkg/gui/controllers/custom_patch_options_menu_action.go @@ -189,9 +189,9 @@ func (self *CustomPatchOptionsMenuAction) handleMovePatchIntoWorkingTree() error }) return nil - } else { - return pull(false) } + + return pull(false) } func (self *CustomPatchOptionsMenuAction) handlePullPatchIntoNewCommit() error { diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index d10d4726a..ab5b6e277 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -18,7 +18,7 @@ import ( ) type FilesController struct { - baseController // nolint: unused + baseController *ListControllerTrait[*filetree.FileNode] c *ControllerCommon } @@ -901,11 +901,10 @@ func (self *FilesController) setStatusFiltering(filter filetree.FileTreeDisplayF // because the untracked files filter applies when running `git status`. if previousFilter != filter && (previousFilter == filetree.DisplayUntracked || filter == filetree.DisplayUntracked) { return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}, Mode: types.ASYNC}) - } else { - self.c.PostRefreshUpdate(self.context()) - - return nil } + + self.c.PostRefreshUpdate(self.context()) + return nil } func (self *FilesController) edit(nodes []*filetree.FileNode) error { diff --git a/pkg/gui/controllers/helpers/gpg_helper.go b/pkg/gui/controllers/helpers/gpg_helper.go index 65f226067..aabd6964a 100644 --- a/pkg/gui/controllers/helpers/gpg_helper.go +++ b/pkg/gui/controllers/helpers/gpg_helper.go @@ -37,9 +37,9 @@ func (self *GpgHelper) WithGpgHandling(cmdObj *oscommands.CmdObj, configKey git_ } return err - } else { - return self.runAndStream(cmdObj, waitingStatus, onSuccess, refreshScope) } + + return self.runAndStream(cmdObj, waitingStatus, onSuccess, refreshScope) } func (self *GpgHelper) runAndStream(cmdObj *oscommands.CmdObj, waitingStatus string, onSuccess func() error, refreshScope []types.RefreshableView) error { diff --git a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go index 079e2ab68..bd3cee7b7 100644 --- a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go +++ b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go @@ -162,9 +162,8 @@ func (self *MergeAndRebaseHelper) CheckMergeOrRebaseWithRefreshOptions(result er } else if strings.Contains(result.Error(), "No rebase in progress?") { // assume in this case that we're already done return nil - } else { - return self.CheckForConflicts(result) } + return self.CheckForConflicts(result) } func (self *MergeAndRebaseHelper) CheckMergeOrRebase(result error) error { diff --git a/pkg/gui/controllers/helpers/refs_helper.go b/pkg/gui/controllers/helpers/refs_helper.go index 8936a1d61..0222f575c 100644 --- a/pkg/gui/controllers/helpers/refs_helper.go +++ b/pkg/gui/controllers/helpers/refs_helper.go @@ -56,9 +56,9 @@ func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions withCheckoutStatus := func(f func(gocui.Task) error) error { if found { return self.c.WithInlineStatus(localBranch, types.ItemOperationCheckingOut, context.LOCAL_BRANCHES_CONTEXT_KEY, f) - } else { - return self.c.WithWaitingStatus(waitingStatus, f) } + + return self.c.WithWaitingStatus(waitingStatus, f) } return withCheckoutStatus(func(gocui.Task) error { @@ -563,7 +563,7 @@ func (self *RefsHelper) CanMoveCommitsToNewBranch() *types.DisabledReason { // SanitizedBranchName will remove all spaces in favor of a dash "-" to meet // git's branch naming requirement. func SanitizedBranchName(input string) string { - return strings.Replace(input, " ", "-", -1) + return strings.ReplaceAll(input, " ", "-") } // Checks if the given branch name is a remote branch, and returns the name of diff --git a/pkg/gui/controllers/helpers/window_arrangement_helper.go b/pkg/gui/controllers/helpers/window_arrangement_helper.go index 393b0ffb1..51c5cf37a 100644 --- a/pkg/gui/controllers/helpers/window_arrangement_helper.go +++ b/pkg/gui/controllers/helpers/window_arrangement_helper.go @@ -385,9 +385,8 @@ func splitMainPanelSideBySide(args WindowArrangementArgs) bool { default: if args.Width < 200 && args.Height > 30 { // 2 80 character width panels + 40 width for side panel return false - } else { - return true } + return true } } @@ -431,11 +430,11 @@ func sidePanelChildren(args WindowArrangementArgs) func(width int, height int) [ Window: window, Weight: 1, } - } else { - return &boxlayout.Box{ - Window: window, - Size: 0, - } + } + + return &boxlayout.Box{ + Window: window, + Size: 0, } } @@ -469,33 +468,33 @@ func sidePanelChildren(args WindowArrangementArgs) func(width int, height int) [ accordionBox(&boxlayout.Box{Window: "commits", Weight: 1}), accordionBox(getDefaultStashWindowBox(args)), } - } else { - squashedHeight := 1 - if height >= 21 { - squashedHeight = 3 - } + } - squashedSidePanelBox := func(window string) *boxlayout.Box { - if window == args.CurrentSideWindow { - return &boxlayout.Box{ - Window: window, - Weight: 1, - } - } else { - return &boxlayout.Box{ - Window: window, - Size: squashedHeight, - } + squashedHeight := 1 + if height >= 21 { + squashedHeight = 3 + } + + squashedSidePanelBox := func(window string) *boxlayout.Box { + if window == args.CurrentSideWindow { + return &boxlayout.Box{ + Window: window, + Weight: 1, } } - return []*boxlayout.Box{ - squashedSidePanelBox("status"), - squashedSidePanelBox("files"), - squashedSidePanelBox("branches"), - squashedSidePanelBox("commits"), - squashedSidePanelBox("stash"), + return &boxlayout.Box{ + Window: window, + Size: squashedHeight, } } + + return []*boxlayout.Box{ + squashedSidePanelBox("status"), + squashedSidePanelBox("files"), + squashedSidePanelBox("branches"), + squashedSidePanelBox("commits"), + squashedSidePanelBox("stash"), + } } } diff --git a/pkg/gui/controllers/helpers/working_tree_helper.go b/pkg/gui/controllers/helpers/working_tree_helper.go index 9bff3dbc7..1e8226363 100644 --- a/pkg/gui/controllers/helpers/working_tree_helper.go +++ b/pkg/gui/controllers/helpers/working_tree_helper.go @@ -245,7 +245,7 @@ func (self *WorkingTreeHelper) commitPrefixConfigsForRepo() []config.CommitPrefi cfg, ok := self.c.UserConfig().Git.CommitPrefixes[self.c.Git().RepoPaths.RepoName()] if ok { return append(cfg, self.c.UserConfig().Git.CommitPrefix...) - } else { - return self.c.UserConfig().Git.CommitPrefix } + + return self.c.UserConfig().Git.CommitPrefix } diff --git a/pkg/gui/controllers/helpers/worktree_helper.go b/pkg/gui/controllers/helpers/worktree_helper.go index 2d6460dcb..ac4e01cf6 100644 --- a/pkg/gui/controllers/helpers/worktree_helper.go +++ b/pkg/gui/controllers/helpers/worktree_helper.go @@ -132,24 +132,24 @@ func (self *WorktreeHelper) NewWorktreeCheckout(base string, canCheckoutBase boo }, }) - return nil - } else { - // prompt for the new branch name where a blank means we just check out the branch - self.c.Prompt(types.PromptOpts{ - Title: self.c.Tr.NewBranchName, - HandleConfirm: func(branchName string) error { - if branchName == "" { - return errors.New(self.c.Tr.BranchNameCannotBeBlank) - } - - opts.Branch = branchName - - return f() - }, - }) - return nil } + + // prompt for the new branch name where a blank means we just check out the branch + self.c.Prompt(types.PromptOpts{ + Title: self.c.Tr.NewBranchName, + HandleConfirm: func(branchName string) error { + if branchName == "" { + return errors.New(self.c.Tr.BranchNameCannotBeBlank) + } + + opts.Branch = branchName + + return f() + }, + }) + + return nil }, }) diff --git a/pkg/gui/controllers/list_controller.go b/pkg/gui/controllers/list_controller.go index 36ac1ba91..2fbadd2fe 100644 --- a/pkg/gui/controllers/list_controller.go +++ b/pkg/gui/controllers/list_controller.go @@ -109,10 +109,11 @@ func (self *ListController) handleLineChangeAux(f func(int), change int) error { // we're not constantly re-rendering the main view. cursorMoved := before != after if cursorMoved { - if change == -1 { + switch change { + case -1: checkScrollUp(self.context.GetViewTrait(), self.c.UserConfig(), self.context.ModelIndexToViewIndex(before), self.context.ModelIndexToViewIndex(after)) - } else if change == 1 { + case 1: checkScrollDown(self.context.GetViewTrait(), self.c.UserConfig(), self.context.ModelIndexToViewIndex(before), self.context.ModelIndexToViewIndex(after)) } diff --git a/pkg/gui/controllers/list_controller_trait.go b/pkg/gui/controllers/list_controller_trait.go index fa5fc1492..4f05a3d2a 100644 --- a/pkg/gui/controllers/list_controller_trait.go +++ b/pkg/gui/controllers/list_controller_trait.go @@ -87,7 +87,7 @@ func (self *ListControllerTrait[T]) itemRangeSelected(callbacks ...func([]T, int } } -func (self *ListControllerTrait[T]) itemsSelected(callbacks ...func([]T) *types.DisabledReason) func() *types.DisabledReason { //nolint:unused +func (self *ListControllerTrait[T]) itemsSelected(callbacks ...func([]T) *types.DisabledReason) func() *types.DisabledReason { return func() *types.DisabledReason { items, _, _ := self.getSelectedItems() if len(items) == 0 { diff --git a/pkg/gui/controllers/sync_controller.go b/pkg/gui/controllers/sync_controller.go index 66c480b93..c1c79fa35 100644 --- a/pkg/gui/controllers/sync_controller.go +++ b/pkg/gui/controllers/sync_controller.go @@ -92,27 +92,27 @@ func (self *SyncController) push(currentBranch *models.Branch) error { opts := pushOpts{remoteBranchStoredLocally: currentBranch.RemoteBranchStoredLocally()} if currentBranch.IsBehindForPush() { return self.requestToForcePush(currentBranch, opts) - } else { - return self.pushAux(currentBranch, opts) } - } else { - if self.c.Git().Config.GetPushToCurrent() { - return self.pushAux(currentBranch, pushOpts{setUpstream: true}) - } else { - return self.c.Helpers().Upstream.PromptForUpstreamWithInitialContent(currentBranch, func(upstream string) error { - upstreamRemote, upstreamBranch, err := self.c.Helpers().Upstream.ParseUpstream(upstream) - if err != nil { - return err - } - return self.pushAux(currentBranch, pushOpts{ - setUpstream: true, - upstreamRemote: upstreamRemote, - upstreamBranch: upstreamBranch, - }) - }) - } + return self.pushAux(currentBranch, opts) } + + if self.c.Git().Config.GetPushToCurrent() { + return self.pushAux(currentBranch, pushOpts{setUpstream: true}) + } + + return self.c.Helpers().Upstream.PromptForUpstreamWithInitialContent(currentBranch, func(upstream string) error { + upstreamRemote, upstreamBranch, err := self.c.Helpers().Upstream.ParseUpstream(upstream) + if err != nil { + return err + } + + return self.pushAux(currentBranch, pushOpts{ + setUpstream: true, + upstreamRemote: upstreamRemote, + upstreamBranch: upstreamBranch, + }) + }) } func (self *SyncController) pull(currentBranch *models.Branch) error { diff --git a/pkg/gui/controllers/workspace_reset_controller.go b/pkg/gui/controllers/workspace_reset_controller.go index 3a2abc0d3..7ecf79c78 100644 --- a/pkg/gui/controllers/workspace_reset_controller.go +++ b/pkg/gui/controllers/workspace_reset_controller.go @@ -180,7 +180,7 @@ func (self *FilesController) Explode(v *gocui.View, onDone func()) { self.c.OnWorker(func(_ gocui.Task) error { max := 25 - for i := 0; i < max; i++ { + for i := range max { image := getExplodeImage(width, height, i, max) style := styles[(i*len(styles)/max)%len(styles)] coloredImage := style.Sprint(image) @@ -229,8 +229,8 @@ func getExplodeImage(width int, height int, frame int, max int) string { innerRadius = (progress - 0.5) * 2 * maxRadius } - for y := 0; y < height; y++ { - for x := 0; x < width; x++ { + for y := range height { + for x := range width { // calculate distance from center, scale x by 2 to compensate for character aspect ratio distance := math.Hypot(float64(x-centerX), float64(y-centerY)*2) diff --git a/pkg/gui/filetree/file_tree_view_model.go b/pkg/gui/filetree/file_tree_view_model.go index 470c2ca1c..3db39d0a1 100644 --- a/pkg/gui/filetree/file_tree_view_model.go +++ b/pkg/gui/filetree/file_tree_view_model.go @@ -138,9 +138,8 @@ func (self *FileTreeViewModel) findNewSelectedIdx(prevNodes []*FileNode, currNod } if node.File != nil && node.File.IsRename() { return node.File.Names() - } else { - return []string{node.path} } + return []string{node.path} } for _, prevNode := range prevNodes { diff --git a/pkg/gui/global_handlers.go b/pkg/gui/global_handlers.go index 62f9311ea..9abadf4e0 100644 --- a/pkg/gui/global_handlers.go +++ b/pkg/gui/global_handlers.go @@ -185,7 +185,7 @@ func (gui *Gui) handleCopySelectedSideContextItemToClipboardWithTruncation(maxWi return err } - truncatedItemId := utils.TruncateWithEllipsis(strings.Replace(itemId, "\n", " ", -1), 50) + truncatedItemId := utils.TruncateWithEllipsis(strings.ReplaceAll(itemId, "\n", " "), 50) gui.c.Toast(fmt.Sprintf("'%s' %s", truncatedItemId, gui.c.Tr.CopiedToClipboard)) diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index ac1be6601..f2ea43156 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -2,6 +2,7 @@ package gui import ( goContext "context" + "errors" "fmt" "io" "os" @@ -586,8 +587,8 @@ func (gui *Gui) resetState(startArgs appTypes.StartArgs) types.Context { return initialContext(contextTree, startArgs) } -func (self *Gui) getViewBufferManagerForView(view *gocui.View) *tasks.ViewBufferManager { - manager, ok := self.viewBufferManagerMap[view.Name()] +func (gui *Gui) getViewBufferManagerForView(view *gocui.View) *tasks.ViewBufferManager { + manager, ok := gui.viewBufferManagerMap[view.Name()] if !ok { return nil } @@ -610,9 +611,9 @@ func initialScreenMode(startArgs appTypes.StartArgs, config config.AppConfigurer return parseScreenModeArg(startArgs.ScreenMode) } else if startArgs.FilterPath != "" || startArgs.GitArg != appTypes.GitArgNone { return types.SCREEN_HALF - } else { - return parseScreenModeArg(config.GetUserConfig().Gui.ScreenMode) } + + return parseScreenModeArg(config.GetUserConfig().Gui.ScreenMode) } func parseScreenModeArg(screenModeArg string) types.ScreenMode { @@ -872,8 +873,7 @@ func (gui *Gui) RunAndHandleError(startArgs appTypes.StartArgs) error { close(gui.stopChan) - switch err { - case gocui.ErrQuit: + if errors.Is(err, gocui.ErrQuit) { if gui.c.State().GetRetainOriginalDir() { if err := gui.helpers.RecordDirectory.RecordDirectory(gui.InitialDir); err != nil { return err @@ -885,10 +885,9 @@ func (gui *Gui) RunAndHandleError(startArgs appTypes.StartArgs) error { } return nil - - default: - return err } + + return err } return nil @@ -965,7 +964,7 @@ func (gui *Gui) runSubprocessWithSuspense(subprocess *oscommands.CmdObj) (bool, return true, nil } -func (gui *Gui) runSubprocess(cmdObj *oscommands.CmdObj) error { //nolint:unparam +func (gui *Gui) runSubprocess(cmdObj *oscommands.CmdObj) error { gui.LogCommand(cmdObj.ToString(), true) subprocess := cmdObj.GetCmd() diff --git a/pkg/gui/information_panel.go b/pkg/gui/information_panel.go index f94ed785a..ab2f3512d 100644 --- a/pkg/gui/information_panel.go +++ b/pkg/gui/information_panel.go @@ -17,9 +17,9 @@ func (gui *Gui) informationStr() string { donate := style.FgMagenta.Sprint(style.PrintHyperlink(gui.c.Tr.Donate, constants.Links.Donate)) askQuestion := style.FgYellow.Sprint(style.PrintHyperlink(gui.c.Tr.AskQuestion, constants.Links.Discussions)) return fmt.Sprintf("%s %s %s", donate, askQuestion, gui.Config.GetVersion()) - } else { - return gui.Config.GetVersion() } + + return gui.Config.GetVersion() } func (gui *Gui) handleInfoClick() error { diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 63d25b622..4b41ebe1d 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -45,27 +45,27 @@ func (gui *Gui) validateNotInFilterMode() bool { } // only to be called from the cheatsheet generate script. This mutates the Gui struct. -func (self *Gui) GetCheatsheetKeybindings() []*types.Binding { - self.g = &gocui.Gui{} - if err := self.createAllViews(); err != nil { +func (gui *Gui) GetCheatsheetKeybindings() []*types.Binding { + gui.g = &gocui.Gui{} + if err := gui.createAllViews(); err != nil { panic(err) } // need to instantiate views - self.helpers = helpers.NewStubHelpers() - self.State = &GuiRepoState{} - self.State.Contexts = self.contextTree() - self.State.ContextMgr = NewContextMgr(self, self.State.Contexts) - self.resetHelpersAndControllers() - bindings, _ := self.GetInitialKeybindings() + gui.helpers = helpers.NewStubHelpers() + gui.State = &GuiRepoState{} + gui.State.Contexts = gui.contextTree() + gui.State.ContextMgr = NewContextMgr(gui, gui.State.Contexts) + gui.resetHelpersAndControllers() + bindings, _ := gui.GetInitialKeybindings() return bindings } -func (self *Gui) keybindingOpts() types.KeybindingsOpts { - config := self.c.UserConfig().Keybinding +func (gui *Gui) keybindingOpts() types.KeybindingsOpts { + config := gui.c.UserConfig().Keybinding guards := types.KeybindingGuards{ - OutsideFilterMode: self.outsideFilterMode, - NoPopupPanel: self.noPopupPanel, + OutsideFilterMode: gui.outsideFilterMode, + NoPopupPanel: gui.noPopupPanel, } return types.KeybindingsOpts{ @@ -76,318 +76,318 @@ func (self *Gui) keybindingOpts() types.KeybindingsOpts { } // renaming receiver to 'self' to aid refactoring. Will probably end up moving all Gui handlers to this pattern eventually. -func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBinding) { - opts := self.c.KeybindingsOpts() +func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBinding) { + opts := gui.c.KeybindingsOpts() bindings := []*types.Binding{ { ViewName: "", Key: opts.GetKey(opts.Config.Universal.OpenRecentRepos), - Handler: opts.Guards.NoPopupPanel(self.helpers.Repos.CreateRecentReposMenu), - Description: self.c.Tr.SwitchRepo, + Handler: opts.Guards.NoPopupPanel(gui.helpers.Repos.CreateRecentReposMenu), + Description: gui.c.Tr.SwitchRepo, }, { ViewName: "", Key: opts.GetKey(opts.Config.Universal.ScrollUpMain), - Handler: self.scrollUpMain, + Handler: gui.scrollUpMain, Alternative: "fn+up/shift+k", - Description: self.c.Tr.ScrollUpMainWindow, + Description: gui.c.Tr.ScrollUpMainWindow, }, { ViewName: "", Key: opts.GetKey(opts.Config.Universal.ScrollDownMain), - Handler: self.scrollDownMain, + Handler: gui.scrollDownMain, Alternative: "fn+down/shift+j", - Description: self.c.Tr.ScrollDownMainWindow, + Description: gui.c.Tr.ScrollDownMainWindow, }, { ViewName: "", Key: opts.GetKey(opts.Config.Universal.ScrollUpMainAlt1), Modifier: gocui.ModNone, - Handler: self.scrollUpMain, + Handler: gui.scrollUpMain, }, { ViewName: "", Key: opts.GetKey(opts.Config.Universal.ScrollDownMainAlt1), Modifier: gocui.ModNone, - Handler: self.scrollDownMain, + Handler: gui.scrollDownMain, }, { ViewName: "", Key: opts.GetKey(opts.Config.Universal.ScrollUpMainAlt2), Modifier: gocui.ModNone, - Handler: self.scrollUpMain, + Handler: gui.scrollUpMain, }, { ViewName: "", Key: opts.GetKey(opts.Config.Universal.ScrollDownMainAlt2), Modifier: gocui.ModNone, - Handler: self.scrollDownMain, + Handler: gui.scrollDownMain, }, { ViewName: "files", Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), - Handler: self.handleCopySelectedSideContextItemToClipboard, - GetDisabledReason: self.getCopySelectedSideContextItemToClipboardDisabledReason, - Description: self.c.Tr.CopyPathToClipboard, + Handler: gui.handleCopySelectedSideContextItemToClipboard, + GetDisabledReason: gui.getCopySelectedSideContextItemToClipboardDisabledReason, + Description: gui.c.Tr.CopyPathToClipboard, }, { ViewName: "localBranches", Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), - Handler: self.handleCopySelectedSideContextItemToClipboard, - GetDisabledReason: self.getCopySelectedSideContextItemToClipboardDisabledReason, - Description: self.c.Tr.CopyBranchNameToClipboard, + Handler: gui.handleCopySelectedSideContextItemToClipboard, + GetDisabledReason: gui.getCopySelectedSideContextItemToClipboardDisabledReason, + Description: gui.c.Tr.CopyBranchNameToClipboard, }, { ViewName: "remoteBranches", Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), - Handler: self.handleCopySelectedSideContextItemToClipboard, - GetDisabledReason: self.getCopySelectedSideContextItemToClipboardDisabledReason, - Description: self.c.Tr.CopyBranchNameToClipboard, + Handler: gui.handleCopySelectedSideContextItemToClipboard, + GetDisabledReason: gui.getCopySelectedSideContextItemToClipboardDisabledReason, + Description: gui.c.Tr.CopyBranchNameToClipboard, }, { ViewName: "tags", Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), - Handler: self.handleCopySelectedSideContextItemToClipboard, - GetDisabledReason: self.getCopySelectedSideContextItemToClipboardDisabledReason, - Description: self.c.Tr.CopyTagToClipboard, + Handler: gui.handleCopySelectedSideContextItemToClipboard, + GetDisabledReason: gui.getCopySelectedSideContextItemToClipboardDisabledReason, + Description: gui.c.Tr.CopyTagToClipboard, }, { ViewName: "commits", Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), - Handler: self.handleCopySelectedSideContextItemCommitHashToClipboard, - GetDisabledReason: self.getCopySelectedSideContextItemToClipboardDisabledReason, - Description: self.c.Tr.CopyCommitHashToClipboard, + Handler: gui.handleCopySelectedSideContextItemCommitHashToClipboard, + GetDisabledReason: gui.getCopySelectedSideContextItemToClipboardDisabledReason, + Description: gui.c.Tr.CopyCommitHashToClipboard, }, { ViewName: "commits", Key: opts.GetKey(opts.Config.Commits.ResetCherryPick), - Handler: self.helpers.CherryPick.Reset, - Description: self.c.Tr.ResetCherryPick, + Handler: gui.helpers.CherryPick.Reset, + Description: gui.c.Tr.ResetCherryPick, }, { ViewName: "reflogCommits", Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), - Handler: self.handleCopySelectedSideContextItemToClipboard, - GetDisabledReason: self.getCopySelectedSideContextItemToClipboardDisabledReason, - Description: self.c.Tr.CopyCommitHashToClipboard, + Handler: gui.handleCopySelectedSideContextItemToClipboard, + GetDisabledReason: gui.getCopySelectedSideContextItemToClipboardDisabledReason, + Description: gui.c.Tr.CopyCommitHashToClipboard, }, { ViewName: "subCommits", Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), - Handler: self.handleCopySelectedSideContextItemCommitHashToClipboard, - GetDisabledReason: self.getCopySelectedSideContextItemToClipboardDisabledReason, - Description: self.c.Tr.CopyCommitHashToClipboard, + Handler: gui.handleCopySelectedSideContextItemCommitHashToClipboard, + GetDisabledReason: gui.getCopySelectedSideContextItemToClipboardDisabledReason, + Description: gui.c.Tr.CopyCommitHashToClipboard, }, { ViewName: "information", Key: gocui.MouseLeft, Modifier: gocui.ModNone, - Handler: self.handleInfoClick, + Handler: gui.handleInfoClick, }, { ViewName: "commitFiles", Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), - Handler: self.handleCopySelectedSideContextItemToClipboard, - GetDisabledReason: self.getCopySelectedSideContextItemToClipboardDisabledReason, - Description: self.c.Tr.CopyPathToClipboard, + Handler: gui.handleCopySelectedSideContextItemToClipboard, + GetDisabledReason: gui.getCopySelectedSideContextItemToClipboardDisabledReason, + Description: gui.c.Tr.CopyPathToClipboard, }, { ViewName: "", Key: opts.GetKey(opts.Config.Universal.ExtrasMenu), - Handler: opts.Guards.NoPopupPanel(self.handleCreateExtrasMenuPanel), - Description: self.c.Tr.OpenCommandLogMenu, - Tooltip: self.c.Tr.OpenCommandLogMenuTooltip, + Handler: opts.Guards.NoPopupPanel(gui.handleCreateExtrasMenuPanel), + Description: gui.c.Tr.OpenCommandLogMenu, + Tooltip: gui.c.Tr.OpenCommandLogMenuTooltip, OpensMenu: true, }, { ViewName: "main", Key: gocui.MouseWheelDown, - Handler: self.scrollDownMain, - Description: self.c.Tr.ScrollDown, + Handler: gui.scrollDownMain, + Description: gui.c.Tr.ScrollDown, Alternative: "fn+up", }, { ViewName: "main", Key: gocui.MouseWheelUp, - Handler: self.scrollUpMain, - Description: self.c.Tr.ScrollUp, + Handler: gui.scrollUpMain, + Description: gui.c.Tr.ScrollUp, Alternative: "fn+down", }, { ViewName: "secondary", Key: gocui.MouseWheelDown, Modifier: gocui.ModNone, - Handler: self.scrollDownSecondary, + Handler: gui.scrollDownSecondary, }, { ViewName: "secondary", Key: gocui.MouseWheelUp, Modifier: gocui.ModNone, - Handler: self.scrollUpSecondary, + Handler: gui.scrollUpSecondary, }, { ViewName: "confirmation", Key: opts.GetKey(opts.Config.Universal.PrevItem), Modifier: gocui.ModNone, - Handler: self.scrollUpConfirmationPanel, + Handler: gui.scrollUpConfirmationPanel, }, { ViewName: "confirmation", Key: opts.GetKey(opts.Config.Universal.NextItem), Modifier: gocui.ModNone, - Handler: self.scrollDownConfirmationPanel, + Handler: gui.scrollDownConfirmationPanel, }, { ViewName: "confirmation", Key: opts.GetKey(opts.Config.Universal.PrevItemAlt), Modifier: gocui.ModNone, - Handler: self.scrollUpConfirmationPanel, + Handler: gui.scrollUpConfirmationPanel, }, { ViewName: "confirmation", Key: opts.GetKey(opts.Config.Universal.NextItemAlt), Modifier: gocui.ModNone, - Handler: self.scrollDownConfirmationPanel, + Handler: gui.scrollDownConfirmationPanel, }, { ViewName: "confirmation", Key: gocui.MouseWheelUp, - Handler: self.scrollUpConfirmationPanel, + Handler: gui.scrollUpConfirmationPanel, }, { ViewName: "confirmation", Key: gocui.MouseWheelDown, - Handler: self.scrollDownConfirmationPanel, + Handler: gui.scrollDownConfirmationPanel, }, { ViewName: "confirmation", Key: opts.GetKey(opts.Config.Universal.NextPage), Modifier: gocui.ModNone, - Handler: self.pageDownConfirmationPanel, + Handler: gui.pageDownConfirmationPanel, }, { ViewName: "confirmation", Key: opts.GetKey(opts.Config.Universal.PrevPage), Modifier: gocui.ModNone, - Handler: self.pageUpConfirmationPanel, + Handler: gui.pageUpConfirmationPanel, }, { ViewName: "confirmation", Key: opts.GetKey(opts.Config.Universal.GotoTop), Modifier: gocui.ModNone, - Handler: self.goToConfirmationPanelTop, + Handler: gui.goToConfirmationPanelTop, }, { ViewName: "confirmation", Key: opts.GetKey(opts.Config.Universal.GotoTopAlt), Modifier: gocui.ModNone, - Handler: self.goToConfirmationPanelTop, + Handler: gui.goToConfirmationPanelTop, }, { ViewName: "confirmation", Key: opts.GetKey(opts.Config.Universal.GotoBottom), Modifier: gocui.ModNone, - Handler: self.goToConfirmationPanelBottom, + Handler: gui.goToConfirmationPanelBottom, }, { ViewName: "confirmation", Key: opts.GetKey(opts.Config.Universal.GotoBottomAlt), Modifier: gocui.ModNone, - Handler: self.goToConfirmationPanelBottom, + Handler: gui.goToConfirmationPanelBottom, }, { ViewName: "submodules", Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), - Handler: self.handleCopySelectedSideContextItemToClipboard, - GetDisabledReason: self.getCopySelectedSideContextItemToClipboardDisabledReason, - Description: self.c.Tr.CopySubmoduleNameToClipboard, + Handler: gui.handleCopySelectedSideContextItemToClipboard, + GetDisabledReason: gui.getCopySelectedSideContextItemToClipboardDisabledReason, + Description: gui.c.Tr.CopySubmoduleNameToClipboard, }, { ViewName: "extras", Key: gocui.MouseWheelUp, - Handler: self.scrollUpExtra, + Handler: gui.scrollUpExtra, }, { ViewName: "extras", Key: gocui.MouseWheelDown, - Handler: self.scrollDownExtra, + Handler: gui.scrollDownExtra, }, { ViewName: "extras", Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItemAlt), Modifier: gocui.ModNone, - Handler: self.scrollUpExtra, + Handler: gui.scrollUpExtra, }, { ViewName: "extras", Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItem), Modifier: gocui.ModNone, - Handler: self.scrollUpExtra, + Handler: gui.scrollUpExtra, }, { ViewName: "extras", Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItem), Modifier: gocui.ModNone, - Handler: self.scrollDownExtra, + Handler: gui.scrollDownExtra, }, { ViewName: "extras", Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItemAlt), Modifier: gocui.ModNone, - Handler: self.scrollDownExtra, + Handler: gui.scrollDownExtra, }, { ViewName: "extras", Key: opts.GetKey(opts.Config.Universal.NextPage), Modifier: gocui.ModNone, - Handler: self.pageDownExtrasPanel, + Handler: gui.pageDownExtrasPanel, }, { ViewName: "extras", Key: opts.GetKey(opts.Config.Universal.PrevPage), Modifier: gocui.ModNone, - Handler: self.pageUpExtrasPanel, + Handler: gui.pageUpExtrasPanel, }, { ViewName: "extras", Key: opts.GetKey(opts.Config.Universal.GotoTop), Modifier: gocui.ModNone, - Handler: self.goToExtrasPanelTop, + Handler: gui.goToExtrasPanelTop, }, { ViewName: "extras", Key: opts.GetKey(opts.Config.Universal.GotoTopAlt), Modifier: gocui.ModNone, - Handler: self.goToExtrasPanelTop, + Handler: gui.goToExtrasPanelTop, }, { ViewName: "extras", Key: opts.GetKey(opts.Config.Universal.GotoBottom), Modifier: gocui.ModNone, - Handler: self.goToExtrasPanelBottom, + Handler: gui.goToExtrasPanelBottom, }, { ViewName: "extras", Key: opts.GetKey(opts.Config.Universal.GotoBottomAlt), Modifier: gocui.ModNone, - Handler: self.goToExtrasPanelBottom, + Handler: gui.goToExtrasPanelBottom, }, { ViewName: "extras", Tag: "navigation", Key: gocui.MouseLeft, Modifier: gocui.ModNone, - Handler: self.handleFocusCommandLog, + Handler: gui.handleFocusCommandLog, }, } mouseKeybindings := []*gocui.ViewMouseBinding{} - for _, c := range self.State.Contexts.Flatten() { + for _, c := range gui.State.Contexts.Flatten() { viewName := c.GetViewName() for _, binding := range c.GetKeybindings(opts) { // TODO: move all mouse keybindings into the mouse keybindings approach below @@ -402,15 +402,15 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi { ViewName: "", Key: opts.GetKey(opts.Config.Universal.NextTab), - Handler: opts.Guards.NoPopupPanel(self.handleNextTab), - Description: self.c.Tr.NextTab, + Handler: opts.Guards.NoPopupPanel(gui.handleNextTab), + Description: gui.c.Tr.NextTab, Tag: "navigation", }, { ViewName: "", Key: opts.GetKey(opts.Config.Universal.PrevTab), - Handler: opts.Guards.NoPopupPanel(self.handlePrevTab), - Description: self.c.Tr.PrevTab, + Handler: opts.Guards.NoPopupPanel(gui.handlePrevTab), + Description: gui.c.Tr.PrevTab, Tag: "navigation", }, }...) @@ -418,12 +418,12 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi return bindings, mouseKeybindings } -func (self *Gui) GetInitialKeybindingsWithCustomCommands() ([]*types.Binding, []*gocui.ViewMouseBinding) { +func (gui *Gui) GetInitialKeybindingsWithCustomCommands() ([]*types.Binding, []*gocui.ViewMouseBinding) { // if the search or filter prompt is open, we only want the keybindings for // that context. It shouldn't be possible, for example, to open a menu while // the prompt is showing; you first need to confirm or cancel the search/filter. - if currentContext := self.State.ContextMgr.Current(); currentContext.GetKey() == context.SEARCH_CONTEXT_KEY { - bindings := currentContext.GetKeybindings(self.c.KeybindingsOpts()) + if currentContext := gui.State.ContextMgr.Current(); currentContext.GetKey() == context.SEARCH_CONTEXT_KEY { + bindings := currentContext.GetKeybindings(gui.c.KeybindingsOpts()) viewName := currentContext.GetViewName() for _, binding := range bindings { binding.ViewName = viewName @@ -431,8 +431,8 @@ func (self *Gui) GetInitialKeybindingsWithCustomCommands() ([]*types.Binding, [] return bindings, nil } - bindings, mouseBindings := self.GetInitialKeybindings() - customBindings, err := self.CustomCommandsClient.GetCustomCommandKeybindings() + bindings, mouseBindings := gui.GetInitialKeybindings() + customBindings, err := gui.CustomCommandsClient.GetCustomCommandKeybindings() if err != nil { log.Fatal(err) } diff --git a/pkg/gui/keybindings/keybindings.go b/pkg/gui/keybindings/keybindings.go index 923a30c3b..0db3e8a61 100644 --- a/pkg/gui/keybindings/keybindings.go +++ b/pkg/gui/keybindings/keybindings.go @@ -41,9 +41,8 @@ func GetKey(key string) types.Key { binding, ok := config.KeyByLabel[strings.ToLower(key)] if !ok { log.Fatalf("Unrecognized key %s for keybinding. For permitted values see %s", strings.ToLower(key), constants.Links.Docs.CustomKeybindings) - } else { - return binding } + return binding } else if runeCount == 1 { return []rune(key)[0] } diff --git a/pkg/gui/mergeconflicts/merge_conflict.go b/pkg/gui/mergeconflicts/merge_conflict.go index e6b617f57..9b9b72f55 100644 --- a/pkg/gui/mergeconflicts/merge_conflict.go +++ b/pkg/gui/mergeconflicts/merge_conflict.go @@ -50,9 +50,8 @@ func (s Selection) bounds(c *mergeConflict) (int, int) { case TOP: if c.hasAncestor() { return c.start, c.ancestor - } else { - return c.start, c.target } + return c.start, c.target case MIDDLE: return c.ancestor, c.target case BOTTOM: @@ -72,7 +71,6 @@ func (s Selection) selected(c *mergeConflict, idx int) bool { func availableSelections(c *mergeConflict) []Selection { if c.hasAncestor() { return []Selection{TOP, MIDDLE, BOTTOM} - } else { - return []Selection{TOP, BOTTOM} } + return []Selection{TOP, BOTTOM} } diff --git a/pkg/gui/patch_exploring/focus.go b/pkg/gui/patch_exploring/focus.go index c2b43c4a3..3548f09d4 100644 --- a/pkg/gui/patch_exploring/focus.go +++ b/pkg/gui/patch_exploring/focus.go @@ -25,9 +25,8 @@ func calculateNewOriginWithNeededAndWantedIdx(currentOrigin int, bufferHeight in requiredChange := wantToSeeIdx - bottom allowedChange := needToSeeIdx - origin return origin + min(requiredChange, allowedChange) - } else { - return origin } + return origin } func getNeedAndWantLineIdx(firstLineIdx int, lastLineIdx int, selectedLineIdx int, mode selectMode) (int, int) { @@ -37,9 +36,8 @@ func getNeedAndWantLineIdx(firstLineIdx int, lastLineIdx int, selectedLineIdx in case RANGE: if selectedLineIdx == firstLineIdx { return firstLineIdx, lastLineIdx - } else { - return lastLineIdx, firstLineIdx } + return lastLineIdx, firstLineIdx case HUNK: return firstLineIdx, lastLineIdx default: diff --git a/pkg/gui/patch_exploring/state.go b/pkg/gui/patch_exploring/state.go index 73ce0a756..53e120849 100644 --- a/pkg/gui/patch_exploring/state.go +++ b/pkg/gui/patch_exploring/state.go @@ -267,9 +267,8 @@ func (s *State) SelectedViewRange() (int, int) { case RANGE: if s.rangeStartLineIdx > s.selectedLineIdx { return s.selectedLineIdx, s.rangeStartLineIdx - } else { - return s.rangeStartLineIdx, s.selectedLineIdx } + return s.rangeStartLineIdx, s.selectedLineIdx case LINE: return s.selectedLineIdx, s.selectedLineIdx default: diff --git a/pkg/gui/presentation/commits.go b/pkg/gui/presentation/commits.go index 63c2b3c9b..a5799bcb3 100644 --- a/pkg/gui/presentation/commits.go +++ b/pkg/gui/presentation/commits.go @@ -145,9 +145,8 @@ func GetCommitListDisplayStrings( getGraphLine = func(idx int) string { if idx >= graphOffset { return graphLines[idx-graphOffset] - } else { - return "" } + return "" } } } else { @@ -305,9 +304,8 @@ func getBisectStatus(index int, commitHash string, bisectInfo *git_commands.Bise } else { if bisectBounds != nil && index >= bisectBounds.newIndex && index <= bisectBounds.oldIndex { return BisectStatusCandidate - } else { - return BisectStatusNone } + return BisectStatusNone } // should never land here diff --git a/pkg/gui/presentation/files.go b/pkg/gui/presentation/files.go index 64296aa8c..cc0a93889 100644 --- a/pkg/gui/presentation/files.go +++ b/pkg/gui/presentation/files.go @@ -63,9 +63,8 @@ func commitFilePatchStatus(node *filetree.Node[models.CommitFile], tree *filetre return patchBuilder.GetFileStatus(file.Path, tree.GetRef().RefName()) == patch.UNSELECTED }) { return patch.UNSELECTED - } else { - return patch.PART } + return patch.PART } func renderAux[T any]( @@ -185,9 +184,10 @@ func getFileLine( func formatFileStatus(file *models.File, restColor style.TextStyle) string { firstChar := file.ShortStatus[0:1] firstCharCl := style.FgGreen - if firstChar == "?" { + switch firstChar { + case "?": firstCharCl = theme.UnstagedChangesColor - } else if firstChar == " " { + case " ": firstCharCl = restColor } diff --git a/pkg/gui/presentation/graph/cell.go b/pkg/gui/presentation/graph/cell.go index a890613f0..be039a018 100644 --- a/pkg/gui/presentation/graph/cell.go +++ b/pkg/gui/presentation/graph/cell.go @@ -177,7 +177,7 @@ func getBoxDrawingChars(up, down, left, right bool) (string, string) { return "╶", "─" } else if !up && !down && !left && !right { return " ", " " - } else { - panic("should not be possible") } + + panic("should not be possible") } diff --git a/pkg/gui/presentation/graph/graph.go b/pkg/gui/presentation/graph/graph.go index 4e204c03f..1639a62e6 100644 --- a/pkg/gui/presentation/graph/graph.go +++ b/pkg/gui/presentation/graph/graph.go @@ -79,7 +79,7 @@ func RenderAux(pipeSets [][]Pipe, commits []*models.Commit, selectedCommitHashPt wg := sync.WaitGroup{} wg.Add(maxProcs) - for i := 0; i < maxProcs; i++ { + for i := range maxProcs { go func() { from := i * perProc to := (i + 1) * perProc @@ -246,9 +246,8 @@ func getNextPipes(prevPipes []Pipe, commit *models.Commit, getStyle func(c *mode for i := pipe.toPos; i > pos; i-- { if takenSpots.Includes(int(i)) || traversedSpots.Includes(int(i)) { break - } else { - last = i } + last = i } newPipes = append(newPipes, Pipe{ fromPos: pipe.toPos, diff --git a/pkg/gui/presentation/graph/graph_test.go b/pkg/gui/presentation/graph/graph_test.go index 13709267e..e567ec674 100644 --- a/pkg/gui/presentation/graph/graph_test.go +++ b/pkg/gui/presentation/graph/graph_test.go @@ -579,7 +579,7 @@ func generateCommits(hashPool *utils.StringPool, count int) []*models.Commit { parentCount := rnd.Intn(2) + 1 parentHashes := currentCommit.Parents() - for j := 0; j < parentCount; j++ { + for j := range parentCount { reuseParent := rnd.Intn(6) != 1 && j <= len(pool)-1 && j != 0 var newParent *models.Commit if reuseParent { diff --git a/pkg/integration/clients/tui.go b/pkg/integration/clients/tui.go index f93644597..992f107e8 100644 --- a/pkg/integration/clients/tui.go +++ b/pkg/integration/clients/tui.go @@ -214,12 +214,10 @@ func RunTUI(raceDetector bool) { err = g.MainLoop() g.Close() - switch err { - case gocui.ErrQuit: + if errors.Is(err, gocui.ErrQuit) { return - default: - log.Panicln(err) } + log.Panicln(err) } type app struct { diff --git a/pkg/integration/components/commit_description_panel_driver.go b/pkg/integration/components/commit_description_panel_driver.go index 0aa200757..6bde2cd29 100644 --- a/pkg/integration/components/commit_description_panel_driver.go +++ b/pkg/integration/components/commit_description_panel_driver.go @@ -33,7 +33,7 @@ func (self *CommitDescriptionPanelDriver) AddNewline() *CommitDescriptionPanelDr func (self *CommitDescriptionPanelDriver) GoToBeginning() *CommitDescriptionPanelDriver { numLines := len(self.getViewDriver().getView().BufferLines()) - for i := 0; i < numLines; i++ { + for range numLines { self.t.pressFast("") } diff --git a/pkg/integration/components/runner.go b/pkg/integration/components/runner.go index f123182cf..f32fde618 100644 --- a/pkg/integration/components/runner.go +++ b/pkg/integration/components/runner.go @@ -48,12 +48,12 @@ func RunTests(args RunTestArgs) error { } for _, test := range args.Tests { - args.TestWrapper(test, func() error { //nolint: thelper + args.TestWrapper(test, func() error { paths := NewPaths( filepath.Join(testDir, test.Name()), ) - for i := 0; i < args.MaxAttempts; i++ { + for i := range args.MaxAttempts { err := runTest(test, args, paths, projectRootDir, gitVersion) if err != nil { if i == args.MaxAttempts-1 { diff --git a/pkg/integration/components/shell.go b/pkg/integration/components/shell.go index 4a66fc9e3..6b711e5a8 100644 --- a/pkg/integration/components/shell.go +++ b/pkg/integration/components/shell.go @@ -257,7 +257,7 @@ func (self *Shell) CreateNCommitsStartingAt(n, startIndex int) *Shell { // Only to be used in demos, because the list might change and we don't want // tests to break when it does. func (self *Shell) CreateNCommitsWithRandomMessages(n int) *Shell { - for i := 0; i < n; i++ { + for i := range n { file := RandomFiles[i] self.CreateFileAndAdd( file.Name, @@ -286,7 +286,7 @@ func (self *Shell) CreateRepoHistory() *Shell { totalCommits := 0 // Generate commits - for i := 0; i < numInitialCommits; i++ { + for i := range numInitialCommits { author := authors[i%numAuthors] commitMessage := RandomCommitMessages[totalCommits%len(RandomCommitMessages)] @@ -296,7 +296,7 @@ func (self *Shell) CreateRepoHistory() *Shell { } // Generate branches and merges - for i := 0; i < numBranches; i++ { + for i := range numBranches { // We'll have one author creating all the commits in the branch author := authors[i%numAuthors] branchName := RandomBranchNames[i%len(RandomBranchNames)] @@ -309,7 +309,7 @@ func (self *Shell) CreateRepoHistory() *Shell { self.NewBranchFrom(branchName, fmt.Sprintf("master~%d", commitOffset)) numCommitsInBranch := rand.Intn(maxCommitsPerBranch) + 1 - for j := 0; j < numCommitsInBranch; j++ { + for range numCommitsInBranch { commitMessage := RandomCommitMessages[totalCommits%len(RandomCommitMessages)] self.SetAuthor(author, "") diff --git a/pkg/integration/components/view_driver.go b/pkg/integration/components/view_driver.go index 44707289c..ea005d371 100644 --- a/pkg/integration/components/view_driver.go +++ b/pkg/integration/components/view_driver.go @@ -44,7 +44,7 @@ func (self *ViewDriver) Clear() *ViewDriver { // clearing multiple times in case there's multiple lines // (the clear button only clears a single line at a time) maxAttempts := 100 - for i := 0; i < maxAttempts+1; i++ { + for i := range maxAttempts + 1 { if self.getView().Buffer() == "" { break } @@ -104,7 +104,7 @@ func (self *ViewDriver) ContainsLines(matchers ...*TextMatcher) *ViewDriver { startIdx, endIdx := self.getSelectedRange() - for i := 0; i < len(lines)-len(matchers)+1; i++ { + for i := range len(lines) - len(matchers) + 1 { matches := true for j, matcher := range matchers { checkIsSelected, matcher := matcher.checkIsSelected() // strip the IsSelected matcher out @@ -375,11 +375,11 @@ func (self *ViewDriver) Focus() *ViewDriver { currentViewName := self.t.gui.CurrentContext().GetViewName() currentViewTabIndex := lo.IndexOf(window.viewNames, currentViewName) if tabIndex > currentViewTabIndex { - for i := 0; i < tabIndex-currentViewTabIndex; i++ { + for range tabIndex - currentViewTabIndex { self.t.press(self.t.keys.Universal.NextTab) } } else if tabIndex < currentViewTabIndex { - for i := 0; i < currentViewTabIndex-tabIndex; i++ { + for range currentViewTabIndex - tabIndex { self.t.press(self.t.keys.Universal.PrevTab) } } @@ -534,7 +534,7 @@ func (self *ViewDriver) NavigateToLine(matcher *TextMatcher) *ViewDriver { keyPress = func() { self.SelectPreviousItem() } } - for i := 0; i < maxNumKeyPresses; i++ { + for range maxNumKeyPresses { keyPress() idx := self.getSelectedLineIdx() // It is important to use view.BufferLines() here and not lines, because it diff --git a/pkg/integration/tests/filter_by_author/shared.go b/pkg/integration/tests/filter_by_author/shared.go index 160bde1c0..22d08ad5c 100644 --- a/pkg/integration/tests/filter_by_author/shared.go +++ b/pkg/integration/tests/filter_by_author/shared.go @@ -18,7 +18,7 @@ func commonSetup(shell *Shell) { repoStartDaysAgo := 100 for _, authorInfo := range authors { - for i := 0; i < authorInfo.numberOfCommits; i++ { + for i := range authorInfo.numberOfCommits { authorEmail := strings.ToLower(strings.ReplaceAll(authorInfo.name, " ", ".")) + "@email.com" commitMessage := fmt.Sprintf("commit %d", i) diff --git a/pkg/jsonschema/generate.go b/pkg/jsonschema/generate.go index d8514e3b6..5350ca46c 100644 --- a/pkg/jsonschema/generate.go +++ b/pkg/jsonschema/generate.go @@ -114,7 +114,7 @@ func setDefaultVals(rootSchema, schema *jsonschema.Schema, defaults any) { return } - for i := 0; i < t.NumField(); i++ { + for i := range t.NumField() { value := v.Field(i).Interface() parentKey := t.Field(i).Name @@ -152,7 +152,7 @@ func isZeroValue(v any) bool { case reflect.Ptr, reflect.Interface: return rv.IsNil() case reflect.Struct: - for i := 0; i < rv.NumField(); i++ { + for i := range rv.NumField() { if !isZeroValue(rv.Field(i).Interface()) { return false } diff --git a/pkg/snake/snake.go b/pkg/snake/snake.go index 68feec15c..62fc0ddfd 100644 --- a/pkg/snake/snake.go +++ b/pkg/snake/snake.go @@ -129,7 +129,7 @@ func (self *Game) newFoodPos(snakePositions []Position) Position { // arbitrarily setting a limit of attempts to place food attemptLimit := 1000 - for i := 0; i < attemptLimit; i++ { + for range attemptLimit { newFoodPos := Position{self.randIntFn(self.width), self.randIntFn(self.height)} if !lo.Contains(snakePositions, newFoodPos) { @@ -183,7 +183,7 @@ func (self *Game) getCells(state State) [][]CellType { cells[pos.y][pos.x] = value } - for i := 0; i < self.height; i++ { + for i := range self.height { cells[i] = make([]CellType, self.width) } diff --git a/pkg/tasks/tasks.go b/pkg/tasks/tasks.go index bc56c5110..5de7fb232 100644 --- a/pkg/tasks/tasks.go +++ b/pkg/tasks/tasks.go @@ -75,8 +75,8 @@ type LinesToRead struct { Then func() } -func (m *ViewBufferManager) GetTaskKey() string { - return m.taskKey +func (self *ViewBufferManager) GetTaskKey() string { + return self.taskKey } func NewViewBufferManager( @@ -260,7 +260,7 @@ func (self *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), p callThen() break outer case line, ok = <-lineChan: - break + // process line below } loadingMutex.Lock() diff --git a/pkg/tasks/tasks_test.go b/pkg/tasks/tasks_test.go index 72da6d83c..c7a499d46 100644 --- a/pkg/tasks/tasks_test.go +++ b/pkg/tasks/tasks_test.go @@ -167,7 +167,7 @@ func (d *BlankLineReader) Read(p []byte) (n int, err error) { return 0, io.EOF } - d.linesYielded += 1 + d.linesYielded++ p[0] = '\n' return 1, nil } diff --git a/pkg/utils/formatting.go b/pkg/utils/formatting.go index b13a2ffa8..0e5a6ee03 100644 --- a/pkg/utils/formatting.go +++ b/pkg/utils/formatting.go @@ -25,7 +25,7 @@ type ColumnConfig struct { func StringWidth(s string) int { // We are intentionally not using a range loop here, because that would // convert the characters to runes, which is unnecessary work in this case. - for i := 0; i < len(s); i++ { + for i := range len(s) { if s[i] > unicode.MaxASCII { return runewidth.StringWidth(s) } @@ -44,9 +44,8 @@ func WithPadding(str string, padding int, alignment Alignment) string { space := strings.Repeat(" ", padding-width) if alignment == AlignLeft { return str + space - } else { - return space + str } + return space + str } // defaults to left-aligning each column. If you want to set the alignment of @@ -187,9 +186,8 @@ func TruncateWithEllipsis(str string, limit int) string { func SafeTruncate(str string, limit int) string { if len(str) > limit { return str[0:limit] - } else { - return str } + return str } const COMMIT_HASH_SHORT_SIZE = 8 diff --git a/pkg/utils/lines.go b/pkg/utils/lines.go index c601bb806..576f48371 100644 --- a/pkg/utils/lines.go +++ b/pkg/utils/lines.go @@ -11,7 +11,7 @@ import ( // currently we are also stripping \r's which may have adverse effects for // windows users (but no issues have been raised yet) func SplitLines(multilineString string) []string { - multilineString = strings.Replace(multilineString, "\r", "", -1) + multilineString = strings.ReplaceAll(multilineString, "\r", "") if multilineString == "" || multilineString == "\n" { return make([]string, 0) } @@ -32,8 +32,8 @@ func SplitNul(str string) []string { // 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) + str = strings.ReplaceAll(str, "\r\n", "\n") + str = strings.ReplaceAll(str, "\r", "") return str } diff --git a/pkg/utils/once_writer_test.go b/pkg/utils/once_writer_test.go index 47f64bb61..aa57ff163 100644 --- a/pkg/utils/once_writer_test.go +++ b/pkg/utils/once_writer_test.go @@ -9,7 +9,7 @@ func TestOnceWriter(t *testing.T) { innerWriter := bytes.NewBuffer(nil) counter := 0 onceWriter := NewOnceWriter(innerWriter, func() { - counter += 1 + counter++ }) _, _ = onceWriter.Write([]byte("hello")) _, _ = onceWriter.Write([]byte("hello")) diff --git a/pkg/utils/search.go b/pkg/utils/search.go index 4ec26bc22..c96cda4ab 100644 --- a/pkg/utils/search.go +++ b/pkg/utils/search.go @@ -41,7 +41,7 @@ func FindSubstringsFrom(pattern string, data fuzzy.Source) fuzzy.Matches { result := fuzzy.Matches{} outer: - for i := 0; i < data.Len(); i++ { + for i := range data.Len() { s := data.String(i) for _, sub := range substrings { if !CaseAwareContains(s, sub) { diff --git a/pkg/utils/thread_safe_map_test.go b/pkg/utils/thread_safe_map_test.go index 9676cfe5f..768aa392c 100644 --- a/pkg/utils/thread_safe_map_test.go +++ b/pkg/utils/thread_safe_map_test.go @@ -48,12 +48,12 @@ func TestThreadSafeMapConcurrentReadWrite(t *testing.T) { m := NewThreadSafeMap[int, int]() go func() { - for i := 0; i < 10000; i++ { + for range 10000 { m.Set(0, 0) } }() - for i := 0; i < 10000; i++ { + for range 10000 { m.Get(0) } } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 5eecc6e70..950555512 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -45,9 +45,8 @@ func ModuloWithWrap(n, max int) int { return n % max } else if n < 0 { return max + n - } else { - return n } + return n } func FindStringSubmatch(str string, regexpStr string) (bool, []string) { diff --git a/pkg/utils/yaml_utils/yaml_utils.go b/pkg/utils/yaml_utils/yaml_utils.go index 432915f5e..f8f7f0679 100644 --- a/pkg/utils/yaml_utils/yaml_utils.go +++ b/pkg/utils/yaml_utils/yaml_utils.go @@ -139,7 +139,7 @@ func walk(node *yaml.Node, path string, callback func(*yaml.Node, string)) error } } case yaml.SequenceNode: - for i := 0; i < len(node.Content); i++ { + for i := range len(node.Content) { childPath := fmt.Sprintf("%s[%d]", path, i) err := walk(node.Content[i], childPath, callback) if err != nil { diff --git a/pkg/utils/yaml_utils/yaml_utils_test.go b/pkg/utils/yaml_utils/yaml_utils_test.go index 9ae099396..d4d1fe074 100644 --- a/pkg/utils/yaml_utils/yaml_utils_test.go +++ b/pkg/utils/yaml_utils/yaml_utils_test.go @@ -224,12 +224,10 @@ func TestTransformNode(t *testing.T) { } else if node.ShortTag() == "!!str" { // We have already transformed it, return nil - } else { - return fmt.Errorf("Node was of bad type") } - } else { - return fmt.Errorf("Node was not a scalar") + return fmt.Errorf("Node was of bad type") } + return fmt.Errorf("Node was not a scalar") } tests := []struct { diff --git a/scripts/lint.sh b/scripts/lint.sh new file mode 100755 index 000000000..98d697bc1 --- /dev/null +++ b/scripts/lint.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +set -e + +if [ ! -x ./.bin/golangci-lint ]; then + echo 'You need to install golangci-lint into .bin' + echo 'One way to do this is to run' + echo ' GOBIN=$(pwd)/.bin go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.2.1' + exit 1 +fi + +./.bin/golangci-lint run