From 31fb3f2df2ce7b038c9c2b9207ddbc7f9ed476c3 Mon Sep 17 00:00:00 2001 From: Zachary Yedidia Date: Tue, 28 Aug 2018 23:30:39 -0400 Subject: [PATCH] More actions --- cmd/micro/action/actions.go | 31 +++++++++++++++++++++++++++ cmd/micro/action/bindings.go | 12 +++++++++-- cmd/micro/action/bufhandler.go | 39 +++++++++++++++++++++++++++++++--- cmd/micro/buffer/buffer.go | 14 ++++++++++++ cmd/micro/screen/screen.go | 2 +- cmd/micro/util/util.go | 11 ++++++++++ 6 files changed, 103 insertions(+), 6 deletions(-) diff --git a/cmd/micro/action/actions.go b/cmd/micro/action/actions.go index ec6c07bc..f69211cc 100644 --- a/cmd/micro/action/actions.go +++ b/cmd/micro/action/actions.go @@ -2,8 +2,10 @@ package action import ( "os" + "unicode/utf8" "github.com/zyedidia/micro/cmd/micro/screen" + "github.com/zyedidia/micro/cmd/micro/util" "github.com/zyedidia/tcell" ) @@ -262,6 +264,11 @@ func (h *BufHandler) SelectToEnd() bool { // InsertSpace inserts a space func (h *BufHandler) InsertSpace() bool { + if h.Cursor.HasSelection() { + h.Cursor.DeleteSelection() + h.Cursor.ResetSelection() + } + h.Buf.Insert(h.Cursor.Loc, " ") return true } @@ -272,6 +279,30 @@ func (h *BufHandler) InsertNewline() bool { // Backspace deletes the previous character func (h *BufHandler) Backspace() bool { + if h.Cursor.HasSelection() { + h.Cursor.DeleteSelection() + h.Cursor.ResetSelection() + } else if h.Cursor.Loc.GreaterThan(h.Buf.Start()) { + // We have to do something a bit hacky here because we want to + // delete the line by first moving left and then deleting backwards + // but the undo redo would place the cursor in the wrong place + // So instead we move left, save the position, move back, delete + // and restore the position + + // If the user is using spaces instead of tabs and they are deleting + // whitespace at the start of the line, we should delete as if it's a + // tab (tabSize number of spaces) + lineStart := util.SliceStart(h.Buf.LineBytes(h.Cursor.Y), h.Cursor.X) + tabSize := int(h.Buf.Settings["tabsize"].(float64)) + if h.Buf.Settings["tabstospaces"].(bool) && util.IsSpaces(lineStart) && len(lineStart) != 0 && utf8.RuneCount(lineStart)%tabSize == 0 { + loc := h.Cursor.Loc + h.Buf.Remove(loc.Move(-tabSize, h.Buf), loc) + } else { + loc := h.Cursor.Loc + h.Buf.Remove(loc.Move(-1, h.Buf), loc) + } + } + h.Cursor.LastVisualX = h.Cursor.GetVisualX() return true } diff --git a/cmd/micro/action/bindings.go b/cmd/micro/action/bindings.go index 816b14ae..b1e2685b 100644 --- a/cmd/micro/action/bindings.go +++ b/cmd/micro/action/bindings.go @@ -102,21 +102,29 @@ modSearch: // see if the key is in bindingKeys with the Ctrl prefix. k = string(unicode.ToUpper(rune(k[0]))) + k[1:] if code, ok := keyEvents["Ctrl"+k]; ok { + var r tcell.Key + if code < 256 { + r = code + } // It is, we're done. return KeyEvent{ code: code, mod: modifiers, - r: rune(code), + r: rune(r), }, true } } // See if we can find the key in bindingKeys if code, ok := keyEvents[k]; ok { + var r tcell.Key + if code < 256 { + r = code + } return KeyEvent{ code: code, mod: modifiers, - r: 0, + r: rune(r), }, true } diff --git a/cmd/micro/action/bufhandler.go b/cmd/micro/action/bufhandler.go index 4fea0e64..9e514277 100644 --- a/cmd/micro/action/bufhandler.go +++ b/cmd/micro/action/bufhandler.go @@ -4,6 +4,7 @@ import ( "time" "github.com/zyedidia/micro/cmd/micro/buffer" + "github.com/zyedidia/micro/cmd/micro/util" "github.com/zyedidia/tcell" ) @@ -19,10 +20,23 @@ func init() { } func BufMapKey(k KeyEvent, action string) { - BufKeyBindings[k] = BufKeyActions[action] + if f, ok := BufKeyActions[action]; ok { + BufKeyBindings[k] = f + } else { + util.TermMessage("Error:", action, "does not exist") + } } func BufMapMouse(k MouseEvent, action string) { - BufMouseBindings[k] = BufMouseActions[action] + if f, ok := BufMouseActions[action]; ok { + BufMouseBindings[k] = f + } else if f, ok := BufKeyActions[action]; ok { + // allowed to map mouse buttons to key actions + BufMouseBindings[k] = func(h *BufHandler, e *tcell.EventMouse) bool { + return f(h) + } + } else { + util.TermMessage("Error:", action, "does not exist") + } } // The BufHandler connects the buffer and the window @@ -91,7 +105,10 @@ func (h *BufHandler) HandleEvent(event tcell.Event) { mod: e.Modifiers(), r: e.Rune(), } - h.DoKeyEvent(ke) + done := h.DoKeyEvent(ke) + if !done && e.Key() == tcell.KeyRune { + h.DoRuneInsert(e.Rune()) + } case *tcell.EventMouse: me := MouseEvent{ btn: e.Buttons(), @@ -117,6 +134,22 @@ func (h *BufHandler) DoMouseEvent(e MouseEvent, te *tcell.EventMouse) bool { return false } +func (h *BufHandler) DoRuneInsert(r rune) { + // Insert a character + if h.Cursor.HasSelection() { + h.Cursor.DeleteSelection() + h.Cursor.ResetSelection() + } + + if h.isOverwriteMode { + next := h.Cursor.Loc + next.X++ + h.Buf.Replace(h.Cursor.Loc, next, string(r)) + } else { + h.Buf.Insert(h.Cursor.Loc, string(r)) + } +} + var BufKeyActions = map[string]BufKeyAction{ "CursorUp": (*BufHandler).CursorUp, "CursorDown": (*BufHandler).CursorDown, diff --git a/cmd/micro/buffer/buffer.go b/cmd/micro/buffer/buffer.go index 8f256c2f..bab1350a 100644 --- a/cmd/micro/buffer/buffer.go +++ b/cmd/micro/buffer/buffer.go @@ -320,6 +320,20 @@ func calcHash(b *Buffer, out *[md5.Size]byte) { h.Sum((*out)[:0]) } +func (b *Buffer) insert(pos Loc, value []byte) { + b.isModified = true + b.LineArray.insert(pos, value) +} +func (b *Buffer) remove(start, end Loc) []byte { + b.isModified = true + sub := b.LineArray.remove(start, end) + return sub +} +func (b *Buffer) deleteToEnd(start Loc) { + b.isModified = true + b.LineArray.deleteToEnd(start) +} + // UpdateRules updates the syntax rules and filetype for this buffer // This is called when the colorscheme changes func (b *Buffer) UpdateRules() { diff --git a/cmd/micro/screen/screen.go b/cmd/micro/screen/screen.go index 3cba43f5..58c45b77 100644 --- a/cmd/micro/screen/screen.go +++ b/cmd/micro/screen/screen.go @@ -24,7 +24,7 @@ func Unlock() { var screenWasNil bool func TempFini() { - screenWasNil := Screen == nil + screenWasNil = Screen == nil if !screenWasNil { Lock() diff --git a/cmd/micro/util/util.go b/cmd/micro/util/util.go index 62a20908..90f2c15e 100644 --- a/cmd/micro/util/util.go +++ b/cmd/micro/util/util.go @@ -139,6 +139,17 @@ func IsWordChar(r rune) bool { return (r >= '0' && r <= '9') || (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') || (r == '_') } +// IsSpaces checks if a given string is only spaces +func IsSpaces(str []byte) bool { + for _, c := range str { + if c != ' ' { + return false + } + } + + return true +} + // IsWhitespace returns true if the given rune is a space, tab, or newline func IsWhitespace(c rune) bool { return c == ' ' || c == '\t' || c == '\n'