mirror of https://github.com/junegunn/fzf
Compare commits
189 Commits
Author | SHA1 | Date |
---|---|---|
Samara Jinnah | e023736c30 | 20 hours ago |
Junegunn Choi | dca2262fe6 | 1 day ago |
Junegunn Choi | 0684a20ea3 | 1 day ago |
Junegunn Choi | a1a72bb8d1 | 1 day ago |
ismay | 144d55a5be | 2 days ago |
Junegunn Choi | 7fc13c5cfd | 3 days ago |
Junegunn Choi | dfee7af57b | 4 days ago |
junegunn | 9b0e2daf02 | 5 days ago |
Junegunn Choi | 590060a16b | 7 days ago |
Junegunn Choi | 368294edf6 | 7 days ago |
Junegunn Choi | c4a9ccd6af | 1 week ago |
Junegunn Choi | cbf91f2ed3 | 1 week ago |
Junegunn Choi | b1460d4787 | 1 week ago |
Junegunn Choi | 7dc9e14874 | 1 week ago |
Junegunn Choi | 1616ed543d | 1 week ago |
Junegunn Choi | dc73fba188 | 1 week ago |
Junegunn Choi | ef148dfd37 | 1 week ago |
Junegunn Choi | 93bbb3032d | 1 week ago |
Junegunn Choi | 4c83d8596d | 2 weeks ago |
Junegunn Choi | d453e6d7db | 2 weeks ago |
Junegunn Choi | c29533994f | 2 weeks ago |
Junegunn Choi | 1afe13b5b5 | 2 weeks ago |
Junegunn Choi | 36600eaaa9 | 2 weeks ago |
junegunn | 3ee1fc2034 | 2 weeks ago |
Junegunn Choi | e2f93e5a2d | 2 weeks ago |
Junegunn Choi | cfdf2f1153 | 2 weeks ago |
Junegunn Choi | e042143e3f | 2 weeks ago |
Junegunn Choi | 7c613d0d9b | 2 weeks ago |
Junegunn Choi | b00d46bc14 | 2 weeks ago |
Junegunn Choi | 555b0d235b | 2 weeks ago |
Junegunn Choi | 564daf9a7d | 2 weeks ago |
Junegunn Choi | 41bcbe342f | 2 weeks ago |
LangLangBart | dbe8dc344e | 2 weeks ago |
Junegunn Choi | e33fb59da1 | 2 weeks ago |
Junegunn Choi | 7aa88aa115 | 2 weeks ago |
LangLangBart | 2b6d600879 | 2 weeks ago |
Junegunn Choi | 05c765d442 | 2 weeks ago |
Junegunn Choi | 49b496269c | 2 weeks ago |
Junegunn Choi | 7405925952 | 2 weeks ago |
Junegunn Choi | 3afd543a7e | 2 weeks ago |
Junegunn Choi | b4f2cde5ac | 2 weeks ago |
Junegunn Choi | ed53ef7cee | 2 weeks ago |
Junegunn Choi | 12630b124d | 2 weeks ago |
Junegunn Choi | 1d59ac09d2 | 2 weeks ago |
Junegunn Choi | a8f3a0dd59 | 2 weeks ago |
Konstantin-Glukhov | 124cd70710 | 2 weeks ago |
Junegunn Choi | 782de139c8 | 2 weeks ago |
Junegunn Choi | 32eb32ee5e | 3 weeks ago |
Junegunn Choi | 2f51eb2b41 | 3 weeks ago |
Junegunn Choi | 0ccbd79e10 | 3 weeks ago |
junegunn | 99bd6de541 | 3 weeks ago |
Junegunn Choi | 1fef36e4bc | 3 weeks ago |
Junegunn Choi | 89375005b5 | 3 weeks ago |
Junegunn Choi | 88e78c9193 | 3 weeks ago |
Junegunn Choi | 29a19ad080 | 3 weeks ago |
Junegunn Choi | 2a039ab746 | 3 weeks ago |
Junegunn Choi | 7e9a0fcdbd | 3 weeks ago |
Junegunn Choi | 7a97532547 | 3 weeks ago |
Junegunn Choi | 996abb2831 | 3 weeks ago |
Junegunn Choi | da500a358f | 3 weeks ago |
Junegunn Choi | c36b846acc | 3 weeks ago |
Junegunn Choi | d9b5c9b2be | 3 weeks ago |
Junegunn Choi | 3dee8778d0 | 3 weeks ago |
Junegunn Choi | d4216b0dcc | 3 weeks ago |
Enno | bfe2bf4dce | 3 weeks ago |
Junegunn Choi | 561f9291fd | 3 weeks ago |
Junegunn Choi | b5b0d6b3ea | 3 weeks ago |
Junegunn Choi | a90426b7ca | 3 weeks ago |
Junegunn Choi | 303c3bae7f | 3 weeks ago |
Junegunn Choi | 6b4358f641 | 3 weeks ago |
Junegunn Choi | 552158f3ad | 3 weeks ago |
Junegunn Choi | 7205203dc8 | 3 weeks ago |
Junegunn Choi | 0cadf70072 | 3 weeks ago |
Junegunn Choi | 076b3d0a9a | 3 weeks ago |
Junegunn Choi | 7b0c9e04d3 | 4 weeks ago |
Junegunn Choi | 573df524fe | 4 weeks ago |
Junegunn Choi | aee417c46a | 4 weeks ago |
Junegunn Choi | 04db44067d | 4 weeks ago |
Junegunn Choi | 5b204c54f9 | 4 weeks ago |
junegunn | daa602422d | 4 weeks ago |
Junegunn Choi | 04dfb14e32 | 4 weeks ago |
Junegunn Choi | c24256cba3 | 4 weeks ago |
Junegunn Choi | 685fb71d89 | 4 weeks ago |
Junegunn Choi | 83b6033906 | 4 weeks ago |
Zhizhen He | 01e7668915 | 4 weeks ago |
Enno | 0994d9c881 | 4 weeks ago |
LangLangBart | 030428ba43 | 1 month ago |
Junegunn Choi | 8a110e02b9 | 1 month ago |
Junegunn Choi | 86d92c17c4 | 1 month ago |
Junegunn Choi | c4cc7891b4 | 1 month ago |
Junegunn Choi | 218843b9f1 | 1 month ago |
Junegunn Choi | d274d093af | 1 month ago |
Junegunn Choi | 6432f00f0d | 1 month ago |
junegunn | 4e9e842aa4 | 1 month ago |
LangLangBart | 07880ca441 | 1 month ago |
Junegunn Choi | bcda25a513 | 1 month ago |
Junegunn Choi | 8256fcde15 | 1 month ago |
Junegunn Choi | af65aa298a | 1 month ago |
Junegunn Choi | 6834d17844 | 1 month ago |
Junegunn Choi | ed511d7867 | 1 month ago |
Junegunn Choi | cd8d736a9f | 1 month ago |
Junegunn Choi | 0952b2dfd4 | 1 month ago |
Junegunn Choi | 4bedd33c59 | 1 month ago |
Junegunn Choi | c5fb0c43f9 | 1 month ago |
Junegunn Choi | 9e4780510e | 1 month ago |
Junegunn Choi | e8405f40fe | 1 month ago |
dependabot[bot] | 065b9e6fb2 | 1 month ago |
dependabot[bot] | 98141ca7d8 | 1 month ago |
Junegunn Choi | 501577ab28 | 1 month ago |
Junegunn Choi | 5669f48343 | 1 month ago |
Junegunn Choi | 24ff66d4a9 | 1 month ago |
Junegunn Choi | bf184449bc | 1 month ago |
Kuremu | 7b98c2c653 | 1 month ago |
Junegunn Choi | b6add2a257 | 1 month ago |
Junegunn Choi | 2bd41f1330 | 1 month ago |
Junegunn Choi | c37cd11ca5 | 1 month ago |
Junegunn Choi | 9dee8edc0c | 1 month ago |
Junegunn Choi | f6aa28c380 | 1 month ago |
cyqsimon | dba1644518 | 1 month ago |
Junegunn Choi | 260a65b0fb | 1 month ago |
Junegunn Choi | 835d2fb98c | 1 month ago |
Charlie Vieth | a9811addaa | 1 month ago |
dependabot[bot] | ee9d88b637 | 2 months ago |
Junegunn Choi | 194a763c46 | 2 months ago |
Junegunn Choi | 8d74446bef | 2 months ago |
Junegunn Choi | 7ed6c7905c | 2 months ago |
Junegunn Choi | 159a37fa37 | 2 months ago |
junegunn | f39ae0e7c1 | 2 months ago |
Junegunn Choi | 4a68eac99b | 2 months ago |
Junegunn Choi | 2665580120 | 2 months ago |
Junegunn Choi | a4391aeedd | 2 months ago |
dependabot[bot] | b86a967ee2 | 2 months ago |
Junegunn Choi | 608232568b | 2 months ago |
Junegunn Choi | 7f85beccb5 | 2 months ago |
Junegunn Choi | 767f1255ab | 2 months ago |
Junegunn Choi | fddbfe7b0e | 2 months ago |
Junegunn Choi | 4ab7fdc28e | 2 months ago |
Junegunn Choi | e352b68878 | 2 months ago |
Junegunn Choi | 207deeadba | 2 months ago |
Cheng | d18d92f925 | 2 months ago |
junegunn | af3ce47c44 | 2 months ago |
Junegunn Choi | d8bfb6712d | 2 months ago |
Junegunn Choi | f864f8b5f7 | 2 months ago |
Junegunn Choi | 31d72efba7 | 2 months ago |
LangLangBart | d169c951f3 | 2 months ago |
Junegunn Choi | 90d7e38909 | 2 months ago |
hidewrong | 938f23e429 | 2 months ago |
Junegunn Choi | f97d275413 | 2 months ago |
Junegunn Choi | 3acb4ca90e | 2 months ago |
Junegunn Choi | e86b81bbf5 | 2 months ago |
Junegunn Choi | a5447b8b75 | 2 months ago |
Junegunn Choi | 7ce6452d83 | 2 months ago |
junegunn | 5643a306bd | 2 months ago |
Charlie Vieth | 3c877c504b | 2 months ago |
Junegunn Choi | 892d1acccb | 2 months ago |
Junegunn Choi | 1a9c282f76 | 2 months ago |
Junegunn Choi | fd1ba46f77 | 2 months ago |
Junegunn Choi | a4745626dd | 2 months ago |
dependabot[bot] | 17bb7ad278 | 2 months ago |
Junegunn Choi | 152988c17b | 2 months ago |
Junegunn Choi | 4cd37fc02b | 2 months ago |
LangLangBart | 69b9d674a3 | 2 months ago |
junegunn | bad8061547 | 2 months ago |
Junegunn Choi | 62963dcefd | 2 months ago |
Junegunn Choi | 68a35e4735 | 2 months ago |
Charlie Vieth | 9b9ad77e1c | 2 months ago |
Junegunn Choi | 118b4d4a01 | 2 months ago |
Junegunn Choi | da14ab6f16 | 2 months ago |
Junegunn Choi | 09a4ca6ab5 | 2 months ago |
Junegunn Choi | 8a2df79711 | 2 months ago |
Junegunn Choi | c30e486b64 | 2 months ago |
Junegunn Choi | a575c0c54b | 2 months ago |
Junegunn Choi | 77fe96ac0d | 2 months ago |
Junegunn Choi | 5234c3759a | 2 months ago |
Junegunn Choi | 41b3511ad9 | 2 months ago |
Junegunn Choi | 128e4a2e8d | 2 months ago |
junegunn | 07ac90d798 | 2 months ago |
Emilio Vesprini | 7de87a9b2c | 3 months ago |
Junegunn Choi | dff865239a | 3 months ago |
Junegunn Choi | 07f8f70c5b | 3 months ago |
Matthieu Cneude | f625c5aabe | 3 months ago |
Junegunn Choi | 8a74976c1f | 3 months ago |
Junegunn Choi | b6bfd4a5cb | 3 months ago |
Junegunn Choi | 008fb9d258 | 3 months ago |
Junegunn Choi | db6db49ed6 | 3 months ago |
Junegunn Choi | 05453881c3 | 3 months ago |
Junegunn Choi | 5e47ab9431 | 3 months ago |
LangLangBart | ec70acd0b9 | 3 months ago |
zeertzjq | 25e61056b6 | 3 months ago |
@ -1,22 +0,0 @@
|
||||
<!-- ISSUES NOT FOLLOWING THIS TEMPLATE WILL BE CLOSED AND DELETED -->
|
||||
|
||||
<!-- Check all that apply [x] -->
|
||||
|
||||
- [ ] I have read through the manual page (`man fzf`)
|
||||
- [ ] I have the latest version of fzf
|
||||
- [ ] I have searched through the existing issues
|
||||
|
||||
## Info
|
||||
|
||||
- OS
|
||||
- [ ] Linux
|
||||
- [ ] Mac OS X
|
||||
- [ ] Windows
|
||||
- [ ] Etc.
|
||||
- Shell
|
||||
- [ ] bash
|
||||
- [ ] zsh
|
||||
- [ ] fish
|
||||
|
||||
## Problem / Steps to reproduce
|
||||
|
@ -0,0 +1,49 @@
|
||||
---
|
||||
name: Issue Template
|
||||
description: Report a problem or bug related to fzf to help us improve
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: ISSUES NOT FOLLOWING THIS TEMPLATE WILL BE CLOSED AND DELETED
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Checklist
|
||||
options:
|
||||
- label: I have read through the manual page (`man fzf`)
|
||||
required: true
|
||||
- label: I have searched through the existing issues
|
||||
required: true
|
||||
- label: For bug reports, I have checked if the bug is reproducible in the latest version of fzf
|
||||
required: false
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: Output of `fzf --version`
|
||||
placeholder: e.g. 0.48.1 (d579e33)
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: OS
|
||||
options:
|
||||
- label: Linux
|
||||
- label: macOS
|
||||
- label: Windows
|
||||
- label: Etc.
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Shell
|
||||
options:
|
||||
- label: bash
|
||||
- label: zsh
|
||||
- label: fish
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Problem / Steps to reproduce
|
||||
validations:
|
||||
required: true
|
@ -0,0 +1,35 @@
|
||||
package fzf
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func WriteTemporaryFile(data []string, printSep string) string {
|
||||
f, err := os.CreateTemp("", "fzf-temp-*")
|
||||
if err != nil {
|
||||
// Unable to create temporary file
|
||||
// FIXME: Should we terminate the program?
|
||||
return ""
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
f.WriteString(strings.Join(data, printSep))
|
||||
f.WriteString(printSep)
|
||||
return f.Name()
|
||||
}
|
||||
|
||||
func removeFiles(files []string) {
|
||||
for _, filename := range files {
|
||||
os.Remove(filename)
|
||||
}
|
||||
}
|
||||
|
||||
func stringBytes(data string) []byte {
|
||||
return unsafe.Slice(unsafe.StringData(data), len(data))
|
||||
}
|
||||
|
||||
func byteString(data []byte) string {
|
||||
return unsafe.String(unsafe.SliceData(data), len(data))
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,13 @@
|
||||
//go:build !pprof
|
||||
// +build !pprof
|
||||
|
||||
package fzf
|
||||
|
||||
import "errors"
|
||||
|
||||
func (o *Options) initProfiling() error {
|
||||
if o.CPUProfile != "" || o.MEMProfile != "" || o.BlockProfile != "" || o.MutexProfile != "" {
|
||||
return errors.New("error: profiling not supported: FZF must be built with '-tags=pprof' to enable profiling")
|
||||
}
|
||||
return nil
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
//go:build pprof
|
||||
// +build pprof
|
||||
|
||||
package fzf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
|
||||
"github.com/junegunn/fzf/src/util"
|
||||
)
|
||||
|
||||
func (o *Options) initProfiling() error {
|
||||
if o.CPUProfile != "" {
|
||||
f, err := os.Create(o.CPUProfile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create CPU profile: %w", err)
|
||||
}
|
||||
|
||||
if err := pprof.StartCPUProfile(f); err != nil {
|
||||
return fmt.Errorf("could not start CPU profile: %w", err)
|
||||
}
|
||||
|
||||
util.AtExit(func() {
|
||||
pprof.StopCPUProfile()
|
||||
if err := f.Close(); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Error: closing cpu profile:", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
stopProfile := func(name string, f *os.File) {
|
||||
if err := pprof.Lookup(name).WriteTo(f, 0); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: could not write %s profile: %v\n", name, err)
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: closing %s profile: %v\n", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
if o.MEMProfile != "" {
|
||||
f, err := os.Create(o.MEMProfile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create MEM profile: %w", err)
|
||||
}
|
||||
util.AtExit(func() {
|
||||
runtime.GC()
|
||||
stopProfile("allocs", f)
|
||||
})
|
||||
}
|
||||
|
||||
if o.BlockProfile != "" {
|
||||
runtime.SetBlockProfileRate(1)
|
||||
f, err := os.Create(o.BlockProfile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create BLOCK profile: %w", err)
|
||||
}
|
||||
util.AtExit(func() { stopProfile("block", f) })
|
||||
}
|
||||
|
||||
if o.MutexProfile != "" {
|
||||
runtime.SetMutexProfileFraction(1)
|
||||
f, err := os.Create(o.MutexProfile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create MUTEX profile: %w", err)
|
||||
}
|
||||
util.AtExit(func() { stopProfile("mutex", f) })
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
//go:build pprof
|
||||
// +build pprof
|
||||
|
||||
package fzf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/junegunn/fzf/src/util"
|
||||
)
|
||||
|
||||
// runInitProfileTests is an internal flag used TestInitProfiling
|
||||
var runInitProfileTests = flag.Bool("test-init-profile", false, "run init profile tests")
|
||||
|
||||
func TestInitProfiling(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("short test")
|
||||
}
|
||||
|
||||
// Run this test in a separate process since it interferes with
|
||||
// profiling and modifies the global atexit state. Without this
|
||||
// running `go test -bench . -cpuprofile cpu.out` will fail.
|
||||
if !*runInitProfileTests {
|
||||
t.Parallel()
|
||||
|
||||
// Make sure we are not the child process.
|
||||
if os.Getenv("_FZF_CHILD_PROC") != "" {
|
||||
t.Fatal("already running as child process!")
|
||||
}
|
||||
|
||||
cmd := exec.Command(os.Args[0],
|
||||
"-test.timeout", "30s",
|
||||
"-test.run", "^"+t.Name()+"$",
|
||||
"-test-init-profile",
|
||||
)
|
||||
cmd.Env = append(os.Environ(), "_FZF_CHILD_PROC=1")
|
||||
|
||||
out, err := cmd.CombinedOutput()
|
||||
out = bytes.TrimSpace(out)
|
||||
if err != nil {
|
||||
t.Fatalf("Child test process failed: %v:\n%s", err, out)
|
||||
}
|
||||
// Make sure the test actually ran
|
||||
if bytes.Contains(out, []byte("no tests to run")) {
|
||||
t.Fatalf("Failed to run test %q:\n%s", t.Name(), out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Child process
|
||||
|
||||
tempdir := t.TempDir()
|
||||
t.Cleanup(util.RunAtExitFuncs)
|
||||
|
||||
o := Options{
|
||||
CPUProfile: filepath.Join(tempdir, "cpu.prof"),
|
||||
MEMProfile: filepath.Join(tempdir, "mem.prof"),
|
||||
BlockProfile: filepath.Join(tempdir, "block.prof"),
|
||||
MutexProfile: filepath.Join(tempdir, "mutex.prof"),
|
||||
}
|
||||
if err := o.initProfiling(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
profiles := []string{
|
||||
o.CPUProfile,
|
||||
o.MEMProfile,
|
||||
o.BlockProfile,
|
||||
o.MutexProfile,
|
||||
}
|
||||
for _, name := range profiles {
|
||||
if _, err := os.Stat(name); err != nil {
|
||||
t.Errorf("Failed to create profile %s: %v", filepath.Base(name), err)
|
||||
}
|
||||
}
|
||||
|
||||
util.RunAtExitFuncs()
|
||||
|
||||
for _, name := range profiles {
|
||||
if _, err := os.Stat(name); err != nil {
|
||||
t.Errorf("Failed to write profile %s: %v", filepath.Base(name), err)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,146 @@
|
||||
package fzf
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"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 += ` --no-force-tty-in --proxy-script "$0"`
|
||||
if opts.Input == nil && (opts.ForceTtyIn || util.IsTty(os.Stdin)) {
|
||||
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)
|
||||
cmd.Stderr = os.Stderr
|
||||
intChan := make(chan os.Signal, 1)
|
||||
defer close(intChan)
|
||||
go func() {
|
||||
if sig, valid := <-intChan; valid {
|
||||
cmd.Process.Signal(sig)
|
||||
}
|
||||
}()
|
||||
signal.Notify(intChan, os.Interrupt)
|
||||
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)
|
||||
ttyin, err := tui.TtyIn()
|
||||
if err != nil {
|
||||
return ExitError, err
|
||||
}
|
||||
executor.Become(ttyin, env, command)
|
||||
}
|
||||
return code, err
|
||||
}
|
||||
}
|
||||
|
||||
return ExitOk, nil
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,57 @@
|
||||
package fzf
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/junegunn/fzf/src/tui"
|
||||
)
|
||||
|
||||
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 {
|
||||
args = append(args, "--border")
|
||||
}
|
||||
argStr := escapeSingleQuote(fzf)
|
||||
for _, arg := range args {
|
||||
argStr += " " + escapeSingleQuote(arg)
|
||||
}
|
||||
argStr += ` --no-tmux --no-height`
|
||||
|
||||
// Get current directory
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
dir = "."
|
||||
}
|
||||
|
||||
// Set tmux options for popup placement
|
||||
// C Both The centre of the terminal
|
||||
// R -x The right side of the terminal
|
||||
// P Both The bottom left of the pane
|
||||
// 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}
|
||||
switch opts.Tmux.position {
|
||||
case posUp:
|
||||
tmuxArgs = append(tmuxArgs, "-xC", "-y0")
|
||||
case posDown:
|
||||
tmuxArgs = append(tmuxArgs, "-xC", "-yS")
|
||||
case posLeft:
|
||||
tmuxArgs = append(tmuxArgs, "-x0", "-yC")
|
||||
case posRight:
|
||||
tmuxArgs = append(tmuxArgs, "-xR", "-yC")
|
||||
case posCenter:
|
||||
tmuxArgs = append(tmuxArgs, "-xC", "-yC")
|
||||
}
|
||||
tmuxArgs = append(tmuxArgs, "-w"+opts.Tmux.width.String())
|
||||
tmuxArgs = append(tmuxArgs, "-h"+opts.Tmux.height.String())
|
||||
|
||||
return runProxy(argStr, func(temp string) *exec.Cmd {
|
||||
sh, _ := sh()
|
||||
tmuxArgs = append(tmuxArgs, sh, temp)
|
||||
return exec.Command("tmux", tmuxArgs...)
|
||||
}, opts, true)
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
// Code generated by "stringer -type=EventType"; DO NOT EDIT.
|
||||
|
||||
package tui
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[Rune-0]
|
||||
_ = x[CtrlA-1]
|
||||
_ = x[CtrlB-2]
|
||||
_ = x[CtrlC-3]
|
||||
_ = x[CtrlD-4]
|
||||
_ = x[CtrlE-5]
|
||||
_ = x[CtrlF-6]
|
||||
_ = x[CtrlG-7]
|
||||
_ = x[CtrlH-8]
|
||||
_ = x[Tab-9]
|
||||
_ = x[CtrlJ-10]
|
||||
_ = x[CtrlK-11]
|
||||
_ = x[CtrlL-12]
|
||||
_ = x[CtrlM-13]
|
||||
_ = x[CtrlN-14]
|
||||
_ = x[CtrlO-15]
|
||||
_ = x[CtrlP-16]
|
||||
_ = x[CtrlQ-17]
|
||||
_ = x[CtrlR-18]
|
||||
_ = x[CtrlS-19]
|
||||
_ = x[CtrlT-20]
|
||||
_ = x[CtrlU-21]
|
||||
_ = x[CtrlV-22]
|
||||
_ = x[CtrlW-23]
|
||||
_ = x[CtrlX-24]
|
||||
_ = x[CtrlY-25]
|
||||
_ = x[CtrlZ-26]
|
||||
_ = x[Esc-27]
|
||||
_ = x[CtrlSpace-28]
|
||||
_ = x[CtrlDelete-29]
|
||||
_ = x[CtrlBackSlash-30]
|
||||
_ = x[CtrlRightBracket-31]
|
||||
_ = x[CtrlCaret-32]
|
||||
_ = x[CtrlSlash-33]
|
||||
_ = x[ShiftTab-34]
|
||||
_ = x[Backspace-35]
|
||||
_ = x[Delete-36]
|
||||
_ = x[PageUp-37]
|
||||
_ = x[PageDown-38]
|
||||
_ = x[Up-39]
|
||||
_ = x[Down-40]
|
||||
_ = x[Left-41]
|
||||
_ = x[Right-42]
|
||||
_ = x[Home-43]
|
||||
_ = x[End-44]
|
||||
_ = x[Insert-45]
|
||||
_ = x[ShiftUp-46]
|
||||
_ = x[ShiftDown-47]
|
||||
_ = x[ShiftLeft-48]
|
||||
_ = x[ShiftRight-49]
|
||||
_ = x[ShiftDelete-50]
|
||||
_ = x[F1-51]
|
||||
_ = x[F2-52]
|
||||
_ = x[F3-53]
|
||||
_ = x[F4-54]
|
||||
_ = x[F5-55]
|
||||
_ = x[F6-56]
|
||||
_ = x[F7-57]
|
||||
_ = x[F8-58]
|
||||
_ = x[F9-59]
|
||||
_ = x[F10-60]
|
||||
_ = x[F11-61]
|
||||
_ = x[F12-62]
|
||||
_ = x[AltBackspace-63]
|
||||
_ = x[AltUp-64]
|
||||
_ = x[AltDown-65]
|
||||
_ = x[AltLeft-66]
|
||||
_ = x[AltRight-67]
|
||||
_ = x[AltShiftUp-68]
|
||||
_ = x[AltShiftDown-69]
|
||||
_ = x[AltShiftLeft-70]
|
||||
_ = x[AltShiftRight-71]
|
||||
_ = x[Alt-72]
|
||||
_ = x[CtrlAlt-73]
|
||||
_ = x[Invalid-74]
|
||||
_ = x[Fatal-75]
|
||||
_ = x[Mouse-76]
|
||||
_ = x[DoubleClick-77]
|
||||
_ = x[LeftClick-78]
|
||||
_ = x[RightClick-79]
|
||||
_ = x[SLeftClick-80]
|
||||
_ = x[SRightClick-81]
|
||||
_ = x[ScrollUp-82]
|
||||
_ = x[ScrollDown-83]
|
||||
_ = x[SScrollUp-84]
|
||||
_ = x[SScrollDown-85]
|
||||
_ = x[PreviewScrollUp-86]
|
||||
_ = x[PreviewScrollDown-87]
|
||||
_ = x[Resize-88]
|
||||
_ = x[Change-89]
|
||||
_ = x[BackwardEOF-90]
|
||||
_ = x[Start-91]
|
||||
_ = x[Load-92]
|
||||
_ = x[Focus-93]
|
||||
_ = x[One-94]
|
||||
_ = x[Zero-95]
|
||||
_ = x[Result-96]
|
||||
_ = x[Jump-97]
|
||||
_ = x[JumpCancel-98]
|
||||
_ = x[ClickHeader-99]
|
||||
}
|
||||
|
||||
const _EventType_name = "RuneCtrlACtrlBCtrlCCtrlDCtrlECtrlFCtrlGCtrlHTabCtrlJCtrlKCtrlLCtrlMCtrlNCtrlOCtrlPCtrlQCtrlRCtrlSCtrlTCtrlUCtrlVCtrlWCtrlXCtrlYCtrlZEscCtrlSpaceCtrlDeleteCtrlBackSlashCtrlRightBracketCtrlCaretCtrlSlashShiftTabBackspaceDeletePageUpPageDownUpDownLeftRightHomeEndInsertShiftUpShiftDownShiftLeftShiftRightShiftDeleteF1F2F3F4F5F6F7F8F9F10F11F12AltBackspaceAltUpAltDownAltLeftAltRightAltShiftUpAltShiftDownAltShiftLeftAltShiftRightAltCtrlAltInvalidFatalMouseDoubleClickLeftClickRightClickSLeftClickSRightClickScrollUpScrollDownSScrollUpSScrollDownPreviewScrollUpPreviewScrollDownResizeChangeBackwardEOFStartLoadFocusOneZeroResultJumpJumpCancelClickHeader"
|
||||
|
||||
var _EventType_index = [...]uint16{0, 4, 9, 14, 19, 24, 29, 34, 39, 44, 47, 52, 57, 62, 67, 72, 77, 82, 87, 92, 97, 102, 107, 112, 117, 122, 127, 132, 135, 144, 154, 167, 183, 192, 201, 209, 218, 224, 230, 238, 240, 244, 248, 253, 257, 260, 266, 273, 282, 291, 301, 312, 314, 316, 318, 320, 322, 324, 326, 328, 330, 333, 336, 339, 351, 356, 363, 370, 378, 388, 400, 412, 425, 428, 435, 442, 447, 452, 463, 472, 482, 492, 503, 511, 521, 530, 541, 556, 573, 579, 585, 596, 601, 605, 610, 613, 617, 623, 627, 637, 648}
|
||||
|
||||
func (i EventType) String() string {
|
||||
if i < 0 || i >= EventType(len(_EventType_index)-1) {
|
||||
return "EventType(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _EventType_name[_EventType_index[i]:_EventType_index[i+1]]
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var atExitFuncs []func()
|
||||
|
||||
// AtExit registers the function fn to be called on program termination.
|
||||
// The functions will be called in reverse order they were registered.
|
||||
func AtExit(fn func()) {
|
||||
if fn == nil {
|
||||
panic("AtExit called with nil func")
|
||||
}
|
||||
once := &sync.Once{}
|
||||
atExitFuncs = append(atExitFuncs, func() {
|
||||
once.Do(fn)
|
||||
})
|
||||
}
|
||||
|
||||
// RunAtExitFuncs runs any functions registered with AtExit().
|
||||
func RunAtExitFuncs() {
|
||||
fns := atExitFuncs
|
||||
for i := len(fns) - 1; i >= 0; i-- {
|
||||
fns[i]()
|
||||
}
|
||||
atExitFuncs = nil
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAtExit(t *testing.T) {
|
||||
want := []int{3, 2, 1, 0}
|
||||
var called []int
|
||||
for i := 0; i < 4; i++ {
|
||||
n := i
|
||||
AtExit(func() { called = append(called, n) })
|
||||
}
|
||||
RunAtExitFuncs()
|
||||
if !reflect.DeepEqual(called, want) {
|
||||
t.Errorf("AtExit: want call order: %v got: %v", want, called)
|
||||
}
|
||||
|
||||
RunAtExitFuncs()
|
||||
if !reflect.DeepEqual(called, want) {
|
||||
t.Error("AtExit: should only call exit funcs once")
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
//go:build !windows
|
||||
|
||||
package fzf
|
||||
|
||||
import "errors"
|
||||
|
||||
func needWinpty(_ *Options) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func runWinpty(_ []string, _ *Options) (int, error) {
|
||||
return ExitError, errors.New("Not supported")
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
//go:build windows
|
||||
|
||||
package fzf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/junegunn/fzf/src/util"
|
||||
)
|
||||
|
||||
func isMintty345() bool {
|
||||
return util.CompareVersions(os.Getenv("TERM_PROGRAM_VERSION"), "3.4.5") >= 0
|
||||
}
|
||||
|
||||
func needWinpty(opts *Options) bool {
|
||||
if os.Getenv("TERM_PROGRAM") != "mintty" {
|
||||
return false
|
||||
}
|
||||
if isMintty345() {
|
||||
/*
|
||||
See: https://github.com/junegunn/fzf/issues/3809
|
||||
|
||||
"MSYS=enable_pcon" allows fzf to run properly on mintty 3.4.5 or later.
|
||||
*/
|
||||
if strings.Contains(os.Getenv("MSYS"), "enable_pcon") {
|
||||
return false
|
||||
}
|
||||
|
||||
// Setting the environment variable here unfortunately doesn't help,
|
||||
// so we need to start a child process with "MSYS=enable_pcon"
|
||||
// os.Setenv("MSYS", "enable_pcon")
|
||||
return true
|
||||
}
|
||||
if opts.NoWinpty {
|
||||
return false
|
||||
}
|
||||
if _, err := exec.LookPath("winpty"); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
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`
|
||||
|
||||
if isMintty345() {
|
||||
return runProxy(argStr, func(temp string) *exec.Cmd {
|
||||
cmd := exec.Command(sh, temp)
|
||||
cmd.Env = append(os.Environ(), "MSYS=enable_pcon")
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
return cmd
|
||||
}, opts, false)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue