diff --git a/internal/editor/state.go b/internal/editor/state.go index 30c51bf..58eb6f5 100644 --- a/internal/editor/state.go +++ b/internal/editor/state.go @@ -456,21 +456,66 @@ func SetCursorFromPoint(x, y float64) { return } - // Simple heuristic: find the closest glyph by distance to (x, y) - bestIdx := 0 - minDist := float64(1e9) - lineHeight := float64(EditorLineHeight()) - - for i := 0; i < len(layout.X); i++ { - dx := float64(layout.X[i]) - x - // layout.Y[i] is the baseline. Taps are generally near the middle of the line. - // Adjust to compare against the approximate vertical center of the line. - dy := float64(layout.Y[i] - ui.Dp(lineHeight/2)) - y - dist := dx*dx + dy*dy - if dist < minDist { - minDist = dist - bestIdx = i + // 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 + } + if yDist < minYDist { + minYDist = yDist + bestLineY = yVal } } - TheState.Editor.CursorPosition = layout.ByteOffsets[bestIdx] + + // 2. Identify glyphs on this line and find the rightmost extent + rightmostX := 0.0 + rightmostIdx := -1 + for i, yVal := range layout.Y { + if yVal == bestLineY { + 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 + if rightmostIdx != -1 && x > rightmostX { + // If rightmostIdx is the last glyph of the entire document + if rightmostIdx == len(layout.X)-1 { + TheState.Editor.CursorPosition = len(TheState.Editor.Buffer) + } else { + // Position after the last character on this line + TheState.Editor.CursorPosition = layout.ByteOffsets[rightmostIdx+1] + } + return + } + + // 4. Otherwise, find the closest glyph on this line. + bestIdx := -1 + minDist := float64(1e9) + for i, yVal := range layout.Y { + if yVal == bestLineY { + if bestIdx == -1 { + bestIdx = i + } + // Calculate distance to the glyph center + glyphCenterX := float64(layout.X[i] + layout.Advance[i]/2) + dist := glyphCenterX - x + if dist < 0 { + dist = -dist + } + if dist < minDist { + minDist = dist + bestIdx = i + } + } + } + if bestIdx != -1 { + TheState.Editor.CursorPosition = layout.ByteOffsets[bestIdx] + } }