Add 'load' event that is triggered when the input stream is complete

and the first search (with or without query) is complete
This commit is contained in:
Junegunn Choi 2022-12-29 20:01:50 +09:00
parent 44b6336372
commit 14775aa975
No known key found for this signature in database
GPG Key ID: 254BC280FEF9C627
5 changed files with 40 additions and 4 deletions

View File

@ -21,6 +21,16 @@ CHANGELOG
# Put the cursor on the 10th to last item # Put the cursor on the 10th to last item
seq 100 | fzf --sync --bind 'start:pos(-10)' seq 100 | fzf --sync --bind 'start:pos(-10)'
``` ```
- Added `load` event that is triggered when the input stream is complete and
the initial processing of the list is complete.
```sh
# Change the prompt to "loaded" when the input stream is complete
(seq 10; sleep 1; seq 11 20) | fzf --prompt 'Loading> ' --bind 'load:change-prompt:Loaded> '
# You can use it instead of 'start' event without `--sync` if asynchronous
# trigger is not an issue.
(seq 10; sleep 1; seq 11 20) | fzf --bind 'load:last'
```
- Added `next-selected` and `prev-selected` actions to move between selected - Added `next-selected` and `prev-selected` actions to move between selected
items items
```sh ```sh

View File

@ -927,6 +927,15 @@ e.g.
\fB# Move cursor to the last item and select all items \fB# Move cursor to the last item and select all items
seq 1000 | fzf --multi --sync --bind start:last+select-all\fR seq 1000 | fzf --multi --sync --bind start:last+select-all\fR
.RE .RE
\fIload\fR
.RS
Triggered when the input stream is complete and the initial processing of the
list is complete.
e.g.
\fB# Change the prompt to "loaded" when the input stream is complete
(seq 10; sleep 1; seq 11 20) | fzf --prompt 'Loading> ' --bind 'load:change-prompt:Loaded> '\fR
.RE
\fIchange\fR \fIchange\fR
.RS .RS
Triggered whenever the query string is changed Triggered whenever the query string is changed

View File

@ -590,6 +590,8 @@ func parseKeyChords(str string, message string) map[tui.Event]string {
add(tui.BackwardEOF) add(tui.BackwardEOF)
case "start": case "start":
add(tui.Start) add(tui.Start)
case "load":
add(tui.Load)
case "alt-enter", "alt-return": case "alt-enter", "alt-return":
chords[tui.CtrlAltKey('m')] = key chords[tui.CtrlAltKey('m')] = key
case "alt-space": case "alt-space":

View File

@ -177,6 +177,8 @@ type Terminal struct {
pwindow tui.Window pwindow tui.Window
count int count int
progress int progress int
hasLoadActions bool
triggerLoad bool
reading bool reading bool
running bool running bool
failed *string failed *string
@ -202,6 +204,7 @@ type Terminal struct {
startChan chan fitpad startChan chan fitpad
killChan chan int killChan chan int
serverChan chan []*action serverChan chan []*action
eventChan chan tui.Event
slab *util.Slab slab *util.Slab
theme *tui.ColorTheme theme *tui.ColorTheme
tui tui.Renderer tui tui.Renderer
@ -579,6 +582,8 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
ellipsis: opts.Ellipsis, ellipsis: opts.Ellipsis,
ansi: opts.Ansi, ansi: opts.Ansi,
tabstop: opts.Tabstop, tabstop: opts.Tabstop,
hasLoadActions: false,
triggerLoad: false,
reading: true, reading: true,
running: true, running: true,
failed: nil, failed: nil,
@ -603,6 +608,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
startChan: make(chan fitpad, 1), startChan: make(chan fitpad, 1),
killChan: make(chan int), killChan: make(chan int),
serverChan: make(chan []*action, 10), serverChan: make(chan []*action, 10),
eventChan: make(chan tui.Event, 1),
tui: renderer, tui: renderer,
initFunc: func() { renderer.Init() }, initFunc: func() { renderer.Init() },
executing: util.NewAtomicBool(false)} executing: util.NewAtomicBool(false)}
@ -624,6 +630,8 @@ 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)
} }
_, t.hasLoadActions = t.keymap[tui.Load.AsEvent()]
if err := startHttpServer(t.listenPort, t.serverChan); err != nil { if err := startHttpServer(t.listenPort, t.serverChan); err != nil {
errorExit(err.Error()) errorExit(err.Error())
} }
@ -763,6 +771,9 @@ func (t *Terminal) Input() (bool, []rune) {
func (t *Terminal) UpdateCount(cnt int, final bool, failedCommand *string) { func (t *Terminal) UpdateCount(cnt int, final bool, failedCommand *string) {
t.mutex.Lock() t.mutex.Lock()
t.count = cnt t.count = cnt
if t.hasLoadActions && t.reading && final {
t.triggerLoad = true
}
t.reading = !final t.reading = !final
t.failed = failedCommand t.failed = failedCommand
t.mutex.Unlock() t.mutex.Unlock()
@ -811,6 +822,10 @@ func (t *Terminal) UpdateList(merger *Merger, reset bool) {
t.selected = make(map[int32]selectedItem) t.selected = make(map[int32]selectedItem)
t.version++ t.version++
} }
if t.hasLoadActions && t.triggerLoad {
t.triggerLoad = false
t.eventChan <- tui.Load.AsEvent()
}
t.mutex.Unlock() t.mutex.Unlock()
t.reqBox.Set(reqInfo, nil) t.reqBox.Set(reqInfo, nil)
t.reqBox.Set(reqList, nil) t.reqBox.Set(reqList, nil)
@ -2515,13 +2530,12 @@ func (t *Terminal) Loop() {
looping := true looping := true
_, startEvent := t.keymap[tui.Start.AsEvent()] _, startEvent := t.keymap[tui.Start.AsEvent()]
eventChan := make(chan tui.Event)
needBarrier := true needBarrier := true
barrier := make(chan bool) barrier := make(chan bool)
go func() { go func() {
for { for {
<-barrier <-barrier
eventChan <- t.tui.GetChar() t.eventChan <- t.tui.GetChar()
} }
}() }()
for looping { for looping {
@ -2540,8 +2554,8 @@ func (t *Terminal) Loop() {
barrier <- true barrier <- true
} }
select { select {
case event = <-eventChan: case event = <-t.eventChan:
needBarrier = true needBarrier = event != tui.Load.AsEvent()
case actions = <-t.serverChan: case actions = <-t.serverChan:
event = tui.Invalid.AsEvent() event = tui.Invalid.AsEvent()
needBarrier = false needBarrier = false

View File

@ -91,6 +91,7 @@ const (
Change Change
BackwardEOF BackwardEOF
Start Start
Load
AltBS AltBS