summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile5
-rw-r--r--src/dged/buffer.c99
-rw-r--r--src/dged/buffer.h22
-rw-r--r--src/dged/buffer_view.c51
-rw-r--r--src/dged/buffer_view.h5
-rw-r--r--src/dged/display.c7
-rw-r--r--src/dged/lang.c22
-rw-r--r--src/dged/s8.c25
-rw-r--r--src/dged/s8.h18
-rw-r--r--src/dged/syntax.c20
-rw-r--r--src/dged/text.c1
-rw-r--r--src/dged/timers.c95
-rw-r--r--src/dged/timers.h21
-rw-r--r--src/dged/window.c6
-rw-r--r--src/dged/window.h2
-rw-r--r--src/main/bindings.c2
-rw-r--r--src/main/cmds.c52
-rw-r--r--src/main/main.c46
-rw-r--r--test/minibuffer.c3
19 files changed, 400 insertions, 102 deletions
diff --git a/Makefile b/Makefile
index be0d2b2..d469509 100644
--- a/Makefile
+++ b/Makefile
@@ -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();
}
}