mirror of
https://github.com/junegunn/fzf.git
synced 2025-08-01 12:42:01 -07:00
Compare commits
26 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
d01ae55109 | ||
|
8868d7d188 | ||
|
2eec9892be | ||
|
01ae621f11 | ||
|
f984aa0d2c | ||
|
0881a6bc17 | ||
|
2c6a73546d | ||
|
a29944660e | ||
|
f6ce624c6f | ||
|
c09ec8e4d1 | ||
|
31bbaad06e | ||
|
b9ca1fe830 | ||
|
e61585f2f3 | ||
|
0de1aacb0c | ||
|
168829b555 | ||
|
170fc517d0 | ||
|
0fbf1c7c71 | ||
|
694be39c71 | ||
|
dad26d81df | ||
|
bcaea097ea | ||
|
d56fe74e24 | ||
|
4603d540c3 | ||
|
f9d53303bb | ||
|
d04faa6505 | ||
|
07da058eae | ||
|
cefa6b9878 |
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
@@ -27,18 +27,18 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@61b9e3751b92087fd0b06925ba6dd6314e06f089
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@86f3159a697a097a813ad9bfa0002412d97690a4
|
uses: github/codeql-action/init@v2
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
|
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@86f3159a697a097a813ad9bfa0002412d97690a4
|
uses: github/codeql-action/autobuild@v2
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@86f3159a697a097a813ad9bfa0002412d97690a4
|
uses: github/codeql-action/analyze@v2
|
||||||
|
14
.github/workflows/depsreview.yaml
vendored
Normal file
14
.github/workflows/depsreview.yaml
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
name: 'Dependency Review'
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
dependency-review:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: 'Checkout Repository'
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: 'Dependency Review'
|
||||||
|
uses: actions/dependency-review-action@v2
|
6
.github/workflows/linux.yml
vendored
6
.github/workflows/linux.yml
vendored
@@ -15,17 +15,17 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@61b9e3751b92087fd0b06925ba6dd6314e06f089
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@268d8c0ca0432bb2cf416faae41297df9d262d7f # v2
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: 1.19
|
go-version: 1.19
|
||||||
|
|
||||||
- name: Setup Ruby
|
- name: Setup Ruby
|
||||||
uses: ruby/setup-ruby@3068fa83f9cbd7ae106cac45483635a2f3a195c9
|
uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
ruby-version: 3.0.0
|
ruby-version: 3.0.0
|
||||||
|
|
||||||
|
6
.github/workflows/macos.yml
vendored
6
.github/workflows/macos.yml
vendored
@@ -15,17 +15,17 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@61b9e3751b92087fd0b06925ba6dd6314e06f089
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@268d8c0ca0432bb2cf416faae41297df9d262d7f # v2
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: 1.18
|
go-version: 1.18
|
||||||
|
|
||||||
- name: Setup Ruby
|
- name: Setup Ruby
|
||||||
uses: ruby/setup-ruby@3068fa83f9cbd7ae106cac45483635a2f3a195c9
|
uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
ruby-version: 3.0.0
|
ruby-version: 3.0.0
|
||||||
|
|
||||||
|
@@ -72,6 +72,7 @@ builds:
|
|||||||
- amd64
|
- amd64
|
||||||
- arm
|
- arm
|
||||||
- arm64
|
- arm64
|
||||||
|
- loong64
|
||||||
goarm:
|
goarm:
|
||||||
- 5
|
- 5
|
||||||
- 6
|
- 6
|
||||||
@@ -99,6 +100,10 @@ archives:
|
|||||||
files:
|
files:
|
||||||
- non-existent*
|
- non-existent*
|
||||||
|
|
||||||
|
checksum:
|
||||||
|
extra_files:
|
||||||
|
- glob: ./dist/fzf-*darwin*.zip
|
||||||
|
|
||||||
release:
|
release:
|
||||||
github:
|
github:
|
||||||
owner: junegunn
|
owner: junegunn
|
||||||
|
@@ -26,3 +26,5 @@ Style/OptionalBooleanParameter:
|
|||||||
Enabled: false
|
Enabled: false
|
||||||
Style/WordArray:
|
Style/WordArray:
|
||||||
MinSize: 1
|
MinSize: 1
|
||||||
|
Minitest/AssertEqual:
|
||||||
|
Enabled: false
|
||||||
|
42
CHANGELOG.md
42
CHANGELOG.md
@@ -1,6 +1,48 @@
|
|||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
0.35.0
|
||||||
|
------
|
||||||
|
- Added `start` event that is triggered only once when fzf finder starts.
|
||||||
|
Since fzf consumes the input stream asynchronously, the input list is not
|
||||||
|
available unless you use `--sync`.
|
||||||
|
```sh
|
||||||
|
seq 100 | fzf --multi --sync --bind 'start:last+select-all+preview(echo welcome)'
|
||||||
|
```
|
||||||
|
- Added `--border-label` and `--border-label-pos` for putting label on the border
|
||||||
|
```sh
|
||||||
|
# ANSI color codes are supported
|
||||||
|
# (with https://github.com/busyloop/lolcat)
|
||||||
|
label=$(curl -s http://metaphorpsum.com/sentences/1 | lolcat -f)
|
||||||
|
|
||||||
|
# Border label at the center
|
||||||
|
fzf --height=10 --border --border-label="╢ $label ╟" --color=label:italic:black
|
||||||
|
|
||||||
|
# Left-aligned (positive integer)
|
||||||
|
fzf --height=10 --border --border-label="╢ $label ╟" --border-label-pos=3 --color=label:italic:black
|
||||||
|
|
||||||
|
# Right-aligned (negative integer) on the bottom line (:bottom)
|
||||||
|
fzf --height=10 --border --border-label="╢ $label ╟" --border-label-pos=-3:bottom --color=label:italic:black
|
||||||
|
```
|
||||||
|
- Also added `--preview-label` and `--preview-label-pos` for the border of the
|
||||||
|
preview window
|
||||||
|
```sh
|
||||||
|
fzf --preview 'cat {}' --border --preview-label=' Preview ' --preview-label-pos=2
|
||||||
|
```
|
||||||
|
- Info panel (match counter) will be followed by a horizontal separator by
|
||||||
|
default
|
||||||
|
- Use `--no-separator` or `--separator=''` to hide the separator
|
||||||
|
- You can specify an arbitrary string that is repeated to form the
|
||||||
|
horizontal separator. e.g. `--separator=╸`
|
||||||
|
- The color of the separator can be customized via `--color=separator:...`
|
||||||
|
- ANSI color codes are also supported
|
||||||
|
```sh
|
||||||
|
fzf --separator=╸ --color=separator:green
|
||||||
|
fzf --separator=$(lolcat -f -F 1.4 <<< ▁▁▂▃▄▅▆▆▅▄▃▂▁▁) --info=inline
|
||||||
|
```
|
||||||
|
- Added `--border=bold` and `--border=double` along with
|
||||||
|
`--preview-window=border-bold` and `--preview-window=border-double`
|
||||||
|
|
||||||
0.34.0
|
0.34.0
|
||||||
------
|
------
|
||||||
- Added support for adaptive `--height`. If the `--height` value is prefixed
|
- Added support for adaptive `--height`. If the `--height` value is prefixed
|
||||||
|
33
install
33
install
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
set -u
|
set -u
|
||||||
|
|
||||||
version=0.34.0
|
version=0.35.0
|
||||||
auto_completion=
|
auto_completion=
|
||||||
key_bindings=
|
key_bindings=
|
||||||
update_config=2
|
update_config=2
|
||||||
@@ -168,21 +168,22 @@ archi=$(uname -sm)
|
|||||||
binary_available=1
|
binary_available=1
|
||||||
binary_error=""
|
binary_error=""
|
||||||
case "$archi" in
|
case "$archi" in
|
||||||
Darwin\ arm64) download fzf-$version-darwin_arm64.zip ;;
|
Darwin\ arm64) download fzf-$version-darwin_arm64.zip ;;
|
||||||
Darwin\ x86_64) download fzf-$version-darwin_amd64.zip ;;
|
Darwin\ x86_64) download fzf-$version-darwin_amd64.zip ;;
|
||||||
Linux\ armv5*) download fzf-$version-linux_armv5.tar.gz ;;
|
Linux\ armv5*) download fzf-$version-linux_armv5.tar.gz ;;
|
||||||
Linux\ armv6*) download fzf-$version-linux_armv6.tar.gz ;;
|
Linux\ armv6*) download fzf-$version-linux_armv6.tar.gz ;;
|
||||||
Linux\ armv7*) download fzf-$version-linux_armv7.tar.gz ;;
|
Linux\ armv7*) download fzf-$version-linux_armv7.tar.gz ;;
|
||||||
Linux\ armv8*) download fzf-$version-linux_arm64.tar.gz ;;
|
Linux\ armv8*) download fzf-$version-linux_arm64.tar.gz ;;
|
||||||
Linux\ aarch64*) download fzf-$version-linux_arm64.tar.gz ;;
|
Linux\ aarch64*) download fzf-$version-linux_arm64.tar.gz ;;
|
||||||
Linux\ *64) download fzf-$version-linux_amd64.tar.gz ;;
|
Linux\ loongarch64) download fzf-$version-linux_loong64.tar.gz ;;
|
||||||
FreeBSD\ *64) download fzf-$version-freebsd_amd64.tar.gz ;;
|
Linux\ *64) download fzf-$version-linux_amd64.tar.gz ;;
|
||||||
OpenBSD\ *64) download fzf-$version-openbsd_amd64.tar.gz ;;
|
FreeBSD\ *64) download fzf-$version-freebsd_amd64.tar.gz ;;
|
||||||
CYGWIN*\ *64) download fzf-$version-windows_amd64.zip ;;
|
OpenBSD\ *64) download fzf-$version-openbsd_amd64.tar.gz ;;
|
||||||
MINGW*\ *64) download fzf-$version-windows_amd64.zip ;;
|
CYGWIN*\ *64) download fzf-$version-windows_amd64.zip ;;
|
||||||
MSYS*\ *64) download fzf-$version-windows_amd64.zip ;;
|
MINGW*\ *64) download fzf-$version-windows_amd64.zip ;;
|
||||||
Windows*\ *64) download fzf-$version-windows_amd64.zip ;;
|
MSYS*\ *64) download fzf-$version-windows_amd64.zip ;;
|
||||||
*) binary_available=0 binary_error=1 ;;
|
Windows*\ *64) download fzf-$version-windows_amd64.zip ;;
|
||||||
|
*) binary_available=0 binary_error=1 ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
cd "$fzf_base"
|
cd "$fzf_base"
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
$version="0.34.0"
|
$version="0.35.0"
|
||||||
|
|
||||||
$fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition
|
$fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition
|
||||||
|
|
||||||
|
2
main.go
2
main.go
@@ -5,7 +5,7 @@ import (
|
|||||||
"github.com/junegunn/fzf/src/protector"
|
"github.com/junegunn/fzf/src/protector"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version string = "0.34"
|
var version string = "0.35"
|
||||||
var revision string = "devel"
|
var revision string = "devel"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@@ -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 "Sep 2022" "fzf 0.34.0" "fzf-tmux - open fzf in tmux split pane"
|
.TH fzf-tmux 1 "Nov 2022" "fzf 0.35.0" "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
|
||||||
|
106
man/man1/fzf.1
106
man/man1/fzf.1
@@ -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 "Sep 2022" "fzf 0.34.0" "fzf - a command-line fuzzy finder"
|
.TH fzf 1 "Nov 2022" "fzf 0.35.0" "fzf - a command-line fuzzy finder"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fzf - a command-line fuzzy finder
|
fzf - a command-line fuzzy finder
|
||||||
@@ -211,6 +211,10 @@ Draw border around the finder
|
|||||||
.br
|
.br
|
||||||
.BR sharp " Border with sharp corners"
|
.BR sharp " Border with sharp corners"
|
||||||
.br
|
.br
|
||||||
|
.BR bold " Border with bold lines"
|
||||||
|
.br
|
||||||
|
.BR double " Border with double lines"
|
||||||
|
.br
|
||||||
.BR horizontal " Horizontal lines above and below the finder"
|
.BR horizontal " Horizontal lines above and below the finder"
|
||||||
.br
|
.br
|
||||||
.BR vertical " Vertical lines on each side of the finder"
|
.BR vertical " Vertical lines on each side of the finder"
|
||||||
@@ -226,6 +230,50 @@ Draw border around the finder
|
|||||||
.BR none
|
.BR none
|
||||||
.br
|
.br
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.BI "--border-label" [=LABEL]
|
||||||
|
Label to print on the horizontal border line. Should be used with one of the
|
||||||
|
following \fB--border\fR options.
|
||||||
|
|
||||||
|
.br
|
||||||
|
.B * rounded
|
||||||
|
.br
|
||||||
|
.B * sharp
|
||||||
|
.br
|
||||||
|
.B * bold
|
||||||
|
.br
|
||||||
|
.B * double
|
||||||
|
.br
|
||||||
|
.B * horizontal
|
||||||
|
.br
|
||||||
|
.BR "* top" " (up)"
|
||||||
|
.br
|
||||||
|
.BR "* bottom" " (down)"
|
||||||
|
.br
|
||||||
|
|
||||||
|
.br
|
||||||
|
e.g.
|
||||||
|
\fB# ANSI color codes are supported
|
||||||
|
# (with https://github.com/busyloop/lolcat)
|
||||||
|
label=$(curl -s http://metaphorpsum.com/sentences/1 | lolcat -f)
|
||||||
|
|
||||||
|
# Border label at the center
|
||||||
|
fzf --height=10 --border --border-label="╢ $label ╟" --color=label:italic:black
|
||||||
|
|
||||||
|
# Left-aligned (positive integer)
|
||||||
|
fzf --height=10 --border --border-label="╢ $label ╟" --border-label-pos=3 --color=label:italic:black
|
||||||
|
|
||||||
|
# Right-aligned (negative integer) on the bottom line (:bottom)
|
||||||
|
fzf --height=10 --border --border-label="╢ $label ╟" --border-label-pos=-3:bottom --color=label:italic:black\fR
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.BI "--border-label-pos" [=N[:top|bottom]]
|
||||||
|
Position of the border label on the border line. Specify a positive integer as
|
||||||
|
the column position from the left. Specify a negative integer to right-align
|
||||||
|
the label. Label is printed on the top border line by default, add
|
||||||
|
\fB:bottom\fR to put it on the border line on the bottom. The default value
|
||||||
|
\fB0 (or \fBcenter\fR) will put the label at the center of the border line.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B "--no-unicode"
|
.B "--no-unicode"
|
||||||
Use ASCII characters instead of Unicode box drawing characters to draw border
|
Use ASCII characters instead of Unicode box drawing characters to draw border
|
||||||
@@ -281,7 +329,7 @@ e.g.
|
|||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BI "--info=" "STYLE"
|
.BI "--info=" "STYLE"
|
||||||
Determines the display style of finder info.
|
Determines the display style of finder info (match counters).
|
||||||
|
|
||||||
.br
|
.br
|
||||||
.BR default " Display on the next line to the prompt"
|
.BR default " Display on the next line to the prompt"
|
||||||
@@ -295,6 +343,18 @@ Determines the display style of finder info.
|
|||||||
.B "--no-info"
|
.B "--no-info"
|
||||||
A synonym for \fB--info=hidden\fB
|
A synonym for \fB--info=hidden\fB
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.BI "--separator=" "STR"
|
||||||
|
The given string will be repeated to form the horizontal separator on the info
|
||||||
|
line (default: '─' or '-' depending on \fB--no-unicode\fR).
|
||||||
|
|
||||||
|
ANSI color codes are supported.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B "--no-separator"
|
||||||
|
Do not display horizontal separator on the info line. A synonym for
|
||||||
|
\fB--separator=''\fB
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BI "--prompt=" "STR"
|
.BI "--prompt=" "STR"
|
||||||
Input prompt (default: '> ')
|
Input prompt (default: '> ')
|
||||||
@@ -355,7 +415,9 @@ color mappings.
|
|||||||
\fBquery \fRQuery string
|
\fBquery \fRQuery string
|
||||||
\fBdisabled \fRQuery string when search is disabled
|
\fBdisabled \fRQuery string when search is disabled
|
||||||
\fBinfo \fRInfo line (match counters)
|
\fBinfo \fRInfo line (match counters)
|
||||||
|
\fBseparator \fRHorizontal separator on info line (match counters)
|
||||||
\fBborder \fRBorder around the window (\fB--border\fR and \fB--preview\fR)
|
\fBborder \fRBorder around the window (\fB--border\fR and \fB--preview\fR)
|
||||||
|
\fBlabel \fRBorder label (\fB--border-label\fR and \fB--preview-label\fR)
|
||||||
\fBprompt \fRPrompt
|
\fBprompt \fRPrompt
|
||||||
\fBpointer \fRPointer to the current line
|
\fBpointer \fRPointer to the current line
|
||||||
\fBmarker \fRMulti-select marker
|
\fBmarker \fRMulti-select marker
|
||||||
@@ -486,6 +548,37 @@ e.g.
|
|||||||
sleep 0.01
|
sleep 0.01
|
||||||
done'\fR
|
done'\fR
|
||||||
.RE
|
.RE
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.BI "--preview-label" [=LABEL]
|
||||||
|
Label to print on the horizontal border line of the preview window.
|
||||||
|
Should be used with one of the following \fB--preview-window\fR options.
|
||||||
|
|
||||||
|
.br
|
||||||
|
.B * border-rounded (default)
|
||||||
|
.br
|
||||||
|
.B * border-sharp
|
||||||
|
.br
|
||||||
|
.B * border-bold
|
||||||
|
.br
|
||||||
|
.B * border-double
|
||||||
|
.br
|
||||||
|
.B * border-horizontal
|
||||||
|
.br
|
||||||
|
.B * border-top
|
||||||
|
.br
|
||||||
|
.B * border-bottom
|
||||||
|
.br
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.BI "--preview-label-pos" [=N[:top|bottom]]
|
||||||
|
Position of the border label on the border line of the preview window. Specify
|
||||||
|
a positive integer as the column position from the left. Specify a negative
|
||||||
|
integer to right-align the label. Label is printed on the top border line by
|
||||||
|
default, add \fB:bottom\fR to put it on the border line on the bottom. The
|
||||||
|
default value 0 (or \fBcenter\fR) will put the label at the center of the
|
||||||
|
border line.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BI "--preview-window=" "[POSITION][,SIZE[%]][,border-BORDER_OPT][,[no]wrap][,[no]follow][,[no]cycle][,[no]hidden][,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES][,default][,<SIZE_THRESHOLD(ALTERNATIVE_LAYOUT)]"
|
.BI "--preview-window=" "[POSITION][,SIZE[%]][,border-BORDER_OPT][,[no]wrap][,[no]follow][,[no]cycle][,[no]hidden][,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES][,default][,<SIZE_THRESHOLD(ALTERNATIVE_LAYOUT)]"
|
||||||
|
|
||||||
@@ -811,6 +904,15 @@ e.g.
|
|||||||
or any single character
|
or any single character
|
||||||
|
|
||||||
.SS AVAILABLE EVENTS:
|
.SS AVAILABLE EVENTS:
|
||||||
|
\fIstart\fR
|
||||||
|
.RS
|
||||||
|
Triggered only once when fzf finder starts. Since fzf consumes the input stream
|
||||||
|
asynchronously, the input list is not available unless you use \fI--sync\fR.
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
\fB# Move cursor to the last item and select all items
|
||||||
|
seq 1000 | fzf --multi --sync --bind start:last+select-all\fR
|
||||||
|
.RE
|
||||||
\fIchange\fR
|
\fIchange\fR
|
||||||
.RS
|
.RS
|
||||||
Triggered whenever the query string is changed
|
Triggered whenever the query string is changed
|
||||||
|
@@ -143,7 +143,7 @@ function! fzf#install()
|
|||||||
if !filereadable(script)
|
if !filereadable(script)
|
||||||
throw script.' not found'
|
throw script.' not found'
|
||||||
endif
|
endif
|
||||||
let script = 'powershell -ExecutionPolicy Bypass -file ' . script
|
let script = 'powershell -ExecutionPolicy Bypass -file ' . shellescape(script)
|
||||||
else
|
else
|
||||||
let script = s:base_dir.'/install'
|
let script = s:base_dir.'/install'
|
||||||
if !executable(script)
|
if !executable(script)
|
||||||
@@ -164,7 +164,7 @@ function s:get_version(bin)
|
|||||||
if has_key(s:versions, a:bin)
|
if has_key(s:versions, a:bin)
|
||||||
return s:versions[a:bin]
|
return s:versions[a:bin]
|
||||||
end
|
end
|
||||||
let command = (&shell =~ 'powershell' ? '&' : '') . shellescape(a:bin) . ' --version --no-height'
|
let command = (&shell =~ 'powershell' ? '&' : '') . s:fzf_call('shellescape', a:bin) . ' --version --no-height'
|
||||||
let output = systemlist(command)
|
let output = systemlist(command)
|
||||||
if v:shell_error || empty(output)
|
if v:shell_error || empty(output)
|
||||||
return ''
|
return ''
|
||||||
@@ -464,7 +464,7 @@ try
|
|||||||
let temps = { 'result': s:fzf_tempname() }
|
let temps = { 'result': s:fzf_tempname() }
|
||||||
let optstr = s:evaluate_opts(get(dict, 'options', ''))
|
let optstr = s:evaluate_opts(get(dict, 'options', ''))
|
||||||
try
|
try
|
||||||
let fzf_exec = fzf#shellescape(fzf#exec())
|
let fzf_exec = shellescape(fzf#exec())
|
||||||
catch
|
catch
|
||||||
throw v:exception
|
throw v:exception
|
||||||
endtry
|
endtry
|
||||||
@@ -973,16 +973,16 @@ function! s:callback(dict, lines) abort
|
|||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
if has('nvim')
|
if has('nvim')
|
||||||
function s:create_popup(hl, opts) abort
|
function s:create_popup(opts) abort
|
||||||
let buf = nvim_create_buf(v:false, v:true)
|
let buf = nvim_create_buf(v:false, v:true)
|
||||||
let opts = extend({'relative': 'editor', 'style': 'minimal'}, a:opts)
|
let opts = extend({'relative': 'editor', 'style': 'minimal'}, a:opts)
|
||||||
let win = nvim_open_win(buf, v:true, opts)
|
let win = nvim_open_win(buf, v:true, opts)
|
||||||
call setwinvar(win, '&winhighlight', 'NormalFloat:'..a:hl)
|
silent! call setwinvar(win, '&winhighlight', 'Pmenu:,Normal:Normal')
|
||||||
call setwinvar(win, '&colorcolumn', '')
|
call setwinvar(win, '&colorcolumn', '')
|
||||||
return buf
|
return buf
|
||||||
endfunction
|
endfunction
|
||||||
else
|
else
|
||||||
function! s:create_popup(hl, opts) abort
|
function! s:create_popup(opts) abort
|
||||||
let s:popup_create = {buf -> popup_create(buf, #{
|
let s:popup_create = {buf -> popup_create(buf, #{
|
||||||
\ line: a:opts.row,
|
\ line: a:opts.row,
|
||||||
\ col: a:opts.col,
|
\ col: a:opts.col,
|
||||||
@@ -1017,7 +1017,7 @@ function! s:popup(opts) abort
|
|||||||
let row += !has('nvim')
|
let row += !has('nvim')
|
||||||
let col += !has('nvim')
|
let col += !has('nvim')
|
||||||
|
|
||||||
call s:create_popup('Normal', {
|
call s:create_popup({
|
||||||
\ 'row': row, 'col': col, 'width': width, 'height': height
|
\ 'row': row, 'col': col, 'width': width, 'height': height
|
||||||
\ })
|
\ })
|
||||||
endfunction
|
endfunction
|
||||||
|
@@ -37,7 +37,7 @@ bind '"\e[0n": redraw-current-line' 2> /dev/null
|
|||||||
__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
|
||||||
@@ -55,8 +55,8 @@ __fzf_orig_completion() {
|
|||||||
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
|
||||||
done
|
done
|
||||||
@@ -139,17 +139,18 @@ _fzf_handle_dynamic_completion() {
|
|||||||
shift
|
shift
|
||||||
orig_cmd="$1"
|
orig_cmd="$1"
|
||||||
orig_var="_fzf_orig_completion_$cmd"
|
orig_var="_fzf_orig_completion_$cmd"
|
||||||
orig="${!orig_var##*#}"
|
orig="${!orig_var-}"
|
||||||
|
orig="${orig##*#}"
|
||||||
if [[ -n "$orig" ]] && type "$orig" > /dev/null 2>&1; then
|
if [[ -n "$orig" ]] && type "$orig" > /dev/null 2>&1; then
|
||||||
$orig "$@"
|
$orig "$@"
|
||||||
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)
|
||||||
_completion_loader "$@"
|
_completion_loader "$@"
|
||||||
ret=$?
|
ret=$?
|
||||||
# _completion_loader may not have updated completion for the command
|
# _completion_loader may not have updated completion for the command
|
||||||
if [[ "$(complete -p "$orig_cmd" 2> /dev/null)" != "$orig_complete" ]]; then
|
if [[ "$(complete -p "$orig_cmd" 2> /dev/null)" != "$orig_complete" ]]; then
|
||||||
__fzf_orig_completion < <(complete -p "$orig_cmd" 2> /dev/null)
|
__fzf_orig_completion < <(complete -p "$orig_cmd" 2> /dev/null)
|
||||||
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"
|
||||||
@@ -173,6 +174,7 @@ __fzf_generic_path_completion() {
|
|||||||
base=${cur:0:${#cur}-${#trigger}}
|
base=${cur:0:${#cur}-${#trigger}}
|
||||||
eval "base=$base"
|
eval "base=$base"
|
||||||
|
|
||||||
|
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
|
||||||
@@ -180,11 +182,11 @@ __fzf_generic_path_completion() {
|
|||||||
leftover=${leftover/#\/}
|
leftover=${leftover/#\/}
|
||||||
[[ -z "$dir" ]] && dir='.'
|
[[ -z "$dir" ]] && dir='.'
|
||||||
[[ "$dir" != "/" ]] && dir="${dir/%\//}"
|
[[ "$dir" != "/" ]] && dir="${dir/%\//}"
|
||||||
matches=$(eval "$1 $(printf %q "$dir")" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS $2" __fzf_comprun "$4" -q "$leftover" | while read -r item; do
|
matches=$(eval "$1 $(printf %q "$dir")" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} ${FZF_COMPLETION_OPTS-} $2" __fzf_comprun "$4" -q "$leftover" | while read -r item; do
|
||||||
printf "%q " "${item%$3}$3"
|
printf "%q " "${item%$3}$3"
|
||||||
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
|
||||||
@@ -236,7 +238,7 @@ _fzf_complete() {
|
|||||||
if [[ "$cur" == *"$trigger" ]]; then
|
if [[ "$cur" == *"$trigger" ]]; then
|
||||||
cur=${cur:0:${#cur}-${#trigger}}
|
cur=${cur:0:${#cur}-${#trigger}}
|
||||||
|
|
||||||
selected=$(FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS $str_arg" __fzf_comprun "${rest[0]}" "${args[@]}" -q "$cur" | $post | tr '\n' ' ')
|
selected=$(FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} ${FZF_COMPLETION_OPTS-} $str_arg" __fzf_comprun "${rest[0]}" "${args[@]}" -q "$cur" | $post | 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")
|
||||||
@@ -329,7 +331,7 @@ __fzf_defc() {
|
|||||||
func="$2"
|
func="$2"
|
||||||
opts="$3"
|
opts="$3"
|
||||||
orig_var="_fzf_orig_completion_${cmd//[^A-Za-z0-9_]/_}"
|
orig_var="_fzf_orig_completion_${cmd//[^A-Za-z0-9_]/_}"
|
||||||
orig="${!orig_var}"
|
orig="${!orig_var-}"
|
||||||
if [[ -n "$orig" ]]; then
|
if [[ -n "$orig" ]]; then
|
||||||
printf -v def "$orig" "$func"
|
printf -v def "$orig" "$func"
|
||||||
eval "$def"
|
eval "$def"
|
||||||
|
@@ -99,9 +99,9 @@ fi
|
|||||||
__fzf_comprun() {
|
__fzf_comprun() {
|
||||||
if [[ "$(type _fzf_comprun 2>&1)" =~ function ]]; then
|
if [[ "$(type _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
|
||||||
if [ -n "$FZF_TMUX_OPTS" ]; then
|
if [ -n "${FZF_TMUX_OPTS-}" ]; then
|
||||||
fzf-tmux ${(Q)${(Z+n+)FZF_TMUX_OPTS}} -- "$@"
|
fzf-tmux ${(Q)${(Z+n+)FZF_TMUX_OPTS}} -- "$@"
|
||||||
else
|
else
|
||||||
fzf-tmux -d ${FZF_TMUX_HEIGHT:-40%} -- "$@"
|
fzf-tmux -d ${FZF_TMUX_HEIGHT:-40%} -- "$@"
|
||||||
@@ -145,7 +145,7 @@ __fzf_generic_path_completion() {
|
|||||||
leftover=${leftover/#\/}
|
leftover=${leftover/#\/}
|
||||||
[ -z "$dir" ] && dir='.'
|
[ -z "$dir" ] && dir='.'
|
||||||
[ "$dir" != "/" ] && dir="${dir/%\//}"
|
[ "$dir" != "/" ] && dir="${dir/%\//}"
|
||||||
matches=$(eval "$compgen $(printf %q "$dir")" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS" __fzf_comprun "$cmd" ${(Q)${(Z+n+)fzf_opts}} -q "$leftover" | while read item; do
|
matches=$(eval "$compgen $(printf %q "$dir")" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} ${FZF_COMPLETION_OPTS-}" __fzf_comprun "$cmd" ${(Q)${(Z+n+)fzf_opts}} -q "$leftover" | while read item; do
|
||||||
item="${item%$suffix}$suffix"
|
item="${item%$suffix}$suffix"
|
||||||
echo -n "${(q)item} "
|
echo -n "${(q)item} "
|
||||||
done)
|
done)
|
||||||
@@ -184,7 +184,7 @@ _fzf_complete() {
|
|||||||
args=("$@")
|
args=("$@")
|
||||||
sep=
|
sep=
|
||||||
for i in {0..${#args[@]}}; do
|
for i in {0..${#args[@]}}; do
|
||||||
if [[ "${args[$i]}" = -- ]]; then
|
if [[ "${args[$i]-}" = -- ]]; then
|
||||||
sep=$i
|
sep=$i
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
@@ -208,7 +208,7 @@ _fzf_complete() {
|
|||||||
type $post > /dev/null 2>&1 || post=cat
|
type $post > /dev/null 2>&1 || post=cat
|
||||||
|
|
||||||
_fzf_feed_fifo "$fifo"
|
_fzf_feed_fifo "$fifo"
|
||||||
matches=$(FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS $str_arg" __fzf_comprun "$cmd" "${args[@]}" -q "${(Q)prefix}" < "$fifo" | $post | tr '\n' ' ')
|
matches=$(FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} ${FZF_COMPLETION_OPTS-} $str_arg" __fzf_comprun "$cmd" "${args[@]}" -q "${(Q)prefix}" < "$fifo" | $post | tr '\n' ' ')
|
||||||
if [ -n "$matches" ]; then
|
if [ -n "$matches" ]; then
|
||||||
LBUFFER="$lbuf$matches"
|
LBUFFER="$lbuf$matches"
|
||||||
fi
|
fi
|
||||||
@@ -279,8 +279,8 @@ fzf-completion() {
|
|||||||
[ -z "$trigger" -a ${LBUFFER[-1]} = ' ' ] && tokens+=("")
|
[ -z "$trigger" -a ${LBUFFER[-1]} = ' ' ] && tokens+=("")
|
||||||
|
|
||||||
# When the trigger starts with ';', it becomes a separate token
|
# When the trigger starts with ';', it becomes a separate token
|
||||||
if [[ ${LBUFFER} = *"${tokens[-2]}${tokens[-1]}" ]]; then
|
if [[ ${LBUFFER} = *"${tokens[-2]-}${tokens[-1]}" ]]; then
|
||||||
tokens[-2]="${tokens[-2]}${tokens[-1]}"
|
tokens[-2]="${tokens[-2]-}${tokens[-1]}"
|
||||||
tokens=(${tokens[0,-2]})
|
tokens=(${tokens[0,-2]})
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@@ -19,7 +19,7 @@ __fzf_select__() {
|
|||||||
-o -type f -print \
|
-o -type f -print \
|
||||||
-o -type d -print \
|
-o -type d -print \
|
||||||
-o -type l -print 2> /dev/null | cut -b3-"}"
|
-o -type l -print 2> /dev/null | cut -b3-"}"
|
||||||
opts="--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore --reverse $FZF_DEFAULT_OPTS $FZF_CTRL_T_OPTS -m"
|
opts="--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore --reverse ${FZF_DEFAULT_OPTS-} ${FZF_CTRL_T_OPTS-} -m"
|
||||||
eval "$cmd" |
|
eval "$cmd" |
|
||||||
FZF_DEFAULT_OPTS="$opts" $(__fzfcmd) "$@" |
|
FZF_DEFAULT_OPTS="$opts" $(__fzfcmd) "$@" |
|
||||||
while read -r item; do
|
while read -r item; do
|
||||||
@@ -30,7 +30,7 @@ __fzf_select__() {
|
|||||||
if [[ $- =~ i ]]; then
|
if [[ $- =~ i ]]; then
|
||||||
|
|
||||||
__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"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,13 +44,13 @@ __fzf_cd__() {
|
|||||||
local cmd opts dir
|
local cmd opts dir
|
||||||
cmd="${FZF_ALT_C_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \
|
cmd="${FZF_ALT_C_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \
|
||||||
-o -type d -print 2> /dev/null | cut -b3-"}"
|
-o -type d -print 2> /dev/null | cut -b3-"}"
|
||||||
opts="--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore --reverse $FZF_DEFAULT_OPTS $FZF_ALT_C_OPTS +m"
|
opts="--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore --reverse ${FZF_DEFAULT_OPTS-} ${FZF_ALT_C_OPTS-} +m"
|
||||||
dir=$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" $(__fzfcmd)) && printf 'builtin cd -- %q' "$dir"
|
dir=$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" $(__fzfcmd)) && printf 'builtin cd -- %q' "$dir"
|
||||||
}
|
}
|
||||||
|
|
||||||
__fzf_history__() {
|
__fzf_history__() {
|
||||||
local output opts script
|
local output opts script
|
||||||
opts="--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS -n2..,.. --scheme=history --bind=ctrl-r:toggle-sort $FZF_CTRL_R_OPTS +m --read0"
|
opts="--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} -n2..,.. --scheme=history --bind=ctrl-r:toggle-sort ${FZF_CTRL_R_OPTS-} +m --read0"
|
||||||
script='BEGIN { getc; $/ = "\n\t"; $HISTCOUNT = $ENV{last_hist} + 1 } s/^[ *]//; print $HISTCOUNT - $. . "\t$_" if !$seen{$_}++'
|
script='BEGIN { getc; $/ = "\n\t"; $HISTCOUNT = $ENV{last_hist} + 1 } s/^[ *]//; print $HISTCOUNT - $. . "\t$_" if !$seen{$_}++'
|
||||||
output=$(
|
output=$(
|
||||||
builtin fc -lnr -2147483648 |
|
builtin fc -lnr -2147483648 |
|
||||||
|
@@ -46,7 +46,7 @@ __fsel() {
|
|||||||
-o -type l -print 2> /dev/null | cut -b3-"}"
|
-o -type l -print 2> /dev/null | cut -b3-"}"
|
||||||
setopt localoptions pipefail no_aliases 2> /dev/null
|
setopt localoptions pipefail no_aliases 2> /dev/null
|
||||||
local item
|
local item
|
||||||
eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_CTRL_T_OPTS" $(__fzfcmd) -m "$@" | while read item; do
|
eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} ${FZF_CTRL_T_OPTS-}" $(__fzfcmd) -m "$@" | while read item; do
|
||||||
echo -n "${(q)item} "
|
echo -n "${(q)item} "
|
||||||
done
|
done
|
||||||
local ret=$?
|
local ret=$?
|
||||||
@@ -55,7 +55,7 @@ __fsel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
__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"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ fzf-cd-widget() {
|
|||||||
local cmd="${FZF_ALT_C_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \
|
local cmd="${FZF_ALT_C_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \
|
||||||
-o -type d -print 2> /dev/null | cut -b3-"}"
|
-o -type d -print 2> /dev/null | cut -b3-"}"
|
||||||
setopt localoptions pipefail no_aliases 2> /dev/null
|
setopt localoptions pipefail no_aliases 2> /dev/null
|
||||||
local dir="$(eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_ALT_C_OPTS" $(__fzfcmd) +m)"
|
local dir="$(eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} ${FZF_ALT_C_OPTS-}" $(__fzfcmd) +m)"
|
||||||
if [[ -z "$dir" ]]; then
|
if [[ -z "$dir" ]]; then
|
||||||
zle redisplay
|
zle redisplay
|
||||||
return 0
|
return 0
|
||||||
@@ -98,7 +98,7 @@ fzf-history-widget() {
|
|||||||
local selected num
|
local selected num
|
||||||
setopt localoptions noglobsubst noposixbuiltins pipefail no_aliases 2> /dev/null
|
setopt localoptions noglobsubst noposixbuiltins pipefail no_aliases 2> /dev/null
|
||||||
selected=( $(fc -rl 1 | awk '{ cmd=$0; sub(/^[ \t]*[0-9]+\**[ \t]+/, "", cmd); if (!seen[cmd]++) print $0 }' |
|
selected=( $(fc -rl 1 | awk '{ cmd=$0; sub(/^[ \t]*[0-9]+\**[ \t]+/, "", cmd); if (!seen[cmd]++) print $0 }' |
|
||||||
FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} $FZF_DEFAULT_OPTS -n2..,.. --scheme=history --bind=ctrl-r:toggle-sort,ctrl-z:ignore $FZF_CTRL_R_OPTS --query=${(qqq)LBUFFER} +m" $(__fzfcmd)) )
|
FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} ${FZF_DEFAULT_OPTS-} -n2..,.. --scheme=history --bind=ctrl-r:toggle-sort,ctrl-z:ignore ${FZF_CTRL_R_OPTS-} --query=${(qqq)LBUFFER} +m" $(__fzfcmd)) )
|
||||||
local ret=$?
|
local ret=$?
|
||||||
if [ -n "$selected" ]; then
|
if [ -n "$selected" ]; then
|
||||||
num=$selected[1]
|
num=$selected[1]
|
||||||
|
475
src/options.go
475
src/options.go
@@ -18,97 +18,107 @@ import (
|
|||||||
const usage = `usage: fzf [options]
|
const usage = `usage: fzf [options]
|
||||||
|
|
||||||
Search
|
Search
|
||||||
-x, --extended Extended-search mode
|
-x, --extended Extended-search mode
|
||||||
(enabled by default; +x or --no-extended to disable)
|
(enabled by default; +x or --no-extended to disable)
|
||||||
-e, --exact Enable Exact-match
|
-e, --exact Enable Exact-match
|
||||||
-i Case-insensitive match (default: smart-case match)
|
-i Case-insensitive match (default: smart-case match)
|
||||||
+i Case-sensitive match
|
+i Case-sensitive match
|
||||||
--scheme=SCHEME Scoring scheme [default|path|history]
|
--scheme=SCHEME Scoring scheme [default|path|history]
|
||||||
--literal Do not normalize latin script letters before matching
|
--literal Do not normalize latin script letters before matching
|
||||||
-n, --nth=N[,..] Comma-separated list of field index expressions
|
-n, --nth=N[,..] Comma-separated list of field index expressions
|
||||||
for limiting search scope. Each can be a non-zero
|
for limiting search scope. Each can be a non-zero
|
||||||
integer or a range expression ([BEGIN]..[END]).
|
integer or a range expression ([BEGIN]..[END]).
|
||||||
--with-nth=N[,..] Transform the presentation of each line using
|
--with-nth=N[,..] Transform the presentation of each line using
|
||||||
field index expressions
|
field index expressions
|
||||||
-d, --delimiter=STR Field delimiter regex (default: AWK-style)
|
-d, --delimiter=STR Field delimiter regex (default: AWK-style)
|
||||||
+s, --no-sort Do not sort the result
|
+s, --no-sort Do not sort the result
|
||||||
--tac Reverse the order of the input
|
--tac Reverse the order of the input
|
||||||
--disabled Do not perform search
|
--disabled Do not perform search
|
||||||
--tiebreak=CRI[,..] Comma-separated list of sort criteria to apply
|
--tiebreak=CRI[,..] Comma-separated list of sort criteria to apply
|
||||||
when the scores are tied [length|chunk|begin|end|index]
|
when the scores are tied [length|chunk|begin|end|index]
|
||||||
(default: length)
|
(default: length)
|
||||||
|
|
||||||
Interface
|
Interface
|
||||||
-m, --multi[=MAX] Enable multi-select with tab/shift-tab
|
-m, --multi[=MAX] Enable multi-select with tab/shift-tab
|
||||||
--no-mouse Disable mouse
|
--no-mouse Disable mouse
|
||||||
--bind=KEYBINDS Custom key bindings. Refer to the man page.
|
--bind=KEYBINDS Custom key bindings. Refer to the man page.
|
||||||
--cycle Enable cyclic scroll
|
--cycle Enable cyclic scroll
|
||||||
--keep-right Keep the right end of the line visible on overflow
|
--keep-right Keep the right end of the line visible on overflow
|
||||||
--scroll-off=LINES Number of screen lines to keep above or below when
|
--scroll-off=LINES Number of screen lines to keep above or below when
|
||||||
scrolling to the top or to the bottom (default: 0)
|
scrolling to the top or to the bottom (default: 0)
|
||||||
--no-hscroll Disable horizontal scroll
|
--no-hscroll Disable horizontal scroll
|
||||||
--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)
|
||||||
--filepath-word Make word-wise movements respect path separators
|
--filepath-word Make word-wise movements respect path separators
|
||||||
--jump-labels=CHARS Label characters for jump and jump-accept
|
--jump-labels=CHARS Label characters for jump and jump-accept
|
||||||
|
|
||||||
Layout
|
Layout
|
||||||
--height=[~]HEIGHT[%] Display fzf window below the cursor with the given
|
--height=[~]HEIGHT[%] Display fzf window below the cursor with the given
|
||||||
height instead of using fullscreen.
|
height instead of using fullscreen.
|
||||||
If prefixed with '~', fzf will determine the height
|
If prefixed with '~', fzf will determine the height
|
||||||
according to the input size.
|
according to the input size.
|
||||||
--min-height=HEIGHT Minimum height when --height is given in percent
|
--min-height=HEIGHT Minimum height when --height is given in percent
|
||||||
(default: 10)
|
(default: 10)
|
||||||
--layout=LAYOUT Choose layout: [default|reverse|reverse-list]
|
--layout=LAYOUT Choose layout: [default|reverse|reverse-list]
|
||||||
--border[=STYLE] Draw border around the finder
|
--border[=STYLE] Draw border around the finder
|
||||||
[rounded|sharp|horizontal|vertical|
|
[rounded|sharp|horizontal|vertical|
|
||||||
top|bottom|left|right|none] (default: rounded)
|
top|bottom|left|right|none] (default: rounded)
|
||||||
--margin=MARGIN Screen margin (TRBL | TB,RL | T,RL,B | T,R,B,L)
|
--border-label=LABEL Label to print on the border
|
||||||
--padding=PADDING Padding inside border (TRBL | TB,RL | T,RL,B | T,R,B,L)
|
--border-label-pos=COL Position of the border label
|
||||||
--info=STYLE Finder info style [default|inline|hidden]
|
[POSITIVE_INTEGER: columns from left|
|
||||||
--prompt=STR Input prompt (default: '> ')
|
NEGATIVE_INTEGER: columns from right][:bottom]
|
||||||
--pointer=STR Pointer to the current line (default: '>')
|
(default: 0 or center)
|
||||||
--marker=STR Multi-select marker (default: '>')
|
--margin=MARGIN Screen margin (TRBL | TB,RL | T,RL,B | T,R,B,L)
|
||||||
--header=STR String to print as header
|
--padding=PADDING Padding inside border (TRBL | TB,RL | T,RL,B | T,R,B,L)
|
||||||
--header-lines=N The first N lines of the input are treated as header
|
--info=STYLE Finder info style [default|inline|hidden]
|
||||||
--header-first Print header before the prompt line
|
--separator=STR String to form horizontal separator on info line
|
||||||
--ellipsis=STR Ellipsis to show when line is truncated (default: '..')
|
--no-separator Hide info line separator
|
||||||
|
--prompt=STR Input prompt (default: '> ')
|
||||||
|
--pointer=STR Pointer to the current line (default: '>')
|
||||||
|
--marker=STR Multi-select marker (default: '>')
|
||||||
|
--header=STR String to print as header
|
||||||
|
--header-lines=N The first N lines of the input are treated as header
|
||||||
|
--header-first Print header before the prompt line
|
||||||
|
--ellipsis=STR Ellipsis to show when line is truncated (default: '..')
|
||||||
|
|
||||||
Display
|
Display
|
||||||
--ansi Enable processing of ANSI color codes
|
--ansi Enable processing of ANSI color codes
|
||||||
--tabstop=SPACES Number of spaces for a tab character (default: 8)
|
--tabstop=SPACES Number of spaces for a tab character (default: 8)
|
||||||
--color=COLSPEC Base scheme (dark|light|16|bw) and/or custom colors
|
--color=COLSPEC Base scheme (dark|light|16|bw) and/or custom colors
|
||||||
--no-bold Do not use bold text
|
--no-bold Do not use bold text
|
||||||
|
|
||||||
History
|
History
|
||||||
--history=FILE History file
|
--history=FILE History file
|
||||||
--history-size=N Maximum number of history entries (default: 1000)
|
--history-size=N Maximum number of history entries (default: 1000)
|
||||||
|
|
||||||
Preview
|
Preview
|
||||||
--preview=COMMAND Command to preview highlighted line ({})
|
--preview=COMMAND Command to preview highlighted line ({})
|
||||||
--preview-window=OPT Preview window layout (default: right:50%)
|
--preview-window=OPT Preview window layout (default: right:50%)
|
||||||
[up|down|left|right][,SIZE[%]]
|
[up|down|left|right][,SIZE[%]]
|
||||||
[,[no]wrap][,[no]cycle][,[no]follow][,[no]hidden]
|
[,[no]wrap][,[no]cycle][,[no]follow][,[no]hidden]
|
||||||
[,border-BORDER_OPT]
|
[,border-BORDER_OPT]
|
||||||
[,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES]
|
[,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES]
|
||||||
[,default][,<SIZE_THRESHOLD(ALTERNATIVE_LAYOUT)]
|
[,default][,<SIZE_THRESHOLD(ALTERNATIVE_LAYOUT)]
|
||||||
|
--preview-label=LABEL
|
||||||
|
--preview-label-pos=N Same as --border-label and --border-label-pos,
|
||||||
|
but for preview window
|
||||||
|
|
||||||
Scripting
|
Scripting
|
||||||
-q, --query=STR Start the finder with the given query
|
-q, --query=STR Start the finder with the given query
|
||||||
-1, --select-1 Automatically select the only match
|
-1, --select-1 Automatically select the only match
|
||||||
-0, --exit-0 Exit immediately when there's no match
|
-0, --exit-0 Exit immediately when there's no match
|
||||||
-f, --filter=STR Filter mode. Do not start interactive finder.
|
-f, --filter=STR Filter mode. Do not start interactive finder.
|
||||||
--print-query Print query as the first line
|
--print-query Print query as the first line
|
||||||
--expect=KEYS Comma-separated list of keys to complete fzf
|
--expect=KEYS Comma-separated list of keys to complete fzf
|
||||||
--read0 Read input delimited by ASCII NUL characters
|
--read0 Read input delimited by ASCII NUL characters
|
||||||
--print0 Print output delimited by ASCII NUL characters
|
--print0 Print output delimited by ASCII NUL characters
|
||||||
--sync Synchronous search for multi-staged filtering
|
--sync Synchronous search for multi-staged filtering
|
||||||
--version Display version information and exit
|
--version Display version information and exit
|
||||||
|
|
||||||
Environment variables
|
Environment variables
|
||||||
FZF_DEFAULT_COMMAND Default command to use when input is tty
|
FZF_DEFAULT_COMMAND Default command to use when input is tty
|
||||||
FZF_DEFAULT_OPTS Default options
|
FZF_DEFAULT_OPTS Default options
|
||||||
(e.g. '--layout=reverse --inline-info')
|
(e.g. '--layout=reverse --inline-info')
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
@@ -173,6 +183,12 @@ const (
|
|||||||
infoHidden
|
infoHidden
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type labelOpts struct {
|
||||||
|
label string
|
||||||
|
column int
|
||||||
|
bottom bool
|
||||||
|
}
|
||||||
|
|
||||||
type previewOpts struct {
|
type previewOpts struct {
|
||||||
command string
|
command string
|
||||||
position windowPosition
|
position windowPosition
|
||||||
@@ -188,6 +204,23 @@ type previewOpts struct {
|
|||||||
alternative *previewOpts
|
alternative *previewOpts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseLabelPosition(opts *labelOpts, arg string) {
|
||||||
|
opts.column = 0
|
||||||
|
opts.bottom = false
|
||||||
|
for _, token := range splitRegexp.Split(strings.ToLower(arg), -1) {
|
||||||
|
switch token {
|
||||||
|
case "center":
|
||||||
|
opts.column = 0
|
||||||
|
case "bottom":
|
||||||
|
opts.bottom = true
|
||||||
|
case "top":
|
||||||
|
opts.bottom = false
|
||||||
|
default:
|
||||||
|
opts.column = atoi(token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (a previewOpts) aboveOrBelow() bool {
|
func (a previewOpts) aboveOrBelow() bool {
|
||||||
return a.size.size > 0 && (a.position == posUp || a.position == posDown)
|
return a.size.size > 0 && (a.position == posUp || a.position == posDown)
|
||||||
}
|
}
|
||||||
@@ -204,64 +237,67 @@ func (a previewOpts) sameContentLayout(b previewOpts) bool {
|
|||||||
|
|
||||||
// Options stores the values of command-line options
|
// Options stores the values of command-line options
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Fuzzy bool
|
Fuzzy bool
|
||||||
FuzzyAlgo algo.Algo
|
FuzzyAlgo algo.Algo
|
||||||
Scheme string
|
Scheme string
|
||||||
Extended bool
|
Extended bool
|
||||||
Phony bool
|
Phony bool
|
||||||
Case Case
|
Case Case
|
||||||
Normalize bool
|
Normalize bool
|
||||||
Nth []Range
|
Nth []Range
|
||||||
WithNth []Range
|
WithNth []Range
|
||||||
Delimiter Delimiter
|
Delimiter Delimiter
|
||||||
Sort int
|
Sort int
|
||||||
Tac bool
|
Tac bool
|
||||||
Criteria []criterion
|
Criteria []criterion
|
||||||
Multi int
|
Multi int
|
||||||
Ansi bool
|
Ansi bool
|
||||||
Mouse bool
|
Mouse bool
|
||||||
Theme *tui.ColorTheme
|
Theme *tui.ColorTheme
|
||||||
Black bool
|
Black bool
|
||||||
Bold bool
|
Bold bool
|
||||||
Height heightSpec
|
Height heightSpec
|
||||||
MinHeight int
|
MinHeight int
|
||||||
Layout layoutType
|
Layout layoutType
|
||||||
Cycle bool
|
Cycle bool
|
||||||
KeepRight bool
|
KeepRight bool
|
||||||
Hscroll bool
|
Hscroll bool
|
||||||
HscrollOff int
|
HscrollOff int
|
||||||
ScrollOff int
|
ScrollOff int
|
||||||
FileWord bool
|
FileWord bool
|
||||||
InfoStyle infoStyle
|
InfoStyle infoStyle
|
||||||
JumpLabels string
|
Separator *string
|
||||||
Prompt string
|
JumpLabels string
|
||||||
Pointer string
|
Prompt string
|
||||||
Marker string
|
Pointer string
|
||||||
Query string
|
Marker string
|
||||||
Select1 bool
|
Query string
|
||||||
Exit0 bool
|
Select1 bool
|
||||||
Filter *string
|
Exit0 bool
|
||||||
ToggleSort bool
|
Filter *string
|
||||||
Expect map[tui.Event]string
|
ToggleSort bool
|
||||||
Keymap map[tui.Event][]*action
|
Expect map[tui.Event]string
|
||||||
Preview previewOpts
|
Keymap map[tui.Event][]*action
|
||||||
PrintQuery bool
|
Preview previewOpts
|
||||||
ReadZero bool
|
PrintQuery bool
|
||||||
Printer func(string)
|
ReadZero bool
|
||||||
PrintSep string
|
Printer func(string)
|
||||||
Sync bool
|
PrintSep string
|
||||||
History *History
|
Sync bool
|
||||||
Header []string
|
History *History
|
||||||
HeaderLines int
|
Header []string
|
||||||
HeaderFirst bool
|
HeaderLines int
|
||||||
Ellipsis string
|
HeaderFirst bool
|
||||||
Margin [4]sizeSpec
|
Ellipsis string
|
||||||
Padding [4]sizeSpec
|
Margin [4]sizeSpec
|
||||||
BorderShape tui.BorderShape
|
Padding [4]sizeSpec
|
||||||
Unicode bool
|
BorderShape tui.BorderShape
|
||||||
Tabstop int
|
BorderLabel labelOpts
|
||||||
ClearOnExit bool
|
PreviewLabel labelOpts
|
||||||
Version bool
|
Unicode bool
|
||||||
|
Tabstop int
|
||||||
|
ClearOnExit bool
|
||||||
|
Version bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultPreviewOpts(command string) previewOpts {
|
func defaultPreviewOpts(command string) previewOpts {
|
||||||
@@ -270,62 +306,65 @@ func defaultPreviewOpts(command string) previewOpts {
|
|||||||
|
|
||||||
func defaultOptions() *Options {
|
func defaultOptions() *Options {
|
||||||
return &Options{
|
return &Options{
|
||||||
Fuzzy: true,
|
Fuzzy: true,
|
||||||
FuzzyAlgo: algo.FuzzyMatchV2,
|
FuzzyAlgo: algo.FuzzyMatchV2,
|
||||||
Scheme: "default",
|
Scheme: "default",
|
||||||
Extended: true,
|
Extended: true,
|
||||||
Phony: false,
|
Phony: false,
|
||||||
Case: CaseSmart,
|
Case: CaseSmart,
|
||||||
Normalize: true,
|
Normalize: true,
|
||||||
Nth: make([]Range, 0),
|
Nth: make([]Range, 0),
|
||||||
WithNth: make([]Range, 0),
|
WithNth: make([]Range, 0),
|
||||||
Delimiter: Delimiter{},
|
Delimiter: Delimiter{},
|
||||||
Sort: 1000,
|
Sort: 1000,
|
||||||
Tac: false,
|
Tac: false,
|
||||||
Criteria: []criterion{byScore, byLength},
|
Criteria: []criterion{byScore, byLength},
|
||||||
Multi: 0,
|
Multi: 0,
|
||||||
Ansi: false,
|
Ansi: false,
|
||||||
Mouse: true,
|
Mouse: true,
|
||||||
Theme: tui.EmptyTheme(),
|
Theme: tui.EmptyTheme(),
|
||||||
Black: false,
|
Black: false,
|
||||||
Bold: true,
|
Bold: true,
|
||||||
MinHeight: 10,
|
MinHeight: 10,
|
||||||
Layout: layoutDefault,
|
Layout: layoutDefault,
|
||||||
Cycle: false,
|
Cycle: false,
|
||||||
KeepRight: false,
|
KeepRight: false,
|
||||||
Hscroll: true,
|
Hscroll: true,
|
||||||
HscrollOff: 10,
|
HscrollOff: 10,
|
||||||
ScrollOff: 0,
|
ScrollOff: 0,
|
||||||
FileWord: false,
|
FileWord: false,
|
||||||
InfoStyle: infoDefault,
|
InfoStyle: infoDefault,
|
||||||
JumpLabels: defaultJumpLabels,
|
Separator: nil,
|
||||||
Prompt: "> ",
|
JumpLabels: defaultJumpLabels,
|
||||||
Pointer: ">",
|
Prompt: "> ",
|
||||||
Marker: ">",
|
Pointer: ">",
|
||||||
Query: "",
|
Marker: ">",
|
||||||
Select1: false,
|
Query: "",
|
||||||
Exit0: false,
|
Select1: false,
|
||||||
Filter: nil,
|
Exit0: false,
|
||||||
ToggleSort: false,
|
Filter: nil,
|
||||||
Expect: make(map[tui.Event]string),
|
ToggleSort: false,
|
||||||
Keymap: make(map[tui.Event][]*action),
|
Expect: make(map[tui.Event]string),
|
||||||
Preview: defaultPreviewOpts(""),
|
Keymap: make(map[tui.Event][]*action),
|
||||||
PrintQuery: false,
|
Preview: defaultPreviewOpts(""),
|
||||||
ReadZero: false,
|
PrintQuery: false,
|
||||||
Printer: func(str string) { fmt.Println(str) },
|
ReadZero: false,
|
||||||
PrintSep: "\n",
|
Printer: func(str string) { fmt.Println(str) },
|
||||||
Sync: false,
|
PrintSep: "\n",
|
||||||
History: nil,
|
Sync: false,
|
||||||
Header: make([]string, 0),
|
History: nil,
|
||||||
HeaderLines: 0,
|
Header: make([]string, 0),
|
||||||
HeaderFirst: false,
|
HeaderLines: 0,
|
||||||
Ellipsis: "..",
|
HeaderFirst: false,
|
||||||
Margin: defaultMargin(),
|
Ellipsis: "..",
|
||||||
Padding: defaultMargin(),
|
Margin: defaultMargin(),
|
||||||
Unicode: true,
|
Padding: defaultMargin(),
|
||||||
Tabstop: 8,
|
Unicode: true,
|
||||||
ClearOnExit: true,
|
Tabstop: 8,
|
||||||
Version: false}
|
BorderLabel: labelOpts{},
|
||||||
|
PreviewLabel: labelOpts{},
|
||||||
|
ClearOnExit: true,
|
||||||
|
Version: false}
|
||||||
}
|
}
|
||||||
|
|
||||||
func help(code int) {
|
func help(code int) {
|
||||||
@@ -470,6 +509,10 @@ func parseBorder(str string, optional bool) tui.BorderShape {
|
|||||||
return tui.BorderRounded
|
return tui.BorderRounded
|
||||||
case "sharp":
|
case "sharp":
|
||||||
return tui.BorderSharp
|
return tui.BorderSharp
|
||||||
|
case "bold":
|
||||||
|
return tui.BorderBold
|
||||||
|
case "double":
|
||||||
|
return tui.BorderDouble
|
||||||
case "horizontal":
|
case "horizontal":
|
||||||
return tui.BorderHorizontal
|
return tui.BorderHorizontal
|
||||||
case "vertical":
|
case "vertical":
|
||||||
@@ -488,7 +531,7 @@ func parseBorder(str string, optional bool) tui.BorderShape {
|
|||||||
if optional && str == "" {
|
if optional && str == "" {
|
||||||
return tui.BorderRounded
|
return tui.BorderRounded
|
||||||
}
|
}
|
||||||
errorExit("invalid border style (expected: rounded|sharp|horizontal|vertical|top|bottom|left|right|none)")
|
errorExit("invalid border style (expected: rounded|sharp|bold|double|horizontal|vertical|top|bottom|left|right|none)")
|
||||||
}
|
}
|
||||||
return tui.BorderNone
|
return tui.BorderNone
|
||||||
}
|
}
|
||||||
@@ -543,6 +586,8 @@ func parseKeyChords(str string, message string) map[tui.Event]string {
|
|||||||
add(tui.Change)
|
add(tui.Change)
|
||||||
case "backward-eof":
|
case "backward-eof":
|
||||||
add(tui.BackwardEOF)
|
add(tui.BackwardEOF)
|
||||||
|
case "start":
|
||||||
|
add(tui.Start)
|
||||||
case "alt-enter", "alt-return":
|
case "alt-enter", "alt-return":
|
||||||
chords[tui.CtrlAltKey('m')] = key
|
chords[tui.CtrlAltKey('m')] = key
|
||||||
case "alt-space":
|
case "alt-space":
|
||||||
@@ -796,6 +841,10 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) *tui.ColorTheme {
|
|||||||
mergeAttr(&theme.CurrentMatch)
|
mergeAttr(&theme.CurrentMatch)
|
||||||
case "border":
|
case "border":
|
||||||
mergeAttr(&theme.Border)
|
mergeAttr(&theme.Border)
|
||||||
|
case "separator":
|
||||||
|
mergeAttr(&theme.Separator)
|
||||||
|
case "label":
|
||||||
|
mergeAttr(&theme.BorderLabel)
|
||||||
case "prompt":
|
case "prompt":
|
||||||
mergeAttr(&theme.Prompt)
|
mergeAttr(&theme.Prompt)
|
||||||
case "spinner":
|
case "spinner":
|
||||||
@@ -816,7 +865,10 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) *tui.ColorTheme {
|
|||||||
return theme
|
return theme
|
||||||
}
|
}
|
||||||
|
|
||||||
var executeRegexp *regexp.Regexp
|
var (
|
||||||
|
executeRegexp *regexp.Regexp
|
||||||
|
splitRegexp *regexp.Regexp
|
||||||
|
)
|
||||||
|
|
||||||
func firstKey(keymap map[tui.Event]string) tui.Event {
|
func firstKey(keymap map[tui.Event]string) tui.Event {
|
||||||
for k := range keymap {
|
for k := range keymap {
|
||||||
@@ -836,6 +888,7 @@ func init() {
|
|||||||
// "~!@#$%^&*;/|".each_char.map { |c| Regexp.escape(c) }.map { |c| "#{c}[^#{c}]*#{c}" }.join('|')
|
// "~!@#$%^&*;/|".each_char.map { |c| Regexp.escape(c) }.map { |c| "#{c}[^#{c}]*#{c}" }.join('|')
|
||||||
executeRegexp = regexp.MustCompile(
|
executeRegexp = regexp.MustCompile(
|
||||||
`(?si)[:+](execute(?:-multi|-silent)?|reload|preview|change-prompt|change-preview-window|change-preview|(?:re|un)bind):.+|[:+](execute(?:-multi|-silent)?|reload|preview|change-prompt|change-preview-window|change-preview|(?:re|un)bind)(\([^)]*\)|\[[^\]]*\]|~[^~]*~|![^!]*!|@[^@]*@|\#[^\#]*\#|\$[^\$]*\$|%[^%]*%|\^[^\^]*\^|&[^&]*&|\*[^\*]*\*|;[^;]*;|/[^/]*/|\|[^\|]*\|)`)
|
`(?si)[:+](execute(?:-multi|-silent)?|reload|preview|change-prompt|change-preview-window|change-preview|(?:re|un)bind):.+|[:+](execute(?:-multi|-silent)?|reload|preview|change-prompt|change-preview-window|change-preview|(?:re|un)bind)(\([^)]*\)|\[[^\]]*\]|~[^~]*~|![^!]*!|@[^@]*@|\#[^\#]*\#|\$[^\$]*\$|%[^%]*%|\^[^\^]*\^|&[^&]*&|\*[^\*]*\*|;[^;]*;|/[^/]*/|\|[^\|]*\|)`)
|
||||||
|
splitRegexp = regexp.MustCompile("[,:]+")
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseKeymap(keymap map[tui.Event][]*action, str string) {
|
func parseKeymap(keymap map[tui.Event][]*action, str string) {
|
||||||
@@ -1203,7 +1256,7 @@ func parseInfoStyle(str string) infoStyle {
|
|||||||
case "hidden":
|
case "hidden":
|
||||||
return infoHidden
|
return infoHidden
|
||||||
default:
|
default:
|
||||||
errorExit("invalid info style (expected: default / inline / hidden)")
|
errorExit("invalid info style (expected: default|inline|hidden)")
|
||||||
}
|
}
|
||||||
return infoDefault
|
return infoDefault
|
||||||
}
|
}
|
||||||
@@ -1250,6 +1303,10 @@ func parsePreviewWindow(opts *previewOpts, input string) {
|
|||||||
opts.border = tui.BorderRounded
|
opts.border = tui.BorderRounded
|
||||||
case "sharp", "border-sharp":
|
case "sharp", "border-sharp":
|
||||||
opts.border = tui.BorderSharp
|
opts.border = tui.BorderSharp
|
||||||
|
case "border-bold":
|
||||||
|
opts.border = tui.BorderBold
|
||||||
|
case "border-double":
|
||||||
|
opts.border = tui.BorderDouble
|
||||||
case "noborder", "border-none":
|
case "noborder", "border-none":
|
||||||
opts.border = tui.BorderNone
|
opts.border = tui.BorderNone
|
||||||
case "border-horizontal":
|
case "border-horizontal":
|
||||||
@@ -1472,6 +1529,12 @@ func parseOptions(opts *Options, allArgs []string) {
|
|||||||
opts.InfoStyle = infoInline
|
opts.InfoStyle = infoInline
|
||||||
case "--no-inline-info":
|
case "--no-inline-info":
|
||||||
opts.InfoStyle = infoDefault
|
opts.InfoStyle = infoDefault
|
||||||
|
case "--separator":
|
||||||
|
separator := nextString(allArgs, &i, "separator character required")
|
||||||
|
opts.Separator = &separator
|
||||||
|
case "--no-separator":
|
||||||
|
nosep := ""
|
||||||
|
opts.Separator = &nosep
|
||||||
case "--jump-labels":
|
case "--jump-labels":
|
||||||
opts.JumpLabels = nextString(allArgs, &i, "label characters required")
|
opts.JumpLabels = nextString(allArgs, &i, "label characters required")
|
||||||
validateJumpLabels = true
|
validateJumpLabels = true
|
||||||
@@ -1554,6 +1617,20 @@ func parseOptions(opts *Options, allArgs []string) {
|
|||||||
case "--border":
|
case "--border":
|
||||||
hasArg, arg := optionalNextString(allArgs, &i)
|
hasArg, arg := optionalNextString(allArgs, &i)
|
||||||
opts.BorderShape = parseBorder(arg, !hasArg)
|
opts.BorderShape = parseBorder(arg, !hasArg)
|
||||||
|
case "--no-border-label":
|
||||||
|
opts.BorderLabel.label = ""
|
||||||
|
case "--border-label":
|
||||||
|
opts.BorderLabel.label = nextString(allArgs, &i, "label required")
|
||||||
|
case "--border-label-pos":
|
||||||
|
pos := nextString(allArgs, &i, "label position required (positive or negative integer or 'center')")
|
||||||
|
parseLabelPosition(&opts.BorderLabel, pos)
|
||||||
|
case "--no-preview-label":
|
||||||
|
opts.PreviewLabel.label = ""
|
||||||
|
case "--preview-label":
|
||||||
|
opts.PreviewLabel.label = nextString(allArgs, &i, "preview label required")
|
||||||
|
case "--preview-label-pos":
|
||||||
|
pos := nextString(allArgs, &i, "preview label position required (positive or negative integer or 'center')")
|
||||||
|
parseLabelPosition(&opts.PreviewLabel, pos)
|
||||||
case "--no-unicode":
|
case "--no-unicode":
|
||||||
opts.Unicode = false
|
opts.Unicode = false
|
||||||
case "--unicode":
|
case "--unicode":
|
||||||
@@ -1589,6 +1666,14 @@ func parseOptions(opts *Options, allArgs []string) {
|
|||||||
opts.Delimiter = delimiterRegexp(value)
|
opts.Delimiter = delimiterRegexp(value)
|
||||||
} else if match, value := optString(arg, "--border="); match {
|
} else if match, value := optString(arg, "--border="); match {
|
||||||
opts.BorderShape = parseBorder(value, false)
|
opts.BorderShape = parseBorder(value, false)
|
||||||
|
} else if match, value := optString(arg, "--border-label="); match {
|
||||||
|
opts.BorderLabel.label = value
|
||||||
|
} else if match, value := optString(arg, "--border-label-pos="); match {
|
||||||
|
parseLabelPosition(&opts.BorderLabel, value)
|
||||||
|
} else if match, value := optString(arg, "--preview-label="); match {
|
||||||
|
opts.PreviewLabel.label = value
|
||||||
|
} else if match, value := optString(arg, "--preview-label-pos="); match {
|
||||||
|
parseLabelPosition(&opts.PreviewLabel, value)
|
||||||
} else if match, value := optString(arg, "--prompt="); match {
|
} else if match, value := optString(arg, "--prompt="); match {
|
||||||
opts.Prompt = value
|
opts.Prompt = value
|
||||||
} else if match, value := optString(arg, "--pointer="); match {
|
} else if match, value := optString(arg, "--pointer="); match {
|
||||||
@@ -1613,6 +1698,8 @@ func parseOptions(opts *Options, allArgs []string) {
|
|||||||
opts.Layout = parseLayout(value)
|
opts.Layout = parseLayout(value)
|
||||||
} else if match, value := optString(arg, "--info="); match {
|
} else if match, value := optString(arg, "--info="); match {
|
||||||
opts.InfoStyle = parseInfoStyle(value)
|
opts.InfoStyle = parseInfoStyle(value)
|
||||||
|
} else if match, value := optString(arg, "--separator="); match {
|
||||||
|
opts.Separator = &value
|
||||||
} else if match, value := optString(arg, "--toggle-sort="); match {
|
} else if match, value := optString(arg, "--toggle-sort="); match {
|
||||||
parseToggleSort(opts.Keymap, value)
|
parseToggleSort(opts.Keymap, value)
|
||||||
} else if match, value := optString(arg, "--expect="); match {
|
} else if match, value := optString(arg, "--expect="); match {
|
||||||
|
152
src/terminal.go
152
src/terminal.go
@@ -107,13 +107,23 @@ type fitpad struct {
|
|||||||
|
|
||||||
var emptyLine = itemLine{}
|
var emptyLine = itemLine{}
|
||||||
|
|
||||||
|
type labelPrinter func(tui.Window, int)
|
||||||
|
|
||||||
// Terminal represents terminal input/output
|
// Terminal represents terminal input/output
|
||||||
type Terminal struct {
|
type Terminal struct {
|
||||||
initDelay time.Duration
|
initDelay time.Duration
|
||||||
infoStyle infoStyle
|
infoStyle infoStyle
|
||||||
|
separator labelPrinter
|
||||||
|
separatorLen int
|
||||||
spinner []string
|
spinner []string
|
||||||
prompt func()
|
prompt func()
|
||||||
promptLen int
|
promptLen int
|
||||||
|
borderLabel labelPrinter
|
||||||
|
borderLabelLen int
|
||||||
|
borderLabelOpts labelOpts
|
||||||
|
previewLabel labelPrinter
|
||||||
|
previewLabelLen int
|
||||||
|
previewLabelOpts labelOpts
|
||||||
pointer string
|
pointer string
|
||||||
pointerLen int
|
pointerLen int
|
||||||
pointerEmpty string
|
pointerEmpty string
|
||||||
@@ -514,6 +524,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
|||||||
t := Terminal{
|
t := Terminal{
|
||||||
initDelay: delay,
|
initDelay: delay,
|
||||||
infoStyle: opts.InfoStyle,
|
infoStyle: opts.InfoStyle,
|
||||||
|
separator: nil,
|
||||||
spinner: makeSpinner(opts.Unicode),
|
spinner: makeSpinner(opts.Unicode),
|
||||||
queryLen: [2]int{0, 0},
|
queryLen: [2]int{0, 0},
|
||||||
layout: opts.Layout,
|
layout: opts.Layout,
|
||||||
@@ -544,6 +555,10 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
|||||||
padding: opts.Padding,
|
padding: opts.Padding,
|
||||||
unicode: opts.Unicode,
|
unicode: opts.Unicode,
|
||||||
borderShape: opts.BorderShape,
|
borderShape: opts.BorderShape,
|
||||||
|
borderLabel: nil,
|
||||||
|
borderLabelOpts: opts.BorderLabel,
|
||||||
|
previewLabel: nil,
|
||||||
|
previewLabelOpts: opts.PreviewLabel,
|
||||||
cleanExit: opts.ClearOnExit,
|
cleanExit: opts.ClearOnExit,
|
||||||
paused: opts.Phony,
|
paused: opts.Phony,
|
||||||
strong: strongAttr,
|
strong: strongAttr,
|
||||||
@@ -587,13 +602,24 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
|||||||
// Pre-calculated empty pointer and marker signs
|
// Pre-calculated empty pointer and marker signs
|
||||||
t.pointerEmpty = strings.Repeat(" ", t.pointerLen)
|
t.pointerEmpty = strings.Repeat(" ", t.pointerLen)
|
||||||
t.markerEmpty = strings.Repeat(" ", t.markerLen)
|
t.markerEmpty = strings.Repeat(" ", t.markerLen)
|
||||||
|
t.borderLabel, t.borderLabelLen = t.ansiLabelPrinter(opts.BorderLabel.label, &tui.ColBorderLabel, false)
|
||||||
|
t.previewLabel, t.previewLabelLen = t.ansiLabelPrinter(opts.PreviewLabel.label, &tui.ColBorderLabel, false)
|
||||||
|
if opts.Separator == nil || len(*opts.Separator) > 0 {
|
||||||
|
bar := "─"
|
||||||
|
if opts.Separator != nil {
|
||||||
|
bar = *opts.Separator
|
||||||
|
} else if !t.unicode {
|
||||||
|
bar = "-"
|
||||||
|
}
|
||||||
|
t.separator, t.separatorLen = t.ansiLabelPrinter(bar, &tui.ColSeparator, true)
|
||||||
|
}
|
||||||
|
|
||||||
return &t
|
return &t
|
||||||
}
|
}
|
||||||
|
|
||||||
func borderLines(shape tui.BorderShape) int {
|
func borderLines(shape tui.BorderShape) int {
|
||||||
switch shape {
|
switch shape {
|
||||||
case tui.BorderHorizontal, tui.BorderRounded, tui.BorderSharp:
|
case tui.BorderHorizontal, tui.BorderRounded, tui.BorderSharp, tui.BorderBold, tui.BorderDouble:
|
||||||
return 2
|
return 2
|
||||||
case tui.BorderTop, tui.BorderBottom:
|
case tui.BorderTop, tui.BorderBottom:
|
||||||
return 1
|
return 1
|
||||||
@@ -617,6 +643,65 @@ func (t *Terminal) MaxFitAndPad(opts *Options) (int, int) {
|
|||||||
return fit, padHeight
|
return fit, padHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) ansiLabelPrinter(str string, color *tui.ColorPair, fill bool) (labelPrinter, int) {
|
||||||
|
// Nothing to do
|
||||||
|
if len(str) == 0 {
|
||||||
|
return nil, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract ANSI color codes
|
||||||
|
text, colors, _ := extractColor(str, nil, nil)
|
||||||
|
runes := []rune(text)
|
||||||
|
|
||||||
|
// Simpler printer for strings without ANSI colors or tab characters
|
||||||
|
if colors == nil && strings.IndexRune(str, '\t') < 0 {
|
||||||
|
length := runewidth.StringWidth(str)
|
||||||
|
if length == 0 {
|
||||||
|
return nil, 0
|
||||||
|
}
|
||||||
|
printFn := func(window tui.Window, limit int) {
|
||||||
|
if length > limit {
|
||||||
|
trimmedRunes, _ := t.trimRight(runes, limit)
|
||||||
|
window.CPrint(*color, string(trimmedRunes))
|
||||||
|
} else if fill {
|
||||||
|
window.CPrint(*color, util.RepeatToFill(str, length, limit))
|
||||||
|
} else {
|
||||||
|
window.CPrint(*color, str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return printFn, len(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Printer that correctly handles ANSI color codes and tab characters
|
||||||
|
item := &Item{text: util.RunesToChars(runes), colors: colors}
|
||||||
|
length := t.displayWidth(runes)
|
||||||
|
if length == 0 {
|
||||||
|
return nil, 0
|
||||||
|
}
|
||||||
|
result := Result{item: item}
|
||||||
|
var offsets []colorOffset
|
||||||
|
printFn := func(window tui.Window, limit int) {
|
||||||
|
if offsets == nil {
|
||||||
|
// tui.Col* are not initialized until renderer.Init()
|
||||||
|
offsets = result.colorOffsets(nil, t.theme, *color, *color, false)
|
||||||
|
}
|
||||||
|
for limit > 0 {
|
||||||
|
if length > limit {
|
||||||
|
trimmedRunes, _ := t.trimRight(runes, limit)
|
||||||
|
t.printColoredString(window, trimmedRunes, offsets, *color)
|
||||||
|
break
|
||||||
|
} else if fill {
|
||||||
|
t.printColoredString(window, runes, offsets, *color)
|
||||||
|
limit -= length
|
||||||
|
} else {
|
||||||
|
t.printColoredString(window, runes, offsets, *color)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return printFn, length
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Terminal) parsePrompt(prompt string) (func(), int) {
|
func (t *Terminal) parsePrompt(prompt string) (func(), int) {
|
||||||
var state *ansiState
|
var state *ansiState
|
||||||
trimmed, colors, _ := extractColor(prompt, state, nil)
|
trimmed, colors, _ := extractColor(prompt, state, nil)
|
||||||
@@ -813,7 +898,7 @@ func (t *Terminal) adjustMarginAndPadding() (int, int, [4]int, [4]int) {
|
|||||||
if idx == 3 {
|
if idx == 3 {
|
||||||
extraMargin[idx] += 2
|
extraMargin[idx] += 2
|
||||||
}
|
}
|
||||||
case tui.BorderRounded, tui.BorderSharp:
|
case tui.BorderRounded, tui.BorderSharp, tui.BorderBold, tui.BorderDouble:
|
||||||
extraMargin[idx] += 1 + idx%2
|
extraMargin[idx] += 1 + idx%2
|
||||||
}
|
}
|
||||||
marginInt[idx] = sizeSpecToInt(idx, sizeSpec) + extraMargin[idx]
|
marginInt[idx] = sizeSpecToInt(idx, sizeSpec) + extraMargin[idx]
|
||||||
@@ -905,7 +990,7 @@ func (t *Terminal) resizeWindows() {
|
|||||||
t.border = t.tui.NewWindow(
|
t.border = t.tui.NewWindow(
|
||||||
marginInt[0], marginInt[3], width+2, height,
|
marginInt[0], marginInt[3], width+2, height,
|
||||||
false, tui.MakeBorderStyle(tui.BorderRight, t.unicode))
|
false, tui.MakeBorderStyle(tui.BorderRight, t.unicode))
|
||||||
case tui.BorderRounded, tui.BorderSharp:
|
case tui.BorderRounded, tui.BorderSharp, tui.BorderBold, tui.BorderDouble:
|
||||||
t.border = t.tui.NewWindow(
|
t.border = t.tui.NewWindow(
|
||||||
marginInt[0]-1, marginInt[3]-2, width+4, height+2,
|
marginInt[0]-1, marginInt[3]-2, width+4, height+2,
|
||||||
false, tui.MakeBorderStyle(t.borderShape, t.unicode))
|
false, tui.MakeBorderStyle(t.borderShape, t.unicode))
|
||||||
@@ -935,7 +1020,7 @@ func (t *Terminal) resizeWindows() {
|
|||||||
}
|
}
|
||||||
t.pborder = t.tui.NewWindow(y, x, w, h, true, previewBorder)
|
t.pborder = t.tui.NewWindow(y, x, w, h, true, previewBorder)
|
||||||
switch previewOpts.border {
|
switch previewOpts.border {
|
||||||
case tui.BorderSharp, tui.BorderRounded:
|
case tui.BorderSharp, tui.BorderRounded, tui.BorderBold, tui.BorderDouble:
|
||||||
pwidth -= 4
|
pwidth -= 4
|
||||||
pheight -= 2
|
pheight -= 2
|
||||||
x += 2
|
x += 2
|
||||||
@@ -1015,6 +1100,34 @@ func (t *Terminal) resizeWindows() {
|
|||||||
width,
|
width,
|
||||||
height, false, noBorder)
|
height, false, noBorder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Print border label
|
||||||
|
printLabel := func(window tui.Window, render labelPrinter, opts labelOpts, length int, borderShape tui.BorderShape) {
|
||||||
|
if window == nil || render == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch borderShape {
|
||||||
|
case tui.BorderHorizontal, tui.BorderTop, tui.BorderBottom, tui.BorderRounded, tui.BorderSharp, tui.BorderBold, tui.BorderDouble:
|
||||||
|
var col int
|
||||||
|
if opts.column == 0 {
|
||||||
|
col = util.Max(0, (window.Width()-length)/2)
|
||||||
|
} else if opts.column < 0 {
|
||||||
|
col = util.Max(0, window.Width()+opts.column+1-length)
|
||||||
|
} else {
|
||||||
|
col = util.Min(opts.column-1, window.Width()-length)
|
||||||
|
}
|
||||||
|
row := 0
|
||||||
|
if borderShape == tui.BorderBottom || opts.bottom {
|
||||||
|
row = window.Height() - 1
|
||||||
|
}
|
||||||
|
window.Move(row, col)
|
||||||
|
render(window, window.Width())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printLabel(t.border, t.borderLabel, t.borderLabelOpts, t.borderLabelLen, t.borderShape)
|
||||||
|
printLabel(t.pborder, t.previewLabel, t.previewLabelOpts, t.previewLabelLen, t.previewOpts.border)
|
||||||
|
|
||||||
for i := 0; i < t.window.Height(); i++ {
|
for i := 0; i < t.window.Height(); i++ {
|
||||||
t.window.MoveAndClear(i, 0)
|
t.window.MoveAndClear(i, 0)
|
||||||
}
|
}
|
||||||
@@ -1154,8 +1267,15 @@ func (t *Terminal) printInfo() {
|
|||||||
if t.failed != nil && t.count == 0 {
|
if t.failed != nil && t.count == 0 {
|
||||||
output = fmt.Sprintf("[Command failed: %s]", *t.failed)
|
output = fmt.Sprintf("[Command failed: %s]", *t.failed)
|
||||||
}
|
}
|
||||||
output = t.trimMessage(output, t.window.Width()-pos)
|
maxWidth := t.window.Width() - pos
|
||||||
|
output = t.trimMessage(output, maxWidth)
|
||||||
t.window.CPrint(tui.ColInfo, output)
|
t.window.CPrint(tui.ColInfo, output)
|
||||||
|
|
||||||
|
fillLength := maxWidth - len(output) - 2
|
||||||
|
if t.separatorLen > 0 && fillLength > 0 {
|
||||||
|
t.window.CPrint(tui.ColSeparator, " ")
|
||||||
|
t.separator(t.window, fillLength)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terminal) printHeader() {
|
func (t *Terminal) printHeader() {
|
||||||
@@ -1394,6 +1514,11 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
|
|||||||
displayWidth = t.displayWidthWithLimit(text, 0, displayWidth)
|
displayWidth = t.displayWidthWithLimit(text, 0, displayWidth)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.printColoredString(t.window, text, offsets, colBase)
|
||||||
|
return displayWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) printColoredString(window tui.Window, text []rune, offsets []colorOffset, colBase tui.ColorPair) {
|
||||||
var index int32
|
var index int32
|
||||||
var substr string
|
var substr string
|
||||||
var prefixWidth int
|
var prefixWidth int
|
||||||
@@ -1403,11 +1528,11 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
|
|||||||
e := util.Constrain32(offset.offset[1], index, maxOffset)
|
e := util.Constrain32(offset.offset[1], index, maxOffset)
|
||||||
|
|
||||||
substr, prefixWidth = t.processTabs(text[index:b], prefixWidth)
|
substr, prefixWidth = t.processTabs(text[index:b], prefixWidth)
|
||||||
t.window.CPrint(colBase, substr)
|
window.CPrint(colBase, substr)
|
||||||
|
|
||||||
if b < e {
|
if b < e {
|
||||||
substr, prefixWidth = t.processTabs(text[b:e], prefixWidth)
|
substr, prefixWidth = t.processTabs(text[b:e], prefixWidth)
|
||||||
t.window.CPrint(offset.color, substr)
|
window.CPrint(offset.color, substr)
|
||||||
}
|
}
|
||||||
|
|
||||||
index = e
|
index = e
|
||||||
@@ -1417,9 +1542,8 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
|
|||||||
}
|
}
|
||||||
if index < maxOffset {
|
if index < maxOffset {
|
||||||
substr, _ = t.processTabs(text[index:], prefixWidth)
|
substr, _ = t.processTabs(text[index:], prefixWidth)
|
||||||
t.window.CPrint(colBase, substr)
|
window.CPrint(colBase, substr)
|
||||||
}
|
}
|
||||||
return displayWidth
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terminal) renderPreviewSpinner() {
|
func (t *Terminal) renderPreviewSpinner() {
|
||||||
@@ -2362,13 +2486,21 @@ func (t *Terminal) Loop() {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
looping := true
|
looping := true
|
||||||
|
_, startEvent := t.keymap[tui.Start.AsEvent()]
|
||||||
|
|
||||||
for looping {
|
for looping {
|
||||||
var newCommand *string
|
var newCommand *string
|
||||||
changed := false
|
changed := false
|
||||||
beof := false
|
beof := false
|
||||||
queryChanged := false
|
queryChanged := false
|
||||||
|
|
||||||
event := t.tui.GetChar()
|
var event tui.Event
|
||||||
|
if startEvent {
|
||||||
|
event = tui.Start.AsEvent()
|
||||||
|
startEvent = false
|
||||||
|
} else {
|
||||||
|
event = t.tui.GetChar()
|
||||||
|
}
|
||||||
|
|
||||||
t.mutex.Lock()
|
t.mutex.Lock()
|
||||||
previousInput := t.input
|
previousInput := t.input
|
||||||
|
@@ -712,7 +712,7 @@ func (r *LightRenderer) NewWindow(top int, left int, width int, height int, prev
|
|||||||
|
|
||||||
func (w *LightWindow) drawBorder() {
|
func (w *LightWindow) drawBorder() {
|
||||||
switch w.border.shape {
|
switch w.border.shape {
|
||||||
case BorderRounded, BorderSharp:
|
case BorderRounded, BorderSharp, BorderBold, BorderDouble:
|
||||||
w.drawBorderAround()
|
w.drawBorderAround()
|
||||||
case BorderHorizontal:
|
case BorderHorizontal:
|
||||||
w.drawBorderHorizontal(true, true)
|
w.drawBorderHorizontal(true, true)
|
||||||
|
@@ -75,8 +75,6 @@ func (w *TcellWindow) Refresh() {
|
|||||||
}
|
}
|
||||||
w.lastX = 0
|
w.lastX = 0
|
||||||
w.lastY = 0
|
w.lastY = 0
|
||||||
|
|
||||||
w.drawBorder()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *TcellWindow) FinishFill() {
|
func (w *TcellWindow) FinishFill() {
|
||||||
@@ -517,7 +515,7 @@ func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int,
|
|||||||
if preview {
|
if preview {
|
||||||
normal = ColPreview
|
normal = ColPreview
|
||||||
}
|
}
|
||||||
return &TcellWindow{
|
w := &TcellWindow{
|
||||||
color: r.theme.Colored,
|
color: r.theme.Colored,
|
||||||
preview: preview,
|
preview: preview,
|
||||||
top: top,
|
top: top,
|
||||||
@@ -526,6 +524,8 @@ func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int,
|
|||||||
height: height,
|
height: height,
|
||||||
normal: normal,
|
normal: normal,
|
||||||
borderStyle: borderStyle}
|
borderStyle: borderStyle}
|
||||||
|
w.drawBorder()
|
||||||
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *TcellWindow) Close() {
|
func (w *TcellWindow) Close() {
|
||||||
@@ -705,31 +705,31 @@ func (w *TcellWindow) drawBorder() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch shape {
|
switch shape {
|
||||||
case BorderRounded, BorderSharp, BorderHorizontal, BorderTop:
|
case BorderRounded, BorderSharp, BorderBold, BorderDouble, BorderHorizontal, BorderTop:
|
||||||
for x := left; x < right; x++ {
|
for x := left; x < right; x++ {
|
||||||
_screen.SetContent(x, top, w.borderStyle.horizontal, nil, style)
|
_screen.SetContent(x, top, w.borderStyle.horizontal, nil, style)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch shape {
|
switch shape {
|
||||||
case BorderRounded, BorderSharp, BorderHorizontal, BorderBottom:
|
case BorderRounded, BorderSharp, BorderBold, BorderDouble, BorderHorizontal, BorderBottom:
|
||||||
for x := left; x < right; x++ {
|
for x := left; x < right; x++ {
|
||||||
_screen.SetContent(x, bot-1, w.borderStyle.horizontal, nil, style)
|
_screen.SetContent(x, bot-1, w.borderStyle.horizontal, nil, style)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch shape {
|
switch shape {
|
||||||
case BorderRounded, BorderSharp, BorderVertical, BorderLeft:
|
case BorderRounded, BorderSharp, BorderBold, BorderDouble, BorderVertical, BorderLeft:
|
||||||
for y := top; y < bot; y++ {
|
for y := top; y < bot; y++ {
|
||||||
_screen.SetContent(left, y, w.borderStyle.vertical, nil, style)
|
_screen.SetContent(left, y, w.borderStyle.vertical, nil, style)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch shape {
|
switch shape {
|
||||||
case BorderRounded, BorderSharp, BorderVertical, BorderRight:
|
case BorderRounded, BorderSharp, BorderBold, BorderDouble, BorderVertical, BorderRight:
|
||||||
for y := top; y < bot; y++ {
|
for y := top; y < bot; y++ {
|
||||||
_screen.SetContent(right-1, y, w.borderStyle.vertical, nil, style)
|
_screen.SetContent(right-1, y, w.borderStyle.vertical, nil, style)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch shape {
|
switch shape {
|
||||||
case BorderRounded, BorderSharp:
|
case BorderRounded, BorderSharp, BorderBold, BorderDouble:
|
||||||
_screen.SetContent(left, top, w.borderStyle.topLeft, nil, style)
|
_screen.SetContent(left, top, w.borderStyle.topLeft, nil, style)
|
||||||
_screen.SetContent(right-1, top, w.borderStyle.topRight, nil, style)
|
_screen.SetContent(right-1, top, w.borderStyle.topRight, nil, style)
|
||||||
_screen.SetContent(left, bot-1, w.borderStyle.bottomLeft, nil, style)
|
_screen.SetContent(left, bot-1, w.borderStyle.bottomLeft, nil, style)
|
||||||
|
@@ -90,6 +90,7 @@ const (
|
|||||||
|
|
||||||
Change
|
Change
|
||||||
BackwardEOF
|
BackwardEOF
|
||||||
|
Start
|
||||||
|
|
||||||
AltBS
|
AltBS
|
||||||
|
|
||||||
@@ -266,7 +267,9 @@ type ColorTheme struct {
|
|||||||
Cursor ColorAttr
|
Cursor ColorAttr
|
||||||
Selected ColorAttr
|
Selected ColorAttr
|
||||||
Header ColorAttr
|
Header ColorAttr
|
||||||
|
Separator ColorAttr
|
||||||
Border ColorAttr
|
Border ColorAttr
|
||||||
|
BorderLabel ColorAttr
|
||||||
}
|
}
|
||||||
|
|
||||||
type Event struct {
|
type Event struct {
|
||||||
@@ -291,6 +294,8 @@ const (
|
|||||||
BorderNone BorderShape = iota
|
BorderNone BorderShape = iota
|
||||||
BorderRounded
|
BorderRounded
|
||||||
BorderSharp
|
BorderSharp
|
||||||
|
BorderBold
|
||||||
|
BorderDouble
|
||||||
BorderHorizontal
|
BorderHorizontal
|
||||||
BorderVertical
|
BorderVertical
|
||||||
BorderTop
|
BorderTop
|
||||||
@@ -312,18 +317,19 @@ type BorderStyle struct {
|
|||||||
type BorderCharacter int
|
type BorderCharacter int
|
||||||
|
|
||||||
func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
|
func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
|
||||||
if unicode {
|
if !unicode {
|
||||||
if shape == BorderRounded {
|
return BorderStyle{
|
||||||
return BorderStyle{
|
shape: shape,
|
||||||
shape: shape,
|
horizontal: '-',
|
||||||
horizontal: '─',
|
vertical: '|',
|
||||||
vertical: '│',
|
topLeft: '+',
|
||||||
topLeft: '╭',
|
topRight: '+',
|
||||||
topRight: '╮',
|
bottomLeft: '+',
|
||||||
bottomLeft: '╰',
|
bottomRight: '+',
|
||||||
bottomRight: '╯',
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
switch shape {
|
||||||
|
case BorderSharp:
|
||||||
return BorderStyle{
|
return BorderStyle{
|
||||||
shape: shape,
|
shape: shape,
|
||||||
horizontal: '─',
|
horizontal: '─',
|
||||||
@@ -333,15 +339,35 @@ func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
|
|||||||
bottomLeft: '└',
|
bottomLeft: '└',
|
||||||
bottomRight: '┘',
|
bottomRight: '┘',
|
||||||
}
|
}
|
||||||
|
case BorderBold:
|
||||||
|
return BorderStyle{
|
||||||
|
shape: shape,
|
||||||
|
horizontal: '━',
|
||||||
|
vertical: '┃',
|
||||||
|
topLeft: '┏',
|
||||||
|
topRight: '┓',
|
||||||
|
bottomLeft: '┗',
|
||||||
|
bottomRight: '┛',
|
||||||
|
}
|
||||||
|
case BorderDouble:
|
||||||
|
return BorderStyle{
|
||||||
|
shape: shape,
|
||||||
|
horizontal: '═',
|
||||||
|
vertical: '║',
|
||||||
|
topLeft: '╔',
|
||||||
|
topRight: '╗',
|
||||||
|
bottomLeft: '╚',
|
||||||
|
bottomRight: '╝',
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return BorderStyle{
|
return BorderStyle{
|
||||||
shape: shape,
|
shape: shape,
|
||||||
horizontal: '-',
|
horizontal: '─',
|
||||||
vertical: '|',
|
vertical: '│',
|
||||||
topLeft: '+',
|
topLeft: '╭',
|
||||||
topRight: '+',
|
topRight: '╮',
|
||||||
bottomLeft: '+',
|
bottomLeft: '╰',
|
||||||
bottomRight: '+',
|
bottomRight: '╯',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -437,9 +463,11 @@ var (
|
|||||||
ColSpinner ColorPair
|
ColSpinner ColorPair
|
||||||
ColInfo ColorPair
|
ColInfo ColorPair
|
||||||
ColHeader ColorPair
|
ColHeader ColorPair
|
||||||
|
ColSeparator ColorPair
|
||||||
ColBorder ColorPair
|
ColBorder ColorPair
|
||||||
ColPreview ColorPair
|
ColPreview ColorPair
|
||||||
ColPreviewBorder ColorPair
|
ColPreviewBorder ColorPair
|
||||||
|
ColBorderLabel ColorPair
|
||||||
)
|
)
|
||||||
|
|
||||||
func EmptyTheme() *ColorTheme {
|
func EmptyTheme() *ColorTheme {
|
||||||
@@ -462,7 +490,10 @@ func EmptyTheme() *ColorTheme {
|
|||||||
Cursor: ColorAttr{colUndefined, AttrUndefined},
|
Cursor: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Selected: ColorAttr{colUndefined, AttrUndefined},
|
Selected: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Header: ColorAttr{colUndefined, AttrUndefined},
|
Header: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Border: ColorAttr{colUndefined, AttrUndefined}}
|
Separator: ColorAttr{colUndefined, AttrUndefined},
|
||||||
|
Border: ColorAttr{colUndefined, AttrUndefined},
|
||||||
|
BorderLabel: ColorAttr{colUndefined, AttrUndefined},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NoColorTheme() *ColorTheme {
|
func NoColorTheme() *ColorTheme {
|
||||||
@@ -485,7 +516,10 @@ func NoColorTheme() *ColorTheme {
|
|||||||
Cursor: ColorAttr{colDefault, AttrRegular},
|
Cursor: ColorAttr{colDefault, AttrRegular},
|
||||||
Selected: ColorAttr{colDefault, AttrRegular},
|
Selected: ColorAttr{colDefault, AttrRegular},
|
||||||
Header: ColorAttr{colDefault, AttrRegular},
|
Header: ColorAttr{colDefault, AttrRegular},
|
||||||
Border: ColorAttr{colDefault, AttrRegular}}
|
Separator: ColorAttr{colDefault, AttrRegular},
|
||||||
|
Border: ColorAttr{colDefault, AttrRegular},
|
||||||
|
BorderLabel: ColorAttr{colDefault, AttrRegular},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func errorExit(message string) {
|
func errorExit(message string) {
|
||||||
@@ -513,7 +547,10 @@ func init() {
|
|||||||
Cursor: ColorAttr{colRed, AttrUndefined},
|
Cursor: ColorAttr{colRed, AttrUndefined},
|
||||||
Selected: ColorAttr{colMagenta, AttrUndefined},
|
Selected: ColorAttr{colMagenta, AttrUndefined},
|
||||||
Header: ColorAttr{colCyan, AttrUndefined},
|
Header: ColorAttr{colCyan, AttrUndefined},
|
||||||
Border: ColorAttr{colBlack, AttrUndefined}}
|
Separator: ColorAttr{colBlack, AttrUndefined},
|
||||||
|
Border: ColorAttr{colBlack, AttrUndefined},
|
||||||
|
BorderLabel: ColorAttr{colWhite, AttrUndefined},
|
||||||
|
}
|
||||||
Dark256 = &ColorTheme{
|
Dark256 = &ColorTheme{
|
||||||
Colored: true,
|
Colored: true,
|
||||||
Input: ColorAttr{colDefault, AttrUndefined},
|
Input: ColorAttr{colDefault, AttrUndefined},
|
||||||
@@ -533,7 +570,10 @@ func init() {
|
|||||||
Cursor: ColorAttr{161, AttrUndefined},
|
Cursor: ColorAttr{161, AttrUndefined},
|
||||||
Selected: ColorAttr{168, AttrUndefined},
|
Selected: ColorAttr{168, AttrUndefined},
|
||||||
Header: ColorAttr{109, AttrUndefined},
|
Header: ColorAttr{109, AttrUndefined},
|
||||||
Border: ColorAttr{59, AttrUndefined}}
|
Separator: ColorAttr{59, AttrUndefined},
|
||||||
|
Border: ColorAttr{59, AttrUndefined},
|
||||||
|
BorderLabel: ColorAttr{145, AttrUndefined},
|
||||||
|
}
|
||||||
Light256 = &ColorTheme{
|
Light256 = &ColorTheme{
|
||||||
Colored: true,
|
Colored: true,
|
||||||
Input: ColorAttr{colDefault, AttrUndefined},
|
Input: ColorAttr{colDefault, AttrUndefined},
|
||||||
@@ -553,7 +593,10 @@ func init() {
|
|||||||
Cursor: ColorAttr{161, AttrUndefined},
|
Cursor: ColorAttr{161, AttrUndefined},
|
||||||
Selected: ColorAttr{168, AttrUndefined},
|
Selected: ColorAttr{168, AttrUndefined},
|
||||||
Header: ColorAttr{31, AttrUndefined},
|
Header: ColorAttr{31, AttrUndefined},
|
||||||
Border: ColorAttr{145, AttrUndefined}}
|
Separator: ColorAttr{145, AttrUndefined},
|
||||||
|
Border: ColorAttr{145, AttrUndefined},
|
||||||
|
BorderLabel: ColorAttr{59, AttrUndefined},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func initTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool) {
|
func initTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool) {
|
||||||
@@ -588,7 +631,9 @@ func initTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool) {
|
|||||||
theme.Cursor = o(baseTheme.Cursor, theme.Cursor)
|
theme.Cursor = o(baseTheme.Cursor, theme.Cursor)
|
||||||
theme.Selected = o(baseTheme.Selected, theme.Selected)
|
theme.Selected = o(baseTheme.Selected, theme.Selected)
|
||||||
theme.Header = o(baseTheme.Header, theme.Header)
|
theme.Header = o(baseTheme.Header, theme.Header)
|
||||||
|
theme.Separator = o(baseTheme.Separator, theme.Separator)
|
||||||
theme.Border = o(baseTheme.Border, theme.Border)
|
theme.Border = o(baseTheme.Border, theme.Border)
|
||||||
|
theme.BorderLabel = o(baseTheme.BorderLabel, theme.BorderLabel)
|
||||||
|
|
||||||
initPalette(theme)
|
initPalette(theme)
|
||||||
}
|
}
|
||||||
@@ -620,7 +665,9 @@ func initPalette(theme *ColorTheme) {
|
|||||||
ColSpinner = pair(theme.Spinner, theme.Bg)
|
ColSpinner = pair(theme.Spinner, theme.Bg)
|
||||||
ColInfo = pair(theme.Info, theme.Bg)
|
ColInfo = pair(theme.Info, theme.Bg)
|
||||||
ColHeader = pair(theme.Header, theme.Bg)
|
ColHeader = pair(theme.Header, theme.Bg)
|
||||||
|
ColSeparator = pair(theme.Separator, theme.Bg)
|
||||||
ColBorder = pair(theme.Border, theme.Bg)
|
ColBorder = pair(theme.Border, theme.Bg)
|
||||||
|
ColBorderLabel = pair(theme.BorderLabel, theme.Bg)
|
||||||
ColPreview = pair(theme.PreviewFg, theme.PreviewBg)
|
ColPreview = pair(theme.PreviewFg, theme.PreviewBg)
|
||||||
ColPreviewBorder = pair(theme.Border, theme.PreviewBg)
|
ColPreviewBorder = pair(theme.Border, theme.PreviewBg)
|
||||||
}
|
}
|
||||||
|
@@ -153,3 +153,23 @@ func Once(nextResponse bool) func() bool {
|
|||||||
return prevState
|
return prevState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RepeatToFill repeats the given string to fill the given width
|
||||||
|
func RepeatToFill(str string, length int, limit int) string {
|
||||||
|
times := limit / length
|
||||||
|
rest := limit % length
|
||||||
|
output := strings.Repeat(str, times)
|
||||||
|
if rest > 0 {
|
||||||
|
for _, r := range str {
|
||||||
|
rest -= runewidth.RuneWidth(r)
|
||||||
|
if rest < 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
output += string(r)
|
||||||
|
if rest == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
@@ -192,6 +192,13 @@ class TestBase < Minitest::Test
|
|||||||
tmux.prepare
|
tmux.prepare
|
||||||
end
|
end
|
||||||
|
|
||||||
|
alias assert_equal_org assert_equal
|
||||||
|
def assert_equal(expected, actual)
|
||||||
|
# Ignore info separator
|
||||||
|
actual = actual&.sub(/\s*─+$/, '') if actual.is_a?(String) && actual&.match?(%r{\d+/\d+})
|
||||||
|
assert_equal_org(expected, actual)
|
||||||
|
end
|
||||||
|
|
||||||
def fzf(*opts)
|
def fzf(*opts)
|
||||||
fzf!(*opts) + " > #{tempname}.tmp; mv #{tempname}.tmp #{tempname}"
|
fzf!(*opts) + " > #{tempname}.tmp; mv #{tempname}.tmp #{tempname}"
|
||||||
end
|
end
|
||||||
@@ -255,7 +262,7 @@ class TestGoFZF < TestBase
|
|||||||
|
|
||||||
def test_fzf_default_command_failure
|
def test_fzf_default_command_failure
|
||||||
tmux.send_keys fzf.sub('FZF_DEFAULT_COMMAND=', 'FZF_DEFAULT_COMMAND=false'), :Enter
|
tmux.send_keys fzf.sub('FZF_DEFAULT_COMMAND=', 'FZF_DEFAULT_COMMAND=false'), :Enter
|
||||||
tmux.until { |lines| assert_equal ' [Command failed: false]', lines[-2] }
|
tmux.until { |lines| assert_includes lines[-2], ' [Command failed: false] ─' }
|
||||||
tmux.send_keys :Enter
|
tmux.send_keys :Enter
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -447,7 +454,7 @@ class TestGoFZF < TestBase
|
|||||||
def test_scroll
|
def test_scroll
|
||||||
[true, false].each do |rev|
|
[true, false].each do |rev|
|
||||||
tmux.send_keys "seq 1 100 | #{fzf(rev && :reverse)}", :Enter
|
tmux.send_keys "seq 1 100 | #{fzf(rev && :reverse)}", :Enter
|
||||||
tmux.until { |lines| assert_includes lines, ' 100/100' }
|
tmux.until { |lines| assert_equal ' 100/100', lines[rev ? 1 : -2] }
|
||||||
tmux.send_keys(*Array.new(110) { rev ? :Down : :Up })
|
tmux.send_keys(*Array.new(110) { rev ? :Down : :Up })
|
||||||
tmux.until { |lines| assert_includes lines, '> 100' }
|
tmux.until { |lines| assert_includes lines, '> 100' }
|
||||||
tmux.send_keys :Enter
|
tmux.send_keys :Enter
|
||||||
@@ -2249,7 +2256,7 @@ class TestGoFZF < TestBase
|
|||||||
def assert_block(expected, lines)
|
def assert_block(expected, lines)
|
||||||
cols = expected.lines.map(&:chomp).map(&:length).max
|
cols = expected.lines.map(&:chomp).map(&:length).max
|
||||||
actual = lines.reverse.take(expected.lines.length).reverse.map { _1[0, cols].rstrip + "\n" }.join
|
actual = lines.reverse.take(expected.lines.length).reverse.map { _1[0, cols].rstrip + "\n" }.join
|
||||||
assert_equal expected, actual
|
assert_equal_org expected, actual
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_height_range_fit
|
def test_height_range_fit
|
||||||
@@ -2297,7 +2304,7 @@ class TestGoFZF < TestBase
|
|||||||
│ 2
|
│ 2
|
||||||
│ 1
|
│ 1
|
||||||
│ hello
|
│ hello
|
||||||
│ 1/1
|
│ 1/1 ─
|
||||||
│ >
|
│ >
|
||||||
│
|
│
|
||||||
└─────────
|
└─────────
|
||||||
@@ -2314,7 +2321,7 @@ class TestGoFZF < TestBase
|
|||||||
│ 3 │ 1
|
│ 3 │ 1
|
||||||
│ │ hello
|
│ │ hello
|
||||||
│ │ world
|
│ │ world
|
||||||
│ │ 1/1
|
│ │ 1/1 ─
|
||||||
│ │>
|
│ │>
|
||||||
│
|
│
|
||||||
OUTPUT
|
OUTPUT
|
||||||
@@ -2332,6 +2339,71 @@ class TestGoFZF < TestBase
|
|||||||
OUTPUT
|
OUTPUT
|
||||||
tmux.until { assert_block(expected, _1) }
|
tmux.until { assert_block(expected, _1) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_start_event
|
||||||
|
tmux.send_keys 'seq 100 | fzf --multi --sync --preview-window border-none --bind "start:select-all+last+preview(echo welcome)"', :Enter
|
||||||
|
tmux.until do |lines|
|
||||||
|
assert_match(/>100.*welcome/, lines[0])
|
||||||
|
assert_includes(lines[-2], '100/100 (100)')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_labels_center
|
||||||
|
tmux.send_keys ': | fzf --border --border-label foobar --preview : --preview-label barfoo', :Enter
|
||||||
|
tmux.until do
|
||||||
|
assert_includes(_1[0], '─foobar─')
|
||||||
|
assert_includes(_1[1], '─barfoo─')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_labels_left
|
||||||
|
tmux.send_keys ': | fzf --border --border-label foobar --border-label-pos 2 --preview : --preview-label barfoo --preview-label-pos 2', :Enter
|
||||||
|
tmux.until do
|
||||||
|
assert_includes(_1[0], '╭foobar─')
|
||||||
|
assert_includes(_1[1], '╭barfoo─')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_labels_right
|
||||||
|
tmux.send_keys ': | fzf --border --border-label foobar --border-label-pos -2 --preview : --preview-label barfoo --preview-label-pos -2', :Enter
|
||||||
|
tmux.until do
|
||||||
|
assert_includes(_1[0], '─foobar╮')
|
||||||
|
assert_includes(_1[1], '─barfoo╮')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_labels_bottom
|
||||||
|
tmux.send_keys ': | fzf --border --border-label foobar --border-label-pos 2:bottom --preview : --preview-label barfoo --preview-label-pos -2:bottom', :Enter
|
||||||
|
tmux.until do
|
||||||
|
assert_includes(_1[-1], '╰foobar─')
|
||||||
|
assert_includes(_1[-2], '─barfoo╯')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_info_separator_unicode
|
||||||
|
tmux.send_keys 'seq 100 | fzf -q55', :Enter
|
||||||
|
tmux.until { assert_includes(_1[-2], ' 1/100 ─') }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_info_separator_no_unicode
|
||||||
|
tmux.send_keys 'seq 100 | fzf -q55 --no-unicode', :Enter
|
||||||
|
tmux.until { assert_includes(_1[-2], ' 1/100 -') }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_info_separator_repeat
|
||||||
|
tmux.send_keys 'seq 100 | fzf -q55 --separator _-', :Enter
|
||||||
|
tmux.until { assert_includes(_1[-2], ' 1/100 _-_-') }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_info_separator_ansi_colors_and_tabs
|
||||||
|
tmux.send_keys "seq 100 | fzf -q55 --tabstop 4 --separator $'\\x1b[33ma\\tb'", :Enter
|
||||||
|
tmux.until { assert_includes(_1[-2], ' 1/100 a ba ba') }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_info_no_separator
|
||||||
|
tmux.send_keys 'seq 100 | fzf -q55 --no-separator', :Enter
|
||||||
|
tmux.until { assert(_1[-2] == ' 1/100') }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
module TestShell
|
module TestShell
|
||||||
@@ -2758,6 +2830,7 @@ class TestFish < TestBase
|
|||||||
end
|
end
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
|
set -u
|
||||||
PS1= PROMPT_COMMAND= HISTFILE= HISTSIZE=100
|
PS1= PROMPT_COMMAND= HISTFILE= HISTSIZE=100
|
||||||
unset <%= UNSETS.join(' ') %>
|
unset <%= UNSETS.join(' ') %>
|
||||||
unset $(env | sed -n /^_fzf_orig/s/=.*//p)
|
unset $(env | sed -n /^_fzf_orig/s/=.*//p)
|
||||||
@@ -2801,8 +2874,8 @@ _fzf_complete_g_post() {
|
|||||||
awk '{print "g" $0 $0}'
|
awk '{print "g" $0 $0}'
|
||||||
}
|
}
|
||||||
|
|
||||||
[ -n "$BASH" ] && complete -F _fzf_complete_f -o default -o bashdefault f
|
[ -n "${BASH-}" ] && complete -F _fzf_complete_f -o default -o bashdefault f
|
||||||
[ -n "$BASH" ] && complete -F _fzf_complete_g -o default -o bashdefault g
|
[ -n "${BASH-}" ] && complete -F _fzf_complete_g -o default -o bashdefault g
|
||||||
|
|
||||||
_comprun() {
|
_comprun() {
|
||||||
local command=$1
|
local command=$1
|
||||||
|
Reference in New Issue
Block a user