Skip to content

Commit 6214abb

Browse files
committed
Overhaul LastVisualX and GetVisualX() usage
Restore the original meaning of LastVisualX before commit 6d13710 ("Implement moving cursor up/down within a wrapped line"): last visual x location of the cursor in a logical line in the buffer, not in a visual line on the screen (in other words, taking tabs and wide characters into account, but not taking softwrap into account). And add a separate LastWrappedVisualX field, similar to LastVisualX but taking softwrap into account as well. This allows tracking last x position at the same time for both cases when we care about softwrap and when we don't care about it. This can be useful, for example, for implementing cursor up/down movement actions that always move by logical lines, not by visual lines, even if softwrap is enabled (in addition to our default CursorUp and CursorDown actions that move by visual lines). Also this fixes a minor bug: in InsertTab(), when `tabstospaces` is enabled and we insert a tab, the amount of inserted spaces depends on the visual line wrapping (i.e. on the window width), which is probably not a good idea.
1 parent 85afb6e commit 6214abb

File tree

4 files changed

+28
-16
lines changed

4 files changed

+28
-16
lines changed

internal/action/actions.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,10 @@ func (h *BufPane) MoveCursorUp(n int) {
170170
if sloc == vloc.SLoc {
171171
// we are at the beginning of buffer
172172
h.Cursor.Loc = h.Buf.Start()
173-
h.Cursor.LastVisualX = 0
173+
h.Cursor.StoreVisualX()
174174
} else {
175175
vloc.SLoc = sloc
176-
vloc.VisualX = h.Cursor.LastVisualX
176+
vloc.VisualX = h.Cursor.LastWrappedVisualX
177177
h.Cursor.Loc = h.LocFromVLoc(vloc)
178178
}
179179
}
@@ -189,11 +189,10 @@ func (h *BufPane) MoveCursorDown(n int) {
189189
if sloc == vloc.SLoc {
190190
// we are at the end of buffer
191191
h.Cursor.Loc = h.Buf.End()
192-
vloc = h.VLocFromLoc(h.Cursor.Loc)
193-
h.Cursor.LastVisualX = vloc.VisualX
192+
h.Cursor.StoreVisualX()
194193
} else {
195194
vloc.SLoc = sloc
196-
vloc.VisualX = h.Cursor.LastVisualX
195+
vloc.VisualX = h.Cursor.LastWrappedVisualX
197196
h.Cursor.Loc = h.LocFromVLoc(vloc)
198197
}
199198
}
@@ -889,7 +888,7 @@ func (h *BufPane) InsertTab() bool {
889888
b := h.Buf
890889
indent := b.IndentString(util.IntOpt(b.Settings["tabsize"]))
891890
tabBytes := len(indent)
892-
bytesUntilIndent := tabBytes - (h.Cursor.GetVisualX() % tabBytes)
891+
bytesUntilIndent := tabBytes - (h.Cursor.GetVisualX(false) % tabBytes)
893892
b.Insert(h.Cursor.Loc, indent[:bytesUntilIndent])
894893
h.Relocate()
895894
return true
@@ -1275,6 +1274,7 @@ func (h *BufPane) Copy() bool {
12751274
func (h *BufPane) CopyLine() bool {
12761275
origLoc := h.Cursor.Loc
12771276
origLastVisualX := h.Cursor.LastVisualX
1277+
origLastWrappedVisualX := h.Cursor.LastWrappedVisualX
12781278
origSelection := h.Cursor.CurSelection
12791279

12801280
nlines := h.selectLines()
@@ -1291,6 +1291,7 @@ func (h *BufPane) CopyLine() bool {
12911291

12921292
h.Cursor.Loc = origLoc
12931293
h.Cursor.LastVisualX = origLastVisualX
1294+
h.Cursor.LastWrappedVisualX = origLastWrappedVisualX
12941295
h.Cursor.CurSelection = origSelection
12951296
h.Relocate()
12961297
return true
@@ -1360,6 +1361,7 @@ func (h *BufPane) DuplicateLine() bool {
13601361
if h.Cursor.HasSelection() {
13611362
origLoc := h.Cursor.Loc
13621363
origLastVisualX := h.Cursor.LastVisualX
1364+
origLastWrappedVisualX := h.Cursor.LastWrappedVisualX
13631365
origSelection := h.Cursor.CurSelection
13641366

13651367
start := h.Cursor.CurSelection[0]
@@ -1380,6 +1382,7 @@ func (h *BufPane) DuplicateLine() bool {
13801382

13811383
h.Cursor.Loc = origLoc
13821384
h.Cursor.LastVisualX = origLastVisualX
1385+
h.Cursor.LastWrappedVisualX = origLastWrappedVisualX
13831386
h.Cursor.CurSelection = origSelection
13841387

13851388
if start.Y < end.Y {
@@ -2070,6 +2073,7 @@ func (h *BufPane) SpawnMultiCursorUpN(n int) bool {
20702073

20712074
c = buffer.NewCursor(h.Buf, buffer.Loc{lastC.X, lastC.Y - n})
20722075
c.LastVisualX = lastC.LastVisualX
2076+
c.LastWrappedVisualX = lastC.LastWrappedVisualX
20732077
c.X = c.GetCharPosInLine(h.Buf.LineBytes(c.Y), c.LastVisualX)
20742078
c.Relocate()
20752079
} else {
@@ -2082,9 +2086,10 @@ func (h *BufPane) SpawnMultiCursorUpN(n int) bool {
20822086
h.Buf.DeselectCursors()
20832087

20842088
vloc.SLoc = sloc
2085-
vloc.VisualX = lastC.LastVisualX
2089+
vloc.VisualX = lastC.LastWrappedVisualX
20862090
c = buffer.NewCursor(h.Buf, h.LocFromVLoc(vloc))
20872091
c.LastVisualX = lastC.LastVisualX
2092+
c.LastWrappedVisualX = lastC.LastWrappedVisualX
20882093
}
20892094

20902095
h.Buf.AddCursor(c)

internal/buffer/cursor.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,14 @@ type Cursor struct {
2020
buf *Buffer
2121
Loc
2222

23-
// Last cursor x position
23+
// Last visual x position of the cursor. Used in cursor up/down movements
24+
// for remembering the original x position when moving to a line that is
25+
// shorter than current x position.
2426
LastVisualX int
27+
// Similar to LastVisualX but takes softwrapping into account, i.e. last
28+
// visual x position in a visual (wrapped) line on the screen, which may be
29+
// different from the line in the buffer.
30+
LastWrappedVisualX int
2531

2632
// The current selection as a range of character numbers (inclusive)
2733
CurSelection [2]Loc
@@ -61,7 +67,7 @@ func (c *Cursor) Buf() *Buffer {
6167
// Goto puts the cursor at the given cursor's location and gives
6268
// the current cursor its selection too
6369
func (c *Cursor) Goto(b Cursor) {
64-
c.X, c.Y, c.LastVisualX = b.X, b.Y, b.LastVisualX
70+
c.X, c.Y, c.LastVisualX, c.LastWrappedVisualX = b.X, b.Y, b.LastVisualX, b.LastWrappedVisualX
6571
c.OrigSelection, c.CurSelection = b.OrigSelection, b.CurSelection
6672
}
6773

@@ -73,8 +79,8 @@ func (c *Cursor) GotoLoc(l Loc) {
7379
}
7480

7581
// GetVisualX returns the x value of the cursor in visual spaces
76-
func (c *Cursor) GetVisualX() int {
77-
if c.buf.GetVisualX != nil {
82+
func (c *Cursor) GetVisualX(wrap bool) int {
83+
if wrap && c.buf.GetVisualX != nil {
7884
return c.buf.GetVisualX(c.Loc)
7985
}
8086

@@ -615,5 +621,6 @@ func (c *Cursor) RuneUnder(x int) rune {
615621
}
616622

617623
func (c *Cursor) StoreVisualX() {
618-
c.LastVisualX = c.GetVisualX()
624+
c.LastVisualX = c.GetVisualX(false)
625+
c.LastWrappedVisualX = c.GetVisualX(true)
619626
}

internal/display/bufwindow.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func (w *BufWindow) SetBuffer(b *buffer.Buffer) {
5858
if option == "softwrap" || option == "wordwrap" {
5959
w.Relocate()
6060
for _, c := range w.Buf.GetCursors() {
61-
c.LastVisualX = c.GetVisualX()
61+
c.LastWrappedVisualX = c.GetVisualX(true)
6262
}
6363
}
6464
}
@@ -160,7 +160,7 @@ func (w *BufWindow) updateDisplayInfo() {
160160

161161
if w.bufWidth != prevBufWidth && w.Buf.Settings["softwrap"].(bool) {
162162
for _, c := range w.Buf.GetCursors() {
163-
c.LastVisualX = c.GetVisualX()
163+
c.LastWrappedVisualX = c.GetVisualX(true)
164164
}
165165
}
166166
}
@@ -238,7 +238,7 @@ func (w *BufWindow) Relocate() bool {
238238

239239
// horizontal relocation (scrolling)
240240
if !b.Settings["softwrap"].(bool) {
241-
cx := activeC.GetVisualX()
241+
cx := activeC.GetVisualX(false)
242242
rw := runewidth.RuneWidth(activeC.RuneUnder(activeC.X))
243243
if rw == 0 {
244244
rw = 1 // tab or newline

runtime/plugins/status/status.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ function lines(b)
2121
end
2222

2323
function vcol(b)
24-
return tostring(b:GetActiveCursor():GetVisualX())
24+
return tostring(b:GetActiveCursor():GetVisualX(false))
2525
end
2626

2727
function bytes(b)

0 commit comments

Comments
 (0)