remove global file buffer array
parent
86b2dcfbfb
commit
e412dbe7a2
|
@ -38,9 +38,6 @@ State :: struct {
|
||||||
source_font_height: int,
|
source_font_height: int,
|
||||||
line_number_padding: int,
|
line_number_padding: int,
|
||||||
|
|
||||||
current_buffer: int,
|
|
||||||
buffers: [dynamic]FileBuffer,
|
|
||||||
|
|
||||||
// TODO: make more than one register to plop stuff into
|
// TODO: make more than one register to plop stuff into
|
||||||
yank_register: Register,
|
yank_register: Register,
|
||||||
|
|
||||||
|
@ -117,81 +114,55 @@ GrepQueryResult :: struct {
|
||||||
col: int,
|
col: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
current_buffer :: proc(state: ^State) -> ^FileBuffer {
|
yank_whole_line :: proc(state: ^State, buffer: ^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) {
|
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
if buffer := current_buffer(state); buffer != nil {
|
selection := new_selection(buffer, buffer.history.cursor)
|
||||||
selection := new_selection(buffer, buffer.history.cursor)
|
length := selection_length(buffer, selection)
|
||||||
length := selection_length(buffer, selection)
|
|
||||||
|
|
||||||
state.yank_register.whole_line = true
|
state.yank_register.whole_line = true
|
||||||
state.yank_register.data = make([]u8, length)
|
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
|
index := 0
|
||||||
for !it.hit_end && index < length {
|
for !it.hit_end && index < length {
|
||||||
state.yank_register.data[index] = get_character_at_iter(it)
|
state.yank_register.data[index] = get_character_at_iter(it)
|
||||||
|
|
||||||
iterate_file_buffer(&it)
|
iterate_file_buffer(&it)
|
||||||
index += 1
|
index += 1
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
yank_selection :: proc(state: ^State) {
|
yank_selection :: proc(state: ^State, buffer: ^FileBuffer) {
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
if buffer := current_buffer(state); buffer != nil && buffer.selection != nil {
|
selection := swap_selections(buffer.selection.?)
|
||||||
selection := swap_selections(buffer.selection.?)
|
length := selection_length(buffer, selection)
|
||||||
length := selection_length(buffer, selection)
|
|
||||||
|
|
||||||
state.yank_register.whole_line = false
|
state.yank_register.whole_line = false
|
||||||
state.yank_register.data = make([]u8, length)
|
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
|
index := 0
|
||||||
for !it.hit_end && index < length {
|
for !it.hit_end && index < length {
|
||||||
state.yank_register.data[index] = get_character_at_iter(it)
|
state.yank_register.data[index] = get_character_at_iter(it)
|
||||||
|
|
||||||
iterate_file_buffer(&it)
|
iterate_file_buffer(&it)
|
||||||
index += 1
|
index += 1
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
paste_register :: proc(state: ^State, register: Register) {
|
paste_register :: proc(state: ^State, register: Register, buffer: ^FileBuffer) {
|
||||||
if buffer := current_buffer(state); buffer != nil && register.data != nil {
|
insert_content(buffer, register.data)
|
||||||
insert_content(buffer, register.data)
|
move_cursor_left(buffer)
|
||||||
move_cursor_left(buffer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reset_input_map_from_state_mode :: proc(state: ^State) {
|
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}
|
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 {
|
InputMap :: struct {
|
||||||
mode: map[Mode]InputActions,
|
mode: map[Mode]InputActions,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InputGroup :: union {EditorAction, InputActions}
|
||||||
|
EditorAction :: proc(state: ^State, user_data: rawptr);
|
||||||
InputActions :: struct {
|
InputActions :: struct {
|
||||||
key_actions: map[Key]Action,
|
key_actions: map[Key]Action,
|
||||||
ctrl_key_actions: map[Key]Action,
|
ctrl_key_actions: map[Key]Action,
|
||||||
}
|
}
|
||||||
|
Action :: struct {
|
||||||
|
action: InputGroup,
|
||||||
|
description: string,
|
||||||
|
}
|
||||||
|
|
||||||
new_input_map :: proc() -> InputMap {
|
new_input_map :: proc() -> InputMap {
|
||||||
input_map := InputMap {
|
input_map := InputMap {
|
||||||
|
@ -377,7 +341,8 @@ run_command :: proc(state: ^State, group: string, name: string) {
|
||||||
for cmd in cmds {
|
for cmd in cmds {
|
||||||
if cmd.name == name {
|
if cmd.name == name {
|
||||||
log.info("Running command", group, name);
|
log.info("Running command", group, name);
|
||||||
cmd.action(state);
|
// TODO: rework command system
|
||||||
|
// cmd.action(state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -776,18 +776,6 @@ save_buffer_to_disk :: proc(state: ^State, buffer: ^FileBuffer) -> (error: os.Er
|
||||||
return
|
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
|
// TODO: replace this with arena for the file buffer
|
||||||
free_file_buffer :: proc(buffer: ^FileBuffer) {
|
free_file_buffer :: proc(buffer: ^FileBuffer) {
|
||||||
ts.delete_state(&buffer.tree)
|
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) {
|
draw_file_buffer :: proc(state: ^State, buffer: ^FileBuffer, x, y, w, h: int, show_line_numbers: bool = true, show_cursor: bool = true) {
|
||||||
update_glyph_buffer(buffer);
|
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;
|
padding := 0;
|
||||||
if show_line_numbers {
|
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;
|
cursor_y -= begin * state.source_font_height;
|
||||||
|
|
||||||
// draw cursor
|
// draw cursor
|
||||||
if state.mode == .Normal || current_buffer(state) != buffer {
|
if show_cursor {
|
||||||
draw_rect(state, cursor_x, cursor_y, state.source_font_width, state.source_font_height, .Background4);
|
if state.mode == .Normal {
|
||||||
} else if state.mode == .Visual {
|
draw_rect(state, cursor_x, cursor_y, state.source_font_width, state.source_font_height, .Background4);
|
||||||
start_sel_x := x + padding + buffer.selection.?.start.col * state.source_font_width;
|
} else if state.mode == .Visual {
|
||||||
start_sel_y := y + buffer.selection.?.start.line * state.source_font_height;
|
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_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_y := y + buffer.selection.?.end.line * state.source_font_height;
|
||||||
|
|
||||||
start_sel_y -= begin * state.source_font_height;
|
start_sel_y -= begin * state.source_font_height;
|
||||||
end_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, 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);
|
draw_rect(state, end_sel_x, end_sel_y, state.source_font_width, state.source_font_height, .Blue);
|
||||||
}
|
} else if state.mode == .Insert {
|
||||||
else if state.mode == .Insert {
|
draw_rect(state, cursor_x, cursor_y, state.source_font_width, state.source_font_height, .Green);
|
||||||
draw_rect(state, cursor_x, cursor_y, state.source_font_width, state.source_font_height, .Green);
|
|
||||||
|
|
||||||
num_line_break := 0;
|
num_line_break := 0;
|
||||||
line_length := 0;
|
line_length := 0;
|
||||||
for c in buffer.input_buffer {
|
for c in buffer.input_buffer {
|
||||||
if c == '\n' {
|
if c == '\n' {
|
||||||
num_line_break += 1;
|
num_line_break += 1;
|
||||||
line_length = 0;
|
line_length = 0;
|
||||||
} else {
|
} else {
|
||||||
line_length += 1;
|
line_length += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if num_line_break > 0 {
|
if num_line_break > 0 {
|
||||||
cursor_x = x + padding + line_length * state.source_font_width;
|
cursor_x = x + padding + line_length * state.source_font_width;
|
||||||
cursor_y = cursor_y + num_line_break * state.source_font_height;
|
cursor_y = cursor_y + num_line_break * state.source_font_height;
|
||||||
} else {
|
} else {
|
||||||
cursor_x += line_length * state.source_font_width;
|
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
|
// 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
|
// 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
|
// 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 := swap_selections(buffer.selection.?)
|
||||||
// selection := buffer.selection.?
|
// selection := buffer.selection.?
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
for &glyph in buffer.glyphs.buffer {
|
||||||
glyph = Glyph {}
|
glyph = Glyph {}
|
||||||
glyph.color = .Foreground
|
glyph.color = .Foreground
|
||||||
|
|
|
@ -11,12 +11,16 @@ import "../util"
|
||||||
State :: core.State
|
State :: core.State
|
||||||
|
|
||||||
register_default_go_actions :: proc(input_map: ^core.InputActions) {
|
register_default_go_actions :: proc(input_map: ^core.InputActions) {
|
||||||
core.register_key_action(input_map, .H, proc(state: ^State) {
|
core.register_key_action(input_map, .H, proc(state: ^State, user_data: rawptr) {
|
||||||
core.move_cursor_start_of_line(core.current_buffer(state));
|
buffer := transmute(^core.FileBuffer)user_data
|
||||||
|
|
||||||
|
core.move_cursor_start_of_line(buffer);
|
||||||
core.reset_input_map(state)
|
core.reset_input_map(state)
|
||||||
}, "move to beginning of line");
|
}, "move to beginning of line");
|
||||||
core.register_key_action(input_map, .L, proc(state: ^State) {
|
core.register_key_action(input_map, .L, proc(state: ^State, user_data: rawptr) {
|
||||||
core.move_cursor_end_of_line(core.current_buffer(state));
|
buffer := transmute(^core.FileBuffer)user_data
|
||||||
|
|
||||||
|
core.move_cursor_end_of_line(buffer);
|
||||||
core.reset_input_map(state)
|
core.reset_input_map(state)
|
||||||
}, "move to end of line");
|
}, "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) {
|
register_default_input_actions :: proc(input_map: ^core.InputActions) {
|
||||||
// Cursor Movement
|
// Cursor Movement
|
||||||
{
|
{
|
||||||
core.register_key_action(input_map, .W, proc(state: ^State) {
|
core.register_key_action(input_map, .W, proc(state: ^State, user_data: rawptr) {
|
||||||
core.move_cursor_forward_start_of_word(core.current_buffer(state));
|
buffer := transmute(^core.FileBuffer)user_data
|
||||||
|
|
||||||
|
core.move_cursor_forward_start_of_word(buffer);
|
||||||
}, "move forward one word");
|
}, "move forward one word");
|
||||||
core.register_key_action(input_map, .E, proc(state: ^State) {
|
core.register_key_action(input_map, .E, proc(state: ^State, user_data: rawptr) {
|
||||||
core.move_cursor_forward_end_of_word(core.current_buffer(state));
|
buffer := transmute(^core.FileBuffer)user_data
|
||||||
|
|
||||||
|
core.move_cursor_forward_end_of_word(buffer);
|
||||||
}, "move forward to end of word");
|
}, "move forward to end of word");
|
||||||
|
|
||||||
core.register_key_action(input_map, .B, proc(state: ^State) {
|
core.register_key_action(input_map, .B, proc(state: ^State, user_data: rawptr) {
|
||||||
core.move_cursor_backward_start_of_word(core.current_buffer(state));
|
buffer := transmute(^core.FileBuffer)user_data
|
||||||
|
|
||||||
|
core.move_cursor_backward_start_of_word(buffer);
|
||||||
}, "move backward one word");
|
}, "move backward one word");
|
||||||
|
|
||||||
core.register_key_action(input_map, .K, proc(state: ^State) {
|
core.register_key_action(input_map, .K, proc(state: ^State, user_data: rawptr) {
|
||||||
core.move_cursor_up(core.current_buffer(state));
|
buffer := transmute(^core.FileBuffer)user_data
|
||||||
|
|
||||||
|
core.move_cursor_up(buffer);
|
||||||
}, "move up one line");
|
}, "move up one line");
|
||||||
core.register_key_action(input_map, .J, proc(state: ^State) {
|
core.register_key_action(input_map, .J, proc(state: ^State, user_data: rawptr) {
|
||||||
core.move_cursor_down(core.current_buffer(state));
|
buffer := transmute(^core.FileBuffer)user_data
|
||||||
|
|
||||||
|
core.move_cursor_down(buffer);
|
||||||
}, "move down one line");
|
}, "move down one line");
|
||||||
core.register_key_action(input_map, .H, proc(state: ^State) {
|
core.register_key_action(input_map, .H, proc(state: ^State, user_data: rawptr) {
|
||||||
core.move_cursor_left(core.current_buffer(state));
|
buffer := transmute(^core.FileBuffer)user_data
|
||||||
|
|
||||||
|
core.move_cursor_left(buffer);
|
||||||
}, "move left one char");
|
}, "move left one char");
|
||||||
core.register_key_action(input_map, .L, proc(state: ^State) {
|
core.register_key_action(input_map, .L, proc(state: ^State, user_data: rawptr) {
|
||||||
core.move_cursor_right(core.current_buffer(state));
|
buffer := transmute(^core.FileBuffer)user_data
|
||||||
|
|
||||||
|
core.move_cursor_right(buffer);
|
||||||
}, "move right one char");
|
}, "move right one char");
|
||||||
|
|
||||||
core.register_ctrl_key_action(input_map, .U, proc(state: ^State) {
|
core.register_ctrl_key_action(input_map, .U, proc(state: ^State, user_data: rawptr) {
|
||||||
core.scroll_file_buffer(core.current_buffer(state), .Up);
|
buffer := transmute(^core.FileBuffer)user_data
|
||||||
|
|
||||||
|
core.scroll_file_buffer(buffer, .Up);
|
||||||
}, "scroll buffer up");
|
}, "scroll buffer up");
|
||||||
core.register_ctrl_key_action(input_map, .D, proc(state: ^State) {
|
core.register_ctrl_key_action(input_map, .D, proc(state: ^State, user_data: rawptr) {
|
||||||
core.scroll_file_buffer(core.current_buffer(state), .Down);
|
buffer := transmute(^core.FileBuffer)user_data
|
||||||
|
|
||||||
|
core.scroll_file_buffer(buffer, .Down);
|
||||||
}, "scroll buffer up");
|
}, "scroll buffer up");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scale font size
|
// 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 {
|
if state.source_font_height > 16 {
|
||||||
state.source_font_height -= 2;
|
state.source_font_height -= 2;
|
||||||
state.source_font_width = 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);
|
log.debug(state.source_font_height);
|
||||||
}, "increase font size");
|
}, "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_height += 2;
|
||||||
state.source_font_width = 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
|
// Save file
|
||||||
core.register_ctrl_key_action(input_map, .S, proc(state: ^State) {
|
core.register_ctrl_key_action(input_map, .S, proc(state: ^State, user_data: rawptr) {
|
||||||
if err := core.save_buffer_to_disk(state, core.current_buffer(state)); err != nil {
|
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)
|
log.errorf("failed to save buffer to disk: %v", err)
|
||||||
}
|
}
|
||||||
}, "Save file")
|
}, "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");
|
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));
|
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;
|
state.mode = .Visual;
|
||||||
core.reset_input_map(state)
|
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");
|
}, "enter visual mode");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
register_default_visual_actions :: proc(input_map: ^core.InputActions) {
|
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;
|
state.mode = .Normal;
|
||||||
core.reset_input_map(state)
|
core.reset_input_map(state)
|
||||||
|
|
||||||
core.current_buffer(state).selection = nil;
|
buffer.selection = nil;
|
||||||
core.update_file_buffer_scroll(core.current_buffer(state))
|
core.update_file_buffer_scroll(buffer)
|
||||||
}, "exit visual mode");
|
}, "exit visual mode");
|
||||||
|
|
||||||
// Cursor Movement
|
// Cursor Movement
|
||||||
{
|
{
|
||||||
core.register_key_action(input_map, .W, proc(state: ^State) {
|
core.register_key_action(input_map, .W, proc(state: ^State, user_data: rawptr) {
|
||||||
sel_cur := &(core.current_buffer(state).selection.?);
|
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");
|
}, "move forward one word");
|
||||||
core.register_key_action(input_map, .E, proc(state: ^State) {
|
core.register_key_action(input_map, .E, proc(state: ^State, user_data: rawptr) {
|
||||||
sel_cur := &(core.current_buffer(state).selection.?);
|
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");
|
}, "move forward to end of word");
|
||||||
|
|
||||||
core.register_key_action(input_map, .B, proc(state: ^State) {
|
core.register_key_action(input_map, .B, proc(state: ^State, user_data: rawptr) {
|
||||||
sel_cur := &(core.current_buffer(state).selection.?);
|
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");
|
}, "move backward one word");
|
||||||
|
|
||||||
core.register_key_action(input_map, .K, proc(state: ^State) {
|
core.register_key_action(input_map, .K, proc(state: ^State, user_data: rawptr) {
|
||||||
sel_cur := &(core.current_buffer(state).selection.?);
|
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");
|
}, "move up one line");
|
||||||
core.register_key_action(input_map, .J, proc(state: ^State) {
|
core.register_key_action(input_map, .J, proc(state: ^State, user_data: rawptr) {
|
||||||
sel_cur := &(core.current_buffer(state).selection.?);
|
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");
|
}, "move down one line");
|
||||||
core.register_key_action(input_map, .H, proc(state: ^State) {
|
core.register_key_action(input_map, .H, proc(state: ^State, user_data: rawptr) {
|
||||||
sel_cur := &(core.current_buffer(state).selection.?);
|
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");
|
}, "move left one char");
|
||||||
core.register_key_action(input_map, .L, proc(state: ^State) {
|
core.register_key_action(input_map, .L, proc(state: ^State, user_data: rawptr) {
|
||||||
sel_cur := &(core.current_buffer(state).selection.?);
|
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");
|
}, "move right one char");
|
||||||
|
|
||||||
core.register_ctrl_key_action(input_map, .U, proc(state: ^State) {
|
core.register_ctrl_key_action(input_map, .U, proc(state: ^State, user_data: rawptr) {
|
||||||
sel_cur := &(core.current_buffer(state).selection.?);
|
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");
|
}, "scroll buffer up");
|
||||||
core.register_ctrl_key_action(input_map, .D, proc(state: ^State) {
|
core.register_ctrl_key_action(input_map, .D, proc(state: ^State, user_data: rawptr) {
|
||||||
sel_cur := &(core.current_buffer(state).selection.?);
|
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");
|
}, "scroll buffer up");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Text Modification
|
// Text Modification
|
||||||
{
|
{
|
||||||
core.register_key_action(input_map, .D, proc(state: ^State) {
|
core.register_key_action(input_map, .D, proc(state: ^State, user_data: rawptr) {
|
||||||
core.push_new_snapshot(&core.current_buffer(state).history)
|
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);
|
sel_cur := &(buffer.selection.?);
|
||||||
core.current_buffer(state).selection = nil;
|
|
||||||
core.update_file_buffer_scroll(core.current_buffer(state))
|
core.delete_content(buffer, sel_cur);
|
||||||
|
buffer.selection = nil;
|
||||||
|
core.update_file_buffer_scroll(buffer)
|
||||||
|
|
||||||
state.mode = .Normal
|
state.mode = .Normal
|
||||||
core.reset_input_map(state)
|
core.reset_input_map(state)
|
||||||
}, "delete selection");
|
}, "delete selection");
|
||||||
|
|
||||||
core.register_key_action(input_map, .C, proc(state: ^State) {
|
core.register_key_action(input_map, .C, proc(state: ^State, user_data: rawptr) {
|
||||||
core.push_new_snapshot(&core.current_buffer(state).history)
|
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);
|
sel_cur := &(buffer.selection.?);
|
||||||
core.current_buffer(state).selection = nil;
|
|
||||||
core.update_file_buffer_scroll(core.current_buffer(state))
|
core.delete_content(buffer, sel_cur);
|
||||||
|
buffer.selection = nil;
|
||||||
|
core.update_file_buffer_scroll(buffer)
|
||||||
|
|
||||||
state.mode = .Insert
|
state.mode = .Insert
|
||||||
core.reset_input_map(state, core.Mode.Normal)
|
core.reset_input_map(state, core.Mode.Normal)
|
||||||
|
@ -187,25 +237,29 @@ register_default_visual_actions :: proc(input_map: ^core.InputActions) {
|
||||||
|
|
||||||
// Copy-Paste
|
// Copy-Paste
|
||||||
{
|
{
|
||||||
core.register_key_action(input_map, .Y, proc(state: ^State) {
|
core.register_key_action(input_map, .Y, proc(state: ^State, user_data: rawptr) {
|
||||||
core.yank_selection(state)
|
buffer := transmute(^core.FileBuffer)user_data
|
||||||
|
|
||||||
|
core.yank_selection(state, buffer)
|
||||||
|
|
||||||
state.mode = .Normal;
|
state.mode = .Normal;
|
||||||
core.reset_input_map(state)
|
core.reset_input_map(state)
|
||||||
|
|
||||||
core.current_buffer(state).selection = nil;
|
buffer.selection = nil;
|
||||||
core.update_file_buffer_scroll(core.current_buffer(state))
|
core.update_file_buffer_scroll(buffer)
|
||||||
}, "Yank Line");
|
}, "Yank Line");
|
||||||
|
|
||||||
core.register_key_action(input_map, .P, proc(state: ^State) {
|
core.register_key_action(input_map, .P, proc(state: ^State, user_data: rawptr) {
|
||||||
core.push_new_snapshot(&core.current_buffer(state).history)
|
buffer := transmute(^core.FileBuffer)user_data
|
||||||
|
|
||||||
|
core.push_new_snapshot(&buffer.history)
|
||||||
|
|
||||||
if state.yank_register.whole_line {
|
if state.yank_register.whole_line {
|
||||||
core.insert_content(core.current_buffer(state), []u8{'\n'});
|
core.insert_content(buffer, []u8{'\n'});
|
||||||
core.paste_register(state, state.yank_register)
|
core.paste_register(state, state.yank_register, buffer)
|
||||||
core.insert_content(core.current_buffer(state), []u8{'\n'});
|
core.insert_content(buffer, []u8{'\n'});
|
||||||
} else {
|
} else {
|
||||||
core.paste_register(state, state.yank_register)
|
core.paste_register(state, state.yank_register, buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
core.reset_input_map(state)
|
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) {
|
register_default_text_input_actions :: proc(input_map: ^core.InputActions) {
|
||||||
core.register_key_action(input_map, .I, proc(state: ^State) {
|
core.register_key_action(input_map, .I, proc(state: ^State, user_data: rawptr) {
|
||||||
core.push_new_snapshot(&core.current_buffer(state).history)
|
buffer := transmute(^core.FileBuffer)user_data
|
||||||
|
|
||||||
|
core.push_new_snapshot(&buffer.history)
|
||||||
|
|
||||||
state.mode = .Insert;
|
state.mode = .Insert;
|
||||||
sdl2.StartTextInput();
|
sdl2.StartTextInput();
|
||||||
}, "enter insert mode");
|
}, "enter insert mode");
|
||||||
core.register_key_action(input_map, .A, proc(state: ^State) {
|
core.register_key_action(input_map, .A, proc(state: ^State, user_data: rawptr) {
|
||||||
core.push_new_snapshot(&core.current_buffer(state).history)
|
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;
|
state.mode = .Insert;
|
||||||
sdl2.StartTextInput();
|
sdl2.StartTextInput();
|
||||||
}, "enter insert mode after character (append)");
|
}, "enter insert mode after character (append)");
|
||||||
|
|
||||||
core.register_key_action(input_map, .U, proc(state: ^State) {
|
core.register_key_action(input_map, .U, proc(state: ^State, user_data: rawptr) {
|
||||||
core.pop_snapshot(&core.current_buffer(state).history, true)
|
buffer := transmute(^core.FileBuffer)user_data
|
||||||
|
|
||||||
|
core.pop_snapshot(&buffer.history, true)
|
||||||
}, "Undo");
|
}, "Undo");
|
||||||
|
|
||||||
core.register_ctrl_key_action(input_map, .R, proc(state: ^State) {
|
core.register_ctrl_key_action(input_map, .R, proc(state: ^State, user_data: rawptr) {
|
||||||
core.recover_snapshot(&core.current_buffer(state).history)
|
buffer := transmute(^core.FileBuffer)user_data
|
||||||
|
|
||||||
|
core.recover_snapshot(&buffer.history)
|
||||||
}, "Redo");
|
}, "Redo");
|
||||||
|
|
||||||
// TODO: add shift+o to insert newline above current one
|
// TODO: add shift+o to insert newline above current one
|
||||||
|
|
||||||
core.register_key_action(input_map, .O, proc(state: ^State) {
|
core.register_key_action(input_map, .O, proc(state: ^State, user_data: rawptr) {
|
||||||
core.push_new_snapshot(&core.current_buffer(state).history)
|
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);
|
core.move_cursor_end_of_line(buffer, false);
|
||||||
runtime.clear(&buffer.input_buffer)
|
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()
|
yank_actions := core.new_input_actions()
|
||||||
defer core.register_key_action(input_map, .Y, yank_actions)
|
defer core.register_key_action(input_map, .Y, yank_actions)
|
||||||
|
|
||||||
core.register_key_action(&yank_actions, .Y, proc(state: ^State) {
|
core.register_key_action(&yank_actions, .Y, proc(state: ^State, user_data: rawptr) {
|
||||||
core.yank_whole_line(state)
|
buffer := transmute(^core.FileBuffer)user_data
|
||||||
|
|
||||||
|
core.yank_whole_line(state, buffer)
|
||||||
|
|
||||||
core.reset_input_map(state)
|
core.reset_input_map(state)
|
||||||
}, "Yank Line");
|
}, "Yank Line");
|
||||||
}
|
}
|
||||||
|
|
||||||
core.register_key_action(input_map, .P, proc(state: ^State) {
|
core.register_key_action(input_map, .P, proc(state: ^State, user_data: rawptr) {
|
||||||
core.push_new_snapshot(&core.current_buffer(state).history)
|
buffer := transmute(^core.FileBuffer)user_data
|
||||||
|
|
||||||
|
core.push_new_snapshot(&buffer.history)
|
||||||
|
|
||||||
if state.yank_register.whole_line {
|
if state.yank_register.whole_line {
|
||||||
core.move_cursor_end_of_line(core.current_buffer(state), false);
|
core.move_cursor_end_of_line(buffer, false);
|
||||||
core.insert_content(core.current_buffer(state), []u8{'\n'});
|
core.insert_content(buffer, []u8{'\n'});
|
||||||
core.move_cursor_right(core.current_buffer(state), false);
|
core.move_cursor_right(buffer, false);
|
||||||
} else {
|
} else {
|
||||||
core.move_cursor_right(core.current_buffer(state))
|
core.move_cursor_right(buffer)
|
||||||
}
|
}
|
||||||
core.paste_register(state, state.yank_register)
|
core.paste_register(state, state.yank_register, buffer)
|
||||||
core.move_cursor_start_of_line(core.current_buffer(state))
|
core.move_cursor_start_of_line(buffer)
|
||||||
|
|
||||||
core.reset_input_map(state)
|
core.reset_input_map(state)
|
||||||
}, "Paste");
|
}, "Paste");
|
||||||
|
|
126
src/main.odin
126
src/main.odin
|
@ -54,11 +54,6 @@ ui_font_height :: proc() -> i32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
draw :: proc(state: ^State) {
|
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);
|
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.SetRenderDrawColor(state.sdl_renderer, render_color.r, render_color.g, render_color.b, render_color.a);
|
||||||
sdl2.RenderClear(state.sdl_renderer);
|
sdl2.RenderClear(state.sdl_renderer);
|
||||||
|
@ -165,41 +160,6 @@ expose_event_watcher :: proc "c" (state: rawptr, event: ^sdl2.Event) -> i32 {
|
||||||
return 0;
|
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() {
|
main :: proc() {
|
||||||
ts.set_allocator()
|
ts.set_allocator()
|
||||||
|
|
||||||
|
@ -276,55 +236,55 @@ main :: proc() {
|
||||||
// }
|
// }
|
||||||
// )
|
// )
|
||||||
|
|
||||||
core.register_editor_command(
|
// core.register_editor_command(
|
||||||
&state.commands,
|
// &state.commands,
|
||||||
"nl.spacegirl.editor.core",
|
// "nl.spacegirl.editor.core",
|
||||||
"New Scratch Buffer",
|
// "New Scratch Buffer",
|
||||||
"Opens a new scratch buffer",
|
// "Opens a new scratch buffer",
|
||||||
proc(state: ^State) {
|
// proc(state: ^State) {
|
||||||
buffer := core.new_virtual_file_buffer(context.allocator);
|
// buffer := core.new_virtual_file_buffer(context.allocator);
|
||||||
util.append_static_list(&state.panels, panels.make_file_buffer_panel(len(state.buffers)))
|
// util.append_static_list(&state.panels, panels.make_file_buffer_panel(len(state.buffers)))
|
||||||
runtime.append(&state.buffers, buffer);
|
// runtime.append(&state.buffers, buffer);
|
||||||
}
|
// }
|
||||||
)
|
// )
|
||||||
core.register_editor_command(
|
// core.register_editor_command(
|
||||||
&state.commands,
|
// &state.commands,
|
||||||
"nl.spacegirl.editor.core",
|
// "nl.spacegirl.editor.core",
|
||||||
"Open File",
|
// "Open File",
|
||||||
"Opens a file in a new buffer",
|
// "Opens a file in a new buffer",
|
||||||
proc(state: ^State) {
|
// proc(state: ^State) {
|
||||||
log.info("open file args:");
|
// log.info("open file args:");
|
||||||
|
|
||||||
Args :: struct {
|
// Args :: struct {
|
||||||
file_path: string
|
// file_path: string
|
||||||
}
|
// }
|
||||||
|
|
||||||
if args, ok := core.attempt_read_command_args(Args, state.command_args[:]); ok {
|
// if args, ok := core.attempt_read_command_args(Args, state.command_args[:]); ok {
|
||||||
log.info("attempting to open file", args.file_path)
|
// log.info("attempting to open file", args.file_path)
|
||||||
|
|
||||||
panels.open_file_buffer_in_new_panel(state, args.file_path, 0, 0)
|
// panels.open_file_buffer_in_new_panel(state, args.file_path, 0, 0)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
)
|
// )
|
||||||
core.register_editor_command(
|
// core.register_editor_command(
|
||||||
&state.commands,
|
// &state.commands,
|
||||||
"nl.spacegirl.editor.core",
|
// "nl.spacegirl.editor.core",
|
||||||
"Quit",
|
// "Quit",
|
||||||
"Quits the application",
|
// "Quits the application",
|
||||||
proc(state: ^State) {
|
// proc(state: ^State) {
|
||||||
state.should_close = true
|
// state.should_close = true
|
||||||
}
|
// }
|
||||||
)
|
// )
|
||||||
|
|
||||||
if len(os.args) > 1 {
|
if len(os.args) > 1 {
|
||||||
for arg in os.args[1:] {
|
for arg in os.args[1:] {
|
||||||
panels.open_file_buffer_in_new_panel(&state, arg, 0, 0)
|
panels.open_file_buffer_in_new_panel(&state, arg, 0, 0)
|
||||||
}
|
}
|
||||||
} else {
|
} 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)))
|
// panels.open(&state, panels.make_file_buffer_panel(len(state.buffers)))
|
||||||
runtime.append(&state.buffers, buffer);
|
// runtime.append(&state.buffers, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if sdl2.Init({.VIDEO}) < 0 {
|
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 {
|
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 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)
|
||||||
|
@ -442,7 +404,7 @@ main :: proc() {
|
||||||
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)
|
||||||
|
|
|
@ -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
|
// 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) {
|
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)
|
core.reset_input_map(state)
|
||||||
}, "close this help");
|
}, "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)
|
open_grep_panel(state)
|
||||||
}, "Grep Workspace")
|
}, "Grep Workspace")
|
||||||
|
|
||||||
core.register_key_action(input_map, .K, proc(state: ^core.State) {
|
core.register_key_action(input_map, .K, proc(state: ^core.State, user_data: rawptr) {
|
||||||
buffer := core.current_buffer(state)
|
buffer := transmute(^core.FileBuffer)user_data
|
||||||
ts.update_cursor(&buffer.tree, buffer.history.cursor.line, buffer.history.cursor.col)
|
|
||||||
|
|
||||||
|
ts.update_cursor(&buffer.tree, buffer.history.cursor.line, buffer.history.cursor.col)
|
||||||
ts.print_node_type(&buffer.tree)
|
ts.print_node_type(&buffer.tree)
|
||||||
|
|
||||||
core.reset_input_map(state)
|
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) {
|
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 current_panel, ok := state.current_panel.?; ok {
|
||||||
if prev, ok := util.get_prev(&state.panels, current_panel).?; ok {
|
if prev, ok := util.get_prev(&state.panels, current_panel).?; ok {
|
||||||
state.current_panel = prev
|
state.current_panel = prev
|
||||||
|
@ -87,11 +87,7 @@ register_default_panel_actions :: proc(input_map: ^core.InputActions) {
|
||||||
|
|
||||||
core.reset_input_map(state)
|
core.reset_input_map(state)
|
||||||
}, "focus panel to the left");
|
}, "focus panel to the left");
|
||||||
core.register_key_action(input_map, .L, proc(state: ^core.State) {
|
core.register_key_action(input_map, .L, proc(state: ^core.State, user_data: rawptr) {
|
||||||
if state.current_buffer < len(state.buffers)-1 {
|
|
||||||
state.current_buffer += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if current_panel, ok := state.current_panel.?; ok {
|
if current_panel, ok := state.current_panel.?; ok {
|
||||||
if next, ok := util.get_next(&state.panels, current_panel).?; ok {
|
if next, ok := util.get_next(&state.panels, current_panel).?; ok {
|
||||||
state.current_panel = next
|
state.current_panel = next
|
||||||
|
@ -101,7 +97,7 @@ register_default_panel_actions :: proc(input_map: ^core.InputActions) {
|
||||||
core.reset_input_map(state)
|
core.reset_input_map(state)
|
||||||
}, "focus panel to the right");
|
}, "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 {
|
if current_panel, ok := state.current_panel.?; ok {
|
||||||
close(state, current_panel)
|
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) {
|
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);
|
buffer, err := core.new_file_buffer(context.allocator, file_path, state.directory);
|
||||||
if err.type != .None {
|
if err.type != .None {
|
||||||
log.error("Failed to create file buffer:", err);
|
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
|
buffer.top_line = buffer.history.cursor.line
|
||||||
core.update_file_buffer_index_from_cursor(&buffer)
|
core.update_file_buffer_index_from_cursor(&buffer)
|
||||||
|
|
||||||
buffer_index = len(state.buffers)
|
// buffer_index = len(state.buffers)
|
||||||
runtime.append(&state.buffers, buffer);
|
// runtime.append(&state.buffers, buffer);
|
||||||
|
|
||||||
if panel_id, ok := open(state, make_file_buffer_panel(buffer_index)); ok {
|
if panel_id, ok := open(state, make_file_buffer_panel(buffer_index)); ok {
|
||||||
return panel_id, buffer_index, true
|
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.width = e.layout.size.x / state.source_font_width;
|
||||||
buffer.glyphs.height = e.layout.size.y / state.source_font_height + 1;
|
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.width = e.layout.size.x / state.source_font_width;
|
||||||
buffer.glyphs.height = e.layout.size.y / state.source_font_height + 1;
|
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")
|
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))
|
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_input_actions(&input_map.mode[.Normal]);
|
||||||
input.register_default_visual_actions(&input_map.mode[.Visual]);
|
input.register_default_visual_actions(&input_map.mode[.Visual]);
|
||||||
input.register_default_text_input_actions(&input_map.mode[.Normal]);
|
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 {
|
return core.Panel {
|
||||||
panel_state = core.FileBufferPanel { buffer_index = buffer_index },
|
panel_state = core.FileBufferPanel { buffer_index = buffer_index },
|
||||||
input_map = input_map,
|
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) {
|
drop = proc(state: ^core.State, panel_state: ^core.PanelState) {
|
||||||
if panel_state, ok := &panel_state.(core.FileBufferPanel); ok {
|
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) {
|
render_proc = proc(state: ^core.State, panel_state: ^core.PanelState) -> (ok: bool) {
|
||||||
panel_state := panel_state.(core.FileBufferPanel) or_return;
|
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
|
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))
|
glyphs := core.make_glyph_buffer(256,256, allocator = mem.arena_allocator(&query_arena))
|
||||||
|
|
||||||
input_map := core.new_input_map()
|
input_map := core.new_input_map()
|
||||||
|
// FIXME: add to panel
|
||||||
grep_input_buffer := core.new_virtual_file_buffer(context.allocator)
|
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) {
|
run_query :: proc(panel_state: ^core.GrepPanel, query: string, directory: string) {
|
||||||
if panel_state.query_region.arena != nil {
|
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) {
|
core.register_key_action(&input_map.mode[.Normal], .ENTER, proc(state: ^core.State, user_data: rawptr) {
|
||||||
if current_panel, ok := util.get(&state.panels, state.current_panel.? or_else -1).?; ok {
|
this_panel := transmute(^core.Panel)user_data
|
||||||
this_panel := state.current_panel.?
|
|
||||||
|
|
||||||
if panel_state, ok := ¤t_panel.panel_state.(core.GrepPanel); ok {
|
if panel_state, ok := &this_panel.panel_state.(core.GrepPanel); ok {
|
||||||
if panel_state.query_results != nil {
|
if panel_state.query_results != nil {
|
||||||
selected_result := &panel_state.query_results[panel_state.selected_result]
|
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 {
|
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)
|
// FIXME: store panel_id in core.Panel
|
||||||
|
// close(state, this_panel)
|
||||||
|
|
||||||
state.current_panel = panel_id
|
state.current_panel = panel_id
|
||||||
state.current_buffer = buffer
|
} else {
|
||||||
} else {
|
log.error("failed to open file buffer in new panel")
|
||||||
log.error("failed to open file buffer in new panel")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, "Open File");
|
}, "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;
|
state.mode = .Insert;
|
||||||
sdl2.StartTextInput();
|
sdl2.StartTextInput();
|
||||||
}, "enter insert mode");
|
}, "enter insert mode");
|
||||||
core.register_key_action(&input_map.mode[.Normal], .K, proc(state: ^core.State) {
|
core.register_key_action(&input_map.mode[.Normal], .K, proc(state: ^core.State, user_data: rawptr) {
|
||||||
// NOTE: this is really jank, should probably update the input
|
this_panel := transmute(^core.Panel)user_data
|
||||||
// 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.update_glyph_buffer_from_bytes(
|
if panel_state, ok := &this_panel.panel_state.(core.GrepPanel); ok {
|
||||||
&panel_state.glyphs,
|
// TODO: bounds checking
|
||||||
transmute([]u8)panel_state.query_results[panel_state.selected_result].file_context,
|
panel_state.selected_result -= 1
|
||||||
panel_state.query_results[panel_state.selected_result].line,
|
|
||||||
)
|
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");
|
}, "move selection up");
|
||||||
core.register_key_action(&input_map.mode[.Normal], .J, proc(state: ^core.State) {
|
core.register_key_action(&input_map.mode[.Normal], .J, proc(state: ^core.State, user_data: rawptr) {
|
||||||
// NOTE: this is really jank, should probably update the input
|
this_panel := transmute(^core.Panel)user_data
|
||||||
// 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.update_glyph_buffer_from_bytes(
|
if panel_state, ok := &this_panel.panel_state.(core.GrepPanel); ok {
|
||||||
&panel_state.glyphs,
|
// TODO: bounds checking
|
||||||
transmute([]u8)panel_state.query_results[panel_state.selected_result].file_context,
|
panel_state.selected_result += 1
|
||||||
panel_state.query_results[panel_state.selected_result].line,
|
|
||||||
)
|
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");
|
}, "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;
|
state.mode = .Normal;
|
||||||
sdl2.StopTextInput();
|
sdl2.StopTextInput();
|
||||||
}, "exit insert mode");
|
}, "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 {
|
if state.current_panel != nil {
|
||||||
close(state, state.current_panel.?)
|
// FIXME; store panel_id in core.Panel
|
||||||
|
// close(state, state.current_panel.?)
|
||||||
}
|
}
|
||||||
}, "close panel");
|
}, "close panel");
|
||||||
|
|
||||||
|
@ -423,20 +411,15 @@ make_grep_panel :: proc(state: ^core.State) -> core.Panel {
|
||||||
return core.Panel {
|
return core.Panel {
|
||||||
panel_state = core.GrepPanel {
|
panel_state = core.GrepPanel {
|
||||||
query_arena = query_arena,
|
query_arena = query_arena,
|
||||||
buffer = len(state.buffers)-1,
|
// buffer = len(state.buffers)-1,
|
||||||
query_results = nil,
|
query_results = nil,
|
||||||
glyphs = glyphs,
|
glyphs = glyphs,
|
||||||
},
|
},
|
||||||
input_map = input_map,
|
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) {
|
on_buffer_input_proc = proc(state: ^core.State, panel_state: ^core.PanelState) {
|
||||||
if panel_state, ok := &panel_state.(core.GrepPanel); ok {
|
if panel_state, ok := &panel_state.(core.GrepPanel); ok {
|
||||||
buffer := &state.buffers[panel_state.buffer]
|
// buffer := &state.buffers[panel_state.buffer]
|
||||||
run_query(panel_state, string(buffer.input_buffer[:]), state.directory)
|
// run_query(panel_state, string(buffer.input_buffer[:]), state.directory)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
drop = proc(state: ^core.State, panel_state: ^core.PanelState) {
|
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)
|
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)
|
ui.close_element(s)
|
||||||
|
|
Loading…
Reference in New Issue