diff --git a/src/core/file_buffer.odin b/src/core/file_buffer.odin index 7503077..1d7d360 100644 --- a/src/core/file_buffer.odin +++ b/src/core/file_buffer.odin @@ -63,6 +63,7 @@ FileBuffer :: struct { FileBufferIter :: struct { cursor: Cursor, buffer: ^FileBuffer, + hit_end: bool, } new_file_buffer_iter_from_beginning :: proc(file_buffer: ^FileBuffer) -> FileBufferIter { @@ -98,25 +99,28 @@ iterate_file_buffer :: proc(it: ^FileBufferIter) -> (character: u8, idx: FileBuf return character, it.cursor.index, true; } -// NOTE: This give the character for the NEXT position, unlike the non-reverse version -// which gives the character for the CURRENT position. iterate_file_buffer_reverse_mangle_cursor :: proc(it: ^FileBufferIter) -> (character: u8, idx: FileBufferIndex, cond: bool) { + character = it.buffer.content_slices[it.cursor.index.slice_index][it.cursor.index.content_index]; if it.cursor.index.content_index == 0 { if it.cursor.index.slice_index > 0 { it.cursor.index.slice_index -= 1; it.cursor.index.content_index = len(it.buffer.content_slices[it.cursor.index.slice_index])-1; + } else if it.hit_end { + return character, it.cursor.index, false; } else { - return 0, it.cursor.index, false; + it.hit_end = true; + return character, it.cursor.index, true; } } else { it.cursor.index.content_index -= 1; } - return it.buffer.content_slices[it.cursor.index.slice_index][it.cursor.index.content_index], it.cursor.index, true; + return character, it.cursor.index, true; } +// TODO: figure out how to give the first character of the buffer iterate_file_buffer_reverse :: proc(it: ^FileBufferIter) -> (character: u8, idx: FileBufferIndex, cond: bool) { if character, idx, cond = iterate_file_buffer_reverse_mangle_cursor(it); cond { - if character == '\n' { + if it.cursor.col < 1 { if it.cursor.line > 0 { line_length := file_buffer_line_length(it.buffer, it.cursor.index); if line_length < 0 { line_length = 0; } @@ -124,7 +128,7 @@ iterate_file_buffer_reverse :: proc(it: ^FileBufferIter) -> (character: u8, idx: it.cursor.line -= 1; it.cursor.col = line_length; } else { - return 0, it.cursor.index, false; + return character, it.cursor.index, false; } } else { it.cursor.col -= 1; @@ -296,8 +300,13 @@ update_file_buffer_index_from_cursor :: proc(buffer: ^FileBuffer) { file_buffer_line_length :: proc(buffer: ^FileBuffer, index: FileBufferIndex) -> int { line_length := 0; + first_character := buffer.content_slices[index.slice_index][index.content_index]; left_it := new_file_buffer_iter_with_cursor(buffer, Cursor { index = index }); + if first_character == '\n' { + iterate_file_buffer_reverse_mangle_cursor(&left_it); + } + for character in iterate_file_buffer_reverse_mangle_cursor(&left_it) { if character == '\n' { break; @@ -307,17 +316,49 @@ file_buffer_line_length :: proc(buffer: ^FileBuffer, index: FileBufferIndex) -> } right_it := new_file_buffer_iter_with_cursor(buffer, Cursor { index = index }); + first := true; for character in iterate_file_buffer(&right_it) { if character == '\n' { break; } - line_length += 1; + if !first { + line_length += 1; + } + first = false; } return line_length; } +move_cursor_start_of_line :: proc(buffer: ^FileBuffer) { + if buffer.cursor.col > 0 { + it := new_file_buffer_iter_with_cursor(buffer, buffer.cursor); + for _ in iterate_file_buffer_reverse(&it) { + if it.cursor.col <= 0 { + break; + } + } + + buffer.cursor = it.cursor; + } +} + +move_cursor_end_of_line :: proc(buffer: ^FileBuffer) { + it := new_file_buffer_iter_with_cursor(buffer, buffer.cursor); + line_length := file_buffer_line_length(buffer, it.cursor.index); + + if buffer.cursor.col < line_length-1 { + for _ in iterate_file_buffer(&it) { + if it.cursor.col >= line_length-1 { + break; + } + } + + buffer.cursor = it.cursor; + } +} + move_cursor_up :: proc(buffer: ^FileBuffer, amount: int = 1) { if buffer.cursor.line > 0 { current_line := buffer.cursor.line; @@ -399,6 +440,14 @@ move_cursor_forward_start_of_word :: proc(buffer: ^FileBuffer) { update_file_buffer_scroll(buffer); } +move_cursor_backward_start_of_word :: proc(buffer: ^FileBuffer) { + it := new_file_buffer_iter_with_cursor(buffer, buffer.cursor); + iterate_file_buffer_until_reverse(&it, until_start_of_word); + buffer.cursor = it.cursor; + + update_file_buffer_scroll(buffer); +} + new_file_buffer :: proc(allocator: mem.Allocator, file_path: string) -> (FileBuffer, Error) { context.allocator = allocator; diff --git a/src/main.odin b/src/main.odin index e2a9683..21858be 100644 --- a/src/main.odin +++ b/src/main.odin @@ -19,7 +19,9 @@ FileBuffer :: core.FileBuffer; // TODO: use buffer list in state do_normal_mode :: proc(state: ^State, buffer: ^FileBuffer) { if state.current_input_map != nil { - if raylib.IsKeyDown(.LEFT_CONTROL) { + if raylib.IsKeyDown(.ESCAPE) { + state.current_input_map = &state.input_map; + } else if raylib.IsKeyDown(.LEFT_CONTROL) { for key, action in &state.current_input_map.ctrl_key_actions { if raylib.IsKeyPressed(key) { switch value in action.action { @@ -93,10 +95,24 @@ register_default_leader_actions :: proc(input_map: ^core.InputMap) { }, "close this help"); } +register_default_go_actions :: proc(input_map: ^core.InputMap) { + core.register_key_action(input_map, .H, proc(state: ^State) { + core.move_cursor_start_of_line(&state.buffers[state.current_buffer]); + state.current_input_map = &state.input_map; + }, "move to beginning of line"); + core.register_key_action(input_map, .L, proc(state: ^State) { + core.move_cursor_end_of_line(&state.buffers[state.current_buffer]); + state.current_input_map = &state.input_map; + }, "move to end of line"); +} + register_default_input_actions :: proc(input_map: ^core.InputMap) { core.register_key_action(input_map, .W, proc(state: ^State) { core.move_cursor_forward_start_of_word(&state.buffers[state.current_buffer]); }, "move forward one word"); + core.register_key_action(input_map, .B, proc(state: ^State) { + core.move_cursor_backward_start_of_word(&state.buffers[state.current_buffer]); + }, "move backward one word"); core.register_key_action(input_map, .K, proc(state: ^State) { core.move_cursor_up(&state.buffers[state.current_buffer]); @@ -124,7 +140,7 @@ register_default_input_actions :: proc(input_map: ^core.InputMap) { state.source_font_height -= 2; state.source_font_width = state.source_font_height / 2; - state.font = raylib.LoadFontEx("/Users/temp/Library/Fonts/JetBrainsMono-Regular.ttf", i32(state.source_font_height*2), nil, 0); + state.font = raylib.LoadFontEx("/System/Library/Fonts/Supplemental/Andale Mono.ttf", i32(state.source_font_height*2), nil, 0); raylib.SetTextureFilter(state.font.texture, .BILINEAR); } }, "increase font size"); @@ -132,7 +148,7 @@ register_default_input_actions :: proc(input_map: ^core.InputMap) { state.source_font_height += 2; state.source_font_width = state.source_font_height / 2; - state.font = raylib.LoadFontEx("/Users/temp/Library/Fonts/JetBrainsMono-Regular.ttf", i32(state.source_font_height*2), nil, 0); + state.font = raylib.LoadFontEx("/System/Library/Fonts/Supplemental/Andale Mono.ttf", i32(state.source_font_height*2), nil, 0); raylib.SetTextureFilter(state.font.texture, .BILINEAR); }, "decrease font size"); @@ -142,6 +158,9 @@ register_default_input_actions :: proc(input_map: ^core.InputMap) { core.register_key_action(input_map, .SPACE, core.new_input_map(), "leader commands"); register_default_leader_actions(&(&input_map.key_actions[.SPACE]).action.(core.InputMap)); + + core.register_key_action(input_map, .G, core.new_input_map(), "Go commands"); + register_default_go_actions(&(&input_map.key_actions[.G]).action.(core.InputMap)); } register_buffer_list_input_actions :: proc(input_map: ^core.InputMap) { @@ -239,9 +258,10 @@ main :: proc() { raylib.DrawRectangle(0, i32(state.screen_height - state.source_font_height), i32(state.screen_width), i32(state.source_font_height), theme.get_palette_raylib_color(.Background2)); line_info_text := raylib.TextFormat( - "Line: %d, Col: %d --- Slice Index: %d, Content Index: %d", + "Line: %d, Col: %d, Len: %d --- Slice Index: %d, Content Index: %d", buffer.cursor.line + 1, buffer.cursor.col + 1, + core.file_buffer_line_length(buffer, buffer.cursor.index), buffer.cursor.index.slice_index, buffer.cursor.index.content_index); line_info_width := raylib.MeasureTextEx(state.font, line_info_text, f32(state.source_font_height), 0).x; diff --git a/src/theme/theme.odin b/src/theme/theme.odin index c33e777..f7d372b 100644 --- a/src/theme/theme.odin +++ b/src/theme/theme.odin @@ -98,6 +98,6 @@ light_palette := []u32 { }; get_palette_raylib_color :: proc(palette_color: PaletteColor) -> raylib.Color { - return raylib.GetColor(light_palette[palette_color]); + return raylib.GetColor(palette[palette_color]); } diff --git a/src/ui/floating_window.odin b/src/ui/floating_window.odin index 6aa6730..813f671 100644 --- a/src/ui/floating_window.odin +++ b/src/ui/floating_window.odin @@ -17,7 +17,7 @@ draw_buffer_list_window :: proc(state: ^core.State) { win_rec, theme.get_palette_raylib_color(.Background4)); - win_margin := raylib.Vector2 { f32(text_padding*2), f32(state.source_font_height) }; + win_margin := raylib.Vector2 { f32(state.source_font_width), f32(state.source_font_height) }; buffer_prev_width := (win_rec.width - win_margin.x*2) / 2; buffer_prev_height := win_rec.height - win_margin.y*2; diff --git a/src/ui/ui.odin b/src/ui/ui.odin index 0d32a61..5d22ab4 100644 --- a/src/ui/ui.odin +++ b/src/ui/ui.odin @@ -67,6 +67,10 @@ draw_menu_bar_item :: proc(state: ^core.State, item: ^MenuBarItem, x, y: i32, pa draw_menu_bar :: proc(state: ^core.State, data: ^MenuBarState, x, y: i32, parent_width, parent_height: i32, font_height: int) { raylib.DrawRectangle(x, y, parent_width, i32(font_height), theme.get_palette_raylib_color(.Background3)); + raylib.DrawTextEx(state.font, "Editor", raylib.Vector2 { f32(x), f32(y) }, f32(font_height), 0, theme.get_palette_raylib_color(.Foreground1)); + + x := x + i32((len("Editor") + 4) * state.source_font_width); + for _, index in data.items { item := &data.items[index]; item_text := raylib.TextFormat("%s", item.text); @@ -129,6 +133,8 @@ test_menu_item :: proc(state: ^core.State, item: ^MenuBarItem, rect: raylib.Rect } test_menu_bar :: proc(state: ^core.State, menu_bar: ^MenuBarState, x, y: i32, mouse_pos: raylib.Vector2, mouse_has_clicked: bool, font_height: int) { + x := x + i32((len("Editor") + 4) * state.source_font_width); + for _, index in menu_bar.items { item := &menu_bar.items[index]; item_text := raylib.TextFormat("%s", item.text);