mirror of
https://github.com/Llewellynvdm/fzf.git
synced 2024-11-25 14:17:40 +00:00
Use winpty to launch fzf in Git bash (mintty)
Close #3806 Known limitation: * --height cannot be used
This commit is contained in:
parent
aee417c46a
commit
573df524fe
@ -21,7 +21,11 @@ Matcher -> EvtHeader -> Terminal (update header)
|
|||||||
// Run starts fzf
|
// Run starts fzf
|
||||||
func Run(opts *Options) (int, error) {
|
func Run(opts *Options) (int, error) {
|
||||||
if opts.Tmux != nil && len(os.Getenv("TMUX")) > 0 {
|
if opts.Tmux != nil && len(os.Getenv("TMUX")) > 0 {
|
||||||
return runTmux(os.Args[1:], opts)
|
return runTmux(os.Args, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
if os.Getenv("TERM_PROGRAM") == "mintty" && !opts.NoWinpty {
|
||||||
|
return runWinpty(os.Args, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := postProcessOptions(opts); err != nil {
|
if err := postProcessOptions(opts); err != nil {
|
||||||
|
@ -381,8 +381,9 @@ type walkerOpts struct {
|
|||||||
type Options struct {
|
type Options struct {
|
||||||
Input chan string
|
Input chan string
|
||||||
Output chan string
|
Output chan string
|
||||||
|
NoWinpty bool
|
||||||
Tmux *tmuxOptions
|
Tmux *tmuxOptions
|
||||||
TmuxScript string
|
ProxyScript string
|
||||||
Bash bool
|
Bash bool
|
||||||
Zsh bool
|
Zsh bool
|
||||||
Fish bool
|
Fish bool
|
||||||
@ -1883,6 +1884,8 @@ func parseOptions(opts *Options, allArgs []string) error {
|
|||||||
case "--version":
|
case "--version":
|
||||||
clearExitingOpts()
|
clearExitingOpts()
|
||||||
opts.Version = true
|
opts.Version = true
|
||||||
|
case "--no-winpty":
|
||||||
|
opts.NoWinpty = true
|
||||||
case "--tmux":
|
case "--tmux":
|
||||||
str, err := nextString(allArgs, &i, "tmux options required")
|
str, err := nextString(allArgs, &i, "tmux options required")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1893,8 +1896,8 @@ func parseOptions(opts *Options, allArgs []string) error {
|
|||||||
}
|
}
|
||||||
case "--no-tmux":
|
case "--no-tmux":
|
||||||
opts.Tmux = nil
|
opts.Tmux = nil
|
||||||
case "--tmux-script":
|
case "--proxy-script":
|
||||||
if opts.TmuxScript, err = nextString(allArgs, &i, ""); err != nil {
|
if opts.ProxyScript, err = nextString(allArgs, &i, ""); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case "-x", "--extended":
|
case "-x", "--extended":
|
||||||
|
132
src/proxy.go
Normal file
132
src/proxy.go
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
package fzf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/junegunn/fzf/src/tui"
|
||||||
|
"github.com/junegunn/fzf/src/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
const becomeSuffix = ".become"
|
||||||
|
|
||||||
|
func escapeSingleQuote(str string) string {
|
||||||
|
return "'" + strings.ReplaceAll(str, "'", "'\\''") + "'"
|
||||||
|
}
|
||||||
|
|
||||||
|
func fifo(name string) (string, error) {
|
||||||
|
ns := time.Now().UnixNano()
|
||||||
|
output := filepath.Join(os.TempDir(), fmt.Sprintf("fzf-%s-%d", name, ns))
|
||||||
|
output, err := mkfifo(output, 0600)
|
||||||
|
if err != nil {
|
||||||
|
return output, err
|
||||||
|
}
|
||||||
|
return output, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runProxy(commandPrefix string, cmdBuilder func(temp string) *exec.Cmd, opts *Options, withExports bool) (int, error) {
|
||||||
|
output, err := fifo("proxy-output")
|
||||||
|
if err != nil {
|
||||||
|
return ExitError, err
|
||||||
|
}
|
||||||
|
defer os.Remove(output)
|
||||||
|
|
||||||
|
// Take the output
|
||||||
|
go func() {
|
||||||
|
withOutputPipe(output, func(outputFile io.ReadCloser) {
|
||||||
|
if opts.Output == nil {
|
||||||
|
io.Copy(os.Stdout, outputFile)
|
||||||
|
} else {
|
||||||
|
reader := bufio.NewReader(outputFile)
|
||||||
|
sep := opts.PrintSep[0]
|
||||||
|
for {
|
||||||
|
item, err := reader.ReadString(sep)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
opts.Output <- item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
|
||||||
|
var command string
|
||||||
|
commandPrefix += ` --proxy-script "$0"`
|
||||||
|
if opts.Input == nil && util.IsTty() {
|
||||||
|
command = fmt.Sprintf(`%s > %q`, commandPrefix, output)
|
||||||
|
} else {
|
||||||
|
input, err := fifo("proxy-input")
|
||||||
|
if err != nil {
|
||||||
|
return ExitError, err
|
||||||
|
}
|
||||||
|
defer os.Remove(input)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
withInputPipe(input, func(inputFile io.WriteCloser) {
|
||||||
|
if opts.Input == nil {
|
||||||
|
io.Copy(inputFile, os.Stdin)
|
||||||
|
} else {
|
||||||
|
for item := range opts.Input {
|
||||||
|
fmt.Fprint(inputFile, item+opts.PrintSep)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
|
||||||
|
if withExports {
|
||||||
|
command = fmt.Sprintf(`%s < %q > %q`, commandPrefix, input, output)
|
||||||
|
} else {
|
||||||
|
// For mintty: cannot directly read named pipe from Go code
|
||||||
|
command = fmt.Sprintf(`command cat %q | %s > %q`, input, commandPrefix, output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// To ensure that the options are processed by a POSIX-compliant shell,
|
||||||
|
// we need to write the command to a temporary file and execute it with sh.
|
||||||
|
var exports []string
|
||||||
|
if withExports {
|
||||||
|
exports = os.Environ()
|
||||||
|
for idx, pairStr := range exports {
|
||||||
|
pair := strings.SplitN(pairStr, "=", 2)
|
||||||
|
exports[idx] = fmt.Sprintf("export %s=%s", pair[0], escapeSingleQuote(pair[1]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
temp := writeTemporaryFile(append(exports, command), "\n")
|
||||||
|
defer os.Remove(temp)
|
||||||
|
|
||||||
|
cmd := cmdBuilder(temp)
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
if exitError, ok := err.(*exec.ExitError); ok {
|
||||||
|
code := exitError.ExitCode()
|
||||||
|
if code == ExitBecome {
|
||||||
|
becomeFile := temp + becomeSuffix
|
||||||
|
data, err := os.ReadFile(becomeFile)
|
||||||
|
os.Remove(becomeFile)
|
||||||
|
if err != nil {
|
||||||
|
return ExitError, err
|
||||||
|
}
|
||||||
|
elems := strings.Split(string(data), "\x00")
|
||||||
|
if len(elems) < 1 {
|
||||||
|
return ExitError, errors.New("invalid become command")
|
||||||
|
}
|
||||||
|
command := elems[0]
|
||||||
|
env := []string{}
|
||||||
|
if len(elems) > 1 {
|
||||||
|
env = elems[1:]
|
||||||
|
}
|
||||||
|
executor := util.NewExecutor(opts.WithShell)
|
||||||
|
executor.Become(tui.TtyIn(), env, command)
|
||||||
|
}
|
||||||
|
return code, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExitOk, nil
|
||||||
|
}
|
38
src/proxy_unix.go
Normal file
38
src/proxy_unix.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package fzf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func sh() (string, error) {
|
||||||
|
return "sh", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mkfifo(path string, mode uint32) (string, error) {
|
||||||
|
return path, unix.Mkfifo(path, mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func withOutputPipe(output string, task func(io.ReadCloser)) error {
|
||||||
|
outputFile, err := os.OpenFile(output, os.O_RDONLY, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
task(outputFile)
|
||||||
|
outputFile.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func withInputPipe(input string, task func(io.WriteCloser)) error {
|
||||||
|
inputFile, err := os.OpenFile(input, os.O_WRONLY, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
task(inputFile)
|
||||||
|
inputFile.Close()
|
||||||
|
return nil
|
||||||
|
}
|
81
src/proxy_windows.go
Normal file
81
src/proxy_windows.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package fzf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os/exec"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
var shPath atomic.Value
|
||||||
|
|
||||||
|
func sh() (string, error) {
|
||||||
|
if cached := shPath.Load(); cached != nil {
|
||||||
|
return cached.(string), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command("cygpath", "-w", "/usr/bin/sh")
|
||||||
|
bytes, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
sh := strings.TrimSpace(string(bytes))
|
||||||
|
shPath.Store(sh)
|
||||||
|
return sh, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mkfifo(path string, mode uint32) (string, error) {
|
||||||
|
m := strconv.FormatUint(uint64(mode), 8)
|
||||||
|
sh, err := sh()
|
||||||
|
if err != nil {
|
||||||
|
return path, err
|
||||||
|
}
|
||||||
|
cmd := exec.Command(sh, "-c", fmt.Sprintf(`command mkfifo -m %s %q`, m, path))
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return path, err
|
||||||
|
}
|
||||||
|
return path + ".lnk", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func withOutputPipe(output string, task func(io.ReadCloser)) error {
|
||||||
|
sh, err := sh()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cmd := exec.Command(sh, "-c", fmt.Sprintf(`command cat %q`, output))
|
||||||
|
outputFile, err := cmd.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
task(outputFile)
|
||||||
|
cmd.Wait()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func withInputPipe(input string, task func(io.WriteCloser)) error {
|
||||||
|
sh, err := sh()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cmd := exec.Command(sh, "-c", fmt.Sprintf(`command cat - > %q`, input))
|
||||||
|
inputFile, err := cmd.StdinPipe()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
task(inputFile)
|
||||||
|
inputFile.Close()
|
||||||
|
cmd.Wait()
|
||||||
|
return nil
|
||||||
|
}
|
@ -322,7 +322,7 @@ type Terminal struct {
|
|||||||
forcePreview bool
|
forcePreview bool
|
||||||
clickHeaderLine int
|
clickHeaderLine int
|
||||||
clickHeaderColumn int
|
clickHeaderColumn int
|
||||||
tmuxScript string
|
proxyScript string
|
||||||
}
|
}
|
||||||
|
|
||||||
type selectedItem struct {
|
type selectedItem struct {
|
||||||
@ -795,7 +795,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
|
|||||||
jumpLabels: opts.JumpLabels,
|
jumpLabels: opts.JumpLabels,
|
||||||
printer: opts.Printer,
|
printer: opts.Printer,
|
||||||
printsep: opts.PrintSep,
|
printsep: opts.PrintSep,
|
||||||
tmuxScript: opts.TmuxScript,
|
proxyScript: opts.ProxyScript,
|
||||||
merger: EmptyMerger(0),
|
merger: EmptyMerger(0),
|
||||||
selected: make(map[int32]selectedItem),
|
selected: make(map[int32]selectedItem),
|
||||||
reqBox: util.NewEventBox(),
|
reqBox: util.NewEventBox(),
|
||||||
@ -3608,9 +3608,9 @@ func (t *Terminal) Loop() error {
|
|||||||
t.history.append(string(t.input))
|
t.history.append(string(t.input))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(t.tmuxScript) > 0 {
|
if len(t.proxyScript) > 0 {
|
||||||
data := strings.Join(append([]string{command}, t.environ()...), "\x00")
|
data := strings.Join(append([]string{command}, t.environ()...), "\x00")
|
||||||
os.WriteFile(t.tmuxScript, []byte(data), 0600)
|
os.WriteFile(t.proxyScript+becomeSuffix, []byte(data), 0600)
|
||||||
req(reqBecome)
|
req(reqBecome)
|
||||||
} else {
|
} else {
|
||||||
t.executor.Become(t.ttyin, t.environ(), command)
|
t.executor.Become(t.ttyin, t.environ(), command)
|
||||||
|
131
src/tmux.go
131
src/tmux.go
@ -1,81 +1,24 @@
|
|||||||
package fzf
|
package fzf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/junegunn/fzf/src/tui"
|
"github.com/junegunn/fzf/src/tui"
|
||||||
"github.com/junegunn/fzf/src/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func escapeSingleQuote(str string) string {
|
|
||||||
return "'" + strings.ReplaceAll(str, "'", "'\\''") + "'"
|
|
||||||
}
|
|
||||||
|
|
||||||
func runTmux(args []string, opts *Options) (int, error) {
|
func runTmux(args []string, opts *Options) (int, error) {
|
||||||
ns := time.Now().UnixNano()
|
|
||||||
|
|
||||||
output := filepath.Join(os.TempDir(), fmt.Sprintf("fzf-tmux-output-%d", ns))
|
|
||||||
if err := mkfifo(output, 0666); err != nil {
|
|
||||||
return ExitError, err
|
|
||||||
}
|
|
||||||
defer os.Remove(output)
|
|
||||||
|
|
||||||
// Find fzf executable
|
|
||||||
fzf := "fzf"
|
|
||||||
if found, err := os.Executable(); err == nil {
|
|
||||||
fzf = found
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare arguments
|
// Prepare arguments
|
||||||
args = append([]string{"--bind=ctrl-z:ignore"}, args...)
|
fzf := args[0]
|
||||||
|
args = append([]string{"--bind=ctrl-z:ignore"}, args[1:]...)
|
||||||
if opts.BorderShape == tui.BorderUndefined {
|
if opts.BorderShape == tui.BorderUndefined {
|
||||||
args = append(args, "--border")
|
args = append(args, "--border")
|
||||||
}
|
}
|
||||||
args = append(args, "--no-height")
|
argStr := escapeSingleQuote(fzf)
|
||||||
args = append(args, "--no-tmux")
|
|
||||||
argStr := ""
|
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
// %q formatting escapes $'foo\nbar' to "foo\nbar"
|
|
||||||
argStr += " " + escapeSingleQuote(arg)
|
argStr += " " + escapeSingleQuote(arg)
|
||||||
}
|
}
|
||||||
argStr += ` --tmux-script "$0"`
|
argStr += ` --no-tmux --no-height`
|
||||||
|
|
||||||
// Build command
|
|
||||||
var command string
|
|
||||||
if opts.Input == nil && util.IsTty() {
|
|
||||||
command = fmt.Sprintf(`%q%s > %q`, fzf, argStr, output)
|
|
||||||
} else {
|
|
||||||
input := filepath.Join(os.TempDir(), fmt.Sprintf("fzf-tmux-input-%d", ns))
|
|
||||||
if err := mkfifo(input, 0644); err != nil {
|
|
||||||
return ExitError, err
|
|
||||||
}
|
|
||||||
defer os.Remove(input)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
inputFile, err := os.OpenFile(input, os.O_WRONLY, 0)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if opts.Input == nil {
|
|
||||||
io.Copy(inputFile, os.Stdin)
|
|
||||||
} else {
|
|
||||||
for item := range opts.Input {
|
|
||||||
fmt.Fprint(inputFile, item+opts.PrintSep)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inputFile.Close()
|
|
||||||
}()
|
|
||||||
|
|
||||||
command = fmt.Sprintf(`%q%s < %q > %q`, fzf, argStr, input, output)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get current directory
|
// Get current directory
|
||||||
dir, err := os.Getwd()
|
dir, err := os.Getwd()
|
||||||
@ -106,65 +49,9 @@ func runTmux(args []string, opts *Options) (int, error) {
|
|||||||
tmuxArgs = append(tmuxArgs, "-w"+opts.Tmux.width.String())
|
tmuxArgs = append(tmuxArgs, "-w"+opts.Tmux.width.String())
|
||||||
tmuxArgs = append(tmuxArgs, "-h"+opts.Tmux.height.String())
|
tmuxArgs = append(tmuxArgs, "-h"+opts.Tmux.height.String())
|
||||||
|
|
||||||
// To ensure that the options are processed by a POSIX-compliant shell,
|
return runProxy(argStr, func(temp string) *exec.Cmd {
|
||||||
// we need to write the command to a temporary file and execute it with sh.
|
sh, _ := sh()
|
||||||
exports := os.Environ()
|
tmuxArgs = append(tmuxArgs, sh, temp)
|
||||||
for idx, pairStr := range exports {
|
return exec.Command("tmux", tmuxArgs...)
|
||||||
pair := strings.SplitN(pairStr, "=", 2)
|
}, opts, true)
|
||||||
exports[idx] = fmt.Sprintf("export %s=%s", pair[0], escapeSingleQuote(pair[1]))
|
|
||||||
}
|
|
||||||
temp := writeTemporaryFile(append(exports, command), "\n")
|
|
||||||
defer os.Remove(temp)
|
|
||||||
tmuxArgs = append(tmuxArgs, "sh", temp)
|
|
||||||
|
|
||||||
// Take the output
|
|
||||||
go func() {
|
|
||||||
outputFile, err := os.OpenFile(output, os.O_RDONLY, 0)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if opts.Output == nil {
|
|
||||||
io.Copy(os.Stdout, outputFile)
|
|
||||||
} else {
|
|
||||||
reader := bufio.NewReader(outputFile)
|
|
||||||
sep := opts.PrintSep[0]
|
|
||||||
for {
|
|
||||||
item, err := reader.ReadString(sep)
|
|
||||||
if err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
opts.Output <- item
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
outputFile.Close()
|
|
||||||
}()
|
|
||||||
|
|
||||||
cmd := exec.Command("tmux", tmuxArgs...)
|
|
||||||
if err := cmd.Run(); err != nil {
|
|
||||||
if exitError, ok := err.(*exec.ExitError); ok {
|
|
||||||
code := exitError.ExitCode()
|
|
||||||
if code == ExitBecome {
|
|
||||||
data, err := os.ReadFile(temp)
|
|
||||||
if err != nil {
|
|
||||||
return ExitError, err
|
|
||||||
}
|
|
||||||
elems := strings.Split(string(data), "\x00")
|
|
||||||
if len(elems) < 1 {
|
|
||||||
return ExitError, errors.New("invalid become command")
|
|
||||||
}
|
|
||||||
command := elems[0]
|
|
||||||
env := []string{}
|
|
||||||
if len(elems) > 1 {
|
|
||||||
env = elems[1:]
|
|
||||||
}
|
|
||||||
os.Remove(temp)
|
|
||||||
executor := util.NewExecutor(opts.WithShell)
|
|
||||||
executor.Become(tui.TtyIn(), env, command)
|
|
||||||
}
|
|
||||||
return code, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ExitOk, nil
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
//go:build !windows
|
|
||||||
|
|
||||||
package fzf
|
|
||||||
|
|
||||||
import "golang.org/x/sys/unix"
|
|
||||||
|
|
||||||
func mkfifo(path string, mode uint32) error {
|
|
||||||
return unix.Mkfifo(path, mode)
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package fzf
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os/exec"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
func mkfifo(path string, mode uint32) error {
|
|
||||||
m := strconv.FormatUint(uint64(mode), 8)
|
|
||||||
cmd := exec.Command("mkfifo", "-m", m, path)
|
|
||||||
if err := cmd.Run(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -139,7 +139,8 @@ func DurWithin(
|
|||||||
|
|
||||||
// IsTty returns true if stdin is a terminal
|
// IsTty returns true if stdin is a terminal
|
||||||
func IsTty() bool {
|
func IsTty() bool {
|
||||||
return isatty.IsTerminal(os.Stdin.Fd())
|
fd := os.Stdin.Fd()
|
||||||
|
return isatty.IsTerminal(fd) || isatty.IsCygwinTerminal(fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToTty returns true if stdout is a terminal
|
// ToTty returns true if stdout is a terminal
|
||||||
|
9
src/winpty.go
Normal file
9
src/winpty.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package fzf
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
func runWinpty(_ []string, _ *Options) (int, error) {
|
||||||
|
return ExitError, errors.New("Not supported")
|
||||||
|
}
|
29
src/winpty_windows.go
Normal file
29
src/winpty_windows.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package fzf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func runWinpty(args []string, opts *Options) (int, error) {
|
||||||
|
sh, err := sh()
|
||||||
|
if err != nil {
|
||||||
|
return ExitError, err
|
||||||
|
}
|
||||||
|
|
||||||
|
argStr := escapeSingleQuote(args[0])
|
||||||
|
for _, arg := range args[1:] {
|
||||||
|
argStr += " " + escapeSingleQuote(arg)
|
||||||
|
}
|
||||||
|
argStr += ` --no-winpty --no-height`
|
||||||
|
|
||||||
|
return runProxy(argStr, func(temp string) *exec.Cmd {
|
||||||
|
cmd := exec.Command(sh, "-c", fmt.Sprintf(`winpty < /dev/tty > /dev/tty -- sh %q`, temp))
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
return cmd
|
||||||
|
}, opts, false)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user