]> git.lizzy.rs Git - micro.git/blob - cmd/micro/action/bufhandler.go
Fix serialization
[micro.git] / cmd / micro / action / bufhandler.go
1 package action
2
3 import (
4         "time"
5
6         "github.com/zyedidia/micro/cmd/micro/buffer"
7         "github.com/zyedidia/micro/cmd/micro/util"
8         "github.com/zyedidia/tcell"
9 )
10
11 type BufKeyAction func(*BufHandler) bool
12 type BufMouseAction func(*BufHandler, *tcell.EventMouse) bool
13
14 var BufKeyBindings map[KeyEvent]BufKeyAction
15 var BufMouseBindings map[MouseEvent]BufMouseAction
16
17 func init() {
18         BufKeyBindings = make(map[KeyEvent]BufKeyAction)
19         BufMouseBindings = make(map[MouseEvent]BufMouseAction)
20 }
21
22 func BufMapKey(k KeyEvent, action string) {
23         if f, ok := BufKeyActions[action]; ok {
24                 BufKeyBindings[k] = f
25         } else {
26                 util.TermMessage("Error:", action, "does not exist")
27         }
28 }
29 func BufMapMouse(k MouseEvent, action string) {
30         if f, ok := BufMouseActions[action]; ok {
31                 BufMouseBindings[k] = f
32         } else if f, ok := BufKeyActions[action]; ok {
33                 // allowed to map mouse buttons to key actions
34                 BufMouseBindings[k] = func(h *BufHandler, e *tcell.EventMouse) bool {
35                         return f(h)
36                 }
37         } else {
38                 util.TermMessage("Error:", action, "does not exist")
39         }
40 }
41
42 // The BufHandler connects the buffer and the window
43 // It provides a cursor (or multiple) and defines a set of actions
44 // that can be taken on the buffer
45 // The ActionHandler can access the window for necessary info about
46 // visual positions for mouse clicks and scrolling
47 type BufHandler struct {
48         Buf *buffer.Buffer
49
50         cursors []*buffer.Cursor
51         Cursor  *buffer.Cursor // the active cursor
52
53         StartLine int // Vertical scrolling
54         StartCol  int // Horizontal scrolling
55
56         // Since tcell doesn't differentiate between a mouse release event
57         // and a mouse move event with no keys pressed, we need to keep
58         // track of whether or not the mouse was pressed (or not released) last event to determine
59         // mouse release events
60         mouseReleased bool
61
62         // We need to keep track of insert key press toggle
63         isOverwriteMode bool
64         // This stores when the last click was
65         // This is useful for detecting double and triple clicks
66         lastClickTime time.Time
67         lastLoc       buffer.Loc
68
69         // lastCutTime stores when the last ctrl+k was issued.
70         // It is used for clearing the clipboard to replace it with fresh cut lines.
71         lastCutTime time.Time
72
73         // freshClip returns true if the clipboard has never been pasted.
74         freshClip bool
75
76         // Was the last mouse event actually a double click?
77         // Useful for detecting triple clicks -- if a double click is detected
78         // but the last mouse event was actually a double click, it's a triple click
79         doubleClick bool
80         // Same here, just to keep track for mouse move events
81         tripleClick bool
82 }
83
84 func NewBufHandler(buf *buffer.Buffer) *BufHandler {
85         h := new(BufHandler)
86         h.Buf = buf
87
88         h.cursors = []*buffer.Cursor{buffer.NewCursor(buf, buf.StartCursor)}
89         h.Cursor = h.cursors[0]
90
91         buf.SetCursors(h.cursors)
92         return h
93 }
94
95 // HandleEvent executes the tcell event properly
96 // TODO: multiple actions bound to one key
97 func (h *BufHandler) HandleEvent(event tcell.Event) {
98         switch e := event.(type) {
99         case *tcell.EventKey:
100                 ke := KeyEvent{
101                         code: e.Key(),
102                         mod:  e.Modifiers(),
103                         r:    e.Rune(),
104                 }
105                 done := h.DoKeyEvent(ke)
106                 if !done && e.Key() == tcell.KeyRune {
107                         h.DoRuneInsert(e.Rune())
108                 }
109         case *tcell.EventMouse:
110                 me := MouseEvent{
111                         btn: e.Buttons(),
112                         mod: e.Modifiers(),
113                 }
114                 h.DoMouseEvent(me, e)
115         }
116 }
117
118 func (h *BufHandler) DoKeyEvent(e KeyEvent) bool {
119         if action, ok := BufKeyBindings[e]; ok {
120                 action(h)
121                 return true
122         }
123         return false
124 }
125
126 func (h *BufHandler) DoMouseEvent(e MouseEvent, te *tcell.EventMouse) bool {
127         if action, ok := BufMouseBindings[e]; ok {
128                 action(h, te)
129                 return true
130         }
131         return false
132 }
133
134 func (h *BufHandler) DoRuneInsert(r rune) {
135         // Insert a character
136         if h.Cursor.HasSelection() {
137                 h.Cursor.DeleteSelection()
138                 h.Cursor.ResetSelection()
139         }
140
141         if h.isOverwriteMode {
142                 next := h.Cursor.Loc
143                 next.X++
144                 h.Buf.Replace(h.Cursor.Loc, next, string(r))
145         } else {
146                 h.Buf.Insert(h.Cursor.Loc, string(r))
147         }
148 }
149
150 var BufKeyActions = map[string]BufKeyAction{
151         "CursorUp":               (*BufHandler).CursorUp,
152         "CursorDown":             (*BufHandler).CursorDown,
153         "CursorPageUp":           (*BufHandler).CursorPageUp,
154         "CursorPageDown":         (*BufHandler).CursorPageDown,
155         "CursorLeft":             (*BufHandler).CursorLeft,
156         "CursorRight":            (*BufHandler).CursorRight,
157         "CursorStart":            (*BufHandler).CursorStart,
158         "CursorEnd":              (*BufHandler).CursorEnd,
159         "SelectToStart":          (*BufHandler).SelectToStart,
160         "SelectToEnd":            (*BufHandler).SelectToEnd,
161         "SelectUp":               (*BufHandler).SelectUp,
162         "SelectDown":             (*BufHandler).SelectDown,
163         "SelectLeft":             (*BufHandler).SelectLeft,
164         "SelectRight":            (*BufHandler).SelectRight,
165         "WordRight":              (*BufHandler).WordRight,
166         "WordLeft":               (*BufHandler).WordLeft,
167         "SelectWordRight":        (*BufHandler).SelectWordRight,
168         "SelectWordLeft":         (*BufHandler).SelectWordLeft,
169         "DeleteWordRight":        (*BufHandler).DeleteWordRight,
170         "DeleteWordLeft":         (*BufHandler).DeleteWordLeft,
171         "SelectLine":             (*BufHandler).SelectLine,
172         "SelectToStartOfLine":    (*BufHandler).SelectToStartOfLine,
173         "SelectToEndOfLine":      (*BufHandler).SelectToEndOfLine,
174         "ParagraphPrevious":      (*BufHandler).ParagraphPrevious,
175         "ParagraphNext":          (*BufHandler).ParagraphNext,
176         "InsertNewline":          (*BufHandler).InsertNewline,
177         "InsertSpace":            (*BufHandler).InsertSpace,
178         "Backspace":              (*BufHandler).Backspace,
179         "Delete":                 (*BufHandler).Delete,
180         "InsertTab":              (*BufHandler).InsertTab,
181         "Save":                   (*BufHandler).Save,
182         "SaveAll":                (*BufHandler).SaveAll,
183         "SaveAs":                 (*BufHandler).SaveAs,
184         "Find":                   (*BufHandler).Find,
185         "FindNext":               (*BufHandler).FindNext,
186         "FindPrevious":           (*BufHandler).FindPrevious,
187         "Center":                 (*BufHandler).Center,
188         "Undo":                   (*BufHandler).Undo,
189         "Redo":                   (*BufHandler).Redo,
190         "Copy":                   (*BufHandler).Copy,
191         "Cut":                    (*BufHandler).Cut,
192         "CutLine":                (*BufHandler).CutLine,
193         "DuplicateLine":          (*BufHandler).DuplicateLine,
194         "DeleteLine":             (*BufHandler).DeleteLine,
195         "MoveLinesUp":            (*BufHandler).MoveLinesUp,
196         "MoveLinesDown":          (*BufHandler).MoveLinesDown,
197         "IndentSelection":        (*BufHandler).IndentSelection,
198         "OutdentSelection":       (*BufHandler).OutdentSelection,
199         "OutdentLine":            (*BufHandler).OutdentLine,
200         "Paste":                  (*BufHandler).Paste,
201         "PastePrimary":           (*BufHandler).PastePrimary,
202         "SelectAll":              (*BufHandler).SelectAll,
203         "OpenFile":               (*BufHandler).OpenFile,
204         "Start":                  (*BufHandler).Start,
205         "End":                    (*BufHandler).End,
206         "PageUp":                 (*BufHandler).PageUp,
207         "PageDown":               (*BufHandler).PageDown,
208         "SelectPageUp":           (*BufHandler).SelectPageUp,
209         "SelectPageDown":         (*BufHandler).SelectPageDown,
210         "HalfPageUp":             (*BufHandler).HalfPageUp,
211         "HalfPageDown":           (*BufHandler).HalfPageDown,
212         "StartOfLine":            (*BufHandler).StartOfLine,
213         "EndOfLine":              (*BufHandler).EndOfLine,
214         "ToggleHelp":             (*BufHandler).ToggleHelp,
215         "ToggleKeyMenu":          (*BufHandler).ToggleKeyMenu,
216         "ToggleRuler":            (*BufHandler).ToggleRuler,
217         "JumpLine":               (*BufHandler).JumpLine,
218         "ClearStatus":            (*BufHandler).ClearStatus,
219         "ShellMode":              (*BufHandler).ShellMode,
220         "CommandMode":            (*BufHandler).CommandMode,
221         "ToggleOverwriteMode":    (*BufHandler).ToggleOverwriteMode,
222         "Escape":                 (*BufHandler).Escape,
223         "Quit":                   (*BufHandler).Quit,
224         "QuitAll":                (*BufHandler).QuitAll,
225         "AddTab":                 (*BufHandler).AddTab,
226         "PreviousTab":            (*BufHandler).PreviousTab,
227         "NextTab":                (*BufHandler).NextTab,
228         "NextSplit":              (*BufHandler).NextSplit,
229         "PreviousSplit":          (*BufHandler).PreviousSplit,
230         "Unsplit":                (*BufHandler).Unsplit,
231         "VSplit":                 (*BufHandler).VSplitBinding,
232         "HSplit":                 (*BufHandler).HSplitBinding,
233         "ToggleMacro":            (*BufHandler).ToggleMacro,
234         "PlayMacro":              (*BufHandler).PlayMacro,
235         "Suspend":                (*BufHandler).Suspend,
236         "ScrollUp":               (*BufHandler).ScrollUpAction,
237         "ScrollDown":             (*BufHandler).ScrollDownAction,
238         "SpawnMultiCursor":       (*BufHandler).SpawnMultiCursor,
239         "SpawnMultiCursorSelect": (*BufHandler).SpawnMultiCursorSelect,
240         "RemoveMultiCursor":      (*BufHandler).RemoveMultiCursor,
241         "RemoveAllMultiCursors":  (*BufHandler).RemoveAllMultiCursors,
242         "SkipMultiCursor":        (*BufHandler).SkipMultiCursor,
243         "JumpToMatchingBrace":    (*BufHandler).JumpToMatchingBrace,
244
245         // This was changed to InsertNewline but I don't want to break backwards compatibility
246         "InsertEnter": (*BufHandler).InsertNewline,
247 }
248 var BufMouseActions = map[string]BufMouseAction{
249         "MousePress":       (*BufHandler).MousePress,
250         "MouseMultiCursor": (*BufHandler).MouseMultiCursor,
251 }