Fix cursor Y positioning logic in editor

This commit is contained in:
Greg Pomerantz 2026-06-03 22:47:06 -04:00
parent 6939550527
commit 979656c2d0

View File

@ -457,47 +457,72 @@ func SetCursorFromPoint(x, y float64) {
return
}
// 1. Find the best line based on y
bestLineY := layout.Y[0]
minYDist := 1e9
for _, yVal := range layout.Y {
yDist := float64(yVal) - y
if yDist < 0 {
yDist = -yDist
lineHeight := float64(EditorLineHeight())
// 1. Identify the intended line index based on y
// layout.Y values are relative to the text region origin.
// We need to account for scroll offset.
visualLine := int((y + float64(TheState.ScrollOffset)) / lineHeight)
// Group glyphs by their Y-baseline
type lineGroup struct {
y float64
indices []int
}
if yDist < minYDist {
minYDist = yDist
bestLineY = yVal
groups := []lineGroup{}
seenY := make(map[float64]int) // maps Y to group index
for i, yVal := range layout.Y {
yFloat := float64(yVal)
idx, ok := seenY[yFloat]
if !ok {
idx = len(groups)
groups = append(groups, lineGroup{y: yFloat, indices: []int{}})
seenY[yFloat] = idx
}
groups[idx].indices = append(groups[idx].indices, i)
}
// Sort groups by Y
sort.Slice(groups, func(i, j int) bool { return groups[i].y < groups[j].y })
// If visualLine is out of bounds, clamp
if visualLine < 0 {
visualLine = 0
}
if visualLine >= len(groups) {
visualLine = len(groups) - 1
}
// 2. Identify glyphs on this line and find the rightmost extent
targetGroup := groups[visualLine]
// 3. Identify rightmost extent on this line
rightmostX := 0.0
rightmostIdx := -1
for i, yVal := range layout.Y {
if yVal == bestLineY {
for _, i := range targetGroup.indices {
xEnd := float64(layout.X[i] + layout.Advance[i])
if xEnd > rightmostX {
rightmostX = xEnd
rightmostIdx = i
}
}
}
// 3. Check if tap is to the right of the last character on this line
// 4. Check if tap is to the right of the last character
if rightmostIdx != -1 && x > rightmostX {
// Position after the last character on this line
// Position at the end of the line content, before any trailing newline.
start := layout.ByteOffsets[rightmostIdx]
_, size := utf8.DecodeRuneInString(TheState.Editor.Buffer[start:])
r, size := utf8.DecodeRuneInString(TheState.Editor.Buffer[start:])
if r == '\n' {
TheState.Editor.CursorPosition = start
} else {
TheState.Editor.CursorPosition = start + size
}
return
}
// 4. Otherwise, find the closest glyph on this line.
// 5. Otherwise, find the closest glyph on this line.
bestIdx := -1
minDist := float64(1e9)
for i, yVal := range layout.Y {
if yVal == bestLineY {
for _, i := range targetGroup.indices {
if bestIdx == -1 {
bestIdx = i
}
@ -512,7 +537,6 @@ func SetCursorFromPoint(x, y float64) {
bestIdx = i
}
}
}
if bestIdx != -1 {
TheState.Editor.CursorPosition = layout.ByteOffsets[bestIdx]
}