mirror of
https://github.com/Llewellynvdm/fzf.git
synced 2024-11-10 15:50:56 +00:00
parent
3c34dd8275
commit
fcd7e8768d
14
CHANGELOG.md
14
CHANGELOG.md
@ -1,6 +1,20 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
0.39.0
|
||||
------
|
||||
- If you use `--listen` option without a port number fzf will automatically
|
||||
allocate an available port and export it as `$FZF_PORT` environment
|
||||
variable.
|
||||
```sh
|
||||
# Automatic port assignment
|
||||
fzf --listen --bind 'start:execute-silent:echo $FZF_PORT > /tmp/fzf-port'
|
||||
|
||||
# Say hello
|
||||
curl "localhost:$(cat /tmp/fzf-port)" -d 'preview:echo Hello, fzf is listening on $FZF_PORT.'
|
||||
```
|
||||
- Bug fixes
|
||||
|
||||
0.38.0
|
||||
------
|
||||
- New actions
|
||||
|
@ -738,9 +738,12 @@ ncurses finder only after the input stream is complete.
|
||||
e.g. \fBfzf --multi | fzf --sync\fR
|
||||
.RE
|
||||
.TP
|
||||
.B "--listen=HTTP_PORT"
|
||||
.B "--listen[=HTTP_PORT]"
|
||||
Start HTTP server on the given port. It allows external processes to send
|
||||
actions to perform via POST method.
|
||||
actions to perform via POST method. If the port number is omitted or given as
|
||||
0, fzf will choose the port automatically and export it as \fBFZF_PORT\fR
|
||||
environment variable to the child processes started via \fBexecute\fR and
|
||||
\fBexecute-silent\fR actions.
|
||||
|
||||
e.g.
|
||||
\fB# Start HTTP server on port 6266
|
||||
@ -748,6 +751,9 @@ e.g.
|
||||
|
||||
# Send action to the server
|
||||
curl -XPOST localhost:6266 -d 'reload(seq 100)+change-prompt(hundred> )'
|
||||
|
||||
# Choose port automatically and export it as $FZF_PORT to the child process
|
||||
fzf --listen --bind 'start:execute-silent:echo $FZF_PORT > /tmp/fzf-port'
|
||||
\fR
|
||||
.TP
|
||||
.B "--version"
|
||||
|
@ -116,7 +116,7 @@ const usage = `usage: fzf [options]
|
||||
--read0 Read input delimited by ASCII NUL characters
|
||||
--print0 Print output delimited by ASCII NUL characters
|
||||
--sync Synchronous search for multi-staged filtering
|
||||
--listen=HTTP_PORT Start HTTP server to receive actions (POST /)
|
||||
--listen[=HTTP_PORT] Start HTTP server to receive actions (POST /)
|
||||
--version Display version information and exit
|
||||
|
||||
Environment variables
|
||||
@ -316,7 +316,7 @@ type Options struct {
|
||||
PreviewLabel labelOpts
|
||||
Unicode bool
|
||||
Tabstop int
|
||||
ListenPort int
|
||||
ListenPort *int
|
||||
ClearOnExit bool
|
||||
Version bool
|
||||
}
|
||||
@ -1756,9 +1756,10 @@ func parseOptions(opts *Options, allArgs []string) {
|
||||
case "--tabstop":
|
||||
opts.Tabstop = nextInt(allArgs, &i, "tab stop required")
|
||||
case "--listen":
|
||||
opts.ListenPort = nextInt(allArgs, &i, "listen port required")
|
||||
port := optionalNumeric(allArgs, &i, 0)
|
||||
opts.ListenPort = &port
|
||||
case "--no-listen":
|
||||
opts.ListenPort = 0
|
||||
opts.ListenPort = nil
|
||||
case "--clear":
|
||||
opts.ClearOnExit = true
|
||||
case "--no-clear":
|
||||
@ -1849,7 +1850,8 @@ func parseOptions(opts *Options, allArgs []string) {
|
||||
} else if match, value := optString(arg, "--tabstop="); match {
|
||||
opts.Tabstop = atoi(value)
|
||||
} else if match, value := optString(arg, "--listen="); match {
|
||||
opts.ListenPort = atoi(value)
|
||||
port := atoi(value)
|
||||
opts.ListenPort = &port
|
||||
} else if match, value := optString(arg, "--hscroll-off="); match {
|
||||
opts.HscrollOff = atoi(value)
|
||||
} else if match, value := optString(arg, "--scroll-off="); match {
|
||||
@ -1879,7 +1881,7 @@ func parseOptions(opts *Options, allArgs []string) {
|
||||
errorExit("tab stop must be a positive integer")
|
||||
}
|
||||
|
||||
if opts.ListenPort < 0 || opts.ListenPort > 65535 {
|
||||
if opts.ListenPort != nil && (*opts.ListenPort < 0 || *opts.ListenPort > 65535) {
|
||||
errorExit("invalid listen port")
|
||||
}
|
||||
|
||||
|
@ -19,14 +19,26 @@ const (
|
||||
maxContentLength = 1024 * 1024
|
||||
)
|
||||
|
||||
func startHttpServer(port int, channel chan []*action) error {
|
||||
if port == 0 {
|
||||
return nil
|
||||
func startHttpServer(port int, channel chan []*action) (error, int) {
|
||||
if port < 0 {
|
||||
return nil, port
|
||||
}
|
||||
|
||||
listener, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", port))
|
||||
if err != nil {
|
||||
return fmt.Errorf("port not available: %d", port)
|
||||
return fmt.Errorf("port not available: %d", port), port
|
||||
}
|
||||
if port == 0 {
|
||||
addr := listener.Addr().String()
|
||||
parts := strings.SplitN(addr, ":", 2)
|
||||
if len(parts) < 2 {
|
||||
return fmt.Errorf("cannot extract port: %s", addr), port
|
||||
}
|
||||
var err error
|
||||
port, err = strconv.Atoi(parts[1])
|
||||
if err != nil {
|
||||
return err, port
|
||||
}
|
||||
}
|
||||
|
||||
go func() {
|
||||
@ -45,7 +57,7 @@ func startHttpServer(port int, channel chan []*action) error {
|
||||
listener.Close()
|
||||
}()
|
||||
|
||||
return nil
|
||||
return nil, port
|
||||
}
|
||||
|
||||
// Here we are writing a simplistic HTTP server without using net/http
|
||||
|
@ -203,7 +203,7 @@ type Terminal struct {
|
||||
padding [4]sizeSpec
|
||||
strong tui.Attr
|
||||
unicode bool
|
||||
listenPort int
|
||||
listenPort *int
|
||||
borderShape tui.BorderShape
|
||||
cleanExit bool
|
||||
paused bool
|
||||
@ -538,7 +538,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
||||
}
|
||||
var previewBox *util.EventBox
|
||||
// We need to start previewer if HTTP server is enabled even when --preview option is not specified
|
||||
if len(opts.Preview.command) > 0 || hasPreviewAction(opts) || opts.ListenPort > 0 {
|
||||
if len(opts.Preview.command) > 0 || hasPreviewAction(opts) || opts.ListenPort != nil {
|
||||
previewBox = util.NewEventBox()
|
||||
}
|
||||
strongAttr := tui.Bold
|
||||
@ -694,13 +694,25 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
||||
|
||||
_, t.hasLoadActions = t.keymap[tui.Load.AsEvent()]
|
||||
|
||||
if err := startHttpServer(t.listenPort, t.serverChan); err != nil {
|
||||
errorExit(err.Error())
|
||||
if t.listenPort != nil {
|
||||
err, port := startHttpServer(*t.listenPort, t.serverChan)
|
||||
if err != nil {
|
||||
errorExit(err.Error())
|
||||
}
|
||||
t.listenPort = &port
|
||||
}
|
||||
|
||||
return &t
|
||||
}
|
||||
|
||||
func (t *Terminal) environ() []string {
|
||||
env := os.Environ()
|
||||
if t.listenPort != nil {
|
||||
env = append(env, fmt.Sprintf("FZF_PORT=%d", *t.listenPort))
|
||||
}
|
||||
return env
|
||||
}
|
||||
|
||||
func borderLines(shape tui.BorderShape) int {
|
||||
switch shape {
|
||||
case tui.BorderHorizontal, tui.BorderRounded, tui.BorderSharp, tui.BorderBold, tui.BorderDouble:
|
||||
@ -2248,6 +2260,7 @@ func (t *Terminal) executeCommand(template string, forcePlus bool, background bo
|
||||
}
|
||||
command := t.replacePlaceholder(template, forcePlus, string(t.input), list)
|
||||
cmd := util.ExecCommand(command, false)
|
||||
cmd.Env = t.environ()
|
||||
t.executing.Set(true)
|
||||
if !background {
|
||||
cmd.Stdin = tui.TtyIn()
|
||||
@ -2494,17 +2507,17 @@ func (t *Terminal) Loop() {
|
||||
_, query := t.Input()
|
||||
command := t.replacePlaceholder(commandTemplate, false, string(query), items)
|
||||
cmd := util.ExecCommand(command, true)
|
||||
env := t.environ()
|
||||
if pwindow != nil {
|
||||
height := pwindow.Height()
|
||||
env := os.Environ()
|
||||
lines := fmt.Sprintf("LINES=%d", height)
|
||||
columns := fmt.Sprintf("COLUMNS=%d", pwindow.Width())
|
||||
env = append(env, lines)
|
||||
env = append(env, "FZF_PREVIEW_"+lines)
|
||||
env = append(env, columns)
|
||||
env = append(env, "FZF_PREVIEW_"+columns)
|
||||
cmd.Env = env
|
||||
}
|
||||
cmd.Env = env
|
||||
|
||||
out, _ := cmd.StdoutPipe()
|
||||
cmd.Stderr = cmd.Stdout
|
||||
|
@ -2629,11 +2629,17 @@ class TestGoFZF < TestBase
|
||||
end
|
||||
|
||||
def test_listen
|
||||
tmux.send_keys 'seq 10 | fzf --listen 6266', :Enter
|
||||
tmux.until { |lines| assert_equal 10, lines.item_count }
|
||||
Net::HTTP.post(URI('http://localhost:6266'), 'change-query(yo)+reload(seq 100)+change-prompt:hundred> ')
|
||||
tmux.until { |lines| assert_equal 100, lines.item_count }
|
||||
tmux.until { |lines| assert_equal 'hundred> yo', lines[-1] }
|
||||
{ '--listen 6266' => lambda { URI('http://localhost:6266') },
|
||||
"--listen --sync --bind 'start:execute-silent:echo $FZF_PORT > /tmp/fzf-port'" =>
|
||||
lambda { URI("http://localhost:#{File.read('/tmp/fzf-port').chomp}") } }.each do |opts, fn|
|
||||
tmux.send_keys "seq 10 | fzf #{opts}", :Enter
|
||||
tmux.until { |lines| assert_equal 10, lines.item_count }
|
||||
Net::HTTP.post(fn.call, 'change-query(yo)+reload(seq 100)+change-prompt:hundred> ')
|
||||
tmux.until { |lines| assert_equal 100, lines.item_count }
|
||||
tmux.until { |lines| assert_equal 'hundred> yo', lines[-1] }
|
||||
teardown
|
||||
setup
|
||||
end
|
||||
end
|
||||
|
||||
def test_toggle_alternative_preview_window
|
||||
|
Loading…
Reference in New Issue
Block a user