command stuff?

memory-refactor
Patrick Cleavelin 2025-02-19 18:19:56 -06:00
parent bd01fa6cfb
commit 111f2f8a70
8 changed files with 235 additions and 11 deletions

View File

@ -3,10 +3,10 @@ all: editor
editor: src/*.odin # grep odin_highlighter
# odin build src/ -out:bin/editor.o -build-mode:obj -debug -lld
# dsymutil bin/editor.o -o bin/editor.dSYM
odin build src/ -out:bin/editor -lld
../Odin/odin build src/ -out:bin/editor -debug -lld -extra-linker-flags:"-L./"
odin_highlighter: plugins/highlighter/src/*.odin
odin build plugins/highlighter/src/ -build-mode:dll -no-entry-point -out:bin/highlighter
../Odin/odin build plugins/highlighter/src/ -build-mode:dll -no-entry-point -out:bin/highlighter
grep: plugins/grep/src/*.rs
nightly-cargo b --manifest-path=plugins/grep/Cargo.toml

View File

@ -63,13 +63,17 @@
{
devShell = pkgs.mkShell {
buildInputs = with pkgs; (if pkgs.system == "aarch64-darwin" || pkgs.system == "x86_64-darwin" then [
fixed-odin
# fixed-odin
llvmPackages_17.bintools
llvmPackages_17.lld
llvmPackages_17.clang
local-rust
nightly-cargo
rust-analyzer
lua54Packages.stdlib
SDL2
SDL2_ttf
darwin.apple_sdk.frameworks.System
darwin.apple_sdk.frameworks.CoreData
darwin.apple_sdk.frameworks.Kernel
darwin.apple_sdk.frameworks.CoreVideo

View File

@ -1,6 +1,10 @@
local BufferSearchOpen = false
local BufferSearchOpenElapsed = 0
local CommandSearchOpen = false
local CommandSearchOpenElapsed = 0
local CommandList = {}
local LogWindowOpen = false
local LogWindowOpenElapsed = 0
@ -280,6 +284,7 @@ function render_ui_window(ctx)
end
render_buffer_search(ctx)
render_command_search(ctx)
render_log_window(ctx)
LastMouseX = x
@ -323,6 +328,45 @@ function render_buffer_search(ctx)
end
end
function render_command_search(ctx)
if CommandSearchOpen or CommandSearchOpenElapsed > 0 then
if CommandSearchOpen and CommandSearchOpenElapsed < numFrames then
CommandSearchOpenElapsed = CommandSearchOpenElapsed + 1
elseif not CommandSearchOpen and CommandSearchOpenElapsed > 0 then
CommandSearchOpenElapsed = CommandSearchOpenElapsed - 1
end
end
if CommandSearchOpen or CommandSearchOpenElapsed > 0 then
window_percent_width = 75
window_percent_height = 25
if CommandSearchOpenElapsed > 0 then
window_percent_width = ((CommandSearchOpenElapsed/numFrames) * 75)
window_percent_height = ((CommandSearchOpenElapsed/numFrames) * 25)
end
UI.push_parent(ctx, UI.push_floating(ctx, "buffer search canvas", 0, 0))
centered(ctx, "command search window", UI.Horizontal, UI.PercentOfParent(window_percent_width), UI.PercentOfParent(window_percent_height), (
function ()
UI.push_parent(ctx, UI.push_rect(ctx, "window", true, true, UI.Horizontal, UI.Fill, UI.Fill))
UI.push_parent(ctx, UI.push_rect(ctx, "command list", false, false, UI.Vertical, UI.Fill, UI.Fill))
-- local commands = Editor.query_command_group("nl.spacegirl.editor.core")
for i, cmd in ipairs(CommandList) do
flags = {"DrawText"}
if i == CommandSearchIndex then
table.insert(flags, 1, "DrawBorder")
end
interaction = UI.advanced_button(ctx, " "..cmd.name..": "..cmd.description.." ", flags, UI.Fill, UI.FitText)
end
UI.pop_parent(ctx)
UI.pop_parent(ctx)
end
))
UI.pop_parent(ctx)
end
end
function render_log_window(ctx)
if Editor.get_current_buffer_index() ~= -2 then
LogWindowOpen = false
@ -372,6 +416,36 @@ function OnInit()
end
end)},
{Editor.Key.Space, "", {
{Editor.Key.Backtick, "Command Palette",
(function ()
CommandSearchOpen = true
CommandSearchIndex = 1
CommandList = Editor.query_command_group("nl.spacegirl.editor.core")
end),
{
{Editor.Key.Escape, "Close Window", (
function ()
Editor.request_window_close()
CommandSearchOpen = false
end
)},
{Editor.Key.Enter, "Run Command", (
function ()
if CommandList[CommandSearchIndex] ~= nil then
Editor.run_command("nl.spacegirl.editor.core", CommandList[CommandSearchIndex]["name"])
CommandList = {}
Editor.request_window_close()
CommandSearchOpen = false
end
end
)},
-- TODO: don't scroll past selections
{Editor.Key.K, "Move Selection Up", (function () CommandSearchIndex = CommandSearchIndex - 1 end)},
{Editor.Key.J, "Move Selection Down", (function () CommandSearchIndex = CommandSearchIndex + 1 end)},
}
},
{Editor.Key.B, "Buffer Search", (
function ()
BufferSearchOpen = true

View File

@ -46,6 +46,7 @@ close_window_and_free :: proc(state: ^State) {
}
LuaHookRef :: i32;
EditorCommandList :: map[string][dynamic]EditorCommand;
State :: struct {
ctx: runtime.Context,
L: ^lua.State,
@ -76,6 +77,8 @@ State :: struct {
input_map: InputMap,
current_input_map: ^InputActions,
commands: EditorCommandList,
plugins: [dynamic]plugin.Interface,
plugin_vtable: plugin.Plugin,
highlighters: map[string]plugin.OnColorBufferProc,
@ -83,6 +86,12 @@ State :: struct {
lua_hooks: map[plugin.Hook][dynamic]LuaHookRef,
}
EditorCommand :: struct {
name: string,
description: string,
action: EditorAction,
}
current_buffer :: proc(state: ^State) -> ^FileBuffer {
if state.current_buffer == -2 {
return &state.log_buffer;
@ -142,7 +151,7 @@ new_input_map :: proc() -> InputMap {
ti := runtime.type_info_base(type_info_of(Mode));
if v, ok := ti.variant.(runtime.Type_Info_Enum); ok {
for i in &v.values {
input_map.mode[(cast(^Mode)(&i))^] = new_input_actions();
input_map.mode[cast(Mode)i] = new_input_actions();
}
}
@ -158,7 +167,7 @@ new_input_actions :: proc() -> InputActions {
return input_actions;
}
delete_input_map :: proc(input_map: ^InputMap) {
for _, actions in &input_map.mode {
for _, &actions in &input_map.mode {
delete_input_actions(&actions);
}
delete(input_map.mode);
@ -233,3 +242,59 @@ register_ctrl_key_action_group :: proc(input_map: ^InputActions, key: plugin.Key
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};
register_editor_command :: proc(command_list: ^EditorCommandList, command_group, name, description: string, action: EditorAction) {
if _, ok := command_list[command_group]; !ok {
command_list[command_group] = make([dynamic]EditorCommand);
}
runtime.append(&command_list[command_group], EditorCommand {
name = name,
description = description,
action = action,
});
}
query_editor_commands_by_name :: proc(command_list: ^EditorCommandList, name: string, allocator: runtime.Allocator) -> []EditorCommand {
context.allocator = allocator;
commands := make([dynamic]EditorCommand)
for group, list in command_list {
for cmd in list {
if cmd.name == name {
append(&commands, cmd);
}
}
}
return commands[:];
}
query_editor_commands_by_group :: proc(command_list: ^EditorCommandList, name: string, allocator: runtime.Allocator) -> []EditorCommand {
context.allocator = allocator;
commands := make([dynamic]EditorCommand)
for group, list in command_list {
if group == name {
for cmd in list {
append(&commands, cmd);
}
}
}
return commands[:];
}
run_command :: proc(state: ^State, group: string, name: string) {
if cmds, ok := state.commands[group]; ok {
for cmd in cmds {
if cmd.name == name {
log.info("Running command", group, name);
cmd.action(state);
return;
}
}
}
log.error("no command", group, name);
}

View File

@ -679,7 +679,7 @@ new_file_buffer :: proc(allocator: mem.Allocator, file_path: string, base_dir: s
defer os.close(fd);
fi, fstat_err := os.fstat(fd);
if fstat_err > 0 {
if fstat_err != nil {
return FileBuffer{}, make_error(ErrorType.FileIOError, fmt.aprintf("failed to get file info: errno=%x", fstat_err));
}

View File

@ -21,6 +21,9 @@ import "plugin"
State :: core.State;
FileBuffer :: core.FileBuffer;
// TODO: should probably go into state
scratch: mem.Scratch;
scratch_alloc: runtime.Allocator;
state := core.State {};
StateWithUi :: struct {
@ -1022,6 +1025,8 @@ main :: proc() {
source_font_width = 8,
source_font_height = 16,
input_map = core.new_input_map(),
commands = make(core.EditorCommandList),
window = nil,
directory = os.get_current_directory(),
plugins = make([dynamic]plugin.Interface),
@ -1035,19 +1040,55 @@ main :: proc() {
context.logger = core.new_logger(&state.log_buffer);
state.ctx = context;
mem.scratch_allocator_init(&scratch, 1024*1024);
scratch_alloc = mem.scratch_allocator(&scratch);
state.current_input_map = &state.input_map.mode[.Normal];
register_default_input_actions(&state.input_map.mode[.Normal]);
register_default_visual_actions(&state.input_map.mode[.Visual]);
register_default_text_input_actions(&state.input_map.mode[.Normal]);
for arg in os.args[1:] {
buffer, err := core.new_file_buffer(context.allocator, arg, state.directory);
if err.type != .None {
log.error("Failed to create file buffer:", err);
continue;
core.register_editor_command(
&state.commands,
"nl.spacegirl.editor.core",
"New Scratch Buffer",
"Opens a new scratch buffer",
proc(state: ^State) {
buffer := core.new_virtual_file_buffer(context.allocator);
runtime.append(&state.buffers, buffer);
}
)
core.register_editor_command(
&state.commands,
"nl.spacegirl.editor.core",
"Quit",
"Quits the application",
proc(state: ^State) {
state.should_close = true
}
)
{
cmds := core.query_editor_commands_by_group(&state.commands, "nl.spacegirl.editor.core", scratch_alloc);
log.info("List of commands:");
for cmd in cmds {
log.info(cmd.name, ":", cmd.description);
}
}
if len(os.args) > 1 {
for arg in os.args[1:] {
buffer, err := core.new_file_buffer(context.allocator, arg, state.directory);
if err.type != .None {
log.error("Failed to create file buffer:", err);
continue;
}
runtime.append(&state.buffers, buffer);
}
} else {
buffer := core.new_virtual_file_buffer(context.allocator);
runtime.append(&state.buffers, buffer);
}
@ -1314,6 +1355,44 @@ main :: proc() {
return 1;
}
},
lua.L_Reg {
"query_command_group",
proc "c" (L: ^lua.State) -> i32 {
context = state.ctx;
group := lua.L_checkstring(L, 1);
cmds := core.query_editor_commands_by_group(&state.commands, string(group), scratch_alloc);
lua.newtable(L);
{
for cmd, i in cmds {
lua.newtable(L);
{
lua.pushstring(L, strings.clone_to_cstring(cmd.name, scratch_alloc));
lua.setfield(L, -2, "name");
lua.pushstring(L, strings.clone_to_cstring(cmd.description, scratch_alloc));
lua.setfield(L, -2, "description");
}
lua.rawseti(L, -2, lua.Integer(i+1));
}
}
return 1;
}
},
lua.L_Reg {
"run_command",
proc "c" (L: ^lua.State) -> i32 {
context = state.ctx;
group := lua.L_checkstring(L, 1);
name := lua.L_checkstring(L, 2);
core.run_command(&state, string(group), string(name));
return 1;
}
}
};
bbb = raw_data(editor_lib[:]);

View File

@ -1,3 +1,5 @@
- Stack Like Allocator (for cross-frame temp data)
- Undo/Redo
- Edit History Tree
- Finish selections