]> git.lizzy.rs Git - micro.git/blob - internal/action/infopane.go
Merge
[micro.git] / internal / action / infopane.go
1 package action
2
3 import (
4         "bytes"
5
6         "github.com/zyedidia/micro/v2/internal/buffer"
7         "github.com/zyedidia/micro/v2/internal/config"
8         "github.com/zyedidia/micro/v2/internal/display"
9         "github.com/zyedidia/micro/v2/internal/info"
10         "github.com/zyedidia/micro/v2/internal/util"
11         "github.com/zyedidia/tcell/v2"
12 )
13
14 type InfoKeyAction func(*InfoPane)
15
16 var InfoBindings *KeyTree
17 var InfoBufBindings *KeyTree
18
19 func init() {
20         InfoBindings = NewKeyTree()
21         InfoBufBindings = NewKeyTree()
22 }
23
24 func InfoMapEvent(k Event, action string) {
25         config.Bindings["command"][k.Name()] = action
26
27         switch e := k.(type) {
28         case KeyEvent, KeySequenceEvent, RawEvent:
29                 infoMapKey(e, action)
30         case MouseEvent:
31                 infoMapMouse(e, action)
32         }
33 }
34
35 func infoMapKey(k Event, action string) {
36         if f, ok := InfoKeyActions[action]; ok {
37                 InfoBindings.RegisterKeyBinding(k, InfoKeyActionGeneral(f))
38         } else if f, ok := BufKeyActions[action]; ok {
39                 InfoBufBindings.RegisterKeyBinding(k, BufKeyActionGeneral(f))
40         }
41 }
42
43 func infoMapMouse(k MouseEvent, action string) {
44         // TODO: map mouse
45         if f, ok := BufMouseActions[action]; ok {
46                 InfoBufBindings.RegisterMouseBinding(k, BufMouseActionGeneral(f))
47         } else {
48                 infoMapKey(k, action)
49         }
50 }
51
52 func InfoKeyActionGeneral(a InfoKeyAction) PaneKeyAction {
53         return func(p Pane) bool {
54                 a(p.(*InfoPane))
55                 return true
56         }
57 }
58
59 type InfoPane struct {
60         *BufPane
61         *info.InfoBuf
62 }
63
64 func NewInfoPane(ib *info.InfoBuf, w display.BWindow, tab *Tab) *InfoPane {
65         ip := new(InfoPane)
66         ip.InfoBuf = ib
67         ip.BufPane = NewBufPane(ib.Buffer, w, tab)
68         ip.BufPane.bindings = InfoBufBindings
69
70         return ip
71 }
72
73 func NewInfoBar() *InfoPane {
74         ib := info.NewBuffer()
75         w := display.NewInfoWindow(ib)
76         return NewInfoPane(ib, w, nil)
77 }
78
79 func (h *InfoPane) Close() {
80         h.InfoBuf.Close()
81         h.BufPane.Close()
82 }
83
84 func (h *InfoPane) HandleEvent(event tcell.Event) {
85         switch e := event.(type) {
86         case *tcell.EventKey:
87                 ke := KeyEvent{
88                         code: e.Key(),
89                         mod:  metaToAlt(e.Modifiers()),
90                         r:    e.Rune(),
91                 }
92
93                 done := h.DoKeyEvent(ke)
94                 hasYN := h.HasYN
95                 if e.Key() == tcell.KeyRune && hasYN {
96                         if (e.Rune() == 'y' || e.Rune() == 'Y') && hasYN {
97                                 h.YNResp = true
98                                 h.DonePrompt(false)
99                         } else if (e.Rune() == 'n' || e.Rune() == 'N') && hasYN {
100                                 h.YNResp = false
101                                 h.DonePrompt(false)
102                         }
103                 }
104                 if e.Key() == tcell.KeyRune && !done && !hasYN {
105                         h.DoRuneInsert(e.Rune())
106                         done = true
107                 }
108                 if done && h.HasPrompt && !hasYN {
109                         resp := string(h.LineBytes(0))
110                         hist := h.History[h.PromptType]
111                         hist[h.HistoryNum] = resp
112                         if h.EventCallback != nil {
113                                 h.EventCallback(resp)
114                         }
115                 }
116         default:
117                 h.BufPane.HandleEvent(event)
118         }
119 }
120
121 // DoKeyEvent executes a key event for the command bar, doing any overridden actions
122 func (h *InfoPane) DoKeyEvent(e KeyEvent) bool {
123         action, more := InfoBindings.NextEvent(e, nil)
124         if action != nil && !more {
125                 action(h)
126                 InfoBindings.ResetEvents()
127
128                 return true
129         } else if action == nil && !more {
130                 InfoBindings.ResetEvents()
131                 // return false //TODO:?
132         }
133
134         if !more {
135                 action, more = InfoBufBindings.NextEvent(e, nil)
136                 if action != nil && !more {
137                         done := action(h.BufPane)
138                         InfoBufBindings.ResetEvents()
139                         return done
140                 } else if action == nil && !more {
141                         InfoBufBindings.ResetEvents()
142                 }
143         }
144
145         return more
146 }
147
148 // HistoryUp cycles history up
149 func (h *InfoPane) HistoryUp() {
150         h.UpHistory(h.History[h.PromptType])
151 }
152
153 // HistoryDown cycles history down
154 func (h *InfoPane) HistoryDown() {
155         h.DownHistory(h.History[h.PromptType])
156 }
157
158 // Autocomplete begins autocompletion
159 func (h *InfoPane) CommandComplete() {
160         b := h.Buf
161         if b.HasSuggestions {
162                 b.CycleAutocomplete(true)
163                 return
164         }
165
166         c := b.GetActiveCursor()
167         l := b.LineBytes(0)
168         l = util.SliceStart(l, c.X)
169
170         args := bytes.Split(l, []byte{' '})
171         cmd := string(args[0])
172
173         if h.PromptType == "Command" {
174                 if len(args) == 1 {
175                         b.Autocomplete(CommandComplete)
176                 } else if action, ok := commands[cmd]; ok {
177                         if action.completer != nil {
178                                 b.Autocomplete(action.completer)
179                         }
180                 }
181         } else {
182                 // by default use filename autocompletion
183                 b.Autocomplete(buffer.FileComplete)
184         }
185 }
186
187 // ExecuteCommand completes the prompt
188 func (h *InfoPane) ExecuteCommand() {
189         if !h.HasYN {
190                 h.DonePrompt(false)
191         }
192 }
193
194 // AbortCommand cancels the prompt
195 func (h *InfoPane) AbortCommand() {
196         h.DonePrompt(true)
197 }
198
199 // InfoKeyActions contains the list of all possible key actions the infopane could execute
200 var InfoKeyActions = map[string]InfoKeyAction{
201         "HistoryUp":       (*InfoPane).HistoryUp,
202         "HistoryDown":     (*InfoPane).HistoryDown,
203         "CommandComplete": (*InfoPane).CommandComplete,
204         "ExecuteCommand":  (*InfoPane).ExecuteCommand,
205         "AbortCommand":    (*InfoPane).AbortCommand,
206 }