diff options
| -rw-r--r-- | Makefile | 5 | ||||
| -rw-r--r-- | src/dged/buffer.c | 99 | ||||
| -rw-r--r-- | src/dged/buffer.h | 22 | ||||
| -rw-r--r-- | src/dged/buffer_view.c | 51 | ||||
| -rw-r--r-- | src/dged/buffer_view.h | 5 | ||||
| -rw-r--r-- | src/dged/display.c | 7 | ||||
| -rw-r--r-- | src/dged/lang.c | 22 | ||||
| -rw-r--r-- | src/dged/s8.c | 25 | ||||
| -rw-r--r-- | src/dged/s8.h | 18 | ||||
| -rw-r--r-- | src/dged/syntax.c | 20 | ||||
| -rw-r--r-- | src/dged/text.c | 1 | ||||
| -rw-r--r-- | src/dged/timers.c | 95 | ||||
| -rw-r--r-- | src/dged/timers.h | 21 | ||||
| -rw-r--r-- | src/dged/window.c | 6 | ||||
| -rw-r--r-- | src/dged/window.h | 2 | ||||
| -rw-r--r-- | src/main/bindings.c | 2 | ||||
| -rw-r--r-- | src/main/cmds.c | 52 | ||||
| -rw-r--r-- | src/main/main.c | 46 | ||||
| -rw-r--r-- | test/minibuffer.c | 3 |
19 files changed, 400 insertions, 102 deletions
@@ -14,13 +14,14 @@ HEADERS = src/dged/settings.h src/dged/minibuffer.h src/dged/keyboard.h src/dged src/dged/buffer.h src/dged/btree.h src/dged/command.h src/dged/allocator.h src/dged/reactor.h \ src/dged/vec.h src/dged/window.h src/dged/hash.h src/dged/undo.h src/dged/lang.h \ src/dged/settings-parse.h src/dged/utf8.h src/main/cmds.h src/main/bindings.h \ - src/main/search-replace.h src/dged/location.h src/dged/buffer_view.h src/main/completion.h + src/main/search-replace.h src/dged/location.h src/dged/buffer_view.h src/main/completion.h \ + src/dged/timers.h src/dged/s8.h SOURCES = src/dged/binding.c src/dged/buffer.c src/dged/command.c src/dged/display.c \ src/dged/keyboard.c src/dged/minibuffer.c src/dged/text.c \ src/dged/utf8.c src/dged/buffers.c src/dged/window.c src/dged/allocator.c src/dged/undo.c \ src/dged/settings.c src/dged/lang.c src/dged/settings-parse.c src/dged/location.c \ - src/dged/buffer_view.c + src/dged/buffer_view.c src/dged/timers.c src/dged/s8.c MAIN_SOURCES = src/main/main.c src/main/cmds.c src/main/bindings.c src/main/search-replace.c src/main/completion.c diff --git a/src/dged/buffer.c b/src/dged/buffer.c index bfa0010..d25297f 100644 --- a/src/dged/buffer.c +++ b/src/dged/buffer.c @@ -7,9 +7,11 @@ #include "minibuffer.h" #include "path.h" #include "reactor.h" +#include "s8.h" #include "settings.h" #include "utf8.h" +#include <assert.h> #include <fcntl.h> #include <libgen.h> #include <stdbool.h> @@ -680,7 +682,7 @@ struct location buffer_newline(struct buffer *buffer, struct location at) { return buffer_add(buffer, at, (uint8_t *)"\n", 1); } -struct location buffer_indent(struct buffer *buffer, struct location at) { +static uint32_t get_tab_width(struct buffer *buffer) { struct setting *tw = lang_setting(&buffer->lang, "tab-width"); if (tw == NULL) { tw = settings_get("editor.tab-width"); @@ -690,8 +692,39 @@ struct location buffer_indent(struct buffer *buffer, struct location at) { if (tw != NULL && tw->value.type == Setting_Number) { tab_width = tw->value.number_value; } - return buffer_add(buffer, at, (uint8_t *)" ", - tab_width > 16 ? 16 : tab_width); + return tab_width; +} + +static bool use_tabs(struct buffer *buffer) { + struct setting *ut = lang_setting(&buffer->lang, "use-tabs"); + if (ut == NULL) { + ut = settings_get("editor.use-tabs"); + } + + bool use_tabs = false; + if (ut != NULL && ut->value.type == Setting_Bool) { + use_tabs = ut->value.bool_value; + } + + return use_tabs; +} + +static struct location do_indent(struct buffer *buffer, struct location at, + uint32_t tab_width, bool use_tabs) { + if (use_tabs) { + return buffer_add(buffer, at, (uint8_t *)"\t", 1); + } else { + return buffer_add(buffer, at, (uint8_t *)" ", + tab_width > 16 ? 16 : tab_width); + } +} + +struct location buffer_indent(struct buffer *buffer, struct location at) { + return do_indent(buffer, at, get_tab_width(buffer), use_tabs(buffer)); +} + +struct location buffer_indent_alt(struct buffer *buffer, struct location at) { + return do_indent(buffer, at, get_tab_width(buffer), !use_tabs(buffer)); } struct location buffer_undo(struct buffer *buffer, struct location dot) { @@ -1160,3 +1193,63 @@ void buffer_get_text_properties(struct buffer *buffer, struct location location, void buffer_clear_text_properties(struct buffer *buffer) { text_clear_properties(buffer->text); } + +static int compare_lines(const void *l1, const void *l2) { + return s8cmp(*(const struct s8 *)l1, *(const struct s8 *)l2); +} + +void buffer_sort_lines(struct buffer *buffer, uint32_t start_line, + uint32_t end_line) { + const uint32_t nlines = text_num_lines(buffer->text); + if (nlines == 0) { + return; + } + + uint32_t start = start_line >= nlines ? nlines - 1 : start_line; + uint32_t end = end_line >= nlines ? nlines - 1 : end_line; + + if (end <= start) { + return; + } + + const uint32_t ntosort = end - start + 1; + + struct region region = + region_new((struct location){.line = start, .col = 0}, + (struct location){.line = end + 1, .col = 0}); + + struct s8 *lines = (struct s8 *)malloc(sizeof(struct s8) * ntosort); + struct text_chunk txt = + text_get_region(buffer->text, region.begin.line, region.begin.col, + region.end.line, region.end.col); + + uint32_t line_start = 0; + uint32_t curr_line = 0; + for (uint32_t bytei = 0; bytei < txt.nbytes; ++bytei) { + if (txt.text[bytei] == '\n') { + lines[curr_line] = + (struct s8){.s = &txt.text[line_start], .l = bytei - line_start + 1}; + + ++curr_line; + line_start = bytei + 1; + } + } + + qsort(lines, ntosort, sizeof(struct s8), compare_lines); + + struct location at = buffer_delete(buffer, region); + for (uint32_t linei = 0; linei < ntosort; ++linei) { + struct s8 line = lines[linei]; + at = buffer_add(buffer, at, (uint8_t *)line.s, line.l); + } + + // if the last line we are sorting is the last line in the buffer, + // we have added one extra unwanted newline + if (end == nlines - 1) { + strip_final_newline(buffer); + } + + if (txt.allocated) { + free(txt.text); + } +} diff --git a/src/dged/buffer.h b/src/dged/buffer.h index 3cb8d03..496086a 100644 --- a/src/dged/buffer.h +++ b/src/dged/buffer.h @@ -312,6 +312,18 @@ struct location buffer_newline(struct buffer *buffer, struct location at); struct location buffer_indent(struct buffer *buffer, struct location at); /** + * Insert alternative indentation in the buffer. + * + * Alternative indentation is spaces if it is normally using tabs + * and vice versa. + * + * @param [in] buffer The buffer to indent in. + * @param [in] at The location to insert indentation at. + * @returns The position after indenting. + */ +struct location buffer_indent_alt(struct buffer *buffer, struct location at); + +/** * Undo the last operation in the buffer. * * @param [in] buffer The buffer to undo in. @@ -530,4 +542,14 @@ void buffer_render(struct buffer *buffer, struct buffer_render_params *params); uint32_t visual_string_width(uint8_t *txt, uint32_t len, uint32_t start_col, uint32_t end_col); +/** + * Sort lines in a buffer alphabetically. + * + * @param [in] buffer The buffer to sort lines in. + * @param [in] start_line The first line to sort. + * @param [in] end_line The last line to sort. + */ +void buffer_sort_lines(struct buffer *buffer, uint32_t start_line, + uint32_t end_line); + #endif diff --git a/src/dged/buffer_view.c b/src/dged/buffer_view.c index 15aa812..23bd8e2 100644 --- a/src/dged/buffer_view.c +++ b/src/dged/buffer_view.c @@ -3,6 +3,7 @@ #include "buffer.h" #include "buffer_view.h" #include "display.h" +#include "timers.h" #include "utf8.h" struct modeline { @@ -139,6 +140,10 @@ void buffer_view_indent(struct buffer_view *view) { view->dot = buffer_indent(view->buffer, view->dot); } +void buffer_view_indent_alt(struct buffer_view *view) { + view->dot = buffer_indent_alt(view->buffer, view->dot); +} + void buffer_view_copy(struct buffer_view *view) { if (!view->mark_set) { return; @@ -214,6 +219,18 @@ void buffer_view_kill_line(struct buffer_view *view) { buffer_cut(view->buffer, reg); } +void buffer_view_sort_lines(struct buffer_view *view) { + struct region reg = region_new(view->dot, view->mark); + if (view->mark_set && region_has_size(reg)) { + if (reg.end.line > 0 && buffer_num_chars(view->buffer, reg.end.line) == 0) { + reg.end.line -= 1; + } + + buffer_sort_lines(view->buffer, reg.begin.line, reg.end.line); + buffer_view_clear_mark(view); + } +} + void buffer_view_set_mark(struct buffer_view *view) { buffer_view_set_mark_at(view, view->dot); } @@ -314,23 +331,14 @@ static uint32_t render_line_numbers(struct buffer_view *view, static void render_modeline(struct modeline *modeline, struct buffer_view *view, struct command_list *commands, uint32_t window_id, - uint32_t width, uint32_t height, - uint64_t frame_time) { + uint32_t width, uint32_t height, float frame_time) { char buf[width * 4]; - - static uint64_t samples[10] = {0}; - static uint32_t samplei = 0; - static uint64_t avg = 0; - - // calc a moving average with a window of the last 10 frames - ++samplei; - samplei %= 10; - avg += 0.1 * (frame_time - samples[samplei]); - samples[samplei] = frame_time; + memset(buf, 0, width * 4); time_t now = time(NULL); struct tm *lt = localtime(&now); - char left[128], right[128]; + static char left[128] = {0}; + static char right[128] = {0}; snprintf(left, 128, " %c%c %d:%-16s (%d, %d) (%s)", view->buffer->modified ? '*' : '-', @@ -357,8 +365,11 @@ static void render_modeline(struct modeline *modeline, struct buffer_view *view, void buffer_view_update(struct buffer_view *view, struct buffer_view_update_params *params) { + struct timer *buffer_update_timer = + timer_start("update-windows.buffer-update"); struct buffer_update_params update_params = {}; buffer_update(view->buffer, &update_params); + timer_stop(buffer_update_timer); uint32_t height = params->height; uint32_t width = params->width; @@ -369,6 +380,8 @@ void buffer_view_update(struct buffer_view *view, (int64_t)view->dot.col); // render modeline + struct timer *render_modeline_timer = + timer_start("update-windows.modeline-render"); uint32_t modeline_height = 0; if (view->modeline != NULL) { modeline_height = 1; @@ -387,8 +400,11 @@ void buffer_view_update(struct buffer_view *view, 0) .line; } + timer_stop(render_modeline_timer); // render line numbers + struct timer *render_linenumbers_timer = + timer_start("update-windows.linenum-render"); uint32_t linum_width = 0; if (view->line_numbers) { linum_width = render_line_numbers(view, params->commands, height); @@ -402,6 +418,7 @@ void buffer_view_update(struct buffer_view *view, view->scroll.col = buffer_clamp(view->buffer, view->dot.line, view->dot.col).col; } + timer_stop(render_linenumbers_timer); // color region if (view->mark_set) { @@ -420,7 +437,9 @@ void buffer_view_update(struct buffer_view *view, } } - // update buffer + // render buffer + struct timer *render_buffer_timer = + timer_start("update-windows.buffer-render"); struct command_list *buf_cmds = command_list_create( width * height, params->frame_alloc, params->window_x + linum_width, params->window_y, view->buffer->name); @@ -434,5 +453,9 @@ void buffer_view_update(struct buffer_view *view, // draw buffer commands nested inside this command list command_list_draw_command_list(params->commands, buf_cmds); + timer_stop(render_buffer_timer); + + // TODO: move to somewhere where more correct if buffers + // are in more than one view (same with buffer hooks). buffer_clear_text_properties(view->buffer); } diff --git a/src/dged/buffer_view.h b/src/dged/buffer_view.h index 620c261..4e23b5d 100644 --- a/src/dged/buffer_view.h +++ b/src/dged/buffer_view.h @@ -68,6 +68,7 @@ void buffer_view_kill_line(struct buffer_view *view); void buffer_view_newline(struct buffer_view *view); void buffer_view_indent(struct buffer_view *view); +void buffer_view_indent_alt(struct buffer_view *view); void buffer_view_copy(struct buffer_view *view); void buffer_view_cut(struct buffer_view *view); @@ -83,11 +84,13 @@ struct location buffer_view_dot_to_visual(struct buffer_view *view); void buffer_view_undo(struct buffer_view *view); +void buffer_view_sort_lines(struct buffer_view *view); + struct buffer_view_update_params { struct command_list *commands; void *(*frame_alloc)(size_t); uint32_t window_id; - int64_t frame_time; + float frame_time; uint32_t width; uint32_t height; uint32_t window_x; diff --git a/src/dged/display.c b/src/dged/display.c index 85a6e0b..ed6fc00 100644 --- a/src/dged/display.c +++ b/src/dged/display.c @@ -2,6 +2,7 @@ #include "display.h" #include "buffer.h" +#include "timers.h" #include "utf8.h" #include <assert.h> @@ -358,6 +359,10 @@ void display_render(struct display *display, struct command_list *command_list) { struct command_list *cl = command_list; + static char name[32] = {0}; + snprintf(name, 31, "display.cl.%s", cl->name); + struct timer *render_timer = timer_start(name); + uint8_t fmt_stack[256] = {0}; fmt_stack[0] = ESC; fmt_stack[1] = '['; @@ -419,6 +424,8 @@ void display_render(struct display *display, } cl = cl->next_list; } + + timer_stop(render_timer); } void hide_cursor() { diff --git a/src/dged/lang.c b/src/dged/lang.c index c0b7462..d2d7b34 100644 --- a/src/dged/lang.c +++ b/src/dged/lang.c @@ -14,7 +14,7 @@ static void _lang_setting_set_default(const char *id, const char *key, struct setting_value value); void define_lang(const char *name, const char *id, const char *pattern, - uint32_t tab_width) { + uint32_t tab_width, bool use_tabs) { _lang_setting_set_default( id, "name", @@ -27,6 +27,9 @@ void define_lang(const char *name, const char *id, const char *pattern, _lang_setting_set_default(id, "tab-width", (struct setting_value){.type = Setting_Number, .number_value = tab_width}); + _lang_setting_set_default( + id, "use-tabs", + (struct setting_value){.type = Setting_Bool, .bool_value = use_tabs}); } static struct language g_fundamental = { @@ -36,14 +39,15 @@ static struct language g_fundamental = { void languages_init(bool register_default) { if (register_default) { - define_lang("Bash", "bash", "^.*\\.bash$", 4); - define_lang("C", "c", "^.*\\.(c|h)$", 2); - define_lang("C++", "cxx", "^.*\\.(cpp|cxx|cc|c++|hh|h)$", 2); - define_lang("Rust", "rs", "^.*\\.rs$", 4); - define_lang("Nix", "nix", "^.*\\.nix$", 2); - define_lang("Make", "make", "^.*(Makefile|\\.mk)$", 4); - define_lang("Python", "python", "^.*\\.py$", 4); - define_lang("Git Commit Message", "gitcommit", "^.*COMMIT_EDITMSG$", 4); + define_lang("Bash", "bash", "^.*\\.bash$", 4, false); + define_lang("C", "c", "^.*\\.(c|h)$", 2, false); + define_lang("C++", "cxx", "^.*\\.(cpp|cxx|cc|c++|hh|h)$", 2, false); + define_lang("Rust", "rs", "^.*\\.rs$", 4, false); + define_lang("Nix", "nix", "^.*\\.nix$", 2, false); + define_lang("Make", "make", "^.*(Makefile|\\.mk)$", 4, true); + define_lang("Python", "python", "^.*\\.py$", 4, false); + define_lang("Git Commit Message", "gitcommit", "^.*COMMIT_EDITMSG$", 4, + false); } } diff --git a/src/dged/s8.c b/src/dged/s8.c new file mode 100644 index 0000000..0566fde --- /dev/null +++ b/src/dged/s8.c @@ -0,0 +1,25 @@ +#include "s8.h" + +#include <stdlib.h> +#include <string.h> + +bool s8eq(struct s8 s1, struct s8 s2) { + return s1.l == s2.l && memcmp(s1.s, s2.s, s1.l) == 0; +} + +int s8cmp(struct s8 s1, struct s8 s2) { + if (s1.l < s2.l) { + return memcmp(s1.s, s2.s, s1.l); + } else if (s2.l < s1.l) { + return memcmp(s1.s, s2.s, s2.l); + } + + return memcmp(s1.s, s2.s, s1.l); +} + +char *s8tocstr(struct s8 s) { + char *cstr = (char *)malloc(s.l + 1); + memcpy(cstr, s.s, s.l); + cstr[s.l] = '\0'; + return cstr; +} diff --git a/src/dged/s8.h b/src/dged/s8.h new file mode 100644 index 0000000..955a642 --- /dev/null +++ b/src/dged/s8.h @@ -0,0 +1,18 @@ +#ifndef _S8_H +#define _S8_H + +#include <stdbool.h> +#include <stdint.h> + +#define s8(s) ((struct s8){s, strlen(s)}) + +struct s8 { + char *s; + uint32_t l; +}; + +bool s8eq(struct s8 s1, struct s8 s2); +int s8cmp(struct s8 s1, struct s8 s2); +char *s8tocstr(struct s8 s); + +#endif diff --git a/src/dged/syntax.c b/src/dged/syntax.c index 61f09c2..1544d33 100644 --- a/src/dged/syntax.c +++ b/src/dged/syntax.c @@ -17,6 +17,7 @@ #include "hash.h" #include "minibuffer.h" #include "path.h" +#include "s8.h" #include "settings.h" #include "text.h" #include "vec.h" @@ -26,25 +27,6 @@ static uint32_t treesitter_path_len = 0; static const char *parser_filename = "parser"; static const char *highlight_path = "queries/highlights.scm"; -// TODO: move to own file -#define s8(s) ((struct s8){s, strlen(s)}) - -struct s8 { - char *s; - uint32_t l; -}; - -static bool s8eq(struct s8 s1, struct s8 s2) { - return s1.l == s2.l && memcmp(s1.s, s2.s, s1.l) == 0; -} - -static char *s8tocstr(struct s8 s) { - char *cstr = (char *)malloc(s.l + 1); - memcpy(cstr, s.s, s.l); - cstr[s.l] = '\0'; - return cstr; -} - struct predicate { uint32_t pattern_idx; diff --git a/src/dged/text.c b/src/dged/text.c index 3942efc..0a92933 100644 --- a/src/dged/text.c +++ b/src/dged/text.c @@ -421,6 +421,7 @@ void text_for_each_line(struct text *text, uint32_t line, uint32_t nlines, for (uint32_t li = line; li < nlines_max; ++li) { struct line *src_line = &text->lines[li]; struct text_chunk line = (struct text_chunk){ + .allocated = false, .text = src_line->data, .nbytes = src_line->nbytes, .nchars = src_line->nchars, diff --git a/src/dged/timers.c b/src/dged/timers.c new file mode 100644 index 0000000..37ac367 --- /dev/null +++ b/src/dged/timers.c @@ -0,0 +1,95 @@ +#include "timers.h" +#include "hash.h" +#include "hashmap.h" + +#include <stdbool.h> +#include <string.h> +#include <time.h> + +#define NUM_FRAME_SAMPLES 16 + +struct timer { + char name[32]; + uint64_t samples[NUM_FRAME_SAMPLES]; + struct timespec started_at; +}; + +HASHMAP_ENTRY_TYPE(timer_entry, struct timer); + +static struct timers { + uint32_t frame_index; + HASHMAP(struct timer_entry) timers; +} g_timers; + +void timers_init() { + HASHMAP_INIT(&g_timers.timers, 32, hash_name); + g_timers.frame_index = 0; +} + +void timers_destroy() { HASHMAP_DESTROY(&g_timers.timers); } + +void timers_start_frame() { + HASHMAP_FOR_EACH(&g_timers.timers, struct timer_entry * entry) { + struct timer *timer = &entry->value; + timer->samples[g_timers.frame_index] = 0; + } +} + +void timers_end_frame() { + g_timers.frame_index = (g_timers.frame_index + 1) % NUM_FRAME_SAMPLES; +} + +struct timer *timer_start(const char *name) { + HASHMAP_GET(&g_timers.timers, struct timer_entry, name, struct timer * t); + if (t == NULL) { + HASHMAP_APPEND(&g_timers.timers, struct timer_entry, name, + struct timer_entry * tnew); + struct timer *new_timer = &tnew->value; + + size_t namelen = strlen(name); + namelen = namelen >= 32 ? 31 : namelen; + memcpy(new_timer->name, name, namelen); + new_timer->name[namelen] = '\0'; + + memset(new_timer->samples, 0, sizeof(uint64_t) * NUM_FRAME_SAMPLES); + + t = new_timer; + } + + clock_gettime(CLOCK_MONOTONIC, &t->started_at); + return t; +} + +void timer_stop(struct timer *timer) { + struct timespec end; + clock_gettime(CLOCK_MONOTONIC, &end); + uint64_t elapsed = ((uint64_t)end.tv_sec * 1e9 + (uint64_t)end.tv_nsec) - + ((uint64_t)timer->started_at.tv_sec * 1e9 + + (uint64_t)timer->started_at.tv_nsec); + + timer->samples[g_timers.frame_index] += elapsed; +} + +struct timer *timer_get(const char *name) { + HASHMAP_GET(&g_timers.timers, struct timer_entry, name, struct timer * t); + return t; +} + +float timer_average(const struct timer *timer) { + uint64_t sum = 0; + for (uint32_t samplei = 0; samplei < NUM_FRAME_SAMPLES; ++samplei) { + sum += timer->samples[samplei]; + } + + return (float)sum / NUM_FRAME_SAMPLES; + return 0.f; +} + +const char *timer_name(const struct timer *timer) { return timer->name; } + +void timers_for_each(timer_callback callback, void *userdata) { + HASHMAP_FOR_EACH(&g_timers.timers, struct timer_entry * entry) { + const struct timer *timer = &entry->value; + callback(timer, userdata); + } +} diff --git a/src/dged/timers.h b/src/dged/timers.h new file mode 100644 index 0000000..4911b54 --- /dev/null +++ b/src/dged/timers.h @@ -0,0 +1,21 @@ +#ifndef _TIMERS_H +#define _TIMERS_H + +struct timer; + +void timers_init(); +void timers_start_frame(); + +struct timer *timer_start(const char *name); +void timer_stop(struct timer *timer); +struct timer *timer_get(const char *name); +float timer_average(const struct timer *timer); +const char *timer_name(const struct timer *timer); + +typedef void (*timer_callback)(const struct timer *timer, void *userdata); +void timers_for_each(timer_callback callback, void *userdata); + +void timers_end_frame(); +void timers_destroy(); + +#endif diff --git a/src/dged/window.c b/src/dged/window.c index da2cebe..8fcd51c 100644 --- a/src/dged/window.c +++ b/src/dged/window.c @@ -154,7 +154,7 @@ void windows_resize(uint32_t height, uint32_t width) { window_tree_resize(BINTREE_ROOT(&g_windows.windows), height - 1, width); } -void windows_update(void *(*frame_alloc)(size_t), uint64_t frame_time) { +void windows_update(void *(*frame_alloc)(size_t), float frame_time) { struct window *w = &g_minibuffer_window; w->x = 0; @@ -281,8 +281,8 @@ void windows_update(void *(*frame_alloc)(size_t), uint64_t frame_time) { while (n != NULL) { struct window *w = &BINTREE_VALUE(n); if (w->type == Window_Buffer) { - char name[16]; - snprintf(name, 16, "bufview-%s", w->buffer_view.buffer->name); + char name[16] = {0}; + snprintf(name, 15, "bufview-%s", w->buffer_view.buffer->name); w->commands = command_list_create(w->height * w->width, frame_alloc, w->x, w->y, name); diff --git a/src/dged/window.h b/src/dged/window.h index e9f90aa..3841475 100644 --- a/src/dged/window.h +++ b/src/dged/window.h @@ -25,7 +25,7 @@ void windows_init(uint32_t height, uint32_t width, void windows_destroy(); void windows_resize(uint32_t height, uint32_t width); -void windows_update(void *(*frame_alloc)(size_t), uint64_t frame_time); +void windows_update(void *(*frame_alloc)(size_t), float frame_time); void windows_render(struct display *display); struct window *root_window(); diff --git a/src/main/bindings.c b/src/main/bindings.c index 9038f37..b49a45e 100644 --- a/src/main/bindings.c +++ b/src/main/bindings.c @@ -49,7 +49,7 @@ void set_default_buffer_bindings(struct keymap *keymap) { BINDING(ENTER, "newline"), BINDING(TAB, "indent"), - BINDING(Spec, 'Z', "insert-tab"), + BINDING(Spec, 'Z', "indent-alt"), BINDING(Ctrl, 'K', "kill-line"), BINDING(DELETE, "delete-char"), diff --git a/src/main/cmds.c b/src/main/cmds.c index b454889..2853352 100644 --- a/src/main/cmds.c +++ b/src/main/cmds.c @@ -13,6 +13,7 @@ #include "dged/minibuffer.h" #include "dged/path.h" #include "dged/settings.h" +#include "dged/timers.h" #include "dged/utf8.h" #include "bindings.h" @@ -123,17 +124,38 @@ int32_t switch_buffer(struct command_ctx ctx, int argc, const char *argv[]) { ctx.active_window, ctx.buffers, argc, argv); } +void timer_to_list_line(const struct timer *timer, void *userdata) { + struct buffer *target = (struct buffer *)userdata; + + static char buf[128]; + const char *name = timer_name(timer); + size_t namelen = strlen(name); + size_t len = + snprintf(buf, 128, "%s - %.2f ms", name, (timer_average(timer) / 1e6)); + buffer_add(target, buffer_end(target), (uint8_t *)buf, len); +} + +void timers_refresh(struct buffer *buffer, void *userdata) { + buffer_set_readonly(buffer, false); + buffer_clear(buffer); + timers_for_each(timer_to_list_line, buffer); + uint32_t nlines = buffer_num_lines(buffer); + if (nlines > 0) { + buffer_sort_lines(buffer, 0, nlines); + } + buffer_set_readonly(buffer, true); +} + int32_t timers(struct command_ctx ctx, int argc, const char *argv[]) { - struct buffer *b = buffers_add(ctx.buffers, buffer_create("timers")); - buffer_set_readonly(b, true); - struct window *new_window_a, *new_window_b; - window_split(ctx.active_window, &new_window_a, &new_window_b); + struct buffer *b = buffers_find(ctx.buffers, "*timers*"); + if (b == NULL) { + b = buffers_add(ctx.buffers, buffer_create("*timers*")); + buffer_add_update_hook(b, timers_refresh, NULL); + } - const char *txt = - "TODO: this is not real values!\ntimer 1: 1ms\ntimer 2: 2ms\n"; - buffer_set_text(b, (uint8_t *)txt, strlen(txt)); + window_set_buffer(ctx.active_window, b); + timers_refresh(b, NULL); - window_set_buffer(new_window_b, b); return 0; } @@ -223,12 +245,12 @@ int32_t buffer_list(struct command_ctx ctx, int argc, const char *argv[]) { struct buffer *b = buffers_find(ctx.buffers, "*buffers*"); if (b == NULL) { b = buffers_add(ctx.buffers, buffer_create("*buffers*")); + buffer_add_update_hook(b, buflist_refresh, ctx.buffers); } struct window *w = ctx.active_window; window_set_buffer(ctx.active_window, b); - buffer_add_update_hook(b, buflist_refresh, ctx.buffers); buflist_refresh(b, ctx.buffers); static struct command buflist_visit = { @@ -415,6 +437,7 @@ BUFFER_VIEW_WRAPCMD(goto_end_of_line); BUFFER_VIEW_WRAPCMD(goto_beginning_of_line); BUFFER_VIEW_WRAPCMD(newline); BUFFER_VIEW_WRAPCMD(indent); +BUFFER_VIEW_WRAPCMD(indent_alt); BUFFER_VIEW_WRAPCMD(set_mark); BUFFER_VIEW_WRAPCMD(clear_mark); BUFFER_VIEW_WRAPCMD(copy); @@ -424,6 +447,7 @@ BUFFER_VIEW_WRAPCMD(paste_older); BUFFER_VIEW_WRAPCMD(goto_beginning); BUFFER_VIEW_WRAPCMD(goto_end); BUFFER_VIEW_WRAPCMD(undo); +BUFFER_VIEW_WRAPCMD(sort_lines); static int32_t scroll_up_cmd(struct command_ctx ctx, int argc, const char *argv[]) { @@ -464,13 +488,6 @@ static int32_t goto_line(struct command_ctx ctx, int argc, const char *argv[]) { return 0; } -static int32_t insert_tab(struct command_ctx ctx, int argc, - const char *argv[]) { - struct buffer_view *v = window_buffer_view(ctx.active_window); - buffer_view_add(v, (uint8_t *)"\t", 1); - return 0; -} - void register_buffer_commands(struct commands *commands) { static struct command buffer_commands[] = { {.name = "kill-line", .fn = kill_line_cmd}, @@ -487,7 +504,7 @@ void register_buffer_commands(struct commands *commands) { {.name = "beginning-of-line", .fn = goto_beginning_of_line_cmd}, {.name = "newline", .fn = newline_cmd}, {.name = "indent", .fn = indent_cmd}, - {.name = "insert-tab", .fn = insert_tab}, + {.name = "indent-alt", .fn = indent_alt_cmd}, {.name = "buffer-write-to-file", .fn = to_file_cmd}, {.name = "set-mark", .fn = set_mark_cmd}, {.name = "clear-mark", .fn = clear_mark_cmd}, @@ -502,6 +519,7 @@ void register_buffer_commands(struct commands *commands) { {.name = "scroll-up", .fn = scroll_up_cmd}, {.name = "reload", .fn = reload_cmd}, {.name = "goto-line", .fn = goto_line}, + {.name = "sort-lines", .fn = sort_lines_cmd}, }; register_commands(commands, buffer_commands, diff --git a/src/main/main.c b/src/main/main.c index e722ed2..d0d118b 100644 --- a/src/main/main.c +++ b/src/main/main.c @@ -19,6 +19,7 @@ #include "dged/path.h" #include "dged/reactor.h" #include "dged/settings.h" +#include "dged/timers.h" #ifdef SYNTAX_ENABLE #include "dged/syntax.h" @@ -52,24 +53,6 @@ void resized() { signal(SIGWINCH, resized); } -uint64_t calc_frame_time_ns(struct timespec *timers, uint32_t num_timer_pairs) { - uint64_t total = 0; - for (uint32_t ti = 0; ti < num_timer_pairs * 2; ti += 2) { - struct timespec *start_timer = &timers[ti]; - struct timespec *end_timer = &timers[ti + 1]; - - total += - ((uint64_t)end_timer->tv_sec * 1e9 + (uint64_t)end_timer->tv_nsec) - - ((uint64_t)start_timer->tv_sec * 1e9 + (uint64_t)start_timer->tv_nsec); - } - - return total; -} - -#define DECLARE_TIMER(timer) struct timespec timer##_begin, timer##_end -#define TIMED_SCOPE_BEGIN(timer) clock_gettime(CLOCK_MONOTONIC, &timer##_begin) -#define TIMED_SCOPE_END(timer) clock_gettime(CLOCK_MONOTONIC, &timer##_end) - #define INVALID_WATCH -1 struct watched_file { uint32_t watch_id; @@ -297,32 +280,30 @@ int main(int argc, char *argv[]) { init_bindings(); init_completion(&buflist); + timers_init(); - DECLARE_TIMER(buffer); - DECLARE_TIMER(display); - DECLARE_TIMER(keyboard); - - uint64_t frame_time = 0; + float frame_time = 0.f; static char keyname[64] = {0}; static uint32_t nkeychars = 0; while (running) { + timers_start_frame(); if (display_resized) { windows_resize(display_height(display), display_width(display)); display_resized = false; } /* Update all windows together with the buffers in them. */ - TIMED_SCOPE_BEGIN(buffer); + struct timer *update_windows = timer_start("update-windows"); windows_update(frame_alloc, frame_time); - TIMED_SCOPE_END(buffer); + timer_stop(update_windows); struct window *active_window = windows_get_active(); /* Update the screen by flushing command lists collected * from updating the buffers. */ - TIMED_SCOPE_BEGIN(display); + struct timer *update_display = timer_start("display"); display_begin_render(display); windows_render(display); struct buffer_view *view = window_buffer_view(active_window); @@ -330,7 +311,7 @@ int main(int argc, char *argv[]) { struct window_position winpos = window_position(active_window); display_move_cursor(display, winpos.y + cursor.line, winpos.x + cursor.col); display_end_render(display); - TIMED_SCOPE_END(display); + timer_stop(update_display); /* This blocks for events, so if nothing has happened we block here and let * the CPU do something more useful than updating this editor for no reason. @@ -339,7 +320,7 @@ int main(int argc, char *argv[]) { */ reactor_update(reactor); - TIMED_SCOPE_BEGIN(keyboard); + struct timer *update_keyboard = timer_start("update-keyboard"); struct keyboard_update kbd_upd = keyboard_update(&kbd, reactor, frame_alloc); @@ -413,17 +394,18 @@ int main(int argc, char *argv[]) { keyname[0] = '\0'; } } - TIMED_SCOPE_END(keyboard); + timer_stop(update_keyboard); update_file_watches(reactor); // calculate frame time - struct timespec timers[] = {buffer_begin, buffer_end, display_begin, - display_end, keyboard_begin, keyboard_end}; - frame_time = calc_frame_time_ns(timers, 3); + frame_time = timer_average(update_windows) + + timer_average(update_keyboard) + timer_average(update_display); + frame_allocator_clear(&frame_allocator); } + timers_destroy(); destroy_completion(); windows_destroy(); minibuffer_destroy(); diff --git a/test/minibuffer.c b/test/minibuffer.c index 474f664..96fecca 100644 --- a/test/minibuffer.c +++ b/test/minibuffer.c @@ -10,6 +10,7 @@ #include "dged/display.h" #include "dged/minibuffer.h" #include "dged/settings.h" +#include "dged/timers.h" static struct buffer b = {0}; static struct buffers bufs = {0}; @@ -21,6 +22,7 @@ void *alloc_fn(size_t sz) { return frame_allocator_alloc(g_alloc, sz); } void init() { if (b.name == NULL) { settings_init(10); + timers_init(); b = buffer_create("minibuffer"); buffers_init(&bufs, 10); } @@ -33,6 +35,7 @@ void destroy() { if (b.name != NULL) { buffer_destroy(&b); settings_destroy(); + timers_destroy(); windows_destroy(); } } |
