Compare commits
10 Commits
05f0197d50
...
a351d2eb41
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a351d2eb41 | ||
|
|
0424ca62f2 | ||
|
|
83d5ddff9d | ||
|
|
b600361278 | ||
|
|
9d29a1c187 | ||
|
|
20207e6040 | ||
|
|
ef6a7be285 | ||
|
|
df84d1605d | ||
|
|
88a5adaa0a | ||
|
|
e6e1ae0223 |
@@ -68,6 +68,7 @@ Style.Font = GetExeDir().."/CascadiaMono.ttf"
|
||||
Style.VCVarsall = "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat"
|
||||
Style.TrimWhitespaceOnSave = true
|
||||
Style.ClangFormatOnSave = false
|
||||
Style.StyleUndoMergeTimeout = 0.3
|
||||
|
||||
INTERNET_BROWSER = 'C:/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe'
|
||||
OS_WINDOWS = 0
|
||||
@@ -323,10 +324,6 @@ function MatchGotoBuild(s, meta)
|
||||
end
|
||||
|
||||
function MatchExec(s, meta)
|
||||
if meta ~= "exec" then
|
||||
return nil
|
||||
end
|
||||
|
||||
if s:match(".exe$") or s:match(".bat$") or s:match(".sh$") then
|
||||
return {kind = "exec_console", cmd = s, working_dir = GetMainDir()}
|
||||
end
|
||||
@@ -335,8 +332,7 @@ function MatchExec(s, meta)
|
||||
return {kind = "exec_console", cmd = s:sub(2, -1), working_dir = GetMainDir()}
|
||||
end
|
||||
|
||||
Eval(s)
|
||||
return {kind = "skip"}
|
||||
return nil
|
||||
end
|
||||
|
||||
BuiltinOnOpenMatchers = {
|
||||
|
||||
@@ -13,7 +13,6 @@ Needs to change:
|
||||
- How to design Command view?
|
||||
- How to design popup view (input field)?
|
||||
- How to design search view? or search and replace view?
|
||||
- Window management, splitting, GC
|
||||
|
||||
Things I like:
|
||||
- Basic editing
|
||||
@@ -24,15 +23,24 @@ Splits:
|
||||
- Buffer16 Buffer8?
|
||||
- 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
|
||||
- SpawnProcess wrong memory allocation there
|
||||
- Trying to fix the testing, Command_Open doesn't work on first frame because window is not metricly OK?
|
||||
- window->document_rect is null
|
||||
|
||||
|
||||
|
||||
- move titlebar, search to splits?
|
||||
|
||||
|
||||
Linux
|
||||
- Add backtrace
|
||||
|
||||
|
||||
|
||||
Commands TODO:
|
||||
- Search
|
||||
- Ctrl + F
|
||||
- Next occurence: Enter
|
||||
- Prev occurence: Shift + Enter
|
||||
- next occurence: F3
|
||||
- prev occurence: Shift + F3
|
||||
- Console: OK concept but constrain
|
||||
- Turned off by default
|
||||
- Special: non editable, hotkeys don't work etc.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -759,7 +759,6 @@ API Process SpawnProcess(String command_line, String working_dir, String write_s
|
||||
String16 cmd = ToString16(scratch, command_line);
|
||||
|
||||
char *env = NULL;
|
||||
// TODO: FIX ARENA ALLOCATION USING PushSize, Prealloc maybe? Maybe we want a block arena
|
||||
if (enviroment.len) {
|
||||
Int size = GetSize(enviroment) + enviroment.len + 1;
|
||||
env = (char *)PushSize(scratch, size);
|
||||
@@ -1098,3 +1097,7 @@ API void CloseStdin(Process *process) {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
API double GetTimeSeconds() {
|
||||
return GetTimeMicros() / 1000000.0;
|
||||
}
|
||||
@@ -388,7 +388,7 @@ GLuint UploadAtlas(Atlas *atlas) {
|
||||
return tex;
|
||||
}
|
||||
|
||||
void ReloadFont() {
|
||||
void ReloadFont(String path, U32 size) {
|
||||
if (PrimaryFont.texture_id) {
|
||||
glDeleteTextures(1, &PrimaryFont.texture_id);
|
||||
Dealloc(&PrimaryFont.glyphs);
|
||||
@@ -397,7 +397,7 @@ void ReloadFont() {
|
||||
|
||||
Scratch scratch;
|
||||
Atlas atlas = CreateAtlas(scratch, {2048, 2048});
|
||||
PrimaryFont = CreateFont(&atlas, (uint32_t)ClampBottom(2u, (U32)StyleFontSize), StyleFont);
|
||||
SecondaryFont = CreateFont(&atlas, 10, StyleFont);
|
||||
PrimaryFont = CreateFont(&atlas, (uint32_t)ClampBottom(2u, (U32)size), path);
|
||||
SecondaryFont = CreateFont(&atlas, 12, path);
|
||||
SecondaryFont.texture_id = PrimaryFont.texture_id = UploadAtlas(&atlas);
|
||||
}
|
||||
|
||||
@@ -140,8 +140,8 @@ void PlayTestOpen(mco_coro *co) {
|
||||
}
|
||||
|
||||
void Test(mco_coro *co) {
|
||||
Wait(co); // First phase starts immediately but stuff is not initialized so Command_Open acts weird
|
||||
Command_Open(TestDir);
|
||||
Wait(co); // First phase starts immediately but stuff is not initialized so Open acts weird
|
||||
Open(TestDir);
|
||||
PlayTestOpen(co);
|
||||
Release(&TestArena);
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#define BUFFER_DEBUG 0
|
||||
|
||||
|
||||
API Range MakeRange(Int a, Int b) {
|
||||
Range result = {Min(a, b), Max(a, b)};
|
||||
return result;
|
||||
@@ -917,16 +916,17 @@ API void AddEdit(Array<Edit> *e, Range range, String16 string) {
|
||||
void SaveHistoryBeforeMergeCursor(Buffer *buffer, Array<HistoryEntry> *stack, Array<Caret> &carets) {
|
||||
if (buffer->no_history) return;
|
||||
HistoryEntry entry = {};
|
||||
entry.carets = TightCopy(GetSystemAllocator(), carets);
|
||||
entry.time = GetTimeSeconds();
|
||||
entry.carets = TightCopy(GetSystemAllocator(), carets);
|
||||
Add(stack, entry);
|
||||
}
|
||||
|
||||
void SaveHistoryBeforeApplyEdits(Buffer *buffer, Array<HistoryEntry> *stack, Array<Edit> &edits) {
|
||||
ProfileFunction();
|
||||
if (buffer->no_history) return;
|
||||
HistoryEntry *entry = GetLast(*stack);
|
||||
Allocator sys_allocator = GetSystemAllocator();
|
||||
entry->edits = TightCopy(sys_allocator, edits);
|
||||
HistoryEntry *entry = GetLast(*stack);
|
||||
Allocator sys_allocator = GetSystemAllocator();
|
||||
entry->edits = TightCopy(sys_allocator, edits);
|
||||
|
||||
// Make reverse edits
|
||||
For(entry->edits) {
|
||||
@@ -992,8 +992,16 @@ API void UndoEdit(Buffer *buffer, Array<Caret> *carets) {
|
||||
Allocator sys_allocator = GetSystemAllocator();
|
||||
For(entry.edits) Dealloc(sys_allocator, it.string.data);
|
||||
Dealloc(&entry.edits);
|
||||
|
||||
if (buffer->undo_stack.len > 0) {
|
||||
HistoryEntry *next = GetLast(buffer->undo_stack);
|
||||
if (entry.time - next->time <= StyleUndoMergeTimeout) {
|
||||
UndoEdit(buffer, carets);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
API void DeallocHistoryEntries(Array<HistoryEntry> *entries) {
|
||||
For(*entries) {
|
||||
Dealloc(&it.carets);
|
||||
@@ -1003,6 +1011,21 @@ API void DeallocHistoryEntries(Array<HistoryEntry> *entries) {
|
||||
entries->len = 0;
|
||||
}
|
||||
|
||||
API void ResetHistory(Buffer *buffer) {
|
||||
DeallocHistoryEntries(&buffer->redo_stack);
|
||||
DeallocHistoryEntries(&buffer->undo_stack);
|
||||
}
|
||||
|
||||
API void ResetBuffer(Buffer *buffer) {
|
||||
ResetHistory(buffer);
|
||||
buffer->change_id += 1;
|
||||
buffer->line_starts.len = 0;
|
||||
buffer->len = 0;
|
||||
if (!buffer->no_line_starts) {
|
||||
Add(&buffer->line_starts, (Int)0);
|
||||
}
|
||||
}
|
||||
|
||||
void ClearRedoStack(Buffer *buffer) {
|
||||
DeallocHistoryEntries(&buffer->redo_stack);
|
||||
}
|
||||
@@ -1170,8 +1193,6 @@ API void InitBuffer(Allocator allocator, Buffer *buffer, BufferID id = {}, Strin
|
||||
}
|
||||
|
||||
API void DeinitBuffer(Buffer *buffer) {
|
||||
Assert(buffer->next == NULL);
|
||||
Assert(buffer->prev == NULL);
|
||||
Allocator allocator = buffer->line_starts.allocator;
|
||||
Dealloc(allocator, buffer->data);
|
||||
Dealloc(&buffer->line_starts);
|
||||
@@ -1181,7 +1202,6 @@ API void DeinitBuffer(Buffer *buffer) {
|
||||
|
||||
// Indexing starts from 0 not 1 because this routine creates also the zero buffer
|
||||
// which is the buffer that often is defaulted to in case of errors
|
||||
Int BufferIDs;
|
||||
API Buffer *AllocBuffer(Allocator allocator, String name = "", Int size = 4096) {
|
||||
Buffer *buffer = AllocType(allocator, Buffer);
|
||||
buffer->id = {BufferIDs++, buffer};
|
||||
@@ -1380,6 +1400,167 @@ void RunBufferTest() {
|
||||
DeinitBuffer(&buffer);
|
||||
TrackingAllocatorCheck();
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// Management
|
||||
inline BufferID AllocBufferID(Buffer *buffer) {
|
||||
return {BufferIDs++, buffer};
|
||||
}
|
||||
|
||||
}
|
||||
inline Buffer *GetBuffer(BufferID id) {
|
||||
For(Buffers) {
|
||||
if (it->id == id) return it;
|
||||
}
|
||||
return Buffers[0];
|
||||
}
|
||||
|
||||
inline Buffer *FindBuffer(BufferID id) {
|
||||
For(Buffers) {
|
||||
if (it->id == id) return it;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline Buffer *GetBuffer(String name) {
|
||||
For(Buffers) {
|
||||
if (it->name == name) return it;
|
||||
}
|
||||
return Buffers[0];
|
||||
}
|
||||
|
||||
inline Buffer *FindBuffer(String name) {
|
||||
For(Buffers) {
|
||||
if (it->name == name) return it;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline bool IsNull(Buffer *buffer) {
|
||||
return buffer->id.id == 0;
|
||||
}
|
||||
|
||||
Buffer *CreateBuffer(Allocator allocator, String name, Int size) {
|
||||
Buffer *result = AllocBuffer(allocator, name, size);
|
||||
Add(&Buffers, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
String GetUniqueBufferName(String working_dir, String prepend_name, String extension = ".log") {
|
||||
Scratch scratch;
|
||||
String buffer_name = {};
|
||||
for (int i = 1; i < INT_MAX; i += 1) {
|
||||
buffer_name = Format(scratch, "%S/%S%d%S", working_dir, prepend_name, i, extension);
|
||||
buffer_name = GetAbsolutePath(scratch, buffer_name);
|
||||
Buffer *exists = FindBuffer(buffer_name);
|
||||
if (!exists && !FileExists(buffer_name)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
buffer_name = Intern(&GlobalInternTable, buffer_name);
|
||||
return buffer_name;
|
||||
}
|
||||
|
||||
void InitBuffers() {
|
||||
Allocator sys_allocator = GetSystemAllocator();
|
||||
Scratch scratch;
|
||||
Buffer *null_buffer = CreateBuffer(sys_allocator, GetUniqueBufferName(GetWorkingDir(scratch), "console"));
|
||||
View *null_view = CreateView(null_buffer->id);
|
||||
Assert(null_buffer->id == NullBufferID && null_view->id == NullViewID);
|
||||
|
||||
TraceBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "trace"));
|
||||
TraceView = CreateView(TraceBuffer->id);
|
||||
GCInfoBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "gc"));
|
||||
EventBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "events"));
|
||||
ScratchBuffer = BufferOpenFile(GetUniqueBufferName(WorkDir, "scratch"));
|
||||
|
||||
EventBuffer->no_history = true;
|
||||
GCInfoBuffer->no_history = true;
|
||||
}
|
||||
|
||||
Int ConvertUTF8ToUTF16UnixLine(String string, char16_t *buffer, Int buffer_cap) {
|
||||
if (string.len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Int buffer_len = 0;
|
||||
Assert(buffer_cap > string.len * 2);
|
||||
for (Int i = 0; i < string.len;) {
|
||||
if (string.data[i] == '\r') {
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if (string.data[i] == '\t') {
|
||||
// @WARNING: DONT INCREASE THE SIZE CARELESSLY, WE NEED TO ADJUST BUFFER SIZE
|
||||
for (Int i = 0; i < 4; i += 1) buffer[buffer_len++] = u' ';
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t u32 = '?';
|
||||
UTF32Result decode = UTF8ToUTF32((uint8_t *)(string.data + i), (int64_t)(string.len - i));
|
||||
if (!decode.error) {
|
||||
i += decode.advance;
|
||||
u32 = decode.out_str;
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
UTF16Result encode = UTF32ToUTF16(u32);
|
||||
if (!encode.error) {
|
||||
for (int64_t encode_i = 0; encode_i < encode.len; encode_i += 1) {
|
||||
buffer[buffer_len++] = encode.out_str[encode_i];
|
||||
Assert(buffer_len < buffer_cap);
|
||||
}
|
||||
} else {
|
||||
buffer[buffer_len++] = u'?';
|
||||
}
|
||||
}
|
||||
return buffer_len;
|
||||
}
|
||||
|
||||
String16 ToUnixString16(Allocator allocator, String string_) {
|
||||
Int cap = string_.len * 3;
|
||||
char16_t *string16_buffer = AllocArray(allocator, char16_t, cap);
|
||||
Int len = ConvertUTF8ToUTF16UnixLine(string_, string16_buffer, cap);
|
||||
String16 string = {string16_buffer, len};
|
||||
return string;
|
||||
}
|
||||
|
||||
Buffer *BufferOpenFile(String path) {
|
||||
Allocator sys_allocator = GetSystemAllocator();
|
||||
Scratch scratch;
|
||||
|
||||
path = GetAbsolutePath(scratch, path);
|
||||
Buffer *buffer = GetBuffer(path);
|
||||
if (!IsNull(buffer) || (IsNull(buffer) && buffer->name == path)) {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
if (!FileExists(path)) {
|
||||
buffer = CreateBuffer(sys_allocator, path);
|
||||
} else if (IsDir(path)) {
|
||||
ReportWarningf("failed to open, it's a directory: %S", path);
|
||||
return GetBuffer(NullBufferID);
|
||||
} else {
|
||||
String string = ReadFile(scratch, path);
|
||||
buffer = CreateBuffer(sys_allocator, path, string.len * 4 + 4096);
|
||||
buffer->len = ConvertUTF8ToUTF16UnixLine(string, buffer->str, buffer->cap);
|
||||
buffer->file_mod_time = GetFileModTime(path);
|
||||
UpdateLines(buffer, {}, String16{(char16_t *)buffer->data, buffer->len});
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool BufferIsReferenced(BufferID buffer_id) {
|
||||
if (buffer_id == NullBufferID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (FindView(buffer_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -12,12 +12,11 @@ struct Edit {
|
||||
struct HistoryEntry {
|
||||
Array<Edit> edits;
|
||||
Array<Caret> carets;
|
||||
double time;
|
||||
};
|
||||
|
||||
struct Buffer {
|
||||
BufferID id;
|
||||
Buffer *next;
|
||||
Buffer *prev;
|
||||
String name;
|
||||
Int change_id;
|
||||
Int user_change_id;
|
||||
@@ -158,6 +157,8 @@ API void AssertRanges(Array<Caret> carets);
|
||||
|
||||
API void RedoEdit(Buffer *buffer, Array<Caret> *carets);
|
||||
API void UndoEdit(Buffer *buffer, Array<Caret> *carets);
|
||||
API void ResetHistory(Buffer *buffer);
|
||||
|
||||
API void DeallocHistoryArray(Array<HistoryEntry> *entries);
|
||||
API void DeallocHistoryEntries(Array<HistoryEntry> *entries);
|
||||
API void DeallocHistoryEntries(Array<HistoryEntry> *entries);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
void CheckpointBeforeGoto(Window *window, View *view) {
|
||||
Add(&window->goto_history, {view->id, view->carets[0]});
|
||||
if (window->jump_history == false) return;
|
||||
Add(&window->goto_history, {view->id, view->carets[0], GetTimeSeconds()});
|
||||
window->goto_redo.len = 0;
|
||||
}
|
||||
|
||||
@@ -17,27 +18,43 @@ GotoCrumb GetCrumb(Array<GotoCrumb> *cr) {
|
||||
}
|
||||
|
||||
void GotoBackward(Window *window) {
|
||||
BSet set = GetBSet(window);
|
||||
if (window->jump_history == false) return;
|
||||
if (window->goto_history.len <= 0) return;
|
||||
Add(&window->goto_redo, {set.view->id, set.view->carets[0]});
|
||||
BSet set = GetBSet(window);
|
||||
Add(&window->goto_redo, {set.view->id, set.view->carets[0], GetTimeSeconds()});
|
||||
|
||||
GotoCrumb c = GetCrumb(&window->goto_history);
|
||||
window->active_view = c.view_id;
|
||||
View *view = GetView(c.view_id);
|
||||
view->carets[0] = c.caret;
|
||||
UpdateScroll(window, true);
|
||||
|
||||
if (window->goto_history.len) {
|
||||
GotoCrumb *next = GetLast(window->goto_history);
|
||||
if (c.time - next->time <= StyleUndoMergeTimeout) {
|
||||
GotoBackward(window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GotoForward(Window *window) {
|
||||
BSet set = GetBSet(window);
|
||||
if (window->goto_redo.len <= 0) return;
|
||||
Add(&window->goto_history, {set.view->id, set.view->carets[0]});
|
||||
if (window->jump_history == false) return;
|
||||
BSet set = GetBSet(window);
|
||||
Add(&window->goto_history, {set.view->id, set.view->carets[0], GetTimeSeconds()});
|
||||
|
||||
GotoCrumb c = GetCrumb(&window->goto_redo);
|
||||
GotoCrumb c = GetCrumb(&window->goto_redo);
|
||||
window->active_view = c.view_id;
|
||||
View *view = GetView(c.view_id);
|
||||
view->carets[0] = c.caret;
|
||||
UpdateScroll(window, true);
|
||||
|
||||
if (window->goto_redo.len) {
|
||||
GotoCrumb *next = GetLast(window->goto_redo);
|
||||
if (c.time - next->time <= StyleUndoMergeTimeout) {
|
||||
GotoForward(window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JumpGarbageBuffer(BSet *set, String buffer_name = "") {
|
||||
@@ -51,13 +68,13 @@ void JumpGarbageBuffer(BSet *set, String buffer_name = "") {
|
||||
set->buffer->garbage = true;
|
||||
}
|
||||
|
||||
void Command_BeginJump(BSet *set, BufferID buffer_id = NullBufferID) {
|
||||
void BeginJump(BSet *set, BufferID buffer_id = NullBufferID) {
|
||||
CheckpointBeforeGoto(set->window);
|
||||
set->buffer = GetBuffer(buffer_id);
|
||||
set->view = WindowOpenBufferView(set->window, set->buffer->name);
|
||||
}
|
||||
|
||||
void Command_EndJump(BSet set) {
|
||||
void EndJump(BSet set) {
|
||||
Int pos = XYToPos(set.buffer, {0, set.buffer->line_starts.len - 1});
|
||||
set.view->carets[0] = MakeCaret(pos);
|
||||
UpdateScroll(set.window, true);
|
||||
@@ -83,7 +100,7 @@ Int ScreenSpaceToBufferPosErrorOutOfBounds(Window *window, View *view, Buffer *b
|
||||
|
||||
void MouseLoadWord(Event event, String meta = "") {
|
||||
Vec2I mouse = MouseVec2I();
|
||||
BSet active = GetActiveSet();
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
|
||||
bool mouse_in_document = AreOverlapping(mouse, active.window->document_rect);
|
||||
if (mouse_in_document) {
|
||||
@@ -95,7 +112,7 @@ void MouseLoadWord(Event event, String meta = "") {
|
||||
|
||||
active.view->carets.len = 1;
|
||||
active.view->carets[0] = MakeCaret(p);
|
||||
Command_Open(string, meta);
|
||||
Open(string, meta);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,16 +123,15 @@ View *GetViewForFixingWhenBufferCommand(Buffer *buffer, bool *is_active = NULL)
|
||||
*is_active = false;
|
||||
}
|
||||
|
||||
Window *active_window = GetWindow(ActiveWindow);
|
||||
View *active_view = GetView(active_window->active_view);
|
||||
if (active_view->active_buffer == buffer->id) {
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
if (active.buffer->id == buffer->id) {
|
||||
if (is_active) {
|
||||
*is_active = true;
|
||||
}
|
||||
return active_view;
|
||||
return active.view;
|
||||
}
|
||||
|
||||
for (View *it = FirstView; it; it = it->next) {
|
||||
For(Views) {
|
||||
if (it->active_buffer != buffer->id) {
|
||||
continue;
|
||||
}
|
||||
@@ -135,15 +151,15 @@ void ReplaceWithoutMovingCarets(Buffer *buffer, Range range, String16 string) {
|
||||
Array<Caret> carets = Copy(GetSystemAllocator(), view->carets);
|
||||
|
||||
Scratch scratch;
|
||||
Command_SelectRangeOneCursor(view, range);
|
||||
Command_ReplaceEx(scratch, view, string);
|
||||
SelectRange(view, range);
|
||||
ReplaceEx(scratch, view, string);
|
||||
|
||||
Dealloc(&view->carets);
|
||||
view->carets = carets;
|
||||
}
|
||||
|
||||
// @todo: revamp interface since it scrolls ALL VIEWS??? or maybe not??
|
||||
void Command_Append(View *view, String16 string, bool scroll_to_end_if_cursor_on_last_line) {
|
||||
void Append(View *view, String16 string, bool scroll_to_end_if_cursor_on_last_line) {
|
||||
Scratch scratch;
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
|
||||
@@ -154,7 +170,7 @@ void Command_Append(View *view, String16 string, bool scroll_to_end_if_cursor_on
|
||||
};
|
||||
|
||||
Array<ViewInfo> view_info = {scratch};
|
||||
for (View *it_view = FirstView; it_view; it_view = it_view->next) {
|
||||
ForItem(it_view, Views) {
|
||||
if (it_view->active_buffer != buffer->id) {
|
||||
continue;
|
||||
}
|
||||
@@ -174,8 +190,8 @@ void Command_Append(View *view, String16 string, bool scroll_to_end_if_cursor_on
|
||||
Add(&view_info, vi);
|
||||
}
|
||||
|
||||
Command_SelectRangeOneCursor(view, GetBufferEndAsRange(buffer));
|
||||
Command_Replace(view, string);
|
||||
SelectRange(view, GetBufferEndAsRange(buffer));
|
||||
Replace(view, string);
|
||||
|
||||
For (view_info) {
|
||||
if (it.scroll_to_end) {
|
||||
@@ -187,16 +203,16 @@ void Command_Append(View *view, String16 string, bool scroll_to_end_if_cursor_on
|
||||
}
|
||||
}
|
||||
|
||||
void Command_Append(View *view, String string, bool scroll_to_end_if_cursor_on_last_line) {
|
||||
void Append(View *view, String string, bool scroll_to_end_if_cursor_on_last_line) {
|
||||
Scratch scratch;
|
||||
String16 string16 = ToString16(scratch, string);
|
||||
Command_Append(view, string16, scroll_to_end_if_cursor_on_last_line);
|
||||
Append(view, string16, scroll_to_end_if_cursor_on_last_line);
|
||||
}
|
||||
|
||||
void Command_Appendf(View *view, const char *fmt, ...) {
|
||||
void Appendf(View *view, const char *fmt, ...) {
|
||||
Scratch scratch;
|
||||
STRING_FORMAT(scratch, fmt, string);
|
||||
Command_Append(view, string, true);
|
||||
Append(view, string, true);
|
||||
}
|
||||
|
||||
void ReportErrorf(const char *fmt, ...) {
|
||||
@@ -205,8 +221,8 @@ void ReportErrorf(const char *fmt, ...) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error!", string.data, NULL);
|
||||
View *view = GetView(NullViewID);
|
||||
if (view) {
|
||||
Command_Appendf(view, "%S\n", string);
|
||||
ActiveWindow = NullWindowID;
|
||||
Appendf(view, "%S\n", string);
|
||||
NextActiveWindowID = NullWindowID;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,23 +230,23 @@ void ReportConsolef(const char *fmt, ...) {
|
||||
Scratch scratch;
|
||||
STRING_FORMAT(scratch, fmt, string);
|
||||
View *view = GetView(NullViewID);
|
||||
Command_Appendf(view, "%S\n", string);
|
||||
Appendf(view, "%S\n", string);
|
||||
}
|
||||
|
||||
void ReportWarningf(const char *fmt, ...) {
|
||||
Scratch scratch;
|
||||
STRING_FORMAT(scratch, fmt, string);
|
||||
View *null_view = GetView(NullViewID);
|
||||
Command_Appendf(null_view, "%S\n", string);
|
||||
Appendf(null_view, "%S\n", string);
|
||||
}
|
||||
|
||||
void ReportDebugf(const char *fmt, ...) {
|
||||
Scratch scratch;
|
||||
STRING_FORMAT(scratch, fmt, string);
|
||||
Command_Appendf(TraceView, "%S\n", string);
|
||||
Appendf(TraceView, "%S\n", string);
|
||||
}
|
||||
|
||||
void Command_MoveCursorsByPageSize(Window *window, int direction, bool shift = false) {
|
||||
void MoveCursorByPageSize(Window *window, int direction, bool shift = false) {
|
||||
Assert(direction == DIR_UP || direction == DIR_DOWN);
|
||||
BSet set = GetBSet(window);
|
||||
|
||||
@@ -257,7 +273,7 @@ void Command_MoveCursorsByPageSize(Window *window, int direction, bool shift = f
|
||||
}
|
||||
}
|
||||
|
||||
void Command_MoveCursorsToSide(View *view, int direction, bool shift = false) {
|
||||
void MoveCursorToSide(View *view, int direction, bool shift = false) {
|
||||
Assert(direction == DIR_LEFT || direction == DIR_RIGHT);
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
|
||||
@@ -383,7 +399,7 @@ Caret MoveCaret(Buffer *buffer, Caret it, int direction, bool ctrl = false, bool
|
||||
return it;
|
||||
}
|
||||
|
||||
void Command_Move(View *view, int direction, bool ctrl = false, bool shift = false) {
|
||||
void MoveCarets(View *view, int direction, bool ctrl = false, bool shift = false) {
|
||||
Assert(direction < DIR_COUNT);
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
For(view->carets) {
|
||||
@@ -391,7 +407,7 @@ void Command_Move(View *view, int direction, bool ctrl = false, bool shift = fal
|
||||
}
|
||||
}
|
||||
|
||||
void Command_MoveLine(View *view, int direction) {
|
||||
void MoveCaretsLine(View *view, int direction) {
|
||||
Assert(direction == DIR_DOWN || direction == DIR_UP);
|
||||
Scratch scratch;
|
||||
|
||||
@@ -450,7 +466,7 @@ void Command_MoveLine(View *view, int direction) {
|
||||
}
|
||||
}
|
||||
|
||||
Array<Edit> Command_ReplaceEx(Allocator scratch, View *view, String16 string) {
|
||||
Array<Edit> ReplaceEx(Allocator scratch, View *view, String16 string) {
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
|
||||
MergeCarets(buffer, &view->carets);
|
||||
@@ -459,12 +475,12 @@ Array<Edit> Command_ReplaceEx(Allocator scratch, View *view, String16 string) {
|
||||
return edits;
|
||||
}
|
||||
|
||||
void Command_Replace(View *view, String16 string) {
|
||||
void Replace(View *view, String16 string) {
|
||||
Scratch scratch;
|
||||
Command_ReplaceEx(scratch, view, string);
|
||||
ReplaceEx(scratch, view, string);
|
||||
}
|
||||
|
||||
void Command_DuplicateLine(View *view, int direction) {
|
||||
void DuplicateLine(View *view, int direction) {
|
||||
Assert(direction == DIR_UP || direction == DIR_DOWN);
|
||||
Scratch scratch;
|
||||
|
||||
@@ -530,7 +546,7 @@ Array<Range> GetSelectedLinesSorted(Allocator allocator, View *view) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void Command_IndentSelectedLines(View *view, bool shift = false) {
|
||||
void IndentSelectedLines(View *view, bool shift = false) {
|
||||
Scratch scratch;
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
|
||||
@@ -685,28 +701,31 @@ void SaveBuffer(Buffer *buffer) {
|
||||
ReportWarningf("Failed to save file with name: %S", buffer->name);
|
||||
}
|
||||
}
|
||||
|
||||
void Command_Save() {
|
||||
BSet set = GetActiveMainSet();
|
||||
SaveBuffer(set.buffer);
|
||||
BSet active = GetBSet(LastActiveLayoutWindowID);
|
||||
SaveBuffer(active.buffer);
|
||||
}
|
||||
|
||||
int Lua_Save(lua_State *L) {
|
||||
Command_Save();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Command_SaveAll() {
|
||||
for (Buffer *it = FirstBuffer; it; it = it->next) {
|
||||
For(Buffers) {
|
||||
if (it->file_mod_time) {
|
||||
SaveBuffer(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Lua_SaveAll(lua_State *L) {
|
||||
Command_SaveAll();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Command_KillSelectedLines(View *view) {
|
||||
void KillSelectedLines(View *view) {
|
||||
Scratch scratch;
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
SaveCaretHistoryBeforeBeginEdit(buffer, view->carets);
|
||||
@@ -717,7 +736,7 @@ void Command_KillSelectedLines(View *view) {
|
||||
it.range.min = GetFullLineStart(buffer, it.range.min);
|
||||
it.range.min -= Clamp(eof, (Int)0, buffer->len);
|
||||
}
|
||||
Command_Replace(view, u"");
|
||||
Replace(view, u"");
|
||||
}
|
||||
|
||||
void EncloseLine(View *view) {
|
||||
@@ -746,7 +765,7 @@ void EncloseSpace(View *view) {
|
||||
}
|
||||
}
|
||||
|
||||
void Command_Delete(View *view, int direction, bool ctrl = false) {
|
||||
void Delete(View *view, int direction, bool ctrl = false) {
|
||||
Assert(direction == DIR_LEFT || direction == DIR_RIGHT);
|
||||
Scratch scratch;
|
||||
|
||||
@@ -782,7 +801,7 @@ void Command_Delete(View *view, int direction, bool ctrl = false) {
|
||||
EndEdit(buffer, &edits, &view->carets, true);
|
||||
}
|
||||
|
||||
void Command_SelectAll(View *view, String16 needle) {
|
||||
void SelectAll(View *view, String16 needle) {
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
String16 string_buffer = GetString(buffer);
|
||||
|
||||
@@ -799,7 +818,7 @@ void Command_SelectAll(View *view, String16 needle) {
|
||||
MergeCarets(buffer, &view->carets);
|
||||
}
|
||||
|
||||
void Command_CreateCursorVertical(View *view, int direction) {
|
||||
void CreateCursorVertical(View *view, int direction) {
|
||||
Assert(direction == DIR_UP || direction == DIR_DOWN);
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
|
||||
@@ -823,18 +842,18 @@ void Command_CreateCursorVertical(View *view, int direction) {
|
||||
MergeCarets(buffer, &view->carets);
|
||||
}
|
||||
|
||||
void Command_SelectRangeOneCursor(View *view, Caret caret) {
|
||||
void SelectRange(View *view, Caret caret) {
|
||||
view->carets.len = 1;
|
||||
view->carets[0] = caret;
|
||||
}
|
||||
|
||||
void Command_SelectRangeOneCursor(View *view, Range range) {
|
||||
Command_SelectRangeOneCursor(view, MakeCaret(range.min, range.max));
|
||||
void SelectRange(View *view, Range range) {
|
||||
SelectRange(view, MakeCaret(range.min, range.max));
|
||||
}
|
||||
|
||||
void Command_SelectEntireBuffer(View *view) {
|
||||
void SelectEntireBuffer(View *view) {
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
Command_SelectRangeOneCursor(view, GetRange(buffer));
|
||||
SelectRange(view, GetRange(buffer));
|
||||
}
|
||||
|
||||
Caret FindPrev(Buffer *buffer, String16 needle, Caret caret) {
|
||||
@@ -873,7 +892,7 @@ Caret FindNext(Buffer *buffer, String16 needle, Caret caret) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void Command_IdentedNewLine(View *view) {
|
||||
void IdentedNewLine(View *view) {
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
Scratch scratch;
|
||||
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
|
||||
@@ -889,17 +908,17 @@ void Command_IdentedNewLine(View *view) {
|
||||
EndEdit(buffer, &edits, &view->carets, KILL_SELECTION);
|
||||
}
|
||||
|
||||
void Command_Find(View *seek_view, String16 needle, bool forward = true) {
|
||||
void Find(View *seek_view, String16 needle, bool forward = true) {
|
||||
Buffer *seek_buffer = GetBuffer(seek_view->active_buffer);
|
||||
Caret caret = seek_view->carets[0];
|
||||
if (forward) caret = FindNext(seek_buffer, needle, caret);
|
||||
if (!forward) caret = FindPrev(seek_buffer, needle, caret);
|
||||
Command_SelectRangeOneCursor(seek_view, caret);
|
||||
SelectRange(seek_view, caret);
|
||||
|
||||
IF_DEBUG(AssertRanges(seek_view->carets));
|
||||
}
|
||||
|
||||
void Command_GotoNextInList(Window *window, Int line_offset = 1) {
|
||||
void GotoNextInList(Window *window, Int line_offset = 1) {
|
||||
Assert(line_offset == 1 || line_offset == -1);
|
||||
View *active_view = GetView(window->active_view);
|
||||
|
||||
@@ -924,7 +943,7 @@ void Command_GotoNextInList(Window *window, Int line_offset = 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BSet set = Command_Open(line, "goto_build");
|
||||
BSet set = Open(line, "goto_build");
|
||||
if (set.window == NULL) {
|
||||
continue;
|
||||
}
|
||||
@@ -936,7 +955,7 @@ void Command_GotoNextInList(Window *window, Int line_offset = 1) {
|
||||
if (!opened) window->active_view = active_view->id;
|
||||
}
|
||||
|
||||
void Command_FuzzySort(View *view, String16 needle) {
|
||||
void FuzzySortView(View *view, String16 needle) {
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
|
||||
Scratch scratch;
|
||||
@@ -950,9 +969,9 @@ void Command_FuzzySort(View *view, String16 needle) {
|
||||
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), u"\n");
|
||||
}
|
||||
|
||||
Command_SelectEntireBuffer(view);
|
||||
Command_Replace(view, GetString(temp_buffer));
|
||||
Command_SelectRangeOneCursor(view, MakeRange(0));
|
||||
SelectEntireBuffer(view);
|
||||
Replace(view, GetString(temp_buffer));
|
||||
SelectRange(view, MakeRange(0));
|
||||
}
|
||||
|
||||
void ReopenBuffer(Buffer *buffer) {
|
||||
@@ -970,9 +989,9 @@ void ReopenBuffer(Buffer *buffer) {
|
||||
}
|
||||
|
||||
void Command_Reopen() {
|
||||
BSet set = GetActiveMainSet();
|
||||
ReopenBuffer(set.buffer);
|
||||
ActiveWindow = set.window->id;
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
ReopenBuffer(main.buffer);
|
||||
NextActiveWindowID = main.window->id;
|
||||
}
|
||||
|
||||
int Lua_Reopen(lua_State *L) {
|
||||
@@ -998,7 +1017,7 @@ void New(Window *window, String name = "") {
|
||||
}
|
||||
|
||||
void Command_New(String name = "") {
|
||||
BSet main = GetActiveMainSet();
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
New(main.window, name);
|
||||
}
|
||||
|
||||
@@ -1025,13 +1044,13 @@ void NewDir(Window *window, String name = "") {
|
||||
}
|
||||
|
||||
MakeDir(name);
|
||||
Command_Open(name);
|
||||
Open(name);
|
||||
}
|
||||
|
||||
int Lua_NewDir(lua_State *L) {
|
||||
String name = lua_tostring(L, 1);
|
||||
lua_pop(L, 1);
|
||||
BSet main = GetActiveMainSet();
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
NewDir(main.window, name);
|
||||
return 0;
|
||||
}
|
||||
@@ -1076,64 +1095,61 @@ void ListFilesRecursive(Buffer *buffer, String dir) {
|
||||
}
|
||||
}
|
||||
|
||||
void Command_ListCode(String dir = WorkDir) {
|
||||
BSet main = GetActiveMainSet();
|
||||
void Command_ListCode() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
JumpGarbageBuffer(&main);
|
||||
ListFilesRecursive(main.buffer, dir);
|
||||
ListFilesRecursive(main.buffer, WorkDir);
|
||||
main.view->fuzzy_search = true;
|
||||
main.view->update_scroll = true;
|
||||
Command_SelectRangeOneCursor(main.view, GetBufferEndAsRange(main.buffer));
|
||||
SelectRange(main.view, GetBufferEndAsRange(main.buffer));
|
||||
}
|
||||
|
||||
int Lua_ListCode(lua_State *L) {
|
||||
String string = lua_tostring(L, 1);
|
||||
lua_pop(L, 1);
|
||||
if (string.len == 0) {
|
||||
string = WorkDir;
|
||||
}
|
||||
Command_ListCode(string);
|
||||
Command_ListCode();
|
||||
return 0;
|
||||
}
|
||||
|
||||
View *Command_ExecHidden(String buffer_name, String cmd, String working_dir) {
|
||||
View *ExecHidden(String buffer_name, String cmd, String working_dir) {
|
||||
View *view = OpenBufferView(buffer_name);
|
||||
Exec(view->id, true, cmd, working_dir);
|
||||
return view;
|
||||
}
|
||||
|
||||
BSet Command_Exec(String cmd, String working_dir, bool set_active = true) {
|
||||
BSet set = GetActiveMainSet();
|
||||
if (set_active) ActiveWindow = set.window->id;
|
||||
JumpGarbageBuffer(&set);
|
||||
Exec(set.view->id, true, cmd, working_dir);
|
||||
return set;
|
||||
BSet Exec(String cmd, String working_dir, bool set_active = true) {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
if (set_active) {
|
||||
NextActiveWindowID = main.window->id;
|
||||
}
|
||||
JumpGarbageBuffer(&main);
|
||||
Exec(main.view->id, true, cmd, working_dir);
|
||||
return main;
|
||||
}
|
||||
|
||||
int Lua_C(lua_State *L) {
|
||||
String string = lua_tostring(L, 1);
|
||||
lua_pop(L, 1);
|
||||
Command_Exec(string, Command_GetMainDir());
|
||||
Exec(string, GetMainDir());
|
||||
return 0;
|
||||
}
|
||||
|
||||
BSet Command_Open(Window *window, String path, String meta, bool set_active = true) {
|
||||
BSet Open(Window *window, String path, String meta, bool set_active = true) {
|
||||
Scratch scratch;
|
||||
BSet set = GetBSet(window);
|
||||
path = Trim(path);
|
||||
OnOpenResult ores = CallOnOpen(scratch, path, meta);
|
||||
if (ores.kind == "text") {
|
||||
if (set_active) {
|
||||
ActiveWindow = set.window->id;
|
||||
NextActiveWindowID = set.window->id;
|
||||
}
|
||||
if (IsDir(ores.file_path)) {
|
||||
JumpGarbageBuffer(&set, GetUniqueBufferName(ores.file_path, "temp", ".dirlisting"));
|
||||
Command_Appendf(set.view, "..\n");
|
||||
Appendf(set.view, "..\n");
|
||||
for (FileIter it = IterateFiles(scratch, ores.file_path); IsValid(it); Advance(&it)) {
|
||||
Command_Appendf(set.view, "%S\n", it.filename);
|
||||
Appendf(set.view, "%S\n", it.filename);
|
||||
}
|
||||
} else {
|
||||
CheckpointBeforeGoto(set.window);
|
||||
View *view = WindowOpenBufferView(set.window, ores.file_path);
|
||||
View *view = WindowOpenBufferView(set.window, ores.file_path);
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
if (ores.line != -1) {
|
||||
if (ores.col == -1) ores.col = 1;
|
||||
@@ -1144,7 +1160,7 @@ BSet Command_Open(Window *window, String path, String meta, bool set_active = tr
|
||||
UpdateScroll(set.window, true);
|
||||
} else if (ores.kind == "exec") {
|
||||
if (set_active) {
|
||||
ActiveWindow = set.window->id;
|
||||
NextActiveWindowID = set.window->id;
|
||||
}
|
||||
JumpGarbageBuffer(&set);
|
||||
Exec(set.view->id, true, ores.cmd, ores.working_dir);
|
||||
@@ -1161,23 +1177,23 @@ BSet Command_Open(Window *window, String path, String meta, bool set_active = tr
|
||||
return set;
|
||||
}
|
||||
|
||||
BSet Command_Open(String path, String meta) {
|
||||
BSet main = GetActiveMainSet();
|
||||
main = Command_Open(main.window, path, meta);
|
||||
BSet Open(String path, String meta) {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
main = Open(main.window, path, meta);
|
||||
return main;
|
||||
}
|
||||
|
||||
BSet Command_Open(String16 path, String meta) {
|
||||
BSet Open(String16 path, String meta) {
|
||||
Scratch scratch;
|
||||
String string = ToString(scratch, path);
|
||||
return Command_Open(string, meta);
|
||||
return Open(string, meta);
|
||||
}
|
||||
|
||||
int Lua_Open(lua_State *L) {
|
||||
Scratch scratch;
|
||||
String path = luaL_checkstring(L, 1);
|
||||
lua_pop(L, 1);
|
||||
Command_Open(path);
|
||||
Open(path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1189,7 +1205,7 @@ int Lua_Cmd(lua_State *L) {
|
||||
String working_dir = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
if (working_dir == "") {
|
||||
working_dir = Command_GetMainDir();
|
||||
working_dir = GetMainDir();
|
||||
}
|
||||
|
||||
lua_getfield(L, -1, "cmd");
|
||||
@@ -1201,56 +1217,68 @@ int Lua_Cmd(lua_State *L) {
|
||||
String kind = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
BSet main = GetActiveMainSet();
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
if (kind == "console") {
|
||||
BSet set = GetConsoleSet();
|
||||
main.window->active_goto_list = set.view->id;
|
||||
main.window->goto_list_pos = set.buffer->len;
|
||||
Command_SelectRangeOneCursor(set.view, MakeRange(set.buffer->len));
|
||||
Command_BeginJump(&set);
|
||||
SelectRange(set.view, MakeRange(set.buffer->len));
|
||||
BeginJump(&set);
|
||||
Exec(set.view->id, true, cmd, working_dir);
|
||||
Command_EndJump(set);
|
||||
EndJump(set);
|
||||
} else if (kind == "fuzzy") {
|
||||
JumpGarbageBuffer(&main);
|
||||
Exec(main.view->id, true, cmd, working_dir);
|
||||
main.view->fuzzy_search = true;
|
||||
ActiveWindow = main.window->id;
|
||||
NextActiveWindowID = main.window->id;
|
||||
} else {
|
||||
JumpGarbageBuffer(&main);
|
||||
main.window->active_goto_list = main.view->id;
|
||||
main.window->goto_list_pos = 0;
|
||||
Exec(main.view->id, true, cmd, working_dir);
|
||||
ActiveWindow = main.window->id;
|
||||
NextActiveWindowID = main.window->id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Command_ListBuffers() {
|
||||
BSet main = GetActiveMainSet();
|
||||
ActiveWindow = main.window->id;
|
||||
JumpGarbageBuffer(&main);
|
||||
for (Buffer *it = FirstBuffer; it; it = it->next) {
|
||||
RawAppendf(main.buffer, "%-80S || %S\n", SkipToLastSlash(it->name), it->name);
|
||||
void Command_ShowBufferList() {
|
||||
BSet command_bar = GetBSet(CommandBarWindowID);
|
||||
command_bar.window->visible = true;
|
||||
NextActiveWindowID = command_bar.window->id;
|
||||
ResetBuffer(command_bar.buffer);
|
||||
For(Buffers) {
|
||||
RawAppendf(command_bar.buffer, "%-80S || %S\n", SkipToLastSlash(it->name), it->name);
|
||||
}
|
||||
main.view->fuzzy_search = true;
|
||||
main.view->update_scroll = true;
|
||||
Command_SelectRangeOneCursor(main.view, GetBufferEndAsRange(main.buffer));
|
||||
command_bar.view->update_scroll = true;
|
||||
SelectRange(command_bar.view, GetBufferEndAsRange(command_bar.buffer));
|
||||
}
|
||||
|
||||
int Lua_ListBuffers(lua_State *L) {
|
||||
Command_ListBuffers();
|
||||
return 0;
|
||||
void Command_ShowCommandList() {
|
||||
BSet command_bar = GetBSet(CommandBarWindowID);
|
||||
command_bar.window->visible = true;
|
||||
NextActiveWindowID = command_bar.window->id;
|
||||
ResetBuffer(command_bar.buffer);
|
||||
for (int i = 0; LuaFunctions[i].name != NULL; i += 1) {
|
||||
Appendf(command_bar.view, "%s()\n ", LuaFunctions[i].name);
|
||||
}
|
||||
|
||||
command_bar.view->update_scroll = true;
|
||||
SelectRange(command_bar.view, GetBufferEndAsRange(command_bar.buffer));
|
||||
}
|
||||
|
||||
void Command_ListViews() {
|
||||
BSet main = GetActiveMainSet();
|
||||
ActiveWindow = main.window->id;
|
||||
JumpGarbageBuffer(&main);
|
||||
for (View *it = FirstView; it; it = it->next) {
|
||||
BSet command_bar = GetBSet(CommandBarWindowID);
|
||||
command_bar.window->visible = true;
|
||||
NextActiveWindowID = command_bar.window->id;
|
||||
ResetBuffer(command_bar.buffer);
|
||||
For(Views) {
|
||||
Buffer *buffer = GetBuffer(it->active_buffer);
|
||||
Command_Appendf(main.view, "%d %S\n", (int)it->id.id, buffer->name);
|
||||
Appendf(command_bar.view, "%d %S\n", (int)it->id.id, buffer->name);
|
||||
}
|
||||
command_bar.view->fuzzy_search = true;
|
||||
command_bar.view->update_scroll = true;
|
||||
SelectRange(command_bar.view, GetBufferEndAsRange(command_bar.buffer));
|
||||
}
|
||||
|
||||
int Lua_ListViews(lua_State *L) {
|
||||
@@ -1258,7 +1286,7 @@ int Lua_ListViews(lua_State *L) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Command_Eval(String string) {
|
||||
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);
|
||||
@@ -1266,15 +1294,15 @@ void Command_Eval(String string) {
|
||||
}
|
||||
}
|
||||
|
||||
void Command_Eval(String16 string) {
|
||||
void Eval(String16 string) {
|
||||
Scratch scratch;
|
||||
Command_Eval(ToString(scratch, string));
|
||||
Eval(ToString(scratch, string));
|
||||
}
|
||||
|
||||
int Lua_Eval(lua_State *L) {
|
||||
String string = lua_tostring(L, 1);
|
||||
lua_pop(L, 1);
|
||||
Command_Eval(string);
|
||||
Eval(string);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1285,42 +1313,55 @@ void SetProjectFile(Buffer *buffer) {
|
||||
LuaProjectBuffer->user_change_id = -1;
|
||||
}
|
||||
|
||||
void Command_SetProjectFile() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
SetProjectFile(main.buffer);
|
||||
}
|
||||
|
||||
void Command_SetWorkDir() {
|
||||
String dir = lua_tostring(LuaState, -1);
|
||||
if (dir.len == 0) {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
WorkDir = ChopLastSlash(main.buffer->name);
|
||||
} else {
|
||||
WorkDir = dir;
|
||||
}
|
||||
}
|
||||
|
||||
void Command_SetProject() {
|
||||
Command_SetWorkDir();
|
||||
Command_SetProjectFile();
|
||||
}
|
||||
|
||||
int Lua_SetProjectFile(lua_State *L) {
|
||||
BSet set = GetActiveMainSet();
|
||||
SetProjectFile(set.buffer);
|
||||
Command_SetProjectFile();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Lua_SetWorkDir(lua_State *L) {
|
||||
String dir = lua_tostring(L, -1);
|
||||
if (dir.len == 0) {
|
||||
BSet set = GetActiveMainSet();
|
||||
WorkDir = ChopLastSlash(set.buffer->name);
|
||||
} else {
|
||||
WorkDir = dir;
|
||||
}
|
||||
Command_SetWorkDir();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Lua_ListCommands(lua_State *L) {
|
||||
BSet main = GetActiveMainSet();
|
||||
Command_BeginJump(&main);
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
BeginJump(&main);
|
||||
for (int i = 0; LuaFunctions[i].name != NULL; i += 1) {
|
||||
Command_Appendf(main.view, "%20s() ", LuaFunctions[i].name);
|
||||
Appendf(main.view, "%20s() ", LuaFunctions[i].name);
|
||||
if (((i + 1) % 6) == 0) {
|
||||
Command_Appendf(main.view, "\n");
|
||||
Appendf(main.view, "\n");
|
||||
}
|
||||
}
|
||||
Command_EndJump(main);
|
||||
ActiveWindow = main.window->id;
|
||||
EndJump(main);
|
||||
NextActiveWindowID = main.window->id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Lua_GetBufferList(lua_State *L) {
|
||||
lua_createtable(L, 0, (int)BufferCount);
|
||||
lua_createtable(L, 0, (int)Buffers.len);
|
||||
|
||||
int i = 1;
|
||||
for (Buffer *it = FirstBuffer; it; it = it->next) {
|
||||
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 */
|
||||
@@ -1330,7 +1371,7 @@ int Lua_GetBufferList(lua_State *L) {
|
||||
}
|
||||
|
||||
Window *GetOverlappingWindow(Vec2I p, Window *default_window = NULL) {
|
||||
for (Window *it = FirstWindow; it; it = it->next) {
|
||||
For(Windows) {
|
||||
if (AreOverlapping(p, it->total_rect)) {
|
||||
return it;
|
||||
}
|
||||
@@ -1360,28 +1401,14 @@ Vec2I GetSideOfWindow(Window *window, int direction) {
|
||||
}
|
||||
|
||||
Window *SwitchWindow(int direction) {
|
||||
Window *window = GetWindow(ActiveWindow);
|
||||
Window *window = GetWindow(ActiveWindowID);
|
||||
Vec2I p = GetSideOfWindow(window, direction);
|
||||
Window *result = GetOverlappingWindow(p, window);
|
||||
return result;
|
||||
}
|
||||
|
||||
String16 GetSearchString(Window *window) {
|
||||
if (!window->is_search_bar) {
|
||||
if (window->search_bar_window.id == 0) {
|
||||
return {};
|
||||
}
|
||||
window = GetWindow(window->search_bar_window);
|
||||
}
|
||||
|
||||
View *view = GetView(window->active_view);
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
String16 string = GetString(buffer);
|
||||
return string;
|
||||
}
|
||||
|
||||
String16 FetchLoadWord(void) {
|
||||
BSet active = GetActiveSet();
|
||||
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));
|
||||
@@ -1389,23 +1416,27 @@ String16 FetchLoadWord(void) {
|
||||
return string;
|
||||
}
|
||||
|
||||
void SplitWindow(WindowSplitKind kind) {
|
||||
Window *window = CreateWind();
|
||||
View *view = OpenBufferView(ScratchBuffer->name);
|
||||
window->active_view = view->id;
|
||||
CreateTitlebar(window->id);
|
||||
CreateSearchBar(window->id);
|
||||
|
||||
Window *active_window = GetActiveWind();
|
||||
SplitWindowEx(NULL, &WindowSplits, active_window, window, kind);
|
||||
ActiveWindow = window->id;
|
||||
void Command_ToggleDebug() {
|
||||
Window *window = GetWindow(DebugWindowID);
|
||||
window->visible = !window->visible;
|
||||
}
|
||||
|
||||
int Lua_Split(lua_State *L) {
|
||||
lua_Integer kind = lua_tointeger(L, -1);
|
||||
lua_pop(L, 1);
|
||||
if (kind == 1 || kind == 2) {
|
||||
SplitWindow((WindowSplitKind)kind);
|
||||
}
|
||||
void Command_KillProcess() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
KillProcess(main.view);
|
||||
}
|
||||
|
||||
int Lua_KillProcess(lua_State *L) {
|
||||
Command_KillProcess();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Command_KillWindow() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
main.window->kill = true;
|
||||
}
|
||||
|
||||
int Lua_KillWindow(lua_State *L) {
|
||||
Command_KillWindow();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -46,21 +46,27 @@ void UpdateScroll(Window *window, bool update_caret_scrolling) {
|
||||
}
|
||||
}
|
||||
|
||||
void ResizerDetectMouse(Event event, WindowSplit *split) {
|
||||
if (split == NULL) {
|
||||
return;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
Vec2I mouse = MouseVec2I();
|
||||
bool mouse_in_rect = AreOverlapping(mouse, split->resizer_rect);
|
||||
if (mouse_in_rect) {
|
||||
ResizerHover = split;
|
||||
if (Mouse(LEFT)) {
|
||||
ResizerSelected = split;
|
||||
String16 string = GetLineStringWithoutNL(active.buffer, line);
|
||||
Int idx = 0;
|
||||
if (Seek(string, u"||", &idx)) {
|
||||
string = Skip(string, idx + 3);
|
||||
Open(string);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
ResizerDetectMouse(event, split->left);
|
||||
ResizerDetectMouse(event, split->right);
|
||||
|
||||
if (!success) {
|
||||
Open(FetchLoadWord());
|
||||
}
|
||||
}
|
||||
|
||||
void OnCommand(Event event) {
|
||||
@@ -111,7 +117,7 @@ void OnCommand(Event event) {
|
||||
view->scroll.y = (Int)(v * (double)s.line_count * (double)window->font->line_spacing);
|
||||
}
|
||||
|
||||
if (DocumentSelected != ActiveWindow) {
|
||||
if (DocumentSelected != ActiveWindowID) {
|
||||
DocumentSelected.id = -1;
|
||||
} else if (IsDocumentSelectionValid() && MouseUp()) {
|
||||
Assert(ScrollbarSelected.id == -1);
|
||||
@@ -120,6 +126,7 @@ void OnCommand(Event event) {
|
||||
Assert(ScrollbarSelected.id == -1);
|
||||
BSet selected = GetBSet(DocumentSelected);
|
||||
|
||||
|
||||
Vec2I mouse = MouseVec2I();
|
||||
// Special case for full-screen where we can have document
|
||||
// aligned with monitor screen in which case mouse cursor cannot
|
||||
@@ -134,26 +141,33 @@ void OnCommand(Event event) {
|
||||
|
||||
Int p = ScreenSpaceToBufferPos(selected.window, selected.view, selected.buffer, mouse);
|
||||
Caret &caret = selected.view->carets[0];
|
||||
|
||||
caret = SetFrontWithAnchor(caret, DocumentAnchor, p);
|
||||
}
|
||||
|
||||
if (ResizerSelected && Mouse(LEFT_UP)) {
|
||||
if (ResizerSelected.id != -1 && Mouse(LEFT_UP)) {
|
||||
Assert(DocumentSelected.id == -1);
|
||||
Assert(ScrollbarSelected.id == -1);
|
||||
ResizerSelected = NULL;
|
||||
} else if (ResizerSelected) {
|
||||
Vec2I mouse = MouseVec2I();
|
||||
mouse -= ResizerSelected->total_rect.min;
|
||||
Vec2I size = GetSize(ResizerSelected->total_rect);
|
||||
Vec2 p = ToVec2(mouse) / ToVec2(size);
|
||||
if (ResizerSelected->kind == WindowSplitKind_Vertical) {
|
||||
ResizerSelected->value = p.x;
|
||||
} else {
|
||||
ResizerSelected->value = p.y;
|
||||
ResizerSelected.id = {-1};
|
||||
} else if (ResizerSelected.id != -1) {
|
||||
Window *window = GetWindow(ResizerSelected);
|
||||
if (window->layout) {
|
||||
Vec2I mouse = MouseVec2I();
|
||||
Int offx = mouse.x - window->resizer_rect.min.x;
|
||||
window->weight += (double)offx / (double)WindowCalcEvenResizerValue(event.xwindow);
|
||||
window->weight = Clamp(window->weight, 0.1, 100.0);
|
||||
}
|
||||
} else {
|
||||
ResizerDetectMouse(event, &WindowSplits);
|
||||
ResizerHover = {-1};
|
||||
For(Windows) {
|
||||
Vec2I mouse = MouseVec2I();
|
||||
bool mouse_in_rect = AreOverlapping(mouse, it->resizer_rect);
|
||||
if (mouse_in_rect) {
|
||||
ResizerHover = it->id;
|
||||
if (Mouse(LEFT)) {
|
||||
ResizerSelected = it->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set active window on click
|
||||
@@ -165,17 +179,19 @@ void OnCommand(Event event) {
|
||||
}
|
||||
bool mouse_in_document = AreOverlapping(mouse, it->document_rect);
|
||||
if (mouse_in_document) {
|
||||
ActiveWindow = it->id;
|
||||
NextActiveWindowID = it->id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Mouse(X2)) {
|
||||
GotoForward(GetActiveMainSet().window);
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
GotoForward(main.window);
|
||||
}
|
||||
if (Mouse(X1)) {
|
||||
GotoBackward(GetActiveMainSet().window);
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
GotoBackward(main.window);
|
||||
}
|
||||
|
||||
if (Ctrl() && Shift() && Mouse(RIGHT)) {
|
||||
@@ -185,8 +201,8 @@ void OnCommand(Event event) {
|
||||
|
||||
} else if (Alt() && Mouse(RIGHT)) {
|
||||
} else if (Mouse(RIGHT)) {
|
||||
Vec2I mouse = MouseVec2I();
|
||||
BSet active = GetActiveSet();
|
||||
Vec2I mouse = MouseVec2I();
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
bool mouse_in_document = AreOverlapping(mouse, active.window->document_rect);
|
||||
if (mouse_in_document) {
|
||||
Int p = ScreenSpaceToBufferPos(active.window, active.view, active.buffer, mouse);
|
||||
@@ -213,9 +229,7 @@ void OnCommand(Event event) {
|
||||
}
|
||||
}
|
||||
|
||||
if (Shift() && Ctrl() && Mouse(LEFT)) {
|
||||
MouseLoadWord(event, "exec");
|
||||
} else if (Ctrl() && Mouse(LEFT)) {
|
||||
if (Ctrl() && Mouse(LEFT)) {
|
||||
MouseLoadWord(event);
|
||||
} else if (Mouse(LEFT)) { // Uses Alt and shift
|
||||
Vec2I mouse = MouseVec2I();
|
||||
@@ -223,12 +237,13 @@ void OnCommand(Event event) {
|
||||
Assert(ScrollbarSelected.id == -1);
|
||||
Assert(DocumentSelected.id == -1);
|
||||
|
||||
BSet active = GetActiveSet();
|
||||
BSet active = GetBSet(NextActiveWindowID); // using next to make sure mouse works on first click after switching the window
|
||||
bool mouse_in_document = AreOverlapping(mouse, active.window->document_rect);
|
||||
bool mouse_in_line_numbers = AreOverlapping(mouse, active.window->line_numbers_rect);
|
||||
if (mouse_in_document || mouse_in_line_numbers) {
|
||||
CheckpointBeforeGoto(active.window);
|
||||
DocumentSelected = active.window->id;
|
||||
CheckpointBeforeGoto(active.window);
|
||||
|
||||
|
||||
Int p = ScreenSpaceToBufferPos(active.window, active.view, active.buffer, mouse);
|
||||
if (Alt()) Insert(&active.view->carets, MakeCaret(p, p), 0);
|
||||
@@ -283,41 +298,28 @@ void OnCommand(Event event) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (CtrlAltPress(SDLK_P)) {
|
||||
Command_ListBuffers();
|
||||
} else if (CtrlPress(SDLK_P)) {
|
||||
Command_ListCode();
|
||||
if (CtrlPress(SDLK_W)) {
|
||||
Command_KillWindow();
|
||||
}
|
||||
|
||||
if (CtrlShiftPress(SDLK_BACKSLASH)) {
|
||||
SplitWindow(WindowSplitKind_Horizontal);
|
||||
} else if (CtrlPress(SDLK_BACKSLASH)) {
|
||||
SplitWindow(WindowSplitKind_Vertical);
|
||||
if (CtrlAltPress(SDLK_P)) {
|
||||
} else if (CtrlShiftPress(SDLK_P)) {
|
||||
Command_ShowCommandList();
|
||||
} else if (CtrlPress(SDLK_P)) {
|
||||
Command_ShowBufferList();
|
||||
}
|
||||
|
||||
if (CtrlPress(SDLK_0)) {
|
||||
ToggleVisibility(DebugWindowID);
|
||||
Command_ToggleDebug();
|
||||
}
|
||||
|
||||
if (CtrlPress(SDLK_GRAVE)) {
|
||||
if (ActiveWindow != NullWindowID) {
|
||||
ActiveWindow = NullWindowID;
|
||||
} else {
|
||||
if (WindowSplits.value + 0.01 < 0.9) {
|
||||
WindowSplits.value = (double)0.9;
|
||||
} else {
|
||||
WindowSplits.value = (double)0.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (CtrlPress(SDLK_1)) {
|
||||
ActiveWindow = GetOverlappingWindow({0,0}, GetWindow(ActiveWindow))->id;
|
||||
NextActiveWindowID = GetOverlappingWindow({0,0}, GetWindow(ActiveWindowID))->id;
|
||||
}
|
||||
if (CtrlPress(SDLK_2)) {
|
||||
Window *first = GetOverlappingWindow({0,0}, GetWindow(ActiveWindow));
|
||||
Window *first = GetOverlappingWindow({0,0}, GetWindow(ActiveWindowID));
|
||||
Vec2I p = GetSideOfWindow(first, DIR_RIGHT);
|
||||
ActiveWindow = GetOverlappingWindow(p, GetWindow(ActiveWindow))->id;
|
||||
NextActiveWindowID = GetOverlappingWindow(p, GetWindow(ActiveWindowID))->id;
|
||||
}
|
||||
if (CtrlPress(SDLK_3)) {
|
||||
Window *first = GetOverlappingWindow({0,0});
|
||||
@@ -326,14 +328,14 @@ void OnCommand(Event event) {
|
||||
if (second) {
|
||||
Window *third = GetOverlappingWindow(GetSideOfWindow(second, DIR_RIGHT));
|
||||
if (third) {
|
||||
ActiveWindow = third->id;
|
||||
NextActiveWindowID = third->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BSet main = GetActiveMainSet();
|
||||
BSet active = GetActiveSet();
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
Int buffer_change_id = active.buffer->change_id;
|
||||
|
||||
bool skip = CallOnCommand(&event);
|
||||
@@ -344,67 +346,75 @@ void OnCommand(Event event) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (active.view->fuzzy_search) {
|
||||
if (Press(SDLK_RETURN)) {
|
||||
FuzzySearchOpen(active);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (event.kind == EVENT_DROP_FILE) {
|
||||
WindowOpenBufferView(active.window, event.text);
|
||||
}
|
||||
|
||||
if (Press(SDLK_DOWN) || Press(SDLK_RIGHT) || Press(SDLK_LEFT) || Press(SDLK_UP)) {
|
||||
CheckpointBeforeGoto(active.window);
|
||||
}
|
||||
|
||||
if (CtrlAltPress(SDLK_DOWN)) {
|
||||
Command_DuplicateLine(active.view, DIR_DOWN);
|
||||
DuplicateLine(active.view, DIR_DOWN);
|
||||
} else if (AltShiftPress(SDLK_DOWN)) {
|
||||
Command_CreateCursorVertical(active.view, DIR_DOWN);
|
||||
CreateCursorVertical(active.view, DIR_DOWN);
|
||||
} else if (CtrlShiftPress(SDLK_DOWN)) {
|
||||
Command_Move(active.view, DIR_DOWN, CTRL_PRESSED, SHIFT_PRESS);
|
||||
MoveCarets(active.view, DIR_DOWN, CTRL_PRESSED, SHIFT_PRESS);
|
||||
} else if (AltPress(SDLK_DOWN)) {
|
||||
Command_MoveLine(active.view, DIR_DOWN);
|
||||
MoveCaretsLine(active.view, DIR_DOWN);
|
||||
} else if (CtrlPress(SDLK_DOWN)) {
|
||||
Command_Move(active.view, DIR_DOWN, CTRL_PRESSED);
|
||||
MoveCarets(active.view, DIR_DOWN, CTRL_PRESSED);
|
||||
} else if (ShiftPress(SDLK_DOWN)) {
|
||||
Command_Move(active.view, DIR_DOWN, false, SHIFT_PRESS);
|
||||
MoveCarets(active.view, DIR_DOWN, false, SHIFT_PRESS);
|
||||
} else if (Press(SDLK_DOWN)) {
|
||||
Command_Move(active.view, DIR_DOWN);
|
||||
MoveCarets(active.view, DIR_DOWN);
|
||||
}
|
||||
|
||||
if (CtrlAltPress(SDLK_UP)) {
|
||||
Command_DuplicateLine(active.view, DIR_UP);
|
||||
DuplicateLine(active.view, DIR_UP);
|
||||
} else if (AltShiftPress(SDLK_UP)) {
|
||||
Command_CreateCursorVertical(active.view, DIR_UP);
|
||||
CreateCursorVertical(active.view, DIR_UP);
|
||||
} else if (CtrlShiftPress(SDLK_UP)) {
|
||||
Command_Move(active.view, DIR_UP, CTRL_PRESSED, SHIFT_PRESS);
|
||||
MoveCarets(active.view, DIR_UP, CTRL_PRESSED, SHIFT_PRESS);
|
||||
} else if (AltPress(SDLK_UP)) {
|
||||
Command_MoveLine(active.view, DIR_UP);
|
||||
MoveCaretsLine(active.view, DIR_UP);
|
||||
} else if (CtrlPress(SDLK_UP)) {
|
||||
Command_Move(active.view, DIR_UP, CTRL_PRESSED);
|
||||
MoveCarets(active.view, DIR_UP, CTRL_PRESSED);
|
||||
} else if (ShiftPress(SDLK_UP)) {
|
||||
Command_Move(active.view, DIR_UP, false, SHIFT_PRESS);
|
||||
MoveCarets(active.view, DIR_UP, false, SHIFT_PRESS);
|
||||
} else if (Press(SDLK_UP)) {
|
||||
Command_Move(active.view, DIR_UP);
|
||||
MoveCarets(active.view, DIR_UP);
|
||||
}
|
||||
|
||||
if (CtrlShiftPress(SDLK_LEFT)) {
|
||||
Command_Move(active.view, DIR_LEFT, CTRL_PRESSED, SHIFT_PRESS);
|
||||
MoveCarets(active.view, DIR_LEFT, CTRL_PRESSED, SHIFT_PRESS);
|
||||
} else if (CtrlPress(SDLK_LEFT)) {
|
||||
Command_Move(active.view, DIR_LEFT, CTRL_PRESSED);
|
||||
MoveCarets(active.view, DIR_LEFT, CTRL_PRESSED);
|
||||
} else if (ShiftPress(SDLK_LEFT)) {
|
||||
Command_Move(active.view, DIR_LEFT, false, SHIFT_PRESS);
|
||||
MoveCarets(active.view, DIR_LEFT, false, SHIFT_PRESS);
|
||||
} else if (AltPress(SDLK_LEFT)) {
|
||||
ActiveWindow = SwitchWindow(DIR_LEFT)->id;
|
||||
NextActiveWindowID = SwitchWindow(DIR_LEFT)->id;
|
||||
} else if (Press(SDLK_LEFT)) {
|
||||
Command_Move(active.view, DIR_LEFT);
|
||||
MoveCarets(active.view, DIR_LEFT);
|
||||
}
|
||||
|
||||
if (CtrlShiftPress(SDLK_RIGHT)) {
|
||||
Command_Move(active.view, DIR_RIGHT, CTRL_PRESSED, SHIFT_PRESS);
|
||||
MoveCarets(active.view, DIR_RIGHT, CTRL_PRESSED, SHIFT_PRESS);
|
||||
} else if (CtrlPress(SDLK_RIGHT)) {
|
||||
Command_Move(active.view, DIR_RIGHT, CTRL_PRESSED);
|
||||
MoveCarets(active.view, DIR_RIGHT, CTRL_PRESSED);
|
||||
} else if (ShiftPress(SDLK_RIGHT)) {
|
||||
Command_Move(active.view, DIR_RIGHT, false, SHIFT_PRESS);
|
||||
MoveCarets(active.view, DIR_RIGHT, false, SHIFT_PRESS);
|
||||
} else if (AltPress(SDLK_RIGHT)) {
|
||||
ActiveWindow = SwitchWindow(DIR_RIGHT)->id;
|
||||
NextActiveWindowID = SwitchWindow(DIR_RIGHT)->id;
|
||||
} else if (Press(SDLK_RIGHT)) {
|
||||
Command_Move(active.view, DIR_RIGHT);
|
||||
MoveCarets(active.view, DIR_RIGHT);
|
||||
}
|
||||
|
||||
if (CtrlShiftPress(SDLK_Z)) {
|
||||
@@ -414,152 +424,128 @@ void OnCommand(Event event) {
|
||||
}
|
||||
|
||||
if (CtrlPress(SDLK_C)) {
|
||||
Command_Copy(active.view);
|
||||
ClipboardCopy(active.view);
|
||||
} else if (CtrlPress(SDLK_V)) {
|
||||
Command_Paste(active.view);
|
||||
ClipboardPaste(active.view);
|
||||
} else if (CtrlPress(SDLK_X)) {
|
||||
SaveCaretHistoryBeforeBeginEdit(active.buffer, active.view->carets);
|
||||
Command_Copy(active.view);
|
||||
Command_Replace(active.view, u"");
|
||||
ClipboardCopy(active.view);
|
||||
Replace(active.view, u"");
|
||||
}
|
||||
|
||||
if (CtrlPress(SDLK_A)) {
|
||||
Command_SelectEntireBuffer(active.view);
|
||||
SelectEntireBuffer(active.view);
|
||||
active.view->update_scroll = false;
|
||||
}
|
||||
|
||||
if (ShiftPress(SDLK_PAGEUP)) {
|
||||
Command_MoveCursorsByPageSize(active.window, DIR_UP, SHIFT_PRESS);
|
||||
CheckpointBeforeGoto(active.window);
|
||||
MoveCursorByPageSize(active.window, DIR_UP, SHIFT_PRESS);
|
||||
} else if (CtrlPress(SDLK_PAGEUP)) {
|
||||
Command_SelectRangeOneCursor(active.view, MakeRange(0));
|
||||
CheckpointBeforeGoto(active.window);
|
||||
SelectRange(active.view, MakeRange(0));
|
||||
} else if (Press(SDLK_PAGEUP)) {
|
||||
Command_MoveCursorsByPageSize(active.window, DIR_UP);
|
||||
CheckpointBeforeGoto(active.window);
|
||||
MoveCursorByPageSize(active.window, DIR_UP);
|
||||
}
|
||||
|
||||
if (ShiftPress(SDLK_PAGEDOWN)) {
|
||||
Command_MoveCursorsByPageSize(active.window, DIR_DOWN, SHIFT_PRESS);
|
||||
CheckpointBeforeGoto(active.window);
|
||||
MoveCursorByPageSize(active.window, DIR_DOWN, SHIFT_PRESS);
|
||||
} else if (CtrlPress(SDLK_PAGEDOWN)) {
|
||||
Command_SelectRangeOneCursor(active.view, MakeRange(active.buffer->len));
|
||||
CheckpointBeforeGoto(active.window);
|
||||
SelectRange(active.view, MakeRange(active.buffer->len));
|
||||
} else if (Press(SDLK_PAGEDOWN)) {
|
||||
Command_MoveCursorsByPageSize(active.window, DIR_DOWN);
|
||||
CheckpointBeforeGoto(active.window);
|
||||
MoveCursorByPageSize(active.window, DIR_DOWN);
|
||||
}
|
||||
|
||||
if (ShiftPress(SDLK_HOME)) {
|
||||
Command_MoveCursorsToSide(active.view, DIR_LEFT, SHIFT_PRESS);
|
||||
CheckpointBeforeGoto(active.window);
|
||||
MoveCursorToSide(active.view, DIR_LEFT, SHIFT_PRESS);
|
||||
} else if (Press(SDLK_HOME)) {
|
||||
Command_MoveCursorsToSide(active.view, DIR_LEFT);
|
||||
CheckpointBeforeGoto(active.window);
|
||||
MoveCursorToSide(active.view, DIR_LEFT);
|
||||
}
|
||||
|
||||
if (ShiftPress(SDLK_END)) {
|
||||
Command_MoveCursorsToSide(active.view, DIR_RIGHT, SHIFT_PRESS);
|
||||
CheckpointBeforeGoto(active.window);
|
||||
MoveCursorToSide(active.view, DIR_RIGHT, SHIFT_PRESS);
|
||||
} else if (Press(SDLK_END)) {
|
||||
Command_MoveCursorsToSide(active.view, DIR_RIGHT);
|
||||
CheckpointBeforeGoto(active.window);
|
||||
MoveCursorToSide(active.view, DIR_RIGHT);
|
||||
}
|
||||
|
||||
if (CtrlShiftPress(SDLK_TAB)) {
|
||||
GotoForward(main.window);
|
||||
} else if (ShiftPress(SDLK_TAB)) {
|
||||
Command_IndentSelectedLines(active.view, SHIFT_PRESS);
|
||||
IndentSelectedLines(active.view, SHIFT_PRESS);
|
||||
} else if (CtrlPress(SDLK_TAB)) {
|
||||
GotoBackward(main.window);
|
||||
} else if (Press(SDLK_TAB)) {
|
||||
Command_IndentSelectedLines(active.view);
|
||||
IndentSelectedLines(active.view);
|
||||
}
|
||||
|
||||
if (CtrlPress(SDLK_LEFTBRACKET)) {
|
||||
Command_IndentSelectedLines(active.view, SHIFT_PRESS);
|
||||
IndentSelectedLines(active.view, SHIFT_PRESS);
|
||||
}
|
||||
if (CtrlPress(SDLK_RIGHTBRACKET)) {
|
||||
Command_IndentSelectedLines(active.view);
|
||||
IndentSelectedLines(active.view);
|
||||
}
|
||||
|
||||
if (CtrlShiftPress(SDLK_K)) {
|
||||
Command_KillSelectedLines(active.view);
|
||||
KillSelectedLines(active.view);
|
||||
}
|
||||
|
||||
if (CtrlPress(SDLK_BACKSPACE)) {
|
||||
Command_Delete(active.view, DIR_LEFT, CTRL_PRESSED);
|
||||
Delete(active.view, DIR_LEFT, CTRL_PRESSED);
|
||||
} else if (Press(SDLK_BACKSPACE)) {
|
||||
Command_Delete(active.view, DIR_LEFT);
|
||||
Delete(active.view, DIR_LEFT);
|
||||
}
|
||||
|
||||
if (CtrlPress(SDLK_DELETE)) {
|
||||
Command_Delete(active.view, DIR_RIGHT, CTRL_PRESSED);
|
||||
Delete(active.view, DIR_RIGHT, CTRL_PRESSED);
|
||||
} else if (Press(SDLK_DELETE)) {
|
||||
Command_Delete(active.view, DIR_RIGHT);
|
||||
Delete(active.view, DIR_RIGHT);
|
||||
}
|
||||
|
||||
if (event.kind == EVENT_TEXT_INPUT) {
|
||||
Scratch scratch;
|
||||
String string = event.text;
|
||||
String string = event.text;
|
||||
String16 string16 = ToString16(scratch, string);
|
||||
Command_Replace(active.view, string16);
|
||||
Replace(active.view, string16);
|
||||
}
|
||||
|
||||
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 (CtrlShiftPress(SDLK_N)) {
|
||||
Scratch scratch;
|
||||
String16 search_string = GetSearchString(main.window);
|
||||
Caret caret = FindPrev(main.buffer, search_string, main.view->carets[0]);
|
||||
BSet search = GetBSet(main.window->search_bar_window);
|
||||
search.window->search_bar_anchor = caret;
|
||||
Command_SelectRangeOneCursor(main.view, caret);
|
||||
} else if (CtrlPress(SDLK_N)) {
|
||||
Scratch scratch;
|
||||
String16 search_string = GetSearchString(main.window);
|
||||
Caret caret = FindNext(main.buffer, search_string, main.view->carets[0]);
|
||||
BSet search = GetBSet(main.window->search_bar_window);
|
||||
search.window->search_bar_anchor = caret;
|
||||
Command_SelectRangeOneCursor(main.view, caret);
|
||||
}
|
||||
|
||||
if (CtrlPress(SDLK_EQUALS)) {
|
||||
StyleFontSize += 1;
|
||||
ReloadFont();
|
||||
ReloadFont(StyleFont, (U32)StyleFontSize);
|
||||
}
|
||||
if (CtrlPress(SDLK_MINUS)) {
|
||||
if (StyleFontSize > 4) {
|
||||
StyleFontSize -= 1;
|
||||
ReloadFont();
|
||||
ReloadFont(StyleFont, (U32)StyleFontSize);
|
||||
}
|
||||
}
|
||||
|
||||
if (CtrlPress(SDLK_E)) {
|
||||
Command_GotoNextInList(active.window, 1);
|
||||
} else if (AltPress(SDLK_E)) {
|
||||
Command_GotoNextInList(active.window, -1);
|
||||
}
|
||||
|
||||
if (CtrlPress(SDLK_F)) {
|
||||
if (!active.window->is_search_bar) {
|
||||
BSet search = GetBSet(main.window->search_bar_window);
|
||||
String16 string = GetString(main.buffer, main.view->carets[0].range);
|
||||
if (string.len) {
|
||||
Command_SelectEntireBuffer(search.view);
|
||||
Command_Replace(search.view, string);
|
||||
}
|
||||
Command_SelectEntireBuffer(search.view);
|
||||
search.window->visible = 1;
|
||||
search.window->search_bar_anchor = main.view->carets[0];
|
||||
ActiveWindow = search.window->id;
|
||||
}
|
||||
}
|
||||
|
||||
if (CtrlShiftPress(SDLK_RETURN)) {
|
||||
Command_MoveCursorsToSide(active.view, DIR_LEFT);
|
||||
Command_IdentedNewLine(active.view);
|
||||
Command_Move(active.view, DIR_UP);
|
||||
MoveCursorToSide(active.view, DIR_LEFT);
|
||||
IdentedNewLine(active.view);
|
||||
MoveCarets(active.view, DIR_UP);
|
||||
} else if (CtrlPress(SDLK_RETURN)) {
|
||||
Command_MoveCursorsToSide(active.view, DIR_RIGHT);
|
||||
Command_IdentedNewLine(active.view);
|
||||
MoveCursorToSide(active.view, DIR_RIGHT);
|
||||
IdentedNewLine(active.view);
|
||||
} else if (Press(SDLK_RETURN)) {
|
||||
Command_IdentedNewLine(active.view);
|
||||
IdentedNewLine(active.view);
|
||||
}
|
||||
|
||||
|
||||
@@ -569,7 +555,7 @@ void OnCommand(Event event) {
|
||||
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);
|
||||
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)) {
|
||||
@@ -581,16 +567,18 @@ void OnCommand(Event event) {
|
||||
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), last_line_string);
|
||||
|
||||
Caret caret = active.view->carets[0];
|
||||
Command_SelectEntireBuffer(active.view);
|
||||
Command_Replace(active.view, GetString(temp_buffer));
|
||||
SaveCaretHistoryBeforeBeginEdit(active.buffer, active.view->carets);
|
||||
SelectEntireBuffer(active.view);
|
||||
Replace(active.view, GetString(temp_buffer));
|
||||
active.view->carets[0] = caret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if (CtrlPress(SDLK_N)) {
|
||||
// Command_New();
|
||||
// }
|
||||
if (CtrlPress(SDLK_F)) {
|
||||
Window *window = GetWindow(SearchBarWindowID);
|
||||
window->visible = !window->visible;
|
||||
}
|
||||
|
||||
if (CtrlPress(SDLK_S)) {
|
||||
SaveBuffer(active.buffer);
|
||||
@@ -601,16 +589,10 @@ void OnCommand(Event event) {
|
||||
if (EndsWith(main.buffer->name, "dirlisting")) {
|
||||
name = ChopLastSlash(name);
|
||||
}
|
||||
Command_Open(name);
|
||||
Open(name);
|
||||
}
|
||||
|
||||
if (CtrlPress(SDLK_T)) {
|
||||
ActiveWindow = GetWindow(active.window->title_bar_window)->id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (CtrlShiftPress(SDLK_L)) {
|
||||
if (CtrlShiftPress(SDLK_L)) {
|
||||
EncloseSpace(active.view);
|
||||
} else if (CtrlPress(SDLK_L)) {
|
||||
EncloseLine(active.view);
|
||||
@@ -621,57 +603,30 @@ void OnCommand(Event event) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (CtrlPress(SDLK_SEMICOLON) || CtrlShiftPress(SDLK_Q)) {
|
||||
Command_Open(FetchLoadWord(), "exec");
|
||||
if (AltPress(SDLK_Q)) {
|
||||
GotoBackward(main.window);
|
||||
}
|
||||
else if (CtrlPress(SDLK_Q)) {
|
||||
|
||||
|
||||
if (CtrlPress(SDLK_Q)) {
|
||||
if (active.view->fuzzy_search) {
|
||||
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);
|
||||
Command_Open(string);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
Command_Open(FetchLoadWord());
|
||||
}
|
||||
|
||||
{
|
||||
Range rng = GetLineRangeWithoutNL(active.buffer, active.buffer->line_starts.len - 1);
|
||||
GetLast(active.window->goto_history)->caret = MakeCaret(rng.max, rng.min);
|
||||
}
|
||||
FuzzySearchOpen(active);
|
||||
} else {
|
||||
Command_Open(FetchLoadWord());
|
||||
Open(FetchLoadWord());
|
||||
}
|
||||
}
|
||||
|
||||
if (Press(SDLK_ESCAPE)) {
|
||||
if (active.window->is_search_bar) {
|
||||
ActiveWindow = main.window->id;
|
||||
active.window->visible = 0;
|
||||
} else if (active.window->deactivate_on_escape) {
|
||||
ActiveWindow = main.window->id;
|
||||
} else {
|
||||
active.view->carets.len = 1;
|
||||
active.view->carets[0] = MakeCaret(GetFront(active.view->carets[0]));
|
||||
}
|
||||
}
|
||||
active.view->carets.len = 1;
|
||||
active.view->carets[0] = MakeCaret(GetFront(active.view->carets[0]));
|
||||
|
||||
if (active.window->is_search_bar && buffer_change_id != active.buffer->change_id) {
|
||||
main.view->carets[0] = active.window->search_bar_anchor;
|
||||
Command_Find(main.view, GetSearchString(main.window), true);
|
||||
if (active.window->lose_focus_on_escape && active.window->id == ActiveWindowID) {
|
||||
if (active.window->layout) {
|
||||
//
|
||||
} else {
|
||||
NextActiveWindowID = LastActiveLayoutWindowID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// :OnCommandEnding
|
||||
|
||||
@@ -33,7 +33,7 @@ void SaveStringInClipboard(String16 string) {
|
||||
_SetClipboardText(ToString(scratch, SavedClipboardString).data);
|
||||
}
|
||||
|
||||
void Command_Copy(View *view) {
|
||||
void ClipboardCopy(View *view) {
|
||||
Scratch scratch;
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
|
||||
@@ -59,7 +59,7 @@ void Command_Copy(View *view) {
|
||||
_SetClipboardText(ToString(scratch, SavedClipboardString).data);
|
||||
}
|
||||
|
||||
void Command_Paste(View *view) {
|
||||
void ClipboardPaste(View *view) {
|
||||
Scratch scratch;
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
const char *text = GetClipboardText();
|
||||
|
||||
@@ -46,7 +46,7 @@ void DrawVisibleText(Window *window, Color tint) {
|
||||
Rect2I visible = GetVisibleCells(window);
|
||||
for (Int line_index = visible.min.y; line_index < visible.max.y && line_index >= 0 && line_index < buffer->line_starts.len; line_index += 1) {
|
||||
String16 line_string = GetLineString(buffer, line_index);
|
||||
Vec2I pos = Vec2I{visible.min.x, line_index} * (Int)window->font->line_spacing - view->scroll + window->document_rect.min;
|
||||
Vec2I pos = Vec2I{visible.min.x, line_index} * Vec2I{(Int)window->font->char_spacing, (Int)window->font->line_spacing} - view->scroll + window->document_rect.min;
|
||||
|
||||
float text_offset_x = 0;
|
||||
for (Int col_index = visible.min.x; col_index < visible.max.x && col_index >= 0 && col_index < line_string.len; col_index += 1) {
|
||||
@@ -105,8 +105,8 @@ void DrawWindow(Window *window, Event &event) {
|
||||
Rect2 screen_rect = Rect0Size(event.xwindow, event.ywindow);
|
||||
SetScissor(screen_rect);
|
||||
|
||||
bool is_actib = window->id == ActiveWindow || window->title_bar_window == ActiveWindow || window->search_bar_window == ActiveWindow;
|
||||
bool is_active = window->id == ActiveWindow;
|
||||
bool is_active = window->id == ActiveWindowID;
|
||||
bool active_layed_out_doc = window->id == LastActiveLayoutWindowID;
|
||||
|
||||
Color color_whitespace_during_selection = ColorWhitespaceDuringSelection;
|
||||
Color color_background = ColorBackground;
|
||||
@@ -116,7 +116,8 @@ void DrawWindow(Window *window, Event &event) {
|
||||
Color color_sub_caret = ColorSubCaret;
|
||||
Color color_text_line_numbers = ColorTextLineNumbers;
|
||||
Color color_text = ColorText;
|
||||
if (window->is_title_bar || window->is_search_bar) {
|
||||
|
||||
if (window->draw_darker) {
|
||||
if (is_active) {
|
||||
color_background = ColorTitleBarActiveBackground;
|
||||
} else {
|
||||
@@ -127,7 +128,12 @@ void DrawWindow(Window *window, Event &event) {
|
||||
color_line_highlight = ColorTitleBarBackground;
|
||||
}
|
||||
|
||||
|
||||
DrawRect(window->total_rect, color_background);
|
||||
if (window->draw_darker) {
|
||||
Rect2I rect = window->total_rect;
|
||||
DrawRect(CutTop(&rect, 1), ColorResizerOutline);
|
||||
}
|
||||
|
||||
Rect2I combined_document_line_number = window->document_rect;
|
||||
if (window->draw_line_numbers) combined_document_line_number.min.x = window->line_numbers_rect.min.x;
|
||||
@@ -182,7 +188,7 @@ void DrawWindow(Window *window, Event &event) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (!window->is_title_bar && !window->is_search_bar) {
|
||||
} else if (window->draw_line_highlight) {
|
||||
//
|
||||
// Draw highlight
|
||||
Int front = GetFront(it);
|
||||
@@ -226,8 +232,9 @@ void DrawWindow(Window *window, Event &event) {
|
||||
EndProfileScope();
|
||||
DrawVisibleText(window, color_text);
|
||||
|
||||
BeginProfileScope(draw_carets);
|
||||
if (is_actib) {
|
||||
// Draw caret "|" markings
|
||||
if (is_active) {
|
||||
BeginProfileScope(draw_carets);
|
||||
For(view->carets) {
|
||||
Int front = GetFront(it);
|
||||
XY fxy = PosToXY(buffer, front);
|
||||
@@ -236,8 +243,8 @@ void DrawWindow(Window *window, Event &event) {
|
||||
DrawCaret(window, fxy, 0.3f, main_caret ? color_main_caret : color_sub_caret);
|
||||
}
|
||||
}
|
||||
EndProfileScope();
|
||||
}
|
||||
EndProfileScope();
|
||||
|
||||
// Draw line numbers
|
||||
if (window->draw_line_numbers) {
|
||||
@@ -271,31 +278,22 @@ void DrawWindow(Window *window, Event &event) {
|
||||
DrawRect(rect, color);
|
||||
}
|
||||
|
||||
if (window->z == 1) {
|
||||
// color the floating object to make it stand out
|
||||
if (window->z >= 1) {
|
||||
SetScissor(window->total_rect);
|
||||
DrawRect(window->total_rect, {255, 255, 255, 25});
|
||||
}
|
||||
|
||||
if (!is_actib) {
|
||||
// darken the inactive windows
|
||||
if (!is_active) {
|
||||
SetScissor(screen_rect);
|
||||
DrawRect(window->total_rect, ColorInactiveWindow);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawSplits(WindowSplit *split) {
|
||||
if (split == NULL) {
|
||||
return;
|
||||
// Draw resizer rect
|
||||
{
|
||||
Rect2I rect = window->resizer_rect;
|
||||
DrawRect(rect, ColorResizerBackground);
|
||||
DrawRect(CutRight(&rect, 1), ColorResizerOutline);
|
||||
}
|
||||
Rect2I rect = split->resizer_rect;
|
||||
DrawRect(split->resizer_rect, ColorResizerBackground);
|
||||
if (split->kind == WindowSplitKind_Vertical) {
|
||||
Rect2I s = CutRight(&rect, 1);
|
||||
DrawRect(s, ColorResizerOutline);
|
||||
} else if (split->kind == WindowSplitKind_Horizontal) {
|
||||
Rect2I s = CutBottom(&rect, 1);
|
||||
DrawRect(s, ColorResizerOutline);
|
||||
}
|
||||
|
||||
DrawSplits(split->left);
|
||||
DrawSplits(split->right);
|
||||
}
|
||||
@@ -1,60 +1,3 @@
|
||||
#define EVENT_KINDS \
|
||||
X(EVENT_NONE) \
|
||||
X(EVENT_UPDATE) \
|
||||
X(EVENT_QUIT) \
|
||||
X(EVENT_MOUSE_LEFT) \
|
||||
X(EVENT_MOUSE_RIGHT) \
|
||||
X(EVENT_MOUSE_MIDDLE) \
|
||||
X(EVENT_MOUSE_X1) \
|
||||
X(EVENT_MOUSE_X2) \
|
||||
X(EVENT_MOUSE_LEFT_UP) \
|
||||
X(EVENT_MOUSE_RIGHT_UP) \
|
||||
X(EVENT_MOUSE_MIDDLE_UP) \
|
||||
X(EVENT_MOUSE_X1_UP) \
|
||||
X(EVENT_MOUSE_X2_UP) \
|
||||
X(EVENT_MOUSE_WHEEL) \
|
||||
X(EVENT_KEY_PRESS) \
|
||||
X(EVENT_TEXT_INPUT) \
|
||||
X(EVENT_DROP_FILE)
|
||||
|
||||
enum EventKind {
|
||||
#define X(TYPE) TYPE,
|
||||
EVENT_KINDS
|
||||
#undef X
|
||||
EVENT_KIND_COUNT,
|
||||
EVENT_KIND_INVALID = 111,
|
||||
};
|
||||
|
||||
const char *EventKindStrings[] = {
|
||||
#define X(TYPE) #TYPE,
|
||||
EVENT_KINDS
|
||||
#undef X
|
||||
};
|
||||
|
||||
#define EVENT_FIELDS \
|
||||
X(EventKind, Int, kind) \
|
||||
X(SDL_Keycode, Int, key) \
|
||||
X(int16_t, Int, xwindow) \
|
||||
X(int16_t, Int, ywindow) \
|
||||
X(int16_t, Int, xmouse) \
|
||||
X(int16_t, Int, ymouse) \
|
||||
X(uint8_t, Int, clicks) \
|
||||
X(uint8_t, Int, shift) \
|
||||
X(uint8_t, Int, ctrl) \
|
||||
X(uint8_t, Int, alt) \
|
||||
X(uint8_t, Int, super) \
|
||||
X(float, Float, xwheel) \
|
||||
X(float, Float, ywheel) \
|
||||
X(char *, String, text)
|
||||
#define EVENT_FIELD_COUNT 14
|
||||
|
||||
struct Event {
|
||||
#define X(TYPE, KIND, NAME) TYPE NAME;
|
||||
EVENT_FIELDS
|
||||
#undef X
|
||||
};
|
||||
Array<Event> EventPlayback;
|
||||
|
||||
const char *SDLKeycodeToName(SDL_Keycode keycode) {
|
||||
switch(keycode) {
|
||||
case SDLK_UNKNOWN: return "SDLK_UNKNOWN"; break;
|
||||
@@ -317,6 +260,145 @@ const char *SDLKeycodeToName(SDL_Keycode keycode) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FillEventWithBasicData(Event *event) {
|
||||
SDL_Keymod mod = SDL_GetModState();
|
||||
event->shift = (mod & SDL_KMOD_SHIFT) != 0;
|
||||
event->ctrl = (mod & SDL_KMOD_CTRL) != 0;
|
||||
event->alt = (mod & SDL_KMOD_ALT) != 0;
|
||||
event->super = (mod & SDL_KMOD_GUI) != 0;
|
||||
|
||||
float xmouse, ymouse;
|
||||
SDL_GetMouseState(&xmouse, &ymouse);
|
||||
event->xmouse = (int16_t)xmouse;
|
||||
event->ymouse = (int16_t)ymouse;
|
||||
|
||||
int xwindow, ywindow;
|
||||
SDL_GetWindowSize(SDLWindow, &xwindow, &ywindow);
|
||||
event->xwindow = xwindow;
|
||||
event->ywindow = ywindow;
|
||||
event->text = "";
|
||||
}
|
||||
|
||||
Event TranslateSDLEvent(SDL_Event *input_event) {
|
||||
ProfileFunction();
|
||||
Event event = {};
|
||||
FillEventWithBasicData(&event);
|
||||
|
||||
switch (input_event->type) {
|
||||
case SDL_EVENT_QUIT: {
|
||||
event.kind = EVENT_QUIT;
|
||||
} break;
|
||||
|
||||
case SDL_EVENT_KEY_DOWN: {
|
||||
event.kind = EVENT_KEY_PRESS;
|
||||
SDL_KeyboardEvent &key = input_event->key;
|
||||
event.key = key.key;
|
||||
} break;
|
||||
|
||||
case SDL_EVENT_TEXT_INPUT: {
|
||||
event.kind = EVENT_TEXT_INPUT;
|
||||
SDL_TextInputEvent &b = input_event->text;
|
||||
String string = b.text;
|
||||
event.text = Intern(&GlobalInternTable, string).data;
|
||||
} break;
|
||||
|
||||
case SDL_EVENT_MOUSE_BUTTON_DOWN: {
|
||||
SDL_MouseButtonEvent &b = input_event->button;
|
||||
event.xmouse = (int16_t)b.x;
|
||||
event.ymouse = (int16_t)b.y;
|
||||
event.clicks = b.clicks;
|
||||
if (b.button == SDL_BUTTON_LEFT) {
|
||||
event.kind = EVENT_MOUSE_LEFT;
|
||||
} else if (b.button == SDL_BUTTON_RIGHT) {
|
||||
event.kind = EVENT_MOUSE_RIGHT;
|
||||
} else if (b.button == SDL_BUTTON_MIDDLE) {
|
||||
event.kind = EVENT_MOUSE_MIDDLE;
|
||||
} else if (b.button == SDL_BUTTON_X1) {
|
||||
event.kind = EVENT_MOUSE_X1;
|
||||
} else if (b.button == SDL_BUTTON_X2) {
|
||||
event.kind = EVENT_MOUSE_X2;
|
||||
} else {
|
||||
event.kind = EVENT_NONE;
|
||||
event.clicks = 0;
|
||||
}
|
||||
} break;
|
||||
|
||||
case SDL_EVENT_MOUSE_BUTTON_UP: {
|
||||
SDL_MouseButtonEvent &b = input_event->button;
|
||||
event.xmouse = (int16_t)b.x;
|
||||
event.ymouse = (int16_t)b.y;
|
||||
if (b.button == SDL_BUTTON_LEFT) {
|
||||
event.kind = EVENT_MOUSE_LEFT_UP;
|
||||
} else if (b.button == SDL_BUTTON_RIGHT) {
|
||||
event.kind = EVENT_MOUSE_RIGHT_UP;
|
||||
} else if (b.button == SDL_BUTTON_MIDDLE) {
|
||||
event.kind = EVENT_MOUSE_MIDDLE_UP;
|
||||
} else if (b.button == SDL_BUTTON_X1) {
|
||||
event.kind = EVENT_MOUSE_X1_UP;
|
||||
} else if (b.button == SDL_BUTTON_X2) {
|
||||
event.kind = EVENT_MOUSE_X2_UP;
|
||||
} else {
|
||||
event.kind = EVENT_NONE;
|
||||
}
|
||||
} break;
|
||||
|
||||
case SDL_EVENT_MOUSE_WHEEL: {
|
||||
event.kind = EVENT_MOUSE_WHEEL;
|
||||
SDL_MouseWheelEvent &b = input_event->wheel;
|
||||
event.xmouse = (int16_t)b.mouse_x;
|
||||
event.ymouse = (int16_t)b.mouse_y;
|
||||
event.xwheel = b.x;
|
||||
event.ywheel = b.y;
|
||||
} break;
|
||||
|
||||
case SDL_EVENT_MOUSE_MOTION: {
|
||||
event.kind = EVENT_UPDATE;
|
||||
} break;
|
||||
|
||||
case SDL_EVENT_DROP_FILE: {
|
||||
event.kind = EVENT_DROP_FILE;
|
||||
SDL_DropEvent &b = input_event->drop;
|
||||
String string = b.data;
|
||||
event.text = Intern(&GlobalInternTable, string).data;
|
||||
} break;
|
||||
default: {
|
||||
};
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
Array<Event> GetEventsForFrame(Allocator allocator) {
|
||||
Array<Event> result = {allocator};
|
||||
if (EventPlayback.len) {
|
||||
result = TightCopy(allocator, EventPlayback);
|
||||
EventPlayback.len = 0;
|
||||
}
|
||||
|
||||
SDL_Event event;
|
||||
if (WaitForEvents) {
|
||||
SDL_WaitEvent(&event);
|
||||
Event ev = TranslateSDLEvent(&event);
|
||||
if (ev.kind != EVENT_NONE) Add(&result, ev);
|
||||
}
|
||||
|
||||
while (SDL_PollEvent(&event)) {
|
||||
Event ev = TranslateSDLEvent(&event);
|
||||
if (ev.kind != EVENT_NONE) Add(&result, ev);
|
||||
}
|
||||
|
||||
if (result.len == 0) {
|
||||
Event event = {};
|
||||
FillEventWithBasicData(&event);
|
||||
event.kind = EVENT_UPDATE;
|
||||
Add(&result, event);
|
||||
}
|
||||
|
||||
Assert(result.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
struct Serializer {
|
||||
Buffer *buffer; // for writing
|
||||
};
|
||||
@@ -386,17 +468,14 @@ void Serialize(Serializer *s, Event *e) {
|
||||
SerializeEnd(s);
|
||||
}
|
||||
|
||||
const int DIR_RIGHT = 0;
|
||||
const int DIR_LEFT = 1;
|
||||
const int DIR_DOWN = 2;
|
||||
const int DIR_UP = 3;
|
||||
const int DIR_COUNT = 4;
|
||||
const bool CTRL_PRESSED = true;
|
||||
const 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;
|
||||
|
||||
bool AppIsRunning = true;
|
||||
bool WaitForEvents = true;
|
||||
|
||||
#define Ctrl() event.ctrl
|
||||
#define Alt() event.alt
|
||||
#define Shift() event.shift
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
void ReloadStyle() {
|
||||
ColorText = GetColor("Text", ColorText);
|
||||
ColorLoadTextHighlight = GetColor("LoadTextHighlight", ColorLoadTextHighlight);
|
||||
ColorBackground = GetColor("Background", ColorBackground);
|
||||
ColorInactiveWindow = GetColor("InactiveWindow", ColorInactiveWindow);
|
||||
ColorTextLineNumbers = GetColor("TextLineNumbers", ColorTextLineNumbers);
|
||||
ColorLineHighlight = GetColor("LineHighlight", ColorLineHighlight);
|
||||
ColorMainCaret = GetColor("MainCaret", ColorMainCaret);
|
||||
ColorSubCaret = GetColor("SubCaret", ColorSubCaret);
|
||||
ColorSelection = GetColor("Selection", ColorSelection);
|
||||
ColorWhitespaceDuringSelection = GetColor("WhitespaceDuringSelection", ColorWhitespaceDuringSelection);
|
||||
ColorMouseUnderline = GetColor("MouseUnderline", ColorMouseUnderline);
|
||||
ColorCaretUnderline = GetColor("CaretUnderline", ColorCaretUnderline);
|
||||
ColorFuzzySearchLineHighlight = GetColor("FuzzySearchLineHighlight", ColorFuzzySearchLineHighlight);
|
||||
ColorScrollbarBackground = GetColor("ScrollbarBackground", ColorScrollbarBackground);
|
||||
ColorScrollbarScroller = GetColor("ScrollbarScroller", ColorScrollbarScroller);
|
||||
ColorScrollbarScrollerSelected = GetColor("ScrollbarScrollerSelected", ColorScrollbarScrollerSelected);
|
||||
ColorTitleBarText = GetColor("TitleBarText", ColorTitleBarText);
|
||||
ColorTitleBarBackground = GetColor("TitleBarBackground", ColorTitleBarBackground);
|
||||
ColorTitleBarActiveBackground = GetColor("TitleBarActiveBackground", ColorTitleBarActiveBackground);
|
||||
ColorTitleBarSelection = GetColor("TitleBarSelection", ColorTitleBarSelection);
|
||||
ColorResizerBackground = GetColor("ResizerBackground", ColorResizerBackground);
|
||||
ColorResizerOutline = GetColor("ResizerOutline", ColorResizerOutline);
|
||||
StyleWaitForEvents = GetStyleInt("WaitForEvents", StyleWaitForEvents);
|
||||
StyleDrawLineNumbers = GetStyleInt("DrawLineNumbers", StyleDrawLineNumbers);
|
||||
StyleDrawScrollbar = GetStyleInt("DrawScrollbar", StyleDrawScrollbar);
|
||||
StyleIndentSize = GetStyleInt("IndentSize", StyleIndentSize);
|
||||
StyleFontSize = GetStyleInt("FontSize", StyleFontSize);
|
||||
StyleFontFilter = GetStyleInt("FontFilter", StyleFontFilter);
|
||||
StyleFont = GetStyleString("Font", StyleFont);
|
||||
StyleVCVarsall = GetStyleString("VCVarsall", StyleVCVarsall);
|
||||
}
|
||||
@@ -69,6 +69,7 @@ Style.Font = GetExeDir().."/CascadiaMono.ttf"
|
||||
Style.VCVarsall = "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat"
|
||||
Style.TrimWhitespaceOnSave = true
|
||||
Style.ClangFormatOnSave = false
|
||||
Style.StyleUndoMergeTimeout = 0.3
|
||||
|
||||
INTERNET_BROWSER = 'C:/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe'
|
||||
OS_WINDOWS = 0
|
||||
@@ -324,10 +325,6 @@ function MatchGotoBuild(s, meta)
|
||||
end
|
||||
|
||||
function MatchExec(s, meta)
|
||||
if meta ~= "exec" then
|
||||
return nil
|
||||
end
|
||||
|
||||
if s:match(".exe$") or s:match(".bat$") or s:match(".sh$") then
|
||||
return {kind = "exec_console", cmd = s, working_dir = GetMainDir()}
|
||||
end
|
||||
@@ -336,8 +333,7 @@ function MatchExec(s, meta)
|
||||
return {kind = "exec_console", cmd = s:sub(2, -1), working_dir = GetMainDir()}
|
||||
end
|
||||
|
||||
Eval(s)
|
||||
return {kind = "skip"}
|
||||
return nil
|
||||
end
|
||||
|
||||
BuiltinOnOpenMatchers = {
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
Color GruvboxDark0Hard = {0x1d, 0x20, 0x21, 0xff};
|
||||
Color GruvboxDark0 = {0x28, 0x28, 0x28, 0xff};
|
||||
Color GruvboxDark0Soft = {0x32, 0x30, 0x2f, 0xff};
|
||||
Color GruvboxDark1 = {0x3c, 0x38, 0x36, 0xff};
|
||||
Color GruvboxDark2 = {0x50, 0x49, 0x45, 0xff};
|
||||
Color GruvboxDark3 = {0x66, 0x5c, 0x54, 0xff};
|
||||
Color GruvboxDark4 = {0x7c, 0x6f, 0x64, 0xff};
|
||||
Color GruvboxGray245 = {0x92, 0x83, 0x74, 0xff};
|
||||
Color GruvboxGray244 = {0x92, 0x83, 0x74, 0xff};
|
||||
Color GruvboxLight0Hard = {0xf9, 0xf5, 0xd7, 0xff};
|
||||
Color GruvboxLight0 = {0xfb, 0xf1, 0xc7, 0xff};
|
||||
Color GruvboxLight0Soft = {0xf2, 0xe5, 0xbc, 0xff};
|
||||
Color GruvboxLight1 = {0xeb, 0xdb, 0xb2, 0xff};
|
||||
Color GruvboxLight2 = {0xd5, 0xc4, 0xa1, 0xff};
|
||||
Color GruvboxLight3 = {0xbd, 0xae, 0x93, 0xff};
|
||||
Color GruvboxLight4 = {0xa8, 0x99, 0x84, 0xff};
|
||||
Color GruvboxBrightRed = {0xfb, 0x49, 0x34, 0xff};
|
||||
Color GruvboxBrightGreen = {0xb8, 0xbb, 0x26, 0xff};
|
||||
Color GruvboxBrightYellow = {0xfa, 0xbd, 0x2f, 0xff};
|
||||
Color GruvboxBrightBlue = {0x83, 0xa5, 0x98, 0xff};
|
||||
Color GruvboxBrightPurple = {0xd3, 0x86, 0x9b, 0xff};
|
||||
Color GruvboxBrightAqua = {0x8e, 0xc0, 0x7c, 0xff};
|
||||
Color GruvboxBrightOrange = {0xfe, 0x80, 0x19, 0xff};
|
||||
Color GruvboxNeutralRed = {0xcc, 0x24, 0x1d, 0xff};
|
||||
Color GruvboxNeutralGreen = {0x98, 0x97, 0x1a, 0xff};
|
||||
Color GruvboxNeutralYellow = {0xd7, 0x99, 0x21, 0xff};
|
||||
Color GruvboxNeutralBlue = {0x45, 0x85, 0x88, 0xff};
|
||||
Color GruvboxNeutralPurple = {0xb1, 0x62, 0x86, 0xff};
|
||||
Color GruvboxNeutralAqua = {0x68, 0x9d, 0x6a, 0xff};
|
||||
Color GruvboxNeutralOrange = {0xd6, 0x5d, 0x0e, 0xff};
|
||||
Color GruvboxFadedRed = {0x9d, 0x00, 0x06, 0xff};
|
||||
Color GruvboxFadedGreen = {0x79, 0x74, 0x0e, 0xff};
|
||||
Color GruvboxFadedYellow = {0xb5, 0x76, 0x14, 0xff};
|
||||
Color GruvboxFadedBlue = {0x07, 0x66, 0x78, 0xff};
|
||||
Color GruvboxFadedPurple = {0x8f, 0x3f, 0x71, 0xff};
|
||||
Color GruvboxFadedAqua = {0x42, 0x7b, 0x58, 0xff};
|
||||
Color GruvboxFadedOrange = {0xaf, 0x3a, 0x03, 0xff};
|
||||
Color ColorText = GruvboxDark0Hard;
|
||||
Color ColorLoadTextHighlight = {0x00, 0x00, 0x00, 0x0F};
|
||||
Color ColorBackground = GruvboxLight0Hard;
|
||||
Color ColorInactiveWindow = {0x00, 0x00, 0x00, 0x0F};
|
||||
Color ColorTextLineNumbers = GruvboxDark4;
|
||||
Color ColorLineHighlight = GruvboxLight0Soft;
|
||||
Color ColorMainCaret = GruvboxDark0Hard;
|
||||
Color ColorSubCaret = GruvboxGray245;
|
||||
Color ColorSelection = GruvboxLight1;
|
||||
Color ColorWhitespaceDuringSelection = GruvboxLight4;
|
||||
Color ColorMouseUnderline = GruvboxDark0Hard;
|
||||
Color ColorCaretUnderline = GruvboxGray245;
|
||||
Color ColorFuzzySearchLineHighlight = GruvboxDark0;
|
||||
Color ColorScrollbarBackground = GruvboxLight2;
|
||||
Color ColorScrollbarScroller = GruvboxLight1;
|
||||
Color ColorScrollbarScrollerSelected = GruvboxLight0Hard;
|
||||
Color ColorTitleBarText = GruvboxDark2;
|
||||
Color ColorTitleBarBackground = GruvboxLight1;
|
||||
Color ColorTitleBarActiveBackground = {0xfe, 0xfe, 0xfe, 0xfe};
|
||||
Color ColorTitleBarSelection = GruvboxLight3;
|
||||
Color ColorResizerBackground = GruvboxLight0Hard;
|
||||
Color ColorResizerOutline = GruvboxLight3;
|
||||
Int StyleWaitForEvents = 1;
|
||||
Int StyleDrawLineNumbers = 1;
|
||||
Int StyleDrawScrollbar = 1;
|
||||
Int StyleIndentSize = 4;
|
||||
Int StyleFontSize = 15;
|
||||
Int StyleFontFilter = 0;
|
||||
String StyleFont = "/home/krz/text_editor/package/CascadiaMono.ttf";
|
||||
String StyleVCVarsall = "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat";
|
||||
187
src/text_editor/globals.cpp
Normal file
187
src/text_editor/globals.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
SDL_Window *SDLWindow;
|
||||
bool IsInFullscreen;
|
||||
int FullScreenSizeX, FullScreenSizeY;
|
||||
int FullScreenPositionX, FullScreenPositionY;
|
||||
bool Testing = false;
|
||||
bool AppIsRunning = true;
|
||||
bool WaitForEvents = true;
|
||||
|
||||
WindowID WindowIDs;
|
||||
ViewID ViewIDs;
|
||||
Int BufferIDs;
|
||||
|
||||
Array<Window *> Windows;
|
||||
Array<View *> Views;
|
||||
Array<Buffer *> Buffers;
|
||||
|
||||
// console
|
||||
BufferID NullBufferID;
|
||||
ViewID NullViewID;
|
||||
WindowID NullWindowID;
|
||||
|
||||
// hidden floating window
|
||||
WindowID DebugWindowID;
|
||||
ViewID DebugViewID;
|
||||
BufferID DebugBufferID;
|
||||
|
||||
WindowID CommandBarWindowID;
|
||||
WindowID StatusBarWindowID;
|
||||
WindowID SearchBarWindowID;
|
||||
ViewID SearchViewID;
|
||||
BufferID SearchBufferID;
|
||||
|
||||
WindowID ActiveWindowID;
|
||||
WindowID NextActiveWindowID;
|
||||
WindowID LastActiveLayoutWindowID;
|
||||
WindowID ScrollbarSelected = {-1};
|
||||
WindowID DocumentSelected = {-1};
|
||||
WindowID ResizerSelected = {-1};
|
||||
WindowID ResizerHover = {-1};
|
||||
Caret DocumentAnchor;
|
||||
|
||||
Buffer *LuaProjectBuffer;
|
||||
Buffer *LuaConfigBuffer;
|
||||
Buffer *GCInfoBuffer;
|
||||
Buffer *EventBuffer;
|
||||
Buffer *ScratchBuffer;
|
||||
Buffer *TraceBuffer;
|
||||
View *TraceView;
|
||||
|
||||
String WorkDir;
|
||||
RandomSeed UniqueBufferNameSeed = {};
|
||||
Array<Event> EventPlayback;
|
||||
|
||||
// lua
|
||||
lua_State *LuaState = NULL;
|
||||
String16 LuaCommandResult = {};
|
||||
extern luaL_Reg LuaFunctions[];
|
||||
|
||||
// clipboard
|
||||
BlockArena ClipboardArena;
|
||||
String16 SavedClipboardString;
|
||||
Array<String16> SavedClipboardCarets = {SysAllocator};
|
||||
|
||||
struct InternTable {
|
||||
HashTable<String> strings; // general allocator
|
||||
BlockArena arena;
|
||||
};
|
||||
|
||||
String Intern(InternTable *table, String string) {
|
||||
String *value = table->strings.get(string);
|
||||
if (!value) {
|
||||
String copy = Copy(table->arena, string);
|
||||
table->strings.put(copy, copy);
|
||||
return copy;
|
||||
}
|
||||
return *value;
|
||||
}
|
||||
|
||||
// We use the intern table to optimize for space, I don't want to worry about freeing
|
||||
// buffer names and event text data so let it all accumulate and interning will at least
|
||||
// optimize worst offenders (like event text)
|
||||
InternTable GlobalInternTable;
|
||||
|
||||
///////////////////////////////
|
||||
// CONFIG
|
||||
Color GruvboxDark0Hard = {0x1d, 0x20, 0x21, 0xff};
|
||||
Color GruvboxDark0 = {0x28, 0x28, 0x28, 0xff};
|
||||
Color GruvboxDark0Soft = {0x32, 0x30, 0x2f, 0xff};
|
||||
Color GruvboxDark1 = {0x3c, 0x38, 0x36, 0xff};
|
||||
Color GruvboxDark2 = {0x50, 0x49, 0x45, 0xff};
|
||||
Color GruvboxDark3 = {0x66, 0x5c, 0x54, 0xff};
|
||||
Color GruvboxDark4 = {0x7c, 0x6f, 0x64, 0xff};
|
||||
Color GruvboxGray245 = {0x92, 0x83, 0x74, 0xff};
|
||||
Color GruvboxGray244 = {0x92, 0x83, 0x74, 0xff};
|
||||
Color GruvboxLight0Hard = {0xf9, 0xf5, 0xd7, 0xff};
|
||||
Color GruvboxLight0 = {0xfb, 0xf1, 0xc7, 0xff};
|
||||
Color GruvboxLight0Soft = {0xf2, 0xe5, 0xbc, 0xff};
|
||||
Color GruvboxLight1 = {0xeb, 0xdb, 0xb2, 0xff};
|
||||
Color GruvboxLight2 = {0xd5, 0xc4, 0xa1, 0xff};
|
||||
Color GruvboxLight3 = {0xbd, 0xae, 0x93, 0xff};
|
||||
Color GruvboxLight4 = {0xa8, 0x99, 0x84, 0xff};
|
||||
Color GruvboxBrightRed = {0xfb, 0x49, 0x34, 0xff};
|
||||
Color GruvboxBrightGreen = {0xb8, 0xbb, 0x26, 0xff};
|
||||
Color GruvboxBrightYellow = {0xfa, 0xbd, 0x2f, 0xff};
|
||||
Color GruvboxBrightBlue = {0x83, 0xa5, 0x98, 0xff};
|
||||
Color GruvboxBrightPurple = {0xd3, 0x86, 0x9b, 0xff};
|
||||
Color GruvboxBrightAqua = {0x8e, 0xc0, 0x7c, 0xff};
|
||||
Color GruvboxBrightOrange = {0xfe, 0x80, 0x19, 0xff};
|
||||
Color GruvboxNeutralRed = {0xcc, 0x24, 0x1d, 0xff};
|
||||
Color GruvboxNeutralGreen = {0x98, 0x97, 0x1a, 0xff};
|
||||
Color GruvboxNeutralYellow = {0xd7, 0x99, 0x21, 0xff};
|
||||
Color GruvboxNeutralBlue = {0x45, 0x85, 0x88, 0xff};
|
||||
Color GruvboxNeutralPurple = {0xb1, 0x62, 0x86, 0xff};
|
||||
Color GruvboxNeutralAqua = {0x68, 0x9d, 0x6a, 0xff};
|
||||
Color GruvboxNeutralOrange = {0xd6, 0x5d, 0x0e, 0xff};
|
||||
Color GruvboxFadedRed = {0x9d, 0x00, 0x06, 0xff};
|
||||
Color GruvboxFadedGreen = {0x79, 0x74, 0x0e, 0xff};
|
||||
Color GruvboxFadedYellow = {0xb5, 0x76, 0x14, 0xff};
|
||||
Color GruvboxFadedBlue = {0x07, 0x66, 0x78, 0xff};
|
||||
Color GruvboxFadedPurple = {0x8f, 0x3f, 0x71, 0xff};
|
||||
Color GruvboxFadedAqua = {0x42, 0x7b, 0x58, 0xff};
|
||||
Color GruvboxFadedOrange = {0xaf, 0x3a, 0x03, 0xff};
|
||||
Color ColorText = GruvboxDark0Hard;
|
||||
Color ColorLoadTextHighlight = {0x00, 0x00, 0x00, 0x0F};
|
||||
Color ColorBackground = GruvboxLight0Hard;
|
||||
Color ColorInactiveWindow = {0x00, 0x00, 0x00, 0x0F};
|
||||
Color ColorTextLineNumbers = GruvboxDark4;
|
||||
Color ColorLineHighlight = GruvboxLight0Soft;
|
||||
Color ColorMainCaret = GruvboxDark0Hard;
|
||||
Color ColorSubCaret = GruvboxGray245;
|
||||
Color ColorSelection = GruvboxLight1;
|
||||
Color ColorWhitespaceDuringSelection = GruvboxLight4;
|
||||
Color ColorMouseUnderline = GruvboxDark0Hard;
|
||||
Color ColorCaretUnderline = GruvboxGray245;
|
||||
Color ColorFuzzySearchLineHighlight = GruvboxDark0;
|
||||
Color ColorScrollbarBackground = GruvboxLight2;
|
||||
Color ColorScrollbarScroller = GruvboxLight1;
|
||||
Color ColorScrollbarScrollerSelected = GruvboxLight0Hard;
|
||||
Color ColorTitleBarText = GruvboxDark2;
|
||||
Color ColorTitleBarBackground = GruvboxLight1;
|
||||
Color ColorTitleBarActiveBackground = {0xfe, 0xfe, 0xfe, 0xfe};
|
||||
Color ColorTitleBarSelection = GruvboxLight3;
|
||||
Color ColorResizerBackground = GruvboxLight0Hard;
|
||||
Color ColorResizerOutline = GruvboxLight3;
|
||||
Int StyleWaitForEvents = 1;
|
||||
Int StyleDrawLineNumbers = 1;
|
||||
Int StyleDrawScrollbar = 1;
|
||||
Int StyleIndentSize = 4;
|
||||
Int StyleFontSize = 15;
|
||||
Int StyleFontFilter = 0;
|
||||
String StyleFont = "/home/krz/text_editor/package/CascadiaMono.ttf";
|
||||
String StyleVCVarsall = "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat";
|
||||
double StyleUndoMergeTimeout = 0.3;
|
||||
|
||||
void ReloadStyle() {
|
||||
ColorText = GetColor("Text", ColorText);
|
||||
ColorLoadTextHighlight = GetColor("LoadTextHighlight", ColorLoadTextHighlight);
|
||||
ColorBackground = GetColor("Background", ColorBackground);
|
||||
ColorInactiveWindow = GetColor("InactiveWindow", ColorInactiveWindow);
|
||||
ColorTextLineNumbers = GetColor("TextLineNumbers", ColorTextLineNumbers);
|
||||
ColorLineHighlight = GetColor("LineHighlight", ColorLineHighlight);
|
||||
ColorMainCaret = GetColor("MainCaret", ColorMainCaret);
|
||||
ColorSubCaret = GetColor("SubCaret", ColorSubCaret);
|
||||
ColorSelection = GetColor("Selection", ColorSelection);
|
||||
ColorWhitespaceDuringSelection = GetColor("WhitespaceDuringSelection", ColorWhitespaceDuringSelection);
|
||||
ColorMouseUnderline = GetColor("MouseUnderline", ColorMouseUnderline);
|
||||
ColorCaretUnderline = GetColor("CaretUnderline", ColorCaretUnderline);
|
||||
ColorFuzzySearchLineHighlight = GetColor("FuzzySearchLineHighlight", ColorFuzzySearchLineHighlight);
|
||||
ColorScrollbarBackground = GetColor("ScrollbarBackground", ColorScrollbarBackground);
|
||||
ColorScrollbarScroller = GetColor("ScrollbarScroller", ColorScrollbarScroller);
|
||||
ColorScrollbarScrollerSelected = GetColor("ScrollbarScrollerSelected", ColorScrollbarScrollerSelected);
|
||||
ColorTitleBarText = GetColor("TitleBarText", ColorTitleBarText);
|
||||
ColorTitleBarBackground = GetColor("TitleBarBackground", ColorTitleBarBackground);
|
||||
ColorTitleBarActiveBackground = GetColor("TitleBarActiveBackground", ColorTitleBarActiveBackground);
|
||||
ColorTitleBarSelection = GetColor("TitleBarSelection", ColorTitleBarSelection);
|
||||
ColorResizerBackground = GetColor("ResizerBackground", ColorResizerBackground);
|
||||
ColorResizerOutline = GetColor("ResizerOutline", ColorResizerOutline);
|
||||
StyleWaitForEvents = GetStyleInt("WaitForEvents", StyleWaitForEvents);
|
||||
StyleDrawLineNumbers = GetStyleInt("DrawLineNumbers", StyleDrawLineNumbers);
|
||||
StyleDrawScrollbar = GetStyleInt("DrawScrollbar", StyleDrawScrollbar);
|
||||
StyleIndentSize = GetStyleInt("IndentSize", StyleIndentSize);
|
||||
StyleFontSize = GetStyleInt("FontSize", StyleFontSize);
|
||||
StyleFontFilter = GetStyleInt("FontFilter", StyleFontFilter);
|
||||
StyleFont = GetStyleString("Font", StyleFont);
|
||||
StyleVCVarsall = GetStyleString("VCVarsall", StyleVCVarsall);
|
||||
StyleUndoMergeTimeout = GetStyleFloat("UndoMergeTimeout", StyleUndoMergeTimeout);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
struct InternTable {
|
||||
HashTable<String> strings; // general allocator
|
||||
BlockArena arena;
|
||||
};
|
||||
|
||||
String Intern(InternTable *table, String string) {
|
||||
String *value = table->strings.get(string);
|
||||
if (!value) {
|
||||
String copy = Copy(table->arena, string);
|
||||
table->strings.put(copy, copy);
|
||||
return copy;
|
||||
}
|
||||
return *value;
|
||||
}
|
||||
|
||||
// We use the intern table to optimize for space, I don't want to worry about freeing
|
||||
// buffer names and event text data so let it all accumulate and interning will at least
|
||||
// optimize worst offenders (like event text)
|
||||
InternTable GlobalInternTable;
|
||||
255
src/text_editor/lua.cpp
Normal file
255
src/text_editor/lua.cpp
Normal file
@@ -0,0 +1,255 @@
|
||||
static void HookLuaForceExit(lua_State *L, lua_Debug *debug) {
|
||||
SDL_PumpEvents();
|
||||
int numkeys = 0;
|
||||
const bool *keys = SDL_GetKeyboardState(&numkeys);
|
||||
if (keys[SDL_SCANCODE_F9])
|
||||
luaL_error(L, "lua execution got interrupted");
|
||||
}
|
||||
|
||||
API double GetStyleFloat(String name, double default_float) {
|
||||
double result = default_float;
|
||||
lua_getglobal(LuaState, "Style");
|
||||
defer { lua_pop(LuaState, 1); };
|
||||
if (lua_istable(LuaState, -1)) {
|
||||
lua_pushlstring(LuaState, name.data, name.len);
|
||||
lua_gettable(LuaState, -2);
|
||||
defer { lua_pop(LuaState, 1); };
|
||||
if (lua_isnumber(LuaState, -1) || lua_isboolean(LuaState, -1) || lua_isinteger(LuaState, -1)) {
|
||||
lua_Number num = lua_tonumber(LuaState, -1);
|
||||
result = (double)num;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
API Int GetStyleInt(String name, Int default_int) {
|
||||
Int result = default_int;
|
||||
lua_getglobal(LuaState, "Style");
|
||||
defer { lua_pop(LuaState, 1); };
|
||||
if (lua_istable(LuaState, -1)) {
|
||||
lua_pushlstring(LuaState, name.data, name.len);
|
||||
lua_gettable(LuaState, -2);
|
||||
defer { lua_pop(LuaState, 1); };
|
||||
if (lua_isnumber(LuaState, -1) || lua_isboolean(LuaState, -1) || lua_isinteger(LuaState, -1)) {
|
||||
lua_Integer num = lua_tointeger(LuaState, -1);
|
||||
result = (Int)num;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
API String GetStyleString(String name, String default_string) {
|
||||
String result = default_string;
|
||||
lua_getglobal(LuaState, "Style");
|
||||
defer { lua_pop(LuaState, 1); };
|
||||
if (lua_istable(LuaState, -1)) {
|
||||
lua_pushlstring(LuaState, name.data, name.len);
|
||||
lua_gettable(LuaState, -2);
|
||||
defer { lua_pop(LuaState, 1); };
|
||||
if (lua_isstring(LuaState, -1)) {
|
||||
const char *string = lua_tostring(LuaState, -1);
|
||||
result = Intern(&GlobalInternTable, string);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
API Color GetColor(String name, Color default_color) {
|
||||
Color result = default_color;
|
||||
lua_getglobal(LuaState, "Color");
|
||||
defer { lua_pop(LuaState, 1); };
|
||||
if (lua_istable(LuaState, -1)) {
|
||||
lua_pushlstring(LuaState, name.data, name.len);
|
||||
lua_gettable(LuaState, -2);
|
||||
defer { lua_pop(LuaState, 1); };
|
||||
if (lua_isnumber(LuaState, -1)) {
|
||||
lua_Integer num = lua_tointeger(LuaState, -1);
|
||||
result.r = (uint8_t)((0xFF000000 & num) >> 24);
|
||||
result.g = (uint8_t)((0x00FF0000 & num) >> 16);
|
||||
result.b = (uint8_t)((0x0000FF00 & num) >> 8);
|
||||
result.a = (uint8_t)((0x000000FF & num) >> 0);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
API String GetFieldString(lua_State *L, String name) {
|
||||
String result = {};
|
||||
if (lua_istable(L, -1)) {
|
||||
lua_pushlstring(L, name.data, name.len);
|
||||
lua_gettable(L, -2);
|
||||
defer { lua_pop(L, 1); };
|
||||
if (lua_isstring(L, -1)) {
|
||||
result = lua_tostring(L, -1);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Int GetFieldAInt(lua_State *L, const char *name) {
|
||||
lua_getfield(L, -1, name);
|
||||
lua_Integer num = lua_tointeger(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return (Int)num;
|
||||
}
|
||||
|
||||
double GetFieldAFloat(lua_State *L, const char *name) {
|
||||
lua_getfield(L, -1, name);
|
||||
double num = lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return num;
|
||||
}
|
||||
|
||||
const char *GetFieldAString(lua_State *L, const char *name) {
|
||||
lua_getfield(L, -1, name);
|
||||
const char *result = lua_tostring(L, -1);
|
||||
|
||||
lua_pop(L, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
API void PushEvent(lua_State *L, Event *event) {
|
||||
lua_createtable(L, 0, EVENT_FIELD_COUNT);
|
||||
#define lua_pushInt lua_pushinteger
|
||||
#define lua_pushString lua_pushstring
|
||||
#define lua_pushFloat lua_pushnumber
|
||||
#define X(TYPE, KIND, NAME) \
|
||||
lua_push##KIND(L, event->NAME); \
|
||||
lua_setfield(L, -2, #NAME);
|
||||
EVENT_FIELDS
|
||||
#undef X
|
||||
}
|
||||
|
||||
// :Event
|
||||
API int Lua_Play(lua_State *L) {
|
||||
if (!lua_istable(L, -1)) luaL_error(L, "expected a table of events");
|
||||
defer { lua_pop(L, 1); };
|
||||
|
||||
int size = (int)lua_rawlen(L, -1);
|
||||
for (int i = 0; i < size; i += 1) {
|
||||
lua_geti(L, -1, i + 1);
|
||||
if (!lua_istable(L, -1)) luaL_error(L, "expected a table of events");
|
||||
defer { lua_pop(L, 1); };
|
||||
|
||||
Event event = {};
|
||||
#define X(TYPE, KIND, NAME) event.NAME = (TYPE)GetFieldA##KIND(L, #NAME);
|
||||
EVENT_FIELDS
|
||||
#undef X
|
||||
Add(&EventPlayback, event);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ReloadStyle();
|
||||
extern String BaseLuaConfig;
|
||||
|
||||
API void LoadLuaBuffer(Buffer *lua_buffer) {
|
||||
if (!lua_buffer) return;
|
||||
ReportConsolef("reloading config: %S", lua_buffer->name);
|
||||
|
||||
Scratch scratch;
|
||||
String string = AllocCharString(scratch, lua_buffer);
|
||||
if (luaL_dostring(LuaState, string.data) == LUA_OK) {
|
||||
if (lua_isstring(LuaState, -1)) {
|
||||
const char *text = lua_tostring(LuaState, -1);
|
||||
ReportConsolef(text);
|
||||
lua_pop(LuaState, 1);
|
||||
}
|
||||
} else {
|
||||
const char *error_message = lua_tostring(LuaState, -1);
|
||||
ReportWarningf("Failed to load user config! %s", error_message);
|
||||
lua_pop(LuaState, 1);
|
||||
}
|
||||
lua_buffer->user_change_id = lua_buffer->change_id;
|
||||
}
|
||||
|
||||
API void ReloadLuaConfigs(bool reload) {
|
||||
if (LuaConfigBuffer && !LuaConfigBuffer->dirty && LuaConfigBuffer->change_id != LuaConfigBuffer->user_change_id) {
|
||||
reload = true;
|
||||
}
|
||||
if (LuaProjectBuffer && !LuaProjectBuffer->dirty && LuaProjectBuffer->change_id != LuaProjectBuffer->user_change_id) {
|
||||
reload = true;
|
||||
}
|
||||
if (reload == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
LoadLuaBuffer(LuaConfigBuffer);
|
||||
LoadLuaBuffer(LuaProjectBuffer);
|
||||
|
||||
ReloadStyle();
|
||||
ReloadFont(StyleFont, (U32)StyleFontSize);
|
||||
For(Windows) {
|
||||
it->draw_scrollbar = StyleDrawScrollbar;
|
||||
it->draw_line_numbers = StyleDrawLineNumbers;
|
||||
}
|
||||
}
|
||||
|
||||
API bool CallLuaFunc(char *func_name, int arg_count, int ret_count) {
|
||||
if (lua_pcall(LuaState, arg_count, ret_count, 0) != 0) {
|
||||
const char *error_message = lua_tostring(LuaState, -1);
|
||||
ReportWarningf("Failed to call a lua function: %s! %s", func_name, error_message);
|
||||
lua_pop(LuaState, 1);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CallLuaOnInit() {
|
||||
lua_getglobal(LuaState, "OnInit");
|
||||
CallLuaFunc("OnInit", 0, 0);
|
||||
}
|
||||
|
||||
API void InitLuaConfig() {
|
||||
LuaState = luaL_newstate();
|
||||
luaL_openlibs(LuaState);
|
||||
lua_sethook(LuaState, HookLuaForceExit, LUA_MASKCOUNT, 100000000);
|
||||
|
||||
for (int i = 0; LuaFunctions[i].name; i += 1) {
|
||||
lua_pushcfunction(LuaState, LuaFunctions[i].func);
|
||||
lua_setglobal(LuaState, LuaFunctions[i].name);
|
||||
}
|
||||
|
||||
#if OS_WINDOWS
|
||||
lua_pushinteger(LuaState, 0);
|
||||
#else
|
||||
lua_pushinteger(LuaState, 1);
|
||||
#endif
|
||||
lua_setglobal(LuaState, "OS_VALUE");
|
||||
|
||||
// Init base config, test that it works and initialize the lua stuff
|
||||
if (!luaL_dostring(LuaState, BaseLuaConfig.data) == LUA_OK) {
|
||||
const char *error_message = lua_tostring(LuaState, -1);
|
||||
ReportErrorf("Failed to load base lua config! %s", error_message);
|
||||
lua_pop(LuaState, 1);
|
||||
Assert(!"Invalid codepath");
|
||||
}
|
||||
|
||||
// Init user config
|
||||
Buffer *lua_buffer = NULL;
|
||||
|
||||
Scratch scratch;
|
||||
String lua_config_exe = Format(scratch, "%S/init.lua", GetExeDir(scratch));
|
||||
if (FileExists(lua_config_exe)) {
|
||||
lua_buffer = BufferOpenFile(lua_config_exe);
|
||||
}
|
||||
|
||||
if (lua_buffer == NULL) {
|
||||
String lua_config_remote = Format(scratch, "%S/init.lua", ConfigDir);
|
||||
// #if DEBUG_BUILD
|
||||
// // WARNING! Delete config to make sure we are running this code more frequently
|
||||
// SDL_RemovePath(lua_config_remote.data);
|
||||
// ReportConsolef("deleting config for debug purposes!");
|
||||
// #endif
|
||||
lua_buffer = BufferOpenFile(lua_config_remote);
|
||||
if (lua_buffer->len == 0) {
|
||||
String16 string16 = ToString16(scratch, BaseLuaConfig);
|
||||
RawReplaceText(lua_buffer, {}, string16);
|
||||
ReportConsolef("no config at: %S - creating config buffer", lua_config_remote);
|
||||
}
|
||||
}
|
||||
LuaConfigBuffer = lua_buffer;
|
||||
ReloadLuaConfigs(true);
|
||||
CallLuaOnInit();
|
||||
}
|
||||
10
src/text_editor/lua.h
Normal file
10
src/text_editor/lua.h
Normal file
@@ -0,0 +1,10 @@
|
||||
API double GetStyleFloat(String name, double default_float);
|
||||
API Int GetStyleInt(String name, Int default_int);
|
||||
API String GetStyleString(String name, String default_string);
|
||||
API Color GetColor(String name, Color default_color);
|
||||
API String GetFieldString(lua_State *L, String name);
|
||||
API int Lua_Play(lua_State *L);
|
||||
API void LoadLuaBuffer(Buffer *lua_buffer);
|
||||
API void ReloadLuaConfigs(bool reload = false);
|
||||
API bool CallLuaFunc(char *func_name, int arg_count, int ret_count);
|
||||
API void InitLuaConfig();
|
||||
@@ -4,9 +4,9 @@ int Lua_print(lua_State *L) {
|
||||
View *null_view = GetView(NullViewID);
|
||||
for (int i = 1; i <= nargs; i += 1) {
|
||||
String string = lua_tostring(L, i);
|
||||
Command_Appendf(null_view, "%S ", string);
|
||||
Appendf(null_view, "%S ", string);
|
||||
}
|
||||
Command_Appendf(null_view, "\n");
|
||||
Appendf(null_view, "\n");
|
||||
lua_pop(L, nargs);
|
||||
return 0;
|
||||
}
|
||||
@@ -16,21 +16,15 @@ int Lua_Print(lua_State *L) {
|
||||
int nargs = lua_gettop(L);
|
||||
for (int i = 1; i <= nargs; i += 1) {
|
||||
String string = lua_tostring(L, i);
|
||||
Command_Appendf(TraceView, "%S ", string);
|
||||
Appendf(TraceView, "%S ", string);
|
||||
}
|
||||
Command_Appendf(TraceView, "\n");
|
||||
Appendf(TraceView, "\n");
|
||||
lua_pop(L, nargs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Lua_Kill(lua_State *L) {
|
||||
BSet main = GetActiveMainSet();
|
||||
KillProcess(main.view);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Lua_GetLoadWord(lua_State *L) {
|
||||
BSet active = GetActiveSet();
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
Range range = active.view->carets[0].range;
|
||||
if (GetSize(range) == 0) {
|
||||
range = EncloseLoadWord(active.buffer, range.min);
|
||||
@@ -52,7 +46,7 @@ int Lua_BufferExists(lua_State *L) {
|
||||
|
||||
int Lua_GetSelection(lua_State *L) {
|
||||
Scratch scratch;
|
||||
BSet main = GetActiveMainSet();
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
String16 string16 = GetString(main.buffer, main.view->carets[0].range);
|
||||
String string = ToString(scratch, string16);
|
||||
lua_pushlstring(L, string.data, string.len);
|
||||
@@ -61,7 +55,7 @@ int Lua_GetSelection(lua_State *L) {
|
||||
|
||||
int Lua_GetEntireBuffer(lua_State *L) {
|
||||
Scratch scratch;
|
||||
BSet main = GetActiveMainSet();
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
String16 string16 = GetString(main.buffer);
|
||||
String string = ToString(scratch, string16);
|
||||
lua_pushlstring(L, string.data, string.len);
|
||||
@@ -76,13 +70,13 @@ int Lua_GetClipboard(lua_State *L) {
|
||||
}
|
||||
|
||||
int Lua_GetFilename(lua_State *L) {
|
||||
BSet main = GetActiveMainSet();
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
lua_pushlstring(L, main.buffer->name.data, main.buffer->name.len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Lua_GetLine(lua_State *L) {
|
||||
BSet main = GetActiveMainSet();
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
Caret caret = main.view->carets[0];
|
||||
Int front = GetFront(caret);
|
||||
Int line = PosToLine(main.buffer, front);
|
||||
@@ -111,211 +105,11 @@ int Lua_GetExeDir(lua_State *L) {
|
||||
}
|
||||
|
||||
int Lua_GetMainDir(lua_State *L) {
|
||||
String name = Command_GetMainDir();
|
||||
String name = GetMainDir();
|
||||
lua_pushlstring(L, name.data, name.len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Lua_SplitSize(lua_State *L) {
|
||||
lua_Number num = lua_tonumber(L, 1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
BSet set = GetActiveMainSet();
|
||||
WindowSplit *split = set.window->split_ref;
|
||||
split->parent->value = num;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Lua_KillWindow(lua_State *L) {
|
||||
BSet set = GetActiveMainSet();
|
||||
set.window->kill = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void HookLuaForceExit(lua_State *L, lua_Debug *debug) {
|
||||
SDL_PumpEvents();
|
||||
int numkeys = 0;
|
||||
const bool *keys = SDL_GetKeyboardState(&numkeys);
|
||||
if (keys[SDL_SCANCODE_F9])
|
||||
luaL_error(L, "lua execution got interrupted");
|
||||
}
|
||||
|
||||
Int GetStyleInt(String name, Int default_int) {
|
||||
Int result = default_int;
|
||||
lua_getglobal(LuaState, "Style");
|
||||
defer { lua_pop(LuaState, 1); };
|
||||
if (lua_istable(LuaState, -1)) {
|
||||
lua_pushlstring(LuaState, name.data, name.len);
|
||||
lua_gettable(LuaState, -2);
|
||||
defer { lua_pop(LuaState, 1); };
|
||||
if (lua_isnumber(LuaState, -1) || lua_isboolean(LuaState, -1) || lua_isinteger(LuaState, -1)) {
|
||||
lua_Integer num = lua_tointeger(LuaState, -1);
|
||||
result = (Int)num;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String GetStyleString(String name, String default_string) {
|
||||
String result = default_string;
|
||||
lua_getglobal(LuaState, "Style");
|
||||
defer { lua_pop(LuaState, 1); };
|
||||
if (lua_istable(LuaState, -1)) {
|
||||
lua_pushlstring(LuaState, name.data, name.len);
|
||||
lua_gettable(LuaState, -2);
|
||||
defer { lua_pop(LuaState, 1); };
|
||||
if (lua_isstring(LuaState, -1)) {
|
||||
const char *string = lua_tostring(LuaState, -1);
|
||||
result = Intern(&GlobalInternTable, string);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Color GetColor(String name, Color default_color) {
|
||||
Color result = default_color;
|
||||
lua_getglobal(LuaState, "Color");
|
||||
defer { lua_pop(LuaState, 1); };
|
||||
if (lua_istable(LuaState, -1)) {
|
||||
lua_pushlstring(LuaState, name.data, name.len);
|
||||
lua_gettable(LuaState, -2);
|
||||
defer { lua_pop(LuaState, 1); };
|
||||
if (lua_isnumber(LuaState, -1)) {
|
||||
lua_Integer num = lua_tointeger(LuaState, -1);
|
||||
result.r = (uint8_t)((0xFF000000 & num) >> 24);
|
||||
result.g = (uint8_t)((0x00FF0000 & num) >> 16);
|
||||
result.b = (uint8_t)((0x0000FF00 & num) >> 8);
|
||||
result.a = (uint8_t)((0x000000FF & num) >> 0);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String GetFieldString(lua_State *L, String name) {
|
||||
String result = {};
|
||||
if (lua_istable(L, -1)) {
|
||||
lua_pushlstring(L, name.data, name.len);
|
||||
lua_gettable(L, -2);
|
||||
defer { lua_pop(L, 1); };
|
||||
if (lua_isstring(L, -1)) {
|
||||
result = lua_tostring(L, -1);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Int GetInt(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 GetFloat(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 *GetString(lua_State *L, const char *name) {
|
||||
lua_getfield(L, -1, name);
|
||||
const char *result = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
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
|
||||
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)Get##KIND(L, #NAME);
|
||||
EVENT_FIELDS
|
||||
#undef X
|
||||
Add(&EventPlayback, event);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ReloadStyle();
|
||||
extern String BaseLuaConfig;
|
||||
|
||||
void LoadLuaBuffer(Buffer *lua_buffer) {
|
||||
if (!lua_buffer) return;
|
||||
ReportConsolef("reloading config: %S", lua_buffer->name);
|
||||
|
||||
Scratch scratch;
|
||||
String string = AllocCharString(scratch, lua_buffer);
|
||||
if (luaL_dostring(LuaState, string.data) == LUA_OK) {
|
||||
if (lua_isstring(LuaState, -1)) {
|
||||
const char *text = lua_tostring(LuaState, -1);
|
||||
ReportConsolef(text);
|
||||
lua_pop(LuaState, 1);
|
||||
}
|
||||
} else {
|
||||
const char *error_message = lua_tostring(LuaState, -1);
|
||||
ReportWarningf("Failed to load user config! %s", error_message);
|
||||
lua_pop(LuaState, 1);
|
||||
}
|
||||
lua_buffer->user_change_id = lua_buffer->change_id;
|
||||
}
|
||||
|
||||
void ReloadLuaConfigs(bool reload = false) {
|
||||
if (LuaConfigBuffer && !LuaConfigBuffer->dirty && LuaConfigBuffer->change_id != LuaConfigBuffer->user_change_id) {
|
||||
reload = true;
|
||||
}
|
||||
if (LuaProjectBuffer && !LuaProjectBuffer->dirty && LuaProjectBuffer->change_id != LuaProjectBuffer->user_change_id) {
|
||||
reload = true;
|
||||
}
|
||||
if (reload == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
LoadLuaBuffer(LuaConfigBuffer);
|
||||
LoadLuaBuffer(LuaProjectBuffer);
|
||||
|
||||
ReloadStyle();
|
||||
ReloadFont();
|
||||
for (Window *it = FirstWindow; it; it = it->next) {
|
||||
if (it->is_title_bar || it->is_search_bar) {
|
||||
continue;
|
||||
}
|
||||
it->draw_scrollbar = StyleDrawScrollbar;
|
||||
it->draw_line_numbers = StyleDrawLineNumbers;
|
||||
}
|
||||
}
|
||||
|
||||
bool CallLuaFunc(char *func_name, int arg_count, int ret_count) {
|
||||
if (lua_pcall(LuaState, arg_count, ret_count, 0) != 0) {
|
||||
const char *error_message = lua_tostring(LuaState, -1);
|
||||
ReportWarningf("Failed to call a lua function: %s! %s", func_name, error_message);
|
||||
lua_pop(LuaState, 1);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct OnOpenResult {
|
||||
String kind;
|
||||
String file_path;
|
||||
@@ -344,7 +138,7 @@ OnOpenResult CallOnOpen(Allocator allocator, String path, String meta) {
|
||||
result.working_dir = working_dir;
|
||||
result.file_path = file_path;
|
||||
if (!IsAbsolute(result.file_path)) {
|
||||
String dir = Command_GetMainDir();
|
||||
String dir = GetMainDir();
|
||||
result.file_path = Format(allocator, "%S/%S", dir, result.file_path);
|
||||
}
|
||||
if (col_string.len) {
|
||||
@@ -396,65 +190,3 @@ void CallLuaOnUpdate(Event *event) {
|
||||
PushEvent(LuaState, event);
|
||||
CallLuaFunc("OnUpdate", 1, 0);
|
||||
}
|
||||
|
||||
void CallLuaOnInit() {
|
||||
lua_getglobal(LuaState, "OnInit");
|
||||
CallLuaFunc("OnInit", 0, 0);
|
||||
}
|
||||
|
||||
void InitLuaConfig() {
|
||||
LuaState = luaL_newstate();
|
||||
luaL_openlibs(LuaState);
|
||||
lua_sethook(LuaState, HookLuaForceExit, LUA_MASKCOUNT, 100000000);
|
||||
|
||||
for (int i = 0; LuaFunctions[i].name; i += 1) {
|
||||
lua_pushcfunction(LuaState, LuaFunctions[i].func);
|
||||
lua_setglobal(LuaState, LuaFunctions[i].name);
|
||||
}
|
||||
|
||||
#if OS_WINDOWS
|
||||
lua_pushinteger(LuaState, 0);
|
||||
#else
|
||||
lua_pushinteger(LuaState, 1);
|
||||
#endif
|
||||
lua_setglobal(LuaState, "OS_VALUE");
|
||||
|
||||
// Init base config, test that it works and initialize the lua stuff
|
||||
if (!luaL_dostring(LuaState, BaseLuaConfig.data) == LUA_OK) {
|
||||
const char *error_message = lua_tostring(LuaState, -1);
|
||||
ReportErrorf("Failed to load base lua config! %s", error_message);
|
||||
lua_pop(LuaState, 1);
|
||||
Assert(!"Invalid codepath");
|
||||
}
|
||||
|
||||
// Init user config
|
||||
Buffer *lua_buffer = NULL;
|
||||
|
||||
Scratch scratch;
|
||||
String lua_config_exe = Format(scratch, "%S/init.lua", GetExeDir(scratch));
|
||||
if (FileExists(lua_config_exe)) {
|
||||
lua_buffer = BufferOpenFile(lua_config_exe);
|
||||
}
|
||||
|
||||
if (lua_buffer == NULL) {
|
||||
String lua_config_remote = Format(scratch, "%S/init.lua", ConfigDir);
|
||||
// #if DEBUG_BUILD
|
||||
// // WARNING! Delete config to make sure we are running this code more frequently
|
||||
// SDL_RemovePath(lua_config_remote.data);
|
||||
// ReportConsolef("deleting config for debug purposes!");
|
||||
// #endif
|
||||
lua_buffer = BufferOpenFile(lua_config_remote);
|
||||
if (lua_buffer->len == 0) {
|
||||
String16 string16 = ToString16(scratch, BaseLuaConfig);
|
||||
RawReplaceText(lua_buffer, {}, string16);
|
||||
ReportConsolef("no config at: %S - creating config buffer", lua_config_remote);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
LuaConfigBuffer = lua_buffer;
|
||||
ReloadLuaConfigs(true);
|
||||
CallLuaOnInit();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ luaL_Reg LuaFunctions[] = {
|
||||
{"print", Lua_print},
|
||||
{"Print", Lua_Print},
|
||||
{"SaveAll", Lua_SaveAll},
|
||||
{"Kill", Lua_Kill},
|
||||
{"KillProcess", Lua_KillProcess},
|
||||
{"GetLoadWord", Lua_GetLoadWord},
|
||||
{"BufferExists", Lua_BufferExists},
|
||||
{"GetSelection", Lua_GetSelection},
|
||||
@@ -14,7 +14,6 @@ luaL_Reg LuaFunctions[] = {
|
||||
{"GetWorkDir", Lua_GetWorkDir},
|
||||
{"GetExeDir", Lua_GetExeDir},
|
||||
{"GetMainDir", Lua_GetMainDir},
|
||||
{"SplitSize", Lua_SplitSize},
|
||||
{"KillWindow", Lua_KillWindow},
|
||||
{"Play", Lua_Play},
|
||||
{"TrimTrailingWhitespace", Lua_TrimTrailingWhitespace},
|
||||
@@ -30,13 +29,11 @@ luaL_Reg LuaFunctions[] = {
|
||||
{"C", Lua_C},
|
||||
{"Open", Lua_Open},
|
||||
{"Cmd", Lua_Cmd},
|
||||
{"ListBuffers", Lua_ListBuffers},
|
||||
{"ListViews", Lua_ListViews},
|
||||
{"Eval", Lua_Eval},
|
||||
{"SetProjectFile", Lua_SetProjectFile},
|
||||
{"SetWorkDir", Lua_SetWorkDir},
|
||||
{"ListCommands", Lua_ListCommands},
|
||||
{"GetBufferList", Lua_GetBufferList},
|
||||
{"Split", Lua_Split},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
@@ -1,277 +1,3 @@
|
||||
WindowID WindowIDs;
|
||||
ViewID ViewIDs;
|
||||
|
||||
Window *FirstWindow;
|
||||
Window *LastWindow;
|
||||
Int WindowCount;
|
||||
|
||||
View *FirstView;
|
||||
View *LastView;
|
||||
Int ViewCount;
|
||||
|
||||
Buffer *FirstBuffer;
|
||||
Buffer *LastBuffer;
|
||||
Int BufferCount;
|
||||
|
||||
// console
|
||||
BufferID NullBufferID;
|
||||
ViewID NullViewID;
|
||||
WindowID NullWindowID;
|
||||
|
||||
// hidden floating window
|
||||
WindowID DebugWindowID;
|
||||
ViewID DebugViewID;
|
||||
BufferID DebugBufferID;
|
||||
|
||||
WindowSplit WindowSplits;
|
||||
WindowID ActiveWindow;
|
||||
|
||||
WindowSplit *ResizerSelected = NULL;
|
||||
WindowSplit *ResizerHover = NULL;
|
||||
WindowID ScrollbarSelected = {-1};
|
||||
WindowID DocumentSelected = {-1};
|
||||
Caret DocumentAnchor;
|
||||
|
||||
Buffer *LuaProjectBuffer;
|
||||
Buffer *LuaConfigBuffer;
|
||||
Buffer *GCInfoBuffer;
|
||||
Buffer *EventBuffer;
|
||||
Buffer *ScratchBuffer;
|
||||
Buffer *TraceBuffer;
|
||||
View *TraceView;
|
||||
|
||||
String WorkDir;
|
||||
RandomSeed UniqueBufferNameSeed = {};
|
||||
|
||||
// lua
|
||||
lua_State *LuaState = NULL;
|
||||
String16 LuaCommandResult = {};
|
||||
extern luaL_Reg LuaFunctions[];
|
||||
|
||||
// clipboard
|
||||
BlockArena ClipboardArena;
|
||||
String16 SavedClipboardString;
|
||||
Array<String16> SavedClipboardCarets = {SysAllocator};
|
||||
|
||||
|
||||
String GetUniqueBufferName(String working_dir, String prepend_name, String extension = ".log") {
|
||||
Scratch scratch;
|
||||
String buffer_name = {};
|
||||
for (int i = 1; i < INT_MAX; i += 1) {
|
||||
buffer_name = Format(scratch, "%S/%S%d%S", working_dir, prepend_name, i, extension);
|
||||
buffer_name = GetAbsolutePath(scratch, buffer_name);
|
||||
Buffer *exists = FindBuffer(buffer_name);
|
||||
if (!exists && !FileExists(buffer_name)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
buffer_name = Intern(&GlobalInternTable, buffer_name);
|
||||
return buffer_name;
|
||||
}
|
||||
|
||||
void InitBuffers() {
|
||||
Allocator sys_allocator = GetSystemAllocator();
|
||||
Scratch scratch;
|
||||
Buffer *null_buffer = CreateBuffer(sys_allocator, GetUniqueBufferName(GetWorkingDir(scratch), "console"));
|
||||
View *null_view = CreateView(null_buffer->id);
|
||||
Assert(null_buffer->id == NullBufferID && null_view->id == NullViewID);
|
||||
|
||||
TraceBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "trace"));
|
||||
TraceView = CreateView(TraceBuffer->id);
|
||||
GCInfoBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "gc"));
|
||||
EventBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "events"));
|
||||
ScratchBuffer = BufferOpenFile(GetUniqueBufferName(WorkDir, "scratch"));
|
||||
|
||||
EventBuffer->no_history = true;
|
||||
GCInfoBuffer->no_history = true;
|
||||
}
|
||||
|
||||
inline bool IsDocumentSelectionValid() {
|
||||
if (DocumentSelected.id == -1) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool IsScrollbarSelectionValid() {
|
||||
if (ScrollbarSelected.id == -1) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline ViewID AllocViewID(View *view) { return {ViewIDs.id++, view}; }
|
||||
inline WindowID AllocWindowID(Window *window) { return {WindowIDs.id++, window}; }
|
||||
inline BufferID AllocBufferID(Buffer *buffer) { return {BufferIDs++, buffer}; }
|
||||
|
||||
inline Window *GetWindow(WindowID id) {
|
||||
for (Window *it = FirstWindow; it; it = it->next) {
|
||||
if (it->id == id) return it;
|
||||
}
|
||||
return FirstWindow;
|
||||
}
|
||||
|
||||
inline Buffer *GetBuffer(BufferID id) {
|
||||
for (Buffer *it = FirstBuffer; it; it = it->next) {
|
||||
if (it->id == id) return it;
|
||||
}
|
||||
return FirstBuffer;
|
||||
}
|
||||
|
||||
inline Buffer *FindBuffer(BufferID id) {
|
||||
for (Buffer *it = FirstBuffer; it; it = it->next) {
|
||||
if (it->id == id) return it;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline Buffer *GetBuffer(String name) {
|
||||
for (Buffer *it = FirstBuffer; it; it = it->next) {
|
||||
if (it->name == name) return it;
|
||||
}
|
||||
return FirstBuffer;
|
||||
}
|
||||
|
||||
inline Buffer *FindBuffer(String name) {
|
||||
for (Buffer *it = FirstBuffer; it; it = it->next) {
|
||||
if (it->name == name) return it;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline View *GetView(ViewID id) {
|
||||
for (View *it = FirstView; it; it = it->next) {
|
||||
if (it->id == id) return it;
|
||||
}
|
||||
return FirstView;
|
||||
}
|
||||
|
||||
inline bool IsNull(Buffer *buffer) { return buffer->id.id == NullBufferID.id; }
|
||||
inline Window *GetActiveWind() { return GetWindow(ActiveWindow); }
|
||||
|
||||
Buffer *CreateBuffer(Allocator allocator, String name, Int size) {
|
||||
Buffer *result = AllocBuffer(allocator, name, size);
|
||||
DLL_QUEUE_ADD(FirstBuffer, LastBuffer, result);
|
||||
BufferCount += 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
Window *CreateWind(bool create_command_buffer = true) {
|
||||
Window *w = AllocType(SysAllocator, Window);
|
||||
w->font = &PrimaryFont;
|
||||
w->visible = true;
|
||||
w->draw_scrollbar = StyleDrawScrollbar;
|
||||
w->draw_line_numbers = StyleDrawLineNumbers;
|
||||
w->id = AllocWindowID(w);
|
||||
DLL_QUEUE_ADD(FirstWindow, LastWindow, w);
|
||||
WindowCount += 1;
|
||||
return w;
|
||||
}
|
||||
|
||||
// void DestroyWindow(Window *window) {
|
||||
// WindowSplit *split = window->split_ref;
|
||||
// if (split->parent == NULL) {
|
||||
// Assert(split->kind == WindowSplitKind_Window);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// WindowSplit *p = split->parent;
|
||||
// WindowSplit *valid_node = p->left == split ? p->right : p->left;
|
||||
// if (p->parent == NULL) {
|
||||
// // @todo:
|
||||
// } else {
|
||||
// valid_node->parent = p->parent;
|
||||
// *p = *valid_node;
|
||||
// }
|
||||
//
|
||||
// // @leak window
|
||||
// DLL_QUEUE_REMOVE(FirstWindow, LastWindow, window);
|
||||
// WindowCount -= 1;
|
||||
//
|
||||
// if (window->search_bar_window.id) {
|
||||
// Window *s = GetWindow(window->search_bar_window);
|
||||
// DLL_QUEUE_REMOVE(FirstWindow, LastWindow, s);
|
||||
// WindowCount -= 1;
|
||||
// }
|
||||
//
|
||||
// if (window->title_bar_window.id) {
|
||||
// Window *s = GetWindow(window->title_bar_window);
|
||||
// DLL_QUEUE_REMOVE(FirstWindow, LastWindow, s);
|
||||
// WindowCount -= 1;
|
||||
// }
|
||||
// }
|
||||
|
||||
View *CreateView(BufferID active_buffer) {
|
||||
Allocator al = GetSystemAllocator();
|
||||
View *view = AllocType(al, View);
|
||||
view->id = AllocViewID(view);
|
||||
view->active_buffer = active_buffer;
|
||||
view->carets.allocator = al;
|
||||
Add(&view->carets, {0, 0});
|
||||
DLL_QUEUE_ADD(FirstView, LastView, view);
|
||||
ViewCount += 1;
|
||||
return view;
|
||||
}
|
||||
|
||||
View *FindView(ViewID view_id, View *default_view = NULL) {
|
||||
for (View *it = FirstView; it; it = it->next) {
|
||||
if (it->id == view_id) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return default_view;
|
||||
}
|
||||
|
||||
View *FindView(BufferID buffer_id, View *default_view = NULL) {
|
||||
for (View *it = FirstView; it; it = it->next) {
|
||||
if (it->active_buffer == buffer_id) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return default_view;
|
||||
}
|
||||
|
||||
Window *FindWindow(ViewID view_id, Window *default_window = NULL) {
|
||||
for (Window *it = FirstWindow; it; it = it->next) {
|
||||
if (it->active_view == view_id) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return default_window;
|
||||
}
|
||||
|
||||
Window *FindWindow(String buffer_name, Window *default_window = NULL) {
|
||||
for (Window *it = FirstWindow; it; it = it->next) {
|
||||
View *it_view = GetView(it->active_view);
|
||||
Buffer *it_buffer = GetBuffer(it_view->active_buffer);
|
||||
if (it_buffer->name == buffer_name) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return default_window;
|
||||
}
|
||||
|
||||
Window *FindWindow(BufferID buffer_id) {
|
||||
for (Window *it = FirstWindow; it; it = it->next) {
|
||||
View *view = GetView(it->active_view);
|
||||
if (view->active_buffer == buffer_id) return it;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
View *FindView(String name, View *default_view = NULL) {
|
||||
for (View *it = FirstView; it; it = it->next) {
|
||||
Buffer *buffer = GetBuffer(it->active_buffer);
|
||||
if (buffer->name == name) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return default_view;
|
||||
}
|
||||
|
||||
Window *GetTitlebarWindow(WindowID id) {
|
||||
Window *window = GetWindow(id);
|
||||
if (!window->is_title_bar) window = GetWindow(window->title_bar_window);
|
||||
Assert(window->is_title_bar);
|
||||
return window;
|
||||
}
|
||||
|
||||
BSet GetBSet(Window *window) {
|
||||
BSet set = {window};
|
||||
set.view = GetView(set.window->active_view);
|
||||
@@ -285,30 +11,6 @@ BSet GetBSet(WindowID window_id) {
|
||||
return result;
|
||||
}
|
||||
|
||||
BSet GetTitleSet(Window *window) {
|
||||
if (!window->is_title_bar) window = GetWindow(window->title_bar_window);
|
||||
BSet result = GetBSet(window);
|
||||
return result;
|
||||
}
|
||||
|
||||
BSet GetMainSet(Window *window) {
|
||||
if (window->is_title_bar) window = GetWindow(window->title_bar_window);
|
||||
BSet result = GetBSet(window);
|
||||
return result;
|
||||
}
|
||||
|
||||
BSet GetActiveSet() {
|
||||
Window *window = GetWindow(ActiveWindow);
|
||||
return GetBSet(window);
|
||||
}
|
||||
|
||||
BSet GetActiveMainSet() {
|
||||
Window *window = GetWindow(ActiveWindow);
|
||||
if (window->is_title_bar) window = GetWindow(window->title_bar_window);
|
||||
if (window->is_search_bar) window = GetWindow(window->search_bar_window);
|
||||
return GetBSet(window);
|
||||
}
|
||||
|
||||
BSet GetConsoleSet() {
|
||||
BSet result = {};
|
||||
result.window = GetWindow(NullWindowID);
|
||||
@@ -317,15 +19,9 @@ BSet GetConsoleSet() {
|
||||
return result;
|
||||
}
|
||||
|
||||
BSet GetActiveTitleSet() {
|
||||
Window *window = GetWindow(ActiveWindow);
|
||||
if (!window->is_title_bar) window = GetWindow(window->title_bar_window);
|
||||
return GetBSet(window);
|
||||
}
|
||||
|
||||
String Command_GetFilename() {
|
||||
BSet set = GetActiveMainSet();
|
||||
return set.buffer->name;
|
||||
String GetCurrentFilename() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
return main.buffer->name;
|
||||
}
|
||||
|
||||
String GetDir(Buffer *buffer) {
|
||||
@@ -333,156 +29,36 @@ String GetDir(Buffer *buffer) {
|
||||
return name;
|
||||
}
|
||||
|
||||
String Command_GetMainDir() {
|
||||
BSet set = GetActiveMainSet();
|
||||
String name = ChopLastSlash(set.buffer->name);
|
||||
String GetMainDir() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
String name = ChopLastSlash(main.buffer->name);
|
||||
return name;
|
||||
}
|
||||
|
||||
Int ConvertUTF8ToUTF16UnixLine(String string, char16_t *buffer, Int buffer_cap) {
|
||||
if (string.len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Int buffer_len = 0;
|
||||
Assert(buffer_cap > string.len * 2);
|
||||
for (Int i = 0; i < string.len;) {
|
||||
if (string.data[i] == '\r') {
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if (string.data[i] == '\t') {
|
||||
// @WARNING: DONT INCREASE THE SIZE CARELESSLY, WE NEED TO ADJUST BUFFER SIZE
|
||||
for (Int i = 0; i < 4; i += 1) buffer[buffer_len++] = u' ';
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t u32 = '?';
|
||||
UTF32Result decode = UTF8ToUTF32((uint8_t *)(string.data + i), (int64_t)(string.len - i));
|
||||
if (!decode.error) {
|
||||
i += decode.advance;
|
||||
u32 = decode.out_str;
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
UTF16Result encode = UTF32ToUTF16(u32);
|
||||
if (!encode.error) {
|
||||
for (int64_t encode_i = 0; encode_i < encode.len; encode_i += 1) {
|
||||
buffer[buffer_len++] = encode.out_str[encode_i];
|
||||
Assert(buffer_len < buffer_cap);
|
||||
}
|
||||
} else {
|
||||
buffer[buffer_len++] = u'?';
|
||||
}
|
||||
}
|
||||
return buffer_len;
|
||||
}
|
||||
|
||||
String16 ToUnixString16(Allocator allocator, String string_) {
|
||||
Int cap = string_.len * 3;
|
||||
char16_t *string16_buffer = AllocArray(allocator, char16_t, cap);
|
||||
Int len = ConvertUTF8ToUTF16UnixLine(string_, string16_buffer, cap);
|
||||
String16 string = {string16_buffer, len};
|
||||
return string;
|
||||
}
|
||||
|
||||
Buffer *BufferOpenFile(String path) {
|
||||
Allocator sys_allocator = GetSystemAllocator();
|
||||
Scratch scratch;
|
||||
|
||||
path = GetAbsolutePath(scratch, path);
|
||||
Buffer *buffer = GetBuffer(path);
|
||||
if (!IsNull(buffer) || (IsNull(buffer) && buffer->name == path)) {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
if (!FileExists(path)) {
|
||||
buffer = CreateBuffer(sys_allocator, path);
|
||||
} else if (IsDir(path)) {
|
||||
ReportWarningf("failed to open, it's a directory: %S", path);
|
||||
return GetBuffer(NullBufferID);
|
||||
} else {
|
||||
String string = ReadFile(scratch, path);
|
||||
buffer = CreateBuffer(sys_allocator, path, string.len * 4 + 4096);
|
||||
buffer->len = ConvertUTF8ToUTF16UnixLine(string, buffer->str, buffer->cap);
|
||||
buffer->file_mod_time = GetFileModTime(path);
|
||||
UpdateLines(buffer, {}, String16{(char16_t *)buffer->data, buffer->len});
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
View *OpenBufferView(String name) {
|
||||
Buffer *buffer = BufferOpenFile(name);
|
||||
View *view = CreateView(buffer->id);
|
||||
return view;
|
||||
}
|
||||
|
||||
View *WindowOpenBufferView(Window *new_parent_window, String name) {
|
||||
View *view = FindView(name);
|
||||
if (!view) {
|
||||
View *result = OpenBufferView(name);
|
||||
new_parent_window->active_view = result->id;
|
||||
return result;
|
||||
}
|
||||
|
||||
Window *window = FindWindow(view->id);
|
||||
if (!window) {
|
||||
new_parent_window->active_view = view->id;
|
||||
return view;
|
||||
}
|
||||
if (window == new_parent_window) {
|
||||
return view;
|
||||
}
|
||||
|
||||
Assert(window->active_view.id == view->id.id);
|
||||
View *result = OpenBufferView(name);
|
||||
new_parent_window->active_view = result->id;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ViewIsCrumb(ViewID view_id) {
|
||||
for (Window *window = FirstWindow; window; window = window->next) {
|
||||
For(window->goto_history) if (it.view_id == view_id) return true;
|
||||
For(window->goto_redo) if (it.view_id == view_id) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ViewIsReferenced(ViewID view) {
|
||||
if (view == NullViewID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ViewIsCrumb(view)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (Window *it = FirstWindow; it; it = it->next) {
|
||||
if (it->active_view == view || it->active_goto_list == view) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BufferIsReferenced(BufferID buffer_id) {
|
||||
if (buffer_id == NullBufferID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (FindView(buffer_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GarbageCollect() {
|
||||
Allocator sys_allocator = GetSystemAllocator();
|
||||
for (Buffer *it = FirstBuffer; it; it = it->next) {
|
||||
|
||||
|
||||
ActiveWindowID = NextActiveWindowID;
|
||||
|
||||
For (Windows) {
|
||||
if (it->sync_visibility_with_focus) {
|
||||
if (it->id == ActiveWindowID) {
|
||||
it->visible = true;
|
||||
} else {
|
||||
it->visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ActiveWindowID.id != LastActiveLayoutWindowID.id) {
|
||||
Window *window = GetWindow(ActiveWindowID);
|
||||
if (window->layout) {
|
||||
LastActiveLayoutWindowID = ActiveWindowID;
|
||||
}
|
||||
}
|
||||
|
||||
For(Buffers) {
|
||||
if (it->file_mod_time) {
|
||||
int64_t new_file_mod_time = GetFileModTime(it->name);
|
||||
if (it->file_mod_time != new_file_mod_time) {
|
||||
@@ -492,8 +68,8 @@ void GarbageCollect() {
|
||||
}
|
||||
}
|
||||
|
||||
for (View *it = FirstView, *next = NULL; it; it = next) {
|
||||
next = it->next;
|
||||
IterRemove(Views) {
|
||||
IterRemovePrepare(Views);
|
||||
|
||||
Buffer *buffer = GetBuffer(it->active_buffer);
|
||||
if (!buffer->garbage) {
|
||||
@@ -505,13 +81,13 @@ void GarbageCollect() {
|
||||
continue;
|
||||
}
|
||||
|
||||
DLL_QUEUE_REMOVE(FirstView, LastView, it);
|
||||
remove_item = true;
|
||||
Dealloc(&it->carets);
|
||||
Dealloc(sys_allocator, it);
|
||||
}
|
||||
|
||||
for (Buffer *it = FirstBuffer, *next = NULL; it; it = next) {
|
||||
next = it->next;
|
||||
IterRemove(Buffers) {
|
||||
IterRemovePrepare(Buffers);
|
||||
|
||||
if (!it->garbage) {
|
||||
continue;
|
||||
@@ -522,14 +98,17 @@ void GarbageCollect() {
|
||||
continue;
|
||||
}
|
||||
|
||||
DLL_QUEUE_REMOVE(FirstBuffer, LastBuffer, it);
|
||||
remove_item = true;
|
||||
DeallocBuffer(it);
|
||||
}
|
||||
|
||||
// for (Window *it = FirstWindow, *next = NULL; it; it = next) {
|
||||
// next = it->next;
|
||||
// if (it->kill) {
|
||||
// DestroyWindow(it);
|
||||
// }
|
||||
// }
|
||||
IterRemove(Windows) {
|
||||
IterRemovePrepare(Windows);
|
||||
if (it->kill) {
|
||||
Dealloc(&it->goto_history);
|
||||
Dealloc(&it->goto_redo);
|
||||
Dealloc(sys_allocator, it);
|
||||
remove_item = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ void UpdateProcesses() {
|
||||
|
||||
String poll = PollStdout(scratch, &it, false);
|
||||
if (poll.len) {
|
||||
Command_Append(view, poll, it.scroll_to_end);
|
||||
Append(view, poll, it.scroll_to_end);
|
||||
}
|
||||
if (!IsValid(&it)) {
|
||||
ReportDebugf("process %lld exit code = %d", it.id, it.exit_code);
|
||||
@@ -60,7 +60,7 @@ void KillProcess(View *view) {
|
||||
KillProcess(&it);
|
||||
remove_item = true;
|
||||
String string = "process was killed by user\n";
|
||||
Command_Append(view, string, it.scroll_to_end);
|
||||
Append(view, string, it.scroll_to_end);
|
||||
// dont break because that will fuck with removal ...
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,24 +12,22 @@
|
||||
#define LUA_USE_LONGJMP
|
||||
#include "external/luaunity.c"
|
||||
|
||||
SDL_Window *SDLWindow;
|
||||
bool IsInFullscreen;
|
||||
int FullScreenSizeX, FullScreenSizeY;
|
||||
int FullScreenPositionX, FullScreenPositionY;
|
||||
bool Testing = true;
|
||||
|
||||
#include "generated_variables.cpp"
|
||||
#include "render/generated_font.cpp"
|
||||
#include "render/font.cpp"
|
||||
#include "render/opengl.cpp"
|
||||
|
||||
#include "buffer.h"
|
||||
#include "view.h"
|
||||
#include "window.h"
|
||||
#include "text_editor.h"
|
||||
#include "intern_table.cpp"
|
||||
#include "buffer.cpp"
|
||||
#include "lua.h"
|
||||
|
||||
#include "management.cpp"
|
||||
#include "globals.cpp"
|
||||
#include "lua.cpp"
|
||||
#include "buffer.cpp"
|
||||
#include "view.cpp"
|
||||
#include "window.cpp"
|
||||
#include "management.cpp"
|
||||
#include "process.cpp"
|
||||
#include "event.cpp"
|
||||
|
||||
@@ -41,119 +39,11 @@ bool Testing = true;
|
||||
|
||||
#include "lua_api_generated.cpp"
|
||||
#include "generated_config.cpp"
|
||||
#include "generated.cpp"
|
||||
|
||||
#include "window_draw.cpp"
|
||||
#include "draw.cpp"
|
||||
#include "coroutines.cpp"
|
||||
#include "test/tests.cpp"
|
||||
|
||||
void FillEventWithBasicData(Event *event) {
|
||||
SDL_Keymod mod = SDL_GetModState();
|
||||
event->shift = (mod & SDL_KMOD_SHIFT) != 0;
|
||||
event->ctrl = (mod & SDL_KMOD_CTRL) != 0;
|
||||
event->alt = (mod & SDL_KMOD_ALT) != 0;
|
||||
event->super = (mod & SDL_KMOD_GUI) != 0;
|
||||
|
||||
float xmouse, ymouse;
|
||||
SDL_GetMouseState(&xmouse, &ymouse);
|
||||
event->xmouse = (int16_t)xmouse;
|
||||
event->ymouse = (int16_t)ymouse;
|
||||
|
||||
int xwindow, ywindow;
|
||||
SDL_GetWindowSize(SDLWindow, &xwindow, &ywindow);
|
||||
event->xwindow = xwindow;
|
||||
event->ywindow = ywindow;
|
||||
event->text = "";
|
||||
}
|
||||
|
||||
Event TranslateSDLEvent(SDL_Event *input_event) {
|
||||
ProfileFunction();
|
||||
Event event = {};
|
||||
FillEventWithBasicData(&event);
|
||||
|
||||
switch (input_event->type) {
|
||||
case SDL_EVENT_QUIT: {
|
||||
event.kind = EVENT_QUIT;
|
||||
} break;
|
||||
|
||||
case SDL_EVENT_KEY_DOWN: {
|
||||
event.kind = EVENT_KEY_PRESS;
|
||||
SDL_KeyboardEvent &key = input_event->key;
|
||||
event.key = key.key;
|
||||
} break;
|
||||
|
||||
case SDL_EVENT_TEXT_INPUT: {
|
||||
event.kind = EVENT_TEXT_INPUT;
|
||||
SDL_TextInputEvent &b = input_event->text;
|
||||
String string = b.text;
|
||||
event.text = Intern(&GlobalInternTable, string).data;
|
||||
} break;
|
||||
|
||||
case SDL_EVENT_MOUSE_BUTTON_DOWN: {
|
||||
SDL_MouseButtonEvent &b = input_event->button;
|
||||
event.xmouse = (int16_t)b.x;
|
||||
event.ymouse = (int16_t)b.y;
|
||||
event.clicks = b.clicks;
|
||||
if (b.button == SDL_BUTTON_LEFT) {
|
||||
event.kind = EVENT_MOUSE_LEFT;
|
||||
} else if (b.button == SDL_BUTTON_RIGHT) {
|
||||
event.kind = EVENT_MOUSE_RIGHT;
|
||||
} else if (b.button == SDL_BUTTON_MIDDLE) {
|
||||
event.kind = EVENT_MOUSE_MIDDLE;
|
||||
} else if (b.button == SDL_BUTTON_X1) {
|
||||
event.kind = EVENT_MOUSE_X1;
|
||||
} else if (b.button == SDL_BUTTON_X2) {
|
||||
event.kind = EVENT_MOUSE_X2;
|
||||
} else {
|
||||
event.kind = EVENT_NONE;
|
||||
event.clicks = 0;
|
||||
}
|
||||
} break;
|
||||
|
||||
case SDL_EVENT_MOUSE_BUTTON_UP: {
|
||||
SDL_MouseButtonEvent &b = input_event->button;
|
||||
event.xmouse = (int16_t)b.x;
|
||||
event.ymouse = (int16_t)b.y;
|
||||
if (b.button == SDL_BUTTON_LEFT) {
|
||||
event.kind = EVENT_MOUSE_LEFT_UP;
|
||||
} else if (b.button == SDL_BUTTON_RIGHT) {
|
||||
event.kind = EVENT_MOUSE_RIGHT_UP;
|
||||
} else if (b.button == SDL_BUTTON_MIDDLE) {
|
||||
event.kind = EVENT_MOUSE_MIDDLE_UP;
|
||||
} else if (b.button == SDL_BUTTON_X1) {
|
||||
event.kind = EVENT_MOUSE_X1_UP;
|
||||
} else if (b.button == SDL_BUTTON_X2) {
|
||||
event.kind = EVENT_MOUSE_X2_UP;
|
||||
} else {
|
||||
event.kind = EVENT_NONE;
|
||||
}
|
||||
} break;
|
||||
|
||||
case SDL_EVENT_MOUSE_WHEEL: {
|
||||
event.kind = EVENT_MOUSE_WHEEL;
|
||||
SDL_MouseWheelEvent &b = input_event->wheel;
|
||||
event.xmouse = (int16_t)b.mouse_x;
|
||||
event.ymouse = (int16_t)b.mouse_y;
|
||||
event.xwheel = b.x;
|
||||
event.ywheel = b.y;
|
||||
} break;
|
||||
|
||||
case SDL_EVENT_MOUSE_MOTION: {
|
||||
event.kind = EVENT_UPDATE;
|
||||
} break;
|
||||
|
||||
case SDL_EVENT_DROP_FILE: {
|
||||
event.kind = EVENT_DROP_FILE;
|
||||
SDL_DropEvent &b = input_event->drop;
|
||||
String string = b.data;
|
||||
event.text = Intern(&GlobalInternTable, string).data;
|
||||
} break;
|
||||
default: {
|
||||
};
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
#if OS_WASM
|
||||
EM_JS(void, JS_SetMouseCursor, (const char *cursor_str), {
|
||||
@@ -194,12 +84,21 @@ void SetMouseCursor(Event event) {
|
||||
Array<Window *> order = GetWindowZOrder(scratch);
|
||||
Vec2I mouse = MouseVec2I();
|
||||
|
||||
if (ResizerSelected) {
|
||||
WindowSplit *split = ResizerSelected;
|
||||
if (split->kind == WindowSplitKind_Vertical) {
|
||||
if (ResizerSelected.id != -1) {
|
||||
Window *window = GetWindow(ResizerSelected);
|
||||
if (window->layout) {
|
||||
SetMouseCursor(SDL_SYSTEM_CURSOR_EW_RESIZE);
|
||||
} else {
|
||||
SetMouseCursor(SDL_SYSTEM_CURSOR_NS_RESIZE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (ResizerHover.id != -1) {
|
||||
Window *window = GetWindow(ResizerHover);
|
||||
if (window->layout) {
|
||||
SetMouseCursor(SDL_SYSTEM_CURSOR_EW_RESIZE);
|
||||
} else {
|
||||
Assert(split->kind == WindowSplitKind_Horizontal);
|
||||
SetMouseCursor(SDL_SYSTEM_CURSOR_NS_RESIZE);
|
||||
}
|
||||
return;
|
||||
@@ -219,16 +118,7 @@ void SetMouseCursor(Event event) {
|
||||
}
|
||||
}
|
||||
|
||||
if (ResizerHover) {
|
||||
WindowSplit *split = ResizerHover;
|
||||
if (split->kind == WindowSplitKind_Vertical) {
|
||||
SetMouseCursor(SDL_SYSTEM_CURSOR_EW_RESIZE);
|
||||
} else {
|
||||
Assert(split->kind == WindowSplitKind_Horizontal);
|
||||
SetMouseCursor(SDL_SYSTEM_CURSOR_NS_RESIZE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
SetMouseCursor(SDL_SYSTEM_CURSOR_DEFAULT);
|
||||
}
|
||||
@@ -246,14 +136,12 @@ void Update(Event event) {
|
||||
}
|
||||
|
||||
OnCommand(event);
|
||||
for (Window *it = FirstWindow; it; it = it->next) {
|
||||
if (it->is_title_bar) ReplaceTitleBarData(it);
|
||||
}
|
||||
UpdateProcesses();
|
||||
CoUpdate(&event);
|
||||
ReloadLuaConfigs();
|
||||
CallLuaOnUpdate(&event);
|
||||
StatusBarUpdate();
|
||||
UpdateDebugBuffer();
|
||||
CallLuaOnUpdate(&event);
|
||||
GarbageCollect();
|
||||
|
||||
For(IterateInReverse(&order)) {
|
||||
@@ -264,36 +152,6 @@ void Update(Event event) {
|
||||
}
|
||||
}
|
||||
|
||||
Array<Event> GetEventsForFrame(Allocator allocator) {
|
||||
Array<Event> result = {allocator};
|
||||
if (EventPlayback.len) {
|
||||
result = TightCopy(allocator, EventPlayback);
|
||||
EventPlayback.len = 0;
|
||||
}
|
||||
|
||||
SDL_Event event;
|
||||
if (WaitForEvents) {
|
||||
SDL_WaitEvent(&event);
|
||||
Event ev = TranslateSDLEvent(&event);
|
||||
if (ev.kind != EVENT_NONE) Add(&result, ev);
|
||||
}
|
||||
|
||||
while (SDL_PollEvent(&event)) {
|
||||
Event ev = TranslateSDLEvent(&event);
|
||||
if (ev.kind != EVENT_NONE) Add(&result, ev);
|
||||
}
|
||||
|
||||
if (result.len == 0) {
|
||||
Event event = {};
|
||||
FillEventWithBasicData(&event);
|
||||
event.kind = EVENT_UPDATE;
|
||||
Add(&result, event);
|
||||
}
|
||||
|
||||
Assert(result.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Windows_SetupVCVarsall(mco_coro *co) {
|
||||
View *view = NULL;
|
||||
{
|
||||
@@ -301,7 +159,7 @@ void Windows_SetupVCVarsall(mco_coro *co) {
|
||||
String working_dir = WorkDir;
|
||||
String buffer_name = GetUniqueBufferName(working_dir, "vcvarsall-");
|
||||
String cmd = Format(scratch, "\"%S\" && set", StyleVCVarsall);
|
||||
view = Command_ExecHidden(buffer_name, cmd, working_dir);
|
||||
view = ExecHidden(buffer_name, cmd, working_dir);
|
||||
}
|
||||
for (;;) {
|
||||
if (!ProcessIsActive(view->id)) {
|
||||
@@ -368,7 +226,6 @@ void MainLoop() {
|
||||
SetMouseCursor(*event);
|
||||
LayoutWindows(event->xwindow, event->ywindow); // This is here to render changes in title bar size without a frame of delay
|
||||
BeginFrameRender(event->xwindow, event->ywindow);
|
||||
DrawSplits(&WindowSplits);
|
||||
|
||||
Array<Window *> order = GetWindowZOrder(scratch);
|
||||
For(IterateInReverse(&order)) {
|
||||
@@ -489,7 +346,7 @@ int main(int argc, char **argv)
|
||||
|
||||
InitBuffers();
|
||||
InitRender();
|
||||
ReloadFont();
|
||||
ReloadFont(StyleFont, (U32)StyleFontSize);
|
||||
InitWindows();
|
||||
InitOS(ReportWarningf);
|
||||
|
||||
|
||||
@@ -1,97 +1,61 @@
|
||||
struct Window; struct View; struct WindowSplit;
|
||||
struct ViewID { Int id; View *o; };
|
||||
struct WindowID { Int id; Window *o; };
|
||||
#define EVENT_KINDS \
|
||||
X(EVENT_NONE) \
|
||||
X(EVENT_UPDATE) \
|
||||
X(EVENT_QUIT) \
|
||||
X(EVENT_MOUSE_LEFT) \
|
||||
X(EVENT_MOUSE_RIGHT) \
|
||||
X(EVENT_MOUSE_MIDDLE) \
|
||||
X(EVENT_MOUSE_X1) \
|
||||
X(EVENT_MOUSE_X2) \
|
||||
X(EVENT_MOUSE_LEFT_UP) \
|
||||
X(EVENT_MOUSE_RIGHT_UP) \
|
||||
X(EVENT_MOUSE_MIDDLE_UP) \
|
||||
X(EVENT_MOUSE_X1_UP) \
|
||||
X(EVENT_MOUSE_X2_UP) \
|
||||
X(EVENT_MOUSE_WHEEL) \
|
||||
X(EVENT_KEY_PRESS) \
|
||||
X(EVENT_TEXT_INPUT) \
|
||||
X(EVENT_DROP_FILE)
|
||||
|
||||
struct View {
|
||||
ViewID id;
|
||||
BufferID active_buffer;
|
||||
View *next;
|
||||
View *prev;
|
||||
Vec2I scroll;
|
||||
Array<Caret> carets;
|
||||
|
||||
// window | view
|
||||
Caret main_caret_on_begin_frame;
|
||||
bool update_scroll;
|
||||
|
||||
bool fuzzy_search;
|
||||
String16 prev_search_line;
|
||||
enum EventKind {
|
||||
#define X(TYPE) TYPE,
|
||||
EVENT_KINDS
|
||||
#undef X
|
||||
EVENT_KIND_COUNT,
|
||||
EVENT_KIND_INVALID = 111,
|
||||
};
|
||||
|
||||
struct GotoCrumb {
|
||||
ViewID view_id;
|
||||
Caret caret;
|
||||
const char *EventKindStrings[] = {
|
||||
#define X(TYPE) #TYPE,
|
||||
EVENT_KINDS
|
||||
#undef X
|
||||
};
|
||||
|
||||
struct Window {
|
||||
WindowID id;
|
||||
ViewID active_view;
|
||||
Window *next;
|
||||
Window *prev;
|
||||
WindowSplit *split_ref;
|
||||
#define EVENT_FIELDS \
|
||||
X(EventKind, Int, kind) \
|
||||
X(SDL_Keycode, Int, key) \
|
||||
X(int16_t, Int, xwindow) \
|
||||
X(int16_t, Int, ywindow) \
|
||||
X(int16_t, Int, xmouse) \
|
||||
X(int16_t, Int, ymouse) \
|
||||
X(uint8_t, Int, clicks) \
|
||||
X(uint8_t, Int, shift) \
|
||||
X(uint8_t, Int, ctrl) \
|
||||
X(uint8_t, Int, alt) \
|
||||
X(uint8_t, Int, super) \
|
||||
X(float, Float, xwheel) \
|
||||
X(float, Float, ywheel) \
|
||||
X(char *, String, text)
|
||||
#define EVENT_FIELD_COUNT 14
|
||||
|
||||
WindowID title_bar_window;
|
||||
Int title_bar_last_buffer_change_id; // @todo: bring back the changes to title bar?
|
||||
|
||||
WindowID search_bar_window;
|
||||
|
||||
Rect2I total_rect;
|
||||
Rect2I document_rect;
|
||||
Rect2I scrollbar_rect;
|
||||
Rect2I line_numbers_rect;
|
||||
|
||||
Array<GotoCrumb> goto_history;
|
||||
Array<GotoCrumb> goto_redo;
|
||||
|
||||
ViewID active_goto_list;
|
||||
Int goto_list_pos;
|
||||
|
||||
Font *font;
|
||||
Caret search_bar_anchor;
|
||||
double mouse_scroller_offset;
|
||||
int z;
|
||||
|
||||
struct {
|
||||
bool draw_scrollbar : 1;
|
||||
bool draw_line_numbers : 1;
|
||||
bool visible : 1;
|
||||
|
||||
bool is_title_bar : 1;
|
||||
bool is_search_bar : 1;
|
||||
|
||||
bool deactivate_on_escape : 1;
|
||||
|
||||
bool kill : 1;
|
||||
};
|
||||
};
|
||||
|
||||
enum WindowSplitKind {
|
||||
WindowSplitKind_Window,
|
||||
WindowSplitKind_Vertical,
|
||||
WindowSplitKind_Horizontal,
|
||||
};
|
||||
|
||||
struct WindowSplit {
|
||||
WindowSplitKind kind;
|
||||
WindowSplit *left;
|
||||
WindowSplit *right;
|
||||
WindowSplit *parent;
|
||||
Rect2I total_rect;
|
||||
Rect2I resizer_rect;
|
||||
|
||||
Window *window;
|
||||
double value;
|
||||
};
|
||||
|
||||
struct Scroller {
|
||||
Rect2 rect;
|
||||
double begin;
|
||||
double end;
|
||||
Int line_count;
|
||||
struct Event {
|
||||
#define X(TYPE, KIND, NAME) TYPE NAME;
|
||||
EVENT_FIELDS
|
||||
#undef X
|
||||
};
|
||||
|
||||
struct BSet {
|
||||
Window *window;
|
||||
struct Window *window;
|
||||
View *view;
|
||||
Buffer *buffer;
|
||||
};
|
||||
@@ -106,42 +70,38 @@ Allocator SysAllocator = {SystemAllocatorProc};
|
||||
String ConfigDir;
|
||||
float DPIScale = 1.0f;
|
||||
|
||||
Rect2I GetVisibleCells(Window *window);
|
||||
void AfterEdit(View *view, Array<Edit> edits);
|
||||
Scroller ComputeScrollerRect(Window *window);
|
||||
BSet Command_Open(String path, String meta = "");
|
||||
BSet Command_Open(String16 path, String meta = "");
|
||||
BSet Open(String path, String meta = "");
|
||||
BSet Open(String16 path, String meta = "");
|
||||
void UpdateScroll(Window *window, bool update_caret_scrolling);
|
||||
|
||||
void Command_SelectEntireBuffer(View *view);
|
||||
void Command_Replace(View *view, String16 string);
|
||||
void Command_SelectRangeOneCursor(View *view, Range range);
|
||||
void Command_Append(View *view, String16 string, bool scroll_to_end_if_cursor_on_last_line);
|
||||
void Command_Append(View *view, String string, bool scroll_to_end_if_cursor_on_last_line);
|
||||
Array<Edit> Command_ReplaceEx(Allocator scratch, View *view, String16 string);
|
||||
void Command_Eval(String string);
|
||||
void Command_Eval(String16 string);
|
||||
String Command_GetMainDir();
|
||||
void SelectEntireBuffer(View *view);
|
||||
void Replace(View *view, String16 string);
|
||||
void SelectRange(View *view, Range range);
|
||||
void Append(View *view, String16 string, bool scroll_to_end_if_cursor_on_last_line);
|
||||
void Append(View *view, String string, bool scroll_to_end_if_cursor_on_last_line);
|
||||
Array<Edit> ReplaceEx(Allocator scratch, View *view, String16 string);
|
||||
void Eval(String string);
|
||||
void Eval(String16 string);
|
||||
void ReportDebugf(const char *fmt, ...);
|
||||
|
||||
void ReplaceWithoutMovingCarets(Buffer *buffer, Range range, String16 string);
|
||||
void Command_Copy(View *view);
|
||||
void Command_Paste(View *view);
|
||||
void ReplaceWithoutMovingCarets(Buffer *buffer, Range range, String16 string);
|
||||
void ClipboardCopy(View *view);
|
||||
void ClipboardPaste(View *view);
|
||||
|
||||
void ReportConsolef(const char *fmt, ...);
|
||||
void ReportErrorf(const char *fmt, ...);
|
||||
void ReportWarningf(const char *fmt, ...);
|
||||
void Command_Appendf(View *view, const char *fmt, ...);
|
||||
void Appendf(View *view, const char *fmt, ...);
|
||||
|
||||
Buffer *CreateBuffer(Allocator allocator, String name, Int size = 4096);
|
||||
View *CreateView(BufferID active_buffer);
|
||||
void ReopenBuffer(Buffer *buffer);
|
||||
inline Buffer *FindBuffer(String name);
|
||||
|
||||
inline bool operator==(WindowID a, WindowID b) { return a.id == b.id; }
|
||||
inline bool operator==(BufferID a, BufferID b) { return a.id == b.id; }
|
||||
inline bool operator==(ViewID a, ViewID b) { return a.id == b.id; }
|
||||
inline bool operator!=(WindowID a, WindowID b) { return a.id != b.id; }
|
||||
inline bool operator!=(BufferID a, BufferID b) { return a.id != b.id; }
|
||||
inline bool operator!=(ViewID a, ViewID b) { return a.id != b.id; }
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ void UpdateDebugBuffer() {
|
||||
View *view = GetView(window->active_view);
|
||||
if (view->active_buffer.id == buffer->id.id) return;
|
||||
|
||||
BSet main = GetActiveMainSet();
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
|
||||
Scratch scratch;
|
||||
String s = Format(scratch, "wid: %d\nvid: %d\nbid: %d\nframe: %lld\n", (int)main.window->id.id, (int)main.view->id.id, (int)main.buffer->id.id, (long long)FrameID);
|
||||
@@ -17,8 +17,6 @@ void UpdateDebugBuffer() {
|
||||
RawAppendf(buffer, "mouse: [%f, %f]\n", xmouse, ymouse);
|
||||
|
||||
RawAppendf(buffer, "BufferID id = %d\n", main.buffer->id.id);
|
||||
RawAppendf(buffer, "Buffer *next = %zu\n", main.buffer->next);
|
||||
RawAppendf(buffer, "Buffer *prev = %zu\n", main.buffer->prev);
|
||||
RawAppendf(buffer, "String name = %S\n", main.buffer->name);
|
||||
RawAppendf(buffer, "Int change_id = %lld\n", (long long)main.buffer->change_id);
|
||||
RawAppendf(buffer, "Int user_change_id = %lld\n", (long long)main.buffer->user_change_id);
|
||||
@@ -43,10 +41,15 @@ void UpdateDebugBuffer() {
|
||||
RawAppendf(buffer, "int garbage = %d\n", main.buffer->garbage);
|
||||
}
|
||||
|
||||
void ReplaceTitleBarData(Window *window) {
|
||||
void StatusBarUpdate() {
|
||||
Window *status_bar_window = GetWindow(StatusBarWindowID, NULL);
|
||||
if (status_bar_window == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
Scratch scratch;
|
||||
BSet main = GetMainSet(window);
|
||||
BSet title = GetBSet(window);
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
BSet title = GetBSet(status_bar_window);
|
||||
title.view->scroll.y = 0;
|
||||
|
||||
String16 buffer_string = GetString(title.buffer);
|
||||
@@ -54,11 +57,12 @@ void ReplaceTitleBarData(Window *window) {
|
||||
bool found_separator = Seek(buffer_string, u" |", &replace_range.max);
|
||||
|
||||
// Parse the title and line
|
||||
if (window->id == ActiveWindow) {
|
||||
if (title.buffer->change_id == title.window->title_bar_last_buffer_change_id) {
|
||||
if (title.window->id == ActiveWindowID) {
|
||||
if (title.buffer->change_id == title.window->status_bar_last_buffer_change_id) {
|
||||
return;
|
||||
}
|
||||
String16 buffer_name = GetString(title.buffer, replace_range);
|
||||
buffer_name = Skip(buffer_name, 1);
|
||||
buffer_name = Trim(buffer_name);
|
||||
|
||||
Int column = ChopNumber(&buffer_name);
|
||||
@@ -70,64 +74,41 @@ void ReplaceTitleBarData(Window *window) {
|
||||
column = 0;
|
||||
}
|
||||
|
||||
String name = ToString(scratch, buffer_name);
|
||||
if (name != main.buffer->name) {
|
||||
name = GetAbsolutePath(scratch, name);
|
||||
if (FindBuffer(name)) {
|
||||
title.window->title_bar_last_buffer_change_id = title.buffer->change_id;
|
||||
ReportConsolef("there is already buffer with name: %S", name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (name != main.buffer->name) {
|
||||
main.buffer->name = Intern(&GlobalInternTable, name);
|
||||
title.window->title_bar_last_buffer_change_id = title.buffer->change_id;
|
||||
main.buffer->file_mod_time = 0;
|
||||
main.buffer->changed_on_disk = false;
|
||||
main.buffer->dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
Int buffer_pos = XYToPos(main.buffer, {column, line});
|
||||
Caret &caret = main.view->carets[0];
|
||||
if (GetFront(caret) != buffer_pos) {
|
||||
caret = MakeCaret(buffer_pos);
|
||||
}
|
||||
title.window->status_bar_last_buffer_change_id = title.buffer->change_id;
|
||||
return;
|
||||
}
|
||||
|
||||
Caret caret = main.view->carets[0];
|
||||
XY xy = PosToXY(main.buffer, GetFront(caret));
|
||||
|
||||
Array<Caret> caret_copy = Copy(GetSystemAllocator(), title.view->carets);
|
||||
defer {
|
||||
Dealloc(&title.view->carets);
|
||||
title.view->carets = caret_copy;
|
||||
};
|
||||
|
||||
// add separator at the end of buffer
|
||||
if (!found_separator) {
|
||||
Command_SelectRangeOneCursor(title.view, GetBufferEndAsRange(title.buffer));
|
||||
Array<Edit> edits = Command_ReplaceEx(scratch, title.view, u" |");
|
||||
AdjustCarets(edits, &caret_copy);
|
||||
SelectRange(title.view, GetBufferEndAsRange(title.buffer));
|
||||
Array<Edit> edits = ReplaceEx(scratch, title.view, u" |");
|
||||
}
|
||||
|
||||
|
||||
// replace data up to separator with filename and stuff
|
||||
const char *reopen = main.buffer->changed_on_disk ? " Reopen()" : "";
|
||||
String s = Format(scratch, "%S:%lld:%lld%s", main.buffer->name, (long long)xy.line + 1ll, (long long)xy.col + 1ll, reopen);
|
||||
String s = Format(scratch, "# %S:%lld:%lld%s", main.buffer->name, (long long)xy.line + 1ll, (long long)xy.col + 1ll, reopen);
|
||||
For (ActiveProcesses) {
|
||||
if (it.view_id == main.view->id.id) {
|
||||
s = Format(scratch, "%S %lld", s, (long long)it.id);
|
||||
s = Format(scratch, "%S %lld Kill()", s, (long long)it.id);
|
||||
}
|
||||
}
|
||||
|
||||
String16 string = ToString16(scratch, s);
|
||||
String16 string_to_replace = GetString(title.buffer, replace_range);
|
||||
if (string_to_replace != string) {
|
||||
Command_SelectRangeOneCursor(title.view, replace_range);
|
||||
Array<Edit> edits = Command_ReplaceEx(scratch, title.view, string);
|
||||
Command_SelectRangeOneCursor(title.view, MakeRange(0));
|
||||
AdjustCarets(edits, &caret_copy);
|
||||
SelectRange(title.view, replace_range);
|
||||
Array<Edit> edits = ReplaceEx(scratch, title.view, string);
|
||||
}
|
||||
|
||||
SelectRange(title.view, MakeRange(0));
|
||||
ResetHistory(title.buffer);
|
||||
}
|
||||
77
src/text_editor/view.cpp
Normal file
77
src/text_editor/view.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
API ViewID AllocViewID(View *view) {
|
||||
return {ViewIDs.id++, view};
|
||||
}
|
||||
|
||||
API View *CreateView(BufferID active_buffer) {
|
||||
Allocator al = GetSystemAllocator();
|
||||
View *view = AllocType(al, View);
|
||||
view->id = AllocViewID(view);
|
||||
view->active_buffer = active_buffer;
|
||||
view->carets.allocator = al;
|
||||
Add(&view->carets, {0, 0});
|
||||
Add(&Views, view);
|
||||
return view;
|
||||
}
|
||||
|
||||
API View *FindView(ViewID view_id, View *default_view) {
|
||||
For(Views) {
|
||||
if (it->id == view_id) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return default_view;
|
||||
}
|
||||
|
||||
API View *FindView(BufferID buffer_id, View *default_view) {
|
||||
For(Views) {
|
||||
if (it->active_buffer == buffer_id) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return default_view;
|
||||
}
|
||||
|
||||
API View *FindView(String name, View *default_view) {
|
||||
For(Views) {
|
||||
Buffer *buffer = GetBuffer(it->active_buffer);
|
||||
if (buffer->name == name) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return default_view;
|
||||
}
|
||||
|
||||
API View *GetView(ViewID id) {
|
||||
return FindView(id, Views[0]);
|
||||
}
|
||||
|
||||
API View *OpenBufferView(String name) {
|
||||
Buffer *buffer = BufferOpenFile(name);
|
||||
View *view = CreateView(buffer->id);
|
||||
return view;
|
||||
}
|
||||
|
||||
API bool ViewIsCrumb(ViewID view_id) {
|
||||
ForItem(window, Windows) {
|
||||
For(window->goto_history) if (it.view_id == view_id) return true;
|
||||
For(window->goto_redo) if (it.view_id == view_id) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
API bool ViewIsReferenced(ViewID view) {
|
||||
if (view == NullViewID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ViewIsCrumb(view)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
For(Windows) {
|
||||
if (it->active_view == view) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
32
src/text_editor/view.h
Normal file
32
src/text_editor/view.h
Normal file
@@ -0,0 +1,32 @@
|
||||
struct View;
|
||||
struct ViewID { Int id; View *o; };
|
||||
|
||||
struct View {
|
||||
ViewID id;
|
||||
BufferID active_buffer;
|
||||
Vec2I scroll;
|
||||
Array<Caret> carets;
|
||||
|
||||
// window | view
|
||||
Caret main_caret_on_begin_frame;
|
||||
bool update_scroll;
|
||||
|
||||
bool fuzzy_search;
|
||||
String16 prev_search_line;
|
||||
};
|
||||
|
||||
struct GotoCrumb {
|
||||
ViewID view_id;
|
||||
Caret caret;
|
||||
double time;
|
||||
};
|
||||
|
||||
API ViewID AllocViewID(View *view);
|
||||
API View *CreateView(BufferID active_buffer);
|
||||
API View *FindView(ViewID view_id, View *default_view = NULL);
|
||||
API View *FindView(BufferID buffer_id, View *default_view = NULL);
|
||||
API View *FindView(String name, View *default_view = NULL);
|
||||
API View *GetView(ViewID id);
|
||||
API View *OpenBufferView(String name);
|
||||
API bool ViewIsCrumb(ViewID view_id);
|
||||
API bool ViewIsReferenced(ViewID view);
|
||||
@@ -1,188 +1,169 @@
|
||||
inline WindowID AllocWindowID(Window *window) {
|
||||
return {WindowIDs.id++, window};
|
||||
}
|
||||
|
||||
Window *CreateWind() {
|
||||
Allocator allocator = GetSystemAllocator();
|
||||
Window *w = AllocType(allocator, Window);
|
||||
w->font = &PrimaryFont;
|
||||
w->visible = true;
|
||||
w->layout = true;
|
||||
w->draw_scrollbar = StyleDrawScrollbar;
|
||||
w->draw_line_numbers = StyleDrawLineNumbers;
|
||||
w->draw_line_highlight = true;
|
||||
w->jump_history = true;
|
||||
w->id = AllocWindowID(w);
|
||||
w->weight = 1.0;
|
||||
Add(&Windows, w);
|
||||
return w;
|
||||
}
|
||||
|
||||
inline Window *GetWindow(WindowID id, Window *default_window = Windows[0]) {
|
||||
For(Windows) {
|
||||
if (it->id == id) return it;
|
||||
}
|
||||
return default_window;
|
||||
}
|
||||
|
||||
Window *FindWindow(ViewID view_id, Window *default_window = NULL) {
|
||||
For(Windows) {
|
||||
if (it->active_view == view_id) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return default_window;
|
||||
}
|
||||
|
||||
Window *FindWindow(String buffer_name, Window *default_window = NULL) {
|
||||
For(Windows) {
|
||||
View *it_view = GetView(it->active_view);
|
||||
Buffer *it_buffer = GetBuffer(it_view->active_buffer);
|
||||
if (it_buffer->name == buffer_name) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return default_window;
|
||||
}
|
||||
|
||||
Window *FindWindow(BufferID buffer_id) {
|
||||
For(Windows) {
|
||||
View *view = GetView(it->active_view);
|
||||
if (view->active_buffer == buffer_id) return it;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline Window *GetActiveWind() {
|
||||
return GetWindow(ActiveWindowID);
|
||||
}
|
||||
|
||||
inline bool IsDocumentSelectionValid() {
|
||||
if (DocumentSelected.id == -1) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool IsScrollbarSelectionValid() {
|
||||
if (ScrollbarSelected.id == -1) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
Array<Window *> GetWindowZOrder(Allocator allocator) {
|
||||
Array<Window *> order = {allocator};
|
||||
for (Window *it = FirstWindow; it; it = it->next) if (it->z == 2) Add(&order, it);
|
||||
for (Window *it = FirstWindow; it; it = it->next) if (it->z == 1) Add(&order, it);
|
||||
for (Window *it = FirstWindow; it; it = it->next) if (it->z == 0) Add(&order, it);
|
||||
For(Windows) if (it->z == 2) Add(&order, it);
|
||||
For(Windows) if (it->z == 1) Add(&order, it);
|
||||
For(Windows) if (it->z == 0) Add(&order, it);
|
||||
return order;
|
||||
}
|
||||
|
||||
Window *CreateSearchBar(WindowID parent_window_id) {
|
||||
Window *window = CreateWind(false);
|
||||
window->draw_scrollbar = false;
|
||||
window->deactivate_on_escape = true;
|
||||
window->is_search_bar = true;
|
||||
|
||||
static int BarCount;
|
||||
Allocator sys_allocator = GetSystemAllocator();
|
||||
String name = Format(sys_allocator, "%S/searchbar%d", WorkDir, ++BarCount);
|
||||
|
||||
Buffer *b = CreateBuffer(sys_allocator, name);
|
||||
View *v = CreateView(b->id);
|
||||
window->active_view = v->id;
|
||||
|
||||
Window *parent_window = GetWindow(parent_window_id);
|
||||
parent_window->search_bar_window = window->id;
|
||||
window->search_bar_window = parent_window->id;
|
||||
window->z = parent_window->z + 1;
|
||||
window->visible = false;
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
Window *CreateTitlebar(WindowID parent_window_id) {
|
||||
Window *window = CreateWind(false);
|
||||
window->font = &SecondaryFont;
|
||||
window->draw_scrollbar = false;
|
||||
window->deactivate_on_escape = true;
|
||||
window->is_title_bar = true;
|
||||
|
||||
static int TitlebarCount;
|
||||
Allocator sys_allocator = GetSystemAllocator();
|
||||
String name = Format(sys_allocator, "%S/titlebar%d", WorkDir, ++TitlebarCount);
|
||||
|
||||
Buffer *b = CreateBuffer(sys_allocator, name);
|
||||
View *v = CreateView(b->id);
|
||||
window->active_view = v->id;
|
||||
|
||||
Window *parent_window = GetWindow(parent_window_id);
|
||||
parent_window->title_bar_window = window->id;
|
||||
window->title_bar_window = parent_window->id;
|
||||
|
||||
void ReplaceTitleBarData(Window * window);
|
||||
ReplaceTitleBarData(window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
Int GetTitleBarSize(Window *window) {
|
||||
Int GetExpandingBarSize(Window *window) {
|
||||
View *view = GetView(window->active_view);
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
float result = (float)buffer->line_starts.len * window->font->line_spacing;
|
||||
return (Int)result;
|
||||
}
|
||||
|
||||
WindowSplit *CreateSplitForWindow(WindowSplit *parent, Window *window) {
|
||||
WindowSplit *split = AllocType(SysAllocator, WindowSplit);
|
||||
split->kind = WindowSplitKind_Window;
|
||||
split->window = window;
|
||||
split->parent = parent;
|
||||
window->split_ref = split;
|
||||
return split;
|
||||
}
|
||||
|
||||
void SplitWindowEx(WindowSplit **node, WindowSplit *split, Window *target, Window *new_window, WindowSplitKind kind) {
|
||||
if (split->kind == WindowSplitKind_Horizontal || split->kind == WindowSplitKind_Vertical) {
|
||||
SplitWindowEx(&split->left, split->left, target, new_window, kind);
|
||||
SplitWindowEx(&split->right, split->right, target, new_window, kind);
|
||||
} else {
|
||||
Assert(split->kind == WindowSplitKind_Window);
|
||||
if (target != split->window) {
|
||||
return;
|
||||
}
|
||||
|
||||
WindowSplit *hori = AllocType(SysAllocator, WindowSplit);
|
||||
hori->parent = node[0]->parent;
|
||||
hori->kind = kind;
|
||||
hori->value = 0.5;
|
||||
hori->left = *node;
|
||||
hori->right = CreateSplitForWindow(hori, new_window);
|
||||
*node = hori;
|
||||
View *WindowOpenBufferView(Window *new_parent_window, String name) {
|
||||
View *view = FindView(name);
|
||||
if (!view) {
|
||||
View *result = OpenBufferView(name);
|
||||
new_parent_window->active_view = result->id;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void SetVisibility(WindowID window_id, bool v) {
|
||||
Window *window = GetWindow(window_id);
|
||||
window->visible = v;
|
||||
|
||||
if (window->title_bar_window.id != 0) {
|
||||
Window *title_bar = GetWindow(window->title_bar_window);
|
||||
title_bar->visible = v;
|
||||
Window *window = FindWindow(view->id);
|
||||
if (!window) {
|
||||
new_parent_window->active_view = view->id;
|
||||
return view;
|
||||
}
|
||||
if (window->search_bar_window.id != 0) {
|
||||
Window *search_bar = GetWindow(window->search_bar_window);
|
||||
search_bar->visible = v;
|
||||
if (window == new_parent_window) {
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
bool ToggleVisibility(WindowID window_id) {
|
||||
Window *window = GetWindow(window_id);
|
||||
bool visible = !window->visible;
|
||||
SetVisibility(window_id, visible);
|
||||
return visible;
|
||||
}
|
||||
|
||||
void LoadBigText(Buffer *buffer, int size = 5000000) {
|
||||
for (int i = 0; i < size; i += 1) {
|
||||
RawReplaceText(buffer, GetBufferEndAsRange(buffer), u"Line number or something of the sort which is here or there or maybe somewhere else\n");
|
||||
}
|
||||
}
|
||||
|
||||
void LoadBigLine(Buffer *buffer, int size = 5000000) {
|
||||
for (int i = 0; i < size; i += 1) {
|
||||
RawReplaceText(buffer, GetBufferEndAsRange(buffer), u"Line number or something of the sort which is here or there or maybe somewhere else | ");
|
||||
}
|
||||
}
|
||||
|
||||
void LoadBigTextAndBigLine(Buffer *buffer, int size = 2500000) {
|
||||
LoadBigLine(buffer, size);
|
||||
LoadBigText(buffer, size);
|
||||
}
|
||||
|
||||
void LoadTextA(Buffer *buffer) {
|
||||
Scratch scratch;
|
||||
for (int i = 0; i < 1000; i += 1) {
|
||||
String s = Format(scratch, "line1: %d line2: %d line3: %d line4: %d line5: %d line6: %d line1: %d line2: %d line3: %d line4: %d line5: %d line6: %d\r\n", i, i, i, i, i, i, i, i, i, i, i, i);
|
||||
String16 s16 = ToString16(scratch, s);
|
||||
RawReplaceText(buffer, GetBufferEndAsRange(buffer), s16);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadLine(Buffer *buffer) {
|
||||
Scratch scratch;
|
||||
String s = "Line number and so on óźćż";
|
||||
RawReplaceText(buffer, {}, ToString16(scratch, s));
|
||||
}
|
||||
|
||||
void LoadTestBufferMessage(Buffer *buffer) {
|
||||
String text = R"===(
|
||||
|
||||
commit 225d1ffc067da0723898ade68fb9492bbe308feb
|
||||
https://www.lua.org/manual/5.4/
|
||||
|
||||
)===";
|
||||
Scratch scratch;
|
||||
RawReplaceText(buffer, {}, ToString16(scratch, text));
|
||||
|
||||
// RawReplaceText(buffer, GetBufferEndAsRange(buffer), ToString16(scratch, text));
|
||||
Assert(window->active_view.id == view->id.id);
|
||||
View *result = OpenBufferView(name);
|
||||
new_parent_window->active_view = result->id;
|
||||
return result;
|
||||
}
|
||||
|
||||
void InitWindows() {
|
||||
WindowSplit *split = &WindowSplits;
|
||||
split->kind = WindowSplitKind_Horizontal;
|
||||
split->value = (double)0.9;
|
||||
Scratch scratch;
|
||||
|
||||
CreateWind();
|
||||
CreateWind();
|
||||
|
||||
// COMMAND BAR
|
||||
{
|
||||
Window *window = CreateWind();
|
||||
window->active_view = NullViewID;
|
||||
Assert(window->id.id == 0);
|
||||
CreateTitlebar(window->id);
|
||||
CreateSearchBar(window->id);
|
||||
|
||||
split->right = CreateSplitForWindow(split, window);
|
||||
}
|
||||
|
||||
{
|
||||
Window *window = CreateWind();
|
||||
Buffer *buffer = ScratchBuffer;
|
||||
View *view = CreateView(buffer->id);
|
||||
CommandBarWindowID = window->id;
|
||||
Buffer *buffer = CreateBuffer(SysAllocator, "command_bar");
|
||||
View *view = CreateView(buffer->id);
|
||||
window->active_view = view->id;
|
||||
CreateTitlebar(window->id);
|
||||
CreateSearchBar(window->id);
|
||||
ActiveWindow = window->id;
|
||||
|
||||
split->left = CreateSplitForWindow(split, window);
|
||||
window->draw_line_numbers = false;
|
||||
window->draw_scrollbar = false;
|
||||
window->draw_darker = true;
|
||||
window->draw_line_highlight = false;
|
||||
window->layout = false;
|
||||
window->visible = false;
|
||||
window->sync_visibility_with_focus = true;
|
||||
window->lose_focus_on_escape = true;
|
||||
window->jump_history = false;
|
||||
view->fuzzy_search = true;
|
||||
}
|
||||
|
||||
// SEARCH BAR
|
||||
{
|
||||
Window *window = CreateWind();
|
||||
SearchBarWindowID = window->id;
|
||||
Buffer *buffer = CreateBuffer(SysAllocator, "search_bar");
|
||||
SearchBufferID = buffer->id;
|
||||
View *view = CreateView(buffer->id);
|
||||
SearchViewID = view->id;
|
||||
window->active_view = view->id;
|
||||
window->draw_line_numbers = false;
|
||||
window->draw_scrollbar = false;
|
||||
window->draw_darker = true;
|
||||
window->draw_line_highlight = false;
|
||||
window->layout = false;
|
||||
window->visible = false;
|
||||
window->lose_focus_on_escape = true;
|
||||
}
|
||||
|
||||
// STATUS BAR at the bottom
|
||||
{
|
||||
Window *window = CreateWind();
|
||||
StatusBarWindowID = window->id;
|
||||
Buffer *buffer = CreateBuffer(SysAllocator, "status_bar");
|
||||
View *view = CreateView(buffer->id);
|
||||
window->active_view = view->id;
|
||||
window->font = &SecondaryFont;
|
||||
window->draw_line_numbers = false;
|
||||
window->draw_scrollbar = false;
|
||||
window->draw_line_highlight = false;
|
||||
window->draw_darker = true;
|
||||
window->layout = false;
|
||||
}
|
||||
|
||||
// DEBUG WINDOW
|
||||
{
|
||||
Window *window = CreateWind();
|
||||
DebugWindowID = window->id;
|
||||
@@ -190,6 +171,7 @@ void InitWindows() {
|
||||
window->draw_scrollbar = false;
|
||||
window->visible = false;
|
||||
window->z = 2;
|
||||
window->layout = false;
|
||||
|
||||
Buffer *buffer = CreateBuffer(SysAllocator, GetUniqueBufferName(WorkDir, "debug"));
|
||||
DebugBufferID = buffer->id;
|
||||
@@ -199,86 +181,102 @@ void InitWindows() {
|
||||
DebugViewID = view->id;
|
||||
window->active_view = view->id;
|
||||
|
||||
Window *titlebar = CreateTitlebar(window->id);
|
||||
Window *searchbar = CreateSearchBar(window->id);
|
||||
titlebar->z = 2;
|
||||
searchbar->z = 2;
|
||||
|
||||
SetVisibility(window->id, false);
|
||||
window->visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutWindowSplit(WindowSplit *split, Rect2I rect) {
|
||||
float scrollbar_size = (10.f * DPIScale);
|
||||
float resizer_size = (float)PrimaryFont.char_spacing*0.5f;
|
||||
void CalcNiceties(Window *n) {
|
||||
float scrollbar_size = (10.f * DPIScale);
|
||||
float line_numbers_size = (float)n->font->char_spacing * 10.f;
|
||||
if (n->draw_scrollbar) n->scrollbar_rect = CutRight(&n->document_rect, (Int)scrollbar_size);
|
||||
if (n->draw_line_numbers) n->line_numbers_rect = CutLeft(&n->document_rect, (Int)line_numbers_size);
|
||||
}
|
||||
|
||||
if (split->kind == WindowSplitKind_Window) {
|
||||
Window *it = split->window;
|
||||
float line_numbers_size = (float)it->font->char_spacing * 10;
|
||||
Assert(it->split_ref);
|
||||
it->total_rect = rect;
|
||||
|
||||
Window *title_bar_window = GetWindow(it->title_bar_window);
|
||||
title_bar_window->total_rect = CutBottom(&it->total_rect, GetTitleBarSize(title_bar_window));
|
||||
title_bar_window->document_rect = title_bar_window->total_rect;
|
||||
|
||||
Rect2I save_rect = it->document_rect;
|
||||
CutLeft(&save_rect, GetSize(save_rect).x/2);
|
||||
Window *search_bar_window = GetWindow(it->search_bar_window);
|
||||
search_bar_window->total_rect = CutTop(&save_rect, GetTitleBarSize(search_bar_window));
|
||||
search_bar_window->document_rect = search_bar_window->total_rect;
|
||||
|
||||
it->document_rect = it->total_rect;
|
||||
if (it->draw_scrollbar) it->scrollbar_rect = CutRight(&it->document_rect, (Int)scrollbar_size);
|
||||
if (it->draw_line_numbers) it->line_numbers_rect = CutLeft(&it->document_rect, (Int)line_numbers_size);
|
||||
} else if (split->kind == WindowSplitKind_Vertical) {
|
||||
Rect2I rect2 = {0};
|
||||
split->total_rect = rect;
|
||||
rect2 = CutLeft(&rect, (Int)round((double)GetSize(rect).x * split->value));
|
||||
split->resizer_rect = CutRight(&rect2, (Int)resizer_size);
|
||||
|
||||
LayoutWindowSplit(split->left, rect2);
|
||||
LayoutWindowSplit(split->right, rect);
|
||||
} else if (split->kind == WindowSplitKind_Horizontal) {
|
||||
Rect2I rect2 = {0};
|
||||
split->total_rect = rect;
|
||||
rect2 = CutTop(&rect, (Int)round((double)GetSize(rect).y * split->value));
|
||||
split->resizer_rect = CutTop(&rect, (Int)resizer_size);
|
||||
|
||||
LayoutWindowSplit(split->left, rect2);
|
||||
LayoutWindowSplit(split->right, rect);
|
||||
} else {
|
||||
Assert(!"Invalid codepath");
|
||||
double WindowCalcEvenResizerValue(Int screen_size_x, Int *out_count = NULL) {
|
||||
double w = 0;
|
||||
Int c = 0;
|
||||
ForItem(n, Windows) {
|
||||
if (n->layout) {
|
||||
w += n->weight;
|
||||
c += 1;
|
||||
}
|
||||
}
|
||||
if (out_count) *out_count = c;
|
||||
return (double)screen_size_x / w;
|
||||
}
|
||||
|
||||
void LayoutWindows(int16_t wx, int16_t wy) {
|
||||
Rect2I screen_rect = RectI0Size(wx, wy);
|
||||
LayoutWindowSplit(&WindowSplits, screen_rect);
|
||||
Rect2I screen_rect = RectI0Size(wx, wy);
|
||||
|
||||
// layout debug window
|
||||
// Command bar
|
||||
{
|
||||
Window *window = GetWindow(DebugWindowID);
|
||||
Window *n = GetWindow(CommandBarWindowID);
|
||||
Rect2I *rect = &screen_rect;
|
||||
Rect2I copy_rect = screen_rect;
|
||||
if (!n->visible) {
|
||||
rect = ©_rect;
|
||||
}
|
||||
Int barsize = Clamp((Int)n->font->line_spacing*10, (Int)0, (Int)wx - 100);
|
||||
n->document_rect = n->total_rect = CutBottom(rect, barsize);
|
||||
}
|
||||
|
||||
// bar at the bottom
|
||||
{
|
||||
Window *n = GetWindow(StatusBarWindowID);
|
||||
Rect2I *rect = &screen_rect;
|
||||
Rect2I copy_rect = screen_rect;
|
||||
if (!n->visible) {
|
||||
rect = ©_rect;
|
||||
}
|
||||
Int barsize = GetExpandingBarSize(n);
|
||||
n->document_rect = n->total_rect = CutBottom(rect, barsize);
|
||||
}
|
||||
|
||||
// search bar
|
||||
{
|
||||
Window *n = GetWindow(SearchBarWindowID);
|
||||
Rect2I *rect = &screen_rect;
|
||||
Rect2I copy_rect = screen_rect;
|
||||
if (!n->visible) {
|
||||
rect = ©_rect;
|
||||
}
|
||||
Int barsize = GetExpandingBarSize(n);
|
||||
n->document_rect = n->total_rect = CutBottom(rect, barsize);
|
||||
}
|
||||
|
||||
// floating debug window
|
||||
{
|
||||
Window *n = GetWindow(DebugWindowID);
|
||||
Rect2 screen_rect = Rect0Size(wx, wy);
|
||||
Vec2 size = GetSize(screen_rect);
|
||||
|
||||
Rect2 a = CutLeft(&screen_rect, 0.3f * size.x);
|
||||
Rect2 b = CutBottom(&a, 0.4f * size.y);
|
||||
Rect2 c = Shrink(b, 20);
|
||||
|
||||
window->total_rect = ToRect2I(c);
|
||||
|
||||
Window *title_bar_window = GetWindow(window->title_bar_window);
|
||||
title_bar_window->total_rect = CutBottom(&window->total_rect, GetTitleBarSize(title_bar_window));
|
||||
title_bar_window->document_rect = title_bar_window->total_rect;
|
||||
|
||||
Rect2I save_rect = window->document_rect;
|
||||
CutLeft(&save_rect, GetSize(save_rect).x/2);
|
||||
Window *search_bar_window = GetWindow(window->search_bar_window);
|
||||
search_bar_window->total_rect = CutTop(&save_rect, GetTitleBarSize(search_bar_window));
|
||||
search_bar_window->document_rect = search_bar_window->total_rect;
|
||||
|
||||
window->document_rect = window->total_rect;
|
||||
n->document_rect = n->total_rect = ToRect2I(c);
|
||||
}
|
||||
|
||||
}
|
||||
// Column layout
|
||||
Int c = 0;
|
||||
double size = WindowCalcEvenResizerValue(wx, &c);
|
||||
if (c == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
ForItem(n, Windows) {
|
||||
if (!n->layout) {
|
||||
continue;
|
||||
}
|
||||
|
||||
n->total_rect = n->document_rect = CutLeft(&screen_rect, (Int)(size * n->weight));
|
||||
if (i != (c - 1)) {
|
||||
Int resizer_size = (Int)(PrimaryFont.char_spacing*0.5f);
|
||||
n->resizer_rect = CutRight(&n->document_rect, resizer_size);
|
||||
} else {
|
||||
n->resizer_rect = {};
|
||||
}
|
||||
CalcNiceties(n);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
49
src/text_editor/window.h
Normal file
49
src/text_editor/window.h
Normal file
@@ -0,0 +1,49 @@
|
||||
struct Window;
|
||||
struct WindowID { Int id; Window *o; };
|
||||
|
||||
struct Window {
|
||||
WindowID id;
|
||||
ViewID active_view;
|
||||
|
||||
Rect2I total_rect;
|
||||
Rect2I document_rect;
|
||||
Rect2I scrollbar_rect;
|
||||
Rect2I line_numbers_rect;
|
||||
Rect2I resizer_rect;
|
||||
|
||||
Font *font;
|
||||
double mouse_scroller_offset;
|
||||
int z;
|
||||
double weight;
|
||||
Int status_bar_last_buffer_change_id;
|
||||
|
||||
Array<GotoCrumb> goto_history;
|
||||
Array<GotoCrumb> goto_redo;
|
||||
|
||||
ViewID active_goto_list;
|
||||
Int goto_list_pos;
|
||||
|
||||
struct {
|
||||
bool draw_scrollbar : 1;
|
||||
bool draw_line_numbers : 1;
|
||||
bool draw_darker : 1;
|
||||
bool draw_line_highlight : 1;
|
||||
bool visible : 1;
|
||||
bool layout : 1;
|
||||
bool kill : 1;
|
||||
bool sync_visibility_with_focus : 1;
|
||||
bool lose_focus_on_escape : 1;
|
||||
bool jump_history : 1;
|
||||
};
|
||||
};
|
||||
|
||||
struct Scroller {
|
||||
Rect2 rect;
|
||||
double begin;
|
||||
double end;
|
||||
Int line_count;
|
||||
};
|
||||
|
||||
inline bool operator==(WindowID a, WindowID b) { return a.id == b.id; }
|
||||
inline bool operator!=(WindowID a, WindowID b) { return a.id != b.id; }
|
||||
Rect2I GetVisibleCells(Window *window);
|
||||
Reference in New Issue
Block a user