summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2021-03-02 18:24:37 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2021-03-02 18:24:37 -0500
commit68066ad410368b0e5d66d7fa983bea882eba1eb6 (patch)
tree4124e596cee112aa076f93ab8915732463522a00
parent00b639118e32c7e65a402ddf70a57d0238b5abe1 (diff)
command selector working!
-rw-r--r--buffer.c57
-rw-r--r--main.c87
-rw-r--r--menu.c88
-rw-r--r--ted.c2
-rw-r--r--ted.h1
-rw-r--r--ui.c1
6 files changed, 139 insertions, 97 deletions
diff --git a/buffer.c b/buffer.c
index b016d9e..bdba7ff 100644
--- a/buffer.c
+++ b/buffer.c
@@ -677,7 +677,7 @@ static u32 buffer_index_to_column(TextBuffer *buffer, u32 line, u32 index) {
char32_t *str = buffer->lines[line].str;
u32 col = 0;
uint tab_width = buffer_settings(buffer)->tab_width;
- for (u32 i = 0; i < index; ++i) {
+ for (u32 i = 0; i < index && i < buffer->lines[line].len; ++i) {
switch (str[i]) {
case '\t': {
do
@@ -2093,6 +2093,53 @@ u32 buffer_last_rendered_line(TextBuffer *buffer) {
return clamp_u32(line, 0, buffer->nlines);
}
+// returns true if the buffer "used" this event
+bool buffer_handle_click(Ted *ted, TextBuffer *buffer, v2 click, u8 times) {
+ BufferPos buffer_pos;
+ if (buffer_pixels_to_pos(buffer, click, &buffer_pos)) {
+ // user clicked on buffer
+ if (!ted->menu || buffer->is_line_buffer) {
+ ted_switch_to_buffer(ted, buffer);
+ }
+ if (buffer == ted->active_buffer) {
+ switch (ted->key_modifier) {
+ case KEY_MODIFIER_SHIFT:
+ // select to position
+ buffer_select_to_pos(buffer, buffer_pos);
+ break;
+ case KEY_MODIFIER_CTRL:
+ if (!buffer->is_line_buffer) {
+ buffer_cursor_move_to_pos(buffer, buffer_pos);
+ String32 word = buffer_word_at_cursor(buffer);
+ if (word.len) {
+ char *tag = str32_to_utf8_cstr(word);
+ if (tag) {
+ tag_goto(buffer->ted, tag);
+ free(tag);
+ }
+ }
+ }
+ break;
+ case 0:
+ buffer_cursor_move_to_pos(buffer, buffer_pos);
+ switch ((times - 1) % 3) {
+ case 0: break; // single-click
+ case 1: // double-click: select word
+ buffer_select_word(buffer);
+ break;
+ case 2: // triple-click: select line
+ buffer_select_line(buffer);
+ break;
+ }
+ ted->drag_buffer = buffer;
+ break;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
// Render the text buffer in the given rectangle
void buffer_render(TextBuffer *buffer, Rect r) {
if (r.size.x < 1 || r.size.y < 1) {
@@ -2163,6 +2210,14 @@ void buffer_render(TextBuffer *buffer, Rect r) {
buffer->x1 = x1; buffer->y1 = y1; buffer->x2 = x2; buffer->y2 = y2;
if (x1 == x2 || y1 == y2) return;
+ if (buffer->is_line_buffer) {
+ // handle clicks
+ // this is only done for line buffers, so that ctrl+click works properly (and happens in one frame).
+ for (u32 i = 0; i < ted->nmouse_clicks[SDL_BUTTON_LEFT]; ++i) {
+ buffer_handle_click(ted, buffer, ted->mouse_clicks[SDL_BUTTON_LEFT][i], ted->mouse_click_times[SDL_BUTTON_LEFT][i]);
+ }
+ }
+
// change cursor to ibeam when it's hovering over the buffer
if ((!ted->menu || buffer == &ted->line_buffer) && rect_contains_point(rect4(x1, y1, x2, y2), ted->mouse_pos)) {
ted->cursor = ted->cursor_ibeam;
diff --git a/main.c b/main.c
index 8f1c298..70b36d0 100644
--- a/main.c
+++ b/main.c
@@ -1,5 +1,4 @@
// @TODO:
-// - command selector
// - :open-config
// - test on BSD
@@ -245,51 +244,6 @@ static void ted_update_window_dimensions(Ted *ted) {
gl_window_height = ted->window_height = (float)h;
}
-// returns true if the buffer "used" this event
-static bool handle_buffer_click(Ted *ted, TextBuffer *buffer, v2 click, u8 times) {
- BufferPos buffer_pos;
- if (buffer_pixels_to_pos(buffer, click, &buffer_pos)) {
- // user clicked on buffer
- if (!ted->menu) {
- ted_switch_to_buffer(ted, buffer);
- }
- if (buffer == ted->active_buffer) {
- switch (ted->key_modifier) {
- case KEY_MODIFIER_SHIFT:
- // select to position
- buffer_select_to_pos(buffer, buffer_pos);
- break;
- case KEY_MODIFIER_CTRL: {
- buffer_cursor_move_to_pos(buffer, buffer_pos);
- String32 word = buffer_word_at_cursor(buffer);
- if (word.len) {
- char *tag = str32_to_utf8_cstr(word);
- if (tag) {
- tag_goto(buffer->ted, tag);
- free(tag);
- }
- }
- } break;
- case 0:
- buffer_cursor_move_to_pos(buffer, buffer_pos);
- switch ((times - 1) % 3) {
- case 0: break; // single-click
- case 1: // double-click: select word
- buffer_select_word(buffer);
- break;
- case 2: // triple-click: select line
- buffer_select_line(buffer);
- break;
- }
- ted->drag_buffer = buffer;
- break;
- }
- return true;
- }
- }
- return false;
-}
-
#if _WIN32
INT WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR lpCmdLine, INT nCmdShow) {
@@ -566,6 +520,9 @@ int main(int argc, char **argv) {
Uint32 time_at_last_frame = SDL_GetTicks();
strbuf_cpy(ted->error, config_err);
+
+ SDL_DisplayMode display_mode = {0};
+ SDL_GetDisplayMode(0, 0, &display_mode);
while (!ted->quit) {
#if DEBUG
@@ -628,27 +585,25 @@ int main(int argc, char **argv) {
}
}
- if (add) {
+ if (add) {
// handle mouse click
// we need to do this here, and not in buffer_render, because ctrl+click (go to definition)
// could switch to a different buffer.
- for (u32 i = 0; i < TED_MAX_NODES; ++i) {
- if (ted->nodes_used[i]) {
- Node *node = &ted->nodes[i];
- if (node->tabs) {
- buffer = &ted->buffers[node->tabs[node->active_tab]];
- if (handle_buffer_click(ted, buffer, pos, times)) {
- add = false;
- break;
+ // line buffer click handling, IS done in buffer_render (yes this is less than ideal)
+ if (!ted->menu) {
+ for (u32 i = 0; i < TED_MAX_NODES; ++i) {
+ if (ted->nodes_used[i]) {
+ Node *node = &ted->nodes[i];
+ if (node->tabs) {
+ buffer = &ted->buffers[node->tabs[node->active_tab]];
+ if (buffer_handle_click(ted, buffer, pos, times)) {
+ add = false;
+ break;
+ }
}
}
}
}
- if (ted->find) {
- add = add && !handle_buffer_click(ted, &ted->find_buffer, pos, times);
- if (ted->replace)
- add = add && !handle_buffer_click(ted, &ted->replace_buffer, pos, times);
- }
if (add) {
ted->mouse_clicks[button][ted->nmouse_clicks[button]] = pos;
ted->mouse_click_times[button][ted->nmouse_clicks[button]] = times;
@@ -905,10 +860,14 @@ int main(int argc, char **argv) {
SDL_SetWindowTitle(window, ted->window_title);
SDL_SetCursor(ted->cursor);
- i32 ms_wait = (i32)((frame_end_noswap - frame_start) * 1000);
- if (ms_wait > 0) {
- ms_wait -= 1; // give swap an extra ms to make sure it's actually vsynced
- SDL_Delay((u32)ms_wait);
+ // annoyingly, SDL_GL_SwapWindow seems to be a busy loop on my laptop for some reason...
+ int refresh_rate = display_mode.refresh_rate;
+ if (refresh_rate) {
+ i32 ms_wait = 1000 / refresh_rate - (i32)((frame_end_noswap - frame_start) * 1000);
+ if (ms_wait > 0) {
+ ms_wait -= 1; // give swap an extra ms to make sure it's actually vsynced
+ SDL_Delay((u32)ms_wait);
+ }
}
SDL_GL_SwapWindow(window);
PROFILE_TIME(frame_end);
diff --git a/menu.c b/menu.c
index 54f05df..868a4a4 100644
--- a/menu.c
+++ b/menu.c
@@ -26,11 +26,12 @@ static void menu_close(Ted *ted) {
case MENU_GOTO_LINE:
buffer_clear(&ted->line_buffer);
break;
- case MENU_COMMAND_SELECTOR:
+ case MENU_COMMAND_SELECTOR: {
+ Selector *selector = &ted->command_selector;
buffer_clear(&ted->line_buffer);
buffer_clear(&ted->argument_buffer);
- free(ted->command_selector.entries);
- break;
+ free(selector->entries); selector->entries = NULL; selector->n_entries = 0;
+ } break;
}
ted->menu = MENU_NONE;
ted->selector_open = NULL;
@@ -74,6 +75,9 @@ static void menu_open(Ted *ted, Menu menu) {
case MENU_COMMAND_SELECTOR: {
ted_switch_to_buffer(ted, &ted->line_buffer);
buffer_insert_char_at_cursor(&ted->argument_buffer, '1');
+ Selector *selector = &ted->command_selector;
+ selector->enable_cursor = true;
+ selector->cursor = 0;
} break;
}
}
@@ -107,6 +111,10 @@ static Rect menu_rect(Ted *ted) {
static void menu_update(Ted *ted) {
Menu menu = ted->menu;
+ Settings const *settings = &ted->settings;
+ u32 const *colors = settings->colors;
+ TextBuffer *line_buffer = &ted->line_buffer;
+
assert(menu);
switch (menu) {
case MENU_NONE: break;
@@ -224,7 +232,6 @@ static void menu_update(Ted *ted) {
}
} break;
case MENU_GOTO_LINE: {
- TextBuffer *line_buffer = &ted->line_buffer;
char *contents = str32_to_utf8_cstr(buffer_get_line(line_buffer, 0));
char *end;
long line_number = strtol(contents, &end, 0);
@@ -248,32 +255,38 @@ static void menu_update(Ted *ted) {
case MENU_COMMAND_SELECTOR: {
Selector *selector = &ted->command_selector;
SelectorEntry *entries = selector->entries = calloc(arr_count(command_names), sizeof *selector->entries);
+ char *search_term = str32_to_utf8_cstr(buffer_get_line(line_buffer, 0));
if (entries) {
+ SelectorEntry *entry = entries;
for (size_t i = 0; i < arr_count(command_names); ++i) {
- if (command_names[i].cmd != CMD_UNKNOWN) {
- char const *name = command_names[i].name;
- entries[i].name = name;
- entries[i].color = COLOR_TEXT;
+ char const *name = command_names[i].name;
+ if (command_names[i].cmd != CMD_UNKNOWN && stristr(name, search_term)) {
+ entry->name = name;
+ entry->color = colors[COLOR_TEXT];
+ ++entry;
}
}
- selector->n_entries = arr_count(command_names);
+ selector->n_entries = (u32)(entry - entries);
}
char *chosen_command = selector_update(ted, &ted->command_selector);
if (chosen_command) {
Command c = command_from_str(chosen_command);
- char *argument = str32_to_utf8_cstr(buffer_get_line(&ted->argument_buffer, 0)), *endp = NULL;
- long long arg = strtoll(argument, &endp, 0);
+ if (c != CMD_UNKNOWN) {
+ char *argument = str32_to_utf8_cstr(buffer_get_line(&ted->argument_buffer, 0)), *endp = NULL;
+ long long arg = strtoll(argument, &endp, 0);
- if (*endp == '\0') {
- menu_close(ted);
- command_execute(ted, c, arg);
+ if (*endp == '\0') {
+ menu_close(ted);
+ command_execute(ted, c, arg);
+ }
+
+ free(argument);
}
- free(argument);
free(chosen_command);
}
- free(selector->entries); selector->entries = NULL; selector->n_entries = 0;
+ free(search_term);
} break;
}
}
@@ -305,8 +318,8 @@ static void menu_render(Ted *ted) {
float padding = settings->padding;
Rect bounds = menu_rect(ted);
- float menu_x1, menu_y1, menu_x2, menu_y2;
- rect_coords(bounds, &menu_x1, &menu_y1, &menu_x2, &menu_y2);
+ float x1, y1, x2, y2;
+ rect_coords(bounds, &x1, &y1, &x2, &y2);
if (menu == MENU_OPEN || menu == MENU_SAVE_AS || menu == MENU_GOTO_DEFINITION || menu == MENU_COMMAND_SELECTOR) {
// menu rectangle & border
@@ -314,10 +327,10 @@ static void menu_render(Ted *ted) {
gl_geometry_rect_border(bounds, settings->border_thickness, colors[COLOR_BORDER]);
gl_geometry_draw();
- menu_x1 += padding;
- menu_y1 += padding;
- menu_x2 -= padding;
- menu_y2 -= padding;
+ x1 += padding;
+ y1 += padding;
+ x2 -= padding;
+ y2 -= padding;
}
@@ -339,20 +352,20 @@ static void menu_render(Ted *ted) {
case MENU_SAVE_AS: {
if (menu == MENU_OPEN) {
- text_utf8(font_bold, "Open...", menu_x1, menu_y1, colors[COLOR_TEXT]);
+ text_utf8(font_bold, "Open...", x1, y1, colors[COLOR_TEXT]);
} else if (menu == MENU_SAVE_AS) {
- text_utf8(font_bold, "Save as...", menu_x1, menu_y1, colors[COLOR_TEXT]);
+ text_utf8(font_bold, "Save as...", x1, y1, colors[COLOR_TEXT]);
}
text_render(font_bold);
- menu_y1 += char_height_bold * 0.75f + padding;
+ y1 += char_height_bold * 0.75f + padding;
FileSelector *fs = &ted->file_selector;
- fs->bounds = rect4(menu_x1, menu_y1, menu_x2, menu_y2);
+ fs->bounds = rect4(x1, y1, x2, y2);
file_selector_render(ted, fs);
} break;
case MENU_GOTO_DEFINITION: {
- tag_selector_render(ted, rect4(menu_x1, menu_y1, menu_x2, menu_y2));
+ tag_selector_render(ted, rect4(x1, y1, x2, y2));
} break;
case MENU_GOTO_LINE: {
float menu_height = char_height + 2 * padding;
@@ -361,7 +374,6 @@ static void menu_render(Ted *ted) {
gl_geometry_rect_border(r, settings->border_thickness, colors[COLOR_BORDER]);
char const *text = "Go to line...";
v2 text_size = text_get_size_v2(font_bold, text);
- float x1, y1, x2, y2;
rect_coords(r, &x1, &y1, &x2, &y2);
x1 += padding;
y1 += padding;
@@ -376,8 +388,22 @@ static void menu_render(Ted *ted) {
// line buffer
buffer_render(&ted->line_buffer, rect4(x1, y1, x2, y2));
} break;
- case MENU_COMMAND_SELECTOR:
- selector_render(ted, &ted->command_selector);
- break;
+ case MENU_COMMAND_SELECTOR: {
+ float line_buffer_height = char_height;
+
+ // argument field
+ char const *text = "Argument";
+ text_utf8(font_bold, text, x1, y1, colors[COLOR_TEXT]);
+ float x = x1 + text_get_size_v2(font_bold, text).x + padding;
+ buffer_render(&ted->argument_buffer, rect4(x, y1, x2, y1 + line_buffer_height));
+
+ y1 += line_buffer_height + padding;
+
+ Selector *selector = &ted->command_selector;
+ selector->bounds = rect4(x1, y1, x2, y2);
+ selector_render(ted, selector);
+
+ text_render(font_bold);
+ } break;
}
}
diff --git a/ted.c b/ted.c
index 8b6c657..325755f 100644
--- a/ted.c
+++ b/ted.c
@@ -101,7 +101,7 @@ static void ted_load_fonts(Ted *ted) {
// sets the active buffer to this buffer, and updates active_node, etc. accordingly
// you can pass NULL to buffer to make it so no buffer is active.
-static void ted_switch_to_buffer(Ted *ted, TextBuffer *buffer) {
+void ted_switch_to_buffer(Ted *ted, TextBuffer *buffer) {
ted->active_buffer = buffer;
if (ted->find) find_update(ted, true);
diff --git a/ted.h b/ted.h
index f67a27c..ddbedc8 100644
--- a/ted.h
+++ b/ted.h
@@ -326,3 +326,4 @@ typedef struct Ted {
} Ted;
void command_execute(Ted *ted, Command c, i64 argument);
+void ted_switch_to_buffer(Ted *ted, TextBuffer *buffer);
diff --git a/ui.c b/ui.c
index 45ea056..be3b35c 100644
--- a/ui.c
+++ b/ui.c
@@ -102,6 +102,7 @@ static char *selector_update(Ted *ted, Selector *s) {
return ret;
}
+// NOTE: also renders the line buffer
static void selector_render(Ted *ted, Selector *s) {
Settings const *settings = &ted->settings;
u32 const *colors = settings->colors;