From e412dbe7a2be737a245b4e3b250a757e4c3be76f Mon Sep 17 00:00:00 2001 From: Patrick Cleaveliln Date: Fri, 18 Jul 2025 05:05:40 +0000 Subject: [PATCH] remove global file buffer array --- src/core/core.odin | 103 +++++--------- src/core/file_buffer.odin | 82 +++++------ src/core/glyph_buffer.odin | 6 +- src/input/input.odin | 272 +++++++++++++++++++++++-------------- src/main.odin | 126 ++++++----------- src/panels/panels.odin | 141 +++++++++---------- 6 files changed, 351 insertions(+), 379 deletions(-) diff --git a/src/core/core.odin b/src/core/core.odin index 7e5de5b..11b302f 100644 --- a/src/core/core.odin +++ b/src/core/core.odin @@ -38,9 +38,6 @@ State :: struct { source_font_height: int, line_number_padding: int, - current_buffer: int, - buffers: [dynamic]FileBuffer, - // TODO: make more than one register to plop stuff into yank_register: Register, @@ -117,81 +114,55 @@ GrepQueryResult :: struct { col: int, } -current_buffer :: proc(state: ^State) -> ^FileBuffer { - if current_panel, ok := util.get(&state.panels, state.current_panel.? or_else -1).?; ok { - if current_panel.buffer_proc != nil { - if panel_buffer, ok := current_panel.buffer_proc(state, ¤t_panel.panel_state); ok && panel_buffer != nil { - return panel_buffer - } - } - } - - if state.current_buffer == -2 { - return &state.log_buffer; - } - - if len(state.buffers) < 1 { - return nil - } - - return &state.buffers[state.current_buffer]; -} - -yank_whole_line :: proc(state: ^State) { +yank_whole_line :: proc(state: ^State, buffer: ^FileBuffer) { if state.yank_register.data != nil { delete(state.yank_register.data) state.yank_register.data = nil } - if buffer := current_buffer(state); buffer != nil { - selection := new_selection(buffer, buffer.history.cursor) - length := selection_length(buffer, selection) + selection := new_selection(buffer, buffer.history.cursor) + length := selection_length(buffer, selection) - state.yank_register.whole_line = true - state.yank_register.data = make([]u8, length) + state.yank_register.whole_line = true + state.yank_register.data = make([]u8, length) - it := new_file_buffer_iter_with_cursor(buffer, selection.start) + it := new_file_buffer_iter_with_cursor(buffer, selection.start) - index := 0 - for !it.hit_end && index < length { - state.yank_register.data[index] = get_character_at_iter(it) + index := 0 + for !it.hit_end && index < length { + state.yank_register.data[index] = get_character_at_iter(it) - iterate_file_buffer(&it) - index += 1 - } + iterate_file_buffer(&it) + index += 1 } } -yank_selection :: proc(state: ^State) { +yank_selection :: proc(state: ^State, buffer: ^FileBuffer) { if state.yank_register.data != nil { delete(state.yank_register.data) state.yank_register.data = nil } - if buffer := current_buffer(state); buffer != nil && buffer.selection != nil { - selection := swap_selections(buffer.selection.?) - length := selection_length(buffer, selection) + selection := swap_selections(buffer.selection.?) + length := selection_length(buffer, selection) - state.yank_register.whole_line = false - state.yank_register.data = make([]u8, length) + state.yank_register.whole_line = false + state.yank_register.data = make([]u8, length) - it := new_file_buffer_iter_with_cursor(buffer, selection.start) + it := new_file_buffer_iter_with_cursor(buffer, selection.start) - index := 0 - for !it.hit_end && index < length { - state.yank_register.data[index] = get_character_at_iter(it) + index := 0 + for !it.hit_end && index < length { + state.yank_register.data[index] = get_character_at_iter(it) - iterate_file_buffer(&it) - index += 1 - } + iterate_file_buffer(&it) + index += 1 } } -paste_register :: proc(state: ^State, register: Register) { - if buffer := current_buffer(state); buffer != nil && register.data != nil { - insert_content(buffer, register.data) - move_cursor_left(buffer) - } +paste_register :: proc(state: ^State, register: Register, buffer: ^FileBuffer) { + insert_content(buffer, register.data) + move_cursor_left(buffer) } reset_input_map_from_state_mode :: proc(state: ^State) { @@ -204,27 +175,20 @@ reset_input_map_from_mode :: proc(state: ^State, mode: Mode) { } reset_input_map :: proc{reset_input_map_from_mode, reset_input_map_from_state_mode} -buffer_from_index :: proc(state: ^State, buffer_index: int) -> ^FileBuffer { - if buffer_index == -2 { - return &state.log_buffer; - } - - return &state.buffers[buffer_index]; -} - -EditorAction :: proc(state: ^State); -InputGroup :: union {EditorAction, InputActions} -Action :: struct { - action: InputGroup, - description: string, -} InputMap :: struct { mode: map[Mode]InputActions, } + +InputGroup :: union {EditorAction, InputActions} +EditorAction :: proc(state: ^State, user_data: rawptr); InputActions :: struct { key_actions: map[Key]Action, ctrl_key_actions: map[Key]Action, } +Action :: struct { + action: InputGroup, + description: string, +} new_input_map :: proc() -> InputMap { input_map := InputMap { @@ -377,7 +341,8 @@ run_command :: proc(state: ^State, group: string, name: string) { for cmd in cmds { if cmd.name == name { log.info("Running command", group, name); - cmd.action(state); + // TODO: rework command system + // cmd.action(state); return; } } diff --git a/src/core/file_buffer.odin b/src/core/file_buffer.odin index c79df99..55b2a7e 100644 --- a/src/core/file_buffer.odin +++ b/src/core/file_buffer.odin @@ -776,18 +776,6 @@ save_buffer_to_disk :: proc(state: ^State, buffer: ^FileBuffer) -> (error: os.Er return } -next_buffer :: proc(state: ^State, prev_buffer: ^int) -> int { - index := prev_buffer^; - - if prev_buffer^ >= len(state.buffers)-1 { - prev_buffer^ = -1; - } else { - prev_buffer^ += 1; - } - - return index; -} - // TODO: replace this with arena for the file buffer free_file_buffer :: proc(buffer: ^FileBuffer) { ts.delete_state(&buffer.tree) @@ -831,10 +819,11 @@ color_character :: proc(buffer: ^FileBuffer, start: Cursor, end: Cursor, palette } } -draw_file_buffer :: proc(state: ^State, buffer: ^FileBuffer, x: int, y: int, show_line_numbers: bool = true) { - update_glyph_buffer(buffer); +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_height := math.min(256, int((h - state.source_font_height*2) / state.source_font_height)) + 1; - // TODO: syntax highlighting + update_glyph_buffer(buffer, glyph_width, glyph_height); padding := 0; if show_line_numbers { @@ -848,43 +837,44 @@ draw_file_buffer :: proc(state: ^State, buffer: ^FileBuffer, x: int, y: int, sho cursor_y -= begin * state.source_font_height; // draw cursor - if state.mode == .Normal || current_buffer(state) != buffer { - draw_rect(state, cursor_x, cursor_y, state.source_font_width, state.source_font_height, .Background4); - } else if state.mode == .Visual { - 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; + if show_cursor { + if state.mode == .Normal { + draw_rect(state, cursor_x, cursor_y, state.source_font_width, state.source_font_height, .Background4); + } else if state.mode == .Visual { + 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; - end_sel_x := x + padding + buffer.selection.?.end.col * state.source_font_width; - end_sel_y := y + buffer.selection.?.end.line * state.source_font_height; + end_sel_x := x + padding + buffer.selection.?.end.col * state.source_font_width; + end_sel_y := y + buffer.selection.?.end.line * state.source_font_height; - start_sel_y -= begin * state.source_font_height; - end_sel_y -= begin * state.source_font_height; + start_sel_y -= begin * state.source_font_height; + end_sel_y -= begin * state.source_font_height; - draw_rect(state, start_sel_x, start_sel_y, state.source_font_width, state.source_font_height, .Green); - draw_rect(state, end_sel_x, end_sel_y, state.source_font_width, state.source_font_height, .Blue); - } - else if state.mode == .Insert { - draw_rect(state, cursor_x, cursor_y, state.source_font_width, state.source_font_height, .Green); + draw_rect(state, start_sel_x, start_sel_y, state.source_font_width, state.source_font_height, .Green); + draw_rect(state, end_sel_x, end_sel_y, state.source_font_width, state.source_font_height, .Blue); + } else if state.mode == .Insert { + draw_rect(state, cursor_x, cursor_y, state.source_font_width, state.source_font_height, .Green); - num_line_break := 0; - line_length := 0; - for c in buffer.input_buffer { - if c == '\n' { - num_line_break += 1; - line_length = 0; - } else { - line_length += 1; + num_line_break := 0; + line_length := 0; + for c in buffer.input_buffer { + if c == '\n' { + num_line_break += 1; + line_length = 0; + } else { + line_length += 1; + } } - } - if num_line_break > 0 { - cursor_x = x + padding + line_length * state.source_font_width; - cursor_y = cursor_y + num_line_break * state.source_font_height; - } else { - cursor_x += line_length * state.source_font_width; - } + if num_line_break > 0 { + cursor_x = x + padding + line_length * state.source_font_width; + cursor_y = cursor_y + num_line_break * state.source_font_height; + } else { + cursor_x += line_length * state.source_font_width; + } - draw_rect(state, cursor_x, cursor_y, state.source_font_width, state.source_font_height, .Blue); + draw_rect(state, cursor_x, cursor_y, state.source_font_width, state.source_font_height, .Blue); + } } // TODO: replace with glyph_buffer.draw_glyph_buffer @@ -908,7 +898,7 @@ draw_file_buffer :: proc(state: ^State, buffer: ^FileBuffer, x: int, y: int, sho // NOTE: this requires transparent background color because it renders after the text // and its after the text because the line length needs to be calculated - if state.mode == .Visual && current_buffer(state) == buffer { + if state.mode == .Visual && buffer.selection != nil { selection := swap_selections(buffer.selection.?) // selection := buffer.selection.? diff --git a/src/core/glyph_buffer.odin b/src/core/glyph_buffer.odin index aae2d71..0e43132 100644 --- a/src/core/glyph_buffer.odin +++ b/src/core/glyph_buffer.odin @@ -26,7 +26,11 @@ make_glyph_buffer :: proc(width, height: int, allocator := context.allocator) -> } } -update_glyph_buffer_from_file_buffer :: proc(buffer: ^FileBuffer) { +update_glyph_buffer_from_file_buffer :: proc(buffer: ^FileBuffer, width, height: int) { + // TODO: limit to 256 + buffer.glyphs.width = width + buffer.glyphs.height = height + for &glyph in buffer.glyphs.buffer { glyph = Glyph {} glyph.color = .Foreground diff --git a/src/input/input.odin b/src/input/input.odin index a928105..fef54f9 100644 --- a/src/input/input.odin +++ b/src/input/input.odin @@ -11,12 +11,16 @@ import "../util" State :: core.State register_default_go_actions :: proc(input_map: ^core.InputActions) { - core.register_key_action(input_map, .H, proc(state: ^State) { - core.move_cursor_start_of_line(core.current_buffer(state)); + core.register_key_action(input_map, .H, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data + + core.move_cursor_start_of_line(buffer); core.reset_input_map(state) }, "move to beginning of line"); - core.register_key_action(input_map, .L, proc(state: ^State) { - core.move_cursor_end_of_line(core.current_buffer(state)); + core.register_key_action(input_map, .L, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data + + core.move_cursor_end_of_line(buffer); core.reset_input_map(state) }, "move to end of line"); } @@ -24,41 +28,59 @@ register_default_go_actions :: proc(input_map: ^core.InputActions) { register_default_input_actions :: proc(input_map: ^core.InputActions) { // Cursor Movement { - core.register_key_action(input_map, .W, proc(state: ^State) { - core.move_cursor_forward_start_of_word(core.current_buffer(state)); + core.register_key_action(input_map, .W, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data + + core.move_cursor_forward_start_of_word(buffer); }, "move forward one word"); - core.register_key_action(input_map, .E, proc(state: ^State) { - core.move_cursor_forward_end_of_word(core.current_buffer(state)); + core.register_key_action(input_map, .E, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data + + core.move_cursor_forward_end_of_word(buffer); }, "move forward to end of word"); - core.register_key_action(input_map, .B, proc(state: ^State) { - core.move_cursor_backward_start_of_word(core.current_buffer(state)); + core.register_key_action(input_map, .B, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data + + core.move_cursor_backward_start_of_word(buffer); }, "move backward one word"); - core.register_key_action(input_map, .K, proc(state: ^State) { - core.move_cursor_up(core.current_buffer(state)); + core.register_key_action(input_map, .K, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data + + core.move_cursor_up(buffer); }, "move up one line"); - core.register_key_action(input_map, .J, proc(state: ^State) { - core.move_cursor_down(core.current_buffer(state)); + core.register_key_action(input_map, .J, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data + + core.move_cursor_down(buffer); }, "move down one line"); - core.register_key_action(input_map, .H, proc(state: ^State) { - core.move_cursor_left(core.current_buffer(state)); + core.register_key_action(input_map, .H, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data + + core.move_cursor_left(buffer); }, "move left one char"); - core.register_key_action(input_map, .L, proc(state: ^State) { - core.move_cursor_right(core.current_buffer(state)); + core.register_key_action(input_map, .L, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data + + core.move_cursor_right(buffer); }, "move right one char"); - core.register_ctrl_key_action(input_map, .U, proc(state: ^State) { - core.scroll_file_buffer(core.current_buffer(state), .Up); + core.register_ctrl_key_action(input_map, .U, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data + + core.scroll_file_buffer(buffer, .Up); }, "scroll buffer up"); - core.register_ctrl_key_action(input_map, .D, proc(state: ^State) { - core.scroll_file_buffer(core.current_buffer(state), .Down); + core.register_ctrl_key_action(input_map, .D, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data + + core.scroll_file_buffer(buffer, .Down); }, "scroll buffer up"); } // Scale font size { - core.register_ctrl_key_action(input_map, .MINUS, proc(state: ^State) { + core.register_ctrl_key_action(input_map, .MINUS, proc(state: ^State, user_data: rawptr) { if state.source_font_height > 16 { state.source_font_height -= 2; state.source_font_width = state.source_font_height / 2; @@ -67,7 +89,7 @@ register_default_input_actions :: proc(input_map: ^core.InputActions) { } log.debug(state.source_font_height); }, "increase font size"); - core.register_ctrl_key_action(input_map, .EQUAL, proc(state: ^State) { + core.register_ctrl_key_action(input_map, .EQUAL, proc(state: ^State, user_data: rawptr) { state.source_font_height += 2; state.source_font_width = state.source_font_height / 2; @@ -76,8 +98,10 @@ register_default_input_actions :: proc(input_map: ^core.InputActions) { } // Save file - core.register_ctrl_key_action(input_map, .S, proc(state: ^State) { - if err := core.save_buffer_to_disk(state, core.current_buffer(state)); err != nil { + core.register_ctrl_key_action(input_map, .S, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data + + if err := core.save_buffer_to_disk(state, buffer); err != nil { log.errorf("failed to save buffer to disk: %v", err) } }, "Save file") @@ -85,99 +109,125 @@ register_default_input_actions :: proc(input_map: ^core.InputActions) { core.register_key_action(input_map, .G, core.new_input_actions(), "Go commands"); register_default_go_actions(&(&input_map.key_actions[.G]).action.(core.InputActions)); - core.register_key_action(input_map, .V, proc(state: ^State) { + core.register_key_action(input_map, .V, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data + state.mode = .Visual; core.reset_input_map(state) - core.current_buffer(state).selection = core.new_selection(core.current_buffer(state).history.cursor); + buffer.selection = core.new_selection(buffer.history.cursor); }, "enter visual mode"); } register_default_visual_actions :: proc(input_map: ^core.InputActions) { - core.register_key_action(input_map, .ESCAPE, proc(state: ^State) { + core.register_key_action(input_map, .ESCAPE, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data + state.mode = .Normal; core.reset_input_map(state) - core.current_buffer(state).selection = nil; - core.update_file_buffer_scroll(core.current_buffer(state)) + buffer.selection = nil; + core.update_file_buffer_scroll(buffer) }, "exit visual mode"); // Cursor Movement { - core.register_key_action(input_map, .W, proc(state: ^State) { - sel_cur := &(core.current_buffer(state).selection.?); + core.register_key_action(input_map, .W, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data - core.move_cursor_forward_start_of_word(core.current_buffer(state), cursor = &sel_cur.end); + sel_cur := &(buffer.selection.?); + + core.move_cursor_forward_start_of_word(buffer, cursor = &sel_cur.end); }, "move forward one word"); - core.register_key_action(input_map, .E, proc(state: ^State) { - sel_cur := &(core.current_buffer(state).selection.?); + core.register_key_action(input_map, .E, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data - core.move_cursor_forward_end_of_word(core.current_buffer(state), cursor = &sel_cur.end); + sel_cur := &(buffer.selection.?); + + core.move_cursor_forward_end_of_word(buffer, cursor = &sel_cur.end); }, "move forward to end of word"); - core.register_key_action(input_map, .B, proc(state: ^State) { - sel_cur := &(core.current_buffer(state).selection.?); + core.register_key_action(input_map, .B, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data - core.move_cursor_backward_start_of_word(core.current_buffer(state), cursor = &sel_cur.end); + sel_cur := &(buffer.selection.?); + + core.move_cursor_backward_start_of_word(buffer, cursor = &sel_cur.end); }, "move backward one word"); - core.register_key_action(input_map, .K, proc(state: ^State) { - sel_cur := &(core.current_buffer(state).selection.?); + core.register_key_action(input_map, .K, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data - core.move_cursor_up(core.current_buffer(state), cursor = &sel_cur.end); + sel_cur := &(buffer.selection.?); + + core.move_cursor_up(buffer, cursor = &sel_cur.end); }, "move up one line"); - core.register_key_action(input_map, .J, proc(state: ^State) { - sel_cur := &(core.current_buffer(state).selection.?); + core.register_key_action(input_map, .J, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data - core.move_cursor_down(core.current_buffer(state), cursor = &sel_cur.end); + sel_cur := &(buffer.selection.?); + + core.move_cursor_down(buffer, cursor = &sel_cur.end); }, "move down one line"); - core.register_key_action(input_map, .H, proc(state: ^State) { - sel_cur := &(core.current_buffer(state).selection.?); + core.register_key_action(input_map, .H, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data - core.move_cursor_left(core.current_buffer(state), cursor = &sel_cur.end); + sel_cur := &(buffer.selection.?); + + core.move_cursor_left(buffer, cursor = &sel_cur.end); }, "move left one char"); - core.register_key_action(input_map, .L, proc(state: ^State) { - sel_cur := &(core.current_buffer(state).selection.?); + core.register_key_action(input_map, .L, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data - core.move_cursor_right(core.current_buffer(state), cursor = &sel_cur.end); + sel_cur := &(buffer.selection.?); + + core.move_cursor_right(buffer, cursor = &sel_cur.end); }, "move right one char"); - core.register_ctrl_key_action(input_map, .U, proc(state: ^State) { - sel_cur := &(core.current_buffer(state).selection.?); + core.register_ctrl_key_action(input_map, .U, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data - core.scroll_file_buffer(core.current_buffer(state), .Up, cursor = &sel_cur.end); + sel_cur := &(buffer.selection.?); + + core.scroll_file_buffer(buffer, .Up, cursor = &sel_cur.end); }, "scroll buffer up"); - core.register_ctrl_key_action(input_map, .D, proc(state: ^State) { - sel_cur := &(core.current_buffer(state).selection.?); + core.register_ctrl_key_action(input_map, .D, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data - core.scroll_file_buffer(core.current_buffer(state), .Down, cursor = &sel_cur.end); + sel_cur := &(buffer.selection.?); + + core.scroll_file_buffer(buffer, .Down, cursor = &sel_cur.end); }, "scroll buffer up"); } // Text Modification { - core.register_key_action(input_map, .D, proc(state: ^State) { - core.push_new_snapshot(&core.current_buffer(state).history) + core.register_key_action(input_map, .D, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data - sel_cur := &(core.current_buffer(state).selection.?); + core.push_new_snapshot(&buffer.history) - core.delete_content(core.current_buffer(state), sel_cur); - core.current_buffer(state).selection = nil; - core.update_file_buffer_scroll(core.current_buffer(state)) + sel_cur := &(buffer.selection.?); + + core.delete_content(buffer, sel_cur); + buffer.selection = nil; + core.update_file_buffer_scroll(buffer) state.mode = .Normal core.reset_input_map(state) }, "delete selection"); - core.register_key_action(input_map, .C, proc(state: ^State) { - core.push_new_snapshot(&core.current_buffer(state).history) + core.register_key_action(input_map, .C, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data - sel_cur := &(core.current_buffer(state).selection.?); + core.push_new_snapshot(&buffer.history) - core.delete_content(core.current_buffer(state), sel_cur); - core.current_buffer(state).selection = nil; - core.update_file_buffer_scroll(core.current_buffer(state)) + sel_cur := &(buffer.selection.?); + + core.delete_content(buffer, sel_cur); + buffer.selection = nil; + core.update_file_buffer_scroll(buffer) state.mode = .Insert core.reset_input_map(state, core.Mode.Normal) @@ -187,25 +237,29 @@ register_default_visual_actions :: proc(input_map: ^core.InputActions) { // Copy-Paste { - core.register_key_action(input_map, .Y, proc(state: ^State) { - core.yank_selection(state) + core.register_key_action(input_map, .Y, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data + + core.yank_selection(state, buffer) state.mode = .Normal; core.reset_input_map(state) - core.current_buffer(state).selection = nil; - core.update_file_buffer_scroll(core.current_buffer(state)) + buffer.selection = nil; + core.update_file_buffer_scroll(buffer) }, "Yank Line"); - core.register_key_action(input_map, .P, proc(state: ^State) { - core.push_new_snapshot(&core.current_buffer(state).history) + core.register_key_action(input_map, .P, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data + + core.push_new_snapshot(&buffer.history) if state.yank_register.whole_line { - core.insert_content(core.current_buffer(state), []u8{'\n'}); - core.paste_register(state, state.yank_register) - core.insert_content(core.current_buffer(state), []u8{'\n'}); + core.insert_content(buffer, []u8{'\n'}); + core.paste_register(state, state.yank_register, buffer) + core.insert_content(buffer, []u8{'\n'}); } else { - core.paste_register(state, state.yank_register) + core.paste_register(state, state.yank_register, buffer) } core.reset_input_map(state) @@ -214,34 +268,44 @@ 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) + core.register_key_action(input_map, .I, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data + + core.push_new_snapshot(&buffer.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.register_key_action(input_map, .A, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data - core.move_cursor_right(core.current_buffer(state), false); + core.push_new_snapshot(&buffer.history) + + core.move_cursor_right(buffer, 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) + core.register_key_action(input_map, .U, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data + + core.pop_snapshot(&buffer.history, true) }, "Undo"); - core.register_ctrl_key_action(input_map, .R, proc(state: ^State) { - core.recover_snapshot(&core.current_buffer(state).history) + core.register_ctrl_key_action(input_map, .R, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data + + core.recover_snapshot(&buffer.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) + core.register_key_action(input_map, .O, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data - if buffer := core.current_buffer(state); buffer != nil { + core.push_new_snapshot(&buffer.history) + + if buffer := buffer; buffer != nil { core.move_cursor_end_of_line(buffer, false); runtime.clear(&buffer.input_buffer) @@ -259,25 +323,29 @@ register_default_text_input_actions :: proc(input_map: ^core.InputActions) { yank_actions := core.new_input_actions() defer core.register_key_action(input_map, .Y, yank_actions) - core.register_key_action(&yank_actions, .Y, proc(state: ^State) { - core.yank_whole_line(state) + core.register_key_action(&yank_actions, .Y, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data + + core.yank_whole_line(state, buffer) core.reset_input_map(state) }, "Yank Line"); } - core.register_key_action(input_map, .P, proc(state: ^State) { - core.push_new_snapshot(&core.current_buffer(state).history) + core.register_key_action(input_map, .P, proc(state: ^State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data + + core.push_new_snapshot(&buffer.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'}); - core.move_cursor_right(core.current_buffer(state), false); + core.move_cursor_end_of_line(buffer, false); + core.insert_content(buffer, []u8{'\n'}); + core.move_cursor_right(buffer, false); } else { - core.move_cursor_right(core.current_buffer(state)) + core.move_cursor_right(buffer) } - core.paste_register(state, state.yank_register) - core.move_cursor_start_of_line(core.current_buffer(state)) + core.paste_register(state, state.yank_register, buffer) + core.move_cursor_start_of_line(buffer) core.reset_input_map(state) }, "Paste"); diff --git a/src/main.odin b/src/main.odin index cde68a5..c62c972 100644 --- a/src/main.odin +++ b/src/main.odin @@ -54,11 +54,6 @@ ui_font_height :: proc() -> i32 { } draw :: proc(state: ^State) { - if buffer := core.current_buffer(state); buffer != nil { - buffer.glyphs.height = math.min(256, int((state.screen_height - state.source_font_height*2) / state.source_font_height)) + 1; - buffer.glyphs.width = math.min(256, int((state.screen_width - state.source_font_width) / state.source_font_width)); - } - render_color := theme.get_palette_color(.Background); sdl2.SetRenderDrawColor(state.sdl_renderer, render_color.r, render_color.g, render_color.b, render_color.a); sdl2.RenderClear(state.sdl_renderer); @@ -165,41 +160,6 @@ expose_event_watcher :: proc "c" (state: rawptr, event: ^sdl2.Event) -> i32 { return 0; } -ui_file_buffer :: proc(s: ^ui.State, buffer: ^FileBuffer) { - draw_func := proc(state: ^State, e: ui.UI_Element, user_data: rawptr) { - buffer := transmute(^FileBuffer)user_data; - 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); - } - }; - - relative_file_path, _ := filepath.rel(state.directory, buffer.file_path, context.temp_allocator) - - ui.open_element(s, nil, { - dir = .TopToBottom, - kind = {ui.Grow{}, ui.Grow{}}, - }) - { - ui.open_element(s, ui.UI_Element_Kind_Custom{fn = draw_func, user_data = transmute(rawptr)buffer}, { - kind = {ui.Grow{}, ui.Grow{}} - }) - ui.close_element(s) - - ui.open_element(s, nil, { - kind = {ui.Grow{}, ui.Exact(state.source_font_height)} - }) - { - ui.open_element(s, fmt.tprintf("%s", state.mode), {}) - ui.close_element(s) - } - ui.close_element(s) - } - ui.close_element(s) -} - main :: proc() { ts.set_allocator() @@ -276,55 +236,55 @@ main :: proc() { // } // ) - core.register_editor_command( - &state.commands, - "nl.spacegirl.editor.core", - "New Scratch Buffer", - "Opens a new scratch buffer", - proc(state: ^State) { - buffer := core.new_virtual_file_buffer(context.allocator); - util.append_static_list(&state.panels, panels.make_file_buffer_panel(len(state.buffers))) - runtime.append(&state.buffers, buffer); - } - ) - core.register_editor_command( - &state.commands, - "nl.spacegirl.editor.core", - "Open File", - "Opens a file in a new buffer", - proc(state: ^State) { - log.info("open file args:"); + // core.register_editor_command( + // &state.commands, + // "nl.spacegirl.editor.core", + // "New Scratch Buffer", + // "Opens a new scratch buffer", + // proc(state: ^State) { + // buffer := core.new_virtual_file_buffer(context.allocator); + // util.append_static_list(&state.panels, panels.make_file_buffer_panel(len(state.buffers))) + // runtime.append(&state.buffers, buffer); + // } + // ) + // core.register_editor_command( + // &state.commands, + // "nl.spacegirl.editor.core", + // "Open File", + // "Opens a file in a new buffer", + // proc(state: ^State) { + // log.info("open file args:"); - Args :: struct { - file_path: string - } + // Args :: struct { + // file_path: string + // } - if args, ok := core.attempt_read_command_args(Args, state.command_args[:]); ok { - log.info("attempting to open file", args.file_path) + // if args, ok := core.attempt_read_command_args(Args, state.command_args[:]); ok { + // log.info("attempting to open file", args.file_path) - panels.open_file_buffer_in_new_panel(state, args.file_path, 0, 0) - } - } - ) - core.register_editor_command( - &state.commands, - "nl.spacegirl.editor.core", - "Quit", - "Quits the application", - proc(state: ^State) { - state.should_close = true - } - ) + // panels.open_file_buffer_in_new_panel(state, args.file_path, 0, 0) + // } + // } + // ) + // core.register_editor_command( + // &state.commands, + // "nl.spacegirl.editor.core", + // "Quit", + // "Quits the application", + // proc(state: ^State) { + // state.should_close = true + // } + // ) if len(os.args) > 1 { for arg in os.args[1:] { panels.open_file_buffer_in_new_panel(&state, arg, 0, 0) } } else { - buffer := core.new_virtual_file_buffer(context.allocator); + // buffer := core.new_virtual_file_buffer(context.allocator); - panels.open(&state, panels.make_file_buffer_panel(len(state.buffers))) - runtime.append(&state.buffers, buffer); + // panels.open(&state, panels.make_file_buffer_panel(len(state.buffers))) + // runtime.append(&state.buffers, buffer); } if sdl2.Init({.VIDEO}) < 0 { @@ -426,12 +386,14 @@ main :: proc() { } run_key_action := proc(state: ^core.State, control_key_pressed: bool, key: core.Key) -> bool { - if state.current_input_map != nil { + 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); + value(state, &panel); return true; case core.InputActions: state.current_input_map = &(&state.current_input_map.ctrl_key_actions[key]).action.(core.InputActions) @@ -442,7 +404,7 @@ main :: proc() { if action, exists := state.current_input_map.key_actions[key]; exists { switch value in action.action { case core.EditorAction: - value(state); + value(state, &panel); return true; case core.InputActions: state.current_input_map = &(&state.current_input_map.key_actions[key]).action.(core.InputActions) diff --git a/src/panels/panels.odin b/src/panels/panels.odin index 40e2abd..02eeae6 100644 --- a/src/panels/panels.odin +++ b/src/panels/panels.odin @@ -59,18 +59,18 @@ rs_grep_as_results :: proc(results: ^RS_GrepResults, allocator := context.alloca // NOTE: odd that this is here, but I don't feel like thinking of a better dep-tree to fix it register_default_leader_actions :: proc(input_map: ^core.InputActions) { - core.register_key_action(input_map, .Q, proc(state: ^core.State) { + core.register_key_action(input_map, .Q, proc(state: ^core.State, user_data: rawptr) { core.reset_input_map(state) }, "close this help"); - core.register_key_action(input_map, .R, proc(state: ^core.State) { + core.register_key_action(input_map, .R, proc(state: ^core.State, user_data: rawptr) { open_grep_panel(state) }, "Grep Workspace") - core.register_key_action(input_map, .K, proc(state: ^core.State) { - buffer := core.current_buffer(state) - ts.update_cursor(&buffer.tree, buffer.history.cursor.line, buffer.history.cursor.col) + core.register_key_action(input_map, .K, proc(state: ^core.State, user_data: rawptr) { + buffer := transmute(^core.FileBuffer)user_data + ts.update_cursor(&buffer.tree, buffer.history.cursor.line, buffer.history.cursor.col) ts.print_node_type(&buffer.tree) core.reset_input_map(state) @@ -78,7 +78,7 @@ register_default_leader_actions :: proc(input_map: ^core.InputActions) { } register_default_panel_actions :: proc(input_map: ^core.InputActions) { - core.register_key_action(input_map, .H, proc(state: ^core.State) { + core.register_key_action(input_map, .H, proc(state: ^core.State, user_data: rawptr) { if current_panel, ok := state.current_panel.?; ok { if prev, ok := util.get_prev(&state.panels, current_panel).?; ok { state.current_panel = prev @@ -87,11 +87,7 @@ register_default_panel_actions :: proc(input_map: ^core.InputActions) { core.reset_input_map(state) }, "focus panel to the left"); - core.register_key_action(input_map, .L, proc(state: ^core.State) { - if state.current_buffer < len(state.buffers)-1 { - state.current_buffer += 1 - } - + core.register_key_action(input_map, .L, proc(state: ^core.State, user_data: rawptr) { if current_panel, ok := state.current_panel.?; ok { if next, ok := util.get_next(&state.panels, current_panel).?; ok { state.current_panel = next @@ -101,7 +97,7 @@ register_default_panel_actions :: proc(input_map: ^core.InputActions) { core.reset_input_map(state) }, "focus panel to the right"); - core.register_key_action(input_map, .Q, proc(state: ^core.State) { + core.register_key_action(input_map, .Q, proc(state: ^core.State, user_data: rawptr) { if current_panel, ok := state.current_panel.?; ok { close(state, current_panel) } @@ -139,6 +135,7 @@ close :: proc(state: ^core.State, panel_id: int) { } open_file_buffer_in_new_panel :: proc(state: ^core.State, file_path: string, line, col: int) -> (panel_id, buffer_index: int, ok: bool) { + // FIXME: move into panel buffer, err := core.new_file_buffer(context.allocator, file_path, state.directory); if err.type != .None { log.error("Failed to create file buffer:", err); @@ -150,8 +147,8 @@ open_file_buffer_in_new_panel :: proc(state: ^core.State, file_path: string, lin buffer.top_line = buffer.history.cursor.line core.update_file_buffer_index_from_cursor(&buffer) - buffer_index = len(state.buffers) - runtime.append(&state.buffers, buffer); + // buffer_index = len(state.buffers) + // runtime.append(&state.buffers, buffer); if panel_id, ok := open(state, make_file_buffer_panel(buffer_index)); ok { return panel_id, buffer_index, true @@ -167,7 +164,7 @@ render_file_buffer :: proc(state: ^core.State, s: ^ui.State, buffer: ^core.FileB 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); + core.draw_file_buffer(state, buffer, e.layout.pos.x, e.layout.pos.y, e.layout.size.x, e.layout.size.y); } }; @@ -240,7 +237,7 @@ render_raw_buffer :: proc(state: ^core.State, s: ^ui.State, buffer: ^core.FileBu 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, false); + core.draw_file_buffer(state, buffer, e.layout.pos.x, e.layout.pos.y, e.layout.size.x, e.layout.size.y, false); } }; @@ -279,7 +276,6 @@ make_file_buffer_panel :: proc(buffer_index: int) -> core.Panel { core.register_ctrl_key_action(&input_map.mode[.Normal], .W, core.new_input_actions(), "Panel Navigation") register_default_panel_actions(&(&input_map.mode[.Normal].ctrl_key_actions[.W]).action.(core.InputActions)) - input.register_default_input_actions(&input_map.mode[.Normal]); input.register_default_visual_actions(&input_map.mode[.Visual]); input.register_default_text_input_actions(&input_map.mode[.Normal]); @@ -287,22 +283,18 @@ make_file_buffer_panel :: proc(buffer_index: int) -> core.Panel { return core.Panel { panel_state = core.FileBufferPanel { buffer_index = buffer_index }, input_map = input_map, - buffer_proc = proc(state: ^core.State, panel_state: ^core.PanelState) -> (buffer: ^core.FileBuffer, ok: bool) { - panel_state := panel_state.(core.FileBufferPanel) or_return; - - return &state.buffers[panel_state.buffer_index], true - }, drop = proc(state: ^core.State, panel_state: ^core.PanelState) { if panel_state, ok := &panel_state.(core.FileBufferPanel); ok { - core.free_file_buffer(&state.buffers[panel_state.buffer_index]) + // core.free_file_buffer(&state.buffers[panel_state.buffer_index]) } }, render_proc = proc(state: ^core.State, panel_state: ^core.PanelState) -> (ok: bool) { panel_state := panel_state.(core.FileBufferPanel) or_return; - s := transmute(^ui.State)state.ui - buffer := &state.buffers[panel_state.buffer_index] - render_file_buffer(state, s, buffer) + // FIXME: use buffer from panel + // s := transmute(^ui.State)state.ui + // buffer := &state.buffers[panel_state.buffer_index] + // render_file_buffer(state, s, buffer) return true } @@ -323,8 +315,9 @@ make_grep_panel :: proc(state: ^core.State) -> core.Panel { glyphs := core.make_glyph_buffer(256,256, allocator = mem.arena_allocator(&query_arena)) input_map := core.new_input_map() + // FIXME: add to panel grep_input_buffer := core.new_virtual_file_buffer(context.allocator) - runtime.append(&state.buffers, grep_input_buffer) + // runtime.append(&state.buffers, grep_input_buffer) run_query :: proc(panel_state: ^core.GrepPanel, query: string, directory: string) { if panel_state.query_region.arena != nil { @@ -352,70 +345,65 @@ make_grep_panel :: proc(state: ^core.State) -> core.Panel { } } - core.register_key_action(&input_map.mode[.Normal], .ENTER, proc(state: ^core.State) { - if current_panel, ok := util.get(&state.panels, state.current_panel.? or_else -1).?; ok { - this_panel := state.current_panel.? + core.register_key_action(&input_map.mode[.Normal], .ENTER, proc(state: ^core.State, user_data: rawptr) { + this_panel := transmute(^core.Panel)user_data - if panel_state, ok := ¤t_panel.panel_state.(core.GrepPanel); ok { - if panel_state.query_results != nil { - selected_result := &panel_state.query_results[panel_state.selected_result] + if panel_state, ok := &this_panel.panel_state.(core.GrepPanel); ok { + if panel_state.query_results != nil { + selected_result := &panel_state.query_results[panel_state.selected_result] - if panel_id, buffer, ok := open_file_buffer_in_new_panel(state, selected_result.file_path, selected_result.line, selected_result.col); ok { - close(state, this_panel) + if panel_id, buffer, ok := open_file_buffer_in_new_panel(state, selected_result.file_path, selected_result.line, selected_result.col); ok { + // FIXME: store panel_id in core.Panel + // close(state, this_panel) - state.current_panel = panel_id - state.current_buffer = buffer - } else { - log.error("failed to open file buffer in new panel") - } + state.current_panel = panel_id + } else { + log.error("failed to open file buffer in new panel") } } } }, "Open File"); - core.register_key_action(&input_map.mode[.Normal], .I, proc(state: ^core.State) { + core.register_key_action(&input_map.mode[.Normal], .I, proc(state: ^core.State, user_data: rawptr) { state.mode = .Insert; sdl2.StartTextInput(); }, "enter insert mode"); - core.register_key_action(&input_map.mode[.Normal], .K, proc(state: ^core.State) { - // NOTE: this is really jank, should probably update the input - // action stuff to allow panels to be passed into these handlers - if current_panel, ok := util.get(&state.panels, state.current_panel.? or_else -1).?; ok { - if panel_state, ok := ¤t_panel.panel_state.(core.GrepPanel); ok { - // TODO: bounds checking - panel_state.selected_result -= 1 + core.register_key_action(&input_map.mode[.Normal], .K, proc(state: ^core.State, user_data: rawptr) { + this_panel := transmute(^core.Panel)user_data - core.update_glyph_buffer_from_bytes( - &panel_state.glyphs, - transmute([]u8)panel_state.query_results[panel_state.selected_result].file_context, - panel_state.query_results[panel_state.selected_result].line, - ) - } + if panel_state, ok := &this_panel.panel_state.(core.GrepPanel); ok { + // TODO: bounds checking + panel_state.selected_result -= 1 + + core.update_glyph_buffer_from_bytes( + &panel_state.glyphs, + transmute([]u8)panel_state.query_results[panel_state.selected_result].file_context, + panel_state.query_results[panel_state.selected_result].line, + ) } }, "move selection up"); - core.register_key_action(&input_map.mode[.Normal], .J, proc(state: ^core.State) { - // NOTE: this is really jank, should probably update the input - // action stuff to allow panels to be passed into these handlers - if current_panel, ok := util.get(&state.panels, state.current_panel.? or_else -1).?; ok { - if panel_state, ok := ¤t_panel.panel_state.(core.GrepPanel); ok { - // TODO: bounds checking - panel_state.selected_result += 1 + core.register_key_action(&input_map.mode[.Normal], .J, proc(state: ^core.State, user_data: rawptr) { + this_panel := transmute(^core.Panel)user_data - core.update_glyph_buffer_from_bytes( - &panel_state.glyphs, - transmute([]u8)panel_state.query_results[panel_state.selected_result].file_context, - panel_state.query_results[panel_state.selected_result].line, - ) - } + if panel_state, ok := &this_panel.panel_state.(core.GrepPanel); ok { + // TODO: bounds checking + panel_state.selected_result += 1 + + core.update_glyph_buffer_from_bytes( + &panel_state.glyphs, + transmute([]u8)panel_state.query_results[panel_state.selected_result].file_context, + panel_state.query_results[panel_state.selected_result].line, + ) } }, "move selection down"); - core.register_key_action(&input_map.mode[.Insert], .ESCAPE, proc(state: ^core.State) { + core.register_key_action(&input_map.mode[.Insert], .ESCAPE, proc(state: ^core.State, user_data: rawptr) { state.mode = .Normal; sdl2.StopTextInput(); }, "exit insert mode"); - core.register_key_action(&input_map.mode[.Normal], .ESCAPE, proc(state: ^core.State) { + core.register_key_action(&input_map.mode[.Normal], .ESCAPE, proc(state: ^core.State, user_data: rawptr) { if state.current_panel != nil { - close(state, state.current_panel.?) + // FIXME; store panel_id in core.Panel + // close(state, state.current_panel.?) } }, "close panel"); @@ -423,20 +411,15 @@ make_grep_panel :: proc(state: ^core.State) -> core.Panel { return core.Panel { panel_state = core.GrepPanel { query_arena = query_arena, - buffer = len(state.buffers)-1, + // buffer = len(state.buffers)-1, query_results = nil, glyphs = glyphs, }, input_map = input_map, - buffer_proc = proc(state: ^core.State, panel_state: ^core.PanelState) -> (buffer: ^core.FileBuffer, ok: bool) { - panel_state := panel_state.(core.GrepPanel) or_return; - - return &state.buffers[panel_state.buffer], true - }, on_buffer_input_proc = proc(state: ^core.State, panel_state: ^core.PanelState) { if panel_state, ok := &panel_state.(core.GrepPanel); ok { - buffer := &state.buffers[panel_state.buffer] - run_query(panel_state, string(buffer.input_buffer[:]), state.directory) + // buffer := &state.buffers[panel_state.buffer] + // run_query(panel_state, string(buffer.input_buffer[:]), state.directory) } }, drop = proc(state: ^core.State, panel_state: ^core.PanelState) { @@ -525,7 +508,7 @@ make_grep_panel :: proc(state: ^core.State) -> core.Panel { { defer ui.close_element(s) - render_raw_buffer(state, s, &state.buffers[panel_state.buffer]) + // render_raw_buffer(state, s, &state.buffers[panel_state.buffer]) } } ui.close_element(s)