-
Notifications
You must be signed in to change notification settings - Fork 0
/
hub.go
157 lines (132 loc) · 3.95 KB
/
hub.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package peco
import (
"sync"
"time"
)
// Hub acts as the messaging hub between components -- that is,
// it controls how the communication that goes through channels
// are handled.
type Hub struct {
isSync bool
mutex *sync.Mutex
loopCh chan struct{}
queryCh chan HubReq
drawCh chan HubReq
statusMsgCh chan HubReq
clearStatusCh chan HubReq
pagingCh chan HubReq
}
// HubReq is a wrapper around the actual requst value that needs
// to be passed. It contains an optional channel field which can
// be filled to force synchronous communication between the
// sender and receiver
type HubReq struct {
data interface{}
replyCh chan struct{}
}
// DataInterface returns the underlying data as interface{}
func (hr HubReq) DataInterface() interface{} {
return hr.data
}
// DataString returns the underlying data as a string. Panics
// if type conversion fails.
func (hr HubReq) DataString() string {
return hr.data.(string)
}
// Done marks the request as done. If Hub is operating in
// asynchronous mode (default), it's a no op. Otherwise it
// sends a message back the reply channel to finish up the
// synchronous communication
func (hr HubReq) Done() {
if hr.replyCh == nil {
return
}
hr.replyCh <- struct{}{}
}
// NewHub creates a new Hub struct
func NewHub() *Hub {
return &Hub{
false,
&sync.Mutex{},
make(chan struct{}), // loopCh. You never send messages to this. no point in buffering
make(chan HubReq, 5), // queryCh.
make(chan HubReq, 5), // drawCh.
make(chan HubReq, 5), // statusMsgCh
make(chan HubReq, 5), // clearStatusCh
make(chan HubReq, 5), // pagingCh
}
}
// Batch allows you to synchronously send messages during the
// scope of f() being executed.
func (h *Hub) Batch(f func()) {
// lock during this operation
h.mutex.Lock()
defer h.mutex.Unlock()
// temporarily set isSync = true
o := h.isSync
h.isSync = true
defer func() { h.isSync = o }()
// ignore panics
defer func() { recover() }()
f()
}
// low-level utility
func send(ch chan HubReq, r HubReq, needReply bool) {
if needReply {
r.replyCh = make(chan struct{})
defer func() { <-r.replyCh }()
}
ch <- r
}
// QueryCh returns the underlying channel for queries
func (h *Hub) QueryCh() chan HubReq {
return h.queryCh
}
// SendQuery sends the query string to be processed by the Filter
func (h *Hub) SendQuery(q string) {
send(h.QueryCh(), HubReq{q, nil}, h.isSync)
}
// LoopCh returns the channel to control the main execution loop.
// Nothing should ever be sent through this channel. The only way
// the channel communicates anything to its receivers is when
// it is closed -- which is when peco is done.
func (h *Hub) LoopCh() chan struct{} {
return h.loopCh
}
// DrawCh returns the channel to redraw the terminal display
func (h *Hub) DrawCh() chan HubReq {
return h.drawCh
}
// SendDraw sends a request to redraw the terminal display
func (h *Hub) SendDraw(matches []Match) {
send(h.DrawCh(), HubReq{matches, nil}, h.isSync)
}
// StatusMsgCh returns the channel to update the status message
func (h *Hub) StatusMsgCh() chan HubReq {
return h.statusMsgCh
}
// SendStatusMsg sends a string to be displayed in the status message
func (h *Hub) SendStatusMsg(q string) {
send(h.StatusMsgCh(), HubReq{q, nil}, h.isSync)
}
func (h *Hub) ClearStatusCh() chan HubReq {
return h.clearStatusCh
}
// SendClearStatus sends a request to clear the status message in
// `d` duration. If a new status message is sent before the clear
// request is executed, the clear instruction will be canceled
func (h *Hub) SendClearStatus(d time.Duration) {
send(h.ClearStatusCh(), HubReq{d, nil}, h.isSync)
}
// PagingCh returns the channel to page through the results
func (h *Hub) PagingCh() chan HubReq {
return h.pagingCh
}
// SendPaging sends a request to move the cursor around
func (h *Hub) SendPaging(x PagingRequest) {
send(h.PagingCh(), HubReq{x, nil}, h.isSync)
}
// Stop closes the LoopCh so that peco shutsdown
func (h *Hub) Stop() {
close(h.LoopCh())
}