mirror of
https://github.com/Llewellynvdm/fzf.git
synced 2024-06-03 16:00:49 +00:00
Revert "Add GET endpoints for getting the state of the finder"
This reverts commit 750b2a6313
.
This can cause a deadlock if the endpoints are accessed in the core event
loop via execute action.
fzf --listen 6266 --bind 'space:execute:curl localhost:6266'
Technically, there's no reason to use the API because the information is
already available via `{}` and `{q}`, but I'd like to completely remove
the risk of misuse.
This commit is contained in:
parent
750b2a6313
commit
b7bb973118
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -4,20 +4,13 @@ CHANGELOG
|
||||||
0.36.0
|
0.36.0
|
||||||
------
|
------
|
||||||
- Added `--listen=HTTP_PORT` option to start HTTP server. It allows external
|
- Added `--listen=HTTP_PORT` option to start HTTP server. It allows external
|
||||||
processes to send actions to perform via POST method, or retrieve the
|
processes to send actions to perform via POST method.
|
||||||
current state of the finder.
|
|
||||||
```sh
|
```sh
|
||||||
# Start HTTP server on port 6266
|
# Start HTTP server on port 6266
|
||||||
fzf --listen 6266
|
fzf --listen 6266
|
||||||
|
|
||||||
# Send action to the server via POST method
|
# Send actions to the server
|
||||||
curl localhost:6266 -d 'reload(seq 100)+change-prompt(hundred> )'
|
curl -XPOST localhost:6266 -d 'reload(seq 100)+change-prompt(hundred> )'
|
||||||
|
|
||||||
# Retrieve the current item
|
|
||||||
curl localhost:6266
|
|
||||||
|
|
||||||
# Retrieve the query string
|
|
||||||
curl localhost:6266/query
|
|
||||||
```
|
```
|
||||||
- Added `next-selected` and `prev-selected` actions to move between selected
|
- Added `next-selected` and `prev-selected` actions to move between selected
|
||||||
items
|
items
|
||||||
|
|
|
@ -723,21 +723,14 @@ e.g. \fBfzf --multi | fzf --sync\fR
|
||||||
.TP
|
.TP
|
||||||
.B "--listen=HTTP_PORT"
|
.B "--listen=HTTP_PORT"
|
||||||
Start HTTP server on the given port. It allows external processes to send
|
Start HTTP server on the given port. It allows external processes to send
|
||||||
actions to perform via POST method, or retrieve the current state of the
|
actions to perform via POST method.
|
||||||
finder.
|
|
||||||
|
|
||||||
e.g.
|
e.g.
|
||||||
\fB# Start HTTP server on port 6266
|
\fB# Start HTTP server on port 6266
|
||||||
fzf --listen 6266
|
fzf --listen 6266
|
||||||
|
|
||||||
# Send action to the server via POST method
|
# Send action to the server
|
||||||
curl localhost:6266 -d 'reload(seq 100)+change-prompt(hundred> )'
|
curl -XPOST localhost:6266 -d 'reload(seq 100)+change-prompt(hundred> )'
|
||||||
|
|
||||||
# Retrieve the current item
|
|
||||||
curl localhost:6266
|
|
||||||
|
|
||||||
# Retrieve the query string
|
|
||||||
curl localhost:6266/query
|
|
||||||
\fR
|
\fR
|
||||||
|
|
||||||
The port number is exported as \fB$FZF_LISTEN_PORT\fR on the child processes.
|
The port number is exported as \fB$FZF_LISTEN_PORT\fR on the child processes.
|
||||||
|
|
|
@ -113,7 +113,7 @@ const usage = `usage: fzf [options]
|
||||||
--read0 Read input delimited by ASCII NUL characters
|
--read0 Read input delimited by ASCII NUL characters
|
||||||
--print0 Print output delimited by ASCII NUL characters
|
--print0 Print output delimited by ASCII NUL characters
|
||||||
--sync Synchronous search for multi-staged filtering
|
--sync Synchronous search for multi-staged filtering
|
||||||
--listen=HTTP_PORT Start HTTP server to receive actions
|
--listen=HTTP_PORT Start HTTP server to receive actions (POST /)
|
||||||
--version Display version information and exit
|
--version Display version information and exit
|
||||||
|
|
||||||
Environment variables
|
Environment variables
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -14,18 +13,13 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
crlf = "\r\n"
|
crlf = "\r\n"
|
||||||
httpPattern = "^(GET|POST) (/[^ ]*) HTTP"
|
|
||||||
httpOk = "HTTP/1.1 200 OK" + crlf
|
httpOk = "HTTP/1.1 200 OK" + crlf
|
||||||
httpBadRequest = "HTTP/1.1 400 Bad Request" + crlf
|
httpBadRequest = "HTTP/1.1 400 Bad Request" + crlf
|
||||||
httpReadTimeout = 10 * time.Second
|
httpReadTimeout = 10 * time.Second
|
||||||
maxContentLength = 1024 * 1024
|
maxContentLength = 1024 * 1024
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func startHttpServer(port int, channel chan []*action) error {
|
||||||
httpRegexp *regexp.Regexp
|
|
||||||
)
|
|
||||||
|
|
||||||
func startHttpServer(port int, requestChan chan []*action, responseChan chan string) error {
|
|
||||||
if port == 0 {
|
if port == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -35,7 +29,6 @@ func startHttpServer(port int, requestChan chan []*action, responseChan chan str
|
||||||
return fmt.Errorf("port not available: %d", port)
|
return fmt.Errorf("port not available: %d", port)
|
||||||
}
|
}
|
||||||
|
|
||||||
httpRegexp = regexp.MustCompile(httpPattern)
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
conn, err := listener.Accept()
|
conn, err := listener.Accept()
|
||||||
|
@ -46,7 +39,7 @@ func startHttpServer(port int, requestChan chan []*action, responseChan chan str
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
conn.Write([]byte(handleHttpRequest(conn, requestChan, responseChan)))
|
conn.Write([]byte(handleHttpRequest(conn, channel)))
|
||||||
conn.Close()
|
conn.Close()
|
||||||
}
|
}
|
||||||
listener.Close()
|
listener.Close()
|
||||||
|
@ -61,14 +54,12 @@ func startHttpServer(port int, requestChan chan []*action, responseChan chan str
|
||||||
// * No --listen: 2.8MB
|
// * No --listen: 2.8MB
|
||||||
// * --listen with net/http: 5.7MB
|
// * --listen with net/http: 5.7MB
|
||||||
// * --listen w/o net/http: 3.3MB
|
// * --listen w/o net/http: 3.3MB
|
||||||
func handleHttpRequest(conn net.Conn, requestChan chan []*action, responseChan chan string) string {
|
func handleHttpRequest(conn net.Conn, channel chan []*action) string {
|
||||||
contentLength := 0
|
contentLength := 0
|
||||||
body := ""
|
body := ""
|
||||||
response := func(header string, message string) string {
|
|
||||||
return header + fmt.Sprintf("Content-Length: %d%s", len(message), crlf+crlf+message)
|
|
||||||
}
|
|
||||||
bad := func(message string) string {
|
bad := func(message string) string {
|
||||||
return response(httpBadRequest, strings.TrimSpace(message)+"\n")
|
message += "\n"
|
||||||
|
return httpBadRequest + fmt.Sprintf("Content-Length: %d%s", len(message), crlf+crlf+message)
|
||||||
}
|
}
|
||||||
conn.SetReadDeadline(time.Now().Add(httpReadTimeout))
|
conn.SetReadDeadline(time.Now().Add(httpReadTimeout))
|
||||||
scanner := bufio.NewScanner(conn)
|
scanner := bufio.NewScanner(conn)
|
||||||
|
@ -89,13 +80,8 @@ func handleHttpRequest(conn net.Conn, requestChan chan []*action, responseChan c
|
||||||
text := scanner.Text()
|
text := scanner.Text()
|
||||||
switch section {
|
switch section {
|
||||||
case 0:
|
case 0:
|
||||||
httpMatch := httpRegexp.FindStringSubmatch(text)
|
if !strings.HasPrefix(text, "POST / HTTP") {
|
||||||
if len(httpMatch) != 3 {
|
return bad("invalid request method")
|
||||||
return bad("invalid HTTP request: " + text)
|
|
||||||
}
|
|
||||||
if httpMatch[1] == "GET" {
|
|
||||||
requestChan <- []*action{{t: actEvaluate, a: httpMatch[2][1:]}}
|
|
||||||
return response(httpOk, <-responseChan)
|
|
||||||
}
|
}
|
||||||
section++
|
section++
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -134,6 +120,7 @@ func handleHttpRequest(conn net.Conn, requestChan chan []*action, responseChan c
|
||||||
if len(actions) == 0 {
|
if len(actions) == 0 {
|
||||||
return bad("no action specified")
|
return bad("no action specified")
|
||||||
}
|
}
|
||||||
requestChan <- actions
|
|
||||||
|
channel <- actions
|
||||||
return httpOk
|
return httpOk
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,8 +201,7 @@ type Terminal struct {
|
||||||
sigstop bool
|
sigstop bool
|
||||||
startChan chan fitpad
|
startChan chan fitpad
|
||||||
killChan chan int
|
killChan chan int
|
||||||
serverRequestChan chan []*action
|
serverChan chan []*action
|
||||||
serverResponseChan chan string
|
|
||||||
slab *util.Slab
|
slab *util.Slab
|
||||||
theme *tui.ColorTheme
|
theme *tui.ColorTheme
|
||||||
tui tui.Renderer
|
tui tui.Renderer
|
||||||
|
@ -277,7 +276,6 @@ const (
|
||||||
actDeleteChar
|
actDeleteChar
|
||||||
actDeleteCharEOF
|
actDeleteCharEOF
|
||||||
actEndOfLine
|
actEndOfLine
|
||||||
actEvaluate
|
|
||||||
actForwardChar
|
actForwardChar
|
||||||
actForwardWord
|
actForwardWord
|
||||||
actKillLine
|
actKillLine
|
||||||
|
@ -601,8 +599,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
||||||
theme: opts.Theme,
|
theme: opts.Theme,
|
||||||
startChan: make(chan fitpad, 1),
|
startChan: make(chan fitpad, 1),
|
||||||
killChan: make(chan int),
|
killChan: make(chan int),
|
||||||
serverRequestChan: make(chan []*action),
|
serverChan: make(chan []*action),
|
||||||
serverResponseChan: make(chan string),
|
|
||||||
tui: renderer,
|
tui: renderer,
|
||||||
initFunc: func() { renderer.Init() },
|
initFunc: func() { renderer.Init() },
|
||||||
executing: util.NewAtomicBool(false)}
|
executing: util.NewAtomicBool(false)}
|
||||||
|
@ -624,7 +621,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
||||||
t.separator, t.separatorLen = t.ansiLabelPrinter(bar, &tui.ColSeparator, true)
|
t.separator, t.separatorLen = t.ansiLabelPrinter(bar, &tui.ColSeparator, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := startHttpServer(t.listenPort, t.serverRequestChan, t.serverResponseChan); err != nil {
|
if err := startHttpServer(t.listenPort, t.serverChan); err != nil {
|
||||||
errorExit(err.Error())
|
errorExit(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2534,7 +2531,7 @@ func (t *Terminal) Loop() {
|
||||||
select {
|
select {
|
||||||
case event = <-eventChan:
|
case event = <-eventChan:
|
||||||
needBarrier = true
|
needBarrier = true
|
||||||
case actions = <-t.serverRequestChan:
|
case actions = <-t.serverChan:
|
||||||
event = tui.Invalid.AsEvent()
|
event = tui.Invalid.AsEvent()
|
||||||
needBarrier = false
|
needBarrier = false
|
||||||
}
|
}
|
||||||
|
@ -2617,15 +2614,6 @@ func (t *Terminal) Loop() {
|
||||||
t.executeCommand(a.a, false, a.t == actExecuteSilent)
|
t.executeCommand(a.a, false, a.t == actExecuteSilent)
|
||||||
case actExecuteMulti:
|
case actExecuteMulti:
|
||||||
t.executeCommand(a.a, true, false)
|
t.executeCommand(a.a, true, false)
|
||||||
case actEvaluate:
|
|
||||||
response := ""
|
|
||||||
switch a.a {
|
|
||||||
case "", "current":
|
|
||||||
response = t.currentItem().AsString(t.ansi)
|
|
||||||
case "query":
|
|
||||||
response = string(t.input)
|
|
||||||
}
|
|
||||||
t.serverResponseChan <- response
|
|
||||||
case actInvalid:
|
case actInvalid:
|
||||||
t.mutex.Unlock()
|
t.mutex.Unlock()
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -2440,12 +2440,9 @@ class TestGoFZF < TestBase
|
||||||
def test_listen
|
def test_listen
|
||||||
tmux.send_keys 'seq 10 | fzf --listen 6266', :Enter
|
tmux.send_keys 'seq 10 | fzf --listen 6266', :Enter
|
||||||
tmux.until { |lines| assert_equal 10, lines.item_count }
|
tmux.until { |lines| assert_equal 10, lines.item_count }
|
||||||
Net::HTTP.post(URI('http://localhost:6266'), 'change-query(00)+reload(seq 100)+change-prompt:hundred> ')
|
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 100, lines.item_count }
|
||||||
tmux.until { |lines| assert_equal 'hundred> 00', lines[-1] }
|
tmux.until { |lines| assert_equal 'hundred> yo', lines[-1] }
|
||||||
assert_equal '100', Net::HTTP.get(URI('http://localhost:6266'))
|
|
||||||
assert_equal '100', Net::HTTP.get(URI('http://localhost:6266/current'))
|
|
||||||
assert_equal '00', Net::HTTP.get(URI('http://localhost:6266/query'))
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user