mirror of
https://github.com/junegunn/fzf.git
synced 2025-11-09 11:53:47 -05:00
Compare commits
59 Commits
adjust-def
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a05083503 | ||
|
|
e659b46ff5 | ||
|
|
991c36453c | ||
|
|
4d563c6dfa | ||
|
|
5cb695744f | ||
|
|
c1b259c042 | ||
|
|
1a0371e2c7 | ||
|
|
aa259fdc19 | ||
|
|
b852dc8a56 | ||
|
|
a0cabe021d | ||
|
|
8cdfb23df6 | ||
|
|
4ffde48e2f | ||
|
|
f2b33f038a | ||
|
|
d5913bf86e | ||
|
|
0e9026b817 | ||
|
|
ab407c4645 | ||
|
|
91c4bef35f | ||
|
|
bf77206221 | ||
|
|
0cb1be3f04 | ||
|
|
01cb38a5fb | ||
|
|
c38c6cad79 | ||
|
|
ba6fc40cfd | ||
|
|
dd46a256c0 | ||
|
|
d19ce0ad8d | ||
|
|
ed7becfb47 | ||
|
|
9ace1351ff | ||
|
|
e1de29bc40 | ||
|
|
0df7d10550 | ||
|
|
91e119a77e | ||
|
|
3984161f6c | ||
|
|
91beacf0f4 | ||
|
|
e6ad01fb90 | ||
|
|
ce2200e908 | ||
|
|
548061dbde | ||
|
|
8f0c91545d | ||
|
|
0eefcf348e | ||
|
|
c1f8d18a0c | ||
|
|
8585969d6d | ||
|
|
8a943a9b1a | ||
|
|
c87a8eccd4 | ||
|
|
65df0abf0e | ||
|
|
b51bc6b50e | ||
|
|
febaadbee5 | ||
|
|
0e67c5aa7a | ||
|
|
760d1b7c58 | ||
|
|
9bdacc8df2 | ||
|
|
8e936ecfa7 | ||
|
|
db2e95b1f2 | ||
|
|
687074e772 | ||
|
|
3401c2e0c7 | ||
|
|
e8cb315419 | ||
|
|
f0c4ee4047 | ||
|
|
de0df2422a | ||
|
|
148b0a94cd | ||
|
|
ca294109c3 | ||
|
|
9cad2686e9 | ||
|
|
9a45172232 | ||
|
|
2a92c7d792 | ||
|
|
f5975cf870 |
20
.editorconfig
Normal file
20
.editorconfig
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*.{sh,bash}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
simplify = true
|
||||||
|
binary_next_line = false
|
||||||
|
switch_case_indent = true
|
||||||
|
space_redirects = true
|
||||||
|
function_next_line = false
|
||||||
|
|
||||||
|
# also bash scripts.
|
||||||
|
[{install,uninstall,bin/fzf-preview.sh,bin/fzf-tmux}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
simplify = true
|
||||||
|
binary_next_line = false
|
||||||
|
switch_case_indent = true
|
||||||
|
space_redirects = true
|
||||||
|
function_next_line = false
|
||||||
6
.github/workflows/linux.yml
vendored
6
.github/workflows/linux.yml
vendored
@@ -23,17 +23,17 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: "1.23"
|
go-version: "1.23"
|
||||||
|
|
||||||
- name: Setup Ruby
|
- name: Setup Ruby
|
||||||
uses: ruby/setup-ruby@v1
|
uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
ruby-version: 3.4.1
|
ruby-version: 3.4.6
|
||||||
|
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: sudo apt-get install --yes zsh fish tmux
|
run: sudo apt-get install --yes zsh fish tmux shfmt
|
||||||
|
|
||||||
- name: Install Ruby gems
|
- name: Install Ruby gems
|
||||||
run: bundle install
|
run: bundle install
|
||||||
|
|||||||
4
.github/workflows/macos.yml
vendored
4
.github/workflows/macos.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: "1.23"
|
go-version: "1.23"
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ jobs:
|
|||||||
ruby-version: 3.0.0
|
ruby-version: 3.0.0
|
||||||
|
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: HOMEBREW_NO_INSTALL_CLEANUP=1 brew install fish zsh tmux
|
run: HOMEBREW_NO_INSTALL_CLEANUP=1 brew install fish zsh tmux shfmt
|
||||||
|
|
||||||
- name: Install Ruby gems
|
- name: Install Ruby gems
|
||||||
run: gem install --no-document minitest:5.14.2 rubocop:1.0.0 rubocop-minitest:0.10.1 rubocop-performance:1.8.1
|
run: gem install --no-document minitest:5.14.2 rubocop:1.0.0 rubocop-minitest:0.10.1 rubocop-performance:1.8.1
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
golang 1.23.12
|
golang 1.23
|
||||||
ruby 3.4.1
|
ruby 3.4
|
||||||
|
shfmt 3.12
|
||||||
|
|||||||
297
CHANGELOG.md
297
CHANGELOG.md
@@ -1,12 +1,191 @@
|
|||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
0.66.1
|
||||||
|
------
|
||||||
|
- Bug fixes
|
||||||
|
- Fixed a bug preventing 'ctrl-h' from being bound to an action (#4556)
|
||||||
|
- Fixed `--no-color` / `NO_COLOR` theme (#4561)
|
||||||
|
|
||||||
0.66.0
|
0.66.0
|
||||||
------
|
------
|
||||||
- Style changes
|
|
||||||
- Narrowed the gutter column by using the left-half block character (`▌`).
|
### Quick summary
|
||||||
- Removed background colors from markers.
|
|
||||||
- Added `--gutter CHAR` option for customizing the gutter column. Some examples using [box-drawing characters](https://en.wikipedia.org/wiki/Box-drawing_characters):
|
This version introduces many new features centered around the new "raw" mode.
|
||||||
|
|
||||||
|
| Type | Class | Name | Description |
|
||||||
|
| :-- | :-- | :-- | :-- |
|
||||||
|
| New | Option | `--raw` | Enable raw mode by default |
|
||||||
|
| New | Option | `--gutter CHAR` | Set the gutter column character |
|
||||||
|
| New | Option | `--gutter-raw CHAR` | Set the gutter column character in raw mode |
|
||||||
|
| Enhancement | Option | `--listen SOCKET` | Added support for Unix domain sockets |
|
||||||
|
| New | Action | `toggle-raw` | Toggle raw mode |
|
||||||
|
| New | Action | `enable-raw` | Enable raw mode |
|
||||||
|
| New | Action | `disable-raw` | Disable raw mode |
|
||||||
|
| New | Action | `up-match` | Move up to the matching item |
|
||||||
|
| New | Action | `down-match` | Move down to the matching item |
|
||||||
|
| New | Action | `best` | Move to the matching item with the best score |
|
||||||
|
| New | Color | `nomatch` | Color for non-matching items in raw mode |
|
||||||
|
| New | Env Var | `FZF_RAW` | Matching status in raw mode (0, 1, or undefined) |
|
||||||
|
| New | Env Var | `FZF_DIRECTION` | `up` or `down` depending on the layout |
|
||||||
|
| New | Env Var | `FZF_SOCK` | Path to the Unix domain socket fzf is listening on |
|
||||||
|
| Enhancement | Key | `CTRL-N` | `down` -> `down-match` |
|
||||||
|
| Enhancement | Key | `CTRL-P` | `up` -> `up-match` |
|
||||||
|
| Enhancement | Shell | `CTRL-R` binding | Toggle raw mode with `ALT-R` |
|
||||||
|
| Enhancement | Shell | `CTRL-R` binding | Opt-out with an empty `FZF_CTRL_R_COMMAND` |
|
||||||
|
|
||||||
|
### 1. Introducing "raw" mode
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
This version introduces a new "raw" mode (named so because it shows the list
|
||||||
|
"unfiltered"). In raw mode, non-matching items stay in their original positions,
|
||||||
|
but appear dimmed. This allows you to see the surrounding items of a match and
|
||||||
|
better understand the context of it. You can enable raw mode by default with
|
||||||
|
`--raw`, but it's often more useful when toggled dynamically with the
|
||||||
|
`toggle-raw` action.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
tree | fzf --reverse --bind alt-r:toggle-raw
|
||||||
|
```
|
||||||
|
|
||||||
|
While non-matching items are displayed in a dimmed color, they are treated just
|
||||||
|
like matching items, so you place the cursor on them and perform any action. If
|
||||||
|
you prefer to navigate only through matching items, use the `down-match` and
|
||||||
|
`up-match` actions, which are from now on bound to `CTRL-N` and `CTRL-P`
|
||||||
|
respectively, and also to `ALT-DOWN` and `ALT-UP`.
|
||||||
|
|
||||||
|
| Key | Action | With `--history` |
|
||||||
|
| :-- | :-- | :-- |
|
||||||
|
| `down` | `down` | |
|
||||||
|
| `up` | `up` | |
|
||||||
|
| `ctrl-j` | `down` | |
|
||||||
|
| `ctrl-k` | `up` | |
|
||||||
|
| `ctrl-n` | `down-match` | `next-history` |
|
||||||
|
| `ctrl-p` | `up-match` | `prev-history` |
|
||||||
|
| `alt-down` | `down-match` | |
|
||||||
|
| `alt-up` | `up-match` | |
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> `CTRL-N` and `CTRL-P` are bound to `next-history` and `prev-history` when
|
||||||
|
> `--history` option is enabled, so in that case, you'll need to manually bind
|
||||||
|
> them, or use `ALT-DOWN` and `ALT-UP` instead.
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> `up-match` and `down-match` are equivalent to `up` and `down` when not in
|
||||||
|
> raw mode, so you can safely bind them to `up` and `arrow` keys if you prefer.
|
||||||
|
> ```sh
|
||||||
|
> fzf --bind up:up-match,down:down-match
|
||||||
|
> ```
|
||||||
|
|
||||||
|
#### Customizing the behavior
|
||||||
|
|
||||||
|
In raw mode, the input list is presented in its original order, unfiltered, and
|
||||||
|
your cursor will not move to the matching item automatically. Here are ways to
|
||||||
|
customize the behavior.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# When the result list is updated, move the cursor to the item with the best score
|
||||||
|
# (assuming sorting is not disabled)
|
||||||
|
fzf --raw --bind result:best
|
||||||
|
|
||||||
|
# Move to the first matching item in the original list
|
||||||
|
# - $FZF_RAW is set to 0 when raw mode is enabled and the current item is a non-match
|
||||||
|
# - $FZF_DIRECTION is set to either 'up' or 'down' depending on the layout direction
|
||||||
|
fzf --raw --bind 'result:first+transform:[[ $FZF_RAW = 0 ]] && echo $FZF_DIRECTION-match'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Customizing the look
|
||||||
|
|
||||||
|
##### Gutter
|
||||||
|
|
||||||
|
To make the mode visually distinct, the gutter column is rendered in a dashed
|
||||||
|
line using `▖` character. But you can customize it with the `--gutter-raw CHAR`
|
||||||
|
option.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Use a thinner gutter instead of the default dashed line
|
||||||
|
fzf --bind alt-r:toggle-raw --gutter-raw ▎
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Color and style of non-matching items
|
||||||
|
|
||||||
|
Non-matching items are displayed in a dimmed color by default, but you can
|
||||||
|
change it with the `--color nomatch:...` option.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
fzf --raw --color nomatch:red
|
||||||
|
fzf --raw --color nomatch:red:dim
|
||||||
|
fzf --raw --color nomatch:red:dim:strikethrough
|
||||||
|
fzf --raw --color nomatch:red:dim:strikethrough:italic
|
||||||
|
```
|
||||||
|
|
||||||
|
For colored input, dimming alone may not be enough, and you may prefer to remove
|
||||||
|
colors entirely. For that case, a new special style attribute `strip` has been
|
||||||
|
added.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
fd --color always | fzf --ansi --raw --color nomatch:dim:strip:strikethrough
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Conditional actions for raw mode
|
||||||
|
|
||||||
|
You may want to perform different actions depending on whether the current item
|
||||||
|
is a match or not. For that, fzf now exports `$FZF_RAW` environment variable.
|
||||||
|
|
||||||
|
It's:
|
||||||
|
|
||||||
|
- Undefined if raw mode is disabled
|
||||||
|
- `1` if the current item is a match
|
||||||
|
- `0` otherwise
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Do not allow selecting non-matching items
|
||||||
|
fzf --raw --bind 'enter:transform:[[ ${FZF_RAW-1} = 1 ]] && echo accept || echo bell'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Leveraging raw mode in shell integration
|
||||||
|
|
||||||
|
The `CTRL-R` binding (command history) now lets you toggle raw mode with `ALT-R`.
|
||||||
|
|
||||||
|
### 2. Style changes
|
||||||
|
|
||||||
|
The screenshot on the right shows the updated gutter style:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
This version includes a few minor updates to fzf's classic visual style:
|
||||||
|
|
||||||
|
- The gutter column is now narrower, rendered with the left-half block character (`▌`).
|
||||||
|
- Markers no longer use background colors.
|
||||||
|
- The `--color base16` theme (alias: `16`) has been updated for better compatibility with both dark and light themes.
|
||||||
|
|
||||||
|
### 3. `--listen` now supports Unix domain sockets
|
||||||
|
|
||||||
|
If an argument to `--listen` ends with `.sock`, fzf will listen on a Unix
|
||||||
|
domain socket at the specified path.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
fzf --listen /tmp/fzf.sock --no-tmux
|
||||||
|
|
||||||
|
# GET
|
||||||
|
curl --unix-socket /tmp/fzf.sock http
|
||||||
|
|
||||||
|
# POST
|
||||||
|
curl --unix-socket /tmp/fzf.sock http -d up
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that any existing file at the given path will be removed before creating
|
||||||
|
the socket, so avoid using an important file path.
|
||||||
|
|
||||||
|
### 4. Added options
|
||||||
|
|
||||||
|
#### `--gutter CHAR`
|
||||||
|
|
||||||
|
The gutter column can now be customized using `--gutter CHAR` and styled with
|
||||||
|
`--color gutter:...`. Examples:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# Right-aligned gutter
|
# Right-aligned gutter
|
||||||
fzf --gutter '▐'
|
fzf --gutter '▐'
|
||||||
@@ -14,19 +193,109 @@ CHANGELOG
|
|||||||
# Even thinner gutter
|
# Even thinner gutter
|
||||||
fzf --gutter '▎'
|
fzf --gutter '▎'
|
||||||
|
|
||||||
# Checker
|
# Yellow checker pattern
|
||||||
fzf --gutter '▚'
|
fzf --gutter '▚' --color gutter:yellow
|
||||||
|
|
||||||
# Dotted
|
# Classic style
|
||||||
fzf --gutter '▖'
|
fzf --gutter ' ' --color gutter:reverse
|
||||||
|
|
||||||
# Full-width
|
|
||||||
fzf --gutter '█'
|
|
||||||
|
|
||||||
# No gutter
|
|
||||||
fzf --gutter ' '
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### `--gutter-raw CHAR`
|
||||||
|
|
||||||
|
As noted above, the `--gutter-raw CHAR` option was also added for customizing the gutter column in raw mode.
|
||||||
|
|
||||||
|
### 5. Added actions
|
||||||
|
|
||||||
|
The following actions were introduced to support working with raw mode:
|
||||||
|
|
||||||
|
| Action | Description |
|
||||||
|
| :-- | :-- |
|
||||||
|
| `toggle-raw` | Toggle raw mode |
|
||||||
|
| `enable-raw` | Enable raw mode |
|
||||||
|
| `disable-raw` | Disable raw mode |
|
||||||
|
| `up-match` | Move up to the matching item; identical to `up` if raw mode is disabled |
|
||||||
|
| `down-match` | Move down to the matching item; identical to `down` if raw mode is disabled |
|
||||||
|
| `best` | Move to the matching item with the best score; identical to `first` if raw mode is disabled |
|
||||||
|
|
||||||
|
### 6. Added environment variables
|
||||||
|
|
||||||
|
#### `$FZF_DIRECTION`
|
||||||
|
|
||||||
|
`$FZF_DIRECTION` is now exported to child processes, indicating the list direction of the current layout:
|
||||||
|
|
||||||
|
- `up` for the default layout
|
||||||
|
- `down` for `reverse` or `reverse-list`
|
||||||
|
|
||||||
|
This simplifies writing transform actions involving layout-dependent actions
|
||||||
|
like `{up,down}-match`, `{up,down}-selected`, and `toggle+{up,down}`.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
fzf --raw --bind 'result:first+transform:[[ $FZF_RAW = 0 ]] && echo $FZF_DIRECTION-match'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `$FZF_SOCK`
|
||||||
|
|
||||||
|
When fzf is listening on a Unix domain socket using `--listen`, the path to the
|
||||||
|
socket is exported as `$FZF_SOCK`, analogous to `$FZF_PORT` for TCP sockets.
|
||||||
|
|
||||||
|
#### `$FZF_RAW`
|
||||||
|
|
||||||
|
As described above, `$FZF_RAW` is now exported to child processes in raw mode,
|
||||||
|
indicating whether the current item is a match (`1`) or not (`0`). It is not
|
||||||
|
defined when not in raw mode.
|
||||||
|
|
||||||
|
#### `$FZF_CTRL_R_COMMAND`
|
||||||
|
|
||||||
|
You can opt-out `CTRL-R` binding from the shell integration by setting
|
||||||
|
`FZF_CTRL_R_COMMAND` to an empty string. Setting it to any other value is not
|
||||||
|
supported and will result in a warning.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Disable the CTRL-R binding from the shell integration
|
||||||
|
FZF_CTRL_R_COMMAND= eval "$(fzf --bash)"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. Added key support for `--bind`
|
||||||
|
|
||||||
|
Pull request [#3996](https://github.com/junegunn/fzf/pull/3996) added support
|
||||||
|
for many additional keys for `--bind` option, such as `ctrl-backspace`.
|
||||||
|
|
||||||
|
### 8. Breaking changes
|
||||||
|
|
||||||
|
#### Hiding the gutter column
|
||||||
|
|
||||||
|
In the previous versions, the recommended way to hide the gutter column was to
|
||||||
|
set `--color gutter:-1`. That's because the gutter column was just a space
|
||||||
|
character, reversed. But now that it's using a visible character (`▌`), applying
|
||||||
|
the default color is no longer enough to hide it. Instead, you can set it to
|
||||||
|
a space character.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Hide the gutter column
|
||||||
|
fzf --gutter ' '
|
||||||
|
|
||||||
|
# Classic style
|
||||||
|
fzf --gutter ' ' --color gutter:reverse
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `--color` option
|
||||||
|
|
||||||
|
In the previous versions, some elements had default style attributes applied and
|
||||||
|
you would have to explicitly unset them with `regular` attribute if you wanted
|
||||||
|
to reset them. This is no longer needed now, as the default style attributes
|
||||||
|
are applied only when you do not specify any color or style for that element.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# No 'dim', just red and italic.
|
||||||
|
fzf --ghost 'Type to search' --color ghost:red:italic
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Compatibility changes
|
||||||
|
|
||||||
|
Starting with this release, fzf is built with Go 1.23. Support for some old OS versions has been dropped.
|
||||||
|
|
||||||
|
See https://go.dev/wiki/MinimumRequirements.
|
||||||
|
|
||||||
0.65.2
|
0.65.2
|
||||||
------
|
------
|
||||||
- Bug fixes and improvements
|
- Bug fixes and improvements
|
||||||
|
|||||||
18
Makefile
18
Makefile
@@ -5,6 +5,15 @@ MAKEFILE := $(realpath $(lastword $(MAKEFILE_LIST)))
|
|||||||
ROOT_DIR := $(shell dirname $(MAKEFILE))
|
ROOT_DIR := $(shell dirname $(MAKEFILE))
|
||||||
SOURCES := $(wildcard *.go src/*.go src/*/*.go shell/*sh man/man1/*.1) $(MAKEFILE)
|
SOURCES := $(wildcard *.go src/*.go src/*/*.go shell/*sh man/man1/*.1) $(MAKEFILE)
|
||||||
|
|
||||||
|
BASH_SCRIPTS := $(ROOT_DIR)/bin/fzf-preview.sh \
|
||||||
|
$(ROOT_DIR)/bin/fzf-tmux \
|
||||||
|
$(ROOT_DIR)/install \
|
||||||
|
$(ROOT_DIR)/uninstall \
|
||||||
|
$(ROOT_DIR)/shell/common.sh \
|
||||||
|
$(ROOT_DIR)/shell/update.sh \
|
||||||
|
$(ROOT_DIR)/shell/completion.bash \
|
||||||
|
$(ROOT_DIR)/shell/key-bindings.bash
|
||||||
|
|
||||||
ifdef FZF_VERSION
|
ifdef FZF_VERSION
|
||||||
VERSION := $(FZF_VERSION)
|
VERSION := $(FZF_VERSION)
|
||||||
else
|
else
|
||||||
@@ -88,9 +97,14 @@ itest:
|
|||||||
bench:
|
bench:
|
||||||
cd src && SHELL=/bin/sh GOOS= $(GO) test -v -tags "$(TAGS)" -run=Bench -bench=. -benchmem
|
cd src && SHELL=/bin/sh GOOS= $(GO) test -v -tags "$(TAGS)" -run=Bench -bench=. -benchmem
|
||||||
|
|
||||||
lint: $(SOURCES) test/*.rb test/lib/*.rb
|
lint: $(SOURCES) test/*.rb test/lib/*.rb ${BASH_SCRIPTS}
|
||||||
[ -z "$$(gofmt -s -d src)" ] || (gofmt -s -d src; exit 1)
|
[ -z "$$(gofmt -s -d src)" ] || (gofmt -s -d src; exit 1)
|
||||||
bundle exec rubocop -a --require rubocop-minitest --require rubocop-performance
|
bundle exec rubocop -a --require rubocop-minitest --require rubocop-performance
|
||||||
|
shell/update.sh --check ${BASH_SCRIPTS}
|
||||||
|
|
||||||
|
fmt: $(SOURCES) $(BASH_SCRIPTS)
|
||||||
|
gofmt -s -w src
|
||||||
|
shell/update.sh ${BASH_SCRIPTS}
|
||||||
|
|
||||||
install: bin/fzf
|
install: bin/fzf
|
||||||
|
|
||||||
@@ -189,4 +203,4 @@ update:
|
|||||||
$(GO) get -u
|
$(GO) get -u
|
||||||
$(GO) mod tidy
|
$(GO) mod tidy
|
||||||
|
|
||||||
.PHONY: all generate build release test itest bench lint install clean docker docker-test update
|
.PHONY: all generate build release test itest bench lint install clean docker docker-test update fmt
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ if [[ ! $type =~ image/ ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
dim=${FZF_PREVIEW_COLUMNS}x${FZF_PREVIEW_LINES}
|
dim=${FZF_PREVIEW_COLUMNS}x${FZF_PREVIEW_LINES}
|
||||||
if [[ $dim = x ]]; then
|
if [[ $dim == x ]]; then
|
||||||
dim=$(stty size < /dev/tty | awk '{print $2 "x" $1}')
|
dim=$(stty size < /dev/tty | awk '{print $2 "x" $1}')
|
||||||
elif ! [[ $KITTY_WINDOW_ID ]] && ((FZF_PREVIEW_TOP + FZF_PREVIEW_LINES == $(stty size < /dev/tty | awk '{print $1}'))); then
|
elif ! [[ $KITTY_WINDOW_ID ]] && ((FZF_PREVIEW_TOP + FZF_PREVIEW_LINES == $(stty size < /dev/tty | awk '{print $1}'))); then
|
||||||
# Avoid scrolling issue when the Sixel image touches the bottom of the screen
|
# Avoid scrolling issue when the Sixel image touches the bottom of the screen
|
||||||
|
|||||||
71
bin/fzf-tmux
71
bin/fzf-tmux
@@ -8,7 +8,7 @@ fail() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fzf="$(command which fzf)" || fzf="$(dirname "$0")/fzf"
|
fzf="$(command which fzf)" || fzf="$(dirname "$0")/fzf"
|
||||||
[[ -x "$fzf" ]] || fail 'fzf executable not found'
|
[[ -x $fzf ]] || fail 'fzf executable not found'
|
||||||
|
|
||||||
args=()
|
args=()
|
||||||
opt=""
|
opt=""
|
||||||
@@ -16,8 +16,8 @@ skip=""
|
|||||||
swap=""
|
swap=""
|
||||||
close=""
|
close=""
|
||||||
term=""
|
term=""
|
||||||
[[ -n "$LINES" ]] && lines=$LINES || lines=$(tput lines) || lines=$(tmux display-message -p "#{pane_height}")
|
[[ -n $LINES ]] && lines=$LINES || lines=$(tput lines) || lines=$(tmux display-message -p "#{pane_height}")
|
||||||
[[ -n "$COLUMNS" ]] && columns=$COLUMNS || columns=$(tput cols) || columns=$(tmux display-message -p "#{pane_width}")
|
[[ -n $COLUMNS ]] && columns=$COLUMNS || columns=$(tput cols) || columns=$(tmux display-message -p "#{pane_width}")
|
||||||
|
|
||||||
tmux_version=$(tmux -V | sed 's/[^0-9.]//g')
|
tmux_version=$(tmux -V | sed 's/[^0-9.]//g')
|
||||||
tmux_32=$(awk '{print ($1 >= 3.2)}' <<< "$tmux_version" 2> /dev/null || bc -l <<< "$tmux_version >= 3.2")
|
tmux_32=$(awk '{print ($1 >= 3.2)}' <<< "$tmux_version" 2> /dev/null || bc -l <<< "$tmux_version >= 3.2")
|
||||||
@@ -47,7 +47,7 @@ help() {
|
|||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
arg="$1"
|
arg="$1"
|
||||||
shift
|
shift
|
||||||
[[ -z "$skip" ]] && case "$arg" in
|
[[ -z $skip ]] && case "$arg" in
|
||||||
-)
|
-)
|
||||||
term=1
|
term=1
|
||||||
;;
|
;;
|
||||||
@@ -59,18 +59,18 @@ while [[ $# -gt 0 ]]; do
|
|||||||
exit
|
exit
|
||||||
;;
|
;;
|
||||||
-p* | -w* | -h* | -x* | -y* | -d* | -u* | -r* | -l*)
|
-p* | -w* | -h* | -x* | -y* | -d* | -u* | -r* | -l*)
|
||||||
if [[ "$arg" =~ ^-[pwhxy] ]]; then
|
if [[ $arg =~ ^-[pwhxy] ]]; then
|
||||||
[[ "$opt" =~ "-E" ]] || opt="-E"
|
[[ $opt =~ "-E" ]] || opt="-E"
|
||||||
elif [[ "$arg" =~ ^.[lr] ]]; then
|
elif [[ $arg =~ ^.[lr] ]]; then
|
||||||
opt="-h"
|
opt="-h"
|
||||||
if [[ "$arg" =~ ^.l ]]; then
|
if [[ $arg =~ ^.l ]]; then
|
||||||
opt="$opt -d"
|
opt="$opt -d"
|
||||||
swap="; swap-pane -D ; select-pane -L"
|
swap="; swap-pane -D ; select-pane -L"
|
||||||
close="; tmux swap-pane -D"
|
close="; tmux swap-pane -D"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
opt=""
|
opt=""
|
||||||
if [[ "$arg" =~ ^.u ]]; then
|
if [[ $arg =~ ^.u ]]; then
|
||||||
opt="$opt -d"
|
opt="$opt -d"
|
||||||
swap="; swap-pane -D ; select-pane -U"
|
swap="; swap-pane -D ; select-pane -U"
|
||||||
close="; tmux swap-pane -D"
|
close="; tmux swap-pane -D"
|
||||||
@@ -79,7 +79,7 @@ while [[ $# -gt 0 ]]; do
|
|||||||
if [[ ${#arg} -gt 2 ]]; then
|
if [[ ${#arg} -gt 2 ]]; then
|
||||||
size="${arg:2}"
|
size="${arg:2}"
|
||||||
else
|
else
|
||||||
if [[ "$1" =~ ^[0-9%,]+$ ]] || [[ "$1" =~ ^[A-Z]$ ]]; then
|
if [[ $1 =~ ^[0-9%,]+$ ]] || [[ $1 =~ ^[A-Z]$ ]]; then
|
||||||
size="$1"
|
size="$1"
|
||||||
shift
|
shift
|
||||||
else
|
else
|
||||||
@@ -87,32 +87,32 @@ while [[ $# -gt 0 ]]; do
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$arg" =~ ^-p ]]; then
|
if [[ $arg =~ ^-p ]]; then
|
||||||
if [[ -n "$size" ]]; then
|
if [[ -n $size ]]; then
|
||||||
w=${size%%,*}
|
w=${size%%,*}
|
||||||
h=${size##*,}
|
h=${size##*,}
|
||||||
opt="$opt -w$w -h$h"
|
opt="$opt -w$w -h$h"
|
||||||
fi
|
fi
|
||||||
elif [[ "$arg" =~ ^-[whxy] ]]; then
|
elif [[ $arg =~ ^-[whxy] ]]; then
|
||||||
opt="$opt ${arg:0:2}$size"
|
opt="$opt ${arg:0:2}$size"
|
||||||
elif [[ "$size" =~ %$ ]]; then
|
elif [[ $size =~ %$ ]]; then
|
||||||
size=${size:0:((${#size}-1))}
|
size=${size:0:${#size}-1}
|
||||||
if [[ $tmux_32 = 1 ]]; then
|
if [[ $tmux_32 == 1 ]]; then
|
||||||
if [[ -n "$swap" ]]; then
|
if [[ -n $swap ]]; then
|
||||||
opt="$opt -l $((100 - size))%"
|
opt="$opt -l $((100 - size))%"
|
||||||
else
|
else
|
||||||
opt="$opt -l $size%"
|
opt="$opt -l $size%"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
if [[ -n "$swap" ]]; then
|
if [[ -n $swap ]]; then
|
||||||
opt="$opt -p $((100 - size))"
|
opt="$opt -p $((100 - size))"
|
||||||
else
|
else
|
||||||
opt="$opt -p $size"
|
opt="$opt -p $size"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
if [[ -n "$swap" ]]; then
|
if [[ -n $swap ]]; then
|
||||||
if [[ "$arg" =~ ^.l ]]; then
|
if [[ $arg =~ ^.l ]]; then
|
||||||
max=$columns
|
max=$columns
|
||||||
else
|
else
|
||||||
max=$lines
|
max=$lines
|
||||||
@@ -135,10 +135,10 @@ while [[ $# -gt 0 ]]; do
|
|||||||
args+=("$arg")
|
args+=("$arg")
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
[[ -n "$skip" ]] && args+=("$arg")
|
[[ -n $skip ]] && args+=("$arg")
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ -z "$TMUX" ]]; then
|
if [[ -z $TMUX ]]; then
|
||||||
"$fzf" "${args[@]}"
|
"$fzf" "${args[@]}"
|
||||||
exit $?
|
exit $?
|
||||||
fi
|
fi
|
||||||
@@ -149,7 +149,7 @@ fi
|
|||||||
args=("${args[@]}" "--no-height" "--bind=ctrl-z:ignore" "--no-tmux")
|
args=("${args[@]}" "--no-height" "--bind=ctrl-z:ignore" "--no-tmux")
|
||||||
|
|
||||||
# Handle zoomed tmux pane without popup options by moving it to a temp window
|
# Handle zoomed tmux pane without popup options by moving it to a temp window
|
||||||
if [[ ! "$opt" =~ "-E" ]] && tmux list-panes -F '#F' | grep -q Z; then
|
if [[ ! $opt =~ "-E" ]] && tmux list-panes -F '#F' | grep -q Z; then
|
||||||
zoomed_without_popup=1
|
zoomed_without_popup=1
|
||||||
original_window=$(tmux display-message -p "#{window_id}")
|
original_window=$(tmux display-message -p "#{window_id}")
|
||||||
tmp_window=$(tmux new-window -d -P -F "#{window_id}" "bash -c 'while :; do for c in \\| / - '\\;' do sleep 0.2; printf \"\\r\$c fzf-tmux is running\\r\"; done; done'")
|
tmp_window=$(tmux new-window -d -P -F "#{window_id}" "bash -c 'while :; do for c in \\| / - '\\;' do sleep 0.2; printf \"\\r\$c fzf-tmux is running\\r\"; done; done'")
|
||||||
@@ -175,12 +175,12 @@ cleanup() {
|
|||||||
\rm -f $argsf $fifo1 $fifo2 $fifo3
|
\rm -f $argsf $fifo1 $fifo2 $fifo3
|
||||||
|
|
||||||
# Restore tmux window options
|
# Restore tmux window options
|
||||||
if [[ "${#tmux_win_opts[@]}" -gt 1 ]]; then
|
if [[ ${#tmux_win_opts[@]} -gt 1 ]]; then
|
||||||
eval "tmux ${tmux_win_opts[*]}"
|
eval "tmux ${tmux_win_opts[*]}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Remove temp window if we were zoomed without popup options
|
# Remove temp window if we were zoomed without popup options
|
||||||
if [[ -n "$zoomed_without_popup" ]]; then
|
if [[ -n $zoomed_without_popup ]]; then
|
||||||
tmux display-message -p "#{window_id}" > /dev/null
|
tmux display-message -p "#{window_id}" > /dev/null
|
||||||
tmux swap-pane -t $original_window \; \
|
tmux swap-pane -t $original_window \; \
|
||||||
select-window -t $original_window \; \
|
select-window -t $original_window \; \
|
||||||
@@ -197,10 +197,10 @@ trap 'cleanup 1' SIGUSR1
|
|||||||
trap 'cleanup' EXIT
|
trap 'cleanup' EXIT
|
||||||
|
|
||||||
envs="export TERM=$TERM "
|
envs="export TERM=$TERM "
|
||||||
if [[ "$opt" =~ "-E" ]]; then
|
if [[ $opt =~ "-E" ]]; then
|
||||||
if [[ $tmux_version = 3.2 ]]; then
|
if [[ $tmux_version == 3.2 ]]; then
|
||||||
FZF_DEFAULT_OPTS="--margin 0,1 $FZF_DEFAULT_OPTS"
|
FZF_DEFAULT_OPTS="--margin 0,1 $FZF_DEFAULT_OPTS"
|
||||||
elif [[ $tmux_32 = 1 ]]; then
|
elif [[ $tmux_32 == 1 ]]; then
|
||||||
FZF_DEFAULT_OPTS="--border $FZF_DEFAULT_OPTS"
|
FZF_DEFAULT_OPTS="--border $FZF_DEFAULT_OPTS"
|
||||||
opt="-B $opt"
|
opt="-B $opt"
|
||||||
else
|
else
|
||||||
@@ -211,8 +211,8 @@ fi
|
|||||||
envs="$envs FZF_DEFAULT_COMMAND=$(printf %q "$FZF_DEFAULT_COMMAND")"
|
envs="$envs FZF_DEFAULT_COMMAND=$(printf %q "$FZF_DEFAULT_COMMAND")"
|
||||||
envs="$envs FZF_DEFAULT_OPTS=$(printf %q "$FZF_DEFAULT_OPTS")"
|
envs="$envs FZF_DEFAULT_OPTS=$(printf %q "$FZF_DEFAULT_OPTS")"
|
||||||
envs="$envs FZF_DEFAULT_OPTS_FILE=$(printf %q "$FZF_DEFAULT_OPTS_FILE")"
|
envs="$envs FZF_DEFAULT_OPTS_FILE=$(printf %q "$FZF_DEFAULT_OPTS_FILE")"
|
||||||
[[ -n "$RUNEWIDTH_EASTASIAN" ]] && envs="$envs RUNEWIDTH_EASTASIAN=$(printf %q "$RUNEWIDTH_EASTASIAN")"
|
[[ -n $RUNEWIDTH_EASTASIAN ]] && envs="$envs RUNEWIDTH_EASTASIAN=$(printf %q "$RUNEWIDTH_EASTASIAN")"
|
||||||
[[ -n "$BAT_THEME" ]] && envs="$envs BAT_THEME=$(printf %q "$BAT_THEME")"
|
[[ -n $BAT_THEME ]] && envs="$envs BAT_THEME=$(printf %q "$BAT_THEME")"
|
||||||
echo "$envs;" > "$argsf"
|
echo "$envs;" > "$argsf"
|
||||||
|
|
||||||
# Build arguments to fzf
|
# Build arguments to fzf
|
||||||
@@ -224,9 +224,9 @@ close="; trap - EXIT SIGINT SIGTERM $close"
|
|||||||
|
|
||||||
export TMUX=$(cut -d , -f 1,2 <<< "$TMUX")
|
export TMUX=$(cut -d , -f 1,2 <<< "$TMUX")
|
||||||
mkfifo -m o+w $fifo2
|
mkfifo -m o+w $fifo2
|
||||||
if [[ "$opt" =~ "-E" ]]; then
|
if [[ $opt =~ "-E" ]]; then
|
||||||
cat $fifo2 &
|
cat $fifo2 &
|
||||||
if [[ -n "$term" ]] || [[ -t 0 ]]; then
|
if [[ -n $term ]] || [[ -t 0 ]]; then
|
||||||
cat <<< "\"$fzf\" $opts > $fifo2; out=\$? $close; exit \$out" >> $argsf
|
cat <<< "\"$fzf\" $opts > $fifo2; out=\$? $close; exit \$out" >> $argsf
|
||||||
else
|
else
|
||||||
mkfifo $fifo1
|
mkfifo $fifo1
|
||||||
@@ -239,7 +239,7 @@ if [[ "$opt" =~ "-E" ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
mkfifo -m o+w $fifo3
|
mkfifo -m o+w $fifo3
|
||||||
if [[ -n "$term" ]] || [[ -t 0 ]]; then
|
if [[ -n $term ]] || [[ -t 0 ]]; then
|
||||||
cat <<< "\"$fzf\" $opts > $fifo2; echo \$? > $fifo3 $close" >> $argsf
|
cat <<< "\"$fzf\" $opts > $fifo2; echo \$? > $fifo3 $close" >> $argsf
|
||||||
else
|
else
|
||||||
mkfifo $fifo1
|
mkfifo $fifo1
|
||||||
@@ -249,6 +249,9 @@ fi
|
|||||||
tmux \
|
tmux \
|
||||||
split-window -c "$PWD" $opt "bash -c 'exec -a fzf bash $argsf'" $swap \
|
split-window -c "$PWD" $opt "bash -c 'exec -a fzf bash $argsf'" $swap \
|
||||||
$tmux_off_opts \
|
$tmux_off_opts \
|
||||||
> /dev/null 2>&1 || { "$fzf" "${args[@]}"; exit $?; }
|
> /dev/null 2>&1 || {
|
||||||
|
"$fzf" "${args[@]}"
|
||||||
|
exit $?
|
||||||
|
}
|
||||||
cat $fifo2
|
cat $fifo2
|
||||||
exit "$(cat $fifo3)"
|
exit "$(cat $fifo3)"
|
||||||
|
|||||||
24
install
24
install
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
set -u
|
set -u
|
||||||
|
|
||||||
version=0.65.2
|
version=0.66.1
|
||||||
auto_completion=
|
auto_completion=
|
||||||
key_bindings=
|
key_bindings=
|
||||||
update_config=2
|
update_config=2
|
||||||
@@ -104,7 +104,7 @@ check_binary() {
|
|||||||
|
|
||||||
link_fzf_in_path() {
|
link_fzf_in_path() {
|
||||||
if which_fzf="$(command -v fzf)"; then
|
if which_fzf="$(command -v fzf)"; then
|
||||||
echo " - Found in \$PATH"
|
echo ' - Found in $PATH'
|
||||||
echo " - Creating symlink: bin/fzf -> $which_fzf"
|
echo " - Creating symlink: bin/fzf -> $which_fzf"
|
||||||
(cd "$fzf_base"/bin && rm -f fzf && ln -sf "$which_fzf" fzf)
|
(cd "$fzf_base"/bin && rm -f fzf && ln -sf "$which_fzf" fzf)
|
||||||
check_binary && return
|
check_binary && return
|
||||||
@@ -215,7 +215,7 @@ if [ -n "$binary_error" ]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[[ "$*" =~ "--bin" ]] && exit 0
|
[[ $* =~ "--bin" ]] && exit 0
|
||||||
|
|
||||||
for s in $shells; do
|
for s in $shells; do
|
||||||
if ! command -v "$s" > /dev/null; then
|
if ! command -v "$s" > /dev/null; then
|
||||||
@@ -242,7 +242,7 @@ fi
|
|||||||
|
|
||||||
echo
|
echo
|
||||||
for shell in $shells; do
|
for shell in $shells; do
|
||||||
[[ "$shell" = fish ]] && continue
|
[[ $shell == fish ]] && continue
|
||||||
src=${prefix_expand}.${shell}
|
src=${prefix_expand}.${shell}
|
||||||
echo -n "Generate $src ... "
|
echo -n "Generate $src ... "
|
||||||
|
|
||||||
@@ -266,7 +266,7 @@ fi
|
|||||||
EOF
|
EOF
|
||||||
|
|
||||||
if [[ $auto_completion -eq 1 ]] && [[ $key_bindings -eq 1 ]]; then
|
if [[ $auto_completion -eq 1 ]] && [[ $key_bindings -eq 1 ]]; then
|
||||||
if [[ "$shell" = zsh ]]; then
|
if [[ $shell == zsh ]]; then
|
||||||
echo "source <(fzf --$shell)" >> "$src"
|
echo "source <(fzf --$shell)" >> "$src"
|
||||||
else
|
else
|
||||||
echo "eval \"\$(fzf --$shell)\"" >> "$src"
|
echo "eval \"\$(fzf --$shell)\"" >> "$src"
|
||||||
@@ -286,7 +286,7 @@ EOF
|
|||||||
done
|
done
|
||||||
|
|
||||||
# fish
|
# fish
|
||||||
if [[ "$shells" =~ fish ]]; then
|
if [[ $shells =~ fish ]]; then
|
||||||
echo -n "Update fish_user_paths ... "
|
echo -n "Update fish_user_paths ... "
|
||||||
fish << EOF
|
fish << EOF
|
||||||
echo \$fish_user_paths | \grep "$fzf_base"/bin > /dev/null
|
echo \$fish_user_paths | \grep "$fzf_base"/bin > /dev/null
|
||||||
@@ -356,12 +356,12 @@ if [ $update_config -eq 2 ]; then
|
|||||||
fi
|
fi
|
||||||
echo
|
echo
|
||||||
for shell in $shells; do
|
for shell in $shells; do
|
||||||
[[ "$shell" = fish ]] && continue
|
[[ $shell == fish ]] && continue
|
||||||
[ $shell = zsh ] && dest=${ZDOTDIR:-~}/.zshrc || dest=~/.bashrc
|
[ $shell = zsh ] && dest=${ZDOTDIR:-~}/.zshrc || dest=~/.bashrc
|
||||||
append_line $update_config "[ -f ${prefix}.${shell} ] && source ${prefix}.${shell}" "$dest" "${prefix}.${shell}"
|
append_line $update_config "[ -f ${prefix}.${shell} ] && source ${prefix}.${shell}" "$dest" "${prefix}.${shell}"
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ $key_bindings -eq 1 ] && [[ "$shells" =~ fish ]]; then
|
if [ $key_bindings -eq 1 ] && [[ $shells =~ fish ]]; then
|
||||||
bind_file="${fish_dir}/functions/fish_user_key_bindings.fish"
|
bind_file="${fish_dir}/functions/fish_user_key_bindings.fish"
|
||||||
if [ ! -e "$bind_file" ]; then
|
if [ ! -e "$bind_file" ]; then
|
||||||
mkdir -p "${fish_dir}/functions"
|
mkdir -p "${fish_dir}/functions"
|
||||||
@@ -386,13 +386,13 @@ fi
|
|||||||
|
|
||||||
if [ $update_config -eq 1 ]; then
|
if [ $update_config -eq 1 ]; then
|
||||||
echo 'Finished. Restart your shell or reload config file.'
|
echo 'Finished. Restart your shell or reload config file.'
|
||||||
if [[ "$shells" =~ bash ]]; then
|
if [[ $shells =~ bash ]]; then
|
||||||
echo -n ' source ~/.bashrc # bash'
|
echo -n ' source ~/.bashrc # bash'
|
||||||
[[ "$archi" =~ Darwin ]] && echo -n ' (.bashrc should be loaded from .bash_profile)'
|
[[ $archi =~ Darwin ]] && echo -n ' (.bashrc should be loaded from .bash_profile)'
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
[[ "$shells" =~ zsh ]] && echo " source ${ZDOTDIR:-~}/.zshrc # zsh"
|
[[ $shells =~ zsh ]] && echo " source ${ZDOTDIR:-~}/.zshrc # zsh"
|
||||||
[[ "$shells" =~ fish ]] && [ $key_bindings -eq 1 ] && echo ' fzf_key_bindings # fish'
|
[[ $shells =~ fish ]] && [ $key_bindings -eq 1 ] && echo ' fzf_key_bindings # fish'
|
||||||
echo
|
echo
|
||||||
echo 'Use uninstall script to remove fzf.'
|
echo 'Use uninstall script to remove fzf.'
|
||||||
echo
|
echo
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
$version="0.65.2"
|
$version="0.66.1"
|
||||||
|
|
||||||
$fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition
|
$fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition
|
||||||
|
|
||||||
|
|||||||
2
main.go
2
main.go
@@ -11,7 +11,7 @@ import (
|
|||||||
"github.com/junegunn/fzf/src/protector"
|
"github.com/junegunn/fzf/src/protector"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version = "0.65"
|
var version = "0.66"
|
||||||
var revision = "devel"
|
var revision = "devel"
|
||||||
|
|
||||||
//go:embed shell/key-bindings.bash
|
//go:embed shell/key-bindings.bash
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
..
|
..
|
||||||
.TH fzf\-tmux 1 "Aug 2025" "fzf 0.65.2" "fzf\-tmux - open fzf in tmux split pane"
|
.TH fzf\-tmux 1 "Oct 2025" "fzf 0.66.1" "fzf\-tmux - open fzf in tmux split pane"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fzf\-tmux - open fzf in tmux split pane
|
fzf\-tmux - open fzf in tmux split pane
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
..
|
..
|
||||||
.TH fzf 1 "Aug 2025" "fzf 0.65.2" "fzf - a command-line fuzzy finder"
|
.TH fzf 1 "Oct 2025" "fzf 0.66.1" "fzf - a command-line fuzzy finder"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fzf - a command-line fuzzy finder
|
fzf - a command-line fuzzy finder
|
||||||
@@ -246,11 +246,11 @@ color mappings. Each entry is separated by a comma and/or whitespaces.
|
|||||||
|
|
||||||
.RS
|
.RS
|
||||||
.B BASE SCHEME:
|
.B BASE SCHEME:
|
||||||
(default: \fBdark\fR on 256-color terminal, otherwise \fB16\fR; If \fBNO_COLOR\fR is set, \fBbw\fR)
|
(default: \fBdark\fR on 256-color terminal, otherwise \fBbase16\fR; If \fBNO_COLOR\fR is set, \fBbw\fR)
|
||||||
|
|
||||||
\fBdark \fRColor scheme for dark 256-color terminal
|
\fBdark \fRColor scheme for dark terminal
|
||||||
\fBlight \fRColor scheme for light 256-color terminal
|
\fBlight \fRColor scheme for light terminal
|
||||||
\fB16 \fRColor scheme for 16-color terminal
|
\fBbase16 \fRColor scheme using base 16 colors (alias: \fB16\fR)
|
||||||
\fBbw \fRNo colors (equivalent to \fB\-\-no\-color\fR)
|
\fBbw \fRNo colors (equivalent to \fB\-\-no\-color\fR)
|
||||||
|
|
||||||
.B COLOR NAMES:
|
.B COLOR NAMES:
|
||||||
@@ -299,6 +299,7 @@ color mappings. Each entry is separated by a comma and/or whitespaces.
|
|||||||
\fBheader (header\-fg) \fRHeader
|
\fBheader (header\-fg) \fRHeader
|
||||||
\fBfooter (footer\-fg) \fRFooter
|
\fBfooter (footer\-fg) \fRFooter
|
||||||
\fBnth \fRParts of the line specified by \fB\-\-nth\fR (only supports attributes)
|
\fBnth \fRParts of the line specified by \fB\-\-nth\fR (only supports attributes)
|
||||||
|
\fBnomatch \fRNon-matching items in raw mode (default: \fBdim\fR)
|
||||||
|
|
||||||
.B ANSI COLORS:
|
.B ANSI COLORS:
|
||||||
\fB\-1 \fRDefault terminal foreground/background color
|
\fB\-1 \fRDefault terminal foreground/background color
|
||||||
@@ -324,7 +325,8 @@ color mappings. Each entry is separated by a comma and/or whitespaces.
|
|||||||
\fB#rrggbb \fR24-bit colors
|
\fB#rrggbb \fR24-bit colors
|
||||||
|
|
||||||
.B ANSI ATTRIBUTES: (Only applies to foreground colors)
|
.B ANSI ATTRIBUTES: (Only applies to foreground colors)
|
||||||
\fBregular \fRClears previously set attributes; should precede the other ones
|
\fBregular \fRClear previously set attributes; should precede the other ones
|
||||||
|
\fBstrip \fRRemove colors
|
||||||
\fBbold\fR
|
\fBbold\fR
|
||||||
\fBunderline\fR
|
\fBunderline\fR
|
||||||
\fBreverse\fR
|
\fBreverse\fR
|
||||||
@@ -596,6 +598,9 @@ Indicator for wrapped lines. The default is '↳ ' or '> ' depending on
|
|||||||
.B "\-\-no\-multi\-line"
|
.B "\-\-no\-multi\-line"
|
||||||
Disable multi-line display of items when using \fB\-\-read0\fR
|
Disable multi-line display of items when using \fB\-\-read0\fR
|
||||||
.TP
|
.TP
|
||||||
|
.B "\-\-raw"
|
||||||
|
Enable raw mode where non-matching items are also displayed in a dimmed color.
|
||||||
|
.TP
|
||||||
.B "\-\-track"
|
.B "\-\-track"
|
||||||
Make fzf track the current selection when the result list is updated.
|
Make fzf track the current selection when the result list is updated.
|
||||||
This can be useful when browsing logs using fzf with sorting disabled. It is
|
This can be useful when browsing logs using fzf with sorting disabled. It is
|
||||||
@@ -643,6 +648,12 @@ on the center of the screen.
|
|||||||
.BI "\-\-jump\-labels=" "CHARS"
|
.BI "\-\-jump\-labels=" "CHARS"
|
||||||
Label characters for \fBjump\fR mode.
|
Label characters for \fBjump\fR mode.
|
||||||
.TP
|
.TP
|
||||||
|
.BI "\-\-gutter=" "CHAR"
|
||||||
|
Character used for the gutter column (default: '▌' unless \fB\-\-no\-unicode\fR is given)
|
||||||
|
.TP
|
||||||
|
.BI "\-\-gutter\-raw=" "CHAR"
|
||||||
|
Character used for the gutter column in raw mode (default: '▖' unless \fB\-\-no\-unicode\fR is given)
|
||||||
|
.TP
|
||||||
.BI "\-\-pointer=" "STR"
|
.BI "\-\-pointer=" "STR"
|
||||||
Pointer to the current line (default: '▌' or '>' depending on \fB\-\-no\-unicode\fR)
|
Pointer to the current line (default: '▌' or '>' depending on \fB\-\-no\-unicode\fR)
|
||||||
.TP
|
.TP
|
||||||
@@ -1125,19 +1136,25 @@ On Windows, the default value is \fBcmd /s/c\fR when \fB$SHELL\fR is not
|
|||||||
set.
|
set.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B "\-\-listen[=[ADDR:]PORT]" "\-\-listen\-unsafe[=[ADDR:]PORT]"
|
.B "\-\-listen[=SOCKET_PATH|[ADDR:]PORT]" "\-\-listen\-unsafe[=[ADDR:]PORT]"
|
||||||
Start HTTP server and listen on the given address. It allows external processes
|
Start HTTP server and listen on the given address or Unix socket. It allows
|
||||||
to send actions to perform via POST method.
|
external processes to send actions to perform via POST method and query the
|
||||||
|
program state via GET method. For the argument to be recognized as a socket
|
||||||
|
path, it must have \fB.sock\fR extension.
|
||||||
|
|
||||||
- If the port number is omitted or given as 0, fzf will automatically choose
|
- If the port number is omitted or given as 0, fzf will automatically choose
|
||||||
a port and export it as \fBFZF_PORT\fR environment variable to the child processes
|
a port and export it as \fBFZF_PORT\fR environment variable to the child processes.
|
||||||
|
|
||||||
|
- If a Unix socket path is given, fzf will create a Unix domain socket at the
|
||||||
|
given path. The existing file will be removed. The path to the socket file
|
||||||
|
is exported as \fBFZF_SOCK\fR environment variable.
|
||||||
|
|
||||||
- If \fBFZF_API_KEY\fR environment variable is set, the server would require
|
- If \fBFZF_API_KEY\fR environment variable is set, the server would require
|
||||||
sending an API key with the same value in the \fBx\-api\-key\fR HTTP header
|
sending an API key with the same value in the \fBx\-api\-key\fR HTTP header.
|
||||||
|
|
||||||
- \fBFZF_API_KEY\fR is required for a non-localhost listen address
|
- \fBFZF_API_KEY\fR is required for a non-localhost listen address.
|
||||||
|
|
||||||
- To allow remote process execution, use \fB\-\-listen\-unsafe\fR
|
- To allow remote process execution, use \fB\-\-listen\-unsafe\fR.
|
||||||
|
|
||||||
e.g.
|
e.g.
|
||||||
\fB# Start HTTP server on port 6266
|
\fB# Start HTTP server on port 6266
|
||||||
@@ -1176,6 +1193,18 @@ e.g.
|
|||||||
'
|
'
|
||||||
\fR
|
\fR
|
||||||
|
|
||||||
|
Here is an example script that uses a Unix socket instead of a TCP port.
|
||||||
|
|
||||||
|
\fB
|
||||||
|
fzf --listen=/tmp/fzf.sock
|
||||||
|
|
||||||
|
# GET
|
||||||
|
curl --unix-socket /tmp/fzf.sock http
|
||||||
|
|
||||||
|
# POST
|
||||||
|
curl --unix-socket /tmp/fzf.sock http -d up
|
||||||
|
\fR
|
||||||
|
|
||||||
.SS DIRECTORY TRAVERSAL
|
.SS DIRECTORY TRAVERSAL
|
||||||
.TP
|
.TP
|
||||||
.B "\-\-walker=[file][,dir][,follow][,hidden]"
|
.B "\-\-walker=[file][,dir][,follow][,hidden]"
|
||||||
@@ -1327,6 +1356,8 @@ fzf exports the following environment variables to its child processes.
|
|||||||
.br
|
.br
|
||||||
.BR FZF_COLUMNS " Number of columns fzf takes up excluding padding and margin"
|
.BR FZF_COLUMNS " Number of columns fzf takes up excluding padding and margin"
|
||||||
.br
|
.br
|
||||||
|
.BR FZF_DIRECTION " Direction of the list (\fBup\fR or \fBdown\fR)"
|
||||||
|
.br
|
||||||
.BR FZF_TOTAL_COUNT " Total number of items"
|
.BR FZF_TOTAL_COUNT " Total number of items"
|
||||||
.br
|
.br
|
||||||
.BR FZF_MATCH_COUNT " Number of matched items"
|
.BR FZF_MATCH_COUNT " Number of matched items"
|
||||||
@@ -1363,6 +1394,8 @@ fzf exports the following environment variables to its child processes.
|
|||||||
.br
|
.br
|
||||||
.BR FZF_PORT " Port number when \-\-listen option is used"
|
.BR FZF_PORT " Port number when \-\-listen option is used"
|
||||||
.br
|
.br
|
||||||
|
.BR FZF_SOCK " Unix socket path when \-\-listen option is used"
|
||||||
|
.br
|
||||||
.BR FZF_PREVIEW_TOP " Top position of the preview window"
|
.BR FZF_PREVIEW_TOP " Top position of the preview window"
|
||||||
.br
|
.br
|
||||||
.BR FZF_PREVIEW_LEFT " Left position of the preview window"
|
.BR FZF_PREVIEW_LEFT " Left position of the preview window"
|
||||||
@@ -1370,6 +1403,8 @@ fzf exports the following environment variables to its child processes.
|
|||||||
.BR FZF_PREVIEW_LINES " Number of lines in the preview window"
|
.BR FZF_PREVIEW_LINES " Number of lines in the preview window"
|
||||||
.br
|
.br
|
||||||
.BR FZF_PREVIEW_COLUMNS " Number of columns in the preview window"
|
.BR FZF_PREVIEW_COLUMNS " Number of columns in the preview window"
|
||||||
|
.br
|
||||||
|
.BR FZF_RAW " Only in raw mode. 1 if the current item matches, 0 otherwise"
|
||||||
|
|
||||||
.SH EXTENDED SEARCH MODE
|
.SH EXTENDED SEARCH MODE
|
||||||
|
|
||||||
@@ -1814,6 +1849,7 @@ A key or an event can be bound to one or more of the following actions.
|
|||||||
\fBbecome(...)\fR (replace fzf process with the specified command; see below for the details)
|
\fBbecome(...)\fR (replace fzf process with the specified command; see below for the details)
|
||||||
\fBbeginning\-of\-line\fR \fIctrl\-a home\fR
|
\fBbeginning\-of\-line\fR \fIctrl\-a home\fR
|
||||||
\fBbell\fR (ring the terminal bell)
|
\fBbell\fR (ring the terminal bell)
|
||||||
|
\fBbest\fR (move to the best match; same as \fBfirst\fR if raw mode is disabled)
|
||||||
\fBbg\-cancel\fR (cancel background transform processes)
|
\fBbg\-cancel\fR (cancel background transform processes)
|
||||||
\fBcancel\fR (clear query string if not empty, abort fzf otherwise)
|
\fBcancel\fR (clear query string if not empty, abort fzf otherwise)
|
||||||
\fBchange\-border\-label(...)\fR (change \fB\-\-border\-label\fR to the given string)
|
\fBchange\-border\-label(...)\fR (change \fB\-\-border\-label\fR to the given string)
|
||||||
@@ -1838,9 +1874,13 @@ A key or an event can be bound to one or more of the following actions.
|
|||||||
\fBdelete\-char\fR \fIdel\fR
|
\fBdelete\-char\fR \fIdel\fR
|
||||||
\fBdelete\-char/eof\fR \fIctrl\-d\fR (same as \fBdelete\-char\fR except aborts fzf if query is empty)
|
\fBdelete\-char/eof\fR \fIctrl\-d\fR (same as \fBdelete\-char\fR except aborts fzf if query is empty)
|
||||||
\fBdeselect\fR
|
\fBdeselect\fR
|
||||||
\fBdeselect\-all\fR (deselect all matches; to also clear non-matched selections, use \fBclear\-multi\fR)
|
\fBdeselect\-all\fR (deselect all matches; to also clear non-matching selections, use \fBclear\-multi\fR)
|
||||||
|
\fBdisable\-raw\fR (disable raw mode)
|
||||||
\fBdisable\-search\fR (disable search functionality)
|
\fBdisable\-search\fR (disable search functionality)
|
||||||
\fBdown\fR \fIctrl\-j ctrl\-n down\fR
|
\fBdown\fR \fIctrl\-j down\fR
|
||||||
|
\fBdown\-match\fR \fIctrl\-n\fR \fIalt\-down\fR (move to the match below the cursor)
|
||||||
|
\fBdown\-selected\fR (move to the selected item below the cursor)
|
||||||
|
\fBenable\-raw\fR (enable raw mode)
|
||||||
\fBenable\-search\fR (enable search functionality)
|
\fBenable\-search\fR (enable search functionality)
|
||||||
\fBend\-of\-line\fR \fIctrl\-e end\fR
|
\fBend\-of\-line\fR \fIctrl\-e end\fR
|
||||||
\fBexclude\fR (exclude the current item from the result)
|
\fBexclude\fR (exclude the current item from the result)
|
||||||
@@ -1858,7 +1898,7 @@ A key or an event can be bound to one or more of the following actions.
|
|||||||
\fBkill\-word\fR \fIalt\-d\fR
|
\fBkill\-word\fR \fIalt\-d\fR
|
||||||
\fBlast\fR (move to the last match; same as \fBpos(\-1)\fR)
|
\fBlast\fR (move to the last match; same as \fBpos(\-1)\fR)
|
||||||
\fBnext\-history\fR (\fIctrl\-n\fR on \fB\-\-history\fR)
|
\fBnext\-history\fR (\fIctrl\-n\fR on \fB\-\-history\fR)
|
||||||
\fBnext\-selected\fR (move to the next selected item)
|
\fBnext\-selected\fR (synonym to \fBdown\-selected\fR)
|
||||||
\fBpage\-down\fR \fIpgdn\fR
|
\fBpage\-down\fR \fIpgdn\fR
|
||||||
\fBpage\-up\fR \fIpgup\fR
|
\fBpage\-up\fR \fIpgup\fR
|
||||||
\fBhalf\-page\-down\fR
|
\fBhalf\-page\-down\fR
|
||||||
@@ -1871,7 +1911,7 @@ A key or an event can be bound to one or more of the following actions.
|
|||||||
\fBoffset\-middle\fR (place the current item is in the middle of the screen)
|
\fBoffset\-middle\fR (place the current item is in the middle of the screen)
|
||||||
\fBpos(...)\fR (move cursor to the numeric position; negative number to count from the end)
|
\fBpos(...)\fR (move cursor to the numeric position; negative number to count from the end)
|
||||||
\fBprev\-history\fR (\fIctrl\-p\fR on \fB\-\-history\fR)
|
\fBprev\-history\fR (\fIctrl\-p\fR on \fB\-\-history\fR)
|
||||||
\fBprev\-selected\fR (move to the previous selected item)
|
\fBprev\-selected\fR (synonym to \fBup\-selected\fR)
|
||||||
\fBpreview(...)\fR (see below for the details)
|
\fBpreview(...)\fR (see below for the details)
|
||||||
\fBpreview\-down\fR \fIshift\-down\fR
|
\fBpreview\-down\fR \fIshift\-down\fR
|
||||||
\fBpreview\-up\fR \fIshift\-up\fR
|
\fBpreview\-up\fR \fIshift\-up\fR
|
||||||
@@ -1906,6 +1946,7 @@ A key or an event can be bound to one or more of the following actions.
|
|||||||
\fBtoggle\-multi\-line\fR
|
\fBtoggle\-multi\-line\fR
|
||||||
\fBtoggle\-preview\fR
|
\fBtoggle\-preview\fR
|
||||||
\fBtoggle\-preview\-wrap\fR
|
\fBtoggle\-preview\-wrap\fR
|
||||||
|
\fBtoggle\-raw\fR (toggle raw mode for displaying non-matching items)
|
||||||
\fBtoggle\-search\fR (toggle search functionality)
|
\fBtoggle\-search\fR (toggle search functionality)
|
||||||
\fBtoggle\-sort\fR
|
\fBtoggle\-sort\fR
|
||||||
\fBtoggle\-track\fR (toggle global tracking option (\fB\-\-track\fR))
|
\fBtoggle\-track\fR (toggle global tracking option (\fB\-\-track\fR))
|
||||||
@@ -1932,7 +1973,9 @@ A key or an event can be bound to one or more of the following actions.
|
|||||||
\fBunix\-line\-discard\fR \fIctrl\-u\fR
|
\fBunix\-line\-discard\fR \fIctrl\-u\fR
|
||||||
\fBunix\-word\-rubout\fR \fIctrl\-w\fR
|
\fBunix\-word\-rubout\fR \fIctrl\-w\fR
|
||||||
\fBuntrack\-current\fR (stop tracking the current item; no-op if global tracking is enabled)
|
\fBuntrack\-current\fR (stop tracking the current item; no-op if global tracking is enabled)
|
||||||
\fBup\fR \fIctrl\-k ctrl\-p up\fR
|
\fBup\fR \fIctrl\-k up\fR
|
||||||
|
\fBup\-match\fR \fIctrl\-p\fR \fIalt\-up\fR (move to the match above the cursor)
|
||||||
|
\fBup\-selected\fR (move to the selected item above the cursor)
|
||||||
\fByank\fR \fIctrl\-y\fR
|
\fByank\fR \fIctrl\-y\fR
|
||||||
|
|
||||||
Each \fBtransform*\fR action has a corresponding \fBbg\-transform*\fR
|
Each \fBtransform*\fR action has a corresponding \fBbg\-transform*\fR
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
__fzf_defaults() {
|
__fzf_defaults() {
|
||||||
# $1: Prepend to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
|
# $1: Prepend to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
|
||||||
# $2: Append to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
|
# $2: Append to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
|
||||||
@@ -27,7 +26,10 @@ __fzf_exec_awk() {
|
|||||||
# version >= 1.3.4
|
# version >= 1.3.4
|
||||||
local n x y z d
|
local n x y z d
|
||||||
IFS=' .' read -r n x y z d <<< $(command mawk -W version 2> /dev/null)
|
IFS=' .' read -r n x y z d <<< $(command mawk -W version 2> /dev/null)
|
||||||
[[ $n == mawk ]] && (( d >= 20230302 && (x * 1000 + y) * 1000 + z >= 1003004 )) && __fzf_awk=mawk
|
[[ $n == mawk ]] &&
|
||||||
|
(((x * 1000 + y) * 1000 + z >= 1003004)) 2> /dev/null &&
|
||||||
|
((d >= 20230302)) 2> /dev/null &&
|
||||||
|
__fzf_awk=mawk
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
# Note: macOS awk has a quirk that it stops processing at all when it sees
|
# Note: macOS awk has a quirk that it stops processing at all when it sees
|
||||||
|
|||||||
@@ -31,9 +31,10 @@ if [[ $- =~ i ]]; then
|
|||||||
|
|
||||||
###########################################################
|
###########################################################
|
||||||
|
|
||||||
|
#----BEGIN shfmt
|
||||||
#----BEGIN INCLUDE common.sh
|
#----BEGIN INCLUDE common.sh
|
||||||
# NOTE: Do not directly edit this section, which is copied from "common.sh".
|
# NOTE: Do not directly edit this section, which is copied from "common.sh".
|
||||||
# To modify it, one can edit "common.sh" and run "./update-common.sh" to apply
|
# To modify it, one can edit "common.sh" and run "./update.sh" to apply
|
||||||
# the changes. See code comments in "common.sh" for the implementation details.
|
# the changes. See code comments in "common.sh" for the implementation details.
|
||||||
|
|
||||||
__fzf_defaults() {
|
__fzf_defaults() {
|
||||||
@@ -50,7 +51,10 @@ __fzf_exec_awk() {
|
|||||||
elif command -v mawk > /dev/null 2>&1; then
|
elif command -v mawk > /dev/null 2>&1; then
|
||||||
local n x y z d
|
local n x y z d
|
||||||
IFS=' .' read -r n x y z d <<< $(command mawk -W version 2> /dev/null)
|
IFS=' .' read -r n x y z d <<< $(command mawk -W version 2> /dev/null)
|
||||||
[[ $n == mawk ]] && (( d >= 20230302 && (x * 1000 + y) * 1000 + z >= 1003004 )) && __fzf_awk=mawk
|
[[ $n == mawk ]] &&
|
||||||
|
(((x * 1000 + y) * 1000 + z >= 1003004)) 2> /dev/null &&
|
||||||
|
((d >= 20230302)) 2> /dev/null &&
|
||||||
|
__fzf_awk=mawk
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
LC_ALL=C exec "$__fzf_awk" "$@"
|
LC_ALL=C exec "$__fzf_awk" "$@"
|
||||||
@@ -58,9 +62,9 @@ __fzf_exec_awk() {
|
|||||||
#----END INCLUDE
|
#----END INCLUDE
|
||||||
|
|
||||||
__fzf_comprun() {
|
__fzf_comprun() {
|
||||||
if [[ "$(type -t _fzf_comprun 2>&1)" = function ]]; then
|
if [[ "$(type -t _fzf_comprun 2>&1)" == function ]]; then
|
||||||
_fzf_comprun "$@"
|
_fzf_comprun "$@"
|
||||||
elif [[ -n "${TMUX_PANE-}" ]] && { [[ "${FZF_TMUX:-0}" != 0 ]] || [[ -n "${FZF_TMUX_OPTS-}" ]]; }; then
|
elif [[ -n ${TMUX_PANE-} ]] && { [[ ${FZF_TMUX:-0} != 0 ]] || [[ -n ${FZF_TMUX_OPTS-} ]]; }; then
|
||||||
shift
|
shift
|
||||||
fzf-tmux ${FZF_TMUX_OPTS:--d${FZF_TMUX_HEIGHT:-40%}} -- "$@"
|
fzf-tmux ${FZF_TMUX_OPTS:--d${FZF_TMUX_HEIGHT:-40%}} -- "$@"
|
||||||
else
|
else
|
||||||
@@ -72,13 +76,13 @@ __fzf_comprun() {
|
|||||||
__fzf_orig_completion() {
|
__fzf_orig_completion() {
|
||||||
local l comp f cmd
|
local l comp f cmd
|
||||||
while read -r l; do
|
while read -r l; do
|
||||||
if [[ "$l" =~ ^(.*\ -F)\ *([^ ]*).*\ ([^ ]*)$ ]]; then
|
if [[ $l =~ ^(.*\ -F)\ *([^ ]*).*\ ([^ ]*)$ ]]; then
|
||||||
comp="${BASH_REMATCH[1]}"
|
comp="${BASH_REMATCH[1]}"
|
||||||
f="${BASH_REMATCH[2]}"
|
f="${BASH_REMATCH[2]}"
|
||||||
cmd="${BASH_REMATCH[3]}"
|
cmd="${BASH_REMATCH[3]}"
|
||||||
[[ "$f" = _fzf_* ]] && continue
|
[[ $f == _fzf_* ]] && continue
|
||||||
printf -v "_fzf_orig_completion_${cmd//[^A-Za-z0-9_]/_}" "%s" "${comp} %s ${cmd} #${f}"
|
printf -v "_fzf_orig_completion_${cmd//[^A-Za-z0-9_]/_}" "%s" "${comp} %s ${cmd} #${f}"
|
||||||
if [[ "$l" = *" -o nospace "* ]] && [[ ! "${__fzf_nospace_commands-}" = *" $cmd "* ]]; then
|
if [[ $l == *" -o nospace "* ]] && [[ ${__fzf_nospace_commands-} != *" $cmd "* ]]; then
|
||||||
__fzf_nospace_commands="${__fzf_nospace_commands-} $cmd "
|
__fzf_nospace_commands="${__fzf_nospace_commands-} $cmd "
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -257,7 +261,7 @@ _fzf_opts_completion() {
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if [[ "$cur" =~ ^-|\+ ]]; then
|
if [[ $cur =~ ^-|\+ ]]; then
|
||||||
COMPREPLY=($(compgen -W "${opts}" -- "$cur"))
|
COMPREPLY=($(compgen -W "${opts}" -- "$cur"))
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@@ -272,7 +276,7 @@ _fzf_handle_dynamic_completion() {
|
|||||||
orig_cmd="$1"
|
orig_cmd="$1"
|
||||||
if __fzf_orig_completion_get_orig_func "$cmd"; then
|
if __fzf_orig_completion_get_orig_func "$cmd"; then
|
||||||
"$REPLY" "$@"
|
"$REPLY" "$@"
|
||||||
elif [[ -n "${_fzf_completion_loader-}" ]]; then
|
elif [[ -n ${_fzf_completion_loader-} ]]; then
|
||||||
orig_complete=$(complete -p "$orig_cmd" 2> /dev/null)
|
orig_complete=$(complete -p "$orig_cmd" 2> /dev/null)
|
||||||
$_fzf_completion_loader "$@"
|
$_fzf_completion_loader "$@"
|
||||||
ret=$?
|
ret=$?
|
||||||
@@ -286,7 +290,7 @@ _fzf_handle_dynamic_completion() {
|
|||||||
__fzf_orig_completion_instantiate "$cmd" "${BASH_REMATCH[1]}" &&
|
__fzf_orig_completion_instantiate "$cmd" "${BASH_REMATCH[1]}" &&
|
||||||
orig_complete=$REPLY
|
orig_complete=$REPLY
|
||||||
|
|
||||||
if [[ "${__fzf_nospace_commands-}" = *" $orig_cmd "* ]]; then
|
if [[ ${__fzf_nospace_commands-} == *" $orig_cmd "* ]]; then
|
||||||
eval "${orig_complete/ -F / -o nospace -F }"
|
eval "${orig_complete/ -F / -o nospace -F }"
|
||||||
else
|
else
|
||||||
eval "$orig_complete"
|
eval "$orig_complete"
|
||||||
@@ -306,18 +310,18 @@ __fzf_generic_path_completion() {
|
|||||||
COMPREPLY=()
|
COMPREPLY=()
|
||||||
trigger=${FZF_COMPLETION_TRIGGER-'**'}
|
trigger=${FZF_COMPLETION_TRIGGER-'**'}
|
||||||
[[ $COMP_CWORD -ge 0 ]] && cur="${COMP_WORDS[COMP_CWORD]}"
|
[[ $COMP_CWORD -ge 0 ]] && cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
if [[ "$cur" == *"$trigger" ]] && [[ $cur != *'$('* ]] && [[ $cur != *':='* ]] && [[ $cur != *'`'* ]]; then
|
if [[ $cur == *"$trigger" ]] && [[ $cur != *'$('* ]] && [[ $cur != *':='* ]] && [[ $cur != *'`'* ]]; then
|
||||||
base=${cur:0:${#cur}-${#trigger}}
|
base=${cur:0:${#cur}-${#trigger}}
|
||||||
eval "base=$base" 2> /dev/null || return
|
eval "base=$base" 2> /dev/null || return
|
||||||
|
|
||||||
dir=
|
dir=
|
||||||
[[ $base = *"/"* ]] && dir="$base"
|
[[ $base == *"/"* ]] && dir="$base"
|
||||||
while true; do
|
while true; do
|
||||||
if [[ -z "$dir" ]] || [[ -d "$dir" ]]; then
|
if [[ -z $dir ]] || [[ -d $dir ]]; then
|
||||||
leftover=${base/#"$dir"}
|
leftover=${base/#"$dir"/}
|
||||||
leftover=${leftover/#\/}
|
leftover=${leftover/#\//}
|
||||||
[[ -z "$dir" ]] && dir='.'
|
[[ -z $dir ]] && dir='.'
|
||||||
[[ "$dir" != "/" ]] && dir="${dir/%\//}"
|
[[ $dir != "/" ]] && dir="${dir/%\//}"
|
||||||
matches=$(
|
matches=$(
|
||||||
export FZF_DEFAULT_OPTS=$(__fzf_defaults "--reverse --scheme=path" "${FZF_COMPLETION_OPTS-} $2")
|
export FZF_DEFAULT_OPTS=$(__fzf_defaults "--reverse --scheme=path" "${FZF_COMPLETION_OPTS-} $2")
|
||||||
unset FZF_DEFAULT_COMMAND FZF_DEFAULT_OPTS_FILE
|
unset FZF_DEFAULT_COMMAND FZF_DEFAULT_OPTS_FILE
|
||||||
@@ -337,8 +341,8 @@ __fzf_generic_path_completion() {
|
|||||||
done
|
done
|
||||||
)
|
)
|
||||||
matches=${matches% }
|
matches=${matches% }
|
||||||
[[ -z "$3" ]] && [[ "${__fzf_nospace_commands-}" = *" ${COMP_WORDS[0]} "* ]] && matches="$matches "
|
[[ -z $3 ]] && [[ ${__fzf_nospace_commands-} == *" ${COMP_WORDS[0]} "* ]] && matches="$matches "
|
||||||
if [[ -n "$matches" ]]; then
|
if [[ -n $matches ]]; then
|
||||||
COMPREPLY=("$matches")
|
COMPREPLY=("$matches")
|
||||||
else
|
else
|
||||||
COMPREPLY=("$cur")
|
COMPREPLY=("$cur")
|
||||||
@@ -349,7 +353,7 @@ __fzf_generic_path_completion() {
|
|||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
dir=$(command dirname "$dir")
|
dir=$(command dirname "$dir")
|
||||||
[[ "$dir" =~ /$ ]] || dir="$dir"/
|
[[ $dir =~ /$ ]] || dir="$dir"/
|
||||||
done
|
done
|
||||||
else
|
else
|
||||||
shift
|
shift
|
||||||
@@ -365,15 +369,15 @@ _fzf_complete() {
|
|||||||
args=("$@")
|
args=("$@")
|
||||||
sep=
|
sep=
|
||||||
for i in "${!args[@]}"; do
|
for i in "${!args[@]}"; do
|
||||||
if [[ "${args[$i]}" = -- ]]; then
|
if [[ ${args[$i]} == -- ]]; then
|
||||||
sep=$i
|
sep=$i
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
if [[ -n "$sep" ]]; then
|
if [[ -n $sep ]]; then
|
||||||
str_arg=
|
str_arg=
|
||||||
rest=("${args[@]:$((sep + 1)):${#args[@]}}")
|
rest=("${args[@]:$((sep + 1)):${#args[@]}}")
|
||||||
args=("${args[@]:0:$sep}")
|
args=("${args[@]:0:sep}")
|
||||||
else
|
else
|
||||||
str_arg=$1
|
str_arg=$1
|
||||||
args=()
|
args=()
|
||||||
@@ -388,15 +392,16 @@ _fzf_complete() {
|
|||||||
trigger=${FZF_COMPLETION_TRIGGER-'**'}
|
trigger=${FZF_COMPLETION_TRIGGER-'**'}
|
||||||
cmd="${COMP_WORDS[0]}"
|
cmd="${COMP_WORDS[0]}"
|
||||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
if [[ "$cur" == *"$trigger" ]] && [[ $cur != *'$('* ]] && [[ $cur != *':='* ]] && [[ $cur != *'`'* ]]; then
|
if [[ $cur == *"$trigger" ]] && [[ $cur != *'$('* ]] && [[ $cur != *':='* ]] && [[ $cur != *'`'* ]]; then
|
||||||
cur=${cur:0:${#cur}-${#trigger}}
|
cur=${cur:0:${#cur}-${#trigger}}
|
||||||
|
|
||||||
selected=$(
|
selected=$(
|
||||||
FZF_DEFAULT_OPTS=$(__fzf_defaults "--reverse" "${FZF_COMPLETION_OPTS-} $str_arg") \
|
FZF_DEFAULT_OPTS=$(__fzf_defaults "--reverse" "${FZF_COMPLETION_OPTS-} $str_arg") \
|
||||||
FZF_DEFAULT_OPTS_FILE='' \
|
FZF_DEFAULT_OPTS_FILE='' \
|
||||||
__fzf_comprun "${rest[0]}" "${args[@]}" -q "$cur" | eval "$post" | command tr '\n' ' ')
|
__fzf_comprun "${rest[0]}" "${args[@]}" -q "$cur" | eval "$post" | command tr '\n' ' '
|
||||||
|
)
|
||||||
selected=${selected% } # Strip trailing space not to repeat "-o nospace"
|
selected=${selected% } # Strip trailing space not to repeat "-o nospace"
|
||||||
if [[ -n "$selected" ]]; then
|
if [[ -n $selected ]]; then
|
||||||
COMPREPLY=("$selected")
|
COMPREPLY=("$selected")
|
||||||
else
|
else
|
||||||
COMPREPLY=("$cur")
|
COMPREPLY=("$cur")
|
||||||
@@ -545,7 +550,7 @@ _fzf_complete_ssh() {
|
|||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
local user=
|
local user=
|
||||||
[[ "$2" =~ '@' ]] && user="${2%%@*}@"
|
[[ $2 =~ '@' ]] && user="${2%%@*}@"
|
||||||
_fzf_complete +m -- "$@" < <(__fzf_list_hosts | __fzf_exec_awk -v user="$user" '{print user $0}')
|
_fzf_complete +m -- "$@" < <(__fzf_list_hosts | __fzf_exec_awk -v user="$user" '{print user $0}')
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@@ -683,5 +688,6 @@ _fzf_setup_completion() {
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
#----END shfmt
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ if [[ -o interactive ]]; then
|
|||||||
|
|
||||||
#----BEGIN INCLUDE common.sh
|
#----BEGIN INCLUDE common.sh
|
||||||
# NOTE: Do not directly edit this section, which is copied from "common.sh".
|
# NOTE: Do not directly edit this section, which is copied from "common.sh".
|
||||||
# To modify it, one can edit "common.sh" and run "./update-common.sh" to apply
|
# To modify it, one can edit "common.sh" and run "./update.sh" to apply
|
||||||
# the changes. See code comments in "common.sh" for the implementation details.
|
# the changes. See code comments in "common.sh" for the implementation details.
|
||||||
|
|
||||||
__fzf_defaults() {
|
__fzf_defaults() {
|
||||||
@@ -115,7 +115,10 @@ __fzf_exec_awk() {
|
|||||||
elif command -v mawk > /dev/null 2>&1; then
|
elif command -v mawk > /dev/null 2>&1; then
|
||||||
local n x y z d
|
local n x y z d
|
||||||
IFS=' .' read -r n x y z d <<< $(command mawk -W version 2> /dev/null)
|
IFS=' .' read -r n x y z d <<< $(command mawk -W version 2> /dev/null)
|
||||||
[[ $n == mawk ]] && (( d >= 20230302 && (x * 1000 + y) * 1000 + z >= 1003004 )) && __fzf_awk=mawk
|
[[ $n == mawk ]] &&
|
||||||
|
(((x * 1000 + y) * 1000 + z >= 1003004)) 2> /dev/null &&
|
||||||
|
((d >= 20230302)) 2> /dev/null &&
|
||||||
|
__fzf_awk=mawk
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
LC_ALL=C exec "$__fzf_awk" "$@"
|
LC_ALL=C exec "$__fzf_awk" "$@"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
# - $FZF_TMUX_OPTS
|
# - $FZF_TMUX_OPTS
|
||||||
# - $FZF_CTRL_T_COMMAND
|
# - $FZF_CTRL_T_COMMAND
|
||||||
# - $FZF_CTRL_T_OPTS
|
# - $FZF_CTRL_T_OPTS
|
||||||
|
# - $FZF_CTRL_R_COMMAND
|
||||||
# - $FZF_CTRL_R_OPTS
|
# - $FZF_CTRL_R_OPTS
|
||||||
# - $FZF_ALT_C_COMMAND
|
# - $FZF_ALT_C_COMMAND
|
||||||
# - $FZF_ALT_C_OPTS
|
# - $FZF_ALT_C_OPTS
|
||||||
@@ -17,9 +18,10 @@ if [[ $- =~ i ]]; then
|
|||||||
# Key bindings
|
# Key bindings
|
||||||
# ------------
|
# ------------
|
||||||
|
|
||||||
|
#----BEGIN shfmt
|
||||||
#----BEGIN INCLUDE common.sh
|
#----BEGIN INCLUDE common.sh
|
||||||
# NOTE: Do not directly edit this section, which is copied from "common.sh".
|
# NOTE: Do not directly edit this section, which is copied from "common.sh".
|
||||||
# To modify it, one can edit "common.sh" and run "./update-common.sh" to apply
|
# To modify it, one can edit "common.sh" and run "./update.sh" to apply
|
||||||
# the changes. See code comments in "common.sh" for the implementation details.
|
# the changes. See code comments in "common.sh" for the implementation details.
|
||||||
|
|
||||||
__fzf_defaults() {
|
__fzf_defaults() {
|
||||||
@@ -36,7 +38,10 @@ __fzf_exec_awk() {
|
|||||||
elif command -v mawk > /dev/null 2>&1; then
|
elif command -v mawk > /dev/null 2>&1; then
|
||||||
local n x y z d
|
local n x y z d
|
||||||
IFS=' .' read -r n x y z d <<< $(command mawk -W version 2> /dev/null)
|
IFS=' .' read -r n x y z d <<< $(command mawk -W version 2> /dev/null)
|
||||||
[[ $n == mawk ]] && (( d >= 20230302 && (x * 1000 + y) * 1000 + z >= 1003004 )) && __fzf_awk=mawk
|
[[ $n == mawk ]] &&
|
||||||
|
(((x * 1000 + y) * 1000 + z >= 1003004)) 2> /dev/null &&
|
||||||
|
((d >= 20230302)) 2> /dev/null &&
|
||||||
|
__fzf_awk=mawk
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
LC_ALL=C exec "$__fzf_awk" "$@"
|
LC_ALL=C exec "$__fzf_awk" "$@"
|
||||||
@@ -53,13 +58,13 @@ __fzf_select__() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
__fzfcmd() {
|
__fzfcmd() {
|
||||||
[[ -n "${TMUX_PANE-}" ]] && { [[ "${FZF_TMUX:-0}" != 0 ]] || [[ -n "${FZF_TMUX_OPTS-}" ]]; } &&
|
[[ -n ${TMUX_PANE-} ]] && { [[ ${FZF_TMUX:-0} != 0 ]] || [[ -n ${FZF_TMUX_OPTS-} ]]; } &&
|
||||||
echo "fzf-tmux ${FZF_TMUX_OPTS:--d${FZF_TMUX_HEIGHT:-40%}} -- " || echo "fzf"
|
echo "fzf-tmux ${FZF_TMUX_OPTS:--d${FZF_TMUX_HEIGHT:-40%}} -- " || echo "fzf"
|
||||||
}
|
}
|
||||||
|
|
||||||
fzf-file-widget() {
|
fzf-file-widget() {
|
||||||
local selected="$(__fzf_select__ "$@")"
|
local selected="$(__fzf_select__ "$@")"
|
||||||
READLINE_LINE="${READLINE_LINE:0:$READLINE_POINT}$selected${READLINE_LINE:$READLINE_POINT}"
|
READLINE_LINE="${READLINE_LINE:0:READLINE_POINT}$selected${READLINE_LINE:READLINE_POINT}"
|
||||||
READLINE_POINT=$((READLINE_POINT + ${#selected}))
|
READLINE_POINT=$((READLINE_POINT + ${#selected}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,11 +85,11 @@ if command -v perl > /dev/null; then
|
|||||||
set +o pipefail
|
set +o pipefail
|
||||||
builtin fc -lnr -2147483648 |
|
builtin fc -lnr -2147483648 |
|
||||||
last_hist=$(HISTTIMEFORMAT='' builtin history 1) command perl -n -l0 -e "$script" |
|
last_hist=$(HISTTIMEFORMAT='' builtin history 1) command perl -n -l0 -e "$script" |
|
||||||
FZF_DEFAULT_OPTS=$(__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort --wrap-sign '"$'\t'"↳ ' --highlight-line ${FZF_CTRL_R_OPTS-} +m --read0") \
|
FZF_DEFAULT_OPTS=$(__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort,alt-r:toggle-raw --wrap-sign '"$'\t'"↳ ' --highlight-line ${FZF_CTRL_R_OPTS-} +m --read0") \
|
||||||
FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd) --query "$READLINE_LINE"
|
FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd) --query "$READLINE_LINE"
|
||||||
) || return
|
) || return
|
||||||
READLINE_LINE=$(command perl -pe 's/^\d*\t//' <<< "$output")
|
READLINE_LINE=$(command perl -pe 's/^\d*\t//' <<< "$output")
|
||||||
if [[ -z "$READLINE_POINT" ]]; then
|
if [[ -z $READLINE_POINT ]]; then
|
||||||
echo "$READLINE_LINE"
|
echo "$READLINE_LINE"
|
||||||
else
|
else
|
||||||
READLINE_POINT=0x7fffffff
|
READLINE_POINT=0x7fffffff
|
||||||
@@ -103,11 +108,11 @@ else # awk - fallback for POSIX systems
|
|||||||
set +o pipefail
|
set +o pipefail
|
||||||
builtin fc -lnr -2147483648 2> /dev/null | # ( $'\t '<lines>$'\n' )* ; <lines> ::= [^\n]* ( $'\n'<lines> )*
|
builtin fc -lnr -2147483648 2> /dev/null | # ( $'\t '<lines>$'\n' )* ; <lines> ::= [^\n]* ( $'\n'<lines> )*
|
||||||
__fzf_exec_awk "$script" | # ( <counter>$'\t'<lines>$'\000' )*
|
__fzf_exec_awk "$script" | # ( <counter>$'\t'<lines>$'\000' )*
|
||||||
FZF_DEFAULT_OPTS=$(__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort --wrap-sign '"$'\t'"↳ ' --highlight-line ${FZF_CTRL_R_OPTS-} +m --read0") \
|
FZF_DEFAULT_OPTS=$(__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort,alt-r:toggle-raw --wrap-sign '"$'\t'"↳ ' --highlight-line ${FZF_CTRL_R_OPTS-} +m --read0") \
|
||||||
FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd) --query "$READLINE_LINE"
|
FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd) --query "$READLINE_LINE"
|
||||||
) || return
|
) || return
|
||||||
READLINE_LINE=${output#*$'\t'}
|
READLINE_LINE=${output#*$'\t'}
|
||||||
if [[ -z "$READLINE_POINT" ]]; then
|
if [[ -z $READLINE_POINT ]]; then
|
||||||
echo "$READLINE_LINE"
|
echo "$READLINE_LINE"
|
||||||
else
|
else
|
||||||
READLINE_POINT=0x7fffffff
|
READLINE_POINT=0x7fffffff
|
||||||
@@ -124,35 +129,46 @@ bind -m emacs-standard '"\C-z": vi-editing-mode'
|
|||||||
|
|
||||||
if ((BASH_VERSINFO[0] < 4)); then
|
if ((BASH_VERSINFO[0] < 4)); then
|
||||||
# CTRL-T - Paste the selected file path into the command line
|
# CTRL-T - Paste the selected file path into the command line
|
||||||
if [[ "${FZF_CTRL_T_COMMAND-x}" != "" ]]; then
|
if [[ ${FZF_CTRL_T_COMMAND-x} != "" ]]; then
|
||||||
bind -m emacs-standard '"\C-t": " \C-b\C-k \C-u`__fzf_select__`\e\C-e\er\C-a\C-y\C-h\C-e\e \C-y\ey\C-x\C-x\C-f\C-y\ey\C-_"'
|
bind -m emacs-standard '"\C-t": " \C-b\C-k \C-u`__fzf_select__`\e\C-e\er\C-a\C-y\C-h\C-e\e \C-y\ey\C-x\C-x\C-f\C-y\ey\C-_"'
|
||||||
bind -m vi-command '"\C-t": "\C-z\C-t\C-z"'
|
bind -m vi-command '"\C-t": "\C-z\C-t\C-z"'
|
||||||
bind -m vi-insert '"\C-t": "\C-z\C-t\C-z"'
|
bind -m vi-insert '"\C-t": "\C-z\C-t\C-z"'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# CTRL-R - Paste the selected command from history into the command line
|
# CTRL-R - Paste the selected command from history into the command line
|
||||||
|
if [[ ${FZF_CTRL_R_COMMAND-x} != "" ]]; then
|
||||||
|
if [[ -n ${FZF_CTRL_R_COMMAND-} ]]; then
|
||||||
|
echo "warning: FZF_CTRL_R_COMMAND is set to a custom command, but custom commands are not yet supported for CTRL-R" >&2
|
||||||
|
fi
|
||||||
bind -m emacs-standard '"\C-r": "\C-e \C-u\C-y\ey\C-u`__fzf_history__`\e\C-e\er"'
|
bind -m emacs-standard '"\C-r": "\C-e \C-u\C-y\ey\C-u`__fzf_history__`\e\C-e\er"'
|
||||||
bind -m vi-command '"\C-r": "\C-z\C-r\C-z"'
|
bind -m vi-command '"\C-r": "\C-z\C-r\C-z"'
|
||||||
bind -m vi-insert '"\C-r": "\C-z\C-r\C-z"'
|
bind -m vi-insert '"\C-r": "\C-z\C-r\C-z"'
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
# CTRL-T - Paste the selected file path into the command line
|
# CTRL-T - Paste the selected file path into the command line
|
||||||
if [[ "${FZF_CTRL_T_COMMAND-x}" != "" ]]; then
|
if [[ ${FZF_CTRL_T_COMMAND-x} != "" ]]; then
|
||||||
bind -m emacs-standard -x '"\C-t": fzf-file-widget'
|
bind -m emacs-standard -x '"\C-t": fzf-file-widget'
|
||||||
bind -m vi-command -x '"\C-t": fzf-file-widget'
|
bind -m vi-command -x '"\C-t": fzf-file-widget'
|
||||||
bind -m vi-insert -x '"\C-t": fzf-file-widget'
|
bind -m vi-insert -x '"\C-t": fzf-file-widget'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# CTRL-R - Paste the selected command from history into the command line
|
# CTRL-R - Paste the selected command from history into the command line
|
||||||
|
if [[ ${FZF_CTRL_R_COMMAND-x} != "" ]]; then
|
||||||
|
if [[ -n ${FZF_CTRL_R_COMMAND-} ]]; then
|
||||||
|
echo "warning: FZF_CTRL_R_COMMAND is set to a custom command, but custom commands are not yet supported for CTRL-R" >&2
|
||||||
|
fi
|
||||||
bind -m emacs-standard -x '"\C-r": __fzf_history__'
|
bind -m emacs-standard -x '"\C-r": __fzf_history__'
|
||||||
bind -m vi-command -x '"\C-r": __fzf_history__'
|
bind -m vi-command -x '"\C-r": __fzf_history__'
|
||||||
bind -m vi-insert -x '"\C-r": __fzf_history__'
|
bind -m vi-insert -x '"\C-r": __fzf_history__'
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# ALT-C - cd into the selected directory
|
# ALT-C - cd into the selected directory
|
||||||
if [[ "${FZF_ALT_C_COMMAND-x}" != "" ]]; then
|
if [[ ${FZF_ALT_C_COMMAND-x} != "" ]]; then
|
||||||
bind -m emacs-standard '"\ec": " \C-b\C-k \C-u`__fzf_cd__`\e\C-e\er\C-m\C-y\C-h\e \C-y\ey\C-x\C-x\C-d\C-y\ey\C-_"'
|
bind -m emacs-standard '"\ec": " \C-b\C-k \C-u`__fzf_cd__`\e\C-e\er\C-m\C-y\C-h\e \C-y\ey\C-x\C-x\C-d\C-y\ey\C-_"'
|
||||||
bind -m vi-command '"\ec": "\C-z\ec\C-z"'
|
bind -m vi-command '"\ec": "\C-z\ec\C-z"'
|
||||||
bind -m vi-insert '"\ec": "\C-z\ec\C-z"'
|
bind -m vi-insert '"\ec": "\C-z\ec\C-z"'
|
||||||
fi
|
fi
|
||||||
|
#----END shfmt
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
# - $FZF_TMUX_OPTS
|
# - $FZF_TMUX_OPTS
|
||||||
# - $FZF_CTRL_T_COMMAND
|
# - $FZF_CTRL_T_COMMAND
|
||||||
# - $FZF_CTRL_T_OPTS
|
# - $FZF_CTRL_T_OPTS
|
||||||
|
# - $FZF_CTRL_R_COMMAND
|
||||||
# - $FZF_CTRL_R_OPTS
|
# - $FZF_CTRL_R_OPTS
|
||||||
# - $FZF_ALT_C_COMMAND
|
# - $FZF_ALT_C_COMMAND
|
||||||
# - $FZF_ALT_C_OPTS
|
# - $FZF_ALT_C_OPTS
|
||||||
@@ -159,7 +160,7 @@ function fzf_key_bindings
|
|||||||
set -lx FZF_DEFAULT_OPTS (__fzf_defaults '' \
|
set -lx FZF_DEFAULT_OPTS (__fzf_defaults '' \
|
||||||
'--nth=2..,.. --scheme=history --multi --wrap-sign="\t↳ "' \
|
'--nth=2..,.. --scheme=history --multi --wrap-sign="\t↳ "' \
|
||||||
'--bind=\'shift-delete:execute-silent(eval history delete --exact --case-sensitive -- (string escape -n -- {+} | string replace -r -a "^\d*\\\\\\t|(?<=\\\\\\n)\\\\\\t" ""))+reload(eval $FZF_DEFAULT_COMMAND)\'' \
|
'--bind=\'shift-delete:execute-silent(eval history delete --exact --case-sensitive -- (string escape -n -- {+} | string replace -r -a "^\d*\\\\\\t|(?<=\\\\\\n)\\\\\\t" ""))+reload(eval $FZF_DEFAULT_COMMAND)\'' \
|
||||||
"--bind=ctrl-r:toggle-sort --highlight-line $FZF_CTRL_R_OPTS" \
|
"--bind=ctrl-r:toggle-sort,alt-r:toggle-raw --highlight-line $FZF_CTRL_R_OPTS" \
|
||||||
'--accept-nth=2.. --read0 --print0 --with-shell='(status fish-path)\\ -c)
|
'--accept-nth=2.. --read0 --print0 --with-shell='(status fish-path)\\ -c)
|
||||||
|
|
||||||
set -lx FZF_DEFAULT_OPTS_FILE
|
set -lx FZF_DEFAULT_OPTS_FILE
|
||||||
@@ -214,8 +215,13 @@ function fzf_key_bindings
|
|||||||
commandline -f repaint
|
commandline -f repaint
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if not set -q FZF_CTRL_R_COMMAND; or test -n "$FZF_CTRL_R_COMMAND"
|
||||||
|
if test -n "$FZF_CTRL_R_COMMAND"
|
||||||
|
echo "warning: FZF_CTRL_R_COMMAND is set to a custom command, but custom commands are not yet supported for CTRL-R" >&2
|
||||||
|
end
|
||||||
bind \cr fzf-history-widget
|
bind \cr fzf-history-widget
|
||||||
bind -M insert \cr fzf-history-widget
|
bind -M insert \cr fzf-history-widget
|
||||||
|
end
|
||||||
|
|
||||||
if not set -q FZF_CTRL_T_COMMAND; or test -n "$FZF_CTRL_T_COMMAND"
|
if not set -q FZF_CTRL_T_COMMAND; or test -n "$FZF_CTRL_T_COMMAND"
|
||||||
bind \ct fzf-file-widget
|
bind \ct fzf-file-widget
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
# - $FZF_TMUX_OPTS
|
# - $FZF_TMUX_OPTS
|
||||||
# - $FZF_CTRL_T_COMMAND
|
# - $FZF_CTRL_T_COMMAND
|
||||||
# - $FZF_CTRL_T_OPTS
|
# - $FZF_CTRL_T_OPTS
|
||||||
|
# - $FZF_CTRL_R_COMMAND
|
||||||
# - $FZF_CTRL_R_OPTS
|
# - $FZF_CTRL_R_OPTS
|
||||||
# - $FZF_ALT_C_COMMAND
|
# - $FZF_ALT_C_COMMAND
|
||||||
# - $FZF_ALT_C_OPTS
|
# - $FZF_ALT_C_OPTS
|
||||||
@@ -40,7 +41,7 @@ if [[ -o interactive ]]; then
|
|||||||
|
|
||||||
#----BEGIN INCLUDE common.sh
|
#----BEGIN INCLUDE common.sh
|
||||||
# NOTE: Do not directly edit this section, which is copied from "common.sh".
|
# NOTE: Do not directly edit this section, which is copied from "common.sh".
|
||||||
# To modify it, one can edit "common.sh" and run "./update-common.sh" to apply
|
# To modify it, one can edit "common.sh" and run "./update.sh" to apply
|
||||||
# the changes. See code comments in "common.sh" for the implementation details.
|
# the changes. See code comments in "common.sh" for the implementation details.
|
||||||
|
|
||||||
__fzf_defaults() {
|
__fzf_defaults() {
|
||||||
@@ -57,7 +58,10 @@ __fzf_exec_awk() {
|
|||||||
elif command -v mawk > /dev/null 2>&1; then
|
elif command -v mawk > /dev/null 2>&1; then
|
||||||
local n x y z d
|
local n x y z d
|
||||||
IFS=' .' read -r n x y z d <<< $(command mawk -W version 2> /dev/null)
|
IFS=' .' read -r n x y z d <<< $(command mawk -W version 2> /dev/null)
|
||||||
[[ $n == mawk ]] && (( d >= 20230302 && (x * 1000 + y) * 1000 + z >= 1003004 )) && __fzf_awk=mawk
|
[[ $n == mawk ]] &&
|
||||||
|
(((x * 1000 + y) * 1000 + z >= 1003004)) 2> /dev/null &&
|
||||||
|
((d >= 20230302)) 2> /dev/null &&
|
||||||
|
__fzf_awk=mawk
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
LC_ALL=C exec "$__fzf_awk" "$@"
|
LC_ALL=C exec "$__fzf_awk" "$@"
|
||||||
@@ -132,11 +136,11 @@ fzf-history-widget() {
|
|||||||
if zmodload -F zsh/parameter p:{commands,history} 2>/dev/null && (( ${+commands[perl]} )); then
|
if zmodload -F zsh/parameter p:{commands,history} 2>/dev/null && (( ${+commands[perl]} )); then
|
||||||
selected="$(printf '%s\t%s\000' "${(kv)history[@]}" |
|
selected="$(printf '%s\t%s\000' "${(kv)history[@]}" |
|
||||||
perl -0 -ne 'if (!$seen{(/^\s*[0-9]+\**\t(.*)/s, $1)}++) { s/\n/\n\t/g; print; }' |
|
perl -0 -ne 'if (!$seen{(/^\s*[0-9]+\**\t(.*)/s, $1)}++) { s/\n/\n\t/g; print; }' |
|
||||||
FZF_DEFAULT_OPTS=$(__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort --wrap-sign '\t↳ ' --highlight-line ${FZF_CTRL_R_OPTS-} --query=${(qqq)LBUFFER} +m --read0") \
|
FZF_DEFAULT_OPTS=$(__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort,alt-r:toggle-raw --wrap-sign '\t↳ ' --highlight-line ${FZF_CTRL_R_OPTS-} --query=${(qqq)LBUFFER} +m --read0") \
|
||||||
FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd))"
|
FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd))"
|
||||||
else
|
else
|
||||||
selected="$(fc -rl 1 | __fzf_exec_awk '{ cmd=$0; sub(/^[ \t]*[0-9]+\**[ \t]+/, "", cmd); if (!seen[cmd]++) print $0 }' |
|
selected="$(fc -rl 1 | __fzf_exec_awk '{ cmd=$0; sub(/^[ \t]*[0-9]+\**[ \t]+/, "", cmd); if (!seen[cmd]++) print $0 }' |
|
||||||
FZF_DEFAULT_OPTS=$(__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort --wrap-sign '\t↳ ' --highlight-line ${FZF_CTRL_R_OPTS-} --query=${(qqq)LBUFFER} +m") \
|
FZF_DEFAULT_OPTS=$(__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort,alt-r:toggle-raw --wrap-sign '\t↳ ' --highlight-line ${FZF_CTRL_R_OPTS-} --query=${(qqq)LBUFFER} +m") \
|
||||||
FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd))"
|
FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd))"
|
||||||
fi
|
fi
|
||||||
local ret=$?
|
local ret=$?
|
||||||
@@ -150,11 +154,16 @@ fzf-history-widget() {
|
|||||||
zle reset-prompt
|
zle reset-prompt
|
||||||
return $ret
|
return $ret
|
||||||
}
|
}
|
||||||
|
if [[ ${FZF_CTRL_R_COMMAND-x} != "" ]]; then
|
||||||
|
if [[ -n ${FZF_CTRL_R_COMMAND-} ]]; then
|
||||||
|
echo "warning: FZF_CTRL_R_COMMAND is set to a custom command, but custom commands are not yet supported for CTRL-R" >&2
|
||||||
|
fi
|
||||||
zle -N fzf-history-widget
|
zle -N fzf-history-widget
|
||||||
bindkey -M emacs '^R' fzf-history-widget
|
bindkey -M emacs '^R' fzf-history-widget
|
||||||
bindkey -M vicmd '^R' fzf-history-widget
|
bindkey -M vicmd '^R' fzf-history-widget
|
||||||
bindkey -M viins '^R' fzf-history-widget
|
bindkey -M viins '^R' fzf-history-widget
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
} always {
|
} always {
|
||||||
eval $__fzf_key_bindings_options
|
eval $__fzf_key_bindings_options
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# This script applies the contents of "common.sh" to the other files.
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Go to the directory that contains this script
|
|
||||||
dir=${0%"${0##*/}"}
|
|
||||||
if [ -n "$dir" ]; then
|
|
||||||
cd "$dir"
|
|
||||||
fi
|
|
||||||
|
|
||||||
update() {
|
|
||||||
{
|
|
||||||
sed -n '1,/^#----BEGIN INCLUDE common\.sh/p' "$1"
|
|
||||||
cat <<EOF
|
|
||||||
# NOTE: Do not directly edit this section, which is copied from "common.sh".
|
|
||||||
# To modify it, one can edit "common.sh" and run "./update-common.sh" to apply
|
|
||||||
# the changes. See code comments in "common.sh" for the implementation details.
|
|
||||||
EOF
|
|
||||||
grep -v '^[[:blank:]]*#' common.sh # remove code comments in common.sh
|
|
||||||
sed -n '/^#----END INCLUDE/,$p' "$1"
|
|
||||||
} > "$1.part"
|
|
||||||
|
|
||||||
mv -f "$1.part" "$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
update completion.bash
|
|
||||||
update completion.zsh
|
|
||||||
update key-bindings.bash
|
|
||||||
update key-bindings.zsh
|
|
||||||
68
shell/update.sh
Executable file
68
shell/update.sh
Executable file
@@ -0,0 +1,68 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# This script applies the contents of "common.sh" to the other files.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
dir=${0%"${0##*/}"}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
{
|
||||||
|
sed -n '1,/^#----BEGIN INCLUDE common\.sh/p' "$1"
|
||||||
|
cat << EOF
|
||||||
|
# NOTE: Do not directly edit this section, which is copied from "common.sh".
|
||||||
|
# To modify it, one can edit "common.sh" and run "./update.sh" to apply
|
||||||
|
# the changes. See code comments in "common.sh" for the implementation details.
|
||||||
|
EOF
|
||||||
|
echo
|
||||||
|
grep -v '^[[:blank:]]*#' "$dir/common.sh" # remove code comments in common.sh
|
||||||
|
sed -n '/^#----END INCLUDE/,$p' "$1"
|
||||||
|
} > "$1.part"
|
||||||
|
|
||||||
|
mv -f "$1.part" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
update "$dir/completion.bash"
|
||||||
|
update "$dir/completion.zsh"
|
||||||
|
update "$dir/key-bindings.bash"
|
||||||
|
update "$dir/key-bindings.zsh"
|
||||||
|
|
||||||
|
# Check if --check is in ARGV
|
||||||
|
check=0
|
||||||
|
rest=()
|
||||||
|
for arg in "$@"; do
|
||||||
|
case $arg in
|
||||||
|
--check) check=1 ;;
|
||||||
|
*) rest+=("$arg") ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
fmt() {
|
||||||
|
if ! grep -q "^#----BEGIN shfmt" "$1"; then
|
||||||
|
if [[ $check == 1 ]]; then
|
||||||
|
shfmt -d "$1"
|
||||||
|
return $?
|
||||||
|
else
|
||||||
|
shfmt -w "$1"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sed -n '1,/^#----BEGIN shfmt/p' "$1" | sed '$d'
|
||||||
|
sed -n '/^#----BEGIN shfmt/,/^#----END shfmt/p' "$1" | shfmt --filename "$1"
|
||||||
|
sed -n '/^#----END shfmt/,$p' "$1" | sed '1d'
|
||||||
|
} > "$1.part"
|
||||||
|
|
||||||
|
if [[ $check == 1 ]]; then
|
||||||
|
diff -q "$1" "$1.part"
|
||||||
|
ret=$?
|
||||||
|
rm -f "$1.part"
|
||||||
|
return $ret
|
||||||
|
fi
|
||||||
|
|
||||||
|
mv -f "$1.part" "$1"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
for file in "${rest[@]}"; do
|
||||||
|
fmt "$file" || exit $?
|
||||||
|
done
|
||||||
@@ -77,106 +77,112 @@ func _() {
|
|||||||
_ = x[actToggleWrap-66]
|
_ = x[actToggleWrap-66]
|
||||||
_ = x[actToggleMultiLine-67]
|
_ = x[actToggleMultiLine-67]
|
||||||
_ = x[actToggleHscroll-68]
|
_ = x[actToggleHscroll-68]
|
||||||
_ = x[actTrackCurrent-69]
|
_ = x[actToggleRaw-69]
|
||||||
_ = x[actToggleInput-70]
|
_ = x[actEnableRaw-70]
|
||||||
_ = x[actHideInput-71]
|
_ = x[actDisableRaw-71]
|
||||||
_ = x[actShowInput-72]
|
_ = x[actTrackCurrent-72]
|
||||||
_ = x[actUntrackCurrent-73]
|
_ = x[actToggleInput-73]
|
||||||
_ = x[actDown-74]
|
_ = x[actHideInput-74]
|
||||||
_ = x[actUp-75]
|
_ = x[actShowInput-75]
|
||||||
_ = x[actPageUp-76]
|
_ = x[actUntrackCurrent-76]
|
||||||
_ = x[actPageDown-77]
|
_ = x[actDown-77]
|
||||||
_ = x[actPosition-78]
|
_ = x[actDownMatch-78]
|
||||||
_ = x[actHalfPageUp-79]
|
_ = x[actUp-79]
|
||||||
_ = x[actHalfPageDown-80]
|
_ = x[actUpMatch-80]
|
||||||
_ = x[actOffsetUp-81]
|
_ = x[actPageUp-81]
|
||||||
_ = x[actOffsetDown-82]
|
_ = x[actPageDown-82]
|
||||||
_ = x[actOffsetMiddle-83]
|
_ = x[actPosition-83]
|
||||||
_ = x[actJump-84]
|
_ = x[actHalfPageUp-84]
|
||||||
_ = x[actJumpAccept-85]
|
_ = x[actHalfPageDown-85]
|
||||||
_ = x[actPrintQuery-86]
|
_ = x[actOffsetUp-86]
|
||||||
_ = x[actRefreshPreview-87]
|
_ = x[actOffsetDown-87]
|
||||||
_ = x[actReplaceQuery-88]
|
_ = x[actOffsetMiddle-88]
|
||||||
_ = x[actToggleSort-89]
|
_ = x[actJump-89]
|
||||||
_ = x[actShowPreview-90]
|
_ = x[actJumpAccept-90]
|
||||||
_ = x[actHidePreview-91]
|
_ = x[actPrintQuery-91]
|
||||||
_ = x[actTogglePreview-92]
|
_ = x[actRefreshPreview-92]
|
||||||
_ = x[actTogglePreviewWrap-93]
|
_ = x[actReplaceQuery-93]
|
||||||
_ = x[actTransform-94]
|
_ = x[actToggleSort-94]
|
||||||
_ = x[actTransformBorderLabel-95]
|
_ = x[actShowPreview-95]
|
||||||
_ = x[actTransformGhost-96]
|
_ = x[actHidePreview-96]
|
||||||
_ = x[actTransformHeader-97]
|
_ = x[actTogglePreview-97]
|
||||||
_ = x[actTransformFooter-98]
|
_ = x[actTogglePreviewWrap-98]
|
||||||
_ = x[actTransformHeaderLabel-99]
|
_ = x[actTransform-99]
|
||||||
_ = x[actTransformFooterLabel-100]
|
_ = x[actTransformBorderLabel-100]
|
||||||
_ = x[actTransformInputLabel-101]
|
_ = x[actTransformGhost-101]
|
||||||
_ = x[actTransformListLabel-102]
|
_ = x[actTransformHeader-102]
|
||||||
_ = x[actTransformNth-103]
|
_ = x[actTransformFooter-103]
|
||||||
_ = x[actTransformPointer-104]
|
_ = x[actTransformHeaderLabel-104]
|
||||||
_ = x[actTransformPreviewLabel-105]
|
_ = x[actTransformFooterLabel-105]
|
||||||
_ = x[actTransformPrompt-106]
|
_ = x[actTransformInputLabel-106]
|
||||||
_ = x[actTransformQuery-107]
|
_ = x[actTransformListLabel-107]
|
||||||
_ = x[actTransformSearch-108]
|
_ = x[actTransformNth-108]
|
||||||
_ = x[actTrigger-109]
|
_ = x[actTransformPointer-109]
|
||||||
_ = x[actBgTransform-110]
|
_ = x[actTransformPreviewLabel-110]
|
||||||
_ = x[actBgTransformBorderLabel-111]
|
_ = x[actTransformPrompt-111]
|
||||||
_ = x[actBgTransformGhost-112]
|
_ = x[actTransformQuery-112]
|
||||||
_ = x[actBgTransformHeader-113]
|
_ = x[actTransformSearch-113]
|
||||||
_ = x[actBgTransformFooter-114]
|
_ = x[actTrigger-114]
|
||||||
_ = x[actBgTransformHeaderLabel-115]
|
_ = x[actBgTransform-115]
|
||||||
_ = x[actBgTransformFooterLabel-116]
|
_ = x[actBgTransformBorderLabel-116]
|
||||||
_ = x[actBgTransformInputLabel-117]
|
_ = x[actBgTransformGhost-117]
|
||||||
_ = x[actBgTransformListLabel-118]
|
_ = x[actBgTransformHeader-118]
|
||||||
_ = x[actBgTransformNth-119]
|
_ = x[actBgTransformFooter-119]
|
||||||
_ = x[actBgTransformPointer-120]
|
_ = x[actBgTransformHeaderLabel-120]
|
||||||
_ = x[actBgTransformPreviewLabel-121]
|
_ = x[actBgTransformFooterLabel-121]
|
||||||
_ = x[actBgTransformPrompt-122]
|
_ = x[actBgTransformInputLabel-122]
|
||||||
_ = x[actBgTransformQuery-123]
|
_ = x[actBgTransformListLabel-123]
|
||||||
_ = x[actBgTransformSearch-124]
|
_ = x[actBgTransformNth-124]
|
||||||
_ = x[actBgCancel-125]
|
_ = x[actBgTransformPointer-125]
|
||||||
_ = x[actSearch-126]
|
_ = x[actBgTransformPreviewLabel-126]
|
||||||
_ = x[actPreview-127]
|
_ = x[actBgTransformPrompt-127]
|
||||||
_ = x[actPreviewTop-128]
|
_ = x[actBgTransformQuery-128]
|
||||||
_ = x[actPreviewBottom-129]
|
_ = x[actBgTransformSearch-129]
|
||||||
_ = x[actPreviewUp-130]
|
_ = x[actBgCancel-130]
|
||||||
_ = x[actPreviewDown-131]
|
_ = x[actSearch-131]
|
||||||
_ = x[actPreviewPageUp-132]
|
_ = x[actPreview-132]
|
||||||
_ = x[actPreviewPageDown-133]
|
_ = x[actPreviewTop-133]
|
||||||
_ = x[actPreviewHalfPageUp-134]
|
_ = x[actPreviewBottom-134]
|
||||||
_ = x[actPreviewHalfPageDown-135]
|
_ = x[actPreviewUp-135]
|
||||||
_ = x[actPrevHistory-136]
|
_ = x[actPreviewDown-136]
|
||||||
_ = x[actPrevSelected-137]
|
_ = x[actPreviewPageUp-137]
|
||||||
_ = x[actPrint-138]
|
_ = x[actPreviewPageDown-138]
|
||||||
_ = x[actPut-139]
|
_ = x[actPreviewHalfPageUp-139]
|
||||||
_ = x[actNextHistory-140]
|
_ = x[actPreviewHalfPageDown-140]
|
||||||
_ = x[actNextSelected-141]
|
_ = x[actPrevHistory-141]
|
||||||
_ = x[actExecute-142]
|
_ = x[actPrevSelected-142]
|
||||||
_ = x[actExecuteSilent-143]
|
_ = x[actPrint-143]
|
||||||
_ = x[actExecuteMulti-144]
|
_ = x[actPut-144]
|
||||||
_ = x[actSigStop-145]
|
_ = x[actNextHistory-145]
|
||||||
_ = x[actFirst-146]
|
_ = x[actNextSelected-146]
|
||||||
_ = x[actLast-147]
|
_ = x[actExecute-147]
|
||||||
_ = x[actReload-148]
|
_ = x[actExecuteSilent-148]
|
||||||
_ = x[actReloadSync-149]
|
_ = x[actExecuteMulti-149]
|
||||||
_ = x[actDisableSearch-150]
|
_ = x[actSigStop-150]
|
||||||
_ = x[actEnableSearch-151]
|
_ = x[actBest-151]
|
||||||
_ = x[actSelect-152]
|
_ = x[actFirst-152]
|
||||||
_ = x[actDeselect-153]
|
_ = x[actLast-153]
|
||||||
_ = x[actUnbind-154]
|
_ = x[actReload-154]
|
||||||
_ = x[actRebind-155]
|
_ = x[actReloadSync-155]
|
||||||
_ = x[actToggleBind-156]
|
_ = x[actDisableSearch-156]
|
||||||
_ = x[actBecome-157]
|
_ = x[actEnableSearch-157]
|
||||||
_ = x[actShowHeader-158]
|
_ = x[actSelect-158]
|
||||||
_ = x[actHideHeader-159]
|
_ = x[actDeselect-159]
|
||||||
_ = x[actBell-160]
|
_ = x[actUnbind-160]
|
||||||
_ = x[actExclude-161]
|
_ = x[actRebind-161]
|
||||||
_ = x[actExcludeMulti-162]
|
_ = x[actToggleBind-162]
|
||||||
_ = x[actAsync-163]
|
_ = x[actBecome-163]
|
||||||
|
_ = x[actShowHeader-164]
|
||||||
|
_ = x[actHideHeader-165]
|
||||||
|
_ = x[actBell-166]
|
||||||
|
_ = x[actExclude-167]
|
||||||
|
_ = x[actExcludeMulti-168]
|
||||||
|
_ = x[actAsync-169]
|
||||||
}
|
}
|
||||||
|
|
||||||
const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactBackwardSubWordactCancelactChangeBorderLabelactChangeGhostactChangeHeaderactChangeFooteractChangeHeaderLabelactChangeFooterLabelactChangeInputLabelactChangeListLabelactChangeMultiactChangeNthactChangePointeractChangePreviewactChangePreviewLabelactChangePreviewWindowactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactForwardSubWordactKillLineactKillWordactKillSubWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactBackwardKillSubWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformGhostactTransformHeaderactTransformFooteractTransformHeaderLabelactTransformFooterLabelactTransformInputLabelactTransformListLabelactTransformNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactTriggeractBgTransformactBgTransformBorderLabelactBgTransformGhostactBgTransformHeaderactBgTransformFooteractBgTransformHeaderLabelactBgTransformFooterLabelactBgTransformInputLabelactBgTransformListLabelactBgTransformNthactBgTransformPointeractBgTransformPreviewLabelactBgTransformPromptactBgTransformQueryactBgTransformSearchactBgCancelactSearchactPreviewactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMultiactAsync"
|
const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactBackwardSubWordactCancelactChangeBorderLabelactChangeGhostactChangeHeaderactChangeFooteractChangeHeaderLabelactChangeFooterLabelactChangeInputLabelactChangeListLabelactChangeMultiactChangeNthactChangePointeractChangePreviewactChangePreviewLabelactChangePreviewWindowactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactForwardSubWordactKillLineactKillWordactKillSubWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactBackwardKillSubWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactToggleRawactEnableRawactDisableRawactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactDownMatchactUpactUpMatchactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformGhostactTransformHeaderactTransformFooteractTransformHeaderLabelactTransformFooterLabelactTransformInputLabelactTransformListLabelactTransformNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactTriggeractBgTransformactBgTransformBorderLabelactBgTransformGhostactBgTransformHeaderactBgTransformFooteractBgTransformHeaderLabelactBgTransformFooterLabelactBgTransformInputLabelactBgTransformListLabelactBgTransformNthactBgTransformPointeractBgTransformPreviewLabelactBgTransformPromptactBgTransformQueryactBgTransformSearchactBgCancelactSearchactPreviewactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactBestactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMultiactAsync"
|
||||||
|
|
||||||
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 57, 77, 84, 92, 110, 118, 127, 144, 165, 180, 201, 225, 240, 258, 267, 287, 301, 316, 331, 351, 371, 390, 408, 422, 434, 450, 466, 487, 509, 524, 538, 552, 565, 582, 590, 603, 619, 631, 639, 653, 667, 684, 695, 706, 720, 738, 755, 762, 781, 803, 815, 829, 838, 853, 865, 878, 889, 900, 912, 926, 947, 962, 975, 993, 1009, 1024, 1038, 1050, 1062, 1079, 1086, 1091, 1100, 1111, 1122, 1135, 1150, 1161, 1174, 1189, 1196, 1209, 1222, 1239, 1254, 1267, 1281, 1295, 1311, 1331, 1343, 1366, 1383, 1401, 1419, 1442, 1465, 1487, 1508, 1523, 1542, 1566, 1584, 1601, 1619, 1629, 1643, 1668, 1687, 1707, 1727, 1752, 1777, 1801, 1824, 1841, 1862, 1888, 1908, 1927, 1947, 1958, 1967, 1977, 1990, 2006, 2018, 2032, 2048, 2066, 2086, 2108, 2122, 2137, 2145, 2151, 2165, 2180, 2190, 2206, 2221, 2231, 2239, 2246, 2255, 2268, 2284, 2299, 2308, 2319, 2328, 2337, 2350, 2359, 2372, 2385, 2392, 2402, 2417, 2425}
|
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 57, 77, 84, 92, 110, 118, 127, 144, 165, 180, 201, 225, 240, 258, 267, 287, 301, 316, 331, 351, 371, 390, 408, 422, 434, 450, 466, 487, 509, 524, 538, 552, 565, 582, 590, 603, 619, 631, 639, 653, 667, 684, 695, 706, 720, 738, 755, 762, 781, 803, 815, 829, 838, 853, 865, 878, 889, 900, 912, 926, 947, 962, 975, 993, 1009, 1021, 1033, 1046, 1061, 1075, 1087, 1099, 1116, 1123, 1135, 1140, 1150, 1159, 1170, 1181, 1194, 1209, 1220, 1233, 1248, 1255, 1268, 1281, 1298, 1313, 1326, 1340, 1354, 1370, 1390, 1402, 1425, 1442, 1460, 1478, 1501, 1524, 1546, 1567, 1582, 1601, 1625, 1643, 1660, 1678, 1688, 1702, 1727, 1746, 1766, 1786, 1811, 1836, 1860, 1883, 1900, 1921, 1947, 1967, 1986, 2006, 2017, 2026, 2036, 2049, 2065, 2077, 2091, 2107, 2125, 2145, 2167, 2181, 2196, 2204, 2210, 2224, 2239, 2249, 2265, 2280, 2290, 2297, 2305, 2312, 2321, 2334, 2350, 2365, 2374, 2385, 2394, 2403, 2416, 2425, 2438, 2451, 2458, 2468, 2483, 2491}
|
||||||
|
|
||||||
func (i actionType) String() string {
|
func (i actionType) String() string {
|
||||||
if i < 0 || i >= actionType(len(_actionType_index)-1) {
|
if i < 0 || i >= actionType(len(_actionType_index)-1) {
|
||||||
|
|||||||
25
src/core.go
25
src/core.go
@@ -2,6 +2,7 @@
|
|||||||
package fzf
|
package fzf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"maps"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -225,10 +226,7 @@ func Run(opts *Options) (int, error) {
|
|||||||
}
|
}
|
||||||
patternBuilder := func(runes []rune) *Pattern {
|
patternBuilder := func(runes []rune) *Pattern {
|
||||||
denyMutex.Lock()
|
denyMutex.Lock()
|
||||||
denylistCopy := make(map[int32]struct{})
|
denylistCopy := maps.Clone(denylist)
|
||||||
for k, v := range denylist {
|
|
||||||
denylistCopy[k] = v
|
|
||||||
}
|
|
||||||
denyMutex.Unlock()
|
denyMutex.Unlock()
|
||||||
return BuildPattern(cache, patternCache,
|
return BuildPattern(cache, patternCache,
|
||||||
opts.Fuzzy, opts.FuzzyAlgo, opts.Extended, opts.Case, opts.Normalize, forward, withPos,
|
opts.Fuzzy, opts.FuzzyAlgo, opts.Extended, opts.Case, opts.Normalize, forward, withPos,
|
||||||
@@ -269,11 +267,11 @@ func Run(opts *Options) (int, error) {
|
|||||||
|
|
||||||
// NOTE: Streaming filter is inherently not compatible with --tail
|
// NOTE: Streaming filter is inherently not compatible with --tail
|
||||||
snapshot, _, _ := chunkList.Snapshot(opts.Tail)
|
snapshot, _, _ := chunkList.Snapshot(opts.Tail)
|
||||||
merger, _ := matcher.scan(MatchRequest{
|
result := matcher.scan(MatchRequest{
|
||||||
chunks: snapshot,
|
chunks: snapshot,
|
||||||
pattern: pattern})
|
pattern: pattern})
|
||||||
for i := 0; i < merger.Length(); i++ {
|
for i := 0; i < result.merger.Length(); i++ {
|
||||||
opts.Printer(merger.Get(i).item.AsString(opts.Ansi))
|
opts.Printer(result.merger.Get(i).item.AsString(opts.Ansi))
|
||||||
found = true
|
found = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -481,12 +479,13 @@ func Run(opts *Options) (int, error) {
|
|||||||
|
|
||||||
case EvtSearchFin:
|
case EvtSearchFin:
|
||||||
switch val := value.(type) {
|
switch val := value.(type) {
|
||||||
case *Merger:
|
case MatchResult:
|
||||||
|
merger := val.merger
|
||||||
if deferred {
|
if deferred {
|
||||||
count := val.Length()
|
count := merger.Length()
|
||||||
if opts.Select1 && count > 1 || opts.Exit0 && !opts.Select1 && count > 0 {
|
if opts.Select1 && count > 1 || opts.Exit0 && !opts.Select1 && count > 0 {
|
||||||
determine(val.final)
|
determine(merger.final)
|
||||||
} else if val.final {
|
} else if merger.final {
|
||||||
if opts.Exit0 && count == 0 || opts.Select1 && count == 1 {
|
if opts.Exit0 && count == 0 || opts.Select1 && count == 1 {
|
||||||
if opts.PrintQuery {
|
if opts.PrintQuery {
|
||||||
opts.Printer(opts.Query)
|
opts.Printer(opts.Query)
|
||||||
@@ -504,7 +503,7 @@ func Run(opts *Options) (int, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := 0; i < count; i++ {
|
for i := 0; i < count; i++ {
|
||||||
opts.Printer(transformer(val.Get(i).item))
|
opts.Printer(transformer(merger.Get(i).item))
|
||||||
}
|
}
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
exitCode = ExitNoMatch
|
exitCode = ExitNoMatch
|
||||||
@@ -512,7 +511,7 @@ func Run(opts *Options) (int, error) {
|
|||||||
stop = true
|
stop = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
determine(val.final)
|
determine(merger.final)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
terminal.UpdateList(val)
|
terminal.UpdateList(val)
|
||||||
|
|||||||
@@ -19,6 +19,20 @@ type MatchRequest struct {
|
|||||||
revision revision
|
revision revision
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MatchResult struct {
|
||||||
|
merger *Merger
|
||||||
|
passMerger *Merger
|
||||||
|
cancelled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mr MatchResult) cacheable() bool {
|
||||||
|
return mr.merger != nil && mr.merger.cacheable()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mr MatchResult) final() bool {
|
||||||
|
return mr.merger != nil && mr.merger.final
|
||||||
|
}
|
||||||
|
|
||||||
// Matcher is responsible for performing search
|
// Matcher is responsible for performing search
|
||||||
type Matcher struct {
|
type Matcher struct {
|
||||||
cache *ChunkCache
|
cache *ChunkCache
|
||||||
@@ -29,7 +43,7 @@ type Matcher struct {
|
|||||||
reqBox *util.EventBox
|
reqBox *util.EventBox
|
||||||
partitions int
|
partitions int
|
||||||
slab []*util.Slab
|
slab []*util.Slab
|
||||||
mergerCache map[string]*Merger
|
mergerCache map[string]MatchResult
|
||||||
revision revision
|
revision revision
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +65,7 @@ func NewMatcher(cache *ChunkCache, patternBuilder func([]rune) *Pattern,
|
|||||||
reqBox: util.NewEventBox(),
|
reqBox: util.NewEventBox(),
|
||||||
partitions: partitions,
|
partitions: partitions,
|
||||||
slab: make([]*util.Slab, partitions),
|
slab: make([]*util.Slab, partitions),
|
||||||
mergerCache: make(map[string]*Merger),
|
mergerCache: make(map[string]MatchResult),
|
||||||
revision: revision}
|
revision: revision}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,43 +99,42 @@ func (m *Matcher) Loop() {
|
|||||||
cacheCleared := false
|
cacheCleared := false
|
||||||
if request.sort != m.sort || request.revision != m.revision {
|
if request.sort != m.sort || request.revision != m.revision {
|
||||||
m.sort = request.sort
|
m.sort = request.sort
|
||||||
m.revision = request.revision
|
m.mergerCache = make(map[string]MatchResult)
|
||||||
m.mergerCache = make(map[string]*Merger)
|
|
||||||
if !request.revision.compatible(m.revision) {
|
if !request.revision.compatible(m.revision) {
|
||||||
m.cache.Clear()
|
m.cache.Clear()
|
||||||
}
|
}
|
||||||
|
m.revision = request.revision
|
||||||
cacheCleared = true
|
cacheCleared = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restart search
|
// Restart search
|
||||||
patternString := request.pattern.AsString()
|
patternString := request.pattern.AsString()
|
||||||
var merger *Merger
|
var result MatchResult
|
||||||
cancelled := false
|
|
||||||
count := CountItems(request.chunks)
|
count := CountItems(request.chunks)
|
||||||
|
|
||||||
if !cacheCleared {
|
if !cacheCleared {
|
||||||
if count == prevCount {
|
if count == prevCount {
|
||||||
// Look up mergerCache
|
// Look up mergerCache
|
||||||
if cached, found := m.mergerCache[patternString]; found && cached.final == request.final {
|
if cached, found := m.mergerCache[patternString]; found && cached.final() == request.final {
|
||||||
merger = cached
|
result = cached
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Invalidate mergerCache
|
// Invalidate mergerCache
|
||||||
prevCount = count
|
prevCount = count
|
||||||
m.mergerCache = make(map[string]*Merger)
|
m.mergerCache = make(map[string]MatchResult)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if merger == nil {
|
if result.merger == nil {
|
||||||
merger, cancelled = m.scan(request)
|
result = m.scan(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cancelled {
|
if !result.cancelled {
|
||||||
if merger.cacheable() {
|
if result.cacheable() {
|
||||||
m.mergerCache[patternString] = merger
|
m.mergerCache[patternString] = result
|
||||||
}
|
}
|
||||||
merger.final = request.final
|
result.merger.final = request.final
|
||||||
m.eventBox.Set(EvtSearchFin, merger)
|
m.eventBox.Set(EvtSearchFin, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,16 +165,18 @@ type partialResult struct {
|
|||||||
matches []Result
|
matches []Result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Matcher) scan(request MatchRequest) (*Merger, bool) {
|
func (m *Matcher) scan(request MatchRequest) MatchResult {
|
||||||
startedAt := time.Now()
|
startedAt := time.Now()
|
||||||
|
|
||||||
numChunks := len(request.chunks)
|
numChunks := len(request.chunks)
|
||||||
if numChunks == 0 {
|
if numChunks == 0 {
|
||||||
return EmptyMerger(request.revision), false
|
m := EmptyMerger(request.revision)
|
||||||
|
return MatchResult{m, m, false}
|
||||||
}
|
}
|
||||||
pattern := request.pattern
|
pattern := request.pattern
|
||||||
|
passMerger := PassMerger(&request.chunks, m.tac, request.revision)
|
||||||
if pattern.IsEmpty() {
|
if pattern.IsEmpty() {
|
||||||
return PassMerger(&request.chunks, m.tac, request.revision), false
|
return MatchResult{passMerger, passMerger, false}
|
||||||
}
|
}
|
||||||
|
|
||||||
minIndex := request.chunks[0].items[0].Index()
|
minIndex := request.chunks[0].items[0].Index()
|
||||||
@@ -224,7 +239,7 @@ func (m *Matcher) scan(request MatchRequest) (*Merger, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if m.reqBox.Peek(reqReset) {
|
if m.reqBox.Peek(reqReset) {
|
||||||
return nil, wait()
|
return MatchResult{nil, nil, wait()}
|
||||||
}
|
}
|
||||||
|
|
||||||
if time.Since(startedAt) > progressMinDuration {
|
if time.Since(startedAt) > progressMinDuration {
|
||||||
@@ -237,7 +252,8 @@ func (m *Matcher) scan(request MatchRequest) (*Merger, bool) {
|
|||||||
partialResult := <-resultChan
|
partialResult := <-resultChan
|
||||||
partialResults[partialResult.index] = partialResult.matches
|
partialResults[partialResult.index] = partialResult.matches
|
||||||
}
|
}
|
||||||
return NewMerger(pattern, partialResults, m.sort && request.pattern.sortable, m.tac, request.revision, minIndex, maxIndex), false
|
merger := NewMerger(pattern, partialResults, m.sort && request.pattern.sortable, m.tac, request.revision, minIndex, maxIndex)
|
||||||
|
return MatchResult{merger, passMerger, false}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset is called to interrupt/signal the ongoing search
|
// Reset is called to interrupt/signal the ongoing search
|
||||||
|
|||||||
@@ -141,6 +141,15 @@ func (mg *Merger) Get(idx int) Result {
|
|||||||
panic(fmt.Sprintf("Index out of bounds (unsorted, %d/%d)", idx, mg.count))
|
panic(fmt.Sprintf("Index out of bounds (unsorted, %d/%d)", idx, mg.count))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mg *Merger) ToMap() map[int32]Result {
|
||||||
|
ret := make(map[int32]Result, mg.count)
|
||||||
|
for i := 0; i < mg.count; i++ {
|
||||||
|
result := mg.Get(i)
|
||||||
|
ret[result.Index()] = result
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
func (mg *Merger) cacheable() bool {
|
func (mg *Merger) cacheable() bool {
|
||||||
return mg.count < mergerCacheMax
|
return mg.count < mergerCacheMax
|
||||||
}
|
}
|
||||||
|
|||||||
109
src/options.go
109
src/options.go
@@ -3,6 +3,7 @@ package fzf
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"maps"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -59,7 +60,7 @@ Usage: fzf [options]
|
|||||||
|
|
||||||
GLOBAL STYLE
|
GLOBAL STYLE
|
||||||
--style=PRESET Apply a style preset [default|minimal|full[:BORDER_STYLE]
|
--style=PRESET Apply a style preset [default|minimal|full[:BORDER_STYLE]
|
||||||
--color=COLSPEC Base scheme (dark|light|16|bw) and/or custom colors
|
--color=COLSPEC Base scheme (dark|light|base16|bw) and/or custom colors
|
||||||
--no-color Disable colors
|
--no-color Disable colors
|
||||||
--no-bold Do not use bold text
|
--no-bold Do not use bold text
|
||||||
|
|
||||||
@@ -97,6 +98,7 @@ Usage: fzf [options]
|
|||||||
--wrap Enable line wrap
|
--wrap Enable line wrap
|
||||||
--wrap-sign=STR Indicator for wrapped lines
|
--wrap-sign=STR Indicator for wrapped lines
|
||||||
--no-multi-line Disable multi-line display of items when using --read0
|
--no-multi-line Disable multi-line display of items when using --read0
|
||||||
|
--raw Enable raw mode (show non-matching items)
|
||||||
--track Track the current selection when the result is updated
|
--track Track the current selection when the result is updated
|
||||||
--tac Reverse the order of the input
|
--tac Reverse the order of the input
|
||||||
--gap[=N] Render empty lines between each item
|
--gap[=N] Render empty lines between each item
|
||||||
@@ -109,6 +111,8 @@ Usage: fzf [options]
|
|||||||
--hscroll-off=COLS Number of screen columns to keep to the right of the
|
--hscroll-off=COLS Number of screen columns to keep to the right of the
|
||||||
highlighted substring (default: 10)
|
highlighted substring (default: 10)
|
||||||
--jump-labels=CHARS Label characters for jump mode
|
--jump-labels=CHARS Label characters for jump mode
|
||||||
|
--gutter=CHAR Character used for the gutter column (default: '▌')
|
||||||
|
--gutter-raw=CHAR Character used for the gutter column in raw mode (default: '▖')
|
||||||
--pointer=STR Pointer to the current line (default: '▌' or '>')
|
--pointer=STR Pointer to the current line (default: '▌' or '>')
|
||||||
--marker=STR Multi-select marker (default: '┃' or '>')
|
--marker=STR Multi-select marker (default: '┃' or '>')
|
||||||
--marker-multi-line=STR Multi-select marker for multi-line entries;
|
--marker-multi-line=STR Multi-select marker for multi-line entries;
|
||||||
@@ -202,8 +206,10 @@ Usage: fzf [options]
|
|||||||
|
|
||||||
ADVANCED
|
ADVANCED
|
||||||
--with-shell=STR Shell command and flags to start child processes with
|
--with-shell=STR Shell command and flags to start child processes with
|
||||||
--listen[=[ADDR:]PORT] Start HTTP server to receive actions (POST /)
|
--listen[=[ADDR:]PORT] Start HTTP server to receive actions via TCP
|
||||||
(To allow remote process execution, use --listen-unsafe)
|
(To allow remote process execution, use --listen-unsafe)
|
||||||
|
--listen=SOCKET_PATH Start HTTP server to receive actions via Unix domain socket
|
||||||
|
(Path should end with .sock)
|
||||||
|
|
||||||
DIRECTORY TRAVERSAL (Only used when $FZF_DEFAULT_COMMAND is not set)
|
DIRECTORY TRAVERSAL (Only used when $FZF_DEFAULT_COMMAND is not set)
|
||||||
--walker=OPTS [file][,dir][,follow][,hidden] (default: file,follow,hidden)
|
--walker=OPTS [file][,dir][,follow][,hidden] (default: file,follow,hidden)
|
||||||
@@ -212,8 +218,8 @@ Usage: fzf [options]
|
|||||||
(default: .git,node_modules)
|
(default: .git,node_modules)
|
||||||
|
|
||||||
HISTORY
|
HISTORY
|
||||||
--history=FILE History file
|
--history=FILE File to store fzf search history (*not* shell command history)
|
||||||
--history-size=N Maximum number of history entries (default: 1000)
|
--history-size=N Maximum number of entries to keep in the file (default: 1000)
|
||||||
|
|
||||||
SHELL INTEGRATION
|
SHELL INTEGRATION
|
||||||
--bash Print script to set up Bash shell integration
|
--bash Print script to set up Bash shell integration
|
||||||
@@ -560,6 +566,7 @@ type Options struct {
|
|||||||
AcceptNth func(Delimiter) func([]Token, int32) string
|
AcceptNth func(Delimiter) func([]Token, int32) string
|
||||||
Delimiter Delimiter
|
Delimiter Delimiter
|
||||||
Sort int
|
Sort int
|
||||||
|
Raw bool
|
||||||
Track trackOption
|
Track trackOption
|
||||||
Tac bool
|
Tac bool
|
||||||
Tail int
|
Tail int
|
||||||
@@ -567,6 +574,7 @@ type Options struct {
|
|||||||
Multi int
|
Multi int
|
||||||
Ansi bool
|
Ansi bool
|
||||||
Mouse bool
|
Mouse bool
|
||||||
|
BaseTheme *tui.ColorTheme
|
||||||
Theme *tui.ColorTheme
|
Theme *tui.ColorTheme
|
||||||
Black bool
|
Black bool
|
||||||
Bold bool
|
Bold bool
|
||||||
@@ -591,6 +599,7 @@ type Options struct {
|
|||||||
JumpLabels string
|
JumpLabels string
|
||||||
Prompt string
|
Prompt string
|
||||||
Gutter *string
|
Gutter *string
|
||||||
|
GutterRaw *string
|
||||||
Pointer *string
|
Pointer *string
|
||||||
Marker *string
|
Marker *string
|
||||||
MarkerMulti *[3]string
|
MarkerMulti *[3]string
|
||||||
@@ -664,11 +673,12 @@ func defaultPreviewOpts(command string) previewOpts {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func defaultOptions() *Options {
|
func defaultOptions() *Options {
|
||||||
var theme *tui.ColorTheme
|
var theme, baseTheme *tui.ColorTheme
|
||||||
if os.Getenv("NO_COLOR") != "" {
|
if os.Getenv("NO_COLOR") != "" {
|
||||||
theme = tui.NoColorTheme()
|
theme = tui.NoColorTheme
|
||||||
|
baseTheme = tui.NoColorTheme
|
||||||
} else {
|
} else {
|
||||||
theme = tui.EmptyTheme()
|
theme = tui.EmptyTheme
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Options{
|
return &Options{
|
||||||
@@ -694,6 +704,7 @@ func defaultOptions() *Options {
|
|||||||
Ansi: false,
|
Ansi: false,
|
||||||
Mouse: true,
|
Mouse: true,
|
||||||
Theme: theme,
|
Theme: theme,
|
||||||
|
BaseTheme: baseTheme,
|
||||||
Black: false,
|
Black: false,
|
||||||
Bold: true,
|
Bold: true,
|
||||||
MinHeight: -10,
|
MinHeight: -10,
|
||||||
@@ -712,6 +723,7 @@ func defaultOptions() *Options {
|
|||||||
JumpLabels: defaultJumpLabels,
|
JumpLabels: defaultJumpLabels,
|
||||||
Prompt: "> ",
|
Prompt: "> ",
|
||||||
Gutter: nil,
|
Gutter: nil,
|
||||||
|
GutterRaw: nil,
|
||||||
Pointer: nil,
|
Pointer: nil,
|
||||||
Marker: nil,
|
Marker: nil,
|
||||||
MarkerMulti: nil,
|
MarkerMulti: nil,
|
||||||
@@ -1310,8 +1322,9 @@ func dupeTheme(theme *tui.ColorTheme) *tui.ColorTheme {
|
|||||||
return &dupe
|
return &dupe
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseTheme(defaultTheme *tui.ColorTheme, str string) (*tui.ColorTheme, error) {
|
func parseTheme(defaultTheme *tui.ColorTheme, str string) (*tui.ColorTheme, *tui.ColorTheme, error) {
|
||||||
var err error
|
var err error
|
||||||
|
var baseTheme *tui.ColorTheme
|
||||||
theme := dupeTheme(defaultTheme)
|
theme := dupeTheme(defaultTheme)
|
||||||
rrggbb := regexp.MustCompile("^#[0-9a-fA-F]{6}$")
|
rrggbb := regexp.MustCompile("^#[0-9a-fA-F]{6}$")
|
||||||
comma := regexp.MustCompile(`[\s,]+`)
|
comma := regexp.MustCompile(`[\s,]+`)
|
||||||
@@ -1322,13 +1335,17 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) (*tui.ColorTheme, erro
|
|||||||
}
|
}
|
||||||
switch str {
|
switch str {
|
||||||
case "dark":
|
case "dark":
|
||||||
|
baseTheme = tui.Dark256
|
||||||
theme = dupeTheme(tui.Dark256)
|
theme = dupeTheme(tui.Dark256)
|
||||||
case "light":
|
case "light":
|
||||||
|
baseTheme = tui.Light256
|
||||||
theme = dupeTheme(tui.Light256)
|
theme = dupeTheme(tui.Light256)
|
||||||
case "16":
|
case "base16", "16":
|
||||||
|
baseTheme = tui.Default16
|
||||||
theme = dupeTheme(tui.Default16)
|
theme = dupeTheme(tui.Default16)
|
||||||
case "bw", "no":
|
case "bw", "no":
|
||||||
theme = tui.NoColorTheme()
|
baseTheme = tui.NoColorTheme
|
||||||
|
theme = dupeTheme(tui.NoColorTheme)
|
||||||
default:
|
default:
|
||||||
fail := func() {
|
fail := func() {
|
||||||
// Let the code proceed to simplify the error handling
|
// Let the code proceed to simplify the error handling
|
||||||
@@ -1353,6 +1370,8 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) (*tui.ColorTheme, erro
|
|||||||
cattr.Attr |= tui.Bold
|
cattr.Attr |= tui.Bold
|
||||||
case "dim":
|
case "dim":
|
||||||
cattr.Attr |= tui.Dim
|
cattr.Attr |= tui.Dim
|
||||||
|
case "strip":
|
||||||
|
cattr.Attr |= tui.Strip
|
||||||
case "italic":
|
case "italic":
|
||||||
cattr.Attr |= tui.Italic
|
cattr.Attr |= tui.Italic
|
||||||
case "underline":
|
case "underline":
|
||||||
@@ -1440,6 +1459,8 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) (*tui.ColorTheme, erro
|
|||||||
mergeAttr(&theme.SelectedBg)
|
mergeAttr(&theme.SelectedBg)
|
||||||
case "nth":
|
case "nth":
|
||||||
mergeAttr(&theme.Nth)
|
mergeAttr(&theme.Nth)
|
||||||
|
case "nomatch":
|
||||||
|
mergeAttr(&theme.Nomatch)
|
||||||
case "gutter":
|
case "gutter":
|
||||||
mergeAttr(&theme.Gutter)
|
mergeAttr(&theme.Gutter)
|
||||||
case "hl":
|
case "hl":
|
||||||
@@ -1505,7 +1526,7 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) (*tui.ColorTheme, erro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return theme, err
|
return baseTheme, theme, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseWalkerOpts(str string) (walkerOpts, error) {
|
func parseWalkerOpts(str string) (walkerOpts, error) {
|
||||||
@@ -1739,6 +1760,12 @@ func parseActionList(masked string, original string, prevActions []*action, putA
|
|||||||
appendAction(actToggleMultiLine)
|
appendAction(actToggleMultiLine)
|
||||||
case "toggle-hscroll":
|
case "toggle-hscroll":
|
||||||
appendAction(actToggleHscroll)
|
appendAction(actToggleHscroll)
|
||||||
|
case "toggle-raw":
|
||||||
|
appendAction(actToggleRaw)
|
||||||
|
case "enable-raw":
|
||||||
|
appendAction(actEnableRaw)
|
||||||
|
case "disable-raw":
|
||||||
|
appendAction(actDisableRaw)
|
||||||
case "show-header":
|
case "show-header":
|
||||||
appendAction(actShowHeader)
|
appendAction(actShowHeader)
|
||||||
case "hide-header":
|
case "hide-header":
|
||||||
@@ -1759,12 +1786,18 @@ func parseActionList(masked string, original string, prevActions []*action, putA
|
|||||||
appendAction(actToggle)
|
appendAction(actToggle)
|
||||||
case "down":
|
case "down":
|
||||||
appendAction(actDown)
|
appendAction(actDown)
|
||||||
|
case "down-match":
|
||||||
|
appendAction(actDownMatch)
|
||||||
case "up":
|
case "up":
|
||||||
appendAction(actUp)
|
appendAction(actUp)
|
||||||
|
case "up-match":
|
||||||
|
appendAction(actUpMatch)
|
||||||
case "first", "top":
|
case "first", "top":
|
||||||
appendAction(actFirst)
|
appendAction(actFirst)
|
||||||
case "last":
|
case "last":
|
||||||
appendAction(actLast)
|
appendAction(actLast)
|
||||||
|
case "best":
|
||||||
|
appendAction(actBest)
|
||||||
case "page-up":
|
case "page-up":
|
||||||
appendAction(actPageUp)
|
appendAction(actPageUp)
|
||||||
case "page-down":
|
case "page-down":
|
||||||
@@ -1777,9 +1810,9 @@ func parseActionList(masked string, original string, prevActions []*action, putA
|
|||||||
appendAction(actPrevHistory)
|
appendAction(actPrevHistory)
|
||||||
case "next-history":
|
case "next-history":
|
||||||
appendAction(actNextHistory)
|
appendAction(actNextHistory)
|
||||||
case "prev-selected":
|
case "up-selected", "prev-selected":
|
||||||
appendAction(actPrevSelected)
|
appendAction(actPrevSelected)
|
||||||
case "next-selected":
|
case "down-selected", "next-selected":
|
||||||
appendAction(actNextSelected)
|
appendAction(actNextSelected)
|
||||||
case "show-preview":
|
case "show-preview":
|
||||||
appendAction(actShowPreview)
|
appendAction(actShowPreview)
|
||||||
@@ -2602,9 +2635,7 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for k, v := range chords {
|
maps.Copy(opts.Expect, chords)
|
||||||
opts.Expect[k] = v
|
|
||||||
}
|
|
||||||
case "--no-expect":
|
case "--no-expect":
|
||||||
opts.Expect = make(map[tui.Event]string)
|
opts.Expect = make(map[tui.Event]string)
|
||||||
case "--enabled", "--no-phony":
|
case "--enabled", "--no-phony":
|
||||||
@@ -2632,11 +2663,15 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
|
|||||||
case "--color":
|
case "--color":
|
||||||
_, spec := optionalNextString()
|
_, spec := optionalNextString()
|
||||||
if len(spec) == 0 {
|
if len(spec) == 0 {
|
||||||
opts.Theme = tui.EmptyTheme()
|
opts.Theme = tui.EmptyTheme
|
||||||
} else {
|
} else {
|
||||||
if opts.Theme, err = parseTheme(opts.Theme, spec); err != nil {
|
var baseTheme *tui.ColorTheme
|
||||||
|
if baseTheme, opts.Theme, err = parseTheme(opts.Theme, spec); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if baseTheme != nil {
|
||||||
|
opts.BaseTheme = baseTheme
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case "--toggle-sort":
|
case "--toggle-sort":
|
||||||
str, err := nextString("key name required")
|
str, err := nextString("key name required")
|
||||||
@@ -2682,6 +2717,10 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
|
|||||||
}
|
}
|
||||||
case "+s", "--no-sort":
|
case "+s", "--no-sort":
|
||||||
opts.Sort = 0
|
opts.Sort = 0
|
||||||
|
case "--raw":
|
||||||
|
opts.Raw = true
|
||||||
|
case "--no-raw":
|
||||||
|
opts.Raw = false
|
||||||
case "--track":
|
case "--track":
|
||||||
opts.Track = trackEnabled
|
opts.Track = trackEnabled
|
||||||
case "--no-track":
|
case "--no-track":
|
||||||
@@ -2718,7 +2757,8 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
|
|||||||
case "--no-mouse":
|
case "--no-mouse":
|
||||||
opts.Mouse = false
|
opts.Mouse = false
|
||||||
case "+c", "--no-color":
|
case "+c", "--no-color":
|
||||||
opts.Theme = tui.NoColorTheme()
|
opts.BaseTheme = tui.NoColorTheme
|
||||||
|
opts.Theme = tui.NoColorTheme
|
||||||
case "+2", "--no-256":
|
case "+2", "--no-256":
|
||||||
opts.Theme = tui.Default16
|
opts.Theme = tui.Default16
|
||||||
case "--black":
|
case "--black":
|
||||||
@@ -2866,6 +2906,13 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
|
|||||||
}
|
}
|
||||||
str = firstLine(str)
|
str = firstLine(str)
|
||||||
opts.Gutter = &str
|
opts.Gutter = &str
|
||||||
|
case "--gutter-raw":
|
||||||
|
str, err := nextString("gutter character for raw mode required")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
str = firstLine(str)
|
||||||
|
opts.GutterRaw = &str
|
||||||
case "--pointer":
|
case "--pointer":
|
||||||
str, err := nextString("pointer sign required")
|
str, err := nextString("pointer sign required")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -3384,10 +3431,9 @@ func validateOptions(opts *Options) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Gutter != nil {
|
if opts.Gutter != nil && uniseg.StringWidth(*opts.Gutter) != 1 ||
|
||||||
if err := validateSign(*opts.Gutter, "gutter", 1); err != nil {
|
opts.GutterRaw != nil && uniseg.StringWidth(*opts.GutterRaw) != 1 {
|
||||||
return err
|
return errors.New("gutter display width should be 1")
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Scrollbar != nil {
|
if opts.Scrollbar != nil {
|
||||||
@@ -3589,23 +3635,6 @@ func postProcessOptions(opts *Options) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Bold {
|
|
||||||
theme := opts.Theme
|
|
||||||
boldify := func(c tui.ColorAttr) tui.ColorAttr {
|
|
||||||
dup := c
|
|
||||||
if (c.Attr & tui.AttrRegular) == 0 {
|
|
||||||
dup.Attr |= tui.BoldForce
|
|
||||||
}
|
|
||||||
return dup
|
|
||||||
}
|
|
||||||
theme.Current = boldify(theme.Current)
|
|
||||||
theme.CurrentMatch = boldify(theme.CurrentMatch)
|
|
||||||
theme.Prompt = boldify(theme.Prompt)
|
|
||||||
theme.Input = boldify(theme.Input)
|
|
||||||
theme.Cursor = boldify(theme.Cursor)
|
|
||||||
theme.Spinner = boldify(theme.Spinner)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If --height option is not supported on the platform, just ignore it
|
// If --height option is not supported on the platform, just ignore it
|
||||||
if !tui.IsLightRendererSupported() && opts.Height.size > 0 {
|
if !tui.IsLightRendererSupported() && opts.Height.size > 0 {
|
||||||
opts.Height = heightSpec{}
|
opts.Height = heightSpec{}
|
||||||
|
|||||||
@@ -300,8 +300,12 @@ func TestBind(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestColorSpec(t *testing.T) {
|
func TestColorSpec(t *testing.T) {
|
||||||
|
var base *tui.ColorTheme
|
||||||
theme := tui.Dark256
|
theme := tui.Dark256
|
||||||
dark, _ := parseTheme(theme, "dark")
|
base, dark, _ := parseTheme(theme, "dark")
|
||||||
|
if *dark != *base {
|
||||||
|
t.Errorf("incorrect base theme returned")
|
||||||
|
}
|
||||||
if *dark != *theme {
|
if *dark != *theme {
|
||||||
t.Errorf("colors should be equivalent")
|
t.Errorf("colors should be equivalent")
|
||||||
}
|
}
|
||||||
@@ -309,7 +313,10 @@ func TestColorSpec(t *testing.T) {
|
|||||||
t.Errorf("point should not be equivalent")
|
t.Errorf("point should not be equivalent")
|
||||||
}
|
}
|
||||||
|
|
||||||
light, _ := parseTheme(theme, "dark,light")
|
base, light, _ := parseTheme(theme, "dark,light")
|
||||||
|
if *light != *base {
|
||||||
|
t.Errorf("incorrect base theme returned")
|
||||||
|
}
|
||||||
if *light == *theme {
|
if *light == *theme {
|
||||||
t.Errorf("should not be equivalent")
|
t.Errorf("should not be equivalent")
|
||||||
}
|
}
|
||||||
@@ -320,7 +327,7 @@ func TestColorSpec(t *testing.T) {
|
|||||||
t.Errorf("point should not be equivalent")
|
t.Errorf("point should not be equivalent")
|
||||||
}
|
}
|
||||||
|
|
||||||
customized, _ := parseTheme(theme, "fg:231,bg:232")
|
_, customized, _ := parseTheme(theme, "fg:231,bg:232")
|
||||||
if customized.Fg.Color != 231 || customized.Bg.Color != 232 {
|
if customized.Fg.Color != 231 || customized.Bg.Color != 232 {
|
||||||
t.Errorf("color not customized")
|
t.Errorf("color not customized")
|
||||||
}
|
}
|
||||||
@@ -333,7 +340,7 @@ func TestColorSpec(t *testing.T) {
|
|||||||
t.Errorf("colors should now be equivalent: %v, %v", tui.Dark256, customized)
|
t.Errorf("colors should now be equivalent: %v, %v", tui.Dark256, customized)
|
||||||
}
|
}
|
||||||
|
|
||||||
customized, _ = parseTheme(theme, "fg:231,dark bg:232")
|
_, customized, _ = parseTheme(theme, "fg:231,dark bg:232")
|
||||||
if customized.Fg != tui.Dark256.Fg || customized.Bg == tui.Dark256.Bg {
|
if customized.Fg != tui.Dark256.Fg || customized.Bg == tui.Dark256.Bg {
|
||||||
t.Errorf("color not customized")
|
t.Errorf("color not customized")
|
||||||
}
|
}
|
||||||
@@ -350,8 +357,8 @@ func TestDefaultCtrlNP(t *testing.T) {
|
|||||||
t.Error()
|
t.Error()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
check([]string{}, tui.CtrlN, actDown)
|
check([]string{}, tui.CtrlN, actDownMatch)
|
||||||
check([]string{}, tui.CtrlP, actUp)
|
check([]string{}, tui.CtrlP, actUpMatch)
|
||||||
|
|
||||||
check([]string{"--bind=ctrl-n:accept"}, tui.CtrlN, actAccept)
|
check([]string{"--bind=ctrl-n:accept"}, tui.CtrlN, actAccept)
|
||||||
check([]string{"--bind=ctrl-p:accept"}, tui.CtrlP, actAccept)
|
check([]string{"--bind=ctrl-p:accept"}, tui.CtrlP, actAccept)
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ func minRank() Result {
|
|||||||
return Result{item: &minItem, points: [4]uint16{math.MaxUint16, 0, 0, 0}}
|
return Result{item: &minItem, points: [4]uint16{math.MaxUint16, 0, 0, 0}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, theme *tui.ColorTheme, colBase tui.ColorPair, colMatch tui.ColorPair, attrNth tui.Attr) []colorOffset {
|
func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, theme *tui.ColorTheme, colBase tui.ColorPair, colMatch tui.ColorPair, attrNth tui.Attr, hidden bool) []colorOffset {
|
||||||
itemColors := result.item.Colors()
|
itemColors := result.item.Colors()
|
||||||
|
|
||||||
// No ANSI codes
|
// No ANSI codes
|
||||||
@@ -194,6 +194,10 @@ func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, t
|
|||||||
if !theme.Colored {
|
if !theme.Colored {
|
||||||
return tui.NewColorPair(-1, -1, ansi.color.attr).MergeAttr(base)
|
return tui.NewColorPair(-1, -1, ansi.color.attr).MergeAttr(base)
|
||||||
}
|
}
|
||||||
|
// fd --color always | fzf --ansi --delimiter / --nth -1 --color fg:dim:strip,nth:regular
|
||||||
|
if base.ShouldStripColors() {
|
||||||
|
return base
|
||||||
|
}
|
||||||
fg := ansi.color.fg
|
fg := ansi.color.fg
|
||||||
bg := ansi.color.bg
|
bg := ansi.color.bg
|
||||||
if fg == -1 {
|
if fg == -1 {
|
||||||
@@ -251,6 +255,9 @@ func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, t
|
|||||||
if curr.nth {
|
if curr.nth {
|
||||||
base = base.WithAttr(attrNth)
|
base = base.WithAttr(attrNth)
|
||||||
}
|
}
|
||||||
|
if hidden {
|
||||||
|
base = base.WithFg(theme.Nomatch)
|
||||||
|
}
|
||||||
color := ansiToColorPair(ansi, base)
|
color := ansiToColorPair(ansi, base)
|
||||||
colors = append(colors, colorOffset{
|
colors = append(colors, colorOffset{
|
||||||
offset: [2]int32{int32(start), int32(idx)},
|
offset: [2]int32{int32(start), int32(idx)},
|
||||||
@@ -258,9 +265,13 @@ func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, t
|
|||||||
match: false,
|
match: false,
|
||||||
url: ansi.color.url})
|
url: ansi.color.url})
|
||||||
} else {
|
} else {
|
||||||
|
color := colBase.WithAttr(attrNth)
|
||||||
|
if hidden {
|
||||||
|
color = color.WithFg(theme.Nomatch)
|
||||||
|
}
|
||||||
colors = append(colors, colorOffset{
|
colors = append(colors, colorOffset{
|
||||||
offset: [2]int32{int32(start), int32(idx)},
|
offset: [2]int32{int32(start), int32(idx)},
|
||||||
color: colBase.WithAttr(attrNth),
|
color: color,
|
||||||
match: false,
|
match: false,
|
||||||
url: nil})
|
url: nil})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ func TestColorOffset(t *testing.T) {
|
|||||||
|
|
||||||
colBase := tui.NewColorPair(89, 189, tui.AttrUndefined)
|
colBase := tui.NewColorPair(89, 189, tui.AttrUndefined)
|
||||||
colMatch := tui.NewColorPair(99, 199, tui.AttrUndefined)
|
colMatch := tui.NewColorPair(99, 199, tui.AttrUndefined)
|
||||||
colors := item.colorOffsets(offsets, nil, tui.Dark256, colBase, colMatch, tui.AttrUndefined)
|
colors := item.colorOffsets(offsets, nil, tui.Dark256, colBase, colMatch, tui.AttrUndefined, false)
|
||||||
assert := func(idx int, b int32, e int32, c tui.ColorPair) {
|
assert := func(idx int, b int32, e int32, c tui.ColorPair) {
|
||||||
o := colors[idx]
|
o := colors[idx]
|
||||||
if o.offset[0] != b || o.offset[1] != e || o.color != c {
|
if o.offset[0] != b || o.offset[1] != e || o.color != c {
|
||||||
@@ -158,7 +158,7 @@ func TestColorOffset(t *testing.T) {
|
|||||||
|
|
||||||
nthOffsets := []Offset{{37, 39}, {42, 45}}
|
nthOffsets := []Offset{{37, 39}, {42, 45}}
|
||||||
for _, attr := range []tui.Attr{tui.AttrRegular, tui.StrikeThrough} {
|
for _, attr := range []tui.Attr{tui.AttrRegular, tui.StrikeThrough} {
|
||||||
colors = item.colorOffsets(offsets, nthOffsets, tui.Dark256, colRegular, colUnderline, attr)
|
colors = item.colorOffsets(offsets, nthOffsets, tui.Dark256, colRegular, colUnderline, attr, false)
|
||||||
|
|
||||||
// [{[0 5] {1 5 0}} {[5 15] {1 5 8}} {[15 20] {1 5 0}}
|
// [{[0 5] {1 5 0}} {[5 15] {1 5 8}} {[15 20] {1 5 0}}
|
||||||
// {[22 25] {2 6 1}} {[25 27] {2 6 9}} {[27 30] {-1 -1 8}}
|
// {[22 25] {2 6 1}} {[25 27] {2 6 9}} {[27 30] {-1 -1 8}}
|
||||||
|
|||||||
@@ -46,15 +46,20 @@ type httpServer struct {
|
|||||||
type listenAddress struct {
|
type listenAddress struct {
|
||||||
host string
|
host string
|
||||||
port int
|
port int
|
||||||
|
sock string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (addr listenAddress) IsLocal() bool {
|
func (addr listenAddress) IsLocal() bool {
|
||||||
return addr.host == "localhost" || addr.host == "127.0.0.1"
|
return addr.host == "localhost" || addr.host == "127.0.0.1" || len(addr.sock) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
var defaultListenAddr = listenAddress{"localhost", 0}
|
var defaultListenAddr = listenAddress{"localhost", 0, ""}
|
||||||
|
|
||||||
func parseListenAddress(address string) (listenAddress, error) {
|
func parseListenAddress(address string) (listenAddress, error) {
|
||||||
|
if strings.HasSuffix(address, ".sock") {
|
||||||
|
return listenAddress{"", 0, address}, nil
|
||||||
|
}
|
||||||
|
|
||||||
parts := strings.SplitN(address, ":", 3)
|
parts := strings.SplitN(address, ":", 3)
|
||||||
if len(parts) == 1 {
|
if len(parts) == 1 {
|
||||||
parts = []string{"localhost", parts[0]}
|
parts = []string{"localhost", parts[0]}
|
||||||
@@ -70,7 +75,7 @@ func parseListenAddress(address string) (listenAddress, error) {
|
|||||||
if len(parts[0]) == 0 {
|
if len(parts[0]) == 0 {
|
||||||
parts[0] = "localhost"
|
parts[0] = "localhost"
|
||||||
}
|
}
|
||||||
return listenAddress{parts[0], port}, nil
|
return listenAddress{parts[0], port, ""}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func startHttpServer(address listenAddress, actionChannel chan []*action, getHandler func(getParams) string) (net.Listener, int, error) {
|
func startHttpServer(address listenAddress, actionChannel chan []*action, getHandler func(getParams) string) (net.Listener, int, error) {
|
||||||
@@ -80,8 +85,26 @@ func startHttpServer(address listenAddress, actionChannel chan []*action, getHan
|
|||||||
if !address.IsLocal() && len(apiKey) == 0 {
|
if !address.IsLocal() && len(apiKey) == 0 {
|
||||||
return nil, port, errors.New("FZF_API_KEY is required to allow remote access")
|
return nil, port, errors.New("FZF_API_KEY is required to allow remote access")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var listener net.Listener
|
||||||
|
var err error
|
||||||
|
if len(address.sock) > 0 {
|
||||||
|
if _, err := os.Stat(address.sock); err == nil {
|
||||||
|
// Check if the socket is already in use
|
||||||
|
if conn, err := net.Dial("unix", address.sock); err == nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil, 0, fmt.Errorf("socket already in use: %s", address.sock)
|
||||||
|
}
|
||||||
|
os.Remove(address.sock)
|
||||||
|
}
|
||||||
|
listener, err = net.Listen("unix", address.sock)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("failed to listen on %s", address.sock)
|
||||||
|
}
|
||||||
|
os.Chmod(address.sock, 0600)
|
||||||
|
} else {
|
||||||
addrStr := fmt.Sprintf("%s:%d", host, port)
|
addrStr := fmt.Sprintf("%s:%d", host, port)
|
||||||
listener, err := net.Listen("tcp", addrStr)
|
listener, err = net.Listen("tcp", addrStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, port, fmt.Errorf("failed to listen on %s", addrStr)
|
return nil, port, fmt.Errorf("failed to listen on %s", addrStr)
|
||||||
}
|
}
|
||||||
@@ -97,6 +120,7 @@ func startHttpServer(address listenAddress, actionChannel chan []*action, getHan
|
|||||||
return nil, port, err
|
return nil, port, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
server := httpServer{
|
server := httpServer{
|
||||||
apiKey: []byte(apiKey),
|
apiKey: []byte(apiKey),
|
||||||
|
|||||||
318
src/terminal.go
318
src/terminal.go
@@ -6,6 +6,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"maps"
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
@@ -179,6 +180,7 @@ type itemLine struct {
|
|||||||
result Result
|
result Result
|
||||||
empty bool
|
empty bool
|
||||||
other bool
|
other bool
|
||||||
|
hidden bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terminal) inListWindow() bool {
|
func (t *Terminal) inListWindow() bool {
|
||||||
@@ -273,9 +275,11 @@ type Terminal struct {
|
|||||||
footerLabelLen int
|
footerLabelLen int
|
||||||
footerLabelOpts labelOpts
|
footerLabelOpts labelOpts
|
||||||
gutterReverse bool
|
gutterReverse bool
|
||||||
|
gutterRawReverse bool
|
||||||
pointer string
|
pointer string
|
||||||
pointerLen int
|
pointerLen int
|
||||||
pointerEmpty string
|
pointerEmpty string
|
||||||
|
pointerEmptyRaw string
|
||||||
marker string
|
marker string
|
||||||
markerLen int
|
markerLen int
|
||||||
markerEmpty string
|
markerEmpty string
|
||||||
@@ -382,6 +386,9 @@ type Terminal struct {
|
|||||||
printer func(string)
|
printer func(string)
|
||||||
printsep string
|
printsep string
|
||||||
merger *Merger
|
merger *Merger
|
||||||
|
passMerger *Merger
|
||||||
|
resultMerger *Merger
|
||||||
|
matchMap map[int32]Result
|
||||||
selected map[int32]selectedItem
|
selected map[int32]selectedItem
|
||||||
version int64
|
version int64
|
||||||
revision revision
|
revision revision
|
||||||
@@ -400,7 +407,6 @@ type Terminal struct {
|
|||||||
initFunc func() error
|
initFunc func() error
|
||||||
prevLines []itemLine
|
prevLines []itemLine
|
||||||
suppress bool
|
suppress bool
|
||||||
sigstop bool
|
|
||||||
startChan chan fitpad
|
startChan chan fitpad
|
||||||
killChan chan bool
|
killChan chan bool
|
||||||
serverInputChan chan []*action
|
serverInputChan chan []*action
|
||||||
@@ -429,6 +435,7 @@ type Terminal struct {
|
|||||||
clickFooterColumn int
|
clickFooterColumn int
|
||||||
proxyScript string
|
proxyScript string
|
||||||
numLinesCache map[int32]numLinesCacheValue
|
numLinesCache map[int32]numLinesCacheValue
|
||||||
|
raw bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type numLinesCacheValue struct {
|
type numLinesCacheValue struct {
|
||||||
@@ -489,6 +496,14 @@ const (
|
|||||||
reqFatal
|
reqFatal
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func isTerminalEvent(et util.EventType) bool {
|
||||||
|
switch et {
|
||||||
|
case reqClose, reqPrintQuery, reqBecome, reqQuit, reqFatal:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
type action struct {
|
type action struct {
|
||||||
t actionType
|
t actionType
|
||||||
a string
|
a string
|
||||||
@@ -569,13 +584,18 @@ const (
|
|||||||
actToggleWrap
|
actToggleWrap
|
||||||
actToggleMultiLine
|
actToggleMultiLine
|
||||||
actToggleHscroll
|
actToggleHscroll
|
||||||
|
actToggleRaw
|
||||||
|
actEnableRaw
|
||||||
|
actDisableRaw
|
||||||
actTrackCurrent
|
actTrackCurrent
|
||||||
actToggleInput
|
actToggleInput
|
||||||
actHideInput
|
actHideInput
|
||||||
actShowInput
|
actShowInput
|
||||||
actUntrackCurrent
|
actUntrackCurrent
|
||||||
actDown
|
actDown
|
||||||
|
actDownMatch
|
||||||
actUp
|
actUp
|
||||||
|
actUpMatch
|
||||||
actPageUp
|
actPageUp
|
||||||
actPageDown
|
actPageDown
|
||||||
actPosition
|
actPosition
|
||||||
@@ -651,6 +671,7 @@ const (
|
|||||||
actExecuteSilent
|
actExecuteSilent
|
||||||
actExecuteMulti // Deprecated
|
actExecuteMulti // Deprecated
|
||||||
actSigStop
|
actSigStop
|
||||||
|
actBest
|
||||||
actFirst
|
actFirst
|
||||||
actLast
|
actLast
|
||||||
actReload
|
actReload
|
||||||
@@ -787,7 +808,6 @@ func defaultKeymap() map[tui.Event][]*action {
|
|||||||
add(tui.CtrlD, actDeleteCharEof)
|
add(tui.CtrlD, actDeleteCharEof)
|
||||||
add(tui.CtrlE, actEndOfLine)
|
add(tui.CtrlE, actEndOfLine)
|
||||||
add(tui.CtrlF, actForwardChar)
|
add(tui.CtrlF, actForwardChar)
|
||||||
add(tui.CtrlH, actBackwardDeleteChar)
|
|
||||||
add(tui.Backspace, actBackwardDeleteChar)
|
add(tui.Backspace, actBackwardDeleteChar)
|
||||||
add(tui.CtrlBackspace, actBackwardDeleteChar)
|
add(tui.CtrlBackspace, actBackwardDeleteChar)
|
||||||
add(tui.Tab, actToggleDown)
|
add(tui.Tab, actToggleDown)
|
||||||
@@ -796,8 +816,10 @@ func defaultKeymap() map[tui.Event][]*action {
|
|||||||
add(tui.CtrlK, actUp)
|
add(tui.CtrlK, actUp)
|
||||||
add(tui.CtrlL, actClearScreen)
|
add(tui.CtrlL, actClearScreen)
|
||||||
add(tui.Enter, actAccept)
|
add(tui.Enter, actAccept)
|
||||||
add(tui.CtrlN, actDown)
|
add(tui.CtrlN, actDownMatch)
|
||||||
add(tui.CtrlP, actUp)
|
add(tui.CtrlP, actUpMatch)
|
||||||
|
add(tui.AltDown, actDownMatch)
|
||||||
|
add(tui.AltUp, actUpMatch)
|
||||||
add(tui.CtrlU, actUnixLineDiscard)
|
add(tui.CtrlU, actUnixLineDiscard)
|
||||||
add(tui.CtrlW, actUnixWordRubout)
|
add(tui.CtrlW, actUnixWordRubout)
|
||||||
add(tui.CtrlY, actYank)
|
add(tui.CtrlY, actYank)
|
||||||
@@ -951,11 +973,9 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
|
|||||||
wordRubout = fmt.Sprintf("%s[^%s]", sep, sep)
|
wordRubout = fmt.Sprintf("%s[^%s]", sep, sep)
|
||||||
wordNext = fmt.Sprintf("[^%s]%s|(.$)", sep, sep)
|
wordNext = fmt.Sprintf("[^%s]%s|(.$)", sep, sep)
|
||||||
}
|
}
|
||||||
keymapCopy := make(map[tui.Event][]*action)
|
keymapCopy := maps.Clone(opts.Keymap)
|
||||||
for key, action := range opts.Keymap {
|
|
||||||
keymapCopy[key] = action
|
|
||||||
}
|
|
||||||
|
|
||||||
|
em := EmptyMerger(revision{})
|
||||||
t := Terminal{
|
t := Terminal{
|
||||||
initDelay: delay,
|
initDelay: delay,
|
||||||
infoCommand: opts.InfoCommand,
|
infoCommand: opts.InfoCommand,
|
||||||
@@ -1042,6 +1062,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
|
|||||||
nth: opts.Nth,
|
nth: opts.Nth,
|
||||||
nthCurrent: opts.Nth,
|
nthCurrent: opts.Nth,
|
||||||
tabstop: opts.Tabstop,
|
tabstop: opts.Tabstop,
|
||||||
|
raw: opts.Raw,
|
||||||
hasStartActions: false,
|
hasStartActions: false,
|
||||||
hasResultActions: false,
|
hasResultActions: false,
|
||||||
hasFocusActions: false,
|
hasFocusActions: false,
|
||||||
@@ -1055,7 +1076,10 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
|
|||||||
printer: opts.Printer,
|
printer: opts.Printer,
|
||||||
printsep: opts.PrintSep,
|
printsep: opts.PrintSep,
|
||||||
proxyScript: opts.ProxyScript,
|
proxyScript: opts.ProxyScript,
|
||||||
merger: EmptyMerger(revision{}),
|
merger: em,
|
||||||
|
passMerger: em,
|
||||||
|
resultMerger: em,
|
||||||
|
matchMap: make(map[int32]Result),
|
||||||
selected: make(map[int32]selectedItem),
|
selected: make(map[int32]selectedItem),
|
||||||
runningCmds: util.NewConcurrentSet[*runningCmd](),
|
runningCmds: util.NewConcurrentSet[*runningCmd](),
|
||||||
reqBox: util.NewEventBox(),
|
reqBox: util.NewEventBox(),
|
||||||
@@ -1092,26 +1116,41 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
|
|||||||
t.acceptNth = opts.AcceptNth(t.delimiter)
|
t.acceptNth = opts.AcceptNth(t.delimiter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
baseTheme := opts.BaseTheme
|
||||||
|
if baseTheme == nil {
|
||||||
|
baseTheme = renderer.DefaultTheme()
|
||||||
|
}
|
||||||
// This should be called before accessing tui.Color*
|
// This should be called before accessing tui.Color*
|
||||||
tui.InitTheme(opts.Theme, renderer.DefaultTheme(), opts.Black, opts.InputBorderShape.Visible(), opts.HeaderBorderShape.Visible())
|
tui.InitTheme(opts.Theme, baseTheme, opts.Bold, opts.Black, opts.InputBorderShape.Visible(), opts.HeaderBorderShape.Visible())
|
||||||
|
|
||||||
// Gutter character
|
// Gutter character
|
||||||
var gutterChar string
|
var gutterChar, gutterRawChar string
|
||||||
if opts.Gutter != nil {
|
if opts.Gutter != nil {
|
||||||
gutterChar = *opts.Gutter
|
gutterChar = *opts.Gutter
|
||||||
} else if t.unicode && !t.theme.Gutter.Color.IsDefault() {
|
} else if t.unicode {
|
||||||
gutterChar = "▌"
|
gutterChar = "▌"
|
||||||
} else {
|
} else {
|
||||||
gutterChar = " "
|
gutterChar = " "
|
||||||
t.gutterReverse = true
|
t.gutterReverse = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if opts.GutterRaw != nil {
|
||||||
|
gutterRawChar = *opts.GutterRaw
|
||||||
|
} else if t.unicode {
|
||||||
|
gutterRawChar = "▖"
|
||||||
|
} else {
|
||||||
|
gutterRawChar = ":"
|
||||||
|
t.gutterRawReverse = false
|
||||||
|
}
|
||||||
|
|
||||||
t.prompt, t.promptLen = t.parsePrompt(opts.Prompt)
|
t.prompt, t.promptLen = t.parsePrompt(opts.Prompt)
|
||||||
// Pre-calculated empty pointer and marker signs
|
// Pre-calculated empty pointer and marker signs
|
||||||
if t.pointerLen == 0 {
|
if t.pointerLen == 0 {
|
||||||
t.pointerEmpty = ""
|
t.pointerEmpty = ""
|
||||||
|
t.pointerEmptyRaw = ""
|
||||||
} else {
|
} else {
|
||||||
t.pointerEmpty = gutterChar + strings.Repeat(" ", util.Max(0, t.pointerLen-1))
|
t.pointerEmpty = gutterChar + strings.Repeat(" ", util.Max(0, t.pointerLen-1))
|
||||||
|
t.pointerEmptyRaw = gutterRawChar + strings.Repeat(" ", util.Max(0, t.pointerLen-1))
|
||||||
}
|
}
|
||||||
t.markerEmpty = strings.Repeat(" ", t.markerLen)
|
t.markerEmpty = strings.Repeat(" ", t.markerLen)
|
||||||
|
|
||||||
@@ -1236,8 +1275,10 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
t.listener = listener
|
t.listener = listener
|
||||||
|
if port > 0 {
|
||||||
t.listenPort = &port
|
t.listenPort = &port
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if t.hasStartActions {
|
if t.hasStartActions {
|
||||||
t.eventChan <- tui.Start.AsEvent()
|
t.eventChan <- tui.Start.AsEvent()
|
||||||
@@ -1260,6 +1301,9 @@ func (t *Terminal) environForPreview() []string {
|
|||||||
|
|
||||||
func (t *Terminal) environImpl(forPreview bool) []string {
|
func (t *Terminal) environImpl(forPreview bool) []string {
|
||||||
env := os.Environ()
|
env := os.Environ()
|
||||||
|
if t.listenAddr != nil && len(t.listenAddr.sock) > 0 {
|
||||||
|
env = append(env, "FZF_SOCK="+t.listenAddr.sock)
|
||||||
|
}
|
||||||
if t.listenPort != nil {
|
if t.listenPort != nil {
|
||||||
env = append(env, fmt.Sprintf("FZF_PORT=%d", *t.listenPort))
|
env = append(env, fmt.Sprintf("FZF_PORT=%d", *t.listenPort))
|
||||||
}
|
}
|
||||||
@@ -1274,9 +1318,21 @@ func (t *Terminal) environImpl(forPreview bool) []string {
|
|||||||
env = append(env, "FZF_LIST_LABEL="+t.listLabelOpts.label)
|
env = append(env, "FZF_LIST_LABEL="+t.listLabelOpts.label)
|
||||||
env = append(env, "FZF_INPUT_LABEL="+t.inputLabelOpts.label)
|
env = append(env, "FZF_INPUT_LABEL="+t.inputLabelOpts.label)
|
||||||
env = append(env, "FZF_HEADER_LABEL="+t.headerLabelOpts.label)
|
env = append(env, "FZF_HEADER_LABEL="+t.headerLabelOpts.label)
|
||||||
|
direction := "down"
|
||||||
|
if t.layout == layoutDefault {
|
||||||
|
direction = "up"
|
||||||
|
}
|
||||||
|
env = append(env, "FZF_DIRECTION="+direction)
|
||||||
if len(t.nthCurrent) > 0 {
|
if len(t.nthCurrent) > 0 {
|
||||||
env = append(env, "FZF_NTH="+RangesToString(t.nthCurrent))
|
env = append(env, "FZF_NTH="+RangesToString(t.nthCurrent))
|
||||||
}
|
}
|
||||||
|
if t.raw {
|
||||||
|
val := "0"
|
||||||
|
if t.isCurrentItemMatch() {
|
||||||
|
val = "1"
|
||||||
|
}
|
||||||
|
env = append(env, "FZF_RAW="+val)
|
||||||
|
}
|
||||||
inputState := "enabled"
|
inputState := "enabled"
|
||||||
if t.inputless {
|
if t.inputless {
|
||||||
inputState = "hidden"
|
inputState = "hidden"
|
||||||
@@ -1285,7 +1341,7 @@ func (t *Terminal) environImpl(forPreview bool) []string {
|
|||||||
}
|
}
|
||||||
env = append(env, "FZF_INPUT_STATE="+inputState)
|
env = append(env, "FZF_INPUT_STATE="+inputState)
|
||||||
env = append(env, fmt.Sprintf("FZF_TOTAL_COUNT=%d", t.count))
|
env = append(env, fmt.Sprintf("FZF_TOTAL_COUNT=%d", t.count))
|
||||||
env = append(env, fmt.Sprintf("FZF_MATCH_COUNT=%d", t.merger.Length()))
|
env = append(env, fmt.Sprintf("FZF_MATCH_COUNT=%d", t.resultMerger.Length()))
|
||||||
env = append(env, fmt.Sprintf("FZF_SELECT_COUNT=%d", len(t.selected)))
|
env = append(env, fmt.Sprintf("FZF_SELECT_COUNT=%d", len(t.selected)))
|
||||||
env = append(env, fmt.Sprintf("FZF_LINES=%d", t.areaLines))
|
env = append(env, fmt.Sprintf("FZF_LINES=%d", t.areaLines))
|
||||||
env = append(env, fmt.Sprintf("FZF_COLUMNS=%d", t.areaColumns))
|
env = append(env, fmt.Sprintf("FZF_COLUMNS=%d", t.areaColumns))
|
||||||
@@ -1446,7 +1502,7 @@ func (t *Terminal) ansiLabelPrinter(str string, color *tui.ColorPair, fill bool)
|
|||||||
printFn := func(window tui.Window, limit int) {
|
printFn := func(window tui.Window, limit int) {
|
||||||
if offsets == nil {
|
if offsets == nil {
|
||||||
// tui.Col* are not initialized until renderer.Init()
|
// tui.Col* are not initialized until renderer.Init()
|
||||||
offsets = result.colorOffsets(nil, nil, t.theme, *color, *color, t.nthAttr)
|
offsets = result.colorOffsets(nil, nil, t.theme, *color, *color, t.nthAttr, false)
|
||||||
}
|
}
|
||||||
for limit > 0 {
|
for limit > 0 {
|
||||||
if length > limit {
|
if length > limit {
|
||||||
@@ -1509,7 +1565,7 @@ func (t *Terminal) parsePrompt(prompt string) (func(), int) {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
t.printHighlighted(
|
t.printHighlighted(
|
||||||
Result{item: item}, tui.ColPrompt, tui.ColPrompt, false, false, line, line, true, preTask, nil)
|
Result{item: item}, tui.ColPrompt, tui.ColPrompt, false, false, false, line, line, true, preTask, nil)
|
||||||
})
|
})
|
||||||
t.wrap = wrap
|
t.wrap = wrap
|
||||||
}
|
}
|
||||||
@@ -1696,7 +1752,8 @@ func (t *Terminal) UpdateProgress(progress float32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateList updates Merger to display the list
|
// UpdateList updates Merger to display the list
|
||||||
func (t *Terminal) UpdateList(merger *Merger) {
|
func (t *Terminal) UpdateList(result MatchResult) {
|
||||||
|
merger := result.merger
|
||||||
t.mutex.Lock()
|
t.mutex.Lock()
|
||||||
prevIndex := minItem.Index()
|
prevIndex := minItem.Index()
|
||||||
newRevision := merger.Revision()
|
newRevision := merger.Revision()
|
||||||
@@ -1709,6 +1766,15 @@ func (t *Terminal) UpdateList(merger *Merger) {
|
|||||||
}
|
}
|
||||||
t.progress = 100
|
t.progress = 100
|
||||||
t.merger = merger
|
t.merger = merger
|
||||||
|
t.resultMerger = merger
|
||||||
|
t.passMerger = result.passMerger
|
||||||
|
if t.raw {
|
||||||
|
t.merger = result.passMerger
|
||||||
|
t.matchMap = t.resultMerger.ToMap()
|
||||||
|
} else {
|
||||||
|
t.merger = result.merger
|
||||||
|
t.matchMap = make(map[int32]Result)
|
||||||
|
}
|
||||||
if t.revision != newRevision {
|
if t.revision != newRevision {
|
||||||
if !t.revision.compatible(newRevision) {
|
if !t.revision.compatible(newRevision) {
|
||||||
// Reloaded: clear selection
|
// Reloaded: clear selection
|
||||||
@@ -1757,7 +1823,7 @@ func (t *Terminal) UpdateList(merger *Merger) {
|
|||||||
}
|
}
|
||||||
needActivation := false
|
needActivation := false
|
||||||
if !t.reading {
|
if !t.reading {
|
||||||
switch t.merger.Length() {
|
switch t.resultMerger.Length() {
|
||||||
case 0:
|
case 0:
|
||||||
zero := tui.Zero.AsEvent()
|
zero := tui.Zero.AsEvent()
|
||||||
if _, prs := t.keymap[zero]; prs {
|
if _, prs := t.keymap[zero]; prs {
|
||||||
@@ -2400,6 +2466,13 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
|
|||||||
innerHeight-shrink, tui.WindowList, noBorder, true)
|
innerHeight-shrink, tui.WindowList, noBorder, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(t.scrollbar) == 0 {
|
||||||
|
for y := 0; y < t.window.Height(); y++ {
|
||||||
|
t.window.Move(y, t.window.Width()-1)
|
||||||
|
t.window.Print(" ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
createInnerWindow := func(b tui.Window, shape tui.BorderShape, windowType tui.WindowType, shift int) tui.Window {
|
createInnerWindow := func(b tui.Window, shape tui.BorderShape, windowType tui.WindowType, shift int) tui.Window {
|
||||||
top := b.Top()
|
top := b.Top()
|
||||||
left := b.Left() + shift
|
left := b.Left() + shift
|
||||||
@@ -2797,7 +2870,7 @@ func (t *Terminal) printInfoImpl() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
found := t.merger.Length()
|
found := t.resultMerger.Length()
|
||||||
total := util.Max(found, t.count)
|
total := util.Max(found, t.count)
|
||||||
output := fmt.Sprintf("%d/%d", found, total)
|
output := fmt.Sprintf("%d/%d", found, total)
|
||||||
if t.toggleSort {
|
if t.toggleSort {
|
||||||
@@ -2916,6 +2989,11 @@ func (t *Terminal) printInfoImpl() {
|
|||||||
} else {
|
} else {
|
||||||
outputPrinter(t.window, maxWidth)
|
outputPrinter(t.window, maxWidth)
|
||||||
}
|
}
|
||||||
|
if t.infoStyle == infoInline && outputLen < maxWidth-1 && t.reading {
|
||||||
|
t.window.Print(" ")
|
||||||
|
printSpinner()
|
||||||
|
outputLen += 2
|
||||||
|
}
|
||||||
|
|
||||||
if t.infoStyle == infoInlineRight {
|
if t.infoStyle == infoInlineRight {
|
||||||
if t.separatorLen > 0 {
|
if t.separatorLen > 0 {
|
||||||
@@ -3014,7 +3092,7 @@ func (t *Terminal) printFooter() {
|
|||||||
colors: colors}
|
colors: colors}
|
||||||
|
|
||||||
t.printHighlighted(Result{item: item},
|
t.printHighlighted(Result{item: item},
|
||||||
tui.ColFooter, tui.ColFooter, false, false, line, line, true,
|
tui.ColFooter, tui.ColFooter, false, false, false, line, line, true,
|
||||||
func(markerClass) int {
|
func(markerClass) int {
|
||||||
t.footerWindow.Print(indent)
|
t.footerWindow.Print(indent)
|
||||||
return indentSize
|
return indentSize
|
||||||
@@ -3086,7 +3164,7 @@ func (t *Terminal) printHeaderImpl(window tui.Window, borderShape tui.BorderShap
|
|||||||
colors: colors}
|
colors: colors}
|
||||||
|
|
||||||
t.printHighlighted(Result{item: item},
|
t.printHighlighted(Result{item: item},
|
||||||
tui.ColHeader, tui.ColHeader, false, false, line, line, true,
|
tui.ColHeader, tui.ColHeader, false, false, false, line, line, true,
|
||||||
func(markerClass) int {
|
func(markerClass) int {
|
||||||
t.window.Print(indent)
|
t.window.Print(indent)
|
||||||
return indentSize
|
return indentSize
|
||||||
@@ -3118,12 +3196,16 @@ func (t *Terminal) gutter(current bool) {
|
|||||||
var color tui.ColorPair
|
var color tui.ColorPair
|
||||||
if current {
|
if current {
|
||||||
color = tui.ColCurrentCursorEmpty
|
color = tui.ColCurrentCursorEmpty
|
||||||
} else if t.gutterReverse {
|
} else if !t.raw && t.gutterReverse || t.raw && t.gutterRawReverse {
|
||||||
color = tui.ColCursorEmpty
|
color = tui.ColCursorEmpty
|
||||||
} else {
|
} else {
|
||||||
color = tui.ColCursorEmptyChar
|
color = tui.ColCursorEmptyChar
|
||||||
}
|
}
|
||||||
t.window.CPrint(color, t.pointerEmpty)
|
gutter := t.pointerEmpty
|
||||||
|
if t.raw {
|
||||||
|
gutter = t.pointerEmptyRaw
|
||||||
|
}
|
||||||
|
t.window.CPrint(color, gutter)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terminal) renderGapLine(line int, barRange [2]int, drawLine bool) {
|
func (t *Terminal) renderGapLine(line int, barRange [2]int, drawLine bool) {
|
||||||
@@ -3158,7 +3240,8 @@ func (t *Terminal) printList() {
|
|||||||
for line, itemCount := startLine, 0; line <= maxy; line, itemCount = line+1, itemCount+1 {
|
for line, itemCount := startLine, 0; line <= maxy; line, itemCount = line+1, itemCount+1 {
|
||||||
if itemCount < count {
|
if itemCount < count {
|
||||||
item := t.merger.Get(itemCount + t.offset)
|
item := t.merger.Get(itemCount + t.offset)
|
||||||
line = t.printItem(item, line, maxy, itemCount, itemCount == t.cy-t.offset, barRange)
|
current := itemCount == t.cy-t.offset
|
||||||
|
line = t.printItem(item, line, maxy, itemCount, current, barRange)
|
||||||
} else if !t.prevLines[line].empty {
|
} else if !t.prevLines[line].empty {
|
||||||
t.renderEmptyLine(line, barRange)
|
t.renderEmptyLine(line, barRange)
|
||||||
}
|
}
|
||||||
@@ -3180,6 +3263,14 @@ func (t *Terminal) printBar(lineNum int, forceRedraw bool, barRange [2]int) bool
|
|||||||
|
|
||||||
func (t *Terminal) printItem(result Result, line int, maxLine int, index int, current bool, barRange [2]int) int {
|
func (t *Terminal) printItem(result Result, line int, maxLine int, index int, current bool, barRange [2]int) int {
|
||||||
item := result.item
|
item := result.item
|
||||||
|
matched := true
|
||||||
|
var matchResult Result
|
||||||
|
if t.raw {
|
||||||
|
if matchResult, matched = t.matchMap[item.Index()]; matched {
|
||||||
|
result = matchResult
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_, selected := t.selected[item.Index()]
|
_, selected := t.selected[item.Index()]
|
||||||
label := ""
|
label := ""
|
||||||
extraWidth := 0
|
extraWidth := 0
|
||||||
@@ -3210,7 +3301,7 @@ func (t *Terminal) printItem(result Result, line int, maxLine int, index int, cu
|
|||||||
// Avoid unnecessary redraw
|
// Avoid unnecessary redraw
|
||||||
numLines, _ := t.numItemLines(item, maxLine-line+1)
|
numLines, _ := t.numItemLines(item, maxLine-line+1)
|
||||||
newLine := itemLine{valid: true, firstLine: line, numLines: numLines, cy: index + t.offset, current: current, selected: selected, label: label,
|
newLine := itemLine{valid: true, firstLine: line, numLines: numLines, cy: index + t.offset, current: current, selected: selected, label: label,
|
||||||
result: result, queryLen: len(t.input), width: 0, hasBar: line >= barRange[0] && line < barRange[1]}
|
result: result, queryLen: len(t.input), width: 0, hasBar: line >= barRange[0] && line < barRange[1], hidden: !matched}
|
||||||
prevLine := t.prevLines[line]
|
prevLine := t.prevLines[line]
|
||||||
forceRedraw := !prevLine.valid || prevLine.other || prevLine.firstLine != newLine.firstLine
|
forceRedraw := !prevLine.valid || prevLine.other || prevLine.firstLine != newLine.firstLine
|
||||||
printBar := func(lineNum int, forceRedraw bool) bool {
|
printBar := func(lineNum int, forceRedraw bool) bool {
|
||||||
@@ -3218,6 +3309,7 @@ func (t *Terminal) printItem(result Result, line int, maxLine int, index int, cu
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !forceRedraw &&
|
if !forceRedraw &&
|
||||||
|
prevLine.hidden == newLine.hidden &&
|
||||||
prevLine.numLines == newLine.numLines &&
|
prevLine.numLines == newLine.numLines &&
|
||||||
prevLine.current == newLine.current &&
|
prevLine.current == newLine.current &&
|
||||||
prevLine.selected == newLine.selected &&
|
prevLine.selected == newLine.selected &&
|
||||||
@@ -3306,7 +3398,7 @@ func (t *Terminal) printItem(result Result, line int, maxLine int, index int, cu
|
|||||||
}
|
}
|
||||||
return indentSize
|
return indentSize
|
||||||
}
|
}
|
||||||
finalLineNum = t.printHighlighted(result, tui.ColCurrent, tui.ColCurrentMatch, true, true, line, maxLine, forceRedraw, preTask, postTask)
|
finalLineNum = t.printHighlighted(result, tui.ColCurrent, tui.ColCurrentMatch, true, true, !matched, line, maxLine, forceRedraw, preTask, postTask)
|
||||||
} else {
|
} else {
|
||||||
preTask := func(marker markerClass) int {
|
preTask := func(marker markerClass) int {
|
||||||
w := t.window.Width() - t.pointerLen
|
w := t.window.Width() - t.pointerLen
|
||||||
@@ -3340,7 +3432,7 @@ func (t *Terminal) printItem(result Result, line int, maxLine int, index int, cu
|
|||||||
base = base.WithBg(altBg)
|
base = base.WithBg(altBg)
|
||||||
match = match.WithBg(altBg)
|
match = match.WithBg(altBg)
|
||||||
}
|
}
|
||||||
finalLineNum = t.printHighlighted(result, base, match, false, true, line, maxLine, forceRedraw, preTask, postTask)
|
finalLineNum = t.printHighlighted(result, base, match, false, true, !matched, line, maxLine, forceRedraw, preTask, postTask)
|
||||||
}
|
}
|
||||||
for i := 0; i < t.gap && finalLineNum < maxLine; i++ {
|
for i := 0; i < t.gap && finalLineNum < maxLine; i++ {
|
||||||
finalLineNum++
|
finalLineNum++
|
||||||
@@ -3387,13 +3479,13 @@ func (t *Terminal) overflow(runes []rune, max int) bool {
|
|||||||
return t.displayWidthWithLimit(runes, 0, max) > max
|
return t.displayWidthWithLimit(runes, 0, max) > max
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMatch tui.ColorPair, current bool, match bool, lineNum int, maxLineNum int, forceRedraw bool, preTask func(markerClass) int, postTask func(int, int, bool, bool, tui.ColorPair)) int {
|
func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMatch tui.ColorPair, current bool, match bool, hidden bool, lineNum int, maxLineNum int, forceRedraw bool, preTask func(markerClass) int, postTask func(int, int, bool, bool, tui.ColorPair)) int {
|
||||||
var displayWidth int
|
var displayWidth int
|
||||||
item := result.item
|
item := result.item
|
||||||
matchOffsets := []Offset{}
|
matchOffsets := []Offset{}
|
||||||
var pos *[]int
|
var pos *[]int
|
||||||
if match && t.merger.pattern != nil {
|
if match && t.resultMerger.pattern != nil {
|
||||||
_, matchOffsets, pos = t.merger.pattern.MatchItem(item, true, t.slab)
|
_, matchOffsets, pos = t.resultMerger.pattern.MatchItem(item, true, t.slab)
|
||||||
}
|
}
|
||||||
charOffsets := matchOffsets
|
charOffsets := matchOffsets
|
||||||
if pos != nil {
|
if pos != nil {
|
||||||
@@ -3425,7 +3517,7 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
|
|||||||
}
|
}
|
||||||
if !wholeCovered && t.nthAttr > 0 {
|
if !wholeCovered && t.nthAttr > 0 {
|
||||||
var tokens []Token
|
var tokens []Token
|
||||||
if item.transformed != nil && item.transformed.revision == t.merger.revision {
|
if item.transformed != nil && item.transformed.revision == t.resultMerger.revision {
|
||||||
tokens = item.transformed.tokens
|
tokens = item.transformed.tokens
|
||||||
} else {
|
} else {
|
||||||
tokens = Transform(Tokenize(item.text.ToString(), t.delimiter), t.nthCurrent)
|
tokens = Transform(Tokenize(item.text.ToString(), t.delimiter), t.nthCurrent)
|
||||||
@@ -3439,7 +3531,7 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
|
|||||||
sort.Sort(ByOrder(nthOffsets))
|
sort.Sort(ByOrder(nthOffsets))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
allOffsets := result.colorOffsets(charOffsets, nthOffsets, t.theme, colBase, colMatch, t.nthAttr)
|
allOffsets := result.colorOffsets(charOffsets, nthOffsets, t.theme, colBase, colMatch, t.nthAttr, hidden)
|
||||||
|
|
||||||
maxLines := 1
|
maxLines := 1
|
||||||
if t.canSpanMultiLines() {
|
if t.canSpanMultiLines() {
|
||||||
@@ -3638,7 +3730,11 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
|
|||||||
}
|
}
|
||||||
|
|
||||||
if maxWidth > 0 {
|
if maxWidth > 0 {
|
||||||
t.printColoredString(t.window, line, offsets, colBase)
|
color := colBase
|
||||||
|
if hidden {
|
||||||
|
color = color.WithFg(t.theme.Nomatch)
|
||||||
|
}
|
||||||
|
t.printColoredString(t.window, line, offsets, color)
|
||||||
}
|
}
|
||||||
if postTask != nil {
|
if postTask != nil {
|
||||||
postTask(actualLineNum, displayWidth, wasWrapped, forceRedraw, lbg)
|
postTask(actualLineNum, displayWidth, wasWrapped, forceRedraw, lbg)
|
||||||
@@ -4673,6 +4769,33 @@ func (t *Terminal) currentItem() *Item {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) isCurrentItemMatch() bool {
|
||||||
|
cnt := t.merger.Length()
|
||||||
|
if t.cy >= 0 && cnt > 0 && cnt > t.cy {
|
||||||
|
if !t.raw {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
item := t.merger.Get(t.cy).item
|
||||||
|
return t.isItemMatch(item)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) isItemMatch(item *Item) bool {
|
||||||
|
_, matched := t.matchMap[item.Index()]
|
||||||
|
return matched
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) filterSelected() {
|
||||||
|
filtered := make(map[int32]selectedItem)
|
||||||
|
for k, v := range t.selected {
|
||||||
|
if t.isItemMatch(v.item) {
|
||||||
|
filtered[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.selected = filtered
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Terminal) buildPlusList(template string, forcePlus bool) (bool, [3][]*Item) {
|
func (t *Terminal) buildPlusList(template string, forcePlus bool) (bool, [3][]*Item) {
|
||||||
current := t.currentItem()
|
current := t.currentItem()
|
||||||
slot, plus, asterisk, forceUpdate := hasPreviewFlags(template)
|
slot, plus, asterisk, forceUpdate := hasPreviewFlags(template)
|
||||||
@@ -5413,7 +5536,7 @@ func (t *Terminal) Loop() error {
|
|||||||
req := func(evts ...util.EventType) {
|
req := func(evts ...util.EventType) {
|
||||||
for _, event := range evts {
|
for _, event := range evts {
|
||||||
events = append(events, event)
|
events = append(events, event)
|
||||||
if event == reqClose || event == reqQuit {
|
if isTerminalEvent(event) {
|
||||||
looping = false
|
looping = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5913,8 +6036,9 @@ func (t *Terminal) Loop() error {
|
|||||||
}
|
}
|
||||||
case actSelectAll:
|
case actSelectAll:
|
||||||
if t.multi > 0 {
|
if t.multi > 0 {
|
||||||
for i := 0; i < t.merger.Length(); i++ {
|
// Limit the scope only to the matching items
|
||||||
if !t.selectItem(t.merger.Get(i).item) {
|
for i := 0; i < t.resultMerger.Length(); i++ {
|
||||||
|
if !t.selectItem(t.resultMerger.Get(i).item) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5922,8 +6046,10 @@ func (t *Terminal) Loop() error {
|
|||||||
}
|
}
|
||||||
case actDeselectAll:
|
case actDeselectAll:
|
||||||
if t.multi > 0 {
|
if t.multi > 0 {
|
||||||
for i := 0; i < t.merger.Length() && len(t.selected) > 0; i++ {
|
// Also limit the scope only to the matching items, while this may
|
||||||
t.deselectItem(t.merger.Get(i).item)
|
// not be straightforward in raw mode.
|
||||||
|
for i := 0; i < t.resultMerger.Length() && len(t.selected) > 0; i++ {
|
||||||
|
t.deselectItem(t.resultMerger.Get(i).item)
|
||||||
}
|
}
|
||||||
req(reqList, reqInfo)
|
req(reqList, reqInfo)
|
||||||
}
|
}
|
||||||
@@ -5951,17 +6077,17 @@ func (t *Terminal) Loop() error {
|
|||||||
case actToggleAll:
|
case actToggleAll:
|
||||||
if t.multi > 0 {
|
if t.multi > 0 {
|
||||||
prevIndexes := make(map[int]struct{})
|
prevIndexes := make(map[int]struct{})
|
||||||
for i := 0; i < t.merger.Length() && len(t.selected) > 0; i++ {
|
for i := 0; i < t.resultMerger.Length() && len(t.selected) > 0; i++ {
|
||||||
item := t.merger.Get(i).item
|
item := t.resultMerger.Get(i).item
|
||||||
if _, found := t.selected[item.Index()]; found {
|
if _, found := t.selected[item.Index()]; found {
|
||||||
prevIndexes[i] = struct{}{}
|
prevIndexes[i] = struct{}{}
|
||||||
t.deselectItem(item)
|
t.deselectItem(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < t.merger.Length(); i++ {
|
for i := 0; i < t.resultMerger.Length(); i++ {
|
||||||
if _, found := prevIndexes[i]; !found {
|
if _, found := prevIndexes[i]; !found {
|
||||||
item := t.merger.Get(i).item
|
item := t.resultMerger.Get(i).item
|
||||||
if !t.selectItem(item) {
|
if !t.selectItem(item) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -5989,11 +6115,88 @@ func (t *Terminal) Loop() error {
|
|||||||
t.vmove(1, true)
|
t.vmove(1, true)
|
||||||
req(reqList)
|
req(reqList)
|
||||||
}
|
}
|
||||||
case actDown:
|
case actDown, actDownMatch, actUp, actUpMatch:
|
||||||
t.vmove(-1, true)
|
dir := -1
|
||||||
|
if a.t == actUp || a.t == actUpMatch {
|
||||||
|
dir = 1
|
||||||
|
}
|
||||||
|
if t.raw && (a.t == actDownMatch || a.t == actUpMatch) {
|
||||||
|
if t.resultMerger.Length() > 0 {
|
||||||
|
prevCy := t.cy
|
||||||
|
for t.vmove(dir, true) && !t.isCurrentItemMatch() {
|
||||||
|
}
|
||||||
|
if !t.isCurrentItemMatch() {
|
||||||
|
t.vset(prevCy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.vmove(dir, true)
|
||||||
|
}
|
||||||
req(reqList)
|
req(reqList)
|
||||||
case actUp:
|
case actToggleRaw, actEnableRaw, actDisableRaw:
|
||||||
t.vmove(1, true)
|
prevRaw := t.raw
|
||||||
|
newRaw := t.raw
|
||||||
|
switch a.t {
|
||||||
|
case actEnableRaw:
|
||||||
|
newRaw = true
|
||||||
|
case actDisableRaw:
|
||||||
|
newRaw = false
|
||||||
|
case actToggleRaw:
|
||||||
|
newRaw = !t.raw
|
||||||
|
}
|
||||||
|
if prevRaw == newRaw {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
prevPos := t.cy - t.offset
|
||||||
|
prevIndex := t.currentIndex()
|
||||||
|
if newRaw {
|
||||||
|
// Build matchMap if not available
|
||||||
|
if len(t.matchMap) == 0 {
|
||||||
|
t.matchMap = t.resultMerger.ToMap()
|
||||||
|
}
|
||||||
|
t.merger = t.passMerger
|
||||||
|
} else {
|
||||||
|
// Find the closest matching item
|
||||||
|
if !t.isCurrentItemMatch() && t.resultMerger.Length() > 1 {
|
||||||
|
distance := 0
|
||||||
|
Loop:
|
||||||
|
for {
|
||||||
|
distance++
|
||||||
|
checks := 0
|
||||||
|
for _, cy := range []int{t.cy + distance, t.cy - distance} {
|
||||||
|
if cy >= 0 && cy < t.merger.Length() {
|
||||||
|
checks++
|
||||||
|
item := t.merger.Get(cy).item
|
||||||
|
if t.isItemMatch(item) {
|
||||||
|
prevIndex = item.Index()
|
||||||
|
break Loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if checks == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.merger = t.resultMerger
|
||||||
|
|
||||||
|
// Need to remove non-matching items from the selection
|
||||||
|
if t.multi > 0 && len(t.selected) > 0 {
|
||||||
|
t.filterSelected()
|
||||||
|
req(reqInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.raw = newRaw
|
||||||
|
|
||||||
|
// Try to retain position
|
||||||
|
if prevIndex != minItem.Index() {
|
||||||
|
t.cy = util.Max(0, t.merger.FindIndex(prevIndex))
|
||||||
|
t.offset = t.cy - prevPos
|
||||||
|
}
|
||||||
|
|
||||||
|
// List needs to be rerendered
|
||||||
|
t.forceRerenderList()
|
||||||
req(reqList)
|
req(reqList)
|
||||||
case actAccept:
|
case actAccept:
|
||||||
req(reqClose)
|
req(reqClose)
|
||||||
@@ -6018,8 +6221,14 @@ func (t *Terminal) Loop() error {
|
|||||||
t.version++
|
t.version++
|
||||||
req(reqList, reqInfo)
|
req(reqList, reqInfo)
|
||||||
}
|
}
|
||||||
case actFirst:
|
case actFirst, actBest:
|
||||||
|
if t.raw && a.t == actBest {
|
||||||
|
if t.resultMerger.Length() > 0 {
|
||||||
|
t.vset(t.merger.FindIndex(t.resultMerger.Get(0).item.Index()))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
t.vset(0)
|
t.vset(0)
|
||||||
|
}
|
||||||
t.constrain()
|
t.constrain()
|
||||||
req(reqList)
|
req(reqList)
|
||||||
case actLast:
|
case actLast:
|
||||||
@@ -6147,7 +6356,7 @@ func (t *Terminal) Loop() error {
|
|||||||
if a.t == actOffsetDown {
|
if a.t == actOffsetDown {
|
||||||
diff = -1
|
diff = -1
|
||||||
}
|
}
|
||||||
if t.layout == layoutReverse {
|
if t.layout != layoutDefault {
|
||||||
diff *= -1
|
diff *= -1
|
||||||
}
|
}
|
||||||
t.offset += diff
|
t.offset += diff
|
||||||
@@ -6155,7 +6364,7 @@ func (t *Terminal) Loop() error {
|
|||||||
t.constrain()
|
t.constrain()
|
||||||
if before != t.offset {
|
if before != t.offset {
|
||||||
t.offset = before
|
t.offset = before
|
||||||
if t.layout == layoutReverse {
|
if t.layout != layoutDefault {
|
||||||
diff *= -1
|
diff *= -1
|
||||||
}
|
}
|
||||||
t.vmove(diff, false)
|
t.vmove(diff, false)
|
||||||
@@ -6837,7 +7046,7 @@ func (t *Terminal) Loop() error {
|
|||||||
reload := changed || newCommand != nil
|
reload := changed || newCommand != nil
|
||||||
var reloadRequest *searchRequest
|
var reloadRequest *searchRequest
|
||||||
if reload {
|
if reload {
|
||||||
reloadRequest = &searchRequest{sort: t.sort, sync: reloadSync, nth: newNth, command: newCommand, environ: t.environ(), changed: changed, denylist: denylist, revision: t.merger.Revision()}
|
reloadRequest = &searchRequest{sort: t.sort, sync: reloadSync, nth: newNth, command: newCommand, environ: t.environ(), changed: changed, denylist: denylist, revision: t.resultMerger.Revision()}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dispatch queued background requests
|
// Dispatch queued background requests
|
||||||
@@ -6957,7 +7166,8 @@ func (t *Terminal) constrain() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terminal) vmove(o int, allowCycle bool) {
|
// Returns true if the cursor position is successfully updated
|
||||||
|
func (t *Terminal) vmove(o int, allowCycle bool) bool {
|
||||||
if t.layout != layoutDefault {
|
if t.layout != layoutDefault {
|
||||||
o *= -1
|
o *= -1
|
||||||
}
|
}
|
||||||
@@ -6974,7 +7184,7 @@ func (t *Terminal) vmove(o int, allowCycle bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t.vset(dest)
|
return t.vset(dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terminal) vset(o int) bool {
|
func (t *Terminal) vset(o int) bool {
|
||||||
@@ -7041,9 +7251,9 @@ func (t *Terminal) dumpStatus(params getParams) string {
|
|||||||
selected[i] = t.dumpItem(selectedItems[i+params.offset].item)
|
selected[i] = t.dumpItem(selectedItems[i+params.offset].item)
|
||||||
}
|
}
|
||||||
|
|
||||||
matches := make([]StatusItem, util.Max(0, util.Min(params.limit, t.merger.Length()-params.offset)))
|
matches := make([]StatusItem, util.Max(0, util.Min(params.limit, t.resultMerger.Length()-params.offset)))
|
||||||
for i := range matches {
|
for i := range matches {
|
||||||
matches[i] = t.dumpItem(t.merger.Get(i + params.offset).item)
|
matches[i] = t.dumpItem(t.resultMerger.Get(i + params.offset).item)
|
||||||
}
|
}
|
||||||
|
|
||||||
var current *StatusItem
|
var current *StatusItem
|
||||||
@@ -7060,7 +7270,7 @@ func (t *Terminal) dumpStatus(params getParams) string {
|
|||||||
Position: t.cy,
|
Position: t.cy,
|
||||||
Sort: t.sort,
|
Sort: t.sort,
|
||||||
TotalCount: t.count,
|
TotalCount: t.count,
|
||||||
MatchCount: t.merger.Length(),
|
MatchCount: t.resultMerger.Length(),
|
||||||
Current: current,
|
Current: current,
|
||||||
Matches: matches,
|
Matches: matches,
|
||||||
Selected: selected,
|
Selected: selected,
|
||||||
|
|||||||
@@ -2,30 +2,7 @@
|
|||||||
|
|
||||||
package tui
|
package tui
|
||||||
|
|
||||||
type Attr int32
|
|
||||||
|
|
||||||
func HasFullscreenRenderer() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
var DefaultBorderShape = BorderRounded
|
|
||||||
|
|
||||||
func (a Attr) Merge(b Attr) Attr {
|
|
||||||
if b&AttrRegular > 0 {
|
|
||||||
// Only keep bold attribute set by the system
|
|
||||||
return (b &^ AttrRegular) | (a & BoldForce)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (a &^ AttrRegular) | b
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AttrUndefined = Attr(0)
|
|
||||||
AttrRegular = Attr(1 << 8)
|
|
||||||
AttrClear = Attr(1 << 9)
|
|
||||||
BoldForce = Attr(1 << 10)
|
|
||||||
FullBg = Attr(1 << 11)
|
|
||||||
|
|
||||||
Bold = Attr(1)
|
Bold = Attr(1)
|
||||||
Dim = Attr(1 << 1)
|
Dim = Attr(1 << 1)
|
||||||
Italic = Attr(1 << 2)
|
Italic = Attr(1 << 2)
|
||||||
@@ -36,6 +13,12 @@ const (
|
|||||||
StrikeThrough = Attr(1 << 7)
|
StrikeThrough = Attr(1 << 7)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func HasFullscreenRenderer() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var DefaultBorderShape = BorderRounded
|
||||||
|
|
||||||
func (r *FullscreenRenderer) Init() error { return nil }
|
func (r *FullscreenRenderer) Init() error { return nil }
|
||||||
func (r *FullscreenRenderer) DefaultTheme() *ColorTheme { return nil }
|
func (r *FullscreenRenderer) DefaultTheme() *ColorTheme { return nil }
|
||||||
func (r *FullscreenRenderer) Resize(maxHeightFunc func(int) int) {}
|
func (r *FullscreenRenderer) Resize(maxHeightFunc func(int) int) {}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ func _() {
|
|||||||
_ = x[CtrlE-5]
|
_ = x[CtrlE-5]
|
||||||
_ = x[CtrlF-6]
|
_ = x[CtrlF-6]
|
||||||
_ = x[CtrlG-7]
|
_ = x[CtrlG-7]
|
||||||
_ = x[CtrlH-8]
|
_ = x[CtrlBackspace-8]
|
||||||
_ = x[Tab-9]
|
_ = x[Tab-9]
|
||||||
_ = x[CtrlJ-10]
|
_ = x[CtrlJ-10]
|
||||||
_ = x[CtrlK-11]
|
_ = x[CtrlK-11]
|
||||||
@@ -99,75 +99,74 @@ func _() {
|
|||||||
_ = x[CtrlRight-88]
|
_ = x[CtrlRight-88]
|
||||||
_ = x[CtrlHome-89]
|
_ = x[CtrlHome-89]
|
||||||
_ = x[CtrlEnd-90]
|
_ = x[CtrlEnd-90]
|
||||||
_ = x[CtrlBackspace-91]
|
_ = x[CtrlDelete-91]
|
||||||
_ = x[CtrlDelete-92]
|
_ = x[CtrlPageUp-92]
|
||||||
_ = x[CtrlPageUp-93]
|
_ = x[CtrlPageDown-93]
|
||||||
_ = x[CtrlPageDown-94]
|
_ = x[Alt-94]
|
||||||
_ = x[Alt-95]
|
_ = x[CtrlAlt-95]
|
||||||
_ = x[CtrlAlt-96]
|
_ = x[CtrlAltUp-96]
|
||||||
_ = x[CtrlAltUp-97]
|
_ = x[CtrlAltDown-97]
|
||||||
_ = x[CtrlAltDown-98]
|
_ = x[CtrlAltLeft-98]
|
||||||
_ = x[CtrlAltLeft-99]
|
_ = x[CtrlAltRight-99]
|
||||||
_ = x[CtrlAltRight-100]
|
_ = x[CtrlAltHome-100]
|
||||||
_ = x[CtrlAltHome-101]
|
_ = x[CtrlAltEnd-101]
|
||||||
_ = x[CtrlAltEnd-102]
|
_ = x[CtrlAltBackspace-102]
|
||||||
_ = x[CtrlAltBackspace-103]
|
_ = x[CtrlAltDelete-103]
|
||||||
_ = x[CtrlAltDelete-104]
|
_ = x[CtrlAltPageUp-104]
|
||||||
_ = x[CtrlAltPageUp-105]
|
_ = x[CtrlAltPageDown-105]
|
||||||
_ = x[CtrlAltPageDown-106]
|
_ = x[CtrlShiftUp-106]
|
||||||
_ = x[CtrlShiftUp-107]
|
_ = x[CtrlShiftDown-107]
|
||||||
_ = x[CtrlShiftDown-108]
|
_ = x[CtrlShiftLeft-108]
|
||||||
_ = x[CtrlShiftLeft-109]
|
_ = x[CtrlShiftRight-109]
|
||||||
_ = x[CtrlShiftRight-110]
|
_ = x[CtrlShiftHome-110]
|
||||||
_ = x[CtrlShiftHome-111]
|
_ = x[CtrlShiftEnd-111]
|
||||||
_ = x[CtrlShiftEnd-112]
|
_ = x[CtrlShiftDelete-112]
|
||||||
_ = x[CtrlShiftDelete-113]
|
_ = x[CtrlShiftPageUp-113]
|
||||||
_ = x[CtrlShiftPageUp-114]
|
_ = x[CtrlShiftPageDown-114]
|
||||||
_ = x[CtrlShiftPageDown-115]
|
_ = x[CtrlAltShiftUp-115]
|
||||||
_ = x[CtrlAltShiftUp-116]
|
_ = x[CtrlAltShiftDown-116]
|
||||||
_ = x[CtrlAltShiftDown-117]
|
_ = x[CtrlAltShiftLeft-117]
|
||||||
_ = x[CtrlAltShiftLeft-118]
|
_ = x[CtrlAltShiftRight-118]
|
||||||
_ = x[CtrlAltShiftRight-119]
|
_ = x[CtrlAltShiftHome-119]
|
||||||
_ = x[CtrlAltShiftHome-120]
|
_ = x[CtrlAltShiftEnd-120]
|
||||||
_ = x[CtrlAltShiftEnd-121]
|
_ = x[CtrlAltShiftDelete-121]
|
||||||
_ = x[CtrlAltShiftDelete-122]
|
_ = x[CtrlAltShiftPageUp-122]
|
||||||
_ = x[CtrlAltShiftPageUp-123]
|
_ = x[CtrlAltShiftPageDown-123]
|
||||||
_ = x[CtrlAltShiftPageDown-124]
|
_ = x[Invalid-124]
|
||||||
_ = x[Invalid-125]
|
_ = x[Fatal-125]
|
||||||
_ = x[Fatal-126]
|
_ = x[BracketedPasteBegin-126]
|
||||||
_ = x[BracketedPasteBegin-127]
|
_ = x[BracketedPasteEnd-127]
|
||||||
_ = x[BracketedPasteEnd-128]
|
_ = x[Mouse-128]
|
||||||
_ = x[Mouse-129]
|
_ = x[DoubleClick-129]
|
||||||
_ = x[DoubleClick-130]
|
_ = x[LeftClick-130]
|
||||||
_ = x[LeftClick-131]
|
_ = x[RightClick-131]
|
||||||
_ = x[RightClick-132]
|
_ = x[SLeftClick-132]
|
||||||
_ = x[SLeftClick-133]
|
_ = x[SRightClick-133]
|
||||||
_ = x[SRightClick-134]
|
_ = x[ScrollUp-134]
|
||||||
_ = x[ScrollUp-135]
|
_ = x[ScrollDown-135]
|
||||||
_ = x[ScrollDown-136]
|
_ = x[SScrollUp-136]
|
||||||
_ = x[SScrollUp-137]
|
_ = x[SScrollDown-137]
|
||||||
_ = x[SScrollDown-138]
|
_ = x[PreviewScrollUp-138]
|
||||||
_ = x[PreviewScrollUp-139]
|
_ = x[PreviewScrollDown-139]
|
||||||
_ = x[PreviewScrollDown-140]
|
_ = x[Resize-140]
|
||||||
_ = x[Resize-141]
|
_ = x[Change-141]
|
||||||
_ = x[Change-142]
|
_ = x[BackwardEOF-142]
|
||||||
_ = x[BackwardEOF-143]
|
_ = x[Start-143]
|
||||||
_ = x[Start-144]
|
_ = x[Load-144]
|
||||||
_ = x[Load-145]
|
_ = x[Focus-145]
|
||||||
_ = x[Focus-146]
|
_ = x[One-146]
|
||||||
_ = x[One-147]
|
_ = x[Zero-147]
|
||||||
_ = x[Zero-148]
|
_ = x[Result-148]
|
||||||
_ = x[Result-149]
|
_ = x[Jump-149]
|
||||||
_ = x[Jump-150]
|
_ = x[JumpCancel-150]
|
||||||
_ = x[JumpCancel-151]
|
_ = x[ClickHeader-151]
|
||||||
_ = x[ClickHeader-152]
|
_ = x[ClickFooter-152]
|
||||||
_ = x[ClickFooter-153]
|
_ = x[Multi-153]
|
||||||
_ = x[Multi-154]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const _EventType_name = "RuneCtrlACtrlBCtrlCCtrlDCtrlECtrlFCtrlGCtrlHTabCtrlJCtrlKCtrlLEnterCtrlNCtrlOCtrlPCtrlQCtrlRCtrlSCtrlTCtrlUCtrlVCtrlWCtrlXCtrlYCtrlZEscCtrlSpaceCtrlBackSlashCtrlRightBracketCtrlCaretCtrlSlashShiftTabBackspaceDeletePageUpPageDownUpDownLeftRightHomeEndInsertShiftUpShiftDownShiftLeftShiftRightShiftDeleteShiftHomeShiftEndShiftPageUpShiftPageDownF1F2F3F4F5F6F7F8F9F10F11F12AltBackspaceAltUpAltDownAltLeftAltRightAltDeleteAltHomeAltEndAltPageUpAltPageDownAltShiftUpAltShiftDownAltShiftLeftAltShiftRightAltShiftDeleteAltShiftHomeAltShiftEndAltShiftPageUpAltShiftPageDownCtrlUpCtrlDownCtrlLeftCtrlRightCtrlHomeCtrlEndCtrlBackspaceCtrlDeleteCtrlPageUpCtrlPageDownAltCtrlAltCtrlAltUpCtrlAltDownCtrlAltLeftCtrlAltRightCtrlAltHomeCtrlAltEndCtrlAltBackspaceCtrlAltDeleteCtrlAltPageUpCtrlAltPageDownCtrlShiftUpCtrlShiftDownCtrlShiftLeftCtrlShiftRightCtrlShiftHomeCtrlShiftEndCtrlShiftDeleteCtrlShiftPageUpCtrlShiftPageDownCtrlAltShiftUpCtrlAltShiftDownCtrlAltShiftLeftCtrlAltShiftRightCtrlAltShiftHomeCtrlAltShiftEndCtrlAltShiftDeleteCtrlAltShiftPageUpCtrlAltShiftPageDownInvalidFatalBracketedPasteBeginBracketedPasteEndMouseDoubleClickLeftClickRightClickSLeftClickSRightClickScrollUpScrollDownSScrollUpSScrollDownPreviewScrollUpPreviewScrollDownResizeChangeBackwardEOFStartLoadFocusOneZeroResultJumpJumpCancelClickHeaderClickFooterMulti"
|
const _EventType_name = "RuneCtrlACtrlBCtrlCCtrlDCtrlECtrlFCtrlGCtrlBackspaceTabCtrlJCtrlKCtrlLEnterCtrlNCtrlOCtrlPCtrlQCtrlRCtrlSCtrlTCtrlUCtrlVCtrlWCtrlXCtrlYCtrlZEscCtrlSpaceCtrlBackSlashCtrlRightBracketCtrlCaretCtrlSlashShiftTabBackspaceDeletePageUpPageDownUpDownLeftRightHomeEndInsertShiftUpShiftDownShiftLeftShiftRightShiftDeleteShiftHomeShiftEndShiftPageUpShiftPageDownF1F2F3F4F5F6F7F8F9F10F11F12AltBackspaceAltUpAltDownAltLeftAltRightAltDeleteAltHomeAltEndAltPageUpAltPageDownAltShiftUpAltShiftDownAltShiftLeftAltShiftRightAltShiftDeleteAltShiftHomeAltShiftEndAltShiftPageUpAltShiftPageDownCtrlUpCtrlDownCtrlLeftCtrlRightCtrlHomeCtrlEndCtrlDeleteCtrlPageUpCtrlPageDownAltCtrlAltCtrlAltUpCtrlAltDownCtrlAltLeftCtrlAltRightCtrlAltHomeCtrlAltEndCtrlAltBackspaceCtrlAltDeleteCtrlAltPageUpCtrlAltPageDownCtrlShiftUpCtrlShiftDownCtrlShiftLeftCtrlShiftRightCtrlShiftHomeCtrlShiftEndCtrlShiftDeleteCtrlShiftPageUpCtrlShiftPageDownCtrlAltShiftUpCtrlAltShiftDownCtrlAltShiftLeftCtrlAltShiftRightCtrlAltShiftHomeCtrlAltShiftEndCtrlAltShiftDeleteCtrlAltShiftPageUpCtrlAltShiftPageDownInvalidFatalBracketedPasteBeginBracketedPasteEndMouseDoubleClickLeftClickRightClickSLeftClickSRightClickScrollUpScrollDownSScrollUpSScrollDownPreviewScrollUpPreviewScrollDownResizeChangeBackwardEOFStartLoadFocusOneZeroResultJumpJumpCancelClickHeaderClickFooterMulti"
|
||||||
|
|
||||||
var _EventType_index = [...]uint16{0, 4, 9, 14, 19, 24, 29, 34, 39, 44, 47, 52, 57, 62, 67, 72, 77, 82, 87, 92, 97, 102, 107, 112, 117, 122, 127, 132, 135, 144, 157, 173, 182, 191, 199, 208, 214, 220, 228, 230, 234, 238, 243, 247, 250, 256, 263, 272, 281, 291, 302, 311, 319, 330, 343, 345, 347, 349, 351, 353, 355, 357, 359, 361, 364, 367, 370, 382, 387, 394, 401, 409, 418, 425, 431, 440, 451, 461, 473, 485, 498, 512, 524, 535, 549, 565, 571, 579, 587, 596, 604, 611, 624, 634, 644, 656, 659, 666, 675, 686, 697, 709, 720, 730, 746, 759, 772, 787, 798, 811, 824, 838, 851, 863, 878, 893, 910, 924, 940, 956, 973, 989, 1004, 1022, 1040, 1060, 1067, 1072, 1091, 1108, 1113, 1124, 1133, 1143, 1153, 1164, 1172, 1182, 1191, 1202, 1217, 1234, 1240, 1246, 1257, 1262, 1266, 1271, 1274, 1278, 1284, 1288, 1298, 1309, 1320, 1325}
|
var _EventType_index = [...]uint16{0, 4, 9, 14, 19, 24, 29, 34, 39, 52, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 143, 152, 165, 181, 190, 199, 207, 216, 222, 228, 236, 238, 242, 246, 251, 255, 258, 264, 271, 280, 289, 299, 310, 319, 327, 338, 351, 353, 355, 357, 359, 361, 363, 365, 367, 369, 372, 375, 378, 390, 395, 402, 409, 417, 426, 433, 439, 448, 459, 469, 481, 493, 506, 520, 532, 543, 557, 573, 579, 587, 595, 604, 612, 619, 629, 639, 651, 654, 661, 670, 681, 692, 704, 715, 725, 741, 754, 767, 782, 793, 806, 819, 833, 846, 858, 873, 888, 905, 919, 935, 951, 968, 984, 999, 1017, 1035, 1055, 1062, 1067, 1086, 1103, 1108, 1119, 1128, 1138, 1148, 1159, 1167, 1177, 1186, 1197, 1212, 1229, 1235, 1241, 1252, 1257, 1261, 1266, 1269, 1273, 1279, 1283, 1293, 1304, 1315, 1320}
|
||||||
|
|
||||||
func (i EventType) String() string {
|
func (i EventType) String() string {
|
||||||
if i < 0 || i >= EventType(len(_EventType_index)-1) {
|
if i < 0 || i >= EventType(len(_EventType_index)-1) {
|
||||||
|
|||||||
@@ -479,6 +479,7 @@ func (r *LightRenderer) escSequence(sz *int) Event {
|
|||||||
return Event{Delete, 0, nil}
|
return Event{Delete, 0, nil}
|
||||||
}
|
}
|
||||||
if len(r.buffer) == 7 && r.buffer[6] == '~' && r.buffer[4] == '1' {
|
if len(r.buffer) == 7 && r.buffer[6] == '~' && r.buffer[4] == '1' {
|
||||||
|
*sz = 7
|
||||||
switch r.buffer[5] {
|
switch r.buffer[5] {
|
||||||
case '0':
|
case '0':
|
||||||
return Event{AltShiftDelete, 0, nil}
|
return Event{AltShiftDelete, 0, nil}
|
||||||
@@ -525,6 +526,7 @@ func (r *LightRenderer) escSequence(sz *int) Event {
|
|||||||
return Event{PageUp, 0, nil}
|
return Event{PageUp, 0, nil}
|
||||||
}
|
}
|
||||||
if len(r.buffer) == 7 && r.buffer[6] == '~' && r.buffer[4] == '1' {
|
if len(r.buffer) == 7 && r.buffer[6] == '~' && r.buffer[4] == '1' {
|
||||||
|
*sz = 7
|
||||||
switch r.buffer[5] {
|
switch r.buffer[5] {
|
||||||
case '0':
|
case '0':
|
||||||
return Event{AltShiftPageUp, 0, nil}
|
return Event{AltShiftPageUp, 0, nil}
|
||||||
@@ -569,6 +571,7 @@ func (r *LightRenderer) escSequence(sz *int) Event {
|
|||||||
return Event{PageDown, 0, nil}
|
return Event{PageDown, 0, nil}
|
||||||
}
|
}
|
||||||
if len(r.buffer) == 7 && r.buffer[6] == '~' && r.buffer[4] == '1' {
|
if len(r.buffer) == 7 && r.buffer[6] == '~' && r.buffer[4] == '1' {
|
||||||
|
*sz = 7
|
||||||
switch r.buffer[5] {
|
switch r.buffer[5] {
|
||||||
case '0':
|
case '0':
|
||||||
return Event{AltShiftPageDown, 0, nil}
|
return Event{AltShiftPageDown, 0, nil}
|
||||||
|
|||||||
@@ -36,8 +36,6 @@ func (p ColorPair) style() tcell.Style {
|
|||||||
return style.Foreground(asTcellColor(p.Fg())).Background(asTcellColor(p.Bg()))
|
return style.Foreground(asTcellColor(p.Fg())).Background(asTcellColor(p.Bg()))
|
||||||
}
|
}
|
||||||
|
|
||||||
type Attr int32
|
|
||||||
|
|
||||||
type TcellWindow struct {
|
type TcellWindow struct {
|
||||||
color bool
|
color bool
|
||||||
windowType WindowType
|
windowType WindowType
|
||||||
@@ -98,14 +96,6 @@ const (
|
|||||||
Italic = Attr(tcell.AttrItalic)
|
Italic = Attr(tcell.AttrItalic)
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
AttrUndefined = Attr(0)
|
|
||||||
AttrRegular = Attr(1 << 7)
|
|
||||||
AttrClear = Attr(1 << 8)
|
|
||||||
BoldForce = Attr(1 << 10)
|
|
||||||
FullBg = Attr(1 << 11)
|
|
||||||
)
|
|
||||||
|
|
||||||
func (r *FullscreenRenderer) Bell() {
|
func (r *FullscreenRenderer) Bell() {
|
||||||
_screen.Beep()
|
_screen.Beep()
|
||||||
}
|
}
|
||||||
@@ -159,15 +149,6 @@ func (c Color) Style() tcell.Color {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a Attr) Merge(b Attr) Attr {
|
|
||||||
if b&AttrRegular > 0 {
|
|
||||||
// Only keep bold attribute set by the system
|
|
||||||
return (b &^ AttrRegular) | (a & BoldForce)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (a &^ AttrRegular) | b
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle the following as private members of FullscreenRenderer instance
|
// handle the following as private members of FullscreenRenderer instance
|
||||||
// they are declared here to prevent introducing tcell library in non-windows builds
|
// they are declared here to prevent introducing tcell library in non-windows builds
|
||||||
var (
|
var (
|
||||||
@@ -390,12 +371,10 @@ func (r *FullscreenRenderer) GetChar() Event {
|
|||||||
}
|
}
|
||||||
case rune(tcell.KeyCtrlH):
|
case rune(tcell.KeyCtrlH):
|
||||||
switch {
|
switch {
|
||||||
case ctrl:
|
|
||||||
return keyfn('h')
|
|
||||||
case alt:
|
case alt:
|
||||||
return Event{AltBackspace, 0, nil}
|
return Event{AltBackspace, 0, nil}
|
||||||
case none, shift:
|
case ctrl, none, shift:
|
||||||
return Event{Backspace, 0, nil}
|
return keyfn('h')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case tcell.KeyCtrlI:
|
case tcell.KeyCtrlI:
|
||||||
|
|||||||
@@ -113,18 +113,18 @@ func TestGetCharEventKey(t *testing.T) {
|
|||||||
{giveKey{tcell.KeyBackspace, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
|
{giveKey{tcell.KeyBackspace, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
|
||||||
{giveKey{tcell.KeyBS, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
|
{giveKey{tcell.KeyBS, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
|
||||||
{giveKey{tcell.KeyCtrlH, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
|
{giveKey{tcell.KeyCtrlH, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
|
||||||
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModNone}, wantKey{Backspace, 0, nil}}, // actual "Backspace" keystroke
|
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModNone}, wantKey{CtrlBackspace, 0, nil}}, // actual "Backspace" keystroke
|
||||||
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModAlt}, wantKey{AltBackspace, 0, nil}}, // actual "Alt+Backspace" keystroke
|
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModAlt}, wantKey{AltBackspace, 0, nil}}, // actual "Alt+Backspace" keystroke
|
||||||
{giveKey{tcell.KeyDEL, rune(tcell.KeyDEL), tcell.ModCtrl}, wantKey{CtrlBackspace, 0, nil}}, // actual "Ctrl+Backspace" keystroke
|
{giveKey{tcell.KeyDEL, rune(tcell.KeyDEL), tcell.ModCtrl}, wantKey{CtrlBackspace, 0, nil}}, // actual "Ctrl+Backspace" keystroke
|
||||||
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModShift}, wantKey{Backspace, 0, nil}}, // actual "Shift+Backspace" keystroke
|
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModShift}, wantKey{CtrlBackspace, 0, nil}}, // actual "Shift+Backspace" keystroke
|
||||||
{giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltBackspace, 0, nil}}, // actual "Ctrl+Alt+Backspace" keystroke
|
{giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltBackspace, 0, nil}}, // actual "Ctrl+Alt+Backspace" keystroke
|
||||||
{giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlBackspace, 0, nil}}, // actual "Ctrl+Shift+Backspace" keystroke
|
{giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlBackspace, 0, nil}}, // actual "Ctrl+Shift+Backspace" keystroke
|
||||||
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModShift | tcell.ModAlt}, wantKey{AltBackspace, 0, nil}}, // actual "Shift+Alt+Backspace" keystroke
|
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModShift | tcell.ModAlt}, wantKey{AltBackspace, 0, nil}}, // actual "Shift+Alt+Backspace" keystroke
|
||||||
{giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModAlt | tcell.ModShift}, wantKey{CtrlAltBackspace, 0, nil}}, // actual "Ctrl+Shift+Alt+Backspace" keystroke
|
{giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModAlt | tcell.ModShift}, wantKey{CtrlAltBackspace, 0, nil}}, // actual "Ctrl+Shift+Alt+Backspace" keystroke
|
||||||
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModCtrl}, wantKey{CtrlH, 0, nil}}, // actual "Ctrl+H" keystroke
|
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModCtrl}, wantKey{CtrlBackspace, 0, nil}}, // actual "Ctrl+H" keystroke
|
||||||
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAlt, 'h', nil}}, // fabricated "Ctrl+Alt+H" keystroke
|
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModCtrl | tcell.ModAlt}, wantKey{AltBackspace, 0, nil}}, // fabricated "Ctrl+Alt+H" keystroke
|
||||||
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlH, 0, nil}}, // actual "Ctrl+Shift+H" keystroke
|
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlBackspace, 0, nil}}, // actual "Ctrl+Shift+H" keystroke
|
||||||
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModCtrl | tcell.ModAlt | tcell.ModShift}, wantKey{CtrlAlt, 'h', nil}}, // fabricated "Ctrl+Shift+Alt+H" keystroke
|
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModCtrl | tcell.ModAlt | tcell.ModShift}, wantKey{AltBackspace, 0, nil}}, // fabricated "Ctrl+Shift+Alt+H" keystroke
|
||||||
|
|
||||||
// section 4: (Alt+Shift)+Key(Up|Down|Left|Right)
|
// section 4: (Alt+Shift)+Key(Up|Down|Left|Right)
|
||||||
{giveKey{tcell.KeyUp, 0, tcell.ModNone}, wantKey{Up, 0, nil}},
|
{giveKey{tcell.KeyUp, 0, tcell.ModNone}, wantKey{Up, 0, nil}},
|
||||||
|
|||||||
530
src/tui/tui.go
530
src/tui/tui.go
@@ -8,6 +8,26 @@ import (
|
|||||||
"github.com/rivo/uniseg"
|
"github.com/rivo/uniseg"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Attr int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
AttrUndefined = Attr(0)
|
||||||
|
AttrRegular = Attr(1 << 8)
|
||||||
|
AttrClear = Attr(1 << 9)
|
||||||
|
BoldForce = Attr(1 << 10)
|
||||||
|
FullBg = Attr(1 << 11)
|
||||||
|
Strip = Attr(1 << 12)
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a Attr) Merge(b Attr) Attr {
|
||||||
|
if b&AttrRegular > 0 {
|
||||||
|
// Only keep bold attribute set by the system
|
||||||
|
return (b &^ AttrRegular) | (a & BoldForce)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (a &^ AttrRegular) | b
|
||||||
|
}
|
||||||
|
|
||||||
// Types of user action
|
// Types of user action
|
||||||
//
|
//
|
||||||
//go:generate stringer -type=EventType
|
//go:generate stringer -type=EventType
|
||||||
@@ -23,7 +43,7 @@ const (
|
|||||||
CtrlE
|
CtrlE
|
||||||
CtrlF
|
CtrlF
|
||||||
CtrlG
|
CtrlG
|
||||||
CtrlH
|
CtrlBackspace
|
||||||
Tab
|
Tab
|
||||||
CtrlJ
|
CtrlJ
|
||||||
CtrlK
|
CtrlK
|
||||||
@@ -117,7 +137,6 @@ const (
|
|||||||
CtrlRight
|
CtrlRight
|
||||||
CtrlHome
|
CtrlHome
|
||||||
CtrlEnd
|
CtrlEnd
|
||||||
CtrlBackspace
|
|
||||||
CtrlDelete
|
CtrlDelete
|
||||||
CtrlPageUp
|
CtrlPageUp
|
||||||
CtrlPageDown
|
CtrlPageDown
|
||||||
@@ -275,6 +294,14 @@ func (a ColorAttr) IsColorDefined() bool {
|
|||||||
return a.Color != colUndefined
|
return a.Color != colUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a ColorAttr) IsAttrDefined() bool {
|
||||||
|
return a.Attr&^BoldForce != AttrUndefined
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a ColorAttr) IsUndefined() bool {
|
||||||
|
return !a.IsColorDefined() && !a.IsAttrDefined()
|
||||||
|
}
|
||||||
|
|
||||||
func NewColorAttr() ColorAttr {
|
func NewColorAttr() ColorAttr {
|
||||||
return ColorAttr{Color: colUndefined, Attr: AttrUndefined}
|
return ColorAttr{Color: colUndefined, Attr: AttrUndefined}
|
||||||
}
|
}
|
||||||
@@ -303,6 +330,14 @@ const (
|
|||||||
colMagenta
|
colMagenta
|
||||||
colCyan
|
colCyan
|
||||||
colWhite
|
colWhite
|
||||||
|
colGrey
|
||||||
|
colBrightRed
|
||||||
|
colBrightGreen
|
||||||
|
colBrightYellow
|
||||||
|
colBrightBlue
|
||||||
|
colBrightMagenta
|
||||||
|
colBrightCyan
|
||||||
|
colBrightWhite
|
||||||
)
|
)
|
||||||
|
|
||||||
type FillReturn int
|
type FillReturn int
|
||||||
@@ -350,6 +385,10 @@ func (p ColorPair) IsFullBgMarker() bool {
|
|||||||
return p.attr&FullBg > 0
|
return p.attr&FullBg > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p ColorPair) ShouldStripColors() bool {
|
||||||
|
return p.attr&Strip > 0
|
||||||
|
}
|
||||||
|
|
||||||
func (p ColorPair) HasBg() bool {
|
func (p ColorPair) HasBg() bool {
|
||||||
return p.attr&Reverse == 0 && p.bg != colDefault ||
|
return p.attr&Reverse == 0 && p.bg != colDefault ||
|
||||||
p.attr&Reverse > 0 && p.fg != colDefault
|
p.attr&Reverse > 0 && p.fg != colDefault
|
||||||
@@ -373,6 +412,12 @@ func (p ColorPair) WithAttr(attr Attr) ColorPair {
|
|||||||
return dup
|
return dup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p ColorPair) WithFg(fg ColorAttr) ColorPair {
|
||||||
|
dup := p
|
||||||
|
fgPair := ColorPair{fg.Color, colUndefined, fg.Attr}
|
||||||
|
return dup.Merge(fgPair)
|
||||||
|
}
|
||||||
|
|
||||||
func (p ColorPair) WithBg(bg ColorAttr) ColorPair {
|
func (p ColorPair) WithBg(bg ColorAttr) ColorPair {
|
||||||
dup := p
|
dup := p
|
||||||
bgPair := ColorPair{colUndefined, bg.Color, bg.Attr}
|
bgPair := ColorPair{colUndefined, bg.Color, bg.Attr}
|
||||||
@@ -402,6 +447,7 @@ type ColorTheme struct {
|
|||||||
ListBg ColorAttr
|
ListBg ColorAttr
|
||||||
AltBg ColorAttr
|
AltBg ColorAttr
|
||||||
Nth ColorAttr
|
Nth ColorAttr
|
||||||
|
Nomatch ColorAttr
|
||||||
SelectedFg ColorAttr
|
SelectedFg ColorAttr
|
||||||
SelectedBg ColorAttr
|
SelectedBg ColorAttr
|
||||||
SelectedMatch ColorAttr
|
SelectedMatch ColorAttr
|
||||||
@@ -764,6 +810,8 @@ func NewFullscreenRenderer(theme *ColorTheme, forceBlack bool, mouse bool) Rende
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
NoColorTheme *ColorTheme
|
||||||
|
EmptyTheme *ColorTheme
|
||||||
Default16 *ColorTheme
|
Default16 *ColorTheme
|
||||||
Dark256 *ColorTheme
|
Dark256 *ColorTheme
|
||||||
Light256 *ColorTheme
|
Light256 *ColorTheme
|
||||||
@@ -810,167 +858,170 @@ var (
|
|||||||
ColInputLabel ColorPair
|
ColInputLabel ColorPair
|
||||||
)
|
)
|
||||||
|
|
||||||
func EmptyTheme() *ColorTheme {
|
|
||||||
return &ColorTheme{
|
|
||||||
Colored: true,
|
|
||||||
Input: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
Fg: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
Bg: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
ListFg: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
ListBg: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
AltBg: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
SelectedFg: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
SelectedBg: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
SelectedMatch: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
DarkBg: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
Prompt: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
Match: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
Current: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
CurrentMatch: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
Spinner: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
Info: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
Cursor: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
Marker: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
Header: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
Footer: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
Border: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
BorderLabel: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
ListLabel: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
ListBorder: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
Ghost: ColorAttr{colUndefined, Dim},
|
|
||||||
Disabled: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
PreviewFg: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
PreviewBg: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
Gutter: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
PreviewBorder: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
PreviewScrollbar: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
PreviewLabel: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
Separator: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
Scrollbar: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
InputBg: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
InputBorder: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
InputLabel: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
HeaderBg: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
HeaderBorder: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
HeaderLabel: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
FooterBg: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
FooterBorder: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
FooterLabel: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
GapLine: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
Nth: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NoColorTheme() *ColorTheme {
|
|
||||||
return &ColorTheme{
|
|
||||||
Colored: false,
|
|
||||||
Input: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
Fg: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
Bg: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
ListFg: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
ListBg: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
AltBg: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
SelectedFg: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
SelectedBg: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
SelectedMatch: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
DarkBg: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
Prompt: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
Match: ColorAttr{colDefault, Underline},
|
|
||||||
Current: ColorAttr{colDefault, Reverse},
|
|
||||||
CurrentMatch: ColorAttr{colDefault, Reverse | Underline},
|
|
||||||
Spinner: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
Info: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
Cursor: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
Marker: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
Header: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
Border: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
BorderLabel: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
Ghost: ColorAttr{colDefault, Dim},
|
|
||||||
Disabled: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
PreviewFg: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
PreviewBg: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
Gutter: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
PreviewBorder: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
PreviewScrollbar: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
PreviewLabel: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
ListLabel: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
ListBorder: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
Separator: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
Scrollbar: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
InputBg: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
InputBorder: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
InputLabel: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
HeaderBg: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
HeaderBorder: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
HeaderLabel: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
FooterBg: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
FooterBorder: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
FooterLabel: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
GapLine: ColorAttr{colDefault, AttrUndefined},
|
|
||||||
Nth: ColorAttr{colUndefined, AttrUndefined},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
defaultColor := ColorAttr{colDefault, AttrUndefined}
|
||||||
|
undefined := ColorAttr{colUndefined, AttrUndefined}
|
||||||
|
|
||||||
|
NoColorTheme = &ColorTheme{
|
||||||
|
Colored: false,
|
||||||
|
Input: defaultColor,
|
||||||
|
Fg: defaultColor,
|
||||||
|
Bg: defaultColor,
|
||||||
|
ListFg: defaultColor,
|
||||||
|
ListBg: defaultColor,
|
||||||
|
AltBg: undefined,
|
||||||
|
SelectedFg: defaultColor,
|
||||||
|
SelectedBg: defaultColor,
|
||||||
|
SelectedMatch: defaultColor,
|
||||||
|
DarkBg: defaultColor,
|
||||||
|
Prompt: defaultColor,
|
||||||
|
Match: defaultColor,
|
||||||
|
Current: undefined,
|
||||||
|
CurrentMatch: undefined,
|
||||||
|
Spinner: defaultColor,
|
||||||
|
Info: defaultColor,
|
||||||
|
Cursor: defaultColor,
|
||||||
|
Marker: defaultColor,
|
||||||
|
Header: defaultColor,
|
||||||
|
Border: undefined,
|
||||||
|
BorderLabel: defaultColor,
|
||||||
|
Ghost: undefined,
|
||||||
|
Disabled: defaultColor,
|
||||||
|
PreviewFg: defaultColor,
|
||||||
|
PreviewBg: defaultColor,
|
||||||
|
Gutter: undefined,
|
||||||
|
PreviewBorder: defaultColor,
|
||||||
|
PreviewScrollbar: defaultColor,
|
||||||
|
PreviewLabel: defaultColor,
|
||||||
|
ListLabel: defaultColor,
|
||||||
|
ListBorder: defaultColor,
|
||||||
|
Separator: defaultColor,
|
||||||
|
Scrollbar: defaultColor,
|
||||||
|
InputBg: defaultColor,
|
||||||
|
InputBorder: defaultColor,
|
||||||
|
InputLabel: defaultColor,
|
||||||
|
HeaderBg: defaultColor,
|
||||||
|
HeaderBorder: defaultColor,
|
||||||
|
HeaderLabel: defaultColor,
|
||||||
|
FooterBg: defaultColor,
|
||||||
|
FooterBorder: defaultColor,
|
||||||
|
FooterLabel: defaultColor,
|
||||||
|
GapLine: defaultColor,
|
||||||
|
Nth: undefined,
|
||||||
|
Nomatch: undefined,
|
||||||
|
}
|
||||||
|
|
||||||
|
EmptyTheme = &ColorTheme{
|
||||||
|
Colored: true,
|
||||||
|
Input: undefined,
|
||||||
|
Fg: undefined,
|
||||||
|
Bg: undefined,
|
||||||
|
ListFg: undefined,
|
||||||
|
ListBg: undefined,
|
||||||
|
AltBg: undefined,
|
||||||
|
SelectedFg: undefined,
|
||||||
|
SelectedBg: undefined,
|
||||||
|
SelectedMatch: undefined,
|
||||||
|
DarkBg: undefined,
|
||||||
|
Prompt: undefined,
|
||||||
|
Match: undefined,
|
||||||
|
Current: undefined,
|
||||||
|
CurrentMatch: undefined,
|
||||||
|
Spinner: undefined,
|
||||||
|
Info: undefined,
|
||||||
|
Cursor: undefined,
|
||||||
|
Marker: undefined,
|
||||||
|
Header: undefined,
|
||||||
|
Footer: undefined,
|
||||||
|
Border: undefined,
|
||||||
|
BorderLabel: undefined,
|
||||||
|
ListLabel: undefined,
|
||||||
|
ListBorder: undefined,
|
||||||
|
Ghost: undefined,
|
||||||
|
Disabled: undefined,
|
||||||
|
PreviewFg: undefined,
|
||||||
|
PreviewBg: undefined,
|
||||||
|
Gutter: undefined,
|
||||||
|
PreviewBorder: undefined,
|
||||||
|
PreviewScrollbar: undefined,
|
||||||
|
PreviewLabel: undefined,
|
||||||
|
Separator: undefined,
|
||||||
|
Scrollbar: undefined,
|
||||||
|
InputBg: undefined,
|
||||||
|
InputBorder: undefined,
|
||||||
|
InputLabel: undefined,
|
||||||
|
HeaderBg: undefined,
|
||||||
|
HeaderBorder: undefined,
|
||||||
|
HeaderLabel: undefined,
|
||||||
|
FooterBg: undefined,
|
||||||
|
FooterBorder: undefined,
|
||||||
|
FooterLabel: undefined,
|
||||||
|
GapLine: undefined,
|
||||||
|
Nth: undefined,
|
||||||
|
Nomatch: undefined,
|
||||||
|
}
|
||||||
|
|
||||||
Default16 = &ColorTheme{
|
Default16 = &ColorTheme{
|
||||||
Colored: true,
|
Colored: true,
|
||||||
Input: ColorAttr{colDefault, AttrUndefined},
|
Input: defaultColor,
|
||||||
Fg: ColorAttr{colDefault, AttrUndefined},
|
Fg: defaultColor,
|
||||||
Bg: ColorAttr{colDefault, AttrUndefined},
|
Bg: defaultColor,
|
||||||
ListFg: ColorAttr{colUndefined, AttrUndefined},
|
ListFg: undefined,
|
||||||
ListBg: ColorAttr{colUndefined, AttrUndefined},
|
ListBg: undefined,
|
||||||
AltBg: ColorAttr{colUndefined, AttrUndefined},
|
AltBg: undefined,
|
||||||
SelectedFg: ColorAttr{colUndefined, AttrUndefined},
|
SelectedFg: undefined,
|
||||||
SelectedBg: ColorAttr{colUndefined, AttrUndefined},
|
SelectedBg: undefined,
|
||||||
SelectedMatch: ColorAttr{colUndefined, AttrUndefined},
|
SelectedMatch: undefined,
|
||||||
DarkBg: ColorAttr{colBlack, AttrUndefined},
|
DarkBg: ColorAttr{colGrey, AttrUndefined},
|
||||||
Prompt: ColorAttr{colBlue, AttrUndefined},
|
Prompt: ColorAttr{colBlue, AttrUndefined},
|
||||||
Match: ColorAttr{colGreen, AttrUndefined},
|
Match: ColorAttr{colGreen, AttrUndefined},
|
||||||
Current: ColorAttr{colYellow, AttrUndefined},
|
Current: ColorAttr{colBrightWhite, AttrUndefined},
|
||||||
CurrentMatch: ColorAttr{colGreen, AttrUndefined},
|
CurrentMatch: ColorAttr{colBrightGreen, AttrUndefined},
|
||||||
Spinner: ColorAttr{colGreen, AttrUndefined},
|
Spinner: ColorAttr{colGreen, AttrUndefined},
|
||||||
Info: ColorAttr{colWhite, AttrUndefined},
|
Info: ColorAttr{colYellow, AttrUndefined},
|
||||||
Cursor: ColorAttr{colRed, AttrUndefined},
|
Cursor: ColorAttr{colRed, AttrUndefined},
|
||||||
Marker: ColorAttr{colMagenta, AttrUndefined},
|
Marker: ColorAttr{colMagenta, AttrUndefined},
|
||||||
Header: ColorAttr{colCyan, AttrUndefined},
|
Header: ColorAttr{colCyan, AttrUndefined},
|
||||||
Footer: ColorAttr{colCyan, AttrUndefined},
|
Footer: ColorAttr{colCyan, AttrUndefined},
|
||||||
Border: ColorAttr{colBlack, AttrUndefined},
|
Border: undefined,
|
||||||
BorderLabel: ColorAttr{colWhite, AttrUndefined},
|
BorderLabel: defaultColor,
|
||||||
Ghost: ColorAttr{colUndefined, Dim},
|
Ghost: undefined,
|
||||||
Disabled: ColorAttr{colUndefined, AttrUndefined},
|
Disabled: undefined,
|
||||||
PreviewFg: ColorAttr{colUndefined, AttrUndefined},
|
PreviewFg: undefined,
|
||||||
PreviewBg: ColorAttr{colUndefined, AttrUndefined},
|
PreviewBg: undefined,
|
||||||
Gutter: ColorAttr{colUndefined, AttrUndefined},
|
Gutter: undefined,
|
||||||
PreviewBorder: ColorAttr{colUndefined, AttrUndefined},
|
PreviewBorder: undefined,
|
||||||
PreviewScrollbar: ColorAttr{colUndefined, AttrUndefined},
|
PreviewScrollbar: undefined,
|
||||||
PreviewLabel: ColorAttr{colUndefined, AttrUndefined},
|
PreviewLabel: undefined,
|
||||||
ListLabel: ColorAttr{colUndefined, AttrUndefined},
|
ListLabel: undefined,
|
||||||
ListBorder: ColorAttr{colUndefined, AttrUndefined},
|
ListBorder: undefined,
|
||||||
Separator: ColorAttr{colUndefined, AttrUndefined},
|
Separator: undefined,
|
||||||
Scrollbar: ColorAttr{colUndefined, AttrUndefined},
|
Scrollbar: undefined,
|
||||||
InputBg: ColorAttr{colUndefined, AttrUndefined},
|
InputBg: undefined,
|
||||||
InputBorder: ColorAttr{colUndefined, AttrUndefined},
|
InputBorder: undefined,
|
||||||
InputLabel: ColorAttr{colUndefined, AttrUndefined},
|
InputLabel: undefined,
|
||||||
HeaderBg: ColorAttr{colUndefined, AttrUndefined},
|
HeaderBg: undefined,
|
||||||
HeaderBorder: ColorAttr{colUndefined, AttrUndefined},
|
HeaderBorder: undefined,
|
||||||
HeaderLabel: ColorAttr{colUndefined, AttrUndefined},
|
HeaderLabel: undefined,
|
||||||
FooterBg: ColorAttr{colUndefined, AttrUndefined},
|
FooterBg: undefined,
|
||||||
FooterBorder: ColorAttr{colUndefined, AttrUndefined},
|
FooterBorder: undefined,
|
||||||
FooterLabel: ColorAttr{colUndefined, AttrUndefined},
|
FooterLabel: undefined,
|
||||||
GapLine: ColorAttr{colUndefined, AttrUndefined},
|
GapLine: undefined,
|
||||||
Nth: ColorAttr{colUndefined, AttrUndefined},
|
Nth: undefined,
|
||||||
|
Nomatch: undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
Dark256 = &ColorTheme{
|
Dark256 = &ColorTheme{
|
||||||
Colored: true,
|
Colored: true,
|
||||||
Input: ColorAttr{colDefault, AttrUndefined},
|
Input: defaultColor,
|
||||||
Fg: ColorAttr{colDefault, AttrUndefined},
|
Fg: defaultColor,
|
||||||
Bg: ColorAttr{colDefault, AttrUndefined},
|
Bg: defaultColor,
|
||||||
ListFg: ColorAttr{colUndefined, AttrUndefined},
|
ListFg: undefined,
|
||||||
ListBg: ColorAttr{colUndefined, AttrUndefined},
|
ListBg: undefined,
|
||||||
AltBg: ColorAttr{colUndefined, AttrUndefined},
|
AltBg: undefined,
|
||||||
SelectedFg: ColorAttr{colUndefined, AttrUndefined},
|
SelectedFg: undefined,
|
||||||
SelectedBg: ColorAttr{colUndefined, AttrUndefined},
|
SelectedBg: undefined,
|
||||||
SelectedMatch: ColorAttr{colUndefined, AttrUndefined},
|
SelectedMatch: undefined,
|
||||||
DarkBg: ColorAttr{236, AttrUndefined},
|
DarkBg: ColorAttr{236, AttrUndefined},
|
||||||
Prompt: ColorAttr{110, AttrUndefined},
|
Prompt: ColorAttr{110, AttrUndefined},
|
||||||
Match: ColorAttr{108, AttrUndefined},
|
Match: ColorAttr{108, AttrUndefined},
|
||||||
@@ -984,41 +1035,43 @@ func init() {
|
|||||||
Footer: ColorAttr{109, AttrUndefined},
|
Footer: ColorAttr{109, AttrUndefined},
|
||||||
Border: ColorAttr{59, AttrUndefined},
|
Border: ColorAttr{59, AttrUndefined},
|
||||||
BorderLabel: ColorAttr{145, AttrUndefined},
|
BorderLabel: ColorAttr{145, AttrUndefined},
|
||||||
Ghost: ColorAttr{colUndefined, Dim},
|
Ghost: undefined,
|
||||||
Disabled: ColorAttr{colUndefined, AttrUndefined},
|
Disabled: undefined,
|
||||||
PreviewFg: ColorAttr{colUndefined, AttrUndefined},
|
PreviewFg: undefined,
|
||||||
PreviewBg: ColorAttr{colUndefined, AttrUndefined},
|
PreviewBg: undefined,
|
||||||
Gutter: ColorAttr{colUndefined, AttrUndefined},
|
Gutter: undefined,
|
||||||
PreviewBorder: ColorAttr{colUndefined, AttrUndefined},
|
PreviewBorder: undefined,
|
||||||
PreviewScrollbar: ColorAttr{colUndefined, AttrUndefined},
|
PreviewScrollbar: undefined,
|
||||||
PreviewLabel: ColorAttr{colUndefined, AttrUndefined},
|
PreviewLabel: undefined,
|
||||||
ListLabel: ColorAttr{colUndefined, AttrUndefined},
|
ListLabel: undefined,
|
||||||
ListBorder: ColorAttr{colUndefined, AttrUndefined},
|
ListBorder: undefined,
|
||||||
Separator: ColorAttr{colUndefined, AttrUndefined},
|
Separator: undefined,
|
||||||
Scrollbar: ColorAttr{colUndefined, AttrUndefined},
|
Scrollbar: undefined,
|
||||||
InputBg: ColorAttr{colUndefined, AttrUndefined},
|
InputBg: undefined,
|
||||||
InputBorder: ColorAttr{colUndefined, AttrUndefined},
|
InputBorder: undefined,
|
||||||
InputLabel: ColorAttr{colUndefined, AttrUndefined},
|
InputLabel: undefined,
|
||||||
HeaderBg: ColorAttr{colUndefined, AttrUndefined},
|
HeaderBg: undefined,
|
||||||
HeaderBorder: ColorAttr{colUndefined, AttrUndefined},
|
HeaderBorder: undefined,
|
||||||
HeaderLabel: ColorAttr{colUndefined, AttrUndefined},
|
HeaderLabel: undefined,
|
||||||
FooterBg: ColorAttr{colUndefined, AttrUndefined},
|
FooterBg: undefined,
|
||||||
FooterBorder: ColorAttr{colUndefined, AttrUndefined},
|
FooterBorder: undefined,
|
||||||
FooterLabel: ColorAttr{colUndefined, AttrUndefined},
|
FooterLabel: undefined,
|
||||||
GapLine: ColorAttr{colUndefined, AttrUndefined},
|
GapLine: undefined,
|
||||||
Nth: ColorAttr{colUndefined, AttrUndefined},
|
Nth: undefined,
|
||||||
|
Nomatch: undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
Light256 = &ColorTheme{
|
Light256 = &ColorTheme{
|
||||||
Colored: true,
|
Colored: true,
|
||||||
Input: ColorAttr{colDefault, AttrUndefined},
|
Input: defaultColor,
|
||||||
Fg: ColorAttr{colDefault, AttrUndefined},
|
Fg: defaultColor,
|
||||||
Bg: ColorAttr{colDefault, AttrUndefined},
|
Bg: defaultColor,
|
||||||
ListFg: ColorAttr{colUndefined, AttrUndefined},
|
ListFg: undefined,
|
||||||
ListBg: ColorAttr{colUndefined, AttrUndefined},
|
ListBg: undefined,
|
||||||
AltBg: ColorAttr{colUndefined, AttrUndefined},
|
AltBg: undefined,
|
||||||
SelectedFg: ColorAttr{colUndefined, AttrUndefined},
|
SelectedFg: undefined,
|
||||||
SelectedBg: ColorAttr{colUndefined, AttrUndefined},
|
SelectedBg: undefined,
|
||||||
SelectedMatch: ColorAttr{colUndefined, AttrUndefined},
|
SelectedMatch: undefined,
|
||||||
DarkBg: ColorAttr{251, AttrUndefined},
|
DarkBg: ColorAttr{251, AttrUndefined},
|
||||||
Prompt: ColorAttr{25, AttrUndefined},
|
Prompt: ColorAttr{25, AttrUndefined},
|
||||||
Match: ColorAttr{66, AttrUndefined},
|
Match: ColorAttr{66, AttrUndefined},
|
||||||
@@ -1032,37 +1085,54 @@ func init() {
|
|||||||
Footer: ColorAttr{31, AttrUndefined},
|
Footer: ColorAttr{31, AttrUndefined},
|
||||||
Border: ColorAttr{145, AttrUndefined},
|
Border: ColorAttr{145, AttrUndefined},
|
||||||
BorderLabel: ColorAttr{59, AttrUndefined},
|
BorderLabel: ColorAttr{59, AttrUndefined},
|
||||||
Ghost: ColorAttr{colUndefined, Dim},
|
Ghost: undefined,
|
||||||
Disabled: ColorAttr{colUndefined, AttrUndefined},
|
Disabled: undefined,
|
||||||
PreviewFg: ColorAttr{colUndefined, AttrUndefined},
|
PreviewFg: undefined,
|
||||||
PreviewBg: ColorAttr{colUndefined, AttrUndefined},
|
PreviewBg: undefined,
|
||||||
Gutter: ColorAttr{colUndefined, AttrUndefined},
|
Gutter: undefined,
|
||||||
PreviewBorder: ColorAttr{colUndefined, AttrUndefined},
|
PreviewBorder: undefined,
|
||||||
PreviewScrollbar: ColorAttr{colUndefined, AttrUndefined},
|
PreviewScrollbar: undefined,
|
||||||
PreviewLabel: ColorAttr{colUndefined, AttrUndefined},
|
PreviewLabel: undefined,
|
||||||
ListLabel: ColorAttr{colUndefined, AttrUndefined},
|
ListLabel: undefined,
|
||||||
ListBorder: ColorAttr{colUndefined, AttrUndefined},
|
ListBorder: undefined,
|
||||||
Separator: ColorAttr{colUndefined, AttrUndefined},
|
Separator: undefined,
|
||||||
Scrollbar: ColorAttr{colUndefined, AttrUndefined},
|
Scrollbar: undefined,
|
||||||
InputBg: ColorAttr{colUndefined, AttrUndefined},
|
InputBg: undefined,
|
||||||
InputBorder: ColorAttr{colUndefined, AttrUndefined},
|
InputBorder: undefined,
|
||||||
InputLabel: ColorAttr{colUndefined, AttrUndefined},
|
InputLabel: undefined,
|
||||||
HeaderBg: ColorAttr{colUndefined, AttrUndefined},
|
HeaderBg: undefined,
|
||||||
HeaderBorder: ColorAttr{colUndefined, AttrUndefined},
|
HeaderBorder: undefined,
|
||||||
HeaderLabel: ColorAttr{colUndefined, AttrUndefined},
|
HeaderLabel: undefined,
|
||||||
FooterBg: ColorAttr{colUndefined, AttrUndefined},
|
FooterBg: undefined,
|
||||||
FooterBorder: ColorAttr{colUndefined, AttrUndefined},
|
FooterBorder: undefined,
|
||||||
FooterLabel: ColorAttr{colUndefined, AttrUndefined},
|
FooterLabel: undefined,
|
||||||
GapLine: ColorAttr{colUndefined, AttrUndefined},
|
GapLine: undefined,
|
||||||
Nth: ColorAttr{colUndefined, AttrUndefined},
|
Nth: undefined,
|
||||||
|
Nomatch: undefined,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool, hasInputWindow bool, hasHeaderWindow bool) {
|
func InitTheme(theme *ColorTheme, baseTheme *ColorTheme, boldify bool, forceBlack bool, hasInputWindow bool, hasHeaderWindow bool) {
|
||||||
if forceBlack {
|
if forceBlack {
|
||||||
theme.Bg = ColorAttr{colBlack, AttrUndefined}
|
theme.Bg = ColorAttr{colBlack, AttrUndefined}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if boldify {
|
||||||
|
boldify := func(c ColorAttr) ColorAttr {
|
||||||
|
dup := c
|
||||||
|
if (c.Attr & AttrRegular) == 0 {
|
||||||
|
dup.Attr |= BoldForce
|
||||||
|
}
|
||||||
|
return dup
|
||||||
|
}
|
||||||
|
theme.Current = boldify(theme.Current)
|
||||||
|
theme.CurrentMatch = boldify(theme.CurrentMatch)
|
||||||
|
theme.Prompt = boldify(theme.Prompt)
|
||||||
|
theme.Input = boldify(theme.Input)
|
||||||
|
theme.Cursor = boldify(theme.Cursor)
|
||||||
|
theme.Spinner = boldify(theme.Spinner)
|
||||||
|
}
|
||||||
|
|
||||||
o := func(a ColorAttr, b ColorAttr) ColorAttr {
|
o := func(a ColorAttr, b ColorAttr) ColorAttr {
|
||||||
c := a
|
c := a
|
||||||
if b.Color != colUndefined {
|
if b.Color != colUndefined {
|
||||||
@@ -1078,18 +1148,36 @@ func InitTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool, hasInp
|
|||||||
theme.Bg = o(baseTheme.Bg, theme.Bg)
|
theme.Bg = o(baseTheme.Bg, theme.Bg)
|
||||||
theme.DarkBg = o(baseTheme.DarkBg, theme.DarkBg)
|
theme.DarkBg = o(baseTheme.DarkBg, theme.DarkBg)
|
||||||
theme.Prompt = o(baseTheme.Prompt, theme.Prompt)
|
theme.Prompt = o(baseTheme.Prompt, theme.Prompt)
|
||||||
theme.Match = o(baseTheme.Match, theme.Match)
|
match := theme.Match
|
||||||
|
if !baseTheme.Colored && match.IsUndefined() {
|
||||||
|
match.Attr = Underline
|
||||||
|
}
|
||||||
|
theme.Match = o(baseTheme.Match, match)
|
||||||
// Inherit from 'fg', so that we don't have to write 'current-fg:dim'
|
// Inherit from 'fg', so that we don't have to write 'current-fg:dim'
|
||||||
// e.g. fzf --delimiter / --nth -1 --color fg:dim,nth:regular
|
// e.g. fzf --delimiter / --nth -1 --color fg:dim,nth:regular
|
||||||
theme.Current = theme.Fg.Merge(o(baseTheme.Current, theme.Current))
|
current := theme.Current
|
||||||
theme.CurrentMatch = o(baseTheme.CurrentMatch, theme.CurrentMatch)
|
if !baseTheme.Colored && current.IsUndefined() {
|
||||||
|
current.Attr |= Reverse
|
||||||
|
}
|
||||||
|
theme.Current = theme.Fg.Merge(o(baseTheme.Current, current))
|
||||||
|
currentMatch := theme.CurrentMatch
|
||||||
|
if !baseTheme.Colored && currentMatch.IsUndefined() {
|
||||||
|
currentMatch.Attr |= Reverse | Underline
|
||||||
|
}
|
||||||
|
theme.CurrentMatch = o(baseTheme.CurrentMatch, currentMatch)
|
||||||
theme.Spinner = o(baseTheme.Spinner, theme.Spinner)
|
theme.Spinner = o(baseTheme.Spinner, theme.Spinner)
|
||||||
theme.Info = o(baseTheme.Info, theme.Info)
|
theme.Info = o(baseTheme.Info, theme.Info)
|
||||||
theme.Cursor = o(baseTheme.Cursor, theme.Cursor)
|
theme.Cursor = o(baseTheme.Cursor, theme.Cursor)
|
||||||
theme.Marker = o(baseTheme.Marker, theme.Marker)
|
theme.Marker = o(baseTheme.Marker, theme.Marker)
|
||||||
theme.Header = o(baseTheme.Header, theme.Header)
|
theme.Header = o(baseTheme.Header, theme.Header)
|
||||||
theme.Footer = o(baseTheme.Footer, theme.Footer)
|
theme.Footer = o(baseTheme.Footer, theme.Footer)
|
||||||
theme.Border = o(baseTheme.Border, theme.Border)
|
|
||||||
|
// If border color is undefined, set it to default color with dim attribute.
|
||||||
|
border := theme.Border
|
||||||
|
if baseTheme.Border.IsUndefined() && border.IsUndefined() {
|
||||||
|
border.Attr = Dim
|
||||||
|
}
|
||||||
|
theme.Border = o(baseTheme.Border, border)
|
||||||
theme.BorderLabel = o(baseTheme.BorderLabel, theme.BorderLabel)
|
theme.BorderLabel = o(baseTheme.BorderLabel, theme.BorderLabel)
|
||||||
|
|
||||||
undefined := NewColorAttr()
|
undefined := NewColorAttr()
|
||||||
@@ -1102,9 +1190,23 @@ func InitTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool, hasInp
|
|||||||
theme.SelectedFg = o(theme.ListFg, theme.SelectedFg)
|
theme.SelectedFg = o(theme.ListFg, theme.SelectedFg)
|
||||||
theme.SelectedBg = o(theme.ListBg, theme.SelectedBg)
|
theme.SelectedBg = o(theme.ListBg, theme.SelectedBg)
|
||||||
theme.SelectedMatch = o(theme.Match, theme.SelectedMatch)
|
theme.SelectedMatch = o(theme.Match, theme.SelectedMatch)
|
||||||
theme.Ghost = o(theme.Input, theme.Ghost)
|
|
||||||
|
ghost := theme.Ghost
|
||||||
|
if ghost.IsUndefined() {
|
||||||
|
ghost.Attr = Dim
|
||||||
|
} else if ghost.IsColorDefined() && !ghost.IsAttrDefined() {
|
||||||
|
// Don't want to inherit 'bold' from 'input'
|
||||||
|
ghost.Attr = AttrRegular
|
||||||
|
}
|
||||||
|
theme.Ghost = o(theme.Input, ghost)
|
||||||
theme.Disabled = o(theme.Input, theme.Disabled)
|
theme.Disabled = o(theme.Input, theme.Disabled)
|
||||||
theme.Gutter = o(theme.DarkBg, theme.Gutter)
|
|
||||||
|
// Use dim gutter on non-colored themes if undefined
|
||||||
|
gutter := theme.Gutter
|
||||||
|
if !baseTheme.Colored && gutter.IsUndefined() {
|
||||||
|
gutter.Attr = Dim
|
||||||
|
}
|
||||||
|
theme.Gutter = o(theme.DarkBg, gutter)
|
||||||
theme.PreviewFg = o(theme.Fg, theme.PreviewFg)
|
theme.PreviewFg = o(theme.Fg, theme.PreviewFg)
|
||||||
theme.PreviewBg = o(theme.Bg, theme.PreviewBg)
|
theme.PreviewBg = o(theme.Bg, theme.PreviewBg)
|
||||||
theme.PreviewLabel = o(theme.BorderLabel, theme.PreviewLabel)
|
theme.PreviewLabel = o(theme.BorderLabel, theme.PreviewLabel)
|
||||||
@@ -1146,6 +1248,10 @@ func InitTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool, hasInp
|
|||||||
theme.FooterBorder = o(theme.Border, theme.FooterBorder)
|
theme.FooterBorder = o(theme.Border, theme.FooterBorder)
|
||||||
theme.FooterLabel = o(theme.BorderLabel, theme.FooterLabel)
|
theme.FooterLabel = o(theme.BorderLabel, theme.FooterLabel)
|
||||||
|
|
||||||
|
if theme.Nomatch.IsUndefined() {
|
||||||
|
theme.Nomatch.Attr = Dim
|
||||||
|
}
|
||||||
|
|
||||||
initPalette(theme)
|
initPalette(theme)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ DEFAULT_TIMEOUT = 10
|
|||||||
FILE = File.expand_path(__FILE__)
|
FILE = File.expand_path(__FILE__)
|
||||||
BASE = File.expand_path('../..', __dir__)
|
BASE = File.expand_path('../..', __dir__)
|
||||||
Dir.chdir(BASE)
|
Dir.chdir(BASE)
|
||||||
FZF = %[FZF_DEFAULT_OPTS="--no-scrollbar --gutter ' ' --pointer '>' --marker '>'" FZF_DEFAULT_COMMAND= #{BASE}/bin/fzf].freeze
|
FZF = %(FZF_DEFAULT_OPTS="--no-scrollbar --gutter ' ' --pointer '>' --marker '>'" FZF_DEFAULT_COMMAND= #{BASE}/bin/fzf).freeze
|
||||||
|
|
||||||
def wait(timeout = DEFAULT_TIMEOUT)
|
def wait(timeout = DEFAULT_TIMEOUT)
|
||||||
since = Time.now
|
since = Time.now
|
||||||
|
|||||||
@@ -1682,6 +1682,7 @@ class TestCore < TestInteractive
|
|||||||
|
|
||||||
tmux.send_keys %(seq 100 | #{FZF} --multi --reverse --preview-window 0 --preview 'env | grep ^FZF_ | sort > #{tempname}' --no-input --bind enter:show-input+refresh-preview,space:disable-search+refresh-preview), :Enter
|
tmux.send_keys %(seq 100 | #{FZF} --multi --reverse --preview-window 0 --preview 'env | grep ^FZF_ | sort > #{tempname}' --no-input --bind enter:show-input+refresh-preview,space:disable-search+refresh-preview), :Enter
|
||||||
expected = {
|
expected = {
|
||||||
|
FZF_DIRECTION: 'down',
|
||||||
FZF_TOTAL_COUNT: '100',
|
FZF_TOTAL_COUNT: '100',
|
||||||
FZF_MATCH_COUNT: '100',
|
FZF_MATCH_COUNT: '100',
|
||||||
FZF_SELECT_COUNT: '0',
|
FZF_SELECT_COUNT: '0',
|
||||||
@@ -2004,7 +2005,7 @@ class TestCore < TestInteractive
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
elapsed = Time.now - time
|
elapsed = Time.now - time
|
||||||
assert elapsed < 2
|
assert_operator elapsed, :<, 2
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_bg_cancel
|
def test_bg_cancel
|
||||||
@@ -2017,7 +2018,7 @@ class TestCore < TestInteractive
|
|||||||
tmux.until { assert_equal 2, it.match_count }
|
tmux.until { assert_equal 2, it.match_count }
|
||||||
tmux.send_keys :Space
|
tmux.send_keys :Space
|
||||||
tmux.until { |lines| assert lines.any_include?('[0]') }
|
tmux.until { |lines| assert lines.any_include?('[0]') }
|
||||||
sleep 2
|
sleep(2)
|
||||||
tmux.until do |lines|
|
tmux.until do |lines|
|
||||||
assert lines.any_include?('[0]')
|
assert lines.any_include?('[0]')
|
||||||
refute lines.any_include?('[1]')
|
refute lines.any_include?('[1]')
|
||||||
|
|||||||
@@ -1192,6 +1192,29 @@ class TestLayout < TestInteractive
|
|||||||
tmux.until { assert_block(block, it) }
|
tmux.until { assert_block(block, it) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# https://github.com/junegunn/fzf/issues/4537
|
||||||
|
def test_no_scrollbar_preview_toggle
|
||||||
|
x = 'x' * 300
|
||||||
|
y = 'y' * 300
|
||||||
|
tmux.send_keys %(yes #{x} | head -1000 | fzf --bind 'tab:toggle-preview' --border --no-scrollbar --preview 'echo #{y}' --preview-window 'border-left'), :Enter
|
||||||
|
|
||||||
|
# │ ▌ xxxxxxxx·· │ yyyyyyyy│
|
||||||
|
tmux.until do |lines|
|
||||||
|
lines.any? { it.match?(/x·· │ y+│$/) }
|
||||||
|
end
|
||||||
|
tmux.send_keys :Tab
|
||||||
|
|
||||||
|
# │ ▌ xxxxxxxx·· │
|
||||||
|
tmux.until do |lines|
|
||||||
|
lines.none? { it.match?(/x··y│$/) }
|
||||||
|
end
|
||||||
|
|
||||||
|
tmux.send_keys :Tab
|
||||||
|
tmux.until do |lines|
|
||||||
|
lines.any? { it.match?(/x·· │ y+│$/) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_combinations
|
def test_combinations
|
||||||
skip unless ENV['LONGTEST']
|
skip unless ENV['LONGTEST']
|
||||||
|
|
||||||
|
|||||||
113
test/test_raw.rb
Normal file
113
test/test_raw.rb
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative 'lib/common'
|
||||||
|
|
||||||
|
# Testing raw mode
|
||||||
|
class TestRaw < TestInteractive
|
||||||
|
def test_raw_mode
|
||||||
|
tmux.send_keys %(seq 1000 | #{FZF} --raw --bind ctrl-x:toggle-raw,a:enable-raw,b:disable-raw --gutter '▌' --multi --bind 'space:transform-prompt:echo "[[$FZF_RAW]] "'), :Enter
|
||||||
|
tmux.until { assert_equal 1000, it.match_count }
|
||||||
|
|
||||||
|
tmux.send_keys 1
|
||||||
|
tmux.until { assert_equal 272, it.match_count }
|
||||||
|
|
||||||
|
tmux.send_keys :Up
|
||||||
|
tmux.until { assert_includes it, '> 2' }
|
||||||
|
|
||||||
|
tmux.send_keys 'C-p'
|
||||||
|
tmux.until do
|
||||||
|
assert_includes it, '> 10'
|
||||||
|
assert_includes it, '▖ 9'
|
||||||
|
end
|
||||||
|
|
||||||
|
tmux.send_keys 'C-x'
|
||||||
|
tmux.until do
|
||||||
|
assert_includes it, '> 10'
|
||||||
|
assert_includes it, '▌ 1'
|
||||||
|
end
|
||||||
|
|
||||||
|
tmux.send_keys :Up, 'C-x'
|
||||||
|
tmux.until do
|
||||||
|
assert_includes it, '> 11'
|
||||||
|
assert_includes it, '▖ 10'
|
||||||
|
end
|
||||||
|
|
||||||
|
tmux.send_keys 1
|
||||||
|
tmux.until { assert_equal 28, it.match_count }
|
||||||
|
|
||||||
|
tmux.send_keys 'C-p'
|
||||||
|
tmux.until do
|
||||||
|
assert_includes it, '> 101'
|
||||||
|
assert_includes it, '▖ 100'
|
||||||
|
end
|
||||||
|
|
||||||
|
tmux.send_keys 'C-n'
|
||||||
|
tmux.until do
|
||||||
|
assert_includes it, '> 11'
|
||||||
|
assert_includes it, '▖ 10'
|
||||||
|
end
|
||||||
|
|
||||||
|
tmux.send_keys :Tab, :Tab, :Tab
|
||||||
|
tmux.until { assert_equal 3, it.select_count }
|
||||||
|
|
||||||
|
tmux.send_keys 'C-x'
|
||||||
|
tmux.until do
|
||||||
|
assert_equal 1, it.select_count
|
||||||
|
assert_includes it, '▌ 110'
|
||||||
|
assert_includes it, '>>11'
|
||||||
|
end
|
||||||
|
|
||||||
|
tmux.send_keys 'a'
|
||||||
|
tmux.until do
|
||||||
|
assert_equal 1, it.select_count
|
||||||
|
assert_includes it, '>>11'
|
||||||
|
assert_includes it, '▖ 10'
|
||||||
|
end
|
||||||
|
|
||||||
|
tmux.send_keys :Down, :Space
|
||||||
|
tmux.until { assert_includes it, '[[0]] 11' }
|
||||||
|
|
||||||
|
tmux.send_keys :Up, :Space
|
||||||
|
tmux.until { assert_includes it, '[[1]] 11' }
|
||||||
|
|
||||||
|
tmux.send_keys 'b'
|
||||||
|
tmux.until do
|
||||||
|
assert_equal 1, it.select_count
|
||||||
|
assert_includes it, '▌ 110'
|
||||||
|
assert_includes it, '>>11'
|
||||||
|
end
|
||||||
|
|
||||||
|
tmux.send_keys :Space
|
||||||
|
tmux.until { assert_includes it, '[[]] 11' }
|
||||||
|
|
||||||
|
tmux.send_keys 'C-u', '5'
|
||||||
|
tmux.until { assert_includes it, '> 5' }
|
||||||
|
|
||||||
|
tmux.send_keys 'C-x', 'C-p', 'C-p'
|
||||||
|
tmux.until do
|
||||||
|
assert_includes it, '> 25'
|
||||||
|
assert_includes it, '▖ 24'
|
||||||
|
end
|
||||||
|
|
||||||
|
tmux.send_keys 'C-x'
|
||||||
|
tmux.until do
|
||||||
|
assert_includes it, '> 25'
|
||||||
|
assert_includes it, '▌ 15'
|
||||||
|
end
|
||||||
|
|
||||||
|
# 35 is the closest match in raw mode
|
||||||
|
tmux.send_keys 'C-x', :Up, :Up, :Up, :Up, :Up, :Up, 'C-x'
|
||||||
|
tmux.until do
|
||||||
|
assert_includes it, '> 35'
|
||||||
|
assert_includes it, '▌ 25'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_raw_best
|
||||||
|
tmux.send_keys %(seq 1000 | #{FZF} --raw --bind space:best), :Enter
|
||||||
|
tmux.send_keys 999
|
||||||
|
tmux.until { assert_includes it, '> 1' }
|
||||||
|
tmux.send_keys :Space
|
||||||
|
tmux.until { assert_includes it, '> 999' }
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -109,6 +109,6 @@ if [ -d "${fish_dir}/functions" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
config_dir=$(dirname "$prefix_expand")
|
config_dir=$(dirname "$prefix_expand")
|
||||||
if [[ "$xdg" = 1 ]] && [[ "$config_dir" = */fzf ]] && [[ -d "$config_dir" ]]; then
|
if [[ $xdg == 1 ]] && [[ $config_dir == */fzf ]] && [[ -d $config_dir ]]; then
|
||||||
rmdir "$config_dir"
|
rmdir "$config_dir"
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user