Compare commits
3 Commits
85ca1a6a9e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e7acd4a20 | ||
|
|
4e5a0f6a9b | ||
|
|
f297006dcb |
@@ -36,10 +36,30 @@ Commands TODO:
|
||||
- Console: OK concept but constrain
|
||||
- Turned off by default
|
||||
- Special: non editable, hotkeys don't work etc.
|
||||
- I'M SETTING ACTIVE WINDOW AFTER COMMAND!!! DO WE CONTINUE WITH THIS?
|
||||
|
||||
## Hooks and bindings
|
||||
|
||||
```
|
||||
|
||||
struct Hook {
|
||||
String name;
|
||||
String trigger;
|
||||
HookFunction function;
|
||||
};
|
||||
|
||||
void Command_New() {
|
||||
...
|
||||
} RegisterCommand(Command_New, "ctrl-n");
|
||||
|
||||
void Hook_FormatOnSave() {
|
||||
} RegisterHook(Hook_FormatOnSave, "onsave");
|
||||
|
||||
|
||||
Array<Hook> Hooks;
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
DESIGN try to make console less special, make stuff reusable etc.
|
||||
|
||||
@@ -37,8 +37,6 @@ For(arr.reverse_iter()) {
|
||||
#define ForItem(it, array) for (auto &it : (array))
|
||||
#define For(array) ForItem(it, array)
|
||||
|
||||
|
||||
|
||||
template <class T>
|
||||
struct Slice {
|
||||
T *data;
|
||||
|
||||
@@ -212,4 +212,9 @@ inline uint64_t GetRandomU64(RandomSeed *state) {
|
||||
x ^= x >> 7;
|
||||
x ^= x << 17;
|
||||
return state->a = x;
|
||||
}
|
||||
}
|
||||
|
||||
#define STRINGIFY_(x) x
|
||||
#define STRINGIFY(x) STRINGIFY_(x)
|
||||
#define CONCAT_(a, b) a ## b
|
||||
#define CONCAT(a, b) CONCAT_(a, b)
|
||||
|
||||
@@ -21,11 +21,11 @@ API void (*Error)(const char *, ...);
|
||||
|
||||
struct backtrace_state *backtrace_state = NULL;
|
||||
|
||||
void os_core_backtrace_error_callback(void *data, const char *msg, int errnum) {
|
||||
void BacktraceOnError(void *data, const char *msg, int errnum) {
|
||||
Error("libbacktrace error: %s (errnum: %d)\n", msg, errnum);
|
||||
}
|
||||
|
||||
int os_core_backtrace_print_callback(void *data, uintptr_t pc, const char *filename, int lineno, const char *function) {
|
||||
int BacktraceOnPrint(void *data, uintptr_t pc, const char *filename, int lineno, const char *function) {
|
||||
bool printed = false;
|
||||
if (filename != NULL) {
|
||||
char buffer[512];
|
||||
@@ -43,16 +43,16 @@ int os_core_backtrace_print_callback(void *data, uintptr_t pc, const char *filen
|
||||
return 0;
|
||||
}
|
||||
|
||||
void os_unix_crash_handler(int signal, siginfo_t* info, void* context) {
|
||||
backtrace_full(backtrace_state, 2, os_core_backtrace_print_callback, os_core_backtrace_error_callback, NULL);
|
||||
void CrashHandler(int signal, siginfo_t* info, void* context) {
|
||||
backtrace_full(backtrace_state, 2, BacktraceOnPrint, BacktraceOnError, NULL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void os_unix_register_crash_handler(void) {
|
||||
backtrace_state = backtrace_create_state(NULL, 1, os_core_backtrace_error_callback, NULL);
|
||||
void RegisterCrashHandler(void) {
|
||||
backtrace_state = backtrace_create_state(NULL, 1, BacktraceOnError, NULL);
|
||||
|
||||
struct sigaction sa;
|
||||
sa.sa_sigaction = os_unix_crash_handler;
|
||||
sa.sa_sigaction = CrashHandler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||
|
||||
@@ -65,7 +65,7 @@ void os_unix_register_crash_handler(void) {
|
||||
|
||||
API void InitOS(void (*error_proc)(const char *, ...)) {
|
||||
Error = error_proc;
|
||||
os_unix_register_crash_handler();
|
||||
RegisterCrashHandler();
|
||||
}
|
||||
|
||||
API String ReadFile(Allocator al, String path) {
|
||||
|
||||
@@ -1400,7 +1400,7 @@ void RunBufferTest() {
|
||||
DeinitBuffer(&buffer);
|
||||
TrackingAllocatorCheck();
|
||||
}
|
||||
}
|
||||
} RegisterFunction(&TestFunctions, RunBufferTest);
|
||||
|
||||
///////////////////////////////
|
||||
// Management
|
||||
|
||||
@@ -222,7 +222,7 @@ void ReportErrorf(const char *fmt, ...) {
|
||||
View *view = GetView(NullViewID);
|
||||
if (view) {
|
||||
Appendf(view, "%S\n", string);
|
||||
NextActiveWindowID = NullWindowID;
|
||||
ActiveWindowID = NullWindowID;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -613,15 +613,6 @@ void TrimTrailingWhitespace(Buffer *buffer, bool trim_lines_with_caret = false)
|
||||
view->update_scroll = false;
|
||||
}
|
||||
|
||||
int Lua_TrimTrailingWhitespace(lua_State *L) {
|
||||
lua_Integer buffer_id = luaL_checkinteger(L, 1);
|
||||
int trim_lines_with_caret = lua_toboolean(L, 2);
|
||||
lua_pop(L, 2);
|
||||
Buffer *buffer = GetBuffer({buffer_id});
|
||||
TrimTrailingWhitespace(buffer, trim_lines_with_caret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ConvertLineEndingsToLF(Buffer *buffer, bool trim_lines_with_caret = false) {
|
||||
Scratch scratch;
|
||||
|
||||
@@ -654,15 +645,6 @@ void ConvertLineEndingsToLF(Buffer *buffer, bool trim_lines_with_caret = false)
|
||||
view->update_scroll = false;
|
||||
}
|
||||
|
||||
int Lua_ConvertLineEndingsToLF(lua_State *L) {
|
||||
lua_Integer buffer_id = luaL_checkinteger(L, 1);
|
||||
int trim_lines_with_caret = lua_toboolean(L, 2);
|
||||
lua_pop(L, 2);
|
||||
Buffer *buffer = GetBuffer({buffer_id});
|
||||
ConvertLineEndingsToLF(buffer, trim_lines_with_caret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ApplyClangFormat(Buffer *buffer) {
|
||||
Scratch scratch;
|
||||
String string = AllocCharString(scratch, buffer);
|
||||
@@ -670,22 +652,6 @@ void ApplyClangFormat(Buffer *buffer) {
|
||||
ReplaceWithoutMovingCarets(buffer, GetRange(buffer), {temp_buffer->str, temp_buffer->len});
|
||||
}
|
||||
|
||||
int Lua_ApplyClangFormat(lua_State *L) {
|
||||
lua_Integer buffer_id = luaL_checkinteger(L, 1);
|
||||
lua_pop(L, 1);
|
||||
Buffer *buffer = GetBuffer({buffer_id});
|
||||
ApplyClangFormat(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Lua_GetBufferNameByID(lua_State *L) {
|
||||
lua_Integer buffer_id = luaL_checkinteger(L, 1);
|
||||
lua_pop(L, 1);
|
||||
Buffer *buffer = GetBuffer({buffer_id});
|
||||
lua_pushlstring(L, buffer->name.data, buffer->name.len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void SaveBuffer(Buffer *buffer) {
|
||||
CallOnSave(buffer->id);
|
||||
|
||||
@@ -702,29 +668,6 @@ void SaveBuffer(Buffer *buffer) {
|
||||
}
|
||||
}
|
||||
|
||||
void Command_Save() {
|
||||
BSet active = GetBSet(LastActiveLayoutWindowID);
|
||||
SaveBuffer(active.buffer);
|
||||
} RegisterCommand(Command_Save);
|
||||
|
||||
int Lua_Save(lua_State *L) {
|
||||
Command_Save();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Command_SaveAll() {
|
||||
For(Buffers) {
|
||||
if (it->file_mod_time) {
|
||||
SaveBuffer(it);
|
||||
}
|
||||
}
|
||||
} RegisterCommand(Command_SaveAll);
|
||||
|
||||
int Lua_SaveAll(lua_State *L) {
|
||||
Command_SaveAll();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void KillSelectedLines(View *view) {
|
||||
Scratch scratch;
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
@@ -988,17 +931,6 @@ void ReopenBuffer(Buffer *buffer) {
|
||||
buffer->dirty = false;
|
||||
}
|
||||
|
||||
void Command_Reopen() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
ReopenBuffer(main.buffer);
|
||||
NextActiveWindowID = main.window->id;
|
||||
} RegisterCommand(Command_Reopen);
|
||||
|
||||
int Lua_Reopen(lua_State *L) {
|
||||
Command_Reopen();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void New(Window *window, String name = "") {
|
||||
View *view = GetView(window->active_view);
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
@@ -1016,19 +948,6 @@ void New(Window *window, String name = "") {
|
||||
WindowOpenBufferView(window, name);
|
||||
}
|
||||
|
||||
void Command_New() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
New(main.window, "");
|
||||
} RegisterCommand(Command_New);
|
||||
|
||||
int Lua_New(lua_State *L) {
|
||||
String name = lua_tostring(L, 1);
|
||||
lua_pop(L, 1);
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
New(main.window, name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NewDir(Window *window, String name = "") {
|
||||
View *view = GetView(window->active_view);
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
@@ -1048,36 +967,6 @@ void NewDir(Window *window, String name = "") {
|
||||
Open(name);
|
||||
}
|
||||
|
||||
int Lua_NewDir(lua_State *L) {
|
||||
String name = lua_tostring(L, 1);
|
||||
lua_pop(L, 1);
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
NewDir(main.window, name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Command_ToggleFullscreen() {
|
||||
if (IsInFullscreen) {
|
||||
SDL_SetWindowSize(SDLWindow, FullScreenSizeX, FullScreenSizeY);
|
||||
SDL_SetWindowPosition(SDLWindow, FullScreenPositionX, FullScreenPositionY);
|
||||
} else {
|
||||
SDL_GetWindowSize(SDLWindow, &FullScreenSizeX, &FullScreenSizeY);
|
||||
SDL_GetWindowPosition(SDLWindow, &FullScreenPositionX, &FullScreenPositionY);
|
||||
|
||||
SDL_DisplayID display = SDL_GetDisplayForWindow(SDLWindow);
|
||||
const SDL_DisplayMode *dm = SDL_GetCurrentDisplayMode(display);
|
||||
SDL_SetWindowSize(SDLWindow, dm->w, dm->h);
|
||||
SDL_SetWindowPosition(SDLWindow, 0, 0);
|
||||
}
|
||||
|
||||
IsInFullscreen = !IsInFullscreen;
|
||||
} RegisterCommand(Command_ToggleFullscreen);
|
||||
|
||||
int Lua_ToggleFullscreen(lua_State *L) {
|
||||
Command_ToggleFullscreen();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ListFilesRecursive(Buffer *buffer, String dir) {
|
||||
Scratch scratch(buffer->line_starts.allocator);
|
||||
for (FileIter it = IterateFiles(scratch, dir); IsValid(it); Advance(&it)) {
|
||||
@@ -1096,20 +985,6 @@ void ListFilesRecursive(Buffer *buffer, String dir) {
|
||||
}
|
||||
}
|
||||
|
||||
void Command_ListCode() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
JumpGarbageBuffer(&main);
|
||||
ListFilesRecursive(main.buffer, WorkDir);
|
||||
main.view->fuzzy_search = true;
|
||||
main.view->update_scroll = true;
|
||||
SelectRange(main.view, GetBufferEndAsRange(main.buffer));
|
||||
} RegisterCommand(Command_ListCode);
|
||||
|
||||
int Lua_ListCode(lua_State *L) {
|
||||
Command_ListCode();
|
||||
return 0;
|
||||
}
|
||||
|
||||
View *ExecHidden(String buffer_name, String cmd, String working_dir) {
|
||||
View *view = OpenBufferView(buffer_name);
|
||||
Exec(view->id, true, cmd, working_dir);
|
||||
@@ -1119,20 +994,13 @@ View *ExecHidden(String buffer_name, String cmd, String working_dir) {
|
||||
BSet Exec(String cmd, String working_dir, bool set_active = true) {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
if (set_active) {
|
||||
NextActiveWindowID = main.window->id;
|
||||
ActiveWindowID = main.window->id;
|
||||
}
|
||||
JumpGarbageBuffer(&main);
|
||||
Exec(main.view->id, true, cmd, working_dir);
|
||||
return main;
|
||||
}
|
||||
|
||||
int Lua_C(lua_State *L) {
|
||||
String string = lua_tostring(L, 1);
|
||||
lua_pop(L, 1);
|
||||
Exec(string, GetMainDir());
|
||||
return 0;
|
||||
}
|
||||
|
||||
BSet Open(Window *window, String path, String meta, bool set_active = true) {
|
||||
Scratch scratch;
|
||||
BSet set = GetBSet(window);
|
||||
@@ -1140,7 +1008,7 @@ BSet Open(Window *window, String path, String meta, bool set_active = true) {
|
||||
OnOpenResult ores = CallOnOpen(scratch, path, meta);
|
||||
if (ores.kind == "text") {
|
||||
if (set_active) {
|
||||
NextActiveWindowID = set.window->id;
|
||||
ActiveWindowID = set.window->id;
|
||||
}
|
||||
if (IsDir(ores.file_path)) {
|
||||
JumpGarbageBuffer(&set, GetUniqueBufferName(ores.file_path, "temp", ".dirlisting"));
|
||||
@@ -1161,7 +1029,7 @@ BSet Open(Window *window, String path, String meta, bool set_active = true) {
|
||||
UpdateScroll(set.window, true);
|
||||
} else if (ores.kind == "exec") {
|
||||
if (set_active) {
|
||||
NextActiveWindowID = set.window->id;
|
||||
ActiveWindowID = set.window->id;
|
||||
}
|
||||
JumpGarbageBuffer(&set);
|
||||
Exec(set.view->id, true, ores.cmd, ores.working_dir);
|
||||
@@ -1190,103 +1058,6 @@ BSet Open(String16 path, String meta) {
|
||||
return Open(string, meta);
|
||||
}
|
||||
|
||||
int Lua_Open(lua_State *L) {
|
||||
Scratch scratch;
|
||||
String path = luaL_checkstring(L, 1);
|
||||
lua_pop(L, 1);
|
||||
Open(path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Lua_Cmd(lua_State *L) {
|
||||
if (!lua_istable(L, -1)) luaL_error(L, "expected a table as argument");
|
||||
defer { lua_pop(L, 1); };
|
||||
|
||||
lua_getfield(L, -1, "working_dir");
|
||||
String working_dir = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
if (working_dir == "") {
|
||||
working_dir = GetMainDir();
|
||||
}
|
||||
|
||||
lua_getfield(L, -1, "cmd");
|
||||
if (!lua_isstring(L, -1)) luaL_error(L, "expected a string for cmd param");
|
||||
String cmd = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, -1, "kind");
|
||||
String kind = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
if (kind == "console") {
|
||||
BSet set = GetConsoleSet();
|
||||
main.window->active_goto_list = set.view->id;
|
||||
main.window->goto_list_pos = set.buffer->len;
|
||||
SelectRange(set.view, MakeRange(set.buffer->len));
|
||||
BeginJump(&set);
|
||||
Exec(set.view->id, true, cmd, working_dir);
|
||||
EndJump(set);
|
||||
} else if (kind == "fuzzy") {
|
||||
JumpGarbageBuffer(&main);
|
||||
Exec(main.view->id, true, cmd, working_dir);
|
||||
main.view->fuzzy_search = true;
|
||||
NextActiveWindowID = main.window->id;
|
||||
} else {
|
||||
JumpGarbageBuffer(&main);
|
||||
main.window->active_goto_list = main.view->id;
|
||||
main.window->goto_list_pos = 0;
|
||||
Exec(main.view->id, true, cmd, working_dir);
|
||||
NextActiveWindowID = main.window->id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Command_ShowBufferList() {
|
||||
BSet command_bar = GetBSet(CommandBarWindowID);
|
||||
command_bar.window->visible = true;
|
||||
NextActiveWindowID = command_bar.window->id;
|
||||
ResetBuffer(command_bar.buffer);
|
||||
For(Buffers) {
|
||||
RawAppendf(command_bar.buffer, "%-80S || %S\n", SkipToLastSlash(it->name), it->name);
|
||||
}
|
||||
command_bar.view->update_scroll = true;
|
||||
SelectRange(command_bar.view, GetBufferEndAsRange(command_bar.buffer));
|
||||
} RegisterCommand(Command_ShowBufferList);
|
||||
|
||||
void Command_ShowCommandList() {
|
||||
BSet command_bar = GetBSet(CommandBarWindowID);
|
||||
command_bar.window->visible = true;
|
||||
NextActiveWindowID = command_bar.window->id;
|
||||
ResetBuffer(command_bar.buffer);
|
||||
for (int i = 0; LuaFunctions[i].name != NULL; i += 1) {
|
||||
Appendf(command_bar.view, "%s()\n ", LuaFunctions[i].name);
|
||||
}
|
||||
|
||||
command_bar.view->update_scroll = true;
|
||||
SelectRange(command_bar.view, GetBufferEndAsRange(command_bar.buffer));
|
||||
} RegisterCommand(Command_ShowCommandList);
|
||||
|
||||
void Command_ListViews() {
|
||||
BSet command_bar = GetBSet(CommandBarWindowID);
|
||||
command_bar.window->visible = true;
|
||||
NextActiveWindowID = command_bar.window->id;
|
||||
ResetBuffer(command_bar.buffer);
|
||||
For(Views) {
|
||||
Buffer *buffer = GetBuffer(it->active_buffer);
|
||||
Appendf(command_bar.view, "%d %S\n", (int)it->id.id, buffer->name);
|
||||
}
|
||||
command_bar.view->fuzzy_search = true;
|
||||
command_bar.view->update_scroll = true;
|
||||
SelectRange(command_bar.view, GetBufferEndAsRange(command_bar.buffer));
|
||||
} RegisterCommand(Command_ListViews);
|
||||
|
||||
int Lua_ListViews(lua_State *L) {
|
||||
Command_ListViews();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Eval(String string) {
|
||||
if (luaL_dostring(LuaState, string.data) != LUA_OK) {
|
||||
const char *error_message = lua_tostring(LuaState, -1);
|
||||
@@ -1300,20 +1071,112 @@ void Eval(String16 string) {
|
||||
Eval(ToString(scratch, string));
|
||||
}
|
||||
|
||||
int Lua_Eval(lua_State *L) {
|
||||
String string = lua_tostring(L, 1);
|
||||
lua_pop(L, 1);
|
||||
Eval(string);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SetProjectFile(Buffer *buffer) {
|
||||
WorkDir = ChopLastSlash(buffer->name);
|
||||
LuaProjectBuffer = buffer;
|
||||
LuaProjectBuffer->user_change_id = -1;
|
||||
}
|
||||
|
||||
String16 FetchLoadWord(void) {
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
Caret caret = active.view->carets[0];
|
||||
Range range = caret.range;
|
||||
if (GetSize(caret.range) == 0) range = EncloseLoadWord(active.buffer, GetFront(caret));
|
||||
String16 string = GetString(active.buffer, range);
|
||||
return string;
|
||||
}
|
||||
|
||||
void Command_Save() {
|
||||
BSet active = GetBSet(LastActiveLayoutWindowID);
|
||||
SaveBuffer(active.buffer);
|
||||
} RegisterCommand(Command_Save);
|
||||
|
||||
void Command_SaveAll() {
|
||||
For(Buffers) {
|
||||
if (it->file_mod_time) {
|
||||
SaveBuffer(it);
|
||||
}
|
||||
}
|
||||
} RegisterCommand(Command_SaveAll);
|
||||
|
||||
void Command_Reopen() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
ReopenBuffer(main.buffer);
|
||||
ActiveWindowID = main.window->id;
|
||||
} RegisterCommand(Command_Reopen);
|
||||
|
||||
void Command_New() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
New(main.window, "");
|
||||
} RegisterCommand(Command_New);
|
||||
|
||||
void Command_ToggleFullscreen() {
|
||||
if (IsInFullscreen) {
|
||||
SDL_SetWindowSize(SDLWindow, FullScreenSizeX, FullScreenSizeY);
|
||||
SDL_SetWindowPosition(SDLWindow, FullScreenPositionX, FullScreenPositionY);
|
||||
} else {
|
||||
SDL_GetWindowSize(SDLWindow, &FullScreenSizeX, &FullScreenSizeY);
|
||||
SDL_GetWindowPosition(SDLWindow, &FullScreenPositionX, &FullScreenPositionY);
|
||||
|
||||
SDL_DisplayID display = SDL_GetDisplayForWindow(SDLWindow);
|
||||
const SDL_DisplayMode *dm = SDL_GetCurrentDisplayMode(display);
|
||||
SDL_SetWindowSize(SDLWindow, dm->w, dm->h);
|
||||
SDL_SetWindowPosition(SDLWindow, 0, 0);
|
||||
}
|
||||
|
||||
IsInFullscreen = !IsInFullscreen;
|
||||
} RegisterCommand(Command_ToggleFullscreen);
|
||||
|
||||
void Command_ListCode() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
JumpGarbageBuffer(&main);
|
||||
ListFilesRecursive(main.buffer, WorkDir);
|
||||
main.view->fuzzy_search = true;
|
||||
main.view->update_scroll = true;
|
||||
SelectRange(main.view, GetBufferEndAsRange(main.buffer));
|
||||
} RegisterCommand(Command_ListCode);
|
||||
|
||||
void Command_ShowBufferList() {
|
||||
BSet command_bar = GetBSet(CommandBarWindowID);
|
||||
command_bar.window->visible = true;
|
||||
command_bar.window->eval_command = false;
|
||||
ActiveWindowID = command_bar.window->id;
|
||||
ResetBuffer(command_bar.buffer);
|
||||
For(Buffers) {
|
||||
RawAppendf(command_bar.buffer, "%-80S || %S\n", SkipToLastSlash(it->name), it->name);
|
||||
}
|
||||
command_bar.view->update_scroll = true;
|
||||
SelectRange(command_bar.view, GetBufferEndAsRange(command_bar.buffer));
|
||||
} RegisterCommand(Command_ShowBufferList);
|
||||
|
||||
void Command_ShowCommandList() {
|
||||
BSet command_bar = GetBSet(CommandBarWindowID);
|
||||
command_bar.window->visible = true;
|
||||
command_bar.window->eval_command = false;
|
||||
ActiveWindowID = command_bar.window->id;
|
||||
ResetBuffer(command_bar.buffer);
|
||||
For(LuaFunctions) {
|
||||
Appendf(command_bar.view, "%S()\n ", it.name);
|
||||
}
|
||||
command_bar.view->update_scroll = true;
|
||||
SelectRange(command_bar.view, GetBufferEndAsRange(command_bar.buffer));
|
||||
} RegisterCommand(Command_ShowCommandList);
|
||||
|
||||
void Command_ListViews() {
|
||||
BSet command_bar = GetBSet(CommandBarWindowID);
|
||||
command_bar.window->visible = true;
|
||||
command_bar.window->eval_command = false;
|
||||
ActiveWindowID = command_bar.window->id;
|
||||
ResetBuffer(command_bar.buffer);
|
||||
For(Views) {
|
||||
Buffer *buffer = GetBuffer(it->active_buffer);
|
||||
Appendf(command_bar.view, "%d %S\n", (int)it->id.id, buffer->name);
|
||||
}
|
||||
command_bar.view->fuzzy_search = true;
|
||||
command_bar.view->update_scroll = true;
|
||||
SelectRange(command_bar.view, GetBufferEndAsRange(command_bar.buffer));
|
||||
} RegisterCommand(Command_ListViews);
|
||||
|
||||
void Command_SetProjectFile() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
SetProjectFile(main.buffer);
|
||||
@@ -1334,89 +1197,6 @@ void Command_SetProject() {
|
||||
Command_SetProjectFile();
|
||||
} RegisterCommand(Command_SetProject);
|
||||
|
||||
int Lua_SetProjectFile(lua_State *L) {
|
||||
Command_SetProjectFile();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Lua_SetWorkDir(lua_State *L) {
|
||||
Command_SetWorkDir();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Lua_ListCommands(lua_State *L) {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
BeginJump(&main);
|
||||
for (int i = 0; LuaFunctions[i].name != NULL; i += 1) {
|
||||
Appendf(main.view, "%20s() ", LuaFunctions[i].name);
|
||||
if (((i + 1) % 6) == 0) {
|
||||
Appendf(main.view, "\n");
|
||||
}
|
||||
}
|
||||
EndJump(main);
|
||||
NextActiveWindowID = main.window->id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Lua_GetBufferList(lua_State *L) {
|
||||
lua_createtable(L, 0, (int)Buffers.len);
|
||||
|
||||
int i = 1;
|
||||
For(Buffers) {
|
||||
lua_pushinteger(L, i++);
|
||||
lua_pushlstring(L, it->name.data, it->name.len);
|
||||
lua_settable(L, -3); /* 3rd element from the stack top */
|
||||
}
|
||||
/* We still have table left on top of the Lua stack. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
Window *GetOverlappingWindow(Vec2I p, Window *default_window = NULL) {
|
||||
For(Windows) {
|
||||
if (AreOverlapping(p, it->total_rect)) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return default_window;
|
||||
}
|
||||
|
||||
Vec2I GetSideOfWindow(Window *window, int direction) {
|
||||
Vec2I p = {};
|
||||
Rect2I rect = window->total_rect;
|
||||
float resizer_size = (float)window->font->char_spacing*0.5f; // @check_codebase_when_changing
|
||||
if (direction == DIR_LEFT) {
|
||||
p.x = rect.min.x - (Int)(resizer_size + window->font->char_spacing);
|
||||
p.y = rect.min.y + (rect.max.y / 2);
|
||||
} else if (direction == DIR_RIGHT) {
|
||||
p.x = rect.max.x + (Int)(resizer_size + window->font->char_spacing);
|
||||
p.y = rect.min.y + (rect.max.y / 2);
|
||||
} else if (direction == DIR_UP) {
|
||||
p.x = rect.min.x + (rect.max.x / 2);
|
||||
p.y = rect.min.y - (Int)(resizer_size + window->font->line_spacing);
|
||||
} else {
|
||||
Assert(direction == DIR_DOWN);
|
||||
p.x = rect.min.x + (rect.max.x / 2);
|
||||
p.y = rect.max.y + (Int)(resizer_size + window->font->line_spacing);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
Window *SwitchWindow(int direction) {
|
||||
Window *window = GetWindow(ActiveWindowID);
|
||||
Vec2I p = GetSideOfWindow(window, direction);
|
||||
Window *result = GetOverlappingWindow(p, window);
|
||||
return result;
|
||||
}
|
||||
|
||||
String16 FetchLoadWord(void) {
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
Caret caret = active.view->carets[0];
|
||||
Range range = caret.range;
|
||||
if (GetSize(caret.range) == 0) range = EncloseLoadWord(active.buffer, GetFront(caret));
|
||||
String16 string = GetString(active.buffer, range);
|
||||
return string;
|
||||
}
|
||||
|
||||
void Command_ToggleDebug() {
|
||||
Window *window = GetWindow(DebugWindowID);
|
||||
window->visible = !window->visible;
|
||||
@@ -1427,17 +1207,20 @@ void Command_KillProcess() {
|
||||
KillProcess(main.view);
|
||||
} RegisterCommand(Command_KillProcess);
|
||||
|
||||
int Lua_KillProcess(lua_State *L) {
|
||||
Command_KillProcess();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Command_KillWindow() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
main.window->kill = true;
|
||||
} RegisterCommand(Command_KillWindow);
|
||||
|
||||
int Lua_KillWindow(lua_State *L) {
|
||||
Command_KillWindow();
|
||||
return 0;
|
||||
}
|
||||
void Command_ShowCommands() {
|
||||
BSet command_bar = GetBSet(CommandBarWindowID);
|
||||
command_bar.window->visible = true;
|
||||
command_bar.window->eval_command = true;
|
||||
ActiveWindowID = command_bar.window->id;
|
||||
ResetBuffer(command_bar.buffer);
|
||||
For(CommandFunctions) {
|
||||
Appendf(command_bar.view, "%S\n", it.name);
|
||||
}
|
||||
command_bar.view->update_scroll = true;
|
||||
SelectRange(command_bar.view, GetBufferEndAsRange(command_bar.buffer));
|
||||
} RegisterCommand(Command_ShowCommands);
|
||||
@@ -46,26 +46,41 @@ void UpdateScroll(Window *window, bool update_caret_scrolling) {
|
||||
}
|
||||
}
|
||||
|
||||
void EvalCommand(String command) {
|
||||
For (CommandFunctions) {
|
||||
if (it.name == command) {
|
||||
it.function();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EvalCommand(String16 command) {
|
||||
Scratch scratch;
|
||||
EvalCommand(ToString(scratch, command));
|
||||
}
|
||||
|
||||
void FuzzySearchOpen(BSet active) {
|
||||
bool success = false;
|
||||
Range range = active.view->carets[0].range;
|
||||
String16 string = FetchLoadWord();
|
||||
if (GetSize(range) == 0) {
|
||||
Int line = PosToLine(active.buffer, range.min);
|
||||
if ((active.buffer->line_starts.len - 1) == line) {
|
||||
line = ClampBottom(0ll, line - 1ll);
|
||||
}
|
||||
|
||||
String16 string = GetLineStringWithoutNL(active.buffer, line);
|
||||
string = GetLineStringWithoutNL(active.buffer, line);
|
||||
Int idx = 0;
|
||||
if (Seek(string, u"||", &idx)) {
|
||||
string = Skip(string, idx + 3);
|
||||
Open(string);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
Open(FetchLoadWord());
|
||||
if (active.window->eval_command) {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
ActiveWindowID = main.window->id;
|
||||
EvalCommand(string);
|
||||
} else {
|
||||
Open(string);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,21 +194,12 @@ void OnCommand(Event event) {
|
||||
}
|
||||
bool mouse_in_document = AreOverlapping(mouse, it->document_rect);
|
||||
if (mouse_in_document) {
|
||||
NextActiveWindowID = it->id;
|
||||
ActiveWindowID = it->id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Mouse(X2)) {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
GotoForward(main.window);
|
||||
}
|
||||
if (Mouse(X1)) {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
GotoBackward(main.window);
|
||||
}
|
||||
|
||||
if (Ctrl() && Shift() && Mouse(RIGHT)) {
|
||||
|
||||
} else if (Alt() && Ctrl() && Mouse(RIGHT)) {
|
||||
@@ -237,7 +243,7 @@ void OnCommand(Event event) {
|
||||
Assert(ScrollbarSelected.id == -1);
|
||||
Assert(DocumentSelected.id == -1);
|
||||
|
||||
BSet active = GetBSet(NextActiveWindowID); // using next to make sure mouse works on first click after switching the window
|
||||
BSet active = GetBSet(ActiveWindowID); // using next to make sure mouse works on first click after switching the window
|
||||
bool mouse_in_document = AreOverlapping(mouse, active.window->document_rect);
|
||||
bool mouse_in_line_numbers = AreOverlapping(mouse, active.window->line_numbers_rect);
|
||||
if (mouse_in_document || mouse_in_line_numbers) {
|
||||
@@ -298,13 +304,22 @@ void OnCommand(Event event) {
|
||||
}
|
||||
}
|
||||
|
||||
if (Mouse(X2)) {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
GotoForward(main.window);
|
||||
}
|
||||
if (Mouse(X1)) {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
GotoBackward(main.window);
|
||||
}
|
||||
|
||||
if (CtrlPress(SDLK_W)) {
|
||||
Command_KillWindow();
|
||||
}
|
||||
|
||||
if (CtrlAltPress(SDLK_P)) {
|
||||
} else if (CtrlShiftPress(SDLK_P)) {
|
||||
Command_ShowCommandList();
|
||||
Command_ShowCommands();
|
||||
} else if (CtrlPress(SDLK_P)) {
|
||||
Command_ShowBufferList();
|
||||
}
|
||||
@@ -314,12 +329,12 @@ void OnCommand(Event event) {
|
||||
}
|
||||
|
||||
if (CtrlPress(SDLK_1)) {
|
||||
NextActiveWindowID = GetOverlappingWindow({0,0}, GetWindow(ActiveWindowID))->id;
|
||||
ActiveWindowID = GetOverlappingWindow({0,0}, GetWindow(ActiveWindowID))->id;
|
||||
}
|
||||
if (CtrlPress(SDLK_2)) {
|
||||
Window *first = GetOverlappingWindow({0,0}, GetWindow(ActiveWindowID));
|
||||
Vec2I p = GetSideOfWindow(first, DIR_RIGHT);
|
||||
NextActiveWindowID = GetOverlappingWindow(p, GetWindow(ActiveWindowID))->id;
|
||||
ActiveWindowID = GetOverlappingWindow(p, GetWindow(ActiveWindowID))->id;
|
||||
}
|
||||
if (CtrlPress(SDLK_3)) {
|
||||
Window *first = GetOverlappingWindow({0,0});
|
||||
@@ -328,7 +343,7 @@ void OnCommand(Event event) {
|
||||
if (second) {
|
||||
Window *third = GetOverlappingWindow(GetSideOfWindow(second, DIR_RIGHT));
|
||||
if (third) {
|
||||
NextActiveWindowID = third->id;
|
||||
ActiveWindowID = third->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -349,6 +364,9 @@ void OnCommand(Event event) {
|
||||
if (active.view->fuzzy_search) {
|
||||
if (Press(SDLK_RETURN)) {
|
||||
FuzzySearchOpen(active);
|
||||
// :OnCommandEnding
|
||||
MergeCarets(active.buffer, &active.view->carets);
|
||||
IF_DEBUG(AssertRanges(active.view->carets));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -400,7 +418,7 @@ void OnCommand(Event event) {
|
||||
} else if (ShiftPress(SDLK_LEFT)) {
|
||||
MoveCarets(active.view, DIR_LEFT, false, SHIFT_PRESS);
|
||||
} else if (AltPress(SDLK_LEFT)) {
|
||||
NextActiveWindowID = SwitchWindow(DIR_LEFT)->id;
|
||||
ActiveWindowID = SwitchWindow(DIR_LEFT)->id;
|
||||
} else if (Press(SDLK_LEFT)) {
|
||||
MoveCarets(active.view, DIR_LEFT);
|
||||
}
|
||||
@@ -412,7 +430,7 @@ void OnCommand(Event event) {
|
||||
} else if (ShiftPress(SDLK_RIGHT)) {
|
||||
MoveCarets(active.view, DIR_RIGHT, false, SHIFT_PRESS);
|
||||
} else if (AltPress(SDLK_RIGHT)) {
|
||||
NextActiveWindowID = SwitchWindow(DIR_RIGHT)->id;
|
||||
ActiveWindowID = SwitchWindow(DIR_RIGHT)->id;
|
||||
} else if (Press(SDLK_RIGHT)) {
|
||||
MoveCarets(active.view, DIR_RIGHT);
|
||||
}
|
||||
@@ -551,8 +569,8 @@ void OnCommand(Event event) {
|
||||
|
||||
if (active.view->fuzzy_search) {
|
||||
if (!ProcessIsActive(active.view->id)) {
|
||||
Scratch scratch;
|
||||
String16 last_line_string = GetLineStringWithoutNL(active.buffer, active.buffer->line_starts.len - 1);
|
||||
Scratch scratch;
|
||||
String16 last_line_string = GetLineStringWithoutNL(active.buffer, active.buffer->line_starts.len - 1);
|
||||
if (active.view->prev_search_line != last_line_string) {
|
||||
active.view->prev_search_line = last_line_string;
|
||||
Array<FuzzyPair> ratings = FuzzySearchLines(scratch, active.buffer, 0, active.buffer->line_starts.len - 1, last_line_string);
|
||||
@@ -611,6 +629,10 @@ void OnCommand(Event event) {
|
||||
if (CtrlPress(SDLK_Q)) {
|
||||
if (active.view->fuzzy_search) {
|
||||
FuzzySearchOpen(active);
|
||||
// :OnCommandEnding
|
||||
MergeCarets(active.buffer, &active.view->carets);
|
||||
IF_DEBUG(AssertRanges(active.view->carets));
|
||||
return;
|
||||
} else {
|
||||
Open(FetchLoadWord());
|
||||
}
|
||||
@@ -624,7 +646,7 @@ void OnCommand(Event event) {
|
||||
if (active.window->layout) {
|
||||
//
|
||||
} else {
|
||||
NextActiveWindowID = LastActiveLayoutWindowID;
|
||||
ActiveWindowID = LastActiveLayoutWindowID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,6 +260,87 @@ const char *SDLKeycodeToName(SDL_Keycode keycode) {
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Keycode NameToSDLKeycode(String name) {
|
||||
if (name == "enter") return SDLK_RETURN;
|
||||
if (name == "escape") return SDLK_ESCAPE;
|
||||
if (name == "backspace") return SDLK_BACKSPACE;
|
||||
if (name == "tab") return SDLK_TAB;
|
||||
if (name == "space") return SDLK_SPACE;
|
||||
if (name == "-") return SDLK_MINUS;
|
||||
if (name == ".") return SDLK_PERIOD;
|
||||
if (name == "/") return SDLK_SLASH;
|
||||
if (name == "0") return SDLK_0;
|
||||
if (name == "1") return SDLK_1;
|
||||
if (name == "2") return SDLK_2;
|
||||
if (name == "3") return SDLK_3;
|
||||
if (name == "4") return SDLK_4;
|
||||
if (name == "5") return SDLK_5;
|
||||
if (name == "6") return SDLK_6;
|
||||
if (name == "7") return SDLK_7;
|
||||
if (name == "8") return SDLK_8;
|
||||
if (name == "9") return SDLK_9;
|
||||
if (name == ":") return SDLK_COLON;
|
||||
if (name == ";") return SDLK_SEMICOLON;
|
||||
if (name == "<") return SDLK_LESS;
|
||||
if (name == "=") return SDLK_EQUALS;
|
||||
if (name == ">") return SDLK_GREATER;
|
||||
if (name == "?") return SDLK_QUESTION;
|
||||
if (name == "[") return SDLK_LEFTBRACKET;
|
||||
if (name == "\\") return SDLK_BACKSLASH;
|
||||
if (name == "]") return SDLK_RIGHTBRACKET;
|
||||
if (name == "`") return SDLK_GRAVE;
|
||||
if (name == "a") return SDLK_A;
|
||||
if (name == "b") return SDLK_B;
|
||||
if (name == "c") return SDLK_C;
|
||||
if (name == "d") return SDLK_D;
|
||||
if (name == "e") return SDLK_E;
|
||||
if (name == "f") return SDLK_F;
|
||||
if (name == "g") return SDLK_G;
|
||||
if (name == "h") return SDLK_H;
|
||||
if (name == "i") return SDLK_I;
|
||||
if (name == "j") return SDLK_J;
|
||||
if (name == "k") return SDLK_K;
|
||||
if (name == "l") return SDLK_L;
|
||||
if (name == "m") return SDLK_M;
|
||||
if (name == "n") return SDLK_N;
|
||||
if (name == "o") return SDLK_O;
|
||||
if (name == "p") return SDLK_P;
|
||||
if (name == "q") return SDLK_Q;
|
||||
if (name == "r") return SDLK_R;
|
||||
if (name == "s") return SDLK_S;
|
||||
if (name == "t") return SDLK_T;
|
||||
if (name == "u") return SDLK_U;
|
||||
if (name == "v") return SDLK_V;
|
||||
if (name == "w") return SDLK_W;
|
||||
if (name == "x") return SDLK_X;
|
||||
if (name == "y") return SDLK_Y;
|
||||
if (name == "z") return SDLK_Z;
|
||||
if (name == "delete") return SDLK_DELETE;
|
||||
if (name == "capslock") return SDLK_CAPSLOCK;
|
||||
if (name == "f1") return SDLK_F1;
|
||||
if (name == "f2") return SDLK_F2;
|
||||
if (name == "f3") return SDLK_F3;
|
||||
if (name == "f4") return SDLK_F4;
|
||||
if (name == "f5") return SDLK_F5;
|
||||
if (name == "f6") return SDLK_F6;
|
||||
if (name == "f7") return SDLK_F7;
|
||||
if (name == "f8") return SDLK_F8;
|
||||
if (name == "f9") return SDLK_F9;
|
||||
if (name == "f10") return SDLK_F10;
|
||||
if (name == "f11") return SDLK_F11;
|
||||
if (name == "f12") return SDLK_F12;
|
||||
if (name == "insert") return SDLK_INSERT;
|
||||
if (name == "home") return SDLK_HOME;
|
||||
if (name == "pageup") return SDLK_PAGEUP;
|
||||
if (name == "end") return SDLK_END;
|
||||
if (name == "pagedown") return SDLK_PAGEDOWN;
|
||||
if (name == "right") return SDLK_RIGHT;
|
||||
if (name == "left") return SDLK_LEFT;
|
||||
if (name == "down") return SDLK_DOWN;
|
||||
if (name == "up") return SDLK_UP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void FillEventWithBasicData(Event *event) {
|
||||
SDL_Keymod mod = SDL_GetModState();
|
||||
@@ -468,14 +549,6 @@ void Serialize(Serializer *s, Event *e) {
|
||||
SerializeEnd(s);
|
||||
}
|
||||
|
||||
const int DIR_RIGHT = 0;
|
||||
const int DIR_LEFT = 1;
|
||||
const int DIR_DOWN = 2;
|
||||
const int DIR_UP = 3;
|
||||
const int DIR_COUNT = 4;
|
||||
const bool CTRL_PRESSED = true;
|
||||
const bool SHIFT_PRESS = true;
|
||||
|
||||
#define Ctrl() event.ctrl
|
||||
#define Alt() event.alt
|
||||
#define Shift() event.shift
|
||||
|
||||
@@ -31,7 +31,6 @@ ViewID SearchViewID;
|
||||
BufferID SearchBufferID;
|
||||
|
||||
WindowID ActiveWindowID;
|
||||
WindowID NextActiveWindowID;
|
||||
WindowID LastActiveLayoutWindowID;
|
||||
WindowID ScrollbarSelected = {-1};
|
||||
WindowID DocumentSelected = {-1};
|
||||
@@ -50,11 +49,7 @@ View *TraceView;
|
||||
String WorkDir;
|
||||
RandomSeed UniqueBufferNameSeed = {};
|
||||
Array<Event> EventPlayback;
|
||||
|
||||
// lua
|
||||
lua_State *LuaState = NULL;
|
||||
String16 LuaCommandResult = {};
|
||||
extern luaL_Reg LuaFunctions[];
|
||||
lua_State *LuaState = NULL;
|
||||
|
||||
// clipboard
|
||||
BlockArena ClipboardArena;
|
||||
@@ -186,17 +181,33 @@ void ReloadStyle() {
|
||||
StyleUndoMergeTimeout = GetStyleFloat("UndoMergeTimeout", StyleUndoMergeTimeout);
|
||||
}
|
||||
|
||||
typedef void CommandFunction(void);
|
||||
Array<CommandFunction *> CommandFunctions;
|
||||
typedef void Function(void);
|
||||
typedef int LuaFunction(lua_State *state);
|
||||
struct FunctionData { String name; Function *function; };
|
||||
struct LuaFunctionData { String name; LuaFunction *function; };
|
||||
|
||||
#define STRINGIFY_(x) x
|
||||
#define STRINGIFY(x) STRINGIFY_(x)
|
||||
#define CONCAT_(a, b) a ## b
|
||||
#define CONCAT(a, b) CONCAT_(a, b)
|
||||
Array<FunctionData> CommandFunctions;
|
||||
Array<LuaFunctionData> LuaFunctions;
|
||||
Array<FunctionData> TestFunctions;
|
||||
|
||||
struct Register_Command {
|
||||
Register_Command(CommandFunction *f) {
|
||||
Add(&CommandFunctions, f);
|
||||
struct Register_Function {
|
||||
Register_Function(Array<FunctionData> *functions, String name, Function *f) {
|
||||
int64_t pos = 0;
|
||||
if (Seek(name, "_", &pos, 0)) {
|
||||
name = Skip(name, pos + 1);
|
||||
}
|
||||
Add(functions, {name, f});
|
||||
}
|
||||
};
|
||||
#define RegisterCommand(NAME) Register_Command CONCAT(COMMAND, __COUNTER__)(NAME)
|
||||
#define RegisterFunction(functions, name) Register_Function RF__##name(functions, #name, name)
|
||||
#define RegisterCommand(name) RegisterFunction(&CommandFunctions, name)
|
||||
struct Register_Lua { Register_Lua(LuaFunction *function, String name) { if (StartsWith(name, "Lua_")) name = Skip(name, 4); Add(&LuaFunctions, {name, function}); } };
|
||||
#define RegisterLua(NAME) Register_Lua CONCAT(COMMAND, __COUNTER__)(NAME, #NAME)
|
||||
|
||||
const int DIR_RIGHT = 0;
|
||||
const int DIR_LEFT = 1;
|
||||
const int DIR_DOWN = 2;
|
||||
const int DIR_UP = 3;
|
||||
const int DIR_COUNT = 4;
|
||||
const bool CTRL_PRESSED = true;
|
||||
const bool SHIFT_PRESS = true;
|
||||
@@ -86,61 +86,6 @@ API String GetFieldString(lua_State *L, String name) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Int GetFieldAInt(lua_State *L, const char *name) {
|
||||
lua_getfield(L, -1, name);
|
||||
lua_Integer num = lua_tointeger(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return (Int)num;
|
||||
}
|
||||
|
||||
double GetFieldAFloat(lua_State *L, const char *name) {
|
||||
lua_getfield(L, -1, name);
|
||||
double num = lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return num;
|
||||
}
|
||||
|
||||
const char *GetFieldAString(lua_State *L, const char *name) {
|
||||
lua_getfield(L, -1, name);
|
||||
const char *result = lua_tostring(L, -1);
|
||||
|
||||
lua_pop(L, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
API void PushEvent(lua_State *L, Event *event) {
|
||||
lua_createtable(L, 0, EVENT_FIELD_COUNT);
|
||||
#define lua_pushInt lua_pushinteger
|
||||
#define lua_pushString lua_pushstring
|
||||
#define lua_pushFloat lua_pushnumber
|
||||
#define X(TYPE, KIND, NAME) \
|
||||
lua_push##KIND(L, event->NAME); \
|
||||
lua_setfield(L, -2, #NAME);
|
||||
EVENT_FIELDS
|
||||
#undef X
|
||||
}
|
||||
|
||||
// :Event
|
||||
API int Lua_Play(lua_State *L) {
|
||||
if (!lua_istable(L, -1)) luaL_error(L, "expected a table of events");
|
||||
defer { lua_pop(L, 1); };
|
||||
|
||||
int size = (int)lua_rawlen(L, -1);
|
||||
for (int i = 0; i < size; i += 1) {
|
||||
lua_geti(L, -1, i + 1);
|
||||
if (!lua_istable(L, -1)) luaL_error(L, "expected a table of events");
|
||||
defer { lua_pop(L, 1); };
|
||||
|
||||
Event event = {};
|
||||
#define X(TYPE, KIND, NAME) event.NAME = (TYPE)GetFieldA##KIND(L, #NAME);
|
||||
EVENT_FIELDS
|
||||
#undef X
|
||||
Add(&EventPlayback, event);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ReloadStyle();
|
||||
extern String BaseLuaConfig;
|
||||
|
||||
@@ -206,9 +151,9 @@ API void InitLuaConfig() {
|
||||
luaL_openlibs(LuaState);
|
||||
lua_sethook(LuaState, HookLuaForceExit, LUA_MASKCOUNT, 100000000);
|
||||
|
||||
for (int i = 0; LuaFunctions[i].name; i += 1) {
|
||||
lua_pushcfunction(LuaState, LuaFunctions[i].func);
|
||||
lua_setglobal(LuaState, LuaFunctions[i].name);
|
||||
For(LuaFunctions) {
|
||||
lua_pushcfunction(LuaState, it.function);
|
||||
lua_setglobal(LuaState, it.name.data);
|
||||
}
|
||||
|
||||
#if OS_WINDOWS
|
||||
@@ -253,3 +198,97 @@ API void InitLuaConfig() {
|
||||
ReloadLuaConfigs(true);
|
||||
CallLuaOnInit();
|
||||
}
|
||||
|
||||
struct OnOpenResult {
|
||||
String kind;
|
||||
String file_path;
|
||||
Int line, col;
|
||||
String working_dir;
|
||||
String cmd;
|
||||
};
|
||||
|
||||
OnOpenResult CallOnOpen(Allocator allocator, String path, String meta) {
|
||||
lua_getglobal(LuaState, "OnOpen");
|
||||
lua_pushlstring(LuaState, path.data, path.len);
|
||||
lua_pushlstring(LuaState, meta.data, meta.len);
|
||||
if (!CallLuaFunc("OnOpen", 2, 1)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
String file_path = GetFieldString(LuaState, "file_path");
|
||||
String line_string = GetFieldString(LuaState, "line");
|
||||
String col_string = GetFieldString(LuaState, "col");
|
||||
String cmd = GetFieldString(LuaState, "cmd");
|
||||
String working_dir = GetFieldString(LuaState, "working_dir");
|
||||
String kind = GetFieldString(LuaState, "kind");
|
||||
|
||||
OnOpenResult result = {};
|
||||
result.cmd = cmd;
|
||||
result.working_dir = working_dir;
|
||||
result.file_path = file_path;
|
||||
if (!IsAbsolute(result.file_path)) {
|
||||
String GetMainDir();
|
||||
String dir = GetMainDir();
|
||||
result.file_path = Format(allocator, "%S/%S", dir, result.file_path);
|
||||
}
|
||||
if (col_string.len) {
|
||||
result.col = strtoll(col_string.data, NULL, 10);
|
||||
} else {
|
||||
result.col = -1;
|
||||
}
|
||||
if (line_string.len) {
|
||||
result.line = strtoll(line_string.data, NULL, 10);
|
||||
} else {
|
||||
result.line = -1;
|
||||
}
|
||||
result.kind = kind;
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CallIsCode(String path, String meta = "") {
|
||||
lua_getglobal(LuaState, "IsCode");
|
||||
lua_pushlstring(LuaState, path.data, path.len);
|
||||
lua_pushlstring(LuaState, meta.data, meta.len);
|
||||
if (!CallLuaFunc("IsCode", 2, 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = lua_toboolean(LuaState, -1);
|
||||
lua_pop(LuaState, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
void CallOnSave(BufferID buffer_id) {
|
||||
lua_getglobal(LuaState, "OnSave");
|
||||
lua_pushinteger(LuaState, buffer_id.id);
|
||||
CallLuaFunc("OnSave", 1, 0);
|
||||
}
|
||||
|
||||
void PushEvent(lua_State *L, Event *event) {
|
||||
lua_createtable(L, 0, EVENT_FIELD_COUNT);
|
||||
#define lua_pushInt lua_pushinteger
|
||||
#define lua_pushString lua_pushstring
|
||||
#define lua_pushFloat lua_pushnumber
|
||||
#define X(TYPE, KIND, NAME) \
|
||||
lua_push##KIND(L, event->NAME); \
|
||||
lua_setfield(L, -2, #NAME);
|
||||
EVENT_FIELDS
|
||||
#undef X
|
||||
}
|
||||
|
||||
bool CallOnCommand(Event *event) {
|
||||
lua_getglobal(LuaState, "OnCommand");
|
||||
PushEvent(LuaState, event);
|
||||
CallLuaFunc("OnCommand", 1, 1);
|
||||
bool result = lua_toboolean(LuaState, -1);
|
||||
lua_pop(LuaState, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
void CallLuaOnUpdate(Event *event) {
|
||||
lua_getglobal(LuaState, "OnUpdate");
|
||||
PushEvent(LuaState, event);
|
||||
CallLuaFunc("OnUpdate", 1, 0);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ API Int GetStyleInt(String name, Int default_int);
|
||||
API String GetStyleString(String name, String default_string);
|
||||
API Color GetColor(String name, Color default_color);
|
||||
API String GetFieldString(lua_State *L, String name);
|
||||
API int Lua_Play(lua_State *L);
|
||||
API void LoadLuaBuffer(Buffer *lua_buffer);
|
||||
API void ReloadLuaConfigs(bool reload = false);
|
||||
API bool CallLuaFunc(char *func_name, int arg_count, int ret_count);
|
||||
|
||||
@@ -9,7 +9,7 @@ int Lua_print(lua_State *L) {
|
||||
Appendf(null_view, "\n");
|
||||
lua_pop(L, nargs);
|
||||
return 0;
|
||||
}
|
||||
} RegisterLua(Lua_print);
|
||||
|
||||
int Lua_Print(lua_State *L) {
|
||||
Scratch scratch;
|
||||
@@ -21,7 +21,7 @@ int Lua_Print(lua_State *L) {
|
||||
Appendf(TraceView, "\n");
|
||||
lua_pop(L, nargs);
|
||||
return 0;
|
||||
}
|
||||
} RegisterLua(Lua_Print);
|
||||
|
||||
int Lua_GetLoadWord(lua_State *L) {
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
@@ -34,7 +34,7 @@ int Lua_GetLoadWord(lua_State *L) {
|
||||
String string = AllocCharString(scratch, active.buffer, range);
|
||||
lua_pushlstring(L, string.data, string.len);
|
||||
return 1;
|
||||
}
|
||||
} RegisterLua(Lua_GetLoadWord);
|
||||
|
||||
int Lua_BufferExists(lua_State *L) {
|
||||
String string = lua_tostring(L, 1);
|
||||
@@ -42,7 +42,7 @@ int Lua_BufferExists(lua_State *L) {
|
||||
Buffer *buffer = GetBuffer(string);
|
||||
lua_pushboolean(L, buffer != NULL);
|
||||
return 1;
|
||||
}
|
||||
} RegisterLua(Lua_BufferExists);
|
||||
|
||||
int Lua_GetSelection(lua_State *L) {
|
||||
Scratch scratch;
|
||||
@@ -51,7 +51,7 @@ int Lua_GetSelection(lua_State *L) {
|
||||
String string = ToString(scratch, string16);
|
||||
lua_pushlstring(L, string.data, string.len);
|
||||
return 1;
|
||||
}
|
||||
} RegisterLua(Lua_GetSelection);
|
||||
|
||||
int Lua_GetEntireBuffer(lua_State *L) {
|
||||
Scratch scratch;
|
||||
@@ -60,20 +60,20 @@ int Lua_GetEntireBuffer(lua_State *L) {
|
||||
String string = ToString(scratch, string16);
|
||||
lua_pushlstring(L, string.data, string.len);
|
||||
return 1;
|
||||
}
|
||||
} RegisterLua(Lua_GetEntireBuffer);
|
||||
|
||||
int Lua_GetClipboard(lua_State *L) {
|
||||
Scratch scratch;
|
||||
String string = ToString(scratch, SavedClipboardString);
|
||||
lua_pushlstring(L, string.data, string.len);
|
||||
return 1;
|
||||
}
|
||||
} RegisterLua(Lua_GetClipboard);
|
||||
|
||||
int Lua_GetFilename(lua_State *L) {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
lua_pushlstring(L, main.buffer->name.data, main.buffer->name.len);
|
||||
return 1;
|
||||
}
|
||||
} RegisterLua(Lua_GetFilename);
|
||||
|
||||
int Lua_GetLine(lua_State *L) {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
@@ -82,7 +82,7 @@ int Lua_GetLine(lua_State *L) {
|
||||
Int line = PosToLine(main.buffer, front);
|
||||
lua_pushinteger(L, line + 1);
|
||||
return 1;
|
||||
}
|
||||
} RegisterLua(Lua_GetLine);
|
||||
|
||||
int Lua_FileExists(lua_State *L) {
|
||||
String path = luaL_checkstring(L, 1);
|
||||
@@ -90,103 +90,263 @@ int Lua_FileExists(lua_State *L) {
|
||||
bool exists = FileExists(path);
|
||||
lua_pushboolean(L, exists);
|
||||
return 1;
|
||||
}
|
||||
} RegisterLua(Lua_FileExists);
|
||||
|
||||
int Lua_GetWorkDir(lua_State *L) {
|
||||
lua_pushlstring(L, WorkDir.data, WorkDir.len);
|
||||
return 1;
|
||||
}
|
||||
} RegisterLua(Lua_GetWorkDir);
|
||||
|
||||
int Lua_GetExeDir(lua_State *L) {
|
||||
Scratch scratch;
|
||||
String exe_dir = GetExeDir(scratch);
|
||||
lua_pushlstring(L, exe_dir.data, exe_dir.len);
|
||||
return 1;
|
||||
}
|
||||
} RegisterLua(Lua_GetExeDir);
|
||||
|
||||
int Lua_GetMainDir(lua_State *L) {
|
||||
String name = GetMainDir();
|
||||
lua_pushlstring(L, name.data, name.len);
|
||||
return 1;
|
||||
}
|
||||
} RegisterLua(Lua_GetMainDir);
|
||||
|
||||
struct OnOpenResult {
|
||||
String kind;
|
||||
String file_path;
|
||||
Int line, col;
|
||||
String working_dir;
|
||||
String cmd;
|
||||
};
|
||||
int Lua_KillProcess(lua_State *L) {
|
||||
Command_KillProcess();
|
||||
return 0;
|
||||
} RegisterLua(Lua_KillProcess);
|
||||
|
||||
OnOpenResult CallOnOpen(Allocator allocator, String path, String meta) {
|
||||
lua_getglobal(LuaState, "OnOpen");
|
||||
lua_pushlstring(LuaState, path.data, path.len);
|
||||
lua_pushlstring(LuaState, meta.data, meta.len);
|
||||
if (!CallLuaFunc("OnOpen", 2, 1)) {
|
||||
return {};
|
||||
int Lua_KillWindow(lua_State *L) {
|
||||
Command_KillWindow();
|
||||
return 0;
|
||||
} RegisterLua(Lua_KillWindow);
|
||||
|
||||
int Lua_SetProjectFile(lua_State *L) {
|
||||
Command_SetProjectFile();
|
||||
return 0;
|
||||
} RegisterLua(Lua_SetProjectFile);
|
||||
|
||||
int Lua_SetWorkDir(lua_State *L) {
|
||||
Command_SetWorkDir();
|
||||
return 0;
|
||||
} RegisterLua(Lua_SetWorkDir);
|
||||
|
||||
int Lua_ListCommands(lua_State *L) {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
BeginJump(&main);
|
||||
int i = 0;
|
||||
For (LuaFunctions) {
|
||||
Appendf(main.view, "%20S() ", it.name);
|
||||
if (((i + 1) % 6) == 0) {
|
||||
Appendf(main.view, "\n");
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
EndJump(main);
|
||||
ActiveWindowID = main.window->id;
|
||||
return 0;
|
||||
} RegisterLua(Lua_ListCommands);
|
||||
|
||||
int Lua_GetBufferList(lua_State *L) {
|
||||
lua_createtable(L, 0, (int)Buffers.len);
|
||||
|
||||
int i = 1;
|
||||
For(Buffers) {
|
||||
lua_pushinteger(L, i++);
|
||||
lua_pushlstring(L, it->name.data, it->name.len);
|
||||
lua_settable(L, -3); /* 3rd element from the stack top */
|
||||
}
|
||||
/* We still have table left on top of the Lua stack. */
|
||||
return 1;
|
||||
} RegisterLua(Lua_GetBufferList);
|
||||
|
||||
int Lua_Eval(lua_State *L) {
|
||||
String string = lua_tostring(L, 1);
|
||||
lua_pop(L, 1);
|
||||
Eval(string);
|
||||
return 0;
|
||||
} RegisterLua(Lua_Eval);
|
||||
|
||||
int Lua_ListViews(lua_State *L) {
|
||||
Command_ListViews();
|
||||
return 0;
|
||||
} RegisterLua(Lua_ListViews);
|
||||
|
||||
int Lua_ApplyClangFormat(lua_State *L) {
|
||||
lua_Integer buffer_id = luaL_checkinteger(L, 1);
|
||||
lua_pop(L, 1);
|
||||
Buffer *buffer = GetBuffer({buffer_id});
|
||||
ApplyClangFormat(buffer);
|
||||
return 0;
|
||||
} RegisterLua(Lua_ApplyClangFormat);
|
||||
|
||||
int Lua_GetBufferNameByID(lua_State *L) {
|
||||
lua_Integer buffer_id = luaL_checkinteger(L, 1);
|
||||
lua_pop(L, 1);
|
||||
Buffer *buffer = GetBuffer({buffer_id});
|
||||
lua_pushlstring(L, buffer->name.data, buffer->name.len);
|
||||
return 1;
|
||||
} RegisterLua(Lua_GetBufferNameByID);
|
||||
|
||||
|
||||
int Lua_ConvertLineEndingsToLF(lua_State *L) {
|
||||
lua_Integer buffer_id = luaL_checkinteger(L, 1);
|
||||
int trim_lines_with_caret = lua_toboolean(L, 2);
|
||||
lua_pop(L, 2);
|
||||
Buffer *buffer = GetBuffer({buffer_id});
|
||||
ConvertLineEndingsToLF(buffer, trim_lines_with_caret);
|
||||
return 0;
|
||||
} RegisterLua(Lua_ConvertLineEndingsToLF);
|
||||
|
||||
int Lua_Save(lua_State *L) {
|
||||
Command_Save();
|
||||
return 0;
|
||||
} RegisterLua(Lua_Save);
|
||||
|
||||
int Lua_SaveAll(lua_State *L) {
|
||||
Command_SaveAll();
|
||||
return 0;
|
||||
} RegisterLua(Lua_SaveAll);
|
||||
|
||||
int Lua_Reopen(lua_State *L) {
|
||||
Command_Reopen();
|
||||
return 0;
|
||||
} RegisterLua(Lua_Reopen);
|
||||
|
||||
int Lua_New(lua_State *L) {
|
||||
String name = lua_tostring(L, 1);
|
||||
lua_pop(L, 1);
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
New(main.window, name);
|
||||
return 0;
|
||||
} RegisterLua(Lua_New);
|
||||
|
||||
int Lua_NewDir(lua_State *L) {
|
||||
String name = lua_tostring(L, 1);
|
||||
lua_pop(L, 1);
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
NewDir(main.window, name);
|
||||
return 0;
|
||||
} RegisterLua(Lua_NewDir);
|
||||
|
||||
int Lua_ToggleFullscreen(lua_State *L) {
|
||||
Command_ToggleFullscreen();
|
||||
return 0;
|
||||
} RegisterLua(Lua_ToggleFullscreen);
|
||||
|
||||
int Lua_ListCode(lua_State *L) {
|
||||
Command_ListCode();
|
||||
return 0;
|
||||
} RegisterLua(Lua_ListCode);
|
||||
|
||||
int Lua_C(lua_State *L) {
|
||||
String string = lua_tostring(L, 1);
|
||||
lua_pop(L, 1);
|
||||
Exec(string, GetMainDir());
|
||||
return 0;
|
||||
} RegisterLua(Lua_C);
|
||||
|
||||
int Lua_Open(lua_State *L) {
|
||||
Scratch scratch;
|
||||
String path = luaL_checkstring(L, 1);
|
||||
lua_pop(L, 1);
|
||||
Open(path);
|
||||
return 0;
|
||||
} RegisterLua(Lua_Open);
|
||||
|
||||
int Lua_Cmd(lua_State *L) {
|
||||
if (!lua_istable(L, -1)) luaL_error(L, "expected a table as argument");
|
||||
defer { lua_pop(L, 1); };
|
||||
|
||||
lua_getfield(L, -1, "working_dir");
|
||||
String working_dir = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
if (working_dir == "") {
|
||||
working_dir = GetMainDir();
|
||||
}
|
||||
|
||||
String file_path = GetFieldString(LuaState, "file_path");
|
||||
String line_string = GetFieldString(LuaState, "line");
|
||||
String col_string = GetFieldString(LuaState, "col");
|
||||
String cmd = GetFieldString(LuaState, "cmd");
|
||||
String working_dir = GetFieldString(LuaState, "working_dir");
|
||||
String kind = GetFieldString(LuaState, "kind");
|
||||
lua_getfield(L, -1, "cmd");
|
||||
if (!lua_isstring(L, -1)) luaL_error(L, "expected a string for cmd param");
|
||||
String cmd = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
OnOpenResult result = {};
|
||||
result.cmd = cmd;
|
||||
result.working_dir = working_dir;
|
||||
result.file_path = file_path;
|
||||
if (!IsAbsolute(result.file_path)) {
|
||||
String dir = GetMainDir();
|
||||
result.file_path = Format(allocator, "%S/%S", dir, result.file_path);
|
||||
}
|
||||
if (col_string.len) {
|
||||
result.col = strtoll(col_string.data, NULL, 10);
|
||||
lua_getfield(L, -1, "kind");
|
||||
String kind = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
if (kind == "console") {
|
||||
BSet set = GetConsoleSet();
|
||||
main.window->active_goto_list = set.view->id;
|
||||
main.window->goto_list_pos = set.buffer->len;
|
||||
SelectRange(set.view, MakeRange(set.buffer->len));
|
||||
BeginJump(&set);
|
||||
Exec(set.view->id, true, cmd, working_dir);
|
||||
EndJump(set);
|
||||
} else if (kind == "fuzzy") {
|
||||
JumpGarbageBuffer(&main);
|
||||
Exec(main.view->id, true, cmd, working_dir);
|
||||
main.view->fuzzy_search = true;
|
||||
ActiveWindowID = main.window->id;
|
||||
} else {
|
||||
result.col = -1;
|
||||
JumpGarbageBuffer(&main);
|
||||
main.window->active_goto_list = main.view->id;
|
||||
main.window->goto_list_pos = 0;
|
||||
Exec(main.view->id, true, cmd, working_dir);
|
||||
ActiveWindowID = main.window->id;
|
||||
}
|
||||
if (line_string.len) {
|
||||
result.line = strtoll(line_string.data, NULL, 10);
|
||||
} else {
|
||||
result.line = -1;
|
||||
}
|
||||
result.kind = kind;
|
||||
|
||||
return 0;
|
||||
} RegisterLua(Lua_Cmd);
|
||||
|
||||
Int GetFieldAInt(lua_State *L, const char *name) {
|
||||
lua_getfield(L, -1, name);
|
||||
lua_Integer num = lua_tointeger(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return (Int)num;
|
||||
}
|
||||
|
||||
double GetFieldAFloat(lua_State *L, const char *name) {
|
||||
lua_getfield(L, -1, name);
|
||||
double num = lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return num;
|
||||
}
|
||||
|
||||
const char *GetFieldAString(lua_State *L, const char *name) {
|
||||
lua_getfield(L, -1, name);
|
||||
const char *result = lua_tostring(L, -1);
|
||||
|
||||
lua_pop(L, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CallIsCode(String path, String meta = "") {
|
||||
lua_getglobal(LuaState, "IsCode");
|
||||
lua_pushlstring(LuaState, path.data, path.len);
|
||||
lua_pushlstring(LuaState, meta.data, meta.len);
|
||||
if (!CallLuaFunc("IsCode", 2, 1)) {
|
||||
return false;
|
||||
// :Event
|
||||
int Lua_Play(lua_State *L) {
|
||||
if (!lua_istable(L, -1)) luaL_error(L, "expected a table of events");
|
||||
defer { lua_pop(L, 1); };
|
||||
|
||||
int size = (int)lua_rawlen(L, -1);
|
||||
for (int i = 0; i < size; i += 1) {
|
||||
lua_geti(L, -1, i + 1);
|
||||
if (!lua_istable(L, -1)) luaL_error(L, "expected a table of events");
|
||||
defer { lua_pop(L, 1); };
|
||||
|
||||
Event event = {};
|
||||
#define X(TYPE, KIND, NAME) event.NAME = (TYPE)GetFieldA##KIND(L, #NAME);
|
||||
EVENT_FIELDS
|
||||
#undef X
|
||||
Add(&EventPlayback, event);
|
||||
}
|
||||
|
||||
bool result = lua_toboolean(LuaState, -1);
|
||||
lua_pop(LuaState, 1);
|
||||
return result;
|
||||
}
|
||||
return 0;
|
||||
} RegisterLua(Lua_Play);
|
||||
|
||||
void CallOnSave(BufferID buffer_id) {
|
||||
lua_getglobal(LuaState, "OnSave");
|
||||
lua_pushinteger(LuaState, buffer_id.id);
|
||||
CallLuaFunc("OnSave", 1, 0);
|
||||
}
|
||||
|
||||
bool CallOnCommand(Event *event) {
|
||||
lua_getglobal(LuaState, "OnCommand");
|
||||
PushEvent(LuaState, event);
|
||||
CallLuaFunc("OnCommand", 1, 1);
|
||||
bool result = lua_toboolean(LuaState, -1);
|
||||
lua_pop(LuaState, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
void CallLuaOnUpdate(Event *event) {
|
||||
lua_getglobal(LuaState, "OnUpdate");
|
||||
PushEvent(LuaState, event);
|
||||
CallLuaFunc("OnUpdate", 1, 0);
|
||||
}
|
||||
int Lua_TrimTrailingWhitespace(lua_State *L) {
|
||||
lua_Integer buffer_id = luaL_checkinteger(L, 1);
|
||||
int trim_lines_with_caret = lua_toboolean(L, 2);
|
||||
lua_pop(L, 2);
|
||||
Buffer *buffer = GetBuffer({buffer_id});
|
||||
TrimTrailingWhitespace(buffer, trim_lines_with_caret);
|
||||
return 0;
|
||||
} RegisterLua(Lua_TrimTrailingWhitespace);
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
luaL_Reg LuaFunctions[] = {
|
||||
{"print", Lua_print},
|
||||
{"Print", Lua_Print},
|
||||
{"SaveAll", Lua_SaveAll},
|
||||
{"KillProcess", Lua_KillProcess},
|
||||
{"GetLoadWord", Lua_GetLoadWord},
|
||||
{"BufferExists", Lua_BufferExists},
|
||||
{"GetSelection", Lua_GetSelection},
|
||||
{"GetEntireBuffer", Lua_GetEntireBuffer},
|
||||
{"GetClipboard", Lua_GetClipboard},
|
||||
{"GetFilename", Lua_GetFilename},
|
||||
{"GetLine", Lua_GetLine},
|
||||
{"FileExists", Lua_FileExists},
|
||||
{"GetWorkDir", Lua_GetWorkDir},
|
||||
{"GetExeDir", Lua_GetExeDir},
|
||||
{"GetMainDir", Lua_GetMainDir},
|
||||
{"KillWindow", Lua_KillWindow},
|
||||
{"Play", Lua_Play},
|
||||
{"TrimTrailingWhitespace", Lua_TrimTrailingWhitespace},
|
||||
{"ConvertLineEndingsToLF", Lua_ConvertLineEndingsToLF},
|
||||
{"ApplyClangFormat", Lua_ApplyClangFormat},
|
||||
{"GetBufferNameByID", Lua_GetBufferNameByID},
|
||||
{"Save", Lua_Save},
|
||||
{"Reopen", Lua_Reopen},
|
||||
{"New", Lua_New},
|
||||
{"NewDir", Lua_NewDir},
|
||||
{"ToggleFullscreen", Lua_ToggleFullscreen},
|
||||
{"ListCode", Lua_ListCode},
|
||||
{"C", Lua_C},
|
||||
{"Open", Lua_Open},
|
||||
{"Cmd", Lua_Cmd},
|
||||
{"ListViews", Lua_ListViews},
|
||||
{"Eval", Lua_Eval},
|
||||
{"SetProjectFile", Lua_SetProjectFile},
|
||||
{"SetWorkDir", Lua_SetWorkDir},
|
||||
{"ListCommands", Lua_ListCommands},
|
||||
{"GetBufferList", Lua_GetBufferList},
|
||||
{NULL, NULL},
|
||||
};
|
||||
@@ -38,9 +38,6 @@ String GetMainDir() {
|
||||
void GarbageCollect() {
|
||||
Allocator sys_allocator = GetSystemAllocator();
|
||||
|
||||
|
||||
ActiveWindowID = NextActiveWindowID;
|
||||
|
||||
For (Windows) {
|
||||
if (it->sync_visibility_with_focus) {
|
||||
if (it->id == ActiveWindowID) {
|
||||
@@ -51,8 +48,8 @@ void GarbageCollect() {
|
||||
}
|
||||
}
|
||||
|
||||
Window *window = GetWindow(ActiveWindowID);
|
||||
if (ActiveWindowID.id != LastActiveLayoutWindowID.id) {
|
||||
Window *window = GetWindow(ActiveWindowID);
|
||||
if (window->layout) {
|
||||
LastActiveLayoutWindowID = ActiveWindowID;
|
||||
}
|
||||
|
||||
221
src/text_editor/parser.cpp
Normal file
221
src/text_editor/parser.cpp
Normal file
@@ -0,0 +1,221 @@
|
||||
struct Lexer {
|
||||
Allocator allocator;
|
||||
char *at;
|
||||
char *start;
|
||||
char *end;
|
||||
char *name;
|
||||
int line, column;
|
||||
};
|
||||
|
||||
enum TriggerKind {
|
||||
TriggerKind_Error,
|
||||
TriggerKind_Key,
|
||||
TriggerKind_Binary,
|
||||
};
|
||||
|
||||
struct Trigger {
|
||||
TriggerKind kind;
|
||||
Trigger *left;
|
||||
Trigger *right;
|
||||
SDL_Keycode key;
|
||||
struct {
|
||||
U32 ctrl : 1;
|
||||
U32 alt : 1;
|
||||
U32 shift : 1;
|
||||
};
|
||||
};
|
||||
|
||||
void Advance(Lexer *lex) {
|
||||
if (lex->at < lex->end) {
|
||||
if (lex->at[0] == '\n') {
|
||||
lex->line += 1;
|
||||
lex->column = 0;
|
||||
} else {
|
||||
lex->column += 1;
|
||||
}
|
||||
lex->at += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void Advance(Lexer *lex, int n) {
|
||||
for (int i = 0; i < n; i += 1) Advance(lex);
|
||||
}
|
||||
|
||||
char At(Lexer *lex) {
|
||||
if (lex->at < lex->end) {
|
||||
return lex->at[0];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
String AsString(Lexer *lex) {
|
||||
String result = {lex->at, lex->end - lex->at};
|
||||
return result;
|
||||
}
|
||||
|
||||
void EatWhitespace(Lexer *lex) {
|
||||
while (IsWhitespace(At(lex))) {
|
||||
Advance(lex);
|
||||
}
|
||||
}
|
||||
|
||||
Trigger *TriggerBinary(Lexer *lex, Trigger *left, Trigger *right, int key) {
|
||||
Trigger *result = AllocType(lex->allocator, Trigger);
|
||||
result->kind = TriggerKind_Binary;
|
||||
result->key = key;
|
||||
result->left = left;
|
||||
result->right = right;
|
||||
return result;
|
||||
}
|
||||
|
||||
Trigger *ParseKeyAtom(Lexer *lex) {
|
||||
Trigger *result = AllocType(lex->allocator, Trigger);
|
||||
result->kind = TriggerKind_Key;
|
||||
EatWhitespace(lex);
|
||||
for (;;) {
|
||||
String lex_string = AsString(lex);
|
||||
if (StartsWith(lex_string, "ctrl")) {
|
||||
result->ctrl = true;
|
||||
Advance(lex, 4);
|
||||
} else if (StartsWith(lex_string, "shift")) {
|
||||
result->shift = true;
|
||||
Advance(lex, 5);
|
||||
} else if (StartsWith(lex_string, "alt")) {
|
||||
result->alt = true;
|
||||
Advance(lex, 3);
|
||||
} else if (IsAlphanumeric(At(lex))) {
|
||||
char *start = lex->at;
|
||||
while (IsAlphanumeric(At(lex))) {
|
||||
Advance(lex);
|
||||
}
|
||||
String a = {start, lex->at - start};
|
||||
result->key = NameToSDLKeycode(a);
|
||||
if (result->key == 0) {
|
||||
result->kind = TriggerKind_Error;
|
||||
ReportErrorf("%s:%d:%d: Failed to parse key trigger, unexpected identifier: '%S'", lex->name, lex->line, lex->column, result->key);
|
||||
return result;
|
||||
}
|
||||
Advance(lex);
|
||||
} else {
|
||||
result->kind = TriggerKind_Error;
|
||||
ReportErrorf("%s:%d:%d: Failed to parse key trigger, unexpected character: '%c'", lex->name, lex->line, lex->column, At(lex));
|
||||
return result;
|
||||
}
|
||||
|
||||
if (At(lex) == '-') {
|
||||
Advance(lex);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Trigger *ParseKeyChord(Lexer *lex) {
|
||||
Trigger *left = ParseKeyAtom(lex);
|
||||
EatWhitespace(lex);
|
||||
while (IsAlphanumeric(At(lex))) {
|
||||
int op = At(lex);
|
||||
left = TriggerBinary(lex, left, ParseKeyChord(lex), ' ');
|
||||
EatWhitespace(lex);
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
Trigger *ParseKeyOr(Lexer *lex) {
|
||||
Trigger *left = ParseKeyChord(lex);
|
||||
EatWhitespace(lex);
|
||||
while (At(lex) == '|') {
|
||||
Advance(lex);
|
||||
left = TriggerBinary(lex, left, ParseKeyOr(lex), '|');
|
||||
EatWhitespace(lex);
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
bool MatchEvent(Trigger *trigger, Event *event) {
|
||||
if (event->kind != EVENT_KEY_PRESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (trigger->kind == TriggerKind_Key) {
|
||||
if (trigger->key == event->key && trigger->ctrl == event->ctrl && trigger->alt == event->alt && trigger->shift == event->shift) {
|
||||
return true;
|
||||
}
|
||||
} else if (trigger->kind == TriggerKind_Binary) {
|
||||
if (trigger->key == ' ') {
|
||||
return false;
|
||||
} else if (trigger->key == '|') {
|
||||
bool ok = MatchEvent(trigger->left, event);
|
||||
if (ok) return ok;
|
||||
ok = MatchEvent(trigger->right, event);
|
||||
if (ok) return ok;
|
||||
} ElseInvalidCodepath();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void TestParser() {
|
||||
Scratch scratch;
|
||||
{
|
||||
char *cmd = "ctrl-b";
|
||||
Lexer base_lex = {scratch, cmd, cmd, cmd + strlen(cmd), "keybinding"};
|
||||
Trigger *trigger = ParseKeyOr(&base_lex);
|
||||
Assert(trigger->kind == TriggerKind_Key);
|
||||
Assert(trigger->key == SDLK_B);
|
||||
Assert(trigger->ctrl);
|
||||
Assert(trigger->shift == 0);
|
||||
}
|
||||
|
||||
{
|
||||
char *cmd = "ctrl-b shift-ctrl-a";
|
||||
Lexer base_lex = {scratch, cmd, cmd, cmd + strlen(cmd), "keybinding"};
|
||||
Trigger *trigger = ParseKeyOr(&base_lex);
|
||||
Assert(trigger->kind == TriggerKind_Binary);
|
||||
Assert(trigger->key == ' ');
|
||||
Assert(trigger->left->kind == TriggerKind_Key);
|
||||
Assert(trigger->left->key == SDLK_B);
|
||||
Assert(trigger->left->ctrl);
|
||||
Assert(trigger->left->shift == 0);
|
||||
Assert(trigger->right->kind == TriggerKind_Key);
|
||||
Assert(trigger->right->key == SDLK_A);
|
||||
Assert(trigger->right->ctrl);
|
||||
Assert(trigger->right->shift);
|
||||
}
|
||||
|
||||
{
|
||||
char *cmd = "ctrl-b shift-ctrl-a | ctrl-c | ctrl-d";
|
||||
Lexer base_lex = {scratch, cmd, cmd, cmd + strlen(cmd), "keybinding"};
|
||||
Trigger *trigger = ParseKeyOr(&base_lex);
|
||||
Assert(trigger->kind == TriggerKind_Binary);
|
||||
Assert(trigger->key == '|');
|
||||
|
||||
Assert(trigger->left->kind == TriggerKind_Binary);
|
||||
Assert(trigger->left->key == ' ');
|
||||
|
||||
Assert(trigger->right->kind == TriggerKind_Binary);
|
||||
Assert(trigger->right->key == '|');
|
||||
|
||||
|
||||
Event event = {};
|
||||
event.kind = EVENT_KEY_PRESS;
|
||||
event.key = SDLK_D;
|
||||
event.ctrl = 1;
|
||||
bool ok = MatchEvent(trigger, &event);
|
||||
Assert(ok);
|
||||
|
||||
event.key = SDLK_F1;
|
||||
ok = MatchEvent(trigger, &event);
|
||||
Assert(ok == 0);
|
||||
|
||||
event.ctrl = 1;
|
||||
event.shift = 1;
|
||||
event.key = SDLK_A;
|
||||
ok = MatchEvent(trigger, &event);
|
||||
Assert(!ok);
|
||||
}
|
||||
|
||||
|
||||
} RegisterFunction(&TestFunctions, TestParser);
|
||||
@@ -33,14 +33,14 @@
|
||||
#include "management.cpp"
|
||||
#include "process.cpp"
|
||||
#include "event.cpp"
|
||||
#include "parser.cpp"
|
||||
|
||||
#include "lua_api.cpp"
|
||||
#include "commands.cpp"
|
||||
#include "lua_api.cpp"
|
||||
#include "commands_clipboard.cpp"
|
||||
#include "commands_bindings.cpp"
|
||||
#include "title_bar.cpp"
|
||||
|
||||
#include "lua_api_generated.cpp"
|
||||
#include "generated_config.cpp"
|
||||
|
||||
#include "draw.cpp"
|
||||
@@ -120,9 +120,6 @@ void SetMouseCursor(Event event) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
SetMouseCursor(SDL_SYSTEM_CURSOR_DEFAULT);
|
||||
}
|
||||
|
||||
@@ -239,7 +236,6 @@ void MainLoop() {
|
||||
SDL_GL_SwapWindow(SDLWindow);
|
||||
}
|
||||
|
||||
|
||||
#if _WIN32
|
||||
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
|
||||
#else
|
||||
@@ -256,7 +252,10 @@ int main(int argc, char **argv)
|
||||
|
||||
if (1) {
|
||||
RunArenaTest();
|
||||
RunBufferTest();
|
||||
For (TestFunctions) {
|
||||
it.function();
|
||||
}
|
||||
|
||||
// ReportErrorf("Testing DONE\n");
|
||||
// return 0;
|
||||
}
|
||||
|
||||
@@ -250,8 +250,8 @@ void LayoutWindows(int16_t wx, int16_t wy) {
|
||||
Rect2 screen_rect = Rect0Size(wx, wy);
|
||||
Vec2 size = GetSize(screen_rect);
|
||||
|
||||
Rect2 a = CutLeft(&screen_rect, 0.3f * size.x);
|
||||
Rect2 b = CutBottom(&a, 0.4f * size.y);
|
||||
Rect2 a = CutRight(&screen_rect, 0.3f * size.x);
|
||||
Rect2 b = CutTop(&a, 0.4f * size.y);
|
||||
Rect2 c = Shrink(b, 20);
|
||||
n->document_rect = n->total_rect = ToRect2I(c);
|
||||
}
|
||||
@@ -280,3 +280,40 @@ void LayoutWindows(int16_t wx, int16_t wy) {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
Window *GetOverlappingWindow(Vec2I p, Window *default_window = NULL) {
|
||||
For(Windows) {
|
||||
if (AreOverlapping(p, it->total_rect)) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return default_window;
|
||||
}
|
||||
|
||||
Vec2I GetSideOfWindow(Window *window, int direction) {
|
||||
Vec2I p = {};
|
||||
Rect2I rect = window->total_rect;
|
||||
float resizer_size = (float)window->font->char_spacing*0.5f; // @check_codebase_when_changing
|
||||
if (direction == DIR_LEFT) {
|
||||
p.x = rect.min.x - (Int)(resizer_size + window->font->char_spacing);
|
||||
p.y = rect.min.y + (rect.max.y / 2);
|
||||
} else if (direction == DIR_RIGHT) {
|
||||
p.x = rect.max.x + (Int)(resizer_size + window->font->char_spacing);
|
||||
p.y = rect.min.y + (rect.max.y / 2);
|
||||
} else if (direction == DIR_UP) {
|
||||
p.x = rect.min.x + (rect.max.x / 2);
|
||||
p.y = rect.min.y - (Int)(resizer_size + window->font->line_spacing);
|
||||
} else {
|
||||
Assert(direction == DIR_DOWN);
|
||||
p.x = rect.min.x + (rect.max.x / 2);
|
||||
p.y = rect.max.y + (Int)(resizer_size + window->font->line_spacing);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
Window *SwitchWindow(int direction) {
|
||||
Window *window = GetWindow(ActiveWindowID);
|
||||
Vec2I p = GetSideOfWindow(window, direction);
|
||||
Window *result = GetOverlappingWindow(p, window);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ struct Window {
|
||||
bool sync_visibility_with_focus : 1;
|
||||
bool lose_focus_on_escape : 1;
|
||||
bool jump_history : 1;
|
||||
bool eval_command : 1;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user