1package hub 2 3import ( 4 "time" 5 6 pdebug "github.com/lestrrat/go-pdebug" 7) 8 9func NewPayload(data interface{}) *payload { 10 p := &payload{data: data} 11 return p 12} 13 14// Data returns the underlying data 15func (p payload) Data() interface{} { 16 return p.data 17} 18 19// Done marks the request as done. If Hub is operating in 20// asynchronous mode (default), it's a no op. Otherwise it 21// closes the reply channel to finish up the synchronous communication 22func (p payload) Done() { 23 if p.done == nil { 24 return 25 } 26 close(p.done) 27} 28 29// NewHub creates a new Hub struct 30func New(bufsiz int) *Hub { 31 return &Hub{ 32 isSync: false, 33 queryCh: make(chan Payload, bufsiz), 34 drawCh: make(chan Payload, bufsiz), 35 statusMsgCh: make(chan Payload, bufsiz), 36 pagingCh: make(chan Payload, bufsiz), 37 } 38} 39 40// Batch allows you to synchronously send messages during the 41// scope of f() being executed. 42func (h *Hub) Batch(f func(), shouldLock bool) { 43 if pdebug.Enabled { 44 g := pdebug.Marker("Batch %t", shouldLock) 45 defer g.End() 46 } 47 if shouldLock { 48 // lock during this operation 49 h.mutex.Lock() 50 defer h.mutex.Unlock() 51 } 52 53 // temporarily set isSync = true 54 o := h.isSync 55 h.isSync = true 56 defer func() { h.isSync = o }() 57 58 // ignore panics 59 defer func() { recover() }() 60 61 f() 62} 63 64// low-level utility 65func send(ch chan Payload, r *payload, needReply bool) { 66 if needReply { 67 r.done = make(chan struct{}) 68 defer func() { <-r.done }() 69 } 70 71 ch <- r 72} 73 74// QueryCh returns the underlying channel for queries 75func (h *Hub) QueryCh() chan Payload { 76 return h.queryCh 77} 78 79// SendQuery sends the query string to be processed by the Filter 80func (h *Hub) SendQuery(q string) { 81 send(h.QueryCh(), NewPayload(q), h.isSync) 82} 83 84// DrawCh returns the channel to redraw the terminal display 85func (h *Hub) DrawCh() chan Payload { 86 return h.drawCh 87} 88 89// SendDrawPrompt sends a request to redraw the prompt only 90func (h *Hub) SendDrawPrompt() { 91 send(h.DrawCh(), NewPayload("prompt"), h.isSync) 92} 93 94// SendDraw sends a request to redraw the terminal display 95func (h *Hub) SendDraw(options interface{}) { 96 pdebug.Printf("START Hub.SendDraw %v", options) 97 defer pdebug.Printf("END Hub.SendDraw %v", options) 98 send(h.DrawCh(), NewPayload(options), h.isSync) 99} 100 101// StatusMsgCh returns the channel to update the status message 102func (h *Hub) StatusMsgCh() chan Payload { 103 return h.statusMsgCh 104} 105 106// SendStatusMsg sends a string to be displayed in the status message 107func (h *Hub) SendStatusMsg(q string) { 108 h.SendStatusMsgAndClear(q, 0) 109} 110 111type statusMsgReq struct { 112 msg string 113 delay time.Duration 114} 115 116func (r statusMsgReq) Message() string { 117 return r.msg 118} 119 120func (r statusMsgReq) Delay() time.Duration { 121 return r.delay 122} 123 124func newStatusMsgReq(s string, d time.Duration) *statusMsgReq { 125 return &statusMsgReq{ 126 msg: s, 127 delay: d, 128 } 129} 130 131// SendStatusMsgAndClear sends a string to be displayed in the status message, 132// as well as a delay until the message should be cleared 133func (h *Hub) SendStatusMsgAndClear(q string, clearDelay time.Duration) { 134 msg := newStatusMsgReq(q, clearDelay) 135 send(h.StatusMsgCh(), NewPayload(msg), h.isSync) 136} 137 138func (h *Hub) SendPurgeDisplayCache() { 139 send(h.DrawCh(), NewPayload("purgeCache"), h.isSync) 140} 141 142// PagingCh returns the channel to page through the results 143func (h *Hub) PagingCh() chan Payload { 144 return h.pagingCh 145} 146 147// SendPaging sends a request to move the cursor around 148func (h *Hub) SendPaging(x interface{}) { 149 send(h.PagingCh(), NewPayload(x), h.isSync) 150} 151