diff --git a/src/core/core.odin b/src/core/core.odin index f3f7c9f..7e5de5b 100644 --- a/src/core/core.odin +++ b/src/core/core.odin @@ -144,7 +144,7 @@ yank_whole_line :: proc(state: ^State) { } if buffer := current_buffer(state); buffer != nil { - selection := new_selection(buffer, buffer.cursor) + selection := new_selection(buffer, buffer.history.cursor) length := selection_length(buffer, selection) state.yank_register.whole_line = true diff --git a/src/core/file_buffer.odin b/src/core/file_buffer.odin index ef07f4c..62cd765 100644 --- a/src/core/file_buffer.odin +++ b/src/core/file_buffer.odin @@ -46,7 +46,7 @@ FileBuffer :: struct { extension: string, top_line: int, - cursor: Cursor, + // cursor: Cursor, selection: Maybe(Selection), history: FileHistory, @@ -64,7 +64,7 @@ FileBufferIter :: struct { // TODO: don't make this panic on nil snapshot buffer_piece_table :: proc(file_buffer: ^FileBuffer) -> ^PieceTable { - return &file_buffer.history.snapshots[file_buffer.history.current].(PieceTable) + return &file_buffer.history.piece_table } new_file_buffer_iter_from_beginning :: proc(file_buffer: ^FileBuffer) -> FileBufferIter { @@ -343,7 +343,7 @@ update_file_buffer_index_from_cursor :: proc(buffer: ^FileBuffer) { rendered_line := 0; for character in iterate_file_buffer(&it) { - if line_length == buffer.cursor.col && rendered_line == buffer.cursor.line { + if line_length == buffer.history.cursor.col && rendered_line == buffer.history.cursor.line { break; } @@ -358,7 +358,7 @@ update_file_buffer_index_from_cursor :: proc(buffer: ^FileBuffer) { } // FIXME: just swap cursors - buffer.cursor.index = before_it.cursor.index; + buffer.history.cursor.index = before_it.cursor.index; update_file_buffer_scroll(buffer); } @@ -402,7 +402,7 @@ move_cursor_start_of_line :: proc(buffer: ^FileBuffer, cursor: Maybe(^Cursor) = cursor := cursor; if cursor == nil { - cursor = &buffer.cursor; + cursor = &buffer.history.cursor; } if cursor.?.col > 0 { @@ -421,7 +421,7 @@ move_cursor_end_of_line :: proc(buffer: ^FileBuffer, stop_at_end: bool = true, c cursor := cursor; if cursor == nil { - cursor = &buffer.cursor; + cursor = &buffer.history.cursor; } it := new_file_buffer_iter_with_cursor(buffer, cursor.?^); @@ -445,7 +445,7 @@ move_cursor_up :: proc(buffer: ^FileBuffer, amount: int = 1, cursor: Maybe(^Curs cursor := cursor; if cursor == nil { - cursor = &buffer.cursor; + cursor = &buffer.history.cursor; } if cursor.?.line > 0 { @@ -479,7 +479,7 @@ move_cursor_down :: proc(buffer: ^FileBuffer, amount: int = 1, cursor: Maybe(^Cu cursor := cursor; if cursor == nil { - cursor = &buffer.cursor; + cursor = &buffer.history.cursor; } current_line := cursor.?.line; @@ -512,7 +512,7 @@ move_cursor_left :: proc(buffer: ^FileBuffer, cursor: Maybe(^Cursor) = nil) { cursor := cursor; if cursor == nil { - cursor = &buffer.cursor; + cursor = &buffer.history.cursor; } if cursor.?.col > 0 { @@ -526,7 +526,7 @@ move_cursor_right :: proc(buffer: ^FileBuffer, stop_at_end: bool = true, amt: in cursor := cursor; if cursor == nil { - cursor = &buffer.cursor; + cursor = &buffer.history.cursor; } it := new_file_buffer_iter_with_cursor(buffer, cursor.?^); @@ -544,7 +544,7 @@ move_cursor_forward_start_of_word :: proc(buffer: ^FileBuffer, cursor: Maybe(^Cu cursor := cursor; if cursor == nil { - cursor = &buffer.cursor; + cursor = &buffer.history.cursor; } it := new_file_buffer_iter_with_cursor(buffer, cursor.?^); @@ -558,7 +558,7 @@ move_cursor_forward_end_of_word :: proc(buffer: ^FileBuffer, cursor: Maybe(^Curs cursor := cursor; if cursor == nil { - cursor = &buffer.cursor; + cursor = &buffer.history.cursor; } it := new_file_buffer_iter_with_cursor(buffer, cursor.?^); @@ -572,7 +572,7 @@ move_cursor_backward_start_of_word :: proc(buffer: ^FileBuffer, cursor: Maybe(^C cursor := cursor; if cursor == nil { - cursor = &buffer.cursor; + cursor = &buffer.history.cursor; } it := new_file_buffer_iter_with_cursor(buffer, cursor.?^); @@ -587,7 +587,7 @@ move_cursor_backward_end_of_word :: proc(buffer: ^FileBuffer, cursor: Maybe(^Cur cursor := cursor; if cursor == nil { - cursor = &buffer.cursor; + cursor = &buffer.history.cursor; } it := new_file_buffer_iter_with_cursor(buffer, cursor.?^); @@ -811,8 +811,8 @@ draw_file_buffer :: proc(state: ^State, buffer: ^FileBuffer, x: int, y: int, sho } begin := buffer.top_line; - cursor_x := x + padding + buffer.cursor.col * state.source_font_width; - cursor_y := y + buffer.cursor.line * state.source_font_height; + cursor_x := x + padding + buffer.history.cursor.col * state.source_font_width; + cursor_y := y + buffer.history.cursor.line * state.source_font_height; cursor_y -= begin * state.source_font_height; @@ -908,7 +908,7 @@ draw_file_buffer :: proc(state: ^State, buffer: ^FileBuffer, x: int, y: int, sho update_file_buffer_scroll :: proc(buffer: ^FileBuffer, cursor: Maybe(^Cursor) = nil) { cursor := cursor; if cursor == nil { - cursor = &buffer.cursor; + cursor = &buffer.history.cursor; } if cursor.?.line > (buffer.top_line + buffer.glyphs.height - 5) { @@ -917,10 +917,10 @@ update_file_buffer_scroll :: proc(buffer: ^FileBuffer, cursor: Maybe(^Cursor) = buffer.top_line = math.max(cursor.?.line - 5, 0); } - // if buffer.cursor.line > (buffer.top_line + buffer.glyphs.height - 5) { - // buffer.top_line = math.max(buffer.cursor.line - buffer.glyphs.height + 5, 0); - // } else if buffer.cursor.line < (buffer.top_line + 5) { - // buffer.top_line = math.max(buffer.cursor.line - 5, 0); + // if buffer.history.cursor.line > (buffer.top_line + buffer.glyphs.height - 5) { + // buffer.top_line = math.max(buffer.history.cursor.line - buffer.glyphs.height + 5, 0); + // } else if buffer.history.cursor.line < (buffer.top_line + 5) { + // buffer.top_line = math.max(buffer.history.cursor.line - 5, 0); // } } @@ -944,9 +944,9 @@ insert_content :: proc(buffer: ^FileBuffer, to_be_inserted: []u8, append_to_end: return; } - index := buffer.cursor.index if !append_to_end else new_piece_table_index_from_end(buffer_piece_table(buffer)) + index := buffer.history.cursor.index if !append_to_end else new_piece_table_index_from_end(buffer_piece_table(buffer)) - insert_text(buffer_piece_table(buffer), to_be_inserted, buffer.cursor.index) + insert_text(buffer_piece_table(buffer), to_be_inserted, buffer.history.cursor.index) if !append_to_end { update_file_buffer_index_from_cursor(buffer); @@ -962,13 +962,13 @@ delete_content_from_buffer_cursor :: proc(buffer: ^FileBuffer, amount: int) { runtime.clear(&buffer.input_buffer); // Calculate proper line/col values - it := new_file_buffer_iter_with_cursor(buffer, buffer.cursor); + it := new_file_buffer_iter_with_cursor(buffer, buffer.history.cursor); iterate_file_buffer_reverse(&it) - delete_text(buffer_piece_table(buffer), &buffer.cursor.index) + delete_text(buffer_piece_table(buffer), &buffer.history.cursor.index) - buffer.cursor.line = it.cursor.line - buffer.cursor.col = it.cursor.col + buffer.history.cursor.line = it.cursor.line + buffer.history.cursor.col = it.cursor.col } } @@ -976,7 +976,7 @@ delete_content_from_selection :: proc(buffer: ^FileBuffer, selection: ^Selection selection^ = swap_selections(selection^) delete_text_in_span(buffer_piece_table(buffer), &selection.start.index, &selection.end.index) - buffer.cursor.index = selection.start.index + buffer.history.cursor.index = selection.start.index } delete_content :: proc{delete_content_from_buffer_cursor, delete_content_from_selection}; diff --git a/src/core/glyph_buffer.odin b/src/core/glyph_buffer.odin index cf5c213..c2b9d5d 100644 --- a/src/core/glyph_buffer.odin +++ b/src/core/glyph_buffer.odin @@ -43,7 +43,7 @@ update_glyph_buffer_from_file_buffer :: proc(buffer: ^FileBuffer) { if rendered_line >= begin && screen_line >= buffer.glyphs.height { break; } // render INSERT mode text into glyph buffer - if len(buffer.input_buffer) > 0 && rendered_line == buffer.cursor.line && rendered_col >= buffer.cursor.col && rendered_col < buffer.cursor.col + len(buffer.input_buffer) { + if len(buffer.input_buffer) > 0 && rendered_line == buffer.history.cursor.line && rendered_col >= buffer.history.cursor.col && rendered_col < buffer.history.cursor.col + len(buffer.input_buffer) { for k in 0.. FileHistory { context.allocator = allocator - snapshots := make([]Snapshot, starting_capacity) - snapshots[0] = make_piece_table_from_bytes(initial_data, starting_capacity) - return FileHistory { - snapshots = snapshots, - current = 0 + piece_table = make_piece_table(initial_data, starting_capacity = starting_capacity), + snapshots = make([]Snapshot, starting_capacity), + next = 0, + first = 0, } } make_history_empty :: proc(starting_capacity: int = 1024, allocator := context.allocator) -> FileHistory { context.allocator = allocator - snapshots := make([]Snapshot, starting_capacity) - snapshots[0] = make_piece_table(starting_capacity = starting_capacity) - return FileHistory { - snapshots = snapshots, - current = 0 + piece_table = make_piece_table(starting_capacity = starting_capacity), + snapshots = make([]Snapshot, starting_capacity), + next = 0, + first = 0, } } @@ -37,12 +42,94 @@ make_history :: proc{make_history_with_data, make_history_empty} free_history :: proc(history: ^FileHistory) { for snapshot in &history.snapshots { - if piece_table, ok := snapshot.(PieceTable); ok { - delete(piece_table.original_content); - delete(piece_table.added_content); - delete(piece_table.chunks); + if snapshot.chunks != nil { + delete(snapshot.chunks); + } + } + delete(history.snapshots) + + delete(history.piece_table.original_content) + delete(history.piece_table.added_content) + delete(history.piece_table.chunks) +} + +push_new_snapshot :: proc(history: ^FileHistory) { + if history.snapshots[history.next].chunks != nil { + delete(history.snapshots[history.next].chunks) + } + + history.snapshots[history.next].chunks = clone_chunk(history.piece_table.chunks) + history.snapshots[history.next].cursor = history.cursor + + history.next, history.first = next_indexes(history) +} + +pop_snapshot :: proc(history: ^FileHistory, make_new_snapshot: bool = false) { + new_next, _ := next_indexes(history, backward = true) + if new_next == history.next do return + + if make_new_snapshot { + push_new_snapshot(history) + } + + history.next = new_next + + delete(history.piece_table.chunks) + + history.piece_table.chunks = clone_chunk(history.snapshots[history.next].chunks) + history.cursor = history.snapshots[history.next].cursor +} + +recover_snapshot :: proc(history: ^FileHistory) { + new_next, _ := next_indexes(history) + if history.snapshots[new_next].chunks == nil do return + history.next = new_next + + delete(history.piece_table.chunks) + + history.piece_table.chunks = clone_chunk(history.snapshots[history.next].chunks) + history.cursor = history.snapshots[history.next].cursor +} + +clone_chunk :: proc(chunks: [dynamic][]u8) -> [dynamic][]u8 { + new_chunks := make([dynamic][]u8, len(chunks), len(chunks)) + + for ptr, i in chunks { + new_chunks[i] = ptr + } + + return new_chunks +} + +next_indexes :: proc(history: ^FileHistory, backward: bool = false) -> (next: int, first: int) { + next = history.next + first = history.first + + if backward { + if history.next == history.first { + return + } + + next = history.next - 1 + + if next < 0 { + next = len(history.snapshots) - 1 + } + } else { + next = history.next + 1 + + if next >= len(history.snapshots) { + next = 0 + } + + if next == first { + first += 1 + } + + if first >= len(history.snapshots) { + first = 0 } } - delete(history.snapshots) -} \ No newline at end of file + return +} diff --git a/src/input/input.odin b/src/input/input.odin index 7f885a9..a928105 100644 --- a/src/input/input.odin +++ b/src/input/input.odin @@ -89,7 +89,7 @@ register_default_input_actions :: proc(input_map: ^core.InputActions) { state.mode = .Visual; core.reset_input_map(state) - core.current_buffer(state).selection = core.new_selection(core.current_buffer(state).cursor); + core.current_buffer(state).selection = core.new_selection(core.current_buffer(state).history.cursor); }, "enter visual mode"); } @@ -158,6 +158,8 @@ register_default_visual_actions :: proc(input_map: ^core.InputActions) { // Text Modification { core.register_key_action(input_map, .D, proc(state: ^State) { + core.push_new_snapshot(&core.current_buffer(state).history) + sel_cur := &(core.current_buffer(state).selection.?); core.delete_content(core.current_buffer(state), sel_cur); @@ -169,6 +171,8 @@ register_default_visual_actions :: proc(input_map: ^core.InputActions) { }, "delete selection"); core.register_key_action(input_map, .C, proc(state: ^State) { + core.push_new_snapshot(&core.current_buffer(state).history) + sel_cur := &(core.current_buffer(state).selection.?); core.delete_content(core.current_buffer(state), sel_cur); @@ -194,6 +198,8 @@ register_default_visual_actions :: proc(input_map: ^core.InputActions) { }, "Yank Line"); core.register_key_action(input_map, .P, proc(state: ^State) { + core.push_new_snapshot(&core.current_buffer(state).history) + if state.yank_register.whole_line { core.insert_content(core.current_buffer(state), []u8{'\n'}); core.paste_register(state, state.yank_register) @@ -209,18 +215,32 @@ register_default_visual_actions :: proc(input_map: ^core.InputActions) { register_default_text_input_actions :: proc(input_map: ^core.InputActions) { core.register_key_action(input_map, .I, proc(state: ^State) { + core.push_new_snapshot(&core.current_buffer(state).history) + state.mode = .Insert; sdl2.StartTextInput(); }, "enter insert mode"); core.register_key_action(input_map, .A, proc(state: ^State) { + core.push_new_snapshot(&core.current_buffer(state).history) + core.move_cursor_right(core.current_buffer(state), false); state.mode = .Insert; sdl2.StartTextInput(); }, "enter insert mode after character (append)"); + core.register_key_action(input_map, .U, proc(state: ^State) { + core.pop_snapshot(&core.current_buffer(state).history, true) + }, "Undo"); + + core.register_ctrl_key_action(input_map, .R, proc(state: ^State) { + core.recover_snapshot(&core.current_buffer(state).history) + }, "Redo"); + // TODO: add shift+o to insert newline above current one core.register_key_action(input_map, .O, proc(state: ^State) { + core.push_new_snapshot(&core.current_buffer(state).history) + if buffer := core.current_buffer(state); buffer != nil { core.move_cursor_end_of_line(buffer, false); runtime.clear(&buffer.input_buffer) @@ -247,6 +267,8 @@ register_default_text_input_actions :: proc(input_map: ^core.InputActions) { } core.register_key_action(input_map, .P, proc(state: ^State) { + core.push_new_snapshot(&core.current_buffer(state).history) + if state.yank_register.whole_line { core.move_cursor_end_of_line(core.current_buffer(state), false); core.insert_content(core.current_buffer(state), []u8{'\n'}); diff --git a/src/main.odin b/src/main.odin index 36e24a2..1d65b9a 100644 --- a/src/main.odin +++ b/src/main.odin @@ -389,6 +389,8 @@ main :: proc() { sdl2.AddEventWatch(expose_event_watcher, &state); + core.push_new_snapshot(&core.current_buffer(&state).history) + control_key_pressed: bool; for !state.should_close { { diff --git a/src/panels/panels.odin b/src/panels/panels.odin index c056aab..d383bbf 100644 --- a/src/panels/panels.odin +++ b/src/panels/panels.odin @@ -135,9 +135,9 @@ open_file_buffer_in_new_panel :: proc(state: ^core.State, file_path: string, lin return; } - buffer.cursor.line = line - buffer.cursor.col = col - buffer.top_line = buffer.cursor.line + buffer.history.cursor.line = line + buffer.history.cursor.col = col + buffer.top_line = buffer.history.cursor.line core.update_file_buffer_index_from_cursor(&buffer) buffer_index = len(state.buffers) @@ -183,15 +183,15 @@ render_file_buffer :: proc(state: ^core.State, s: ^ui.State, buffer: ^core.FileB ui.open_element(s, nil, { kind = {ui.Grow{}, ui.Grow{}}}) ui.close_element(s) - it := core.new_file_buffer_iter_with_cursor(buffer, buffer.cursor) + it := core.new_file_buffer_iter_with_cursor(buffer, buffer.history.cursor) ui.open_element( s, fmt.tprintf( "%v:%v - Slice %v:%v - Char: %v", - buffer.cursor.line + 1, - buffer.cursor.col + 1, - buffer.cursor.index.chunk_index, - buffer.cursor.index.char_index, + 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) ), {} diff --git a/src/tests/tests.odin b/src/tests/tests.odin index f5049b7..db036a8 100644 --- a/src/tests/tests.odin +++ b/src/tests/tests.odin @@ -142,8 +142,8 @@ insert_from_empty_no_newlines :: proc(t: ^testing.T) { expected_text := fmt.aprintf("%v\n", inputted_text) run_text_insertion(&e, inputted_text) - expect_line_col(t, buffer.cursor, 0, 12) - expect_cursor_index(t, buffer.cursor, 0, 12) + expect_line_col(t, buffer.history.cursor, 0, 12) + expect_cursor_index(t, buffer.history.cursor, 0, 12) contents := buffer_to_string(core.current_buffer(&e)) testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text) @@ -160,8 +160,8 @@ insert_from_empty_with_newline :: proc(t: ^testing.T) { expected_text := fmt.aprintf("%v\n", inputted_text) run_text_insertion(&e, inputted_text) - expect_line_col(t, buffer.cursor, 1, 17) - expect_cursor_index(t, buffer.cursor, 0, 31) + expect_line_col(t, buffer.history.cursor, 1, 17) + expect_cursor_index(t, buffer.history.cursor, 0, 31) contents := buffer_to_string(core.current_buffer(&e)) testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text) @@ -184,8 +184,8 @@ insert_in_between_text :: proc(t: ^testing.T) { run_text_insertion(&e, " beautiful") - expect_line_col(t, buffer.cursor, 0, 15) - expect_cursor_index(t, buffer.cursor, 1, 9) + expect_line_col(t, buffer.history.cursor, 0, 15) + expect_cursor_index(t, buffer.history.cursor, 1, 9) contents := buffer_to_string(core.current_buffer(&e)) testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text) @@ -211,8 +211,8 @@ insert_before_slice_at_beginning_of_file :: proc(t: ^testing.T) { run_inputs(&e, []ArtificialInput{ press_key(.G), press_key(.H)}) run_text_insertion(&e, "Well, ") - expect_line_col(t, buffer.cursor, 0, 5) - expect_cursor_index(t, buffer.cursor, 0, 5) + expect_line_col(t, buffer.history.cursor, 0, 5) + expect_cursor_index(t, buffer.history.cursor, 0, 5) contents := buffer_to_string(core.current_buffer(&e)) testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text) @@ -239,8 +239,8 @@ insert_before_slice :: proc(t: ^testing.T) { run_text_insertion(&e, " rich") - expect_line_col(t, buffer.cursor, 0, 20) - expect_cursor_index(t, buffer.cursor, 2, 4) + expect_line_col(t, buffer.history.cursor, 0, 20) + expect_cursor_index(t, buffer.history.cursor, 2, 4) contents := buffer_to_string(core.current_buffer(&e)) testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text) @@ -259,14 +259,14 @@ delete_last_content_slice_beginning_of_file :: proc(t: ^testing.T) { run_input_multiple(&e, press_key(.I), 1) run_input_multiple(&e, press_key(.BACKSPACE), 13) - expect_line_col(t, buffer.cursor, 0, 0) - expect_cursor_index(t, buffer.cursor, 0, 0) + expect_line_col(t, buffer.history.cursor, 0, 0) + expect_cursor_index(t, buffer.history.cursor, 0, 0) // Try to delete when there is no text run_input_multiple(&e, press_key(.BACKSPACE), 1) - expect_line_col(t, buffer.cursor, 0, 0) - expect_cursor_index(t, buffer.cursor, 0, 0) + expect_line_col(t, buffer.history.cursor, 0, 0) + expect_cursor_index(t, buffer.history.cursor, 0, 0) testing.expect(t, len(core.buffer_piece_table(buffer).chunks) > 0, "BACKSPACE deleted final content slice in buffer") // "commit" insert mode changes, then re-enter insert mode and try to delete again @@ -274,8 +274,8 @@ delete_last_content_slice_beginning_of_file :: proc(t: ^testing.T) { run_input_multiple(&e, press_key(.I), 1) run_input_multiple(&e, press_key(.BACKSPACE), 1) - expect_line_col(t, buffer.cursor, 0, 0) - expect_cursor_index(t, buffer.cursor, 0, 0) + expect_line_col(t, buffer.history.cursor, 0, 0) + expect_cursor_index(t, buffer.history.cursor, 0, 0) testing.expect(t, len(core.buffer_piece_table(buffer).chunks) > 0, "BACKSPACE deleted final content slice in buffer") } @@ -306,8 +306,8 @@ delete_in_slice :: proc(t: ^testing.T) { run_input_multiple(&e, press_key(.BACKSPACE), 3) run_input_multiple(&e, press_key(.ESCAPE), 1) - expect_line_col(t, buffer.cursor, 0, 17) - expect_cursor_index(t, buffer.cursor, 3, 0) + expect_line_col(t, buffer.history.cursor, 0, 17) + expect_cursor_index(t, buffer.history.cursor, 3, 0) contents := buffer_to_string(core.current_buffer(&e)) testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text) @@ -348,8 +348,8 @@ delete_across_slices :: proc(t: ^testing.T) { run_input_multiple(&e, press_key(.BACKSPACE), 2) run_input_multiple(&e, press_key(.ESCAPE), 1) - expect_line_col(t, buffer.cursor, 0, 16) - expect_cursor_index(t, buffer.cursor, 2, 0) + expect_line_col(t, buffer.history.cursor, 0, 16) + expect_cursor_index(t, buffer.history.cursor, 2, 0) contents := buffer_to_string(core.current_buffer(&e)) testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text) @@ -375,8 +375,8 @@ move_down_next_line_has_shorter_length :: proc(t: ^testing.T) { // Move down to the second line run_input_multiple(&e, press_key(.J), 1) - expect_line_col(t, buffer.cursor, 1, 0) - expect_cursor_index(t, buffer.cursor, 0, 10) + expect_line_col(t, buffer.history.cursor, 1, 0) + expect_cursor_index(t, buffer.history.cursor, 0, 10) } @(test) @@ -394,8 +394,8 @@ move_down_on_last_line :: proc(t: ^testing.T) { run_input_multiple(&e, press_key(.J), 1) // Cursor should stay where it is - expect_line_col(t, buffer.cursor, 0, 8) - expect_cursor_index(t, buffer.cursor, 0, 8) + expect_line_col(t, buffer.history.cursor, 0, 8) + expect_cursor_index(t, buffer.history.cursor, 0, 8) } @(test) @@ -410,15 +410,15 @@ move_left_at_beginning_of_file :: proc(t: ^testing.T) { // to ------------------^ run_input_multiple(&e, press_key(.H), 4) - expect_line_col(t, buffer.cursor, 0, 0) - expect_cursor_index(t, buffer.cursor, 0, 0) + expect_line_col(t, buffer.history.cursor, 0, 0) + expect_cursor_index(t, buffer.history.cursor, 0, 0) // Try to move before the beginning of the file run_input_multiple(&e, press_key(.H), 1) // Should stay the same - expect_line_col(t, buffer.cursor, 0, 0) - expect_cursor_index(t, buffer.cursor, 0, 0) + expect_line_col(t, buffer.history.cursor, 0, 0) + expect_cursor_index(t, buffer.history.cursor, 0, 0) } @(test) @@ -432,15 +432,15 @@ move_right_at_end_of_file :: proc(t: ^testing.T) { run_text_insertion(&e, "01234") - expect_line_col(t, buffer.cursor, 0, 4) - expect_cursor_index(t, buffer.cursor, 0, 4) + expect_line_col(t, buffer.history.cursor, 0, 4) + expect_cursor_index(t, buffer.history.cursor, 0, 4) // Try to move after the end of the file run_input_multiple(&e, press_key(.L), 1) // Should stay the same - expect_line_col(t, buffer.cursor, 0, 4) - expect_cursor_index(t, buffer.cursor, 0, 4) + expect_line_col(t, buffer.history.cursor, 0, 4) + expect_cursor_index(t, buffer.history.cursor, 0, 4) } @(test) @@ -460,8 +460,8 @@ move_to_end_of_line_from_end :: proc(t: ^testing.T) { // Move to the end of the line run_inputs(&e, []ArtificialInput{ press_key(.G), press_key(.L)}) - expect_line_col(t, buffer.cursor, 0, 4) - expect_cursor_index(t, buffer.cursor, 0, 4) + expect_line_col(t, buffer.history.cursor, 0, 4) + expect_cursor_index(t, buffer.history.cursor, 0, 4) } @(test) @@ -484,8 +484,8 @@ move_to_end_of_line_from_middle :: proc(t: ^testing.T) { // Move to the end of the line run_inputs(&e, []ArtificialInput{ press_key(.G), press_key(.L)}) - expect_line_col(t, buffer.cursor, 0, 4) - expect_cursor_index(t, buffer.cursor, 0, 4) + expect_line_col(t, buffer.history.cursor, 0, 4) + expect_cursor_index(t, buffer.history.cursor, 0, 4) } @(test) @@ -508,8 +508,8 @@ move_to_beginning_of_line_from_middle :: proc(t: ^testing.T) { // Move to the beginning of the line run_inputs(&e, []ArtificialInput{ press_key(.G), press_key(.H)}) - expect_line_col(t, buffer.cursor, 0, 0) - expect_cursor_index(t, buffer.cursor, 0, 0) + expect_line_col(t, buffer.history.cursor, 0, 0) + expect_cursor_index(t, buffer.history.cursor, 0, 0) } @(test) @@ -532,8 +532,8 @@ move_to_beginning_of_line_from_start :: proc(t: ^testing.T) { // Move to the beginning of the line run_inputs(&e, []ArtificialInput{ press_key(.G), press_key(.H)}) - expect_line_col(t, buffer.cursor, 0, 0) - expect_cursor_index(t, buffer.cursor, 0, 0) + expect_line_col(t, buffer.history.cursor, 0, 0) + expect_cursor_index(t, buffer.history.cursor, 0, 0) } @(test) @@ -548,14 +548,14 @@ append_end_of_line :: proc(t: ^testing.T) { run_input_multiple(&e, press_key(.A), 1) run_input_multiple(&e, press_key(.ESCAPE), 1) - expect_line_col(t, buffer.cursor, 0, 5) - expect_cursor_index(t, buffer.cursor, 1, 0) + expect_line_col(t, buffer.history.cursor, 0, 5) + expect_cursor_index(t, buffer.history.cursor, 1, 0) run_input_multiple(&e, press_key(.A), 1) run_input_multiple(&e, press_key(.ESCAPE), 1) - expect_line_col(t, buffer.cursor, 0, 5) - expect_cursor_index(t, buffer.cursor, 1, 0) + expect_line_col(t, buffer.history.cursor, 0, 5) + expect_cursor_index(t, buffer.history.cursor, 1, 0) } @(test) @@ -581,13 +581,13 @@ insert_line_under_current :: proc(t: ^testing.T) { // Technically the cursor is still on the first line, because the `input_buffer` // has been modified but not the actual contents of the filebuffer - expect_line_col(t, buffer.cursor, 0, 13) - expect_cursor_index(t, buffer.cursor, 0, 13) + expect_line_col(t, buffer.history.cursor, 0, 13) + expect_cursor_index(t, buffer.history.cursor, 0, 13) run_text_insertion(&e, "This is the second line") - expect_line_col(t, buffer.cursor, 1, 22) - expect_cursor_index(t, buffer.cursor, 1, 23) + expect_line_col(t, buffer.history.cursor, 1, 22) + expect_cursor_index(t, buffer.history.cursor, 1, 23) contents := buffer_to_string(core.current_buffer(&e)) testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text) @@ -614,7 +614,7 @@ yank_and_paste_whole_line :: proc(t: ^testing.T) { // Paste it below current one run_input_multiple(&e, press_key(.P), 1) - expect_line_col(t, buffer.cursor, 1, 0) + expect_line_col(t, buffer.history.cursor, 1, 0) contents := buffer_to_string(core.current_buffer(&e)) testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)