command stuff?
parent
bd01fa6cfb
commit
111f2f8a70
4
Makefile
4
Makefile
|
@ -3,10 +3,10 @@ all: editor
|
||||||
editor: src/*.odin # grep odin_highlighter
|
editor: src/*.odin # grep odin_highlighter
|
||||||
# odin build src/ -out:bin/editor.o -build-mode:obj -debug -lld
|
# odin build src/ -out:bin/editor.o -build-mode:obj -debug -lld
|
||||||
# dsymutil bin/editor.o -o bin/editor.dSYM
|
# 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_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
|
grep: plugins/grep/src/*.rs
|
||||||
nightly-cargo b --manifest-path=plugins/grep/Cargo.toml
|
nightly-cargo b --manifest-path=plugins/grep/Cargo.toml
|
||||||
|
|
|
@ -63,13 +63,17 @@
|
||||||
{
|
{
|
||||||
devShell = pkgs.mkShell {
|
devShell = pkgs.mkShell {
|
||||||
buildInputs = with pkgs; (if pkgs.system == "aarch64-darwin" || pkgs.system == "x86_64-darwin" then [
|
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
|
local-rust
|
||||||
nightly-cargo
|
nightly-cargo
|
||||||
rust-analyzer
|
rust-analyzer
|
||||||
lua54Packages.stdlib
|
lua54Packages.stdlib
|
||||||
SDL2
|
SDL2
|
||||||
SDL2_ttf
|
SDL2_ttf
|
||||||
|
darwin.apple_sdk.frameworks.System
|
||||||
darwin.apple_sdk.frameworks.CoreData
|
darwin.apple_sdk.frameworks.CoreData
|
||||||
darwin.apple_sdk.frameworks.Kernel
|
darwin.apple_sdk.frameworks.Kernel
|
||||||
darwin.apple_sdk.frameworks.CoreVideo
|
darwin.apple_sdk.frameworks.CoreVideo
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
local BufferSearchOpen = false
|
local BufferSearchOpen = false
|
||||||
local BufferSearchOpenElapsed = 0
|
local BufferSearchOpenElapsed = 0
|
||||||
|
|
||||||
|
local CommandSearchOpen = false
|
||||||
|
local CommandSearchOpenElapsed = 0
|
||||||
|
local CommandList = {}
|
||||||
|
|
||||||
local LogWindowOpen = false
|
local LogWindowOpen = false
|
||||||
local LogWindowOpenElapsed = 0
|
local LogWindowOpenElapsed = 0
|
||||||
|
|
||||||
|
@ -280,6 +284,7 @@ function render_ui_window(ctx)
|
||||||
end
|
end
|
||||||
|
|
||||||
render_buffer_search(ctx)
|
render_buffer_search(ctx)
|
||||||
|
render_command_search(ctx)
|
||||||
render_log_window(ctx)
|
render_log_window(ctx)
|
||||||
|
|
||||||
LastMouseX = x
|
LastMouseX = x
|
||||||
|
@ -323,6 +328,45 @@ function render_buffer_search(ctx)
|
||||||
end
|
end
|
||||||
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)
|
function render_log_window(ctx)
|
||||||
if Editor.get_current_buffer_index() ~= -2 then
|
if Editor.get_current_buffer_index() ~= -2 then
|
||||||
LogWindowOpen = false
|
LogWindowOpen = false
|
||||||
|
@ -372,6 +416,36 @@ function OnInit()
|
||||||
end
|
end
|
||||||
end)},
|
end)},
|
||||||
{Editor.Key.Space, "", {
|
{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", (
|
{Editor.Key.B, "Buffer Search", (
|
||||||
function ()
|
function ()
|
||||||
BufferSearchOpen = true
|
BufferSearchOpen = true
|
||||||
|
|
|
@ -46,6 +46,7 @@ close_window_and_free :: proc(state: ^State) {
|
||||||
}
|
}
|
||||||
|
|
||||||
LuaHookRef :: i32;
|
LuaHookRef :: i32;
|
||||||
|
EditorCommandList :: map[string][dynamic]EditorCommand;
|
||||||
State :: struct {
|
State :: struct {
|
||||||
ctx: runtime.Context,
|
ctx: runtime.Context,
|
||||||
L: ^lua.State,
|
L: ^lua.State,
|
||||||
|
@ -76,6 +77,8 @@ State :: struct {
|
||||||
input_map: InputMap,
|
input_map: InputMap,
|
||||||
current_input_map: ^InputActions,
|
current_input_map: ^InputActions,
|
||||||
|
|
||||||
|
commands: EditorCommandList,
|
||||||
|
|
||||||
plugins: [dynamic]plugin.Interface,
|
plugins: [dynamic]plugin.Interface,
|
||||||
plugin_vtable: plugin.Plugin,
|
plugin_vtable: plugin.Plugin,
|
||||||
highlighters: map[string]plugin.OnColorBufferProc,
|
highlighters: map[string]plugin.OnColorBufferProc,
|
||||||
|
@ -83,6 +86,12 @@ State :: struct {
|
||||||
lua_hooks: map[plugin.Hook][dynamic]LuaHookRef,
|
lua_hooks: map[plugin.Hook][dynamic]LuaHookRef,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EditorCommand :: struct {
|
||||||
|
name: string,
|
||||||
|
description: string,
|
||||||
|
action: EditorAction,
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
@ -142,7 +151,7 @@ new_input_map :: proc() -> InputMap {
|
||||||
ti := runtime.type_info_base(type_info_of(Mode));
|
ti := runtime.type_info_base(type_info_of(Mode));
|
||||||
if v, ok := ti.variant.(runtime.Type_Info_Enum); ok {
|
if v, ok := ti.variant.(runtime.Type_Info_Enum); ok {
|
||||||
for i in &v.values {
|
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;
|
return input_actions;
|
||||||
}
|
}
|
||||||
delete_input_map :: proc(input_map: ^InputMap) {
|
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_actions(&actions);
|
||||||
}
|
}
|
||||||
delete(input_map.mode);
|
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_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_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);
|
||||||
|
}
|
||||||
|
|
|
@ -679,7 +679,7 @@ new_file_buffer :: proc(allocator: mem.Allocator, file_path: string, base_dir: s
|
||||||
defer os.close(fd);
|
defer os.close(fd);
|
||||||
|
|
||||||
fi, fstat_err := os.fstat(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));
|
return FileBuffer{}, make_error(ErrorType.FileIOError, fmt.aprintf("failed to get file info: errno=%x", fstat_err));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,9 @@ import "plugin"
|
||||||
State :: core.State;
|
State :: core.State;
|
||||||
FileBuffer :: core.FileBuffer;
|
FileBuffer :: core.FileBuffer;
|
||||||
|
|
||||||
|
// TODO: should probably go into state
|
||||||
|
scratch: mem.Scratch;
|
||||||
|
scratch_alloc: runtime.Allocator;
|
||||||
state := core.State {};
|
state := core.State {};
|
||||||
|
|
||||||
StateWithUi :: struct {
|
StateWithUi :: struct {
|
||||||
|
@ -1022,6 +1025,8 @@ main :: proc() {
|
||||||
source_font_width = 8,
|
source_font_width = 8,
|
||||||
source_font_height = 16,
|
source_font_height = 16,
|
||||||
input_map = core.new_input_map(),
|
input_map = core.new_input_map(),
|
||||||
|
commands = make(core.EditorCommandList),
|
||||||
|
|
||||||
window = nil,
|
window = nil,
|
||||||
directory = os.get_current_directory(),
|
directory = os.get_current_directory(),
|
||||||
plugins = make([dynamic]plugin.Interface),
|
plugins = make([dynamic]plugin.Interface),
|
||||||
|
@ -1035,19 +1040,55 @@ main :: proc() {
|
||||||
context.logger = core.new_logger(&state.log_buffer);
|
context.logger = core.new_logger(&state.log_buffer);
|
||||||
state.ctx = context;
|
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];
|
state.current_input_map = &state.input_map.mode[.Normal];
|
||||||
register_default_input_actions(&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_visual_actions(&state.input_map.mode[.Visual]);
|
||||||
|
|
||||||
register_default_text_input_actions(&state.input_map.mode[.Normal]);
|
register_default_text_input_actions(&state.input_map.mode[.Normal]);
|
||||||
|
|
||||||
for arg in os.args[1:] {
|
core.register_editor_command(
|
||||||
buffer, err := core.new_file_buffer(context.allocator, arg, state.directory);
|
&state.commands,
|
||||||
if err.type != .None {
|
"nl.spacegirl.editor.core",
|
||||||
log.error("Failed to create file buffer:", err);
|
"New Scratch Buffer",
|
||||||
continue;
|
"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);
|
runtime.append(&state.buffers, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1314,6 +1355,44 @@ main :: proc() {
|
||||||
return 1;
|
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[:]);
|
bbb = raw_data(editor_lib[:]);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue