get things ready for mode dependant inputs
parent
55f6005d58
commit
73bb0035ec
4
Makefile
4
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/
|
||||
|
|
|
@ -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);
|
||||
|
|
100
src/main.odin
100
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 {
|
||||
|
|
Loading…
Reference in New Issue