mirror of
https://github.com/junegunn/fzf.git
synced 2026-08-12 10:52:39 +08:00
Set --border-label as the title of the tmux floating pane (#4853)
The pane sets the options itself before running fzf, so that they are
in place no matter how quickly the command exits, targeted at
$TMUX_PANE; the default target would resolve to the active pane of
the session's current window.
- pane-border-format is set to '#{pane_title}' so that the label is
displayed on the border when pane-border-status is enabled;
pane-border-status itself is a window option in released tmux
versions and is left alone
- When a border style is explicitly specified with --border, a popup
is used instead of a floating pane so that the fzf-drawn border is
the only border shown; give 'border-native' to force a floating pane
- 'none' and 'line' are treated as no border; fzf draws no box for
either, so the label is displayed on the native border
- Remove 'border-fzf' which is now redundant; it was never released
- The title is escaped for select-pane -T which expands format
expressions; a lone ';' is escaped as tmux would treat it as a
command separator
- The label is skipped when ANSI stripping leaves an empty string
- --border-label-pos is ignored
- Fix remain-on-exit set on the original pane instead of the floating
pane
This commit is contained in:
+6
-2
@@ -6,9 +6,13 @@ CHANGELOG
|
|||||||
- On tmux 3.7 or above, `--popup` starts fzf in a floating pane instead of a popup (#4850)
|
- On tmux 3.7 or above, `--popup` starts fzf in a floating pane instead of a popup (#4850)
|
||||||
- Unlike a popup, a floating pane is not modal; you can switch to other panes and windows while fzf is running, move and resize the pane with the mouse, zoom it to fullscreen, and use copy-mode in it
|
- Unlike a popup, a floating pane is not modal; you can switch to other panes and windows while fzf is running, move and resize the pane with the mouse, zoom it to fullscreen, and use copy-mode in it
|
||||||
- A floating pane always has a native border, which is what makes the pane movable and resizable, so `border-native` is implied
|
- A floating pane always has a native border, which is what makes the pane movable and resizable, so `border-native` is implied
|
||||||
- Give `border-fzf` to fall back to a popup where fzf draws its own border
|
- A popup is used instead when a border style is explicitly specified with `--border`, so that the fzf-drawn border is the only border shown (`none` and `line` are treated as no border)
|
||||||
```sh
|
```sh
|
||||||
fzf --popup center,80%,border-fzf
|
fzf --popup --border rounded
|
||||||
|
```
|
||||||
|
- `--border-label` is set as the title of the floating pane, and is displayed on the border if `pane-border-status` is enabled in tmux
|
||||||
|
```sh
|
||||||
|
fzf --popup --border-label ' fzf '
|
||||||
```
|
```
|
||||||
- Added `result-final` event, a variant of `result` that is not triggered while the input stream is still open (#4835)
|
- Added `result-final` event, a variant of `result` that is not triggered while the input stream is still open (#4835)
|
||||||
- Use it for one-shot, per-query actions that would otherwise re-fire on every intermediate snapshot during loading
|
- Use it for one-shot, per-query actions that would otherwise re-fire on every intermediate snapshot during loading
|
||||||
|
|||||||
+10
-4
@@ -417,7 +417,7 @@ layout options so that the specified number of items are visible in the list
|
|||||||
section (default: \fB10+\fR).
|
section (default: \fB10+\fR).
|
||||||
Ignored when \fB\-\-height\fR is not specified or set as an absolute value.
|
Ignored when \fB\-\-height\fR is not specified or set as an absolute value.
|
||||||
.TP
|
.TP
|
||||||
.BI "\-\-popup" "[=[center|top|bottom|left|right][,SIZE[%]][,SIZE[%]][,border-native|border-fzf]]"
|
.BI "\-\-popup" "[=[center|top|bottom|left|right][,SIZE[%]][,SIZE[%]][,border-native]]"
|
||||||
Start fzf in a tmux or Zellij floating pane (default \fBcenter,50%\fR).
|
Start fzf in a tmux or Zellij floating pane (default \fBcenter,50%\fR).
|
||||||
Requires tmux 3.3+ or Zellij 0.44+. This option is ignored if you
|
Requires tmux 3.3+ or Zellij 0.44+. This option is ignored if you
|
||||||
are not running fzf inside tmux or Zellij. \fB\-\-tmux\fR is an alias for this option.
|
are not running fzf inside tmux or Zellij. \fB\-\-tmux\fR is an alias for this option.
|
||||||
@@ -426,9 +426,15 @@ On tmux 3.7 or above, the floating pane is not modal; you can switch to
|
|||||||
other panes and windows while fzf is running, move and resize the pane with
|
other panes and windows while fzf is running, move and resize the pane with
|
||||||
the mouse, zoom it to fullscreen, and use copy\-mode in it. The pane always
|
the mouse, zoom it to fullscreen, and use copy\-mode in it. The pane always
|
||||||
has a native border, which is what makes it movable and resizable, so
|
has a native border, which is what makes it movable and resizable, so
|
||||||
\fBborder\-native\fR is implied. On tmux versions below 3.7, or when
|
\fBborder\-native\fR is implied. \fB\-\-border\-label\fR is set as the title
|
||||||
\fBborder\-fzf\fR is given, a modal tmux popup is used instead and fzf draws
|
of the pane, and is displayed on the border if \fBpane\-border\-status\fR
|
||||||
its own border.
|
is enabled in tmux (\fB\-\-border\-label\-pos\fR is ignored).
|
||||||
|
|
||||||
|
A modal tmux popup is used instead on tmux versions below 3.7, or when a
|
||||||
|
border style is explicitly specified with \fB\-\-border\fR, so that the
|
||||||
|
fzf\-drawn border is the only border shown. \fBnone\fR and \fBline\fR are
|
||||||
|
treated as no border. Give \fBborder\-native\fR to
|
||||||
|
force a floating pane nonetheless.
|
||||||
|
|
||||||
e.g.
|
e.g.
|
||||||
\fB# Popup in the center with 70% width and height
|
\fB# Popup in the center with 70% width and height
|
||||||
|
|||||||
+6
-18
@@ -77,7 +77,7 @@ Usage: fzf [options]
|
|||||||
according to the other layout options (default: 10+).
|
according to the other layout options (default: 10+).
|
||||||
--popup[=OPTS] Start fzf in a floating pane (requires tmux 3.3+ or Zellij 0.44+)
|
--popup[=OPTS] Start fzf in a floating pane (requires tmux 3.3+ or Zellij 0.44+)
|
||||||
[center|top|bottom|left|right][,SIZE[%]][,SIZE[%]]
|
[center|top|bottom|left|right][,SIZE[%]][,SIZE[%]]
|
||||||
[,border-native|border-fzf] (default: center,50%)
|
[,border-native] (default: center,50%)
|
||||||
--tmux[=OPTS] Alias for --popup
|
--tmux[=OPTS] Alias for --popup
|
||||||
|
|
||||||
LAYOUT
|
LAYOUT
|
||||||
@@ -335,20 +335,12 @@ const (
|
|||||||
posNext // adjacent to the input section, on the list side
|
posNext // adjacent to the input section, on the list side
|
||||||
)
|
)
|
||||||
|
|
||||||
type tmuxBorder int
|
|
||||||
|
|
||||||
const (
|
|
||||||
tmuxBorderAuto tmuxBorder = iota
|
|
||||||
tmuxBorderNative
|
|
||||||
tmuxBorderFzf
|
|
||||||
)
|
|
||||||
|
|
||||||
type tmuxOptions struct {
|
type tmuxOptions struct {
|
||||||
width sizeSpec
|
width sizeSpec
|
||||||
height sizeSpec
|
height sizeSpec
|
||||||
position windowPosition
|
position windowPosition
|
||||||
index int
|
index int
|
||||||
border tmuxBorder
|
border bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type layoutType int
|
type layoutType int
|
||||||
@@ -435,19 +427,15 @@ func parseTmuxOptions(arg string, index int) (*tmuxOptions, error) {
|
|||||||
var err error
|
var err error
|
||||||
opts := defaultTmuxOptions(index)
|
opts := defaultTmuxOptions(index)
|
||||||
tokens := splitRegexp.Split(arg, -1)
|
tokens := splitRegexp.Split(arg, -1)
|
||||||
errorToReturn := errors.New("invalid popup option: " + arg + " (expected: [center|top|bottom|left|right][,SIZE[%]][,SIZE[%]][,border-native|border-fzf])")
|
errorToReturn := errors.New("invalid popup option: " + arg + " (expected: [center|top|bottom|left|right][,SIZE[%]][,SIZE[%]][,border-native])")
|
||||||
if len(tokens) == 0 || len(tokens) > 4 {
|
if len(tokens) == 0 || len(tokens) > 4 {
|
||||||
return nil, errorToReturn
|
return nil, errorToReturn
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, token := range tokens {
|
for i, token := range tokens {
|
||||||
if token == "border-native" || token == "border-fzf" {
|
if token == "border-native" {
|
||||||
tokens = append(tokens[:i], tokens[i+1:]...) // cut the border option
|
tokens = append(tokens[:i], tokens[i+1:]...) // cut the 'border-native' option
|
||||||
if token == "border-native" {
|
opts.border = true
|
||||||
opts.border = tmuxBorderNative
|
|
||||||
} else {
|
|
||||||
opts.border = tmuxBorderFzf
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -26,14 +26,14 @@ func escapeSingleQuote(str string) string {
|
|||||||
func popupArgStr(args []string, opts *Options) (string, string) {
|
func popupArgStr(args []string, opts *Options) (string, string) {
|
||||||
fzf, rest := args[0], args[1:]
|
fzf, rest := args[0], args[1:]
|
||||||
args = []string{"--bind=ctrl-z:ignore"}
|
args = []string{"--bind=ctrl-z:ignore"}
|
||||||
if opts.Tmux.border != tmuxBorderNative && (opts.BorderShape == tui.BorderUndefined || opts.BorderShape == tui.BorderLine) {
|
if !opts.Tmux.border && (opts.BorderShape == tui.BorderUndefined || opts.BorderShape == tui.BorderLine) {
|
||||||
if tui.DefaultBorderShape == tui.BorderRounded {
|
if tui.DefaultBorderShape == tui.BorderRounded {
|
||||||
rest = append(rest, "--border=rounded")
|
rest = append(rest, "--border=rounded")
|
||||||
} else {
|
} else {
|
||||||
rest = append(rest, "--border=sharp")
|
rest = append(rest, "--border=sharp")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if opts.Tmux.border == tmuxBorderNative && opts.Margin == defaultMargin() {
|
if opts.Tmux.border && opts.Margin == defaultMargin() {
|
||||||
args = append(args, "--margin=0,1")
|
args = append(args, "--margin=0,1")
|
||||||
}
|
}
|
||||||
argStr := escapeSingleQuote(fzf)
|
argStr := escapeSingleQuote(fzf)
|
||||||
|
|||||||
+67
-11
@@ -6,6 +6,8 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/junegunn/fzf/src/tui"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Returns the size of the current window if the tmux server supports
|
// Returns the size of the current window if the tmux server supports
|
||||||
@@ -34,6 +36,21 @@ func tmuxFloatingPaneInfo() (int, int, bool) {
|
|||||||
return width, height, true
|
return width, height, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A lone ';' argument is a command separator to tmux, aborting the whole
|
||||||
|
// command at parse time
|
||||||
|
func escapeTmuxSeparator(str string) string {
|
||||||
|
if str == ";" {
|
||||||
|
return `\;`
|
||||||
|
}
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
// Escape a string for use as the pane title; select-pane -T expands format
|
||||||
|
// expressions denoted by '#', but not time conversion specifiers
|
||||||
|
func escapeTmuxTitle(str string) string {
|
||||||
|
return escapeTmuxSeparator(strings.ReplaceAll(str, "#", "##"))
|
||||||
|
}
|
||||||
|
|
||||||
// Convert sizeSpec to the number of cells, clamped between the minimum
|
// Convert sizeSpec to the number of cells, clamped between the minimum
|
||||||
// footprint of 3, including the border, and the window size
|
// footprint of 3, including the border, and the window size
|
||||||
func tmuxDim(spec sizeSpec, window int) int {
|
func tmuxDim(spec sizeSpec, window int) int {
|
||||||
@@ -90,19 +107,53 @@ func runTmuxFloatingPane(argStr string, dir string, windowWidth int, windowHeigh
|
|||||||
}
|
}
|
||||||
f.Close()
|
f.Close()
|
||||||
code := escapeSingleQuote(codeFile)
|
code := escapeSingleQuote(codeFile)
|
||||||
paneCmd := fmt.Sprintf("%s %s; echo $? > %s; tmux wait-for -S %s",
|
|
||||||
escapeSingleQuote(sh), escapeSingleQuote(temp), code, signal)
|
// Pane options are set by the pane itself before running fzf, so
|
||||||
|
// that they are in place no matter how quickly the command exits.
|
||||||
|
// The target must be explicit; without it, the commands would
|
||||||
|
// resolve to the active pane of the session's current window,
|
||||||
|
// which is not necessarily the pane running them.
|
||||||
|
//
|
||||||
|
// The pane should always close on exit like a popup, even when
|
||||||
|
// remain-on-exit is on.
|
||||||
|
setup := `tmux set-option -p -t "$TMUX_PANE" remain-on-exit off 2> /dev/null; `
|
||||||
|
|
||||||
|
// Set --border-label as the title of the floating pane, and as its
|
||||||
|
// pane-border-format so that it is displayed on the border when
|
||||||
|
// pane-border-status is enabled. pane-border-format is pane-scoped,
|
||||||
|
// but pane-border-status is a window option that only becomes
|
||||||
|
// pane-scoped in the next release of tmux, so it is left alone.
|
||||||
|
// https://github.com/tmux/tmux/commit/7a18fa281db3
|
||||||
|
// --border-label-pos is ignored.
|
||||||
|
// Skipped when fzf draws its own border with the label on it.
|
||||||
|
// '--border=none' is included; fzf would not display the label, but
|
||||||
|
// the native border of a floating pane cannot be removed, so
|
||||||
|
// display the label on it nonetheless.
|
||||||
|
if opts.BorderLabel.label != "" &&
|
||||||
|
(opts.BorderShape == tui.BorderUndefined || opts.BorderShape == tui.BorderLine ||
|
||||||
|
opts.BorderShape == tui.BorderNone) {
|
||||||
|
// Strip ANSI sequences fzf would otherwise render itself
|
||||||
|
label, _, _ := extractColor(opts.BorderLabel.label, nil, nil)
|
||||||
|
if label != "" {
|
||||||
|
setup += fmt.Sprintf(`tmux select-pane -t "$TMUX_PANE" -T %s 2> /dev/null; `,
|
||||||
|
escapeSingleQuote(escapeTmuxTitle(label)))
|
||||||
|
// The title is displayed verbatim; substituted values are
|
||||||
|
// not expanded again
|
||||||
|
setup += `tmux set-option -p -t "$TMUX_PANE" pane-border-format '#{pane_title}' 2> /dev/null; `
|
||||||
|
}
|
||||||
|
}
|
||||||
|
paneCmd := fmt.Sprintf("%s%s %s; echo $? > %s; tmux wait-for -S %s",
|
||||||
|
setup, escapeSingleQuote(sh), escapeSingleQuote(temp), code, signal)
|
||||||
// Unzoom the window first; creating a floating pane over a zoomed
|
// Unzoom the window first; creating a floating pane over a zoomed
|
||||||
// window crashes the tmux server on 3.7b, and newer versions of
|
// window crashes the tmux server on 3.7b, and newer versions of
|
||||||
// tmux unzoom the window anyway. The pane should always close on
|
// tmux unzoom the window anyway.
|
||||||
// exit like a popup, even when remain-on-exit is on. set-option
|
|
||||||
// targets the new pane as new-pane makes it the current pane.
|
|
||||||
target := os.Getenv("TMUX_PANE")
|
target := os.Getenv("TMUX_PANE")
|
||||||
newPane := fmt.Sprintf(
|
newPane := fmt.Sprintf(
|
||||||
"tmux if -F -t %s '#{window_zoomed_flag}' %s ';' new-pane -P -F '#{pane_id}' -t %s -c %s -x %d -y %d -X %d -Y %d %s -c %s ';' set-option -p remain-on-exit off",
|
"tmux if -F -t %s '#{window_zoomed_flag}' %s ';' new-pane -P -F '#{pane_id}' -t %s -c %s -x %d -y %d -X %d -Y %d %s -c %s",
|
||||||
escapeSingleQuote(target), escapeSingleQuote("resize-pane -Z -t "+target),
|
escapeSingleQuote(target), escapeSingleQuote("resize-pane -Z -t "+target),
|
||||||
escapeSingleQuote(target), escapeSingleQuote(dir), width-2, height-2, x, y,
|
escapeSingleQuote(target), escapeSingleQuote(dir), width-2, height-2, x, y,
|
||||||
escapeSingleQuote(sh), escapeSingleQuote(paneCmd))
|
escapeSingleQuote(sh), escapeSingleQuote(paneCmd))
|
||||||
|
|
||||||
// The pane is killed when the proxy process is interrupted or hung up,
|
// The pane is killed when the proxy process is interrupted or hung up,
|
||||||
// like a popup dying with its client. wait-for runs in the background
|
// like a popup dying with its client. wait-for runs in the background
|
||||||
// and is awaited with the interruptible wait builtin so that the trap
|
// and is awaited with the interruptible wait builtin so that the trap
|
||||||
@@ -130,11 +181,16 @@ exit "$code"`, newPane, code, signal, signal, code, code, code)
|
|||||||
func runTmux(args []string, opts *Options) (int, error) {
|
func runTmux(args []string, opts *Options) (int, error) {
|
||||||
// On tmux 3.7 or above, fzf runs in a floating pane instead of a popup.
|
// On tmux 3.7 or above, fzf runs in a floating pane instead of a popup.
|
||||||
// A floating pane always has a native border, so 'border-native' is
|
// A floating pane always has a native border, so 'border-native' is
|
||||||
// implied. Give 'border-fzf' to fall back to a popup where fzf draws
|
// implied. When a border style is explicitly specified with --border, a
|
||||||
// its own border.
|
// popup is used instead so that the fzf-drawn border is the only border
|
||||||
if opts.Tmux.border != tmuxBorderFzf {
|
// shown; the native border of a floating pane cannot be removed. 'none'
|
||||||
|
// and 'line' are treated as no border; fzf draws no box for either, and
|
||||||
|
// 'line' only makes sense with --height. Give 'border-native' to force
|
||||||
|
// a floating pane nonetheless.
|
||||||
|
if opts.Tmux.border || opts.BorderShape == tui.BorderUndefined ||
|
||||||
|
opts.BorderShape == tui.BorderLine || opts.BorderShape == tui.BorderNone {
|
||||||
if windowWidth, windowHeight, ok := tmuxFloatingPaneInfo(); ok {
|
if windowWidth, windowHeight, ok := tmuxFloatingPaneInfo(); ok {
|
||||||
opts.Tmux.border = tmuxBorderNative
|
opts.Tmux.border = true
|
||||||
argStr, dir := popupArgStr(args, opts)
|
argStr, dir := popupArgStr(args, opts)
|
||||||
return runTmuxFloatingPane(argStr, dir, windowWidth, windowHeight, opts)
|
return runTmuxFloatingPane(argStr, dir, windowWidth, windowHeight, opts)
|
||||||
}
|
}
|
||||||
@@ -150,7 +206,7 @@ func runTmux(args []string, opts *Options) (int, error) {
|
|||||||
// W Both The window position on the status line
|
// W Both The window position on the status line
|
||||||
// S -y The line above or below the status line
|
// S -y The line above or below the status line
|
||||||
tmuxArgs := []string{"display-popup", "-E", "-d", dir}
|
tmuxArgs := []string{"display-popup", "-E", "-d", dir}
|
||||||
if opts.Tmux.border != tmuxBorderNative {
|
if !opts.Tmux.border {
|
||||||
tmuxArgs = append(tmuxArgs, "-B")
|
tmuxArgs = append(tmuxArgs, "-B")
|
||||||
}
|
}
|
||||||
switch opts.Tmux.position {
|
switch opts.Tmux.position {
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package fzf
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestEscapeTmuxTitle(t *testing.T) {
|
||||||
|
for _, tc := range []struct {
|
||||||
|
given string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{"", ""},
|
||||||
|
{" fzf ", " fzf "},
|
||||||
|
{"#", "##"},
|
||||||
|
{"##", "####"},
|
||||||
|
{" C# notes #S ", " C## notes ##S "},
|
||||||
|
{"100%", "100%"},
|
||||||
|
{";", `\;`},
|
||||||
|
{"; rm", "; rm"},
|
||||||
|
{" ; ", " ; "},
|
||||||
|
} {
|
||||||
|
if actual := escapeTmuxTitle(tc.given); actual != tc.expected {
|
||||||
|
t.Errorf("expected %q, got %q", tc.expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEscapeTmuxTitleSeparator(t *testing.T) {
|
||||||
|
for _, tc := range []struct {
|
||||||
|
given string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{"#;", "##;"},
|
||||||
|
{";#", ";##"},
|
||||||
|
{";;", ";;"},
|
||||||
|
} {
|
||||||
|
if actual := escapeTmuxTitle(tc.given); actual != tc.expected {
|
||||||
|
t.Errorf("expected %q, got %q", tc.expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -11,7 +11,7 @@ func runZellij(args []string, opts *Options) (int, error) {
|
|||||||
"run", "--floating", "--close-on-exit", "--block-until-exit",
|
"run", "--floating", "--close-on-exit", "--block-until-exit",
|
||||||
"--cwd", dir,
|
"--cwd", dir,
|
||||||
}
|
}
|
||||||
if opts.Tmux.border != tmuxBorderNative {
|
if !opts.Tmux.border {
|
||||||
zellijArgs = append(zellijArgs, "--borderless", "true")
|
zellijArgs = append(zellijArgs, "--borderless", "true")
|
||||||
}
|
}
|
||||||
switch opts.Tmux.position {
|
switch opts.Tmux.position {
|
||||||
|
|||||||
+15
-2
@@ -32,7 +32,20 @@ class TestTmux < TestInteractive
|
|||||||
tmux.until { |lines| assert lines.any_include?('code:130') }
|
tmux.until { |lines| assert lines.any_include?('code:130') }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_border_fzf_falls_back_to_popup
|
def test_floating_pane_border_label
|
||||||
|
tmux.send_keys "seq 100 | #{fzf(%(--popup center,80% --margin 0 --border-label ' #fzf-label 100% '))}", :Enter
|
||||||
|
tmux.until { |lines| assert_equal 100, lines.item_count }
|
||||||
|
pane = floating_pane
|
||||||
|
refute_nil pane
|
||||||
|
title = IO.popen(['tmux', 'display-message', '-p', '-t', pane, "\#{pane_title}"], &:read)
|
||||||
|
assert_equal ' #fzf-label 100% ', title.chomp
|
||||||
|
format = IO.popen(['tmux', 'show-options', '-p', '-t', pane, 'pane-border-format'], &:read)
|
||||||
|
assert_includes format, "\#{pane_title}"
|
||||||
|
tmux.send_keys :Enter
|
||||||
|
assert_equal '1', fzf_output
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_explicit_border_falls_back_to_popup
|
||||||
# display-popup requires an attached client, which the test environment
|
# display-popup requires an attached client, which the test environment
|
||||||
# may not have; intercept it with a tmux shim on PATH
|
# may not have; intercept it with a tmux shim on PATH
|
||||||
dir = Dir.mktmpdir
|
dir = Dir.mktmpdir
|
||||||
@@ -47,7 +60,7 @@ class TestTmux < TestInteractive
|
|||||||
exec #{real.shellescape} "$@"
|
exec #{real.shellescape} "$@"
|
||||||
SH
|
SH
|
||||||
FileUtils.chmod(0o755, shim)
|
FileUtils.chmod(0o755, shim)
|
||||||
tmux.send_keys "seq 100 | PATH=#{dir.shellescape}:$PATH #{FZF} --popup center,border-fzf", :Enter
|
tmux.send_keys "seq 100 | PATH=#{dir.shellescape}:$PATH #{FZF} --popup center --border rounded", :Enter
|
||||||
tmux.until { |lines| assert lines.any_include?('popup-used') }
|
tmux.until { |lines| assert lines.any_include?('popup-used') }
|
||||||
refute floating_pane
|
refute floating_pane
|
||||||
ensure
|
ensure
|
||||||
|
|||||||
Reference in New Issue
Block a user