fix some memory isses
parent
0a0681c704
commit
cdadbbef18
|
@ -136,6 +136,8 @@ current_buffer :: proc(state: ^State) -> ^FileBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
yank_whole_line :: proc(state: ^State, buffer: ^FileBuffer) {
|
yank_whole_line :: proc(state: ^State, buffer: ^FileBuffer) {
|
||||||
|
context.allocator = buffer.allocator
|
||||||
|
|
||||||
if state.yank_register.data != nil {
|
if state.yank_register.data != nil {
|
||||||
delete(state.yank_register.data)
|
delete(state.yank_register.data)
|
||||||
state.yank_register.data = nil
|
state.yank_register.data = nil
|
||||||
|
|
|
@ -825,8 +825,8 @@ color_character :: proc(buffer: ^FileBuffer, start: Cursor, end: Cursor, palette
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_file_buffer :: proc(state: ^State, buffer: ^FileBuffer, x, y, w, h: int, show_line_numbers: bool = true, show_cursor: bool = true) {
|
draw_file_buffer :: proc(state: ^State, buffer: ^FileBuffer, x, y, w, h: int, show_line_numbers: bool = true, show_cursor: bool = true) {
|
||||||
glyph_width := math.min(256, int((w - state.source_font_width) / state.source_font_width));
|
glyph_width := math.min(256, int(w / state.source_font_width));
|
||||||
glyph_height := math.min(256, int((h - state.source_font_height*2) / state.source_font_height)) + 1;
|
glyph_height := math.min(256, int(h / state.source_font_height)) + 1;
|
||||||
|
|
||||||
update_glyph_buffer(buffer, glyph_width, glyph_height);
|
update_glyph_buffer(buffer, glyph_width, glyph_height);
|
||||||
|
|
||||||
|
@ -845,7 +845,7 @@ draw_file_buffer :: proc(state: ^State, buffer: ^FileBuffer, x, y, w, h: int, sh
|
||||||
if show_cursor {
|
if show_cursor {
|
||||||
if state.mode == .Normal {
|
if state.mode == .Normal {
|
||||||
draw_rect(state, cursor_x, cursor_y, state.source_font_width, state.source_font_height, .Background4);
|
draw_rect(state, cursor_x, cursor_y, state.source_font_width, state.source_font_height, .Background4);
|
||||||
} else if state.mode == .Visual {
|
} else if state.mode == .Visual && buffer.selection != nil {
|
||||||
start_sel_x := x + padding + buffer.selection.?.start.col * state.source_font_width;
|
start_sel_x := x + padding + buffer.selection.?.start.col * state.source_font_width;
|
||||||
start_sel_y := y + buffer.selection.?.start.line * state.source_font_height;
|
start_sel_y := y + buffer.selection.?.start.line * state.source_font_height;
|
||||||
|
|
||||||
|
@ -937,7 +937,9 @@ update_file_buffer_scroll :: proc(buffer: ^FileBuffer, cursor: Maybe(^Cursor) =
|
||||||
cursor = &buffer.history.cursor;
|
cursor = &buffer.history.cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if cursor.?.line > (buffer.top_line + buffer.glyphs.height - 5) {
|
if buffer.glyphs.height < 5 {
|
||||||
|
buffer.top_line = cursor.?.line
|
||||||
|
} else if cursor.?.line > (buffer.top_line + buffer.glyphs.height - 5) {
|
||||||
buffer.top_line = math.max(cursor.?.line - buffer.glyphs.height + 5, 0);
|
buffer.top_line = math.max(cursor.?.line - buffer.glyphs.height + 5, 0);
|
||||||
} else if cursor.?.line < (buffer.top_line + 5) {
|
} else if cursor.?.line < (buffer.top_line + 5) {
|
||||||
buffer.top_line = math.max(cursor.?.line - 5, 0);
|
buffer.top_line = math.max(cursor.?.line - 5, 0);
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import "core:log"
|
import "core:log"
|
||||||
|
import "core:mem"
|
||||||
|
|
||||||
FileHistory :: struct {
|
FileHistory :: struct {
|
||||||
|
allocator: mem.Allocator,
|
||||||
|
|
||||||
piece_table: PieceTable,
|
piece_table: PieceTable,
|
||||||
cursor: Cursor,
|
cursor: Cursor,
|
||||||
|
|
||||||
|
@ -20,6 +23,7 @@ make_history_with_data :: proc(initial_data: []u8, starting_capacity: int = 1024
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
|
|
||||||
return FileHistory {
|
return FileHistory {
|
||||||
|
allocator = allocator,
|
||||||
piece_table = make_piece_table(initial_data, starting_capacity = starting_capacity),
|
piece_table = make_piece_table(initial_data, starting_capacity = starting_capacity),
|
||||||
snapshots = make([]Snapshot, starting_capacity),
|
snapshots = make([]Snapshot, starting_capacity),
|
||||||
next = 0,
|
next = 0,
|
||||||
|
@ -31,6 +35,7 @@ make_history_empty :: proc(starting_capacity: int = 1024, allocator := context.a
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
|
|
||||||
return FileHistory {
|
return FileHistory {
|
||||||
|
allocator = allocator,
|
||||||
piece_table = make_piece_table(starting_capacity = starting_capacity),
|
piece_table = make_piece_table(starting_capacity = starting_capacity),
|
||||||
snapshots = make([]Snapshot, starting_capacity),
|
snapshots = make([]Snapshot, starting_capacity),
|
||||||
next = 0,
|
next = 0,
|
||||||
|
@ -54,6 +59,8 @@ free_history :: proc(history: ^FileHistory) {
|
||||||
}
|
}
|
||||||
|
|
||||||
push_new_snapshot :: proc(history: ^FileHistory) {
|
push_new_snapshot :: proc(history: ^FileHistory) {
|
||||||
|
context.allocator = history.allocator
|
||||||
|
|
||||||
if history.snapshots[history.next].chunks != nil {
|
if history.snapshots[history.next].chunks != nil {
|
||||||
delete(history.snapshots[history.next].chunks)
|
delete(history.snapshots[history.next].chunks)
|
||||||
}
|
}
|
||||||
|
@ -65,6 +72,8 @@ push_new_snapshot :: proc(history: ^FileHistory) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pop_snapshot :: proc(history: ^FileHistory, make_new_snapshot: bool = false) {
|
pop_snapshot :: proc(history: ^FileHistory, make_new_snapshot: bool = false) {
|
||||||
|
context.allocator = history.allocator
|
||||||
|
|
||||||
new_next, _ := next_indexes(history, backward = true)
|
new_next, _ := next_indexes(history, backward = true)
|
||||||
if new_next == history.next do return
|
if new_next == history.next do return
|
||||||
|
|
||||||
|
@ -81,6 +90,8 @@ pop_snapshot :: proc(history: ^FileHistory, make_new_snapshot: bool = false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
recover_snapshot :: proc(history: ^FileHistory) {
|
recover_snapshot :: proc(history: ^FileHistory) {
|
||||||
|
context.allocator = history.allocator
|
||||||
|
|
||||||
new_next, _ := next_indexes(history)
|
new_next, _ := next_indexes(history)
|
||||||
if history.snapshots[new_next].chunks == nil do return
|
if history.snapshots[new_next].chunks == nil do return
|
||||||
history.next = new_next
|
history.next = new_next
|
||||||
|
|
|
@ -84,9 +84,6 @@ render_file_buffer :: proc(state: ^core.State, s: ^ui.State, buffer: ^core.FileB
|
||||||
draw_func := proc(state: ^core.State, e: ui.UI_Element, user_data: rawptr) {
|
draw_func := proc(state: ^core.State, e: ui.UI_Element, user_data: rawptr) {
|
||||||
buffer := transmute(^core.FileBuffer)user_data;
|
buffer := transmute(^core.FileBuffer)user_data;
|
||||||
if buffer != nil {
|
if buffer != nil {
|
||||||
buffer.glyphs.width = e.layout.size.x / state.source_font_width;
|
|
||||||
buffer.glyphs.height = e.layout.size.y / state.source_font_height + 1;
|
|
||||||
|
|
||||||
core.draw_file_buffer(state, buffer, e.layout.pos.x, e.layout.pos.y, e.layout.size.x, e.layout.size.y);
|
core.draw_file_buffer(state, buffer, e.layout.pos.x, e.layout.pos.y, e.layout.size.x, e.layout.size.y);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -58,7 +58,12 @@ make_grep_panel :: proc() -> core.Panel {
|
||||||
|
|
||||||
panel_state := &panel.type.(core.GrepPanel)
|
panel_state := &panel.type.(core.GrepPanel)
|
||||||
|
|
||||||
mem.arena_init(&panel_state.query_arena, make([]u8, 1024*1024*2))
|
arena_bytes, err := make([]u8, 1024*1024*2)
|
||||||
|
if err != nil {
|
||||||
|
log.errorf("failed to allocate arena for grep panel: '%v'", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mem.arena_init(&panel_state.query_arena, arena_bytes)
|
||||||
|
|
||||||
panel.input_map = core.new_input_map()
|
panel.input_map = core.new_input_map()
|
||||||
panel_state.glyphs = core.make_glyph_buffer(256,256)
|
panel_state.glyphs = core.make_glyph_buffer(256,256)
|
||||||
|
@ -215,7 +220,7 @@ make_grep_panel :: proc() -> core.Panel {
|
||||||
{
|
{
|
||||||
defer ui.close_element(s)
|
defer ui.close_element(s)
|
||||||
|
|
||||||
// render_raw_buffer(state, s, &state.buffers[panel_state.buffer])
|
render_raw_buffer(state, s, &panel_state.buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ui.close_element(s)
|
ui.close_element(s)
|
||||||
|
@ -275,9 +280,6 @@ render_raw_buffer :: proc(state: ^core.State, s: ^ui.State, buffer: ^core.FileBu
|
||||||
draw_func := proc(state: ^core.State, e: ui.UI_Element, user_data: rawptr) {
|
draw_func := proc(state: ^core.State, e: ui.UI_Element, user_data: rawptr) {
|
||||||
buffer := transmute(^core.FileBuffer)user_data;
|
buffer := transmute(^core.FileBuffer)user_data;
|
||||||
if buffer != nil {
|
if buffer != nil {
|
||||||
buffer.glyphs.width = e.layout.size.x / state.source_font_width;
|
|
||||||
buffer.glyphs.height = e.layout.size.y / state.source_font_height + 1;
|
|
||||||
|
|
||||||
core.draw_file_buffer(state, buffer, e.layout.pos.x, e.layout.pos.y, e.layout.size.x, e.layout.size.y, false);
|
core.draw_file_buffer(state, buffer, e.layout.pos.x, e.layout.pos.y, e.layout.size.x, e.layout.size.y, false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -66,7 +66,14 @@ open :: proc(state: ^core.State, panel: core.Panel, make_active: bool = true) ->
|
||||||
panel.id = panel_id
|
panel.id = panel_id
|
||||||
state.current_panel = panel_id
|
state.current_panel = panel_id
|
||||||
|
|
||||||
mem.arena_init(&panel.arena, make([]u8, 1024*1024*4))
|
arena_bytes, err := make([]u8, 1024*1024*8)
|
||||||
|
if err != nil {
|
||||||
|
log.errorf("failed to allocate memory for panel: '%v'", err)
|
||||||
|
util.delete(&state.panels, panel_id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mem.arena_init(&panel.arena, arena_bytes)
|
||||||
panel.allocator = mem.arena_allocator(&panel.arena)
|
panel.allocator = mem.arena_allocator(&panel.arena)
|
||||||
|
|
||||||
panel->create(state)
|
panel->create(state)
|
||||||
|
|
|
@ -26,6 +26,10 @@ new_test_editor :: proc() -> core.State {
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete_editor :: proc(e: ^core.State) {
|
||||||
|
util.delete(&e.panels)
|
||||||
|
}
|
||||||
|
|
||||||
buffer_to_string :: proc(buffer: ^core.FileBuffer) -> string {
|
buffer_to_string :: proc(buffer: ^core.FileBuffer) -> string {
|
||||||
if buffer == nil {
|
if buffer == nil {
|
||||||
log.error("nil buffer")
|
log.error("nil buffer")
|
||||||
|
@ -84,9 +88,7 @@ input_text :: proc(text: string) -> ArtificialTextInput {
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_empty_buffer :: proc(state: ^core.State) {
|
setup_empty_buffer :: proc(state: ^core.State) {
|
||||||
buffer := core.new_virtual_file_buffer(context.allocator);
|
panels.open(state, panels.make_file_buffer_panel(""))
|
||||||
panels.open(state, panels.make_file_buffer_panel(len(state.buffers)))
|
|
||||||
runtime.append(&state.buffers, buffer);
|
|
||||||
|
|
||||||
core.reset_input_map(state)
|
core.reset_input_map(state)
|
||||||
}
|
}
|
||||||
|
@ -135,8 +137,12 @@ expect_cursor_index :: proc(t: ^testing.T, cursor: core.Cursor, chunk_index, cha
|
||||||
insert_from_empty_no_newlines :: proc(t: ^testing.T) {
|
insert_from_empty_no_newlines :: proc(t: ^testing.T) {
|
||||||
e := new_test_editor()
|
e := new_test_editor()
|
||||||
setup_empty_buffer(&e)
|
setup_empty_buffer(&e)
|
||||||
|
defer {
|
||||||
|
panels.close(&e, 0)
|
||||||
|
delete_editor(&e)
|
||||||
|
}
|
||||||
|
|
||||||
buffer := &e.buffers[0]
|
buffer := core.current_buffer(&e)
|
||||||
|
|
||||||
inputted_text := "Hello, world!"
|
inputted_text := "Hello, world!"
|
||||||
expected_text := fmt.aprintf("%v\n", inputted_text)
|
expected_text := fmt.aprintf("%v\n", inputted_text)
|
||||||
|
@ -146,6 +152,8 @@ insert_from_empty_no_newlines :: proc(t: ^testing.T) {
|
||||||
expect_cursor_index(t, buffer.history.cursor, 0, 12)
|
expect_cursor_index(t, buffer.history.cursor, 0, 12)
|
||||||
|
|
||||||
contents := buffer_to_string(core.current_buffer(&e))
|
contents := buffer_to_string(core.current_buffer(&e))
|
||||||
|
defer delete(contents)
|
||||||
|
|
||||||
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,8 +161,12 @@ insert_from_empty_no_newlines :: proc(t: ^testing.T) {
|
||||||
insert_from_empty_with_newline :: proc(t: ^testing.T) {
|
insert_from_empty_with_newline :: proc(t: ^testing.T) {
|
||||||
e := new_test_editor()
|
e := new_test_editor()
|
||||||
setup_empty_buffer(&e)
|
setup_empty_buffer(&e)
|
||||||
|
defer {
|
||||||
|
panels.close(&e, 0)
|
||||||
|
delete_editor(&e)
|
||||||
|
}
|
||||||
|
|
||||||
buffer := &e.buffers[0]
|
buffer := core.current_buffer(&e)
|
||||||
|
|
||||||
inputted_text := "Hello, world!\nThis is a new line"
|
inputted_text := "Hello, world!\nThis is a new line"
|
||||||
expected_text := fmt.aprintf("%v\n", inputted_text)
|
expected_text := fmt.aprintf("%v\n", inputted_text)
|
||||||
|
@ -164,6 +176,8 @@ insert_from_empty_with_newline :: proc(t: ^testing.T) {
|
||||||
expect_cursor_index(t, buffer.history.cursor, 0, 31)
|
expect_cursor_index(t, buffer.history.cursor, 0, 31)
|
||||||
|
|
||||||
contents := buffer_to_string(core.current_buffer(&e))
|
contents := buffer_to_string(core.current_buffer(&e))
|
||||||
|
defer delete(contents)
|
||||||
|
|
||||||
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,8 +185,12 @@ insert_from_empty_with_newline :: proc(t: ^testing.T) {
|
||||||
insert_in_between_text :: proc(t: ^testing.T) {
|
insert_in_between_text :: proc(t: ^testing.T) {
|
||||||
e := new_test_editor()
|
e := new_test_editor()
|
||||||
setup_empty_buffer(&e)
|
setup_empty_buffer(&e)
|
||||||
|
defer {
|
||||||
|
panels.close(&e, 0)
|
||||||
|
delete_editor(&e)
|
||||||
|
}
|
||||||
|
|
||||||
buffer := &e.buffers[0]
|
buffer := core.current_buffer(&e)
|
||||||
|
|
||||||
inputted_text := "Hello, world!"
|
inputted_text := "Hello, world!"
|
||||||
expected_text := "Hello, beautiful world!\n"
|
expected_text := "Hello, beautiful world!\n"
|
||||||
|
@ -188,6 +206,8 @@ insert_in_between_text :: proc(t: ^testing.T) {
|
||||||
expect_cursor_index(t, buffer.history.cursor, 1, 9)
|
expect_cursor_index(t, buffer.history.cursor, 1, 9)
|
||||||
|
|
||||||
contents := buffer_to_string(core.current_buffer(&e))
|
contents := buffer_to_string(core.current_buffer(&e))
|
||||||
|
defer delete(contents)
|
||||||
|
|
||||||
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,8 +215,12 @@ insert_in_between_text :: proc(t: ^testing.T) {
|
||||||
insert_before_slice_at_beginning_of_file :: proc(t: ^testing.T) {
|
insert_before_slice_at_beginning_of_file :: proc(t: ^testing.T) {
|
||||||
e := new_test_editor()
|
e := new_test_editor()
|
||||||
setup_empty_buffer(&e)
|
setup_empty_buffer(&e)
|
||||||
|
defer {
|
||||||
|
panels.close(&e, 0)
|
||||||
|
delete_editor(&e)
|
||||||
|
}
|
||||||
|
|
||||||
buffer := &e.buffers[0]
|
buffer := core.current_buffer(&e)
|
||||||
|
|
||||||
inputted_text := "Hello, world!"
|
inputted_text := "Hello, world!"
|
||||||
expected_text := "Well, Hello, beautiful world!\n"
|
expected_text := "Well, Hello, beautiful world!\n"
|
||||||
|
@ -215,6 +239,8 @@ insert_before_slice_at_beginning_of_file :: proc(t: ^testing.T) {
|
||||||
expect_cursor_index(t, buffer.history.cursor, 0, 5)
|
expect_cursor_index(t, buffer.history.cursor, 0, 5)
|
||||||
|
|
||||||
contents := buffer_to_string(core.current_buffer(&e))
|
contents := buffer_to_string(core.current_buffer(&e))
|
||||||
|
defer delete(contents)
|
||||||
|
|
||||||
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,8 +248,12 @@ insert_before_slice_at_beginning_of_file :: proc(t: ^testing.T) {
|
||||||
insert_before_slice :: proc(t: ^testing.T) {
|
insert_before_slice :: proc(t: ^testing.T) {
|
||||||
e := new_test_editor()
|
e := new_test_editor()
|
||||||
setup_empty_buffer(&e)
|
setup_empty_buffer(&e)
|
||||||
|
defer {
|
||||||
|
panels.close(&e, 0)
|
||||||
|
delete_editor(&e)
|
||||||
|
}
|
||||||
|
|
||||||
buffer := &e.buffers[0]
|
buffer := core.current_buffer(&e)
|
||||||
|
|
||||||
inputted_text := "Hello, world!"
|
inputted_text := "Hello, world!"
|
||||||
expected_text := "Hello, beautiful rich world!\n"
|
expected_text := "Hello, beautiful rich world!\n"
|
||||||
|
@ -243,6 +273,8 @@ insert_before_slice :: proc(t: ^testing.T) {
|
||||||
expect_cursor_index(t, buffer.history.cursor, 2, 4)
|
expect_cursor_index(t, buffer.history.cursor, 2, 4)
|
||||||
|
|
||||||
contents := buffer_to_string(core.current_buffer(&e))
|
contents := buffer_to_string(core.current_buffer(&e))
|
||||||
|
defer delete(contents)
|
||||||
|
|
||||||
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,8 +282,12 @@ insert_before_slice :: proc(t: ^testing.T) {
|
||||||
delete_last_content_slice_beginning_of_file :: proc(t: ^testing.T) {
|
delete_last_content_slice_beginning_of_file :: proc(t: ^testing.T) {
|
||||||
e := new_test_editor()
|
e := new_test_editor()
|
||||||
setup_empty_buffer(&e)
|
setup_empty_buffer(&e)
|
||||||
|
defer {
|
||||||
|
panels.close(&e, 0)
|
||||||
|
delete_editor(&e)
|
||||||
|
}
|
||||||
|
|
||||||
buffer := &e.buffers[0]
|
buffer := core.current_buffer(&e)
|
||||||
|
|
||||||
run_text_insertion(&e, "Hello, world!")
|
run_text_insertion(&e, "Hello, world!")
|
||||||
|
|
||||||
|
@ -283,8 +319,12 @@ delete_last_content_slice_beginning_of_file :: proc(t: ^testing.T) {
|
||||||
delete_in_slice :: proc(t: ^testing.T) {
|
delete_in_slice :: proc(t: ^testing.T) {
|
||||||
e := new_test_editor()
|
e := new_test_editor()
|
||||||
setup_empty_buffer(&e)
|
setup_empty_buffer(&e)
|
||||||
|
defer {
|
||||||
|
panels.close(&e, 0)
|
||||||
|
delete_editor(&e)
|
||||||
|
}
|
||||||
|
|
||||||
buffer := &e.buffers[0]
|
buffer := core.current_buffer(&e)
|
||||||
|
|
||||||
inputted_text := "Hello, world!"
|
inputted_text := "Hello, world!"
|
||||||
expected_text := "Hello, beautiful h world!\n"
|
expected_text := "Hello, beautiful h world!\n"
|
||||||
|
@ -310,6 +350,8 @@ delete_in_slice :: proc(t: ^testing.T) {
|
||||||
expect_cursor_index(t, buffer.history.cursor, 3, 0)
|
expect_cursor_index(t, buffer.history.cursor, 3, 0)
|
||||||
|
|
||||||
contents := buffer_to_string(core.current_buffer(&e))
|
contents := buffer_to_string(core.current_buffer(&e))
|
||||||
|
defer delete(contents)
|
||||||
|
|
||||||
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,8 +359,12 @@ delete_in_slice :: proc(t: ^testing.T) {
|
||||||
delete_across_slices :: proc(t: ^testing.T) {
|
delete_across_slices :: proc(t: ^testing.T) {
|
||||||
e := new_test_editor()
|
e := new_test_editor()
|
||||||
setup_empty_buffer(&e)
|
setup_empty_buffer(&e)
|
||||||
|
defer {
|
||||||
|
panels.close(&e, 0)
|
||||||
|
delete_editor(&e)
|
||||||
|
}
|
||||||
|
|
||||||
buffer := &e.buffers[0]
|
buffer := core.current_buffer(&e)
|
||||||
|
|
||||||
inputted_text := "Hello, world!"
|
inputted_text := "Hello, world!"
|
||||||
expected_text := "Hello, beautiful world!\n"
|
expected_text := "Hello, beautiful world!\n"
|
||||||
|
@ -352,6 +398,8 @@ delete_across_slices :: proc(t: ^testing.T) {
|
||||||
expect_cursor_index(t, buffer.history.cursor, 2, 0)
|
expect_cursor_index(t, buffer.history.cursor, 2, 0)
|
||||||
|
|
||||||
contents := buffer_to_string(core.current_buffer(&e))
|
contents := buffer_to_string(core.current_buffer(&e))
|
||||||
|
defer delete(contents)
|
||||||
|
|
||||||
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,10 +407,14 @@ delete_across_slices :: proc(t: ^testing.T) {
|
||||||
move_down_next_line_has_shorter_length :: proc(t: ^testing.T) {
|
move_down_next_line_has_shorter_length :: proc(t: ^testing.T) {
|
||||||
e := new_test_editor()
|
e := new_test_editor()
|
||||||
setup_empty_buffer(&e)
|
setup_empty_buffer(&e)
|
||||||
|
defer {
|
||||||
|
panels.close(&e, 0)
|
||||||
|
delete_editor(&e)
|
||||||
|
}
|
||||||
|
|
||||||
is_ctrl_pressed := false
|
is_ctrl_pressed := false
|
||||||
|
|
||||||
buffer := &e.buffers[0]
|
buffer := core.current_buffer(&e)
|
||||||
|
|
||||||
run_text_insertion(&e, "012345678\n0")
|
run_text_insertion(&e, "012345678\n0")
|
||||||
|
|
||||||
|
@ -383,10 +435,14 @@ move_down_next_line_has_shorter_length :: proc(t: ^testing.T) {
|
||||||
move_down_on_last_line :: proc(t: ^testing.T) {
|
move_down_on_last_line :: proc(t: ^testing.T) {
|
||||||
e := new_test_editor()
|
e := new_test_editor()
|
||||||
setup_empty_buffer(&e)
|
setup_empty_buffer(&e)
|
||||||
|
defer {
|
||||||
|
panels.close(&e, 0)
|
||||||
|
delete_editor(&e)
|
||||||
|
}
|
||||||
|
|
||||||
is_ctrl_pressed := false
|
is_ctrl_pressed := false
|
||||||
|
|
||||||
buffer := &e.buffers[0]
|
buffer := core.current_buffer(&e)
|
||||||
|
|
||||||
run_text_insertion(&e, "012345678")
|
run_text_insertion(&e, "012345678")
|
||||||
|
|
||||||
|
@ -402,8 +458,12 @@ move_down_on_last_line :: proc(t: ^testing.T) {
|
||||||
move_left_at_beginning_of_file :: proc(t: ^testing.T) {
|
move_left_at_beginning_of_file :: proc(t: ^testing.T) {
|
||||||
e := new_test_editor()
|
e := new_test_editor()
|
||||||
setup_empty_buffer(&e)
|
setup_empty_buffer(&e)
|
||||||
|
defer {
|
||||||
|
panels.close(&e, 0)
|
||||||
|
delete_editor(&e)
|
||||||
|
}
|
||||||
|
|
||||||
buffer := &e.buffers[0]
|
buffer := core.current_buffer(&e)
|
||||||
|
|
||||||
run_text_insertion(&e, "01234")
|
run_text_insertion(&e, "01234")
|
||||||
// Move cursor from --------^
|
// Move cursor from --------^
|
||||||
|
@ -425,10 +485,14 @@ move_left_at_beginning_of_file :: proc(t: ^testing.T) {
|
||||||
move_right_at_end_of_file :: proc(t: ^testing.T) {
|
move_right_at_end_of_file :: proc(t: ^testing.T) {
|
||||||
e := new_test_editor()
|
e := new_test_editor()
|
||||||
setup_empty_buffer(&e)
|
setup_empty_buffer(&e)
|
||||||
|
defer {
|
||||||
|
panels.close(&e, 0)
|
||||||
|
delete_editor(&e)
|
||||||
|
}
|
||||||
|
|
||||||
is_ctrl_pressed := false
|
is_ctrl_pressed := false
|
||||||
|
|
||||||
buffer := &e.buffers[0]
|
buffer := core.current_buffer(&e)
|
||||||
|
|
||||||
run_text_insertion(&e, "01234")
|
run_text_insertion(&e, "01234")
|
||||||
|
|
||||||
|
@ -447,10 +511,14 @@ move_right_at_end_of_file :: proc(t: ^testing.T) {
|
||||||
move_to_end_of_line_from_end :: proc(t: ^testing.T) {
|
move_to_end_of_line_from_end :: proc(t: ^testing.T) {
|
||||||
e := new_test_editor()
|
e := new_test_editor()
|
||||||
setup_empty_buffer(&e)
|
setup_empty_buffer(&e)
|
||||||
|
defer {
|
||||||
|
panels.close(&e, 0)
|
||||||
|
delete_editor(&e)
|
||||||
|
}
|
||||||
|
|
||||||
is_ctrl_pressed := false
|
is_ctrl_pressed := false
|
||||||
|
|
||||||
buffer := &e.buffers[0]
|
buffer := core.current_buffer(&e)
|
||||||
|
|
||||||
run_text_insertion(&e, "01234\n01234")
|
run_text_insertion(&e, "01234\n01234")
|
||||||
|
|
||||||
|
@ -468,10 +536,14 @@ move_to_end_of_line_from_end :: proc(t: ^testing.T) {
|
||||||
move_to_end_of_line_from_middle :: proc(t: ^testing.T) {
|
move_to_end_of_line_from_middle :: proc(t: ^testing.T) {
|
||||||
e := new_test_editor()
|
e := new_test_editor()
|
||||||
setup_empty_buffer(&e)
|
setup_empty_buffer(&e)
|
||||||
|
defer {
|
||||||
|
panels.close(&e, 0)
|
||||||
|
delete_editor(&e)
|
||||||
|
}
|
||||||
|
|
||||||
is_ctrl_pressed := false
|
is_ctrl_pressed := false
|
||||||
|
|
||||||
buffer := &e.buffers[0]
|
buffer := core.current_buffer(&e)
|
||||||
|
|
||||||
run_text_insertion(&e, "01234\n01234")
|
run_text_insertion(&e, "01234\n01234")
|
||||||
|
|
||||||
|
@ -492,10 +564,14 @@ move_to_end_of_line_from_middle :: proc(t: ^testing.T) {
|
||||||
move_to_beginning_of_line_from_middle :: proc(t: ^testing.T) {
|
move_to_beginning_of_line_from_middle :: proc(t: ^testing.T) {
|
||||||
e := new_test_editor()
|
e := new_test_editor()
|
||||||
setup_empty_buffer(&e)
|
setup_empty_buffer(&e)
|
||||||
|
defer {
|
||||||
|
panels.close(&e, 0)
|
||||||
|
delete_editor(&e)
|
||||||
|
}
|
||||||
|
|
||||||
is_ctrl_pressed := false
|
is_ctrl_pressed := false
|
||||||
|
|
||||||
buffer := &e.buffers[0]
|
buffer := core.current_buffer(&e)
|
||||||
|
|
||||||
run_text_insertion(&e, "01234\n01234")
|
run_text_insertion(&e, "01234\n01234")
|
||||||
|
|
||||||
|
@ -516,10 +592,14 @@ move_to_beginning_of_line_from_middle :: proc(t: ^testing.T) {
|
||||||
move_to_beginning_of_line_from_start :: proc(t: ^testing.T) {
|
move_to_beginning_of_line_from_start :: proc(t: ^testing.T) {
|
||||||
e := new_test_editor()
|
e := new_test_editor()
|
||||||
setup_empty_buffer(&e)
|
setup_empty_buffer(&e)
|
||||||
|
defer {
|
||||||
|
panels.close(&e, 0)
|
||||||
|
delete_editor(&e)
|
||||||
|
}
|
||||||
|
|
||||||
is_ctrl_pressed := false
|
is_ctrl_pressed := false
|
||||||
|
|
||||||
buffer := &e.buffers[0]
|
buffer := core.current_buffer(&e)
|
||||||
|
|
||||||
run_text_insertion(&e, "01234\n01234")
|
run_text_insertion(&e, "01234\n01234")
|
||||||
|
|
||||||
|
@ -540,8 +620,12 @@ move_to_beginning_of_line_from_start :: proc(t: ^testing.T) {
|
||||||
append_end_of_line :: proc(t: ^testing.T) {
|
append_end_of_line :: proc(t: ^testing.T) {
|
||||||
e := new_test_editor()
|
e := new_test_editor()
|
||||||
setup_empty_buffer(&e)
|
setup_empty_buffer(&e)
|
||||||
|
defer {
|
||||||
|
panels.close(&e, 0)
|
||||||
|
delete_editor(&e)
|
||||||
|
}
|
||||||
|
|
||||||
buffer := &e.buffers[0]
|
buffer := core.current_buffer(&e)
|
||||||
|
|
||||||
run_text_insertion(&e, "hello")
|
run_text_insertion(&e, "hello")
|
||||||
|
|
||||||
|
@ -562,8 +646,12 @@ append_end_of_line :: proc(t: ^testing.T) {
|
||||||
insert_line_under_current :: proc(t: ^testing.T) {
|
insert_line_under_current :: proc(t: ^testing.T) {
|
||||||
e := new_test_editor()
|
e := new_test_editor()
|
||||||
setup_empty_buffer(&e)
|
setup_empty_buffer(&e)
|
||||||
|
defer {
|
||||||
|
panels.close(&e, 0)
|
||||||
|
delete_editor(&e)
|
||||||
|
}
|
||||||
|
|
||||||
buffer := &e.buffers[0]
|
buffer := core.current_buffer(&e)
|
||||||
|
|
||||||
initial_text := "Hello, world!\nThis is a new line"
|
initial_text := "Hello, world!\nThis is a new line"
|
||||||
run_text_insertion(&e, initial_text)
|
run_text_insertion(&e, initial_text)
|
||||||
|
@ -590,6 +678,8 @@ insert_line_under_current :: proc(t: ^testing.T) {
|
||||||
expect_cursor_index(t, buffer.history.cursor, 1, 23)
|
expect_cursor_index(t, buffer.history.cursor, 1, 23)
|
||||||
|
|
||||||
contents := buffer_to_string(core.current_buffer(&e))
|
contents := buffer_to_string(core.current_buffer(&e))
|
||||||
|
defer delete(contents)
|
||||||
|
|
||||||
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -597,8 +687,12 @@ insert_line_under_current :: proc(t: ^testing.T) {
|
||||||
yank_and_paste_whole_line :: proc(t: ^testing.T) {
|
yank_and_paste_whole_line :: proc(t: ^testing.T) {
|
||||||
e := new_test_editor()
|
e := new_test_editor()
|
||||||
setup_empty_buffer(&e)
|
setup_empty_buffer(&e)
|
||||||
|
defer {
|
||||||
|
panels.close(&e, 0)
|
||||||
|
delete_editor(&e)
|
||||||
|
}
|
||||||
|
|
||||||
buffer := &e.buffers[0]
|
buffer := core.current_buffer(&e)
|
||||||
|
|
||||||
initial_text := "Hello, world!\nThis is a new line"
|
initial_text := "Hello, world!\nThis is a new line"
|
||||||
run_text_insertion(&e, initial_text)
|
run_text_insertion(&e, initial_text)
|
||||||
|
@ -617,22 +711,22 @@ yank_and_paste_whole_line :: proc(t: ^testing.T) {
|
||||||
expect_line_col(t, buffer.history.cursor, 1, 0)
|
expect_line_col(t, buffer.history.cursor, 1, 0)
|
||||||
|
|
||||||
contents := buffer_to_string(core.current_buffer(&e))
|
contents := buffer_to_string(core.current_buffer(&e))
|
||||||
|
defer delete(contents)
|
||||||
|
|
||||||
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
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_editor_frame :: proc(state: ^core.State, input: ArtificialInput, is_ctrl_pressed: ^bool) {
|
||||||
log.infof("running input: %v", input)
|
|
||||||
|
|
||||||
{
|
{
|
||||||
run_key_action := proc(state: ^core.State, control_key_pressed: bool, key: core.Key) -> bool {
|
run_key_action := proc(state: ^core.State, control_key_pressed: bool, key: core.Key) -> bool {
|
||||||
log.info("key_action")
|
if current_panel, ok := state.current_panel.?; ok {
|
||||||
|
panel := util.get(&state.panels, current_panel).?
|
||||||
|
|
||||||
if state.current_input_map != nil {
|
|
||||||
if control_key_pressed {
|
if control_key_pressed {
|
||||||
if action, exists := state.current_input_map.ctrl_key_actions[key]; exists {
|
if action, exists := state.current_input_map.ctrl_key_actions[key]; exists {
|
||||||
switch value in action.action {
|
switch value in action.action {
|
||||||
case core.EditorAction:
|
case core.EditorAction:
|
||||||
value(state);
|
value(state, panel);
|
||||||
return true;
|
return true;
|
||||||
case core.InputActions:
|
case core.InputActions:
|
||||||
state.current_input_map = &(&state.current_input_map.ctrl_key_actions[key]).action.(core.InputActions)
|
state.current_input_map = &(&state.current_input_map.ctrl_key_actions[key]).action.(core.InputActions)
|
||||||
|
@ -643,7 +737,7 @@ run_editor_frame :: proc(state: ^core.State, input: ArtificialInput, is_ctrl_pre
|
||||||
if action, exists := state.current_input_map.key_actions[key]; exists {
|
if action, exists := state.current_input_map.key_actions[key]; exists {
|
||||||
switch value in action.action {
|
switch value in action.action {
|
||||||
case core.EditorAction:
|
case core.EditorAction:
|
||||||
value(state);
|
value(state, panel);
|
||||||
return true;
|
return true;
|
||||||
case core.InputActions:
|
case core.InputActions:
|
||||||
state.current_input_map = &(&state.current_input_map.key_actions[key]).action.(core.InputActions)
|
state.current_input_map = &(&state.current_input_map.key_actions[key]).action.(core.InputActions)
|
||||||
|
@ -651,8 +745,6 @@ run_editor_frame :: proc(state: ^core.State, input: ArtificialInput, is_ctrl_pre
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
log.info("current_input_map is null")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
@ -661,8 +753,6 @@ run_editor_frame :: proc(state: ^core.State, input: ArtificialInput, is_ctrl_pre
|
||||||
switch state.mode {
|
switch state.mode {
|
||||||
case .Visual: fallthrough
|
case .Visual: fallthrough
|
||||||
case .Normal: {
|
case .Normal: {
|
||||||
log.info("it's normal/visual mode")
|
|
||||||
|
|
||||||
if key, ok := input.(ArtificialKey); ok {
|
if key, ok := input.(ArtificialKey); ok {
|
||||||
if key.is_down {
|
if key.is_down {
|
||||||
if key.key == .LCTRL {
|
if key.key == .LCTRL {
|
||||||
|
@ -678,8 +768,6 @@ run_editor_frame :: proc(state: ^core.State, input: ArtificialInput, is_ctrl_pre
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case .Insert: {
|
case .Insert: {
|
||||||
log.info("it's insert mode")
|
|
||||||
|
|
||||||
buffer := core.current_buffer(state);
|
buffer := core.current_buffer(state);
|
||||||
|
|
||||||
if key, ok := input.(ArtificialKey); ok {
|
if key, ok := input.(ArtificialKey); ok {
|
||||||
|
@ -710,24 +798,20 @@ run_editor_frame :: proc(state: ^core.State, input: ArtificialInput, is_ctrl_pre
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("before text input")
|
|
||||||
if text_input, ok := input.(ArtificialTextInput); ok {
|
if text_input, ok := input.(ArtificialTextInput); ok {
|
||||||
log.infof("attempting to append '%v' to buffer", text_input)
|
|
||||||
|
|
||||||
for char in text_input.text {
|
for char in text_input.text {
|
||||||
if char < 1 {
|
if char < 1 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if char == '\n' || (char >= 32 && char <= 125 && len(buffer.input_buffer) < 1024-1) {
|
if char == '\n' || (char >= 32 && char <= 125 && len(buffer.input_buffer) < 1024-1) {
|
||||||
log.infof("appening '%v' to buffer", char)
|
|
||||||
append(&buffer.input_buffer, u8(char));
|
append(&buffer.input_buffer, u8(char));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if current_panel, ok := state.current_panel.?; ok {
|
if current_panel, ok := state.current_panel.?; ok {
|
||||||
if panel, ok := util.get(&state.panels, current_panel).?; ok && panel.on_buffer_input_proc != nil {
|
if panel, ok := util.get(&state.panels, current_panel).?; ok && panel.on_buffer_input != nil {
|
||||||
panel.on_buffer_input_proc(state, &panel.panel_state)
|
panel->on_buffer_input(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -230,6 +230,10 @@ delete_state :: proc(state: ^State) {
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_buffer :: proc(state: ^State, input: Input) {
|
parse_buffer :: proc(state: ^State, input: Input) {
|
||||||
|
if state.parser == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
old_tree := state.tree
|
old_tree := state.tree
|
||||||
if old_tree != nil {
|
if old_tree != nil {
|
||||||
defer tree_delete(old_tree)
|
defer tree_delete(old_tree)
|
||||||
|
|
|
@ -11,7 +11,7 @@ StaticListSlot :: struct($T: typeid) {
|
||||||
data: T,
|
data: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
append_static_list :: proc(list: ^StaticList($T), value: T) -> (id: int, panel: ^T, ok: bool) {
|
append_static_list :: proc(list: ^StaticList($T), value: T) -> (id: int, item: ^T, ok: bool) {
|
||||||
for i in 0..<len(list.data) {
|
for i in 0..<len(list.data) {
|
||||||
if !list.data[i].active {
|
if !list.data[i].active {
|
||||||
list.data[i].active = true
|
list.data[i].active = true
|
||||||
|
@ -89,4 +89,8 @@ delete_static_list_elem :: proc(list: ^StaticList($T), index: int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delete :: proc{delete_static_list_elem}
|
delete_static_list :: proc(list: ^StaticList($T)) {
|
||||||
|
runtime.delete(list.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
delete :: proc{delete_static_list_elem, delete_static_list}
|
3
todo.md
3
todo.md
|
@ -1,5 +1,4 @@
|
||||||
# Bugs
|
# Bugs
|
||||||
- Memory Leak
|
|
||||||
- Fix jumping forward a word jumping past consecutive brackets
|
- Fix jumping forward a word jumping past consecutive brackets
|
||||||
- Odd scrolling behavior on small screen heights
|
- Odd scrolling behavior on small screen heights
|
||||||
- Scrolling past end/beginning of results panics
|
- Scrolling past end/beginning of results panics
|
||||||
|
@ -9,7 +8,7 @@
|
||||||
|
|
||||||
# Planned Features
|
# Planned Features
|
||||||
- [ ] Jump List
|
- [ ] Jump List
|
||||||
- Use grouped lifetimes exclusively for memory allocation/freeing
|
- [x] Use grouped lifetimes exclusively for memory allocation/freeing
|
||||||
- [ ] Highlight which panel is currently active
|
- [ ] Highlight which panel is currently active
|
||||||
- [ ] Persist end of line cursor position
|
- [ ] Persist end of line cursor position
|
||||||
- Testing Harness
|
- Testing Harness
|
||||||
|
|
Loading…
Reference in New Issue