mirror of
https://github.com/peco/peco.git
synced 2026-09-10 07:16:29 -04:00
Merge pull request #643 from peco/fix-input-alt-key-race
Handle esc in the input loop as well
This commit is contained in:
commit
3ba1cbdb01
20
input.go
20
input.go
|
|
@ -11,9 +11,10 @@ import (
|
|||
|
||||
func NewInput(state *Peco, am ActionMap, src chan Event) *Input {
|
||||
return &Input{
|
||||
actions: am,
|
||||
evsrc: src,
|
||||
state: state,
|
||||
actions: am,
|
||||
evsrc: src,
|
||||
pendingEsc: make(chan Event, 1),
|
||||
state: state,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -24,6 +25,11 @@ func (i *Input) Loop(ctx context.Context, cancel func()) error {
|
|||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
case ev := <-i.pendingEsc:
|
||||
// Timer fired and determined this was a standalone Esc press.
|
||||
// Execute the action here on the input loop goroutine, not
|
||||
// on the timer goroutine, to avoid concurrent ExecuteAction calls.
|
||||
i.state.Keymap().ExecuteAction(ctx, i.state, ev)
|
||||
case ev, ok := <-i.evsrc:
|
||||
if !ok {
|
||||
return nil
|
||||
|
|
@ -73,7 +79,13 @@ func (i *Input) handleInputEvent(ctx context.Context, ev Event) error {
|
|||
}
|
||||
i.mod = nil
|
||||
m.Unlock()
|
||||
i.state.Keymap().ExecuteAction(ctx, i.state, tmp)
|
||||
// Send to the input loop instead of calling ExecuteAction
|
||||
// directly, so all action execution is serialized on the
|
||||
// input loop goroutine.
|
||||
select {
|
||||
case i.pendingEsc <- tmp:
|
||||
case <-ctx.Done():
|
||||
}
|
||||
})
|
||||
m.Unlock()
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -85,9 +85,23 @@ func TestInputModifierKeyRace(t *testing.T) {
|
|||
state.config.Action = map[string][]string{}
|
||||
require.NoError(t, state.populateKeymap())
|
||||
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
input := NewInput(state, state.Keymap(), make(chan Event))
|
||||
|
||||
// Start a goroutine that drains pendingEsc and executes actions,
|
||||
// simulating what Loop does.
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case ev := <-input.pendingEsc:
|
||||
input.state.Keymap().ExecuteAction(ctx, input.state, ev)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Send Esc event — starts the 50ms timer
|
||||
escEv := Event{Type: EventKey, Key: keyseq.KeyEsc, Ch: 0}
|
||||
input.handleInputEvent(ctx, escEv)
|
||||
|
|
|
|||
13
interface.go
13
interface.go
|
|
@ -504,14 +504,15 @@ type ActionMap interface {
|
|||
}
|
||||
|
||||
type Input struct {
|
||||
actions ActionMap
|
||||
evsrc chan Event
|
||||
mod *time.Timer
|
||||
modGen uint64 // generation counter to invalidate stale timer callbacks.
|
||||
actions ActionMap
|
||||
evsrc chan Event
|
||||
pendingEsc chan Event // receives Esc events from the timer callback
|
||||
mod *time.Timer
|
||||
modGen uint64 // generation counter to invalidate stale timer callbacks.
|
||||
// uint64 holds up to ~1.8×10¹⁹. At most 2 increments per Esc key event
|
||||
// and a generous 100 keystrokes/second, overflow would take ~2.9 trillion years.
|
||||
mutex sync.Mutex
|
||||
state *Peco
|
||||
mutex sync.Mutex
|
||||
state *Peco
|
||||
}
|
||||
|
||||
// HubSender provides methods for sending messages to the hub.
|
||||
|
|
|
|||
Loading…
Reference in a new issue