mirror of
https://github.com/peco/peco.git
synced 2026-09-10 07:16:29 -04:00
Merge pull request #635 from peco/split-messagehub
consolidate SendStatusMsg
This commit is contained in:
commit
79bc52f006
28
action.go
28
action.go
|
|
@ -62,7 +62,7 @@ func (a ActionFunc) RegisterKeySequence(name string, k keyseq.KeyList) {
|
|||
|
||||
func wrapDeprecated(fn func(context.Context, *Peco, Event), oldName, newName string) ActionFunc {
|
||||
return ActionFunc(func(ctx context.Context, state *Peco, e Event) {
|
||||
state.Hub().SendStatusMsg(ctx, fmt.Sprintf("%s is deprecated. Use %s", oldName, newName))
|
||||
state.Hub().SendStatusMsg(ctx, fmt.Sprintf("%s is deprecated. Use %s", oldName, newName), 0)
|
||||
fn(ctx, state, e)
|
||||
})
|
||||
}
|
||||
|
|
@ -353,7 +353,7 @@ func doFinish(ctx context.Context, state *Peco, _ Event) {
|
|||
})
|
||||
|
||||
var err error
|
||||
state.Hub().SendStatusMsg(ctx, "Executing "+ccarg)
|
||||
state.Hub().SendStatusMsg(ctx, "Executing "+ccarg, 0)
|
||||
cmd := util.Shell(ccarg)
|
||||
cmd.Stdin = &stdin
|
||||
cmd.Stdout = state.Stdout
|
||||
|
|
@ -732,7 +732,7 @@ func doToggleQuery(ctx context.Context, state *Peco, _ Event) {
|
|||
}
|
||||
|
||||
func doKonamiCommand(ctx context.Context, state *Peco, e Event) {
|
||||
state.Hub().SendStatusMsg(ctx, "All your filters are belongs to us")
|
||||
state.Hub().SendStatusMsg(ctx, "All your filters are belongs to us", 0)
|
||||
}
|
||||
|
||||
func doToggleSingleKeyJump(ctx context.Context, state *Peco, e Event) {
|
||||
|
|
@ -784,7 +784,7 @@ func doGoToAdjacentSelection(ctx context.Context, state *Peco, forward bool) {
|
|||
selection := state.Selection()
|
||||
|
||||
if selection.Len() == 0 {
|
||||
state.Hub().SendStatusMsg(ctx, "No Selection")
|
||||
state.Hub().SendStatusMsg(ctx, "No Selection", 0)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -833,11 +833,11 @@ func doGoToAdjacentSelection(ctx context.Context, state *Peco, forward bool) {
|
|||
}
|
||||
|
||||
if found {
|
||||
state.Hub().SendStatusMsg(ctx, label+" Selection")
|
||||
state.Hub().SendStatusMsg(ctx, label+" Selection", 0)
|
||||
state.Hub().SendPaging(ctx, hub.ToScrollFirstItem)
|
||||
state.Hub().SendPaging(ctx, hub.JumpToLineRequest(target))
|
||||
} else {
|
||||
state.Hub().SendStatusMsg(ctx, label+" Selection (first)")
|
||||
state.Hub().SendStatusMsg(ctx, label+" Selection (first)", 0)
|
||||
state.Hub().SendPaging(ctx, hub.ToScrollFirstItem)
|
||||
state.Hub().SendPaging(ctx, hub.JumpToLineRequest(wrapTarget))
|
||||
}
|
||||
|
|
@ -862,7 +862,7 @@ func doFreezeResults(ctx context.Context, state *Peco, _ Event) {
|
|||
|
||||
b := state.CurrentLineBuffer()
|
||||
if b.Size() == 0 {
|
||||
state.Hub().SendStatusMsg(ctx, "Nothing to freeze")
|
||||
state.Hub().SendStatusMsg(ctx, "Nothing to freeze", 0)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -877,7 +877,7 @@ func doFreezeResults(ctx context.Context, state *Peco, _ Event) {
|
|||
state.SetFrozenSource(frozen)
|
||||
resetQueryState(state)
|
||||
state.SetCurrentLineBuffer(frozen)
|
||||
state.Hub().SendStatusMsg(ctx, "Results frozen")
|
||||
state.Hub().SendStatusMsg(ctx, "Results frozen", 0)
|
||||
state.Hub().SendDrawPrompt(ctx)
|
||||
}
|
||||
|
||||
|
|
@ -888,14 +888,14 @@ func doUnfreezeResults(ctx context.Context, state *Peco, _ Event) {
|
|||
}
|
||||
|
||||
if state.FrozenSource() == nil {
|
||||
state.Hub().SendStatusMsg(ctx, "No frozen results")
|
||||
state.Hub().SendStatusMsg(ctx, "No frozen results", 0)
|
||||
return
|
||||
}
|
||||
|
||||
state.ClearFrozenSource()
|
||||
resetQueryState(state)
|
||||
state.ResetCurrentLineBuffer()
|
||||
state.Hub().SendStatusMsg(ctx, "Results unfrozen")
|
||||
state.Hub().SendStatusMsg(ctx, "Results unfrozen", 0)
|
||||
state.Hub().SendDrawPrompt(ctx)
|
||||
}
|
||||
|
||||
|
|
@ -907,7 +907,7 @@ func doZoomIn(ctx context.Context, state *Peco, _ Event) {
|
|||
|
||||
// Already zoomed in?
|
||||
if state.PreZoomBuffer() != nil {
|
||||
state.Hub().SendStatusMsg(ctx, "Already zoomed in")
|
||||
state.Hub().SendStatusMsg(ctx, "Already zoomed in", 0)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -916,7 +916,7 @@ func doZoomIn(ctx context.Context, state *Peco, _ Event) {
|
|||
|
||||
// If the current buffer is the source (no active filter), nothing to zoom into
|
||||
if currentBuf == state.source {
|
||||
state.Hub().SendStatusMsg(ctx, "Nothing to zoom into")
|
||||
state.Hub().SendStatusMsg(ctx, "Nothing to zoom into", 0)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -925,7 +925,7 @@ func doZoomIn(ctx context.Context, state *Peco, _ Event) {
|
|||
|
||||
contextBuf := NewContextBuffer(currentBuf, source, contextSize)
|
||||
if contextBuf.Size() == 0 {
|
||||
state.Hub().SendStatusMsg(ctx, "Nothing to zoom into")
|
||||
state.Hub().SendStatusMsg(ctx, "Nothing to zoom into", 0)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -957,7 +957,7 @@ func doZoomOut(ctx context.Context, state *Peco, _ Event) {
|
|||
|
||||
preZoom := state.PreZoomBuffer()
|
||||
if preZoom == nil {
|
||||
state.Hub().SendStatusMsg(ctx, "Not zoomed in")
|
||||
state.Hub().SendStatusMsg(ctx, "Not zoomed in", 0)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ func (h *recordingHub) SendPaging(_ context.Context, v hub.PagingRequest) {
|
|||
h.pagingArgs = append(h.pagingArgs, v)
|
||||
}
|
||||
|
||||
func (h *recordingHub) SendStatusMsg(_ context.Context, msg string) {
|
||||
func (h *recordingHub) SendStatusMsg(_ context.Context, msg string, _ time.Duration) {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
h.statusMsgs = append(h.statusMsgs, msg)
|
||||
|
|
|
|||
|
|
@ -443,7 +443,7 @@ func (f *Filter) Work(ctx context.Context, q *hub.Payload[string]) {
|
|||
go func(ctx context.Context) {
|
||||
defer state.Hub().SendDraw(ctx, &hub.DrawOptions{RunningQuery: true})
|
||||
if err := p.Run(ctx); err != nil {
|
||||
state.Hub().SendStatusMsg(ctx, err.Error())
|
||||
state.Hub().SendStatusMsg(ctx, err.Error(), 0)
|
||||
}
|
||||
}(ctx)
|
||||
|
||||
|
|
@ -454,7 +454,7 @@ func (f *Filter) Work(ctx context.Context, q *hub.Payload[string]) {
|
|||
}
|
||||
t := time.NewTicker(50 * time.Millisecond)
|
||||
defer t.Stop()
|
||||
defer state.Hub().SendStatusMsg(ctx, "")
|
||||
defer state.Hub().SendStatusMsg(ctx, "", 0)
|
||||
defer state.Hub().SendDraw(ctx, &hub.DrawOptions{RunningQuery: true})
|
||||
for {
|
||||
select {
|
||||
|
|
@ -512,7 +512,7 @@ func (f *Filter) Loop(ctx context.Context, cancel func()) error {
|
|||
previous = workcancel
|
||||
mutex.Unlock()
|
||||
|
||||
f.state.Hub().SendStatusMsg(ctx, "Running query...")
|
||||
f.state.Hub().SendStatusMsg(ctx, "Running query...", 0)
|
||||
|
||||
go f.Work(workctx, q)
|
||||
}
|
||||
|
|
|
|||
15
hub/hub.go
15
hub/hub.go
|
|
@ -151,9 +151,11 @@ func (h *Hub) StatusMsgCh() chan *Payload[StatusMsg] {
|
|||
return h.statusMsgCh
|
||||
}
|
||||
|
||||
// SendStatusMsg sends a string to be displayed in the status message
|
||||
func (h *Hub) SendStatusMsg(ctx context.Context, q string) {
|
||||
h.SendStatusMsgAndClear(ctx, q, 0)
|
||||
// SendStatusMsg sends a string to be displayed in the status message.
|
||||
// If clearDelay is non-zero, the message will be cleared after that duration.
|
||||
func (h *Hub) SendStatusMsg(ctx context.Context, q string, clearDelay time.Duration) {
|
||||
msg := newStatusMsgReq(q, clearDelay)
|
||||
send(ctx, h.StatusMsgCh(), NewPayload[StatusMsg](msg, isBatchCtx(ctx)))
|
||||
}
|
||||
|
||||
// StatusMsg is an interface for status message requests.
|
||||
|
|
@ -182,13 +184,6 @@ func newStatusMsgReq(s string, d time.Duration) *statusMsgReq {
|
|||
}
|
||||
}
|
||||
|
||||
// SendStatusMsgAndClear sends a string to be displayed in the status message,
|
||||
// as well as a delay until the message should be cleared
|
||||
func (h *Hub) SendStatusMsgAndClear(ctx context.Context, q string, clearDelay time.Duration) {
|
||||
msg := newStatusMsgReq(q, clearDelay)
|
||||
send(ctx, h.StatusMsgCh(), NewPayload[StatusMsg](msg, isBatchCtx(ctx)))
|
||||
}
|
||||
|
||||
// PagingCh returns the channel to page through the results
|
||||
func (h *Hub) PagingCh() chan *Payload[PagingRequest] {
|
||||
return h.pagingCh
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/peco/peco/hub"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestHub(t *testing.T) {
|
||||
|
|
@ -59,7 +60,7 @@ func TestHub(t *testing.T) {
|
|||
h.Batch(ctx, func(ctx context.Context) {
|
||||
h.SendQuery(ctx, "Hello World!")
|
||||
h.SendDraw(ctx, &hub.DrawOptions{})
|
||||
h.SendStatusMsg(ctx, "Hello, World!")
|
||||
h.SendStatusMsg(ctx, "Hello, World!", 0)
|
||||
h.SendPaging(ctx, hub.PagingRequestType(1))
|
||||
}, true)
|
||||
|
||||
|
|
@ -85,3 +86,35 @@ func TestHub(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendStatusMsg(t *testing.T) {
|
||||
t.Run("zero delay", func(t *testing.T) {
|
||||
h := hub.New(5)
|
||||
ctx := context.Background()
|
||||
|
||||
go func() {
|
||||
h.SendStatusMsg(ctx, "hello", 0)
|
||||
}()
|
||||
|
||||
p := <-h.StatusMsgCh()
|
||||
defer p.Done()
|
||||
|
||||
require.Equal(t, "hello", p.Data().Message())
|
||||
require.Equal(t, time.Duration(0), p.Data().Delay())
|
||||
})
|
||||
|
||||
t.Run("non-zero delay", func(t *testing.T) {
|
||||
h := hub.New(5)
|
||||
ctx := context.Background()
|
||||
|
||||
go func() {
|
||||
h.SendStatusMsg(ctx, "temporary", 500*time.Millisecond)
|
||||
}()
|
||||
|
||||
p := <-h.StatusMsgCh()
|
||||
defer p.Done()
|
||||
|
||||
require.Equal(t, "temporary", p.Data().Message())
|
||||
require.Equal(t, 500*time.Millisecond, p.Data().Delay())
|
||||
})
|
||||
}
|
||||
|
|
|
|||
31
interface.go
31
interface.go
|
|
@ -519,23 +519,36 @@ type Input struct {
|
|||
state *Peco
|
||||
}
|
||||
|
||||
// MessageHub is the interface that must be satisfied by the
|
||||
// message hub component. Unless we're in testing, github.com/peco/peco/hub.Hub
|
||||
// is used.
|
||||
type MessageHub interface {
|
||||
// HubSender provides methods for sending messages to the hub.
|
||||
// Most code (actions, input handling, source setup) only needs
|
||||
// the sender side.
|
||||
type HubSender interface {
|
||||
Batch(context.Context, func(context.Context), bool)
|
||||
DrawCh() chan *hub.Payload[*hub.DrawOptions]
|
||||
PagingCh() chan *hub.Payload[hub.PagingRequest]
|
||||
QueryCh() chan *hub.Payload[string]
|
||||
SendDraw(context.Context, *hub.DrawOptions)
|
||||
SendDrawPrompt(context.Context)
|
||||
SendPaging(context.Context, hub.PagingRequest)
|
||||
SendQuery(context.Context, string)
|
||||
SendStatusMsg(context.Context, string)
|
||||
SendStatusMsgAndClear(context.Context, string, time.Duration)
|
||||
SendStatusMsg(context.Context, string, time.Duration)
|
||||
}
|
||||
|
||||
// HubReceiver provides methods for receiving messages from the hub.
|
||||
// Only the view loop and filter loop consume from these channels.
|
||||
type HubReceiver interface {
|
||||
DrawCh() chan *hub.Payload[*hub.DrawOptions]
|
||||
PagingCh() chan *hub.Payload[hub.PagingRequest]
|
||||
QueryCh() chan *hub.Payload[string]
|
||||
StatusMsgCh() chan *hub.Payload[hub.StatusMsg]
|
||||
}
|
||||
|
||||
// MessageHub is the interface that must be satisfied by the
|
||||
// message hub component. Unless we're in testing, github.com/peco/peco/hub.Hub
|
||||
// is used. It combines HubSender (for dispatching messages) and
|
||||
// HubReceiver (for consuming them via channels).
|
||||
type MessageHub interface {
|
||||
HubSender
|
||||
HubReceiver
|
||||
}
|
||||
|
||||
type filterProcessor struct {
|
||||
filter filter.Filter
|
||||
query string
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ func wrapRememberSequence(a Action) Action {
|
|||
if s, err := keyseq.KeyEventToString(ev.Key, ev.Ch, ev.Mod); err == nil {
|
||||
seq := state.Inputseq()
|
||||
seq.Add(s)
|
||||
state.Hub().SendStatusMsg(ctx, strings.Join(seq.KeyNames(), " "))
|
||||
state.Hub().SendStatusMsg(ctx, strings.Join(seq.KeyNames(), " "), 0)
|
||||
}
|
||||
a.Execute(ctx, state, ev)
|
||||
})
|
||||
|
|
@ -94,7 +94,7 @@ func wrapClearSequence(a Action) Action {
|
|||
|
||||
if seq.Len() > 0 {
|
||||
msg := strings.Join(seq.KeyNames(), " ")
|
||||
state.Hub().SendStatusMsgAndClear(ctx, msg, 500*time.Millisecond)
|
||||
state.Hub().SendStatusMsg(ctx, msg, 500*time.Millisecond)
|
||||
seq.Reset()
|
||||
}
|
||||
|
||||
|
|
|
|||
11
peco_test.go
11
peco_test.go
|
|
@ -32,10 +32,17 @@ func (h nullHub) SendDraw(_ context.Context, _ *hub.DrawOptions)
|
|||
func (h nullHub) SendDrawPrompt(context.Context) {}
|
||||
func (h nullHub) SendPaging(_ context.Context, _ hub.PagingRequest) {}
|
||||
func (h nullHub) SendQuery(_ context.Context, _ string) {}
|
||||
func (h nullHub) SendStatusMsg(_ context.Context, _ string) {}
|
||||
func (h nullHub) SendStatusMsgAndClear(_ context.Context, _ string, _ time.Duration) {}
|
||||
func (h nullHub) SendStatusMsg(_ context.Context, _ string, _ time.Duration) {}
|
||||
func (h nullHub) StatusMsgCh() chan *hub.Payload[hub.StatusMsg] { return nil }
|
||||
|
||||
// Compile-time interface compliance checks.
|
||||
var (
|
||||
_ MessageHub = (*hub.Hub)(nil)
|
||||
_ HubSender = (*hub.Hub)(nil)
|
||||
_ HubReceiver = (*hub.Hub)(nil)
|
||||
_ MessageHub = nullHub{}
|
||||
)
|
||||
|
||||
type interceptorArgs []interface{}
|
||||
type interceptor struct {
|
||||
m sync.Mutex
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ func (s *Source) Setup(ctx context.Context, state *Peco) {
|
|||
notifycb := func() {
|
||||
// close the ready channel so others can be notified
|
||||
// that there's at least 1 line in the buffer
|
||||
state.Hub().SendStatusMsg(ctx, "")
|
||||
state.Hub().SendStatusMsg(ctx, "", 0)
|
||||
close(s.ready)
|
||||
}
|
||||
|
||||
|
|
@ -131,7 +131,7 @@ func (s *Source) Setup(ctx context.Context, state *Peco) {
|
|||
}
|
||||
}()
|
||||
|
||||
state.Hub().SendStatusMsg(ctx, "Waiting for input...")
|
||||
state.Hub().SendStatusMsg(ctx, "Waiting for input...", 0)
|
||||
|
||||
readCount := 0
|
||||
for loop := true; loop; {
|
||||
|
|
|
|||
Loading…
Reference in a new issue