From 73bb0035ec0c4d6ce643472c394de7c97230fd66 Mon Sep 17 00:00:00 2001 From: Patrick Cleavelin Date: Sat, 4 Jan 2025 17:28:56 -0500 Subject: [PATCH] get things ready for mode dependant inputs --- Makefile | 4 +- src/core/core.odin | 43 +++++++++++++------ src/main.odin | 100 ++++++++++++++++++++++++++++++--------------- 3 files changed, 99 insertions(+), 48 deletions(-) diff --git a/Makefile b/Makefile index d9868a2..7d1e467 100644 --- a/Makefile +++ b/Makefile @@ -5,9 +5,9 @@ editor: src/*.odin grep odin_highlighter dsymutil bin/editor.o -o bin/editor.dSYM odin build src/ -out:bin/editor -lld -odin_highlighter: +odin_highlighter: plugins/highlighter/src/*.odin odin build plugins/highlighter/src/ -build-mode:dll -no-entry-point -out:bin/highlighter -grep: +grep: plugins/grep/src/*.rs nightly-cargo b --manifest-path=plugins/grep/Cargo.toml cp plugins/grep/target/debug/libgrep_plugin.dylib bin/ diff --git a/src/core/core.odin b/src/core/core.odin index 7fb8a59..a3b2f07 100644 --- a/src/core/core.odin +++ b/src/core/core.odin @@ -10,10 +10,11 @@ import "../plugin" Mode :: enum { Normal, Insert, + Visual, } Window :: struct { - input_map: InputMap, + input_map: InputActions, draw: plugin.WindowDrawProc, free_user_data: plugin.WindowFreeProc, @@ -33,13 +34,13 @@ close_window_and_free :: proc(state: ^State) { state.window.free_user_data(state.plugin_vtable, state.window.user_data); } - delete_input_map(&state.window.input_map); + delete_input_actions(&state.window.input_map); free(state.window); state.window = nil; } - state.current_input_map = &state.input_map; + state.current_input_map = &state.input_map.mode[.Normal]; } LuaHookRef :: i32; @@ -69,7 +70,7 @@ State :: struct { should_close_window: bool, input_map: InputMap, - current_input_map: ^InputMap, + current_input_map: ^InputActions, plugins: [dynamic]plugin.Interface, plugin_vtable: plugin.Plugin, @@ -96,29 +97,47 @@ add_lua_hook :: proc(state: ^State, hook: plugin.Hook, hook_ref: LuaHookRef) { LuaEditorAction :: struct { fn_ref: i32, - maybe_input_map: InputMap, + maybe_input_map: InputActions, }; PluginEditorAction :: proc "c" (plugin: plugin.Plugin); EditorAction :: proc(state: ^State); -InputGroup :: union {LuaEditorAction, PluginEditorAction, EditorAction, InputMap} +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_map; + 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); } @@ -126,7 +145,7 @@ delete_input_map :: proc(input_map: ^InputMap) { // 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: ^InputMap, key: plugin.Key, action: PluginEditorAction, description: string = "") { +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); @@ -138,7 +157,7 @@ register_plugin_key_action_single :: proc(input_map: ^InputMap, key: plugin.Key, }; } -register_key_action_single :: proc(input_map: ^InputMap, key: plugin.Key, action: EditorAction, description: string = "") { +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); @@ -150,7 +169,7 @@ register_key_action_single :: proc(input_map: ^InputMap, key: plugin.Key, action }; } -register_key_action_group :: proc(input_map: ^InputMap, key: plugin.Key, input_group: InputGroup, description: string = "") { +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); @@ -162,7 +181,7 @@ register_key_action_group :: proc(input_map: ^InputMap, key: plugin.Key, input_g }; } -register_ctrl_key_action_single :: proc(input_map: ^InputMap, key: plugin.Key, action: EditorAction, description: string = "") { +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); @@ -174,7 +193,7 @@ register_ctrl_key_action_single :: proc(input_map: ^InputMap, key: plugin.Key, a }; } -register_ctrl_key_action_group :: proc(input_map: ^InputMap, key: plugin.Key, input_group: InputGroup, description: string = "") { +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); diff --git a/src/main.odin b/src/main.odin index 5dac74c..5ec933e 100644 --- a/src/main.odin +++ b/src/main.odin @@ -79,24 +79,27 @@ do_insert_mode :: proc(state: ^State, buffer: ^FileBuffer) { } } -register_default_leader_actions :: proc(input_map: ^core.InputMap) { +do_visual_mode :: proc(state: ^State, buffer: ^FileBuffer) { +} + +register_default_leader_actions :: proc(input_map: ^core.InputActions) { core.register_key_action(input_map, .Q, proc(state: ^State) { - state.current_input_map = &state.input_map; + state.current_input_map = &state.input_map.mode[.Normal]; }, "close this help"); } -register_default_go_actions :: proc(input_map: ^core.InputMap) { +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(&state.buffers[state.current_buffer]); - state.current_input_map = &state.input_map; + state.current_input_map = &state.input_map.mode[.Normal]; }, "move to beginning of line"); core.register_key_action(input_map, .L, proc(state: ^State) { core.move_cursor_end_of_line(&state.buffers[state.current_buffer]); - state.current_input_map = &state.input_map; + state.current_input_map = &state.input_map.mode[.Normal]; }, "move to end of line"); } -register_default_input_actions :: proc(input_map: ^core.InputMap) { +register_default_input_actions :: proc(input_map: ^core.InputActions) { // Cursor Movement { core.register_key_action(input_map, .W, proc(state: ^State) { @@ -174,11 +177,11 @@ register_default_input_actions :: proc(input_map: ^core.InputMap) { }, "insert mode on newline"); } - core.register_key_action(input_map, .SPACE, core.new_input_map(), "leader commands"); - register_default_leader_actions(&(&input_map.key_actions[.SPACE]).action.(core.InputMap)); + core.register_key_action(input_map, .SPACE, core.new_input_actions(), "leader commands"); + register_default_leader_actions(&(&input_map.key_actions[.SPACE]).action.(core.InputActions)); - core.register_key_action(input_map, .G, core.new_input_map(), "Go commands"); - register_default_go_actions(&(&input_map.key_actions[.G]).action.(core.InputMap)); + 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)); } load_plugin :: proc(info: os.File_Info, in_err: os.Errno, state: rawptr) -> (err: os.Errno, skip_dir: bool) { @@ -226,7 +229,7 @@ draw :: proc(state_with_ui: ^StateWithUi) { ui.compute_layout(state_with_ui.ui_context, { state_with_ui.state.screen_width, state_with_ui.state.screen_height }, state_with_ui.state.source_font_width, state_with_ui.state.source_font_height, state_with_ui.ui_context.root); ui.draw(state_with_ui.ui_context, state_with_ui.state, state_with_ui.state.source_font_width, state_with_ui.state.source_font_height, state_with_ui.ui_context.root); - if state_with_ui.state.current_input_map != &state_with_ui.state.input_map { + if state_with_ui.state.current_input_map != &state_with_ui.state.input_map.mode[.Normal] { longest_description := 0; for key, action in state_with_ui.state.current_input_map.key_actions { if len(action.description) > longest_description { @@ -324,6 +327,8 @@ ui_file_buffer :: proc(ctx: ^ui.Context, buffer: ^FileBuffer) -> ui.Interaction ui.push_parent(ctx, info_box); defer ui.pop_parent(ctx); + ui.label(ctx, fmt.tprintf("%s", state.mode)) + ui.spacer(ctx, "spacer"); ui.label(ctx, relative_file_path); } @@ -352,10 +357,10 @@ init_plugin_vtable :: proc(ui_context: ^ui.Context) -> plugin.Plugin { register_input_group = proc "c" (input_map: rawptr, key: plugin.Key, register_group: plugin.InputGroupProc) { context = state.ctx; - to_be_edited_map: ^core.InputMap = nil; + to_be_edited_map: ^core.InputActions = nil; if input_map != nil { - to_be_edited_map = transmute(^core.InputMap)input_map; + to_be_edited_map = transmute(^core.InputActions)input_map; } else { to_be_edited_map = state.current_input_map; } @@ -368,23 +373,23 @@ init_plugin_vtable :: proc(ui_context: ^ui.Context) -> plugin.Plugin { fmt.eprintln("Plugin attempted to register input group on existing key action (added from Plugin)"); case core.EditorAction: fmt.eprintln("Plugin attempted to register input group on existing key action"); - case core.InputMap: - input_map := &(&to_be_edited_map.key_actions[key]).action.(core.InputMap); + case core.InputActions: + input_map := &(&to_be_edited_map.key_actions[key]).action.(core.InputActions); register_group(state.plugin_vtable, transmute(rawptr)input_map); } } else { - core.register_key_action(to_be_edited_map, key, core.new_input_map(), "PLUGIN INPUT GROUP"); - register_group(state.plugin_vtable, &(&to_be_edited_map.key_actions[key]).action.(core.InputMap)); + core.register_key_action(to_be_edited_map, key, core.new_input_actions(), "PLUGIN INPUT GROUP"); + register_group(state.plugin_vtable, &(&to_be_edited_map.key_actions[key]).action.(core.InputActions)); } }, register_input = proc "c" (input_map: rawptr, key: plugin.Key, input_action: plugin.InputActionProc, description: cstring) { context = state.ctx; - to_be_edited_map: ^core.InputMap = nil; + to_be_edited_map: ^core.InputActions = nil; description := strings.clone(string(description)); if input_map != nil { - to_be_edited_map = transmute(^core.InputMap)input_map; + to_be_edited_map = transmute(^core.InputActions)input_map; } else { to_be_edited_map = state.current_input_map; } @@ -397,7 +402,7 @@ init_plugin_vtable :: proc(ui_context: ^ui.Context) -> plugin.Plugin { fmt.eprintln("Plugin attempted to register key action on existing key action (added from Plugin)"); case core.EditorAction: fmt.eprintln("Plugin attempted to register input key action on existing key action"); - case core.InputMap: + case core.InputActions: fmt.eprintln("Plugin attempted to register input key action on existing input group"); } } else { @@ -408,7 +413,7 @@ init_plugin_vtable :: proc(ui_context: ^ui.Context) -> plugin.Plugin { context = state.ctx; window := new(core.Window); window^ = core.Window { - input_map = core.new_input_map(), + input_map = core.new_input_actions(), draw = draw_proc, get_buffer = get_buffer_proc, free_user_data = free_window_proc, @@ -951,8 +956,8 @@ main :: proc() { lua_hooks = make(map[plugin.Hook][dynamic]core.LuaHookRef), }; - state.current_input_map = &state.input_map; - register_default_input_actions(&state.input_map); + state.current_input_map = &state.input_map.mode[.Normal]; + register_default_input_actions(&state.input_map.mode[.Normal]); for arg in os.args[1:] { buffer, err := core.new_file_buffer(context.allocator, arg, state.directory); @@ -1090,7 +1095,7 @@ main :: proc() { lua.L_checktype(L, 1, i32(lua.TTABLE)); - table_to_action :: proc(L: ^lua.State, index: i32, input_map: ^core.InputMap) { + table_to_action :: proc(L: ^lua.State, index: i32, input_map: ^core.InputActions) { lua.len(L, index); key_group_len := lua.tointeger(L, -1); lua.pop(L, 1); @@ -1117,13 +1122,13 @@ main :: proc() { fmt.eprintln("Plugin attempted to register input group on existing key action (added from Plugin)"); case core.EditorAction: fmt.eprintln("Plugin attempted to register input group on existing key action"); - case core.InputMap: - input_map := &(&input_map.key_actions[key]).action.(core.InputMap); + case core.InputActions: + input_map := &(&input_map.key_actions[key]).action.(core.InputActions); table_to_action(L, lua.gettop(L), input_map); } } else { - core.register_key_action(input_map, key, core.new_input_map(), desc); - table_to_action(L, lua.gettop(L), &((&input_map.key_actions[key]).action.(core.InputMap))); + core.register_key_action(input_map, key, core.new_input_actions(), desc); + table_to_action(L, lua.gettop(L), &((&input_map.key_actions[key]).action.(core.InputActions))); } lua.pop(L, 1); @@ -1131,12 +1136,12 @@ main :: proc() { fn_ref := lua.L_ref(L, i32(lua.REGISTRYINDEX)); if lua.rawgeti(L, -1, 4) == i32(lua.TTABLE) { - maybe_input_map := core.new_input_map(); + maybe_input_map := core.new_input_actions(); table_to_action(L, lua.gettop(L), &maybe_input_map); core.register_key_action_group(input_map, key, core.LuaEditorAction { fn_ref, maybe_input_map }, desc); } else { - core.register_key_action_group(input_map, key, core.LuaEditorAction { fn_ref, core.InputMap {} }, desc); + core.register_key_action_group(input_map, key, core.LuaEditorAction { fn_ref, core.InputActions {} }, desc); } case: @@ -1868,8 +1873,8 @@ main :: proc() { value(state.plugin_vtable); case core.EditorAction: value(&state); - case core.InputMap: - state.current_input_map = &(&state.current_input_map.ctrl_key_actions[key]).action.(core.InputMap) + case core.InputActions: + state.current_input_map = &(&state.current_input_map.ctrl_key_actions[key]).action.(core.InputActions) } } } else { @@ -1894,8 +1899,8 @@ main :: proc() { value(state.plugin_vtable); case core.EditorAction: value(&state); - case core.InputMap: - state.current_input_map = &(&state.current_input_map.key_actions[key]).action.(core.InputMap) + case core.InputActions: + state.current_input_map = &(&state.current_input_map.key_actions[key]).action.(core.InputActions) } } } @@ -1980,6 +1985,26 @@ main :: proc() { } } } + case .Visual: { + buffer: ^FileBuffer; + + if state.window != nil && state.window.get_buffer != nil { + buffer = transmute(^core.FileBuffer)(state.window.get_buffer(state.plugin_vtable, state.window.user_data)); + } else { + buffer = &state.buffers[state.current_buffer]; + } + + if sdl_event.type == .KEYDOWN { + key := plugin.Key(sdl_event.key.keysym.sym); + + #partial switch key { + case .ESCAPE: { + state.mode = .Normal; + // TODO: visual mode + } + } + } + } } } } @@ -2005,6 +2030,13 @@ main :: proc() { buffer := &state.buffers[state.current_buffer]; do_insert_mode(&state, buffer); } + case .Visual: + if state.window != nil && state.window.get_buffer != nil { + // TODO + } else { + buffer := &state.buffers[state.current_buffer]; + do_visual_mode(&state, buffer); + } } if state.should_close_window {