first iteration of naive undo/redo
parent
7e128d08cc
commit
aae0c24504
|
@ -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
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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..<len(buffer.input_buffer) {
|
||||
screen_line = rendered_line - begin;
|
||||
|
||||
|
|
|
@ -1,35 +1,40 @@
|
|||
package core
|
||||
|
||||
import "core:log"
|
||||
|
||||
FileHistory :: struct {
|
||||
snapshots: []Snapshot,
|
||||
current: int
|
||||
piece_table: PieceTable,
|
||||
cursor: Cursor,
|
||||
|
||||
snapshots: []Snapshot,
|
||||
next: int,
|
||||
first: int
|
||||
}
|
||||
|
||||
Snapshot :: union {
|
||||
PieceTable,
|
||||
Snapshot :: struct {
|
||||
chunks: [dynamic][]u8,
|
||||
cursor: Cursor,
|
||||
}
|
||||
|
||||
make_history_with_data :: proc(initial_data: []u8, starting_capacity: int = 1024, allocator := context.allocator) -> 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)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -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'});
|
||||
|
|
|
@ -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 {
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
),
|
||||
{}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue