mirror of
https://github.com/zyedidia/micro.git
synced 2026-03-16 13:57:07 +09:00
Get undo working properly with multiple cursors
This commit is contained in:
@@ -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()
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user