Binding parser, TestFunctions
This commit is contained in:
@@ -37,9 +37,29 @@ Commands TODO:
|
||||
- Turned off by default
|
||||
- Special: non editable, hotkeys don't work etc.
|
||||
- I'M SETTING ACTIVE WINDOW AFTER COMMAND!!! DO WE CONTINUE WITH THIS?
|
||||
- RegisterCommand(Command_ShowCommands, KEY_P | KEY_CTRL)
|
||||
|
||||
## 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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -677,19 +668,6 @@ void SaveBuffer(Buffer *buffer) {
|
||||
}
|
||||
}
|
||||
|
||||
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 KillSelectedLines(View *view) {
|
||||
Scratch scratch;
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
@@ -953,12 +931,6 @@ void ReopenBuffer(Buffer *buffer) {
|
||||
buffer->dirty = false;
|
||||
}
|
||||
|
||||
void Command_Reopen() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
ReopenBuffer(main.buffer);
|
||||
ActiveWindowID = main.window->id;
|
||||
} RegisterCommand(Command_Reopen);
|
||||
|
||||
void New(Window *window, String name = "") {
|
||||
View *view = GetView(window->active_view);
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
@@ -976,11 +948,6 @@ void New(Window *window, String name = "") {
|
||||
WindowOpenBufferView(window, name);
|
||||
}
|
||||
|
||||
void Command_New() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
New(main.window, "");
|
||||
} RegisterCommand(Command_New);
|
||||
|
||||
void NewDir(Window *window, String name = "") {
|
||||
View *view = GetView(window->active_view);
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
@@ -1000,23 +967,6 @@ void NewDir(Window *window, String name = "") {
|
||||
Open(name);
|
||||
}
|
||||
|
||||
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 ListFilesRecursive(Buffer *buffer, String dir) {
|
||||
Scratch scratch(buffer->line_starts.allocator);
|
||||
for (FileIter it = IterateFiles(scratch, dir); IsValid(it); Advance(&it)) {
|
||||
@@ -1035,15 +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);
|
||||
|
||||
View *ExecHidden(String buffer_name, String cmd, String working_dir) {
|
||||
View *view = OpenBufferView(buffer_name);
|
||||
Exec(view->id, true, cmd, working_dir);
|
||||
@@ -1117,6 +1058,84 @@ BSet Open(String16 path, String meta) {
|
||||
return Open(string, meta);
|
||||
}
|
||||
|
||||
void Eval(String string) {
|
||||
if (luaL_dostring(LuaState, string.data) != LUA_OK) {
|
||||
const char *error_message = lua_tostring(LuaState, -1);
|
||||
ReportWarningf("Execution error! %s", error_message);
|
||||
lua_pop(LuaState, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void Eval(String16 string) {
|
||||
Scratch scratch;
|
||||
Eval(ToString(scratch, string));
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -1158,25 +1177,6 @@ void Command_ListViews() {
|
||||
SelectRange(command_bar.view, GetBufferEndAsRange(command_bar.buffer));
|
||||
} RegisterCommand(Command_ListViews);
|
||||
|
||||
void Eval(String string) {
|
||||
if (luaL_dostring(LuaState, string.data) != LUA_OK) {
|
||||
const char *error_message = lua_tostring(LuaState, -1);
|
||||
ReportWarningf("Execution error! %s", error_message);
|
||||
lua_pop(LuaState, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void Eval(String16 string) {
|
||||
Scratch scratch;
|
||||
Eval(ToString(scratch, string));
|
||||
}
|
||||
|
||||
void SetProjectFile(Buffer *buffer) {
|
||||
WorkDir = ChopLastSlash(buffer->name);
|
||||
LuaProjectBuffer = buffer;
|
||||
LuaProjectBuffer->user_change_id = -1;
|
||||
}
|
||||
|
||||
void Command_SetProjectFile() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
SetProjectFile(main.buffer);
|
||||
@@ -1197,15 +1197,6 @@ void Command_SetProject() {
|
||||
Command_SetProjectFile();
|
||||
} RegisterCommand(Command_SetProject);
|
||||
|
||||
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;
|
||||
|
||||
@@ -200,15 +200,6 @@ 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 (Ctrl() && Shift() && Mouse(RIGHT)) {
|
||||
|
||||
} else if (Alt() && Ctrl() && Mouse(RIGHT)) {
|
||||
@@ -313,6 +304,15 @@ 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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -181,18 +181,26 @@ void ReloadStyle() {
|
||||
StyleUndoMergeTimeout = GetStyleFloat("UndoMergeTimeout", StyleUndoMergeTimeout);
|
||||
}
|
||||
|
||||
typedef void CommandFunction(void);
|
||||
struct CommandFunctionMeta {
|
||||
String name;
|
||||
CommandFunction *function;
|
||||
};
|
||||
Array<CommandFunctionMeta> CommandFunctions;
|
||||
struct Register_Command { Register_Command(String name, CommandFunction *f) { if (StartsWith(name, "Command_")) name = Skip(name, 8);Add(&CommandFunctions, {name, f}); } };
|
||||
#define RegisterCommand(NAME) Register_Command CONCAT(COMMAND, __COUNTER__)(#NAME, NAME)
|
||||
|
||||
typedef void Function(void);
|
||||
typedef int LuaFunction(lua_State *state);
|
||||
struct LuaFunctionMeta { String name; LuaFunction *function; };
|
||||
Array<LuaFunctionMeta> LuaFunctions;
|
||||
struct FunctionData { String name; Function *function; };
|
||||
struct LuaFunctionData { String name; LuaFunction *function; };
|
||||
|
||||
Array<FunctionData> CommandFunctions;
|
||||
Array<LuaFunctionData> LuaFunctions;
|
||||
Array<FunctionData> TestFunctions;
|
||||
|
||||
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 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)
|
||||
|
||||
|
||||
@@ -341,3 +341,12 @@ int Lua_Play(lua_State *L) {
|
||||
return 0;
|
||||
} RegisterLua(Lua_Play);
|
||||
|
||||
|
||||
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);
|
||||
|
||||
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,6 +33,7 @@
|
||||
#include "management.cpp"
|
||||
#include "process.cpp"
|
||||
#include "event.cpp"
|
||||
#include "parser.cpp"
|
||||
|
||||
#include "commands.cpp"
|
||||
#include "lua_api.cpp"
|
||||
@@ -119,9 +120,6 @@ void SetMouseCursor(Event event) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
SetMouseCursor(SDL_SYSTEM_CURSOR_DEFAULT);
|
||||
}
|
||||
|
||||
@@ -238,7 +236,6 @@ void MainLoop() {
|
||||
SDL_GL_SwapWindow(SDLWindow);
|
||||
}
|
||||
|
||||
|
||||
#if _WIN32
|
||||
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
|
||||
#else
|
||||
@@ -255,7 +252,10 @@ int main(int argc, char **argv)
|
||||
|
||||
if (1) {
|
||||
RunArenaTest();
|
||||
RunBufferTest();
|
||||
For (TestFunctions) {
|
||||
it.function();
|
||||
}
|
||||
|
||||
// ReportErrorf("Testing DONE\n");
|
||||
// return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user