mirror of
https://github.com/junegunn/fzf.git
synced 2025-11-16 15:23:48 -05:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90ad1b7f22 | ||
|
|
f22fbcd1af | ||
|
|
1d761684c5 | ||
|
|
e491770f1c | ||
|
|
a41be61506 | ||
|
|
1a8f633611 | ||
|
|
af8fe918d8 | ||
|
|
8ef9dfd9a2 | ||
|
|
66df24040f | ||
|
|
ed4442d9ea | ||
|
|
0edb5d5ebb | ||
|
|
9ffc2c7ca3 |
@@ -1,6 +1,13 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
0.61.2
|
||||
------
|
||||
- Fixed panic when using header border without pointer/marker (@phanen)
|
||||
- Fixed `--tmux` option when already inside a tmux popup (@peikk0)
|
||||
- Bug fixes and improvements in CTRL-T binding of fish (#4334) (@bitraid)
|
||||
- Added `--no-tty-default` option to make fzf search for the current TTY device instead of defaulting to `/dev/tty` (#4242)
|
||||
|
||||
0.61.1
|
||||
------
|
||||
- Disable bracketed-paste mode on exit. This fixes issue where pasting breaks after running fzf on old bash versions that don't support the mode.
|
||||
|
||||
2
install
2
install
@@ -2,7 +2,7 @@
|
||||
|
||||
set -u
|
||||
|
||||
version=0.61.1
|
||||
version=0.61.2
|
||||
auto_completion=
|
||||
key_bindings=
|
||||
update_config=2
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
$version="0.61.1"
|
||||
$version="0.61.2"
|
||||
|
||||
$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
|
||||
THE SOFTWARE.
|
||||
..
|
||||
.TH fzf\-tmux 1 "Apr 2025" "fzf 0.61.1" "fzf\-tmux - open fzf in tmux split pane"
|
||||
.TH fzf\-tmux 1 "Apr 2025" "fzf 0.61.2" "fzf\-tmux - open fzf in tmux split pane"
|
||||
|
||||
.SH NAME
|
||||
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
|
||||
THE SOFTWARE.
|
||||
..
|
||||
.TH fzf 1 "Apr 2025" "fzf 0.61.1" "fzf - a command-line fuzzy finder"
|
||||
.TH fzf 1 "Apr 2025" "fzf 0.61.2" "fzf - a command-line fuzzy finder"
|
||||
|
||||
.SH NAME
|
||||
fzf - a command-line fuzzy finder
|
||||
@@ -228,6 +228,13 @@ e.g. \fB# Avoid rendering both fzf instances at the same time
|
||||
(sleep 1; seq 1000000; sleep 1) |
|
||||
fzf \-\-sync \-\-query 5 \-\-listen \-\-bind start:up,load:up,result:up,focus:change\-header:Ready\fR
|
||||
.RE
|
||||
.TP
|
||||
.B "\-\-no\-tty\-default"
|
||||
Make fzf search for the current TTY device via standard error instead of
|
||||
defaulting to \fB/dev/tty\fR. This option avoids issues when launching
|
||||
emacsclient from within fzf. Alternatively, you can change the default TTY
|
||||
device by setting \fB--tty-default=DEVICE_NAME\fR.
|
||||
|
||||
.SS GLOBAL STYLE
|
||||
.TP
|
||||
.BI "\-\-style=" "PRESET"
|
||||
|
||||
@@ -42,45 +42,79 @@ function fzf_key_bindings
|
||||
end
|
||||
|
||||
function __fzf_parse_commandline -d 'Parse the current command line token and return split of existing filepath, fzf query, and optional -option= prefix'
|
||||
set -l fzf_query ''
|
||||
set -l prefix ''
|
||||
set -l dir '.'
|
||||
set -l query
|
||||
set -l commandline (commandline -t | string unescape -n)
|
||||
|
||||
# Strip -option= from token if present
|
||||
set -l prefix (string match -r -- '^-[^\s=]+=' $commandline)
|
||||
set commandline (string replace -- "$prefix" '' $commandline)
|
||||
# Set variables containing the major and minor fish version numbers, using
|
||||
# a method compatible with all supported fish versions.
|
||||
set -l -- fish_major (string match -r -- '^\d+' $version)
|
||||
set -l -- fish_minor (string match -r -- '^\d+\.(\d+)' $version)[2]
|
||||
|
||||
# Enable home directory expansion of leading ~/
|
||||
set commandline (string replace -r -- '^~/' '\$HOME/' $commandline)
|
||||
# fish v3.3.0 and newer: Don't use option prefix if " -- " is preceded.
|
||||
set -l -- match_regex '(?<fzf_query>[\s\S]*?(?=\n?$)$)'
|
||||
set -l -- prefix_regex '^-[^\s=]+=|^-(?!-)\S'
|
||||
if test "$fish_major" -eq 3 -a "$fish_minor" -lt 3
|
||||
or string match -q -v -- '* -- *' (string sub -l (commandline -Cp) -- (commandline -p))
|
||||
set -- match_regex "(?<prefix>$prefix_regex)?$match_regex"
|
||||
end
|
||||
|
||||
# Escape special characters, except for the $ sign of valid variable names,
|
||||
# so that the original string with expanded variables is returned after eval.
|
||||
set commandline (string escape -n -- $commandline)
|
||||
set commandline (string replace -r -a -- '\\\\\$(?=[\w])' '\$' $commandline)
|
||||
# Set $prefix and expanded $fzf_query with preserved trailing newlines.
|
||||
if test "$fish_major" -ge 4
|
||||
# fish v4.0.0 and newer
|
||||
string match -q -r -- $match_regex (commandline --current-token --tokens-expanded | string collect -N)
|
||||
else if test "$fish_major" -eq 3 -a "$fish_minor" -ge 2
|
||||
# fish v3.2.0 - v3.7.1 (last v3)
|
||||
string match -q -r -- $match_regex (commandline --current-token --tokenize | string collect -N)
|
||||
eval set -- fzf_query (string escape -n -- $fzf_query | string replace -r -a '^\\\(?=~)|\\\(?=\$\w)' '')
|
||||
else
|
||||
# fish older than v3.2.0 (v3.1b1 - v3.1.2)
|
||||
set -l -- cl_token (commandline --current-token --tokenize | string collect -N)
|
||||
set -- prefix (string match -r -- $prefix_regex $cl_token)
|
||||
set -- fzf_query (string replace -- "$prefix" '' $cl_token | string collect -N)
|
||||
eval set -- fzf_query (string escape -n -- $fzf_query | string replace -r -a '^\\\(?=~)|\\\(?=\$\w)|\\\n\\\n$' '')
|
||||
end
|
||||
|
||||
# eval is used to do shell expansion on paths
|
||||
eval set commandline $commandline
|
||||
|
||||
# Combine multiple consecutive slashes into one.
|
||||
set commandline (string replace -r -a -- '/+' '/' $commandline)
|
||||
|
||||
if test -n "$commandline"
|
||||
# Strip trailing slash, unless $dir is root dir (/)
|
||||
set dir (string replace -r -- '(?<!^)/$' '' $commandline)
|
||||
|
||||
# Set $dir to the longest existing filepath
|
||||
while not test -d "$dir"
|
||||
# If path is absolute, this can keep going until ends up at /
|
||||
# If path is relative, this can keep going until entire input is consumed, dirname returns "."
|
||||
set dir (dirname -- $dir)
|
||||
if test -n "$fzf_query"
|
||||
# Normalize path in $fzf_query, set $dir to the longest existing directory.
|
||||
if test \( "$fish_major" -ge 4 \) -o \( "$fish_major" -eq 3 -a "$fish_minor" -ge 5 \)
|
||||
# fish v3.5.0 and newer
|
||||
set -- fzf_query (path normalize -- $fzf_query)
|
||||
set -- dir $fzf_query
|
||||
while not path is -d $dir
|
||||
set -- dir (path dirname $dir)
|
||||
end
|
||||
else
|
||||
# fish older than v3.5.0 (v3.1b1 - v3.4.1)
|
||||
if test "$fish_major" -eq 3 -a "$fish_minor" -ge 2
|
||||
# fish v3.2.0 - v3.4.1
|
||||
string match -q -r -- '(?<fzf_query>^[\s\S]*?(?=\n?$)$)' \
|
||||
(string replace -r -a -- '(?<=/)/|(?<!^)/+(?!\n)$' '' $fzf_query | string collect -N)
|
||||
else
|
||||
# fish v3.1b1 - v3.1.2
|
||||
set -- fzf_query (string replace -r -a -- '(?<=/)/|(?<!^)/+(?!\n)$' '' $fzf_query | string collect -N)
|
||||
eval set -- fzf_query (string escape -n -- $fzf_query | string replace -r '\\\n$' '')
|
||||
end
|
||||
set -- dir $fzf_query
|
||||
while not test -d "$dir"
|
||||
set -- dir (dirname -z -- "$dir" | string split0)
|
||||
end
|
||||
end
|
||||
|
||||
if test "$dir" = '.'; and test (string sub -l 2 -- $commandline) != './'
|
||||
# If $dir is "." but commandline is not a relative path, this means no file path found
|
||||
set fzf_query $commandline
|
||||
else
|
||||
# Also remove trailing slash after dir, to "split" input properly
|
||||
set fzf_query (string replace -r -- "^$dir/?" '' $commandline)
|
||||
if not string match -q -- '.' $dir; or string match -q -r -- '^\./|^\.$' $fzf_query
|
||||
# Strip $dir from $fzf_query - preserve trailing newlines.
|
||||
if test "$fish_major" -ge 4
|
||||
# fish v4.0.0 and newer
|
||||
string match -q -r -- '^'(string escape --style=regex -- $dir)'/?(?<fzf_query>[\s\S]*)' $fzf_query
|
||||
else if test "$fish_major" -eq 3 -a "$fish_minor" -ge 2
|
||||
# fish v3.2.0 - v3.7.1 (last v3)
|
||||
string match -q -r -- '^/?(?<fzf_query>[\s\S]*?(?=\n?$)$)' \
|
||||
(string replace -- "$dir" '' $fzf_query | string collect -N)
|
||||
else
|
||||
# fish older than v3.2.0 (v3.1b1 - v3.1.2)
|
||||
set -- fzf_query (string replace -- "$dir" '' $fzf_query | string collect -N)
|
||||
eval set -- fzf_query (string escape -n -- $fzf_query | string replace -r -a '^/?|\\\n$' '')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -95,13 +129,13 @@ function fzf_key_bindings
|
||||
set -l prefix $commandline[3]
|
||||
|
||||
set -lx FZF_DEFAULT_OPTS (__fzf_defaults \
|
||||
"--reverse --walker=file,dir,follow,hidden --scheme=path --walker-root=$dir" \
|
||||
"$FZF_CTRL_T_OPTS --multi")
|
||||
"--reverse --walker=file,dir,follow,hidden --scheme=path" \
|
||||
"$FZF_CTRL_T_OPTS --multi --print0")
|
||||
|
||||
set -lx FZF_DEFAULT_COMMAND "$FZF_CTRL_T_COMMAND"
|
||||
set -lx FZF_DEFAULT_OPTS_FILE
|
||||
|
||||
if set -l result (eval (__fzfcmd) --query=$fzf_query)
|
||||
if set -l result (eval (__fzfcmd) --walker-root=$dir --query=$fzf_query | string split0)
|
||||
# Remove last token from commandline.
|
||||
commandline -t ''
|
||||
for i in $result
|
||||
@@ -154,13 +188,13 @@ function fzf_key_bindings
|
||||
set -l prefix $commandline[3]
|
||||
|
||||
set -lx FZF_DEFAULT_OPTS (__fzf_defaults \
|
||||
"--reverse --walker=dir,follow,hidden --scheme=path --walker-root=$dir" \
|
||||
"$FZF_ALT_C_OPTS --no-multi")
|
||||
"--reverse --walker=dir,follow,hidden --scheme=path" \
|
||||
"$FZF_ALT_C_OPTS --no-multi --print0")
|
||||
|
||||
set -lx FZF_DEFAULT_OPTS_FILE
|
||||
set -lx FZF_DEFAULT_COMMAND "$FZF_ALT_C_COMMAND"
|
||||
|
||||
if set -l result (eval (__fzfcmd) --query=$fzf_query)
|
||||
if set -l result (eval (__fzfcmd) --query=$fzf_query --walker-root=$dir | string split0)
|
||||
cd -- $result
|
||||
commandline -rt -- $prefix
|
||||
end
|
||||
|
||||
@@ -39,7 +39,7 @@ func (r revision) compatible(other revision) bool {
|
||||
// Run starts fzf
|
||||
func Run(opts *Options) (int, error) {
|
||||
if opts.Filter == nil {
|
||||
if opts.Tmux != nil && len(os.Getenv("TMUX")) > 0 && opts.Tmux.index >= opts.Height.index {
|
||||
if opts.Tmux != nil && len(os.Getenv("TMUX")) > 0 && len(os.Getenv("TMUX_PANE")) > 0 && opts.Tmux.index >= opts.Height.index {
|
||||
return runTmux(os.Args, opts)
|
||||
}
|
||||
|
||||
|
||||
@@ -631,6 +631,7 @@ type Options struct {
|
||||
MEMProfile string
|
||||
BlockProfile string
|
||||
MutexProfile string
|
||||
TtyDefault string
|
||||
}
|
||||
|
||||
func filterNonEmpty(input []string) []string {
|
||||
@@ -730,6 +731,7 @@ func defaultOptions() *Options {
|
||||
WalkerOpts: walkerOpts{file: true, hidden: true, follow: true},
|
||||
WalkerRoot: []string{"."},
|
||||
WalkerSkip: []string{".git", "node_modules"},
|
||||
TtyDefault: tui.DefaultTtyDevice,
|
||||
Help: false,
|
||||
Version: false}
|
||||
}
|
||||
@@ -2336,6 +2338,12 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
|
||||
}
|
||||
case "--no-tmux":
|
||||
opts.Tmux = nil
|
||||
case "--tty-default":
|
||||
if opts.TtyDefault, err = nextString("tty device name required"); err != nil {
|
||||
return err
|
||||
}
|
||||
case "--no-tty-default":
|
||||
opts.TtyDefault = ""
|
||||
case "--force-tty-in":
|
||||
// NOTE: We need this because `system('fzf --tmux < /dev/tty')` doesn't
|
||||
// work on Neovim. Same as '-' option of fzf-tmux.
|
||||
|
||||
@@ -98,7 +98,8 @@ func runProxy(commandPrefix string, cmdBuilder func(temp string, needBash bool)
|
||||
validIdentifier := regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)
|
||||
for _, pairStr := range os.Environ() {
|
||||
pair := strings.SplitN(pairStr, "=", 2)
|
||||
if validIdentifier.MatchString(pair[0]) {
|
||||
// TMUX_PANE is never set inside a tmux popup, and should not be set so as to not be detected as a regular tmux pane
|
||||
if validIdentifier.MatchString(pair[0]) && pair[0] != "TMUX_PANE" {
|
||||
exports = append(exports, fmt.Sprintf("export %s=%s", pair[0], escapeSingleQuote(pair[1])))
|
||||
} else if strings.HasPrefix(pair[0], "BASH_FUNC_") && strings.HasSuffix(pair[0], "%%") {
|
||||
name := pair[0][10 : len(pair[0])-2]
|
||||
@@ -144,7 +145,7 @@ func runProxy(commandPrefix string, cmdBuilder func(temp string, needBash bool)
|
||||
env = elems[1:]
|
||||
}
|
||||
executor := util.NewExecutor(opts.WithShell)
|
||||
ttyin, err := tui.TtyIn()
|
||||
ttyin, err := tui.TtyIn(opts.TtyDefault)
|
||||
if err != nil {
|
||||
return ExitError, err
|
||||
}
|
||||
|
||||
@@ -323,7 +323,9 @@ func (r *Reader) readFiles(roots []string, opts walkerOpts, ignores []string) bo
|
||||
return filepath.SkipDir
|
||||
}
|
||||
}
|
||||
path += sep
|
||||
if path != sep {
|
||||
path += sep
|
||||
}
|
||||
}
|
||||
if ((opts.file && !isDir) || (opts.dir && isDir)) && r.pusher(stringBytes(path)) {
|
||||
atomic.StoreInt32(&r.event, int32(EvtReadNew))
|
||||
|
||||
@@ -381,6 +381,7 @@ type Terminal struct {
|
||||
slab *util.Slab
|
||||
theme *tui.ColorTheme
|
||||
tui tui.Renderer
|
||||
ttyDefault string
|
||||
ttyin *os.File
|
||||
executing *util.AtomicBool
|
||||
termSize tui.TermSize
|
||||
@@ -809,7 +810,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
|
||||
// when you run fzf multiple times in your Go program. Closing it is known to
|
||||
// cause problems with 'become' action and invalid terminal state after exit.
|
||||
if ttyin == nil {
|
||||
if ttyin, err = tui.TtyIn(); err != nil {
|
||||
if ttyin, err = tui.TtyIn(opts.TtyDefault); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -817,7 +818,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
|
||||
if tui.HasFullscreenRenderer() {
|
||||
renderer = tui.NewFullscreenRenderer(opts.Theme, opts.Black, opts.Mouse)
|
||||
} else {
|
||||
renderer, err = tui.NewLightRenderer(ttyin, opts.Theme, opts.Black, opts.Mouse, opts.Tabstop, opts.ClearOnExit,
|
||||
renderer, err = tui.NewLightRenderer(opts.TtyDefault, ttyin, opts.Theme, opts.Black, opts.Mouse, opts.Tabstop, opts.ClearOnExit,
|
||||
true, func(h int) int { return h })
|
||||
}
|
||||
} else {
|
||||
@@ -833,7 +834,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
|
||||
effectiveMinHeight += borderLines(opts.BorderShape)
|
||||
return util.Min(termHeight, util.Max(evaluateHeight(opts, termHeight), effectiveMinHeight))
|
||||
}
|
||||
renderer, err = tui.NewLightRenderer(ttyin, opts.Theme, opts.Black, opts.Mouse, opts.Tabstop, opts.ClearOnExit, false, maxHeightFunc)
|
||||
renderer, err = tui.NewLightRenderer(opts.TtyDefault, ttyin, opts.Theme, opts.Black, opts.Mouse, opts.Tabstop, opts.ClearOnExit, false, maxHeightFunc)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -967,6 +968,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
|
||||
keyChan: make(chan tui.Event),
|
||||
eventChan: make(chan tui.Event, 6), // start | (load + result + zero|one) | (focus) | (resize)
|
||||
tui: renderer,
|
||||
ttyDefault: opts.TtyDefault,
|
||||
ttyin: ttyin,
|
||||
initFunc: func() error { return renderer.Init() },
|
||||
executing: util.NewAtomicBool(false),
|
||||
@@ -2647,6 +2649,9 @@ func (t *Terminal) headerIndent(borderShape tui.BorderShape) int {
|
||||
}
|
||||
if borderShape.HasLeft() {
|
||||
indentSize -= 1 + t.borderWidth
|
||||
if indentSize < 0 {
|
||||
indentSize = 0
|
||||
}
|
||||
}
|
||||
return indentSize
|
||||
}
|
||||
@@ -3144,7 +3149,7 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
|
||||
wasWrapped = true
|
||||
}
|
||||
|
||||
if len(line) > 0 && line[len(line)-1] == '\n' {
|
||||
if len(line) > 0 && line[len(line)-1] == '\n' && lineOffset < len(lines)-1 {
|
||||
line = line[:len(line)-1]
|
||||
} else {
|
||||
wrapped = true
|
||||
@@ -4039,7 +4044,7 @@ func (t *Terminal) executeCommand(template string, forcePlus bool, background bo
|
||||
t.executing.Set(true)
|
||||
if !background {
|
||||
// Open a separate handle for tty input
|
||||
if in, _ := tui.TtyIn(); in != nil {
|
||||
if in, _ := tui.TtyIn(t.ttyDefault); in != nil {
|
||||
cmd.Stdin = in
|
||||
if in != os.Stdin {
|
||||
defer in.Close()
|
||||
@@ -4048,7 +4053,7 @@ func (t *Terminal) executeCommand(template string, forcePlus bool, background bo
|
||||
|
||||
cmd.Stdout = os.Stdout
|
||||
if !util.IsTty(os.Stdout) {
|
||||
if out, _ := tui.TtyOut(); out != nil {
|
||||
if out, _ := tui.TtyOut(t.ttyDefault); out != nil {
|
||||
cmd.Stdout = out
|
||||
defer out.Close()
|
||||
}
|
||||
@@ -4056,7 +4061,7 @@ func (t *Terminal) executeCommand(template string, forcePlus bool, background bo
|
||||
|
||||
cmd.Stderr = os.Stderr
|
||||
if !util.IsTty(os.Stderr) {
|
||||
if out, _ := tui.TtyOut(); out != nil {
|
||||
if out, _ := tui.TtyOut(t.ttyDefault); out != nil {
|
||||
cmd.Stderr = out
|
||||
defer out.Close()
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ const (
|
||||
maxInputBuffer = 1024 * 1024
|
||||
)
|
||||
|
||||
const consoleDevice string = "/dev/tty"
|
||||
const DefaultTtyDevice string = "/dev/tty"
|
||||
|
||||
var offsetRegexp = regexp.MustCompile("(.*?)\x00?\x1b\\[([0-9]+);([0-9]+)R")
|
||||
var offsetRegexpBegin = regexp.MustCompile("^\x1b\\[[0-9]+;[0-9]+R")
|
||||
@@ -146,8 +146,8 @@ type LightWindow struct {
|
||||
wrapSignWidth int
|
||||
}
|
||||
|
||||
func NewLightRenderer(ttyin *os.File, theme *ColorTheme, forceBlack bool, mouse bool, tabstop int, clearOnExit bool, fullscreen bool, maxHeightFunc func(int) int) (Renderer, error) {
|
||||
out, err := openTtyOut()
|
||||
func NewLightRenderer(ttyDefault string, ttyin *os.File, theme *ColorTheme, forceBlack bool, mouse bool, tabstop int, clearOnExit bool, fullscreen bool, maxHeightFunc func(int) int) (Renderer, error) {
|
||||
out, err := openTtyOut(ttyDefault)
|
||||
if err != nil {
|
||||
out = os.Stderr
|
||||
}
|
||||
@@ -271,7 +271,7 @@ func (r *LightRenderer) getBytesInternal(buffer []byte, nonblock bool) ([]byte,
|
||||
c, ok := r.getch(nonblock)
|
||||
if !nonblock && !ok {
|
||||
r.Close()
|
||||
return nil, errors.New("failed to read " + consoleDevice)
|
||||
return nil, errors.New("failed to read " + DefaultTtyDevice)
|
||||
}
|
||||
|
||||
retries := 0
|
||||
|
||||
@@ -42,26 +42,35 @@ func (r *LightRenderer) closePlatform() {
|
||||
r.ttyout.Close()
|
||||
}
|
||||
|
||||
func openTty(mode int) (*os.File, error) {
|
||||
in, err := os.OpenFile(consoleDevice, mode, 0)
|
||||
if err != nil {
|
||||
func openTty(ttyDefault string, mode int) (*os.File, error) {
|
||||
var in *os.File
|
||||
var err error
|
||||
if len(ttyDefault) > 0 {
|
||||
in, err = os.OpenFile(ttyDefault, mode, 0)
|
||||
}
|
||||
if in == nil || err != nil || ttyDefault != DefaultTtyDevice && !util.IsTty(in) {
|
||||
tty := ttyname()
|
||||
if len(tty) > 0 {
|
||||
if in, err := os.OpenFile(tty, mode, 0); err == nil {
|
||||
return in, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("failed to open " + consoleDevice)
|
||||
if ttyDefault != DefaultTtyDevice {
|
||||
if in, err = os.OpenFile(DefaultTtyDevice, mode, 0); err == nil {
|
||||
return in, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("failed to open " + DefaultTtyDevice)
|
||||
}
|
||||
return in, nil
|
||||
}
|
||||
|
||||
func openTtyIn() (*os.File, error) {
|
||||
return openTty(syscall.O_RDONLY)
|
||||
func openTtyIn(ttyDefault string) (*os.File, error) {
|
||||
return openTty(ttyDefault, syscall.O_RDONLY)
|
||||
}
|
||||
|
||||
func openTtyOut() (*os.File, error) {
|
||||
return openTty(syscall.O_WRONLY)
|
||||
func openTtyOut(ttyDefault string) (*os.File, error) {
|
||||
return openTty(ttyDefault, syscall.O_WRONLY)
|
||||
}
|
||||
|
||||
func (r *LightRenderer) setupTerminal() {
|
||||
|
||||
@@ -76,12 +76,12 @@ func (r *LightRenderer) closePlatform() {
|
||||
windows.SetConsoleMode(windows.Handle(r.inHandle), r.origStateInput)
|
||||
}
|
||||
|
||||
func openTtyIn() (*os.File, error) {
|
||||
func openTtyIn(ttyDefault string) (*os.File, error) {
|
||||
// not used
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func openTtyOut() (*os.File, error) {
|
||||
func openTtyOut(ttyDefault string) (*os.File, error) {
|
||||
return os.Stderr, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -44,11 +44,11 @@ func ttyname() string {
|
||||
}
|
||||
|
||||
// TtyIn returns terminal device to read user input
|
||||
func TtyIn() (*os.File, error) {
|
||||
return openTtyIn()
|
||||
func TtyIn(ttyDefault string) (*os.File, error) {
|
||||
return openTtyIn(ttyDefault)
|
||||
}
|
||||
|
||||
// TtyIn returns terminal device to write to
|
||||
func TtyOut() (*os.File, error) {
|
||||
return openTtyOut()
|
||||
func TtyOut(ttyDefault string) (*os.File, error) {
|
||||
return openTtyOut(ttyDefault)
|
||||
}
|
||||
|
||||
@@ -11,11 +11,11 @@ func ttyname() string {
|
||||
}
|
||||
|
||||
// TtyIn on Windows returns os.Stdin
|
||||
func TtyIn() (*os.File, error) {
|
||||
func TtyIn(ttyDefault string) (*os.File, error) {
|
||||
return os.Stdin, nil
|
||||
}
|
||||
|
||||
// TtyOut on Windows returns nil
|
||||
func TtyOut() (*os.File, error) {
|
||||
func TtyOut(ttyDefault string) (*os.File, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -1931,4 +1931,9 @@ class TestCore < TestInteractive
|
||||
tmux.send_keys :Space
|
||||
tmux.until { |lines| assert lines.any_include?('bar') }
|
||||
end
|
||||
|
||||
def test_trailing_new_line
|
||||
tmux.send_keys %(echo -en "foo\n" | fzf --read0 --no-multi-line), :Enter
|
||||
tmux.until { |lines| assert_includes lines, '> foo␊' }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -991,4 +991,16 @@ class TestLayout < TestInteractive
|
||||
BLOCK
|
||||
tmux.until { assert_block(block, it) }
|
||||
end
|
||||
|
||||
def test_header_border_no_pointer_and_marker
|
||||
tmux.send_keys %(seq 10 | #{FZF} --header-lines 1 --header-border sharp --no-list-border --pointer '' --marker ''), :Enter
|
||||
block = <<~BLOCK
|
||||
┌──────
|
||||
│ 1
|
||||
└──────
|
||||
9/9 ─
|
||||
>
|
||||
BLOCK
|
||||
tmux.until { assert_block(block, it) }
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user