mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-28 10:16:22 -04:00
Compare commits
78
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab7b5f6d84 | ||
|
|
4065175a58 | ||
|
|
43106b6c7f | ||
|
|
7bea41534b | ||
|
|
14a91d9829 | ||
|
|
274e24d75e | ||
|
|
a1a8cd114d | ||
|
|
c64a7904b7 | ||
|
|
3e623cd1ce | ||
|
|
6da99a49a4 | ||
|
|
977a01172f | ||
|
|
91cb1ff29a | ||
|
|
28d10c26a4 | ||
|
|
2c321011db | ||
|
|
dbd407c01d | ||
|
|
b8d5e481bb | ||
|
|
2b3525bfd6 | ||
|
|
b2c46c33b6 | ||
|
|
c44231a7d7 | ||
|
|
3518ec9f72 | ||
|
|
ec19fcf134 | ||
|
|
2d193cb296 | ||
|
|
64cd7cd9f6 | ||
|
|
eaaf123238 | ||
|
|
1c5fe8ff17 | ||
|
|
49ca7f6a84 | ||
|
|
80c212faba | ||
|
|
ae53059ed2 | ||
|
|
13829d8ff7 | ||
|
|
53b1e12110 | ||
|
|
009062534e | ||
|
|
33e81f717d | ||
|
|
ef718f3386 | ||
|
|
bf9339557e | ||
|
|
ebfc7ff7c6 | ||
|
|
928e76a82f | ||
|
|
9de8d17d84 | ||
|
|
9776be3131 | ||
|
|
7f7d9b166f | ||
|
|
3dd2e25dfa | ||
|
|
9790a7e00c | ||
|
|
a5c6a6120d | ||
|
|
bf9f9b6c04 | ||
|
|
d520d5e404 | ||
|
|
3241a9c251 | ||
|
|
4c4a2c3ff4 | ||
|
|
508cdb40a8 | ||
|
|
ae459b2377 | ||
|
|
c834e132c7 | ||
|
|
5e9ba82d7b | ||
|
|
fc78082e81 | ||
|
|
d7d5733a71 | ||
|
|
5240b2862f | ||
|
|
e1c18226bf | ||
|
|
c4e59aea66 | ||
|
|
75311750c8 | ||
|
|
16a158a025 | ||
|
|
621229bb09 | ||
|
|
536ef82866 | ||
|
|
54680e0836 | ||
|
|
fc69945a80 | ||
|
|
69a048c0ff | ||
|
|
6c6d835d50 | ||
|
|
2a72e96011 | ||
|
|
a507c836b2 | ||
|
|
8b90cca521 | ||
|
|
3573289452 | ||
|
|
87b54a4107 | ||
|
|
1b0d3829f8 | ||
|
|
aad3dc42a7 | ||
|
|
f884cc2af9 | ||
|
|
f4c8287143 | ||
|
|
03d7bc854e | ||
|
|
fdf1643f63 | ||
|
|
d93be027b6 | ||
|
|
fd5be11370 | ||
|
|
1e1fba4ce6 | ||
|
|
b174791490 |
@@ -0,0 +1,72 @@
|
||||
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: 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: |
|
||||
latest_tag=$(git describe --tags $(git rev-list --tags --max-count=1) || echo "v0.0.0")
|
||||
echo "Latest tag: $latest_tag"
|
||||
IFS='.' read -r major minor patch <<< "$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_TOKEN }}
|
||||
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
+44
-7
@@ -219,9 +219,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'
|
||||
@@ -571,6 +571,8 @@ keybinding:
|
||||
openMergeTool: M
|
||||
openStatusFilter: <c-b>
|
||||
copyFileInfoToClipboard: "y"
|
||||
collapseAll: '-'
|
||||
expandAll: =
|
||||
branches:
|
||||
createPullRequest: o
|
||||
viewPullRequestOptions: O
|
||||
@@ -659,6 +661,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 +676,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 +834,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
|
||||
|
||||

|
||||
@@ -916,6 +945,14 @@ git:
|
||||
replace: '[$1] '
|
||||
```
|
||||
|
||||
> [!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.
|
||||
|
||||
@@ -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 |
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
@@ -65,6 +65,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 +149,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 +352,7 @@ 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. |
|
||||
| `` <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. |
|
||||
|
||||
@@ -143,6 +143,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 +182,7 @@ 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. |
|
||||
| `` <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 +220,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 |
|
||||
| `` / `` | 検索を開始 | |
|
||||
|
||||
## ブランチ
|
||||
|
||||
@@ -308,6 +308,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,7 +323,7 @@ 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. |
|
||||
| `` <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. |
|
||||
@@ -359,6 +361,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 |
|
||||
| `` / `` | 검색 시작 | |
|
||||
|
||||
## 확인 패널
|
||||
|
||||
@@ -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
|
||||
@@ -136,6 +138,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 +352,7 @@ 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. |
|
||||
| `` <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. |
|
||||
|
||||
@@ -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
|
||||
@@ -245,6 +247,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
|
||||
|
||||
@@ -270,6 +270,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 +288,7 @@ 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. |
|
||||
| `` <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 +355,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 |
|
||||
| `` / `` | Найти | |
|
||||
|
||||
## Хранилище
|
||||
|
||||
@@ -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 `` | 删除 | 查看本地/远程分支的删除选项 |
|
||||
@@ -195,6 +195,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 +227,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 |
|
||||
| `` / `` | 开始搜索 | |
|
||||
|
||||
## 构建补丁中
|
||||
|
||||
@@ -219,6 +219,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 +284,7 @@ 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. |
|
||||
| `` <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 +322,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 |
|
||||
| `` / `` | 搜尋 | |
|
||||
|
||||
## 狀態
|
||||
|
||||
@@ -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.0
|
||||
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.20250111205211-82d518436b5a
|
||||
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
|
||||
@@ -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
|
||||
@@ -73,10 +72,10 @@ require (
|
||||
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/crypto v0.31.0 // indirect
|
||||
golang.org/x/net v0.33.0 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/term v0.28.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
)
|
||||
|
||||
@@ -85,11 +85,10 @@ 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 h1:IDclow1j6kKpU/gOhjmc+7Pj5Dxnukb74pfKN4Cxrfg=
|
||||
github.com/gdamore/tcell/v2 v2.8.0/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 +144,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 +187,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.20250111205211-82d518436b5a h1:GLFWB8rESraTt2eIe2yssy4d4VEkCnmKbPeeZ5vCT2s=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20250111205211-82d518436b5a/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 +234,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=
|
||||
@@ -327,8 +325,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 +368,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 +406,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,6 +433,9 @@ 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.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 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20170407050850-f3918c30c5c2/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -474,15 +486,22 @@ 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 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.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 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||
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,7 +511,10 @@ 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.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -547,6 +569,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
@@ -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,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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -88,6 +88,7 @@ type PullOptions struct {
|
||||
BranchName string
|
||||
FastForwardOnly bool
|
||||
WorktreeGitDir string
|
||||
WorktreePath string
|
||||
}
|
||||
|
||||
func (self *SyncCommands) Pull(task gocui.Task, opts PullOptions) error {
|
||||
@@ -97,6 +98,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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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}}",
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ func TestOSCommandFileType(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
"nonExistant",
|
||||
"nonExistent",
|
||||
func() {},
|
||||
func(output string) {
|
||||
assert.EqualValues(t, "other", output)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,16 +217,23 @@ 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")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err)
|
||||
changedContent := content
|
||||
|
||||
pathsToReplace := []struct {
|
||||
oldPath []string
|
||||
newName string
|
||||
}{
|
||||
{[]string{"gui", "skipUnstageLineWarning"}, "skipDiscardChangeWarning"},
|
||||
{[]string{"keybinding", "universal", "executeCustomCommand"}, "executeShellCommand"},
|
||||
{[]string{"gui", "windowSize"}, "screenMode"},
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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
|
||||
@@ -148,9 +151,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"`
|
||||
@@ -453,6 +456,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 {
|
||||
@@ -734,7 +739,7 @@ func GetDefaultConfig() *UserConfig {
|
||||
CommandLogSize: 8,
|
||||
SplitDiff: "auto",
|
||||
SkipRewordInEditorWarning: false,
|
||||
WindowSize: "normal",
|
||||
ScreenMode: "normal",
|
||||
Border: "rounded",
|
||||
AnimateExplosion: true,
|
||||
PortraitMode: "auto",
|
||||
@@ -895,6 +900,8 @@ func GetDefaultConfig() *UserConfig {
|
||||
OpenStatusFilter: "<c-b>",
|
||||
ConfirmDiscard: "x",
|
||||
CopyFileInfoToClipboard: "y",
|
||||
CollapseAll: "-",
|
||||
ExpandAll: "=",
|
||||
},
|
||||
Branches: KeybindingBranchesConfig{
|
||||
CopyPullRequestURL: "<c-y>",
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -53,3 +53,7 @@ func (self *RemotesContext) GetDiffTerminals() []string {
|
||||
|
||||
return []string{itemId}
|
||||
}
|
||||
|
||||
func (self *RemotesContext) RefForAdjustingLineNumberInDiff() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -71,3 +71,7 @@ func (self *StashContext) GetDiffTerminals() []string {
|
||||
|
||||
return []string{itemId}
|
||||
}
|
||||
|
||||
func (self *StashContext) RefForAdjustingLineNumberInDiff() string {
|
||||
return self.GetSelectedItemId()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -280,15 +280,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 {
|
||||
|
||||
@@ -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 {
|
||||
@@ -59,6 +61,15 @@ 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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -109,6 +109,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
|
||||
@@ -401,6 +415,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 +450,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
|
||||
}
|
||||
|
||||
@@ -186,6 +186,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 +492,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 {
|
||||
@@ -664,7 +694,7 @@ func (self *FilesController) handleAmendCommitPress() error {
|
||||
Title: self.c.Tr.AmendLastCommitTitle,
|
||||
Prompt: self.c.Tr.SureToAmend,
|
||||
HandleConfirm: func() error {
|
||||
return self.c.Helpers().WorkingTree.WithEnsureCommitableFiles(func() error {
|
||||
return self.c.Helpers().WorkingTree.WithEnsureCommittableFiles(func() error {
|
||||
if len(self.c.Model().Commits) == 0 {
|
||||
return errors.New(self.c.Tr.NoCommitToAmend)
|
||||
}
|
||||
@@ -869,7 +899,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 +924,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 +1211,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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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,53 @@ 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
|
||||
var menuItems []*types.MenuItem
|
||||
|
||||
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',
|
||||
})
|
||||
}
|
||||
|
||||
menuItems = append(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',
|
||||
})
|
||||
|
||||
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 +353,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 +413,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(),
|
||||
@@ -172,7 +172,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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -161,6 +161,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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ type ITree[T any] interface {
|
||||
IsCollapsed(path string) bool
|
||||
ToggleCollapsed(path string)
|
||||
CollapsedPaths() *CollapsedPaths
|
||||
CollapseAll()
|
||||
ExpandAll()
|
||||
}
|
||||
|
||||
type IFileTree interface {
|
||||
@@ -171,6 +173,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)
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -453,7 +453,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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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", ""))
|
||||
|
||||
@@ -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
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
type IconProperties struct {
|
||||
Icon string
|
||||
Color uint8
|
||||
Color string
|
||||
}
|
||||
|
||||
var isIconEnabled = false
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+43
-19
@@ -256,6 +256,11 @@ type TranslationSet struct {
|
||||
NoBranchOnRemote string
|
||||
Fetch string
|
||||
FetchTooltip string
|
||||
CollapseAll string
|
||||
CollapseAllTooltip string
|
||||
ExpandAll string
|
||||
ExpandAllTooltip string
|
||||
DisabledInFlatView string
|
||||
FileEnter string
|
||||
FileEnterTooltip string
|
||||
FileStagingRequirements string
|
||||
@@ -290,6 +295,7 @@ type TranslationSet struct {
|
||||
CommitSummaryTitle string
|
||||
CommitDescriptionTitle string
|
||||
CommitDescriptionSubTitle string
|
||||
CommitDescriptionFooter string
|
||||
LocalBranchesTitle string
|
||||
SearchTitle string
|
||||
TagsTitle string
|
||||
@@ -527,6 +533,7 @@ type TranslationSet struct {
|
||||
FetchingRemoteStatus string
|
||||
CheckoutCommit string
|
||||
CheckoutCommitTooltip string
|
||||
NoBranchesFoundAtCommitTooltip string
|
||||
SureCheckoutThisCommit string
|
||||
GitFlowOptions string
|
||||
NotAGitFlowBranch string
|
||||
@@ -725,8 +732,9 @@ type TranslationSet struct {
|
||||
ConfirmRevertCommit string
|
||||
RewordInEditorTitle string
|
||||
RewordInEditorPrompt string
|
||||
CheckoutPrompt string
|
||||
CheckoutAutostashPrompt string
|
||||
HardResetAutostashPrompt string
|
||||
SoftResetPrompt string
|
||||
UpstreamGone string
|
||||
NukeDescription string
|
||||
DiscardStagedChangesDescription string
|
||||
@@ -860,8 +868,11 @@ type Log struct {
|
||||
|
||||
type Actions struct {
|
||||
CheckoutCommit string
|
||||
CheckoutBranchAtCommit string
|
||||
CheckoutCommitAsDetachedHead string
|
||||
CheckoutTag string
|
||||
CheckoutBranch string
|
||||
CheckoutBranchOrCommit string
|
||||
ForceCheckoutBranch string
|
||||
DeleteLocalBranch string
|
||||
Merge string
|
||||
@@ -1072,7 +1083,7 @@ func EnglishTranslationSet() *TranslationSet {
|
||||
Checkout: "Checkout",
|
||||
CheckoutTooltip: "Checkout selected item.",
|
||||
CantCheckoutBranchWhilePulling: "You cannot checkout another branch while pulling the current branch",
|
||||
TagCheckoutTooltip: "Checkout the selected tag tag as a detached HEAD.",
|
||||
TagCheckoutTooltip: "Checkout the selected tag as a detached HEAD.",
|
||||
RemoteBranchCheckoutTooltip: "Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head.",
|
||||
CantPullOrPushSameBranchTwice: "You cannot push or pull a branch while it is already being pushed or pulled",
|
||||
FileFilter: "Filter files by status",
|
||||
@@ -1253,6 +1264,11 @@ func EnglishTranslationSet() *TranslationSet {
|
||||
NoBranchOnRemote: `This branch doesn't exist on remote. You need to push it to remote first.`,
|
||||
Fetch: `Fetch`,
|
||||
FetchTooltip: "Fetch changes from remote.",
|
||||
CollapseAll: "Collapse all files",
|
||||
CollapseAllTooltip: "Collapse all directories in the files tree",
|
||||
ExpandAll: "Expand all files",
|
||||
ExpandAllTooltip: "Expand all directories in the file tree",
|
||||
DisabledInFlatView: "Not available in flat view",
|
||||
FileEnter: `Stage lines / Collapse directory`,
|
||||
FileEnterTooltip: "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.",
|
||||
FileStagingRequirements: `Can only stage individual lines for tracked files`,
|
||||
@@ -1286,6 +1302,7 @@ func EnglishTranslationSet() *TranslationSet {
|
||||
CommitSummaryTitle: "Commit summary",
|
||||
CommitDescriptionTitle: "Commit description",
|
||||
CommitDescriptionSubTitle: "Press {{.togglePanelKeyBinding}} to toggle focus, {{.commitMenuKeybinding}} to open menu",
|
||||
CommitDescriptionFooter: "Press {{.confirmInEditorKeybinding}} to commit",
|
||||
LocalBranchesTitle: "Local branches",
|
||||
SearchTitle: "Search",
|
||||
TagsTitle: "Tags",
|
||||
@@ -1331,7 +1348,7 @@ func EnglishTranslationSet() *TranslationSet {
|
||||
CherryPickCopyTooltip: "Mark commit as copied. Then, within the local commits view, you can press `{{.paste}}` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `{{.escape}}` to cancel the selection.",
|
||||
CherryPickCopyRangeTooltip: "Mark commits as copied from the last copied commit to the selected commit.",
|
||||
PasteCommits: "Paste (cherry-pick)",
|
||||
SureCherryPick: "Are you sure you want to cherry-pick the copied commits onto this branch?",
|
||||
SureCherryPick: "Are you sure you want to cherry-pick the {{.numCommits}} copied commit(s) onto this branch?",
|
||||
CherryPick: "Cherry-pick",
|
||||
CannotCherryPickNonCommit: "Cannot cherry-pick this kind of todo item",
|
||||
CannotCherryPickMergeCommit: "Cherry-picking merge commits is not supported",
|
||||
@@ -1522,21 +1539,22 @@ func EnglishTranslationSet() *TranslationSet {
|
||||
DeleteRemoteTagPrompt: "Are you sure you want to delete the remote tag '{{.tagName}}' from '{{.upstream}}'?",
|
||||
PushTagTitle: "Remote to push tag '{{.tagName}}' to:",
|
||||
// Using 'push tag' rather than just 'push' to disambiguate from a global push
|
||||
PushTag: "Push tag",
|
||||
PushTagTooltip: "Push the selected tag to a remote. You'll be prompted to select a remote.",
|
||||
NewTag: "New tag",
|
||||
NewTagTooltip: "Create new tag from current commit. You'll be prompted to enter a tag name and optional description.",
|
||||
CreatingTag: "Creating tag",
|
||||
ForceTag: "Force Tag",
|
||||
ForceTagPrompt: "The tag '{{.tagName}}' exists already. Press {{.cancelKey}} to cancel, or {{.confirmKey}} to overwrite.",
|
||||
FetchRemoteTooltip: "Fetch updates from the remote repository. This retrieves new commits and branches without merging them into your local branches.",
|
||||
FetchingRemoteStatus: "Fetching remote",
|
||||
CheckoutCommit: "Checkout commit",
|
||||
CheckoutCommitTooltip: "Checkout the selected commit as a detached HEAD.",
|
||||
SureCheckoutThisCommit: "Are you sure you want to checkout this commit?",
|
||||
GitFlowOptions: "Show git-flow options",
|
||||
NotAGitFlowBranch: "This does not seem to be a git flow branch",
|
||||
NewGitFlowBranchPrompt: "New {{.branchType}} name:",
|
||||
PushTag: "Push tag",
|
||||
PushTagTooltip: "Push the selected tag to a remote. You'll be prompted to select a remote.",
|
||||
NewTag: "New tag",
|
||||
NewTagTooltip: "Create new tag from current commit. You'll be prompted to enter a tag name and optional description.",
|
||||
CreatingTag: "Creating tag",
|
||||
ForceTag: "Force Tag",
|
||||
ForceTagPrompt: "The tag '{{.tagName}}' exists already. Press {{.cancelKey}} to cancel, or {{.confirmKey}} to overwrite.",
|
||||
FetchRemoteTooltip: "Fetch updates from the remote repository. This retrieves new commits and branches without merging them into your local branches.",
|
||||
FetchingRemoteStatus: "Fetching remote",
|
||||
CheckoutCommit: "Checkout commit",
|
||||
CheckoutCommitTooltip: "Checkout the selected commit as a detached HEAD.",
|
||||
NoBranchesFoundAtCommitTooltip: "No branches found at selected commit.",
|
||||
SureCheckoutThisCommit: "Are you sure you want to checkout this commit?",
|
||||
GitFlowOptions: "Show git-flow options",
|
||||
NotAGitFlowBranch: "This does not seem to be a git flow branch",
|
||||
NewGitFlowBranchPrompt: "New {{.branchType}} name:",
|
||||
|
||||
IgnoreTracked: "Ignore tracked file",
|
||||
IgnoreTrackedPrompt: "Are you sure you want to ignore a tracked file?",
|
||||
@@ -1728,7 +1746,8 @@ func EnglishTranslationSet() *TranslationSet {
|
||||
RewordInEditorTitle: "Reword in editor",
|
||||
RewordInEditorPrompt: "Are you sure you want to reword this commit in your editor?",
|
||||
HardResetAutostashPrompt: "Are you sure you want to hard reset to '%s'? An auto-stash will be performed if necessary.",
|
||||
CheckoutPrompt: "Are you sure you want to checkout '%s'?",
|
||||
SoftResetPrompt: "Are you sure you want to soft reset to '%s'?",
|
||||
CheckoutAutostashPrompt: "Are you sure you want to checkout '%s'? An auto-stash will be performed if necessary.",
|
||||
UpstreamGone: "(upstream gone)",
|
||||
NukeDescription: "If you want to make all the changes in the worktree go away, this is the way to do it. If there are dirty submodule changes this will stash those changes in the submodule(s).",
|
||||
DiscardStagedChangesDescription: "This will create a new stash entry containing only staged files and then drop it, so that the working tree is left with only unstaged changes",
|
||||
@@ -1822,9 +1841,12 @@ func EnglishTranslationSet() *TranslationSet {
|
||||
Actions: Actions{
|
||||
// TODO: combine this with the original keybinding descriptions (those are all in lowercase atm)
|
||||
CheckoutCommit: "Checkout commit",
|
||||
CheckoutBranchAtCommit: "Checkout branch '%s'",
|
||||
CheckoutCommitAsDetachedHead: "Checkout commit %s as detached head",
|
||||
CheckoutTag: "Checkout tag",
|
||||
CheckoutBranch: "Checkout branch",
|
||||
ForceCheckoutBranch: "Force checkout branch",
|
||||
CheckoutBranchOrCommit: "Checkout branch or commit",
|
||||
DeleteLocalBranch: "Delete local branch",
|
||||
Merge: "Merge",
|
||||
SquashMerge: "Squash merge",
|
||||
@@ -1996,6 +2018,8 @@ keybinding:
|
||||
gui:
|
||||
filterMode: 'fuzzy'
|
||||
`,
|
||||
"0.44.0": `- The gui.branchColors config option is deprecated; it will be removed in a future version. Please use gui.branchColorPatterns instead.
|
||||
- The automatic coloring of branches starting with "feature/", "bugfix/", or "hotfix/" has been removed; if you want this, it's easy to set up using the new gui.branchColorPatterns option.`,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@
|
||||
"SwitchRepo": "切换到最近的仓库",
|
||||
"AllBranchesLogGraph": "显示所有分支的日志",
|
||||
"UnsupportedGitService": "不支持的 git 服务",
|
||||
"CopyPullRequestURL": "将抓取请求 URL 复制到剪贴板",
|
||||
"CopyPullRequestURL": "将拉取请求 URL 复制到剪贴板",
|
||||
"NoBranchOnRemote": "该分支在远程上不存在. 您需要先将其推送到远程.",
|
||||
"Fetch": "抓取",
|
||||
"FetchTooltip": "从远程获取变更",
|
||||
@@ -632,7 +632,7 @@
|
||||
"SuggestionsSubtitle": "(按 %s 键进行删除, %s 键进行编辑)",
|
||||
"ExtrasTitle": "附加",
|
||||
"PushingTagStatus": "推送标签",
|
||||
"PullRequestURLCopiedToClipboard": "抓取请求网址已复制到剪贴板",
|
||||
"PullRequestURLCopiedToClipboard": "拉取请求网址已复制到剪贴板",
|
||||
"CommitDiffCopiedToClipboard": "复制提交差异到剪贴板",
|
||||
"CommitURLCopiedToClipboard": "复制提交URL到剪贴板",
|
||||
"CommitMessageCopiedToClipboard": "复制提交消息到剪贴板",
|
||||
@@ -659,10 +659,10 @@
|
||||
"DecreaseContextInDiffView": "缩小差异视图中显示的上下文范围",
|
||||
"DecreaseContextInDiffViewTooltip": "减少diff视图中围绕更改显示的上下文数量",
|
||||
"DiffContextSizeChanged": "将diff上下文大小更改为%d",
|
||||
"CreatePullRequestOptions": "创建抓取请求选项",
|
||||
"CreatePullRequestOptions": "创建拉取请求选项",
|
||||
"DefaultBranch": "默认分支",
|
||||
"SelectBranch": "选择分支",
|
||||
"CreatePullRequest": "创建抓取请求",
|
||||
"CreatePullRequest": "创建拉取请求",
|
||||
"SelectConfigFile": "选择配置文件",
|
||||
"NoConfigFileFoundErr": "找不到配置文件",
|
||||
"LoadingFileSuggestions": "正在加载文件建议",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package clients
|
||||
|
||||
// This file allows you to use `go test` to run integration tests.
|
||||
// See See pkg/integration/README.md for more info.
|
||||
// See pkg/integration/README.md for more info.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
@@ -19,7 +19,7 @@ const (
|
||||
// which is good to test for.
|
||||
PWD = "PWD"
|
||||
|
||||
// We set $HOME and $GIT_CONFIG_NOGLOBAL during integrationt tests so
|
||||
// We set $HOME and $GIT_CONFIG_NOGLOBAL during integration tests so
|
||||
// that older versions of git that don't respect $GIT_CONFIG_GLOBAL
|
||||
// will find the correct global config file for testing
|
||||
HOME = "HOME"
|
||||
|
||||
@@ -142,6 +142,10 @@ func (self *Shell) NewBranchFrom(name string, from string) *Shell {
|
||||
return self.RunCommand([]string{"git", "checkout", "-b", name, from})
|
||||
}
|
||||
|
||||
func (self *Shell) RenameCurrentBranch(newName string) *Shell {
|
||||
return self.RunCommand([]string{"git", "branch", "-m", newName})
|
||||
}
|
||||
|
||||
func (self *Shell) Checkout(name string) *Shell {
|
||||
return self.RunCommand([]string{"git", "checkout", name})
|
||||
}
|
||||
|
||||
@@ -16,8 +16,9 @@ var RebaseToUpstream = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
EmptyCommit("ensure-master").
|
||||
EmptyCommit("to-be-added"). // <- this will only exist remotely
|
||||
PushBranchAndSetUpstream("origin", "master").
|
||||
RenameCurrentBranch("master-local").
|
||||
HardReset("HEAD~1").
|
||||
NewBranchFrom("base-branch", "master").
|
||||
NewBranchFrom("base-branch", "master-local").
|
||||
EmptyCommit("base-branch-commit").
|
||||
NewBranch("target").
|
||||
EmptyCommit("target-commit")
|
||||
@@ -34,13 +35,13 @@ var RebaseToUpstream = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Lines(
|
||||
Contains("target").IsSelected(),
|
||||
Contains("base-branch"),
|
||||
Contains("master"),
|
||||
Contains("master-local"),
|
||||
).
|
||||
SelectNextItem().
|
||||
Lines(
|
||||
Contains("target"),
|
||||
Contains("base-branch").IsSelected(),
|
||||
Contains("master"),
|
||||
Contains("master-local"),
|
||||
).
|
||||
Press(keys.Branches.SetUpstream).
|
||||
Tap(func() {
|
||||
@@ -58,7 +59,7 @@ var RebaseToUpstream = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Lines(
|
||||
Contains("target"),
|
||||
Contains("base-branch"),
|
||||
Contains("master").IsSelected(),
|
||||
Contains("master-local").IsSelected(),
|
||||
).
|
||||
Press(keys.Branches.SetUpstream).
|
||||
Tap(func() {
|
||||
|
||||
@@ -19,6 +19,7 @@ var ResetToUpstream = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
NewBranch("soft-branch").
|
||||
EmptyCommit("soft commit").
|
||||
PushBranchAndSetUpstream("origin", "soft-branch").
|
||||
RenameCurrentBranch("soft-branch-local").
|
||||
NewBranch("base").
|
||||
EmptyCommit("base-branch commit").
|
||||
CreateFile("file-1", "content").
|
||||
@@ -33,7 +34,7 @@ var ResetToUpstream = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Focus().
|
||||
Lines(
|
||||
Contains("base").IsSelected(),
|
||||
Contains("soft-branch"),
|
||||
Contains("soft-branch-local"),
|
||||
Contains("hard-branch"),
|
||||
).
|
||||
Press(keys.Branches.SetUpstream).
|
||||
@@ -51,7 +52,7 @@ var ResetToUpstream = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
SelectNextItem().
|
||||
Lines(
|
||||
Contains("base"),
|
||||
Contains("soft-branch").IsSelected(),
|
||||
Contains("soft-branch-local").IsSelected(),
|
||||
Contains("hard-branch"),
|
||||
).
|
||||
Press(keys.Branches.SetUpstream).
|
||||
@@ -80,7 +81,7 @@ var ResetToUpstream = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Focus().
|
||||
Lines(
|
||||
Contains("base"),
|
||||
Contains("soft-branch").IsSelected(),
|
||||
Contains("soft-branch-local").IsSelected(),
|
||||
Contains("hard-branch"),
|
||||
).
|
||||
NavigateToLine(Contains("hard-branch")).
|
||||
|
||||
@@ -66,7 +66,7 @@ var CherryPick = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Alert().
|
||||
Title(Equals("Cherry-pick")).
|
||||
Content(Contains("Are you sure you want to cherry-pick the copied commits onto this branch?")).
|
||||
Content(Contains("Are you sure you want to cherry-pick the 2 copied commit(s) onto this branch?")).
|
||||
Confirm()
|
||||
}).
|
||||
Tap(func() {
|
||||
@@ -95,7 +95,7 @@ var CherryPick = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Alert().
|
||||
Title(Equals("Cherry-pick")).
|
||||
Content(Contains("Are you sure you want to cherry-pick the copied commits onto this branch?")).
|
||||
Content(Contains("Are you sure you want to cherry-pick the 2 copied commit(s) onto this branch?")).
|
||||
Confirm()
|
||||
}).
|
||||
Tap(func() {
|
||||
|
||||
@@ -49,7 +49,7 @@ var CherryPickConflicts = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.ExpectPopup().Alert().
|
||||
Title(Equals("Cherry-pick")).
|
||||
Content(Contains("Are you sure you want to cherry-pick the copied commits onto this branch?")).
|
||||
Content(Contains("Are you sure you want to cherry-pick the 2 copied commit(s) onto this branch?")).
|
||||
Confirm()
|
||||
|
||||
t.Common().AcknowledgeConflicts()
|
||||
|
||||
@@ -67,7 +67,7 @@ var CherryPickDuringRebase = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Alert().
|
||||
Title(Equals("Cherry-pick")).
|
||||
Content(Contains("Are you sure you want to cherry-pick the copied commits onto this branch?")).
|
||||
Content(Contains("Are you sure you want to cherry-pick the 1 copied commit(s) onto this branch?")).
|
||||
Confirm()
|
||||
}).
|
||||
Tap(func() {
|
||||
|
||||
@@ -63,7 +63,7 @@ var CherryPickRange = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Alert().
|
||||
Title(Equals("Cherry-pick")).
|
||||
Content(Contains("Are you sure you want to cherry-pick the copied commits onto this branch?")).
|
||||
Content(Contains("Are you sure you want to cherry-pick the 2 copied commit(s) onto this branch?")).
|
||||
Confirm()
|
||||
}).
|
||||
Tap(func() {
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
package commit
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var Checkout = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Checkout a commit as a detached head, or checkout an existing branch at a commit",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.EmptyCommit("one")
|
||||
shell.EmptyCommit("two")
|
||||
shell.NewBranch("branch1")
|
||||
shell.NewBranch("branch2")
|
||||
shell.EmptyCommit("three")
|
||||
shell.EmptyCommit("four")
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Commits().
|
||||
Focus().
|
||||
Lines(
|
||||
Contains("four").IsSelected(),
|
||||
Contains("three"),
|
||||
Contains("two"),
|
||||
Contains("one"),
|
||||
).
|
||||
PressPrimaryAction()
|
||||
|
||||
t.ExpectPopup().Menu().
|
||||
Title(Contains("Checkout branch or commit")).
|
||||
Lines(
|
||||
Contains("Checkout branch").IsSelected(),
|
||||
MatchesRegexp("Checkout commit [a-f0-9]+ as detached head"),
|
||||
Contains("Cancel"),
|
||||
).
|
||||
Tooltip(Contains("Disabled: No branches found at selected commit.")).
|
||||
Select(MatchesRegexp("Checkout commit [a-f0-9]+ as detached head")).
|
||||
Confirm()
|
||||
t.Views().Branches().Lines(
|
||||
Contains("* (HEAD detached at"),
|
||||
Contains("branch2"),
|
||||
Contains("branch1"),
|
||||
Contains("master"),
|
||||
)
|
||||
|
||||
t.Views().Commits().
|
||||
NavigateToLine(Contains("two")).
|
||||
PressPrimaryAction()
|
||||
|
||||
t.ExpectPopup().Menu().
|
||||
Title(Contains("Checkout branch or commit")).
|
||||
Lines(
|
||||
Contains("Checkout branch 'branch1'").IsSelected(),
|
||||
Contains("Checkout branch 'master'"),
|
||||
MatchesRegexp("Checkout commit [a-f0-9]+ as detached head"),
|
||||
Contains("Cancel"),
|
||||
).
|
||||
Select(Contains("Checkout branch 'master'")).
|
||||
Confirm()
|
||||
t.Views().Branches().Lines(
|
||||
Contains("master"),
|
||||
Contains("branch2"),
|
||||
Contains("branch1"),
|
||||
)
|
||||
},
|
||||
})
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
var Bisect = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Interactive rebase",
|
||||
ExtraCmdArgs: []string{"log"},
|
||||
ExtraCmdArgs: []string{"log", "--screen-mode=full"},
|
||||
Skip: false,
|
||||
IsDemo: true,
|
||||
SetupConfig: func(config *config.AppConfig) {
|
||||
|
||||
@@ -71,7 +71,7 @@ var CherryPick = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Wait(1000)
|
||||
t.ExpectPopup().Alert().
|
||||
Title(Equals("Cherry-pick")).
|
||||
Content(Contains("Are you sure you want to cherry-pick the copied commits onto this branch?")).
|
||||
Content(Contains("Are you sure you want to cherry-pick the 2 copied commit(s) onto this branch?")).
|
||||
Confirm()
|
||||
}).
|
||||
TopLines(
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
var CommitGraph = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Show commit graph",
|
||||
ExtraCmdArgs: []string{"log"},
|
||||
ExtraCmdArgs: []string{"log", "--screen-mode=full"},
|
||||
Skip: false,
|
||||
IsDemo: true,
|
||||
SetupConfig: func(config *config.AppConfig) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
var InteractiveRebase = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Interactive rebase",
|
||||
ExtraCmdArgs: []string{"log"},
|
||||
ExtraCmdArgs: []string{"log", "--screen-mode=full"},
|
||||
Skip: false,
|
||||
IsDemo: true,
|
||||
SetupConfig: func(config *config.AppConfig) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
var NukeWorkingTree = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Nuke the working tree",
|
||||
ExtraCmdArgs: []string{"status"},
|
||||
ExtraCmdArgs: []string{"status", "--screen-mode=full"},
|
||||
Skip: false,
|
||||
IsDemo: true,
|
||||
SetupConfig: func(config *config.AppConfig) {
|
||||
|
||||
@@ -14,6 +14,6 @@ func setGeneratedAuthorColours(config *config.AppConfig) {
|
||||
}
|
||||
|
||||
func setDefaultDemoConfig(config *config.AppConfig) {
|
||||
// demos look much nicers with icons shown
|
||||
// demos look much nicer with icons shown
|
||||
config.GetUserConfig().Gui.NerdFontsVersion = "3"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var CollapseExpand = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Collapsing and expanding all files in the file tree",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {
|
||||
},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.CreateDir("dir")
|
||||
shell.CreateFile("dir/file-one", "original content\n")
|
||||
shell.CreateDir("dir2")
|
||||
shell.CreateFile("dir2/file-two", "original content\n")
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("dir").IsSelected(),
|
||||
Contains("??").Contains("file-one"),
|
||||
Contains("dir2"),
|
||||
Contains("??").Contains("file-two"),
|
||||
)
|
||||
|
||||
t.Views().Files().
|
||||
Press(keys.Files.CollapseAll).
|
||||
Lines(
|
||||
Contains("dir"),
|
||||
Contains("dir2"),
|
||||
)
|
||||
|
||||
t.Views().Files().
|
||||
Press(keys.Files.ExpandAll).
|
||||
Lines(
|
||||
Contains("dir").IsSelected(),
|
||||
Contains("??").Contains("file-one"),
|
||||
Contains("dir2"),
|
||||
Contains("??").Contains("file-two"),
|
||||
)
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,47 @@
|
||||
package patch_building
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var EditLineInPatchBuildingPanel = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Edit a line in the patch building panel; make sure we end up on the right line",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {
|
||||
config.GetUserConfig().OS.EditAtLine = "echo {{filename}}:{{line}} > edit-command"
|
||||
},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.CreateFileAndAdd("file.txt", "4\n5\n6\n")
|
||||
shell.Commit("01")
|
||||
shell.UpdateFileAndAdd("file.txt", "1\n2a\n2b\n3\n4\n5\n6\n")
|
||||
shell.Commit("02")
|
||||
shell.UpdateFile("file.txt", "1\n2\n3\n4\n5\n6\n")
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Commits().
|
||||
Focus().
|
||||
Lines(
|
||||
Contains("02").IsSelected(),
|
||||
Contains("01"),
|
||||
).
|
||||
Press(keys.Universal.NextItem).
|
||||
PressEnter()
|
||||
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("A file.txt").IsSelected(),
|
||||
).
|
||||
PressEnter()
|
||||
|
||||
t.Views().PatchBuilding().
|
||||
IsFocused().
|
||||
Content(Contains("+4\n+5\n+6")).
|
||||
NavigateToLine(Contains("+5")).
|
||||
Press(keys.Universal.Edit)
|
||||
|
||||
t.FileSystem().FileContent("edit-command", Contains("file.txt:5\n"))
|
||||
},
|
||||
})
|
||||
@@ -64,6 +64,6 @@ var MoveToIndexPartOfAdjacentAddedLines = NewIntegrationTest(NewIntegrationTestA
|
||||
)
|
||||
|
||||
t.Views().Main().
|
||||
Content(Contains("+1st line\n 2nd line\n"))
|
||||
Content(Contains("+1st line\n 2nd line"))
|
||||
},
|
||||
})
|
||||
|
||||
@@ -28,9 +28,9 @@ var Checkout = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
SelectNextItem().
|
||||
PressPrimaryAction().
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Confirmation().
|
||||
Title(Contains("Checkout commit")).
|
||||
Content(Contains("Are you sure you want to checkout this commit?")).
|
||||
t.ExpectPopup().Menu().
|
||||
Title(Contains("Checkout branch or commit")).
|
||||
Select(MatchesRegexp("Checkout commit [a-f0-9]+ as detached head")).
|
||||
Confirm()
|
||||
}).
|
||||
TopLines(
|
||||
|
||||
@@ -39,7 +39,7 @@ var CherryPick = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Alert().
|
||||
Title(Equals("Cherry-pick")).
|
||||
Content(Contains("Are you sure you want to cherry-pick the copied commits onto this branch?")).
|
||||
Content(Contains("Are you sure you want to cherry-pick the 1 copied commit(s) onto this branch?")).
|
||||
Confirm()
|
||||
}).
|
||||
Lines(
|
||||
|
||||
@@ -23,12 +23,12 @@ var StashStagedPartialFile = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Staging().
|
||||
Content(
|
||||
Contains(" line1\n-line2\n+line2 mod\n line3\n-line4\n+line4 mod\n"),
|
||||
Contains(" line1\n-line2\n+line2 mod\n line3\n-line4\n+line4 mod"),
|
||||
).
|
||||
PressPrimaryAction().
|
||||
PressPrimaryAction().
|
||||
Content(
|
||||
Contains(" line1\n line2 mod\n line3\n-line4\n+line4 mod\n"),
|
||||
Contains(" line1\n line2 mod\n line3\n-line4\n+line4 mod"),
|
||||
).
|
||||
PressEscape()
|
||||
|
||||
@@ -54,7 +54,7 @@ var StashStagedPartialFile = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
)
|
||||
t.Views().Main().
|
||||
Content(
|
||||
Contains(" line1\n-line2\n+line2 mod\n line3\n line4\n"),
|
||||
Contains(" line1\n-line2\n+line2 mod\n line3\n line4"),
|
||||
)
|
||||
|
||||
t.Views().Files().
|
||||
@@ -64,7 +64,7 @@ var StashStagedPartialFile = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Staging().
|
||||
Content(
|
||||
Contains(" line1\n line2\n line3\n-line4\n+line4 mod\n"),
|
||||
Contains(" line1\n line2\n line3\n-line4\n+line4 mod"),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user