Compare commits

..

8 Commits

Author SHA1 Message Date
Krzosa Karol
7720176e60 First hooks 2025-12-18 08:29:54 +01:00
Krzosa Karol
29002c965c Commands and keybindings 2025-12-16 23:07:16 +01:00
Krzosa Karol
5e7acd4a20 Binding parser, TestFunctions 2025-12-15 23:29:18 +01:00
Krzosa Karol
4e5a0f6a9b Remove NextActiveWindowID 2025-12-14 23:08:22 +01:00
Krzosa Karol
f297006dcb RegisterLua and ShowCommands, continue refactor 2025-12-14 21:54:37 +01:00
Krzosa Karol
85ca1a6a9e RegisterCommand 2025-12-14 17:32:48 +01:00
Krzosa Karol
5a12ab8d8c Linux add backtrace, fixing scaling / DPI problems 2025-12-14 17:05:55 +01:00
Krzosa Karol
2d79790d83 Remove init.project.lua 2025-12-14 12:04:03 +01:00
26 changed files with 1418 additions and 1036 deletions

0
build.bat Normal file → Executable file
View File

81
build.sh Normal file → Executable file
View File

@@ -3,79 +3,10 @@
mkdir build mkdir build
cd build cd build
if [ "$1" = "release" ]; then FLAGS="-nostdlib++ -fno-exceptions -fdiagnostics-absolute-paths -g -Wno-writable-strings -I../src -DDEBUG_BUILD=1"
profile_flags="-DDEBUG_BUILD=0 -O2" # clang -o metaprogram $FLAGS ../src/metaprogram/metaprogram.cpp
else # ./metaprogram
profile_flags="-DDEBUG_BUILD=1"
fi
if [ ! -f "lbaselib.o" ]; then I="-I../src/external/SDL/include -I../src/external/lua/src -I../src/external/glad"
clang -g -I../src/external/lua/src -I../src/external/glad \ clang -o te $FLAGS ../src/text_editor/text_editor.cpp $I -lSDL3 -lm -lbacktrace
../src/external/lua/src/lbaselib.c \ cp te ../data/te
../src/external/lua/src/lctype.c \
../src/external/lua/src/ldo.c \
../src/external/lua/src/lgc.c \
../src/external/lua/src/liolib.c \
../src/external/lua/src/lmem.c \
../src/external/lua/src/lopcodes.c \
../src/external/lua/src/lstate.c \
../src/external/lua/src/ltable.c \
../src/external/lua/src/lundump.c \
../src/external/lua/src/lzio.c \
../src/external/lua/src/lapi.c \
../src/external/lua/src/lcode.c \
../src/external/lua/src/ldblib.c \
../src/external/lua/src/ldump.c \
../src/external/lua/src/llex.c \
../src/external/lua/src/loadlib.c \
../src/external/lua/src/loslib.c \
../src/external/lua/src/lstring.c \
../src/external/lua/src/ltablib.c \
../src/external/lua/src/lutf8lib.c \
../src/external/lua/src/lauxlib.c \
../src/external/lua/src/lcorolib.c \
../src/external/lua/src/ldebug.c \
../src/external/lua/src/lfunc.c \
../src/external/lua/src/linit.c \
../src/external/lua/src/lmathlib.c \
../src/external/lua/src/lobject.c \
../src/external/lua/src/lparser.c \
../src/external/lua/src/lstrlib.c \
../src/external/lua/src/ltm.c \
../src/external/lua/src/lvm.c \
../src/external/glad/glad.c \
-c
fi
if [ ! -f "metaprogram.exe" ]; then
clang ../src/metaprogram/metaprogram.cpp ../src/basic/unix.cpp -o metaprogram.exe \
-nostdlib++ -fno-exceptions -fdiagnostics-absolute-paths -g \
-Wno-writable-strings \
-I../src
fi
./metaprogram.exe
clang ../src/text_editor/text_editor.cpp ../src/basic/unix.cpp -o te_linux.exe \
-nostdlib++ -fno-exceptions -fdiagnostics-absolute-paths -g \
$profile_flags \
-Wno-writable-strings \
-I../src/external/SDL/include \
-I../src/external/lua/src \
-I../src/external/glad \
-I../src/ \
-lm \
../src/external/SDL/build/libSDL3.a \
lbaselib.o lctype.o ldo.o lgc.o liolib.o lmem.o \
lopcodes.o lstate.o ltable.o lundump.o lzio.o lapi.o lcode.o ldblib.o ldump.o \
llex.o loadlib.o loslib.o lstring.o ltablib.o lutf8lib.o lauxlib.o lcorolib.o ldebug.o \
lfunc.o linit.o lmathlib.o lobject.o lparser.o lstrlib.o ltm.o lvm.o \
glad.o \
if [ "$1" = "release" ]; then
cp te_linux.exe ../data/te
echo written ../data/te
else
cp te_linux.exe ../data/te_debug
echo written ../data/te_debug
fi

0
build_web.bat Normal file → Executable file
View File

0
build_web.sh Normal file → Executable file
View File

View File

@@ -1,14 +0,0 @@
FKey[2] = "remedybg.exe build\\te.exe"
FKey[5] = "remedybg.exe continue-execution"
FKey[9] = function () return 'remedybg.exe add-breakpoint-at-file '..GetFilename()..' '..tostring(GetLine()) end
FKey[10] = function () return 'remedybg.exe run-to-cursor '..GetFilename()..' '..tostring(GetLine()) end
function OnInit()
Open("init.project.lua")
Split(VERTICAL)
Open("src/text_editor/todo.txt")
Split(HORIZONTAL)
Open("src/text_editor/commands.cpp")
SplitSize(0.15)
end

View File

@@ -1,12 +1,3 @@
REDESIGN and DELETE CODE
- Reduce the amount of actions needed to navigate using keyboard
- Make mouse important but much less so
Needs to change:
- Make it more similar to sublime like editors
- Need Ctrl + P
- Clickable title bar may be cool or whatever but it's pretty bad
- Executing lua commands is clunky, need a real Ctrl+P and keybind actions, popups: remove a lot of the lua functionality, just for config files
- Window, View, Buffer + flags design (or is completely new kind based approach needed for Windows/Views?) - Window, View, Buffer + flags design (or is completely new kind based approach needed for Windows/Views?)
- How to make non-editable, informative, with different font size, title bar. Which might also contain tabs - How to make non-editable, informative, with different font size, title bar. Which might also contain tabs
- How to design clickable tree view in this way? - How to design clickable tree view in this way?
@@ -14,22 +5,9 @@ Needs to change:
- How to design popup view (input field)? - How to design popup view (input field)?
- How to design search view? or search and replace view? - How to design search view? or search and replace view?
Things I like:
- Basic editing
- Configurable Open
- Lua config files work pretty well
Splits: Splits:
- Buffer16 Buffer8?
- Why constraint that name of buffer needs to be unique? For Open() and default behavior but is this required? - Why constraint that name of buffer needs to be unique? For Open() and default behavior but is this required?
- Try to add Tracking Allocator and rewrite the app, free all memory at the end of the app and check all is well - Try to add Tracking Allocator and rewrite the app, free all memory at the end of the app and check all is well
- move titlebar, search to splits?
Linux
- Add backtrace
Commands TODO: Commands TODO:
- Search - Search
@@ -41,12 +19,13 @@ Commands TODO:
- Console: OK concept but constrain - Console: OK concept but constrain
- Turned off by default - Turned off by default
- Special: non editable, hotkeys don't work etc. - Special: non editable, hotkeys don't work etc.
- I'M SETTING ACTIVE WINDOW AFTER COMMAND!!! DO WE CONTINUE WITH THIS?
- CONSIDER AUTOMATING: CheckpointBeforeGoto
- GotoBackward how to handle that in case we want to automate and create on every move?
backlog
DESIGN try to make console less special, make stuff reusable etc. DESIGN try to make console less special, make stuff reusable etc.
DESIGN Config file versions, when loading should be checked, at the top of the file, what to do when old version? DESIGN Config file versions, when loading should be checked, at the top of the file, what to do when old version?
ISSUE Ctrl+Alt+Down (DuplicateLine) doesn't work on ubuntu ISSUE Ctrl+Alt+Down (DuplicateLine) doesn't work on ubuntu
@@ -79,7 +58,6 @@ FEATURE group history entries so the you can rollback through multiple ones at o
- code sections, visual demarkation if beginning of line has a very specific text + goto next / goto prev section hotkey! - code sections, visual demarkation if beginning of line has a very specific text + goto next / goto prev section hotkey!
- combine glyph and selection rendering - combine glyph and selection rendering
backlog
- expose a coroutine based scripting enviorment where user can execute shell commands wait for them and perform actions in very linear manner - expose a coroutine based scripting enviorment where user can execute shell commands wait for them and perform actions in very linear manner
- Test stdin writing code - Test stdin writing code
- Implement shell interaction (the valid cmd lines should start with '>' or '$', user can add more lines like this to expand the command size maybe?, if we have a case where we have a line with '>' but the last line doesn't have (just a space) then it should execute?) - Implement shell interaction (the valid cmd lines should start with '>' or '$', user can add more lines like this to expand the command size maybe?, if we have a case where we have a line with '>' but the last line doesn't have (just a space) then it should execute?)

View File

@@ -42,6 +42,8 @@ API bool VDecommit(void *p, size_t size) {
} }
#elif OS_LINUX || OS_MAC #elif OS_LINUX || OS_MAC
#include <sys/mman.h>
API void *VReserve(size_t size) { API void *VReserve(size_t size) {
void *result = mmap(0, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, (off_t)0); void *result = mmap(0, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, (off_t)0);

View File

@@ -37,8 +37,6 @@ For(arr.reverse_iter()) {
#define ForItem(it, array) for (auto &it : (array)) #define ForItem(it, array) for (auto &it : (array))
#define For(array) ForItem(it, array) #define For(array) ForItem(it, array)
template <class T> template <class T>
struct Slice { struct Slice {
T *data; T *data;

View File

@@ -213,3 +213,8 @@ inline uint64_t GetRandomU64(RandomSeed *state) {
x ^= x << 17; x ^= x << 17;
return state->a = x; 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)

View File

@@ -14,11 +14,58 @@
#include <stdlib.h> #include <stdlib.h>
#include <spawn.h> #include <spawn.h>
#include <poll.h> #include <poll.h>
#include <execinfo.h>
#include <backtrace.h>
API void (*Error)(const char *, ...); API void (*Error)(const char *, ...);
struct backtrace_state *backtrace_state = NULL;
void BacktraceOnError(void *data, const char *msg, int errnum) {
Error("libbacktrace error: %s (errnum: %d)\n", msg, errnum);
}
int BacktraceOnPrint(void *data, uintptr_t pc, const char *filename, int lineno, const char *function) {
bool printed = false;
if (filename != NULL) {
char buffer[512];
char *f = realpath(filename, buffer);
printf("%s:%d:1: ", f, lineno);
printed = true;
}
if (function != NULL) {
printf("%s", function);
printed = true;
}
if (printed) {
printf("\n");
}
return 0;
}
void CrashHandler(int signal, siginfo_t* info, void* context) {
backtrace_full(backtrace_state, 2, BacktraceOnPrint, BacktraceOnError, NULL);
exit(1);
}
void RegisterCrashHandler(void) {
backtrace_state = backtrace_create_state(NULL, 1, BacktraceOnError, NULL);
struct sigaction sa;
sa.sa_sigaction = CrashHandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_SIGINFO;
sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGABRT, &sa, NULL);
sigaction(SIGBUS, &sa, NULL);
sigaction(SIGILL, &sa, NULL);
sigaction(SIGFPE, &sa, NULL);
}
API void InitOS(void (*error_proc)(const char *, ...)) { API void InitOS(void (*error_proc)(const char *, ...)) {
Error = error_proc; Error = error_proc;
RegisterCrashHandler();
} }
API String ReadFile(Allocator al, String path) { API String ReadFile(Allocator al, String path) {
@@ -171,9 +218,9 @@ API void Advance(FileIter *it) {
const char *dir_char_ending = it->is_directory ? "/" : ""; const char *dir_char_ending = it->is_directory ? "/" : "";
const char *separator = it->path.data[it->path.len - 1] == '/' ? "" : "/"; const char *separator = it->path.data[it->path.len - 1] == '/' ? "" : "/";
it->relative_path = Format(it->allocator, "%.*s%s%s%s", FmtString(it->path), separator, file->d_name, dir_char_ending); it->relative_path = Format(it->allocator, "%S%s%s%s", it->path, separator, file->d_name, dir_char_ending);
it->absolute_path = GetAbsolutePath(it->allocator, it->relative_path); it->absolute_path = GetAbsolutePath(it->allocator, it->relative_path);
if (it->is_directory) it->absolute_path = Format(it->allocator, "%.*s/", FmtString(it->absolute_path)); if (it->is_directory) it->absolute_path = Format(it->allocator, "%S/", it->absolute_path);
it->is_valid = true; it->is_valid = true;
return; return;
} }

View File

@@ -93,6 +93,16 @@ API Int GetBack(Caret caret) {
return result; return result;
} }
API Int GetMax(Caret caret) {
Int result = Max(caret.pos[0], caret.pos[1]);
return result;
}
API Int GetMin(Caret caret) {
Int result = Min(caret.pos[0], caret.pos[1]);
return result;
}
API Caret MakeCaret(Int pos) { API Caret MakeCaret(Int pos) {
Caret result = {}; Caret result = {};
result.range.min = result.range.max = pos; result.range.min = result.range.max = pos;
@@ -1400,7 +1410,7 @@ void RunBufferTest() {
DeinitBuffer(&buffer); DeinitBuffer(&buffer);
TrackingAllocatorCheck(); TrackingAllocatorCheck();
} }
} } RegisterFunction(&TestFunctions, RunBufferTest);
/////////////////////////////// ///////////////////////////////
// Management // Management
@@ -1467,13 +1477,11 @@ void InitBuffers() {
Buffer *null_buffer = CreateBuffer(sys_allocator, GetUniqueBufferName(GetWorkingDir(scratch), "console")); Buffer *null_buffer = CreateBuffer(sys_allocator, GetUniqueBufferName(GetWorkingDir(scratch), "console"));
View *null_view = CreateView(null_buffer->id); View *null_view = CreateView(null_buffer->id);
Assert(null_buffer->id == NullBufferID && null_view->id == NullViewID); Assert(null_buffer->id == NullBufferID && null_view->id == NullViewID);
TraceBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "trace")); TraceBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "trace"));
TraceView = CreateView(TraceBuffer->id); TraceView = CreateView(TraceBuffer->id);
GCInfoBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "gc")); GCInfoBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "gc"));
EventBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "events")); EventBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "events"));
ScratchBuffer = BufferOpenFile(GetUniqueBufferName(WorkDir, "scratch")); ScratchBuffer = BufferOpenFile(GetUniqueBufferName(WorkDir, "scratch"));
EventBuffer->no_history = true; EventBuffer->no_history = true;
GCInfoBuffer->no_history = true; GCInfoBuffer->no_history = true;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -46,29 +46,6 @@ void UpdateScroll(Window *window, bool update_caret_scrolling) {
} }
} }
void FuzzySearchOpen(BSet active) {
bool success = false;
Range range = active.view->carets[0].range;
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);
Int idx = 0;
if (Seek(string, u"||", &idx)) {
string = Skip(string, idx + 3);
Open(string);
success = true;
}
}
if (!success) {
Open(FetchLoadWord());
}
}
void OnCommand(Event event) { void OnCommand(Event event) {
ProfileFunction(); ProfileFunction();
// //
@@ -125,8 +102,6 @@ void OnCommand(Event event) {
} else if (IsDocumentSelectionValid()) { } else if (IsDocumentSelectionValid()) {
Assert(ScrollbarSelected.id == -1); Assert(ScrollbarSelected.id == -1);
BSet selected = GetBSet(DocumentSelected); BSet selected = GetBSet(DocumentSelected);
Vec2I mouse = MouseVec2I(); Vec2I mouse = MouseVec2I();
// Special case for full-screen where we can have document // Special case for full-screen where we can have document
// aligned with monitor screen in which case mouse cursor cannot // aligned with monitor screen in which case mouse cursor cannot
@@ -134,6 +109,8 @@ void OnCommand(Event event) {
if (mouse.y == 0 && selected.window->document_rect.min.y == 0) { if (mouse.y == 0 && selected.window->document_rect.min.y == 0) {
float x, y; float x, y;
SDL_GetGlobalMouseState(&x, &y); SDL_GetGlobalMouseState(&x, &y);
x = roundf(DPIScale * x);
y = roundf(DPIScale * y);
if (y == 0) { if (y == 0) {
mouse.y = -10; mouse.y = -10;
} }
@@ -179,21 +156,12 @@ void OnCommand(Event event) {
} }
bool mouse_in_document = AreOverlapping(mouse, it->document_rect); bool mouse_in_document = AreOverlapping(mouse, it->document_rect);
if (mouse_in_document) { if (mouse_in_document) {
NextActiveWindowID = it->id; ActiveWindowID = it->id;
break; 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)) { if (Ctrl() && Shift() && Mouse(RIGHT)) {
} else if (Alt() && Ctrl() && Mouse(RIGHT)) { } else if (Alt() && Ctrl() && Mouse(RIGHT)) {
@@ -237,7 +205,7 @@ void OnCommand(Event event) {
Assert(ScrollbarSelected.id == -1); Assert(ScrollbarSelected.id == -1);
Assert(DocumentSelected.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_document = AreOverlapping(mouse, active.window->document_rect);
bool mouse_in_line_numbers = AreOverlapping(mouse, active.window->line_numbers_rect); bool mouse_in_line_numbers = AreOverlapping(mouse, active.window->line_numbers_rect);
if (mouse_in_document || mouse_in_line_numbers) { if (mouse_in_document || mouse_in_line_numbers) {
@@ -298,338 +266,54 @@ void OnCommand(Event event) {
} }
} }
if (CtrlPress(SDLK_W)) {
Command_KillWindow();
}
if (CtrlAltPress(SDLK_P)) {
} else if (CtrlShiftPress(SDLK_P)) {
Command_ShowCommandList();
} else if (CtrlPress(SDLK_P)) {
Command_ShowBufferList();
}
if (CtrlPress(SDLK_0)) {
Command_ToggleDebug();
}
if (CtrlPress(SDLK_1)) {
NextActiveWindowID = 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;
}
if (CtrlPress(SDLK_3)) {
Window *first = GetOverlappingWindow({0,0});
if (first) {
Window *second = GetOverlappingWindow(GetSideOfWindow(first, DIR_RIGHT));
if (second) {
Window *third = GetOverlappingWindow(GetSideOfWindow(second, DIR_RIGHT));
if (third) {
NextActiveWindowID = third->id;
}
}
}
}
BSet main = GetBSet(LastActiveLayoutWindowID); BSet main = GetBSet(LastActiveLayoutWindowID);
BSet active = GetBSet(ActiveWindowID); BSet active = GetBSet(ActiveWindowID);
// @todo: somehow detect in post command that buffer changed but random buffer can get changed??? Not sure
// maybe we
Int buffer_change_id = active.buffer->change_id; Int buffer_change_id = active.buffer->change_id;
String event_text = event.text;
bool skip = CallOnCommand(&event); SkipRemainingCommands = false;
if (skip) { For (CommandFunctions) {
// :OnCommandEnding if (it.trigger && MatchEvent(it.trigger, &event)) {
MergeCarets(active.buffer, &active.view->carets); it.function();
IF_DEBUG(AssertRanges(active.view->carets)); if (SkipRemainingCommands) {
return; break;
} }
if (active.view->fuzzy_search) {
if (Press(SDLK_RETURN)) {
FuzzySearchOpen(active);
return;
} }
} }
if (event.kind == EVENT_DROP_FILE) { if (event.kind == EVENT_DROP_FILE) {
WindowOpenBufferView(active.window, event.text); SkipRemainingCommands = false;
For (OnDropFileHooks) {
it.function(&event_text);
if (SkipRemainingCommands) {
break;
} }
if (Press(SDLK_DOWN) || Press(SDLK_RIGHT) || Press(SDLK_LEFT) || Press(SDLK_UP)) {
CheckpointBeforeGoto(active.window);
} }
if (CtrlAltPress(SDLK_DOWN)) {
DuplicateLine(active.view, DIR_DOWN);
} else if (AltShiftPress(SDLK_DOWN)) {
CreateCursorVertical(active.view, DIR_DOWN);
} else if (CtrlShiftPress(SDLK_DOWN)) {
MoveCarets(active.view, DIR_DOWN, CTRL_PRESSED, SHIFT_PRESS);
} else if (AltPress(SDLK_DOWN)) {
MoveCaretsLine(active.view, DIR_DOWN);
} else if (CtrlPress(SDLK_DOWN)) {
MoveCarets(active.view, DIR_DOWN, CTRL_PRESSED);
} else if (ShiftPress(SDLK_DOWN)) {
MoveCarets(active.view, DIR_DOWN, false, SHIFT_PRESS);
} else if (Press(SDLK_DOWN)) {
MoveCarets(active.view, DIR_DOWN);
}
if (CtrlAltPress(SDLK_UP)) {
DuplicateLine(active.view, DIR_UP);
} else if (AltShiftPress(SDLK_UP)) {
CreateCursorVertical(active.view, DIR_UP);
} else if (CtrlShiftPress(SDLK_UP)) {
MoveCarets(active.view, DIR_UP, CTRL_PRESSED, SHIFT_PRESS);
} else if (AltPress(SDLK_UP)) {
MoveCaretsLine(active.view, DIR_UP);
} else if (CtrlPress(SDLK_UP)) {
MoveCarets(active.view, DIR_UP, CTRL_PRESSED);
} else if (ShiftPress(SDLK_UP)) {
MoveCarets(active.view, DIR_UP, false, SHIFT_PRESS);
} else if (Press(SDLK_UP)) {
MoveCarets(active.view, DIR_UP);
}
if (CtrlShiftPress(SDLK_LEFT)) {
MoveCarets(active.view, DIR_LEFT, CTRL_PRESSED, SHIFT_PRESS);
} else if (CtrlPress(SDLK_LEFT)) {
MoveCarets(active.view, DIR_LEFT, CTRL_PRESSED);
} else if (ShiftPress(SDLK_LEFT)) {
MoveCarets(active.view, DIR_LEFT, false, SHIFT_PRESS);
} else if (AltPress(SDLK_LEFT)) {
NextActiveWindowID = SwitchWindow(DIR_LEFT)->id;
} else if (Press(SDLK_LEFT)) {
MoveCarets(active.view, DIR_LEFT);
}
if (CtrlShiftPress(SDLK_RIGHT)) {
MoveCarets(active.view, DIR_RIGHT, CTRL_PRESSED, SHIFT_PRESS);
} else if (CtrlPress(SDLK_RIGHT)) {
MoveCarets(active.view, DIR_RIGHT, CTRL_PRESSED);
} else if (ShiftPress(SDLK_RIGHT)) {
MoveCarets(active.view, DIR_RIGHT, false, SHIFT_PRESS);
} else if (AltPress(SDLK_RIGHT)) {
NextActiveWindowID = SwitchWindow(DIR_RIGHT)->id;
} else if (Press(SDLK_RIGHT)) {
MoveCarets(active.view, DIR_RIGHT);
}
if (CtrlShiftPress(SDLK_Z)) {
RedoEdit(active.buffer, &active.view->carets);
} else if (CtrlPress(SDLK_Z)) {
UndoEdit(active.buffer, &active.view->carets);
}
if (CtrlPress(SDLK_C)) {
ClipboardCopy(active.view);
} else if (CtrlPress(SDLK_V)) {
ClipboardPaste(active.view);
} else if (CtrlPress(SDLK_X)) {
SaveCaretHistoryBeforeBeginEdit(active.buffer, active.view->carets);
ClipboardCopy(active.view);
Replace(active.view, u"");
}
if (CtrlPress(SDLK_A)) {
SelectEntireBuffer(active.view);
active.view->update_scroll = false;
}
if (ShiftPress(SDLK_PAGEUP)) {
CheckpointBeforeGoto(active.window);
MoveCursorByPageSize(active.window, DIR_UP, SHIFT_PRESS);
} else if (CtrlPress(SDLK_PAGEUP)) {
CheckpointBeforeGoto(active.window);
SelectRange(active.view, MakeRange(0));
} else if (Press(SDLK_PAGEUP)) {
CheckpointBeforeGoto(active.window);
MoveCursorByPageSize(active.window, DIR_UP);
}
if (ShiftPress(SDLK_PAGEDOWN)) {
CheckpointBeforeGoto(active.window);
MoveCursorByPageSize(active.window, DIR_DOWN, SHIFT_PRESS);
} else if (CtrlPress(SDLK_PAGEDOWN)) {
CheckpointBeforeGoto(active.window);
SelectRange(active.view, MakeRange(active.buffer->len));
} else if (Press(SDLK_PAGEDOWN)) {
CheckpointBeforeGoto(active.window);
MoveCursorByPageSize(active.window, DIR_DOWN);
}
if (ShiftPress(SDLK_HOME)) {
CheckpointBeforeGoto(active.window);
MoveCursorToSide(active.view, DIR_LEFT, SHIFT_PRESS);
} else if (Press(SDLK_HOME)) {
CheckpointBeforeGoto(active.window);
MoveCursorToSide(active.view, DIR_LEFT);
}
if (ShiftPress(SDLK_END)) {
CheckpointBeforeGoto(active.window);
MoveCursorToSide(active.view, DIR_RIGHT, SHIFT_PRESS);
} else if (Press(SDLK_END)) {
CheckpointBeforeGoto(active.window);
MoveCursorToSide(active.view, DIR_RIGHT);
}
if (CtrlShiftPress(SDLK_TAB)) {
} else if (ShiftPress(SDLK_TAB)) {
IndentSelectedLines(active.view, SHIFT_PRESS);
} else if (CtrlPress(SDLK_TAB)) {
} else if (Press(SDLK_TAB)) {
IndentSelectedLines(active.view);
}
if (CtrlPress(SDLK_LEFTBRACKET)) {
IndentSelectedLines(active.view, SHIFT_PRESS);
}
if (CtrlPress(SDLK_RIGHTBRACKET)) {
IndentSelectedLines(active.view);
}
if (CtrlShiftPress(SDLK_K)) {
KillSelectedLines(active.view);
}
if (CtrlPress(SDLK_BACKSPACE)) {
Delete(active.view, DIR_LEFT, CTRL_PRESSED);
} else if (Press(SDLK_BACKSPACE)) {
Delete(active.view, DIR_LEFT);
}
if (CtrlPress(SDLK_DELETE)) {
Delete(active.view, DIR_RIGHT, CTRL_PRESSED);
} else if (Press(SDLK_DELETE)) {
Delete(active.view, DIR_RIGHT);
} }
if (event.kind == EVENT_TEXT_INPUT) { if (event.kind == EVENT_TEXT_INPUT) {
Scratch scratch; SkipRemainingCommands = false;
String string = event.text; For (OnTextInputHooks) {
String16 string16 = ToString16(scratch, string); it.function(&event_text);
Replace(active.view, string16); if (SkipRemainingCommands) {
} break;
if (CtrlPress(SDLK_D)) {
CheckpointBeforeGoto(active.window);
String16 string = GetString(active.buffer, active.view->carets[0].range);
Caret caret = FindNext(active.buffer, string, active.view->carets[0]);
Insert(&active.view->carets, caret, 0);
MergeCarets(active.buffer, &active.view->carets);
}
if (CtrlPress(SDLK_EQUALS)) {
StyleFontSize += 1;
ReloadFont(StyleFont, (U32)StyleFontSize);
}
if (CtrlPress(SDLK_MINUS)) {
if (StyleFontSize > 4) {
StyleFontSize -= 1;
ReloadFont(StyleFont, (U32)StyleFontSize);
}
}
if (CtrlPress(SDLK_E)) {
} else if (AltPress(SDLK_E)) {
}
if (CtrlShiftPress(SDLK_RETURN)) {
MoveCursorToSide(active.view, DIR_LEFT);
IdentedNewLine(active.view);
MoveCarets(active.view, DIR_UP);
} else if (CtrlPress(SDLK_RETURN)) {
MoveCursorToSide(active.view, DIR_RIGHT);
IdentedNewLine(active.view);
} else if (Press(SDLK_RETURN)) {
IdentedNewLine(active.view);
}
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);
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);
Buffer *temp_buffer = CreateTempBuffer(scratch, active.buffer->cap);
For(IterateInReverse(&ratings)) {
String16 s = GetLineStringWithoutNL(active.buffer, it.index);
if (s.len == 0) continue;
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), s);
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), u"\n");
}
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), last_line_string);
Caret caret = active.view->carets[0];
SaveCaretHistoryBeforeBeginEdit(active.buffer, active.view->carets);
SelectEntireBuffer(active.view);
Replace(active.view, GetString(temp_buffer));
active.view->carets[0] = caret;
} }
} }
} }
if (CtrlPress(SDLK_F)) {
Window *window = GetWindow(SearchBarWindowID);
window->visible = !window->visible;
}
if (CtrlPress(SDLK_S)) {
SaveBuffer(active.buffer);
}
if (CtrlPress(SDLK_PERIOD)) {
String name = ChopLastSlash(main.buffer->name);
if (EndsWith(main.buffer->name, "dirlisting")) {
name = ChopLastSlash(name);
}
Open(name);
}
if (CtrlShiftPress(SDLK_L)) {
EncloseSpace(active.view);
} else if (CtrlPress(SDLK_L)) {
EncloseLine(active.view);
}
if (CtrlShiftPress(SDLK_G)) {
} else if (CtrlPress(SDLK_G)) {
}
if (AltPress(SDLK_Q)) {
GotoBackward(main.window);
}
if (CtrlPress(SDLK_Q)) {
if (active.view->fuzzy_search) {
FuzzySearchOpen(active);
} else {
Open(FetchLoadWord());
}
}
if (Press(SDLK_ESCAPE)) {
active.view->carets.len = 1;
active.view->carets[0] = MakeCaret(GetFront(active.view->carets[0]));
if (active.window->lose_focus_on_escape && active.window->id == ActiveWindowID) {
if (active.window->layout) {
//
} else {
NextActiveWindowID = LastActiveLayoutWindowID;
}
}
}
// :OnCommandEnding
MergeCarets(active.buffer, &active.view->carets); MergeCarets(active.buffer, &active.view->carets);
IF_DEBUG(AssertRanges(active.view->carets)); IF_DEBUG(AssertRanges(active.view->carets));
MergeCarets(main.buffer, &main.view->carets);
IF_DEBUG(AssertRanges(main.view->carets));
SkipRemainingCommands = false;
For (PostCommandHooks) {
it.function(NULL);
if (SkipRemainingCommands) {
return;
}
}
} }

View File

@@ -86,3 +86,20 @@ void ClipboardPaste(View *view) {
} }
EndEdit(buffer, &edits, &view->carets, KILL_SELECTION); EndEdit(buffer, &edits, &view->carets, KILL_SELECTION);
} }
void Command_Paste() {
BSet active = GetBSet(ActiveWindowID);
ClipboardPaste(active.view);
} RegisterCommand(Command_Paste, "ctrl-v");
void Command_Copy() {
BSet active = GetBSet(ActiveWindowID);
ClipboardCopy(active.view);
} RegisterCommand(Command_Copy, "ctrl-c");
void Command_Cut() {
BSet active = GetBSet(ActiveWindowID);
SaveCaretHistoryBeforeBeginEdit(active.buffer, active.view->carets);
ClipboardCopy(active.view);
Replace(active.view, u"");
} RegisterCommand(Command_Cut, "ctrl-x");

View File

@@ -260,6 +260,91 @@ const char *SDLKeycodeToName(SDL_Keycode keycode) {
} }
} }
struct { String string; EventKind value; } MouseConversionTable[] = {
{"mousex1", EVENT_MOUSE_X1},
{"mousex2", EVENT_MOUSE_X2},
{"mouseleft", EVENT_MOUSE_LEFT},
{"mouseright", EVENT_MOUSE_RIGHT},
{"mousemiddle", EVENT_MOUSE_MIDDLE},
};
struct { String string; SDL_Keycode value; } SDLKeycodeConversionTable[] = {
{"enter", SDLK_RETURN},
{"escape", SDLK_ESCAPE},
{"backspace", SDLK_BACKSPACE},
{"tab", SDLK_TAB},
{"space", SDLK_SPACE},
{"minus", SDLK_MINUS},
{"period", SDLK_PERIOD},
{"slash", SDLK_SLASH},
{"0", SDLK_0},
{"1", SDLK_1},
{"2", SDLK_2},
{"3", SDLK_3},
{"4", SDLK_4},
{"5", SDLK_5},
{"6", SDLK_6},
{"7", SDLK_7},
{"8", SDLK_8},
{"9", SDLK_9},
{"semicolon", SDLK_SEMICOLON},
{"less", SDLK_LESS},
{"equals", SDLK_EQUALS},
{"greater", SDLK_GREATER},
{"leftbracket", SDLK_LEFTBRACKET},
{"backslash", SDLK_BACKSLASH},
{"rightbracket", SDLK_RIGHTBRACKET},
{"grave", SDLK_GRAVE},
{"a", SDLK_A},
{"b", SDLK_B},
{"c", SDLK_C},
{"d", SDLK_D},
{"e", SDLK_E},
{"f", SDLK_F},
{"g", SDLK_G},
{"h", SDLK_H},
{"i", SDLK_I},
{"j", SDLK_J},
{"k", SDLK_K},
{"l", SDLK_L},
{"m", SDLK_M},
{"n", SDLK_N},
{"o", SDLK_O},
{"p", SDLK_P},
{"q", SDLK_Q},
{"r", SDLK_R},
{"s", SDLK_S},
{"t", SDLK_T},
{"u", SDLK_U},
{"v", SDLK_V},
{"w", SDLK_W},
{"x", SDLK_X},
{"y", SDLK_Y},
{"z", SDLK_Z},
{"delete", SDLK_DELETE},
{"capslock", SDLK_CAPSLOCK},
{"f1", SDLK_F1},
{"f2", SDLK_F2},
{"f3", SDLK_F3},
{"f4", SDLK_F4},
{"f5", SDLK_F5},
{"f6", SDLK_F6},
{"f7", SDLK_F7},
{"f8", SDLK_F8},
{"f9", SDLK_F9},
{"f10", SDLK_F10},
{"f11", SDLK_F11},
{"f12", SDLK_F12},
{"insert", SDLK_INSERT},
{"home", SDLK_HOME},
{"pageup", SDLK_PAGEUP},
{"end", SDLK_END},
{"pagedown", SDLK_PAGEDOWN},
{"right", SDLK_RIGHT},
{"left", SDLK_LEFT},
{"down", SDLK_DOWN},
{"up", SDLK_UP},
};
void FillEventWithBasicData(Event *event) { void FillEventWithBasicData(Event *event) {
SDL_Keymod mod = SDL_GetModState(); SDL_Keymod mod = SDL_GetModState();
@@ -270,11 +355,11 @@ void FillEventWithBasicData(Event *event) {
float xmouse, ymouse; float xmouse, ymouse;
SDL_GetMouseState(&xmouse, &ymouse); SDL_GetMouseState(&xmouse, &ymouse);
event->xmouse = (int16_t)xmouse; event->xmouse = (int16_t)roundf(DPIScale * xmouse);
event->ymouse = (int16_t)ymouse; event->ymouse = (int16_t)roundf(DPIScale * ymouse);
int xwindow, ywindow; int xwindow, ywindow;
SDL_GetWindowSize(SDLWindow, &xwindow, &ywindow); SDL_GetWindowSizeInPixels(SDLWindow, &xwindow, &ywindow);
event->xwindow = xwindow; event->xwindow = xwindow;
event->ywindow = ywindow; event->ywindow = ywindow;
event->text = ""; event->text = "";
@@ -305,8 +390,8 @@ Event TranslateSDLEvent(SDL_Event *input_event) {
case SDL_EVENT_MOUSE_BUTTON_DOWN: { case SDL_EVENT_MOUSE_BUTTON_DOWN: {
SDL_MouseButtonEvent &b = input_event->button; SDL_MouseButtonEvent &b = input_event->button;
event.xmouse = (int16_t)b.x; event.xmouse = (int16_t)roundf(DPIScale * b.x);
event.ymouse = (int16_t)b.y; event.ymouse = (int16_t)roundf(DPIScale * b.y);
event.clicks = b.clicks; event.clicks = b.clicks;
if (b.button == SDL_BUTTON_LEFT) { if (b.button == SDL_BUTTON_LEFT) {
event.kind = EVENT_MOUSE_LEFT; event.kind = EVENT_MOUSE_LEFT;
@@ -326,8 +411,8 @@ Event TranslateSDLEvent(SDL_Event *input_event) {
case SDL_EVENT_MOUSE_BUTTON_UP: { case SDL_EVENT_MOUSE_BUTTON_UP: {
SDL_MouseButtonEvent &b = input_event->button; SDL_MouseButtonEvent &b = input_event->button;
event.xmouse = (int16_t)b.x; event.xmouse = (int16_t)roundf(DPIScale * b.x);
event.ymouse = (int16_t)b.y; event.ymouse = (int16_t)roundf(DPIScale * b.y);
if (b.button == SDL_BUTTON_LEFT) { if (b.button == SDL_BUTTON_LEFT) {
event.kind = EVENT_MOUSE_LEFT_UP; event.kind = EVENT_MOUSE_LEFT_UP;
} else if (b.button == SDL_BUTTON_RIGHT) { } else if (b.button == SDL_BUTTON_RIGHT) {
@@ -346,8 +431,8 @@ Event TranslateSDLEvent(SDL_Event *input_event) {
case SDL_EVENT_MOUSE_WHEEL: { case SDL_EVENT_MOUSE_WHEEL: {
event.kind = EVENT_MOUSE_WHEEL; event.kind = EVENT_MOUSE_WHEEL;
SDL_MouseWheelEvent &b = input_event->wheel; SDL_MouseWheelEvent &b = input_event->wheel;
event.xmouse = (int16_t)b.mouse_x; event.xmouse = (int16_t)roundf(DPIScale * b.x);
event.ymouse = (int16_t)b.mouse_y; event.ymouse = (int16_t)roundf(DPIScale * b.y);
event.xwheel = b.x; event.xwheel = b.x;
event.ywheel = b.y; event.ywheel = b.y;
} break; } break;
@@ -468,14 +553,6 @@ void Serialize(Serializer *s, Event *e) {
SerializeEnd(s); 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 Ctrl() event.ctrl
#define Alt() event.alt #define Alt() event.alt
#define Shift() event.shift #define Shift() event.shift

View File

@@ -31,7 +31,6 @@ ViewID SearchViewID;
BufferID SearchBufferID; BufferID SearchBufferID;
WindowID ActiveWindowID; WindowID ActiveWindowID;
WindowID NextActiveWindowID;
WindowID LastActiveLayoutWindowID; WindowID LastActiveLayoutWindowID;
WindowID ScrollbarSelected = {-1}; WindowID ScrollbarSelected = {-1};
WindowID DocumentSelected = {-1}; WindowID DocumentSelected = {-1};
@@ -50,11 +49,9 @@ View *TraceView;
String WorkDir; String WorkDir;
RandomSeed UniqueBufferNameSeed = {}; RandomSeed UniqueBufferNameSeed = {};
Array<Event> EventPlayback; Array<Event> EventPlayback;
// lua
lua_State *LuaState = NULL; lua_State *LuaState = NULL;
String16 LuaCommandResult = {}; BlockArena Perm;
extern luaL_Reg LuaFunctions[]; Event *OnCommandEvent;
// clipboard // clipboard
BlockArena ClipboardArena; BlockArena ClipboardArena;
@@ -185,3 +182,48 @@ void ReloadStyle() {
StyleVCVarsall = GetStyleString("VCVarsall", StyleVCVarsall); StyleVCVarsall = GetStyleString("VCVarsall", StyleVCVarsall);
StyleUndoMergeTimeout = GetStyleFloat("UndoMergeTimeout", StyleUndoMergeTimeout); StyleUndoMergeTimeout = GetStyleFloat("UndoMergeTimeout", StyleUndoMergeTimeout);
} }
typedef void Function();
typedef void PFunction(void *param);
typedef int LuaFunction(lua_State *state);
struct FunctionData { String name; Function *function; };
struct LuaFunctionData { String name; LuaFunction *function; };
struct CommandData { String name; String binding; Function *function; struct Trigger *trigger; };
struct PFunctionData { String name; PFunction *function; };
bool SkipRemainingCommands;
Array<CommandData> CommandFunctions;
Array<LuaFunctionData> LuaFunctions;
Array<FunctionData> TestFunctions;
Array<PFunctionData> PostCommandHooks;
Array<PFunctionData> OnTextInputHooks;
Array<PFunctionData> OnDropFileHooks;
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)
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 RL_##NAME(NAME, #NAME)
struct Register_Command { Register_Command(Function *function, String name, String binding) { if (StartsWith(name, "Command_")) name = Skip(name, 8); Add(&CommandFunctions, {name, binding, function}); } };
#define RegisterCommand(name, binding) Register_Command RC__##name(name, #name, binding)
struct Register_Hook { Register_Hook(Array<PFunctionData> *functions, PFunction *function, String name) { if (StartsWith(name, "Hook_")) name = Skip(name, 5); Add(functions, {name, function}); } };
#define RegisterHook(functions, name) Register_Hook RC__##name(functions, (PFunction *)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;

View File

@@ -86,61 +86,6 @@ API String GetFieldString(lua_State *L, String name) {
return result; 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(); void ReloadStyle();
extern String BaseLuaConfig; extern String BaseLuaConfig;
@@ -206,9 +151,9 @@ API void InitLuaConfig() {
luaL_openlibs(LuaState); luaL_openlibs(LuaState);
lua_sethook(LuaState, HookLuaForceExit, LUA_MASKCOUNT, 100000000); lua_sethook(LuaState, HookLuaForceExit, LUA_MASKCOUNT, 100000000);
for (int i = 0; LuaFunctions[i].name; i += 1) { For(LuaFunctions) {
lua_pushcfunction(LuaState, LuaFunctions[i].func); lua_pushcfunction(LuaState, it.function);
lua_setglobal(LuaState, LuaFunctions[i].name); lua_setglobal(LuaState, it.name.data);
} }
#if OS_WINDOWS #if OS_WINDOWS
@@ -253,3 +198,97 @@ API void InitLuaConfig() {
ReloadLuaConfigs(true); ReloadLuaConfigs(true);
CallLuaOnInit(); 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);
}

View File

@@ -3,7 +3,6 @@ API Int GetStyleInt(String name, Int default_int);
API String GetStyleString(String name, String default_string); API String GetStyleString(String name, String default_string);
API Color GetColor(String name, Color default_color); API Color GetColor(String name, Color default_color);
API String GetFieldString(lua_State *L, String name); API String GetFieldString(lua_State *L, String name);
API int Lua_Play(lua_State *L);
API void LoadLuaBuffer(Buffer *lua_buffer); API void LoadLuaBuffer(Buffer *lua_buffer);
API void ReloadLuaConfigs(bool reload = false); API void ReloadLuaConfigs(bool reload = false);
API bool CallLuaFunc(char *func_name, int arg_count, int ret_count); API bool CallLuaFunc(char *func_name, int arg_count, int ret_count);

View File

@@ -9,7 +9,7 @@ int Lua_print(lua_State *L) {
Appendf(null_view, "\n"); Appendf(null_view, "\n");
lua_pop(L, nargs); lua_pop(L, nargs);
return 0; return 0;
} } RegisterLua(Lua_print);
int Lua_Print(lua_State *L) { int Lua_Print(lua_State *L) {
Scratch scratch; Scratch scratch;
@@ -21,7 +21,7 @@ int Lua_Print(lua_State *L) {
Appendf(TraceView, "\n"); Appendf(TraceView, "\n");
lua_pop(L, nargs); lua_pop(L, nargs);
return 0; return 0;
} } RegisterLua(Lua_Print);
int Lua_GetLoadWord(lua_State *L) { int Lua_GetLoadWord(lua_State *L) {
BSet active = GetBSet(ActiveWindowID); BSet active = GetBSet(ActiveWindowID);
@@ -34,7 +34,7 @@ int Lua_GetLoadWord(lua_State *L) {
String string = AllocCharString(scratch, active.buffer, range); String string = AllocCharString(scratch, active.buffer, range);
lua_pushlstring(L, string.data, string.len); lua_pushlstring(L, string.data, string.len);
return 1; return 1;
} } RegisterLua(Lua_GetLoadWord);
int Lua_BufferExists(lua_State *L) { int Lua_BufferExists(lua_State *L) {
String string = lua_tostring(L, 1); String string = lua_tostring(L, 1);
@@ -42,7 +42,7 @@ int Lua_BufferExists(lua_State *L) {
Buffer *buffer = GetBuffer(string); Buffer *buffer = GetBuffer(string);
lua_pushboolean(L, buffer != NULL); lua_pushboolean(L, buffer != NULL);
return 1; return 1;
} } RegisterLua(Lua_BufferExists);
int Lua_GetSelection(lua_State *L) { int Lua_GetSelection(lua_State *L) {
Scratch scratch; Scratch scratch;
@@ -51,7 +51,7 @@ int Lua_GetSelection(lua_State *L) {
String string = ToString(scratch, string16); String string = ToString(scratch, string16);
lua_pushlstring(L, string.data, string.len); lua_pushlstring(L, string.data, string.len);
return 1; return 1;
} } RegisterLua(Lua_GetSelection);
int Lua_GetEntireBuffer(lua_State *L) { int Lua_GetEntireBuffer(lua_State *L) {
Scratch scratch; Scratch scratch;
@@ -60,20 +60,20 @@ int Lua_GetEntireBuffer(lua_State *L) {
String string = ToString(scratch, string16); String string = ToString(scratch, string16);
lua_pushlstring(L, string.data, string.len); lua_pushlstring(L, string.data, string.len);
return 1; return 1;
} } RegisterLua(Lua_GetEntireBuffer);
int Lua_GetClipboard(lua_State *L) { int Lua_GetClipboard(lua_State *L) {
Scratch scratch; Scratch scratch;
String string = ToString(scratch, SavedClipboardString); String string = ToString(scratch, SavedClipboardString);
lua_pushlstring(L, string.data, string.len); lua_pushlstring(L, string.data, string.len);
return 1; return 1;
} } RegisterLua(Lua_GetClipboard);
int Lua_GetFilename(lua_State *L) { int Lua_GetFilename(lua_State *L) {
BSet main = GetBSet(LastActiveLayoutWindowID); BSet main = GetBSet(LastActiveLayoutWindowID);
lua_pushlstring(L, main.buffer->name.data, main.buffer->name.len); lua_pushlstring(L, main.buffer->name.data, main.buffer->name.len);
return 1; return 1;
} } RegisterLua(Lua_GetFilename);
int Lua_GetLine(lua_State *L) { int Lua_GetLine(lua_State *L) {
BSet main = GetBSet(LastActiveLayoutWindowID); BSet main = GetBSet(LastActiveLayoutWindowID);
@@ -82,7 +82,7 @@ int Lua_GetLine(lua_State *L) {
Int line = PosToLine(main.buffer, front); Int line = PosToLine(main.buffer, front);
lua_pushinteger(L, line + 1); lua_pushinteger(L, line + 1);
return 1; return 1;
} } RegisterLua(Lua_GetLine);
int Lua_FileExists(lua_State *L) { int Lua_FileExists(lua_State *L) {
String path = luaL_checkstring(L, 1); String path = luaL_checkstring(L, 1);
@@ -90,103 +90,213 @@ int Lua_FileExists(lua_State *L) {
bool exists = FileExists(path); bool exists = FileExists(path);
lua_pushboolean(L, exists); lua_pushboolean(L, exists);
return 1; return 1;
} } RegisterLua(Lua_FileExists);
int Lua_GetWorkDir(lua_State *L) { int Lua_GetWorkDir(lua_State *L) {
lua_pushlstring(L, WorkDir.data, WorkDir.len); lua_pushlstring(L, WorkDir.data, WorkDir.len);
return 1; return 1;
} } RegisterLua(Lua_GetWorkDir);
int Lua_GetExeDir(lua_State *L) { int Lua_GetExeDir(lua_State *L) {
Scratch scratch; Scratch scratch;
String exe_dir = GetExeDir(scratch); String exe_dir = GetExeDir(scratch);
lua_pushlstring(L, exe_dir.data, exe_dir.len); lua_pushlstring(L, exe_dir.data, exe_dir.len);
return 1; return 1;
} } RegisterLua(Lua_GetExeDir);
int Lua_GetMainDir(lua_State *L) { int Lua_GetMainDir(lua_State *L) {
String name = GetMainDir(); String name = GetMainDir();
lua_pushlstring(L, name.data, name.len); lua_pushlstring(L, name.data, name.len);
return 1; return 1;
} RegisterLua(Lua_GetMainDir);
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_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_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_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();
} }
struct OnOpenResult { lua_getfield(L, -1, "cmd");
String kind; if (!lua_isstring(L, -1)) luaL_error(L, "expected a string for cmd param");
String file_path; String cmd = lua_tostring(L, -1);
Int line, col; lua_pop(L, 1);
String working_dir;
String cmd;
};
OnOpenResult CallOnOpen(Allocator allocator, String path, String meta) { lua_getfield(L, -1, "kind");
lua_getglobal(LuaState, "OnOpen"); String kind = lua_tostring(L, -1);
lua_pushlstring(LuaState, path.data, path.len); lua_pop(L, 1);
lua_pushlstring(LuaState, meta.data, meta.len);
if (!CallLuaFunc("OnOpen", 2, 1)) {
return {};
}
String file_path = GetFieldString(LuaState, "file_path"); BSet main = GetBSet(LastActiveLayoutWindowID);
String line_string = GetFieldString(LuaState, "line"); if (kind == "console") {
String col_string = GetFieldString(LuaState, "col"); BSet set = GetConsoleSet();
String cmd = GetFieldString(LuaState, "cmd"); main.window->active_goto_list = set.view->id;
String working_dir = GetFieldString(LuaState, "working_dir"); main.window->goto_list_pos = set.buffer->len;
String kind = GetFieldString(LuaState, "kind"); SelectRange(set.view, MakeRange(set.buffer->len));
BeginJump(&set);
OnOpenResult result = {}; Exec(set.view->id, true, cmd, working_dir);
result.cmd = cmd; EndJump(set);
result.working_dir = working_dir; } else if (kind == "fuzzy") {
result.file_path = file_path; JumpGarbageBuffer(&main);
if (!IsAbsolute(result.file_path)) { Exec(main.view->id, true, cmd, working_dir);
String dir = GetMainDir(); main.view->fuzzy_search = true;
result.file_path = Format(allocator, "%S/%S", dir, result.file_path); ActiveWindowID = main.window->id;
}
if (col_string.len) {
result.col = strtoll(col_string.data, NULL, 10);
} else { } 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); return 0;
} else { } RegisterLua(Lua_Cmd);
result.line = -1;
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;
} }
result.kind = kind;
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; return result;
} }
bool CallIsCode(String path, String meta = "") { // :Event
lua_getglobal(LuaState, "IsCode"); int Lua_Play(lua_State *L) {
lua_pushlstring(LuaState, path.data, path.len); if (!lua_istable(L, -1)) luaL_error(L, "expected a table of events");
lua_pushlstring(LuaState, meta.data, meta.len); defer { lua_pop(L, 1); };
if (!CallLuaFunc("IsCode", 2, 1)) {
return false; 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); return 0;
lua_pop(LuaState, 1); } RegisterLua(Lua_Play);
return result;
}
void CallOnSave(BufferID buffer_id) {
lua_getglobal(LuaState, "OnSave");
lua_pushinteger(LuaState, buffer_id.id);
CallLuaFunc("OnSave", 1, 0);
}
bool CallOnCommand(Event *event) { int Lua_TrimTrailingWhitespace(lua_State *L) {
lua_getglobal(LuaState, "OnCommand"); lua_Integer buffer_id = luaL_checkinteger(L, 1);
PushEvent(LuaState, event); int trim_lines_with_caret = lua_toboolean(L, 2);
CallLuaFunc("OnCommand", 1, 1); lua_pop(L, 2);
bool result = lua_toboolean(LuaState, -1); Buffer *buffer = GetBuffer({buffer_id});
lua_pop(LuaState, 1); TrimTrailingWhitespace(buffer, trim_lines_with_caret);
return result; return 0;
} } RegisterLua(Lua_TrimTrailingWhitespace);
void CallLuaOnUpdate(Event *event) {
lua_getglobal(LuaState, "OnUpdate");
PushEvent(LuaState, event);
CallLuaFunc("OnUpdate", 1, 0);
}

View File

@@ -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},
};

View File

@@ -38,9 +38,6 @@ String GetMainDir() {
void GarbageCollect() { void GarbageCollect() {
Allocator sys_allocator = GetSystemAllocator(); Allocator sys_allocator = GetSystemAllocator();
ActiveWindowID = NextActiveWindowID;
For (Windows) { For (Windows) {
if (it->sync_visibility_with_focus) { if (it->sync_visibility_with_focus) {
if (it->id == ActiveWindowID) { if (it->id == ActiveWindowID) {
@@ -51,8 +48,8 @@ void GarbageCollect() {
} }
} }
if (ActiveWindowID.id != LastActiveLayoutWindowID.id) {
Window *window = GetWindow(ActiveWindowID); Window *window = GetWindow(ActiveWindowID);
if (ActiveWindowID.id != LastActiveLayoutWindowID.id) {
if (window->layout) { if (window->layout) {
LastActiveLayoutWindowID = ActiveWindowID; LastActiveLayoutWindowID = ActiveWindowID;
} }

245
src/text_editor/parser.cpp Normal file
View File

@@ -0,0 +1,245 @@
struct Lexer {
Allocator allocator;
char *at;
char *start;
char *end;
char *name;
int line, column;
};
enum TriggerKind {
TriggerKind_Error,
TriggerKind_Key,
TriggerKind_Mouse,
TriggerKind_Binary,
};
struct Trigger {
TriggerKind kind;
Trigger *left;
Trigger *right;
SDL_Keycode key;
struct {
EventKind event_kind : 8;
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};
Advance(lex);
bool found = false;
for (int i = 0; !found && i < Lengthof(MouseConversionTable); i += 1) {
if (a == MouseConversionTable[i].string) {
result->event_kind = MouseConversionTable[i].value;
result->kind = TriggerKind_Mouse;
found = true;
}
}
for (int i = 0; !found && i < Lengthof(SDLKeycodeConversionTable); i += 1) {
if (a == SDLKeycodeConversionTable[i].string) {
result->key = SDLKeycodeConversionTable[i].value;
found = true;
}
}
if (!found) {
result->kind = TriggerKind_Error;
ReportErrorf("%s:%d:%d: Failed to parse key trigger, unexpected identifier: '%d'", lex->name, lex->line, lex->column, result->key);
return result;
}
} 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 *ParseKeyExpr(Lexer *lex) {
Trigger *left = ParseKeyChord(lex);
EatWhitespace(lex);
while (At(lex) == '|') {
Advance(lex);
left = TriggerBinary(lex, left, ParseKeyExpr(lex), '|');
EatWhitespace(lex);
}
return left;
}
Trigger *ParseKey(Allocator allocator, String key, char *debug_name) {
Lexer lex = {allocator, key.data, key.data, key.data + key.len, debug_name};
Trigger *result = ParseKeyExpr(&lex);
return result;
}
bool MatchEvent(Trigger *trigger, Event *event) {
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_Mouse) {
if (trigger->event_kind == event->kind) {
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 = ParseKeyExpr(&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 = ParseKeyExpr(&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 = ParseKeyExpr(&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);

View File

@@ -7,6 +7,9 @@
#include "external/glad/glad.h" #include "external/glad/glad.h"
#include "external/stb_truetype.h" #include "external/stb_truetype.h"
#include "external/stb_truetype.c" #include "external/stb_truetype.c"
#if OS_LINUX
#define MCO_USE_UCONTEXT
#endif
#define MINICORO_IMPL #define MINICORO_IMPL
#include "external/minicoro.h" #include "external/minicoro.h"
#define LUA_USE_LONGJMP #define LUA_USE_LONGJMP
@@ -30,14 +33,14 @@
#include "management.cpp" #include "management.cpp"
#include "process.cpp" #include "process.cpp"
#include "event.cpp" #include "event.cpp"
#include "parser.cpp"
#include "lua_api.cpp"
#include "commands.cpp" #include "commands.cpp"
#include "lua_api.cpp"
#include "commands_clipboard.cpp" #include "commands_clipboard.cpp"
#include "commands_bindings.cpp" #include "commands_bindings.cpp"
#include "title_bar.cpp" #include "title_bar.cpp"
#include "lua_api_generated.cpp"
#include "generated_config.cpp" #include "generated_config.cpp"
#include "draw.cpp" #include "draw.cpp"
@@ -117,9 +120,6 @@ void SetMouseCursor(Event event) {
return; return;
} }
} }
SetMouseCursor(SDL_SYSTEM_CURSOR_DEFAULT); SetMouseCursor(SDL_SYSTEM_CURSOR_DEFAULT);
} }
@@ -135,7 +135,9 @@ void Update(Event event) {
view->update_scroll = true; view->update_scroll = true;
} }
OnCommandEvent = &event;
OnCommand(event); OnCommand(event);
OnCommandEvent = NULL;
UpdateProcesses(); UpdateProcesses();
CoUpdate(&event); CoUpdate(&event);
ReloadLuaConfigs(); ReloadLuaConfigs();
@@ -198,7 +200,7 @@ void MainLoop() {
if (it.xwindow == 0 || it.ywindow == 0) { if (it.xwindow == 0 || it.ywindow == 0) {
int xwindow, ywindow; int xwindow, ywindow;
SDL_GetWindowSize(SDLWindow, &xwindow, &ywindow); SDL_GetWindowSizeInPixels(SDLWindow, &xwindow, &ywindow);
it.xwindow = xwindow; it.xwindow = xwindow;
it.ywindow = ywindow; it.ywindow = ywindow;
} }
@@ -236,7 +238,6 @@ void MainLoop() {
SDL_GL_SwapWindow(SDLWindow); SDL_GL_SwapWindow(SDLWindow);
} }
#if _WIN32 #if _WIN32
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
#else #else
@@ -253,18 +254,21 @@ int main(int argc, char **argv)
if (1) { if (1) {
RunArenaTest(); RunArenaTest();
RunBufferTest(); For (TestFunctions) {
it.function();
}
// ReportErrorf("Testing DONE\n"); // ReportErrorf("Testing DONE\n");
// return 0; // return 0;
} }
#if !OS_WINDOWS #if !OS_WINDOWS
for (int i = 0; environ[i]; i += 1) { for (int i = 0; environ[i]; i += 1) {
Add(&Enviroment, Copy(GetSystemAllocator(), environ[i])); Add(&Enviroment, Copy(Perm, environ[i]));
} }
#endif #endif
WorkDir = GetWorkingDir(SysAllocator); WorkDir = GetWorkingDir(Perm);
{ {
String sdl_config_path = SDL_GetPrefPath("krzosa", "text_editor"); String sdl_config_path = SDL_GetPrefPath("krzosa", "text_editor");
if (sdl_config_path.len && sdl_config_path.data[sdl_config_path.len - 1] == '\\') { if (sdl_config_path.len && sdl_config_path.data[sdl_config_path.len - 1] == '\\') {
@@ -273,7 +277,7 @@ int main(int argc, char **argv)
if (sdl_config_path.len && sdl_config_path.data[sdl_config_path.len - 1] == '/') { if (sdl_config_path.len && sdl_config_path.data[sdl_config_path.len - 1] == '/') {
sdl_config_path = Chop(sdl_config_path, 1); // chop '/' sdl_config_path = Chop(sdl_config_path, 1); // chop '/'
} }
ConfigDir = NormalizePath(SysAllocator, sdl_config_path); ConfigDir = NormalizePath(Perm, sdl_config_path);
SDL_free(sdl_config_path.data); SDL_free(sdl_config_path.data);
} }
@@ -350,6 +354,11 @@ int main(int argc, char **argv)
InitWindows(); InitWindows();
InitOS(ReportWarningf); InitOS(ReportWarningf);
For (CommandFunctions) {
if (it.binding.len != 0) {
it.trigger = ParseKey(Perm, it.binding, it.name.data);
}
}
for (int i = 1; i < argc; i += 1) { for (int i = 1; i < argc; i += 1) {
String it = argv[i]; String it = argv[i];

View File

@@ -14,7 +14,7 @@ void UpdateDebugBuffer() {
float xmouse, ymouse; float xmouse, ymouse;
SDL_GetMouseState(&xmouse, &ymouse); SDL_GetMouseState(&xmouse, &ymouse);
RawAppendf(buffer, "mouse: [%f, %f]\n", xmouse, ymouse); RawAppendf(buffer, "mouse: [%f, %f]\n", roundf(DPIScale * xmouse), roundf(DPIScale * ymouse));
RawAppendf(buffer, "BufferID id = %d\n", main.buffer->id.id); RawAppendf(buffer, "BufferID id = %d\n", main.buffer->id.id);
RawAppendf(buffer, "String name = %S\n", main.buffer->name); RawAppendf(buffer, "String name = %S\n", main.buffer->name);

View File

@@ -250,8 +250,8 @@ void LayoutWindows(int16_t wx, int16_t wy) {
Rect2 screen_rect = Rect0Size(wx, wy); Rect2 screen_rect = Rect0Size(wx, wy);
Vec2 size = GetSize(screen_rect); Vec2 size = GetSize(screen_rect);
Rect2 a = CutLeft(&screen_rect, 0.3f * size.x); Rect2 a = CutRight(&screen_rect, 0.3f * size.x);
Rect2 b = CutBottom(&a, 0.4f * size.y); Rect2 b = CutTop(&a, 0.4f * size.y);
Rect2 c = Shrink(b, 20); Rect2 c = Shrink(b, 20);
n->document_rect = n->total_rect = ToRect2I(c); n->document_rect = n->total_rect = ToRect2I(c);
} }
@@ -280,3 +280,40 @@ void LayoutWindows(int16_t wx, int16_t wy) {
i += 1; 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;
}

View File

@@ -34,6 +34,7 @@ struct Window {
bool sync_visibility_with_focus : 1; bool sync_visibility_with_focus : 1;
bool lose_focus_on_escape : 1; bool lose_focus_on_escape : 1;
bool jump_history : 1; bool jump_history : 1;
bool eval_command : 1;
}; };
}; };