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) {
|
void ReplaceWithoutMovingCarets(Buffer *buffer, Range range, String16 string) {
|
||||||
View *view = GetViewForFixingWhenBufferCommand(buffer);
|
View *view = GetViewForBuffer(buffer);
|
||||||
Array<Caret> carets = Copy(GetSystemAllocator(), view->carets);
|
Array<Caret> carets = Copy(GetSystemAllocator(), view->carets);
|
||||||
|
|
||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
@@ -133,7 +102,7 @@ void TrimWhitespace(Buffer *buffer, bool trim_lines_with_caret) {
|
|||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
|
|
||||||
bool is_active_view = false;
|
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) {
|
if (!is_active_view && !trim_lines_with_caret) {
|
||||||
trim_lines_with_caret = true;
|
trim_lines_with_caret = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,13 @@ Rect2I GetVisibleCells(Window *window) {
|
|||||||
|
|
||||||
Int _cx = size.x / window->font->char_spacing;
|
Int _cx = size.x / window->font->char_spacing;
|
||||||
Int _cy = size.y / window->font->line_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 cx = _cx + 1;
|
||||||
Int cy = _cy + 2;
|
Int cy = _cy + 2;
|
||||||
|
|
||||||
@@ -200,7 +207,7 @@ void DrawWindow(Window *window, Event &event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Underline word under mouse cursor
|
// Underline word under mouse cursor
|
||||||
if (0) {
|
if (1) {
|
||||||
Caret caret = view->carets[0];
|
Caret caret = view->carets[0];
|
||||||
Vec2I mouse = MouseVec2I();
|
Vec2I mouse = MouseVec2I();
|
||||||
bool mouse_in_document = AreOverlapping(mouse, window->document_rect);
|
bool mouse_in_document = AreOverlapping(mouse, window->document_rect);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ Int ErrorCount;
|
|||||||
#if DEBUG_BUILD
|
#if DEBUG_BUILD
|
||||||
String16 InitialScratchContent = uR"==(:OpenProject
|
String16 InitialScratchContent = uR"==(:OpenProject
|
||||||
C:/text_editor/src/text_editor/text_editor.cpp
|
C:/text_editor/src/text_editor/text_editor.cpp
|
||||||
|
:Set FontSize 70
|
||||||
0
|
0
|
||||||
1
|
1
|
||||||
2
|
2
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ void SearchWindowFindNext(bool forward = true) {
|
|||||||
BSet set = GetBSet(SearchWindowID);
|
BSet set = GetBSet(SearchWindowID);
|
||||||
String16 seek = GetString(set.buffer, GetRange(set.buffer));
|
String16 seek = GetString(set.buffer, GetRange(set.buffer));
|
||||||
Find(main.view, seek, forward);
|
Find(main.view, seek, forward);
|
||||||
CenterView(PrimaryWindowID);
|
if (!IsMainCaretOnScreen(main.window).caret_on_screen) {
|
||||||
|
CenterView(main.window->id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMD_SearchNextInSearch() {
|
void CMD_SearchNextInSearch() {
|
||||||
@@ -100,7 +102,9 @@ void UpdateSearchWindow() {
|
|||||||
main.view->carets[0] = main.window->search_bar_anchor;
|
main.view->carets[0] = main.window->search_bar_anchor;
|
||||||
String16 seek = GetString(active.buffer, GetRange(active.buffer));
|
String16 seek = GetString(active.buffer, GetRange(active.buffer));
|
||||||
Find(main.view, seek, true);
|
Find(main.view, seek, true);
|
||||||
|
if (!IsMainCaretOnScreen(main.window).caret_on_screen) {
|
||||||
CenterView(main.window->id);
|
CenterView(main.window->id);
|
||||||
|
}
|
||||||
SearchBufferChangeID = active.buffer->change_id;
|
SearchBufferChangeID = active.buffer->change_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,42 +83,53 @@ void CWSLexIdentifiers(Array<StringAndDistance> *out_idents, Buffer *buffer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WordComplete(mco_coro *co) {
|
#if 0
|
||||||
Array<BufferID> buffers = {CWS.arena};
|
void CWSGetNextBuffer(mco_coro *co) {
|
||||||
{
|
// Would be nice to iterate through 64 last active buffers
|
||||||
Add(&buffers, CWS.buffer->id);
|
// - 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) {
|
ForItem (window, Windows) {
|
||||||
if (window->visible) {
|
if (!window->visible) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
View *view = GetView(window->active_view);
|
View *view = GetView(window->active_view);
|
||||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||||
if (!Contains(buffers, buffer->id)) {
|
if (Contains(CWS.visited_buffers, buffer->id)) {
|
||||||
Add(&buffers, buffer->id);
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Int len = 0;
|
Add(&CWS.visited_buffers, buffer->id);
|
||||||
For (IterateInReverse(&window->goto_history)) {
|
mco_result res = mco_push(co, &buffer->id, sizeof(buffer->id));
|
||||||
View *view = GetView(it.view_id);
|
Assert(res == MCO_SUCCESS);
|
||||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
mco_yield(co);
|
||||||
if (!Contains(buffers, buffer->id)) {
|
}
|
||||||
Add(&buffers, buffer->id);
|
}
|
||||||
len += 1;
|
#endif
|
||||||
if (len > 16) continue;
|
|
||||||
}
|
void WordComplete(mco_coro *co) {
|
||||||
}
|
Array<BufferID> buffers = {CWS.arena};
|
||||||
}
|
Add(&buffers, CWS.buffer->id);
|
||||||
Window *active = GetWindow(ActiveWindowID);
|
For (IterateInReverse(&Buffers)) {
|
||||||
|
Add(&buffers, it->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer *curr_buffer = NULL;
|
|
||||||
Int buffer_i = 0;
|
Int buffer_i = 0;
|
||||||
Array<StringAndDistance> idents = {CWS.arena};
|
Array<StringAndDistance> idents = {CWS.arena};
|
||||||
Add(&idents, {CWS.prefix_string, 0});
|
Add(&idents, {CWS.prefix_string, 0});
|
||||||
for (Int i = 1;;) {
|
for (Int i = 1;;) {
|
||||||
if (i >= idents.len) {
|
if (i >= idents.len) {
|
||||||
while (buffer_i < buffers.len) {
|
while (buffer_i < buffers.len) {
|
||||||
curr_buffer = GetBuffer(buffers[buffer_i++]);
|
Buffer *buffer = GetBuffer(buffers[buffer_i++]);
|
||||||
CWSLexIdentifiers(&idents, curr_buffer);
|
CWSLexIdentifiers(&idents, buffer);
|
||||||
if (i < idents.len) {
|
if (i < idents.len) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -130,14 +141,18 @@ void WordComplete(mco_coro *co) {
|
|||||||
StringAndDistance it = idents[i];
|
StringAndDistance it = idents[i];
|
||||||
String16 ident = Copy16(CWS.arena, it.string);
|
String16 ident = Copy16(CWS.arena, it.string);
|
||||||
CWS.last_string = ident;
|
CWS.last_string = ident;
|
||||||
Range range = EncloseWord(curr_buffer, CWS.original_caret_pos);
|
Range range = EncloseWord(CWS.buffer, CWS.original_caret_pos);
|
||||||
View *view = GetViewForFixingWhenBufferCommand(curr_buffer);
|
SelectRange(CWS.view, range);
|
||||||
SelectRange(view, range);
|
Replace(CWS.view, ident);
|
||||||
Replace(view, ident);
|
|
||||||
yield:;
|
yield:;
|
||||||
mco_yield(co);
|
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 += 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;
|
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 (!continue_with_previous) {
|
||||||
if (CWS.co) {
|
if (CWS.co) {
|
||||||
mco_result res = mco_destroy(CWS.co);
|
mco_result res = mco_destroy(CWS.co);
|
||||||
@@ -159,6 +174,7 @@ void WordComplete(View *view, Int pos) {
|
|||||||
Release(&CWS.arena);
|
Release(&CWS.arena);
|
||||||
MemoryZero(&CWS, sizeof(CWS));
|
MemoryZero(&CWS, sizeof(CWS));
|
||||||
|
|
||||||
|
// CWS.visited_buffers.allocator = CWS.arena;
|
||||||
CWS.buffer = buffer;
|
CWS.buffer = buffer;
|
||||||
CWS.view = view;
|
CWS.view = view;
|
||||||
CWS.original_caret_pos = pos;
|
CWS.original_caret_pos = pos;
|
||||||
|
|||||||
@@ -41,13 +41,33 @@ View *GetView(ViewID id, View *default_view = Views[0]) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
API View *GetView(BufferID buffer_id, View *default_view = Views[0]) {
|
View *GetViewForBuffer(Buffer *buffer, bool *is_active = NULL) {
|
||||||
For (Views) {
|
View *view = NULL;
|
||||||
if (it->active_buffer == buffer_id) {
|
if (is_active) {
|
||||||
return it;
|
*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]) {
|
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;
|
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) {
|
API View *OpenBufferView(String name) {
|
||||||
Buffer *buffer = BufferOpenFile(name);
|
Buffer *buffer = BufferOpenFile(name);
|
||||||
View *view = CreateView(buffer->id);
|
View *view = CreateView(buffer->id);
|
||||||
@@ -100,7 +129,7 @@ bool BufferIsReferenced(Buffer *buffer) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetView(buffer->id, NULL)) {
|
if (FindView(buffer->id, NULL)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -412,13 +412,46 @@ String GetDirectory(Window *window) {
|
|||||||
return GetDirectory(main.buffer);
|
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) {
|
void MoveCursorByPageSize(Window *window, int direction, bool shift = false) {
|
||||||
Assert(direction == DIR_UP || direction == DIR_DOWN);
|
Assert(direction == DIR_UP || direction == DIR_DOWN);
|
||||||
BSet set = GetBSet(window);
|
BSet set = GetBSet(window);
|
||||||
|
IsOnScreenResult is_on_screen_res = IsMainCaretOnScreen(window);
|
||||||
Rect2I visible_cells_rect = GetVisibleCells(window);
|
Rect2I visible_cells_rect = GetVisibleCells(window);
|
||||||
Int y = GetSize(visible_cells_rect).y - 2;
|
Int y = GetSize(visible_cells_rect).y - 2;
|
||||||
if (direction == DIR_UP) y = -y;
|
if (direction == DIR_UP) {
|
||||||
|
y = -y;
|
||||||
|
}
|
||||||
|
|
||||||
For(set.view->carets) {
|
For(set.view->carets) {
|
||||||
XY xy = PosToXY(set.buffer, GetFront(it));
|
XY xy = PosToXY(set.buffer, GetFront(it));
|
||||||
@@ -430,11 +463,13 @@ void MoveCursorByPageSize(Window *window, int direction, bool shift = false) {
|
|||||||
}
|
}
|
||||||
xy.line += y;
|
xy.line += y;
|
||||||
|
|
||||||
Int pos = XYToPos(set.buffer, xy);
|
Int pos = XYToPosWithoutNL(set.buffer, xy);
|
||||||
if (shift) {
|
if (shift) {
|
||||||
it = SetFront(it, pos);
|
it = SetFront(it, pos);
|
||||||
} else {
|
} else {
|
||||||
it = MakeCaret(pos);
|
it = MakeCaret(pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetStoredOffsetFromTop(window, is_on_screen_res);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user