mirror of
https://github.com/zyedidia/micro.git
synced 2026-03-16 05:47:06 +09:00
Add VLoc, VLocFromLoc and LocFromVLoc
VLoc allows any location in the buffer to be represented as a visual location in the linewrapped buffer. In particular, this is useful for implementing moving cursor up and down within a wrapped line.
This commit is contained in:
@@ -78,6 +78,8 @@ func (i *InfoWindow) BufHeight() int { return 1 }
|
|||||||
func (i *InfoWindow) Scroll(s SLoc, n int) SLoc { return s }
|
func (i *InfoWindow) Scroll(s SLoc, n int) SLoc { return s }
|
||||||
func (i *InfoWindow) Diff(s1, s2 SLoc) int { return 0 }
|
func (i *InfoWindow) Diff(s1, s2 SLoc) int { return 0 }
|
||||||
func (i *InfoWindow) SLocFromLoc(loc buffer.Loc) SLoc { return SLoc{0, 0} }
|
func (i *InfoWindow) SLocFromLoc(loc buffer.Loc) SLoc { return SLoc{0, 0} }
|
||||||
|
func (i *InfoWindow) VLocFromLoc(loc buffer.Loc) VLoc { return VLoc{SLoc{0, 0}, loc.X} }
|
||||||
|
func (i *InfoWindow) LocFromVLoc(vloc VLoc) buffer.Loc { return buffer.Loc{vloc.VisualX, 0} }
|
||||||
|
|
||||||
func (i *InfoWindow) Clear() {
|
func (i *InfoWindow) Clear() {
|
||||||
for x := 0; x < i.Width; x++ {
|
for x := 0; x < i.Width; x++ {
|
||||||
|
|||||||
@@ -30,27 +30,36 @@ func (s SLoc) GreaterThan(b SLoc) bool {
|
|||||||
return s.Line == b.Line && s.Row > b.Row
|
return s.Line == b.Line && s.Row > b.Row
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VLoc represents a location in the buffer as a visual location in the
|
||||||
|
// linewrapped buffer.
|
||||||
|
type VLoc struct {
|
||||||
|
SLoc
|
||||||
|
VisualX int
|
||||||
|
}
|
||||||
|
|
||||||
type SoftWrap interface {
|
type SoftWrap interface {
|
||||||
Scroll(s SLoc, n int) SLoc
|
Scroll(s SLoc, n int) SLoc
|
||||||
Diff(s1, s2 SLoc) int
|
Diff(s1, s2 SLoc) int
|
||||||
SLocFromLoc(loc buffer.Loc) SLoc
|
SLocFromLoc(loc buffer.Loc) SLoc
|
||||||
|
VLocFromLoc(loc buffer.Loc) VLoc
|
||||||
|
LocFromVLoc(vloc VLoc) buffer.Loc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *BufWindow) getRow(loc buffer.Loc) int {
|
func (w *BufWindow) getVLocFromLoc(loc buffer.Loc) VLoc {
|
||||||
|
vloc := VLoc{SLoc: SLoc{loc.Y, 0}, VisualX: 0}
|
||||||
|
|
||||||
if loc.X <= 0 {
|
if loc.X <= 0 {
|
||||||
return 0
|
return vloc
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.bufWidth <= 0 {
|
if w.bufWidth <= 0 {
|
||||||
return 0
|
return vloc
|
||||||
}
|
}
|
||||||
|
|
||||||
tabsize := util.IntOpt(w.Buf.Settings["tabsize"])
|
tabsize := util.IntOpt(w.Buf.Settings["tabsize"])
|
||||||
|
|
||||||
line := w.Buf.LineBytes(loc.Y)
|
line := w.Buf.LineBytes(loc.Y)
|
||||||
x := 0
|
x := 0
|
||||||
visualx := 0
|
|
||||||
row := 0
|
|
||||||
totalwidth := 0
|
totalwidth := 0
|
||||||
|
|
||||||
for len(line) > 0 {
|
for len(line) > 0 {
|
||||||
@@ -60,7 +69,7 @@ func (w *BufWindow) getRow(loc buffer.Loc) int {
|
|||||||
switch r {
|
switch r {
|
||||||
case '\t':
|
case '\t':
|
||||||
ts := tabsize - (totalwidth % tabsize)
|
ts := tabsize - (totalwidth % tabsize)
|
||||||
width = util.Min(ts, w.bufWidth-visualx)
|
width = util.Min(ts, w.bufWidth-vloc.VisualX)
|
||||||
totalwidth += ts
|
totalwidth += ts
|
||||||
default:
|
default:
|
||||||
width = runewidth.RuneWidth(r)
|
width = runewidth.RuneWidth(r)
|
||||||
@@ -68,28 +77,81 @@ func (w *BufWindow) getRow(loc buffer.Loc) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If a wide rune does not fit in the window
|
// If a wide rune does not fit in the window
|
||||||
if visualx+width > w.bufWidth && visualx > 0 {
|
if vloc.VisualX+width > w.bufWidth && vloc.VisualX > 0 {
|
||||||
row++
|
vloc.Row++
|
||||||
visualx = 0
|
vloc.VisualX = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if x == loc.X {
|
if x == loc.X {
|
||||||
return row
|
return vloc
|
||||||
}
|
}
|
||||||
x++
|
x++
|
||||||
line = line[size:]
|
line = line[size:]
|
||||||
|
|
||||||
visualx += width
|
vloc.VisualX += width
|
||||||
if visualx >= w.bufWidth {
|
if vloc.VisualX >= w.bufWidth {
|
||||||
row++
|
vloc.Row++
|
||||||
visualx = 0
|
vloc.VisualX = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return row
|
return vloc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *BufWindow) getLocFromVLoc(svloc VLoc) buffer.Loc {
|
||||||
|
loc := buffer.Loc{X: 0, Y: svloc.Line}
|
||||||
|
|
||||||
|
if w.bufWidth <= 0 {
|
||||||
|
return loc
|
||||||
|
}
|
||||||
|
|
||||||
|
tabsize := util.IntOpt(w.Buf.Settings["tabsize"])
|
||||||
|
|
||||||
|
line := w.Buf.LineBytes(svloc.Line)
|
||||||
|
vloc := VLoc{SLoc: SLoc{svloc.Line, 0}, VisualX: 0}
|
||||||
|
|
||||||
|
totalwidth := 0
|
||||||
|
|
||||||
|
for len(line) > 0 {
|
||||||
|
r, _, size := util.DecodeCharacter(line)
|
||||||
|
|
||||||
|
width := 0
|
||||||
|
switch r {
|
||||||
|
case '\t':
|
||||||
|
ts := tabsize - (totalwidth % tabsize)
|
||||||
|
width = util.Min(ts, w.bufWidth-vloc.VisualX)
|
||||||
|
totalwidth += ts
|
||||||
|
default:
|
||||||
|
width = runewidth.RuneWidth(r)
|
||||||
|
totalwidth += width
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a wide rune does not fit in the window
|
||||||
|
if vloc.VisualX+width > w.bufWidth && vloc.VisualX > 0 {
|
||||||
|
if vloc.Row == svloc.Row {
|
||||||
|
return loc
|
||||||
|
}
|
||||||
|
vloc.Row++
|
||||||
|
vloc.VisualX = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
vloc.VisualX += width
|
||||||
|
if vloc.Row == svloc.Row && vloc.VisualX > svloc.VisualX {
|
||||||
|
return loc
|
||||||
|
}
|
||||||
|
loc.X++
|
||||||
|
line = line[size:]
|
||||||
|
|
||||||
|
if vloc.VisualX >= w.bufWidth {
|
||||||
|
vloc.Row++
|
||||||
|
vloc.VisualX = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return loc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *BufWindow) getRowCount(line int) int {
|
func (w *BufWindow) getRowCount(line int) int {
|
||||||
return w.getRow(buffer.Loc{X: util.CharacterCount(w.Buf.LineBytes(line)), Y: line}) + 1
|
eol := buffer.Loc{X: util.CharacterCount(w.Buf.LineBytes(line)), Y: line}
|
||||||
|
return w.getVLocFromLoc(eol).Row + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *BufWindow) scrollUp(s SLoc, n int) SLoc {
|
func (w *BufWindow) scrollUp(s SLoc, n int) SLoc {
|
||||||
@@ -184,5 +246,29 @@ func (w *BufWindow) SLocFromLoc(loc buffer.Loc) SLoc {
|
|||||||
if !w.Buf.Settings["softwrap"].(bool) {
|
if !w.Buf.Settings["softwrap"].(bool) {
|
||||||
return SLoc{loc.Y, 0}
|
return SLoc{loc.Y, 0}
|
||||||
}
|
}
|
||||||
return SLoc{loc.Y, w.getRow(loc)}
|
return w.getVLocFromLoc(loc).SLoc
|
||||||
|
}
|
||||||
|
|
||||||
|
// VLocFromLoc takes a position in the buffer and returns the corresponding
|
||||||
|
// visual location in the linewrapped buffer.
|
||||||
|
func (w *BufWindow) VLocFromLoc(loc buffer.Loc) VLoc {
|
||||||
|
if !w.Buf.Settings["softwrap"].(bool) {
|
||||||
|
tabsize := util.IntOpt(w.Buf.Settings["tabsize"])
|
||||||
|
|
||||||
|
visualx := util.StringWidth(w.Buf.LineBytes(loc.Y), loc.X, tabsize)
|
||||||
|
return VLoc{SLoc{loc.Y, 0}, visualx}
|
||||||
|
}
|
||||||
|
return w.getVLocFromLoc(loc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LocFromVLoc takes a visual location in the linewrapped buffer and returns
|
||||||
|
// the position in the buffer corresponding to this visual location.
|
||||||
|
func (w *BufWindow) LocFromVLoc(vloc VLoc) buffer.Loc {
|
||||||
|
if !w.Buf.Settings["softwrap"].(bool) {
|
||||||
|
tabsize := util.IntOpt(w.Buf.Settings["tabsize"])
|
||||||
|
|
||||||
|
x := util.GetCharPosInLine(w.Buf.LineBytes(vloc.Line), vloc.VisualX, tabsize)
|
||||||
|
return buffer.Loc{x, vloc.Line}
|
||||||
|
}
|
||||||
|
return w.getLocFromVLoc(vloc)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user