summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2022-12-23 18:57:41 -0500
committerpommicket <pommicket@gmail.com>2022-12-23 18:57:41 -0500
commiteb7519e92f768224803ab66985541c99bddc2bf0 (patch)
tree53a414205020cad9e8fcd2d8436e30cfae872a6e
parent431a785f20127a7f1b6c1a6f1cd2a5031a7236ca (diff)
scroll through completions
-rw-r--r--autocomplete.c89
-rw-r--r--main.c10
-rw-r--r--math.c5
-rw-r--r--ted.h2
4 files changed, 72 insertions, 34 deletions
diff --git a/autocomplete.c b/autocomplete.c
index adfda6f..cc1bf41 100644
--- a/autocomplete.c
+++ b/autocomplete.c
@@ -37,13 +37,37 @@ static void autocomplete_select_cursor_completion(Ted *ted) {
}
}
+static void autocomplete_correct_scroll(Ted *ted) {
+ Autocomplete *ac = &ted->autocomplete;
+ i32 scroll = ac->scroll;
+ scroll = min_i32(scroll, (i32)arr_len(ac->suggested) - AUTOCOMPLETE_NCOMPLETIONS_VISIBLE);
+ scroll = max_i32(scroll, 0);
+ ac->scroll = scroll;
+}
+
+void autocomplete_scroll(Ted *ted, i32 by) {
+ Autocomplete *ac = &ted->autocomplete;
+ ac->scroll += by;
+ autocomplete_correct_scroll(ted);
+}
+
+static void autocomplete_move_cursor(Ted *ted, i32 by) {
+ Autocomplete *ac = &ted->autocomplete;
+ u32 ncompletions = arr_len(ac->suggested);
+ i32 cursor = ac->cursor;
+ cursor += by;
+ cursor = (i32)mod_i32(cursor, (i32)ncompletions);
+ ac->cursor = cursor;
+ ac->scroll = ac->cursor - AUTOCOMPLETE_NCOMPLETIONS_VISIBLE / 2;
+ autocomplete_correct_scroll(ted);
+}
static void autocomplete_next(Ted *ted) {
- ++ted->autocomplete.cursor;
+ autocomplete_move_cursor(ted, 1);
}
static void autocomplete_prev(Ted *ted) {
- --ted->autocomplete.cursor;
+ autocomplete_move_cursor(ted, -1);
}
void autocomplete_close(Ted *ted) {
@@ -240,20 +264,7 @@ static void autocomplete_frame(Ted *ted) {
autocomplete_find_completions(ted, 0);
- Autocompletion completions[AUTOCOMPLETE_NCOMPLETIONS_VISIBLE] = {0};
- size_t ncompletions = 0;
- arr_foreach_ptr(ac->suggested, u32, suggestion) {
- Autocompletion *completion = &ac->completions[*suggestion];
- completions[ncompletions++] = *completion;
- if (ncompletions == AUTOCOMPLETE_NCOMPLETIONS_VISIBLE)
- break;
- }
-
- float menu_width = 400, menu_height = (float)ncompletions * char_height;
-
- if (ac->waiting_for_lsp) {
- menu_height = 200.f;
- }
+ size_t ncompletions = arr_len(ac->suggested);
if (ac->waiting_for_lsp && ncompletions == 0) {
struct timespec now = ted->frame_time;
@@ -271,6 +282,16 @@ static void autocomplete_frame(Ted *ted) {
ac->cursor = ncompletions ? (i32)mod_i64(ac->cursor, (i64)ncompletions) : 0;
+ autocomplete_correct_scroll(ted);
+ i32 scroll = ac->scroll;
+ u32 ncompletions_visible = min_u32((u32)ncompletions, AUTOCOMPLETE_NCOMPLETIONS_VISIBLE);
+
+ float menu_width = 400, menu_height = (float)ncompletions_visible * char_height;
+
+ if (ac->waiting_for_lsp) {
+ menu_height = 200.f;
+ }
+
v2 cursor_pos = buffer_pos_to_pixels(buffer, buffer->cursor_pos);
bool open_up = cursor_pos.y > 0.5f * (buffer->y1 + buffer->y2); // should the completion menu open upwards?
bool open_left = cursor_pos.x > 0.5f * (buffer->x1 + buffer->x2);
@@ -287,20 +308,25 @@ static void autocomplete_frame(Ted *ted) {
ac->rect = menu_rect;
}
- u16 cursor_entry = (u16)((ted->mouse_pos.y - start_y) / char_height);
+ i32 mouse_entry = scroll + (i32)((ted->mouse_pos.y - start_y) / char_height);
Autocompletion *document = NULL;
- if (cursor_entry < ncompletions) {
+ if (ncompletions) {
+ assert(ac->cursor >= 0 && ac->cursor < (i32)ncompletions);
+ // highlight cursor entry
+ Rect r = rect(V2(x, start_y + (float)(ac->cursor - scroll) * char_height), V2(menu_width, char_height));
+ if (rect_contains_point(ac->rect, rect_center(r))) {
+ gl_geometry_rect(r, colors[COLOR_AUTOCOMPLETE_HL]);
+ document = &ac->completions[ac->suggested[ac->cursor]];
+ }
+ }
+ if (mouse_entry >= 0 && mouse_entry < (i32)ncompletions
+ && rect_contains_point(ac->rect, ted->mouse_pos)) {
// highlight moused over entry
- Rect r = rect(V2(x, start_y + cursor_entry * char_height), V2(menu_width, char_height));
+ Rect r = rect(V2(x, start_y + (float)(mouse_entry - scroll) * char_height), V2(menu_width, char_height));
gl_geometry_rect(r, colors[COLOR_AUTOCOMPLETE_HL]);
ted->cursor = ted->cursor_hand;
- document = &completions[cursor_entry];
- } else if (ncompletions) {
- // highlight cursor entry
- Rect r = rect(V2(x, start_y + (float)ac->cursor * char_height), V2(menu_width, char_height));
- gl_geometry_rect(r, colors[COLOR_AUTOCOMPLETE_HL]);
- document = &completions[ac->cursor];
+ document = &ac->completions[ac->suggested[mouse_entry]];
}
float border_thickness = settings->border_thickness;
@@ -309,7 +335,7 @@ static void autocomplete_frame(Ted *ted) {
if (document) {
// document that entry!!
- // we've go tsome wacky calculations to figure out the
+ // we've got some wacky calculations to figure out the
// bounding rect for the documentation
float doc_width = open_left ? ac->rect.pos.x - 2*padding
: buffer->x2 - (ac->rect.pos.x + ac->rect.size.x + 2*padding);
@@ -343,10 +369,11 @@ static void autocomplete_frame(Ted *ted) {
for (uint i = 0; i < ted->nmouse_clicks[SDL_BUTTON_LEFT]; ++i) {
v2 click = ted->mouse_clicks[SDL_BUTTON_LEFT][i];
if (rect_contains_point(ac->rect, click)) {
- u16 entry = (u16)((click.y - start_y) / char_height);
- if (entry < ncompletions) {
+ i32 entry = scroll + (i32)((click.y - start_y) / char_height);
+ if (entry >= 0 && entry < (i32)ncompletions) {
// entry was clicked on! use this completion.
autocomplete_complete(ted, ac->completions[ac->suggested[entry]]);
+ return;
}
}
}
@@ -360,11 +387,11 @@ static void autocomplete_frame(Ted *ted) {
state.x = x + padding; state.y = y;
text_utf8_with_state(font, &state, "Loading...");
} else {
- for (size_t i = 0; i < ncompletions; ++i) {
- const Autocompletion *completion = &completions[i];
+ for (size_t i = 0; i < ncompletions_visible; ++i) {
+ const Autocompletion *completion = &ac->completions[ac->suggested[(i32)i + scroll]];
state.x = x; state.y = y;
- if (i != ncompletions-1) {
+ if (i != ncompletions_visible-1) {
gl_geometry_rect(rect(V2(x, y + char_height),
V2(menu_width, border_thickness)),
colors[COLOR_AUTOCOMPLETE_BORDER]);
diff --git a/main.c b/main.c
index f7d91a3..82840b8 100644
--- a/main.c
+++ b/main.c
@@ -1,6 +1,5 @@
/*
@TODO:
-- scroll through completions
- LSP setting
- figure out workspace
- make sure "save as" works
@@ -723,8 +722,13 @@ int main(int argc, char **argv) {
case SDL_MOUSEWHEEL: {
// scroll with mouse wheel
Sint32 dx = event.wheel.x, dy = -event.wheel.y;
- ted->scroll_total_x += dx;
- ted->scroll_total_y += dy;
+ Autocomplete *ac = &ted->autocomplete;
+ if (ac->open && rect_contains_point(ac->rect, ted->mouse_pos)) {
+ autocomplete_scroll(ted, dy);
+ } else {
+ ted->scroll_total_x += dx;
+ ted->scroll_total_y += dy;
+ }
} break;
case SDL_MOUSEBUTTONDOWN: {
Uint32 button = event.button.button;
diff --git a/math.c b/math.c
index c7ac64b..80ef10e 100644
--- a/math.c
+++ b/math.c
@@ -147,6 +147,11 @@ static inline i64 mod_i64(i64 a, i64 b) {
if (ret < 0) ret += b;
return ret;
}
+static inline i32 mod_i32(i32 a, i32 b) {
+ i32 ret = a % b;
+ if (ret < 0) ret += b;
+ return ret;
+}
static inline i64 abs_i64(i64 x) {
return x < 0 ? -x : +x;
diff --git a/ted.h b/ted.h
index ddd2695..4c7da63 100644
--- a/ted.h
+++ b/ted.h
@@ -390,6 +390,8 @@ typedef struct {
u32 *suggested; // dynamic array of completions to be suggested (indices into completions)
BufferPos last_pos; // position of cursor last time completions were generated. if this changes, we need to recompute completions.
i32 cursor; // which completion is currently selected (index into suggested)
+ i32 scroll;
+
Rect rect; // rectangle where the autocomplete menu is (needed to avoid interpreting autocomplete clicks as other clicks)
} Autocomplete;