summaryrefslogtreecommitdiff
path: root/src/main/main.c
diff options
context:
space:
mode:
authorAlbert Cervin <albert@acervin.com>2023-04-06 23:23:46 +0200
committerAlbert Cervin <albert@acervin.com>2023-05-01 22:19:14 +0200
commita123725a12e948d78badb2cb686d38548f1c633b (patch)
treec92c46134ef5536fbbf3bf08983c4f0dea1aaf58 /src/main/main.c
parentb5ed4cf757afc50afb6ac499eee7b87a2648fa4c (diff)
downloaddged-a123725a12e948d78badb2cb686d38548f1c633b.tar.gz
dged-a123725a12e948d78badb2cb686d38548f1c633b.tar.xz
dged-a123725a12e948d78badb2cb686d38548f1c633b.zip
Implement window handling
Also implement searching. fix undo boundaries when it checked for other save point, it used && instead of == which caused it to overwrite other types. Fix bytes vs chars bug in text_get_region
Diffstat (limited to 'src/main/main.c')
-rw-r--r--src/main/main.c294
1 files changed, 294 insertions, 0 deletions
diff --git a/src/main/main.c b/src/main/main.c
new file mode 100644
index 0000000..f13e77e
--- /dev/null
+++ b/src/main/main.c
@@ -0,0 +1,294 @@
+#include <getopt.h>
+#include <locale.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "dged/allocator.h"
+#include "dged/binding.h"
+#include "dged/buffer.h"
+#include "dged/buffers.h"
+#include "dged/display.h"
+#include "dged/lang.h"
+#include "dged/minibuffer.h"
+#include "dged/reactor.h"
+#include "dged/settings.h"
+
+#include "bindings.h"
+#include "cmds.h"
+
+struct frame_allocator frame_allocator;
+
+void *frame_alloc(size_t sz) {
+ return frame_allocator_alloc(&frame_allocator, sz);
+}
+
+bool running = true;
+
+void terminate() { running = false; }
+
+static struct display *display = NULL;
+static bool display_resized = false;
+void resized() {
+ if (display != NULL) {
+ display_resize(display);
+ }
+ display_resized = true;
+
+ 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)
+
+void usage() { printf("TODO: print usage\n"); }
+
+int main(int argc, char *argv[]) {
+
+ static struct option longopts[] = {{"line", required_argument, NULL, 'l'},
+ {"end", no_argument, NULL, 'e'},
+ {"help", no_argument, NULL, 'h'},
+ {NULL, 0, NULL, 0}};
+
+ char *filename = NULL;
+ uint32_t jumpline = 1;
+ bool goto_end = false;
+ char ch;
+ while ((ch = getopt_long(argc, argv, "hel:", longopts, NULL)) != -1) {
+ switch (ch) {
+ case 'l':
+ jumpline = atoi(optarg);
+ break;
+ case 'e':
+ goto_end = true;
+ break;
+ case 'h':
+ usage();
+ return 0;
+ break;
+ default:
+ usage();
+ return 1;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 1) {
+ fprintf(stderr, "More than one file to open is not supported\n");
+ return 2;
+ } else if (argc == 1) {
+ filename = strdup(argv[0]);
+ }
+
+ setlocale(LC_ALL, "");
+
+ signal(SIGTERM, terminate);
+
+ struct commands commands = command_registry_create(32);
+
+ settings_init(64);
+ languages_init(true);
+ buffer_static_init();
+
+ frame_allocator = frame_allocator_create(16 * 1024 * 1024);
+
+ struct reactor *reactor = reactor_create();
+
+ display = display_create();
+ display_clear(display);
+ signal(SIGWINCH, resized);
+
+ register_global_commands(&commands, terminate);
+ register_buffer_commands(&commands);
+ register_window_commands(&commands);
+ register_settings_commands(&commands);
+
+ struct keyboard kbd = keyboard_create(reactor);
+
+ struct keymap *current_keymap = NULL;
+ struct keymap *global_keymap = register_bindings();
+
+ struct buffers buflist = {0};
+ buffers_init(&buflist, 32);
+ struct buffer initial_buffer = buffer_create("welcome");
+ if (filename != NULL) {
+ buffer_destroy(&initial_buffer);
+ initial_buffer = buffer_from_file(filename);
+ } else {
+ const char *welcome_txt = "Welcome to the editor for datagubbar 👴\n";
+ buffer_set_text(&initial_buffer, (uint8_t *)welcome_txt,
+ strlen(welcome_txt));
+ }
+
+ struct buffer *ib = buffers_add(&buflist, initial_buffer);
+ struct buffer minibuffer = buffer_create("minibuffer");
+ minibuffer_init(&minibuffer);
+ reset_minibuffer_keys(&minibuffer);
+
+ windows_init(display_height(display), display_width(display), ib,
+ &minibuffer);
+ struct window *active = windows_get_active();
+ if (goto_end) {
+ buffer_goto_end(window_buffer_view(active));
+ } else {
+ buffer_goto(window_buffer_view(active), jumpline > 0 ? jumpline - 1 : 0, 0);
+ }
+
+ DECLARE_TIMER(buffer);
+ DECLARE_TIMER(display);
+ DECLARE_TIMER(keyboard);
+
+ uint64_t frame_time = 0;
+ static char keyname[64] = {0};
+ static uint32_t nkeychars = 0;
+
+ while (running) {
+
+ 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);
+ windows_update(frame_alloc, frame_time);
+ TIMED_SCOPE_END(buffer);
+
+ struct window *active_window = windows_get_active();
+ if (minibuffer_focused()) {
+ active_window = minibuffer_window();
+ }
+
+ /* Update the screen by flushing command lists collected from updating the
+ * buffers.
+ */
+ TIMED_SCOPE_BEGIN(display);
+ display_begin_render(display);
+ windows_render(display);
+ struct buffer_location cursor =
+ window_absolute_cursor_location(active_window);
+ display_move_cursor(display, cursor.line, cursor.col);
+ display_end_render(display);
+ TIMED_SCOPE_END(display);
+
+ /* This blocks for events, so if nothing has happened we block here and let
+ * the CPU do something more useful than updating this narcissistic editor.
+ * This is also the reason that there is no timed scope around this, it
+ * simply makes no sense.
+ */
+ reactor_update(reactor);
+
+ TIMED_SCOPE_BEGIN(keyboard);
+ struct keyboard_update kbd_upd =
+ keyboard_update(&kbd, reactor, frame_alloc);
+
+ uint32_t input_data_idx = 0;
+ for (uint32_t ki = 0; ki < kbd_upd.nkeys; ++ki) {
+ struct key *k = &kbd_upd.keys[ki];
+
+ struct lookup_result res = {.found = false};
+ if (current_keymap != NULL) {
+ res = lookup_key(current_keymap, 1, k, &commands);
+ } else {
+ // check the global keymap first, then the buffer one
+ res = lookup_key(global_keymap, 1, k, &commands);
+ if (!res.found) {
+ res = lookup_key(buffer_keymap(window_buffer(active_window)), 1, k,
+ &commands);
+ }
+ }
+
+ if (res.found) {
+ switch (res.type) {
+ case BindingType_Command: {
+ if (res.command == NULL) {
+ minibuffer_echo_timeout(
+ 4, "binding found for key %s but not command", k);
+ } else {
+ int32_t ec = execute_command(res.command, &commands, active_window,
+ &buflist, 0, NULL);
+ if (ec != 0 && !minibuffer_displaying()) {
+ minibuffer_echo_timeout(4, "command %s failed with exit code %d",
+ res.command->name, ec);
+ }
+ }
+ current_keymap = NULL;
+ nkeychars = 0;
+ keyname[0] = '\0';
+ break;
+ }
+ case BindingType_Keymap: {
+ if (nkeychars > 0 && nkeychars < 64) {
+ keyname[nkeychars] = '-';
+ ++nkeychars;
+ }
+
+ if (nkeychars < 64) {
+ nkeychars += key_name(k, keyname + nkeychars, 64 - nkeychars);
+ minibuffer_echo("%s", keyname);
+ }
+
+ current_keymap = res.keymap;
+ break;
+ }
+ }
+ } else if (k->mod == 0) {
+ buffer_add_text(window_buffer_view(active_window),
+ &kbd_upd.raw[k->start], k->end - k->start);
+ } else {
+ char keyname[16];
+ key_name(k, keyname, 16);
+ if (current_keymap == NULL) {
+ minibuffer_echo_timeout(4, "key \"%s\" is not bound!", keyname);
+ } else {
+ minibuffer_echo_timeout(4, "key \"%s %s\" is not bound!",
+ current_keymap->name, keyname);
+ }
+ current_keymap = NULL;
+ nkeychars = 0;
+ keyname[0] = '\0';
+ }
+ }
+ TIMED_SCOPE_END(keyboard);
+
+ // 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_allocator_clear(&frame_allocator);
+ }
+
+ windows_destroy();
+ minibuffer_destroy();
+ buffer_destroy(&minibuffer);
+ buffers_destroy(&buflist);
+ display_clear(display);
+ display_destroy(display);
+ destroy_keymaps();
+ command_registry_destroy(&commands);
+ reactor_destroy(reactor);
+ frame_allocator_destroy(&frame_allocator);
+ buffer_static_teardown();
+ settings_destroy();
+
+ return 0;
+}