diff --git a/cmd/micro/actions.go b/cmd/micro/actions.go index 7a961229..c09f2a4e 100644 --- a/cmd/micro/actions.go +++ b/cmd/micro/actions.go @@ -1848,6 +1848,7 @@ func (v *View) SpawnMultiCursor(usePlugin bool) bool { } } v.Buf.cursors = append(v.Buf.cursors, c) + v.Buf.UpdateCursors() v.Relocate() v.Cursor = spawner } @@ -1879,6 +1880,7 @@ func (v *View) MouseMultiCursor(usePlugin bool, e *tcell.EventMouse) bool { v.Cursor = &v.Buf.Cursor v.Buf.cursors = append(v.Buf.cursors, c) + v.Buf.UpdateCursors() if usePlugin { PostActionCall("SpawnMultiCursorAtMouse", v) @@ -1923,6 +1925,7 @@ func (v *View) RemoveMultiCursor(usePlugin bool) bool { if end > 1 { v.Buf.cursors[end-1] = nil v.Buf.cursors = v.Buf.cursors[:end-1] + v.Buf.UpdateCursors() } v.Relocate() @@ -1948,6 +1951,7 @@ func (v *View) RemoveAllMultiCursors(usePlugin bool) bool { v.Buf.cursors[i] = nil } v.Buf.cursors = v.Buf.cursors[:1] + v.Buf.UpdateCursors() v.Cursor.ResetSelection() v.Relocate() diff --git a/cmd/micro/buffer.go b/cmd/micro/buffer.go index ab3b18e4..7f08acd5 100644 --- a/cmd/micro/buffer.go +++ b/cmd/micro/buffer.go @@ -28,8 +28,9 @@ type Buffer struct { // This stores all the text in the buffer as an array of lines *LineArray - Cursor Cursor - cursors []*Cursor // for multiple cursors + Cursor Cursor + cursors []*Cursor // for multiple cursors + curCursor int // the current cursor // Path to the file on disk Path string @@ -308,6 +309,12 @@ func (b *Buffer) Update() { b.NumLines = len(b.lines) } +func (b *Buffer) UpdateCursors() { + for i, c := range b.cursors { + c.Num = i + } +} + // Save saves the buffer to its default path func (b *Buffer) Save() error { return b.SaveAs(b.Path) diff --git a/cmd/micro/cursor.go b/cmd/micro/cursor.go index b864974a..2682dee4 100644 --- a/cmd/micro/cursor.go +++ b/cmd/micro/cursor.go @@ -21,6 +21,9 @@ type Cursor struct { // This is used for line and word selection where it is necessary // to know what the original selection was OrigSelection [2]Loc + + // Which cursor index is this (for multiple cursors) + Num int } // Goto puts the cursor at the given cursor's location and gives the current cursor its selection too diff --git a/cmd/micro/eventhandler.go b/cmd/micro/eventhandler.go index 85809284..24bc593e 100644 --- a/cmd/micro/eventhandler.go +++ b/cmd/micro/eventhandler.go @@ -97,7 +97,7 @@ func (eh *EventHandler) ApplyDiff(new string) { // Insert creates an insert text event and executes it func (eh *EventHandler) Insert(start Loc, text string) { e := &TextEvent{ - C: eh.buf.Cursor, + C: *eh.buf.cursors[eh.buf.curCursor], EventType: TextEventInsert, Deltas: []Delta{Delta{text, start, Loc{0, 0}}}, Time: time.Now(), @@ -119,7 +119,7 @@ func (eh *EventHandler) Insert(start Loc, text string) { // Remove creates a remove text event and executes it func (eh *EventHandler) Remove(start, end Loc) { e := &TextEvent{ - C: eh.buf.Cursor, + C: *eh.buf.cursors[eh.buf.curCursor], EventType: TextEventRemove, Deltas: []Delta{Delta{"", start, end}}, Time: time.Now(), @@ -141,7 +141,7 @@ func (eh *EventHandler) Remove(start, end Loc) { // MultipleReplace creates an multiple insertions executes them func (eh *EventHandler) MultipleReplace(deltas []Delta) { e := &TextEvent{ - C: eh.buf.Cursor, + C: *eh.buf.cursors[eh.buf.curCursor], EventType: TextEventReplace, Deltas: deltas, Time: time.Now(), @@ -216,8 +216,12 @@ func (eh *EventHandler) UndoOneEvent() { // Set the cursor in the right place teCursor := t.C - t.C = eh.buf.Cursor - eh.buf.Cursor.Goto(teCursor) + if teCursor.Num >= 0 && teCursor.Num < len(eh.buf.cursors) { + t.C = *eh.buf.cursors[teCursor.Num] + eh.buf.cursors[teCursor.Num].Goto(teCursor) + } else { + teCursor.Num = -1 + } // Push it to the redo stack eh.RedoStack.Push(t) @@ -259,8 +263,12 @@ func (eh *EventHandler) RedoOneEvent() { UndoTextEvent(t, eh.buf) teCursor := t.C - t.C = eh.buf.Cursor - eh.buf.Cursor.Goto(teCursor) + if teCursor.Num >= 0 && teCursor.Num < len(eh.buf.cursors) { + t.C = *eh.buf.cursors[teCursor.Num] + eh.buf.cursors[teCursor.Num].Goto(teCursor) + } else { + teCursor.Num = -1 + } eh.UndoStack.Push(t) } diff --git a/cmd/micro/view.go b/cmd/micro/view.go index 8a009b65..72380093 100644 --- a/cmd/micro/view.go +++ b/cmd/micro/view.go @@ -479,6 +479,11 @@ func (v *View) ExecuteActions(actions []func(*View, bool) bool) bool { return relocate } +func (v *View) SetCursor(c *Cursor) { + v.Cursor = c + v.Buf.curCursor = c.Num +} + // HandleEvent handles an event passed by the main loop func (v *View) HandleEvent(event tcell.Event) { // This bool determines whether the view is relocated at the end of the function @@ -500,12 +505,12 @@ func (v *View) HandleEvent(event tcell.Event) { } if e.Modifiers() == key.modifiers { for _, c := range v.Buf.cursors { - v.Cursor = c + v.SetCursor(c) relocate = false isBinding = true relocate = v.ExecuteActions(actions) || relocate } - v.Cursor = &v.Buf.Cursor + v.SetCursor(&v.Buf.Cursor) break } } @@ -514,7 +519,7 @@ func (v *View) HandleEvent(event tcell.Event) { // Check viewtype if readonly don't insert a rune (readonly help and log view etc.) if v.Type.readonly == false { for _, c := range v.Buf.cursors { - v.Cursor = c + v.SetCursor(c) // Insert a character if v.Cursor.HasSelection() { @@ -534,7 +539,7 @@ func (v *View) HandleEvent(event tcell.Event) { curMacro = append(curMacro, e.Rune()) } } - v.Cursor = &v.Buf.Cursor + v.SetCursor(&v.Buf.Cursor) } } case *tcell.EventPaste: @@ -545,11 +550,11 @@ func (v *View) HandleEvent(event tcell.Event) { } for _, c := range v.Buf.cursors { - v.Cursor = c + v.SetCursor(c) v.paste(e.Text()) } - v.Cursor = &v.Buf.Cursor + v.SetCursor(&v.Buf.Cursor) PostActionCall("Paste", v) } @@ -562,10 +567,10 @@ func (v *View) HandleEvent(event tcell.Event) { for key, actions := range bindings { if button == key.buttons && e.Modifiers() == key.modifiers { for _, c := range v.Buf.cursors { - v.Cursor = c + v.SetCursor(c) relocate = v.ExecuteActions(actions) || relocate } - v.Cursor = &v.Buf.Cursor + v.SetCursor(&v.Buf.Cursor) } } @@ -841,7 +846,7 @@ func (v *View) DisplayView() { charLoc := char.realLoc for _, c := range v.Buf.cursors { - v.Cursor = c + v.SetCursor(c) if v.Cursor.HasSelection() && (charLoc.GreaterEqual(v.Cursor.CurSelection[0]) && charLoc.LessThan(v.Cursor.CurSelection[1]) || charLoc.LessThan(v.Cursor.CurSelection[0]) && charLoc.GreaterEqual(v.Cursor.CurSelection[1])) { @@ -853,7 +858,7 @@ func (v *View) DisplayView() { } } } - v.Cursor = &v.Buf.Cursor + v.SetCursor(&v.Buf.Cursor) if v.Buf.Settings["cursorline"].(bool) && tabs[curTab].CurView == v.Num && !v.Cursor.HasSelection() && v.Cursor.Y == realLineN { @@ -865,14 +870,14 @@ func (v *View) DisplayView() { screen.SetContent(xOffset+char.visualLoc.X, yOffset+char.visualLoc.Y, char.drawChar, nil, lineStyle) for i, c := range v.Buf.cursors { - v.Cursor = c + v.SetCursor(c) if tabs[curTab].CurView == v.Num && !v.Cursor.HasSelection() && v.Cursor.Y == char.realLoc.Y && v.Cursor.X == char.realLoc.X && (!cursorSet || i != 0) { ShowMultiCursor(xOffset+char.visualLoc.X, yOffset+char.visualLoc.Y, i) cursorSet = true } } - v.Cursor = &v.Buf.Cursor + v.SetCursor(&v.Buf.Cursor) lastChar = char } @@ -885,26 +890,26 @@ func (v *View) DisplayView() { if lastChar != nil { lastX = xOffset + lastChar.visualLoc.X + lastChar.width for i, c := range v.Buf.cursors { - v.Cursor = c + v.SetCursor(c) if tabs[curTab].CurView == v.Num && !v.Cursor.HasSelection() && v.Cursor.Y == lastChar.realLoc.Y && v.Cursor.X == lastChar.realLoc.X+1 { ShowMultiCursor(lastX, yOffset+lastChar.visualLoc.Y, i) cx, cy = lastX, yOffset+lastChar.visualLoc.Y } } - v.Cursor = &v.Buf.Cursor + v.SetCursor(&v.Buf.Cursor) realLoc = Loc{lastChar.realLoc.X + 1, realLineN} visualLoc = Loc{lastX - xOffset, lastChar.visualLoc.Y} } else if len(line) == 0 { for i, c := range v.Buf.cursors { - v.Cursor = c + v.SetCursor(c) if tabs[curTab].CurView == v.Num && !v.Cursor.HasSelection() && v.Cursor.Y == realLineN { ShowMultiCursor(xOffset, yOffset+visualLineN, i) cx, cy = xOffset, yOffset+visualLineN } } - v.Cursor = &v.Buf.Cursor + v.SetCursor(&v.Buf.Cursor) lastX = xOffset realLoc = Loc{0, realLineN} visualLoc = Loc{0, visualLineN}