mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-10-05 21:46:49 -04:00
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab7b5f6d84 | ||
|
|
4065175a58 | ||
|
|
43106b6c7f | ||
|
|
7bea41534b | ||
|
|
14a91d9829 | ||
|
|
274e24d75e | ||
|
|
a1a8cd114d | ||
|
|
c64a7904b7 | ||
|
|
3e623cd1ce | ||
|
|
6da99a49a4 | ||
|
|
977a01172f |
@@ -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 }}
|
||||||
+8
-3
@@ -571,6 +571,8 @@ keybinding:
|
|||||||
openMergeTool: M
|
openMergeTool: M
|
||||||
openStatusFilter: <c-b>
|
openStatusFilter: <c-b>
|
||||||
copyFileInfoToClipboard: "y"
|
copyFileInfoToClipboard: "y"
|
||||||
|
collapseAll: '-'
|
||||||
|
expandAll: =
|
||||||
branches:
|
branches:
|
||||||
createPullRequest: o
|
createPullRequest: o
|
||||||
viewPullRequestOptions: O
|
viewPullRequestOptions: O
|
||||||
@@ -832,14 +834,17 @@ gui:
|
|||||||
|
|
||||||
## Custom Branch Color
|
## 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
|
```yaml
|
||||||
gui:
|
gui:
|
||||||
branchColors:
|
branchColorPatterns:
|
||||||
'docs': '#11aaff' # use a light blue for branches beginning with 'docs/'
|
'^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
|
## Example Coloring
|
||||||
|
|
||||||

|

|
||||||
|
|||||||
@@ -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. |
|
| `` 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. |
|
| `` <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. |
|
| `` ` `` | 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 | |
|
| `` / `` | Search the current view by text | |
|
||||||
|
|
||||||
## Commit summary
|
## 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) | |
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` M `` | Open external merge tool | Run `git mergetool`. |
|
| `` M `` | Open external merge tool | Run `git mergetool`. |
|
||||||
| `` f `` | Fetch | Fetch changes from remote. |
|
| `` 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 | |
|
| `` / `` | Search the current view by text | |
|
||||||
|
|
||||||
## Local branches
|
## Local branches
|
||||||
|
|||||||
@@ -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. |
|
| `` 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. |
|
| `` <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. |
|
| `` ` `` | ファイルツリーの表示を切り替え | 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 |
|
||||||
| `` / `` | 検索を開始 | |
|
| `` / `` | 検索を開始 | |
|
||||||
|
|
||||||
## コミットメッセージ
|
## コミットメッセージ
|
||||||
@@ -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) | |
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` M `` | Git mergetoolを開く | Run `git mergetool`. |
|
| `` M `` | Git mergetoolを開く | Run `git mergetool`. |
|
||||||
| `` f `` | Fetch | Fetch changes from remote. |
|
| `` 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. |
|
| `` 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. |
|
| `` <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. |
|
| `` ` `` | 파일 트리뷰로 전환 | 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 |
|
||||||
| `` / `` | 검색 시작 | |
|
| `` / `` | 검색 시작 | |
|
||||||
|
|
||||||
## 커밋메시지
|
## 커밋메시지
|
||||||
@@ -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) | |
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` M `` | Git mergetool를 열기 | Run `git mergetool`. |
|
| `` M `` | Git mergetool를 열기 | Run `git mergetool`. |
|
||||||
| `` f `` | Fetch | Fetch changes from remote. |
|
| `` 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) | |
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` M `` | Open external merge tool | Run `git mergetool`. |
|
| `` M `` | Open external merge tool | Run `git mergetool`. |
|
||||||
| `` f `` | Fetch | Fetch changes from remote. |
|
| `` 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 | |
|
| `` / `` | Start met zoeken | |
|
||||||
|
|
||||||
## Bevestigingspaneel
|
## 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. |
|
| `` 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. |
|
| `` <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. |
|
| `` ` `` | 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 | |
|
| `` / `` | Start met zoeken | |
|
||||||
|
|
||||||
## Commits
|
## Commits
|
||||||
|
|||||||
@@ -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) | |
|
| `` <c-t> `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | |
|
||||||
| `` M `` | Otwórz zewnętrzne narzędzie scalania | Uruchom `git mergetool`. |
|
| `` M `` | Otwórz zewnętrzne narzędzie scalania | Uruchom `git mergetool`. |
|
||||||
| `` f `` | Pobierz | Pobierz zmiany ze zdalnego serwera. |
|
| `` 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 | |
|
| `` / `` | Szukaj w bieżącym widoku po tekście | |
|
||||||
|
|
||||||
## Pliki commita
|
## 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. |
|
| `` 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. |
|
| `` <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. |
|
| `` ` `` | 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 | |
|
| `` / `` | Szukaj w bieżącym widoku po tekście | |
|
||||||
|
|
||||||
## Podsumowanie commita
|
## 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. |
|
| `` 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. |
|
| `` <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. |
|
| `` ` `` | Переключить вид дерева файлов | 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 |
|
||||||
| `` / `` | Найти | |
|
| `` / `` | Найти | |
|
||||||
|
|
||||||
## Статус
|
## Статус
|
||||||
@@ -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) | |
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` M `` | Открыть внешний инструмент слияния (git mergetool) | Run `git mergetool`. |
|
| `` M `` | Открыть внешний инструмент слияния (git mergetool) | Run `git mergetool`. |
|
||||||
| `` f `` | Получить изменения | Fetch changes from remote. |
|
| `` 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 |
|
||||||
| `` / `` | Найти | |
|
| `` / `` | Найти | |
|
||||||
|
|
||||||
## Хранилище
|
## Хранилище
|
||||||
|
|||||||
@@ -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。 |
|
| `` a `` | 操作所有文件 | 添加或删除所有提交中的文件到自定义的补丁中。请参阅 https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches。 |
|
||||||
| `` <enter> `` | 输入文件以将所选行添加到补丁中(或切换目录折叠) | 如果已选择一个文件,则Enter进入该文件,以便您可以向自定义补丁添加/删除单独的行。如果选择了目录,则切换目录。 |
|
| `` <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) | |
|
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
|
||||||
| `` M `` | 打开外部合并工具(git mergetool) | 执行 `git mergetool`. |
|
| `` M `` | 打开外部合并工具(git mergetool) | 执行 `git mergetool`. |
|
||||||
| `` f `` | 抓取 | 从远程获取变更 |
|
| `` 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. |
|
| `` 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. |
|
| `` <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. |
|
| `` ` `` | 顯示檔案樹狀視圖 | 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)
|
## 收藏 (Stash)
|
||||||
@@ -320,6 +322,8 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
|
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
|
||||||
| `` M `` | 開啟外部合併工具 | 執行 `git mergetool`。 |
|
| `` M `` | 開啟外部合併工具 | 執行 `git mergetool`。 |
|
||||||
| `` f `` | 擷取 | 同步遠端異動 |
|
| `` 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/aybabtme/humanlog v0.4.1
|
||||||
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
|
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
|
||||||
github.com/creack/pty v1.1.11
|
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/go-errors/errors v1.5.1
|
||||||
github.com/gookit/color v1.4.2
|
github.com/gookit/color v1.4.2
|
||||||
github.com/iancoleman/orderedmap v0.3.0
|
github.com/iancoleman/orderedmap v0.3.0
|
||||||
@@ -16,7 +16,7 @@ require (
|
|||||||
github.com/integrii/flaggy v1.4.0
|
github.com/integrii/flaggy v1.4.0
|
||||||
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
|
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
|
||||||
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d
|
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d
|
||||||
github.com/jesseduffield/gocui v0.3.1-0.20250107151125-716b1eb82fb4
|
github.com/jesseduffield/gocui v0.3.1-0.20250111205211-82d518436b5a
|
||||||
github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a
|
github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a
|
||||||
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
|
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
|
||||||
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
|
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
|
||||||
@@ -54,7 +54,6 @@ require (
|
|||||||
github.com/go-git/go-billy/v5 v5.0.0 // indirect
|
github.com/go-git/go-billy/v5 v5.0.0 // indirect
|
||||||
github.com/go-logfmt/logfmt v0.5.0 // indirect
|
github.com/go-logfmt/logfmt v0.5.0 // indirect
|
||||||
github.com/gobwas/glob v0.2.3 // 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/invopop/jsonschema v0.10.0 // indirect
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect
|
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // 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/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/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/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 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw=
|
||||||
github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo=
|
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.8.0 h1:IDclow1j6kKpU/gOhjmc+7Pj5Dxnukb74pfKN4Cxrfg=
|
||||||
github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg=
|
github.com/gdamore/tcell/v2 v2.8.0/go.mod h1:bj8ori1BG3OYMjmb3IklZVWfZUJ1UBQt9JXrOCOhGWw=
|
||||||
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
|
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
|
||||||
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||||
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
|
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.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.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.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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
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 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.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=
|
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
@@ -188,8 +187,8 @@ 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/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 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/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o=
|
||||||
github.com/jesseduffield/gocui v0.3.1-0.20250107151125-716b1eb82fb4 h1:hSAimLVb4b5ktU3uJRtBsZW0P2dtXECReTcsHYfOy58=
|
github.com/jesseduffield/gocui v0.3.1-0.20250111205211-82d518436b5a h1:GLFWB8rESraTt2eIe2yssy4d4VEkCnmKbPeeZ5vCT2s=
|
||||||
github.com/jesseduffield/gocui v0.3.1-0.20250107151125-716b1eb82fb4/go.mod h1:XtEbqCbn45keRXEu+OMZkjN5gw6AEob59afsgHjokZ8=
|
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 h1:UDeJ3EBk04bXDLOPvuqM3on8HvyJfISw0+UMqW+0a4g=
|
||||||
github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a/go.mod h1:FSWDLKT0NQpntbDd1H3lbz51fhCVlMzy/J0S6nM727Q=
|
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 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY=
|
||||||
@@ -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.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 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
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 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/mgutz/str v1.2.0 h1:4IzWSdIz9qPQWLfKZ0rJcV0jcUDpxvP4JVZ4GXQyvSw=
|
github.com/mgutz/str v1.2.0 h1:4IzWSdIz9qPQWLfKZ0rJcV0jcUDpxvP4JVZ4GXQyvSw=
|
||||||
@@ -328,6 +326,9 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
|||||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
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 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
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-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
@@ -367,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.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.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.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-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-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -402,6 +406,10 @@ 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-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.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.6.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 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
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-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
@@ -425,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-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.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.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 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
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=
|
golang.org/x/sys v0.0.0-20170407050850-f3918c30c5c2/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -475,13 +486,20 @@ 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-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.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.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.17.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 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
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-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.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.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.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
|
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 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
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.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -493,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.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.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.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.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 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
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=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
@@ -548,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.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.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.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-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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
|||||||
@@ -52,7 +52,10 @@ type GuiConfig struct {
|
|||||||
// See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-author-color
|
// See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-author-color
|
||||||
AuthorColors map[string]string `yaml:"authorColors"`
|
AuthorColors map[string]string `yaml:"authorColors"`
|
||||||
// See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-branch-color
|
// See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-branch-color
|
||||||
|
// Deprecated: use branchColorPatterns instead
|
||||||
BranchColors map[string]string `yaml:"branchColors"`
|
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
|
// The number of lines you scroll by when scrolling the main window
|
||||||
ScrollHeight int `yaml:"scrollHeight" jsonschema:"minimum=1"`
|
ScrollHeight int `yaml:"scrollHeight" jsonschema:"minimum=1"`
|
||||||
// If true, allow scrolling past the bottom of the content in the main window
|
// If true, allow scrolling past the bottom of the content in the main window
|
||||||
@@ -453,6 +456,8 @@ type KeybindingFilesConfig struct {
|
|||||||
OpenMergeTool string `yaml:"openMergeTool"`
|
OpenMergeTool string `yaml:"openMergeTool"`
|
||||||
OpenStatusFilter string `yaml:"openStatusFilter"`
|
OpenStatusFilter string `yaml:"openStatusFilter"`
|
||||||
CopyFileInfoToClipboard string `yaml:"copyFileInfoToClipboard"`
|
CopyFileInfoToClipboard string `yaml:"copyFileInfoToClipboard"`
|
||||||
|
CollapseAll string `yaml:"collapseAll"`
|
||||||
|
ExpandAll string `yaml:"expandAll"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type KeybindingBranchesConfig struct {
|
type KeybindingBranchesConfig struct {
|
||||||
@@ -895,6 +900,8 @@ func GetDefaultConfig() *UserConfig {
|
|||||||
OpenStatusFilter: "<c-b>",
|
OpenStatusFilter: "<c-b>",
|
||||||
ConfirmDiscard: "x",
|
ConfirmDiscard: "x",
|
||||||
CopyFileInfoToClipboard: "y",
|
CopyFileInfoToClipboard: "y",
|
||||||
|
CollapseAll: "-",
|
||||||
|
ExpandAll: "=",
|
||||||
},
|
},
|
||||||
Branches: KeybindingBranchesConfig{
|
Branches: KeybindingBranchesConfig{
|
||||||
CopyPullRequestURL: "<c-y>",
|
CopyPullRequestURL: "<c-y>",
|
||||||
|
|||||||
@@ -109,6 +109,20 @@ func (self *CommitFilesController) GetKeybindings(opts types.KeybindingsOpts) []
|
|||||||
Description: self.c.Tr.ToggleTreeView,
|
Description: self.c.Tr.ToggleTreeView,
|
||||||
Tooltip: self.c.Tr.ToggleTreeViewTooltip,
|
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
|
return bindings
|
||||||
@@ -401,6 +415,22 @@ func (self *CommitFilesController) toggleTreeView() error {
|
|||||||
return nil
|
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
|
// NOTE: these functions are identical to those in files_controller.go (except for types) and
|
||||||
// could also be cleaned up with some generics
|
// could also be cleaned up with some generics
|
||||||
func normalisedSelectedCommitFileNodes(selectedNodes []*filetree.CommitFileNode) []*filetree.CommitFileNode {
|
func normalisedSelectedCommitFileNodes(selectedNodes []*filetree.CommitFileNode) []*filetree.CommitFileNode {
|
||||||
@@ -420,3 +450,11 @@ func isDescendentOfSelectedCommitFileNodes(node *filetree.CommitFileNode, select
|
|||||||
}
|
}
|
||||||
return false
|
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,
|
Description: self.c.Tr.Fetch,
|
||||||
Tooltip: self.c.Tr.FetchTooltip,
|
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})
|
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 {
|
func (self *FilesController) EnterFile(opts types.OnFocusOpts) error {
|
||||||
node := self.context().GetSelected()
|
node := self.context().GetSelected()
|
||||||
if node == nil {
|
if node == nil {
|
||||||
@@ -1181,3 +1211,11 @@ func (self *FilesController) formattedPaths(nodes []*filetree.FileNode) string {
|
|||||||
return node.GetPath()
|
return node.GetPath()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *FilesController) isInTreeMode() *types.DisabledReason {
|
||||||
|
if !self.context().FileTreeViewModel.InTreeMode() {
|
||||||
|
return &types.DisabledReason{Text: self.c.Tr.DisabledInFlatView}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -88,7 +88,20 @@ func (self *UndoController) reflogUndo() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch action.kind {
|
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{
|
self.c.Confirm(types.ConfirmOpts{
|
||||||
Title: self.c.Tr.Actions.Undo,
|
Title: self.c.Tr.Actions.Undo,
|
||||||
Prompt: fmt.Sprintf(self.c.Tr.HardResetAutostashPrompt, action.from),
|
Prompt: fmt.Sprintf(self.c.Tr.HardResetAutostashPrompt, action.from),
|
||||||
@@ -105,7 +118,7 @@ func (self *UndoController) reflogUndo() error {
|
|||||||
case CHECKOUT:
|
case CHECKOUT:
|
||||||
self.c.Confirm(types.ConfirmOpts{
|
self.c.Confirm(types.ConfirmOpts{
|
||||||
Title: self.c.Tr.Actions.Undo,
|
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 {
|
HandleConfirm: func() error {
|
||||||
self.c.LogAction(self.c.Tr.Actions.Undo)
|
self.c.LogAction(self.c.Tr.Actions.Undo)
|
||||||
return self.c.Helpers().Refs.CheckoutRef(action.from, types.CheckoutRefOptions{
|
return self.c.Helpers().Refs.CheckoutRef(action.from, types.CheckoutRefOptions{
|
||||||
@@ -159,7 +172,7 @@ func (self *UndoController) reflogRedo() error {
|
|||||||
case CHECKOUT:
|
case CHECKOUT:
|
||||||
self.c.Confirm(types.ConfirmOpts{
|
self.c.Confirm(types.ConfirmOpts{
|
||||||
Title: self.c.Tr.Actions.Redo,
|
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 {
|
HandleConfirm: func() error {
|
||||||
self.c.LogAction(self.c.Tr.Actions.Redo)
|
self.c.LogAction(self.c.Tr.Actions.Redo)
|
||||||
return self.c.Helpers().Refs.CheckoutRef(action.to, types.CheckoutRefOptions{
|
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)
|
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()
|
dirtyWorkingTree := self.c.Helpers().WorkingTree.IsWorkingTreeDirty()
|
||||||
if dirtyWorkingTree {
|
if dirtyWorkingTree {
|
||||||
// offer to autostash changes
|
return self.c.WithWaitingStatus(options.WaitingStatus, func(gocui.Task) error {
|
||||||
self.c.Confirm(types.ConfirmOpts{
|
if err := self.c.Git().Stash.Push(self.c.Tr.StashPrefix + commitHash); err != nil {
|
||||||
Title: self.c.Tr.AutoStashTitle,
|
return err
|
||||||
Prompt: self.c.Tr.AutoStashPrompt,
|
}
|
||||||
HandleConfirm: func() error {
|
if err := reset(); err != nil {
|
||||||
return self.c.WithWaitingStatus(options.WaitingStatus, func(gocui.Task) error {
|
return err
|
||||||
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)
|
err := self.c.Git().Stash.Pop(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return self.c.Refresh(types.RefreshOptions{})
|
return self.c.Refresh(types.RefreshOptions{})
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.c.WithWaitingStatus(options.WaitingStatus, func(gocui.Task) error {
|
return self.c.WithWaitingStatus(options.WaitingStatus, func(gocui.Task) error {
|
||||||
|
|||||||
@@ -36,3 +36,8 @@ func (self *CollapsedPaths) ToggleCollapsed(path string) {
|
|||||||
self.collapsedPaths.Add(path)
|
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
|
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{}
|
var _ ICommitFileTree = &CommitFileTree{}
|
||||||
|
|
||||||
func NewCommitFileTree(getFiles func() []*models.CommitFile, log *logrus.Entry, showTree bool) *CommitFileTree {
|
func NewCommitFileTree(getFiles func() []*models.CommitFile, log *logrus.Entry, showTree bool) *CommitFileTree {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package filetree
|
package filetree
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
@@ -160,3 +161,33 @@ func (self *CommitFileTreeViewModel) ToggleShowTree() {
|
|||||||
self.SetSelection(index)
|
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
|
IsCollapsed(path string) bool
|
||||||
ToggleCollapsed(path string)
|
ToggleCollapsed(path string)
|
||||||
CollapsedPaths() *CollapsedPaths
|
CollapsedPaths() *CollapsedPaths
|
||||||
|
CollapseAll()
|
||||||
|
ExpandAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
type IFileTree interface {
|
type IFileTree interface {
|
||||||
@@ -171,6 +173,20 @@ func (self *FileTree) ToggleCollapsed(path string) {
|
|||||||
self.collapsedPaths.ToggleCollapsed(path)
|
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 {
|
func (self *FileTree) Tree() *FileNode {
|
||||||
return NewFileNode(self.tree)
|
return NewFileNode(self.tree)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package filetree
|
package filetree
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
@@ -190,3 +191,33 @@ func (self *FileTreeViewModel) ToggleShowTree() {
|
|||||||
self.SetSelectedLineIdx(index)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+7
-1
@@ -455,7 +455,13 @@ func (gui *Gui) onUserConfigLoaded() error {
|
|||||||
} else if userConfig.Gui.ShowIcons {
|
} else if userConfig.Gui.ShowIcons {
|
||||||
icons.SetNerdFontsVersion("2")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package presentation
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -18,7 +19,12 @@ import (
|
|||||||
"github.com/samber/lo"
|
"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(
|
func GetBranchListDisplayStrings(
|
||||||
branches []*models.Branch,
|
branches []*models.Branch,
|
||||||
@@ -125,22 +131,29 @@ func getBranchDisplayStrings(
|
|||||||
|
|
||||||
// GetBranchTextStyle branch color
|
// GetBranchTextStyle branch color
|
||||||
func GetBranchTextStyle(name string) style.TextStyle {
|
func GetBranchTextStyle(name string) style.TextStyle {
|
||||||
branchType := strings.Split(name, "/")[0]
|
if style, ok := colorPatterns.match(name); ok {
|
||||||
|
return *style
|
||||||
if value, ok := branchPrefixColorCache[branchType]; ok {
|
|
||||||
return value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch branchType {
|
return theme.DefaultTextColor
|
||||||
case "feature":
|
}
|
||||||
return style.FgGreen
|
|
||||||
case "bugfix":
|
func (m *colorMatcher) match(name string) (*style.TextStyle, bool) {
|
||||||
return style.FgYellow
|
if m.isRegex {
|
||||||
case "hotfix":
|
for pattern, style := range m.patterns {
|
||||||
return style.FgRed
|
if matched, _ := regexp.MatchString(pattern, name); matched {
|
||||||
default:
|
return &style, true
|
||||||
return theme.DefaultTextColor
|
}
|
||||||
|
}
|
||||||
|
} 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(
|
func BranchStatus(
|
||||||
@@ -189,6 +202,9 @@ func BranchStatus(
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetCustomBranches(customBranchColors map[string]string) {
|
func SetCustomBranches(customBranchColors map[string]string, isRegex bool) {
|
||||||
branchPrefixColorCache = utils.SetCustomColors(customBranchColors)
|
colorPatterns = &colorMatcher{
|
||||||
|
patterns: utils.SetCustomColors(customBranchColors),
|
||||||
|
isRegex: isRegex,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -321,6 +321,7 @@ func Test_getBranchDisplayStrings(t *testing.T) {
|
|||||||
defer color.ForceSetColorLevel(oldColorLevel)
|
defer color.ForceSetColorLevel(oldColorLevel)
|
||||||
|
|
||||||
c := utils.NewDummyCommon()
|
c := utils.NewDummyCommon()
|
||||||
|
SetCustomBranches(c.UserConfig().Gui.BranchColorPatterns, true)
|
||||||
|
|
||||||
for i, s := range scenarios {
|
for i, s := range scenarios {
|
||||||
icons.SetNerdFontsVersion(lo.Ternary(s.useIcons, "3", ""))
|
icons.SetNerdFontsVersion(lo.Ternary(s.useIcons, "3", ""))
|
||||||
|
|||||||
+16
-2
@@ -256,6 +256,11 @@ type TranslationSet struct {
|
|||||||
NoBranchOnRemote string
|
NoBranchOnRemote string
|
||||||
Fetch string
|
Fetch string
|
||||||
FetchTooltip string
|
FetchTooltip string
|
||||||
|
CollapseAll string
|
||||||
|
CollapseAllTooltip string
|
||||||
|
ExpandAll string
|
||||||
|
ExpandAllTooltip string
|
||||||
|
DisabledInFlatView string
|
||||||
FileEnter string
|
FileEnter string
|
||||||
FileEnterTooltip string
|
FileEnterTooltip string
|
||||||
FileStagingRequirements string
|
FileStagingRequirements string
|
||||||
@@ -727,8 +732,9 @@ type TranslationSet struct {
|
|||||||
ConfirmRevertCommit string
|
ConfirmRevertCommit string
|
||||||
RewordInEditorTitle string
|
RewordInEditorTitle string
|
||||||
RewordInEditorPrompt string
|
RewordInEditorPrompt string
|
||||||
CheckoutPrompt string
|
CheckoutAutostashPrompt string
|
||||||
HardResetAutostashPrompt string
|
HardResetAutostashPrompt string
|
||||||
|
SoftResetPrompt string
|
||||||
UpstreamGone string
|
UpstreamGone string
|
||||||
NukeDescription string
|
NukeDescription string
|
||||||
DiscardStagedChangesDescription string
|
DiscardStagedChangesDescription string
|
||||||
@@ -1258,6 +1264,11 @@ func EnglishTranslationSet() *TranslationSet {
|
|||||||
NoBranchOnRemote: `This branch doesn't exist on remote. You need to push it to remote first.`,
|
NoBranchOnRemote: `This branch doesn't exist on remote. You need to push it to remote first.`,
|
||||||
Fetch: `Fetch`,
|
Fetch: `Fetch`,
|
||||||
FetchTooltip: "Fetch changes from remote.",
|
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`,
|
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.",
|
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`,
|
FileStagingRequirements: `Can only stage individual lines for tracked files`,
|
||||||
@@ -1735,7 +1746,8 @@ func EnglishTranslationSet() *TranslationSet {
|
|||||||
RewordInEditorTitle: "Reword in editor",
|
RewordInEditorTitle: "Reword in editor",
|
||||||
RewordInEditorPrompt: "Are you sure you want to reword this commit in your 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.",
|
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)",
|
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).",
|
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",
|
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",
|
||||||
@@ -2006,6 +2018,8 @@ keybinding:
|
|||||||
gui:
|
gui:
|
||||||
filterMode: 'fuzzy'
|
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.`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -164,6 +164,7 @@ var tests = []*components.IntegrationTest{
|
|||||||
diff.DiffNonStickyRange,
|
diff.DiffNonStickyRange,
|
||||||
diff.IgnoreWhitespace,
|
diff.IgnoreWhitespace,
|
||||||
diff.RenameSimilarityThresholdChange,
|
diff.RenameSimilarityThresholdChange,
|
||||||
|
file.CollapseExpand,
|
||||||
file.CopyMenu,
|
file.CopyMenu,
|
||||||
file.DirWithUntrackedFile,
|
file.DirWithUntrackedFile,
|
||||||
file.DiscardAllDirChanges,
|
file.DiscardAllDirChanges,
|
||||||
@@ -366,6 +367,7 @@ var tests = []*components.IntegrationTest{
|
|||||||
ui.SwitchTabFromMenu,
|
ui.SwitchTabFromMenu,
|
||||||
ui.SwitchTabWithPanelJumpKeys,
|
ui.SwitchTabWithPanelJumpKeys,
|
||||||
undo.UndoCheckoutAndDrop,
|
undo.UndoCheckoutAndDrop,
|
||||||
|
undo.UndoCommit,
|
||||||
undo.UndoDrop,
|
undo.UndoDrop,
|
||||||
worktree.AddFromBranch,
|
worktree.AddFromBranch,
|
||||||
worktree.AddFromBranchDetached,
|
worktree.AddFromBranchDetached,
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
package undo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var UndoCommit = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Undo/redo a commit",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
shell.CreateFileAndAdd("other-file", "other-file-1")
|
||||||
|
shell.Commit("one")
|
||||||
|
shell.CreateFileAndAdd("file", "file-1")
|
||||||
|
shell.Commit("two")
|
||||||
|
shell.UpdateFile("other-file", "other-file-2")
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
confirmUndo := func() {
|
||||||
|
t.ExpectPopup().Confirmation().
|
||||||
|
Title(Equals("Undo")).
|
||||||
|
Content(MatchesRegexp(`Are you sure you want to soft reset to '.*'\?`)).
|
||||||
|
Confirm()
|
||||||
|
}
|
||||||
|
|
||||||
|
confirmRedo := func() {
|
||||||
|
t.ExpectPopup().Confirmation().
|
||||||
|
Title(Equals("Redo")).
|
||||||
|
Content(MatchesRegexp(`Are you sure you want to hard reset to '.*'\? An auto-stash will be performed if necessary\.`)).
|
||||||
|
Confirm()
|
||||||
|
}
|
||||||
|
|
||||||
|
confirmDiscardFile := func() {
|
||||||
|
t.ExpectPopup().Menu().
|
||||||
|
Title(Equals("Discard changes")).
|
||||||
|
Select(Contains("Discard all changes")).
|
||||||
|
Confirm()
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Views().Files().
|
||||||
|
Lines(
|
||||||
|
Contains(" M other-file"),
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Views().Commits().Focus().
|
||||||
|
Lines(
|
||||||
|
Contains("two").IsSelected(),
|
||||||
|
Contains("one"),
|
||||||
|
).
|
||||||
|
Press(keys.Universal.Undo).
|
||||||
|
Tap(confirmUndo).
|
||||||
|
Lines(
|
||||||
|
Contains("one").IsSelected(),
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Views().Files().
|
||||||
|
Lines(
|
||||||
|
Contains("A file"),
|
||||||
|
Contains(" M other-file"),
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Views().Commits().Focus().
|
||||||
|
Press(keys.Universal.Redo).
|
||||||
|
Tap(confirmRedo).
|
||||||
|
Lines(
|
||||||
|
Contains("two").IsSelected(),
|
||||||
|
Contains("one"),
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Views().Files().
|
||||||
|
Lines(
|
||||||
|
Contains(" M other-file"),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Undo again, this time discarding the original change before redoing again
|
||||||
|
t.Views().Commits().Focus().
|
||||||
|
Press(keys.Universal.Undo).
|
||||||
|
Tap(confirmUndo).
|
||||||
|
Lines(
|
||||||
|
Contains("one").IsSelected(),
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Views().Files().Focus().
|
||||||
|
Lines(
|
||||||
|
Contains("A file"),
|
||||||
|
Contains(" M other-file").IsSelected(),
|
||||||
|
).
|
||||||
|
Press(keys.Universal.PrevItem).
|
||||||
|
Press(keys.Universal.Remove).
|
||||||
|
Tap(confirmDiscardFile).
|
||||||
|
Lines(
|
||||||
|
Contains(" M other-file"),
|
||||||
|
).
|
||||||
|
Press(keys.Universal.Redo).
|
||||||
|
Tap(confirmRedo)
|
||||||
|
|
||||||
|
t.Views().Commits().
|
||||||
|
Lines(
|
||||||
|
Contains("two"),
|
||||||
|
Contains("one"),
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Views().Files().
|
||||||
|
Lines(
|
||||||
|
Contains(" M other-file"),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -12,6 +12,13 @@
|
|||||||
"description": "See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-author-color"
|
"description": "See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-author-color"
|
||||||
},
|
},
|
||||||
"branchColors": {
|
"branchColors": {
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "object",
|
||||||
|
"description": "See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-branch-color\nDeprecated: use branchColorPatterns instead"
|
||||||
|
},
|
||||||
|
"branchColorPatterns": {
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@@ -1456,6 +1463,14 @@
|
|||||||
"copyFileInfoToClipboard": {
|
"copyFileInfoToClipboard": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "y"
|
"default": "y"
|
||||||
|
},
|
||||||
|
"collapseAll": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "-"
|
||||||
|
},
|
||||||
|
"expandAll": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "="
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
|
|||||||
+2
-2
@@ -20,7 +20,7 @@ In `tcell.js`, you also need to change the constant
|
|||||||
```js
|
```js
|
||||||
const wasmFilePath = "yourfile.wasm"
|
const wasmFilePath = "yourfile.wasm"
|
||||||
```
|
```
|
||||||
to the file you outputed to when building.
|
to the file you outputted to when building.
|
||||||
|
|
||||||
## Displaying your project
|
## Displaying your project
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ func main() {
|
|||||||
To see the webpage with this example, you can type in `localhost:8080/tcell.html` into your browser while `server.go` is running.
|
To see the webpage with this example, you can type in `localhost:8080/tcell.html` into your browser while `server.go` is running.
|
||||||
|
|
||||||
### Embedding
|
### Embedding
|
||||||
It is recomended to use an iframe if you want to embed the app into a webpage:
|
It is recommended to use an iframe if you want to embed the app into a webpage:
|
||||||
```html
|
```html
|
||||||
<iframe src="tcell.html" title="Tcell app"></iframe>
|
<iframe src="tcell.html" title="Tcell app"></iframe>
|
||||||
```
|
```
|
||||||
|
|||||||
+5
-3
@@ -33,7 +33,7 @@ A brief, and still somewhat rough, [tutorial](TUTORIAL.md) is available.
|
|||||||
- [godu](https://github.com/viktomas/godu) - utility to discover large files/folders
|
- [godu](https://github.com/viktomas/godu) - utility to discover large files/folders
|
||||||
- [tview](https://github.com/rivo/tview/) - rich interactive widgets
|
- [tview](https://github.com/rivo/tview/) - rich interactive widgets
|
||||||
- [cview](https://code.rocketnine.space/tslocum/cview) - user interface toolkit (fork of _tview_)
|
- [cview](https://code.rocketnine.space/tslocum/cview) - user interface toolkit (fork of _tview_)
|
||||||
- [awsome gocui](https://github.com/awesome-gocui/gocui) - Go Console User Interface
|
- [awesome gocui](https://github.com/awesome-gocui/gocui) - Go Console User Interface
|
||||||
- [gomandelbrot](https://github.com/rgm3/gomandelbrot) - Mandelbrot!
|
- [gomandelbrot](https://github.com/rgm3/gomandelbrot) - Mandelbrot!
|
||||||
- [WTF](https://github.com/senorprogrammer/wtf) - personal information dashboard
|
- [WTF](https://github.com/senorprogrammer/wtf) - personal information dashboard
|
||||||
- [browsh](https://github.com/browsh-org/browsh) - modern web browser ([video](https://www.youtube.com/watch?v=HZq86XfBoRo))
|
- [browsh](https://github.com/browsh-org/browsh) - modern web browser ([video](https://www.youtube.com/watch?v=HZq86XfBoRo))
|
||||||
@@ -67,6 +67,8 @@ A brief, and still somewhat rough, [tutorial](TUTORIAL.md) is available.
|
|||||||
- [gbb](https://github.com/sdemingo/gbb) - A classical bulletin board app for tildes or public unix servers
|
- [gbb](https://github.com/sdemingo/gbb) - A classical bulletin board app for tildes or public unix servers
|
||||||
- [lil](https://github.com/andrievsky/lil) - A simple and flexible interface for any service by implementing only list and get operations
|
- [lil](https://github.com/andrievsky/lil) - A simple and flexible interface for any service by implementing only list and get operations
|
||||||
- [hero.go](https://github.com/barisbll/hero.go) - 2d monster shooter ([video](https://user-images.githubusercontent.com/40062673/277157369-240d7606-b471-4aa1-8c54-4379a513122b.mp4))
|
- [hero.go](https://github.com/barisbll/hero.go) - 2d monster shooter ([video](https://user-images.githubusercontent.com/40062673/277157369-240d7606-b471-4aa1-8c54-4379a513122b.mp4))
|
||||||
|
- [go-tetris](https://github.com/aaronriekenberg/go-tetris) - simple tetris game for native terminal and WASM using github actions+pages
|
||||||
|
- [oddshub](https://github.com/dos-2/oddshub) - A TUI designed for analyzing sports betting odds
|
||||||
|
|
||||||
## Pure Go Terminfo Database
|
## Pure Go Terminfo Database
|
||||||
|
|
||||||
@@ -143,7 +145,7 @@ Most _termbox-go_ programs will probably work without further modification.
|
|||||||
Internally _Tcell_ uses UTF-8, just like Go.
|
Internally _Tcell_ uses UTF-8, just like Go.
|
||||||
However, _Tcell_ understands how to
|
However, _Tcell_ understands how to
|
||||||
convert to and from other character sets, using the capabilities of
|
convert to and from other character sets, using the capabilities of
|
||||||
the `golang.org/x/text/encoding packages`.
|
the `golang.org/x/text/encoding` packages.
|
||||||
Your application must supply
|
Your application must supply
|
||||||
them, as the full set of the most common ones bloats the program by about 2 MB.
|
them, as the full set of the most common ones bloats the program by about 2 MB.
|
||||||
If you're lazy, and want them all anyway, see the `encoding` sub-directory.
|
If you're lazy, and want them all anyway, see the `encoding` sub-directory.
|
||||||
@@ -285,4 +287,4 @@ please let me know. PRs are especially welcome.
|
|||||||
_Tcell_ is absolutely free, but if you want to obtain commercial, professional support, there are options.
|
_Tcell_ is absolutely free, but if you want to obtain commercial, professional support, there are options.
|
||||||
|
|
||||||
- [TideLift](https://tidelift.com/) subscriptions include support for _Tcell_, as well as many other open source packages.
|
- [TideLift](https://tidelift.com/) subscriptions include support for _Tcell_, as well as many other open source packages.
|
||||||
- [Staysail Systems Inc.](mailto:info@staysail.tech) offers direct support, and custom development around _Tcell_ on an hourly basis.
|
- [Staysail Systems Inc.](mailto:info@staysail.tech) offers direct support, and custom development around _Tcell_ on an hourly basis.
|
||||||
|
|||||||
+6
-5
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020 The TCell Authors
|
// Copyright 2024 The TCell Authors
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use file except in compliance with the License.
|
// you may not use file except in compliance with the License.
|
||||||
@@ -19,15 +19,16 @@ package tcell
|
|||||||
type AttrMask int
|
type AttrMask int
|
||||||
|
|
||||||
// Attributes are not colors, but affect the display of text. They can
|
// Attributes are not colors, but affect the display of text. They can
|
||||||
// be combined.
|
// be combined, in some cases, but not others. (E.g. you can have Dim Italic,
|
||||||
|
// but only CurlyUnderline cannot be mixed with DottedUnderline.)
|
||||||
const (
|
const (
|
||||||
AttrBold AttrMask = 1 << iota
|
AttrBold AttrMask = 1 << iota
|
||||||
AttrBlink
|
AttrBlink
|
||||||
AttrReverse
|
AttrReverse
|
||||||
AttrUnderline
|
AttrUnderline // Deprecated: Use UnderlineStyle
|
||||||
AttrDim
|
AttrDim
|
||||||
AttrItalic
|
AttrItalic
|
||||||
AttrStrikeThrough
|
AttrStrikeThrough
|
||||||
AttrInvalid // Mark the style or attributes invalid
|
AttrInvalid AttrMask = 1 << 31 // Mark the style or attributes invalid
|
||||||
AttrNone AttrMask = 0 // Just normal text.
|
AttrNone AttrMask = 0 // Just normal text.
|
||||||
)
|
)
|
||||||
|
|||||||
+1
-8
@@ -58,7 +58,7 @@ func (cb *CellBuffer) SetContent(x int, y int,
|
|||||||
// dirty as well as the base cell, to make sure we consider
|
// dirty as well as the base cell, to make sure we consider
|
||||||
// both cells as dirty together. We only need to do this
|
// both cells as dirty together. We only need to do this
|
||||||
// if we're changing content
|
// if we're changing content
|
||||||
if (c.width > 0) && (mainc != c.currMain || !reflect.DeepEqual(combc, c.currComb)) {
|
if (c.width > 0) && (mainc != c.currMain || len(combc) != len(c.currComb) || (len(combc) > 0 && !reflect.DeepEqual(combc, c.currComb))) {
|
||||||
for i := 0; i < c.width; i++ {
|
for i := 0; i < c.width; i++ {
|
||||||
cb.SetDirty(x+i, y, true)
|
cb.SetDirty(x+i, y, true)
|
||||||
}
|
}
|
||||||
@@ -246,11 +246,4 @@ func init() {
|
|||||||
if os.Getenv("RUNEWIDTH_EASTASIAN") == "" {
|
if os.Getenv("RUNEWIDTH_EASTASIAN") == "" {
|
||||||
runewidth.DefaultCondition.EastAsianWidth = false
|
runewidth.DefaultCondition.EastAsianWidth = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// For performance reasons, we create a lookup table. However, some users
|
|
||||||
// might be more memory conscious. If that's you, set the TCELL_MINIMIZE
|
|
||||||
// environment variable.
|
|
||||||
if os.Getenv("TCELL_MINIMIZE") == "" {
|
|
||||||
runewidth.CreateLUT()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+123
-123
@@ -314,129 +314,129 @@ const (
|
|||||||
Color253
|
Color253
|
||||||
Color254
|
Color254
|
||||||
Color255
|
Color255
|
||||||
ColorAliceBlue
|
ColorAliceBlue = ColorIsRGB | ColorValid | 0xF0F8FF
|
||||||
ColorAntiqueWhite
|
ColorAntiqueWhite = ColorIsRGB | ColorValid | 0xFAEBD7
|
||||||
ColorAquaMarine
|
ColorAquaMarine = ColorIsRGB | ColorValid | 0x7FFFD4
|
||||||
ColorAzure
|
ColorAzure = ColorIsRGB | ColorValid | 0xF0FFFF
|
||||||
ColorBeige
|
ColorBeige = ColorIsRGB | ColorValid | 0xF5F5DC
|
||||||
ColorBisque
|
ColorBisque = ColorIsRGB | ColorValid | 0xFFE4C4
|
||||||
ColorBlanchedAlmond
|
ColorBlanchedAlmond = ColorIsRGB | ColorValid | 0xFFEBCD
|
||||||
ColorBlueViolet
|
ColorBlueViolet = ColorIsRGB | ColorValid | 0x8A2BE2
|
||||||
ColorBrown
|
ColorBrown = ColorIsRGB | ColorValid | 0xA52A2A
|
||||||
ColorBurlyWood
|
ColorBurlyWood = ColorIsRGB | ColorValid | 0xDEB887
|
||||||
ColorCadetBlue
|
ColorCadetBlue = ColorIsRGB | ColorValid | 0x5F9EA0
|
||||||
ColorChartreuse
|
ColorChartreuse = ColorIsRGB | ColorValid | 0x7FFF00
|
||||||
ColorChocolate
|
ColorChocolate = ColorIsRGB | ColorValid | 0xD2691E
|
||||||
ColorCoral
|
ColorCoral = ColorIsRGB | ColorValid | 0xFF7F50
|
||||||
ColorCornflowerBlue
|
ColorCornflowerBlue = ColorIsRGB | ColorValid | 0x6495ED
|
||||||
ColorCornsilk
|
ColorCornsilk = ColorIsRGB | ColorValid | 0xFFF8DC
|
||||||
ColorCrimson
|
ColorCrimson = ColorIsRGB | ColorValid | 0xDC143C
|
||||||
ColorDarkBlue
|
ColorDarkBlue = ColorIsRGB | ColorValid | 0x00008B
|
||||||
ColorDarkCyan
|
ColorDarkCyan = ColorIsRGB | ColorValid | 0x008B8B
|
||||||
ColorDarkGoldenrod
|
ColorDarkGoldenrod = ColorIsRGB | ColorValid | 0xB8860B
|
||||||
ColorDarkGray
|
ColorDarkGray = ColorIsRGB | ColorValid | 0xA9A9A9
|
||||||
ColorDarkGreen
|
ColorDarkGreen = ColorIsRGB | ColorValid | 0x006400
|
||||||
ColorDarkKhaki
|
ColorDarkKhaki = ColorIsRGB | ColorValid | 0xBDB76B
|
||||||
ColorDarkMagenta
|
ColorDarkMagenta = ColorIsRGB | ColorValid | 0x8B008B
|
||||||
ColorDarkOliveGreen
|
ColorDarkOliveGreen = ColorIsRGB | ColorValid | 0x556B2F
|
||||||
ColorDarkOrange
|
ColorDarkOrange = ColorIsRGB | ColorValid | 0xFF8C00
|
||||||
ColorDarkOrchid
|
ColorDarkOrchid = ColorIsRGB | ColorValid | 0x9932CC
|
||||||
ColorDarkRed
|
ColorDarkRed = ColorIsRGB | ColorValid | 0x8B0000
|
||||||
ColorDarkSalmon
|
ColorDarkSalmon = ColorIsRGB | ColorValid | 0xE9967A
|
||||||
ColorDarkSeaGreen
|
ColorDarkSeaGreen = ColorIsRGB | ColorValid | 0x8FBC8F
|
||||||
ColorDarkSlateBlue
|
ColorDarkSlateBlue = ColorIsRGB | ColorValid | 0x483D8B
|
||||||
ColorDarkSlateGray
|
ColorDarkSlateGray = ColorIsRGB | ColorValid | 0x2F4F4F
|
||||||
ColorDarkTurquoise
|
ColorDarkTurquoise = ColorIsRGB | ColorValid | 0x00CED1
|
||||||
ColorDarkViolet
|
ColorDarkViolet = ColorIsRGB | ColorValid | 0x9400D3
|
||||||
ColorDeepPink
|
ColorDeepPink = ColorIsRGB | ColorValid | 0xFF1493
|
||||||
ColorDeepSkyBlue
|
ColorDeepSkyBlue = ColorIsRGB | ColorValid | 0x00BFFF
|
||||||
ColorDimGray
|
ColorDimGray = ColorIsRGB | ColorValid | 0x696969
|
||||||
ColorDodgerBlue
|
ColorDodgerBlue = ColorIsRGB | ColorValid | 0x1E90FF
|
||||||
ColorFireBrick
|
ColorFireBrick = ColorIsRGB | ColorValid | 0xB22222
|
||||||
ColorFloralWhite
|
ColorFloralWhite = ColorIsRGB | ColorValid | 0xFFFAF0
|
||||||
ColorForestGreen
|
ColorForestGreen = ColorIsRGB | ColorValid | 0x228B22
|
||||||
ColorGainsboro
|
ColorGainsboro = ColorIsRGB | ColorValid | 0xDCDCDC
|
||||||
ColorGhostWhite
|
ColorGhostWhite = ColorIsRGB | ColorValid | 0xF8F8FF
|
||||||
ColorGold
|
ColorGold = ColorIsRGB | ColorValid | 0xFFD700
|
||||||
ColorGoldenrod
|
ColorGoldenrod = ColorIsRGB | ColorValid | 0xDAA520
|
||||||
ColorGreenYellow
|
ColorGreenYellow = ColorIsRGB | ColorValid | 0xADFF2F
|
||||||
ColorHoneydew
|
ColorHoneydew = ColorIsRGB | ColorValid | 0xF0FFF0
|
||||||
ColorHotPink
|
ColorHotPink = ColorIsRGB | ColorValid | 0xFF69B4
|
||||||
ColorIndianRed
|
ColorIndianRed = ColorIsRGB | ColorValid | 0xCD5C5C
|
||||||
ColorIndigo
|
ColorIndigo = ColorIsRGB | ColorValid | 0x4B0082
|
||||||
ColorIvory
|
ColorIvory = ColorIsRGB | ColorValid | 0xFFFFF0
|
||||||
ColorKhaki
|
ColorKhaki = ColorIsRGB | ColorValid | 0xF0E68C
|
||||||
ColorLavender
|
ColorLavender = ColorIsRGB | ColorValid | 0xE6E6FA
|
||||||
ColorLavenderBlush
|
ColorLavenderBlush = ColorIsRGB | ColorValid | 0xFFF0F5
|
||||||
ColorLawnGreen
|
ColorLawnGreen = ColorIsRGB | ColorValid | 0x7CFC00
|
||||||
ColorLemonChiffon
|
ColorLemonChiffon = ColorIsRGB | ColorValid | 0xFFFACD
|
||||||
ColorLightBlue
|
ColorLightBlue = ColorIsRGB | ColorValid | 0xADD8E6
|
||||||
ColorLightCoral
|
ColorLightCoral = ColorIsRGB | ColorValid | 0xF08080
|
||||||
ColorLightCyan
|
ColorLightCyan = ColorIsRGB | ColorValid | 0xE0FFFF
|
||||||
ColorLightGoldenrodYellow
|
ColorLightGoldenrodYellow = ColorIsRGB | ColorValid | 0xFAFAD2
|
||||||
ColorLightGray
|
ColorLightGray = ColorIsRGB | ColorValid | 0xD3D3D3
|
||||||
ColorLightGreen
|
ColorLightGreen = ColorIsRGB | ColorValid | 0x90EE90
|
||||||
ColorLightPink
|
ColorLightPink = ColorIsRGB | ColorValid | 0xFFB6C1
|
||||||
ColorLightSalmon
|
ColorLightSalmon = ColorIsRGB | ColorValid | 0xFFA07A
|
||||||
ColorLightSeaGreen
|
ColorLightSeaGreen = ColorIsRGB | ColorValid | 0x20B2AA
|
||||||
ColorLightSkyBlue
|
ColorLightSkyBlue = ColorIsRGB | ColorValid | 0x87CEFA
|
||||||
ColorLightSlateGray
|
ColorLightSlateGray = ColorIsRGB | ColorValid | 0x778899
|
||||||
ColorLightSteelBlue
|
ColorLightSteelBlue = ColorIsRGB | ColorValid | 0xB0C4DE
|
||||||
ColorLightYellow
|
ColorLightYellow = ColorIsRGB | ColorValid | 0xFFFFE0
|
||||||
ColorLimeGreen
|
ColorLimeGreen = ColorIsRGB | ColorValid | 0x32CD32
|
||||||
ColorLinen
|
ColorLinen = ColorIsRGB | ColorValid | 0xFAF0E6
|
||||||
ColorMediumAquamarine
|
ColorMediumAquamarine = ColorIsRGB | ColorValid | 0x66CDAA
|
||||||
ColorMediumBlue
|
ColorMediumBlue = ColorIsRGB | ColorValid | 0x0000CD
|
||||||
ColorMediumOrchid
|
ColorMediumOrchid = ColorIsRGB | ColorValid | 0xBA55D3
|
||||||
ColorMediumPurple
|
ColorMediumPurple = ColorIsRGB | ColorValid | 0x9370DB
|
||||||
ColorMediumSeaGreen
|
ColorMediumSeaGreen = ColorIsRGB | ColorValid | 0x3CB371
|
||||||
ColorMediumSlateBlue
|
ColorMediumSlateBlue = ColorIsRGB | ColorValid | 0x7B68EE
|
||||||
ColorMediumSpringGreen
|
ColorMediumSpringGreen = ColorIsRGB | ColorValid | 0x00FA9A
|
||||||
ColorMediumTurquoise
|
ColorMediumTurquoise = ColorIsRGB | ColorValid | 0x48D1CC
|
||||||
ColorMediumVioletRed
|
ColorMediumVioletRed = ColorIsRGB | ColorValid | 0xC71585
|
||||||
ColorMidnightBlue
|
ColorMidnightBlue = ColorIsRGB | ColorValid | 0x191970
|
||||||
ColorMintCream
|
ColorMintCream = ColorIsRGB | ColorValid | 0xF5FFFA
|
||||||
ColorMistyRose
|
ColorMistyRose = ColorIsRGB | ColorValid | 0xFFE4E1
|
||||||
ColorMoccasin
|
ColorMoccasin = ColorIsRGB | ColorValid | 0xFFE4B5
|
||||||
ColorNavajoWhite
|
ColorNavajoWhite = ColorIsRGB | ColorValid | 0xFFDEAD
|
||||||
ColorOldLace
|
ColorOldLace = ColorIsRGB | ColorValid | 0xFDF5E6
|
||||||
ColorOliveDrab
|
ColorOliveDrab = ColorIsRGB | ColorValid | 0x6B8E23
|
||||||
ColorOrange
|
ColorOrange = ColorIsRGB | ColorValid | 0xFFA500
|
||||||
ColorOrangeRed
|
ColorOrangeRed = ColorIsRGB | ColorValid | 0xFF4500
|
||||||
ColorOrchid
|
ColorOrchid = ColorIsRGB | ColorValid | 0xDA70D6
|
||||||
ColorPaleGoldenrod
|
ColorPaleGoldenrod = ColorIsRGB | ColorValid | 0xEEE8AA
|
||||||
ColorPaleGreen
|
ColorPaleGreen = ColorIsRGB | ColorValid | 0x98FB98
|
||||||
ColorPaleTurquoise
|
ColorPaleTurquoise = ColorIsRGB | ColorValid | 0xAFEEEE
|
||||||
ColorPaleVioletRed
|
ColorPaleVioletRed = ColorIsRGB | ColorValid | 0xDB7093
|
||||||
ColorPapayaWhip
|
ColorPapayaWhip = ColorIsRGB | ColorValid | 0xFFEFD5
|
||||||
ColorPeachPuff
|
ColorPeachPuff = ColorIsRGB | ColorValid | 0xFFDAB9
|
||||||
ColorPeru
|
ColorPeru = ColorIsRGB | ColorValid | 0xCD853F
|
||||||
ColorPink
|
ColorPink = ColorIsRGB | ColorValid | 0xFFC0CB
|
||||||
ColorPlum
|
ColorPlum = ColorIsRGB | ColorValid | 0xDDA0DD
|
||||||
ColorPowderBlue
|
ColorPowderBlue = ColorIsRGB | ColorValid | 0xB0E0E6
|
||||||
ColorRebeccaPurple
|
ColorRebeccaPurple = ColorIsRGB | ColorValid | 0x663399
|
||||||
ColorRosyBrown
|
ColorRosyBrown = ColorIsRGB | ColorValid | 0xBC8F8F
|
||||||
ColorRoyalBlue
|
ColorRoyalBlue = ColorIsRGB | ColorValid | 0x4169E1
|
||||||
ColorSaddleBrown
|
ColorSaddleBrown = ColorIsRGB | ColorValid | 0x8B4513
|
||||||
ColorSalmon
|
ColorSalmon = ColorIsRGB | ColorValid | 0xFA8072
|
||||||
ColorSandyBrown
|
ColorSandyBrown = ColorIsRGB | ColorValid | 0xF4A460
|
||||||
ColorSeaGreen
|
ColorSeaGreen = ColorIsRGB | ColorValid | 0x2E8B57
|
||||||
ColorSeashell
|
ColorSeashell = ColorIsRGB | ColorValid | 0xFFF5EE
|
||||||
ColorSienna
|
ColorSienna = ColorIsRGB | ColorValid | 0xA0522D
|
||||||
ColorSkyblue
|
ColorSkyblue = ColorIsRGB | ColorValid | 0x87CEEB
|
||||||
ColorSlateBlue
|
ColorSlateBlue = ColorIsRGB | ColorValid | 0x6A5ACD
|
||||||
ColorSlateGray
|
ColorSlateGray = ColorIsRGB | ColorValid | 0x708090
|
||||||
ColorSnow
|
ColorSnow = ColorIsRGB | ColorValid | 0xFFFAFA
|
||||||
ColorSpringGreen
|
ColorSpringGreen = ColorIsRGB | ColorValid | 0x00FF7F
|
||||||
ColorSteelBlue
|
ColorSteelBlue = ColorIsRGB | ColorValid | 0x4682B4
|
||||||
ColorTan
|
ColorTan = ColorIsRGB | ColorValid | 0xD2B48C
|
||||||
ColorThistle
|
ColorThistle = ColorIsRGB | ColorValid | 0xD8BFD8
|
||||||
ColorTomato
|
ColorTomato = ColorIsRGB | ColorValid | 0xFF6347
|
||||||
ColorTurquoise
|
ColorTurquoise = ColorIsRGB | ColorValid | 0x40E0D0
|
||||||
ColorViolet
|
ColorViolet = ColorIsRGB | ColorValid | 0xEE82EE
|
||||||
ColorWheat
|
ColorWheat = ColorIsRGB | ColorValid | 0xF5DEB3
|
||||||
ColorWhiteSmoke
|
ColorWhiteSmoke = ColorIsRGB | ColorValid | 0xF5F5F5
|
||||||
ColorYellowGreen
|
ColorYellowGreen = ColorIsRGB | ColorValid | 0x9ACD32
|
||||||
)
|
)
|
||||||
|
|
||||||
// These are aliases for the color gray, because some of us spell
|
// These are aliases for the color gray, because some of us spell
|
||||||
|
|||||||
+78
-6
@@ -42,6 +42,7 @@ type cScreen struct {
|
|||||||
truecolor bool
|
truecolor bool
|
||||||
running bool
|
running bool
|
||||||
disableAlt bool // disable the alternate screen
|
disableAlt bool // disable the alternate screen
|
||||||
|
title string
|
||||||
|
|
||||||
w int
|
w int
|
||||||
h int
|
h int
|
||||||
@@ -49,6 +50,7 @@ type cScreen struct {
|
|||||||
oscreen consoleInfo
|
oscreen consoleInfo
|
||||||
ocursor cursorInfo
|
ocursor cursorInfo
|
||||||
cursorStyle CursorStyle
|
cursorStyle CursorStyle
|
||||||
|
cursorColor Color
|
||||||
oimode uint32
|
oimode uint32
|
||||||
oomode uint32
|
oomode uint32
|
||||||
cells CellBuffer
|
cells CellBuffer
|
||||||
@@ -164,6 +166,20 @@ const (
|
|||||||
vtEnableAm = "\x1b[?7h"
|
vtEnableAm = "\x1b[?7h"
|
||||||
vtEnterCA = "\x1b[?1049h\x1b[22;0;0t"
|
vtEnterCA = "\x1b[?1049h\x1b[22;0;0t"
|
||||||
vtExitCA = "\x1b[?1049l\x1b[23;0;0t"
|
vtExitCA = "\x1b[?1049l\x1b[23;0;0t"
|
||||||
|
vtDoubleUnderline = "\x1b[4:2m"
|
||||||
|
vtCurlyUnderline = "\x1b[4:3m"
|
||||||
|
vtDottedUnderline = "\x1b[4:4m"
|
||||||
|
vtDashedUnderline = "\x1b[4:5m"
|
||||||
|
vtUnderColor = "\x1b[58:5:%dm"
|
||||||
|
vtUnderColorRGB = "\x1b[58:2::%d:%d:%dm"
|
||||||
|
vtUnderColorReset = "\x1b[59m"
|
||||||
|
vtEnterUrl = "\x1b]8;%s;%s\x1b\\" // NB arg 1 is id, arg 2 is url
|
||||||
|
vtExitUrl = "\x1b]8;;\x1b\\"
|
||||||
|
vtCursorColorRGB = "\x1b]12;#%02x%02x%02x\007"
|
||||||
|
vtCursorColorReset = "\x1b]112\007"
|
||||||
|
vtSaveTitle = "\x1b[22;2t"
|
||||||
|
vtRestoreTitle = "\x1b[23;2t"
|
||||||
|
vtSetTitle = "\x1b]2;%s\x1b\\"
|
||||||
)
|
)
|
||||||
|
|
||||||
var vtCursorStyles = map[CursorStyle]string{
|
var vtCursorStyles = map[CursorStyle]string{
|
||||||
@@ -335,8 +351,10 @@ func (s *cScreen) disengage() {
|
|||||||
|
|
||||||
if s.vten {
|
if s.vten {
|
||||||
s.emitVtString(vtCursorStyles[CursorStyleDefault])
|
s.emitVtString(vtCursorStyles[CursorStyleDefault])
|
||||||
|
s.emitVtString(vtCursorColorReset)
|
||||||
s.emitVtString(vtEnableAm)
|
s.emitVtString(vtEnableAm)
|
||||||
if !s.disableAlt {
|
if !s.disableAlt {
|
||||||
|
s.emitVtString(vtRestoreTitle)
|
||||||
s.emitVtString(vtExitCA)
|
s.emitVtString(vtExitCA)
|
||||||
}
|
}
|
||||||
} else if !s.disableAlt {
|
} else if !s.disableAlt {
|
||||||
@@ -374,9 +392,13 @@ func (s *cScreen) engage() error {
|
|||||||
if s.vten {
|
if s.vten {
|
||||||
s.setOutMode(modeVtOutput | modeNoAutoNL | modeCookedOut | modeUnderline)
|
s.setOutMode(modeVtOutput | modeNoAutoNL | modeCookedOut | modeUnderline)
|
||||||
if !s.disableAlt {
|
if !s.disableAlt {
|
||||||
|
s.emitVtString(vtSaveTitle)
|
||||||
s.emitVtString(vtEnterCA)
|
s.emitVtString(vtEnterCA)
|
||||||
}
|
}
|
||||||
s.emitVtString(vtDisableAm)
|
s.emitVtString(vtDisableAm)
|
||||||
|
if s.title != "" {
|
||||||
|
s.emitVtString(fmt.Sprintf(vtSetTitle, s.title))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
s.setOutMode(0)
|
s.setOutMode(0)
|
||||||
}
|
}
|
||||||
@@ -426,6 +448,12 @@ func (s *cScreen) showCursor() {
|
|||||||
if s.vten {
|
if s.vten {
|
||||||
s.emitVtString(vtShowCursor)
|
s.emitVtString(vtShowCursor)
|
||||||
s.emitVtString(vtCursorStyles[s.cursorStyle])
|
s.emitVtString(vtCursorStyles[s.cursorStyle])
|
||||||
|
if s.cursorColor == ColorReset {
|
||||||
|
s.emitVtString(vtCursorColorReset)
|
||||||
|
} else if s.cursorColor.Valid() {
|
||||||
|
r, g, b := s.cursorColor.RGB()
|
||||||
|
s.emitVtString(fmt.Sprintf(vtCursorColorRGB, r, g, b))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
s.setCursorInfo(&cursorInfo{size: 100, visible: 1})
|
s.setCursorInfo(&cursorInfo{size: 100, visible: 1})
|
||||||
}
|
}
|
||||||
@@ -449,11 +477,12 @@ func (s *cScreen) ShowCursor(x, y int) {
|
|||||||
s.Unlock()
|
s.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *cScreen) SetCursorStyle(cs CursorStyle) {
|
func (s *cScreen) SetCursor(cs CursorStyle, cc Color) {
|
||||||
s.Lock()
|
s.Lock()
|
||||||
if !s.fini {
|
if !s.fini {
|
||||||
if _, ok := vtCursorStyles[cs]; ok {
|
if _, ok := vtCursorStyles[cs]; ok {
|
||||||
s.cursorStyle = cs
|
s.cursorStyle = cs
|
||||||
|
s.cursorColor = cc
|
||||||
s.doCursor()
|
s.doCursor()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -875,7 +904,7 @@ func mapColor2RGB(c Color) uint16 {
|
|||||||
|
|
||||||
// Map a tcell style to Windows attributes
|
// Map a tcell style to Windows attributes
|
||||||
func (s *cScreen) mapStyle(style Style) uint16 {
|
func (s *cScreen) mapStyle(style Style) uint16 {
|
||||||
f, b, a := style.Decompose()
|
f, b, a := style.fg, style.bg, style.attrs
|
||||||
fa := s.oscreen.attrs & 0xf
|
fa := s.oscreen.attrs & 0xf
|
||||||
ba := (s.oscreen.attrs) >> 4 & 0xf
|
ba := (s.oscreen.attrs) >> 4 & 0xf
|
||||||
if f != ColorDefault && f != ColorReset {
|
if f != ColorDefault && f != ColorReset {
|
||||||
@@ -912,19 +941,41 @@ func (s *cScreen) mapStyle(style Style) uint16 {
|
|||||||
func (s *cScreen) sendVtStyle(style Style) {
|
func (s *cScreen) sendVtStyle(style Style) {
|
||||||
esc := &strings.Builder{}
|
esc := &strings.Builder{}
|
||||||
|
|
||||||
fg, bg, attrs := style.Decompose()
|
fg, bg, attrs := style.fg, style.bg, style.attrs
|
||||||
|
us, uc := style.ulStyle, style.ulColor
|
||||||
|
|
||||||
esc.WriteString(vtSgr0)
|
esc.WriteString(vtSgr0)
|
||||||
|
|
||||||
if attrs&(AttrBold|AttrDim) == AttrBold {
|
if attrs&(AttrBold|AttrDim) == AttrBold {
|
||||||
esc.WriteString(vtBold)
|
esc.WriteString(vtBold)
|
||||||
}
|
}
|
||||||
if attrs&AttrBlink != 0 {
|
if attrs&AttrBlink != 0 {
|
||||||
esc.WriteString(vtBlink)
|
esc.WriteString(vtBlink)
|
||||||
}
|
}
|
||||||
if attrs&AttrUnderline != 0 {
|
if us != UnderlineStyleNone {
|
||||||
|
if uc == ColorReset {
|
||||||
|
esc.WriteString(vtUnderColorReset)
|
||||||
|
} else if uc.IsRGB() {
|
||||||
|
r, g, b := uc.RGB()
|
||||||
|
_, _ = fmt.Fprintf(esc, vtUnderColorRGB, int(r), int(g), int(b))
|
||||||
|
} else if uc.Valid() {
|
||||||
|
_, _ = fmt.Fprintf(esc, vtUnderColor, uc&0xff)
|
||||||
|
}
|
||||||
|
|
||||||
esc.WriteString(vtUnderline)
|
esc.WriteString(vtUnderline)
|
||||||
|
// legacy ConHost does not understand these but Terminal does
|
||||||
|
switch us {
|
||||||
|
case UnderlineStyleSolid:
|
||||||
|
case UnderlineStyleDouble:
|
||||||
|
esc.WriteString(vtDoubleUnderline)
|
||||||
|
case UnderlineStyleCurly:
|
||||||
|
esc.WriteString(vtCurlyUnderline)
|
||||||
|
case UnderlineStyleDotted:
|
||||||
|
esc.WriteString(vtDottedUnderline)
|
||||||
|
case UnderlineStyleDashed:
|
||||||
|
esc.WriteString(vtDashedUnderline)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if attrs&AttrReverse != 0 {
|
if attrs&AttrReverse != 0 {
|
||||||
esc.WriteString(vtReverse)
|
esc.WriteString(vtReverse)
|
||||||
}
|
}
|
||||||
@@ -940,6 +991,13 @@ func (s *cScreen) sendVtStyle(style Style) {
|
|||||||
} else if bg.Valid() {
|
} else if bg.Valid() {
|
||||||
_, _ = fmt.Fprintf(esc, vtSetBg, bg&0xff)
|
_, _ = fmt.Fprintf(esc, vtSetBg, bg&0xff)
|
||||||
}
|
}
|
||||||
|
// URL string can be long, so don't send it unless we really need to
|
||||||
|
if style.url != "" {
|
||||||
|
_, _ = fmt.Fprintf(esc, vtEnterUrl, style.urlId, style.url)
|
||||||
|
} else {
|
||||||
|
esc.WriteString(vtExitUrl)
|
||||||
|
}
|
||||||
|
|
||||||
s.emitVtString(esc.String())
|
s.emitVtString(esc.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1062,7 +1120,6 @@ func (s *cScreen) setCursorInfo(info *cursorInfo) {
|
|||||||
_, _, _ = procSetConsoleCursorInfo.Call(
|
_, _, _ = procSetConsoleCursorInfo.Call(
|
||||||
uintptr(s.out),
|
uintptr(s.out),
|
||||||
uintptr(unsafe.Pointer(info)))
|
uintptr(unsafe.Pointer(info)))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *cScreen) setCursorPos(x, y int, vtEnable bool) {
|
func (s *cScreen) setCursorPos(x, y int, vtEnable bool) {
|
||||||
@@ -1227,6 +1284,15 @@ func (s *cScreen) SetStyle(style Style) {
|
|||||||
s.Unlock()
|
s.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *cScreen) SetTitle(title string) {
|
||||||
|
s.Lock()
|
||||||
|
s.title = title
|
||||||
|
if s.vten {
|
||||||
|
s.emitVtString(fmt.Sprintf(vtSetTitle, title))
|
||||||
|
}
|
||||||
|
s.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
// No fallback rune support, since we have Unicode. Yay!
|
// No fallback rune support, since we have Unicode. Yay!
|
||||||
|
|
||||||
func (s *cScreen) RegisterRuneFallback(_ rune, _ string) {
|
func (s *cScreen) RegisterRuneFallback(_ rune, _ string) {
|
||||||
@@ -1246,6 +1312,12 @@ func (s *cScreen) HasMouse() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *cScreen) SetClipboard(_ []byte) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *cScreen) GetClipboard() {
|
||||||
|
}
|
||||||
|
|
||||||
func (s *cScreen) Resize(int, int, int, int) {}
|
func (s *cScreen) Resize(int, int, int, int) {}
|
||||||
|
|
||||||
func (s *cScreen) HasKey(k Key) bool {
|
func (s *cScreen) HasKey(k Key) bool {
|
||||||
|
|||||||
+28
-4
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020 The TCell Authors
|
// Copyright 2024 The TCell Authors
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use file except in compliance with the License.
|
// you may not use file except in compliance with the License.
|
||||||
@@ -19,12 +19,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// EventPaste is used to mark the start and end of a bracketed paste.
|
// EventPaste is used to mark the start and end of a bracketed paste.
|
||||||
// An event with .Start() true will be sent to mark the start.
|
//
|
||||||
// Then a number of keys will be sent to indicate that the content
|
// An event with .Start() true will be sent to mark the start of a bracketed paste,
|
||||||
// is pasted in. At the end, an event with .Start() false will be sent.
|
// followed by a number of keys (string data) for the content, ending with the
|
||||||
|
// an event with .End() true.
|
||||||
type EventPaste struct {
|
type EventPaste struct {
|
||||||
start bool
|
start bool
|
||||||
t time.Time
|
t time.Time
|
||||||
|
data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// When returns the time when this EventPaste was created.
|
// When returns the time when this EventPaste was created.
|
||||||
@@ -46,3 +48,25 @@ func (ev *EventPaste) End() bool {
|
|||||||
func NewEventPaste(start bool) *EventPaste {
|
func NewEventPaste(start bool) *EventPaste {
|
||||||
return &EventPaste{t: time.Now(), start: start}
|
return &EventPaste{t: time.Now(), start: start}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewEventClipboard returns a new NewEventClipboard with a data payload
|
||||||
|
func NewEventClipboard(data []byte) *EventClipboard {
|
||||||
|
return &EventClipboard{t: time.Now(), data: data}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EventClipboard represents data from the clipboard,
|
||||||
|
// in response to a GetClipboard request.
|
||||||
|
type EventClipboard struct {
|
||||||
|
t time.Time
|
||||||
|
data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data returns the attached binary data.
|
||||||
|
func (ev *EventClipboard) Data() []byte {
|
||||||
|
return ev.data
|
||||||
|
}
|
||||||
|
|
||||||
|
// When returns the time when this event was created.
|
||||||
|
func (ev *EventClipboard) When() time.Time {
|
||||||
|
return ev.t
|
||||||
|
}
|
||||||
|
|||||||
+33
-4
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2023 The TCell Authors
|
// Copyright 2024 The TCell Authors
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use file except in compliance with the License.
|
// you may not use file except in compliance with the License.
|
||||||
@@ -79,8 +79,9 @@ type Screen interface {
|
|||||||
|
|
||||||
// SetCursorStyle is used to set the cursor style. If the style
|
// SetCursorStyle is used to set the cursor style. If the style
|
||||||
// is not supported (or cursor styles are not supported at all),
|
// is not supported (or cursor styles are not supported at all),
|
||||||
// then this will have no effect.
|
// then this will have no effect. Color will be changed if supplied,
|
||||||
SetCursorStyle(CursorStyle)
|
// and the terminal supports doing so.
|
||||||
|
SetCursorStyle(CursorStyle, ...Color)
|
||||||
|
|
||||||
// Size returns the screen size as width, height. This changes in
|
// Size returns the screen size as width, height. This changes in
|
||||||
// response to a call to Clear or Flush.
|
// response to a call to Clear or Flush.
|
||||||
@@ -265,6 +266,23 @@ type Screen interface {
|
|||||||
// Tty returns the underlying Tty. If the screen is not a terminal, the
|
// Tty returns the underlying Tty. If the screen is not a terminal, the
|
||||||
// returned bool will be false
|
// returned bool will be false
|
||||||
Tty() (Tty, bool)
|
Tty() (Tty, bool)
|
||||||
|
|
||||||
|
// SetTitle sets a window title on the screen.
|
||||||
|
// Terminals may be configured to ignore this, or unable to.
|
||||||
|
// Tcell may attempt to save and restore the window title on entry and exit, but
|
||||||
|
// the results may vary. Use of unicode characters may not be supported.
|
||||||
|
SetTitle(string)
|
||||||
|
|
||||||
|
// SetClipboard is used to post arbitrary data to the system clipboard.
|
||||||
|
// This need not be UTF-8 string data. It's up to the recipient to decode the
|
||||||
|
// data meaningfully. Terminals may prevent this for security reasons.
|
||||||
|
SetClipboard([]byte)
|
||||||
|
|
||||||
|
// GetClipboard is used to request the clipboard contents. It may be ignored.
|
||||||
|
// If the terminal is willing, it will be post the clipboard contents using an
|
||||||
|
// EventPaste with the clipboard content as the Data() field. Terminals may
|
||||||
|
// prevent this for security reasons.
|
||||||
|
GetClipboard()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewScreen returns a default Screen suitable for the user's terminal
|
// NewScreen returns a default Screen suitable for the user's terminal
|
||||||
@@ -312,7 +330,7 @@ type screenImpl interface {
|
|||||||
SetStyle(style Style)
|
SetStyle(style Style)
|
||||||
ShowCursor(x int, y int)
|
ShowCursor(x int, y int)
|
||||||
HideCursor()
|
HideCursor()
|
||||||
SetCursorStyle(CursorStyle)
|
SetCursor(CursorStyle, Color)
|
||||||
Size() (width, height int)
|
Size() (width, height int)
|
||||||
EnableMouse(...MouseFlags)
|
EnableMouse(...MouseFlags)
|
||||||
DisableMouse()
|
DisableMouse()
|
||||||
@@ -334,7 +352,10 @@ type screenImpl interface {
|
|||||||
Resume() error
|
Resume() error
|
||||||
Beep() error
|
Beep() error
|
||||||
SetSize(int, int)
|
SetSize(int, int)
|
||||||
|
SetTitle(string)
|
||||||
Tty() (Tty, bool)
|
Tty() (Tty, bool)
|
||||||
|
SetClipboard([]byte)
|
||||||
|
GetClipboard()
|
||||||
|
|
||||||
// Following methods are not part of the Screen api, but are used for interaction with
|
// Following methods are not part of the Screen api, but are used for interaction with
|
||||||
// the common layer code.
|
// the common layer code.
|
||||||
@@ -464,3 +485,11 @@ func (b *baseScreen) PostEvent(ev Event) error {
|
|||||||
return ErrEventQFull
|
return ErrEventQFull
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *baseScreen) SetCursorStyle(cs CursorStyle, ccs ...Color) {
|
||||||
|
if len(ccs) > 0 {
|
||||||
|
b.SetCursor(cs, ccs[0])
|
||||||
|
} else {
|
||||||
|
b.SetCursor(cs, ColorNone)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+33
-2
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2023 The TCell Authors
|
// Copyright 2024 The TCell Authors
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use file except in compliance with the License.
|
// you may not use file except in compliance with the License.
|
||||||
@@ -60,6 +60,12 @@ type SimulationScreen interface {
|
|||||||
|
|
||||||
// GetCursor returns the cursor details.
|
// GetCursor returns the cursor details.
|
||||||
GetCursor() (x int, y int, visible bool)
|
GetCursor() (x int, y int, visible bool)
|
||||||
|
|
||||||
|
// GetTitle gets the previously set title.
|
||||||
|
GetTitle() string
|
||||||
|
|
||||||
|
// GetClipboardData gets the actual data for the clipboard.
|
||||||
|
GetClipboardData() []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimCell represents a simulated screen cell. The purpose of this
|
// SimCell represents a simulated screen cell. The purpose of this
|
||||||
@@ -98,6 +104,8 @@ type simscreen struct {
|
|||||||
fillchar rune
|
fillchar rune
|
||||||
fillstyle Style
|
fillstyle Style
|
||||||
fallback map[rune]string
|
fallback map[rune]string
|
||||||
|
title string
|
||||||
|
clipboard []byte
|
||||||
|
|
||||||
Screen
|
Screen
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
@@ -239,7 +247,7 @@ func (s *simscreen) hideCursor() {
|
|||||||
s.cursorvis = false
|
s.cursorvis = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *simscreen) SetCursorStyle(CursorStyle) {}
|
func (s *simscreen) SetCursor(CursorStyle, Color) {}
|
||||||
|
|
||||||
func (s *simscreen) Show() {
|
func (s *simscreen) Show() {
|
||||||
s.Lock()
|
s.Lock()
|
||||||
@@ -495,3 +503,26 @@ func (s *simscreen) EventQ() chan Event {
|
|||||||
func (s *simscreen) StopQ() <-chan struct{} {
|
func (s *simscreen) StopQ() <-chan struct{} {
|
||||||
return s.quit
|
return s.quit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *simscreen) SetTitle(title string) {
|
||||||
|
s.title = title
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *simscreen) GetTitle() string {
|
||||||
|
return s.title
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *simscreen) SetClipboard(data []byte) {
|
||||||
|
s.clipboard = data
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *simscreen) GetClipboard() {
|
||||||
|
if s.clipboard != nil {
|
||||||
|
ev := NewEventClipboard(s.clipboard)
|
||||||
|
s.postEvent(ev)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *simscreen) GetClipboardData() []byte {
|
||||||
|
return s.clipboard
|
||||||
|
}
|
||||||
|
|||||||
+77
-61
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 The TCell Authors
|
// Copyright 2024 The TCell Authors
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use file except in compliance with the License.
|
// you may not use file except in compliance with the License.
|
||||||
@@ -23,11 +23,13 @@ package tcell
|
|||||||
//
|
//
|
||||||
// To use Style, just declare a variable of its type.
|
// To use Style, just declare a variable of its type.
|
||||||
type Style struct {
|
type Style struct {
|
||||||
fg Color
|
fg Color
|
||||||
bg Color
|
bg Color
|
||||||
attrs AttrMask
|
ulStyle UnderlineStyle
|
||||||
url string
|
ulColor Color
|
||||||
urlId string
|
attrs AttrMask
|
||||||
|
url string
|
||||||
|
urlId string
|
||||||
}
|
}
|
||||||
|
|
||||||
// StyleDefault represents a default style, based upon the context.
|
// StyleDefault represents a default style, based upon the context.
|
||||||
@@ -40,50 +42,35 @@ var styleInvalid = Style{attrs: AttrInvalid}
|
|||||||
// Foreground returns a new style based on s, with the foreground color set
|
// Foreground returns a new style based on s, with the foreground color set
|
||||||
// as requested. ColorDefault can be used to select the global default.
|
// as requested. ColorDefault can be used to select the global default.
|
||||||
func (s Style) Foreground(c Color) Style {
|
func (s Style) Foreground(c Color) Style {
|
||||||
return Style{
|
s2 := s
|
||||||
fg: c,
|
s2.fg = c
|
||||||
bg: s.bg,
|
return s2
|
||||||
attrs: s.attrs,
|
|
||||||
url: s.url,
|
|
||||||
urlId: s.urlId,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Background returns a new style based on s, with the background color set
|
// Background returns a new style based on s, with the background color set
|
||||||
// as requested. ColorDefault can be used to select the global default.
|
// as requested. ColorDefault can be used to select the global default.
|
||||||
func (s Style) Background(c Color) Style {
|
func (s Style) Background(c Color) Style {
|
||||||
return Style{
|
s2 := s
|
||||||
fg: s.fg,
|
s2.bg = c
|
||||||
bg: c,
|
return s2
|
||||||
attrs: s.attrs,
|
|
||||||
url: s.url,
|
|
||||||
urlId: s.urlId,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decompose breaks a style up, returning the foreground, background,
|
// Decompose breaks a style up, returning the foreground, background,
|
||||||
// and other attributes. The URL if set is not included.
|
// and other attributes. The URL if set is not included.
|
||||||
|
// Deprecated: Applications should not attempt to decompose style,
|
||||||
|
// as this content is not sufficient to describe the actual style.
|
||||||
func (s Style) Decompose() (fg Color, bg Color, attr AttrMask) {
|
func (s Style) Decompose() (fg Color, bg Color, attr AttrMask) {
|
||||||
return s.fg, s.bg, s.attrs
|
return s.fg, s.bg, s.attrs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Style) setAttrs(attrs AttrMask, on bool) Style {
|
func (s Style) setAttrs(attrs AttrMask, on bool) Style {
|
||||||
|
s2 := s
|
||||||
if on {
|
if on {
|
||||||
return Style{
|
s2.attrs |= attrs
|
||||||
fg: s.fg,
|
} else {
|
||||||
bg: s.bg,
|
s2.attrs &^= attrs
|
||||||
attrs: s.attrs | attrs,
|
|
||||||
url: s.url,
|
|
||||||
urlId: s.urlId,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Style{
|
|
||||||
fg: s.fg,
|
|
||||||
bg: s.bg,
|
|
||||||
attrs: s.attrs &^ attrs,
|
|
||||||
url: s.url,
|
|
||||||
urlId: s.urlId,
|
|
||||||
}
|
}
|
||||||
|
return s2
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normal returns the style with all attributes disabled.
|
// Normal returns the style with all attributes disabled.
|
||||||
@@ -125,40 +112,73 @@ func (s Style) Reverse(on bool) Style {
|
|||||||
return s.setAttrs(AttrReverse, on)
|
return s.setAttrs(AttrReverse, on)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Underline returns a new style based on s, with the underline attribute set
|
|
||||||
// as requested.
|
|
||||||
func (s Style) Underline(on bool) Style {
|
|
||||||
return s.setAttrs(AttrUnderline, on)
|
|
||||||
}
|
|
||||||
|
|
||||||
// StrikeThrough sets strikethrough mode.
|
// StrikeThrough sets strikethrough mode.
|
||||||
func (s Style) StrikeThrough(on bool) Style {
|
func (s Style) StrikeThrough(on bool) Style {
|
||||||
return s.setAttrs(AttrStrikeThrough, on)
|
return s.setAttrs(AttrStrikeThrough, on)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Underline style. Modern terminals have the option of rendering the
|
||||||
|
// underline using different styles, and even different colors.
|
||||||
|
type UnderlineStyle int
|
||||||
|
|
||||||
|
const (
|
||||||
|
UnderlineStyleNone = UnderlineStyle(iota)
|
||||||
|
UnderlineStyleSolid
|
||||||
|
UnderlineStyleDouble
|
||||||
|
UnderlineStyleCurly
|
||||||
|
UnderlineStyleDotted
|
||||||
|
UnderlineStyleDashed
|
||||||
|
)
|
||||||
|
|
||||||
|
// Underline returns a new style based on s, with the underline attribute set
|
||||||
|
// as requested. The parameters can be:
|
||||||
|
//
|
||||||
|
// bool: on / off - enables just a simple underline
|
||||||
|
// UnderlineStyle: sets a specific style (should not coexist with the bool)
|
||||||
|
// Color: the color to use
|
||||||
|
func (s Style) Underline(params ...interface{}) Style {
|
||||||
|
s2 := s
|
||||||
|
for _, param := range params {
|
||||||
|
switch v := param.(type) {
|
||||||
|
case bool:
|
||||||
|
if v {
|
||||||
|
s2.ulStyle = UnderlineStyleSolid
|
||||||
|
s2.attrs |= AttrUnderline
|
||||||
|
} else {
|
||||||
|
s2.ulStyle = UnderlineStyleNone
|
||||||
|
s2.attrs &^= AttrUnderline
|
||||||
|
}
|
||||||
|
case UnderlineStyle:
|
||||||
|
if v == UnderlineStyleNone {
|
||||||
|
s2.attrs &^= AttrUnderline
|
||||||
|
} else {
|
||||||
|
s2.attrs |= AttrUnderline
|
||||||
|
}
|
||||||
|
s2.ulStyle = v
|
||||||
|
case Color:
|
||||||
|
s2.ulColor = v
|
||||||
|
default:
|
||||||
|
panic("Bad type for underline")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s2
|
||||||
|
}
|
||||||
|
|
||||||
// Attributes returns a new style based on s, with its attributes set as
|
// Attributes returns a new style based on s, with its attributes set as
|
||||||
// specified.
|
// specified.
|
||||||
func (s Style) Attributes(attrs AttrMask) Style {
|
func (s Style) Attributes(attrs AttrMask) Style {
|
||||||
return Style{
|
s2 := s
|
||||||
fg: s.fg,
|
s2.attrs = attrs
|
||||||
bg: s.bg,
|
return s2
|
||||||
attrs: attrs,
|
|
||||||
url: s.url,
|
|
||||||
urlId: s.urlId,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Url returns a style with the Url set. If the provided Url is not empty,
|
// Url returns a style with the Url set. If the provided Url is not empty,
|
||||||
// and the terminal supports it, text will typically be marked up as a clickable
|
// and the terminal supports it, text will typically be marked up as a clickable
|
||||||
// link to that Url. If the Url is empty, then this mode is turned off.
|
// link to that Url. If the Url is empty, then this mode is turned off.
|
||||||
func (s Style) Url(url string) Style {
|
func (s Style) Url(url string) Style {
|
||||||
return Style{
|
s2 := s
|
||||||
fg: s.fg,
|
s2.url = url
|
||||||
bg: s.bg,
|
return s2
|
||||||
attrs: s.attrs,
|
|
||||||
url: url,
|
|
||||||
urlId: s.urlId,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UrlId returns a style with the UrlId set. If the provided UrlId is not empty,
|
// UrlId returns a style with the UrlId set. If the provided UrlId is not empty,
|
||||||
@@ -166,11 +186,7 @@ func (s Style) Url(url string) Style {
|
|||||||
// terminal supports it, any text with the same UrlId will be grouped as if it
|
// terminal supports it, any text with the same UrlId will be grouped as if it
|
||||||
// were one Url, even if it spans multiple lines.
|
// were one Url, even if it spans multiple lines.
|
||||||
func (s Style) UrlId(id string) Style {
|
func (s Style) UrlId(id string) Style {
|
||||||
return Style{
|
s2 := s
|
||||||
fg: s.fg,
|
s2.urlId = "id=" + id
|
||||||
bg: s.bg,
|
return s2
|
||||||
attrs: s.attrs,
|
|
||||||
url: s.url,
|
|
||||||
urlId: "id=" + id,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -67,5 +67,10 @@ func init() {
|
|||||||
KeyBacktab: "\x1b[Z",
|
KeyBacktab: "\x1b[Z",
|
||||||
Modifiers: 1,
|
Modifiers: 1,
|
||||||
AutoMargin: true,
|
AutoMargin: true,
|
||||||
|
DoubleUnderline: "\x1b[4:2m",
|
||||||
|
CurlyUnderline: "\x1b[4:3m",
|
||||||
|
DottedUnderline: "\x1b[4:4m",
|
||||||
|
DashedUnderline: "\x1b[4:5m",
|
||||||
|
XTermLike: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ package base
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
// The following imports just register themselves --
|
// The following imports just register themselves --
|
||||||
// thse are the terminal types we aggregate in this package.
|
// these are the terminal types we aggregate in this package.
|
||||||
_ "github.com/gdamore/tcell/v2/terminfo/a/ansi"
|
_ "github.com/gdamore/tcell/v2/terminfo/a/ansi"
|
||||||
_ "github.com/gdamore/tcell/v2/terminfo/v/vt100"
|
_ "github.com/gdamore/tcell/v2/terminfo/v/vt100"
|
||||||
_ "github.com/gdamore/tcell/v2/terminfo/v/vt102"
|
_ "github.com/gdamore/tcell/v2/terminfo/v/vt102"
|
||||||
|
|||||||
+1
@@ -52,5 +52,6 @@ import (
|
|||||||
_ "github.com/gdamore/tcell/v2/terminfo/w/wy99_ansi"
|
_ "github.com/gdamore/tcell/v2/terminfo/w/wy99_ansi"
|
||||||
_ "github.com/gdamore/tcell/v2/terminfo/x/xfce"
|
_ "github.com/gdamore/tcell/v2/terminfo/x/xfce"
|
||||||
_ "github.com/gdamore/tcell/v2/terminfo/x/xterm"
|
_ "github.com/gdamore/tcell/v2/terminfo/x/xterm"
|
||||||
|
_ "github.com/gdamore/tcell/v2/terminfo/x/xterm_ghostty"
|
||||||
_ "github.com/gdamore/tcell/v2/terminfo/x/xterm_kitty"
|
_ "github.com/gdamore/tcell/v2/terminfo/x/xterm_kitty"
|
||||||
)
|
)
|
||||||
|
|||||||
+2
@@ -67,6 +67,7 @@ func init() {
|
|||||||
KeyBacktab: "\x1b[Z",
|
KeyBacktab: "\x1b[Z",
|
||||||
Modifiers: 1,
|
Modifiers: 1,
|
||||||
AutoMargin: true,
|
AutoMargin: true,
|
||||||
|
XTermLike: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
// GNOME Terminal with xterm 256-colors
|
// GNOME Terminal with xterm 256-colors
|
||||||
@@ -130,5 +131,6 @@ func init() {
|
|||||||
KeyBacktab: "\x1b[Z",
|
KeyBacktab: "\x1b[Z",
|
||||||
Modifiers: 1,
|
Modifiers: 1,
|
||||||
AutoMargin: true,
|
AutoMargin: true,
|
||||||
|
XTermLike: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -68,6 +68,7 @@ func init() {
|
|||||||
KeyBacktab: "\x1b[Z",
|
KeyBacktab: "\x1b[Z",
|
||||||
Modifiers: 1,
|
Modifiers: 1,
|
||||||
AutoMargin: true,
|
AutoMargin: true,
|
||||||
|
XTermLike: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
// KDE console window with xterm 256-colors
|
// KDE console window with xterm 256-colors
|
||||||
@@ -132,5 +133,6 @@ func init() {
|
|||||||
KeyBacktab: "\x1b[Z",
|
KeyBacktab: "\x1b[Z",
|
||||||
Modifiers: 1,
|
Modifiers: 1,
|
||||||
AutoMargin: true,
|
AutoMargin: true,
|
||||||
|
XTermLike: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -66,5 +66,6 @@ func init() {
|
|||||||
KeyF19: "\x1b[33~",
|
KeyF19: "\x1b[33~",
|
||||||
KeyF20: "\x1b[34~",
|
KeyF20: "\x1b[34~",
|
||||||
AutoMargin: true,
|
AutoMargin: true,
|
||||||
|
XTermLike: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -14,7 +14,7 @@ pcansi
|
|||||||
rxvt,rxvt-256color,rxvt-88color,rxvt-unicode,rxvt-unicode-256color
|
rxvt,rxvt-256color,rxvt-88color,rxvt-unicode,rxvt-unicode-256color
|
||||||
screen,screen-256color
|
screen,screen-256color
|
||||||
st,st-256color|simpleterm
|
st,st-256color|simpleterm
|
||||||
tmux
|
tmux,tmux-256color
|
||||||
vt52
|
vt52
|
||||||
vt100
|
vt100
|
||||||
vt102
|
vt102
|
||||||
@@ -27,4 +27,5 @@ wy60
|
|||||||
wy99-ansi,wy99a-ansi
|
wy99-ansi,wy99a-ansi
|
||||||
xfce
|
xfce
|
||||||
xterm,xterm-88color,xterm-256color
|
xterm,xterm-88color,xterm-256color
|
||||||
|
xterm-ghostty
|
||||||
xterm-kitty
|
xterm-kitty
|
||||||
|
|||||||
+3
@@ -110,6 +110,7 @@ func init() {
|
|||||||
KeyCtrlHome: "\x1b[7^",
|
KeyCtrlHome: "\x1b[7^",
|
||||||
KeyCtrlEnd: "\x1b[8^",
|
KeyCtrlEnd: "\x1b[8^",
|
||||||
AutoMargin: true,
|
AutoMargin: true,
|
||||||
|
XTermLike: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
// rxvt 2.7.9 with xterm 256-colors
|
// rxvt 2.7.9 with xterm 256-colors
|
||||||
@@ -215,6 +216,7 @@ func init() {
|
|||||||
KeyCtrlHome: "\x1b[7^",
|
KeyCtrlHome: "\x1b[7^",
|
||||||
KeyCtrlEnd: "\x1b[8^",
|
KeyCtrlEnd: "\x1b[8^",
|
||||||
AutoMargin: true,
|
AutoMargin: true,
|
||||||
|
XTermLike: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
// rxvt 2.7.9 with xterm 88-colors
|
// rxvt 2.7.9 with xterm 88-colors
|
||||||
@@ -320,6 +322,7 @@ func init() {
|
|||||||
KeyCtrlHome: "\x1b[7^",
|
KeyCtrlHome: "\x1b[7^",
|
||||||
KeyCtrlEnd: "\x1b[8^",
|
KeyCtrlEnd: "\x1b[8^",
|
||||||
AutoMargin: true,
|
AutoMargin: true,
|
||||||
|
XTermLike: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
// rxvt-unicode terminal (X Window System)
|
// rxvt-unicode terminal (X Window System)
|
||||||
|
|||||||
+2
@@ -67,6 +67,7 @@ func init() {
|
|||||||
KeyClear: "\x1b[3;5~",
|
KeyClear: "\x1b[3;5~",
|
||||||
Modifiers: 1,
|
Modifiers: 1,
|
||||||
AutoMargin: true,
|
AutoMargin: true,
|
||||||
|
XTermLike: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
// simpleterm with 256 colors
|
// simpleterm with 256 colors
|
||||||
@@ -130,5 +131,6 @@ func init() {
|
|||||||
KeyClear: "\x1b[3;5~",
|
KeyClear: "\x1b[3;5~",
|
||||||
Modifiers: 1,
|
Modifiers: 1,
|
||||||
AutoMargin: true,
|
AutoMargin: true,
|
||||||
|
XTermLike: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+130
-59
@@ -8,64 +8,135 @@ func init() {
|
|||||||
|
|
||||||
// tmux terminal multiplexer
|
// tmux terminal multiplexer
|
||||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||||
Name: "tmux",
|
Name: "tmux",
|
||||||
Columns: 80,
|
Columns: 80,
|
||||||
Lines: 24,
|
Lines: 24,
|
||||||
Colors: 8,
|
Colors: 8,
|
||||||
Bell: "\a",
|
Bell: "\a",
|
||||||
Clear: "\x1b[H\x1b[J",
|
Clear: "\x1b[H\x1b[J",
|
||||||
EnterCA: "\x1b[?1049h",
|
EnterCA: "\x1b[?1049h",
|
||||||
ExitCA: "\x1b[?1049l",
|
ExitCA: "\x1b[?1049l",
|
||||||
ShowCursor: "\x1b[34h\x1b[?25h",
|
ShowCursor: "\x1b[34h\x1b[?25h",
|
||||||
HideCursor: "\x1b[?25l",
|
HideCursor: "\x1b[?25l",
|
||||||
AttrOff: "\x1b[m\x0f",
|
AttrOff: "\x1b[m\x0f",
|
||||||
Underline: "\x1b[4m",
|
Underline: "\x1b[4m",
|
||||||
Bold: "\x1b[1m",
|
Bold: "\x1b[1m",
|
||||||
Dim: "\x1b[2m",
|
Dim: "\x1b[2m",
|
||||||
Italic: "\x1b[3m",
|
Italic: "\x1b[3m",
|
||||||
Blink: "\x1b[5m",
|
Blink: "\x1b[5m",
|
||||||
Reverse: "\x1b[7m",
|
Reverse: "\x1b[7m",
|
||||||
EnterKeypad: "\x1b[?1h\x1b=",
|
EnterKeypad: "\x1b[?1h\x1b=",
|
||||||
ExitKeypad: "\x1b[?1l\x1b>",
|
ExitKeypad: "\x1b[?1l\x1b>",
|
||||||
SetFg: "\x1b[3%p1%dm",
|
SetFg: "\x1b[3%p1%dm",
|
||||||
SetBg: "\x1b[4%p1%dm",
|
SetBg: "\x1b[4%p1%dm",
|
||||||
SetFgBg: "\x1b[3%p1%d;4%p2%dm",
|
SetFgBg: "\x1b[3%p1%d;4%p2%dm",
|
||||||
ResetFgBg: "\x1b[39;49m",
|
ResetFgBg: "\x1b[39;49m",
|
||||||
PadChar: "\x00",
|
PadChar: "\x00",
|
||||||
AltChars: "++,,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
|
AltChars: "++,,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
|
||||||
EnterAcs: "\x0e",
|
EnterAcs: "\x0e",
|
||||||
ExitAcs: "\x0f",
|
ExitAcs: "\x0f",
|
||||||
EnableAcs: "\x1b(B\x1b)0",
|
EnableAcs: "\x1b(B\x1b)0",
|
||||||
StrikeThrough: "\x1b[9m",
|
StrikeThrough: "\x1b[9m",
|
||||||
Mouse: "\x1b[M",
|
Mouse: "\x1b[M",
|
||||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
CursorBack1: "\b",
|
CursorBack1: "\b",
|
||||||
CursorUp1: "\x1bM",
|
CursorUp1: "\x1bM",
|
||||||
KeyUp: "\x1bOA",
|
KeyUp: "\x1bOA",
|
||||||
KeyDown: "\x1bOB",
|
KeyDown: "\x1bOB",
|
||||||
KeyRight: "\x1bOC",
|
KeyRight: "\x1bOC",
|
||||||
KeyLeft: "\x1bOD",
|
KeyLeft: "\x1bOD",
|
||||||
KeyInsert: "\x1b[2~",
|
KeyInsert: "\x1b[2~",
|
||||||
KeyDelete: "\x1b[3~",
|
KeyDelete: "\x1b[3~",
|
||||||
KeyBackspace: "\x7f",
|
KeyBackspace: "\x7f",
|
||||||
KeyHome: "\x1b[1~",
|
KeyHome: "\x1b[1~",
|
||||||
KeyEnd: "\x1b[4~",
|
KeyEnd: "\x1b[4~",
|
||||||
KeyPgUp: "\x1b[5~",
|
KeyPgUp: "\x1b[5~",
|
||||||
KeyPgDn: "\x1b[6~",
|
KeyPgDn: "\x1b[6~",
|
||||||
KeyF1: "\x1bOP",
|
KeyF1: "\x1bOP",
|
||||||
KeyF2: "\x1bOQ",
|
KeyF2: "\x1bOQ",
|
||||||
KeyF3: "\x1bOR",
|
KeyF3: "\x1bOR",
|
||||||
KeyF4: "\x1bOS",
|
KeyF4: "\x1bOS",
|
||||||
KeyF5: "\x1b[15~",
|
KeyF5: "\x1b[15~",
|
||||||
KeyF6: "\x1b[17~",
|
KeyF6: "\x1b[17~",
|
||||||
KeyF7: "\x1b[18~",
|
KeyF7: "\x1b[18~",
|
||||||
KeyF8: "\x1b[19~",
|
KeyF8: "\x1b[19~",
|
||||||
KeyF9: "\x1b[20~",
|
KeyF9: "\x1b[20~",
|
||||||
KeyF10: "\x1b[21~",
|
KeyF10: "\x1b[21~",
|
||||||
KeyF11: "\x1b[23~",
|
KeyF11: "\x1b[23~",
|
||||||
KeyF12: "\x1b[24~",
|
KeyF12: "\x1b[24~",
|
||||||
KeyBacktab: "\x1b[Z",
|
KeyBacktab: "\x1b[Z",
|
||||||
Modifiers: 1,
|
Modifiers: 1,
|
||||||
AutoMargin: true,
|
AutoMargin: true,
|
||||||
|
DoubleUnderline: "\x1b[4:2m",
|
||||||
|
CurlyUnderline: "\x1b[4:3m",
|
||||||
|
DottedUnderline: "\x1b[4:4m",
|
||||||
|
DashedUnderline: "\x1b[4:5m",
|
||||||
|
})
|
||||||
|
|
||||||
|
// tmux with 256 colors
|
||||||
|
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||||
|
Name: "tmux-256color",
|
||||||
|
Columns: 80,
|
||||||
|
Lines: 24,
|
||||||
|
Colors: 256,
|
||||||
|
Bell: "\a",
|
||||||
|
Clear: "\x1b[H\x1b[J",
|
||||||
|
EnterCA: "\x1b[?1049h",
|
||||||
|
ExitCA: "\x1b[?1049l",
|
||||||
|
ShowCursor: "\x1b[34h\x1b[?25h",
|
||||||
|
HideCursor: "\x1b[?25l",
|
||||||
|
AttrOff: "\x1b[m\x0f",
|
||||||
|
Underline: "\x1b[4m",
|
||||||
|
Bold: "\x1b[1m",
|
||||||
|
Dim: "\x1b[2m",
|
||||||
|
Italic: "\x1b[3m",
|
||||||
|
Blink: "\x1b[5m",
|
||||||
|
Reverse: "\x1b[7m",
|
||||||
|
EnterKeypad: "\x1b[?1h\x1b=",
|
||||||
|
ExitKeypad: "\x1b[?1l\x1b>",
|
||||||
|
SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m",
|
||||||
|
SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m",
|
||||||
|
SetFgBg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;;%?%p2%{8}%<%t4%p2%d%e%p2%{16}%<%t10%p2%{8}%-%d%e48;5;%p2%d%;m",
|
||||||
|
ResetFgBg: "\x1b[39;49m",
|
||||||
|
PadChar: "\x00",
|
||||||
|
AltChars: "++,,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
|
||||||
|
EnterAcs: "\x0e",
|
||||||
|
ExitAcs: "\x0f",
|
||||||
|
EnableAcs: "\x1b(B\x1b)0",
|
||||||
|
StrikeThrough: "\x1b[9m",
|
||||||
|
Mouse: "\x1b[M",
|
||||||
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
|
CursorBack1: "\b",
|
||||||
|
CursorUp1: "\x1bM",
|
||||||
|
KeyUp: "\x1bOA",
|
||||||
|
KeyDown: "\x1bOB",
|
||||||
|
KeyRight: "\x1bOC",
|
||||||
|
KeyLeft: "\x1bOD",
|
||||||
|
KeyInsert: "\x1b[2~",
|
||||||
|
KeyDelete: "\x1b[3~",
|
||||||
|
KeyBackspace: "\x7f",
|
||||||
|
KeyHome: "\x1b[1~",
|
||||||
|
KeyEnd: "\x1b[4~",
|
||||||
|
KeyPgUp: "\x1b[5~",
|
||||||
|
KeyPgDn: "\x1b[6~",
|
||||||
|
KeyF1: "\x1bOP",
|
||||||
|
KeyF2: "\x1bOQ",
|
||||||
|
KeyF3: "\x1bOR",
|
||||||
|
KeyF4: "\x1bOS",
|
||||||
|
KeyF5: "\x1b[15~",
|
||||||
|
KeyF6: "\x1b[17~",
|
||||||
|
KeyF7: "\x1b[18~",
|
||||||
|
KeyF8: "\x1b[19~",
|
||||||
|
KeyF9: "\x1b[20~",
|
||||||
|
KeyF10: "\x1b[21~",
|
||||||
|
KeyF11: "\x1b[23~",
|
||||||
|
KeyF12: "\x1b[24~",
|
||||||
|
KeyBacktab: "\x1b[Z",
|
||||||
|
Modifiers: 1,
|
||||||
|
AutoMargin: true,
|
||||||
|
DoubleUnderline: "\x1b[4:2m",
|
||||||
|
CurlyUnderline: "\x1b[4:3m",
|
||||||
|
DottedUnderline: "\x1b[4:4m",
|
||||||
|
DashedUnderline: "\x1b[4:5m",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+12
@@ -227,13 +227,25 @@ type Terminfo struct {
|
|||||||
CursorSteadyUnderline string
|
CursorSteadyUnderline string
|
||||||
CursorBlinkingBar string
|
CursorBlinkingBar string
|
||||||
CursorSteadyBar string
|
CursorSteadyBar string
|
||||||
|
CursorColor string // nothing uses it yet
|
||||||
|
CursorColorRGB string // Cs (but not really because Cs uses X11 color string)
|
||||||
|
CursorColorReset string // Cr
|
||||||
EnterUrl string
|
EnterUrl string
|
||||||
ExitUrl string
|
ExitUrl string
|
||||||
SetWindowSize string
|
SetWindowSize string
|
||||||
|
SetWindowTitle string // no terminfo extension
|
||||||
EnableFocusReporting string
|
EnableFocusReporting string
|
||||||
DisableFocusReporting string
|
DisableFocusReporting string
|
||||||
DisableAutoMargin string // smam
|
DisableAutoMargin string // smam
|
||||||
EnableAutoMargin string // rmam
|
EnableAutoMargin string // rmam
|
||||||
|
DoubleUnderline string // Smulx with param 2
|
||||||
|
CurlyUnderline string // Smulx with param 3
|
||||||
|
DottedUnderline string // Smulx with param 4
|
||||||
|
DashedUnderline string // Smulx with param 5
|
||||||
|
UnderlineColor string // Setuc1
|
||||||
|
UnderlineColorRGB string // Setulc
|
||||||
|
UnderlineColorReset string // ol
|
||||||
|
XTermLike bool // (XT) has XTerm extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
+1
@@ -65,5 +65,6 @@ func init() {
|
|||||||
KeyBacktab: "\x1b[Z",
|
KeyBacktab: "\x1b[Z",
|
||||||
Modifiers: 1,
|
Modifiers: 1,
|
||||||
AutoMargin: true,
|
AutoMargin: true,
|
||||||
|
XTermLike: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -68,6 +68,7 @@ func init() {
|
|||||||
KeyBacktab: "\x1b[Z",
|
KeyBacktab: "\x1b[Z",
|
||||||
Modifiers: 1,
|
Modifiers: 1,
|
||||||
AutoMargin: true,
|
AutoMargin: true,
|
||||||
|
XTermLike: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
// xterm with 88 colors
|
// xterm with 88 colors
|
||||||
@@ -131,6 +132,7 @@ func init() {
|
|||||||
KeyBacktab: "\x1b[Z",
|
KeyBacktab: "\x1b[Z",
|
||||||
Modifiers: 1,
|
Modifiers: 1,
|
||||||
AutoMargin: true,
|
AutoMargin: true,
|
||||||
|
XTermLike: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
// xterm with 256 colors
|
// xterm with 256 colors
|
||||||
@@ -194,5 +196,6 @@ func init() {
|
|||||||
KeyBacktab: "\x1b[Z",
|
KeyBacktab: "\x1b[Z",
|
||||||
Modifiers: 1,
|
Modifiers: 1,
|
||||||
AutoMargin: true,
|
AutoMargin: true,
|
||||||
|
XTermLike: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+79
@@ -0,0 +1,79 @@
|
|||||||
|
// Generated automatically. DO NOT HAND-EDIT.
|
||||||
|
|
||||||
|
package xterm_ghostty
|
||||||
|
|
||||||
|
import "github.com/gdamore/tcell/v2/terminfo"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
|
||||||
|
// Ghostty
|
||||||
|
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||||
|
Name: "xterm-ghostty",
|
||||||
|
Aliases: []string{"ghostty"},
|
||||||
|
Columns: 80,
|
||||||
|
Lines: 24,
|
||||||
|
Colors: 256,
|
||||||
|
Bell: "\a",
|
||||||
|
Clear: "\x1b[H\x1b[2J",
|
||||||
|
EnterCA: "\x1b[?1049h",
|
||||||
|
ExitCA: "\x1b[?1049l",
|
||||||
|
ShowCursor: "\x1b[?12l\x1b[?25h",
|
||||||
|
HideCursor: "\x1b[?25l",
|
||||||
|
AttrOff: "\x1b(B\x1b[m",
|
||||||
|
Underline: "\x1b[4m",
|
||||||
|
Bold: "\x1b[1m",
|
||||||
|
Dim: "\x1b[2m",
|
||||||
|
Italic: "\x1b[3m",
|
||||||
|
Blink: "\x1b[5m",
|
||||||
|
Reverse: "\x1b[7m",
|
||||||
|
EnterKeypad: "\x1b[?1h\x1b=",
|
||||||
|
ExitKeypad: "\x1b[?1l\x1b>",
|
||||||
|
SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m",
|
||||||
|
SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m",
|
||||||
|
SetFgBg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;;%?%p2%{8}%<%t4%p2%d%e%p2%{16}%<%t10%p2%{8}%-%d%e48;5;%p2%d%;m",
|
||||||
|
ResetFgBg: "\x1b[39;49m",
|
||||||
|
AltChars: "++,,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
|
||||||
|
EnterAcs: "\x1b(0",
|
||||||
|
ExitAcs: "\x1b(B",
|
||||||
|
EnableAutoMargin: "\x1b[?7h",
|
||||||
|
DisableAutoMargin: "\x1b[?7l",
|
||||||
|
StrikeThrough: "\x1b[9m",
|
||||||
|
Mouse: "\x1b[<",
|
||||||
|
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||||
|
CursorBack1: "\b",
|
||||||
|
CursorUp1: "\x1b[A",
|
||||||
|
KeyUp: "\x1bOA",
|
||||||
|
KeyDown: "\x1bOB",
|
||||||
|
KeyRight: "\x1bOC",
|
||||||
|
KeyLeft: "\x1bOD",
|
||||||
|
KeyInsert: "\x1b[2~",
|
||||||
|
KeyDelete: "\x1b[3~",
|
||||||
|
KeyBackspace: "\x7f",
|
||||||
|
KeyHome: "\x1bOH",
|
||||||
|
KeyEnd: "\x1bOF",
|
||||||
|
KeyPgUp: "\x1b[5~",
|
||||||
|
KeyPgDn: "\x1b[6~",
|
||||||
|
KeyF1: "\x1bOP",
|
||||||
|
KeyF2: "\x1bOQ",
|
||||||
|
KeyF3: "\x1bOR",
|
||||||
|
KeyF4: "\x1bOS",
|
||||||
|
KeyF5: "\x1b[15~",
|
||||||
|
KeyF6: "\x1b[17~",
|
||||||
|
KeyF7: "\x1b[18~",
|
||||||
|
KeyF8: "\x1b[19~",
|
||||||
|
KeyF9: "\x1b[20~",
|
||||||
|
KeyF10: "\x1b[21~",
|
||||||
|
KeyF11: "\x1b[23~",
|
||||||
|
KeyF12: "\x1b[24~",
|
||||||
|
KeyBacktab: "\x1b[Z",
|
||||||
|
Modifiers: 1,
|
||||||
|
TrueColor: true,
|
||||||
|
AutoMargin: true,
|
||||||
|
InsertChar: "\x1b[@",
|
||||||
|
DoubleUnderline: "\x1b[4:2m",
|
||||||
|
CurlyUnderline: "\x1b[4:3m",
|
||||||
|
DottedUnderline: "\x1b[4:4m",
|
||||||
|
DashedUnderline: "\x1b[4:5m",
|
||||||
|
XTermLike: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
+4
@@ -67,5 +67,9 @@ func init() {
|
|||||||
Modifiers: 1,
|
Modifiers: 1,
|
||||||
TrueColor: true,
|
TrueColor: true,
|
||||||
AutoMargin: true,
|
AutoMargin: true,
|
||||||
|
DoubleUnderline: "\x1b[4:2m",
|
||||||
|
CurlyUnderline: "\x1b[4:3m",
|
||||||
|
DottedUnderline: "\x1b[4:4m",
|
||||||
|
DashedUnderline: "\x1b[4:5m",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -27,9 +27,14 @@ import (
|
|||||||
// will be automatically included anyway.
|
// will be automatically included anyway.
|
||||||
"github.com/gdamore/tcell/v2/terminfo"
|
"github.com/gdamore/tcell/v2/terminfo"
|
||||||
"github.com/gdamore/tcell/v2/terminfo/dynamic"
|
"github.com/gdamore/tcell/v2/terminfo/dynamic"
|
||||||
|
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func loadDynamicTerminfo(term string) (*terminfo.Terminfo, error) {
|
func loadDynamicTerminfo(term string) (*terminfo.Terminfo, error) {
|
||||||
|
if term == "" {
|
||||||
|
return nil, fmt.Errorf("%w: term not set", ErrTermNotFound)
|
||||||
|
}
|
||||||
ti, _, e := dynamic.LoadTerminfo(term)
|
ti, _, e := dynamic.LoadTerminfo(term)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return nil, e
|
return nil, e
|
||||||
|
|||||||
+253
-15
@@ -19,6 +19,7 @@ package tcell
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
@@ -32,9 +33,6 @@ import (
|
|||||||
"golang.org/x/text/transform"
|
"golang.org/x/text/transform"
|
||||||
|
|
||||||
"github.com/gdamore/tcell/v2/terminfo"
|
"github.com/gdamore/tcell/v2/terminfo"
|
||||||
|
|
||||||
// import the stock terminals
|
|
||||||
_ "github.com/gdamore/tcell/v2/terminfo/base"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewTerminfoScreen returns a Screen that uses the stock TTY interface
|
// NewTerminfoScreen returns a Screen that uses the stock TTY interface
|
||||||
@@ -154,8 +152,18 @@ type tScreen struct {
|
|||||||
setWinSize string
|
setWinSize string
|
||||||
enableFocus string
|
enableFocus string
|
||||||
disableFocus string
|
disableFocus string
|
||||||
|
doubleUnder string
|
||||||
|
curlyUnder string
|
||||||
|
dottedUnder string
|
||||||
|
dashedUnder string
|
||||||
|
underColor string
|
||||||
|
underRGB string
|
||||||
|
underFg string
|
||||||
cursorStyles map[CursorStyle]string
|
cursorStyles map[CursorStyle]string
|
||||||
cursorStyle CursorStyle
|
cursorStyle CursorStyle
|
||||||
|
cursorColor Color
|
||||||
|
cursorRGB string
|
||||||
|
cursorFg string
|
||||||
saved *term.State
|
saved *term.State
|
||||||
stopQ chan struct{}
|
stopQ chan struct{}
|
||||||
eventQ chan Event
|
eventQ chan Event
|
||||||
@@ -164,6 +172,11 @@ type tScreen struct {
|
|||||||
mouseFlags MouseFlags
|
mouseFlags MouseFlags
|
||||||
pasteEnabled bool
|
pasteEnabled bool
|
||||||
focusEnabled bool
|
focusEnabled bool
|
||||||
|
setTitle string
|
||||||
|
saveTitle string
|
||||||
|
restoreTitle string
|
||||||
|
title string
|
||||||
|
setClipboard string
|
||||||
|
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
@@ -338,7 +351,7 @@ func (t *tScreen) prepareBracketedPaste() {
|
|||||||
t.disablePaste = t.ti.DisablePaste
|
t.disablePaste = t.ti.DisablePaste
|
||||||
t.prepareKey(keyPasteStart, t.ti.PasteStart)
|
t.prepareKey(keyPasteStart, t.ti.PasteStart)
|
||||||
t.prepareKey(keyPasteEnd, t.ti.PasteEnd)
|
t.prepareKey(keyPasteEnd, t.ti.PasteEnd)
|
||||||
} else if t.ti.Mouse != "" {
|
} else if t.ti.Mouse != "" || t.ti.XTermLike {
|
||||||
t.enablePaste = "\x1b[?2004h"
|
t.enablePaste = "\x1b[?2004h"
|
||||||
t.disablePaste = "\x1b[?2004l"
|
t.disablePaste = "\x1b[?2004l"
|
||||||
t.prepareKey(keyPasteStart, "\x1b[200~")
|
t.prepareKey(keyPasteStart, "\x1b[200~")
|
||||||
@@ -346,6 +359,54 @@ func (t *tScreen) prepareBracketedPaste() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *tScreen) prepareUnderlines() {
|
||||||
|
if t.ti.DoubleUnderline != "" {
|
||||||
|
t.doubleUnder = t.ti.DoubleUnderline
|
||||||
|
} else if t.ti.XTermLike {
|
||||||
|
t.doubleUnder = "\x1b[4:2m"
|
||||||
|
}
|
||||||
|
if t.ti.CurlyUnderline != "" {
|
||||||
|
t.curlyUnder = t.ti.CurlyUnderline
|
||||||
|
} else if t.ti.XTermLike {
|
||||||
|
t.curlyUnder = "\x1b[4:3m"
|
||||||
|
}
|
||||||
|
if t.ti.DottedUnderline != "" {
|
||||||
|
t.dottedUnder = t.ti.DottedUnderline
|
||||||
|
} else if t.ti.XTermLike {
|
||||||
|
t.dottedUnder = "\x1b[4:4m"
|
||||||
|
}
|
||||||
|
if t.ti.DashedUnderline != "" {
|
||||||
|
t.dashedUnder = t.ti.DashedUnderline
|
||||||
|
} else if t.ti.XTermLike {
|
||||||
|
t.dashedUnder = "\x1b[4:5m"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Underline colors. We're not going to rely upon terminfo for this
|
||||||
|
// Essentially all terminals that support the curly underlines are
|
||||||
|
// expected to also support coloring them too - which reflects actual
|
||||||
|
// practice since these were introduced at about the same time.
|
||||||
|
if t.ti.UnderlineColor != "" {
|
||||||
|
t.underColor = t.ti.UnderlineColor
|
||||||
|
} else if t.ti.CurlyUnderline != "" {
|
||||||
|
t.underColor = "\x1b[58:5:%p1%dm"
|
||||||
|
}
|
||||||
|
if t.ti.UnderlineColorRGB != "" {
|
||||||
|
// An interesting wart here is that in order to facilitate
|
||||||
|
// using just a single parameter, the Setulc parameter takes
|
||||||
|
// the 24-bit color as an integer rather than separate bytes.
|
||||||
|
// This matches the "new" style direct color approach that
|
||||||
|
// ncurses took, even though everyone else when another way.
|
||||||
|
t.underRGB = t.ti.UnderlineColorRGB
|
||||||
|
} else if t.ti.CurlyUnderline != "" {
|
||||||
|
t.underRGB = "\x1b[58:2::%p1%d:%p2%d:%p3%dm"
|
||||||
|
}
|
||||||
|
if t.ti.UnderlineColorReset != "" {
|
||||||
|
t.underFg = t.ti.UnderlineColorReset
|
||||||
|
} else if t.ti.CurlyUnderline != "" {
|
||||||
|
t.underFg = "\x1b[59m"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (t *tScreen) prepareExtendedOSC() {
|
func (t *tScreen) prepareExtendedOSC() {
|
||||||
// Linux is a special beast - because it has a mouse entry, but does
|
// Linux is a special beast - because it has a mouse entry, but does
|
||||||
// not swallow these OSC commands properly.
|
// not swallow these OSC commands properly.
|
||||||
@@ -359,27 +420,43 @@ func (t *tScreen) prepareExtendedOSC() {
|
|||||||
if t.ti.EnterUrl != "" {
|
if t.ti.EnterUrl != "" {
|
||||||
t.enterUrl = t.ti.EnterUrl
|
t.enterUrl = t.ti.EnterUrl
|
||||||
t.exitUrl = t.ti.ExitUrl
|
t.exitUrl = t.ti.ExitUrl
|
||||||
} else if t.ti.Mouse != "" {
|
} else if t.ti.Mouse != "" || t.ti.XTermLike {
|
||||||
t.enterUrl = "\x1b]8;%p2%s;%p1%s\x1b\\"
|
t.enterUrl = "\x1b]8;%p2%s;%p1%s\x1b\\"
|
||||||
t.exitUrl = "\x1b]8;;\x1b\\"
|
t.exitUrl = "\x1b]8;;\x1b\\"
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.ti.SetWindowSize != "" {
|
if t.ti.SetWindowSize != "" {
|
||||||
t.setWinSize = t.ti.SetWindowSize
|
t.setWinSize = t.ti.SetWindowSize
|
||||||
} else if t.ti.Mouse != "" {
|
} else if t.ti.Mouse != "" || t.ti.XTermLike {
|
||||||
t.setWinSize = "\x1b[8;%p1%p2%d;%dt"
|
t.setWinSize = "\x1b[8;%p1%p2%d;%dt"
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.ti.EnableFocusReporting != "" {
|
if t.ti.EnableFocusReporting != "" {
|
||||||
t.enableFocus = t.ti.EnableFocusReporting
|
t.enableFocus = t.ti.EnableFocusReporting
|
||||||
} else if t.ti.Mouse != "" {
|
} else if t.ti.Mouse != "" || t.ti.XTermLike {
|
||||||
t.enableFocus = "\x1b[?1004h"
|
t.enableFocus = "\x1b[?1004h"
|
||||||
}
|
}
|
||||||
if t.ti.DisableFocusReporting != "" {
|
if t.ti.DisableFocusReporting != "" {
|
||||||
t.disableFocus = t.ti.DisableFocusReporting
|
t.disableFocus = t.ti.DisableFocusReporting
|
||||||
} else if t.ti.Mouse != "" {
|
} else if t.ti.Mouse != "" || t.ti.XTermLike {
|
||||||
t.disableFocus = "\x1b[?1004l"
|
t.disableFocus = "\x1b[?1004l"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if t.ti.SetWindowTitle != "" {
|
||||||
|
t.setTitle = t.ti.SetWindowTitle
|
||||||
|
} else if t.ti.XTermLike {
|
||||||
|
t.saveTitle = "\x1b[22;2t"
|
||||||
|
t.restoreTitle = "\x1b[23;2t"
|
||||||
|
// this also tries to request that UTF-8 is allowed in the title
|
||||||
|
t.setTitle = "\x1b[>2t\x1b]2;%p1%s\x1b\\"
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.setClipboard == "" && t.ti.XTermLike {
|
||||||
|
// this string takes a base64 string and sends it to the clipboard.
|
||||||
|
// it will also be able to retrieve the clipboard using "?" as the
|
||||||
|
// sent string, when we support that.
|
||||||
|
t.setClipboard = "\x1b]52;c;%p1%s\x1b\\"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tScreen) prepareCursorStyles() {
|
func (t *tScreen) prepareCursorStyles() {
|
||||||
@@ -397,7 +474,7 @@ func (t *tScreen) prepareCursorStyles() {
|
|||||||
CursorStyleBlinkingBar: t.ti.CursorBlinkingBar,
|
CursorStyleBlinkingBar: t.ti.CursorBlinkingBar,
|
||||||
CursorStyleSteadyBar: t.ti.CursorSteadyBar,
|
CursorStyleSteadyBar: t.ti.CursorSteadyBar,
|
||||||
}
|
}
|
||||||
} else if t.ti.Mouse != "" {
|
} else if t.ti.Mouse != "" || t.ti.XTermLike {
|
||||||
t.cursorStyles = map[CursorStyle]string{
|
t.cursorStyles = map[CursorStyle]string{
|
||||||
CursorStyleDefault: "\x1b[0 q",
|
CursorStyleDefault: "\x1b[0 q",
|
||||||
CursorStyleBlinkingBlock: "\x1b[1 q",
|
CursorStyleBlinkingBlock: "\x1b[1 q",
|
||||||
@@ -408,6 +485,20 @@ func (t *tScreen) prepareCursorStyles() {
|
|||||||
CursorStyleSteadyBar: "\x1b[6 q",
|
CursorStyleSteadyBar: "\x1b[6 q",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if t.ti.CursorColorRGB != "" {
|
||||||
|
// if it was X11 style with just a single %p1%s, then convert
|
||||||
|
t.cursorRGB = t.ti.CursorColorRGB
|
||||||
|
}
|
||||||
|
if t.ti.CursorColorReset != "" {
|
||||||
|
t.cursorFg = t.ti.CursorColorReset
|
||||||
|
}
|
||||||
|
if t.cursorRGB == "" {
|
||||||
|
t.cursorRGB = "\x1b]12;%p1%s\007"
|
||||||
|
t.cursorFg = "\x1b]112\007"
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert XTERM style color names to RGB color code. We have no way to do palette colors
|
||||||
|
t.cursorRGB = strings.Replace(t.cursorRGB, "%p1%s", "#%p1%02x%p2%02x%p3%02x", 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tScreen) prepareKey(key Key, val string) {
|
func (t *tScreen) prepareKey(key Key, val string) {
|
||||||
@@ -416,6 +507,11 @@ func (t *tScreen) prepareKey(key Key, val string) {
|
|||||||
|
|
||||||
func (t *tScreen) prepareKeys() {
|
func (t *tScreen) prepareKeys() {
|
||||||
ti := t.ti
|
ti := t.ti
|
||||||
|
if strings.HasPrefix(ti.Name, "xterm") {
|
||||||
|
// assume its some form of XTerm clone
|
||||||
|
t.ti.XTermLike = true
|
||||||
|
ti.XTermLike = true
|
||||||
|
}
|
||||||
t.prepareKey(KeyBackspace, ti.KeyBackspace)
|
t.prepareKey(KeyBackspace, ti.KeyBackspace)
|
||||||
t.prepareKey(KeyF1, ti.KeyF1)
|
t.prepareKey(KeyF1, ti.KeyF1)
|
||||||
t.prepareKey(KeyF2, ti.KeyF2)
|
t.prepareKey(KeyF2, ti.KeyF2)
|
||||||
@@ -550,6 +646,7 @@ func (t *tScreen) prepareKeys() {
|
|||||||
t.prepareXtermModifiers()
|
t.prepareXtermModifiers()
|
||||||
t.prepareBracketedPaste()
|
t.prepareBracketedPaste()
|
||||||
t.prepareCursorStyles()
|
t.prepareCursorStyles()
|
||||||
|
t.prepareUnderlines()
|
||||||
t.prepareExtendedOSC()
|
t.prepareExtendedOSC()
|
||||||
|
|
||||||
outer:
|
outer:
|
||||||
@@ -742,7 +839,7 @@ func (t *tScreen) drawCell(x, y int) int {
|
|||||||
style = t.style
|
style = t.style
|
||||||
}
|
}
|
||||||
if style != t.curstyle {
|
if style != t.curstyle {
|
||||||
fg, bg, attrs := style.Decompose()
|
fg, bg, attrs := style.fg, style.bg, style.attrs
|
||||||
|
|
||||||
t.TPuts(ti.AttrOff)
|
t.TPuts(ti.AttrOff)
|
||||||
|
|
||||||
@@ -750,8 +847,39 @@ func (t *tScreen) drawCell(x, y int) int {
|
|||||||
if attrs&AttrBold != 0 {
|
if attrs&AttrBold != 0 {
|
||||||
t.TPuts(ti.Bold)
|
t.TPuts(ti.Bold)
|
||||||
}
|
}
|
||||||
if attrs&AttrUnderline != 0 {
|
if us, uc := style.ulStyle, style.ulColor; us != UnderlineStyleNone {
|
||||||
t.TPuts(ti.Underline)
|
if t.underColor != "" || t.underRGB != "" {
|
||||||
|
if uc == ColorReset {
|
||||||
|
t.TPuts(t.underFg)
|
||||||
|
} else if uc.IsRGB() {
|
||||||
|
if t.underRGB != "" {
|
||||||
|
r, g, b := uc.RGB()
|
||||||
|
t.TPuts(ti.TParm(t.underRGB, int(r), int(g), int(b)))
|
||||||
|
} else {
|
||||||
|
if v, ok := t.colors[uc]; ok {
|
||||||
|
uc = v
|
||||||
|
} else {
|
||||||
|
v = FindColor(uc, t.palette)
|
||||||
|
t.colors[uc] = v
|
||||||
|
uc = v
|
||||||
|
}
|
||||||
|
t.TPuts(ti.TParm(t.underColor, int(uc&0xff)))
|
||||||
|
}
|
||||||
|
} else if uc.Valid() {
|
||||||
|
t.TPuts(ti.TParm(t.underColor, int(uc&0xff)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.TPuts(ti.Underline) // to ensure everyone gets at least a basic underline
|
||||||
|
switch us {
|
||||||
|
case UnderlineStyleDouble:
|
||||||
|
t.TPuts(t.doubleUnder)
|
||||||
|
case UnderlineStyleCurly:
|
||||||
|
t.TPuts(t.curlyUnder)
|
||||||
|
case UnderlineStyleDotted:
|
||||||
|
t.TPuts(t.dottedUnder)
|
||||||
|
case UnderlineStyleDashed:
|
||||||
|
t.TPuts(t.dashedUnder)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if attrs&AttrReverse != 0 {
|
if attrs&AttrReverse != 0 {
|
||||||
t.TPuts(ti.Reverse)
|
t.TPuts(ti.Reverse)
|
||||||
@@ -827,9 +955,10 @@ func (t *tScreen) ShowCursor(x, y int) {
|
|||||||
t.Unlock()
|
t.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tScreen) SetCursorStyle(cs CursorStyle) {
|
func (t *tScreen) SetCursor(cs CursorStyle, cc Color) {
|
||||||
t.Lock()
|
t.Lock()
|
||||||
t.cursorStyle = cs
|
t.cursorStyle = cs
|
||||||
|
t.cursorColor = cc
|
||||||
t.Unlock()
|
t.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -852,6 +981,14 @@ func (t *tScreen) showCursor() {
|
|||||||
t.TPuts(esc)
|
t.TPuts(esc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if t.cursorRGB != "" {
|
||||||
|
if t.cursorColor == ColorReset {
|
||||||
|
t.TPuts(t.cursorFg)
|
||||||
|
} else if t.cursorColor.Valid() {
|
||||||
|
r, g, b := t.cursorColor.RGB()
|
||||||
|
t.TPuts(t.ti.TParm(t.cursorRGB, int(r), int(g), int(b)))
|
||||||
|
}
|
||||||
|
}
|
||||||
t.cx = x
|
t.cx = x
|
||||||
t.cy = y
|
t.cy = y
|
||||||
}
|
}
|
||||||
@@ -890,8 +1027,7 @@ func (t *tScreen) Show() {
|
|||||||
func (t *tScreen) clearScreen() {
|
func (t *tScreen) clearScreen() {
|
||||||
t.TPuts(t.ti.AttrOff)
|
t.TPuts(t.ti.AttrOff)
|
||||||
t.TPuts(t.exitUrl)
|
t.TPuts(t.exitUrl)
|
||||||
fg, bg, _ := t.style.Decompose()
|
_ = t.sendFgBg(t.style.fg, t.style.bg, AttrNone)
|
||||||
_ = t.sendFgBg(fg, bg, AttrNone)
|
|
||||||
t.TPuts(t.ti.Clear)
|
t.TPuts(t.ti.Clear)
|
||||||
t.clear = false
|
t.clear = false
|
||||||
}
|
}
|
||||||
@@ -1376,6 +1512,61 @@ func (t *tScreen) parseFocus(buf *bytes.Buffer, evs *[]Event) (bool, bool) {
|
|||||||
return true, false
|
return true, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *tScreen) parseClipboard(buf *bytes.Buffer, evs *[]Event) (bool, bool) {
|
||||||
|
b := buf.Bytes()
|
||||||
|
state := 0
|
||||||
|
prefix := []byte("\x1b]52;c;")
|
||||||
|
|
||||||
|
if len(prefix) >= len(b) {
|
||||||
|
if bytes.HasPrefix(prefix, b) {
|
||||||
|
// inconclusive so far
|
||||||
|
return true, false
|
||||||
|
}
|
||||||
|
// definitely not a match
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
b = b[len(prefix):]
|
||||||
|
|
||||||
|
for _, c := range b {
|
||||||
|
// valid base64 digits
|
||||||
|
if (state == 0) {
|
||||||
|
if (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c == '+') || (c == '/') || (c == '=') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (c == '\x1b') {
|
||||||
|
state = 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (c == '\a') {
|
||||||
|
// matched with BEL instead of ST
|
||||||
|
b = b[:len(b)-1] // drop the trailing BEL
|
||||||
|
decoded := make([]byte, base64.StdEncoding.DecodedLen(len(b)))
|
||||||
|
if num, err := base64.StdEncoding.Decode(decoded, b); err == nil {
|
||||||
|
*evs = append(*evs, NewEventClipboard(decoded[:num]))
|
||||||
|
}
|
||||||
|
_, _ = buf.ReadBytes('\a')
|
||||||
|
return true, true
|
||||||
|
}
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
if (state == 1) {
|
||||||
|
if (c == '\\') {
|
||||||
|
b = b[:len(b)-2] // drop the trailing ST (\x1b\\)
|
||||||
|
// now decode the data
|
||||||
|
decoded := make([]byte, base64.StdEncoding.DecodedLen(len(b)))
|
||||||
|
if num, err := base64.StdEncoding.Decode(decoded, b); err == nil {
|
||||||
|
*evs = append(*evs, NewEventClipboard(decoded[:num]))
|
||||||
|
}
|
||||||
|
_, _ = buf.ReadBytes('\\')
|
||||||
|
return true, true
|
||||||
|
}
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// not enough data yet (not terminated)
|
||||||
|
return true, false
|
||||||
|
}
|
||||||
|
|
||||||
// parseXtermMouse is like parseSgrMouse, but it parses a legacy
|
// parseXtermMouse is like parseSgrMouse, but it parses a legacy
|
||||||
// X11 mouse record.
|
// X11 mouse record.
|
||||||
func (t *tScreen) parseXtermMouse(buf *bytes.Buffer, evs *[]Event) (bool, bool) {
|
func (t *tScreen) parseXtermMouse(buf *bytes.Buffer, evs *[]Event) (bool, bool) {
|
||||||
@@ -1579,6 +1770,14 @@ func (t *tScreen) collectEventsFromInput(buf *bytes.Buffer, expire bool) []Event
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if t.setClipboard != "" {
|
||||||
|
if part, comp := t.parseClipboard(buf, &res); comp {
|
||||||
|
continue
|
||||||
|
} else if part {
|
||||||
|
partials++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if partials == 0 || expire {
|
if partials == 0 || expire {
|
||||||
if b[0] == '\x1b' {
|
if b[0] == '\x1b' {
|
||||||
if len(b) == 1 {
|
if len(b) == 1 {
|
||||||
@@ -1829,12 +2028,18 @@ func (t *tScreen) engage() error {
|
|||||||
// (In theory there could be terminals that don't support X,Y cursor
|
// (In theory there could be terminals that don't support X,Y cursor
|
||||||
// positions without a setup command, but we don't support them.)
|
// positions without a setup command, but we don't support them.)
|
||||||
t.TPuts(ti.EnterCA)
|
t.TPuts(ti.EnterCA)
|
||||||
|
if t.saveTitle != "" {
|
||||||
|
t.TPuts(t.saveTitle)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
t.TPuts(ti.EnterKeypad)
|
t.TPuts(ti.EnterKeypad)
|
||||||
t.TPuts(ti.HideCursor)
|
t.TPuts(ti.HideCursor)
|
||||||
t.TPuts(ti.EnableAcs)
|
t.TPuts(ti.EnableAcs)
|
||||||
t.TPuts(ti.DisableAutoMargin)
|
t.TPuts(ti.DisableAutoMargin)
|
||||||
t.TPuts(ti.Clear)
|
t.TPuts(ti.Clear)
|
||||||
|
if t.title != "" && t.setTitle != "" {
|
||||||
|
t.TPuts(t.ti.TParm(t.setTitle, t.title))
|
||||||
|
}
|
||||||
|
|
||||||
t.wg.Add(2)
|
t.wg.Add(2)
|
||||||
go t.inputLoop(stopQ)
|
go t.inputLoop(stopQ)
|
||||||
@@ -1870,11 +2075,17 @@ func (t *tScreen) disengage() {
|
|||||||
if t.cursorStyles != nil && t.cursorStyle != CursorStyleDefault {
|
if t.cursorStyles != nil && t.cursorStyle != CursorStyleDefault {
|
||||||
t.TPuts(t.cursorStyles[CursorStyleDefault])
|
t.TPuts(t.cursorStyles[CursorStyleDefault])
|
||||||
}
|
}
|
||||||
|
if t.cursorFg != "" && t.cursorColor.Valid() {
|
||||||
|
t.TPuts(t.cursorFg)
|
||||||
|
}
|
||||||
t.TPuts(ti.ResetFgBg)
|
t.TPuts(ti.ResetFgBg)
|
||||||
t.TPuts(ti.AttrOff)
|
t.TPuts(ti.AttrOff)
|
||||||
t.TPuts(ti.ExitKeypad)
|
t.TPuts(ti.ExitKeypad)
|
||||||
t.TPuts(ti.EnableAutoMargin)
|
t.TPuts(ti.EnableAutoMargin)
|
||||||
if os.Getenv("TCELL_ALTSCREEN") != "disable" {
|
if os.Getenv("TCELL_ALTSCREEN") != "disable" {
|
||||||
|
if t.restoreTitle != "" {
|
||||||
|
t.TPuts(t.restoreTitle)
|
||||||
|
}
|
||||||
t.TPuts(ti.Clear) // only needed if ExitCA is empty
|
t.TPuts(ti.Clear) // only needed if ExitCA is empty
|
||||||
t.TPuts(ti.ExitCA)
|
t.TPuts(ti.ExitCA)
|
||||||
}
|
}
|
||||||
@@ -1909,3 +2120,30 @@ func (t *tScreen) EventQ() chan Event {
|
|||||||
func (t *tScreen) GetCells() *CellBuffer {
|
func (t *tScreen) GetCells() *CellBuffer {
|
||||||
return &t.cells
|
return &t.cells
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *tScreen) SetTitle(title string) {
|
||||||
|
t.Lock()
|
||||||
|
t.title = title
|
||||||
|
if t.setTitle != "" && t.running {
|
||||||
|
t.TPuts(t.ti.TParm(t.setTitle, title))
|
||||||
|
}
|
||||||
|
t.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tScreen) SetClipboard(data []byte) {
|
||||||
|
// Post binary data to the system clipboard. It might be UTF-8, it might not be.
|
||||||
|
t.Lock()
|
||||||
|
if t.setClipboard != "" {
|
||||||
|
encoded := base64.StdEncoding.EncodeToString(data)
|
||||||
|
t.TPuts(t.ti.TParm(t.setClipboard, encoded))
|
||||||
|
}
|
||||||
|
t.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tScreen) GetClipboard() {
|
||||||
|
t.Lock()
|
||||||
|
if t.setClipboard != "" {
|
||||||
|
t.TPuts(t.ti.TParm(t.setClipboard, "?"))
|
||||||
|
}
|
||||||
|
t.Unlock()
|
||||||
|
}
|
||||||
|
|||||||
+6
-1
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2021 The TCell Authors
|
// Copyright 2024 The TCell Authors
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use file except in compliance with the License.
|
// you may not use file except in compliance with the License.
|
||||||
@@ -17,6 +17,11 @@
|
|||||||
|
|
||||||
package tcell
|
package tcell
|
||||||
|
|
||||||
|
import (
|
||||||
|
// import the stock terminals
|
||||||
|
_ "github.com/gdamore/tcell/v2/terminfo/base"
|
||||||
|
)
|
||||||
|
|
||||||
// initialize is used at application startup, and sets up the initial values
|
// initialize is used at application startup, and sets up the initial values
|
||||||
// including file descriptors used for terminals and saving the initial state
|
// including file descriptors used for terminals and saving the initial state
|
||||||
// so that it can be restored when the application terminates.
|
// so that it can be restored when the application terminates.
|
||||||
|
|||||||
+29
-8
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2023 The TCell Authors
|
// Copyright 2024 The TCell Authors
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use file except in compliance with the License.
|
// you may not use file except in compliance with the License.
|
||||||
@@ -19,11 +19,13 @@ package tcell
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/gdamore/tcell/v2/terminfo"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall/js"
|
"syscall/js"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/gdamore/tcell/v2/terminfo"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewTerminfoScreen() (Screen, error) {
|
func NewTerminfoScreen() (Screen, error) {
|
||||||
@@ -66,6 +68,9 @@ func (t *wScreen) Init() error {
|
|||||||
t.Unlock()
|
t.Unlock()
|
||||||
|
|
||||||
js.Global().Set("onKeyEvent", js.FuncOf(t.onKeyEvent))
|
js.Global().Set("onKeyEvent", js.FuncOf(t.onKeyEvent))
|
||||||
|
js.Global().Set("onMouseClick", js.FuncOf(t.unset))
|
||||||
|
js.Global().Set("onMouseMove", js.FuncOf(t.unset))
|
||||||
|
js.Global().Set("onFocus", js.FuncOf(t.unset))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -133,14 +138,23 @@ func (t *wScreen) drawCell(x, y int) int {
|
|||||||
if bg == -1 {
|
if bg == -1 {
|
||||||
bg = 0x000000
|
bg = 0x000000
|
||||||
}
|
}
|
||||||
|
us, uc := style.ulStyle, paletteColor(style.ulColor)
|
||||||
|
if uc == -1 {
|
||||||
|
uc = 0x000000
|
||||||
|
}
|
||||||
|
|
||||||
var combcarr []interface{} = make([]interface{}, len(combc))
|
s := ""
|
||||||
for i, c := range combc {
|
if len(combc) > 0 {
|
||||||
combcarr[i] = c
|
b := make([]rune, 0, 1 + len(combc))
|
||||||
|
b = append(b, mainc)
|
||||||
|
b = append(b, combc...)
|
||||||
|
s = string(b)
|
||||||
|
} else {
|
||||||
|
s = string(mainc)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.cells.SetDirty(x, y, false)
|
t.cells.SetDirty(x, y, false)
|
||||||
js.Global().Call("drawCell", x, y, mainc, combcarr, fg, bg, int(style.attrs))
|
js.Global().Call("drawCell", x, y, s, fg, bg, int(style.attrs), int(us), int(uc))
|
||||||
|
|
||||||
return width
|
return width
|
||||||
}
|
}
|
||||||
@@ -151,9 +165,12 @@ func (t *wScreen) ShowCursor(x, y int) {
|
|||||||
t.Unlock()
|
t.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *wScreen) SetCursorStyle(cs CursorStyle) {
|
func (t *wScreen) SetCursor(cs CursorStyle, cc Color) {
|
||||||
|
if !cc.Valid() {
|
||||||
|
cc = ColorLightGray
|
||||||
|
}
|
||||||
t.Lock()
|
t.Lock()
|
||||||
js.Global().Call("setCursorStyle", curStyleClasses[cs])
|
js.Global().Call("setCursorStyle", curStyleClasses[cs], fmt.Sprintf("#%06x", cc.Hex()))
|
||||||
t.Unlock()
|
t.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -511,6 +528,10 @@ func (t *wScreen) StopQ() <-chan struct{} {
|
|||||||
return t.quit
|
return t.quit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *wScreen) SetTitle(title string) {
|
||||||
|
js.Global().Call("setTitle", title)
|
||||||
|
}
|
||||||
|
|
||||||
// WebKeyNames maps string names reported from HTML
|
// WebKeyNames maps string names reported from HTML
|
||||||
// (KeyboardEvent.key) to tcell accepted keys.
|
// (KeyboardEvent.key) to tcell accepted keys.
|
||||||
var WebKeyNames = map[string]Key{
|
var WebKeyNames = map[string]Key{
|
||||||
|
|||||||
Vendored
+3
-4
@@ -37,7 +37,7 @@ github.com/fatih/color
|
|||||||
# github.com/gdamore/encoding v1.0.1
|
# github.com/gdamore/encoding v1.0.1
|
||||||
## explicit; go 1.9
|
## explicit; go 1.9
|
||||||
github.com/gdamore/encoding
|
github.com/gdamore/encoding
|
||||||
# github.com/gdamore/tcell/v2 v2.7.4
|
# github.com/gdamore/tcell/v2 v2.8.0
|
||||||
## explicit; go 1.12
|
## explicit; go 1.12
|
||||||
github.com/gdamore/tcell/v2
|
github.com/gdamore/tcell/v2
|
||||||
github.com/gdamore/tcell/v2/terminfo
|
github.com/gdamore/tcell/v2/terminfo
|
||||||
@@ -75,6 +75,7 @@ github.com/gdamore/tcell/v2/terminfo/w/wy60
|
|||||||
github.com/gdamore/tcell/v2/terminfo/w/wy99_ansi
|
github.com/gdamore/tcell/v2/terminfo/w/wy99_ansi
|
||||||
github.com/gdamore/tcell/v2/terminfo/x/xfce
|
github.com/gdamore/tcell/v2/terminfo/x/xfce
|
||||||
github.com/gdamore/tcell/v2/terminfo/x/xterm
|
github.com/gdamore/tcell/v2/terminfo/x/xterm
|
||||||
|
github.com/gdamore/tcell/v2/terminfo/x/xterm_ghostty
|
||||||
github.com/gdamore/tcell/v2/terminfo/x/xterm_kitty
|
github.com/gdamore/tcell/v2/terminfo/x/xterm_kitty
|
||||||
# github.com/go-errors/errors v1.5.1
|
# github.com/go-errors/errors v1.5.1
|
||||||
## explicit; go 1.14
|
## explicit; go 1.14
|
||||||
@@ -105,8 +106,6 @@ github.com/gobwas/glob/syntax/ast
|
|||||||
github.com/gobwas/glob/syntax/lexer
|
github.com/gobwas/glob/syntax/lexer
|
||||||
github.com/gobwas/glob/util/runes
|
github.com/gobwas/glob/util/runes
|
||||||
github.com/gobwas/glob/util/strings
|
github.com/gobwas/glob/util/strings
|
||||||
# github.com/google/go-cmp v0.5.6
|
|
||||||
## explicit; go 1.8
|
|
||||||
# github.com/gookit/color v1.4.2
|
# github.com/gookit/color v1.4.2
|
||||||
## explicit; go 1.12
|
## explicit; go 1.12
|
||||||
github.com/gookit/color
|
github.com/gookit/color
|
||||||
@@ -172,7 +171,7 @@ github.com/jesseduffield/go-git/v5/utils/merkletrie/filesystem
|
|||||||
github.com/jesseduffield/go-git/v5/utils/merkletrie/index
|
github.com/jesseduffield/go-git/v5/utils/merkletrie/index
|
||||||
github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame
|
github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame
|
||||||
github.com/jesseduffield/go-git/v5/utils/merkletrie/noder
|
github.com/jesseduffield/go-git/v5/utils/merkletrie/noder
|
||||||
# github.com/jesseduffield/gocui v0.3.1-0.20250107151125-716b1eb82fb4
|
# github.com/jesseduffield/gocui v0.3.1-0.20250111205211-82d518436b5a
|
||||||
## explicit; go 1.12
|
## explicit; go 1.12
|
||||||
github.com/jesseduffield/gocui
|
github.com/jesseduffield/gocui
|
||||||
# github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a
|
# github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a
|
||||||
|
|||||||
Reference in New Issue
Block a user