Scrolling and word complete improvements
This commit is contained in:
@@ -1,36 +1,5 @@
|
||||
|
||||
|
||||
View *GetViewForFixingWhenBufferCommand(Buffer *buffer, bool *is_active = NULL) {
|
||||
View *view = NULL;
|
||||
if (is_active) {
|
||||
*is_active = false;
|
||||
}
|
||||
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
if (active.buffer->id == buffer->id) {
|
||||
if (is_active) {
|
||||
*is_active = true;
|
||||
}
|
||||
return active.view;
|
||||
}
|
||||
|
||||
For(Views) {
|
||||
if (it->active_buffer != buffer->id) {
|
||||
continue;
|
||||
}
|
||||
view = it;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!view) {
|
||||
view = CreateView(buffer->id);
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
void ReplaceWithoutMovingCarets(Buffer *buffer, Range range, String16 string) {
|
||||
View *view = GetViewForFixingWhenBufferCommand(buffer);
|
||||
View *view = GetViewForBuffer(buffer);
|
||||
Array<Caret> carets = Copy(GetSystemAllocator(), view->carets);
|
||||
|
||||
Scratch scratch;
|
||||
@@ -133,7 +102,7 @@ void TrimWhitespace(Buffer *buffer, bool trim_lines_with_caret) {
|
||||
Scratch scratch;
|
||||
|
||||
bool is_active_view = false;
|
||||
View *view = GetViewForFixingWhenBufferCommand(buffer, &is_active_view);
|
||||
View *view = GetViewForBuffer(buffer, &is_active_view);
|
||||
if (!is_active_view && !trim_lines_with_caret) {
|
||||
trim_lines_with_caret = true;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,13 @@ Rect2I GetVisibleCells(Window *window) {
|
||||
|
||||
Int _cx = size.x / window->font->char_spacing;
|
||||
Int _cy = size.y / window->font->line_spacing;
|
||||
|
||||
// This function is mostly used for rendering, these magic numbers are here
|
||||
// to make sure we are not showing unrendered part of the screen to the user.
|
||||
// These were derived by testing and experience. We are only rendering the
|
||||
// part that is on screen but need to account for the arbitrary pixel scrolling.
|
||||
// That is a cell can be half on screen, it's not like vim where you are stuck
|
||||
// to the grid.
|
||||
Int cx = _cx + 1;
|
||||
Int cy = _cy + 2;
|
||||
|
||||
@@ -200,7 +207,7 @@ void DrawWindow(Window *window, Event &event) {
|
||||
}
|
||||
|
||||
// Underline word under mouse cursor
|
||||
if (0) {
|
||||
if (1) {
|
||||
Caret caret = view->carets[0];
|
||||
Vec2I mouse = MouseVec2I();
|
||||
bool mouse_in_document = AreOverlapping(mouse, window->document_rect);
|
||||
|
||||
@@ -13,6 +13,7 @@ Int ErrorCount;
|
||||
#if DEBUG_BUILD
|
||||
String16 InitialScratchContent = uR"==(:OpenProject
|
||||
C:/text_editor/src/text_editor/text_editor.cpp
|
||||
:Set FontSize 70
|
||||
0
|
||||
1
|
||||
2
|
||||
|
||||
@@ -23,7 +23,9 @@ void SearchWindowFindNext(bool forward = true) {
|
||||
BSet set = GetBSet(SearchWindowID);
|
||||
String16 seek = GetString(set.buffer, GetRange(set.buffer));
|
||||
Find(main.view, seek, forward);
|
||||
CenterView(PrimaryWindowID);
|
||||
if (!IsMainCaretOnScreen(main.window).caret_on_screen) {
|
||||
CenterView(main.window->id);
|
||||
}
|
||||
}
|
||||
|
||||
void CMD_SearchNextInSearch() {
|
||||
@@ -100,7 +102,9 @@ void UpdateSearchWindow() {
|
||||
main.view->carets[0] = main.window->search_bar_anchor;
|
||||
String16 seek = GetString(active.buffer, GetRange(active.buffer));
|
||||
Find(main.view, seek, true);
|
||||
if (!IsMainCaretOnScreen(main.window).caret_on_screen) {
|
||||
CenterView(main.window->id);
|
||||
}
|
||||
SearchBufferChangeID = active.buffer->change_id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,42 +83,53 @@ void CWSLexIdentifiers(Array<StringAndDistance> *out_idents, Buffer *buffer) {
|
||||
}
|
||||
}
|
||||
|
||||
void WordComplete(mco_coro *co) {
|
||||
Array<BufferID> buffers = {CWS.arena};
|
||||
{
|
||||
Add(&buffers, CWS.buffer->id);
|
||||
#if 0
|
||||
void CWSGetNextBuffer(mco_coro *co) {
|
||||
// Would be nice to iterate through 64 last active buffers
|
||||
// - Then all buffers
|
||||
Add(&CWS.visited_buffers, CWS.buffer->id);
|
||||
mco_result res = mco_push(co, &CWS.buffer->id, sizeof(CWS.buffer->id));
|
||||
Assert(res == MCO_SUCCESS);
|
||||
mco_yield(co);
|
||||
|
||||
For (IterateInReverse(&Buffers)) {
|
||||
Add(&buffers, it->id);
|
||||
}
|
||||
|
||||
ForItem (window, Windows) {
|
||||
if (window->visible) {
|
||||
if (!window->visible) {
|
||||
continue;
|
||||
}
|
||||
|
||||
View *view = GetView(window->active_view);
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
if (!Contains(buffers, buffer->id)) {
|
||||
Add(&buffers, buffer->id);
|
||||
}
|
||||
}
|
||||
Int len = 0;
|
||||
For (IterateInReverse(&window->goto_history)) {
|
||||
View *view = GetView(it.view_id);
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
if (!Contains(buffers, buffer->id)) {
|
||||
Add(&buffers, buffer->id);
|
||||
len += 1;
|
||||
if (len > 16) continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
Window *active = GetWindow(ActiveWindowID);
|
||||
|
||||
if (Contains(CWS.visited_buffers, buffer->id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Add(&CWS.visited_buffers, buffer->id);
|
||||
mco_result res = mco_push(co, &buffer->id, sizeof(buffer->id));
|
||||
Assert(res == MCO_SUCCESS);
|
||||
mco_yield(co);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void WordComplete(mco_coro *co) {
|
||||
Array<BufferID> buffers = {CWS.arena};
|
||||
Add(&buffers, CWS.buffer->id);
|
||||
For (IterateInReverse(&Buffers)) {
|
||||
Add(&buffers, it->id);
|
||||
}
|
||||
|
||||
Buffer *curr_buffer = NULL;
|
||||
Int buffer_i = 0;
|
||||
Array<StringAndDistance> idents = {CWS.arena};
|
||||
Add(&idents, {CWS.prefix_string, 0});
|
||||
for (Int i = 1;;) {
|
||||
if (i >= idents.len) {
|
||||
while (buffer_i < buffers.len) {
|
||||
curr_buffer = GetBuffer(buffers[buffer_i++]);
|
||||
CWSLexIdentifiers(&idents, curr_buffer);
|
||||
Buffer *buffer = GetBuffer(buffers[buffer_i++]);
|
||||
CWSLexIdentifiers(&idents, buffer);
|
||||
if (i < idents.len) {
|
||||
break;
|
||||
}
|
||||
@@ -130,14 +141,18 @@ void WordComplete(mco_coro *co) {
|
||||
StringAndDistance it = idents[i];
|
||||
String16 ident = Copy16(CWS.arena, it.string);
|
||||
CWS.last_string = ident;
|
||||
Range range = EncloseWord(curr_buffer, CWS.original_caret_pos);
|
||||
View *view = GetViewForFixingWhenBufferCommand(curr_buffer);
|
||||
SelectRange(view, range);
|
||||
Replace(view, ident);
|
||||
Range range = EncloseWord(CWS.buffer, CWS.original_caret_pos);
|
||||
SelectRange(CWS.view, range);
|
||||
Replace(CWS.view, ident);
|
||||
yield:;
|
||||
mco_yield(co);
|
||||
if (CWS.direction == -1 && i > 0 && i == idents.len) {
|
||||
// special case for when we are at the end of the list and we want to go back
|
||||
// to make it sure we don't need to click twice to flip
|
||||
i -= 1;
|
||||
}
|
||||
i += CWS.direction;
|
||||
i = Clamp(i, 0ll, idents.len - 1);
|
||||
i = Clamp(i, 0ll, idents.len);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,7 +164,7 @@ void WordComplete(View *view, Int pos) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool continue_with_previous = CWS.co && CWS.last_string == prefix && CWS.buffer == buffer;
|
||||
bool continue_with_previous = CWS.co && CWS.last_string == prefix && CWS.buffer == buffer && CWS.view == view;
|
||||
if (!continue_with_previous) {
|
||||
if (CWS.co) {
|
||||
mco_result res = mco_destroy(CWS.co);
|
||||
@@ -159,6 +174,7 @@ void WordComplete(View *view, Int pos) {
|
||||
Release(&CWS.arena);
|
||||
MemoryZero(&CWS, sizeof(CWS));
|
||||
|
||||
// CWS.visited_buffers.allocator = CWS.arena;
|
||||
CWS.buffer = buffer;
|
||||
CWS.view = view;
|
||||
CWS.original_caret_pos = pos;
|
||||
|
||||
@@ -41,13 +41,33 @@ View *GetView(ViewID id, View *default_view = Views[0]) {
|
||||
return result;
|
||||
}
|
||||
|
||||
API View *GetView(BufferID buffer_id, View *default_view = Views[0]) {
|
||||
For (Views) {
|
||||
if (it->active_buffer == buffer_id) {
|
||||
return it;
|
||||
View *GetViewForBuffer(Buffer *buffer, bool *is_active = NULL) {
|
||||
View *view = NULL;
|
||||
if (is_active) {
|
||||
*is_active = false;
|
||||
}
|
||||
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
if (active.buffer->id == buffer->id) {
|
||||
if (is_active) {
|
||||
*is_active = true;
|
||||
}
|
||||
return default_view;
|
||||
return active.view;
|
||||
}
|
||||
|
||||
For(Views) {
|
||||
if (it->active_buffer != buffer->id) {
|
||||
continue;
|
||||
}
|
||||
view = it;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!view) {
|
||||
view = CreateView(buffer->id);
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
API View *GetView(String name, View *default_view = Views[0]) {
|
||||
@@ -60,6 +80,15 @@ API View *GetView(String name, View *default_view = Views[0]) {
|
||||
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 *OpenBufferView(String name) {
|
||||
Buffer *buffer = BufferOpenFile(name);
|
||||
View *view = CreateView(buffer->id);
|
||||
@@ -100,7 +129,7 @@ bool BufferIsReferenced(Buffer *buffer) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (GetView(buffer->id, NULL)) {
|
||||
if (FindView(buffer->id, NULL)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -412,13 +412,46 @@ String GetDirectory(Window *window) {
|
||||
return GetDirectory(main.buffer);
|
||||
}
|
||||
|
||||
struct IsOnScreenResult {
|
||||
bool caret_on_screen;
|
||||
Int offset_from_top;
|
||||
};
|
||||
|
||||
IsOnScreenResult IsMainCaretOnScreen(Window *window) {
|
||||
BSet set = GetBSet(window);
|
||||
Int front = GetFront(set.view->carets[0]);
|
||||
XY front_xy = PosToXY(set.buffer, front);
|
||||
Int caret_pixel_size = front_xy.y * set.window->font->line_spacing;
|
||||
Vec2I doc_pixel_size = GetSize(set.window->document_rect);
|
||||
|
||||
Int ystart = set.view->scroll.y;
|
||||
Int yend = ystart + doc_pixel_size.y;
|
||||
bool caret_on_screen = caret_pixel_size >= ystart && caret_pixel_size < yend;
|
||||
Int offset_from_top = caret_pixel_size - ystart;
|
||||
return {caret_on_screen, offset_from_top};
|
||||
}
|
||||
|
||||
bool SetStoredOffsetFromTop(Window *window, IsOnScreenResult res) {
|
||||
if (res.caret_on_screen) {
|
||||
BSet set = GetBSet(window);
|
||||
Int front = GetFront(set.view->carets[0]);
|
||||
XY front_xy = PosToXY(set.buffer, front);
|
||||
Int caret_pixel_size = front_xy.y * set.window->font->line_spacing;
|
||||
set.view->scroll.y = caret_pixel_size - res.offset_from_top;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MoveCursorByPageSize(Window *window, int direction, bool shift = false) {
|
||||
Assert(direction == DIR_UP || direction == DIR_DOWN);
|
||||
BSet set = GetBSet(window);
|
||||
|
||||
IsOnScreenResult is_on_screen_res = IsMainCaretOnScreen(window);
|
||||
Rect2I visible_cells_rect = GetVisibleCells(window);
|
||||
Int y = GetSize(visible_cells_rect).y - 2;
|
||||
if (direction == DIR_UP) y = -y;
|
||||
if (direction == DIR_UP) {
|
||||
y = -y;
|
||||
}
|
||||
|
||||
For(set.view->carets) {
|
||||
XY xy = PosToXY(set.buffer, GetFront(it));
|
||||
@@ -430,11 +463,13 @@ void MoveCursorByPageSize(Window *window, int direction, bool shift = false) {
|
||||
}
|
||||
xy.line += y;
|
||||
|
||||
Int pos = XYToPos(set.buffer, xy);
|
||||
Int pos = XYToPosWithoutNL(set.buffer, xy);
|
||||
if (shift) {
|
||||
it = SetFront(it, pos);
|
||||
} else {
|
||||
it = MakeCaret(pos);
|
||||
}
|
||||
}
|
||||
|
||||
SetStoredOffsetFromTop(window, is_on_screen_res);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user