Implement vertical cursor movement and reset cursor on file open

This commit is contained in:
Greg Pomerantz 2026-06-03 19:49:27 -04:00
parent d33e68ab2c
commit 3f53836ade

View File

@ -167,6 +167,7 @@ func GoToEditor(data any) {
// data is the filename string from the browser list. // data is the filename string from the browser list.
func OpenFile(data any) { func OpenFile(data any) {
TheState.Editor.Buffer = "Select a file to edit..." // Placeholder, should be loaded from file TheState.Editor.Buffer = "Select a file to edit..." // Placeholder, should be loaded from file
TheState.Editor.CursorPosition = 0 // Reset cursor to top
TheState.ScrollOffset = 0 // Reset editor scroll to top when opening a new file TheState.ScrollOffset = 0 // Reset editor scroll to top when opening a new file
TheState.page = EditorPage TheState.page = EditorPage
TheState.FocusedElementID = "editor_text" // Set focus to editor TheState.FocusedElementID = "editor_text" // Set focus to editor
@ -214,6 +215,10 @@ func HandleKeyDown(data any) {
HandleCursorMove(-1) HandleCursorMove(-1)
case key.NameRightArrow: case key.NameRightArrow:
HandleCursorMove(1) HandleCursorMove(1)
case key.NameUpArrow:
HandleVerticalCursorMove(true)
case key.NameDownArrow:
HandleVerticalCursorMove(false)
case key.NameDeleteBackward: case key.NameDeleteBackward:
HandleBackspace() HandleBackspace()
case key.NameDeleteForward: case key.NameDeleteForward:
@ -222,6 +227,91 @@ func HandleKeyDown(data any) {
} }
} }
// HandleVerticalCursorMove updates the cursor position to the previous or next visual line.
func HandleVerticalCursorMove(up bool) {
layout := TheState.Editor.GlyphLayout
if len(layout.ByteOffsets) == 0 {
return
}
pos := TheState.Editor.CursorPosition
// Find current glyph index.
idx := sort.Search(len(layout.ByteOffsets), func(i int) bool {
return layout.ByteOffsets[i] >= pos
})
// If idx == len, we are at the end. Use the last glyph.
if idx == len(layout.ByteOffsets) {
idx = len(layout.ByteOffsets) - 1
}
currentX := layout.X[idx]
currentY := layout.Y[idx]
var targetIdx int = idx
if up {
// Scan backwards to find the previous line's Y.
prevY := currentY
for i := idx; i >= 0; i-- {
if layout.Y[i] < prevY {
prevY = layout.Y[i]
break
}
}
if prevY == currentY {
// Already at the top line?
return
}
// Now find the closest X in prevY.
bestDiff := float32(1e9)
for i := 0; i < len(layout.Y); i++ {
if layout.Y[i] == prevY {
diff := float32(layout.X[i] - currentX)
if diff < 0 {
diff = -diff
}
if diff < bestDiff {
bestDiff = diff
targetIdx = i
}
}
}
} else {
// Scan forwards to find the next line's Y.
nextY := currentY
for i := idx; i < len(layout.Y); i++ {
if layout.Y[i] > nextY {
nextY = layout.Y[i]
break
}
}
if nextY == currentY {
// Already at the bottom line?
return
}
// Now find the closest X in nextY.
bestDiff := float32(1e9)
for i := 0; i < len(layout.Y); i++ {
if layout.Y[i] == nextY {
diff := float32(layout.X[i] - currentX)
if diff < 0 {
diff = -diff
}
if diff < bestDiff {
bestDiff = diff
targetIdx = i
}
}
}
}
TheState.Editor.CursorPosition = layout.ByteOffsets[targetIdx]
}
// HandleDelete removes the character after the cursor. // HandleDelete removes the character after the cursor.
func HandleDelete() { func HandleDelete() {
pos := TheState.Editor.CursorPosition pos := TheState.Editor.CursorPosition