Implement moving cursor up/down within a wrapped line

Modified behavior of CursorUp, CursorDown, CursorPageUp etc:
if softwrap is enabled, cursor moves by visual lines, not logical lines.

TODO: implement it also for Home and End keys: move cursor to the
visual start or end of a line. I haven't implemented it for now, because
I'm not sure what should be the behavior of StartOfTextToggle then
(considering that Home key is bound to StartOfTextToggle by default).

Fixes #1598
This commit is contained in:
Dmitry Maluka 2021-03-06 23:43:36 +01:00
parent 7a3d1e6e30
commit 6d13710d93
4 changed files with 72 additions and 8 deletions

View File

@ -123,10 +123,49 @@ func (h *BufPane) Center() bool {
return true
}
// MoveCursorUp is not an action
func (h *BufPane) MoveCursorUp(n int) {
if !h.Buf.Settings["softwrap"].(bool) {
h.Cursor.UpN(n)
} else {
vloc := h.VLocFromLoc(h.Cursor.Loc)
sloc := h.Scroll(vloc.SLoc, -n)
if sloc == vloc.SLoc {
// we are at the beginning of buffer
h.Cursor.Loc = h.Buf.Start()
h.Cursor.LastVisualX = 0
} else {
vloc.SLoc = sloc
vloc.VisualX = h.Cursor.LastVisualX
h.Cursor.Loc = h.LocFromVLoc(vloc)
}
}
}
// MoveCursorDown is not an action
func (h *BufPane) MoveCursorDown(n int) {
if !h.Buf.Settings["softwrap"].(bool) {
h.Cursor.DownN(n)
} else {
vloc := h.VLocFromLoc(h.Cursor.Loc)
sloc := h.Scroll(vloc.SLoc, n)
if sloc == vloc.SLoc {
// we are at the end of buffer
h.Cursor.Loc = h.Buf.End()
vloc = h.VLocFromLoc(h.Cursor.Loc)
h.Cursor.LastVisualX = vloc.VisualX
} else {
vloc.SLoc = sloc
vloc.VisualX = h.Cursor.LastVisualX
h.Cursor.Loc = h.LocFromVLoc(vloc)
}
}
}
// CursorUp moves the cursor up
func (h *BufPane) CursorUp() bool {
h.Cursor.Deselect(true)
h.Cursor.Up()
h.MoveCursorUp(1)
h.Relocate()
return true
}
@ -134,7 +173,7 @@ func (h *BufPane) CursorUp() bool {
// CursorDown moves the cursor down
func (h *BufPane) CursorDown() bool {
h.Cursor.Deselect(true)
h.Cursor.Down()
h.MoveCursorDown(1)
h.Relocate()
return true
}
@ -212,7 +251,7 @@ func (h *BufPane) SelectUp() bool {
if !h.Cursor.HasSelection() {
h.Cursor.OrigSelection[0] = h.Cursor.Loc
}
h.Cursor.Up()
h.MoveCursorUp(1)
h.Cursor.SelectTo(h.Cursor.Loc)
h.Relocate()
return true
@ -223,7 +262,7 @@ func (h *BufPane) SelectDown() bool {
if !h.Cursor.HasSelection() {
h.Cursor.OrigSelection[0] = h.Cursor.Loc
}
h.Cursor.Down()
h.MoveCursorDown(1)
h.Cursor.SelectTo(h.Cursor.Loc)
h.Relocate()
return true
@ -1274,7 +1313,7 @@ func (h *BufPane) SelectPageUp() bool {
if !h.Cursor.HasSelection() {
h.Cursor.OrigSelection[0] = h.Cursor.Loc
}
h.Cursor.UpN(h.BufHeight())
h.MoveCursorUp(h.BufHeight())
h.Cursor.SelectTo(h.Cursor.Loc)
h.Relocate()
return true
@ -1285,7 +1324,7 @@ func (h *BufPane) SelectPageDown() bool {
if !h.Cursor.HasSelection() {
h.Cursor.OrigSelection[0] = h.Cursor.Loc
}
h.Cursor.DownN(h.BufHeight())
h.MoveCursorDown(h.BufHeight())
h.Cursor.SelectTo(h.Cursor.Loc)
h.Relocate()
return true
@ -1300,7 +1339,7 @@ func (h *BufPane) CursorPageUp() bool {
h.Cursor.ResetSelection()
h.Cursor.StoreVisualX()
}
h.Cursor.UpN(h.BufHeight())
h.MoveCursorUp(h.BufHeight())
h.Relocate()
return true
}
@ -1314,7 +1353,7 @@ func (h *BufPane) CursorPageDown() bool {
h.Cursor.ResetSelection()
h.Cursor.StoreVisualX()
}
h.Cursor.DownN(h.BufHeight())
h.MoveCursorDown(h.BufHeight())
h.Relocate()
return true
}

View File

@ -196,6 +196,12 @@ type Buffer struct {
// the buffer module cannot directly call the display's API (it would mean
// a circular dependency between packages).
OptionCallback func(option string, nativeValue interface{})
// The display module registers its own GetVisualX function for getting
// the correct visual x location of a cursor when softwrap is used.
// This is hacky. Maybe it would be better to move all the visual x logic
// from buffer to display, but it would require rewriting a lot of code.
GetVisualX func(loc Loc) int
}
// NewBufferFromFileAtLoc opens a new buffer with a given cursor location

View File

@ -67,6 +67,10 @@ func (c *Cursor) GotoLoc(l Loc) {
// GetVisualX returns the x value of the cursor in visual spaces
func (c *Cursor) GetVisualX() int {
if c.buf.GetVisualX != nil {
return c.buf.GetVisualX(c.Loc)
}
if c.X <= 0 {
c.X = 0
return 0

View File

@ -54,8 +54,15 @@ func (w *BufWindow) SetBuffer(b *buffer.Buffer) {
w.StartLine.Row = 0
}
w.Relocate()
for _, c := range w.Buf.GetCursors() {
c.LastVisualX = c.GetVisualX()
}
}
}
b.GetVisualX = func(loc buffer.Loc) int {
return w.VLocFromLoc(loc).VisualX
}
}
func (w *BufWindow) GetView() *View {
@ -68,7 +75,15 @@ func (w *BufWindow) SetView(view *View) {
func (w *BufWindow) Resize(width, height int) {
w.Width, w.Height = width, height
w.updateDisplayInfo()
w.Relocate()
if w.Buf.Settings["softwrap"].(bool) {
for _, c := range w.Buf.GetCursors() {
c.LastVisualX = c.GetVisualX()
}
}
}
func (w *BufWindow) SetActive(b bool) {