Compare commits

...
Author SHA1 Message Date
Jesse Duffield daf1fd3419 Update README.md (#4305)
- **PR Description**

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [ ] Docs have been updated if necessary
* [ ] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-02-22 08:35:24 +11:00
Jesse Duffield 54d0ebeff0 Update README.md 2025-02-22 08:34:35 +11:00
Jesse Duffield af9699e59a Add --include-untracked flag to stash show command (#3932)
- **PR Description**

This PR fixes #3931 by adding `--include-untracked` to `git stash show`
command. Untracked stashed file diff is now shown in the main view.

![before this
PR](https://github.com/user-attachments/assets/81097c71-3764-4467-a960-a87c51921139)
*Before: the untracked stashed file is not shown in lazygit*.

![after this
PR](https://github.com/user-attachments/assets/4aafd5f6-5305-4f9b-9068-1570d22e755c)
*After: the untracked stashed file diff is shown in lazygit*.

## One Issue

This PR does not fix the fact that untracked stashed files are not shown
in the list of files in the "Stash" panel when entering a stash entry, I
could not find an easy way to make them appear there.

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2025-02-22 08:26:54 +11:00
Matteo Golinelli d92c6d116b Replace --include-untracked with -u in stash show command for compatibility and update failing tests 2025-02-22 08:17:38 +11:00
Matteo Golinelli 343a3e466a Add --include-untracked flag to stash show command 2025-02-22 08:17:38 +11:00
Stefan Haller 16f5348790 Validate user config keybindings (#4275)
- **PR Description**

This improves the user experience when users try to use an invalid key
name in their config, either for one of our standard keybindings or for
the key of a custom command.

Fixes half of #4256 (only the keybindings aspect of it, not the context
names).
2025-02-21 13:24:41 +01:00
Stefan Haller 5979b40546 Validate keys of custom commands 2025-02-21 13:20:53 +01:00
Stefan Haller a5f78d3222 Validate that Universal.JumpToBlock array has 5 elements
The code that uses this panics if it has fewer.
2025-02-21 13:20:53 +01:00
Stefan Haller f3791e6ab6 Validate keybindings 2025-02-21 13:20:53 +01:00
Stefan Haller 130801dbf6 Add a few missing keybindings to docs/keybindings/Custom_Keybindings.md 2025-02-21 13:20:33 +01:00
Stefan Haller 67bb7f62c5 Move labelByKey to config package 2025-02-21 13:20:33 +01:00
Stefan Haller 52b1c42d38 Add gui.tabWidth config (#4291)
- **PR Description**

This adds a config `gui.tabWidth` that can be used to change the tab
width from the default of 4 to a different number. It affects everything
that's shown in the main view, but is probably mostly relevant for
diffs.

When using a pager, the pager needs to be configured separately for the
same tab width.

This may often be different for different repos, so it may make sense to
put it in a repo-local config file.

In some cases this may still not be flexible enough, e.g. in
multi-language projects that use different tab widths for the different
file types; but it's better than before and was easy to do...

Addresses #4290.
2025-02-20 09:17:05 +01:00
Stefan Haller 11616190ee Add a gui.tabWidth config
Affects everything that is shown in the main view, but probably mostly relevant
for diffs.
2025-02-20 09:13:56 +01:00
Stefan Haller e5137b86cf Add a tabWidth parameter to WrapViewLinesToWidth to match gocui 2025-02-20 09:13:56 +01:00
Stefan Haller ac3824bd7c Bump gocui 2025-02-20 09:13:54 +01:00
Stefan Haller 56c9d5abeb Add a "Copy to clipboard" menu to the Commit Files panel (#4271)
- **PR Description**

Add a "Copy to clipboard" menu to the Commit Files panel

This is very similar to the same menu in the Files panel, except that it
works on whatever diff is currently shown in the main view, including
range diffs either in diffing mode (shift-W), or from a range selection
of commits.

The menu has some code duplication with the existing menu in the Files
panel, but actually not so much. The first two menu items could be
unified once we have generalized the filetrees, but these are pretty
trivial; the other two menu items are sufficiently different that
unifying them is not practical, I think.

Fixes #4254.
2025-02-19 18:52:34 +01:00
Stefan Haller c9196812a2 Add a "Copy to clipboard" menu to the Commit Files panel
This is very similar to the same menu in the Files panel, except that it works
on whatever diff is currently shown in the main view, including range diffs
either in diffing mode (shift-W), or from a range selection of commits.
2025-02-19 18:50:12 +01:00
Stefan Haller caca62b89e Cleanup: simplify and tighten test expectations related to clipboard
Change our fake clipboard command to not append a linefeed; that's closer to
what the production code does.

This allows us to use Equals instead of Contains for checking the clipboard
contents.

Finally, use FileSystem().FileContent() to assert the clipboard contents,
instead of selecting the clipboard file and then checking the diff view.
2025-02-19 18:50:12 +01:00
Stefan Haller e15e4951ab Fix documentation of gui.showFileTree config (#4282)
Change `~` to `` ` `` as it's the correct key.
2025-02-17 20:19:10 +01:00
Adrian Gielniewski e3944c1707 Fix description of showFileTree
Change '~' to '`' as it's the correct key.

Signed-off-by: Adrian Gielniewski <adrian.gielniewski@gmail.com>
2025-02-17 20:14:11 +01:00
Stefan Haller 0d155e1478 feat: Support multiple commit prefixes (#4261)
- **PR Description**
This implementation, unlike that proposed in
https://github.com/jesseduffield/lazygit/pull/4253 keeps the yaml schema
easy, and does a migration from the single elements to a sequence of
elements.

Addresses https://github.com/jesseduffield/lazygit/issues/4194
2025-02-17 20:02:12 +01:00
Chris McDonnell 2fa4ee2cac feat: Support multiple commit prefixes
This implementation, unlike that proposed in https://github.com/jesseduffield/lazygit/pull/4253
keeps the yaml schema easy, and does a migration from the single
elements to a sequence of elements.
2025-02-17 19:58:31 +01:00
Stefan Haller a7bfeca9c0 Add option to copy commit body (#4274)
I based this off of the existing `CommitMessage` option in the copy
commit attributes menu.
2025-02-17 18:56:44 +01:00
Chris McDonnell ab23539c0c Add option to copy commit message body 2025-02-17 18:43:39 +01:00
Jesse Duffield 01eece3737 Use personal access token to push tag (#4266)
Github actions refuses to trigger a workflow from another workflow, but
if you use your own personal access token (in this case,
GITHUB_API_TOKEN), it should work.

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [ ] Docs have been updated if necessary
* [ ] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-02-15 15:55:20 +11:00
Jesse Duffield 57220ba478 Use personal access token to push tag
Github actions refuses to trigger a workflow from another workflow, but
if you use your own personal access token (in this case,
GITHUB_API_TOKEN), it should work.
2025-02-15 15:54:47 +11:00
Jesse Duffield 6636d0c15a Fix auto-release workflow (#4265)
The latest_tag env var wasn't defined when it was used.

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [ ] Docs have been updated if necessary
* [ ] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-02-15 15:37:50 +11:00
Jesse Duffield 269d89ea51 Fix issue where latest tag wasn't obtained early enough in auto-release script 2025-02-15 15:36:54 +11:00
Jesse Duffield dcf264b182 README.md: Update Sponsors (#4177)
Automated changes by
[create-pull-request](https://github.com/peter-evans/create-pull-request)
GitHub action
2025-02-15 15:24:27 +11:00
github-actions[bot] e37d7d5ad2 README.md: Update Sponsors 2025-02-15 04:23:38 +00:00
Jesse Duffield 988162848a Don't try killing processes if we already know the command finished + reduce error logging noise on Windows (#4231)
- **PR Description**

I was tinkering around with the code and then checking associated logs
but even with LOG_LEVEL=error, I found there was a lot of noise on
Windows.

This PR fixes two such sources:
1. Navigating through files in the Files panel
1. Navigating through branches in the Branches panel when there are a
lot of commits (e.g. this repo)

More details in the comments below.

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-02-15 15:23:26 +11:00
Brandon ed9519a241 Suppress error logs when killing process on Windows
There is a string check here to suppress the failure logs due to this reason but on Windows, the string is different ("exit status 1").
2025-02-15 14:51:35 +11:00
Brandon 7731311674 Don't try killing processes if we already know the command finished
This may lead to unrelated processes being killed on Windows (https://github.com/jesseduffield/lazygit/issues/3008). Imagine:
1. lazygit is started and runs git diff in process X which completes immediately and exits.
2. lazygit is left in the background for several hours by which process X pid is reused by an unrelated process.
3. lazygit is focused back on and runs another git diff. It first runs this stop logic which will kill process X and its children.
2025-02-15 14:51:35 +11:00
Stefan Haller 853a04dfd0 Update translations; includes a new Portuguese translation (#4250)
- **PR Description**

Update translations from Crowdin.
2025-02-12 08:23:56 +01:00
Stefan Haller c02709698c Update translations from Crowdin
This adds a new Portuguese translation.
2025-02-12 08:21:47 +01:00
Stefan Haller 555ab8735a Change update_language_files.sh script to rename pt-PT to pt 2025-02-12 08:21:47 +01:00
Stefan Haller 20fe43f972 Add some more information to pkg/i18n/translations/README.md 2025-02-12 08:21:47 +01:00
Stefan Haller 0fd7b9baa4 Fix json schema for context of CustomCommand (#4255)
- **PR Description**

Fix ugly error squiggles in VS Code when using a custom command with a
context of e.g. "commits, subCommits".

Previously the schema only allowed a single value for the context field;
however, it is now possible to specify multiple values separated by
comma (see #3784).

The only solution that I can see is to get rid of the "enum"
specification, and mention the valid values only in the description. Add
examples too so that you get at least auto-completion.
2025-02-12 08:21:06 +01:00
Stefan Haller 19921b7c42 Fix json schema for context of CustomCommand
Previously the schema only allowed a single value; however, it is now possible
to specify multiple values separated by comma, and you would get very ugly red
error squiggles in VS Code when you did that.

The only solution that I can see is to get rid of the "enum" specification, and
mention the valid values only in the description. Add examples too so that you
get at least auto-completion.
2025-02-12 08:18:26 +01:00
Stefan Haller c37376af74 fix: properly detect icon for BAZEL and WORKSPACE files (#4252)
- **PR Description**
We were using lowercase for checking the `BUILD` and `WORKSPACE` file
names when they are always uppercase. Fix these.
2025-02-11 21:46:38 +01:00
Peter Cardenas 9dbde94952 fix: properly detect icon for BAZEL and WORKSPACE files 2025-02-11 11:26:18 -08:00
Stefan Haller 3915cb6e71 Fix pasting multi-line text into commit message panel (#4234)
- **PR Description**

When pasting a multi-line commit message into the subject field of the
commit editor, we would interpret the first newline as the confirmation
for closing the editor, and then all remaining characters as whatever
command they are bound to, resulting in executing all sorts of arbitrary
commands.

Now we recognize this being a paste, and interpret the first newline as
moving to the description.

Also, prevent tabs in the pasted content from switching to the
respective other panel; simply insert four spaces instead, which should
be good enough for the leading indentation in pasted code snippets, for
example.

Finally, disable pasting text into non-editable views; my assumption is
that this is always a mistake, as it would execute arbitrary commands
depending on what's in the clipboard.

This depends on the terminal emulator supporting bracketed paste; I
didn't find one on Mac that doesn't (I tested with Terminal.app, iTerm2,
Ghostty, kitty, Alacritty, WezTerm, and VSCode's builtin terminal. It
works well in all of them).

I couldn't get it to work in Windows Terminal though, and I don't
understand why, as it does seem to support bracketed paste (it works in
bash).

Fixes #3151
Fixes #4066
Fixes #4216
2025-02-10 13:44:05 +01:00
Stefan Haller ba6cfc1f85 Handle pasting multi-line commit messages
When pasting a multi-line commit message into the subject field of the commit
editor, we would interpret the first newline as the confirmation for closing the
editor, and then all remaining characters as whatever command they are bound to,
resulting in executing all sorts of arbitrary commands.

Now we recognize this being a paste, and interpret the first newline as moving
to the description.

Also, prevent tabs in the pasted content from switching to the respective other
panel; simply insert four spaces instead, which should be good enough for the
leading indentation in pasted code snippets, for example.
2025-02-10 13:40:25 +01:00
Stefan Haller 46ebfbbe87 Bump gocui 2025-02-10 13:40:22 +01:00
Stefan Haller 3012306ac3 Swap position of checkout-commit and checkout-branch menu items (#4238)
- **PR Description**

Fixes #4237.
2025-02-10 13:37:34 +01:00
Stefan Haller e987d4b519 Swap position of checkout-commit and checkout-branch menu items
Jesse's comment from https://github.com/jesseduffield/lazygit/issues/4237:

We recently added a new option to check out a commit's branch from within the
commits, reflog, and sub-commits panels:

https://github.com/user-attachments/assets/0a5cf3f2-6803-4709-ae5a-e4addc061012

After using it for some time, I find it annoying that the default option has
changed. I rarely find myself wanting to check out a branch from the commits
panel, and it's rarer still to want to check out a branch from the reflog and
sub-commits panel. Although there may be use cases for this, it is jarring that
something you can always do (checkout the commit) is harder to do than something
that you can sometimes do (checkout the branch).

We've also had a user complain (see
https://github.com/jesseduffield/lazygit/pull/4117) about their muscle-memory
being broken by the recent change, and I have also fallen victim to this. I
don't think that the new branch checkout option is sufficiently useful to
dislodge the existing keybinding, so let's swap them.
2025-02-10 13:35:01 +01:00
Stefan Haller 190954568e Bump go-deadlock version to fix crash with go 1.23 in debug mode (#4248)
- **PR Description**

This PR solves https://github.com/jesseduffield/lazygit/issues/4002, and
perhaps https://github.com/jesseduffield/lazygit/issues/3880 (if they
are indeed duplicates), and the error message preventing debugging in
https://github.com/jesseduffield/lazygit/issues/3973.

The problem is that our version of `go-deadlock` transitively depends on
a version of `goid` that predates their changes to support go `1.23`,
which results in every goid being the number `2` for some reason.
Bumping the version of `go-deadlock` to include the updated transitive
dependency means that the goids are now correct, and `go-deadlock` does
not confused why goroutine 2 is trying to lock so many things.

I know very little about go vendored dependencies, so all I have done is
edit the `go.mod` entry for `go-deadlock` to be v0.3.5, and then run a
`go mod tidy` and `go mod vendor`. If there is a more correct way to
bump a vendored dependency, feel free to close this PR and just do that!
2025-02-10 13:23:54 +01:00
Chris McDonnell f117eed614 go-deadlock version bump to fix crash with go 1.23 2025-02-10 01:43:35 -05:00
Stefan Haller a5698b86fa Improve contrast of highlighted search results (#4242)
- **PR Description**

Bump gocui to include https://github.com/jesseduffield/gocui/pull/73.

Fixes #4162.
2025-02-07 14:27:45 +01:00
Stefan Haller 050a91b7d1 Bump gocui
This improves the contrast of highlighted search results by setting the
foreground color to black.
2025-02-07 14:20:49 +01:00
Stefan Haller 0b524293e1 Fix possible crash when deleting a branch while filtering is active (#4195)
- **PR Description**

Fix #4179.
2025-02-07 09:37:55 +01:00
Stefan Haller ff4ae4a544 Fix possible crash when deleting a branch while filtering is active
The code that tries to reselect the same branch again uses GetItems, which in
case of filtering is the filtered list. After replacing the branches slice with
a new one, the filtered list is no longer up to date, so we must reapply the
filter before working with it. It so happens that refreshView does that, so
simply call that before setting the selection again; I don't think the order
matters in this case. Otherwise we'd have to insert another call to
ReApplyFilter before the call to GetItems, which we can avoid this way.

Note that this doesn't actually make anything work better in the case of
deleting a branch, since we can't reselect the deleted branch anyway of course.
But it avoids a possible crash if the branch that was deleted was the last one
in the unfiltered list.
2025-02-07 09:34:25 +01:00
Stefan Haller a0aa7a1940 Preserve pending commit message when closing/re-opening (#4191)
- **PR Description**
This PR allows lazygit to preserve the commit messages when the commit
popup gets closed.

While discussing the feature as part of its issue, two approaches were
taken into consideration:
- to store the commit content as part of the global state file
- to store the commit content in a special file to place inside the
`.git` folder

I opted for the second approach to avoid worrying about associating each
preserved message to the worktree it belongs to. I am happy to
reconsider this and opt for the alternative approach, but I wanted to
discuss this with the maintainers before deciding.

Note: The preserving file (`.git/LAZYGIT_PENDING_COMMIT`) is deleted
when the commit is finalized or when the commit content becomes empty.
2025-02-07 09:31:56 +01:00
AzraelSec 6065908b0d Improve and adapt commit persistence test-cases 2025-02-07 09:28:27 +01:00
AzraelSec a32be7e9fa Implement reboot-resistant commit message persistence 2025-02-07 09:28:27 +01:00
Stefan Haller fcf30caf40 Show files filter status (#4230)
- **PR Description**

This PR contains three improvements to the Files panel filtering:
- it allows the user to switch to a different filter type (or reset the
filter) when we are auto-showing only conflicting files
- it shows the filter menu as radio buttons
- it displays the current filter in the top-right corner of the Files
panel's frame

See the individual commits for details.
2025-02-07 09:27:23 +01:00
Stefan Haller aad2622278 Show filter state in top right corner of Files panel frame
This includes the "only conflicting" status that the user can't switch to
themselves. We display it anyway to give a hint that files are being filtered,
and to let them know that they can turn the filter off if they want to.
2025-02-07 09:24:24 +01:00
Stefan Haller 2f4cedd025 Show current files filter as radio buttons
I renamed the "Reset filter" item to "No filter" to make it look more like a
state than an action, so that it fits the radio button concept better.

When there are conflicts and we set the filter to show only conflicting files,
then none of the radio buttons light up, which is slightly strange. I guess it's
ok though.
2025-02-07 09:24:24 +01:00
Stefan Haller e883f74f3c Allow user to switch filter when showing only conflicts
We don't need to maintain additional state to allow this; all we need to do is
take over the filter only when the number of conflicting files goes from zero to
non-zero, rather than every time it is non-zero.

The only problem is that we don't allow users to go back to showing only
conflicted files, but that's just because we don't have that as an entry in the
menu. And I don't think it's a problem.
2025-02-07 09:24:24 +01:00
Jesse Duffield a1838d33e7 Allow user to filter the files view to only show untracked files (#4226)
This handles the situation where the user's own config says to not show
untracked files, as is often the case with bare repos managing a user's
dotfiles.

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-02-07 09:08:23 +11:00
Jesse Duffield 7e85cdd027 Allow user to filter the files view to only show untracked files
This handles the situation where the user's own config says to not show
untracked files, as is often the case with bare repos managing a user's
dotfiles.
2025-02-07 09:04:55 +11:00
Stefan Haller 31e54eadaa Fix incorrect stash diff after rename (#4213)
- **PR Description**

Reproduction:
```bash
git init
git commit --allow-empty -m "first commit"
touch file1
git add .
git stash push -m "stash1"
touch file2
git add .
git stash push -m "stash2"
lazygit
```
Navigate to the Stash view and rename stash 1

![image](https://github.com/user-attachments/assets/f43b065c-9d28-4375-a5d7-cfe39a4bf216)

Manually refreshing fixes the diff.

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2025-02-06 10:09:21 +01:00
Brandon 02ca07a9be Fix incorrect stash diff after rename 2025-02-06 09:55:26 +01:00
Stefan Haller 5dff9af027 Disable staging and unstaging lines or hunks when the diff context size is 0 (#4235)
- **PR Description**

Git diff and patch doesn't work reliably with a context size of 0, so
disable it in this case (and discarding changes as well). Magit does the
same, see https://github.com/magit/magit/issues/4222.

Staging entire files by pressing space in the Files panel is still
possible, of course.

Fixes #4233.
2025-02-06 08:53:43 +01:00
Stefan Haller 437daf2f74 Disable staging and unstaging lines or hunks when the diff context size is 0
Git diff and patch doesn't work reliably with a context size of 0, so disable it
in this case (and discarding changes as well). Magit does the same, see
https://github.com/magit/magit/issues/4222.

Staging entire files by pressing space in the Files panel is still possible, of
course.
2025-02-05 16:07:22 +01:00
Stefan Haller c0141685fe Fix tag being truncated when copying to clipboard (#4232)
Copy the whole tag to clipboard instead of truncating to the value of
TruncateCopiedCommitHashesTo.

- **PR Description**
My PR for copying the tag to clipboard was recently merged (#4219).
While using LazyGit built from the latest master I noticed that some
tags were being truncated, turns out it was due to a bug I introduced on
that previous PR.
Sorry for that.
2025-02-04 08:57:22 +01:00
Bruno Jesus 4856c96521 Fix tag truncated when copying to clipboard
Copy the whole tag to clipboard instead of truncating to the value of
TruncateCopiedCommitHashesTo.
2025-02-03 21:25:34 +00:00
Stefan Haller 49f8dc2ce4 Improve error reporting on config migration (#4210)
- **PR Description**

closes #4209

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2025-01-30 09:14:18 +01:00
Karem Abdul-Samad afc3061c51 Improve error reporting on config migration 2025-01-30 09:01:17 +01:00
Stefan Haller 2bed09ef67 Show confirmation menu when trying to amend changes while there are conflicts (#4222)
- **PR Description**

Show confirmation menu when trying to amend changes while there are
conflicts, as this is very likely not what users want at that point.
Resolves #4208.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2025-01-30 08:55:56 +01:00
Stefan Haller 0a78d0016e Show confirmation menu when trying to amend changes while there are conflicts 2025-01-30 08:53:34 +01:00
Stefan Haller c0e3922d02 Fix flicker when showing backround fetch status (#4223)
- **PR Description**

Fix occasional ugly flicker when showing the background fetch status
(recently introduced with #4215).

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2025-01-30 08:52:37 +01:00
Stefan Haller 638c9c5fe7 Fix flicker when showing the status of a background fetch
This was recently introduced, but it was done the wrong way.
WithWaitingStatusSync should only be called from the main thread, and it is
meant to be used for updating the bottom line while the UI is blocked. It is a
bad idea to call this from a background thread, and it results in ugly flicker
(occasionally).

Use the newly extracted WithWaitingStatusImpl instead, this is the same as
WithWaitingStatus (which is exactly what we need) but without the implicit
OnWorker, which we don't want because we are on a background thread already.
2025-01-30 08:49:58 +01:00
Stefan Haller e48e7a2ebc Extract the inner part of WithWaitingStatus as a synchronous variant of it
This is the same as WithWaitingStatus but without the implicit OnWorker, for
those who are on a background thread already.
2025-01-30 08:49:58 +01:00
Jesse Duffield d2723ff2dd Add option to delete local and remote tag (#4217)
- **PR Description**

Option to delete both local and remote tag, closes #4203.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-30 09:36:12 +11:00
Anvar Umuraliev 7db8fb8e9c Add option to delete local and remote tag 2025-01-30 09:05:17 +11:00
Jesse Duffield abf914c923 Copy tags to clipboard (#4218)
- **PR Description**

This PR adds a new feature that allows users to copy tags to the
clipboard.
It can be used from the Commits "Copy to clipboard" menu and also from
the Tags list.
Closes #4219 

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2025-01-30 08:56:07 +11:00
Bruno Jesus 698f9287d4 Rename NoTags to CommitHasNoTags 2025-01-28 23:11:06 +00:00
Bruno Jesus 632695f71c Integration tests for copy tags to clipboard
Adds integration test in order to confirm if tags are being properly
sent to the clipboard
2025-01-28 00:34:57 +00:00
Bruno Jesus ef0d319686 Add copy commit tags to clipboard toast message 2025-01-28 00:33:55 +00:00
Bruno Jesus 0397ede8a6 Document copy tag keybinding
Add the default keybinding for the "Copy tag to clipboard" function on
the Tags section.
2025-01-27 22:07:08 +00:00
Bruno Jesus 333802fffc Copy Tags to clipboard
Add an option to copy tag(s) to the clipboard.

Works on both the Tags and Commits sections.
2025-01-27 21:53:13 +00:00
Stefan Haller 3722824298 Show background fetch status in bottom line (#4215)
- **PR Description**

This shows a status as if the user had typed 'f' manually in the files panel.

I want this particularly for the first fetch after startup. There are often
situations where I need to wait for this first background fetch to be done
before I can do what I want (e.g. rebase my branch onto its base branch, or
check out a branch that my coworker has told me they just pushed), but currently
it's hard to tell when that is.

For every subsequent background fetch after the first one it is less important,
but it hopefully doesn't hurt, and it might be nice to have some visual indication 
that background activity is happening.
2025-01-27 14:01:05 +01:00
Stefan Haller 542478546d Show background fetch status in bottom line
This shows a status as if the user had typed 'f' manually in the files panel.

I want this particularly for the first fetch after startup. There are often
situations where I need to wait for this first background fetch to be done
before I can do what I want (e.g. rebase my branch onto its base branch, or
check out a branch that my coworker has told me they just pushed), but currently
it's hard to tell when that is.

For every subsequent background fetch after the first one it is less important,
but it hopefully doesn't hurt, and it might be nice to have some visual
indication that background activity is happening.
2025-01-27 13:59:04 +01:00
Stefan Haller 9ea2ff8f41 Remove call to Render()
As far as I can tell, this is not needed. The call to Refresh at the end of
backgroundFetch takes care of redrawing after refreshing.

The call was added in 2fc1498517, that's a long time ago, and we had multiple
big refactorings since then. Maybe it was needed back then but no longer is
today.
2025-01-27 13:59:04 +01:00
Stefan Haller 55236802c3 Expose {{.SelectedCommitRange}} to custom commands (#4204)
- **PR Description**

Expose `{{.SelectedCommitRange}}` to custom commands. It has fields .To
and .From (the hashes of the last and the first selected commits,
respectively), and it is useful for creating git commands that act on a
range of commits.

Fixes #4184.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2025-01-27 09:03:47 +01:00
Stefan Haller 4baf008ac7 Expose {{.SelectedCommitRange}} to custom commands
It has fields .To and .From (the hashes of the last and the first selected
commits, respectively), and it is useful for creating git commands that act on a
range of commits.
2025-01-27 08:53:50 +01:00
Stefan Haller d768327814 Fix checking out a different branch while pushing a branch for the first time (#4214)
- **PR Description**

When pushing a branch that didn't have an upstream yet, we use the
command line

  git push --set-upstream origin HEAD:branch-name

The HEAD: part of this is too unspecific; when checking out a different
branch while the push is still running, then git will set the upstream
branch on the newly checked out branch, not the branch that was being
pushed. This might be considered a bug in git; you might expect that it
resolves HEAD at the beginning of the operation, and uses the result at
the end.

But we can easily work around this by explicitly supplying the real
branch name instead of HEAD.

Fixes #4207.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2025-01-27 08:50:24 +01:00
Stefan Haller 0864affc8f Fix checking out a different branch while pushing a branch for the first time
When pushing a branch that didn't have an upstream yet, we use the command line

  git push --set-upstream origin HEAD:branch-name

The HEAD: part of this is too unspecific; when checking out a different branch
while the push is still running, then git will set the upstream branch on the
newly checked out branch, not the branch that was being pushed. This might be
considered a bug in git; you might expect that it resolves HEAD at the beginning
of the operation, and uses the result at the end.

But we can easily work around this by explicitly supplying the real branch name
instead of HEAD.
2025-01-26 10:22:19 +01:00
Stefan Haller 40d6800fd3 Fix adding blank line at end of commit message (#4182)
- **PR Description**

This fixes a bug where adding enough new lines to a commit message
description such that it becomes taller than the window so that the
window needs to resize vertically, the cursor wouldn't move to the added
blank line, but stay at the end of the previous line. This was a
regression introduced with #4152.
2025-01-20 17:54:59 +01:00
Stefan Haller 20d0b4316d Only avoid the blank line at end of view if view is not editable
For editable views it is important to actually show the blank line so that we
can put the cursor there for typing.

This fixes problems with adding blank lines at the end of longer commit
messages.
2025-01-20 17:52:53 +01:00
Stefan Haller fe429c6184 Bump gocui 2025-01-20 17:52:51 +01:00
Stefan Haller a77dcbe3a1 Add '--' to 'git rev-list' to disambiguate branch name from path (#4185)
- **PR Description**

When deleting a local branch that has the same name as a file known to
git (say `test`), a popup with the following error is shown:
```
fatal: ambiguous argument 'test': both revision and filename
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]' 
```
The command log reveals this:
```
git rev-list --max-count=1 test ^HEAD ^refs/heads/main
```

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2025-01-20 09:25:50 +01:00
Erich Fussi 2a87c048b9 Add '--' to 'git rev-list' to disambiguate branch name from path 2025-01-19 14:33:42 +01:00
Jesse Duffield c03b892270 Bump tcell to fix broken deployment (#4178)
- **PR Description**

See
https://github.com/jesseduffield/lazygit/actions/runs/12829856652/job/35776769332
and https://github.com/gdamore/tcell/issues/768
2025-01-18 00:36:18 +11:00
Jesse Duffield 5e26183ae1 Bump tcell to fix broken deployment 2025-01-18 00:31:57 +11:00
Jesse Duffield ab7b5f6d84 Improve undo action to restore files upon undoing a commit (#4167)
- **PR Description**

Right now, undoing a commit performs a hard reset, which also discards
all the changes from that commit. This PR adds new config options (and a
new `undo` section) which allow users to choose between `hard` and
`soft` reset modes when undoing commits.

Personally, I think that the default should be `soft`, because the state
before the commit had the files, so undoing a commit should put the
files where they were before. But this PR keeps `hard` as the default
and does not change current behavior.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-18 00:17:12 +11:00
Gabriel Lanata 4065175a58 Improve undo action to restore files upon undoing a commit 2025-01-18 00:07:15 +11:00
Stefan Haller 43106b6c7f Collapse/uncollapse all files in tree (#4131) 2025-01-13 21:18:38 +01:00
Mauricio TrajanoandStefan Haller 7bea41534b Collapse/expand all files in tree
Co-authored-by: Stefan Haller <stefan@haller-berlin.de>
2025-01-13 21:13:11 +01:00
Stefan Haller 14a91d9829 Bump gocui (and tcell) (#4166)
This updates our tcell dependency to v2.8.0, adding support for ghostty
and tmux-256color.

This will hopefully fix #4133, and it might also fix #2962 and #3434
(but I don't understand enough about these to tell).
2025-01-12 13:51:33 +01:00
Stefan Haller 274e24d75e Bump gocui (and tcell)
This updates our tcell dependency to v2.8.0, adding support for ghostty and
tmux-256color.
2025-01-12 13:48:52 +01:00
Stefan Haller a1a8cd114d Add ability to configure branch color patterns using regex (#4130)
- **PR Description**

Add ability to specify color patterns in the `branchColorPatterns`
config using regex, ex. `JIRA-\d+` would match all branch names in the
form `JIRA-456`.

Example config:
```yaml
gui:
  branchColorPatterns:
    'docs/.+': 'black' # make all branches prefixed with docs/ have a black color
    'feature/collapse-all': 'red' # make a specfic branch name red
    'IDEA-\d+': 'blue' # make all branches with the prefix `IDEA-` followed by a digit, blue

```
2025-01-12 13:47:17 +01:00
Mauricio Trajano c64a7904b7 Add ability to configure branch color patterns 2025-01-12 13:44:26 +01:00
Stefan Haller 3e623cd1ce Remove the automatic coloring of certain branch names
We used to automatically color branches starting with "feature/", "bugfix/", or
"hotfix/". For those who don't want this, it's a bit non-obvious to turn off,
but it's actually pretty easy to configure manually for those who want this, so
we just remove this default coloring.
2025-01-11 22:13:33 +01:00
Jesse Duffield 6da99a49a4 Cut a new release automatically each month (#4146)
- **PR Description**

I regularly struggle to stay on top of releases, and that's because I
like to spend some time polishing the release notes and I don't always
have time for that. But that shouldn't block releases, so now releases
will happen automatically on the first Saturday of each month.

In order to block an automatic release, we simply need to add a
blocks-release label on any open PR or issue.

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [ ] Docs have been updated if necessary
* [ ] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-11 15:47:43 +11:00
Jesse Duffield 977a01172f Automatically cut release each month 2025-01-11 15:44:00 +11:00
Jesse Duffield 91cb1ff29a Standardise on 'screen mode' naming convention (#4142)
We had some conflicting names: screen-mode, window-size, and
window-maximisation. I think panel-size sounds good.

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-11 14:30:12 +11:00
Jesse Duffield 28d10c26a4 Standardise on 'screen mode' name
We had some conflicting names so we're standardising on screen mode
2025-01-11 14:25:48 +11:00
Stefan Haller 2c321011db Use interactive shell for running shell commands only if shell is bash or zsh (#4159)
- **PR Description**

Fix running shell commands with fish or nushell.

Fixes #4153.
2025-01-10 00:26:35 +01:00
Stefan Haller dbd407c01d Use interactive shell for running shell commands only if shell is bash or zsh
We use an interactive shell so that users can use their custom shell aliases in
lazygit's shell prompt, which is convenient; however, this only really works for
shells like bash or zsh. We know it doesn't work for fish or nushell (because
these use different names for the $? variable); so use an interactive shell only
if the user's shell is either bash or zsh.
2025-01-09 09:29:31 +01:00
Stefan Haller b8d5e481bb Fix micro editor preset (#4156)
- **PR Description**

I don't know what was I thinking when making #3049, because Micro does
not actually support `--` as delimiter between options and files. As
such, when trying to edit files with `micro` set as editor, an empty
file named `--` would be open first.

This PR fixes this by explicitly defining a preset for `micro`. I've
double-tested it to make sure that it doesn't behave wierdly any more :D
2025-01-09 08:51:39 +01:00
Nikita Karamov 2b3525bfd6 Fix micro editor preset 2025-01-09 08:48:59 +01:00
Stefan Haller b2c46c33b6 Add number of commits to cherry-pick confirmation prompt (#4158)
- **PR Description**

The other day, I was cherry-picking a selection of commits and was
annoyed that the "Are you sure..." prompt did not include the actual
number of commits I was about to cherry-pick.

I failed to realize the number of copied commits is displayed at the
bottom right until going to update the integration tests. I personally
think it's still nice to display the number in the actual confirmation
prompt but feel free to close this PR if the change is unwanted.
2025-01-09 08:46:37 +01:00
Brandon c44231a7d7 Add number of commits to cherry-pick confirmation prompt 2025-01-08 21:08:42 -08:00
Jesse Duffield 3518ec9f72 README.md: Update Sponsors (#3746)
Automated changes by
[create-pull-request](https://github.com/peter-evans/create-pull-request)
GitHub action
2025-01-09 11:26:19 +11:00
github-actions[bot] ec19fcf134 README.md: Update Sponsors 2025-01-09 00:25:30 +00:00
Stefan Haller 2d193cb296 Adjust line number for working copy when editing a line (#4119)
- **PR Description**

There are two ways to jump to the editor on a specific line: pressing `e` in the
staging or patch building panels, or clicking on a hyperlink in a delta diff. In
both cases, this works perfectly in the unstaged changes view, but in other
views (either staged changes, or an older commit) it can often jump to the wrong
line; this happens when there are further changes to the file being viewed in
later commits or in unstaged changes.

This commit fixes this so that you end up on the right line in these cases.
2025-01-07 17:50:01 +01:00
Stefan Haller 64cd7cd9f6 Adjust line number for working copy when editing a line
There are two ways to jump to the editor on a specific line: pressing `e` in the
staging or patch building panels, or clicking on a hyperlink in a delta diff. In
both cases, this works perfectly in the unstaged changes view, but in other
views (either staged changes, or an older commit) it can often jump to the wrong
line; this happens when there are further changes to the file being viewed in
later commits or in unstaged changes.

This commit fixes this so that you end up on the right line in these cases.
2025-01-07 17:46:51 +01:00
Stefan Haller eaaf123238 Combine GetPathDiff and GetAllDiff into one command (GetDiff)
This makes it more reusable for other purposes.
2025-01-07 17:46:51 +01:00
Stefan Haller 1c5fe8ff17 Add a test demonstrating the problem
When pressing `e` on line 5 in a diff of an older commit, we expect it to take
us to line 5 in that file. But we end up on line 2, because the file had further
changes both in newer commits, and in the unstaged changes of the working copy.
2025-01-07 17:46:51 +01:00
Stefan Haller 49ca7f6a84 Bump gocui 2025-01-07 17:39:01 +01:00
Stefan Haller 80c212faba Avoid blank line at end of view (#4152)
- **PR Description**

This updates gocui to include
https://github.com/jesseduffield/gocui/pull/68 and
https://github.com/jesseduffield/gocui/pull/69, which changes views to
not have an extra blank line at the end when content ending in a newline
character is written to them. This makes text views more consistent with
list views, which don't have a blank line after the last list entry
either.
2025-01-07 17:37:57 +01:00
Stefan Haller ae53059ed2 Bump gocui
This updates gocui to include https://github.com/jesseduffield/gocui/pull/68 and
https://github.com/jesseduffield/gocui/pull/69, which changes views to not have
an extra blank line at the end when content ending in a newline character is
written to them. This makes text views more consistent with list views, which
don't have a blank line after the last list entry either.
2025-01-07 17:34:30 +01:00
Stefan Haller 13829d8ff7 Fix reset/rebase to upstream (#4151)
- **PR Description**

Resetting to the upstream branch was broken when the remote branch has a
different name than the local branch.

Rebasing onto the upstream worked fine, but also displayed the wrong
branch name in the menu.

Fixes #4148.
2025-01-06 09:31:44 +01:00
Stefan Haller 53b1e12110 Cleanup: use the upstream local variable consistently
We need to move it closer to the beginning of the method to use it everywhere.
2025-01-04 15:48:26 +01:00
Stefan Haller 009062534e Fix resetting or rebasing a branch to its upstream when the upstream branch name is different 2025-01-04 15:48:26 +01:00
Stefan Haller 33e81f717d Extend reset/rebase test to use upstream branch name that is different from local one
The easiest way to do that is to rename the local branch after pushing.

This shows various levels of brokenness for the reset and rebase to upstream
commands: both menu entries display the wrong upstream branch name in the menu
(the local one rather than the remote one); executing the rebase command works
correctly though, the rebase command uses the right branch name. Resetting
fails, though.

We'll fix this in the next commit.
2025-01-04 15:46:14 +01:00
Stefan Haller ef718f3386 Show the alt-enter keybinding at bottom of commit description view (#4136)
- **PR Description**

It wasn't really obvious how to commit when the focus is in the commit
description view, since pressing enter inserts a newline there. To
improve this, show the `<a-enter>` keybinding at the bottom of the
description view when it is focused.

Fixes #4134.
2025-01-03 10:19:14 +01:00
Stefan Haller bf9339557e Show the <a-enter> keybinding at bottom of commit description view
It was hard to discover, this should make it more obvious.
2025-01-03 10:16:29 +01:00
Stefan Haller ebfc7ff7c6 Don't show keybindings option in bottom line when panel is open (#4143)
- **PR Description**

Hide the `Keybindings: ?` option from the bottom line if a panel is open.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2025-01-03 10:13:20 +01:00
Stefan Haller 928e76a82f Disable KeybindingsMenu using a DisabledReason when a panel is open
This hides it from the options map at the bottom of the screen.
2025-01-03 10:09:42 +01:00
Stefan Haller 9de8d17d84 Don't show error toast for disabled keybindings if DisabledReason text is empty
This makes it possible to "silently" disable a keybinding. The effect is the
same as putting the check in the handler and returning nil from there, except
that doing it this way also hides it from the bottom line if DisplayOnScreen is
true.
2025-01-03 10:09:42 +01:00
Jesse Duffield 9776be3131 Tweak file icons (#4145)
YML icon should be purple, and folder icon should be grey

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [ ] Docs have been updated if necessary
* [ ] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-03 15:39:43 +11:00
Jesse Duffield 7f7d9b166f Tweak file icons
YML icon should be purple, and folder icon should be grey
2025-01-03 15:29:20 +11:00
Jesse Duffield 3dd2e25dfa Clarify commit message prefix mechanics (#4114)
- **PR Description**
Added quote that qlarifies that users should use subgroups instead of
regular match when configuring commit message prefixes

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-03 14:29:52 +11:00
ZeroMask 9790a7e00c docs: qlarify commit message prefix mechanics
Added quote that qlarifies that users should use subgroups instead of regular match when configuring commit message prefixes
2025-01-03 14:22:02 +11:00
Jesse Duffield a5c6a6120d documentation - describe os.openLink (#3094)
- this helps to solve issues as in #3052
- provide an example of how to pass a link to a bash script

- **PR Description** 

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [ ] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-03 14:12:44 +11:00
Sebastian Mangelsen bf9f9b6c04 provide section for openLink
- this helps to solve issues as in #3052
- provide an example of how to pass it
  to a bash script
2025-01-03 14:07:30 +11:00
Jesse Duffield d520d5e404 Bump crypto and net packages (#4144)
The old versions had some CVEs which I'm almost certain were not
relevant to lazygit but this means I get to close a couple PRs easily.

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [ ] Docs have been updated if necessary
* [ ] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-03 14:07:12 +11:00
Jesse Duffield 3241a9c251 Bump crypto and net packages
The old versions had some CVEs which I'm almost certain were not
relevant to lazygit but this means I get to close a couple PRs easily.
2025-01-03 14:01:26 +11:00
Jesse Duffield 4c4a2c3ff4 Fix typos (#3920)
Just thought I'd contribute some typo fixes that I stumbled on. Nothing
controversial (hopefully).

Use the following command to quickly review the corrections made:
```shell
git diff HEAD^! --word-diff-regex='\w+' -U0 \
  | grep -E '\[\-.*\-\]\{\+.*\+\}' \
  | sed -r 's/.*\[\-(.*)\-\]\{\+(.*)\+\}.*/\1 \2/' \
  | sort | uniq -c | sort -n
```

FWIW, the typos are:
* commitable -> committable (x8)
* uncommited -> uncommitted (x3)
* uniquefy -> uniquify
* acccordion -> accordion
* integrationt -> integration
* nicers -> nicer
* existant -> existent
* potentiall -> potentially
* subling -> sibling
* supporta -> supports
* unbenownst -> unbeknownst
* worktre -> worktree
2025-01-03 10:57:10 +11:00
Nathan Baulch 508cdb40a8 Fix typos 2025-01-03 10:50:36 +11:00
Jesse Duffield ae459b2377 chore: use errors.New to replace fmt.Errorf with no parameters (#4107)
use errors.New to replace fmt.Errorf with no parameters
2025-01-03 10:33:39 +11:00
RiceChuan c834e132c7 chore: use errors.New to replace fmt.Errorf with no parameters
Signed-off-by: RiceChuan <lc582041246@gmail.com>
2025-01-02 17:27:54 +11:00
Jesse Duffield 5e9ba82d7b Add worktree option to fast forwarding operation (#4051)
- **PR Description**

Fix a reported issue regarding Fast-forwarding a branch that is checked
out in a different worktree. It's reported, and I could
[repro](https://github.com/jesseduffield/lazygit/issues/2957#issuecomment-2462872838),
that whenever such an action is taken, the current worktree is polluted
with unwanted File changes related to the Fast-forward operation.

A solution is suggested – and tested to produce expected results – that
adding `--work-tree` option to the generated command should fix the
issue.

[Issue: 2957](https://github.com/jesseduffield/lazygit/issues/2957)

I'm proposing to merge these changes as it produces expected results:
<img width="1722" alt="Screenshot 2024-11-08 at 19 55 31"
src="https://github.com/user-attachments/assets/89ac1c8d-7a64-4d88-afd9-3ec3d41705f1">



- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-02 17:25:43 +11:00
John Mutuma fc78082e81 Formatting the file with gofumpt 2025-01-02 16:52:24 +11:00
John Mutuma d7d5733a71 Revert unwanted change 2025-01-02 16:52:24 +11:00
John Mutuma 5240b2862f Add worktree option to fast forwarding operation 2025-01-02 16:52:24 +11:00
John Mutuma e1c18226bf Add worktree option to fast forwarding operation 2025-01-02 16:52:24 +11:00
Jesse Duffield c4e59aea66 Update docs to describe use of custom commands without keybindings (#3846)
- **PR Description**

Update custom command documentation to describe how commands can be used
without keybindings (see [issue
3799](https://github.com/jesseduffield/lazygit/issues/3799#issuecomment-2297999051))

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2025-01-02 16:50:32 +11:00
A. Jensen 75311750c8 update documentation to describe use of custom commands without keys specified. 2025-01-02 16:50:26 +11:00
Jesse Duffield 16a158a025 Default to half-screen mode when opening with certain CLI args (#4141)
It should have been half-screen from the get-go. I think I just used
full-screen to make demos look nicer. Now that we have a CLI arg for the
screen mode we can make use of that in the demos.

Relates to https://github.com/jesseduffield/lazygit/issues/3042

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [ ] Docs have been updated if necessary
* [ ] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-02 16:44:25 +11:00
Jesse Duffield 621229bb09 Default to half-screen mode when filtering files or using the git-arg CLI arg
It should have been half-screen from the get-go. I think I just used
full-screen to make demos look nicer. Now that we have a CLI arg for the
screen mode we can make use of that in the demos.
2025-01-02 16:10:58 +11:00
Jesse Duffield 536ef82866 Add screen-mode command line argument (#4103)
Introduce a new "screen-mode" command line argument (`-sm
normal|half|full` / `--screen-mode normal|half|full`) that allows a user
to specify which screen mode (normal, half or full) Lazygit should use
when it runs.

This argument will take precedence over a default Window Size specified
in user config.

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-02 16:09:09 +11:00
Alex Lewis 54680e0836 Add screen-mode command line argument
Introduce a new "screen-mode" command line argument that allows a user
to specify which screen mode (normal, half or full) Lazygit should use
when it runs.

This argument will take precedence over a default Window Size specified
in user config.
2025-01-02 16:01:48 +11:00
Jesse Duffield fc69945a80 Update instructions for using OSC52 with tmux (#3597)
- **PR Description**
Update the instructions on using copyToClipboardCmd config to copy using
OSC52 with tmux

Added `-w 0` flag to `base64` command because it wraps lines that are
longer than 76 by default, [that fails to copy on some terminal
emulators](https://github.com/jesseduffield/lazygit/issues/3595).

We compare `$TERM` to `^(screen|tmux)` because both of them are valid as
[per the manual](https://man7.org/linux/man-pages/man1/tmux.1.html):
```
default-terminal terminal
               Set the default terminal for new windows created in this
               session - the default value of the TERM environment
               variable.  For to work correctly, this must be set to
               ‘screen’, ‘tmux’ or a derivative of them.
```

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`) -- not
relevant
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
-- not relevant
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide) -- not relevant
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
-- not relevant
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-02 15:47:34 +11:00
Elias Assaf 69a048c0ff Update instructions for using OSC52 with tmux
Signed-off-by: Elias Assaf <elyas51000@gmail.com>
2025-01-02 15:47:27 +11:00
Jesse Duffield 6c6d835d50 Set repology table to 3 columns (#4138)
- **Set repology table to 3 columns on the README file because a single
column takes too much vertical space**

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [ ] Docs have been updated if necessary
* [ ] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-02 15:41:40 +11:00
hasecilu 2a72e96011 Set repology table to 3 columns 2025-01-02 15:41:29 +11:00
Jesse Duffield a507c836b2 enhancement: Use HEX colors on file icons instead of C256 colors (#4029)
- **PR Description**
Lazygit already accepts to customize UI colors using HEX values but the
color of the icons still were using C256 notation, this PR makes the
change to use HEX values. Not sure if there is a special reason to not
make the change.

You can create the available files with:
```shell
touch _gvimrc _vimrc bin brewfile bspwmrc build build.gradle build.zig.zon cantorrc Cargo.lock Cargo.toml checkhealth cmakelists.txt CODE-OF-CONDUCT.md CODE_OF_CONDUCT CODE_OF_CONDUCT.md COMMIT_EDITMSG commit_editmsg commitlint.config.js commitlint.config.ts compose.yaml compose.yml config containerfile copying copying.lesser docker-compose.yaml docker-compose.yml dockerfile Dockerfile ds_store eslint.config.cjs eslint.config.js eslint.config.mjs eslint.config.ts ext_typoscript_setup.txt favicon.ico fn fp-info-cache fp-lib-table FreeCAD.conf gemfile$ gitignore_global gnumakefile GNUmakefile go.mod go.sum go.work gradle gradle-wrapper.properties gradle.properties gradlew gruntfile.babel.js gruntfile.coffee gruntfile.js gruntfile.ls gruntfile.ts gtkrc gulpfile.babel.js gulpfile.coffee gulpfile.js gulpfile.ls gulpfile.ts hidden hypridle.conf hyprland.conf hyprlock.conf hyprpaper.conf i3blocks.conf i3status.conf include ionic.config.json justfile kalgebrarc kdeglobals kdenlive-layoutsrc kdenliverc kritadisplayrc kritarc lib LICENSE LICENSE.md localized lxde-rc.xml lxqt.conf Makefile mix.lock mpv.conf node_modules npmignore nuxt.config.cjs nuxt.config.js nuxt.config.mjs nuxt.config.ts package-lock.json package.json PKGBUILD platformio.ini pom.xml prettier.config.cjs prettier.config.js prettier.config.mjs prettier.config.ts PrusaSlicer.ini PrusaSlicerGcodeViewer.ini py.typed QtProject.conf R robots.txt rubydoc SECURITY SECURITY.md settings.gradle strings svelte.config.js sxhkdrc sym-lib-table tailwind.config.js tailwind.config.mjs tailwind.config.ts tmux.conf tmux.conf.local tsconfig.json unlicense vagrantfile$ vlcrc webpack weston.ini workspace xmobarrc xmobarrc.hs xmonad.hs xorg.conf xsettingsd.conf yarn.lock 

```
and 
```shell
touch f.{cmake,3gp,3mf,7z,a,aac,ai,aif,aiff,android,ape,apk,app,apple,applescript,asc,ass,astro,avi,avif,avro,awk,azcli,bak,bash,bash_history,bash_pro,bashrc,bat,bats,bazel,bib,bicep,bicepparam,bladephp,blend,blp,bmp,brep,bz,bz2,bz3,bzl,c,c++,cab,cache,cast,cbl,cc,ccm,cfg,cjs,class,clj,cljc,cljd,cljs,cls,cmake,cmd,cob,cobol,coffee,conf,configru,cp,cpio,cpp,cppm,cpy,cr,crdownload,cs,csh,cshtml,cson,csproj,css,csv,csx,cts,cu,cue,cuh,cxx,cxxm,d,dts,dart,db,dconf,deb,desktop,diff,djvu,dll,doc,docx,dot,download,drl,dropbox,ds_store,DS_store,dump,dwg,dxf,ebook,ebuild,editorconfig,edn,eex,ejs,el,elc,elf,elm,eln,env,eot,epp,epub,erb,erl,ex,exe,exs,f#,f3d,f90,fbx,fcbak,fcmacro,fcmat,fcparam,fcscript,fcstd,fcstd1,fctb,fctl,fdmdownload,fish,flac,flc,flf,flv,fnl,font,fs,fsi,fsscript,fsx,gcode,gd,gdoc,gem,gem,gemspec,gform,gif,git,glb,gnumake,go,godot,gql,gradle,graphql,gresource,groovy,gsheet,gslides,guard,gv,gz,h,haml,hbs,hc,heex,hex,hh,hpp,hrl,hs,htm,html,huff,hurl,hx,hxx,ical,icalendar,ico,ics,ifb,ifc,ige,iges,igs,image,img,iml,import,info,ini,ino,ipynb,iso,ixx,j2c,j2k,jad,jar,java,jfi,jfif,jif,jl,jmd,jp2,jpe,jpeg,jpg,jpx,js,json,json5,jsonc,jsx,jwmrc,jxl,kbx,kdb,kdbx,kdenlive,kdenlivetitle,kicad_dru,kicad_mod,kicad_pcb,kicad_prl,kicad_pro,kicad_sch,kicad_sym,kicad_wks,ko,kpp,kra,krz,ksh,kt,kts,latex,lck,leex,less,lff,lhs,license,liquid,localized,lock,log,lrc,lua,luac,luau,lz,lz4,lzh,lzma,lzo,m,m3u,m3u8,m4a,m4v,magnet,make,markdown,material,md,md5,mdx,mint,mjs,mk,mkd,mkv,ml,mli,mm,mo,mobi,mojo,mov,mp3,mp4,mpp,msf,msi,mts,mustache,nfo,nim,nix,node,npmignore,nswag,nu,o,obj,odp,ods,odt,ogg,ogv,opus,org,otf,out,part,patch,pck,pdf,php,pl,pls,ply,pm,png,po,pot,pp,ppt,pptx,prisma,pro,proc,properties,ps1,psb,psd,psd1,psm1,pub,pxd,pxi,pxm,py,pyc,pyd,pyi,pyo,pyw,pyx,qm,qml,qrc,qss,query,r,rake,rake,rar,razor,rb,rdata,rdb,rdoc,rds,readme,res,resi,rlib,rmd,rpm,rproj,rs,rspec,rspec_parallel,rspec_status,rss,rtf,ru,rubydoc,sass,sbt,sc,scad,scala,scm,scss,sh,sha1,sha224,sha256,sha384,sha512,shell,sig,signature,skp,sldasm,sldprt,slim,sln,slvs,sml,so,sol,specjs,specjsx,spects,spectsx,sql,sqlite,sqlite3,srt,ssa,ste,step,stl,stp,strings,sty,styl,stylus,sub,sublime,suo,sv,svelte,svg,svh,swift,t,tar,taz,tbc,tbz,tbz2,tcl,templ,terminal,testjs,testjsx,testts,testtsx,tex,tf,tfvars,tgz,tiff,tlz,tmux,toml,torrent,tres,ts,tscn,tsconfig,tsv,tsx,ttf,twig,txt,txz,typoscript,tz,tzo,ui,v,vala,vh,vhd,vhdl,video,vim,vsh,vsix,vue,war,wasm,wav,webm,webmanifest,webp,webpack,windows,wma,woff,woff2,wrl,wrz,wv,wvc,x,xaml,xcf,xcplayground,xcstrings,xhtml,xls,xlsx,xm,xml,xpi,xul,xz,yaml,yml,zig,zip,zsh,zsh-theme,zshrc,zst,strings}
```
to check the new colors.

Some icons could have be changed because I compared againa
nvim-web-devicons file.

Let me know if you want to change some icon or color.


**Edit**: I added 2 new commits that use glyphs from Nerd Fonts 3.3.0

---

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [X] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [x] Docs have been updated if necessary
* [X] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-02 15:41:16 +11:00
hasecilu 8b90cca521 Use HEX colors on file icons instead of C256 colors 2025-01-02 15:36:27 +11:00
Jesse Duffield 3573289452 Update chinese translation for pull requests (#4140)
- **PR Description**

Based on https://github.com/jesseduffield/lazygit/pull/3246

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-02 15:33:18 +11:00
Jesse Duffield 87b54a4107 Update chinese translation for pull requests 2025-01-02 15:26:42 +11:00
Jesse Duffield 1b0d3829f8 Allow on prem Azure DevOps Server pull request (#3954)
- **PR Description**

Allows creating a pull request for an on prem Azure DevOps Server

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-02 15:17:58 +11:00
Wayne Bowie aad3dc42a7 Allow on prem Azure DevOps Server pull request 2025-01-02 15:10:02 +11:00
Stefan Haller f884cc2af9 Allow to switch branches in Commit View (#4115) (#4117)
- **PR Description**

When the user checks out a commit which has a local branch ref attached
to it, they can select between checking out the branch or checking out
the commit as detached head. If no local branch is attached to the
commit, the behavior is like before: They are asked to confirm, if they
want to checkout the commit as detached head.

Requested in #4115.

Note: I tried also to consider remote branches, but because I wasn't
able to correlate remote branches to their commits, I deferred it and
leave it open for later improvement.
2025-01-01 14:59:20 +01:00
Sebastian Flügge f4c8287143 Allow to switch branches in Commit View
When the user checks out a commit which has a local branch ref attached
to it, they can select between checking out the branch or checking out
the commit as detached head.
2025-01-01 14:55:12 +01:00
Jesse Duffield 03d7bc854e Bump kill package (#4137)
Closes https://github.com/jesseduffield/lazygit/issues/3008

This should reduce the instances of killing random processes on windows.

See https://github.com/jesseduffield/kill/pull/1

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] If a new UserConfig entry was added, make sure it can be
hot-reloaded (see
[here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-01 23:56:58 +11:00
Jesse Duffield fdf1643f63 Bump kill package
This should reduce the instances of killing random processes on windows.

See https://github.com/jesseduffield/kill/pull/1
2025-01-01 23:45:53 +11:00
Stefan Haller d93be027b6 docs: Stylize and correct the NixOS section in README.md (#4135)
- **PR Description**

configuration.nix is a file, and most files in the README.md are
stylized as code blocks. `environment.systemPackages` is actually just a
code block, and should be stylized as such.
2025-01-01 13:11:15 +01:00
wadsaek fd5be11370 Stylize and correct the NixOS section in README.md
configuration.nix is a file, and most files in the README.md are
stylized as code blocks. `environment.systemPackages` is actually just a
code block, and should be stylized as such
2025-01-01 12:48:19 +02:00
Jesse Duffield 1e1fba4ce6 Add vision and design principles doc (#4053)
I want to spell out the design principles behind Lazygit so that our
priorities are clear and it's easier to make UX decisions (especially
for early contributors).

It's not possible to codify this in a way that will resolve all disputes
but I think it's worthwhile to enumerate some of the things that keep
coming up in our discussions about X or Y feature.

This is a very rough draft (effectively a brain-dump). So I expect
plenty of feedback :)

CC @stefanhaller @karimkhaleel @mark2185 @afhoffman @AzraelSec

- **Please check if the PR fulfills these requirements**

* [ ] Docs have been updated if necessary
2024-12-31 16:53:23 +11:00
Jesse Duffield b174791490 Add vision and design principles doc
I want to spell out the design principles behind lazygit so that our priorities are clear
and it's easier to make UX decisions
2024-12-31 16:50:06 +11:00
343 changed files with 8293 additions and 3787 deletions
+77
View File
@@ -0,0 +1,77 @@
name: Automated Release
on:
schedule:
# Runs at 2:00 AM UTC on the first Saturday of every month
- cron: '0 2 * * 6'
workflow_dispatch: # Allow manual triggering of the workflow
jobs:
check-and-release:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Get Latest Tag
run: |
latest_tag=$(git describe --tags $(git rev-list --tags --max-count=1) || echo "v0.0.0")
echo "Latest tag: $latest_tag"
echo "latest_tag=$latest_tag" >> $GITHUB_ENV
- name: Check for changes since last release
run: |
if [ -z "$(git diff --name-only ${{ env.latest_tag }})" ]; then
echo "No changes detected since last release"
exit 1
fi
- name: Check for Blocking Issues/PRs
id: check_blocks
run: |
gh auth setup-git
gh auth status
echo "Checking for blocking issues and PRs..."
# Check for blocking issues
blocking_issues=$(gh issue list -l blocks-release --json number,title --jq '.[] | "- \(.title) (#\(.number))"')
# Check for blocking PRs
blocking_prs=$(gh pr list -l blocks-release --json number,title --jq '.[] | "- \(.title) (#\(.number)) (PR)"')
# Combine the results
blocking_items="$blocking_issues"$'\n'"$blocking_prs"
# Remove empty lines
blocking_items=$(echo "$blocking_items" | grep . || true)
if [ -n "$blocking_items" ]; then
echo "Blocking issues/PRs detected:"
echo "$blocking_items"
exit 1
fi
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Calculate next version
run: |
echo "Latest tag: ${{ env.latest_tag }}"
IFS='.' read -r major minor patch <<< "${{ env.latest_tag }}"
new_minor=$((minor + 1))
new_tag="$major.$new_minor.0"
echo "New tag: $new_tag"
echo "new_tag=$new_tag" >> $GITHUB_ENV
# This will trigger a deploy via .github/workflows/cd.yml
- name: Push New Tag
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag ${{ env.new_tag }}
git push origin ${{ env.new_tag }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_API_TOKEN }}
+4
View File
@@ -10,6 +10,10 @@ before making a change.
[This video](https://www.youtube.com/watch?v=kNavnhzZHtk) walks through the process of adding a small feature to lazygit. If you have no idea where to start, watching that video is a good first step.
## Design principles
See [here](./VISION.md) for a set of design principles that we want to consider when building a feature or making a change.
## Codebase guide
[This doc](./docs/dev/Codebase_Guide.md) explains:
+9 -6
View File
File diff suppressed because one or more lines are too long
+104
View File
@@ -0,0 +1,104 @@
# Vision and Design Principles
## Vision
Lazygit's vision is to be the most enjoyable UI for git.
## Design Principles
There are seven (sometimes contradictory) design principles we follow:
- Dicoverability
- Simplicity
- Safety
- Power
- Speed
- Conformity with git
- Think of the codebase
### Discoverability
TUI's are notoriously hard to learn, thanks to limited screen real-estate to provide contextual help and a general lack of effort on the part of developers to make things obvious. We want Lazygit to buck the trend and be easy for a new user to grok.
Examples:
- Clearly document all the features/configuration options
- e.g. gifs in the README
- Document how to solve various git problems with Lazygit
- This is something we don't have yet but should: a section in the docs explaining how Lazygit can help you in various scenarios
- Use tooltips to explain what actions will do
- Make it easy for users to ask questions and get answers from the community
- Make it easy to find entities and actions from within Lazygit
- Use visual elements to make things obvious
- e.g. '<-- YOU ARE HERE' label when rebasing
- Don't require the user to memorise keybindings
- e.g. when the user is mid-rebase, we prominently show that the keybinding for viewing rebase options is 'm'
- When the user performs an action in Lazygit, make the impact obvious
- If the affected entity isn't visible, show a toast notification
- If a keybinding is disabled, give a reason why
### Simplicity
The git CLI is very complex but most git use cases are simple. Lazygit needs to ensure that simple use cases are easy to satisfy.
- Make the most common use cases dead-simple (staging files, committing, pulling/pushing)
- Don't overwhelm the user with options
- Use sensible defaults
- We already have too many configuration options: think hard before adding any new ones
### Safety
It's easy to screw things up in git so Lazygit should try to protect the user from screwing things up.
- Prompt for a confirmation before doing anything that's hard to reverse
- Make it easy to correct mistakes
- e.g. undo action
- the escape key should get you out of most transient situations (rebasing, diffing, etc)
## Power
Users shouldn't have to drop down the CLI _too_ often. Lazygit should be able to handle some complex use cases.
- Make complex (but common) CLI flows simple
- e.g. interactive rebasing
- Use the custom commands system to handle the really rare complex edge-cases
### Speed
Pro users should be able to move at lightning speed with Lazygit.
- Always think about the number of keypresses involved in a given UX flow
- Make lazygit performant and responsive
- Think about the individual commands being run and how fast they are
- Startup should be FAST. If you want to run something at startup that is slow, make it non-blocking.
- Support muscle-memory
- Prefer disabling menu items instead of hiding them so that muscle memory can be used to select the desired menu item
- Try to make keybinding intuitions to transfer across contexts (e.g. 'd' for destroy)
- When changing keybindings in a new release, always consider what will happen if a user does not read the release notes and relies on muscle memory.
### Conformity with git
Satisfying the use-cases of git users is more important than perfectly conforming to git's API, but even obscure parts of git's API were motivated by real use-cases.
- Users should only have to drop down to the git CLI in rare circumstances
- Honour the git config
- Don't override anything set in the git config without the user's permission
- Work with git, not against it.
- Too much magic will get us into trouble
- Avoid storing Lazygit-specific session state that could instead be stored in git
- Ensure that Lazygit can represent the state of any repo
- Sometimes git's default behaviour is just silly and we'll make the call to override but it should be a well-considered decision.
### Think of the codebase
Will somebody PLEASE think of the codebase!
Some features are not worth the added complexity in the codebase. The more this codebase grows, the harder it will be to make the changes that everybody wants.
## Resolving conflicts
Many of the above objectives are directly antithetical to one another. If you add an extra confirmation prompt for the sake of _safety_, you're sacrificing _speed_. If you support toggling various git flags in the name of _power_, you're sacrificing _simplicity_. There are a few things to say here.
When there are conflicts, we need to make a judgement call. In general we should err on the side of safety and simplicity as the default, with the ability for users to make things faster / more powerful either through configuration or separate keybindings.
This does not mean for example that force pushes should be impossible without being manually enabled: force pushes are table stakes for anybody who rebases. But it does mean that a confirmation popup should appear when force pushing.
+69 -23
View File
@@ -47,6 +47,10 @@ gui:
# One of: 'margin' (default) | 'jump'
scrollOffBehavior: margin
# The number of spaces per tab; used for everything that's shown in the main view, but probably mostly relevant for diffs.
# Note that when using a pager, the pager has its own tab width setting, so you need to pass it separately in the pager command.
tabWidth: 4
# If true, capture mouse events.
# When mouse events are captured, it's a little harder to select text: e.g. requiring you to hold the option key when on macOS.
mouseEvents: true
@@ -166,7 +170,7 @@ gui:
showListFooter: true
# If true, display the files in the file views as a tree. If false, display the files as a flat list.
# This can be toggled from within Lazygit with the '~' key, but that will not change the default.
# This can be toggled from within Lazygit with the '`' key, but that will not change the default.
showFileTree: true
# If true, show the number of lines changed per file in the Files view
@@ -219,9 +223,9 @@ gui:
# If 'auto', only split the main window when a file has both staged and unstaged changes
splitDiff: auto
# Default size for focused window. Window size can be changed from within Lazygit with '+' and '_' (but this won't change the default).
# Default size for focused window. Can be changed from within Lazygit with '+' and '_' (but this won't change the default).
# One of: 'normal' (default) | 'half' | 'full'
windowSize: normal
screenMode: normal
# Window border style.
# One of 'rounded' (default) | 'single' | 'double' | 'hidden'
@@ -341,14 +345,6 @@ git:
# If true, do not allow force pushes
disableForcePushing: false
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#predefined-commit-message-prefix
commitPrefix:
# pattern to match on. E.g. for 'feature/AB-123' to match on the AB-123 use "^\\w+\\/(\\w+-\\w+).*"
pattern: ""
# Replace directive. E.g. for 'feature/AB-123' to start the commit message with 'AB-123 ' use "[$1] "
replace: ""
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#predefined-branch-name-prefix
branchPrefix: ""
@@ -571,6 +567,8 @@ keybinding:
openMergeTool: M
openStatusFilter: <c-b>
copyFileInfoToClipboard: "y"
collapseAll: '-'
expandAll: =
branches:
createPullRequest: o
viewPullRequestOptions: O
@@ -659,6 +657,13 @@ os:
open: 'open {{filename}}'
```
## Custom Command for Opening a Link
```yaml
os:
openLink: 'bash -C /path/to/your/shell-script.sh {{link}}'
```
Specify the external command to invoke when opening URL links (i.e. creating MR/PR in GitLab, BitBucket or GitHub). `{{link}}` will be replaced by the URL to be opened. A simple shell script can be used to further mangle the passed URL.
## Custom Command for Copying to and Pasting from Clipboard
```yaml
os:
@@ -667,9 +672,26 @@ os:
Specify an external command to invoke when copying to clipboard is requested. `{{text}` will be replaced by text to be copied. Default is to copy to system clipboard.
If you are working on a terminal that supports OSC52, the following command will let you take advantage of it:
```
```yaml
os:
copyToClipboardCmd: printf "\033]52;c;$(printf {{text}} | base64)\a" > /dev/tty
copyToClipboardCmd: printf "\033]52;c;$(printf {{text}} | base64 -w 0)\a" > /dev/tty
```
For tmux you need to wrap it with the [tmux escape sequence](https://github.com/tmux/tmux/wiki/FAQ#what-is-the-passthrough-escape-sequence-and-how-do-i-use-it), and enable passthrough in tmux config with `set -g allow-passthrough on`:
```yaml
os:
copyToClipboardCmd: printf "\033Ptmux;\033\033]52;c;$(printf {{text}} | base64 -w 0)\a\033\\" > /dev/tty
```
For the best of both worlds, we can let the command determine if we are running in a tmux session and send the correct sequence:
```yaml
os:
copyToClipboardCmd: >
if [[ "$TERM" =~ ^(screen|tmux) ]]; then
printf "\033Ptmux;\033\033]52;c;$(printf {{text}} | base64 -w 0)\a\033\\" > /dev/tty
else
printf "\033]52;c;$(printf {{text}} | base64 -w 0)\a" > /dev/tty
fi
```
A custom command for reading from the clipboard can be set using
@@ -808,14 +830,17 @@ gui:
## Custom Branch Color
You can customize the color of branches based on the branch prefix:
You can customize the color of branches based on branch patterns (regular expressions):
```yaml
gui:
branchColors:
'docs': '#11aaff' # use a light blue for branches beginning with 'docs/'
branchColorPatterns:
'^docs/': '#11aaff' # use a light blue for branches beginning with 'docs/'
'ISSUE-\d+': '#ff5733' # use a bright orange for branches containing 'ISSUE-<some-number>'
```
Note that the regular expressions are not implicitly anchored to the beginning/end of the branch name. If you want to do that, add leading `^` and/or trailing `$` as needed.
## Example Coloring
![border example](../../assets/colored-border-example.png)
@@ -893,29 +918,50 @@ Where:
## Predefined commit message prefix
In situations where certain naming pattern is used for branches and commits, pattern can be used to populate commit message with prefix that is parsed from the branch name.
If you define multiple naming patterns, they will be attempted in order until one matches.
Example:
Example hitting first match:
- Branch name: feature/AB-123
- Commit message: [AB-123] Adding feature
- Generated commit message prefix: [AB-123]
Example hitting second match:
- Branch name: CD-456_fix_problem
- Generated commit message prefix: (CD-456)
```yaml
git:
commitPrefix:
pattern: "^\\w+\\/(\\w+-\\w+).*"
replace: '[$1] '
- pattern: "^\\w+\\/(\\w+-\\w+).*"
replace: '[$1] '
- pattern: "^([^_]+)_.*" # Take all text prior to the first underscore
replace: '($1) '
```
If you want repository-specific prefixes, you can map them with `commitPrefixes`. If you have both `commitPrefixes` defined and an entry in `commitPrefixes` for the current repo, the `commitPrefixes` entry is given higher precedence. Repository folder names must be an exact match.
If you want repository-specific prefixes, you can map them with `commitPrefixes`. If you have both entries in `commitPrefix` defined and an repository match in `commitPrefixes` for the current repo, the `commitPrefixes` entries will be attempted first. Repository folder names must be an exact match.
```yaml
git:
commitPrefixes:
my_project: # This is repository folder name
pattern: "^\\w+\\/(\\w+-\\w+).*"
replace: '[$1] '
- pattern: "^\\w+\\/(\\w+-\\w+).*"
replace: '[$1] '
commitPrefix:
- pattern: "^(\\w+)-.*" # A more general match for any leading word
replace : '[$1] '
- pattern: ".*" # The final fallthrough regex that copies over the whole branch name
replace : '[$0] '
```
> [!IMPORTANT]
> The way golang regex works is when you use `$n` in the replacement string, where `n` is a number, it puts the nth captured subgroup at that place. If `n` is out of range because there aren't that many capture groups in the regex, it puts an empty string there.
>
> So make sure you are capturing group or groups in your regex.
>
> For example `^[A-Z]+-\d+$` won't work on branch name like BRANCH-1111
> But `^([A-Z]+-\d+)$` will
## Predefined branch name prefix
In situations where certain naming pattern is used for branches, this can be used to populate new branch creation with a static prefix.
+7 -1
View File
@@ -50,7 +50,7 @@ Custom command keybindings will appear alongside inbuilt keybindings when you vi
For a given custom command, here are the allowed fields:
| _field_ | _description_ | required |
|-----------------|----------------------|-|
| key | The key to trigger the command. Use a single letter or one of the values from [here](https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md) | yes |
| key | The key to trigger the command. Use a single letter or one of the values from [here](https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md). Custom commands without a key specified can be triggered by selecting them from the keybindings (`?`) menu | no |
| command | The command to run (using Go template syntax for placeholder values) | yes |
| context | The context in which to listen for the key (see [below](#contexts)) | yes |
| subprocess | Whether you want the command to run in a subprocess (e.g. if the command requires user input) | no |
@@ -297,6 +297,7 @@ Your commands can contain placeholder strings using Go's [template syntax](https
```
SelectedCommit
SelectedCommitRange
SelectedFile
SelectedPath
SelectedLocalBranch
@@ -314,6 +315,11 @@ CheckedOutBranch
To see what fields are available on e.g. the `SelectedFile`, see [here](https://github.com/jesseduffield/lazygit/blob/master/pkg/gui/services/custom_commands/models.go) (all the modelling lives in the same file).
We don't support accessing all elements of a range selection yet. We might add this in the future, but as a special case you can access the range of selected commits by using `SelectedCommitRange`, which has two properties `.To` and `.From` which are the hashes of the bottom and top selected commits, respectively. This is useful for passing them to a git command that operates on a range of commits. For example, to create patches for all selected commits, you might use
```yml
command: "git format-patch {{.SelectedCommitRange.From}}^..{{.SelectedCommitRange.To}}"
```
## Keybinding collisions
If your custom keybinding collides with an inbuilt keybinding that is defined for the same context, only the custom keybinding will be executed. This also applies to the global context. However, one caveat is that if you have a custom keybinding defined on the global context for some key, and there is an in-built keybinding defined for the same key and for a specific context (say the 'files' context), then the in-built keybinding will take precedence. See how to change in-built keybindings [here](https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#keybindings)
+1 -1
View File
@@ -2,7 +2,7 @@
## The use-case
This topic deserves its own doc because there there are a few touch points for it. We have a use-case for knowing when Lazygit is idle or busy because integration tests follow the following process:
This topic deserves its own doc because there are a few touch points for it. We have a use-case for knowing when Lazygit is idle or busy because integration tests follow the following process:
1) press a key
2) wait until Lazygit is idle
3) run assertion / press another key
+4
View File
@@ -20,11 +20,15 @@
| `<pgup>` | Pgup |
| `<pgdown>` | Pgdn |
| `<up>` | ArrowUp |
| `<s-up>` | ShiftArrowUp |
| `<down>` | ArrowDown |
| `<s-down>` | ShiftArrowDown |
| `<left>` | ArrowLeft |
| `<right>` | ArrowRight |
| `<tab>` | Tab |
| `<backtab>` | Backtab |
| `<enter>` | Enter |
| `<a-enter>` | AltEnter |
| `<esc>` | Esc |
| `<backspace>` | Backspace |
| `<c-space>` | CtrlSpace |
+7 -1
View File
@@ -56,6 +56,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Copy path to clipboard | |
| `` y `` | Copy to clipboard | |
| `` c `` | Checkout | Checkout file. This replaces the file in your working tree with the version from the selected commit. |
| `` d `` | Remove | Discard this commit's changes to this file. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes this file. |
| `` o `` | Open file | Open file in default application. |
@@ -65,6 +66,8 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` a `` | Toggle all files | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
| `` <enter> `` | Enter file / Toggle directory collapsed | If a file is selected, enter the file so that you can add/remove individual lines to the custom patch. If a directory is selected, toggle the directory. |
| `` ` `` | Toggle file tree view | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` / `` | Search the current view by text | |
## Commit summary
@@ -147,6 +150,8 @@ If you would instead like to start an interactive rebase from the selected commi
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` M `` | Open external merge tool | Run `git mergetool`. |
| `` f `` | Fetch | Fetch changes from remote. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` / `` | Search the current view by text | |
## Local branches
@@ -348,7 +353,8 @@ If you would instead like to start an interactive rebase from the selected commi
| Key | Action | Info |
|-----|--------|-------------|
| `` <space> `` | Checkout | Checkout the selected tag tag as a detached HEAD. |
| `` <c-o> `` | Copy tag to clipboard | |
| `` <space> `` | Checkout | Checkout the selected tag as a detached HEAD. |
| `` n `` | New tag | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
| `` d `` | Delete | View delete options for local/remote tag. |
| `` P `` | Push tag | Push the selected tag to a remote. You'll be prompted to select a remote. |
+7 -1
View File
@@ -134,6 +134,7 @@ If you would instead like to start an interactive rebase from the selected commi
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | ファイル名をクリップボードにコピー | |
| `` y `` | Copy to clipboard | |
| `` c `` | チェックアウト | Checkout file. This replaces the file in your working tree with the version from the selected commit. |
| `` d `` | Remove | Discard this commit's changes to this file. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes this file. |
| `` o `` | ファイルを開く | Open file in default application. |
@@ -143,6 +144,8 @@ If you would instead like to start an interactive rebase from the selected commi
| `` a `` | Toggle all files | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
| `` <enter> `` | Enter file / Toggle directory collapsed | If a file is selected, enter the file so that you can add/remove individual lines to the custom patch. If a directory is selected, toggle the directory. |
| `` ` `` | ファイルツリーの表示を切り替え | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` / `` | 検索を開始 | |
## コミットメッセージ
@@ -180,7 +183,8 @@ If you would instead like to start an interactive rebase from the selected commi
| Key | Action | Info |
|-----|--------|-------------|
| `` <space> `` | チェックアウト | Checkout the selected tag tag as a detached HEAD. |
| `` <c-o> `` | Copy tag to clipboard | |
| `` <space> `` | チェックアウト | Checkout the selected tag as a detached HEAD. |
| `` n `` | タグを作成 | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
| `` d `` | Delete | View delete options for local/remote tag. |
| `` P `` | タグをpush | Push the selected tag to a remote. You'll be prompted to select a remote. |
@@ -218,6 +222,8 @@ If you would instead like to start an interactive rebase from the selected commi
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` M `` | Git mergetoolを開く | Run `git mergetool`. |
| `` f `` | Fetch | Fetch changes from remote. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` / `` | 検索を開始 | |
## ブランチ
+14 -8
View File
@@ -189,7 +189,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` <c-y> `` | 풀 리퀘스트 URL을 클립보드에 복사 | |
| `` c `` | 이름으로 체크아웃 | Checkout by name. In the input box you can enter '-' to switch to the last branch. |
| `` F `` | 강제 체크아웃 | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
| `` d `` | Delete | View delete options for local/remote branch. |
| `` d `` | 삭제 | View delete options for local/remote branch. |
| `` r `` | 체크아웃된 브랜치를 이 브랜치에 리베이스 | Rebase the checked-out branch onto the selected branch. |
| `` M `` | 현재 브랜치에 병합 | View options for merging the selected item into the current branch (regular merge, squash merge) |
| `` f `` | Fast-forward this branch from its upstream | Fast-forward selected branch from its upstream. |
@@ -247,7 +247,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` n `` | 새 브랜치 생성 | |
| `` M `` | 현재 브랜치에 병합 | View options for merging the selected item into the current branch (regular merge, squash merge) |
| `` r `` | 체크아웃된 브랜치를 이 브랜치에 리베이스 | Rebase the checked-out branch onto the selected branch. |
| `` d `` | Delete | Delete the remote branch from the remote. |
| `` d `` | 삭제 | Delete the remote branch from the remote. |
| `` u `` | Set as upstream | Set the selected remote branch as the upstream of the checked-out branch. |
| `` s `` | Sort order | |
| `` g `` | View reset options | View reset options (soft/mixed/hard) for resetting onto selected item. |
@@ -263,7 +263,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` <c-o> `` | 커밋 해시를 클립보드에 복사 | |
| `` <c-r> `` | Reset cherry-picked (copied) commits selection | |
| `` b `` | Bisect 옵션 보기 | |
| `` s `` | Squash | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
| `` s `` | 스쿼시 | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
| `` f `` | Fixup | Meld the selected commit into the commit below it. Similar to squash, but the selected commit's message will be discarded. |
| `` r `` | 커밋메시지 변경 | Reword the selected commit's message. |
| `` R `` | 에디터에서 커밋메시지 수정 | |
@@ -299,6 +299,7 @@ If you would instead like to start an interactive rebase from the selected commi
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 파일명을 클립보드에 복사 | |
| `` y `` | 클립보드에 복사 | |
| `` c `` | 체크아웃 | Checkout file |
| `` d `` | Remove | Discard this commit's changes to this file |
| `` o `` | 파일 닫기 | Open file in default application. |
@@ -308,6 +309,8 @@ If you would instead like to start an interactive rebase from the selected commi
| `` a `` | Toggle all files included in patch | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
| `` <enter> `` | Enter file to add selected lines to the patch (or toggle directory collapsed) | If a file is selected, enter the file so that you can add/remove individual lines to the custom patch. If a directory is selected, toggle the directory. |
| `` ` `` | 파일 트리뷰로 전환 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` / `` | 검색 시작 | |
## 커밋메시지
@@ -321,11 +324,12 @@ If you would instead like to start an interactive rebase from the selected commi
| Key | Action | Info |
|-----|--------|-------------|
| `` <space> `` | 체크아웃 | Checkout the selected tag tag as a detached HEAD. |
| `` <c-o> `` | Copy tag to clipboard | |
| `` <space> `` | 체크아웃 | Checkout the selected tag as a detached HEAD. |
| `` n `` | 태그를 생성 | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
| `` d `` | Delete | View delete options for local/remote tag. |
| `` d `` | 삭제 | View delete options for local/remote tag. |
| `` P `` | 태그를 push | Push the selected tag to a remote. You'll be prompted to select a remote. |
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` g `` | 초기화 | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | 커밋 보기 | |
| `` w `` | View worktree options | |
@@ -338,7 +342,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` <c-o> `` | 파일명을 클립보드에 복사 | |
| `` <space> `` | Staged 전환 | Toggle staged for selected file. |
| `` <c-b> `` | 파일을 필터하기 (Staged/unstaged) | |
| `` y `` | Copy to clipboard | |
| `` y `` | 클립보드에 복사 | |
| `` c `` | 커밋 변경내용 | Commit staged changes. |
| `` w `` | Commit changes without pre-commit hook | |
| `` A `` | 마지맛 커밋 수정 | |
@@ -354,11 +358,13 @@ If you would instead like to start an interactive rebase from the selected commi
| `` <enter> `` | Stage individual hunks/lines for file, or collapse/expand for directory | If the selected item is a file, focus the staging view so you can stage individual hunks/lines. If the selected item is a directory, collapse/expand it. |
| `` d `` | View 'discard changes' options | View options for discarding changes to the selected file. |
| `` g `` | View upstream reset options | |
| `` D `` | Reset | View reset options for working tree (e.g. nuking the working tree). |
| `` D `` | 초기화 | View reset options for working tree (e.g. nuking the working tree). |
| `` ` `` | 파일 트리뷰로 전환 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` M `` | Git mergetool를 열기 | Run `git mergetool`. |
| `` f `` | Fetch | Fetch changes from remote. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` / `` | 검색 시작 | |
## 확인 패널
+7 -1
View File
@@ -79,6 +79,8 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` M `` | Open external merge tool | Run `git mergetool`. |
| `` f `` | Fetch | Fetch changes from remote. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` / `` | Start met zoeken | |
## Bevestigingspaneel
@@ -127,6 +129,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Kopieer de bestandsnaam naar het klembord | |
| `` y `` | Copy to clipboard | |
| `` c `` | Uitchecken | Bestand uitchecken |
| `` d `` | Remove | Uitsluit deze commit zijn veranderingen aan dit bestand |
| `` o `` | Open bestand | Open file in default application. |
@@ -136,6 +139,8 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` a `` | Toggle all files | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
| `` <enter> `` | Enter bestand om geselecteerde regels toe te voegen aan de patch | If a file is selected, enter the file so that you can add/remove individual lines to the custom patch. If a directory is selected, toggle the directory. |
| `` ` `` | Toggle bestandsboom weergave | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` / `` | Start met zoeken | |
## Commits
@@ -348,7 +353,8 @@ If you would instead like to start an interactive rebase from the selected commi
| Key | Action | Info |
|-----|--------|-------------|
| `` <space> `` | Uitchecken | Checkout the selected tag tag as a detached HEAD. |
| `` <c-o> `` | Copy tag to clipboard | |
| `` <space> `` | Uitchecken | Checkout the selected tag as a detached HEAD. |
| `` n `` | Creëer tag | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
| `` d `` | Delete | View delete options for local/remote tag. |
| `` P `` | Push tag | Push the selected tag to a remote. You'll be prompted to select a remote. |
+6
View File
@@ -229,6 +229,8 @@ Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita,
| `` <c-t> `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | |
| `` M `` | Otwórz zewnętrzne narzędzie scalania | Uruchom `git mergetool`. |
| `` f `` | Pobierz | Pobierz zmiany ze zdalnego serwera. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` / `` | Szukaj w bieżącym widoku po tekście | |
## Pliki commita
@@ -236,6 +238,7 @@ Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita,
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Kopiuj ścieżkę do schowka | |
| `` y `` | Kopiuj do schowka | |
| `` c `` | Przełącz | Przełącz plik. Zastępuje plik w twoim drzewie roboczym wersją z wybranego commita. |
| `` d `` | Usuń | Odrzuć zmiany w tym pliku z tego commita. Uruchamia interaktywny rebase w tle, więc możesz otrzymać konflikt scalania, jeśli późniejszy commit również zmienia ten plik. |
| `` o `` | Otwórz plik | Otwórz plik w domyślnej aplikacji. |
@@ -245,6 +248,8 @@ Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita,
| `` a `` | Przełącz wszystkie pliki | Dodaj/usuń wszystkie pliki commita do niestandardowej łatki. Zobacz https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
| `` <enter> `` | Wejdź do pliku / Przełącz zwiń katalog | Jeśli plik jest wybrany, wejdź do pliku, aby móc dodawać/usuwać poszczególne linie do niestandardowej łatki. Jeśli wybrany jest katalog, przełącz katalog. |
| `` ` `` | Przełącz widok drzewa plików | Przełącz widok plików między płaskim a drzewem. Płaski układ pokazuje wszystkie ścieżki plików na jednej liście, układ drzewa grupuje pliki według katalogów. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` / `` | Szukaj w bieżącym widoku po tekście | |
## Podsumowanie commita
@@ -329,6 +334,7 @@ Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita,
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Copy tag to clipboard | |
| `` <space> `` | Przełącz | Przełącz wybrany tag jako odłączoną głowę (detached HEAD). |
| `` n `` | Nowy tag | Utwórz nowy tag z bieżącego commita. Zostaniesz poproszony o wprowadzenie nazwy tagu i opcjonalnego opisu. |
| `` d `` | Usuń | Wyświetl opcje usuwania lokalnego/odległego tagu. |
+379
View File
@@ -0,0 +1,379 @@
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go generate ./...` from the project root._
# Lazygit Keybindings
_Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
## Combinações globais de teclas
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-r> `` | Mudar para um repositório recente | |
| `` <pgup> (fn+up/shift+k) `` | Scroll up main window | |
| `` <pgdown> (fn+down/shift+j) `` | Scroll down main window | |
| `` @ `` | View command log options | View options for the command log e.g. show/hide the command log and focus the command log. |
| `` P `` | Empurre (Push) | Faça push do branch atual para o seu branch upstream. Se nenhum upstream estiver configurado, você será solicitado a configurar um branch a montante. |
| `` p `` | Puxar (Pull) | Puxe alterações do controle remoto para o ramo atual. Se nenhum upstream estiver configurado, será solicitado configurar um ramo a montante. |
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
| `` } `` | Increase diff context size | Increase the amount of the context shown around changes in the diff view. |
| `` { `` | Decrease diff context size | Decrease the amount of the context shown around changes in the diff view. |
| `` : `` | Execute shell command | Bring up a prompt where you can enter a shell command to execute. |
| `` <c-p> `` | View custom patch options | |
| `` m `` | Ver opções de mesclar/rebase | Ver opções para abortar/continuar/pular o merge/rebase atual. |
| `` R `` | Atualizar | Atualize o estado do git (ou seja, execute `git status`, `git branch`, etc em segundo plano para atualizar o conteúdo de painéis). Isso não executa `git fetch`. |
| `` + `` | Next screen mode (normal/half/fullscreen) | |
| `` _ `` | Prev screen mode | |
| `` ? `` | Open keybindings menu | |
| `` <c-s> `` | View filter options | View options for filtering the commit log, so that only commits matching the filter are shown. |
| `` W `` | View diffing options | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
| `` <c-e> `` | View diffing options | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
| `` q `` | Sair | |
| `` <esc> `` | Cancel | |
| `` <c-w> `` | Toggle whitespace | Toggle whether or not whitespace changes are shown in the diff view. |
| `` z `` | Desfazer | O reflog será usado para determinar qual comando git para executar para desfazer o último comando git. Isto não inclui mudanças na árvore de trabalho; apenas compromissos são tidos em consideração. |
| `` <c-z> `` | Refazer | O reflog será usado para determinar qual comando git para executar para refazer o último comando git. Isto não inclui mudanças na árvore de trabalho; apenas compromissos são tidos em consideração. |
## List panel navigation
| Key | Action | Info |
|-----|--------|-------------|
| `` , `` | Previous page | |
| `` . `` | Next page | |
| `` < `` | Scroll to top | |
| `` > `` | Scroll to bottom | |
| `` v `` | Toggle range select | |
| `` <s-down> `` | Range select down | |
| `` <s-up> `` | Range select up | |
| `` / `` | Search the current view by text | |
| `` H `` | Scroll left | |
| `` L `` | Scroll right | |
| `` ] `` | Next tab | |
| `` [ `` | Previous tab | |
## Arquivos
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Copy path to clipboard | |
| `` <space> `` | Etapa | Alternar para staging para o arquivo selecionado. |
| `` <c-b> `` | Filtrar arquivos por status | |
| `` y `` | Copy to clipboard | |
| `` c `` | Commit | Submeter mudanças em staging |
| `` w `` | Commit changes without pre-commit hook | |
| `` A `` | Alterar último commit | |
| `` C `` | Enviar alteração usando um editor Git | |
| `` <c-f> `` | Encontrar commit da base para consertar | Encontre o commit em que as suas mudanças atuais estão se baseando, para alterar/consertar o commit. Isso poupa-te você de ter que olhar pelos commits da sua branch um por um para ver qual commit deve ser alterado/consertado
Veja a documentação:
<https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
| `` e `` | Editar | Abrir arquivo no editor externo. |
| `` o `` | Abrir arquivo | Abrir arquivo no aplicativo padrão. |
| `` i `` | Ignore or exclude file | |
| `` r `` | Atualizar arquivos | |
| `` s `` | Stash | Stash all changes. For other variations of stashing, use the view stash options keybinding. |
| `` S `` | View stash options | View stash options (e.g. stash all, stash staged, stash unstaged). |
| `` a `` | Stage completo | Alternar para todos os arquivos na árvore de trabalho |
| `` <enter> `` | Stage lines / Colapso diretório | Se o item selecionado for um arquivo, o foco na exibição de preparo para o estágio de cenas/linhas individuais. Se o item selecionado for um diretório, recolher/expandi-lo. |
| `` d `` | Discard | View options for discarding changes to the selected file. |
| `` g `` | View upstream reset options | |
| `` D `` | Reset | View reset options for working tree (e.g. nuking the working tree). |
| `` ` `` | Alternar exibição de árvore de arquivo | Alternar a visualização de arquivo entre layout plano e layout de árvore. Layout plano mostra todos os caminhos de arquivo em uma única lista, layout de árvore agrupa arquivos por diretório. |
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
| `` M `` | Abrir ferramenta de merge externa | Execute `git mergetool`. |
| `` f `` | Buscar | Buscar alterações do controle remoto. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` / `` | Search the current view by text | |
## Branches locais
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Copy branch name to clipboard | |
| `` i `` | Show git-flow options | |
| `` <space> `` | Verificar | Checar item selecionado |
| `` n `` | Nova branch | |
| `` o `` | Create pull request | |
| `` O `` | View create pull request options | |
| `` <c-y> `` | Copiar URL do pull request para área de transferência | |
| `` c `` | Checar por nome | Checar por nome. Na caixa de entrada você pode inserir '-' para trocar para a última branch |
| `` F `` | Forçar checagem | Forçar checagem da branch selecionada. Isso irá descartar todas as mudanças no seu diretório de trabalho antes cheque a branch selecionada |
| `` d `` | Delete | View delete options for local/remote branch. |
| `` r `` | Refazer | Refazer a branch checada na branch selecionada |
| `` M `` | Mesclar | Ver opções para mesclar o item selecionado no branch atual (mesclar regularmente, mesclar squash) |
| `` f `` | Avanço rápido | Encaminhamento rápido de branch selecionada a partir do upstream. |
| `` T `` | New tag | |
| `` s `` | Sort order | |
| `` g `` | Reset | |
| `` R `` | Rename branch | |
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
| `` <enter> `` | View commits | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## Branches remotos
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Copy branch name to clipboard | |
| `` <space> `` | Verificar | Checar a nova branch baseada na brach remota selecionada, ou a branch remota como HEAD, desanexado |
| `` n `` | Nova branch | |
| `` M `` | Mesclar | Ver opções para mesclar o item selecionado no branch atual (mesclar regularmente, mesclar squash) |
| `` r `` | Refazer | Refazer a branch checada na branch selecionada |
| `` d `` | Delete | Delete the remote branch from the remote. |
| `` u `` | Set as upstream | Set the selected remote branch as the upstream of the checked-out branch. |
| `` s `` | Sort order | |
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
| `` <enter> `` | View commits | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## Commit files
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Copy path to clipboard | |
| `` y `` | Copy to clipboard | |
| `` c `` | Verificar | Checkout file. This replaces the file in your working tree with the version from the selected commit. |
| `` d `` | Remove | Discard this commit's changes to this file. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes this file. |
| `` o `` | Abrir arquivo | Abrir arquivo no aplicativo padrão. |
| `` e `` | Editar | Abrir arquivo no editor externo. |
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
| `` <space> `` | Toggle file included in patch | Toggle whether the file is included in the custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
| `` a `` | Toggle all files | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
| `` <enter> `` | Enter file / Toggle directory collapsed | If a file is selected, enter the file so that you can add/remove individual lines to the custom patch. If a directory is selected, toggle the directory. |
| `` ` `` | Alternar exibição de árvore de arquivo | Alternar a visualização de arquivo entre layout plano e layout de árvore. Layout plano mostra todos os caminhos de arquivo em uma única lista, layout de árvore agrupa arquivos por diretório. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` / `` | Search the current view by text | |
## Commits
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Copy commit hash to clipboard | |
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
| `` b `` | View bisect options | |
| `` s `` | Squash | Squash o commit selecionado no commit abaixo dele. A mensagem do commit selecionado será anexada ao commit abaixo dele. |
| `` f `` | Fixup | Faça o commit selecionado no commit abaixo dele. Semelhante para o squash, mas a mensagem do commit selecionado será descartada. |
| `` r `` | Reword | Repetir a mensagem de submissão selecionada. |
| `` R `` | Republicar com o editor | |
| `` d `` | Descartar | Solte o commit selecionado. Isso irá remover o commit do branch através de uma rebase. Se o commit faz com que as alterações em commits posteriores dependem, você pode precisar resolver conflitos de merge. |
| `` e `` | Editar (iniciar rebase interativa) | Editar o commit selecionado. Use isto para iniciar uma rebase interativa a partir do commit selecionado. Quando já estiver no meio da reconstrução, isto irá marcar o commit selecionado para edição, o que significa que ao continuar com a reformulação. a rebase irá pausar no commit selecionado para permitir que você faça alterações. |
| `` i `` | Start interactive rebase | Start an interactive rebase for the commits on your branch. This will include all commits from the HEAD commit down to the first merge commit or main branch commit.
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
| `` p `` | Escolher | Marque o commit selecionado para ser escolhido (quando meados da base). Isso significa que o commit será mantido ao continuar o rebase. |
| `` F `` | Create fixup commit | Create 'fixup!' commit for the selected commit. Later on, you can press `S` on this same commit to apply all above fixup commits. |
| `` S `` | Apply fixup commits | Squash all 'fixup!' commits, either above the selected commit, or all in current branch (autosquash). |
| `` <c-j> `` | Mover commit um para baixo | |
| `` <c-k> `` | Mover o commit um para cima | |
| `` V `` | Colar (cherry-pick) | |
| `` B `` | Mark as base commit for rebase | Select a base commit for the next rebase. When you rebase onto a branch, only commits above the base commit will be brought across. This uses the `git rebase --onto` command. |
| `` A `` | Modificar | Alterar o commit com mudanças em sted. Se o commit selecionado for o commit HEAD, ele executará o `git commit --amend`. Caso contrário, o compromisso será alterado por meio de uma base de apoio. |
| `` a `` | Alterar atributo de commit | Definir/Redefinir autor de submissão ou co-autor definido. |
| `` t `` | Reverter | Crie um commit reverter para o commit selecionado, que aplica as alterações do commit selecionado em reverso. |
| `` T `` | Tag commit | Create a new tag pointing at the selected commit. You'll be prompted to enter a tag name and optional description. |
| `` <c-l> `` | View log options | View options for commit log e.g. changing sort order, hiding the git graph, showing the whole git graph. |
| `` <space> `` | Verificar | Checkout the selected commit as a detached HEAD. |
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
| `` o `` | Open commit in browser | |
| `` n `` | Create new branch off of commit | |
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` C `` | Copiar (cherry-pick) | Marcar commit como copiado. Então, dentro da visualização local de commits, você pode pressionar `V` para colar (cherry-pick) o(s) commit(s) copiado(s) em seu branch de check-out. A qualquer momento você pode pressionar `<esc>` para cancelar a seleção. |
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
| `` <enter> `` | View files | |
| `` w `` | View worktree options | |
| `` / `` | Search the current view by text | |
## Confirmation panel
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | Confirmar | |
| `` <esc> `` | Fechar/Cancelar | |
## Etiquetas
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Copy tag to clipboard | |
| `` <space> `` | Verificar | Checar a tag selecionada como um HEAD, desanexado |
| `` n `` | New tag | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
| `` d `` | Delete | View delete options for local/remote tag. |
| `` P `` | Push tag | Push the selected tag to a remote. You'll be prompted to select a remote. |
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
| `` <enter> `` | View commits | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## Menu
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | Executar | |
| `` <esc> `` | Fechar | |
| `` / `` | Filter the current view by text | |
## Painel Principal (Normal)
| Key | Action | Info |
|-----|--------|-------------|
| `` mouse wheel down (fn+up) `` | Scroll down | |
| `` mouse wheel up (fn+down) `` | Scroll up | |
## Painel Principal (preparação)
| Key | Action | Info |
|-----|--------|-------------|
| `` <left> `` | Go to previous hunk | |
| `` <right> `` | Go to next hunk | |
| `` v `` | Toggle range select | |
| `` a `` | Selecione o local | Ativa/desativa modo seleção de hunk |
| `` <c-o> `` | Copy selected text to clipboard | |
| `` <space> `` | Etapa | Ativar/desativar seleção em staged/unstaged |
| `` d `` | Descartar | Quando a mudança não desejada for selecionada, descarte a mudança usando `git reset`. Quando a mudança em fase é selecionada, despare a mudança. |
| `` o `` | Abrir arquivo | Abrir arquivo no aplicativo padrão. |
| `` e `` | Editar arquivo | Abrir arquivo no editor externo. |
| `` <esc> `` | Retornar ao painel de arquivos | |
| `` <tab> `` | Mudar de visão | Alternar para outra visão (staged/não processadas alterações). |
| `` E `` | Editar hunk | Editar o local selecionado no editor externo. |
| `` c `` | Commit | Submeter mudanças em staging |
| `` w `` | Commit changes without pre-commit hook | |
| `` C `` | Enviar alteração usando um editor Git | |
| `` <c-f> `` | Encontrar commit da base para consertar | Encontre o commit em que as suas mudanças atuais estão se baseando, para alterar/consertar o commit. Isso poupa-te você de ter que olhar pelos commits da sua branch um por um para ver qual commit deve ser alterado/consertado
Veja a documentação:
<https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
| `` / `` | Search the current view by text | |
## Painel principal (mesclagem)
| Key | Action | Info |
|-----|--------|-------------|
| `` <space> `` | Escolha o local | |
| `` b `` | Pegar todos os pedaços | |
| `` <up> `` | Previous hunk | |
| `` <down> `` | Next hunk | |
| `` <left> `` | Previous conflict | |
| `` <right> `` | Next conflict | |
| `` z `` | Desfazer | Desfazer resolução de conflitos de última mesclagem. |
| `` e `` | Editar arquivo | Abrir arquivo no editor externo. |
| `` o `` | Abrir arquivo | Abrir arquivo no aplicativo padrão. |
| `` M `` | Abrir ferramenta de merge externa | Execute `git mergetool`. |
| `` <esc> `` | Retornar ao painel de arquivos | |
## Painel principal (patch build)
| Key | Action | Info |
|-----|--------|-------------|
| `` <left> `` | Go to previous hunk | |
| `` <right> `` | Go to next hunk | |
| `` v `` | Toggle range select | |
| `` a `` | Selecione o local | Ativa/desativa modo seleção de hunk |
| `` <c-o> `` | Copy selected text to clipboard | |
| `` o `` | Abrir arquivo | Abrir arquivo no aplicativo padrão. |
| `` e `` | Editar arquivo | Abrir arquivo no editor externo. |
| `` <space> `` | Alternar linhas no caminho | |
| `` <esc> `` | Exit custom patch builder | |
| `` / `` | Search the current view by text | |
## Reflog
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Copy commit hash to clipboard | |
| `` <space> `` | Verificar | Checkout the selected commit as a detached HEAD. |
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
| `` o `` | Open commit in browser | |
| `` n `` | Create new branch off of commit | |
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` C `` | Copiar (cherry-pick) | Marcar commit como copiado. Então, dentro da visualização local de commits, você pode pressionar `V` para colar (cherry-pick) o(s) commit(s) copiado(s) em seu branch de check-out. A qualquer momento você pode pressionar `<esc>` para cancelar a seleção. |
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
| `` <enter> `` | View commits | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## Remotes
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | View branches | |
| `` n `` | New remote | |
| `` d `` | Remove | Remove the selected remote. Any local branches tracking a remote branch from the remote will be unaffected. |
| `` e `` | Editar | Edit the selected remote's name or URL. |
| `` f `` | Buscar | Fetch updates from the remote repository. This retrieves new commits and branches without merging them into your local branches. |
| `` / `` | Filter the current view by text | |
## Stash
| Key | Action | Info |
|-----|--------|-------------|
| `` <space> `` | Aplicar | Aplique o stash no seu diretório de trabalho. |
| `` g `` | Pop | Aplique a entrada de stash no seu diretório de trabalho e remova a entrada de stash. |
| `` d `` | Descartar | Remova a entrada do stash da lista de armazenamento. |
| `` n `` | Nova branch | Criar um novo ramo a partir da entrada de lixo selecionada. Isso funciona verificando o commit do qual a entrada de lixo foi criada, criar um novo branch a partir desse commit e, em seguida, aplicar a entrada de lixo ao novo branch como um commit adicional. |
| `` r `` | Renomear o stasj | |
| `` <enter> `` | View files | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## Status
| Key | Action | Info |
|-----|--------|-------------|
| `` o `` | Abrir o ficheiro de config | Abrir arquivo no aplicativo padrão. |
| `` e `` | Editar arquivo de configuração | Abrir arquivo no editor externo. |
| `` u `` | Verificar atualização | |
| `` <enter> `` | Mudar para um repositório recente | |
| `` a `` | Mostrar todos os logs da branch | |
## Sub-commits
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Copy commit hash to clipboard | |
| `` <space> `` | Verificar | Checkout the selected commit as a detached HEAD. |
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
| `` o `` | Open commit in browser | |
| `` n `` | Create new branch off of commit | |
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` C `` | Copiar (cherry-pick) | Marcar commit como copiado. Então, dentro da visualização local de commits, você pode pressionar `V` para colar (cherry-pick) o(s) commit(s) copiado(s) em seu branch de check-out. A qualquer momento você pode pressionar `<esc>` para cancelar a seleção. |
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
| `` <enter> `` | View files | |
| `` w `` | View worktree options | |
| `` / `` | Search the current view by text | |
## Submodules
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Copy submodule name to clipboard | |
| `` <enter> `` | Enter | Enter submodule. After entering the submodule, you can press `<esc>` to escape back to the parent repo. |
| `` d `` | Remove | Remove the selected submodule and its corresponding directory. |
| `` u `` | Update | Update selected submodule. |
| `` n `` | New submodule | |
| `` e `` | Update submodule URL | |
| `` i `` | Initialize | Initialize the selected submodule to prepare for fetching. You probably want to follow this up by invoking the 'update' action to fetch the submodule. |
| `` b `` | View bulk submodule options | |
| `` / `` | Filter the current view by text | |
## Sumário do commit
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | Confirmar | |
| `` <esc> `` | Fechar | |
## Worktrees
| Key | Action | Info |
|-----|--------|-------------|
| `` n `` | New worktree | |
| `` <space> `` | Switch | Switch to the selected worktree. |
| `` o `` | Abrir no editor | |
| `` d `` | Remove | Remove the selected worktree. This will both delete the worktree's directory, as well as metadata about the worktree in the .git directory. |
| `` / `` | Filter the current view by text | |
+7 -1
View File
@@ -261,6 +261,7 @@ If you would instead like to start an interactive rebase from the selected commi
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Скопировать название файла в буфер обмена | |
| `` y `` | Copy to clipboard | |
| `` c `` | Переключить | Переключить файл |
| `` d `` | Remove | Отменить изменения коммита в этом файле |
| `` o `` | Открыть файл | Open file in default application. |
@@ -270,6 +271,8 @@ If you would instead like to start an interactive rebase from the selected commi
| `` a `` | Переключить все файлы, включённые в патч | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
| `` <enter> `` | Введите файл, чтобы добавить выбранные строки в патч (или свернуть каталог переключения) | If a file is selected, enter the file so that you can add/remove individual lines to the custom patch. If a directory is selected, toggle the directory. |
| `` ` `` | Переключить вид дерева файлов | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` / `` | Найти | |
## Статус
@@ -286,7 +289,8 @@ If you would instead like to start an interactive rebase from the selected commi
| Key | Action | Info |
|-----|--------|-------------|
| `` <space> `` | Переключить | Checkout the selected tag tag as a detached HEAD. |
| `` <c-o> `` | Copy tag to clipboard | |
| `` <space> `` | Переключить | Checkout the selected tag as a detached HEAD. |
| `` n `` | Создать тег | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
| `` d `` | Delete | View delete options for local/remote tag. |
| `` P `` | Отправить тег | Push the selected tag to a remote. You'll be prompted to select a remote. |
@@ -353,6 +357,8 @@ If you would instead like to start an interactive rebase from the selected commi
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` M `` | Открыть внешний инструмент слияния (git mergetool) | Run `git mergetool`. |
| `` f `` | Получить изменения | Fetch changes from remote. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` / `` | Найти | |
## Хранилище
+11 -5
View File
@@ -12,8 +12,8 @@ _图例:`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
| `` <pgup> (fn+up/shift+k) `` | 向上滚动主面板 | |
| `` <pgdown> (fn+down/shift+j) `` | 向下滚动主面板 | |
| `` @ `` | 打开命令日志菜单 | 查看命令日志的选项,例如显示/隐藏命令日志以及聚焦命令日志 |
| `` P `` | 推送 | 推送当前分支到它的上游。如果上游为配置,你可以在弹窗中配置上游分支。 |
| `` p `` | 拉取 | 从当前分支的远程分支获取改动。如果上游为配置,你可以在弹窗中配置上游分支。 |
| `` P `` | 推送 | 推送当前分支到它的上游。如果上游未配置,你可以在弹窗中配置上游分支。 |
| `` p `` | 拉取 | 从当前分支的远程分支获取改动。如果上游未配置,你可以在弹窗中配置上游分支。 |
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
| `` } `` | 扩大差异视图中显示的上下文范围 | 增加diff视图中围绕更改显示的上下文数量 |
@@ -76,9 +76,9 @@ _图例:`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
| `` i `` | 显示 git-flow 选项 | |
| `` <space> `` | 检出 | 检出选中的项目 |
| `` n `` | 新分支 | |
| `` o `` | 创建抓取请求 | |
| `` O `` | 创建抓取请求选项 | |
| `` <c-y> `` | 将抓取请求 URL 复制到剪贴板 | |
| `` o `` | 创建拉取请求 | |
| `` O `` | 创建拉取请求选项 | |
| `` <c-y> `` | 将拉取请求 URL 复制到剪贴板 | |
| `` c `` | 按名称检出 | 按名称检出。在输入框中,您可以输入'-' 来切换到最后一个分支。 |
| `` F `` | 强制检出 | 强制检出所选分支。这将在检出所选分支之前放弃工作目录中的所有本地更改。 |
| `` d `` | 删除 | 查看本地/远程分支的删除选项 |
@@ -186,6 +186,7 @@ _图例:`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 将文件名复制到剪贴板 | |
| `` y `` | 复制到剪贴板 | |
| `` c `` | 检出 | 检出文件 |
| `` d `` | 删除 | 放弃对此文件的提交变更 |
| `` o `` | 打开文件 | 使用默认程序打开该文件 |
@@ -195,6 +196,8 @@ _图例:`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
| `` a `` | 操作所有文件 | 添加或删除所有提交中的文件到自定义的补丁中。请参阅 https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches。 |
| `` <enter> `` | 输入文件以将所选行添加到补丁中(或切换目录折叠) | 如果已选择一个文件,则Enter进入该文件,以便您可以向自定义补丁添加/删除单独的行。如果选择了目录,则切换目录。 |
| `` ` `` | 切换文件树视图 | 在平铺部署与树布局之间切换文件视图。平铺布局在一个列表中展示所有文件路径,树布局则根据目录分组展示。 |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` / `` | 开始搜索 | |
## 文件
@@ -225,6 +228,8 @@ _图例:`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
| `` M `` | 打开外部合并工具(git mergetool) | 执行 `git mergetool`. |
| `` f `` | 抓取 | 从远程获取变更 |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` / `` | 开始搜索 | |
## 构建补丁中
@@ -246,6 +251,7 @@ _图例:`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Copy tag to clipboard | |
| `` <space> `` | 检出 | 检出选择的标签作为分离的HEAD |
| `` n `` | 创建标签 | 基于当前提交创建一个新标签。你将在弹窗中输入标签名称和描述(可选)。 |
| `` d `` | 删除 | 查看本地/远程标签的删除选项 |
+7 -1
View File
@@ -210,6 +210,7 @@ If you would instead like to start an interactive rebase from the selected commi
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 複製檔案名稱到剪貼簿 | |
| `` y `` | 複製到剪貼簿 | |
| `` c `` | 檢出 | 檢出檔案 |
| `` d `` | Remove | Discard this commit's changes to this file. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes this file. |
| `` o `` | 開啟檔案 | 使用預設軟體開啟 |
@@ -219,6 +220,8 @@ If you would instead like to start an interactive rebase from the selected commi
| `` a `` | 切換所有檔案是否包含在補丁中 | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
| `` <enter> `` | 輸入檔案以將選定的行添加至補丁(或切換目錄折疊) | If a file is selected, enter the file so that you can add/remove individual lines to the custom patch. If a directory is selected, toggle the directory. |
| `` ` `` | 顯示檔案樹狀視圖 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` / `` | 搜尋 | |
## 收藏 (Stash)
@@ -282,7 +285,8 @@ If you would instead like to start an interactive rebase from the selected commi
| Key | Action | Info |
|-----|--------|-------------|
| `` <space> `` | 檢出 | Checkout the selected tag tag as a detached HEAD. |
| `` <c-o> `` | Copy tag to clipboard | |
| `` <space> `` | 檢出 | Checkout the selected tag as a detached HEAD. |
| `` n `` | 建立標籤 | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
| `` d `` | 刪除 | View delete options for local/remote tag. |
| `` P `` | 推送標籤 | Push the selected tag to a remote. You'll be prompted to select a remote. |
@@ -320,6 +324,8 @@ If you would instead like to start an interactive rebase from the selected commi
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
| `` M `` | 開啟外部合併工具 | 執行 `git mergetool`。 |
| `` f `` | 擷取 | 同步遠端異動 |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` / `` | 搜尋 | |
## 狀態
+11 -12
View File
@@ -8,7 +8,7 @@ require (
github.com/aybabtme/humanlog v0.4.1
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
github.com/creack/pty v1.1.11
github.com/gdamore/tcell/v2 v2.7.4
github.com/gdamore/tcell/v2 v2.8.1
github.com/go-errors/errors v1.5.1
github.com/gookit/color v1.4.2
github.com/iancoleman/orderedmap v0.3.0
@@ -16,8 +16,8 @@ require (
github.com/integrii/flaggy v1.4.0
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d
github.com/jesseduffield/gocui v0.3.1-0.20241223111608-9967d0e928a0
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10
github.com/jesseduffield/gocui v0.3.1-0.20250220081214-b376cb0857ac
github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
@@ -30,7 +30,7 @@ require (
github.com/sahilm/fuzzy v0.1.0
github.com/samber/lo v1.31.0
github.com/sanity-io/litter v1.5.2
github.com/sasha-s/go-deadlock v0.3.1
github.com/sasha-s/go-deadlock v0.3.5
github.com/sirupsen/logrus v1.4.2
github.com/spf13/afero v1.9.5
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad
@@ -38,7 +38,7 @@ require (
github.com/stretchr/testify v1.8.1
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8
golang.org/x/sync v0.10.0
golang.org/x/sync v0.11.0
gopkg.in/ozeidan/fuzzy-patricia.v3 v3.0.0
gopkg.in/yaml.v3 v3.0.1
)
@@ -54,7 +54,6 @@ require (
github.com/go-git/go-billy/v5 v5.0.0 // indirect
github.com/go-logfmt/logfmt v0.5.0 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/google/go-cmp v0.5.6 // indirect
github.com/invopop/jsonschema v0.10.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect
@@ -67,16 +66,16 @@ require (
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/onsi/ginkgo v1.10.3 // indirect
github.com/onsi/gomega v1.7.1 // indirect
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/sergi/go-diff v1.1.0 // indirect
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
github.com/xanzy/ssh-agent v0.2.1 // indirect
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/term v0.27.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/term v0.29.0 // indirect
golang.org/x/text v0.22.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
)
+52 -23
View File
@@ -85,11 +85,11 @@ github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw=
github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo=
github.com/gdamore/tcell/v2 v2.7.4 h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAYU=
github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg=
github.com/gdamore/tcell/v2 v2.8.0/go.mod h1:bj8ori1BG3OYMjmb3IklZVWfZUJ1UBQt9JXrOCOhGWw=
github.com/gdamore/tcell/v2 v2.8.1 h1:KPNxyqclpWpWQlPLx6Xui1pMk8S+7+R37h3g07997NU=
github.com/gdamore/tcell/v2 v2.8.1/go.mod h1:bj8ori1BG3OYMjmb3IklZVWfZUJ1UBQt9JXrOCOhGWw=
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
@@ -145,8 +145,8 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@@ -188,10 +188,10 @@ github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 h1:EQP2Tv8T
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk=
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d h1:bO+OmbreIv91rCe8NmscRwhFSqkDJtzWCPV4Y+SQuXE=
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o=
github.com/jesseduffield/gocui v0.3.1-0.20241223111608-9967d0e928a0 h1:R29+E15wHqTDBfZxmzCLu0x34j5ljsXWT/DhR+2YiOU=
github.com/jesseduffield/gocui v0.3.1-0.20241223111608-9967d0e928a0/go.mod h1:XtEbqCbn45keRXEu+OMZkjN5gw6AEob59afsgHjokZ8=
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0=
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo=
github.com/jesseduffield/gocui v0.3.1-0.20250220081214-b376cb0857ac h1:vUNTiVEB9Bz16pTJ5kNgb/1HhnWdSA1P0GfFLUJeITI=
github.com/jesseduffield/gocui v0.3.1-0.20250220081214-b376cb0857ac/go.mod h1:sLIyZ2J42R6idGdtemZzsiR3xY5EF0KsvYEGh3dQv3s=
github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a h1:UDeJ3EBk04bXDLOPvuqM3on8HvyJfISw0+UMqW+0a4g=
github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a/go.mod h1:FSWDLKT0NQpntbDd1H3lbz51fhCVlMzy/J0S6nM727Q=
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY=
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5/go.mod h1:qxN4mHOAyeIDLP7IK7defgPClM/z1Kze8VVQiaEjzsQ=
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e h1:uw/oo+kg7t/oeMs6sqlAwr85ND/9cpO3up3VxphxY0U=
@@ -235,7 +235,6 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mgutz/str v1.2.0 h1:4IzWSdIz9qPQWLfKZ0rJcV0jcUDpxvP4JVZ4GXQyvSw=
@@ -251,8 +250,8 @@ github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY=
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ=
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o=
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw=
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -272,8 +271,8 @@ github.com/samber/lo v1.31.0 h1:Sfa+/064Tdo4SvlohQUQzBhgSer9v/coGvKQI/XLWAM=
github.com/samber/lo v1.31.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8=
github.com/sanity-io/litter v1.5.2 h1:AnC8s9BMORWH5a4atZ4D6FPVvKGzHcnc5/IVTa87myw=
github.com/sanity-io/litter v1.5.2/go.mod h1:5Z71SvaYy5kcGtyglXOC9rrUi3c1E8CamFWjQsazTh0=
github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0=
github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM=
github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU=
github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
@@ -327,8 +326,12 @@ golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -366,6 +369,9 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -401,8 +407,12 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -424,8 +434,12 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20170407050850-f3918c30c5c2/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -474,15 +488,24 @@ golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -492,9 +515,13 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -547,6 +574,8 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+10 -5
View File
@@ -29,16 +29,17 @@ type cliArgs struct {
RepoPath string
FilterPath string
GitArg string
UseConfigDir string
WorkTree string
GitDir string
CustomConfigFile string
ScreenMode string
PrintVersionInfo bool
Debug bool
TailLogs bool
Profile bool
PrintDefaultConfig bool
PrintConfigDir bool
UseConfigDir string
WorkTree string
GitDir string
CustomConfigFile string
}
type BuildInfo struct {
@@ -164,7 +165,7 @@ func Start(buildInfo *BuildInfo, integrationTest integrationTypes.IntegrationTes
parsedGitArg := parseGitArg(cliArgs.GitArg)
Run(appConfig, common, appTypes.NewStartArgs(cliArgs.FilterPath, parsedGitArg, integrationTest))
Run(appConfig, common, appTypes.NewStartArgs(cliArgs.FilterPath, parsedGitArg, cliArgs.ScreenMode, integrationTest))
}
func parseCliArgsAndEnvVars() *cliArgs {
@@ -209,6 +210,9 @@ func parseCliArgsAndEnvVars() *cliArgs {
customConfigFile := ""
flaggy.String(&customConfigFile, "ucf", "use-config-file", "Comma separated list to custom config file(s)")
screenMode := ""
flaggy.String(&screenMode, "sm", "screen-mode", "The initial screen-mode, which determines the size of the focused panel. Valid options: 'normal' (default), 'half', 'full'")
flaggy.Parse()
if os.Getenv("DEBUG") == "TRUE" {
@@ -229,6 +233,7 @@ func parseCliArgsAndEnvVars() *cliArgs {
WorkTree: workTree,
GitDir: gitDir,
CustomConfigFile: customConfigFile,
ScreenMode: screenMode,
}
}
+6 -3
View File
@@ -6,12 +6,14 @@ import (
// StartArgs is the struct that represents some things we want to do on program start
type StartArgs struct {
// FilterPath determines which path we're going to filter on so that we only see commits from that file.
FilterPath string
// GitArg determines what context we open in
GitArg GitArg
// integration test (only relevant when invoking lazygit in the context of an integration test)
IntegrationTest integrationTypes.IntegrationTest
// FilterPath determines which path we're going to filter on so that we only see commits from that file.
FilterPath string
// ScreenMode determines the initial Screen Mode (normal, half or full) to use
ScreenMode string
}
type GitArg string
@@ -24,10 +26,11 @@ const (
GitArgStash GitArg = "stash"
)
func NewStartArgs(filterPath string, gitArg GitArg, test integrationTypes.IntegrationTest) StartArgs {
func NewStartArgs(filterPath string, gitArg GitArg, screenMode string, test integrationTypes.IntegrationTest) StartArgs {
return StartArgs{
FilterPath: filterPath,
GitArg: gitArg,
ScreenMode: screenMode,
IntegrationTest: test,
}
}
+1
View File
@@ -275,6 +275,7 @@ func (self *BranchCommands) IsBranchMerged(branch *models.Branch, mainBranches *
Arg(lo.Map(branchesToCheckAgainst, func(branch string, _ int) string {
return fmt.Sprintf("^%s", branch)
})...).
Arg("--").
ToArgv()
stdout, _, err := self.cmd.New(cmdArgs).RunWithOutputs()
+15 -19
View File
@@ -16,6 +16,8 @@ func NewDiffCommands(gitCommon *GitCommon) *DiffCommands {
}
}
// This is for generating diffs to be shown in the UI (e.g. rendering a range
// diff to the main view). It uses a custom pager if one is configured.
func (self *DiffCommands) DiffCmdObj(diffArgs []string) oscommands.ICmdObj {
extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand
useExtDiff := extDiffCmd != ""
@@ -36,27 +38,21 @@ func (self *DiffCommands) DiffCmdObj(diffArgs []string) oscommands.ICmdObj {
)
}
func (self *DiffCommands) internalDiffCmdObj(diffArgs ...string) *GitCommandBuilder {
return NewGitCmd("diff").
Config("diff.noprefix=false").
Arg("--no-ext-diff", "--no-color").
Arg(diffArgs...).
Dir(self.repoPaths.worktreePath)
}
func (self *DiffCommands) GetPathDiff(path string, staged bool) (string, error) {
// This is a basic generic diff command that can be used for any diff operation
// (e.g. copying a diff to the clipboard). It will not use a custom pager, and
// does not use user configs such as ignore whitespace.
// If you want to diff specific refs (one or two), you need to add them yourself
// in additionalArgs; it is recommended to also pass `--` after that. If you
// want to restrict the diff to specific paths, pass them in additionalArgs
// after the `--`.
func (self *DiffCommands) GetDiff(staged bool, additionalArgs ...string) (string, error) {
return self.cmd.New(
self.internalDiffCmdObj().
ArgIf(staged, "--staged").
Arg(path).
ToArgv(),
).RunWithOutput()
}
func (self *DiffCommands) GetAllDiff(staged bool) (string, error) {
return self.cmd.New(
self.internalDiffCmdObj().
NewGitCmd("diff").
Config("diff.noprefix=false").
Arg("--no-ext-diff", "--no-color").
ArgIf(staged, "--staged").
Dir(self.repoPaths.worktreePath).
Arg(additionalArgs...).
ToArgv(),
).RunWithOutput()
}
+5 -1
View File
@@ -32,13 +32,17 @@ func NewFileLoader(gitCommon *GitCommon, cmd oscommands.ICmdObjBuilder, config F
type GetStatusFileOptions struct {
NoRenames bool
// If true, we'll show untracked files even if the user has set the config to hide them.
// This is useful for users with bare repos for dotfiles who default to hiding untracked files,
// but want to occasionally see them to `git add` a new file.
ForceShowUntracked bool
}
func (self *FileLoader) GetStatusFiles(opts GetStatusFileOptions) []*models.File {
// check if config wants us ignoring untracked files
untrackedFilesSetting := self.config.GetShowUntrackedFiles()
if untrackedFilesSetting == "" {
if opts.ForceShowUntracked || untrackedFilesSetting == "" {
untrackedFilesSetting = "all"
}
untrackedFilesArg := fmt.Sprintf("--untracked-files=%s", untrackedFilesSetting)
@@ -76,6 +76,14 @@ func (self *GitCommandBuilder) Worktree(path string) *GitCommandBuilder {
return self
}
func (self *GitCommandBuilder) WorktreePathIf(condition bool, path string) *GitCommandBuilder {
if condition {
return self.Worktree(path)
}
return self
}
// Note, you may prefer to use the Dir method instead of this one
func (self *GitCommandBuilder) GitDir(path string) *GitCommandBuilder {
// git dir arg comes before the command
+2
View File
@@ -81,9 +81,11 @@ func (self *StashCommands) Hash(index int) (string, error) {
}
func (self *StashCommands) ShowStashEntryCmdObj(index int) oscommands.ICmdObj {
// "-u" is the same as "--include-untracked", but the latter fails in older git versions for some reason
cmdArgs := NewGitCmd("stash").Arg("show").
Arg("-p").
Arg("--stat").
Arg("-u").
Arg(fmt.Sprintf("--color=%s", self.UserConfig().Git.Paging.ColorArg)).
Arg(fmt.Sprintf("--unified=%d", self.AppState.DiffContextSize)).
ArgIf(self.AppState.IgnoreWhitespaceInDiffView, "--ignore-all-space").
+4 -4
View File
@@ -113,7 +113,7 @@ func TestStashStashEntryCmdObj(t *testing.T) {
contextSize: 3,
similarityThreshold: 50,
ignoreWhitespace: false,
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "--color=always", "--unified=3", "--find-renames=50%", "stash@{5}"},
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "-u", "--color=always", "--unified=3", "--find-renames=50%", "stash@{5}"},
},
{
testName: "Show diff with custom context size",
@@ -121,7 +121,7 @@ func TestStashStashEntryCmdObj(t *testing.T) {
contextSize: 77,
similarityThreshold: 50,
ignoreWhitespace: false,
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "--color=always", "--unified=77", "--find-renames=50%", "stash@{5}"},
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "-u", "--color=always", "--unified=77", "--find-renames=50%", "stash@{5}"},
},
{
testName: "Show diff with custom similarity threshold",
@@ -129,7 +129,7 @@ func TestStashStashEntryCmdObj(t *testing.T) {
contextSize: 3,
similarityThreshold: 33,
ignoreWhitespace: false,
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "--color=always", "--unified=3", "--find-renames=33%", "stash@{5}"},
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "-u", "--color=always", "--unified=3", "--find-renames=33%", "stash@{5}"},
},
{
testName: "Default case",
@@ -137,7 +137,7 @@ func TestStashStashEntryCmdObj(t *testing.T) {
contextSize: 3,
similarityThreshold: 50,
ignoreWhitespace: true,
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "--color=always", "--unified=3", "--ignore-all-space", "--find-renames=50%", "stash@{5}"},
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "-u", "--color=always", "--unified=3", "--ignore-all-space", "--find-renames=50%", "stash@{5}"},
},
}
+6 -1
View File
@@ -1,6 +1,8 @@
package git_commands
import (
"fmt"
"github.com/go-errors/errors"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
@@ -20,6 +22,7 @@ func NewSyncCommands(gitCommon *GitCommon) *SyncCommands {
type PushOpts struct {
Force bool
ForceWithLease bool
CurrentBranch string
UpstreamRemote string
UpstreamBranch string
SetUpstream bool
@@ -35,7 +38,7 @@ func (self *SyncCommands) PushCmdObj(task gocui.Task, opts PushOpts) (oscommands
ArgIf(opts.ForceWithLease, "--force-with-lease").
ArgIf(opts.SetUpstream, "--set-upstream").
ArgIf(opts.UpstreamRemote != "", opts.UpstreamRemote).
ArgIf(opts.UpstreamBranch != "", "HEAD:"+opts.UpstreamBranch).
ArgIf(opts.UpstreamBranch != "", fmt.Sprintf("refs/heads/%s:%s", opts.CurrentBranch, opts.UpstreamBranch)).
ToArgv()
cmdObj := self.cmd.New(cmdArgs).PromptOnCredentialRequest(task)
@@ -88,6 +91,7 @@ type PullOptions struct {
BranchName string
FastForwardOnly bool
WorktreeGitDir string
WorktreePath string
}
func (self *SyncCommands) Pull(task gocui.Task, opts PullOptions) error {
@@ -97,6 +101,7 @@ func (self *SyncCommands) Pull(task gocui.Task, opts PullOptions) error {
ArgIf(opts.RemoteName != "", opts.RemoteName).
ArgIf(opts.BranchName != "", "refs/heads/"+opts.BranchName).
GitDirIf(opts.WorktreeGitDir != "", opts.WorktreeGitDir).
WorktreePathIf(opts.WorktreePath != "", opts.WorktreePath).
ToArgv()
// setting GIT_SEQUENCE_EDITOR to ':' as a way of skipping it, in case the user
+6 -3
View File
@@ -44,11 +44,12 @@ func TestSyncPush(t *testing.T) {
testName: "Push with force disabled, upstream supplied",
opts: PushOpts{
ForceWithLease: false,
CurrentBranch: "master",
UpstreamRemote: "origin",
UpstreamBranch: "master",
},
test: func(cmdObj oscommands.ICmdObj, err error) {
assert.Equal(t, cmdObj.Args(), []string{"git", "push", "origin", "HEAD:master"})
assert.Equal(t, cmdObj.Args(), []string{"git", "push", "origin", "refs/heads/master:master"})
assert.NoError(t, err)
},
},
@@ -56,12 +57,13 @@ func TestSyncPush(t *testing.T) {
testName: "Push with force disabled, setting upstream",
opts: PushOpts{
ForceWithLease: false,
CurrentBranch: "master-local",
UpstreamRemote: "origin",
UpstreamBranch: "master",
SetUpstream: true,
},
test: func(cmdObj oscommands.ICmdObj, err error) {
assert.Equal(t, cmdObj.Args(), []string{"git", "push", "--set-upstream", "origin", "HEAD:master"})
assert.Equal(t, cmdObj.Args(), []string{"git", "push", "--set-upstream", "origin", "refs/heads/master-local:master"})
assert.NoError(t, err)
},
},
@@ -69,12 +71,13 @@ func TestSyncPush(t *testing.T) {
testName: "Push with force-with-lease enabled, setting upstream",
opts: PushOpts{
ForceWithLease: true,
CurrentBranch: "master",
UpstreamRemote: "origin",
UpstreamBranch: "master",
SetUpstream: true,
},
test: func(cmdObj oscommands.ICmdObj, err error) {
assert.Equal(t, cmdObj.Args(), []string{"git", "push", "--force-with-lease", "--set-upstream", "origin", "HEAD:master"})
assert.Equal(t, cmdObj.Args(), []string{"git", "push", "--force-with-lease", "--set-upstream", "origin", "refs/heads/master:master"})
assert.NoError(t, err)
},
},
@@ -1,7 +1,6 @@
package git_commands
import (
"fmt"
"testing"
"github.com/go-errors/errors"
@@ -100,7 +99,7 @@ func TestWorkingTreeDiscardAllFileChanges(t *testing.T) {
Added: true,
},
removeFile: func(string) error {
return fmt.Errorf("an error occurred when removing file")
return errors.New("an error occurred when removing file")
},
runner: oscommands.NewFakeRunner(t),
expectedError: "an error occurred when removing file",
@@ -48,6 +48,7 @@ var azdoServiceDef = ServiceDefinition{
regexStrings: []string{
`^git@ssh.dev.azure.com.*/(?P<org>.*)/(?P<project>.*)/(?P<repo>.*?)(?:\.git)?$`,
`^https://.*@dev.azure.com/(?P<org>.*?)/(?P<project>.*?)/_git/(?P<repo>.*?)(?:\.git)?$`,
`^https://.*/(?P<org>.*?)/(?P<project>.*?)/_git/(?P<repo>.*?)(?:\.git)?$`,
},
repoURLTemplate: "https://{{.webDomain}}/{{.org}}/{{.project}}/_git/{{.repo}}",
}
@@ -210,6 +210,19 @@ func TestGetPullRequestURL(t *testing.T) {
assert.Equal(t, "https://dev.azure.com/myorg/myproject/_git/myrepo/pullrequestcreate?sourceRef=feature%2Fnew&targetRef=dev", url)
},
},
{
testName: "Opens a link to new pull request on Azure DevOps Server (HTTP)",
from: "feature/new",
remoteUrl: "https://mycompany.azuredevops.com/collection/myproject/_git/myrepo",
configServiceDomains: map[string]string{
// valid configuration for a azure devops server URL
"mycompany.azuredevops.com": "azuredevops:mycompany.azuredevops.com",
},
test: func(url string, err error) {
assert.NoError(t, err)
assert.Equal(t, "https://mycompany.azuredevops.com/collection/myproject/_git/myrepo/pullrequestcreate?sourceRef=feature%2Fnew", url)
},
},
{
testName: "Opens a link to new pull request on Bitbucket Server (SSH)",
from: "feature/new",
+16 -3
View File
@@ -6,16 +6,29 @@ package oscommands
import (
"os"
"runtime"
"strings"
)
func GetPlatform() *Platform {
shell := getUserShell()
interactiveShell := shell
interactiveShellArg := "-i"
interactiveShellExit := "; exit $?"
if !(strings.HasSuffix(shell, "bash") || strings.HasSuffix(shell, "zsh")) {
interactiveShell = "bash"
interactiveShellArg = ""
interactiveShellExit = ""
}
return &Platform{
OS: runtime.GOOS,
Shell: "bash",
InteractiveShell: getUserShell(),
InteractiveShell: interactiveShell,
ShellArg: "-c",
InteractiveShellArg: "-i",
InteractiveShellExit: "; exit $?",
InteractiveShellArg: interactiveShellArg,
InteractiveShellExit: interactiveShellExit,
OpenCommand: "open {{filename}}",
OpenLinkCommand: "open {{link}}",
}
+1 -1
View File
@@ -122,7 +122,7 @@ func TestOSCommandFileType(t *testing.T) {
},
},
{
"nonExistant",
"nonExistent",
func() {},
func(output string) {
assert.EqualValues(t, "other", output)
+21
View File
@@ -154,3 +154,24 @@ func (self *Patch) LineCount() int {
func (self *Patch) HunkCount() int {
return len(self.hunks)
}
// Adjust the given line number (one-based) according to the current patch. The
// patch is supposed to be a diff of an old file state against the working
// directory; the line number is a line number in that old file, and the
// function returns the corresponding line number in the working directory file.
func (self *Patch) AdjustLineNumber(lineNumber int) int {
adjustedLineNumber := lineNumber
for _, hunk := range self.hunks {
if hunk.oldStart >= lineNumber {
break
}
if hunk.oldStart+hunk.oldLength() > lineNumber {
return hunk.newStart
}
adjustedLineNumber += hunk.newLength() - hunk.oldLength()
}
return adjustedLineNumber
}
+56
View File
@@ -639,3 +639,59 @@ func TestGetNextStageableLineIndex(t *testing.T) {
})
}
}
func TestAdjustLineNumber(t *testing.T) {
type scenario struct {
oldLineNumbers []int
expectedResults []int
}
scenarios := []scenario{
{
oldLineNumbers: []int{1, 2, 3, 4, 5, 6, 7},
expectedResults: []int{1, 2, 2, 3, 4, 7, 8},
},
}
// The following diff was generated from old.txt:
// 1
// 2a
// 2b
// 3
// 4
// 7
// 8
// against new.txt:
// 1
// 2
// 3
// 4
// 5
// 6
// 7
// 8
// This test setup makes the test easy to understand, because the resulting
// adjusted line numbers are the same as the content of the lines in new.txt.
diff := `--- old.txt 2024-12-16 18:04:29
+++ new.txt 2024-12-16 18:04:27
@@ -2,2 +2 @@
-2a
-2b
+2
@@ -5,0 +5,2 @@
+5
+6
`
patch := Parse(diff)
for _, s := range scenarios {
t.Run("TestAdjustLineNumber", func(t *testing.T) {
for idx, oldLineNumber := range s.oldLineNumbers {
result := patch.AdjustLineNumber(oldLineNumber)
assert.Equal(t, s.expectedResults[idx], result)
}
})
}
}
+84 -16
View File
@@ -217,16 +217,43 @@ func loadUserConfig(configFiles []*ConfigFile, base *UserConfig) (*UserConfig, e
// from one container to another, or changing the type of a key (e.g. from bool
// to an enum).
func migrateUserConfig(path string, content []byte) ([]byte, error) {
changedContent, err := yaml_utils.RenameYamlKey(content, []string{"gui", "skipUnstageLineWarning"},
"skipDiscardChangeWarning")
changedContent, err := computeMigratedConfig(path, content)
if err != nil {
return nil, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err)
return nil, err
}
changedContent, err = yaml_utils.RenameYamlKey(changedContent, []string{"keybinding", "universal", "executeCustomCommand"},
"executeShellCommand")
if err != nil {
return nil, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err)
// Write config back if changed
if string(changedContent) != string(content) {
fmt.Println("Provided user config is deprecated but auto-fixable. Attempting to write fixed version back to file...")
if err := os.WriteFile(path, changedContent, 0o644); err != nil {
return nil, fmt.Errorf("While attempting to write back fixed user config to %s, an error occurred: %s", path, err)
}
fmt.Printf("Success. New config written to %s\n", path)
return changedContent, nil
}
return content, nil
}
// A pure function helper for testing purposes
func computeMigratedConfig(path string, content []byte) ([]byte, error) {
changedContent := content
pathsToReplace := []struct {
oldPath []string
newName string
}{
{[]string{"gui", "skipUnstageLineWarning"}, "skipDiscardChangeWarning"},
{[]string{"keybinding", "universal", "executeCustomCommand"}, "executeShellCommand"},
{[]string{"gui", "windowSize"}, "screenMode"},
}
var err error
for _, pathToReplace := range pathsToReplace {
changedContent, err = yaml_utils.RenameYamlKey(changedContent, pathToReplace.oldPath, pathToReplace.newName)
if err != nil {
return nil, fmt.Errorf("Couldn't migrate config file at `%s` for key %s: %s", path, strings.Join(pathToReplace.oldPath, "."), err)
}
}
changedContent, err = changeNullKeybindingsToDisabled(changedContent)
@@ -234,17 +261,18 @@ func migrateUserConfig(path string, content []byte) ([]byte, error) {
return nil, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err)
}
// Add more migrations here...
// Write config back if changed
if string(changedContent) != string(content) {
if err := os.WriteFile(path, changedContent, 0o644); err != nil {
return nil, fmt.Errorf("Couldn't write migrated config back to `%s`: %s", path, err)
}
return changedContent, nil
changedContent, err = changeElementToSequence(changedContent, []string{"git", "commitPrefix"})
if err != nil {
return nil, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err)
}
return content, nil
changedContent, err = changeCommitPrefixesMap(changedContent)
if err != nil {
return nil, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err)
}
// Add more migrations here...
return changedContent, nil
}
func changeNullKeybindingsToDisabled(changedContent []byte) ([]byte, error) {
@@ -258,6 +286,46 @@ func changeNullKeybindingsToDisabled(changedContent []byte) ([]byte, error) {
})
}
func changeElementToSequence(changedContent []byte, path []string) ([]byte, error) {
return yaml_utils.TransformNode(changedContent, path, func(node *yaml.Node) (bool, error) {
if node.Kind == yaml.MappingNode {
nodeContentCopy := node.Content
node.Kind = yaml.SequenceNode
node.Value = ""
node.Tag = "!!seq"
node.Content = []*yaml.Node{{
Kind: yaml.MappingNode,
Content: nodeContentCopy,
}}
return true, nil
}
return false, nil
})
}
func changeCommitPrefixesMap(changedContent []byte) ([]byte, error) {
return yaml_utils.TransformNode(changedContent, []string{"git", "commitPrefixes"}, func(prefixesNode *yaml.Node) (bool, error) {
if prefixesNode.Kind == yaml.MappingNode {
for _, contentNode := range prefixesNode.Content {
if contentNode.Kind == yaml.MappingNode {
nodeContentCopy := contentNode.Content
contentNode.Kind = yaml.SequenceNode
contentNode.Value = ""
contentNode.Tag = "!!seq"
contentNode.Content = []*yaml.Node{{
Kind: yaml.MappingNode,
Content: nodeContentCopy,
}}
}
}
return true, nil
}
return false, nil
})
}
func (c *AppConfig) GetDebug() bool {
return c.debug
}
+78
View File
@@ -0,0 +1,78 @@
package config
import (
"testing"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
)
func TestCommitPrefixMigrations(t *testing.T) {
scenarios := []struct {
name string
input string
expected string
}{
{
"Empty String",
"",
"",
}, {
"Single CommitPrefix Rename",
`
git:
commitPrefix:
pattern: "^\\w+-\\w+.*"
replace: '[JIRA $0] '`,
`
git:
commitPrefix:
- pattern: "^\\w+-\\w+.*"
replace: '[JIRA $0] '`,
}, {
"Complicated CommitPrefixes Rename",
`
git:
commitPrefixes:
foo:
pattern: "^\\w+-\\w+.*"
replace: '[OTHER $0] '
CrazyName!@#$^*&)_-)[[}{f{[]:
pattern: "^foo.bar*"
replace: '[FUN $0] '`,
`
git:
commitPrefixes:
foo:
- pattern: "^\\w+-\\w+.*"
replace: '[OTHER $0] '
CrazyName!@#$^*&)_-)[[}{f{[]:
- pattern: "^foo.bar*"
replace: '[FUN $0] '`,
}, {
"Incomplete Configuration",
"git:",
"git:",
},
}
for _, s := range scenarios {
t.Run(s.name, func(t *testing.T) {
expectedConfig := GetDefaultConfig()
err := yaml.Unmarshal([]byte(s.expected), expectedConfig)
if err != nil {
t.Error(err)
}
actual, err := computeMigratedConfig("path doesn't matter", []byte(s.input))
if err != nil {
t.Error(err)
}
actualConfig := GetDefaultConfig()
err = yaml.Unmarshal(actual, actualConfig)
if err != nil {
t.Error(err)
}
assert.Equal(t, expectedConfig, actualConfig)
})
}
}
+9 -3
View File
@@ -66,9 +66,15 @@ func getPreset(osConfig *OSConfig, guessDefaultEditor func() string) *editPreset
return !ok
},
},
"lvim": standardTerminalEditorPreset("lvim"),
"emacs": standardTerminalEditorPreset("emacs"),
"micro": standardTerminalEditorPreset("micro"),
"lvim": standardTerminalEditorPreset("lvim"),
"emacs": standardTerminalEditorPreset("emacs"),
"micro": {
editTemplate: "micro {{filename}}",
editAtLineTemplate: "micro +{{line}} {{filename}}",
editAtLineAndWaitTemplate: "micro +{{line}} {{filename}}",
openDirInEditorTemplate: "micro {{dir}}",
suspend: returnBool(true),
},
"nano": standardTerminalEditorPreset("nano"),
"kakoune": standardTerminalEditorPreset("kak"),
"helix": {
+93
View File
@@ -0,0 +1,93 @@
package config
import (
"strings"
"unicode/utf8"
"github.com/jesseduffield/gocui"
"github.com/samber/lo"
)
// NOTE: if you make changes to this table, be sure to update
// docs/keybindings/Custom_Keybindings.md as well
var LabelByKey = map[gocui.Key]string{
gocui.KeyF1: "<f1>",
gocui.KeyF2: "<f2>",
gocui.KeyF3: "<f3>",
gocui.KeyF4: "<f4>",
gocui.KeyF5: "<f5>",
gocui.KeyF6: "<f6>",
gocui.KeyF7: "<f7>",
gocui.KeyF8: "<f8>",
gocui.KeyF9: "<f9>",
gocui.KeyF10: "<f10>",
gocui.KeyF11: "<f11>",
gocui.KeyF12: "<f12>",
gocui.KeyInsert: "<insert>",
gocui.KeyDelete: "<delete>",
gocui.KeyHome: "<home>",
gocui.KeyEnd: "<end>",
gocui.KeyPgup: "<pgup>",
gocui.KeyPgdn: "<pgdown>",
gocui.KeyArrowUp: "<up>",
gocui.KeyShiftArrowUp: "<s-up>",
gocui.KeyArrowDown: "<down>",
gocui.KeyShiftArrowDown: "<s-down>",
gocui.KeyArrowLeft: "<left>",
gocui.KeyArrowRight: "<right>",
gocui.KeyTab: "<tab>", // <c-i>
gocui.KeyBacktab: "<backtab>",
gocui.KeyEnter: "<enter>", // <c-m>
gocui.KeyAltEnter: "<a-enter>",
gocui.KeyEsc: "<esc>", // <c-[>, <c-3>
gocui.KeyBackspace: "<backspace>", // <c-h>
gocui.KeyCtrlSpace: "<c-space>", // <c-~>, <c-2>
gocui.KeyCtrlSlash: "<c-/>", // <c-_>
gocui.KeySpace: "<space>",
gocui.KeyCtrlA: "<c-a>",
gocui.KeyCtrlB: "<c-b>",
gocui.KeyCtrlC: "<c-c>",
gocui.KeyCtrlD: "<c-d>",
gocui.KeyCtrlE: "<c-e>",
gocui.KeyCtrlF: "<c-f>",
gocui.KeyCtrlG: "<c-g>",
gocui.KeyCtrlJ: "<c-j>",
gocui.KeyCtrlK: "<c-k>",
gocui.KeyCtrlL: "<c-l>",
gocui.KeyCtrlN: "<c-n>",
gocui.KeyCtrlO: "<c-o>",
gocui.KeyCtrlP: "<c-p>",
gocui.KeyCtrlQ: "<c-q>",
gocui.KeyCtrlR: "<c-r>",
gocui.KeyCtrlS: "<c-s>",
gocui.KeyCtrlT: "<c-t>",
gocui.KeyCtrlU: "<c-u>",
gocui.KeyCtrlV: "<c-v>",
gocui.KeyCtrlW: "<c-w>",
gocui.KeyCtrlX: "<c-x>",
gocui.KeyCtrlY: "<c-y>",
gocui.KeyCtrlZ: "<c-z>",
gocui.KeyCtrl4: "<c-4>", // <c-\>
gocui.KeyCtrl5: "<c-5>", // <c-]>
gocui.KeyCtrl6: "<c-6>",
gocui.KeyCtrl8: "<c-8>",
gocui.MouseWheelUp: "mouse wheel up",
gocui.MouseWheelDown: "mouse wheel down",
}
var KeyByLabel = lo.Invert(LabelByKey)
func isValidKeybindingKey(key string) bool {
runeCount := utf8.RuneCountInString(key)
if key == "<disabled>" {
return true
}
if runeCount > 1 {
_, ok := KeyByLabel[strings.ToLower(key)]
return ok
}
return true
}
+20 -9
View File
@@ -52,7 +52,10 @@ type GuiConfig struct {
// See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-author-color
AuthorColors map[string]string `yaml:"authorColors"`
// See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-branch-color
// Deprecated: use branchColorPatterns instead
BranchColors map[string]string `yaml:"branchColors"`
// See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-branch-color
BranchColorPatterns map[string]string `yaml:"branchColorPatterns"`
// The number of lines you scroll by when scrolling the main window
ScrollHeight int `yaml:"scrollHeight" jsonschema:"minimum=1"`
// If true, allow scrolling past the bottom of the content in the main window
@@ -61,6 +64,9 @@ type GuiConfig struct {
ScrollOffMargin int `yaml:"scrollOffMargin"`
// One of: 'margin' (default) | 'jump'
ScrollOffBehavior string `yaml:"scrollOffBehavior"`
// The number of spaces per tab; used for everything that's shown in the main view, but probably mostly relevant for diffs.
// Note that when using a pager, the pager has its own tab width setting, so you need to pass it separately in the pager command.
TabWidth int `yaml:"tabWidth" jsonschema:"minimum=1"`
// If true, capture mouse events.
// When mouse events are captured, it's a little harder to select text: e.g. requiring you to hold the option key when on macOS.
MouseEvents bool `yaml:"mouseEvents"`
@@ -111,7 +117,7 @@ type GuiConfig struct {
// If true, show the '5 of 20' footer at the bottom of list views
ShowListFooter bool `yaml:"showListFooter"`
// If true, display the files in the file views as a tree. If false, display the files as a flat list.
// This can be toggled from within Lazygit with the '~' key, but that will not change the default.
// This can be toggled from within Lazygit with the '`' key, but that will not change the default.
ShowFileTree bool `yaml:"showFileTree"`
// If true, show the number of lines changed per file in the Files view
ShowNumstatInFilesView bool `yaml:"showNumstatInFilesView"`
@@ -148,9 +154,9 @@ type GuiConfig struct {
// One of: 'auto' | 'always'
// If 'auto', only split the main window when a file has both staged and unstaged changes
SplitDiff string `yaml:"splitDiff" jsonschema:"enum=auto,enum=always"`
// Default size for focused window. Window size can be changed from within Lazygit with '+' and '_' (but this won't change the default).
// Default size for focused window. Can be changed from within Lazygit with '+' and '_' (but this won't change the default).
// One of: 'normal' (default) | 'half' | 'full'
WindowSize string `yaml:"windowSize" jsonschema:"enum=normal,enum=half,enum=full"`
ScreenMode string `yaml:"screenMode" jsonschema:"enum=normal,enum=half,enum=full"`
// Window border style.
// One of 'rounded' (default) | 'single' | 'double' | 'hidden'
Border string `yaml:"border" jsonschema:"enum=single,enum=double,enum=rounded,enum=hidden"`
@@ -253,9 +259,9 @@ type GitConfig struct {
// If true, do not allow force pushes
DisableForcePushing bool `yaml:"disableForcePushing"`
// See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#predefined-commit-message-prefix
CommitPrefix *CommitPrefixConfig `yaml:"commitPrefix"`
CommitPrefix []CommitPrefixConfig `yaml:"commitPrefix"`
// See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#predefined-commit-message-prefix
CommitPrefixes map[string]CommitPrefixConfig `yaml:"commitPrefixes"`
CommitPrefixes map[string][]CommitPrefixConfig `yaml:"commitPrefixes"`
// See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#predefined-branch-name-prefix
BranchPrefix string `yaml:"branchPrefix"`
// If true, parse emoji strings in commit messages e.g. render :rocket: as 🚀
@@ -453,6 +459,8 @@ type KeybindingFilesConfig struct {
OpenMergeTool string `yaml:"openMergeTool"`
OpenStatusFilter string `yaml:"openStatusFilter"`
CopyFileInfoToClipboard string `yaml:"copyFileInfoToClipboard"`
CollapseAll string `yaml:"collapseAll"`
ExpandAll string `yaml:"expandAll"`
}
type KeybindingBranchesConfig struct {
@@ -606,8 +614,8 @@ type CustomCommandAfterHook struct {
type CustomCommand struct {
// The key to trigger the command. Use a single letter or one of the values from https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md
Key string `yaml:"key"`
// The context in which to listen for the key
Context string `yaml:"context" jsonschema:"enum=status,enum=files,enum=worktrees,enum=localBranches,enum=remotes,enum=remoteBranches,enum=tags,enum=commits,enum=reflogCommits,enum=subCommits,enum=commitFiles,enum=stash,enum=global"`
// The context in which to listen for the key. Valid values are: status, files, worktrees, localBranches, remotes, remoteBranches, tags, commits, reflogCommits, subCommits, commitFiles, stash, and global. Multiple contexts separated by comma are allowed; most useful for "commits, subCommits" or "files, commitFiles".
Context string `yaml:"context" jsonschema:"example=status,example=files,example=worktrees,example=localBranches,example=remotes,example=remoteBranches,example=tags,example=commits,example=reflogCommits,example=subCommits,example=commitFiles,example=stash,example=global"`
// The command to run (using Go template syntax for placeholder values)
Command string `yaml:"command" jsonschema:"example=git fetch {{.Form.Remote}} {{.Form.Branch}} && git checkout FETCH_HEAD"`
// If true, run the command in a subprocess (e.g. if the command requires user input)
@@ -688,6 +696,7 @@ func GetDefaultConfig() *UserConfig {
ScrollPastBottom: true,
ScrollOffMargin: 2,
ScrollOffBehavior: "margin",
TabWidth: 4,
MouseEvents: true,
SkipDiscardChangeWarning: false,
SkipStashWarning: false,
@@ -734,7 +743,7 @@ func GetDefaultConfig() *UserConfig {
CommandLogSize: 8,
SplitDiff: "auto",
SkipRewordInEditorWarning: false,
WindowSize: "normal",
ScreenMode: "normal",
Border: "rounded",
AnimateExplosion: true,
PortraitMode: "auto",
@@ -779,7 +788,7 @@ func GetDefaultConfig() *UserConfig {
BranchLogCmd: "git log --graph --color=always --abbrev-commit --decorate --date=relative --pretty=medium {{branchName}} --",
AllBranchesLogCmd: "git log --graph --all --color=always --abbrev-commit --decorate --date=relative --pretty=medium",
DisableForcePushing: false,
CommitPrefixes: map[string]CommitPrefixConfig(nil),
CommitPrefixes: map[string][]CommitPrefixConfig(nil),
BranchPrefix: "",
ParseEmoji: false,
TruncateCopiedCommitHashesTo: 12,
@@ -895,6 +904,8 @@ func GetDefaultConfig() *UserConfig {
OpenStatusFilter: "<c-b>",
ConfirmDiscard: "x",
CopyFileInfoToClipboard: "y",
CollapseAll: "-",
ExpandAll: "=",
},
Branches: KeybindingBranchesConfig{
CopyPullRequestURL: "<c-y>",
+74
View File
@@ -2,8 +2,12 @@ package config
import (
"fmt"
"log"
"reflect"
"slices"
"strings"
"github.com/jesseduffield/lazygit/pkg/constants"
)
func (config *UserConfig) Validate() error {
@@ -15,6 +19,12 @@ func (config *UserConfig) Validate() error {
[]string{"none", "onlyArrow", "arrowAndNumber"}); err != nil {
return err
}
if err := validateKeybindings(config.Keybinding); err != nil {
return err
}
if err := validateCustomCommands(config.CustomCommands); err != nil {
return err
}
return nil
}
@@ -25,3 +35,67 @@ func validateEnum(name string, value string, allowedValues []string) error {
allowedValuesStr := strings.Join(allowedValues, ", ")
return fmt.Errorf("Unexpected value '%s' for '%s'. Allowed values: %s", value, name, allowedValuesStr)
}
func validateKeybindingsRecurse(path string, node any) error {
value := reflect.ValueOf(node)
if value.Kind() == reflect.Struct {
for _, field := range reflect.VisibleFields(reflect.TypeOf(node)) {
var newPath string
if len(path) == 0 {
newPath = field.Name
} else {
newPath = fmt.Sprintf("%s.%s", path, field.Name)
}
if err := validateKeybindingsRecurse(newPath,
value.FieldByName(field.Name).Interface()); err != nil {
return err
}
}
} else if value.Kind() == reflect.Slice {
for i := 0; i < value.Len(); i++ {
if err := validateKeybindingsRecurse(
fmt.Sprintf("%s[%d]", path, i), value.Index(i).Interface()); err != nil {
return err
}
}
} else if value.Kind() == reflect.String {
key := node.(string)
if !isValidKeybindingKey(key) {
return fmt.Errorf("Unrecognized key '%s' for keybinding '%s'. For permitted values see %s",
key, path, constants.Links.Docs.CustomKeybindings)
}
} else {
log.Fatalf("Unexpected type for property '%s': %s", path, value.Kind())
}
return nil
}
func validateKeybindings(keybindingConfig KeybindingConfig) error {
if err := validateKeybindingsRecurse("", keybindingConfig); err != nil {
return err
}
if len(keybindingConfig.Universal.JumpToBlock) != 5 {
return fmt.Errorf("keybinding.universal.jumpToBlock must have 5 elements; found %d.",
len(keybindingConfig.Universal.JumpToBlock))
}
return nil
}
func validateCustomCommandKey(key string) error {
if !isValidKeybindingKey(key) {
return fmt.Errorf("Unrecognized key '%s' for custom command. For permitted values see %s",
key, constants.Links.Docs.CustomKeybindings)
}
return nil
}
func validateCustomCommands(customCommands []CustomCommand) error {
for _, customCommand := range customCommands {
if err := validateCustomCommandKey(customCommand.Key); err != nil {
return err
}
}
return nil
}
+45
View File
@@ -1,6 +1,7 @@
package config
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
@@ -29,6 +30,50 @@ func TestUserConfigValidate_enums(t *testing.T) {
{value: "invalid_value", valid: false},
},
},
{
name: "Keybindings",
setup: func(config *UserConfig, value string) {
config.Keybinding.Universal.Quit = value
},
testCases: []testCase{
{value: "", valid: true},
{value: "<disabled>", valid: true},
{value: "q", valid: true},
{value: "<c-c>", valid: true},
{value: "invalid_value", valid: false},
},
},
{
name: "JumpToBlock keybinding",
setup: func(config *UserConfig, value string) {
config.Keybinding.Universal.JumpToBlock = strings.Split(value, ",")
},
testCases: []testCase{
{value: "", valid: false},
{value: "1,2,3", valid: false},
{value: "1,2,3,4,5", valid: true},
{value: "1,2,3,4,invalid", valid: false},
{value: "1,2,3,4,5,6", valid: false},
},
},
{
name: "Custom command keybinding",
setup: func(config *UserConfig, value string) {
config.CustomCommands = []CustomCommand{
{
Key: value,
Command: "echo 'hello'",
},
}
},
testCases: []testCase{
{value: "", valid: true},
{value: "<disabled>", valid: true},
{value: "q", valid: true},
{value: "<c-c>", valid: true},
{value: "invalid_value", valid: false},
},
},
}
for _, s := range scenarios {
+3 -3
View File
@@ -76,9 +76,9 @@ func (self *BackgroundRoutineMgr) startBackgroundFetch() {
self.gui.waitForIntro.Wait()
fetch := func() error {
err := self.backgroundFetch()
self.gui.c.Render()
return err
return self.gui.helpers.AppStatus.WithWaitingStatusImpl(self.gui.Tr.FetchingStatus, func(gocui.Task) error {
return self.backgroundFetch()
}, nil)
}
// We want an immediate fetch at startup, and since goEvery starts by
+8
View File
@@ -80,6 +80,14 @@ func (self *BranchesContext) GetDiffTerminals() []string {
return nil
}
func (self *BranchesContext) RefForAdjustingLineNumberInDiff() string {
branch := self.GetSelected()
if branch != nil {
return branch.ID()
}
return ""
}
func (self *BranchesContext) ShowBranchHeadsInSubCommits() bool {
return true
}
+7
View File
@@ -77,6 +77,13 @@ func (self *CommitFilesContext) GetDiffTerminals() []string {
return []string{self.GetRef().RefName()}
}
func (self *CommitFilesContext) RefForAdjustingLineNumberInDiff() string {
if refs := self.GetRefRange(); refs != nil {
return refs.To.RefName()
}
return self.GetRef().RefName()
}
func (self *CommitFilesContext) GetFromAndToForDiff() (string, string) {
if refs := self.GetRefRange(); refs != nil {
return refs.From.ParentRefName(), refs.To.RefName()
+44 -6
View File
@@ -1,6 +1,8 @@
package context
import (
"os"
"path/filepath"
"strconv"
"strings"
@@ -8,8 +10,11 @@ import (
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/spf13/afero"
)
const PreservedCommitMessageFileName = "LAZYGIT_PENDING_COMMIT"
type CommitMessageContext struct {
c *ContextCommon
types.Context
@@ -33,8 +38,6 @@ type CommitMessageViewModel struct {
// we remember the initial message so that we can tell whether we should preserve
// the message; if it's still identical to the initial message, we don't
initialMessage string
// the full preserved message (combined summary and description)
preservedMessage string
// invoked when pressing enter in the commit message panel
onConfirm func(string, string) error
// invoked when pressing the switch-to-editor key binding
@@ -75,16 +78,51 @@ func (self *CommitMessageContext) GetSelectedIndex() int {
return self.viewModel.selectedindex
}
func (self *CommitMessageContext) GetPreservedMessagePath() string {
return filepath.Join(self.c.Git().RepoPaths.WorktreeGitDirPath(), PreservedCommitMessageFileName)
}
func (self *CommitMessageContext) GetPreserveMessage() bool {
return self.viewModel.preserveMessage
}
func (self *CommitMessageContext) GetPreservedMessage() string {
return self.viewModel.preservedMessage
func (self *CommitMessageContext) getPreservedMessage() (string, error) {
buf, err := afero.ReadFile(self.c.Fs, self.GetPreservedMessagePath())
if os.IsNotExist(err) {
return "", nil
}
if err != nil {
return "", err
}
return string(buf), nil
}
func (self *CommitMessageContext) SetPreservedMessage(message string) {
self.viewModel.preservedMessage = message
func (self *CommitMessageContext) GetPreservedMessageAndLogError() string {
msg, err := self.getPreservedMessage()
if err != nil {
self.c.Log.Errorf("error when retrieving persisted commit message: %v", err)
}
return msg
}
func (self *CommitMessageContext) setPreservedMessage(message string) error {
preservedFilePath := self.GetPreservedMessagePath()
if len(message) == 0 {
err := self.c.Fs.Remove(preservedFilePath)
if os.IsNotExist(err) {
return nil
}
return err
}
return afero.WriteFile(self.c.Fs, preservedFilePath, []byte(message), 0o644)
}
func (self *CommitMessageContext) SetPreservedMessageAndLogError(message string) {
if err := self.setPreservedMessage(message); err != nil {
self.c.Log.Errorf("error when persisting commit message: %v", err)
}
}
func (self *CommitMessageContext) GetInitialMessage() string {
+1 -1
View File
@@ -131,7 +131,7 @@ func (self *ListContextTrait) IsItemVisible(item types.HasUrn) bool {
return false
}
// By default, list contexts supporta range select
// By default, list contexts supports range select
func (self *ListContextTrait) RangeSelectEnabled() bool {
return true
}
+8
View File
@@ -170,6 +170,14 @@ func (self *LocalCommitsContext) GetDiffTerminals() []string {
return []string{itemId}
}
func (self *LocalCommitsContext) RefForAdjustingLineNumberInDiff() string {
commits, _, _ := self.GetSelectedItems()
if commits == nil {
return ""
}
return commits[0].Hash
}
func (self *LocalCommitsContext) ModelSearchResults(searchStr string, caseSensitive bool) []gocui.SearchPosition {
return searchModelCommits(caseSensitive, self.GetCommits(), self.ColumnPositions(), searchStr)
}
@@ -86,6 +86,10 @@ func (self *ReflogCommitsContext) GetDiffTerminals() []string {
return []string{itemId}
}
func (self *ReflogCommitsContext) RefForAdjustingLineNumberInDiff() string {
return self.GetSelectedItemId()
}
func (self *ReflogCommitsContext) ShowBranchHeadsInSubCommits() bool {
return false
}
@@ -78,6 +78,10 @@ func (self *RemoteBranchesContext) GetDiffTerminals() []string {
return []string{itemId}
}
func (self *RemoteBranchesContext) RefForAdjustingLineNumberInDiff() string {
return self.GetSelectedItemId()
}
func (self *RemoteBranchesContext) ShowBranchHeadsInSubCommits() bool {
return true
}
+4
View File
@@ -53,3 +53,7 @@ func (self *RemotesContext) GetDiffTerminals() []string {
return []string{itemId}
}
func (self *RemotesContext) RefForAdjustingLineNumberInDiff() string {
return ""
}
+4
View File
@@ -71,3 +71,7 @@ func (self *StashContext) GetDiffTerminals() []string {
return []string{itemId}
}
func (self *StashContext) RefForAdjustingLineNumberInDiff() string {
return self.GetSelectedItemId()
}
+8
View File
@@ -217,6 +217,14 @@ func (self *SubCommitsContext) GetDiffTerminals() []string {
return []string{itemId}
}
func (self *SubCommitsContext) RefForAdjustingLineNumberInDiff() string {
commits, _, _ := self.GetSelectedItems()
if commits == nil {
return ""
}
return commits[0].Hash
}
func (self *SubCommitsContext) ModelSearchResults(searchStr string, caseSensitive bool) []gocui.SearchPosition {
return searchModelCommits(caseSensitive, self.GetCommits(), self.ColumnPositions(), searchStr)
}
+4
View File
@@ -66,6 +66,10 @@ func (self *TagsContext) GetDiffTerminals() []string {
return []string{itemId}
}
func (self *TagsContext) RefForAdjustingLineNumberInDiff() string {
return self.GetSelectedItemId()
}
func (self *TagsContext) ShowBranchHeadsInSubCommits() bool {
return true
}
+108 -52
View File
@@ -3,6 +3,7 @@ package controllers
import (
"errors"
"fmt"
"strings"
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/commands/models"
@@ -121,52 +122,93 @@ func (self *BasicCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
return bindings
}
func (self *BasicCommitsController) getCommitMessageBody(hash string) string {
commitMessageBody, err := self.c.Git().Commit.GetCommitMessage(hash)
if err != nil {
return ""
}
_, body := self.c.Helpers().Commits.SplitCommitMessageAndDescription(commitMessageBody)
return body
}
func (self *BasicCommitsController) copyCommitAttribute(commit *models.Commit) error {
return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.Actions.CopyCommitAttributeToClipboard,
Items: []*types.MenuItem{
{
Label: self.c.Tr.CommitHash,
OnPress: func() error {
return self.copyCommitHashToClipboard(commit)
},
},
{
Label: self.c.Tr.CommitSubject,
OnPress: func() error {
return self.copyCommitSubjectToClipboard(commit)
},
Key: 's',
},
{
Label: self.c.Tr.CommitMessage,
OnPress: func() error {
return self.copyCommitMessageToClipboard(commit)
},
Key: 'm',
},
{
Label: self.c.Tr.CommitURL,
OnPress: func() error {
return self.copyCommitURLToClipboard(commit)
},
Key: 'u',
},
{
Label: self.c.Tr.CommitDiff,
OnPress: func() error {
return self.copyCommitDiffToClipboard(commit)
},
Key: 'd',
},
{
Label: self.c.Tr.CommitAuthor,
OnPress: func() error {
return self.copyAuthorToClipboard(commit)
},
Key: 'a',
commitMessageBody := self.getCommitMessageBody(commit.Hash)
var commitMessageBodyDisabled *types.DisabledReason
if commitMessageBody == "" {
commitMessageBodyDisabled = &types.DisabledReason{
Text: self.c.Tr.CommitHasNoMessageBody,
}
}
items := []*types.MenuItem{
{
Label: self.c.Tr.CommitHash,
OnPress: func() error {
return self.copyCommitHashToClipboard(commit)
},
},
{
Label: self.c.Tr.CommitSubject,
OnPress: func() error {
return self.copyCommitSubjectToClipboard(commit)
},
Key: 's',
},
{
Label: self.c.Tr.CommitMessage,
OnPress: func() error {
return self.copyCommitMessageToClipboard(commit)
},
Key: 'm',
},
{
Label: self.c.Tr.CommitMessageBody,
DisabledReason: commitMessageBodyDisabled,
OnPress: func() error {
return self.copyCommitMessageBodyToClipboard(commitMessageBody)
},
Key: 'b',
},
{
Label: self.c.Tr.CommitURL,
OnPress: func() error {
return self.copyCommitURLToClipboard(commit)
},
Key: 'u',
},
{
Label: self.c.Tr.CommitDiff,
OnPress: func() error {
return self.copyCommitDiffToClipboard(commit)
},
Key: 'd',
},
{
Label: self.c.Tr.CommitAuthor,
OnPress: func() error {
return self.copyAuthorToClipboard(commit)
},
Key: 'a',
},
}
commitTagsItem := types.MenuItem{
Label: self.c.Tr.CommitTags,
OnPress: func() error {
return self.copyCommitTagsToClipboard(commit)
},
Key: 't',
}
if len(commit.Tags) == 0 {
commitTagsItem.DisabledReason = &types.DisabledReason{Text: self.c.Tr.CommitHasNoTags}
}
items = append(items, &commitTagsItem)
return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.Actions.CopyCommitAttributeToClipboard,
Items: items,
})
}
@@ -242,6 +284,16 @@ func (self *BasicCommitsController) copyCommitMessageToClipboard(commit *models.
return nil
}
func (self *BasicCommitsController) copyCommitMessageBodyToClipboard(commitMessageBody string) error {
self.c.LogAction(self.c.Tr.Actions.CopyCommitMessageBodyToClipboard)
if err := self.c.OS().CopyToClipboard(commitMessageBody); err != nil {
return err
}
self.c.Toast(self.c.Tr.CommitMessageBodyCopiedToClipboard)
return nil
}
func (self *BasicCommitsController) copyCommitSubjectToClipboard(commit *models.Commit) error {
message, err := self.c.Git().Commit.GetCommitSubject(commit.Hash)
if err != nil {
@@ -257,6 +309,18 @@ func (self *BasicCommitsController) copyCommitSubjectToClipboard(commit *models.
return nil
}
func (self *BasicCommitsController) copyCommitTagsToClipboard(commit *models.Commit) error {
message := strings.Join(commit.Tags, "\n")
self.c.LogAction(self.c.Tr.Actions.CopyCommitTagsToClipboard)
if err := self.c.OS().CopyToClipboard(message); err != nil {
return err
}
self.c.Toast(self.c.Tr.CommitTagsCopiedToClipboard)
return nil
}
func (self *BasicCommitsController) openInBrowser(commit *models.Commit) error {
url, err := self.c.Helpers().Host.GetCommitURL(commit.Hash)
if err != nil {
@@ -280,15 +344,7 @@ func (self *BasicCommitsController) createResetMenu(commit *models.Commit) error
}
func (self *BasicCommitsController) checkout(commit *models.Commit) error {
self.c.Confirm(types.ConfirmOpts{
Title: self.c.Tr.CheckoutCommit,
Prompt: self.c.Tr.SureCheckoutThisCommit,
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.CheckoutCommit)
return self.c.Helpers().Refs.CheckoutRef(commit.Hash, types.CheckoutRefOptions{})
},
})
return nil
return self.c.Helpers().Refs.CreateCheckoutMenu(commit)
}
func (self *BasicCommitsController) copyRange(*models.Commit) error {
+9 -5
View File
@@ -194,6 +194,10 @@ func (self *BranchesController) GetOnRenderToMain() func() {
}
func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branch) error {
upstream := lo.Ternary(selectedBranch.RemoteBranchStoredLocally(),
selectedBranch.ShortUpstreamRefName(),
self.c.Tr.UpstreamGenericName)
viewDivergenceItem := &types.MenuItem{
LabelColumns: []string{self.c.Tr.ViewDivergenceFromUpstream},
OnPress: func() error {
@@ -204,7 +208,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc
return self.c.Helpers().SubCommits.ViewSubCommits(helpers.ViewSubCommitsOpts{
Ref: branch,
TitleRef: fmt.Sprintf("%s <-> %s", branch.RefName(), branch.ShortUpstreamRefName()),
TitleRef: fmt.Sprintf("%s <-> %s", branch.RefName(), upstream),
RefToShowDivergenceFrom: branch.FullUpstreamRefName(),
Context: self.context(),
ShowBranchHeads: false,
@@ -293,9 +297,6 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc
Key: 's',
}
upstream := lo.Ternary(selectedBranch.RemoteBranchStoredLocally(),
fmt.Sprintf("%s/%s", selectedBranch.UpstreamRemote, selectedBranch.Name),
self.c.Tr.UpstreamGenericName)
upstreamResetOptions := utils.ResolvePlaceholderString(
self.c.Tr.ViewUpstreamResetOptions,
map[string]string{"upstream": upstream},
@@ -332,7 +333,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc
LabelColumns: []string{upstreamRebaseOptions},
OpensMenu: true,
OnPress: func() error {
if err := self.c.Helpers().MergeAndRebase.RebaseOntoRef(selectedBranch.ShortUpstreamRefName()); err != nil {
if err := self.c.Helpers().MergeAndRebase.RebaseOntoRef(upstream); err != nil {
return err
}
return nil
@@ -629,9 +630,11 @@ func (self *BranchesController) fastForward(branch *models.Branch) error {
self.c.LogAction(action)
worktreeGitDir := ""
worktreePath := ""
// if it is the current worktree path, no need to specify the path
if !worktree.IsCurrent {
worktreeGitDir = worktree.GitDir
worktreePath = worktree.Path
}
err := self.c.Git().Sync.Pull(
@@ -641,6 +644,7 @@ func (self *BranchesController) fastForward(branch *models.Branch) error {
BranchName: branch.UpstreamBranch,
FastForwardOnly: true,
WorktreeGitDir: worktreeGitDir,
WorktreePath: worktreePath,
},
)
_ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
@@ -3,7 +3,9 @@ package controllers
import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
)
type CommitDescriptionController struct {
@@ -26,7 +28,7 @@ func (self *CommitDescriptionController) GetKeybindings(opts types.KeybindingsOp
bindings := []*types.Binding{
{
Key: opts.GetKey(opts.Config.Universal.TogglePanel),
Handler: self.switchToCommitMessage,
Handler: self.handleTogglePanel,
},
{
Key: opts.GetKey(opts.Config.Universal.Return),
@@ -59,11 +61,46 @@ func (self *CommitDescriptionController) GetMouseKeybindings(opts types.Keybindi
}
}
func (self *CommitDescriptionController) GetOnFocus() func(types.OnFocusOpts) {
return func(types.OnFocusOpts) {
self.c.Views().CommitDescription.Footer = utils.ResolvePlaceholderString(self.c.Tr.CommitDescriptionFooter,
map[string]string{
"confirmInEditorKeybinding": keybindings.Label(self.c.UserConfig().Keybinding.Universal.ConfirmInEditor),
})
}
}
func (self *CommitDescriptionController) switchToCommitMessage() error {
self.c.Context().Replace(self.c.Contexts().CommitMessage)
return nil
}
func (self *CommitDescriptionController) handleTogglePanel() error {
// The default keybinding for this action is "<tab>", which means that we
// also get here when pasting multi-line text that contains tabs. In that
// case we don't want to toggle the panel, but insert the tab as a character
// (somehow, see below).
//
// Only do this if the TogglePanel command is actually mapped to "<tab>"
// (the default). If it's not, we can only hope that it's mapped to some
// ctrl key or fn key, which is unlikely to occur in pasted text. And if
// they mapped some *other* command to "<tab>", then we're totally out of
// luck.
if self.c.GocuiGui().IsPasting && self.c.UserConfig().Keybinding.Universal.TogglePanel == "<tab>" {
// Handling tabs in pasted commit messages is not optimal, but hopefully
// good enough for now. We simply insert 4 spaces without worrying about
// column alignment. This works well enough for leading indentation,
// which is common in pasted code snippets.
view := self.Context().GetView()
for range 4 {
view.Editor.Edit(view, gocui.KeySpace, ' ', 0)
}
return nil
}
return self.switchToCommitMessage()
}
func (self *CommitDescriptionController) close() error {
self.c.Helpers().Commits.CloseCommitMessagePanel()
return nil
@@ -48,7 +48,7 @@ func (self *CommitMessageController) GetKeybindings(opts types.KeybindingsOpts)
},
{
Key: opts.GetKey(opts.Config.Universal.TogglePanel),
Handler: self.switchToCommitDescription,
Handler: self.handleTogglePanel,
},
{
Key: opts.GetKey(opts.Config.CommitMessage.CommitMenu),
@@ -69,6 +69,12 @@ func (self *CommitMessageController) GetMouseKeybindings(opts types.KeybindingsO
}
}
func (self *CommitMessageController) GetOnFocus() func(types.OnFocusOpts) {
return func(types.OnFocusOpts) {
self.c.Views().CommitDescription.Footer = ""
}
}
func (self *CommitMessageController) GetOnFocusLost() func(types.OnFocusLostOpts) {
return func(types.OnFocusLostOpts) {
self.context().RenderCommitLength()
@@ -99,6 +105,32 @@ func (self *CommitMessageController) switchToCommitDescription() error {
return nil
}
func (self *CommitMessageController) handleTogglePanel() error {
// The default keybinding for this action is "<tab>", which means that we
// also get here when pasting multi-line text that contains tabs. In that
// case we don't want to toggle the panel, but insert the tab as a character
// (somehow, see below).
//
// Only do this if the TogglePanel command is actually mapped to "<tab>"
// (the default). If it's not, we can only hope that it's mapped to some
// ctrl key or fn key, which is unlikely to occur in pasted text. And if
// they mapped some *other* command to "<tab>", then we're totally out of
// luck.
if self.c.GocuiGui().IsPasting && self.c.UserConfig().Keybinding.Universal.TogglePanel == "<tab>" {
// It is unlikely that a pasted commit message contains a tab in the
// subject line, so it shouldn't matter too much how we handle it.
// Simply insert 4 spaces instead; all that matters is that we don't
// switch to the description panel.
view := self.context().GetView()
for range 4 {
view.Editor.Edit(view, gocui.KeySpace, ' ', 0)
}
return nil
}
return self.switchToCommitDescription()
}
func (self *CommitMessageController) handleCommitIndexChange(value int) error {
currentIndex := self.context().GetSelectedIndex()
newIndex := currentIndex + value
@@ -134,6 +166,20 @@ func (self *CommitMessageController) setCommitMessageAtIndex(index int) (bool, e
}
func (self *CommitMessageController) confirm() error {
// The default keybinding for this action is "<enter>", which means that we
// also get here when pasting multi-line text that contains newlines. In
// that case we don't want to confirm the commit, but switch to the
// description panel instead so that the rest of the pasted text goes there.
//
// Only do this if the SubmitEditorText command is actually mapped to
// "<enter>" (the default). If it's not, we can only hope that it's mapped
// to some ctrl key or fn key, which is unlikely to occur in pasted text.
// And if they mapped some *other* command to "<enter>", then we're totally
// out of luck.
if self.c.GocuiGui().IsPasting && self.c.UserConfig().Keybinding.Universal.SubmitEditorText == "<enter>" {
return self.switchToCommitDescription()
}
return self.c.Helpers().Commits.HandleCommitConfirm()
}
@@ -41,6 +41,12 @@ func NewCommitFilesController(
func (self *CommitFilesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
bindings := []*types.Binding{
{
Key: opts.GetKey(opts.Config.Files.CopyFileInfoToClipboard),
Handler: self.openCopyMenu,
Description: self.c.Tr.CopyToClipboardMenu,
OpensMenu: true,
},
{
Key: opts.GetKey(opts.Config.CommitFiles.CheckoutCommitFile),
Handler: self.withItem(self.checkout),
@@ -109,6 +115,20 @@ func (self *CommitFilesController) GetKeybindings(opts types.KeybindingsOpts) []
Description: self.c.Tr.ToggleTreeView,
Tooltip: self.c.Tr.ToggleTreeViewTooltip,
},
{
Key: opts.GetKey(opts.Config.Files.CollapseAll),
Handler: self.collapseAll,
Description: self.c.Tr.CollapseAll,
Tooltip: self.c.Tr.CollapseAllTooltip,
GetDisabledReason: self.require(self.isInTreeMode),
},
{
Key: opts.GetKey(opts.Config.Files.ExpandAll),
Handler: self.expandAll,
Description: self.c.Tr.ExpandAll,
Tooltip: self.c.Tr.ExpandAllTooltip,
GetDisabledReason: self.require(self.isInTreeMode),
},
}
return bindings
@@ -167,6 +187,77 @@ func (self *CommitFilesController) onClickMain(opts gocui.ViewMouseBindingOpts)
return self.enterCommitFile(node, types.OnFocusOpts{ClickedWindowName: "main", ClickedViewLineIdx: opts.Y})
}
func (self *CommitFilesController) copyDiffToClipboard(path string, toastMessage string) error {
from, to := self.context().GetFromAndToForDiff()
from, reverse := self.c.Modes().Diffing.GetFromAndReverseArgsForDiff(from)
cmdObj := self.c.Git().WorkingTree.ShowFileDiffCmdObj(from, to, reverse, path, true)
diff, err := cmdObj.RunWithOutput()
if err != nil {
return err
}
if err := self.c.OS().CopyToClipboard(diff); err != nil {
return err
}
self.c.Toast(toastMessage)
return nil
}
func (self *CommitFilesController) openCopyMenu() error {
node := self.context().GetSelected()
copyNameItem := &types.MenuItem{
Label: self.c.Tr.CopyFileName,
OnPress: func() error {
if err := self.c.OS().CopyToClipboard(node.Name()); err != nil {
return err
}
self.c.Toast(self.c.Tr.FileNameCopiedToast)
return nil
},
DisabledReason: self.require(self.singleItemSelected())(),
Key: 'n',
}
copyPathItem := &types.MenuItem{
Label: self.c.Tr.CopyFilePath,
OnPress: func() error {
if err := self.c.OS().CopyToClipboard(node.Path); err != nil {
return err
}
self.c.Toast(self.c.Tr.FilePathCopiedToast)
return nil
},
DisabledReason: self.require(self.singleItemSelected())(),
Key: 'p',
}
copyFileDiffItem := &types.MenuItem{
Label: self.c.Tr.CopySelectedDiff,
OnPress: func() error {
return self.copyDiffToClipboard(node.GetPath(), self.c.Tr.FileDiffCopiedToast)
},
DisabledReason: self.require(self.singleItemSelected())(),
Key: 's',
}
copyAllDiff := &types.MenuItem{
Label: self.c.Tr.CopyAllFilesDiff,
OnPress: func() error {
return self.copyDiffToClipboard(".", self.c.Tr.AllFilesDiffCopiedToast)
},
DisabledReason: self.require(self.itemsSelected())(),
Key: 'a',
}
return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.CopyToClipboardMenu,
Items: []*types.MenuItem{
copyNameItem,
copyPathItem,
copyFileDiffItem,
copyAllDiff,
},
})
}
func (self *CommitFilesController) checkout(node *filetree.CommitFileNode) error {
self.c.LogAction(self.c.Tr.Actions.CheckoutFile)
if err := self.c.Git().WorkingTree.CheckoutFile(self.context().GetRef().RefName(), node.GetPath()); err != nil {
@@ -401,6 +492,22 @@ func (self *CommitFilesController) toggleTreeView() error {
return nil
}
func (self *CommitFilesController) collapseAll() error {
self.context().CommitFileTreeViewModel.CollapseAll()
self.c.PostRefreshUpdate(self.context())
return nil
}
func (self *CommitFilesController) expandAll() error {
self.context().CommitFileTreeViewModel.ExpandAll()
self.c.PostRefreshUpdate(self.context())
return nil
}
// NOTE: these functions are identical to those in files_controller.go (except for types) and
// could also be cleaned up with some generics
func normalisedSelectedCommitFileNodes(selectedNodes []*filetree.CommitFileNode) []*filetree.CommitFileNode {
@@ -420,3 +527,11 @@ func isDescendentOfSelectedCommitFileNodes(node *filetree.CommitFileNode, select
}
return false
}
func (self *CommitFilesController) isInTreeMode() *types.DisabledReason {
if !self.context().CommitFileTreeViewModel.InTreeMode() {
return &types.DisabledReason{Text: self.c.Tr.DisabledInFlatView}
}
return nil
}
+148 -21
View File
@@ -2,6 +2,7 @@ package controllers
import (
"errors"
"fmt"
"strings"
"github.com/jesseduffield/gocui"
@@ -186,6 +187,20 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types
Description: self.c.Tr.Fetch,
Tooltip: self.c.Tr.FetchTooltip,
},
{
Key: opts.GetKey(opts.Config.Files.CollapseAll),
Handler: self.collapseAll,
Description: self.c.Tr.CollapseAll,
Tooltip: self.c.Tr.CollapseAllTooltip,
GetDisabledReason: self.require(self.isInTreeMode),
},
{
Key: opts.GetKey(opts.Config.Files.ExpandAll),
Handler: self.expandAll,
Description: self.c.Tr.ExpandAll,
Tooltip: self.c.Tr.ExpandAllTooltip,
GetDisabledReason: self.require(self.isInTreeMode),
},
}
}
@@ -478,6 +493,22 @@ func (self *FilesController) enter() error {
return self.EnterFile(types.OnFocusOpts{ClickedWindowName: "", ClickedViewLineIdx: -1})
}
func (self *FilesController) collapseAll() error {
self.context().FileTreeViewModel.CollapseAll()
self.c.PostRefreshUpdate(self.context())
return nil
}
func (self *FilesController) expandAll() error {
self.context().FileTreeViewModel.ExpandAll()
self.c.PostRefreshUpdate(self.context())
return nil
}
func (self *FilesController) EnterFile(opts types.OnFocusOpts) error {
node := self.context().GetSelected()
if node == nil {
@@ -660,24 +691,70 @@ func (self *FilesController) refresh() error {
}
func (self *FilesController) handleAmendCommitPress() error {
self.c.Confirm(types.ConfirmOpts{
Title: self.c.Tr.AmendLastCommitTitle,
Prompt: self.c.Tr.SureToAmend,
HandleConfirm: func() error {
return self.c.Helpers().WorkingTree.WithEnsureCommitableFiles(func() error {
if len(self.c.Model().Commits) == 0 {
return errors.New(self.c.Tr.NoCommitToAmend)
}
doAmend := func() error {
return self.c.Helpers().WorkingTree.WithEnsureCommittableFiles(func() error {
if len(self.c.Model().Commits) == 0 {
return errors.New(self.c.Tr.NoCommitToAmend)
}
return self.c.Helpers().AmendHelper.AmendHead()
})
},
})
return self.c.Helpers().AmendHelper.AmendHead()
})
}
if self.isResolvingConflicts() {
return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.AmendCommitTitle,
Prompt: self.c.Tr.AmendCommitWithConflictsMenuPrompt,
HideCancel: true, // We want the cancel item first, so we add one manually
Items: []*types.MenuItem{
{
Label: self.c.Tr.Cancel,
OnPress: func() error {
return nil
},
},
{
Label: self.c.Tr.AmendCommitWithConflictsContinue,
OnPress: func() error {
return self.c.Helpers().MergeAndRebase.ContinueRebase()
},
},
{
Label: self.c.Tr.AmendCommitWithConflictsAmend,
OnPress: func() error {
return doAmend()
},
},
},
})
} else {
self.c.Confirm(types.ConfirmOpts{
Title: self.c.Tr.AmendLastCommitTitle,
Prompt: self.c.Tr.SureToAmend,
HandleConfirm: func() error {
return doAmend()
},
})
}
return nil
}
func (self *FilesController) isResolvingConflicts() bool {
commits := self.c.Model().Commits
for _, c := range commits {
if c.Status != models.StatusRebasing {
break
}
if c.Action == models.ActionConflict {
return true
}
}
return false
}
func (self *FilesController) handleStatusFilterPressed() error {
currentFilter := self.context().GetFilter()
return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.FilteringMenuTitle,
Items: []*types.MenuItem{
@@ -686,37 +763,79 @@ func (self *FilesController) handleStatusFilterPressed() error {
OnPress: func() error {
return self.setStatusFiltering(filetree.DisplayStaged)
},
Key: 's',
Key: 's',
Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayStaged),
},
{
Label: self.c.Tr.FilterUnstagedFiles,
OnPress: func() error {
return self.setStatusFiltering(filetree.DisplayUnstaged)
},
Key: 'u',
Key: 'u',
Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayUnstaged),
},
{
Label: self.c.Tr.FilterTrackedFiles,
OnPress: func() error {
return self.setStatusFiltering(filetree.DisplayTracked)
},
Key: 't',
Key: 't',
Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayTracked),
},
{
Label: self.c.Tr.ResetFilter,
Label: self.c.Tr.FilterUntrackedFiles,
OnPress: func() error {
return self.setStatusFiltering(filetree.DisplayUntracked)
},
Key: 'T',
Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayUntracked),
},
{
Label: self.c.Tr.NoFilter,
OnPress: func() error {
return self.setStatusFiltering(filetree.DisplayAll)
},
Key: 'r',
Key: 'r',
Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayAll),
},
},
})
}
func (self *FilesController) filteringLabel(filter filetree.FileTreeDisplayFilter) string {
switch filter {
case filetree.DisplayAll:
return ""
case filetree.DisplayStaged:
return self.c.Tr.FilterLabelStagedFiles
case filetree.DisplayUnstaged:
return self.c.Tr.FilterLabelUnstagedFiles
case filetree.DisplayTracked:
return self.c.Tr.FilterLabelTrackedFiles
case filetree.DisplayUntracked:
return self.c.Tr.FilterLabelUntrackedFiles
case filetree.DisplayConflicted:
return self.c.Tr.FilterLabelConflictingFiles
}
panic(fmt.Sprintf("Unexpected files display filter: %d", filter))
}
func (self *FilesController) setStatusFiltering(filter filetree.FileTreeDisplayFilter) error {
previousFilter := self.context().GetFilter()
self.context().FileTreeViewModel.SetStatusFilter(filter)
self.c.PostRefreshUpdate(self.context())
return nil
self.c.Contexts().Files.GetView().Subtitle = self.filteringLabel(filter)
// Whenever we switch between untracked and other filters, we need to refresh the files view
// 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
}
}
func (self *FilesController) edit(nodes []*filetree.FileNode) error {
@@ -869,7 +988,7 @@ func (self *FilesController) openCopyMenu() error {
OnPress: func() error {
path := self.context().GetSelectedPath()
hasStaged := self.hasPathStagedChanges(node)
diff, err := self.c.Git().Diff.GetPathDiff(path, hasStaged)
diff, err := self.c.Git().Diff.GetDiff(hasStaged, "--", path)
if err != nil {
return err
}
@@ -894,7 +1013,7 @@ func (self *FilesController) openCopyMenu() error {
Tooltip: self.c.Tr.CopyFileDiffTooltip,
OnPress: func() error {
hasStaged := self.c.Helpers().WorkingTree.AnyStagedFiles()
diff, err := self.c.Git().Diff.GetAllDiff(hasStaged)
diff, err := self.c.Git().Diff.GetDiff(hasStaged, "--")
if err != nil {
return err
}
@@ -1181,3 +1300,11 @@ func (self *FilesController) formattedPaths(nodes []*filetree.FileNode) string {
return node.GetPath()
}))
}
func (self *FilesController) isInTreeMode() *types.DisabledReason {
if !self.context().FileTreeViewModel.InTreeMode() {
return &types.DisabledReason{Text: self.c.Tr.DisabledInFlatView}
}
return nil
}
+16 -4
View File
@@ -69,10 +69,11 @@ func (self *GlobalController) GetKeybindings(opts types.KeybindingsOpts) []*type
Modifier: gocui.ModNone,
// we have the description on the alt key and not the main key for legacy reasons
// (the original main key was 'x' but we've reassigned that to other purposes)
Description: self.c.Tr.OpenKeybindingsMenu,
Handler: self.createOptionsMenu,
ShortDescription: self.c.Tr.Keybindings,
DisplayOnScreen: true,
Description: self.c.Tr.OpenKeybindingsMenu,
Handler: self.createOptionsMenu,
ShortDescription: self.c.Tr.Keybindings,
DisplayOnScreen: true,
GetDisabledReason: self.optionsMenuDisabledReason,
},
{
ViewName: "",
@@ -156,6 +157,17 @@ func (self *GlobalController) createOptionsMenu() error {
return (&OptionsMenuAction{c: self.c}).Call()
}
func (self *GlobalController) optionsMenuDisabledReason() *types.DisabledReason {
ctx := self.c.Context().Current()
// Don't show options menu while displaying popup.
if ctx.GetKind() == types.PERSISTENT_POPUP || ctx.GetKind() == types.TEMPORARY_POPUP {
// The empty error text is intentional. We don't want to show an error
// toast for this, but only hide it from the options map.
return &types.DisabledReason{Text: ""}
}
return nil
}
func (self *GlobalController) createFilteringMenu() error {
return (&FilteringMenuAction{c: self.c}).Call()
}
@@ -60,9 +60,13 @@ func (self appStatusHelperTask) Continue() {
// withWaitingStatus wraps a function and shows a waiting status while the function is still executing
func (self *AppStatusHelper) WithWaitingStatus(message string, f func(gocui.Task) error) {
self.c.OnWorker(func(task gocui.Task) error {
return self.statusMgr().WithWaitingStatus(message, self.renderAppStatus, func(waitingStatusHandle *status.WaitingStatusHandle) error {
return f(appStatusHelperTask{task, waitingStatusHandle})
})
return self.WithWaitingStatusImpl(message, f, task)
})
}
func (self *AppStatusHelper) WithWaitingStatusImpl(message string, f func(gocui.Task) error, task gocui.Task) error {
return self.statusMgr().WithWaitingStatus(message, self.renderAppStatus, func(waitingStatusHandle *status.WaitingStatusHandle) error {
return f(appStatusHelperTask{task, waitingStatusHandle})
})
}
@@ -1,10 +1,13 @@
package helpers
import (
"strconv"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/modes/cherrypicking"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo"
)
@@ -67,8 +70,12 @@ func (self *CherryPickHelper) CopyRange(commitsList []*models.Commit, context ty
// Only to be called from the branch commits controller
func (self *CherryPickHelper) Paste() error {
self.c.Confirm(types.ConfirmOpts{
Title: self.c.Tr.CherryPick,
Prompt: self.c.Tr.SureCherryPick,
Title: self.c.Tr.CherryPick,
Prompt: utils.ResolvePlaceholderString(
self.c.Tr.SureCherryPick,
map[string]string{
"numCommits": strconv.Itoa(len(self.getData().CherryPickedCommits)),
}),
HandleConfirm: func() error {
isInRebase, err := self.c.Git().Status.IsInInteractiveRebase()
if err != nil {
@@ -113,7 +113,7 @@ func (self *CommitsHelper) UpdateCommitPanelView(message string) {
}
if self.c.Contexts().CommitMessage.GetPreserveMessage() {
preservedMessage := self.c.Contexts().CommitMessage.GetPreservedMessage()
preservedMessage := self.c.Contexts().CommitMessage.GetPreservedMessageAndLogError()
self.SetMessageAndDescriptionInView(preservedMessage)
return
}
@@ -156,7 +156,7 @@ func (self *CommitsHelper) OpenCommitMessagePanel(opts *OpenCommitMessagePanelOp
func (self *CommitsHelper) OnCommitSuccess() {
// if we have a preserved message we want to clear it on success
if self.c.Contexts().CommitMessage.GetPreserveMessage() {
self.c.Contexts().CommitMessage.SetPreservedMessage("")
self.c.Contexts().CommitMessage.SetPreservedMessageAndLogError("")
}
}
@@ -179,7 +179,7 @@ func (self *CommitsHelper) CloseCommitMessagePanel() {
if self.c.Contexts().CommitMessage.GetPreserveMessage() {
message := self.JoinCommitMessageAndUnwrappedDescription()
if message != self.c.Contexts().CommitMessage.GetInitialMessage() {
self.c.Contexts().CommitMessage.SetPreservedMessage(message)
self.c.Contexts().CommitMessage.SetPreservedMessageAndLogError(message)
}
} else {
self.SetMessageAndDescriptionInView("")
@@ -56,8 +56,8 @@ func (self *ConfirmationHelper) DeactivateConfirmationPrompt() {
self.clearConfirmationViewKeyBindings()
}
func getMessageHeight(wrap bool, message string, width int) int {
wrappedLines, _, _ := utils.WrapViewLinesToWidth(wrap, message, width)
func getMessageHeight(wrap bool, editable bool, message string, width int, tabWidth int) int {
wrappedLines, _, _ := utils.WrapViewLinesToWidth(wrap, editable, message, width, tabWidth)
return len(wrappedLines)
}
@@ -265,7 +265,7 @@ func (self *ConfirmationHelper) resizeMenu(parentPopupContext types.Context) {
if selectedItem != nil {
tooltip = self.TooltipForMenuItem(selectedItem)
}
tooltipHeight := getMessageHeight(true, tooltip, contentWidth) + 2 // plus 2 for the frame
tooltipHeight := getMessageHeight(true, false, tooltip, contentWidth, self.c.Views().Menu.TabWidth) + 2 // plus 2 for the frame
_, _ = self.c.GocuiGui().SetView(self.c.Views().Tooltip.Name(), x0, tooltipTop, x1, tooltipTop+tooltipHeight-1, 0)
}
@@ -276,7 +276,7 @@ func (self *ConfirmationHelper) layoutMenuPrompt(contentWidth int) int {
var promptLines []string
prompt := self.c.Contexts().Menu.GetPrompt()
if len(prompt) > 0 {
promptLines, _, _ = utils.WrapViewLinesToWidth(true, prompt, contentWidth)
promptLines, _, _ = utils.WrapViewLinesToWidth(true, false, prompt, contentWidth, self.c.Views().Menu.TabWidth)
promptLines = append(promptLines, "")
}
self.c.Contexts().Menu.SetPromptLines(promptLines)
@@ -305,16 +305,18 @@ func (self *ConfirmationHelper) resizeConfirmationPanel(parentPopupContext types
}
panelWidth := self.getPopupPanelWidth()
contentWidth := panelWidth - 2 // minus 2 for the frame
prompt := self.c.Views().Confirmation.Buffer()
confirmationView := self.c.Views().Confirmation
prompt := confirmationView.Buffer()
wrap := true
if self.c.Views().Confirmation.Editable {
prompt = self.c.Views().Confirmation.TextArea.GetContent()
editable := confirmationView.Editable
if editable {
prompt = confirmationView.TextArea.GetContent()
wrap = false
}
panelHeight := getMessageHeight(wrap, prompt, contentWidth) + suggestionsViewHeight
panelHeight := getMessageHeight(wrap, editable, prompt, contentWidth, confirmationView.TabWidth) + suggestionsViewHeight
x0, y0, x1, y1 := self.getPopupPanelDimensionsAux(panelWidth, panelHeight, parentPopupContext)
confirmationViewBottom := y1 - suggestionsViewHeight
_, _ = self.c.GocuiGui().SetView(self.c.Views().Confirmation.Name(), x0, y0, x1, confirmationViewBottom, 0)
_, _ = self.c.GocuiGui().SetView(confirmationView.Name(), x0, y0, x1, confirmationViewBottom, 0)
suggestionsViewTop := confirmationViewBottom + 1
_, _ = self.c.GocuiGui().SetView(self.c.Views().Suggestions.Name(), x0, suggestionsViewTop, x1, suggestionsViewTop+suggestionsViewHeight, 0)
@@ -324,7 +326,7 @@ func (self *ConfirmationHelper) ResizeCommitMessagePanels(parentPopupContext typ
panelWidth := self.getPopupPanelWidth()
content := self.c.Views().CommitDescription.TextArea.GetContent()
summaryViewHeight := 3
panelHeight := getMessageHeight(false, content, panelWidth)
panelHeight := getMessageHeight(false, true, content, panelWidth, self.c.Views().CommitDescription.TabWidth)
minHeight := 7
if panelHeight < minHeight {
panelHeight = minHeight
@@ -5,6 +5,7 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/patch"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/modes/diffing"
"github.com/jesseduffield/lazygit/pkg/gui/style"
@@ -164,3 +165,45 @@ func (self *DiffHelper) OpenDiffToolForRef(selectedRef types.Ref) error {
}))
return err
}
// AdjustLineNumber is used to adjust a line number in the diff that's currently
// being viewed, so that it corresponds to the line number in the actual working
// copy state of the file. It is used when clicking on a delta hyperlink in a
// diff, or when pressing `e` in the staging or patch building panels. It works
// by getting a diff of what's being viewed in the main view against the working
// copy, and then using that diff to adjust the line number.
// path is the file path of the file being viewed
// linenumber is the line number to adjust (one-based)
// viewname is the name of the view that shows the diff. We need to pass it
// because the diff adjustment is slightly different depending on which view is
// showing the diff.
func (self *DiffHelper) AdjustLineNumber(path string, linenumber int, viewname string) int {
switch viewname {
case "main", "patchBuilding":
if diffableContext, ok := self.c.Context().CurrentSide().(types.DiffableContext); ok {
ref := diffableContext.RefForAdjustingLineNumberInDiff()
if len(ref) != 0 {
return self.adjustLineNumber(linenumber, ref, "--", path)
}
}
// if the type cast to DiffableContext returns false, we are in the
// unstaged changes view of the Files panel; no need to adjust line
// numbers in this case
case "secondary", "stagingSecondary":
return self.adjustLineNumber(linenumber, "--", path)
}
return linenumber
}
func (self *DiffHelper) adjustLineNumber(linenumber int, diffArgs ...string) int {
args := append([]string{"--unified=0"}, diffArgs...)
diff, err := self.c.Git().Diff.GetDiff(false, args...)
if err != nil {
return linenumber
}
patch := patch.Parse(diff)
return patch.AdjustLineNumber(linenumber)
}
@@ -77,6 +77,10 @@ func (self *MergeAndRebaseHelper) CreateRebaseOptionsMenu() error {
return self.c.Menu(types.CreateMenuOptions{Title: title, Items: menuItems})
}
func (self *MergeAndRebaseHelper) ContinueRebase() error {
return self.genericMergeCommand(REBASE_OPTION_CONTINUE)
}
func (self *MergeAndRebaseHelper) genericMergeCommand(command string) error {
status := self.c.Git().Status.WorkingTreeState()
@@ -490,6 +490,8 @@ func (self *RefreshHelper) refreshBranches(refreshWorktrees bool, keepBranchSele
self.refreshView(self.c.Contexts().Worktrees)
}
self.refreshView(self.c.Contexts().Branches)
if !keepBranchSelectionIndex && prevSelectedBranch != nil {
_, idx, found := lo.FindIndexOf(self.c.Contexts().Branches.GetItems(),
func(b *models.Branch) bool { return b.Name == prevSelectedBranch.Name })
@@ -498,8 +500,6 @@ func (self *RefreshHelper) refreshBranches(refreshWorktrees bool, keepBranchSele
}
}
self.refreshView(self.c.Contexts().Branches)
// Need to re-render the commits view because the visualization of local
// branch heads might have changed
self.c.Mutexes().LocalCommitsMutex.Lock()
@@ -570,7 +570,9 @@ func (self *RefreshHelper) refreshStateFiles() error {
}
files := self.c.Git().Loaders.FileLoader.
GetStatusFiles(git_commands.GetStatusFileOptions{})
GetStatusFiles(git_commands.GetStatusFileOptions{
ForceShowUntracked: self.c.Contexts().Files.ForceShowUntracked(),
})
conflictFileCount := 0
for _, file := range files {
@@ -586,16 +588,14 @@ func (self *RefreshHelper) refreshStateFiles() error {
fileTreeViewModel.RWMutex.Lock()
// only taking over the filter if it hasn't already been set by the user.
// Though this does make it impossible for the user to actually say they want to display all if
// conflicts are currently being shown. Hmm. Worth it I reckon. If we need to add some
// extra state here to see if the user's set the filter themselves we can do that, but
// I'd prefer to maintain as little state as possible.
if conflictFileCount > 0 {
if conflictFileCount > 0 && prevConflictFileCount == 0 {
if fileTreeViewModel.GetFilter() == filetree.DisplayAll {
fileTreeViewModel.SetStatusFilter(filetree.DisplayConflicted)
self.c.Contexts().Files.GetView().Subtitle = self.c.Tr.FilterLabelConflictingFiles
}
} else if fileTreeViewModel.GetFilter() == filetree.DisplayConflicted {
} else if conflictFileCount == 0 && fileTreeViewModel.GetFilter() == filetree.DisplayConflicted {
fileTreeViewModel.SetStatusFilter(filetree.DisplayAll)
self.c.Contexts().Files.GetView().Subtitle = ""
}
self.c.Model().Files = files
+52 -3
View File
@@ -18,6 +18,7 @@ type IRefsHelper interface {
CheckoutRef(ref string, options types.CheckoutRefOptions) error
GetCheckedOutRef() *models.Branch
CreateGitResetMenu(ref string) error
CreateCheckoutMenu(commit *models.Commit) error
ResetToRef(ref string, strength string, envVars []string) error
NewBranch(from string, fromDescription string, suggestedBranchname string) error
}
@@ -74,7 +75,7 @@ func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions
return options.OnRefNotFound(ref)
}
if IsSwitchBranchUncommitedChangesError(err) {
if IsSwitchBranchUncommittedChangesError(err) {
// offer to autostash changes
self.c.OnUIThread(func() error {
// (Before showing the prompt, render again to remove the inline status)
@@ -271,6 +272,54 @@ func (self *RefsHelper) CreateGitResetMenu(ref string) error {
})
}
func (self *RefsHelper) CreateCheckoutMenu(commit *models.Commit) error {
branches := lo.Filter(self.c.Model().Branches, func(branch *models.Branch, _ int) bool {
return commit.Hash == branch.CommitHash && branch.Name != self.c.Model().CheckedOutBranch
})
hash := commit.Hash
menuItems := []*types.MenuItem{
{
LabelColumns: []string{fmt.Sprintf(self.c.Tr.Actions.CheckoutCommitAsDetachedHead, utils.ShortHash(hash))},
OnPress: func() error {
self.c.LogAction(self.c.Tr.Actions.CheckoutCommit)
return self.CheckoutRef(hash, types.CheckoutRefOptions{})
},
Key: 'd',
},
}
if len(branches) > 0 {
menuItems = append(menuItems, lo.Map(branches, func(branch *models.Branch, index int) *types.MenuItem {
var key types.Key
if index < 9 {
key = rune(index + 1 + '0') // Convert 1-based index to key
}
return &types.MenuItem{
LabelColumns: []string{fmt.Sprintf(self.c.Tr.Actions.CheckoutBranchAtCommit, branch.Name)},
OnPress: func() error {
self.c.LogAction(self.c.Tr.Actions.CheckoutBranch)
return self.CheckoutRef(branch.RefName(), types.CheckoutRefOptions{})
},
Key: key,
}
})...)
} else {
menuItems = append(menuItems, &types.MenuItem{
LabelColumns: []string{self.c.Tr.Actions.CheckoutBranch},
OnPress: func() error { return nil },
DisabledReason: &types.DisabledReason{Text: self.c.Tr.NoBranchesFoundAtCommitTooltip},
Key: '1',
})
}
return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.Actions.CheckoutBranchOrCommit,
Items: menuItems,
})
}
func (self *RefsHelper) NewBranch(from string, fromFormattedName string, suggestedBranchName string) error {
message := utils.ResolvePlaceholderString(
self.c.Tr.NewBranchNameBranchOff,
@@ -305,7 +354,7 @@ func (self *RefsHelper) NewBranch(from string, fromFormattedName string, suggest
newBranchFunc = self.c.Git().Branch.NewWithoutTracking
}
if err := newBranchFunc(newBranchName, from); err != nil {
if IsSwitchBranchUncommitedChangesError(err) {
if IsSwitchBranchUncommittedChangesError(err) {
// offer to autostash changes
self.c.Confirm(types.ConfirmOpts{
Title: self.c.Tr.AutoStashTitle,
@@ -365,6 +414,6 @@ func (self *RefsHelper) ParseRemoteBranchName(fullBranchName string) (string, st
return remoteName, branchName, true
}
func IsSwitchBranchUncommitedChangesError(err error) bool {
func IsSwitchBranchUncommittedChangesError(err error) bool {
return strings.Contains(err.Error(), "Please commit your changes or stash them before you switch branch")
}
@@ -53,7 +53,7 @@ type WindowArrangementArgs struct {
// staged and unstaged changes)
SplitMainPanel bool
// The current screen mode (normal, half, full)
ScreenMode types.WindowMaximisation
ScreenMode types.ScreenMode
// The content shown on the bottom left of the screen when showing a loader
// or toast e.g. 'Rebasing /'
AppStatus string
@@ -422,7 +422,7 @@ func renderLayout(windows map[string]boxlayout.Dimensions) string {
return dimensionsA.X0 < dimensionsB.X0
})
// Uniquefy windows by dimensions (so perfectly overlapping windows are de-duped). This prevents getting 'fileshes' as a label where the files and branches windows overlap.
// Uniquify windows by dimensions (so perfectly overlapping windows are de-duped). This prevents getting 'fileshes' as a label where the files and branches windows overlap.
// branches windows overlap.
windowNames = lo.UniqBy(windowNames, func(windowName string) boxlayout.Dimensions {
return windows[windowName]
@@ -87,7 +87,7 @@ func (self *WorkingTreeHelper) OpenMergeTool() error {
}
func (self *WorkingTreeHelper) HandleCommitPressWithMessage(initialMessage string) error {
return self.WithEnsureCommitableFiles(func() error {
return self.WithEnsureCommittableFiles(func() error {
self.commitsHelper.OpenCommitMessagePanel(
&OpenCommitMessagePanelOpts{
CommitIndex: context.NoCommitIndex,
@@ -131,7 +131,7 @@ func (self *WorkingTreeHelper) switchFromCommitMessagePanelToEditor(filepath str
// HandleCommitEditorPress - handle when the user wants to commit changes via
// their editor rather than via the popup panel
func (self *WorkingTreeHelper) HandleCommitEditorPress() error {
return self.WithEnsureCommitableFiles(func() error {
return self.WithEnsureCommittableFiles(func() error {
self.c.LogAction(self.c.Tr.Actions.Commit)
return self.c.RunSubprocessAndRefresh(
self.c.Git().Commit.CommitEditorCmdObj(),
@@ -149,11 +149,11 @@ func (self *WorkingTreeHelper) HandleWIPCommitPress() error {
}
func (self *WorkingTreeHelper) HandleCommitPress() error {
message := self.c.Contexts().CommitMessage.GetPreservedMessage()
message := self.c.Contexts().CommitMessage.GetPreservedMessageAndLogError()
if message == "" {
commitPrefixConfig := self.commitPrefixConfigForRepo()
if commitPrefixConfig != nil {
commitPrefixConfigs := self.commitPrefixConfigsForRepo()
for _, commitPrefixConfig := range commitPrefixConfigs {
prefixPattern := commitPrefixConfig.Pattern
prefixReplace := commitPrefixConfig.Replace
branchName := self.refHelper.GetCheckedOutRef().Name
@@ -165,6 +165,7 @@ func (self *WorkingTreeHelper) HandleCommitPress() error {
if rgx.MatchString(branchName) {
prefix := rgx.ReplaceAllString(branchName, prefixReplace)
message = prefix
break
}
}
}
@@ -172,7 +173,7 @@ func (self *WorkingTreeHelper) HandleCommitPress() error {
return self.HandleCommitPressWithMessage(message)
}
func (self *WorkingTreeHelper) WithEnsureCommitableFiles(handler func() error) error {
func (self *WorkingTreeHelper) WithEnsureCommittableFiles(handler func() error) error {
if err := self.prepareFilesForCommit(); err != nil {
return err
}
@@ -228,11 +229,11 @@ func (self *WorkingTreeHelper) prepareFilesForCommit() error {
return nil
}
func (self *WorkingTreeHelper) commitPrefixConfigForRepo() *config.CommitPrefixConfig {
func (self *WorkingTreeHelper) commitPrefixConfigsForRepo() []config.CommitPrefixConfig {
cfg, ok := self.c.UserConfig().Git.CommitPrefixes[self.c.Git().RepoPaths.RepoName()]
if ok {
return &cfg
return append(cfg, self.c.UserConfig().Git.CommitPrefix...)
} else {
return self.c.UserConfig().Git.CommitPrefix
}
return self.c.UserConfig().Git.CommitPrefix
}
@@ -736,7 +736,7 @@ func (self *LocalCommitsController) amendTo(commit *models.Commit) error {
Title: self.c.Tr.AmendCommitTitle,
Prompt: self.c.Tr.AmendCommitPrompt,
HandleConfirm: func() error {
return self.c.Helpers().WorkingTree.WithEnsureCommitableFiles(func() error {
return self.c.Helpers().WorkingTree.WithEnsureCommittableFiles(func() error {
if err := self.c.Helpers().AmendHelper.AmendHead(); err != nil {
return err
}
@@ -752,7 +752,7 @@ func (self *LocalCommitsController) amendTo(commit *models.Commit) error {
Title: self.c.Tr.AmendCommitTitle,
Prompt: self.c.Tr.AmendCommitPrompt,
HandleConfirm: func() error {
return self.c.Helpers().WorkingTree.WithEnsureCommitableFiles(func() error {
return self.c.Helpers().WorkingTree.WithEnsureCommittableFiles(func() error {
return self.c.WithWaitingStatus(self.c.Tr.AmendingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.AmendCommit)
err := self.c.Git().Rebase.AmendTo(self.c.Model().Commits, self.context().GetView().SelectedLineIdx())
@@ -928,7 +928,7 @@ func (self *LocalCommitsController) createFixupCommit(commit *models.Commit) err
Label: self.c.Tr.FixupMenu_Fixup,
Key: 'f',
OnPress: func() error {
return self.c.Helpers().WorkingTree.WithEnsureCommitableFiles(func() error {
return self.c.Helpers().WorkingTree.WithEnsureCommittableFiles(func() error {
self.c.LogAction(self.c.Tr.Actions.CreateFixupCommit)
return self.c.WithWaitingStatusSync(self.c.Tr.CreatingFixupCommitStatus, func() error {
if err := self.c.Git().Commit.CreateFixupCommit(commit.Hash); err != nil {
@@ -951,7 +951,7 @@ func (self *LocalCommitsController) createFixupCommit(commit *models.Commit) err
Label: self.c.Tr.FixupMenu_AmendWithChanges,
Key: 'a',
OnPress: func() error {
return self.c.Helpers().WorkingTree.WithEnsureCommitableFiles(func() error {
return self.c.Helpers().WorkingTree.WithEnsureCommittableFiles(func() error {
return self.createAmendCommit(commit, true)
})
},
@@ -13,11 +13,6 @@ type OptionsMenuAction struct {
func (self *OptionsMenuAction) Call() error {
ctx := self.c.Context().Current()
// Don't show menu while displaying popup.
if ctx.GetKind() == types.PERSISTENT_POPUP || ctx.GetKind() == types.TEMPORARY_POPUP {
return nil
}
local, global, navigation := self.getBindings(ctx)
menuItems := []*types.MenuItem{}
@@ -107,6 +107,7 @@ func (self *PatchBuildingController) EditFile() error {
}
lineNumber := self.context().GetState().CurrentLineNumber()
lineNumber = self.c.Helpers().Diff.AdjustLineNumber(path, lineNumber, self.context().GetViewName())
return self.c.Helpers().Files.EditFileAtLine(path, lineNumber)
}
+4 -4
View File
@@ -12,7 +12,7 @@ type ScreenModeActions struct {
func (self *ScreenModeActions) Next() error {
self.c.State().GetRepoState().SetScreenMode(
nextIntInCycle(
[]types.WindowMaximisation{types.SCREEN_NORMAL, types.SCREEN_HALF, types.SCREEN_FULL},
[]types.ScreenMode{types.SCREEN_NORMAL, types.SCREEN_HALF, types.SCREEN_FULL},
self.c.State().GetRepoState().GetScreenMode(),
),
)
@@ -24,7 +24,7 @@ func (self *ScreenModeActions) Next() error {
func (self *ScreenModeActions) Prev() error {
self.c.State().GetRepoState().SetScreenMode(
prevIntInCycle(
[]types.WindowMaximisation{types.SCREEN_NORMAL, types.SCREEN_HALF, types.SCREEN_FULL},
[]types.ScreenMode{types.SCREEN_NORMAL, types.SCREEN_HALF, types.SCREEN_FULL},
self.c.State().GetRepoState().GetScreenMode(),
),
)
@@ -53,7 +53,7 @@ func (self *ScreenModeActions) rerenderView(view *gocui.View) {
context.HandleRender()
}
func nextIntInCycle(sl []types.WindowMaximisation, current types.WindowMaximisation) types.WindowMaximisation {
func nextIntInCycle(sl []types.ScreenMode, current types.ScreenMode) types.ScreenMode {
for i, val := range sl {
if val == current {
if i == len(sl)-1 {
@@ -65,7 +65,7 @@ func nextIntInCycle(sl []types.WindowMaximisation, current types.WindowMaximisat
return sl[0]
}
func prevIntInCycle(sl []types.WindowMaximisation, current types.WindowMaximisation) types.WindowMaximisation {
func prevIntInCycle(sl []types.ScreenMode, current types.ScreenMode) types.ScreenMode {
for i, val := range sl {
if val == current {
if i > 0 {
+13
View File
@@ -1,11 +1,13 @@
package controllers
import (
"fmt"
"strings"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/commands/patch"
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
@@ -161,6 +163,7 @@ func (self *StagingController) EditFile() error {
}
lineNumber := self.context.GetState().CurrentLineNumber()
lineNumber = self.c.Helpers().Diff.AdjustLineNumber(path, lineNumber, self.context.GetViewName())
return self.c.Helpers().Files.EditFileAtLine(path, lineNumber)
}
@@ -184,10 +187,20 @@ func (self *StagingController) TogglePanel() error {
}
func (self *StagingController) ToggleStaged() error {
if self.c.AppState.DiffContextSize == 0 {
return fmt.Errorf(self.c.Tr.Actions.NotEnoughContextToStage,
keybindings.Label(self.c.UserConfig().Keybinding.Universal.IncreaseContextInDiffView))
}
return self.applySelectionAndRefresh(self.staged)
}
func (self *StagingController) DiscardSelection() error {
if self.c.AppState.DiffContextSize == 0 {
return fmt.Errorf(self.c.Tr.Actions.NotEnoughContextToDiscard,
keybindings.Label(self.c.UserConfig().Keybinding.Universal.IncreaseContextInDiffView))
}
reset := func() error { return self.applySelectionAndRefresh(true) }
if !self.staged && !self.c.UserConfig().Gui.SkipDiscardChangeWarning {
+2 -2
View File
@@ -201,13 +201,13 @@ func (self *StashController) handleRenameStashEntry(stashEntry *models.StashEntr
HandleConfirm: func(response string) error {
self.c.LogAction(self.c.Tr.Actions.RenameStash)
err := self.c.Git().Stash.Rename(stashEntry.Index, response)
_ = self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}})
if err != nil {
_ = self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}})
return err
}
self.context().SetSelection(0) // Select the renamed stash
self.context().FocusLine()
return nil
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}})
},
})
+1
View File
@@ -200,6 +200,7 @@ func (self *SyncController) pushAux(currentBranch *models.Branch, opts pushOpts)
git_commands.PushOpts{
Force: opts.force,
ForceWithLease: opts.forceWithLease,
CurrentBranch: currentBranch.Name,
UpstreamRemote: opts.upstreamRemote,
UpstreamBranch: opts.upstreamBranch,
SetUpstream: opts.setUpstream,
+61
View File
@@ -177,6 +177,59 @@ func (self *TagsController) remoteDelete(tag *models.Tag) error {
return nil
}
func (self *TagsController) localAndRemoteDelete(tag *models.Tag) error {
title := utils.ResolvePlaceholderString(
self.c.Tr.SelectRemoteTagUpstream,
map[string]string{
"tagName": tag.Name,
},
)
self.c.Prompt(types.PromptOpts{
Title: title,
InitialContent: "origin",
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetRemoteSuggestionsFunc(),
HandleConfirm: func(upstream string) error {
confirmTitle := utils.ResolvePlaceholderString(
self.c.Tr.DeleteTagTitle,
map[string]string{
"tagName": tag.Name,
},
)
confirmPrompt := utils.ResolvePlaceholderString(
self.c.Tr.DeleteLocalAndRemoteTagPrompt,
map[string]string{
"tagName": tag.Name,
"upstream": upstream,
},
)
self.c.Confirm(types.ConfirmOpts{
Title: confirmTitle,
Prompt: confirmPrompt,
HandleConfirm: func() error {
return self.c.WithInlineStatus(tag, types.ItemOperationDeleting, context.TAGS_CONTEXT_KEY, func(task gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.DeleteRemoteTag)
if err := self.c.Git().Remote.DeleteRemoteTag(task, upstream, tag.Name); err != nil {
return err
}
self.c.LogAction(self.c.Tr.Actions.DeleteLocalTag)
if err := self.c.Git().Tag.LocalDelete(tag.Name); err != nil {
return err
}
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS, types.TAGS}})
})
},
})
return nil
},
})
return nil
}
func (self *TagsController) delete(tag *models.Tag) error {
menuTitle := utils.ResolvePlaceholderString(
self.c.Tr.DeleteTagTitle,
@@ -201,6 +254,14 @@ func (self *TagsController) delete(tag *models.Tag) error {
return self.remoteDelete(tag)
},
},
{
Label: self.c.Tr.DeleteLocalAndRemoteTag,
Key: 'b',
OpensMenu: true,
OnPress: func() error {
return self.localAndRemoteDelete(tag)
},
},
}
return self.c.Menu(types.CreateMenuOptions{
+29 -24
View File
@@ -88,7 +88,20 @@ func (self *UndoController) reflogUndo() error {
}
switch action.kind {
case COMMIT, REBASE:
case COMMIT:
self.c.Confirm(types.ConfirmOpts{
Title: self.c.Tr.Actions.Undo,
Prompt: fmt.Sprintf(self.c.Tr.SoftResetPrompt, action.from),
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.Undo)
return self.c.WithWaitingStatus(undoingStatus, func(gocui.Task) error {
return self.c.Helpers().Refs.ResetToRef(action.from, "soft", undoEnvVars)
})
},
})
return true, nil
case REBASE:
self.c.Confirm(types.ConfirmOpts{
Title: self.c.Tr.Actions.Undo,
Prompt: fmt.Sprintf(self.c.Tr.HardResetAutostashPrompt, action.from),
@@ -105,7 +118,7 @@ func (self *UndoController) reflogUndo() error {
case CHECKOUT:
self.c.Confirm(types.ConfirmOpts{
Title: self.c.Tr.Actions.Undo,
Prompt: fmt.Sprintf(self.c.Tr.CheckoutPrompt, action.from),
Prompt: fmt.Sprintf(self.c.Tr.CheckoutAutostashPrompt, action.from),
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.Undo)
return self.c.Helpers().Refs.CheckoutRef(action.from, types.CheckoutRefOptions{
@@ -159,7 +172,7 @@ func (self *UndoController) reflogRedo() error {
case CHECKOUT:
self.c.Confirm(types.ConfirmOpts{
Title: self.c.Tr.Actions.Redo,
Prompt: fmt.Sprintf(self.c.Tr.CheckoutPrompt, action.to),
Prompt: fmt.Sprintf(self.c.Tr.CheckoutAutostashPrompt, action.to),
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.Redo)
return self.c.Helpers().Refs.CheckoutRef(action.to, types.CheckoutRefOptions{
@@ -244,31 +257,23 @@ func (self *UndoController) hardResetWithAutoStash(commitHash string, options ha
return self.c.Helpers().Refs.ResetToRef(commitHash, "hard", options.EnvVars)
}
// if we have any modified tracked files we need to ask the user if they want us to stash for them
// if we have any modified tracked files we need to auto-stash
dirtyWorkingTree := self.c.Helpers().WorkingTree.IsWorkingTreeDirty()
if dirtyWorkingTree {
// offer to autostash changes
self.c.Confirm(types.ConfirmOpts{
Title: self.c.Tr.AutoStashTitle,
Prompt: self.c.Tr.AutoStashPrompt,
HandleConfirm: func() error {
return self.c.WithWaitingStatus(options.WaitingStatus, func(gocui.Task) error {
if err := self.c.Git().Stash.Push(self.c.Tr.StashPrefix + commitHash); err != nil {
return err
}
if err := reset(); err != nil {
return err
}
return self.c.WithWaitingStatus(options.WaitingStatus, func(gocui.Task) error {
if err := self.c.Git().Stash.Push(self.c.Tr.StashPrefix + commitHash); err != nil {
return err
}
if err := reset(); err != nil {
return err
}
err := self.c.Git().Stash.Pop(0)
if err != nil {
return err
}
return self.c.Refresh(types.RefreshOptions{})
})
},
err := self.c.Git().Stash.Pop(0)
if err != nil {
return err
}
return self.c.Refresh(types.RefreshOptions{})
})
return nil
}
return self.c.WithWaitingStatus(options.WaitingStatus, func(gocui.Task) error {
+5
View File
@@ -36,3 +36,8 @@ func (self *CollapsedPaths) ToggleCollapsed(path string) {
self.collapsedPaths.Add(path)
}
}
func (self *CollapsedPaths) ExpandAll() {
// Could be cleaner if Set had a Clear() method...
self.collapsedPaths.RemoveSlice(self.collapsedPaths.ToSlice())
}
+14
View File
@@ -25,6 +25,20 @@ type CommitFileTree struct {
collapsedPaths *CollapsedPaths
}
func (self *CommitFileTree) CollapseAll() {
dirPaths := lo.FilterMap(self.GetAllItems(), func(file *CommitFileNode, index int) (string, bool) {
return file.Path, !file.IsFile()
})
for _, path := range dirPaths {
self.collapsedPaths.Collapse(path)
}
}
func (self *CommitFileTree) ExpandAll() {
self.collapsedPaths.ExpandAll()
}
var _ ICommitFileTree = &CommitFileTree{}
func NewCommitFileTree(getFiles func() []*models.CommitFile, log *logrus.Entry, showTree bool) *CommitFileTree {
@@ -1,6 +1,7 @@
package filetree
import (
"strings"
"sync"
"github.com/jesseduffield/lazygit/pkg/commands/models"
@@ -160,3 +161,33 @@ func (self *CommitFileTreeViewModel) ToggleShowTree() {
self.SetSelection(index)
}
}
func (self *CommitFileTreeViewModel) CollapseAll() {
selectedNode := self.GetSelected()
self.ICommitFileTree.CollapseAll()
if selectedNode == nil {
return
}
topLevelPath := strings.Split(selectedNode.Path, "/")[0]
index, found := self.GetIndexForPath(topLevelPath)
if found {
self.SetSelectedLineIdx(index)
}
}
func (self *CommitFileTreeViewModel) ExpandAll() {
selectedNode := self.GetSelected()
self.ICommitFileTree.ExpandAll()
if selectedNode == nil {
return
}
index, found := self.GetIndexForPath(selectedNode.Path)
if found {
self.SetSelectedLineIdx(index)
}
}
+24
View File
@@ -16,6 +16,7 @@ const (
DisplayStaged
DisplayUnstaged
DisplayTracked
DisplayUntracked
// this shows files with merge conflicts
DisplayConflicted
)
@@ -31,6 +32,8 @@ type ITree[T any] interface {
IsCollapsed(path string) bool
ToggleCollapsed(path string)
CollapsedPaths() *CollapsedPaths
CollapseAll()
ExpandAll()
}
type IFileTree interface {
@@ -38,6 +41,7 @@ type IFileTree interface {
FilterFiles(test func(*models.File) bool) []*models.File
SetStatusFilter(filter FileTreeDisplayFilter)
ForceShowUntracked() bool
Get(index int) *FileNode
GetFile(path string) *models.File
GetAllItems() []*FileNode
@@ -85,6 +89,8 @@ func (self *FileTree) getFilesForDisplay() []*models.File {
return self.FilterFiles(func(file *models.File) bool { return file.HasUnstagedChanges })
case DisplayTracked:
return self.FilterFiles(func(file *models.File) bool { return file.Tracked })
case DisplayUntracked:
return self.FilterFiles(func(file *models.File) bool { return !file.Tracked })
case DisplayConflicted:
return self.FilterFiles(func(file *models.File) bool { return file.HasMergeConflicts })
default:
@@ -92,6 +98,10 @@ func (self *FileTree) getFilesForDisplay() []*models.File {
}
}
func (self *FileTree) ForceShowUntracked() bool {
return self.filter == DisplayUntracked
}
func (self *FileTree) FilterFiles(test func(*models.File) bool) []*models.File {
return lo.Filter(self.getFiles(), func(file *models.File, _ int) bool { return test(file) })
}
@@ -171,6 +181,20 @@ func (self *FileTree) ToggleCollapsed(path string) {
self.collapsedPaths.ToggleCollapsed(path)
}
func (self *FileTree) CollapseAll() {
dirPaths := lo.FilterMap(self.GetAllItems(), func(file *FileNode, index int) (string, bool) {
return file.Path, !file.IsFile()
})
for _, path := range dirPaths {
self.collapsedPaths.Collapse(path)
}
}
func (self *FileTree) ExpandAll() {
self.collapsedPaths.ExpandAll()
}
func (self *FileTree) Tree() *FileNode {
return NewFileNode(self.tree)
}
+31
View File
@@ -1,6 +1,7 @@
package filetree
import (
"strings"
"sync"
"github.com/jesseduffield/lazygit/pkg/commands/models"
@@ -190,3 +191,33 @@ func (self *FileTreeViewModel) ToggleShowTree() {
self.SetSelectedLineIdx(index)
}
}
func (self *FileTreeViewModel) CollapseAll() {
selectedNode := self.GetSelected()
self.IFileTree.CollapseAll()
if selectedNode == nil {
return
}
topLevelPath := strings.Split(selectedNode.Path, "/")[0]
index, found := self.GetIndexForPath(topLevelPath)
if found {
self.SetSelectedLineIdx(index)
}
}
func (self *FileTreeViewModel) ExpandAll() {
selectedNode := self.GetSelected()
self.IFileTree.ExpandAll()
if selectedNode == nil {
return
}
index, found := self.GetIndexForPath(selectedNode.Path)
if found {
self.SetSelectedLineIdx(index)
}
}
+28 -17
View File
@@ -244,7 +244,7 @@ type GuiRepoState struct {
// back in sync with the repo state
ViewsSetup bool
ScreenMode types.WindowMaximisation
ScreenMode types.ScreenMode
CurrentPopupOpts *types.CreatePopupPanelOpts
}
@@ -275,11 +275,11 @@ func (self *GuiRepoState) SetCurrentPopupOpts(value *types.CreatePopupPanelOpts)
self.CurrentPopupOpts = value
}
func (self *GuiRepoState) GetScreenMode() types.WindowMaximisation {
func (self *GuiRepoState) GetScreenMode() types.ScreenMode {
return self.ScreenMode
}
func (self *GuiRepoState) SetScreenMode(value types.WindowMaximisation) {
func (self *GuiRepoState) SetScreenMode(value types.ScreenMode) {
self.ScreenMode = value
}
@@ -358,7 +358,7 @@ func (gui *Gui) onNewRepo(startArgs appTypes.StartArgs, contextKey types.Context
return nil
})
gui.g.SetOpenHyperlinkFunc(func(url string) error {
gui.g.SetOpenHyperlinkFunc(func(url string, viewname string) error {
if strings.HasPrefix(url, "lazygit-edit:") {
re := regexp.MustCompile(`^lazygit-edit://(.+?)(?::(\d+))?$`)
matches := re.FindStringSubmatch(url)
@@ -368,6 +368,7 @@ func (gui *Gui) onNewRepo(startArgs appTypes.StartArgs, contextKey types.Context
filepath := matches[1]
if matches[2] != "" {
lineNumber := utils.MustConvertToInt(matches[2])
lineNumber = gui.helpers.Diff.AdjustLineNumber(filepath, lineNumber, viewname)
return gui.helpers.Files.EditFileAtLine(filepath, lineNumber)
}
return gui.helpers.Files.EditFiles([]string{filepath})
@@ -454,7 +455,13 @@ func (gui *Gui) onUserConfigLoaded() error {
} else if userConfig.Gui.ShowIcons {
icons.SetNerdFontsVersion("2")
}
presentation.SetCustomBranches(userConfig.Gui.BranchColors)
if len(userConfig.Gui.BranchColorPatterns) > 0 {
presentation.SetCustomBranches(userConfig.Gui.BranchColorPatterns, true)
} else {
// Fall back to the deprecated branchColors config
presentation.SetCustomBranches(userConfig.Gui.BranchColors, false)
}
return nil
}
@@ -579,20 +586,24 @@ func initialWindowViewNameMap(contextTree *context.ContextTree) *utils.ThreadSaf
return result
}
func initialScreenMode(startArgs appTypes.StartArgs, config config.AppConfigurer) types.WindowMaximisation {
if startArgs.FilterPath != "" || startArgs.GitArg != appTypes.GitArgNone {
return types.SCREEN_FULL
func initialScreenMode(startArgs appTypes.StartArgs, config config.AppConfigurer) types.ScreenMode {
if startArgs.ScreenMode != "" {
return parseScreenModeArg(startArgs.ScreenMode)
} else if startArgs.FilterPath != "" || startArgs.GitArg != appTypes.GitArgNone {
return types.SCREEN_HALF
} else {
defaultWindowSize := config.GetUserConfig().Gui.WindowSize
return parseScreenModeArg(config.GetUserConfig().Gui.ScreenMode)
}
}
switch defaultWindowSize {
case "half":
return types.SCREEN_HALF
case "full":
return types.SCREEN_FULL
default:
return types.SCREEN_NORMAL
}
func parseScreenModeArg(screenModeArg string) types.ScreenMode {
switch screenModeArg {
case "half":
return types.SCREEN_HALF
case "full":
return types.SCREEN_FULL
default:
return types.SCREEN_NORMAL
}
}
+10 -1
View File
@@ -145,6 +145,13 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi
GetDisabledReason: self.getCopySelectedSideContextItemToClipboardDisabledReason,
Description: self.c.Tr.CopyBranchNameToClipboard,
},
{
ViewName: "tags",
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
Handler: self.handleCopySelectedSideContextItemToClipboard,
GetDisabledReason: self.getCopySelectedSideContextItemToClipboardDisabledReason,
Description: self.c.Tr.CopyTagToClipboard,
},
{
ViewName: "commits",
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
@@ -453,7 +460,9 @@ func (gui *Gui) callKeybindingHandler(binding *types.Binding) error {
return errors.New(disabledReason.Text)
}
gui.c.ErrorToast(gui.Tr.DisabledMenuItemPrefix + disabledReason.Text)
if len(disabledReason.Text) > 0 {
gui.c.ErrorToast(gui.Tr.DisabledMenuItemPrefix + disabledReason.Text)
}
return nil
}
return binding.Handler()
+3 -70
View File
@@ -7,78 +7,11 @@ import (
"unicode/utf8"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/constants"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/samber/lo"
)
var labelByKey = map[gocui.Key]string{
gocui.KeyF1: "<f1>",
gocui.KeyF2: "<f2>",
gocui.KeyF3: "<f3>",
gocui.KeyF4: "<f4>",
gocui.KeyF5: "<f5>",
gocui.KeyF6: "<f6>",
gocui.KeyF7: "<f7>",
gocui.KeyF8: "<f8>",
gocui.KeyF9: "<f9>",
gocui.KeyF10: "<f10>",
gocui.KeyF11: "<f11>",
gocui.KeyF12: "<f12>",
gocui.KeyInsert: "<insert>",
gocui.KeyDelete: "<delete>",
gocui.KeyHome: "<home>",
gocui.KeyEnd: "<end>",
gocui.KeyPgup: "<pgup>",
gocui.KeyPgdn: "<pgdown>",
gocui.KeyArrowUp: "<up>",
gocui.KeyShiftArrowUp: "<s-up>",
gocui.KeyArrowDown: "<down>",
gocui.KeyShiftArrowDown: "<s-down>",
gocui.KeyArrowLeft: "<left>",
gocui.KeyArrowRight: "<right>",
gocui.KeyTab: "<tab>", // <c-i>
gocui.KeyBacktab: "<backtab>",
gocui.KeyEnter: "<enter>", // <c-m>
gocui.KeyAltEnter: "<a-enter>",
gocui.KeyEsc: "<esc>", // <c-[>, <c-3>
gocui.KeyBackspace: "<backspace>", // <c-h>
gocui.KeyCtrlSpace: "<c-space>", // <c-~>, <c-2>
gocui.KeyCtrlSlash: "<c-/>", // <c-_>
gocui.KeySpace: "<space>",
gocui.KeyCtrlA: "<c-a>",
gocui.KeyCtrlB: "<c-b>",
gocui.KeyCtrlC: "<c-c>",
gocui.KeyCtrlD: "<c-d>",
gocui.KeyCtrlE: "<c-e>",
gocui.KeyCtrlF: "<c-f>",
gocui.KeyCtrlG: "<c-g>",
gocui.KeyCtrlJ: "<c-j>",
gocui.KeyCtrlK: "<c-k>",
gocui.KeyCtrlL: "<c-l>",
gocui.KeyCtrlN: "<c-n>",
gocui.KeyCtrlO: "<c-o>",
gocui.KeyCtrlP: "<c-p>",
gocui.KeyCtrlQ: "<c-q>",
gocui.KeyCtrlR: "<c-r>",
gocui.KeyCtrlS: "<c-s>",
gocui.KeyCtrlT: "<c-t>",
gocui.KeyCtrlU: "<c-u>",
gocui.KeyCtrlV: "<c-v>",
gocui.KeyCtrlW: "<c-w>",
gocui.KeyCtrlX: "<c-x>",
gocui.KeyCtrlY: "<c-y>",
gocui.KeyCtrlZ: "<c-z>",
gocui.KeyCtrl4: "<c-4>", // <c-\>
gocui.KeyCtrl5: "<c-5>", // <c-]>
gocui.KeyCtrl6: "<c-6>",
gocui.KeyCtrl8: "<c-8>",
gocui.MouseWheelUp: "mouse wheel up",
gocui.MouseWheelDown: "mouse wheel down",
}
var keyByLabel = lo.Invert(labelByKey)
func Label(name string) string {
return LabelFromKey(GetKey(name))
}
@@ -90,7 +23,7 @@ func LabelFromKey(key types.Key) string {
case rune:
keyInt = int(key)
case gocui.Key:
value, ok := labelByKey[key]
value, ok := config.LabelByKey[key]
if ok {
return value
}
@@ -105,7 +38,7 @@ func GetKey(key string) types.Key {
if key == "<disabled>" {
return nil
} else if runeCount > 1 {
binding, ok := keyByLabel[strings.ToLower(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 {
+2 -2
View File
@@ -41,7 +41,7 @@ const (
func NewState(diff string, selectedLineIdx int, view *gocui.View, oldState *State) *State {
if oldState != nil && diff == oldState.diff && selectedLineIdx == -1 {
// if we're here then we can return the old state. If selectedLineIdx was not -1
// then that would mean we were trying to click and potentiall drag a range, which
// then that would mean we were trying to click and potentially drag a range, which
// is why in that case we continue below
return oldState
}
@@ -323,6 +323,6 @@ func (s *State) CalculateOrigin(currentOrigin int, bufferHeight int, numLines in
func wrapPatchLines(diff string, view *gocui.View) ([]int, []int) {
_, viewLineIndices, patchLineIndices := utils.WrapViewLinesToWidth(
view.Wrap, strings.TrimSuffix(diff, "\n"), view.InnerWidth())
view.Wrap, view.Editable, strings.TrimSuffix(diff, "\n"), view.InnerWidth(), view.TabWidth)
return viewLineIndices, patchLineIndices
}
+32 -16
View File
@@ -2,6 +2,7 @@ package presentation
import (
"fmt"
"regexp"
"strings"
"time"
@@ -18,7 +19,12 @@ import (
"github.com/samber/lo"
)
var branchPrefixColorCache = make(map[string]style.TextStyle)
type colorMatcher struct {
patterns map[string]style.TextStyle
isRegex bool // NOTE: this value is needed only until the deprecated branchColors config is removed and only regex color patterns are used
}
var colorPatterns *colorMatcher
func GetBranchListDisplayStrings(
branches []*models.Branch,
@@ -125,22 +131,29 @@ func getBranchDisplayStrings(
// GetBranchTextStyle branch color
func GetBranchTextStyle(name string) style.TextStyle {
branchType := strings.Split(name, "/")[0]
if value, ok := branchPrefixColorCache[branchType]; ok {
return value
if style, ok := colorPatterns.match(name); ok {
return *style
}
switch branchType {
case "feature":
return style.FgGreen
case "bugfix":
return style.FgYellow
case "hotfix":
return style.FgRed
default:
return theme.DefaultTextColor
return theme.DefaultTextColor
}
func (m *colorMatcher) match(name string) (*style.TextStyle, bool) {
if m.isRegex {
for pattern, style := range m.patterns {
if matched, _ := regexp.MatchString(pattern, name); matched {
return &style, true
}
}
} else {
// old behavior using the deprecated branchColors behavior matching on branch type
branchType := strings.Split(name, "/")[0]
if value, ok := m.patterns[branchType]; ok {
return &value, true
}
}
return nil, false
}
func BranchStatus(
@@ -189,6 +202,9 @@ func BranchStatus(
return result
}
func SetCustomBranches(customBranchColors map[string]string) {
branchPrefixColorCache = utils.SetCustomColors(customBranchColors)
func SetCustomBranches(customBranchColors map[string]string, isRegex bool) {
colorPatterns = &colorMatcher{
patterns: utils.SetCustomColors(customBranchColors),
isRegex: isRegex,
}
}
+1
View File
@@ -321,6 +321,7 @@ func Test_getBranchDisplayStrings(t *testing.T) {
defer color.ForceSetColorLevel(oldColorLevel)
c := utils.NewDummyCommon()
SetCustomBranches(c.UserConfig().Gui.BranchColorPatterns, true)
for i, s := range scenarios {
icons.SetNerdFontsVersion(lo.Ternary(s.useIcons, "3", ""))
+2 -2
View File
@@ -157,7 +157,7 @@ func getFileLine(
if showFileIcons {
icon := icons.IconForFile(name, isSubmodule, isLinkedWorktree, isDirectory)
paint := color.C256(icon.Color, false)
paint := color.HEX(icon.Color, false)
output += paint.Sprint(icon.Icon) + nameColor.Sprint(" ")
}
@@ -267,7 +267,7 @@ func getCommitFileLine(
if showFileIcons {
icon := icons.IconForFile(name, isSubmodule, isLinkedWorktree, isDirectory)
paint := color.C256(icon.Color, false)
paint := color.HEX(icon.Color, false)
output += paint.Sprint(icon.Icon) + " "
}
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -8,7 +8,7 @@ import (
type IconProperties struct {
Icon string
Color uint8
Color string
}
var isIconEnabled = false
@@ -162,12 +162,29 @@ func worktreeShimFromModelRemote(worktree *models.Worktree) *Worktree {
}
}
type CommitRange struct {
From string
To string
}
func makeCommitRange(commits []*models.Commit, _ int, _ int) *CommitRange {
if len(commits) == 0 {
return nil
}
return &CommitRange{
From: commits[len(commits)-1].Hash,
To: commits[0].Hash,
}
}
// SessionState captures the current state of the application for use in custom commands
type SessionState struct {
SelectedLocalCommit *Commit // deprecated, use SelectedCommit
SelectedReflogCommit *Commit // deprecated, use SelectedCommit
SelectedSubCommit *Commit // deprecated, use SelectedCommit
SelectedCommit *Commit
SelectedCommitRange *CommitRange
SelectedFile *File
SelectedPath string
SelectedLocalBranch *Branch
@@ -183,14 +200,20 @@ type SessionState struct {
func (self *SessionStateLoader) call() *SessionState {
selectedLocalCommit := commitShimFromModelCommit(self.c.Contexts().LocalCommits.GetSelected())
selectedLocalCommitRange := makeCommitRange(self.c.Contexts().LocalCommits.GetSelectedItems())
selectedReflogCommit := commitShimFromModelCommit(self.c.Contexts().ReflogCommits.GetSelected())
selectedReflogCommitRange := makeCommitRange(self.c.Contexts().ReflogCommits.GetSelectedItems())
selectedSubCommit := commitShimFromModelCommit(self.c.Contexts().SubCommits.GetSelected())
selectedSubCommitRange := makeCommitRange(self.c.Contexts().SubCommits.GetSelectedItems())
selectedCommit := selectedLocalCommit
selectedCommitRange := selectedLocalCommitRange
if self.c.Context().IsCurrentOrParent(self.c.Contexts().ReflogCommits) {
selectedCommit = selectedReflogCommit
selectedCommitRange = selectedReflogCommitRange
} else if self.c.Context().IsCurrentOrParent(self.c.Contexts().SubCommits) {
selectedCommit = selectedSubCommit
selectedCommitRange = selectedSubCommitRange
}
selectedPath := self.c.Contexts().Files.GetSelectedPath()
@@ -207,6 +230,7 @@ func (self *SessionStateLoader) call() *SessionState {
SelectedReflogCommit: selectedReflogCommit,
SelectedSubCommit: selectedSubCommit,
SelectedCommit: selectedCommit,
SelectedCommitRange: selectedCommitRange,
SelectedLocalBranch: branchShimFromModelBranch(self.c.Contexts().Branches.GetSelected()),
SelectedRemoteBranch: remoteBranchShimFromModelRemoteBranch(self.c.Contexts().RemoteBranches.GetSelected()),
SelectedRemote: remoteShimFromModelRemote(self.c.Contexts().Remotes.GetSelected()),
+4 -4
View File
@@ -362,8 +362,8 @@ type IRepoStateAccessor interface {
SetStartupStage(stage StartupStage)
GetCurrentPopupOpts() *CreatePopupPanelOpts
SetCurrentPopupOpts(*CreatePopupPanelOpts)
GetScreenMode() WindowMaximisation
SetScreenMode(WindowMaximisation)
GetScreenMode() ScreenMode
SetScreenMode(ScreenMode)
InSearchPrompt() bool
GetSearchState() *SearchState
SetSplitMainPanel(bool)
@@ -382,10 +382,10 @@ const (
// as in panel, not your terminal's window). Sometimes you want a bit more space
// to see the contents of a panel, and this keeps track of how much maximisation
// you've set
type WindowMaximisation int
type ScreenMode int
const (
SCREEN_NORMAL WindowMaximisation = iota
SCREEN_NORMAL ScreenMode = iota
SCREEN_HALF
SCREEN_FULL
)
+8
View File
@@ -152,6 +152,14 @@ type DiffableContext interface {
// which becomes an option when you bring up the diff menu, but when you're just
// flicking through branches it will be using the local branch name.
GetDiffTerminals() []string
// Returns the ref that should be used for creating a diff of what's
// currently shown in the main view against the working directory, in order
// to adjust line numbers in the diff to match the current state of the
// shown file. For example, if the main view shows a range diff of commits,
// we need to pass the first commit of the range. This is used by
// DiffHelper.AdjustLineNumber.
RefForAdjustingLineNumberInDiff() string
}
type IListContext interface {
+1
View File
@@ -203,6 +203,7 @@ func (gui *Gui) configureViewProperties() {
for _, view := range []*gocui.View{gui.Views.Main, gui.Views.Secondary, gui.Views.Staging, gui.Views.StagingSecondary, gui.Views.PatchBuilding, gui.Views.PatchBuildingSecondary, gui.Views.MergeConflicts} {
view.CanScrollPastBottom = gui.c.UserConfig().Gui.ScrollPastBottom
view.TabWidth = gui.c.UserConfig().Gui.TabWidth
}
gui.Views.CommitDescription.FgColor = theme.GocuiDefaultTextColor

Some files were not shown because too many files have changed in this diff Show More