From 705606e92a7c9e355fd73d966a16f23aea58e0ce Mon Sep 17 00:00:00 2001 From: Patrick Cleaveliln Date: Mon, 21 Jul 2025 00:03:50 +0000 Subject: [PATCH] persist cursor column --- src/core/file_buffer.odin | 32 ++++++++++++++++++++++++++++++++ src/main.odin | 19 ++++++++++++++++++- src/panels/file_buffer.odin | 28 ++++++++++++++++------------ src/panels/grep.odin | 5 ++++- src/panels/panels.odin | 10 ---------- src/theme/theme.odin | 3 +++ src/tree_sitter/ts.odin | 9 ++++++++- 7 files changed, 81 insertions(+), 25 deletions(-) diff --git a/src/core/file_buffer.odin b/src/core/file_buffer.odin index 5ba0128..40a5d8e 100644 --- a/src/core/file_buffer.odin +++ b/src/core/file_buffer.odin @@ -47,6 +47,7 @@ FileBuffer :: struct { extension: string, flags: BufferFlagSet, + last_col: int, top_line: int, selection: Maybe(Selection), @@ -423,6 +424,8 @@ move_cursor_start_of_line :: proc(buffer: ^FileBuffer, cursor: Maybe(^Cursor) = cursor.?^ = it.cursor; } + + buffer.last_col = cursor.?.col } move_cursor_end_of_line :: proc(buffer: ^FileBuffer, stop_at_end: bool = true, cursor: Maybe(^Cursor) = nil) { @@ -432,6 +435,8 @@ move_cursor_end_of_line :: proc(buffer: ^FileBuffer, stop_at_end: bool = true, c cursor = &buffer.history.cursor; } + buffer.last_col = cursor.?.col + it := new_file_buffer_iter_with_cursor(buffer, cursor.?^); line_length := file_buffer_line_length(buffer, it.cursor.index); if stop_at_end { @@ -447,6 +452,8 @@ move_cursor_end_of_line :: proc(buffer: ^FileBuffer, stop_at_end: bool = true, c cursor.?^ = it.cursor; } + + buffer.last_col = cursor.?.col } move_cursor_up :: proc(buffer: ^FileBuffer, amount: int = 1, cursor: Maybe(^Cursor) = nil) { @@ -480,6 +487,12 @@ move_cursor_up :: proc(buffer: ^FileBuffer, amount: int = 1, cursor: Maybe(^Curs cursor.?^ = it.cursor; } + if cursor.?.col < buffer.last_col && file_buffer_line_length(buffer, cursor.?.index)-1 >= cursor.?.col { + last_col := buffer.last_col + move_cursor_right(buffer, amt = buffer.last_col - cursor.?.col, cursor = cursor) + buffer.last_col = last_col + } + update_file_buffer_scroll(buffer, cursor); } @@ -513,6 +526,13 @@ move_cursor_down :: proc(buffer: ^FileBuffer, amount: int = 1, cursor: Maybe(^Cu } cursor.?^ = it.cursor; + + if cursor.?.col < buffer.last_col && file_buffer_line_length(buffer, cursor.?.index)-1 >= cursor.?.col { + last_col := buffer.last_col + move_cursor_right(buffer, amt = buffer.last_col - cursor.?.col, cursor = cursor) + buffer.last_col = last_col + } + update_file_buffer_scroll(buffer, cursor); } @@ -523,6 +543,8 @@ move_cursor_left :: proc(buffer: ^FileBuffer, cursor: Maybe(^Cursor) = nil) { cursor = &buffer.history.cursor; } + buffer.last_col = cursor.?.col + if cursor.?.col > 0 { it := new_file_buffer_iter_with_cursor(buffer, cursor.?^); iterate_file_buffer_reverse(&it); @@ -537,6 +559,8 @@ move_cursor_right :: proc(buffer: ^FileBuffer, stop_at_end: bool = true, amt: in cursor = &buffer.history.cursor; } + buffer.last_col = cursor.?.col + it := new_file_buffer_iter_with_cursor(buffer, cursor.?^); line_length := file_buffer_line_length(buffer, it.cursor.index); @@ -559,6 +583,8 @@ move_cursor_forward_start_of_word :: proc(buffer: ^FileBuffer, cursor: Maybe(^Cu iterate_file_buffer_until(&it, until_start_of_word); cursor.?^ = it.cursor; + buffer.last_col = cursor.?.col + update_file_buffer_scroll(buffer, cursor); } @@ -573,6 +599,8 @@ move_cursor_forward_end_of_word :: proc(buffer: ^FileBuffer, cursor: Maybe(^Curs iterate_file_buffer_until(&it, until_end_of_word); cursor.?^ = it.cursor; + buffer.last_col = cursor.?.col + update_file_buffer_scroll(buffer, cursor); } @@ -588,6 +616,8 @@ move_cursor_backward_start_of_word :: proc(buffer: ^FileBuffer, cursor: Maybe(^C //iterate_file_buffer_until(&it, until_non_whitespace); cursor.?^ = it.cursor; + buffer.last_col = cursor.?.col + update_file_buffer_scroll(buffer, cursor); } @@ -602,6 +632,8 @@ move_cursor_backward_end_of_word :: proc(buffer: ^FileBuffer, cursor: Maybe(^Cur iterate_file_buffer_until_reverse(&it, until_start_of_word); cursor.?^ = it.cursor; + buffer.last_col = cursor.?.col + update_file_buffer_scroll(buffer, cursor); } diff --git a/src/main.odin b/src/main.odin index a555475..bbc27d3 100644 --- a/src/main.odin +++ b/src/main.odin @@ -67,7 +67,24 @@ draw :: proc(state: ^State) { for i in 0..render(state) + + background_color: theme.PaletteColor = .Background1 if panel.id == state.current_panel else .Background2 + + ui.open_element(new_ui, nil, + { + dir = .LeftToRight, + kind = {ui.Grow{}, ui.Grow{}}, + }, + style = { + border = {.Left, .Right, .Top, .Bottom }, + border_color = .Green, + background_color = background_color, + } + ) + { + panel->render(state) + } + ui.close_element(new_ui) } } } diff --git a/src/panels/file_buffer.odin b/src/panels/file_buffer.odin index bb1a1ce..92c63a1 100644 --- a/src/panels/file_buffer.odin +++ b/src/panels/file_buffer.odin @@ -48,6 +48,7 @@ make_file_buffer_panel :: proc(file_path: string, line: int = 0, col: int = 0) - leader_actions := core.new_input_actions() register_default_leader_actions(&leader_actions); + file_buffer_leader_actions(&leader_actions); core.register_key_action(&panel.input_map.mode[.Normal], .SPACE, leader_actions, "leader commands"); core.register_ctrl_key_action(&panel.input_map.mode[.Normal], .W, core.new_input_actions(), "Panel Navigation") @@ -88,11 +89,6 @@ render_file_buffer :: proc(state: ^core.State, s: ^ui.State, buffer: ^core.FileB dir = .TopToBottom, kind = {ui.Grow{}, ui.Grow{}}, }, - style = { - border = {.Left, .Right, .Top, .Bottom}, - border_color = .Background4, - background_color = .Background1, - } ) { ui.open_element(s, @@ -100,11 +96,6 @@ render_file_buffer :: proc(state: ^core.State, s: ^ui.State, buffer: ^core.FileB { kind = {ui.Grow{}, ui.Grow{}} }, - style = { - border = {.Left, .Right, .Top, .Bottom}, - border_color = .Background4, - background_color = .Background1, - } ) ui.close_element(s) @@ -114,6 +105,7 @@ render_file_buffer :: proc(state: ^core.State, s: ^ui.State, buffer: ^core.FileB style = { border = {.Left, .Right, .Top, .Bottom}, border_color = .Background4, + background_color = .Background1, } ) { @@ -132,12 +124,13 @@ render_file_buffer :: proc(state: ^core.State, s: ^ui.State, buffer: ^core.FileB ui.open_element( s, fmt.tprintf( - "%v:%v - Slice %v:%v - Char: %v", + "%v:%v - Slice %v:%v - Char: %v - Last Col: %v", buffer.history.cursor.line + 1, buffer.history.cursor.col + 1, buffer.history.cursor.index.chunk_index, buffer.history.cursor.index.char_index, - core.get_character_at_iter(it) + core.get_character_at_iter(it), + buffer.last_col, ), {} ) @@ -148,6 +141,17 @@ render_file_buffer :: proc(state: ^core.State, s: ^ui.State, buffer: ^core.FileB ui.close_element(s) } +file_buffer_leader_actions :: proc(input_map: ^core.InputActions) { + core.register_key_action(input_map, .K, proc(state: ^core.State, user_data: rawptr) { + buffer := &(&(transmute(^core.Panel)user_data).type.(core.FileBufferPanel)).buffer + + ts.update_cursor(&buffer.tree, buffer.history.cursor.line, buffer.history.cursor.col) + ts.print_node_type(&buffer.tree) + + core.reset_input_map(state) + }, "View Symbol") +} + file_buffer_go_actions :: proc(input_map: ^core.InputActions) { core.register_key_action(input_map, .H, proc(state: ^core.State, user_data: rawptr) { buffer := &(&(transmute(^core.Panel)user_data).type.(core.FileBufferPanel)).buffer diff --git a/src/panels/grep.odin b/src/panels/grep.odin index 3e94853..47b7da5 100644 --- a/src/panels/grep.odin +++ b/src/panels/grep.odin @@ -69,6 +69,9 @@ make_grep_panel :: proc() -> core.Panel { panel_state.glyphs = core.make_glyph_buffer(256,256) panel_state.buffer = core.new_virtual_file_buffer() + core.register_ctrl_key_action(&panel.input_map.mode[.Normal], .W, core.new_input_actions(), "Panel Navigation") + register_default_panel_actions(&(&panel.input_map.mode[.Normal].ctrl_key_actions[.W]).action.(core.InputActions)) + core.register_key_action(&panel.input_map.mode[.Normal], .ENTER, proc(state: ^core.State, user_data: rawptr) { this_panel := transmute(^core.Panel)user_data @@ -163,7 +166,7 @@ make_grep_panel :: proc() -> core.Panel { kind = {ui.Grow{}, ui.Grow{}} }, style = { - border = {.Left, .Right, .Top, .Bottom}, + border = {.Right}, border_color = .Background4 } ) diff --git a/src/panels/panels.odin b/src/panels/panels.odin index df8e378..2da385b 100644 --- a/src/panels/panels.odin +++ b/src/panels/panels.odin @@ -13,7 +13,6 @@ import "../core" import "../util" import "../ui" -// NOTE: odd that this is here, but I don't feel like thinking of a better dep-tree to fix it register_default_leader_actions :: proc(input_map: ^core.InputActions) { core.register_key_action(input_map, .Q, proc(state: ^core.State, user_data: rawptr) { core.reset_input_map(state) @@ -22,15 +21,6 @@ register_default_leader_actions :: proc(input_map: ^core.InputActions) { core.register_key_action(input_map, .R, proc(state: ^core.State, user_data: rawptr) { open_grep_panel(state) }, "Grep Workspace") - - core.register_key_action(input_map, .K, proc(state: ^core.State, user_data: rawptr) { - buffer := transmute(^core.FileBuffer)user_data - - ts.update_cursor(&buffer.tree, buffer.history.cursor.line, buffer.history.cursor.col) - ts.print_node_type(&buffer.tree) - - core.reset_input_map(state) - }, "View Symbol") } register_default_panel_actions :: proc(input_map: ^core.InputActions) { diff --git a/src/theme/theme.odin b/src/theme/theme.odin index e9f1168..1ac7242 100644 --- a/src/theme/theme.odin +++ b/src/theme/theme.odin @@ -1,6 +1,7 @@ package theme PaletteColor :: enum { + None, Background, Foreground, @@ -33,6 +34,7 @@ PaletteColor :: enum { // Its the gruvbox dark theme palette := []u32 { + 0x00000000, 0x282828ff, 0xebdbb2ff, @@ -65,6 +67,7 @@ palette := []u32 { light_palette := []u32 { + 0x00000000, 0xfbf1c7ff, 0x3c3836ff, diff --git a/src/tree_sitter/ts.odin b/src/tree_sitter/ts.odin index 9d26299..25e6461 100644 --- a/src/tree_sitter/ts.odin +++ b/src/tree_sitter/ts.odin @@ -251,7 +251,9 @@ parse_buffer :: proc(state: ^State, input: Input) { } update_cursor :: proc(state: ^State, line: int, col: int) { - assert(state.tree != nil) + if state.tree == nil { + return + } root_node := tree_root_node(state.tree) tree_cursor_reset(&state.cursor, root_node) @@ -274,6 +276,7 @@ load_highlights :: proc(state: ^State) { capture_to_color := make(map[string]theme.PaletteColor, allocator = context.temp_allocator) capture_to_color["include"] = .Red capture_to_color["keyword.function"] = .Red + capture_to_color["keyword.return"] = .Red capture_to_color["storageclass"] = .Red capture_to_color["keyword.operator"] = .Purple @@ -347,6 +350,10 @@ load_highlights :: proc(state: ^State) { } print_node_type :: proc(state: ^State) { + if state.tree == nil { + return + } + current_node := tree_cursor_current_node(&state.cursor) if node_is_null(current_node) { log.error("Current node is null after goto_first_child")