mirror of
https://github.com/junegunn/fzf.git
synced 2025-11-11 04:43:48 -05:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
416aff86e9 | ||
|
|
59dc7f178f | ||
|
|
a3c9f8bfee | ||
|
|
5546c65491 | ||
|
|
f2179f015c | ||
|
|
9a53d84b9c | ||
|
|
0a8ff7899c | ||
|
|
f9d7877d8b | ||
|
|
9fe9976591 | ||
|
|
de1824f71d | ||
|
|
19a9296c47 | ||
|
|
49967f3d45 | ||
|
|
978b6254c7 | ||
|
|
1afd143810 |
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/depsreview.yaml
vendored
2
.github/workflows/depsreview.yaml
vendored
@@ -9,6 +9,6 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: 'Checkout Repository'
|
- name: 'Checkout Repository'
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
- name: 'Dependency Review'
|
- name: 'Dependency Review'
|
||||||
uses: actions/dependency-review-action@v4
|
uses: actions/dependency-review-action@v4
|
||||||
|
|||||||
2
.github/workflows/linux.yml
vendored
2
.github/workflows/linux.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/macos.yml
vendored
2
.github/workflows/macos.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/sponsors.yml
vendored
2
.github/workflows/sponsors.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout 🛎️
|
- name: Checkout 🛎️
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Generate Sponsors 💖
|
- name: Generate Sponsors 💖
|
||||||
uses: JamesIves/github-sponsors-readme-action@v1
|
uses: JamesIves/github-sponsors-readme-action@v1
|
||||||
|
|||||||
2
.github/workflows/typos.yml
vendored
2
.github/workflows/typos.yml
vendored
@@ -6,5 +6,5 @@ jobs:
|
|||||||
name: Spell Check with Typos
|
name: Spell Check with Typos
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- uses: crate-ci/typos@v1.29.4
|
- uses: crate-ci/typos@v1.29.4
|
||||||
|
|||||||
11
CHANGELOG.md
11
CHANGELOG.md
@@ -1,6 +1,17 @@
|
|||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
0.65.2
|
||||||
|
------
|
||||||
|
- Bug fixes and improvements
|
||||||
|
- Fix incorrect truncation of `--info-command` with `--info=inline-right` (#4479)
|
||||||
|
- [install] Support old uname in macOS (#4492)
|
||||||
|
- [bash 3] Fix `CTRL-T` and `ALT-C` to preserve the last yank (#4496)
|
||||||
|
- Do not unset `FZF_DEFAULT_*` variables when using winpty (#4497) (#4400)
|
||||||
|
- Fix rendering of items with tabs when using a non-default ellipsis (#4505)
|
||||||
|
- **This is the final release to support Windows 7.**
|
||||||
|
- Future versions will be built with the latest Go toolchain, which has dropped support for Windows 7.
|
||||||
|
|
||||||
0.65.1
|
0.65.1
|
||||||
------
|
------
|
||||||
- Fixed incorrect `$FZF_CLICK_HEADER_WORD` and `$FZF_CLICK_FOOTER_WORD` when the header or footer contains ANSI escape sequences and tab characters.
|
- Fixed incorrect `$FZF_CLICK_HEADER_WORD` and `$FZF_CLICK_FOOTER_WORD` when the header or footer contains ANSI escape sequences and tab characters.
|
||||||
|
|||||||
4
install
4
install
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
set -u
|
set -u
|
||||||
|
|
||||||
version=0.65.1
|
version=0.65.2
|
||||||
auto_completion=
|
auto_completion=
|
||||||
key_bindings=
|
key_bindings=
|
||||||
update_config=2
|
update_config=2
|
||||||
@@ -164,7 +164,7 @@ download() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Try to download binary executable
|
# Try to download binary executable
|
||||||
archi=$(uname -smo)
|
archi=$(uname -smo 2>/dev/null || uname -sm)
|
||||||
binary_available=1
|
binary_available=1
|
||||||
binary_error=""
|
binary_error=""
|
||||||
case "$archi" in
|
case "$archi" in
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
$version="0.65.1"
|
$version="0.65.2"
|
||||||
|
|
||||||
$fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition
|
$fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
..
|
..
|
||||||
.TH fzf\-tmux 1 "Aug 2025" "fzf 0.65.1" "fzf\-tmux - open fzf in tmux split pane"
|
.TH fzf\-tmux 1 "Aug 2025" "fzf 0.65.2" "fzf\-tmux - open fzf in tmux split pane"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fzf\-tmux - open fzf in tmux split pane
|
fzf\-tmux - open fzf in tmux split pane
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
..
|
..
|
||||||
.TH fzf 1 "Aug 2025" "fzf 0.65.1" "fzf - a command-line fuzzy finder"
|
.TH fzf 1 "Aug 2025" "fzf 0.65.2" "fzf - a command-line fuzzy finder"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fzf - a command-line fuzzy finder
|
fzf - a command-line fuzzy finder
|
||||||
@@ -1046,7 +1046,7 @@ are not affected by \fB\-\-with\-nth\fR. ANSI color codes are processed even whe
|
|||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BI "\-\-footer\-border" [=STYLE]
|
.BI "\-\-footer\-border" [=STYLE]
|
||||||
Draw border around the header section. \fBline\fR style draws a single
|
Draw border around the footer section. \fBline\fR style draws a single
|
||||||
separator line between the footer and the list section.
|
separator line between the footer and the list section.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ bind -m emacs-standard '"\C-z": vi-editing-mode'
|
|||||||
if (( BASH_VERSINFO[0] < 4 )); then
|
if (( BASH_VERSINFO[0] < 4 )); then
|
||||||
# CTRL-T - Paste the selected file path into the command line
|
# CTRL-T - Paste the selected file path into the command line
|
||||||
if [[ "${FZF_CTRL_T_COMMAND-x}" != "" ]]; then
|
if [[ "${FZF_CTRL_T_COMMAND-x}" != "" ]]; then
|
||||||
bind -m emacs-standard '"\C-t": " \C-b\C-k \C-u`__fzf_select__`\e\C-e\er\C-a\C-y\C-h\C-e\e \C-y\ey\C-x\C-x\C-f"'
|
bind -m emacs-standard '"\C-t": " \C-b\C-k \C-u`__fzf_select__`\e\C-e\er\C-a\C-y\C-h\C-e\e \C-y\ey\C-x\C-x\C-f\C-y\ey\C-_"'
|
||||||
bind -m vi-command '"\C-t": "\C-z\C-t\C-z"'
|
bind -m vi-command '"\C-t": "\C-z\C-t\C-z"'
|
||||||
bind -m vi-insert '"\C-t": "\C-z\C-t\C-z"'
|
bind -m vi-insert '"\C-t": "\C-z\C-t\C-z"'
|
||||||
fi
|
fi
|
||||||
@@ -150,7 +150,7 @@ fi
|
|||||||
|
|
||||||
# ALT-C - cd into the selected directory
|
# ALT-C - cd into the selected directory
|
||||||
if [[ "${FZF_ALT_C_COMMAND-x}" != "" ]]; then
|
if [[ "${FZF_ALT_C_COMMAND-x}" != "" ]]; then
|
||||||
bind -m emacs-standard '"\ec": " \C-b\C-k \C-u`__fzf_cd__`\e\C-e\er\C-m\C-y\C-h\e \C-y\ey\C-x\C-x\C-d"'
|
bind -m emacs-standard '"\ec": " \C-b\C-k \C-u`__fzf_cd__`\e\C-e\er\C-m\C-y\C-h\e \C-y\ey\C-x\C-x\C-d\C-y\ey\C-_"'
|
||||||
bind -m vi-command '"\ec": "\C-z\ec\C-z"'
|
bind -m vi-command '"\ec": "\C-z\ec\C-z"'
|
||||||
bind -m vi-insert '"\ec": "\C-z\ec\C-z"'
|
bind -m vi-insert '"\ec": "\C-z\ec\C-z"'
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ func TestChunkList(t *testing.T) {
|
|||||||
|
|
||||||
// Add more data
|
// Add more data
|
||||||
for i := 0; i < chunkSize*2; i++ {
|
for i := 0; i < chunkSize*2; i++ {
|
||||||
cl.Push([]byte(fmt.Sprintf("item %d", i)))
|
cl.Push(fmt.Appendf(nil, "item %d", i))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Previous snapshot should remain the same
|
// Previous snapshot should remain the same
|
||||||
@@ -86,7 +86,7 @@ func TestChunkListTail(t *testing.T) {
|
|||||||
})
|
})
|
||||||
total := chunkSize*2 + chunkSize/2
|
total := chunkSize*2 + chunkSize/2
|
||||||
for i := 0; i < total; i++ {
|
for i := 0; i < total; i++ {
|
||||||
cl.Push([]byte(fmt.Sprintf("item %d", i)))
|
cl.Push(fmt.Appendf(nil, "item %d", i))
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshot, count, changed := cl.Snapshot(0)
|
snapshot, count, changed := cl.Snapshot(0)
|
||||||
|
|||||||
@@ -90,11 +90,12 @@ func runProxy(commandPrefix string, cmdBuilder func(temp string, needBash bool)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// * Write the command to a temporary file and run it with sh to ensure POSIX compliance.
|
// Write the command to a temporary file and run it with sh to ensure POSIX compliance.
|
||||||
// * Nullify FZF_DEFAULT_* variables as tmux popup may inject them even when undefined.
|
var exports []string
|
||||||
exports := []string{"FZF_DEFAULT_COMMAND=", "FZF_DEFAULT_OPTS=", "FZF_DEFAULT_OPTS_FILE="}
|
|
||||||
needBash := false
|
needBash := false
|
||||||
if withExports {
|
if withExports {
|
||||||
|
// Nullify FZF_DEFAULT_* variables as tmux popup may inject them even when undefined.
|
||||||
|
exports = []string{"FZF_DEFAULT_COMMAND=", "FZF_DEFAULT_OPTS=", "FZF_DEFAULT_OPTS_FILE="}
|
||||||
validIdentifier := regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)
|
validIdentifier := regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)
|
||||||
for _, pairStr := range os.Environ() {
|
for _, pairStr := range os.Environ() {
|
||||||
pair := strings.SplitN(pairStr, "=", 2)
|
pair := strings.SplitN(pairStr, "=", 2)
|
||||||
|
|||||||
@@ -285,7 +285,7 @@ func (r *Reader) readFiles(roots []string, opts walkerOpts, ignores []string) bo
|
|||||||
if strings.HasPrefix(ignore, sep) {
|
if strings.HasPrefix(ignore, sep) {
|
||||||
ignoresSuffix = append(ignoresSuffix, ignore)
|
ignoresSuffix = append(ignoresSuffix, ignore)
|
||||||
} else {
|
} else {
|
||||||
// 'foo/bar' should match match
|
// 'foo/bar' should match
|
||||||
// * 'foo/bar'
|
// * 'foo/bar'
|
||||||
// * 'baz/foo/bar'
|
// * 'baz/foo/bar'
|
||||||
// * but NOT 'bazfoo/bar'
|
// * but NOT 'bazfoo/bar'
|
||||||
|
|||||||
@@ -128,9 +128,9 @@ func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, t
|
|||||||
|
|
||||||
// No ANSI codes
|
// No ANSI codes
|
||||||
if len(itemColors) == 0 && len(nthOffsets) == 0 {
|
if len(itemColors) == 0 && len(nthOffsets) == 0 {
|
||||||
var offsets []colorOffset
|
offsets := make([]colorOffset, len(matchOffsets))
|
||||||
for _, off := range matchOffsets {
|
for i, off := range matchOffsets {
|
||||||
offsets = append(offsets, colorOffset{offset: [2]int32{off[0], off[1]}, color: colMatch, match: true})
|
offsets[i] = colorOffset{offset: [2]int32{off[0], off[1]}, color: colMatch, match: true}
|
||||||
}
|
}
|
||||||
return offsets
|
return offsets
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1394,7 +1394,7 @@ func (t *Terminal) ansiLabelPrinter(str string, color *tui.ColorPair, fill bool)
|
|||||||
if !fill {
|
if !fill {
|
||||||
ellipsis, ellipsisWidth = util.Truncate(t.ellipsis, limit)
|
ellipsis, ellipsisWidth = util.Truncate(t.ellipsis, limit)
|
||||||
}
|
}
|
||||||
if length > limit-ellipsisWidth {
|
if length > limit {
|
||||||
trimmedRunes, _ := t.trimRight(runes, limit-ellipsisWidth)
|
trimmedRunes, _ := t.trimRight(runes, limit-ellipsisWidth)
|
||||||
window.CPrint(*color, string(trimmedRunes)+string(ellipsis))
|
window.CPrint(*color, string(trimmedRunes)+string(ellipsis))
|
||||||
} else if fill {
|
} else if fill {
|
||||||
@@ -2617,11 +2617,11 @@ func (t *Terminal) updatePromptOffset() ([]rune, []rune) {
|
|||||||
}
|
}
|
||||||
maxWidth := util.Max(1, w.Width()-t.promptLen-1)
|
maxWidth := util.Max(1, w.Width()-t.promptLen-1)
|
||||||
|
|
||||||
_, overflow := t.trimLeft(t.input[:t.cx], maxWidth)
|
_, overflow := t.trimLeft(t.input[:t.cx], maxWidth, 0)
|
||||||
minOffset := int(overflow)
|
minOffset := int(overflow)
|
||||||
maxOffset := minOffset + (maxWidth-util.Max(0, maxWidth-t.cx))/2
|
maxOffset := minOffset + (maxWidth-util.Max(0, maxWidth-t.cx))/2
|
||||||
t.xoffset = util.Constrain(t.xoffset, minOffset, maxOffset)
|
t.xoffset = util.Constrain(t.xoffset, minOffset, maxOffset)
|
||||||
before, _ := t.trimLeft(t.input[t.xoffset:t.cx], maxWidth)
|
before, _ := t.trimLeft(t.input[t.xoffset:t.cx], maxWidth, 0)
|
||||||
beforeLen := t.displayWidth(before)
|
beforeLen := t.displayWidth(before)
|
||||||
after, _ := t.trimRight(t.input[t.cx:], maxWidth-beforeLen)
|
after, _ := t.trimRight(t.input[t.cx:], maxWidth-beforeLen)
|
||||||
afterLen := t.displayWidth(after)
|
afterLen := t.displayWidth(after)
|
||||||
@@ -3322,22 +3322,22 @@ func (t *Terminal) displayWidthWithLimit(runes []rune, prefixWidth int, limit in
|
|||||||
return width
|
return width
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terminal) trimLeft(runes []rune, width int) ([]rune, int32) {
|
func (t *Terminal) trimLeft(runes []rune, width int, ellipsisWidth int) ([]rune, int32) {
|
||||||
width = util.Max(0, width)
|
width = util.Max(0, width)
|
||||||
var trimmed int32
|
var trimmed int32
|
||||||
// Assume that each rune takes at least one column on screen
|
// Assume that each rune takes at least one column on screen
|
||||||
if len(runes) > width+2 {
|
if len(runes) > width {
|
||||||
diff := len(runes) - width - 2
|
diff := len(runes) - width
|
||||||
trimmed = int32(diff)
|
trimmed = int32(diff)
|
||||||
runes = runes[diff:]
|
runes = runes[diff:]
|
||||||
}
|
}
|
||||||
|
|
||||||
currentWidth := t.displayWidth(runes)
|
currentWidth := t.displayWidth(runes)
|
||||||
|
|
||||||
for currentWidth > width && len(runes) > 0 {
|
for currentWidth > width-ellipsisWidth && len(runes) > 0 {
|
||||||
runes = runes[1:]
|
runes = runes[1:]
|
||||||
trimmed++
|
trimmed++
|
||||||
currentWidth = t.displayWidthWithLimit(runes, 2, width)
|
currentWidth = t.displayWidthWithLimit(runes, ellipsisWidth, width)
|
||||||
}
|
}
|
||||||
return runes, trimmed
|
return runes, trimmed
|
||||||
}
|
}
|
||||||
@@ -3562,7 +3562,7 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
|
|||||||
}
|
}
|
||||||
if t.hscroll {
|
if t.hscroll {
|
||||||
if t.keepRight && pos == nil {
|
if t.keepRight && pos == nil {
|
||||||
trimmed, diff := t.trimLeft(line, maxWidth-ellipsisWidth)
|
trimmed, diff := t.trimLeft(line, maxWidth, ellipsisWidth)
|
||||||
transformOffsets(diff, false)
|
transformOffsets(diff, false)
|
||||||
line = append(ellipsis, trimmed...)
|
line = append(ellipsis, trimmed...)
|
||||||
} else if !t.overflow(line[:maxe], maxWidth-ellipsisWidth) {
|
} else if !t.overflow(line[:maxe], maxWidth-ellipsisWidth) {
|
||||||
@@ -3578,7 +3578,7 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
|
|||||||
}
|
}
|
||||||
// ..ri..
|
// ..ri..
|
||||||
var diff int32
|
var diff int32
|
||||||
line, diff = t.trimLeft(line, maxWidth-ellipsisWidth)
|
line, diff = t.trimLeft(line, maxWidth, ellipsisWidth)
|
||||||
|
|
||||||
// Transform offsets
|
// Transform offsets
|
||||||
transformOffsets(diff, rightTrim)
|
transformOffsets(diff, rightTrim)
|
||||||
|
|||||||
@@ -1415,6 +1415,11 @@ class TestCore < TestInteractive
|
|||||||
tmux.until { assert_match(%r{ --1/10000/10000-- *$}, it[-1]) }
|
tmux.until { assert_match(%r{ --1/10000/10000-- *$}, it[-1]) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_info_command_inline_right_no_ansi
|
||||||
|
tmux.send_keys(%(seq 10000 | #{FZF} --info-command 'echo -e "--$FZF_POS/$FZF_INFO--"' --info inline-right), :Enter)
|
||||||
|
tmux.until { assert_match(%r{ --1/10000/10000-- *$}, it[-1]) }
|
||||||
|
end
|
||||||
|
|
||||||
def test_info_command_and_focus
|
def test_info_command_and_focus
|
||||||
tmux.send_keys(%(seq 100 | #{FZF} --separator x --info-command 'echo $FZF_POS' --bind focus:clear-query), :Enter)
|
tmux.send_keys(%(seq 100 | #{FZF} --separator x --info-command 'echo $FZF_POS' --bind focus:clear-query), :Enter)
|
||||||
tmux.until { assert_match(/^ 1 xx/, it[-2]) }
|
tmux.until { assert_match(/^ 1 xx/, it[-2]) }
|
||||||
|
|||||||
Reference in New Issue
Block a user