get base panel registration working

memory-refactor
Patrick Cleavelin 2025-03-01 20:45:07 -06:00
parent 0039da5c42
commit 6541256a8c
5 changed files with 272 additions and 136 deletions

View File

@ -4,6 +4,38 @@ M.version = "0.1"
M.name = "Default_View" M.name = "Default_View"
M.namespace = "nl_spacegirl_plugin_Default" 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() function M.open_file_search_window()
local input = { local input = {
{Editor.Key.Enter, "Open File", function() Editor.log("this should open a file") end} {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("default view loaded")
Editor.log(nl_spacegirl_plugin_Default_Legacy_View['namespace']) 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.register_key_group({
{Editor.Key.Space, "", { {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 end
function M.view_render(cx) function M.view_render(cx)

View File

@ -314,7 +314,7 @@ function M.render_ui_window(ctx)
end end
-- render_buffer_search(ctx) -- render_buffer_search(ctx)
render_command_search(ctx) -- render_command_search(ctx)
render_log_window(ctx) render_log_window(ctx)
LastMouseX = x LastMouseX = x
@ -395,7 +395,7 @@ function M.open_buffer_search_window(ctx)
-- end -- end
end end
function M.open_command_palette(ctx) function M.open_command_palette()
-- if CommandSearchOpen or CommandSearchOpenElapsed > 0 then -- if CommandSearchOpen or CommandSearchOpenElapsed > 0 then
-- if CommandSearchOpen and CommandSearchOpenElapsed < numFrames then -- if CommandSearchOpen and CommandSearchOpenElapsed < numFrames then
-- CommandSearchOpenElapsed = CommandSearchOpenElapsed + 1 -- 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) Editor.register_hook(Editor.Hook.OnBufferInput, handle_buffer_input)
end end

View File

@ -92,6 +92,9 @@ State :: struct {
command_arena: runtime.Allocator, command_arena: runtime.Allocator,
command_args: [dynamic]EditorCommandArgument, command_args: [dynamic]EditorCommandArgument,
active_panels: [128]Maybe(Panel),
panel_catalog: [dynamic]PanelId,
plugins: [dynamic]plugin.Interface, plugins: [dynamic]plugin.Interface,
new_plugins: [dynamic]plugin.NewInterface, new_plugins: [dynamic]plugin.NewInterface,
plugin_vtable: plugin.Plugin, plugin_vtable: plugin.Plugin,
@ -111,11 +114,34 @@ EditorCommandExec :: struct {
args: [dynamic]EditorCommandArgument, args: [dynamic]EditorCommandArgument,
} }
EditorCommandArgument :: union { EditorCommandArgument :: union #no_nil {
string, string,
i32 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 { current_buffer :: proc(state: ^State) -> ^FileBuffer {
if state.current_buffer == -2 { if state.current_buffer == -2 {
return &state.log_buffer; return &state.log_buffer;
@ -398,3 +424,11 @@ where intrinsics.type_is_struct(T) {
return return
} }
register_panel_lua :: proc(state: ^State, name: string, id: string) {
append(&state.panel_catalog, LuaPanelId {
id = id,
name = name,
})
}

View File

@ -63,6 +63,18 @@ new_state :: proc(_state: ^core.State) {
"register_key_group", "register_key_group",
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 { lua.L_Reg {
"spawn_floating_window", "spawn_floating_window",
proc "c" (L: ^lua.State) -> i32 { proc "c" (L: ^lua.State) -> i32 {
@ -195,6 +207,25 @@ new_state :: proc(_state: ^core.State) {
group := lua.L_checkstring(L, 1); group := lua.L_checkstring(L, 1);
name := lua.L_checkstring(L, 2); 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)); core.run_command(state, string(group), string(name));
return 1; return 1;
@ -860,13 +891,13 @@ ui_flags :: proc(L: ^lua.State, index: i32) -> (bit_set[ui.Flag], bool) {
return flags, true 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)); lua.rawgeti(state.L, lua.REGISTRYINDEX, lua.Integer(action.fn_ref));
if lua.pcall(state.L, 0, 0, 0) != i32(lua.OK) { if lua.pcall(state.L, 0, 0, 0) != i32(lua.OK) {
err := lua.tostring(state.L, lua.gettop(state.L)); err := lua.tostring(state.L, lua.gettop(state.L));
lua.pop(state.L, lua.gettop(state.L)); lua.pop(state.L, lua.gettop(state.L));
log.error(err); log.error(err, location);
} else { } else {
lua.pop(state.L, lua.gettop(state.L)); 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 // TODO: don't duplicate this procedure
ui_file_buffer :: proc(ctx: ^ui.Context, buffer: ^core.FileBuffer) -> ui.Interaction { ui_file_buffer :: proc(ctx: ^ui.Context, buffer: ^core.FileBuffer) -> ui.Interaction {
draw_func := proc(state: ^core.State, box: ^ui.Box, user_data: rawptr) { draw_func := proc(state: ^core.State, box: ^ui.Box, user_data: rawptr) {

View File

@ -1033,6 +1033,8 @@ main :: proc() {
commands = make(core.EditorCommandList), commands = make(core.EditorCommandList),
command_arena = mem.arena_allocator(&_command_arena), command_arena = mem.arena_allocator(&_command_arena),
panel_catalog = make([dynamic]core.PanelId),
window = nil, window = nil,
directory = os.get_current_directory(), directory = os.get_current_directory(),
plugins = make([dynamic]plugin.Interface), plugins = make([dynamic]plugin.Interface),
@ -1062,8 +1064,8 @@ main :: proc() {
} }
} }
context.logger = core.new_logger(&state.log_buffer); // context.logger = core.new_logger(&state.log_buffer);
// context.logger = log.create_console_logger(); context.logger = log.create_console_logger();
state.ctx = context; state.ctx = context;
// TODO: don't use this // TODO: don't use this
@ -1076,6 +1078,46 @@ main :: proc() {
register_default_text_input_actions(&state.input_map.mode[.Normal]); 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..<len(state.active_panels) {
if state.active_panels[i] == nil {
state.active_panels[i] = index
break;
}
}
} else {
log.error("failed to open panel")
}
}
}
case core.LibPanelId:
{
log.warn("lib panels not supported yet")
}
}
}
}
}
)
core.register_editor_command( core.register_editor_command(
&state.commands, &state.commands,
"nl.spacegirl.editor.core", "nl.spacegirl.editor.core",
@ -1218,137 +1260,25 @@ main :: proc() {
control_key_pressed: bool; control_key_pressed: bool;
for !state.should_close { for !state.should_close {
// if false { // TODO: remove this functionality
// buffer := core.current_buffer(&state);
// ui.push_parent(&ui_context, ui.push_box(&ui_context, "main", {}, .Vertical, semantic_size = {ui.make_semantic_size(.Fill, 100), ui.make_semantic_size(.Fill, 100)}));
// defer ui.pop_parent(&ui_context);
// {
// ui.push_parent(&ui_context, ui.push_box(&ui_context, "top_nav", {.DrawBackground}, semantic_size = {ui.make_semantic_size(.PercentOfParent, 100), ui.make_semantic_size(.Exact, state.source_font_height)}));
// defer ui.pop_parent(&ui_context);
// if ui.label(&ui_context, "Editor").clicked {
// fmt.println("you clicked the button");
// }
// ui.push_box(
// &ui_context,
// "nav spacer",
// {.DrawBackground},
// semantic_size = {
// ui.make_semantic_size(.Exact, 16),
// ui.make_semantic_size(.Exact, state.source_font_height)
// }
// );
// if ui.label(&ui_context, "Buffers").clicked {
// fmt.println("you clicked the button");
// }
// }
// {
// ui.push_parent(&ui_context, ui.push_box(&ui_context, "deezbuffer", {}, .Horizontal, semantic_size = {ui.make_semantic_size(.PercentOfParent, 100), ui.make_semantic_size(.Fill, 0)}));
// defer ui.pop_parent(&ui_context);
// {
// ui.push_parent(&ui_context, ui.push_box(&ui_context, "left side", {}, .Vertical, semantic_size = {ui.make_semantic_size(.Fill), ui.make_semantic_size(.Fill, 0)}));
// defer ui.pop_parent(&ui_context);
// {
// if ui_file_buffer(&ui_context, &state.buffers[0]).clicked {
// state.current_buffer = 0;
// }
// }
// {
// if ui_file_buffer(&ui_context, &state.buffers[0+1]).clicked {
// state.current_buffer = 1;
// }
// }
// {
// if ui_file_buffer(&ui_context, &state.buffers[0+2]).clicked {
// state.current_buffer = 2;
// }
// }
// }
// {
// ui.push_parent(&ui_context, ui.push_box(&ui_context, "right side", {}, .Vertical, semantic_size = {ui.make_semantic_size(.Fill), ui.make_semantic_size(.Fill, 0)}));
// defer ui.pop_parent(&ui_context);
// {
// if ui_file_buffer(&ui_context, core.current_buffer(&state)).clicked {
// state.current_buffer = 3;
// }
// }
// }
// }
// {
// ui.push_parent(&ui_context, ui.push_box(&ui_context, "bottom stats", {.DrawBackground}, semantic_size = {ui.make_semantic_size(.PercentOfParent, 100), ui.make_semantic_size(.Exact, state.source_font_height)}));
// defer ui.pop_parent(&ui_context);
// label := "";
// if state.mode == .Insert {
// label = "INSERT";
// } else if state.mode == .Normal {
// label = "NORMAL";
// }
// if ui.label(&ui_context, label).clicked {
// fmt.println("you clicked the button");
// }
// ui.spacer(&ui_context, "mode spacer", semantic_size = {ui.make_semantic_size(.Exact, 16), ui.make_semantic_size(.Fill)});
// relative_file_path, _ := filepath.rel(state.directory, buffer.file_path, context.temp_allocator)
// ui.label(&ui_context, relative_file_path);
// ui.spacer(&ui_context, "stats inbetween");
// {
// ui.push_parent(&ui_context, ui.push_box(&ui_context, "center info", {}, semantic_size = ui.ChildrenSum));
// defer ui.pop_parent(&ui_context);
// line_info_text := fmt.tprintf(
// //"Line: %d, Col: %d, Len: %d --- Slice Index: %d, Content Index: %d",
// "Line: %d, Col: %d",
// buffer.cursor.line + 1,
// buffer.cursor.col + 1,
// //core.file_buffer_line_length(buffer, buffer.cursor.index),
// // buffer.cursor.index.slice_index,
// // buffer.cursor.index.content_index,
// );
// ui.label(&ui_context, line_info_text);
// mouse_pos_str := fmt.tprintf("x,y: [%d,%d]", ui_context.mouse_x, ui_context.mouse_y);
// ui.label(&ui_context, mouse_pos_str);
// }
// }
// }
// TODO: move this to view.lua
// log_window, _ := ui.push_floating(&ui_context, "log", {0,0}, flags = {.Floating, .DrawBackground}, semantic_size = {ui.make_semantic_size(.PercentOfParent, 75), ui.make_semantic_size(.PercentOfParent, 75)});
// ui.push_parent(&ui_context, log_window);
{
// defer ui.pop_parent(&ui_context);
ui_file_buffer(&ui_context, &state.log_buffer);
}
if draw_hooks, ok := state.lua_hooks[plugin.Hook.Draw]; ok { if draw_hooks, ok := state.lua_hooks[plugin.Hook.Draw]; ok {
for hook_ref in draw_hooks { for hook_ref in draw_hooks {
/* lua.run_ui_function(&state, &ui_context, hook_ref)
lua.rawgeti(state.L, lua.REGISTRYINDEX, lua.Integer(hook_ref));
lua.pushlightuserdata(state.L, &ui_context);
if lua.pcall(state.L, 1, 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));
}
*/
} }
} }
for panel in state.active_panels {
if panel != nil {
switch v in panel.? {
case core.LuaPanel:
lua.run_panel_render(&state, &ui_context, v.index, v.render_ref)
case core.LibPanel:
log.warn("LibPanel not supported")
}
}
}
// TODO: mirror how this is done for Lua
if state.window != nil && state.window.draw != nil { if state.window != nil && state.window.draw != nil {
state.window.draw(state.plugin_vtable, state.window.user_data); state.window.draw(state.plugin_vtable, state.window.user_data);
} }