From 6541256a8ce66618b4dfc91a1530af62f27217f0 Mon Sep 17 00:00:00 2001 From: Patrick Cleavelin Date: Sat, 1 Mar 2025 20:45:07 -0600 Subject: [PATCH] get base panel registration working --- plugins/default_view/init.lua | 52 +++++++++- plugins/lua/view.lua | 6 +- src/core/core.odin | 36 ++++++- src/lua/lua.odin | 128 ++++++++++++++++++++++- src/main.odin | 186 +++++++++++----------------------- 5 files changed, 272 insertions(+), 136 deletions(-) diff --git a/plugins/default_view/init.lua b/plugins/default_view/init.lua index 452523d..1be80f3 100644 --- a/plugins/default_view/init.lua +++ b/plugins/default_view/init.lua @@ -4,6 +4,38 @@ M.version = "0.1" M.name = "Default_View" M.namespace = "nl_spacegirl_plugin_Default" +M.BufferListPanel = { + num_clicks = 0 +} + +M.SomeOtherPanel = { + num_clicks_2 = 0 +} + +function M.BufferListPanel.new() + local p = {} + setmetatable(p, {__index = M.BufferListPanel}) + return p +end + +function M.BufferListPanel:render(ctx) + if UI.button(ctx, "Number of Clicks "..self.num_clicks).clicked then + self.num_clicks = self.num_clicks + 1 + end +end + +function M.SomeOtherPanel.new() + local p = {} + setmetatable(p, {__index = M.SomeOtherPanel}) + return p +end + +function M.SomeOtherPanel:render(ctx) + if UI.button(ctx, "Number of Clicks 2 "..self.num_clicks_2).clicked then + self.num_clicks_2 = self.num_clicks_2 + 1 + end +end + function M.open_file_search_window() local input = { {Editor.Key.Enter, "Open File", function() Editor.log("this should open a file") end} @@ -26,11 +58,27 @@ function M.OnLoad() Editor.log("default view loaded") Editor.log(nl_spacegirl_plugin_Default_Legacy_View['namespace']) + local a = M.BufferListPanel.new() + local b = M.BufferListPanel.new() + + print(M.BufferListPanel) + print(a) + print(b) + Editor.register_key_group({ {Editor.Key.Space, "", { - {Editor.Key.F, "Open File", M.open_file_search_window} - }} + {Editor.Key.F, "Open File", M.open_file_search_window}, + {Editor.Key.J, "New Panel", function() + Editor.run_command("nl.spacegirl.editor.core", "Open New Panel", "BufferListPanel") + end}, + {Editor.Key.K, "Some Other Panel", function() + Editor.run_command("nl.spacegirl.editor.core", "Open New Panel", "SomeOtherPanel") + end} + }}, }) + + Editor.register_panel("BufferList", "BufferListPanel") + Editor.register_panel("aksjdhflkasjdf", "SomeOtherPanel") end function M.view_render(cx) diff --git a/plugins/lua/view.lua b/plugins/lua/view.lua index d2834b8..a017a15 100644 --- a/plugins/lua/view.lua +++ b/plugins/lua/view.lua @@ -314,7 +314,7 @@ function M.render_ui_window(ctx) end -- render_buffer_search(ctx) - render_command_search(ctx) + -- render_command_search(ctx) render_log_window(ctx) LastMouseX = x @@ -395,7 +395,7 @@ function M.open_buffer_search_window(ctx) -- end end -function M.open_command_palette(ctx) +function M.open_command_palette() -- if CommandSearchOpen or CommandSearchOpenElapsed > 0 then -- if CommandSearchOpen and CommandSearchOpenElapsed < numFrames then -- CommandSearchOpenElapsed = CommandSearchOpenElapsed + 1 @@ -519,7 +519,7 @@ function M.OnLoad() }} }) - Editor.register_hook(Editor.Hook.OnDraw, render_ui_window) + Editor.register_hook(Editor.Hook.OnDraw, M.render_ui_window) Editor.register_hook(Editor.Hook.OnBufferInput, handle_buffer_input) end diff --git a/src/core/core.odin b/src/core/core.odin index 28910f4..9bbd282 100644 --- a/src/core/core.odin +++ b/src/core/core.odin @@ -92,6 +92,9 @@ State :: struct { command_arena: runtime.Allocator, command_args: [dynamic]EditorCommandArgument, + active_panels: [128]Maybe(Panel), + panel_catalog: [dynamic]PanelId, + plugins: [dynamic]plugin.Interface, new_plugins: [dynamic]plugin.NewInterface, plugin_vtable: plugin.Plugin, @@ -111,11 +114,34 @@ EditorCommandExec :: struct { args: [dynamic]EditorCommandArgument, } -EditorCommandArgument :: union { +EditorCommandArgument :: union #no_nil { string, i32 } +PanelId :: union #no_nil { + LuaPanelId, + LibPanelId, +} +Panel :: union #no_nil { + LuaPanel, + LibPanel, +} + + +LuaPanelId :: struct { + id: string, + name: string, +} +LuaPanel :: struct { + index: i32, + render_ref: i32 +} + +// TODO +LibPanelId :: struct {} +LibPanel :: struct {} + current_buffer :: proc(state: ^State) -> ^FileBuffer { if state.current_buffer == -2 { return &state.log_buffer; @@ -398,3 +424,11 @@ where intrinsics.type_is_struct(T) { return } + +register_panel_lua :: proc(state: ^State, name: string, id: string) { + append(&state.panel_catalog, LuaPanelId { + id = id, + name = name, + }) +} + diff --git a/src/lua/lua.odin b/src/lua/lua.odin index 7272d54..1dce3d0 100644 --- a/src/lua/lua.odin +++ b/src/lua/lua.odin @@ -63,6 +63,18 @@ new_state :: proc(_state: ^core.State) { "register_key_group", register_key_group, }, + lua.L_Reg { + "register_panel", + proc "c" (L: ^lua.State) -> i32 { + context = state.ctx; + + panel_name := strings.clone(string(lua.L_checkstring(L, 1))); + panel_identifier := strings.clone(string(lua.L_checkstring(L, 2))); + core.register_panel_lua(state, panel_name, panel_identifier) + + return i32(lua.OK) + } + }, lua.L_Reg { "spawn_floating_window", proc "c" (L: ^lua.State) -> i32 { @@ -195,6 +207,25 @@ new_state :: proc(_state: ^core.State) { group := lua.L_checkstring(L, 1); name := lua.L_checkstring(L, 2); + + num_args := lua.gettop(state.L) + for i in 0..<(num_args-2) { + if lua.isstring(state.L, 3) { + value := lua.L_checkstring(state.L, 3) + lua.pop(L, 3); + + core.push_command_arg(state, string(value)) + } else if lua.isinteger(state.L, 3) { + value := lua.L_checkinteger(state.L, 3) + lua.pop(L, 3); + + core.push_command_arg(state, i32(value)) + } else { + log.error("expected string or integer for command arguments") + return 0; + } + } + core.run_command(state, string(group), string(name)); return 1; @@ -860,13 +891,13 @@ ui_flags :: proc(L: ^lua.State, index: i32) -> (bit_set[ui.Flag], bool) { return flags, true } -run_editor_action :: proc(state: ^core.State, key: plugin.Key, action: core.LuaEditorAction) { +run_editor_action :: proc(state: ^core.State, key: plugin.Key, action: core.LuaEditorAction, location := #caller_location) { lua.rawgeti(state.L, lua.REGISTRYINDEX, lua.Integer(action.fn_ref)); if lua.pcall(state.L, 0, 0, 0) != i32(lua.OK) { err := lua.tostring(state.L, lua.gettop(state.L)); lua.pop(state.L, lua.gettop(state.L)); - log.error(err); + log.error(err, location); } else { lua.pop(state.L, lua.gettop(state.L)); } @@ -890,6 +921,99 @@ run_ui_function :: proc(state: ^core.State, ui_context: ^ui.Context, fn_ref: i32 } } +run_panel_render :: proc(state: ^core.State, ui_context: ^ui.Context, panel_index: i32, fn_ref: i32) { + lua.getglobal(state.L, "__core_panels") + + lua.rawgeti(state.L, lua.REGISTRYINDEX, lua.Integer(fn_ref)); + + lua.pushinteger(state.L, lua.Integer(panel_index)); + lua.gettable(state.L, -3); + + lua.pushlightuserdata(state.L, ui_context); + if lua.pcall(state.L, 2, 0, 0) != i32(lua.OK) { + err := lua.tostring(state.L, lua.gettop(state.L)); + lua.pop(state.L, lua.gettop(state.L)); + + log.error(err); + } else { + lua.pop(state.L, lua.gettop(state.L)); + } +} + +add_panel :: proc(state: ^core.State, id: core.LuaPanelId) -> (new_panel: core.LuaPanel, ok: bool) { + lua.getglobal(state.L, "__core_panels") + + // create panel list if it doesn't already exist + if !lua.istable(state.L, -1) { + log.info("__core_panels doesn't exist yet, create it..") + + lua.newtable(state.L) + lua.setglobal(state.L, "__core_panels") + } + + lua.getglobal(state.L, "__core_panels") + + l_panel_list := lua.gettop(state.L) + + lua.len(state.L, l_panel_list); + num_panels := lua.tointeger(state.L, -1); + lua.pop(state.L, 1); + + render_ref: i32 + + // lua.pushinteger(state.L, lua.Integer(num_panels + 1)) + { + // create new panel object in lua + + // FIXME: eventually grab the appropriate namespace from the panel id + lua.getglobal(state.L, "nl_spacegirl_plugin_Default_Default_View"); + + lua.getfield(state.L, -1, strings.clone_to_cstring(id.id, allocator = context.temp_allocator)); + if (lua.isnil(state.L, -1)) { + lua.pop(state.L, lua.gettop(state.L)-l_panel_list+1) + + log.error("no lua panel with identifier:", id.id) + return + } + + lua.getfield(state.L, -1, "render") + if lua.isfunction(state.L, -1) { + render_ref = lua.L_ref(state.L, i32(lua.REGISTRYINDEX)); + } else { + lua.pop(state.L, lua.gettop(state.L)-l_panel_list+1) + + log.error("no 'render' function for lua panel:", id.id) + return + } + + lua.getfield(state.L, -1, "new") + if (lua.isnil(state.L, -1)) { + lua.pop(state.L, lua.gettop(state.L)-l_panel_list+1) + + log.error("no 'new' function for lua panel:", id.id) + return + } + + if lua.pcall(state.L, 0, 1, 0) != i32(lua.OK) { + err := lua.tostring(state.L, lua.gettop(state.L)); + lua.pop(state.L, lua.gettop(state.L)-l_panel_list+1); + + // FIXME: do we need this? + // lua.pop(state.L, 1); + + log.error("failed to create new lua panel:", err); + } + log.info("called") + } + lua.rawseti(state.L, l_panel_list, num_panels + 1); + lua.settable(state.L, l_panel_list) + + return core.LuaPanel{ + index = i32(num_panels) + 1, + render_ref = render_ref + }, true +} + // TODO: don't duplicate this procedure ui_file_buffer :: proc(ctx: ^ui.Context, buffer: ^core.FileBuffer) -> ui.Interaction { draw_func := proc(state: ^core.State, box: ^ui.Box, user_data: rawptr) { diff --git a/src/main.odin b/src/main.odin index 87efc8e..c31a951 100644 --- a/src/main.odin +++ b/src/main.odin @@ -1033,6 +1033,8 @@ main :: proc() { commands = make(core.EditorCommandList), command_arena = mem.arena_allocator(&_command_arena), + panel_catalog = make([dynamic]core.PanelId), + window = nil, directory = os.get_current_directory(), plugins = make([dynamic]plugin.Interface), @@ -1062,8 +1064,8 @@ main :: proc() { } } - context.logger = core.new_logger(&state.log_buffer); - // context.logger = log.create_console_logger(); + // context.logger = core.new_logger(&state.log_buffer); + context.logger = log.create_console_logger(); state.ctx = context; // TODO: don't use this @@ -1076,6 +1078,46 @@ main :: proc() { register_default_text_input_actions(&state.input_map.mode[.Normal]); + core.register_editor_command( + &state.commands, + "nl.spacegirl.editor.core", + "Open New Panel", + "Opens a new panel", + proc(state: ^State) { + Args :: struct { + panel_id: string + } + + if args, ok := core.attempt_read_command_args(Args, state.command_args[:]); ok { + log.info("maybe going to open panel with id", args.panel_id) + + for p in state.panel_catalog { + switch v in p { + case core.LuaPanelId: + { + if v.id == args.panel_id { + if index, ok := lua.add_panel(state, v); ok { + for i in 0..