Skip to content

Commit fa41c93

Browse files
committed
Refactor cursor_up and cursor_down functions to support multi-line navigation, introduce page up/down handling, and improve cursor movement logic in view_text.v.
1 parent 1a80b35 commit fa41c93

File tree

2 files changed

+47
-33
lines changed

2 files changed

+47
-33
lines changed

view_text.v

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -241,48 +241,56 @@ fn (tv &TextView) on_key_down(layout &Layout, mut e Event, mut window Window) {
241241
return
242242
}
243243
mut input_state := window.view_state.input_state[layout.shape.id_focus]
244-
mut position := input_state.cursor_pos
244+
mut pos := input_state.cursor_pos
245245
mut offset := input_state.cursor_offset
246246
text_lines := layout.shape.text_lines
247247

248248
// Handle navigation with modifiers
249249
if e.modifiers == .alt || e.modifiers == .alt_shift {
250250
// Alt: Jump by word or paragraph
251251
match e.key_code {
252-
.left { position = cursor_start_of_word(text_lines, position) }
253-
.right { position = cursor_end_of_word(text_lines, position) }
254-
.up { position = cursor_start_of_paragraph(text_lines, position) }
252+
.left { pos = cursor_start_of_word(text_lines, pos) }
253+
.right { pos = cursor_end_of_word(text_lines, pos) }
254+
.up { pos = cursor_start_of_paragraph(text_lines, pos) }
255255
else { return }
256256
}
257257
} else if e.modifiers == .ctrl || e.modifiers == .ctrl_shift {
258258
// Ctrl: Jump to start/end of line
259259
match e.key_code {
260-
.left { position = cursor_start_of_line(text_lines, position) }
261-
.right { position = cursor_end_of_line(text_lines, position) }
260+
.left { pos = cursor_start_of_line(text_lines, pos) }
261+
.right { pos = cursor_end_of_line(text_lines, pos) }
262262
else { return }
263263
}
264264
} else if e.modifiers.has_any(.none, .shift) {
265265
// Standard navigation: char by char, prev/next line, home/end of text
266+
mut lpp := 0 // lines per page
267+
layout_scroll := find_layout_by_id_scroll(window.layout, layout.shape.id_scroll_container)
268+
if layout_scroll != none {
269+
layout_scroll_height := layout_scroll.shape.height - layout_scroll.shape.padding.height()
270+
lpp = int(layout_scroll_height / line_height(layout.shape))
271+
}
266272
match e.key_code {
267-
.left { position = cursor_left(position) }
268-
.right { position = cursor_right(text_lines, position) }
269-
.up { position = cursor_up(layout.shape, position, offset, window) }
270-
.down { position = cursor_down(layout.shape, position, offset, window) }
271-
.home { position = cursor_home() }
272-
.end { position = cursor_end(text_lines) }
273+
.left { pos = cursor_left(pos) }
274+
.right { pos = cursor_right(text_lines, pos) }
275+
.up { pos = cursor_up(layout.shape, pos, offset, 1, window) }
276+
.down { pos = cursor_down(layout.shape, pos, offset, 1, window) }
277+
.page_up { pos = cursor_up(layout.shape, pos, offset, lpp, window) }
278+
.page_down { pos = cursor_down(layout.shape, pos, offset, lpp, window) }
279+
.home { pos = cursor_home() }
280+
.end { pos = cursor_end(text_lines) }
273281
else { return }
274282
}
275283
} else if e.modifiers == Modifier.super {
276284
return
277285
}
278286

279287
if (e.key_code != .up && e.key_code != .down) || input_state.cursor_offset < 0 {
280-
offset = offset_from_cursor_position(layout.shape, position, window)
288+
offset = offset_from_cursor_position(layout.shape, pos, window)
281289
}
282290

283291
// input_cursor_on_sticky allows the cursor to stay on during cursor movements.
284292
// See `blinky_cursor_animation()`
285-
if position != input_state.cursor_pos {
293+
if pos != input_state.cursor_pos {
286294
window.view_state.cursor_on_sticky = true
287295
}
288296

@@ -305,16 +313,16 @@ fn (tv &TextView) on_key_down(layout &Layout, mut e Event, mut window Window) {
305313

306314
// Move the selection boundary that was at the old cursor position.
307315
if old_cursor_pos == int(select_beg) {
308-
select_beg = u32(position)
316+
select_beg = u32(pos)
309317
} else if old_cursor_pos == int(select_end) {
310-
select_end = u32(position)
318+
select_end = u32(pos)
311319
} else {
312320
// If the old cursor was not at a boundary (e.g., from a click),
313321
// move the boundary closest to the new cursor position.
314-
if math.abs(position - int(select_beg)) < math.abs(position - int(select_end)) {
315-
select_beg = u32(position)
322+
if math.abs(pos - int(select_beg)) < math.abs(pos - int(select_end)) {
323+
select_beg = u32(pos)
316324
} else {
317-
select_end = u32(position)
325+
select_end = u32(pos)
318326
}
319327
}
320328
// Ensure beg is always less than or equal to end
@@ -324,24 +332,24 @@ fn (tv &TextView) on_key_down(layout &Layout, mut e Event, mut window Window) {
324332
} else if input_state.select_beg != input_state.select_end && e.modifiers == .none {
325333
// If a selection exists and a non-shift movement key is pressed,
326334
// collapse the selection to the beginning or end of the selection.
327-
position = match e.key_code {
335+
pos = match e.key_code {
328336
.left, .home { int(input_state.select_beg) }
329337
.right, .end { int(input_state.select_end) }
330-
else { position }
338+
else { pos }
331339
}
332340
}
333341

334342
// Update input state with new cursor position and selection
335343
window.view_state.input_state[layout.shape.id_focus] = InputState{
336344
...input_state
337-
cursor_pos: position
345+
cursor_pos: pos
338346
select_beg: select_beg
339347
select_end: select_end
340348
cursor_offset: offset
341349
}
342350

343351
// Ensure the new cursor position is visible
344-
scroll_cursor_into_view(position, layout, mut window)
352+
scroll_cursor_into_view(pos, layout, mut window)
345353
e.is_handled = true
346354
}
347355
}

xtra_text_cursor.v

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ fn cursor_right(strs []string, pos int) int {
2525
// from the current cursor position. If the previous line is shorter than the
2626
// calculated column, the cursor moves to the end of that line. Returns the
2727
// original position if already at the first line.
28-
fn cursor_up(shape Shape, cursor_pos int, cursor_offset f32, window &Window) int {
28+
fn cursor_up(shape Shape, cursor_pos int, cursor_offset f32, lines_up int, window &Window) int {
29+
if lines_up < 0 {
30+
return cursor_pos
31+
}
2932
mut idx := 0
3033
mut offset := 0
3134
lengths := shape.text_lines.map(utf8_str_visible_length(it))
@@ -39,9 +42,9 @@ fn cursor_up(shape Shape, cursor_pos int, cursor_offset f32, window &Window) int
3942
offset += len
4043
}
4144

42-
// move to previous line
43-
if idx > 0 {
44-
p_idx := idx - 1
45+
// move to previous lines_up
46+
p_idx := int_max(idx - lines_up, 0)
47+
if idx != p_idx {
4548
p_len := lengths[p_idx]
4649
mut p_start := 0
4750
for i, len in lengths {
@@ -80,7 +83,10 @@ fn cursor_up(shape Shape, cursor_pos int, cursor_offset f32, window &Window) int
8083
// cursor position is adjusted: for lines ending with a newline, it moves to the
8184
// position before the newline; for the last line, it moves to the end of the line.
8285
// Returns the original position if already at the last line.
83-
fn cursor_down(shape Shape, cursor_pos int, cursor_offset f32, window &Window) int {
86+
fn cursor_down(shape Shape, cursor_pos int, cursor_offset f32, lines_down int, window &Window) int {
87+
if lines_down < 0 {
88+
return cursor_pos
89+
}
8490
mut idx := 0
8591
mut offset := 0
8692
lengths := shape.text_lines.map(utf8_str_visible_length(it))
@@ -94,9 +100,9 @@ fn cursor_down(shape Shape, cursor_pos int, cursor_offset f32, window &Window) i
94100
offset += len
95101
}
96102

97-
// move to next line
98-
if idx < shape.text_lines.len - 1 {
99-
n_idx := idx + 1
103+
// move to next lines_down
104+
n_idx := int_min(idx + lines_down, shape.text_lines.len - 1)
105+
if idx != n_idx {
100106
n_len := lengths[n_idx]
101107
n_text := shape.text_lines[n_idx]
102108
mut n_start := 0
@@ -421,9 +427,9 @@ fn (tv &TextView) auto_scroll_cursor(id_focus u32, id_scroll_container u32, mut
421427
// Here's the key difference from mouse-move. If the cursor is outside
422428
// the view, scroll up or down one line, not to mouse_cursor_pos
423429
if scroll_y > current_scroll_y {
424-
mouse_cursor_pos = cursor_up(layout.shape, cursor_pos, -1, w)
430+
mouse_cursor_pos = cursor_up(layout.shape, cursor_pos, -1, 1, w)
425431
} else if scroll_y < current_scroll_y {
426-
mouse_cursor_pos = cursor_down(layout.shape, cursor_pos, -1, w)
432+
mouse_cursor_pos = cursor_down(layout.shape, cursor_pos, -1, 1, w)
427433
} else {
428434
return
429435
}

0 commit comments

Comments
 (0)