Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support zellij floating pane via --popup (new name for --tmux) #4145

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions man/man1/fzf.1
Original file line number Diff line number Diff line change
Expand Up @@ -271,22 +271,23 @@ Adaptive height has the following limitations:
Minimum height when \fB\-\-height\fR is given in percent (default: 10).
Ignored when \fB\-\-height\fR is not specified.
.TP
.BI "\-\-tmux" "[=[center|top|bottom|left|right][,SIZE[%]][,SIZE[%]]]"
Start fzf in a tmux popup (default \fBcenter,50%\fR). Requires tmux 3.3 or
later. This option is ignored if you are not running fzf inside tmux.
.BI "\-\-popup" "[=[center|top|bottom|left|right][,SIZE[%]][,SIZE[%]]]"
Start fzf in a tmux popup or in a zellij floating pane (default
\fBcenter,50%\fR). Requires tmux 3.3+ or zellij. This option is ignored if you
are not running fzf inside tmux or zellij.

e.g.
\fB# Popup in the center with 70% width and height
fzf \-\-tmux 70%
fzf \-\-popup 70%

# Popup on the left with 40% width and 100% height
fzf \-\-tmux right,40%
fzf \-\-popup right,40%

# Popup on the bottom with 100% width and 30% height
fzf \-\-tmux bottom,30%
fzf \-\-popup bottom,30%

# Popup on the top with 80% width and 40% height
fzf \-\-tmux top,80%,40%\fR
fzf \-\-popup top,80%,40%\fR

.TP
.BI "\-\-layout=" "LAYOUT"
Expand Down
9 changes: 7 additions & 2 deletions src/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,13 @@ 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 {
return runTmux(os.Args, opts)
if opts.Tmux != nil && opts.Tmux.index >= opts.Height.index {
if len(os.Getenv("TMUX")) > 0 {
return runTmux(os.Args, opts)
}
if len(os.Getenv("ZELLIJ")) > 0 {
return runZellij(os.Args, opts)
}
}

if needWinpty(opts) {
Expand Down
12 changes: 8 additions & 4 deletions src/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Usage: fzf [options]
according to the input size.
--min-height=HEIGHT Minimum height when --height is given in percent
(default: 10)
--tmux[=OPTS] Start fzf in a tmux popup (requires tmux 3.3+)
--popup[=OPTS] Start fzf in a popup (requires tmux 3.3+ or zellij)
[center|top|bottom|left|right][,SIZE[%]][,SIZE[%]]
(default: center,50%)
--layout=LAYOUT Choose layout: [default|reverse|reverse-list]
Expand Down Expand Up @@ -299,7 +299,7 @@ func parseTmuxOptions(arg string, index int) (*tmuxOptions, error) {
var err error
opts := defaultTmuxOptions(index)
tokens := splitRegexp.Split(arg, -1)
errorToReturn := errors.New("invalid tmux option: " + arg + " (expected: [center|top|bottom|left|right][,SIZE[%]][,SIZE[%]])")
errorToReturn := errors.New("invalid popup option: " + arg + " (expected: [center|top|bottom|left|right][,SIZE[%]][,SIZE[%]])")
if len(tokens) == 0 || len(tokens) > 3 {
return nil, errorToReturn
}
Expand Down Expand Up @@ -2031,7 +2031,7 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
opts.Version = true
case "--no-winpty":
opts.NoWinpty = true
case "--tmux":
case "--tmux", "--popup":
given, str := optionalNextString(allArgs, &i)
if given {
if opts.Tmux, err = parseTmuxOptions(str, index); err != nil {
Expand All @@ -2040,7 +2040,7 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
} else {
opts.Tmux = defaultTmuxOptions(index)
}
case "--no-tmux":
case "--no-tmux", "--no-popup":
opts.Tmux = nil
case "--force-tty-in":
// NOTE: We need this because `system('fzf --tmux < /dev/tty')` doesn't
Expand Down Expand Up @@ -2577,6 +2577,10 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
if opts.FuzzyAlgo, err = parseAlgo(value); err != nil {
return err
}
} else if match, value := optString(arg, "--popup="); match {
if opts.Tmux, err = parseTmuxOptions(value, index); err != nil {
return err
}
} else if match, value := optString(arg, "--tmux="); match {
if opts.Tmux, err = parseTmuxOptions(value, index); err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion src/terminal.go
Original file line number Diff line number Diff line change
Expand Up @@ -1539,7 +1539,7 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
width := screenWidth - marginInt[1] - marginInt[3]
height := screenHeight - marginInt[0] - marginInt[2]

t.prevLines = make([]itemLine, screenHeight)
t.prevLines = make([]itemLine, util.Max(1, screenHeight))
if t.border != nil && redrawBorder {
t.border = nil
}
Expand Down
2 changes: 1 addition & 1 deletion src/tmux.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func runTmux(args []string, opts *Options) (int, error) {
for _, arg := range args {
argStr += " " + escapeSingleQuote(arg)
}
argStr += ` --no-tmux --no-height`
argStr += ` --no-popup --no-height`

// Get current directory
dir, err := os.Getwd()
Expand Down
103 changes: 103 additions & 0 deletions src/zellij.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package fzf

import (
"fmt"
"os"
"os/exec"
"strconv"

"github.com/junegunn/fzf/src/tui"
)

func runZellij(args []string, opts *Options) (int, error) {
// Prepare arguments
fzf := args[0]
args = append([]string{"--bind=ctrl-z:ignore"}, args[1:]...)
if opts.BorderShape == tui.BorderUndefined {
args = append(args, "--no-border")
}
argStr := escapeSingleQuote(fzf)
for _, arg := range args {
argStr += " " + escapeSingleQuote(arg)
}
argStr += ` --no-popup --no-height`

// Get current directory
dir, err := os.Getwd()
if err != nil {
dir = "."
}

sh, err := sh(false)
if err != nil {
return ExitError, err
}

fifo, err := fifo("zellij-fifo")
if err != nil {
return ExitError, err
}

zopts := " --width " + opts.Tmux.width.String() + " --height " + opts.Tmux.height.String()
centerX := func() {
// TODO: Handle non-percent values
if opts.Tmux.width.percent {
x := (100.0 - opts.Tmux.width.size) / 2
if x <= 0 {
zopts += " -x0"
} else {
zopts += fmt.Sprintf(" -x%d%%", int(x))
}
} else if cols := os.Getenv("COLUMNS"); len(cols) > 0 {
if w, e := strconv.Atoi(cols); e == nil {
x := (float64(w) - opts.Tmux.width.size) / 2
zopts += fmt.Sprintf(" -x%d", int(x))
}
}

}
centerY := func() {
if opts.Tmux.height.percent {
y := (100.0 - opts.Tmux.height.size) / 2
if y <= 0 {
zopts += " -y0"
} else {
zopts += fmt.Sprintf(" -y%d%%", int(y))
}
} else if lines := os.Getenv("LINES"); len(lines) > 0 {
if h, e := strconv.Atoi(lines); e == nil {
y := (float64(h) - opts.Tmux.height.size) / 2
zopts += fmt.Sprintf(" -y%d", int(y))
}
}
}
switch opts.Tmux.position {
case posUp:
zopts += " -y0"
centerX()
case posDown:
zopts += " -y9999"
centerX()
case posLeft:
zopts += " -x0"
centerY()
case posRight:
zopts += " -x9999"
centerY()
case posCenter:
centerX()
centerY()
}

lines := []string{
"#!/bin/sh",
fmt.Sprintf(`zellij run --name '' --floating --close-on-exit --cwd %s %s -- %s -c "%s $1; echo \$? > %s" || exit $?`, dir, zopts, sh, sh, fifo),
fmt.Sprintf(`exit $(cat %s)`, fifo),
}
temptemp := WriteTemporaryFile(lines, "\n")
defer os.Remove(temptemp)

return runProxy(argStr, func(temp string, needBash bool) (*exec.Cmd, error) {
return exec.Command(sh, temptemp, temp), nil
}, opts, true)
}
Loading