869 lines
25 KiB
Plaintext
869 lines
25 KiB
Plaintext
package tests
|
|
|
|
import "base:runtime"
|
|
import "core:testing"
|
|
import "core:fmt"
|
|
import "core:mem"
|
|
import "core:log"
|
|
|
|
import "../core"
|
|
import "../panels"
|
|
import "../util"
|
|
|
|
new_test_editor :: proc() -> core.State {
|
|
state := core.State {
|
|
ctx = context,
|
|
screen_width = 640,
|
|
screen_height = 480,
|
|
source_font_width = 8,
|
|
source_font_height = 16,
|
|
|
|
panels = util.make_static_list(core.Panel, 128),
|
|
|
|
directory = "test_directory",
|
|
};
|
|
|
|
return state
|
|
}
|
|
|
|
delete_editor :: proc(e: ^core.State) {
|
|
util.delete(&e.panels)
|
|
}
|
|
|
|
buffer_to_string :: proc(buffer: ^core.FileBuffer) -> string {
|
|
if buffer == nil {
|
|
log.error("nil buffer")
|
|
}
|
|
|
|
length := 0
|
|
for chunk in core.buffer_piece_table(buffer).chunks {
|
|
length += len(chunk)
|
|
}
|
|
|
|
buffer_contents := make([]u8, length)
|
|
|
|
offset := 0
|
|
for chunk in core.buffer_piece_table(buffer).chunks {
|
|
for c in chunk {
|
|
buffer_contents[offset] = c
|
|
offset += 1
|
|
}
|
|
}
|
|
|
|
return string(buffer_contents)
|
|
}
|
|
|
|
ArtificialInput :: union {
|
|
ArtificialKey,
|
|
ArtificialTextInput,
|
|
}
|
|
|
|
ArtificialKey :: struct {
|
|
is_down: bool,
|
|
key: core.Key,
|
|
}
|
|
|
|
ArtificialTextInput :: struct {
|
|
text: string,
|
|
}
|
|
|
|
press_key :: proc(key: core.Key) -> ArtificialKey {
|
|
return ArtificialKey {
|
|
is_down = true,
|
|
key = key
|
|
}
|
|
}
|
|
|
|
release_key :: proc(key: core.Key) -> ArtificialKey {
|
|
return ArtificialKey {
|
|
is_down = false,
|
|
key = key
|
|
}
|
|
}
|
|
|
|
input_text :: proc(text: string) -> ArtificialTextInput {
|
|
return ArtificialTextInput {
|
|
text = text
|
|
}
|
|
}
|
|
|
|
setup_empty_buffer :: proc(state: ^core.State) {
|
|
panels.open(state, panels.make_file_buffer_panel(""))
|
|
|
|
core.reset_input_map(state)
|
|
}
|
|
|
|
run_inputs :: proc(state: ^core.State, inputs: []ArtificialInput) {
|
|
is_ctrl_pressed := false
|
|
|
|
for input in inputs {
|
|
run_editor_frame(state, input, &is_ctrl_pressed)
|
|
}
|
|
}
|
|
|
|
run_input_multiple :: proc(state: ^core.State, input: ArtificialInput, amount: int) {
|
|
is_ctrl_pressed := false
|
|
|
|
for _ in 0..<amount {
|
|
run_editor_frame(state, input, &is_ctrl_pressed)
|
|
}
|
|
}
|
|
|
|
run_text_insertion :: proc(state: ^core.State, text: string) {
|
|
is_ctrl_pressed := false
|
|
|
|
inputs := []ArtificialInput {
|
|
press_key(.I),
|
|
input_text(text),
|
|
press_key(.ESCAPE),
|
|
}
|
|
|
|
for input in inputs {
|
|
run_editor_frame(state, input, &is_ctrl_pressed)
|
|
}
|
|
}
|
|
|
|
expect_line_col :: proc(t: ^testing.T, cursor: core.Cursor, line, col: int) {
|
|
testing.expect_value(t, cursor.line, line)
|
|
testing.expect_value(t, cursor.col, col)
|
|
}
|
|
|
|
expect_cursor_index :: proc(t: ^testing.T, cursor: core.Cursor, chunk_index, char_index: int) {
|
|
testing.expect_value(t, cursor.index.chunk_index, chunk_index)
|
|
testing.expect_value(t, cursor.index.char_index, char_index)
|
|
}
|
|
|
|
@(test)
|
|
insert_from_empty_no_newlines :: proc(t: ^testing.T) {
|
|
e := new_test_editor()
|
|
setup_empty_buffer(&e)
|
|
defer {
|
|
panels.close(&e, 0)
|
|
delete_editor(&e)
|
|
}
|
|
|
|
buffer := core.current_buffer(&e)
|
|
|
|
inputted_text := "Hello, world!"
|
|
expected_text := fmt.aprintf("%v\n", inputted_text)
|
|
run_text_insertion(&e, inputted_text)
|
|
|
|
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))
|
|
defer delete(contents)
|
|
|
|
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
|
}
|
|
|
|
@(test)
|
|
insert_from_empty_with_newline :: proc(t: ^testing.T) {
|
|
e := new_test_editor()
|
|
setup_empty_buffer(&e)
|
|
defer {
|
|
panels.close(&e, 0)
|
|
delete_editor(&e)
|
|
}
|
|
|
|
buffer := core.current_buffer(&e)
|
|
|
|
inputted_text := "Hello, world!\nThis is a new line"
|
|
expected_text := fmt.aprintf("%v\n", inputted_text)
|
|
run_text_insertion(&e, inputted_text)
|
|
|
|
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))
|
|
defer delete(contents)
|
|
|
|
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
|
}
|
|
|
|
@(test)
|
|
insert_in_between_text :: proc(t: ^testing.T) {
|
|
e := new_test_editor()
|
|
setup_empty_buffer(&e)
|
|
defer {
|
|
panels.close(&e, 0)
|
|
delete_editor(&e)
|
|
}
|
|
|
|
buffer := core.current_buffer(&e)
|
|
|
|
inputted_text := "Hello, world!"
|
|
expected_text := "Hello, beautiful world!\n"
|
|
|
|
run_text_insertion(&e, inputted_text)
|
|
|
|
// Move the cursor to the space in between 'Hello,' and 'world!'
|
|
run_input_multiple(&e, press_key(.H), 6)
|
|
|
|
run_text_insertion(&e, " beautiful")
|
|
|
|
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))
|
|
defer delete(contents)
|
|
|
|
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
|
}
|
|
|
|
@(test)
|
|
insert_before_slice_at_beginning_of_file :: proc(t: ^testing.T) {
|
|
e := new_test_editor()
|
|
setup_empty_buffer(&e)
|
|
defer {
|
|
panels.close(&e, 0)
|
|
delete_editor(&e)
|
|
}
|
|
|
|
buffer := core.current_buffer(&e)
|
|
|
|
inputted_text := "Hello, world!"
|
|
expected_text := "Well, Hello, beautiful world!\n"
|
|
|
|
run_text_insertion(&e, inputted_text)
|
|
|
|
// Move the cursor to the space in between 'Hello,' and 'world!'
|
|
run_input_multiple(&e, press_key(.H), 6)
|
|
run_text_insertion(&e, " beautiful")
|
|
|
|
// Move to beginning of line (and hence the file)
|
|
run_inputs(&e, []ArtificialInput{ press_key(.G), press_key(.H)})
|
|
run_text_insertion(&e, "Well, ")
|
|
|
|
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))
|
|
defer delete(contents)
|
|
|
|
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
|
}
|
|
|
|
@(test)
|
|
insert_before_slice :: proc(t: ^testing.T) {
|
|
e := new_test_editor()
|
|
setup_empty_buffer(&e)
|
|
defer {
|
|
panels.close(&e, 0)
|
|
delete_editor(&e)
|
|
}
|
|
|
|
buffer := core.current_buffer(&e)
|
|
|
|
inputted_text := "Hello, world!"
|
|
expected_text := "Hello, beautiful rich world!\n"
|
|
|
|
run_text_insertion(&e, inputted_text)
|
|
|
|
// Move the cursor to the space in between 'Hello,' and 'world!'
|
|
run_input_multiple(&e, press_key(.H), 6)
|
|
run_text_insertion(&e, " beautiful")
|
|
|
|
// Move right to the start of the slice of ' world!'
|
|
run_input_multiple(&e, press_key(.L), 1)
|
|
|
|
run_text_insertion(&e, " rich")
|
|
|
|
expect_line_col(t, buffer.history.cursor, 0, 20)
|
|
|
|
contents := buffer_to_string(core.current_buffer(&e))
|
|
defer delete(contents)
|
|
|
|
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
|
}
|
|
|
|
@(test)
|
|
delete_last_content_slice_beginning_of_file :: proc(t: ^testing.T) {
|
|
e := new_test_editor()
|
|
setup_empty_buffer(&e)
|
|
defer {
|
|
panels.close(&e, 0)
|
|
delete_editor(&e)
|
|
}
|
|
|
|
buffer := core.current_buffer(&e)
|
|
|
|
run_text_insertion(&e, "Hello, world!")
|
|
|
|
// Delete just the text
|
|
run_input_multiple(&e, press_key(.I), 1)
|
|
run_input_multiple(&e, press_key(.BACKSPACE), 13)
|
|
|
|
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.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
|
|
run_input_multiple(&e, press_key(.ESCAPE), 1)
|
|
run_input_multiple(&e, press_key(.I), 1)
|
|
run_input_multiple(&e, press_key(.BACKSPACE), 1)
|
|
|
|
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")
|
|
}
|
|
|
|
@(test)
|
|
delete_in_slice :: proc(t: ^testing.T) {
|
|
e := new_test_editor()
|
|
setup_empty_buffer(&e)
|
|
defer {
|
|
panels.close(&e, 0)
|
|
delete_editor(&e)
|
|
}
|
|
|
|
buffer := core.current_buffer(&e)
|
|
|
|
inputted_text := "Hello, world!"
|
|
expected_text := "Hello, beautiful h world!\n"
|
|
// ------ - ---------
|
|
// ---------- -
|
|
// 0 1 234
|
|
|
|
run_text_insertion(&e, inputted_text)
|
|
|
|
// Move the cursor to the space in between 'Hello,' and 'world!'
|
|
run_input_multiple(&e, press_key(.H), 6)
|
|
run_text_insertion(&e, " beautiful")
|
|
|
|
// Move right to the start of the slice of ' world!'
|
|
run_input_multiple(&e, press_key(.L), 1)
|
|
run_text_insertion(&e, " rich")
|
|
|
|
run_input_multiple(&e, press_key(.I), 1)
|
|
run_input_multiple(&e, press_key(.BACKSPACE), 3)
|
|
run_input_multiple(&e, press_key(.ESCAPE), 1)
|
|
|
|
expect_line_col(t, buffer.history.cursor, 0, 16)
|
|
|
|
contents := buffer_to_string(core.current_buffer(&e))
|
|
defer delete(contents)
|
|
|
|
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
|
}
|
|
|
|
@(test)
|
|
delete_across_slices :: proc(t: ^testing.T) {
|
|
e := new_test_editor()
|
|
setup_empty_buffer(&e)
|
|
defer {
|
|
panels.close(&e, 0)
|
|
delete_editor(&e)
|
|
}
|
|
|
|
buffer := core.current_buffer(&e)
|
|
|
|
inputted_text := "Hello, world!"
|
|
expected_text := "Hello, beautiful world!\n"
|
|
// ------ ---------
|
|
// ----------
|
|
// 0 1 2
|
|
|
|
run_text_insertion(&e, inputted_text)
|
|
|
|
// Move the cursor to the space in between 'Hello,' and 'world!'
|
|
run_input_multiple(&e, press_key(.H), 6)
|
|
run_text_insertion(&e, " beautiful")
|
|
|
|
// Move right to the start of the slice of ' world!'
|
|
run_input_multiple(&e, press_key(.L), 1)
|
|
run_text_insertion(&e, " rich")
|
|
|
|
run_input_multiple(&e, press_key(.I), 1)
|
|
run_input_multiple(&e, press_key(.BACKSPACE), 3)
|
|
run_input_multiple(&e, press_key(.ESCAPE), 1)
|
|
|
|
// Move right, passed the 'h' on to the space before 'world!'
|
|
run_input_multiple(&e, press_key(.L), 2)
|
|
|
|
// Remove the ' h', which consists of two content slices
|
|
run_input_multiple(&e, press_key(.I), 1)
|
|
run_input_multiple(&e, press_key(.BACKSPACE), 2)
|
|
run_input_multiple(&e, press_key(.ESCAPE), 1)
|
|
|
|
expect_line_col(t, buffer.history.cursor, 0, 15)
|
|
|
|
contents := buffer_to_string(core.current_buffer(&e))
|
|
defer delete(contents)
|
|
|
|
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
|
}
|
|
|
|
@(test)
|
|
move_down_next_line_has_shorter_length :: proc(t: ^testing.T) {
|
|
e := new_test_editor()
|
|
setup_empty_buffer(&e)
|
|
defer {
|
|
panels.close(&e, 0)
|
|
delete_editor(&e)
|
|
}
|
|
|
|
is_ctrl_pressed := false
|
|
|
|
buffer := core.current_buffer(&e)
|
|
|
|
run_text_insertion(&e, "012345678\n0")
|
|
|
|
// Move up to the first line
|
|
run_input_multiple(&e, press_key(.K), 1)
|
|
|
|
// Move to the end of the line
|
|
run_inputs(&e, []ArtificialInput{ press_key(.G), press_key(.L)})
|
|
|
|
// Move down to the second line
|
|
run_input_multiple(&e, press_key(.J), 1)
|
|
|
|
expect_line_col(t, buffer.history.cursor, 1, 0)
|
|
expect_cursor_index(t, buffer.history.cursor, 0, 10)
|
|
}
|
|
|
|
@(test)
|
|
move_down_on_last_line :: proc(t: ^testing.T) {
|
|
e := new_test_editor()
|
|
setup_empty_buffer(&e)
|
|
defer {
|
|
panels.close(&e, 0)
|
|
delete_editor(&e)
|
|
}
|
|
|
|
is_ctrl_pressed := false
|
|
|
|
buffer := core.current_buffer(&e)
|
|
|
|
run_text_insertion(&e, "012345678")
|
|
|
|
// Try to move down
|
|
run_input_multiple(&e, press_key(.J), 1)
|
|
|
|
// Cursor should stay where it is
|
|
expect_line_col(t, buffer.history.cursor, 0, 8)
|
|
expect_cursor_index(t, buffer.history.cursor, 0, 8)
|
|
}
|
|
|
|
@(test)
|
|
move_left_at_beginning_of_file :: proc(t: ^testing.T) {
|
|
e := new_test_editor()
|
|
setup_empty_buffer(&e)
|
|
defer {
|
|
panels.close(&e, 0)
|
|
delete_editor(&e)
|
|
}
|
|
|
|
buffer := core.current_buffer(&e)
|
|
|
|
run_text_insertion(&e, "01234")
|
|
// Move cursor from --------^
|
|
// to ------------------^
|
|
run_input_multiple(&e, press_key(.H), 4)
|
|
|
|
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.history.cursor, 0, 0)
|
|
expect_cursor_index(t, buffer.history.cursor, 0, 0)
|
|
}
|
|
|
|
@(test)
|
|
move_right_at_end_of_file :: proc(t: ^testing.T) {
|
|
e := new_test_editor()
|
|
setup_empty_buffer(&e)
|
|
defer {
|
|
panels.close(&e, 0)
|
|
delete_editor(&e)
|
|
}
|
|
|
|
is_ctrl_pressed := false
|
|
|
|
buffer := core.current_buffer(&e)
|
|
|
|
run_text_insertion(&e, "01234")
|
|
|
|
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.history.cursor, 0, 4)
|
|
expect_cursor_index(t, buffer.history.cursor, 0, 4)
|
|
}
|
|
|
|
@(test)
|
|
move_to_end_of_line_from_end :: proc(t: ^testing.T) {
|
|
e := new_test_editor()
|
|
setup_empty_buffer(&e)
|
|
defer {
|
|
panels.close(&e, 0)
|
|
delete_editor(&e)
|
|
}
|
|
|
|
is_ctrl_pressed := false
|
|
|
|
buffer := core.current_buffer(&e)
|
|
|
|
run_text_insertion(&e, "01234\n01234")
|
|
|
|
// Move up to the first line
|
|
run_input_multiple(&e, press_key(.K), 1)
|
|
|
|
// Move to the end of the line
|
|
run_inputs(&e, []ArtificialInput{ press_key(.G), press_key(.L)})
|
|
|
|
expect_line_col(t, buffer.history.cursor, 0, 4)
|
|
expect_cursor_index(t, buffer.history.cursor, 0, 4)
|
|
}
|
|
|
|
@(test)
|
|
move_to_end_of_line_from_middle :: proc(t: ^testing.T) {
|
|
e := new_test_editor()
|
|
setup_empty_buffer(&e)
|
|
defer {
|
|
panels.close(&e, 0)
|
|
delete_editor(&e)
|
|
}
|
|
|
|
is_ctrl_pressed := false
|
|
|
|
buffer := core.current_buffer(&e)
|
|
|
|
run_text_insertion(&e, "01234\n01234")
|
|
|
|
// Move up to the first line
|
|
run_input_multiple(&e, press_key(.K), 1)
|
|
|
|
// Move into the middle of the line
|
|
run_input_multiple(&e, press_key(.H), 2)
|
|
|
|
// Move to the end of the line
|
|
run_inputs(&e, []ArtificialInput{ press_key(.G), press_key(.L)})
|
|
|
|
expect_line_col(t, buffer.history.cursor, 0, 4)
|
|
expect_cursor_index(t, buffer.history.cursor, 0, 4)
|
|
}
|
|
|
|
@(test)
|
|
move_to_beginning_of_line_from_middle :: proc(t: ^testing.T) {
|
|
e := new_test_editor()
|
|
setup_empty_buffer(&e)
|
|
defer {
|
|
panels.close(&e, 0)
|
|
delete_editor(&e)
|
|
}
|
|
|
|
is_ctrl_pressed := false
|
|
|
|
buffer := core.current_buffer(&e)
|
|
|
|
run_text_insertion(&e, "01234\n01234")
|
|
|
|
// Move up to the first line
|
|
run_input_multiple(&e, press_key(.K), 1)
|
|
|
|
// Move into the middle of the line
|
|
run_input_multiple(&e, press_key(.H), 2)
|
|
|
|
// Move to the beginning of the line
|
|
run_inputs(&e, []ArtificialInput{ press_key(.G), press_key(.H)})
|
|
|
|
expect_line_col(t, buffer.history.cursor, 0, 0)
|
|
expect_cursor_index(t, buffer.history.cursor, 0, 0)
|
|
}
|
|
|
|
@(test)
|
|
move_to_beginning_of_line_from_start :: proc(t: ^testing.T) {
|
|
e := new_test_editor()
|
|
setup_empty_buffer(&e)
|
|
defer {
|
|
panels.close(&e, 0)
|
|
delete_editor(&e)
|
|
}
|
|
|
|
is_ctrl_pressed := false
|
|
|
|
buffer := core.current_buffer(&e)
|
|
|
|
run_text_insertion(&e, "01234\n01234")
|
|
|
|
// Move up to the first line
|
|
run_input_multiple(&e, press_key(.K), 1)
|
|
|
|
// Move to the start of the line
|
|
run_input_multiple(&e, press_key(.H), 4)
|
|
|
|
// Move to the beginning of the line
|
|
run_inputs(&e, []ArtificialInput{ press_key(.G), press_key(.H)})
|
|
|
|
expect_line_col(t, buffer.history.cursor, 0, 0)
|
|
expect_cursor_index(t, buffer.history.cursor, 0, 0)
|
|
}
|
|
|
|
@(test)
|
|
append_end_of_line :: proc(t: ^testing.T) {
|
|
e := new_test_editor()
|
|
setup_empty_buffer(&e)
|
|
defer {
|
|
panels.close(&e, 0)
|
|
delete_editor(&e)
|
|
}
|
|
|
|
buffer := core.current_buffer(&e)
|
|
|
|
run_text_insertion(&e, "hello")
|
|
|
|
run_input_multiple(&e, press_key(.A), 1)
|
|
run_input_multiple(&e, press_key(.ESCAPE), 1)
|
|
|
|
expect_line_col(t, buffer.history.cursor, 0, 4)
|
|
|
|
run_input_multiple(&e, press_key(.A), 1)
|
|
run_input_multiple(&e, press_key(.ESCAPE), 1)
|
|
|
|
expect_line_col(t, buffer.history.cursor, 0, 4)
|
|
}
|
|
|
|
@(test)
|
|
insert_line_under_current :: proc(t: ^testing.T) {
|
|
e := new_test_editor()
|
|
setup_empty_buffer(&e)
|
|
defer {
|
|
panels.close(&e, 0)
|
|
delete_editor(&e)
|
|
}
|
|
|
|
buffer := core.current_buffer(&e)
|
|
|
|
initial_text := "Hello, world!\nThis is a new line"
|
|
run_text_insertion(&e, initial_text)
|
|
|
|
expected_text := "Hello, world!\nThis is the second line\nThis is a new line\n"
|
|
// ------------- ----------------------
|
|
// -------------------------
|
|
// 0 1 3
|
|
|
|
// Move cursor up onto the end of "Hello, world!"
|
|
run_input_multiple(&e, press_key(.K), 1)
|
|
|
|
// Insert line below and enter insert mode
|
|
run_input_multiple(&e, press_key(.O), 1)
|
|
|
|
expect_line_col(t, buffer.history.cursor, 1, 0)
|
|
|
|
run_text_insertion(&e, "This is the second line")
|
|
|
|
expect_line_col(t, buffer.history.cursor, 1, 22)
|
|
|
|
contents := buffer_to_string(core.current_buffer(&e))
|
|
defer delete(contents)
|
|
|
|
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
|
}
|
|
|
|
@(test)
|
|
yank_and_paste_whole_line :: proc(t: ^testing.T) {
|
|
e := new_test_editor()
|
|
setup_empty_buffer(&e)
|
|
defer {
|
|
panels.close(&e, 0)
|
|
delete_editor(&e)
|
|
}
|
|
|
|
buffer := core.current_buffer(&e)
|
|
|
|
initial_text := "Hello, world!\nThis is a new line"
|
|
run_text_insertion(&e, initial_text)
|
|
|
|
expected_text := "Hello, world!\nThis is a new line\nThis is a new line\n"
|
|
|
|
// Copy whole line
|
|
run_input_multiple(&e, press_key(.Y), 2)
|
|
|
|
// Move up to "Hello, world!"
|
|
run_input_multiple(&e, press_key(.K), 1)
|
|
|
|
// Paste it below current one
|
|
run_input_multiple(&e, press_key(.P), 1)
|
|
|
|
expect_line_col(t, buffer.history.cursor, 1, 0)
|
|
|
|
contents := buffer_to_string(core.current_buffer(&e))
|
|
defer delete(contents)
|
|
|
|
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
|
}
|
|
|
|
@(test)
|
|
select_and_delete_half_of_line_backwards :: proc(t: ^testing.T) {
|
|
e := new_test_editor()
|
|
setup_empty_buffer(&e)
|
|
defer {
|
|
panels.close(&e, 0)
|
|
delete_editor(&e)
|
|
}
|
|
|
|
buffer := core.current_buffer(&e)
|
|
|
|
initial_text := "Hello, world!\nThis is a new line"
|
|
run_text_insertion(&e, initial_text)
|
|
|
|
expected_text := "Hello\nThis is a new line\n"
|
|
|
|
// Move up to "Hello, world!"
|
|
run_input_multiple(&e, press_key(.K), 1)
|
|
|
|
// Move to end of line
|
|
run_inputs(&e, []ArtificialInput{ press_key(.G), press_key(.L)})
|
|
|
|
// Move to the end of 'Hello' and delete selection
|
|
run_input_multiple(&e, press_key(.V), 1)
|
|
run_input_multiple(&e, press_key(.H), 7)
|
|
run_input_multiple(&e, press_key(.D), 1)
|
|
|
|
expect_line_col(t, buffer.history.cursor, 0, 4)
|
|
|
|
contents := buffer_to_string(core.current_buffer(&e))
|
|
defer delete(contents)
|
|
|
|
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
|
}
|
|
|
|
run_editor_frame :: proc(state: ^core.State, input: ArtificialInput, is_ctrl_pressed: ^bool) {
|
|
{
|
|
run_key_action := proc(state: ^core.State, control_key_pressed: bool, key: core.Key) -> bool {
|
|
if current_panel, ok := state.current_panel.?; ok {
|
|
panel := util.get(&state.panels, current_panel).?
|
|
|
|
if control_key_pressed {
|
|
if action, exists := state.current_input_map.ctrl_key_actions[key]; exists {
|
|
switch value in action.action {
|
|
case core.EditorAction:
|
|
value(state, panel);
|
|
return true;
|
|
case core.InputActions:
|
|
state.current_input_map = &(&state.current_input_map.ctrl_key_actions[key]).action.(core.InputActions)
|
|
return true;
|
|
}
|
|
}
|
|
} else {
|
|
if action, exists := state.current_input_map.key_actions[key]; exists {
|
|
switch value in action.action {
|
|
case core.EditorAction:
|
|
value(state, panel);
|
|
return true;
|
|
case core.InputActions:
|
|
state.current_input_map = &(&state.current_input_map.key_actions[key]).action.(core.InputActions)
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
switch state.mode {
|
|
case .Visual: fallthrough
|
|
case .Normal: {
|
|
if key, ok := input.(ArtificialKey); ok {
|
|
if key.is_down {
|
|
if key.key == .LCTRL {
|
|
is_ctrl_pressed^ = true;
|
|
} else {
|
|
run_key_action(state, is_ctrl_pressed^, key.key)
|
|
}
|
|
} else {
|
|
if key.key == .LCTRL {
|
|
is_ctrl_pressed^ = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
case .Insert: {
|
|
buffer := core.current_buffer(state);
|
|
|
|
if key, ok := input.(ArtificialKey); ok {
|
|
if key.is_down {
|
|
// TODO: make this work properly
|
|
if true || !run_key_action(state, is_ctrl_pressed^, key.key) {
|
|
#partial switch key.key {
|
|
case .ESCAPE: {
|
|
state.mode = .Normal;
|
|
core.move_cursor_left(buffer)
|
|
}
|
|
case .TAB: {
|
|
// TODO: change this to insert a tab character
|
|
core.insert_content(buffer, transmute([]u8)string(" "))
|
|
|
|
if current_panel, ok := state.current_panel.?; ok {
|
|
if panel, ok := util.get(&state.panels, current_panel).?; ok && panel.on_buffer_input != nil {
|
|
panel->on_buffer_input(state)
|
|
}
|
|
}
|
|
}
|
|
case .BACKSPACE: {
|
|
core.delete_content(buffer, 1);
|
|
|
|
if current_panel, ok := state.current_panel.?; ok {
|
|
if panel, ok := util.get(&state.panels, current_panel).?; ok && panel.on_buffer_input != nil {
|
|
panel->on_buffer_input(state)
|
|
}
|
|
}
|
|
}
|
|
case .ENTER: {
|
|
indent := core.get_buffer_indent(buffer)
|
|
core.insert_content(buffer, []u8{'\n'})
|
|
|
|
for i in 0..<indent {
|
|
core.insert_content(buffer, []u8{' '})
|
|
}
|
|
|
|
if current_panel, ok := state.current_panel.?; ok {
|
|
if panel, ok := util.get(&state.panels, current_panel).?; ok && panel.on_buffer_input != nil {
|
|
panel->on_buffer_input(state)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if text_input, ok := input.(ArtificialTextInput); ok {
|
|
for char in text_input.text {
|
|
if char < 1 {
|
|
break;
|
|
}
|
|
|
|
if char == '\n' || (char >= 32 && char <= 125) {
|
|
core.insert_content(buffer, []u8{u8(char)})
|
|
}
|
|
}
|
|
|
|
if current_panel, ok := state.current_panel.?; ok {
|
|
if panel, ok := util.get(&state.panels, current_panel).?; ok && panel.on_buffer_input != nil {
|
|
panel->on_buffer_input(state)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
runtime.free_all(context.temp_allocator);
|
|
}
|