Remove hooks, file modifications
This commit is contained in:
@@ -1,3 +1,41 @@
|
||||
BSet GetBSet(Window *window) {
|
||||
BSet set = {window};
|
||||
set.view = GetView(set.window->active_view);
|
||||
set.buffer = GetBuffer(set.view->active_buffer);
|
||||
return set;
|
||||
}
|
||||
|
||||
BSet GetBSet(WindowID window_id) {
|
||||
Window *window = GetWindow(window_id);
|
||||
BSet result = GetBSet(window);
|
||||
return result;
|
||||
}
|
||||
|
||||
BSet GetConsoleSet() {
|
||||
BSet result = {};
|
||||
result.window = GetWindow(NullWindowID);
|
||||
result.view = GetView(NullViewID);
|
||||
result.buffer = GetBuffer(NullBufferID);
|
||||
return result;
|
||||
}
|
||||
|
||||
String GetCurrentFilename() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
return main.buffer->name;
|
||||
}
|
||||
|
||||
String GetDir(Buffer *buffer) {
|
||||
String name = ChopLastSlash(buffer->name);
|
||||
return name;
|
||||
}
|
||||
|
||||
String GetMainDir() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
String name = ChopLastSlash(main.buffer->name);
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
void CheckpointBeforeGoto(Window *window, View *view) {
|
||||
if (window->jump_history == false) return;
|
||||
Add(&window->goto_history, {view->id, view->carets[0], GetTimeSeconds()});
|
||||
@@ -1336,13 +1374,13 @@ void Command_KillSelectedLines() {
|
||||
|
||||
void Command_IndentSelectedLines() {
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
Event event = *OnCommandEvent;
|
||||
bool left = false;
|
||||
if (Press(SDLK_LEFTBRACKET) || ShiftPress(SDLK_TAB)) {
|
||||
left = true;
|
||||
}
|
||||
IndentSelectedLines(active.view, left);
|
||||
} RegisterCommand(Command_IndentSelectedLines, "ctrl-leftbracket | ctrl-rightbracket | tab | shift-tab");
|
||||
IndentSelectedLines(active.view);
|
||||
} RegisterCommand(Command_IndentSelectedLines, "ctrl-rightbracket | tab");
|
||||
|
||||
void Command_DedentSelectedLines() {
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
IndentSelectedLines(active.view, true);
|
||||
} RegisterCommand(Command_DedentSelectedLines, "ctrl-leftbracket | shift-tab");
|
||||
|
||||
void Command_DuplicateLineDown() {
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
@@ -1608,44 +1646,3 @@ void Command_ClearCarets() {
|
||||
}
|
||||
}
|
||||
} RegisterCommand(Command_ClearCarets, "escape");
|
||||
|
||||
void Hook_OnDropFile(String *text) {
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
WindowOpenBufferView(active.window, *text);
|
||||
} RegisterHook(&OnDropFileHooks, Hook_OnDropFile);
|
||||
|
||||
void Hook_OnTextInput(String *text) {
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
Scratch scratch;
|
||||
String16 string16 = ToString16(scratch, *text);
|
||||
Replace(active.view, string16);
|
||||
} RegisterHook(&OnTextInputHooks, Hook_OnTextInput);
|
||||
|
||||
void Hook_PostCommandFuzzySearchUpdate(void *param) {
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
if (active.view->fuzzy_search) {
|
||||
if (!ProcessIsActive(active.view->id)) {
|
||||
Scratch scratch;
|
||||
String16 last_line_string = GetLineStringWithoutNL(active.buffer, active.buffer->line_starts.len - 1);
|
||||
if (active.view->prev_search_line != last_line_string) {
|
||||
active.view->prev_search_line = last_line_string;
|
||||
Array<FuzzyPair> ratings = FuzzySearchLines(scratch, active.buffer, 0, active.buffer->line_starts.len - 1, last_line_string);
|
||||
|
||||
Buffer *temp_buffer = CreateTempBuffer(scratch, active.buffer->cap);
|
||||
For(IterateInReverse(&ratings)) {
|
||||
String16 s = GetLineStringWithoutNL(active.buffer, it.index);
|
||||
if (s.len == 0) continue;
|
||||
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), s);
|
||||
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), u"\n");
|
||||
}
|
||||
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), last_line_string);
|
||||
|
||||
Caret caret = active.view->carets[0];
|
||||
SaveCaretHistoryBeforeBeginEdit(active.buffer, active.view->carets);
|
||||
SelectEntireBuffer(active.view);
|
||||
Replace(active.view, GetString(temp_buffer));
|
||||
active.view->carets[0] = caret;
|
||||
}
|
||||
}
|
||||
}
|
||||
} RegisterHook(&PostCommandHooks, Hook_PostCommandFuzzySearchUpdate);
|
||||
@@ -1,319 +0,0 @@
|
||||
void UpdateScroll(Window *window, bool update_caret_scrolling) {
|
||||
ProfileFunction();
|
||||
BSet set = GetBSet(window);
|
||||
|
||||
// Scrolling with caret
|
||||
if (update_caret_scrolling) {
|
||||
Caret c = set.view->carets[0];
|
||||
Int front = GetFront(c);
|
||||
XY xy = PosToXY(set.buffer, front);
|
||||
|
||||
Rect2I visible = GetVisibleCells(window);
|
||||
Vec2I visible_cells = GetSize(visible);
|
||||
Vec2I visible_size = visible_cells * Vec2I{window->font->char_spacing, window->font->line_spacing};
|
||||
Vec2I rect_size = GetSize(window->document_rect);
|
||||
|
||||
if (xy.line >= visible.max.y - 2) {
|
||||
Int set_view_at_line = xy.line - (visible_cells.y - 1);
|
||||
Int cut_off_y = Max((Int)0, visible_size.y - rect_size.y);
|
||||
set.view->scroll.y = (set_view_at_line * window->font->line_spacing) + cut_off_y;
|
||||
}
|
||||
|
||||
if (xy.line < visible.min.y + 1) {
|
||||
set.view->scroll.y = xy.line * window->font->line_spacing;
|
||||
}
|
||||
|
||||
if (xy.col >= visible.max.x - 1) {
|
||||
Int set_view_at_line = xy.col - (visible_cells.x - 1);
|
||||
Int cut_off_x = Max((Int)0, visible_size.x - rect_size.x);
|
||||
set.view->scroll.x = (set_view_at_line * window->font->char_spacing) + cut_off_x;
|
||||
}
|
||||
|
||||
if (xy.col <= visible.min.x) {
|
||||
set.view->scroll.x = xy.col * window->font->char_spacing;
|
||||
}
|
||||
}
|
||||
|
||||
// Clip scroll
|
||||
{
|
||||
Int last_line = LastLine(set.buffer);
|
||||
set.view->scroll.y = Clamp(set.view->scroll.y, (Int)0, Max((Int)0, (last_line - 1) * window->font->line_spacing));
|
||||
|
||||
// @note:
|
||||
// GetCharCountOfLongestLine is a bottleneck, there is probably an algorithm for
|
||||
// calculating this value incrementally but do we even need X scrollbar or x clipping?
|
||||
set.view->scroll.x = ClampBottom(set.view->scroll.x, (Int)0);
|
||||
}
|
||||
}
|
||||
|
||||
void OnCommand(Event event) {
|
||||
ProfileFunction();
|
||||
//
|
||||
// Window cursor setting
|
||||
//
|
||||
Scratch scratch;
|
||||
Array<Window *> order = GetWindowZOrder(scratch);
|
||||
|
||||
|
||||
// Handle wheel scrolling
|
||||
if (event.xwheel || event.ywheel) {
|
||||
Vec2I mouse = MouseVec2I();
|
||||
|
||||
For(order) {
|
||||
if (!it->visible) continue;
|
||||
|
||||
bool mouse_in_window = AreOverlapping(mouse, it->total_rect);
|
||||
if (mouse_in_window) {
|
||||
View *view = GetView(it->active_view);
|
||||
view->scroll.y -= (Int)(event.ywheel * 48);
|
||||
view->scroll.x += (Int)(event.xwheel * 48);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle selected window scrollbar
|
||||
// @note: the order here assumes that we won't run this code on the
|
||||
// same event as the scroll was pressed
|
||||
if (IsScrollbarSelectionValid() && Mouse(LEFT_UP)) {
|
||||
Assert(DocumentSelected.id == -1);
|
||||
ScrollbarSelected.id = -1;
|
||||
} else if (IsScrollbarSelectionValid()) {
|
||||
// :ScrollbarImprovement
|
||||
// @todo: it generally works ok but it moves the scrollbar a bit on click
|
||||
// when mouse is not even moving
|
||||
Assert(DocumentSelected.id == -1);
|
||||
Window *window = GetWindow(ScrollbarSelected);
|
||||
View *view = GetView(window->active_view);
|
||||
Vec2 mouse_vec2 = MouseVec2();
|
||||
Scroller s = ComputeScrollerRect(window);
|
||||
double size_y = (double)GetSize(window->scrollbar_rect).y;
|
||||
double p = mouse_vec2.y - window->scrollbar_rect.min.y;
|
||||
double v = p / size_y;
|
||||
v = v + (window->mouse_scroller_offset);
|
||||
view->scroll.y = (Int)(v * (double)s.line_count * (double)window->font->line_spacing);
|
||||
}
|
||||
|
||||
if (DocumentSelected != ActiveWindowID) {
|
||||
DocumentSelected.id = -1;
|
||||
} else if (IsDocumentSelectionValid() && MouseUp()) {
|
||||
Assert(ScrollbarSelected.id == -1);
|
||||
DocumentSelected.id = -1;
|
||||
} else if (IsDocumentSelectionValid()) {
|
||||
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
|
||||
// be smaller then 0 which means we cannot scroll
|
||||
if (mouse.y == 0 && selected.window->document_rect.min.y == 0) {
|
||||
float x, y;
|
||||
SDL_GetGlobalMouseState(&x, &y);
|
||||
x = roundf(DPIScale * x);
|
||||
y = roundf(DPIScale * y);
|
||||
if (y == 0) {
|
||||
mouse.y = -10;
|
||||
}
|
||||
}
|
||||
|
||||
Int p = ScreenSpaceToBufferPos(selected.window, selected.view, selected.buffer, mouse);
|
||||
Caret &caret = selected.view->carets[0];
|
||||
caret = SetFrontWithAnchor(caret, DocumentAnchor, p);
|
||||
}
|
||||
|
||||
if (ResizerSelected.id != -1 && Mouse(LEFT_UP)) {
|
||||
Assert(DocumentSelected.id == -1);
|
||||
Assert(ScrollbarSelected.id == -1);
|
||||
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 {
|
||||
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
|
||||
if (MousePress()) {
|
||||
Vec2I mouse = MouseVec2I();
|
||||
For(order) {
|
||||
if (!it->visible) {
|
||||
continue;
|
||||
}
|
||||
bool mouse_in_document = AreOverlapping(mouse, it->document_rect);
|
||||
if (mouse_in_document) {
|
||||
ActiveWindowID = it->id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Ctrl() && Shift() && Mouse(RIGHT)) {
|
||||
|
||||
} else if (Alt() && Ctrl() && Mouse(RIGHT)) {
|
||||
} else if (Ctrl() && Mouse(RIGHT)) {
|
||||
|
||||
} else if (Alt() && Mouse(RIGHT)) {
|
||||
} else if (Mouse(RIGHT)) {
|
||||
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);
|
||||
Int saved_front = -1;
|
||||
|
||||
IterRemove(active.view->carets) {
|
||||
IterRemovePrepare(active.view->carets);
|
||||
if (InBounds(it.range, p)) {
|
||||
String16 string = GetString(active.buffer, it.range);
|
||||
SaveStringInClipboard(string);
|
||||
|
||||
remove_item = true;
|
||||
saved_front = GetFront(it);
|
||||
}
|
||||
}
|
||||
if (active.view->carets.len == 0) Add(&active.view->carets, MakeCaret(saved_front));
|
||||
|
||||
if (saved_front == -1) {
|
||||
Int line = PosToLine(active.buffer, p);
|
||||
Range line_range = GetLineRangeWithoutNL(active.buffer, line);
|
||||
String16 string = GetString(active.buffer, line_range);
|
||||
SaveStringInClipboard(string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Ctrl() && Mouse(LEFT)) {
|
||||
MouseLoadWord(event);
|
||||
} else if (Mouse(LEFT)) { // Uses Alt and shift
|
||||
Vec2I mouse = MouseVec2I();
|
||||
{
|
||||
Assert(ScrollbarSelected.id == -1);
|
||||
Assert(DocumentSelected.id == -1);
|
||||
|
||||
BSet active = GetBSet(ActiveWindowID); // using next to make sure mouse works on first click after switching the window
|
||||
bool mouse_in_document = AreOverlapping(mouse, active.window->document_rect);
|
||||
bool mouse_in_line_numbers = AreOverlapping(mouse, active.window->line_numbers_rect);
|
||||
if (mouse_in_document || mouse_in_line_numbers) {
|
||||
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);
|
||||
if (!Alt() && !Shift()) active.view->carets.len = 1;
|
||||
|
||||
Caret &caret = active.view->carets[0];
|
||||
if (Shift()) {
|
||||
if (p <= caret.range.min) {
|
||||
caret.range.min = p;
|
||||
caret.ifront = 0;
|
||||
} else if (p >= caret.range.max) {
|
||||
caret.range.max = p;
|
||||
caret.ifront = 1;
|
||||
}
|
||||
} else if (event.clicks >= 2 && InBounds({caret.range.min - 1, caret.range.max + 1}, p)) {
|
||||
Range range = EncloseWord(active.buffer, p);
|
||||
if (event.clicks >= 3) {
|
||||
range = EncloseFullLine(active.buffer, p);
|
||||
}
|
||||
caret = MakeCaret(range.max, range.min);
|
||||
} else {
|
||||
caret = MakeCaret(p);
|
||||
}
|
||||
MergeCarets(active.buffer, &active.view->carets);
|
||||
DocumentAnchor = caret;
|
||||
}
|
||||
}
|
||||
|
||||
// Figure out scrollbar click
|
||||
// :ScrollbarImprovement
|
||||
// @todo: it generally works ok but it moves the scrollbar a bit on click
|
||||
// when mouse is not even moving
|
||||
For(order) {
|
||||
if (!it->visible) continue;
|
||||
bool mouse_in_scrollbar = AreOverlapping(mouse, it->scrollbar_rect);
|
||||
if (mouse_in_scrollbar) {
|
||||
ScrollbarSelected = it->id;
|
||||
|
||||
View *view = GetView(it->active_view);
|
||||
Vec2 mouse_vec2 = MouseVec2();
|
||||
Scroller s = ComputeScrollerRect(it);
|
||||
double size_y = (double)GetSize(it->scrollbar_rect).y;
|
||||
double p = mouse_vec2.y - it->scrollbar_rect.min.y;
|
||||
if (mouse_vec2.y < s.rect.min.y || mouse_vec2.y > s.rect.max.y) {
|
||||
view->scroll.y = (Int)(p / size_y * (double)s.line_count * (double)it->font->line_spacing);
|
||||
it->mouse_scroller_offset = -(double)GetSize(s.rect).y / 2.0 / size_y;
|
||||
} else {
|
||||
it->mouse_scroller_offset = (s.rect.min.y - p) / size_y;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
|
||||
// @todo: somehow detect in post command that buffer changed but random buffer can get changed??? Not sure
|
||||
// maybe we
|
||||
Int buffer_change_id = active.buffer->change_id;
|
||||
String event_text = event.text;
|
||||
|
||||
SkipRemainingCommands = false;
|
||||
For (CommandFunctions) {
|
||||
if (it.trigger && MatchEvent(it.trigger, &event)) {
|
||||
it.function();
|
||||
if (SkipRemainingCommands) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event.kind == EVENT_DROP_FILE) {
|
||||
SkipRemainingCommands = false;
|
||||
For (OnDropFileHooks) {
|
||||
it.function(&event_text);
|
||||
if (SkipRemainingCommands) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event.kind == EVENT_TEXT_INPUT) {
|
||||
SkipRemainingCommands = false;
|
||||
For (OnTextInputHooks) {
|
||||
it.function(&event_text);
|
||||
if (SkipRemainingCommands) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MergeCarets(active.buffer, &active.view->carets);
|
||||
IF_DEBUG(AssertRanges(active.view->carets));
|
||||
MergeCarets(main.buffer, &main.view->carets);
|
||||
IF_DEBUG(AssertRanges(main.view->carets));
|
||||
|
||||
SkipRemainingCommands = false;
|
||||
For (PostCommandHooks) {
|
||||
it.function(NULL);
|
||||
if (SkipRemainingCommands) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,6 @@ RandomSeed UniqueBufferNameSeed = {};
|
||||
Array<Event> EventPlayback;
|
||||
lua_State *LuaState = NULL;
|
||||
BlockArena Perm;
|
||||
Event *OnCommandEvent;
|
||||
|
||||
// clipboard
|
||||
BlockArena ClipboardArena;
|
||||
@@ -196,10 +195,6 @@ Array<CommandData> CommandFunctions;
|
||||
Array<LuaFunctionData> LuaFunctions;
|
||||
Array<FunctionData> TestFunctions;
|
||||
|
||||
Array<PFunctionData> PostCommandHooks;
|
||||
Array<PFunctionData> OnTextInputHooks;
|
||||
Array<PFunctionData> OnDropFileHooks;
|
||||
|
||||
struct Register_Function {
|
||||
Register_Function(Array<FunctionData> *functions, String name, Function *f) {
|
||||
int64_t pos = 0;
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
BSet GetBSet(Window *window) {
|
||||
BSet set = {window};
|
||||
set.view = GetView(set.window->active_view);
|
||||
set.buffer = GetBuffer(set.view->active_buffer);
|
||||
return set;
|
||||
}
|
||||
|
||||
BSet GetBSet(WindowID window_id) {
|
||||
Window *window = GetWindow(window_id);
|
||||
BSet result = GetBSet(window);
|
||||
return result;
|
||||
}
|
||||
|
||||
BSet GetConsoleSet() {
|
||||
BSet result = {};
|
||||
result.window = GetWindow(NullWindowID);
|
||||
result.view = GetView(NullViewID);
|
||||
result.buffer = GetBuffer(NullBufferID);
|
||||
return result;
|
||||
}
|
||||
|
||||
String GetCurrentFilename() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
return main.buffer->name;
|
||||
}
|
||||
|
||||
String GetDir(Buffer *buffer) {
|
||||
String name = ChopLastSlash(buffer->name);
|
||||
return name;
|
||||
}
|
||||
|
||||
String GetMainDir() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
String name = ChopLastSlash(main.buffer->name);
|
||||
return name;
|
||||
}
|
||||
|
||||
void GarbageCollect() {
|
||||
Allocator sys_allocator = GetSystemAllocator();
|
||||
|
||||
For (Windows) {
|
||||
if (it->sync_visibility_with_focus) {
|
||||
if (it->id == ActiveWindowID) {
|
||||
it->visible = true;
|
||||
} else {
|
||||
it->visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Window *window = GetWindow(ActiveWindowID);
|
||||
if (ActiveWindowID.id != LastActiveLayoutWindowID.id) {
|
||||
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) {
|
||||
it->changed_on_disk = true;
|
||||
if (it->dirty == false) ReopenBuffer(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IterRemove(Views) {
|
||||
IterRemovePrepare(Views);
|
||||
|
||||
Buffer *buffer = GetBuffer(it->active_buffer);
|
||||
if (!buffer->garbage) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool ref = ViewIsReferenced(it->id);
|
||||
if (ref) {
|
||||
continue;
|
||||
}
|
||||
|
||||
remove_item = true;
|
||||
Dealloc(&it->carets);
|
||||
Dealloc(sys_allocator, it);
|
||||
}
|
||||
|
||||
IterRemove(Buffers) {
|
||||
IterRemovePrepare(Buffers);
|
||||
|
||||
if (!it->garbage) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool ref = BufferIsReferenced(it->id);
|
||||
if (ref) {
|
||||
continue;
|
||||
}
|
||||
|
||||
remove_item = true;
|
||||
DeallocBuffer(it);
|
||||
}
|
||||
|
||||
IterRemove(Windows) {
|
||||
IterRemovePrepare(Windows);
|
||||
if (it->kill) {
|
||||
Dealloc(&it->goto_history);
|
||||
Dealloc(&it->goto_redo);
|
||||
Dealloc(sys_allocator, it);
|
||||
remove_item = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,6 @@
|
||||
#include "buffer.cpp"
|
||||
#include "view.cpp"
|
||||
#include "window.cpp"
|
||||
#include "management.cpp"
|
||||
#include "process.cpp"
|
||||
#include "event.cpp"
|
||||
#include "parser.cpp"
|
||||
@@ -38,7 +37,6 @@
|
||||
#include "commands.cpp"
|
||||
#include "lua_api.cpp"
|
||||
#include "commands_clipboard.cpp"
|
||||
#include "commands_bindings.cpp"
|
||||
#include "title_bar.cpp"
|
||||
|
||||
#include "generated_config.cpp"
|
||||
@@ -122,6 +120,407 @@ void SetMouseCursor(Event event) {
|
||||
}
|
||||
SetMouseCursor(SDL_SYSTEM_CURSOR_DEFAULT);
|
||||
}
|
||||
void UpdateScroll(Window *window, bool update_caret_scrolling) {
|
||||
ProfileFunction();
|
||||
BSet set = GetBSet(window);
|
||||
|
||||
// Scrolling with caret
|
||||
if (update_caret_scrolling) {
|
||||
Caret c = set.view->carets[0];
|
||||
Int front = GetFront(c);
|
||||
XY xy = PosToXY(set.buffer, front);
|
||||
|
||||
Rect2I visible = GetVisibleCells(window);
|
||||
Vec2I visible_cells = GetSize(visible);
|
||||
Vec2I visible_size = visible_cells * Vec2I{window->font->char_spacing, window->font->line_spacing};
|
||||
Vec2I rect_size = GetSize(window->document_rect);
|
||||
|
||||
if (xy.line >= visible.max.y - 2) {
|
||||
Int set_view_at_line = xy.line - (visible_cells.y - 1);
|
||||
Int cut_off_y = Max((Int)0, visible_size.y - rect_size.y);
|
||||
set.view->scroll.y = (set_view_at_line * window->font->line_spacing) + cut_off_y;
|
||||
}
|
||||
|
||||
if (xy.line < visible.min.y + 1) {
|
||||
set.view->scroll.y = xy.line * window->font->line_spacing;
|
||||
}
|
||||
|
||||
if (xy.col >= visible.max.x - 1) {
|
||||
Int set_view_at_line = xy.col - (visible_cells.x - 1);
|
||||
Int cut_off_x = Max((Int)0, visible_size.x - rect_size.x);
|
||||
set.view->scroll.x = (set_view_at_line * window->font->char_spacing) + cut_off_x;
|
||||
}
|
||||
|
||||
if (xy.col <= visible.min.x) {
|
||||
set.view->scroll.x = xy.col * window->font->char_spacing;
|
||||
}
|
||||
}
|
||||
|
||||
// Clip scroll
|
||||
{
|
||||
Int last_line = LastLine(set.buffer);
|
||||
set.view->scroll.y = Clamp(set.view->scroll.y, (Int)0, Max((Int)0, (last_line - 1) * window->font->line_spacing));
|
||||
|
||||
// @note:
|
||||
// GetCharCountOfLongestLine is a bottleneck, there is probably an algorithm for
|
||||
// calculating this value incrementally but do we even need X scrollbar or x clipping?
|
||||
set.view->scroll.x = ClampBottom(set.view->scroll.x, (Int)0);
|
||||
}
|
||||
}
|
||||
|
||||
void OnCommand(Event event) {
|
||||
ProfileFunction();
|
||||
//
|
||||
// Window cursor setting
|
||||
//
|
||||
Scratch scratch;
|
||||
Array<Window *> order = GetWindowZOrder(scratch);
|
||||
|
||||
|
||||
// Handle wheel scrolling
|
||||
if (event.xwheel || event.ywheel) {
|
||||
Vec2I mouse = MouseVec2I();
|
||||
|
||||
For(order) {
|
||||
if (!it->visible) continue;
|
||||
|
||||
bool mouse_in_window = AreOverlapping(mouse, it->total_rect);
|
||||
if (mouse_in_window) {
|
||||
View *view = GetView(it->active_view);
|
||||
view->scroll.y -= (Int)(event.ywheel * 48);
|
||||
view->scroll.x += (Int)(event.xwheel * 48);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle selected window scrollbar
|
||||
// @note: the order here assumes that we won't run this code on the
|
||||
// same event as the scroll was pressed
|
||||
if (IsScrollbarSelectionValid() && Mouse(LEFT_UP)) {
|
||||
Assert(DocumentSelected.id == -1);
|
||||
ScrollbarSelected.id = -1;
|
||||
} else if (IsScrollbarSelectionValid()) {
|
||||
// :ScrollbarImprovement
|
||||
// @todo: it generally works ok but it moves the scrollbar a bit on click
|
||||
// when mouse is not even moving
|
||||
Assert(DocumentSelected.id == -1);
|
||||
Window *window = GetWindow(ScrollbarSelected);
|
||||
View *view = GetView(window->active_view);
|
||||
Vec2 mouse_vec2 = MouseVec2();
|
||||
Scroller s = ComputeScrollerRect(window);
|
||||
double size_y = (double)GetSize(window->scrollbar_rect).y;
|
||||
double p = mouse_vec2.y - window->scrollbar_rect.min.y;
|
||||
double v = p / size_y;
|
||||
v = v + (window->mouse_scroller_offset);
|
||||
view->scroll.y = (Int)(v * (double)s.line_count * (double)window->font->line_spacing);
|
||||
}
|
||||
|
||||
if (DocumentSelected != ActiveWindowID) {
|
||||
DocumentSelected.id = -1;
|
||||
} else if (IsDocumentSelectionValid() && MouseUp()) {
|
||||
Assert(ScrollbarSelected.id == -1);
|
||||
DocumentSelected.id = -1;
|
||||
} else if (IsDocumentSelectionValid()) {
|
||||
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
|
||||
// be smaller then 0 which means we cannot scroll
|
||||
if (mouse.y == 0 && selected.window->document_rect.min.y == 0) {
|
||||
float x, y;
|
||||
SDL_GetGlobalMouseState(&x, &y);
|
||||
x = roundf(DPIScale * x);
|
||||
y = roundf(DPIScale * y);
|
||||
if (y == 0) {
|
||||
mouse.y = -10;
|
||||
}
|
||||
}
|
||||
|
||||
Int p = ScreenSpaceToBufferPos(selected.window, selected.view, selected.buffer, mouse);
|
||||
Caret &caret = selected.view->carets[0];
|
||||
caret = SetFrontWithAnchor(caret, DocumentAnchor, p);
|
||||
}
|
||||
|
||||
if (ResizerSelected.id != -1 && Mouse(LEFT_UP)) {
|
||||
Assert(DocumentSelected.id == -1);
|
||||
Assert(ScrollbarSelected.id == -1);
|
||||
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 {
|
||||
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
|
||||
if (MousePress()) {
|
||||
Vec2I mouse = MouseVec2I();
|
||||
For(order) {
|
||||
if (!it->visible) {
|
||||
continue;
|
||||
}
|
||||
bool mouse_in_document = AreOverlapping(mouse, it->document_rect);
|
||||
if (mouse_in_document) {
|
||||
ActiveWindowID = it->id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Ctrl() && Shift() && Mouse(RIGHT)) {
|
||||
|
||||
} else if (Alt() && Ctrl() && Mouse(RIGHT)) {
|
||||
} else if (Ctrl() && Mouse(RIGHT)) {
|
||||
|
||||
} else if (Alt() && Mouse(RIGHT)) {
|
||||
} else if (Mouse(RIGHT)) {
|
||||
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);
|
||||
Int saved_front = -1;
|
||||
|
||||
IterRemove(active.view->carets) {
|
||||
IterRemovePrepare(active.view->carets);
|
||||
if (InBounds(it.range, p)) {
|
||||
String16 string = GetString(active.buffer, it.range);
|
||||
SaveStringInClipboard(string);
|
||||
|
||||
remove_item = true;
|
||||
saved_front = GetFront(it);
|
||||
}
|
||||
}
|
||||
if (active.view->carets.len == 0) Add(&active.view->carets, MakeCaret(saved_front));
|
||||
|
||||
if (saved_front == -1) {
|
||||
Int line = PosToLine(active.buffer, p);
|
||||
Range line_range = GetLineRangeWithoutNL(active.buffer, line);
|
||||
String16 string = GetString(active.buffer, line_range);
|
||||
SaveStringInClipboard(string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Ctrl() && Mouse(LEFT)) {
|
||||
MouseLoadWord(event);
|
||||
} else if (Mouse(LEFT)) { // Uses Alt and shift
|
||||
Vec2I mouse = MouseVec2I();
|
||||
{
|
||||
Assert(ScrollbarSelected.id == -1);
|
||||
Assert(DocumentSelected.id == -1);
|
||||
|
||||
BSet active = GetBSet(ActiveWindowID); // using next to make sure mouse works on first click after switching the window
|
||||
bool mouse_in_document = AreOverlapping(mouse, active.window->document_rect);
|
||||
bool mouse_in_line_numbers = AreOverlapping(mouse, active.window->line_numbers_rect);
|
||||
if (mouse_in_document || mouse_in_line_numbers) {
|
||||
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);
|
||||
if (!Alt() && !Shift()) active.view->carets.len = 1;
|
||||
|
||||
Caret &caret = active.view->carets[0];
|
||||
if (Shift()) {
|
||||
if (p <= caret.range.min) {
|
||||
caret.range.min = p;
|
||||
caret.ifront = 0;
|
||||
} else if (p >= caret.range.max) {
|
||||
caret.range.max = p;
|
||||
caret.ifront = 1;
|
||||
}
|
||||
} else if (event.clicks >= 2 && InBounds({caret.range.min - 1, caret.range.max + 1}, p)) {
|
||||
Range range = EncloseWord(active.buffer, p);
|
||||
if (event.clicks >= 3) {
|
||||
range = EncloseFullLine(active.buffer, p);
|
||||
}
|
||||
caret = MakeCaret(range.max, range.min);
|
||||
} else {
|
||||
caret = MakeCaret(p);
|
||||
}
|
||||
MergeCarets(active.buffer, &active.view->carets);
|
||||
DocumentAnchor = caret;
|
||||
}
|
||||
}
|
||||
|
||||
// Figure out scrollbar click
|
||||
// :ScrollbarImprovement
|
||||
// @todo: it generally works ok but it moves the scrollbar a bit on click
|
||||
// when mouse is not even moving
|
||||
For(order) {
|
||||
if (!it->visible) continue;
|
||||
bool mouse_in_scrollbar = AreOverlapping(mouse, it->scrollbar_rect);
|
||||
if (mouse_in_scrollbar) {
|
||||
ScrollbarSelected = it->id;
|
||||
|
||||
View *view = GetView(it->active_view);
|
||||
Vec2 mouse_vec2 = MouseVec2();
|
||||
Scroller s = ComputeScrollerRect(it);
|
||||
double size_y = (double)GetSize(it->scrollbar_rect).y;
|
||||
double p = mouse_vec2.y - it->scrollbar_rect.min.y;
|
||||
if (mouse_vec2.y < s.rect.min.y || mouse_vec2.y > s.rect.max.y) {
|
||||
view->scroll.y = (Int)(p / size_y * (double)s.line_count * (double)it->font->line_spacing);
|
||||
it->mouse_scroller_offset = -(double)GetSize(s.rect).y / 2.0 / size_y;
|
||||
} else {
|
||||
it->mouse_scroller_offset = (s.rect.min.y - p) / size_y;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
|
||||
// @todo: somehow detect in post command that buffer changed but random buffer can get changed??? Not sure
|
||||
// maybe we use a timestamo instead !
|
||||
Int buffer_change_id = active.buffer->change_id;
|
||||
|
||||
SkipRemainingCommands = false;
|
||||
For (CommandFunctions) {
|
||||
if (it.trigger && MatchEvent(it.trigger, &event)) {
|
||||
it.function();
|
||||
if (SkipRemainingCommands) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event.kind == EVENT_DROP_FILE) {
|
||||
WindowOpenBufferView(active.window, event.text);
|
||||
}
|
||||
|
||||
if (event.kind == EVENT_TEXT_INPUT) {
|
||||
Scratch scratch;
|
||||
String16 string16 = ToString16(scratch, event.text);
|
||||
Replace(active.view, string16);
|
||||
}
|
||||
|
||||
if (active.view->fuzzy_search) {
|
||||
if (!ProcessIsActive(active.view->id)) {
|
||||
Scratch scratch;
|
||||
String16 last_line_string = GetLineStringWithoutNL(active.buffer, active.buffer->line_starts.len - 1);
|
||||
if (active.view->prev_search_line != last_line_string) {
|
||||
active.view->prev_search_line = last_line_string;
|
||||
Array<FuzzyPair> ratings = FuzzySearchLines(scratch, active.buffer, 0, active.buffer->line_starts.len - 1, last_line_string);
|
||||
|
||||
Buffer *temp_buffer = CreateTempBuffer(scratch, active.buffer->cap);
|
||||
For(IterateInReverse(&ratings)) {
|
||||
String16 s = GetLineStringWithoutNL(active.buffer, it.index);
|
||||
if (s.len == 0) continue;
|
||||
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), s);
|
||||
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), u"\n");
|
||||
}
|
||||
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), last_line_string);
|
||||
|
||||
Caret caret = active.view->carets[0];
|
||||
SaveCaretHistoryBeforeBeginEdit(active.buffer, active.view->carets);
|
||||
SelectEntireBuffer(active.view);
|
||||
Replace(active.view, GetString(temp_buffer));
|
||||
active.view->carets[0] = caret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MergeCarets(active.buffer, &active.view->carets);
|
||||
IF_DEBUG(AssertRanges(active.view->carets));
|
||||
MergeCarets(main.buffer, &main.view->carets);
|
||||
IF_DEBUG(AssertRanges(main.view->carets));
|
||||
}
|
||||
|
||||
void GarbageCollect() {
|
||||
Allocator sys_allocator = GetSystemAllocator();
|
||||
|
||||
For (Windows) {
|
||||
if (it->sync_visibility_with_focus) {
|
||||
if (it->id == ActiveWindowID) {
|
||||
it->visible = true;
|
||||
} else {
|
||||
it->visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Window *window = GetWindow(ActiveWindowID);
|
||||
if (ActiveWindowID.id != LastActiveLayoutWindowID.id) {
|
||||
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) {
|
||||
it->changed_on_disk = true;
|
||||
if (it->dirty == false) ReopenBuffer(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IterRemove(Views) {
|
||||
IterRemovePrepare(Views);
|
||||
|
||||
Buffer *buffer = GetBuffer(it->active_buffer);
|
||||
if (!buffer->garbage) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool ref = ViewIsReferenced(it->id);
|
||||
if (ref) {
|
||||
continue;
|
||||
}
|
||||
|
||||
remove_item = true;
|
||||
Dealloc(&it->carets);
|
||||
Dealloc(sys_allocator, it);
|
||||
}
|
||||
|
||||
IterRemove(Buffers) {
|
||||
IterRemovePrepare(Buffers);
|
||||
|
||||
if (!it->garbage) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool ref = BufferIsReferenced(it->id);
|
||||
if (ref) {
|
||||
continue;
|
||||
}
|
||||
|
||||
remove_item = true;
|
||||
DeallocBuffer(it);
|
||||
}
|
||||
|
||||
IterRemove(Windows) {
|
||||
IterRemovePrepare(Windows);
|
||||
if (it->kill) {
|
||||
Dealloc(&it->goto_history);
|
||||
Dealloc(&it->goto_redo);
|
||||
Dealloc(sys_allocator, it);
|
||||
remove_item = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Update(Event event) {
|
||||
LayoutWindows(event.xwindow, event.ywindow);
|
||||
@@ -135,9 +534,7 @@ void Update(Event event) {
|
||||
view->update_scroll = true;
|
||||
}
|
||||
|
||||
OnCommandEvent = &event;
|
||||
OnCommand(event);
|
||||
OnCommandEvent = NULL;
|
||||
UpdateProcesses();
|
||||
CoUpdate(&event);
|
||||
ReloadLuaConfigs();
|
||||
|
||||
Reference in New Issue
Block a user