odin_editor/src/core/core.odin

210 lines
5.9 KiB
Plaintext

package core
import "core:runtime"
import "core:fmt"
import "vendor:sdl2"
import lua "vendor:lua/5.4"
import "../plugin"
Mode :: enum {
Normal,
Insert,
Visual,
}
Window :: struct {
input_map: InputActions,
draw: plugin.WindowDrawProc,
free_user_data: plugin.WindowFreeProc,
get_buffer: plugin.WindowGetBufferProc,
// TODO: create hook for when mode changes happen
user_data: rawptr,
}
request_window_close :: proc(state: ^State) {
state.should_close_window = true;
}
close_window_and_free :: proc(state: ^State) {
if state.window != nil {
if state.window.free_user_data != nil {
state.window.free_user_data(state.plugin_vtable, state.window.user_data);
}
delete_input_actions(&state.window.input_map);
free(state.window);
state.window = nil;
}
state.current_input_map = &state.input_map.mode[.Normal];
}
LuaHookRef :: i32;
State :: struct {
ctx: runtime.Context,
L: ^lua.State,
sdl_renderer: ^sdl2.Renderer,
font_atlas: FontAtlas,
mode: Mode,
should_close: bool,
screen_height: int,
screen_width: int,
width_dpi_ratio: f32,
height_dpi_ratio: f32,
directory: string,
source_font_width: int,
source_font_height: int,
line_number_padding: int,
current_buffer: int,
buffers: [dynamic]FileBuffer,
window: ^Window,
should_close_window: bool,
input_map: InputMap,
current_input_map: ^InputActions,
plugins: [dynamic]plugin.Interface,
plugin_vtable: plugin.Plugin,
highlighters: map[string]plugin.OnColorBufferProc,
hooks: map[plugin.Hook][dynamic]plugin.OnHookProc,
lua_hooks: map[plugin.Hook][dynamic]LuaHookRef,
}
add_hook :: proc(state: ^State, hook: plugin.Hook, hook_proc: plugin.OnHookProc) {
if _, exists := state.hooks[hook]; !exists {
state.hooks[hook] = make([dynamic]plugin.OnHookProc);
}
runtime.append(&state.hooks[hook], hook_proc);
}
add_lua_hook :: proc(state: ^State, hook: plugin.Hook, hook_ref: LuaHookRef) {
if _, exists := state.lua_hooks[hook]; !exists {
state.lua_hooks[hook] = make([dynamic]LuaHookRef);
}
runtime.append(&state.lua_hooks[hook], hook_ref);
}
LuaEditorAction :: struct {
fn_ref: i32,
maybe_input_map: InputActions,
};
PluginEditorAction :: proc "c" (plugin: plugin.Plugin);
EditorAction :: proc(state: ^State);
InputGroup :: union {LuaEditorAction, PluginEditorAction, EditorAction, InputActions}
Action :: struct {
action: InputGroup,
description: string,
}
InputMap :: struct {
mode: map[Mode]InputActions,
}
InputActions :: struct {
key_actions: map[plugin.Key]Action,
ctrl_key_actions: map[plugin.Key]Action,
}
new_input_map :: proc() -> InputMap {
input_map := InputMap {
mode = make(map[Mode]InputActions),
}
input_map.mode[.Normal] = new_input_actions();
return input_map;
}
new_input_actions :: proc() -> InputActions {
input_actions := InputActions {
key_actions = make(map[plugin.Key]Action),
ctrl_key_actions = make(map[plugin.Key]Action),
}
return input_actions;
}
delete_input_map :: proc(input_map: ^InputMap) {
for _, actions in &input_map.mode {
delete_input_actions(&actions);
}
delete(input_map.mode);
}
delete_input_actions :: proc(input_map: ^InputActions) {
delete(input_map.key_actions);
delete(input_map.ctrl_key_actions);
}
// NOTE(pcleavelin): might be a bug in the compiler where it can't coerce
// `EditorAction` to `InputGroup` when given as a proc parameter, that is why there
// are two functions
register_plugin_key_action_single :: proc(input_map: ^InputActions, key: plugin.Key, action: PluginEditorAction, description: string = "") {
if ok := key in input_map.key_actions; ok {
// TODO: log that key is already registered
fmt.eprintln("plugin key already registered with single action", key);
}
input_map.key_actions[key] = Action {
action = action,
description = description,
};
}
register_key_action_single :: proc(input_map: ^InputActions, key: plugin.Key, action: EditorAction, description: string = "") {
if ok := key in input_map.key_actions; ok {
// TODO: log that key is already registered
fmt.eprintln("key already registered with single action", key);
}
input_map.key_actions[key] = Action {
action = action,
description = description,
};
}
register_key_action_group :: proc(input_map: ^InputActions, key: plugin.Key, input_group: InputGroup, description: string = "") {
if ok := key in input_map.key_actions; ok {
// TODO: log that key is already registered
fmt.eprintln("key already registered with single action", key);
}
input_map.key_actions[key] = Action {
action = input_group,
description = description,
};
}
register_ctrl_key_action_single :: proc(input_map: ^InputActions, key: plugin.Key, action: EditorAction, description: string = "") {
if ok := key in input_map.key_actions; ok {
// TODO: log that key is already registered
fmt.eprintln("key already registered with single action", key);
}
input_map.ctrl_key_actions[key] = Action {
action = action,
description = description,
};
}
register_ctrl_key_action_group :: proc(input_map: ^InputActions, key: plugin.Key, input_group: InputGroup, description: string = "") {
if ok := key in input_map.key_actions; ok {
// TODO: log that key is already registered
fmt.eprintln("key already registered with single action", key);
}
input_map.ctrl_key_actions[key] = Action {
action = input_group,
description = description,
};
}
register_key_action :: proc{register_plugin_key_action_single, register_key_action_single, register_key_action_group};
register_ctrl_key_action :: proc{register_ctrl_key_action_single, register_ctrl_key_action_group};