Repository: junegunn/fzf (language: go)

Issue:
[feature request] add an option to enable tmux popup window borders 
### Checklist

- [X] I have read through the manual page (`man fzf`)
- [X] I have searched through the existing issues
- [ ] For bug reports, I have checked if the bug is reproducible in the latest version of fzf

### Output of `fzf --version`

0.57.0

### OS

- [ ] Linux
- [X] macOS
- [ ] Windows
- [ ] Etc.

### Shell

- [ ] bash
- [ ] zsh
- [X] fish

### Problem / Steps to reproduce

Currently, the tmux popup window is launched with:
https://github.com/junegunn/fzf/blob/fb3bf6c9841d849ec459fc6b251b4aa0f16d8038/src/tmux.go#L36

The `-B` flag disables the popup window border. This seems to be a good default. However, there are situations where it would be nice if the popup window had a border. For example, I have a fzf command listing git-log entries and a key binding that executes a pager for viewing the commit message or entire commit (including diff).

Without a popup border, the pager output isn't visually separated from the background and harder to read.

![Screenshot 2025-01-03 at 13 18 40](https://github.com/user-attachments/assets/b3281a5c-0308-487f-a358-6c1321ef8980)

vs.

![Screenshot 2025-01-03 at 13 19 41](https://github.com/user-attachments/assets/b724e9f5-ecd2-4a46-8585-d6c55d79abc7)


If customizing this should be supported, I see two ways to do this:
- Allow tmux flags in the list of elements passed via `--tmux[=[center|top|bottom|left|right][,SIZE[%]][,SIZE[%]]]`
   For example, `--tmux[=[center|top|bottom|left|right][,SIZE[%]][,SIZE[%]],[-B],[-E],[-d DIR]]`. If no flags are
   specified, the current list of default flags is applied.
- Add a new flag `--tmux-flags` that contains a list of flags passed to `tmux popup`. Again, if not specified, the current
   list of default flags is applied.


Discussion / hints:
Another variation of the above proposed solution would be extending the `--tmux` flag to:
```
--tmux[=[center|top|bottom|left|right][,SIZE[%]][,SIZE[%]][,border]]
```
which would wrap the tmux interface and not expose tmux flag names as part of the fzf interface.
There is an ongoing discussion where we're trying to abstract `--tmux` into `--popup` and support both tmux, zellij, and any alternative that would allow you to open a popup window. See https://github.com/junegunn/fzf/pull/4145

So considering that, I'd like to avoid leaking any tmux-specific options to the users, so I prefer your last suggestion, but the word `border` alone can easily be misunderstood. We should be more specific, maybe something like `border-native`.
Somewhat related: https://github.com/junegunn/fzf/pull/4155
> So considering that, I'd like to avoid leaking any tmux-specific options to the users, so I prefer your last suggestion, but the word border alone can easily be misunderstood. We should be more specific, maybe something like border-native.

Sounds reasonable to me. With a more generic `--popup` flag in mind the options should be generic as well and def. not leak popup-implementation specifics into the fzf interface. I can send a PR for the current `--tmux` flag. I assume it has to remain for backward compatibility anyway but becomes an alias for `--popup` eventually. 

Fix patch:
diff --git a/ADVANCED.md b/ADVANCED.md
index b152d5a67ee..bafe9708fac 100644
--- a/ADVANCED.md
+++ b/ADVANCED.md
@@ -128,7 +128,7 @@ fzf  --height 70% --tmux 70%
 You can also specify the position, width, and height of the popup window in
 the following format:
 
-* `[center|top|bottom|left|right][,SIZE[%]][,SIZE[%]]`
+* `[center|top|bottom|left|right][,SIZE[%]][,SIZE[%][,border-native]]`
 
 ```sh
 # 100% width and 60% height
diff --git a/README.md b/README.md
index 1172d12ff75..0faa552e51f 100644
--- a/README.md
+++ b/README.md
@@ -343,7 +343,7 @@ fzf --height -3
 With `--tmux` option, fzf will start in a tmux popup.
 
 ```sh
-# --tmux [center|top|bottom|left|right][,SIZE[%]][,SIZE[%]]
+# --tmux [center|top|bottom|left|right][,SIZE[%]][,SIZE[%][,border-native]]
 
 fzf --tmux center         # Center, 50% width and height
 fzf --tmux 80%            # Center, 80% width and height
diff --git a/man/man1/fzf.1 b/man/man1/fzf.1
index 28d27f181ff..8d499697c98 100644
--- a/man/man1/fzf.1
+++ b/man/man1/fzf.1
@@ -271,7 +271,7 @@ 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[%]]]"
+.BI "\-\-tmux" "[=[center|top|bottom|left|right][,SIZE[%]][,SIZE[%]][,border-native]]"
 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.
 
@@ -286,7 +286,10 @@ e.g.
   fzf \-\-tmux bottom,30%
 
   # Popup on the top with 80% width and 40% height
-  fzf \-\-tmux top,80%,40%\fR
+  fzf \-\-tmux top,80%,40%
+
+  # Popup with a native tmux border in the center with 80% width and height
+  fzf \-\-tmux center,80%,border\-native\fR
 
 .TP
 .BI "\-\-layout=" "LAYOUT"
diff --git a/src/options.go b/src/options.go
index 0b6250f35e7..a3096d1131b 100644
--- a/src/options.go
+++ b/src/options.go
@@ -77,7 +77,7 @@ Usage: fzf [options]
                              (default: 10)
     --tmux[=OPTS]            Start fzf in a tmux popup (requires tmux 3.3+)
                              [center|top|bottom|left|right][,SIZE[%]][,SIZE[%]]
-                             (default: center,50%)
+                             [,border-native] (default: center,50%)
     --layout=LAYOUT          Choose layout: [default|reverse|reverse-list]
     --border[=STYLE]         Draw border around the finder
                              [rounded|sharp|bold|block|thinblock|double|horizontal|vertical|
@@ -254,6 +254,7 @@ type tmuxOptions struct {
 	height   sizeSpec
 	position windowPosition
 	index    int
+	border   bool
 }
 
 type layoutType int
@@ -316,11 +317,19 @@ 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[%]])")
-	if len(tokens) == 0 || len(tokens) > 3 {
+	errorToReturn := errors.New("invalid tmux option: " + arg + " (expected: [center|top|bottom|left|right][,SIZE[%]][,SIZE[%][,border-native]])")
+	if len(tokens) == 0 || len(tokens) > 4 {
 		return nil, errorToReturn
 	}
 
+	for i, token := range tokens {
+		if token == "border-native" {
+			tokens = append(tokens[:i], tokens[i+1:]...) // cut the 'border-native' option
+			opts.border = true
+			break
+		}
+	}
+
 	// Defaults to 'center'
 	switch tokens[0] {
 	case "top", "up":
diff --git a/src/tmux.go b/src/tmux.go
index b2315dcd2c3..e459000a265 100644
--- a/src/tmux.go
+++ b/src/tmux.go
@@ -9,13 +9,16 @@ import (
 
 func runTmux(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 {
+	fzf, rest := args[0], args[1:]
+	args = []string{"--bind=ctrl-z:ignore"}
+	if !opts.Tmux.border && opts.BorderShape == tui.BorderUndefined {
 		args = append(args, "--border")
 	}
+	if opts.Tmux.border && opts.Margin == defaultMargin() {
+		args = append(args, "--margin=0,1")
+	}
 	argStr := escapeSingleQuote(fzf)
-	for _, arg := range args {
+	for _, arg := range append(args, rest...) {
 		argStr += " " + escapeSingleQuote(arg)
 	}
 	argStr += ` --no-tmux --no-height`
@@ -33,7 +36,10 @@ func runTmux(args []string, opts *Options) (int, error) {
 	// M        Both    The mouse position
 	// W        Both    The window position on the status line
 	// S        -y      The line above or below the status line
-	tmuxArgs := []string{"display-popup", "-E", "-B", "-d", dir}
+	tmuxArgs := []string{"display-popup", "-E", "-d", dir}
+	if !opts.Tmux.border {
+		tmuxArgs = append(tmuxArgs, "-B")
+	}
 	switch opts.Tmux.position {
 	case posUp:
 		tmuxArgs = append(tmuxArgs, "-xC", "-y0")


Test patch: