diff options
Diffstat (limited to 'src/dged')
| -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 |
14 files changed, 344 insertions, 50 deletions
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(); |
