]> git.mdlowis.com Git - proto/aos.git/commitdiff
switch editor over to GTK based
authorMike Lowis <mike.lowis@gentex.com>
Tue, 8 Jul 2025 17:30:13 +0000 (13:30 -0400)
committerMike Lowis <mike.lowis@gentex.com>
Tue, 8 Jul 2025 17:30:13 +0000 (13:30 -0400)
21 files changed:
Makefile
bin/editor.c [new file with mode: 0644]
bin/editor/buf.c [deleted file]
bin/editor/config.h [deleted file]
bin/editor/dbc.c [deleted file]
bin/editor/dbc.h [deleted file]
bin/editor/draw.c [deleted file]
bin/editor/editlog.c [deleted file]
bin/editor/exec.c [deleted file]
bin/editor/gapbuf.c [deleted file]
bin/editor/job.c [deleted file]
bin/editor/leap.c [deleted file]
bin/editor/main.c [deleted file]
bin/editor/mouse.c [deleted file]
bin/editor/range.c [deleted file]
bin/editor/shortcuts.c [deleted file]
bin/editor/tide.h [deleted file]
bin/editor/view.c [deleted file]
bin/editor/xpty.c [deleted file]
bin/rules.mk
config.mk

index 371b9e62c4d36d34a5802e75cbd8134d448471d5..936e7b1fe5e15546d76d75c541a9ee567f54f6f0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,15 @@
-.PHONY: all libs bins tests rules clean
+.PHONY: all libs bins tests rules clean install
 
 all: bins
 
 clean:
        rm -rf $(OUTDIR) rules.mk
 
+install: bins
+       mkdir -p $(HOME)/bin $(HOME)/libexec
+       cp -f build/bin/* $(HOME)/bin
+       cp -rf libexec/* $(HOME)/libexec
+
 bins: libs tests
 
 tests:
diff --git a/bin/editor.c b/bin/editor.c
new file mode 100644 (file)
index 0000000..be189be
--- /dev/null
@@ -0,0 +1,558 @@
+#include <gtk/gtk.h>
+#include <stdbool.h>
+
+// TODO:
+//   * implement command language
+//   * implement editing shortcuts
+
+typedef struct EditItem {
+    struct EditItem* next; /* pointer to next operation in the stack */
+    gint beg;              /* beginning of affected region */
+    gint end;              /* end of affected region*/
+    gchar* data;           /* pointer to deleted character data */
+    gint transid;          /* id of transaction this item is a part of */
+} EditItem;
+
+typedef struct {
+    char* path;
+    GtkApplication* app;
+    GtkWidget* window;
+    GtkWidget* text_view;
+    GtkTextBuffer* buffer;
+    GtkEntry* cmd_entry;
+    GtkToolItem* save_icon;
+    GtkToolItem* save_as_icon;
+    GtkToolItem* undo_icon;
+    GtkToolItem* redo_icon;
+    EditItem* undo;
+    EditItem* redo;
+    bool edit_in_progress;
+} WindowContext;
+
+#ifdef __APPLE__
+    #define MOD_MASK     GDK_META_MASK
+    #define DEFAULT_FONT "18pt Monaco"
+#else
+    #define MOD_MASK      GDK_CONTROL_MASK
+    #define DEFAULT_FONT "14pt Liberation Mono"
+#endif
+
+
+
+static void CreateWindow(GtkApplication *app, char* path);
+
+//---------------------------------------------------------
+// Edit Helper Routines
+//---------------------------------------------------------
+
+static void UpdateUndoRedoIcons(WindowContext* ctx)
+{
+    gtk_widget_set_sensitive(GTK_WIDGET(ctx->save_icon), TRUE);
+    gtk_widget_set_sensitive(GTK_WIDGET(ctx->undo_icon), (ctx->undo != NULL));
+    gtk_widget_set_sensitive(GTK_WIDGET(ctx->redo_icon), (ctx->redo != NULL));
+}
+
+static void ReverseEdit(WindowContext* ctx, EditItem** from, EditItem** to)
+{
+    EditItem* item = *from;
+    if (item)
+    {
+        *from = item->next;
+       GtkTextIter start, stop;
+       gtk_text_buffer_get_start_iter(ctx->buffer, &start);
+       gtk_text_buffer_get_start_iter(ctx->buffer, &stop);
+       gtk_text_iter_set_offset(&start, item->beg);
+       gtk_text_iter_set_offset(&stop,  item->end);
+       ctx->edit_in_progress = true;
+       if (item->data) // If action was a delete
+       {
+           gtk_text_buffer_insert(ctx->buffer, &start, item->data, item->end - item->beg);
+           g_free(item->data);
+           item->data = NULL;
+       }
+       else // it was an insert
+       {
+           item->data = (char*)gtk_text_buffer_get_text(ctx->buffer, &start, &stop, FALSE);
+           gtk_text_buffer_delete(ctx->buffer, &start, &stop);
+       }
+       item->next = *to;
+       *to = item;
+       ctx->edit_in_progress = false;
+    }
+    UpdateUndoRedoIcons(ctx);
+}
+
+static void ClearEdits(EditItem** edits)
+{
+    EditItem* curr = *edits;
+    *edits = NULL;
+    while (curr)
+    {
+        if (curr->data)
+       {
+           g_free(curr->data);
+       }
+       EditItem* dead = curr;
+       curr = dead->next;
+       g_free(dead);
+    }
+
+}
+
+//---------------------------------------------------------
+// UI Event Routines
+//---------------------------------------------------------
+
+static void OnOpenApp(GtkApplication *app, GFile **files, gint n_files, gpointer user_data)
+{
+    for (int i = 0; i < n_files; i++)
+    {
+       char* path = g_file_get_path(files[i]);
+        CreateWindow(app, path);
+    }
+}
+
+static void OnActivateApp(GtkApplication *app, gpointer user_data)
+{
+    CreateWindow(app, NULL);
+}
+
+static void OnNew(GtkApplication *app, gpointer user_data)
+{
+    WindowContext* ctx = (WindowContext*)user_data;
+    CreateWindow(ctx->app, NULL);
+}
+
+static void OnOpen(GtkApplication *app, gpointer user_data)
+{
+    WindowContext* ctx = (WindowContext*)user_data;
+    GtkWidget* dialog = gtk_file_chooser_dialog_new (
+      "Open File", GTK_WINDOW(ctx->window), GTK_FILE_CHOOSER_ACTION_OPEN,
+      "_Cancel", GTK_RESPONSE_CANCEL,
+      "_Open", GTK_RESPONSE_ACCEPT,
+      NULL);
+    gint res = gtk_dialog_run (GTK_DIALOG (dialog));
+    if (res == GTK_RESPONSE_ACCEPT)
+    {
+        GtkFileChooser* chooser = GTK_FILE_CHOOSER (dialog);
+        char* path = gtk_file_chooser_get_filename (chooser);
+        CreateWindow(ctx->app, path);
+    }
+    gtk_widget_destroy (dialog);
+}
+
+static void OnSaveAs(GtkApplication *app, gpointer user_data);
+
+static void OnSave(GtkApplication *app, gpointer user_data)
+{
+    WindowContext* ctx = (WindowContext*)user_data;
+
+    if (ctx->path == NULL)
+    {
+        OnSaveAs(app, user_data);
+    }
+    else
+    {
+        // Get the text from the buffer
+        GtkTextIter start, end;
+        gtk_text_buffer_get_start_iter(ctx->buffer, &start);
+        gtk_text_buffer_get_end_iter(ctx->buffer, &end);
+        char *text = gtk_text_buffer_get_text(ctx->buffer, &start, &end, FALSE);
+
+        // Save the text to a file
+        FILE* file = fopen(ctx->path, "w");
+        if (file)
+        {
+            fputs(text, file);
+            fclose(file);
+            gtk_widget_set_sensitive(GTK_WIDGET(ctx->save_icon), FALSE);
+        }
+
+        // Free the allocated text
+        g_free(text);
+    }
+}
+
+static void OnSaveAs(GtkApplication *app, gpointer user_data)
+{
+    WindowContext* ctx = (WindowContext*)user_data;
+    GtkWidget* dialog = gtk_file_chooser_dialog_new (
+      "Save File As", GTK_WINDOW(ctx->window), GTK_FILE_CHOOSER_ACTION_SAVE,
+      "_Cancel", GTK_RESPONSE_CANCEL,
+      "_Save As", GTK_RESPONSE_ACCEPT,
+      NULL);
+    gint res = gtk_dialog_run (GTK_DIALOG (dialog));
+    if (res == GTK_RESPONSE_ACCEPT)
+    {
+        GtkFileChooser* chooser = GTK_FILE_CHOOSER (dialog);
+        ctx->path = gtk_file_chooser_get_filename (chooser);
+       gtk_window_set_title(GTK_WINDOW(ctx->window), ctx->path);
+       OnSave(app, user_data);
+    }
+    gtk_widget_destroy (dialog);
+}
+
+static void OnUndo(GtkApplication *app, gpointer user_data)
+{
+    WindowContext* ctx = (WindowContext*)user_data;
+    ReverseEdit(ctx, &ctx->undo, &ctx->redo);
+}
+
+static void OnRedo(GtkApplication *app, gpointer user_data)
+{
+    WindowContext* ctx = (WindowContext*)user_data;
+    ReverseEdit(ctx, &ctx->redo, &ctx->undo);
+}
+
+static void OnExec(GtkApplication *app, gpointer user_data)
+{
+    printf("%s\n", __func__);
+}
+
+static void OnHelp(GtkApplication *app, gpointer user_data)
+{
+    printf("%s\n", __func__);
+}
+
+static void OnCmdChanged(GtkApplication *app, gpointer user_data)
+{
+    WindowContext* ctx = (WindowContext*)user_data;
+    GtkEntryBuffer* buffer = gtk_entry_get_buffer(ctx->cmd_entry);
+    char *text = (char*)gtk_entry_buffer_get_text(buffer);
+    printf("cmd: '%s'\n", text);
+}
+
+static void OnQuit(GtkApplication *app, gpointer user_data)
+{
+    WindowContext* ctx = (WindowContext*)user_data;
+    gtk_window_close(GTK_WINDOW(ctx->window));
+    g_free(ctx);
+}
+
+static void OnJoin(GtkApplication *app, gpointer user_data)
+{
+    printf("%s\n", __func__);
+}
+
+static void OnSelectLine(GtkApplication *app, gpointer user_data)
+{
+    WindowContext* ctx = (WindowContext*)user_data;
+    GtkTextIter start, end;
+    gtk_text_buffer_get_selection_bounds (ctx->buffer, &start, &end);
+    gtk_text_iter_set_line_offset(&start, 0);
+    gtk_text_iter_forward_to_line_end(&end);
+    gtk_text_buffer_move_mark_by_name(ctx->buffer, "insert", &start);
+    gtk_text_buffer_move_mark_by_name(ctx->buffer, "selection_bound", &end);
+}
+
+static void OnUnindent(GtkApplication *app, gpointer user_data)
+{
+    printf("%s\n", __func__);
+}
+
+static void OnIndent(GtkApplication *app, gpointer user_data)
+{
+    printf("%s\n", __func__);
+}
+
+static void OnToggleComment(GtkApplication *app, gpointer user_data)
+{
+    printf("%s\n", __func__);
+}
+
+static void OnHighlightPrev(GtkApplication *app, gpointer user_data)
+{
+    printf("%s\n", __func__);
+}
+
+static void OnNewline(GtkApplication *app, gpointer user_data)
+{
+    WindowContext* ctx = (WindowContext*)user_data;
+    if (gtk_widget_has_focus(GTK_WIDGET(ctx->cmd_entry)))
+    {
+        OnExec(app, user_data);
+    }
+    else
+    {
+        GtkTextIter start, end;
+        gtk_text_buffer_get_selection_bounds(ctx->buffer, &start, NULL);
+       end = start;
+        gtk_text_iter_set_line_offset(&start, 0);
+        gtk_text_iter_forward_to_line_end(&end);
+        char* text = gtk_text_buffer_get_text(ctx->buffer, &start, &end, FALSE);
+        char* indent_end = text;
+        for (; *indent_end == ' ' || *indent_end == '\t'; indent_end++);
+        *indent_end = '\0';
+        gtk_text_buffer_delete_selection(ctx->buffer, FALSE, FALSE);
+        gtk_text_buffer_insert_at_cursor(ctx->buffer, "\n", 1);
+        gtk_text_buffer_insert_at_cursor(ctx->buffer, text, indent_end - text);
+        g_free(text);
+    }
+}
+
+static void OnTab(GtkApplication *app, gpointer user_data)
+{
+    WindowContext* ctx = (WindowContext*)user_data;
+    if (!gtk_widget_has_focus(GTK_WIDGET(ctx->cmd_entry)))
+    {
+       gtk_text_buffer_insert_at_cursor(ctx->buffer, "    ", 4);
+    }
+}
+
+static void OnToggleCommand(GtkApplication *app, gpointer user_data)
+{
+    WindowContext* ctx = (WindowContext*)user_data;
+    if (gtk_widget_has_focus(GTK_WIDGET(ctx->cmd_entry)))
+    {
+        gtk_widget_grab_focus(GTK_WIDGET(ctx->text_view));
+    }
+    else
+    {
+        gtk_widget_grab_focus(GTK_WIDGET(ctx->cmd_entry));
+    }
+}
+
+struct {
+    int mods;
+    int key;
+    void (*action)(GtkApplication*, gpointer);
+} Keyboard_Shortcuts[] = {
+    { MOD_MASK, GDK_KEY_s,            OnSave          },
+    { MOD_MASK, GDK_KEY_q,            OnQuit          },
+    { MOD_MASK, GDK_KEY_z,            OnUndo          },
+    { MOD_MASK, GDK_KEY_y,            OnRedo          },
+    { MOD_MASK, GDK_KEY_j,            OnJoin          },
+    { MOD_MASK, GDK_KEY_l,            OnSelectLine    },
+    { MOD_MASK, GDK_KEY_bracketleft,  OnUnindent      },
+    { MOD_MASK, GDK_KEY_bracketright, OnIndent        },
+    { MOD_MASK, GDK_KEY_slash,        OnToggleComment },
+    { MOD_MASK, GDK_KEY_t,            OnToggleCommand },
+    { 0,        GDK_KEY_Escape,       OnHighlightPrev },
+    { 0,        GDK_KEY_Return,       OnNewline       },
+    { 0,        GDK_KEY_Tab,          OnTab           },
+    { 0, 0, NULL }
+};
+
+static gboolean OnKeyPress(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
+{
+    WindowContext* ctx = (WindowContext*)user_data;
+    for(int i = 0; Keyboard_Shortcuts[i].action; i++)
+    {
+        if ((event->keyval == Keyboard_Shortcuts[i].key) &&
+            ((event->state & Keyboard_Shortcuts[i].mods) == Keyboard_Shortcuts[i].mods))
+        {
+            Keyboard_Shortcuts[i].action(ctx->app, user_data);
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+void OnInsert(GtkTextBuffer* self, const GtkTextIter* location, gchar* text, gint len, gpointer user_data)
+{
+    WindowContext* ctx = (WindowContext*)user_data;
+    if (!ctx->edit_in_progress)
+    {
+        gtk_widget_set_sensitive(GTK_WIDGET(ctx->save_icon), TRUE);
+       gint offset = gtk_text_iter_get_offset(location);
+       if (ctx->undo && !ctx->undo->data && ctx->undo->end == offset)
+       {
+            ctx->undo->end = offset + len;
+       }
+       else
+       {
+            EditItem* item = g_malloc0(sizeof(EditItem));
+            item->beg  = gtk_text_iter_get_offset(location);
+            item->end  = item->beg + strlen((char*)text);
+            item->next = ctx->undo;
+            ctx->undo = item;
+       }
+       ClearEdits(&ctx->redo);
+    }
+}
+
+void OnDelete(GtkTextBuffer* self, const GtkTextIter* start, const GtkTextIter* end, gpointer user_data)
+{
+    WindowContext* ctx = (WindowContext*)user_data;
+    if (!ctx->edit_in_progress)
+    {
+        gtk_widget_set_sensitive(GTK_WIDGET(ctx->save_icon), TRUE);
+        gint first = gtk_text_iter_get_offset(start);
+       gint last = gtk_text_iter_get_offset(end);
+
+       if (ctx->undo && ctx->undo->data && ctx->undo->beg == last)
+       {
+           gint size = (last - first) + (ctx->undo->end - ctx->undo->beg);
+           char* new_data = g_malloc(size + 1);
+           char* del_data = gtk_text_buffer_get_text(ctx->buffer, start, end, FALSE);
+           strncpy(new_data, del_data, (last-first));
+           strncpy(&new_data[last-first], ctx->undo->data, (ctx->undo->end - ctx->undo->beg));
+           new_data[size] = '\0';
+           ctx->undo->data = new_data;
+           ctx->undo->beg = first;
+       }
+       else
+       {
+            EditItem* item = g_malloc0(sizeof(EditItem));
+            item->beg = gtk_text_iter_get_offset(start);
+            item->end = gtk_text_iter_get_offset(end);
+            item->data = gtk_text_buffer_get_text(ctx->buffer, start, end, FALSE);
+            item->next = ctx->undo;
+            ctx->undo = item;
+       }
+       ClearEdits(&ctx->redo);
+    }
+}
+
+void OnStopEdit(GtkTextBuffer* self, gpointer user_data)
+{
+    WindowContext* ctx = (WindowContext*)user_data;
+    UpdateUndoRedoIcons(ctx);
+}
+
+//---------------------------------------------------------
+// UI Creation Routines
+//---------------------------------------------------------
+
+GtkToolItem* toolbar_add_icon(GtkWidget* toolbar, char* icon_name, char* label)
+{
+    GtkWidget* icon = gtk_image_new_from_icon_name(icon_name, GTK_ICON_SIZE_SMALL_TOOLBAR);
+    GtkToolItem* button = gtk_tool_button_new (icon, label);
+    gtk_tool_item_set_tooltip_text(button, label);
+    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), button, -1);
+    return button;
+}
+
+void toolbar_add_separator(GtkWidget* toolbar)
+{
+    GtkToolItem* sep = gtk_separator_tool_item_new();
+    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), sep, -1);
+}
+
+GtkEntry* toolbar_add_text_entry(GtkWidget* toolbar)
+{
+    GtkToolItem* item = gtk_tool_item_new();
+    GtkWidget* entry = gtk_entry_new();
+    gtk_tool_item_set_expand(item, TRUE);
+    gtk_container_add(GTK_CONTAINER(item), GTK_WIDGET(entry));
+    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), GTK_TOOL_ITEM(item), -1);
+    return GTK_ENTRY(entry);
+}
+
+static void CreateWindow(GtkApplication *app, char* path)
+{
+    GtkWidget *vbox;
+    GtkWidget *scrolled_window;
+    GtkWidget *toolbar;
+
+    // Create the main window
+    WindowContext* ctx = g_malloc0(sizeof(WindowContext));
+    ctx->app = app;
+    ctx->path = path;
+    ctx->window = gtk_application_window_new(app);
+    gtk_widget_add_events(GTK_WIDGET(ctx->window), GDK_KEY_PRESS_MASK);
+    gtk_window_set_title(GTK_WINDOW(ctx->window), (path ? path : "New File"));
+    gtk_window_set_default_size(GTK_WINDOW(ctx->window), 600, 480);
+
+    // Create a vertical box to hold the text view and button
+    vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
+    gtk_container_add(GTK_CONTAINER(ctx->window), vbox);
+
+    // Create the Toolbar
+    toolbar = gtk_toolbar_new();
+    gtk_toolbar_set_show_arrow(GTK_TOOLBAR(toolbar), FALSE);
+    gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
+    GtkToolItem* new_icon  = toolbar_add_icon(toolbar, "document-new", "New File");
+    GtkToolItem* open_icon = toolbar_add_icon(toolbar, "document-open", "Open File");
+    ctx->save_icon = toolbar_add_icon(toolbar, "document-save", "Save File");
+    ctx->save_as_icon = toolbar_add_icon(toolbar, "document-save-as", "Save File As...");
+    gtk_widget_set_sensitive(GTK_WIDGET(ctx->save_icon), (path == NULL ? TRUE : FALSE));
+    toolbar_add_separator(toolbar);
+    ctx->undo_icon = toolbar_add_icon(toolbar, "edit-undo", "Undo");
+    ctx->redo_icon = toolbar_add_icon(toolbar, "edit-redo", "Redo");
+    toolbar_add_separator(toolbar);
+    ctx->cmd_entry = toolbar_add_text_entry(toolbar);
+    GtkToolItem* exec_icon = toolbar_add_icon(toolbar, "media-playback-start", "Execute");
+    GtkToolItem* help_icon = toolbar_add_icon(toolbar, "dialog-question", "Help");
+
+    // Set default state of the icons
+    gtk_widget_set_sensitive(GTK_WIDGET(ctx->save_icon), FALSE);
+    gtk_widget_set_sensitive(GTK_WIDGET(ctx->undo_icon), FALSE);
+    gtk_widget_set_sensitive(GTK_WIDGET(ctx->redo_icon), FALSE);
+
+    // Create the text view and scrolled window
+    ctx->text_view = gtk_text_view_new();
+    ctx->buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ctx->text_view));
+    if (path)
+    {
+        FILE* file = fopen(path, "r");
+        if (file)
+       {
+            // Allocate memory for the file
+            fseek(file, 0, SEEK_END);
+            size_t file_size = ftell(file);
+            fseek(file, 0, SEEK_SET);
+            char* file_contents = (char *)g_malloc(file_size + 1);
+
+            // Read file contents
+            fread(file_contents, 1, file_size, file);
+            file_contents[file_size] = '\0'; // Null-terminate the string
+            fclose(file);
+
+            // Set the text buffer content
+            gtk_text_buffer_set_text(ctx->buffer, file_contents, -1);
+            g_free(file_contents);
+       }
+    }
+
+    GtkCssProvider *provider = gtk_css_provider_new ();
+    gtk_css_provider_load_from_data (
+        provider, "textview { font: " DEFAULT_FONT "; }", -1, NULL);
+    GtkStyleContext *context = gtk_widget_get_style_context (ctx->text_view);
+    gtk_style_context_add_provider (
+        context, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+    gtk_text_view_set_top_margin(GTK_TEXT_VIEW (ctx->text_view), 10);
+    gtk_text_view_set_bottom_margin(GTK_TEXT_VIEW (ctx->text_view), 10);
+    gtk_text_view_set_left_margin(GTK_TEXT_VIEW (ctx->text_view), 10);
+    gtk_text_view_set_right_margin(GTK_TEXT_VIEW (ctx->text_view), 10);
+    gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW (ctx->text_view), GTK_WRAP_NONE);
+    gtk_text_view_set_monospace(GTK_TEXT_VIEW (ctx->text_view), TRUE);
+    scrolled_window = gtk_scrolled_window_new(NULL, NULL);
+    gtk_container_add(GTK_CONTAINER(scrolled_window), ctx->text_view);
+
+    // Add toolbar and textview to the window
+    gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
+    gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0);
+
+    // Add event handlers
+    g_signal_connect(new_icon,          "clicked",           G_CALLBACK(OnNew),        ctx);
+    g_signal_connect(open_icon,         "clicked",           G_CALLBACK(OnOpen),       ctx);
+    g_signal_connect(ctx->save_icon,    "clicked",           G_CALLBACK(OnSave),       ctx);
+    g_signal_connect(ctx->save_as_icon, "clicked",           G_CALLBACK(OnSaveAs),     ctx);
+    g_signal_connect(ctx->undo_icon,    "clicked",           G_CALLBACK(OnUndo),       ctx);
+    g_signal_connect(ctx->redo_icon,    "clicked",           G_CALLBACK(OnRedo),       ctx);
+    g_signal_connect(exec_icon,         "clicked",           G_CALLBACK(OnExec),       ctx);
+    g_signal_connect(help_icon,         "clicked",           G_CALLBACK(OnHelp),       ctx);
+    g_signal_connect(ctx->buffer,       "insert-text",       G_CALLBACK(OnInsert),     ctx);
+    g_signal_connect(ctx->buffer,       "delete-range",      G_CALLBACK(OnDelete),     ctx);
+    g_signal_connect(ctx->buffer,       "end-user-action",   G_CALLBACK(OnStopEdit),   ctx);
+    g_signal_connect(ctx->cmd_entry,    "changed",           G_CALLBACK(OnCmdChanged), ctx);
+    g_signal_connect(ctx->window,       "key-press-event",   G_CALLBACK(OnKeyPress),   ctx);
+
+    // Show all the widgets
+    gtk_widget_show_all(ctx->window);
+}
+
+//---------------------------------------------------------
+// Main Routine
+//---------------------------------------------------------
+int main(int argc, char **argv)
+{
+    GtkApplication* app = gtk_application_new(NULL, G_APPLICATION_HANDLES_OPEN);
+    g_signal_connect(app, "activate", G_CALLBACK(OnActivateApp), NULL);
+    g_signal_connect(app, "open", G_CALLBACK(OnOpenApp), NULL);
+    int status = g_application_run(G_APPLICATION(app), argc, argv);
+    g_object_unref(app);
+    return status;
+}
+
diff --git a/bin/editor/buf.c b/bin/editor/buf.c
deleted file mode 100644 (file)
index 3447e8b..0000000
+++ /dev/null
@@ -1,918 +0,0 @@
-#define _XOPEN_SOURCE 700
-#include <liba.h>
-#include <stdc.h>
-#include "dbc.h"
-#include <ctype.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-#include "tide.h"
-#include "config.h"
-
-#ifndef NDEBUG
-static bool buf_valid(Buf* buf)
-{
-    return (
-           (buf->contents.bufsize > 0)
-        && (buf->contents.bufstart != NULL)
-        && (buf->contents.bufend != NULL)
-        && (buf->contents.gapstart != NULL)
-        && (buf->contents.gapend != NULL)
-        && (buf->contents.bufstart < buf->contents.bufend)
-        && (buf->contents.gapstart <= buf->contents.gapend)
-        && (buf->contents.gapstart >= buf->contents.bufstart)
-        && (buf->contents.gapend >= buf->contents.bufstart)
-        && (buf->contents.gapstart <= buf->contents.bufend)
-        && (buf->contents.gapend <= buf->contents.bufend)
-    );
-}
-#endif
-
-static void getcol(Buf* buf)
-{
-    require(buf != NULL);
-    Sel sel = buf->selection;
-    size_t pos = sel.end, curr = buf_bol(buf, pos);
-    for (sel.col = 0; curr < pos; curr = buf_byrune(buf, curr, 1))
-    {
-        sel.col += runewidth(sel.col, buf_getrat(buf, curr));
-    }
-    buf->selection = sel;
-}
-
-static void setcol(Buf* buf)
-{
-    require(buf != NULL);
-    Sel sel = buf->selection;
-    size_t bol = buf_bol(buf, sel.end);
-    size_t curr = bol, len = 0, i = 0;
-
-    /* determine the length of the line in columns */
-    for (; !buf_iseol(buf, curr); curr++)
-    {
-        len += runewidth(len, buf_getrat(buf, curr));
-    }
-
-    /* iterate over the runes until we reach the target column */
-    for (sel.end = bol, i = 0; i < sel.col && i < len;)
-    {
-        int width = runewidth(i, buf_getrat(buf, sel.end));
-        sel.end = buf_byrune(buf, sel.end, 1);
-        if (sel.col >= i && sel.col < (i + width))
-        {
-            break;
-        }
-        i += width;
-    }
-    buf->selection = sel;
-}
-
-static Sel selswap(Sel sel)
-{
-    size_t off = sel.beg;
-    sel.beg = sel.end;
-    sel.end = off;
-    return sel;
-}
-
-static Sel selget(Buf* buf)
-{
-    Sel sel = buf->selection;
-    return (sel.end < sel.beg ? selswap(sel) : sel);
-}
-
-static void selset(Buf* buf, Sel sel)
-{
-    buf->selection = sel;
-    getcol(buf);
-}
-
-static void putb(Buf* buf, char b, Sel* p_sel)
-{
-    range_add(&(buf->point), p_sel->end);
-    gapbuf_putb(&buf->contents, b, p_sel);
-}
-
-static void putch(Buf* buf, char b, Sel* p_sel)
-{
-    if (b != '\r')
-    {
-        if (b == '\n' && DosLineFeed)
-        {
-            putb(buf, '\r', p_sel);
-            putb(buf, '\n', p_sel);
-        }
-        else
-        {
-            putb(buf, b, p_sel);
-        }
-        buf->status = MODIFIED;
-    }
-}
-
-void buf_init(Buf* buf)
-{
-    require(buf != NULL);
-
-    /* reset the state to defaults */
-    gapbuf_init(&buf->contents);
-    buf->status = NORMAL;
-    buf->log.undo = NULL;
-    buf->log.redo = NULL;
-    buf->log.transid = -1;
-    buf->selection = (Sel){0,0,0};
-
-    ensure(buf_valid(buf));
-}
-
-void buf_setpath(Buf* buf, char* path)
-{
-    require(buf != NULL);
-    if (path)
-    {
-        free(buf->path);
-        buf->path = strdup(path);
-        ensure(buf->path != NULL);
-    }
-}
-
-void buf_load(Buf* buf, char* path)
-{
-    require(buf != NULL);
-    if (path)
-    {
-        buf->path = strdup(path);
-        gapbuf_load(&buf->contents, buf->path);
-
-        /* reset buffer state */
-        buf->status  = NORMAL;
-        buf_logclear(buf);
-
-        /* use the EOL style of the first line to determine EOL style */
-        DosLineFeed = (gapbuf_getb(&buf->contents, buf_eol(buf, 0)) == '\r');
-    }
-    ensure(buf_valid(buf));
-}
-
-void buf_reload(Buf* buf)
-{
-    require(buf != NULL);
-    char* path = buf->path;
-    buf->path = NULL;
-    buf_init(buf);
-    buf_load(buf, path);
-}
-
-static void trim_whitespace(Buf* buf)
-{
-    require(buf != NULL);
-    require(buf_end(buf) > 0);
-
-    Sel sel = buf->selection;
-    bool swapped = (sel.beg > sel.end);
-    if (swapped)
-    {
-        sel = selswap(sel);
-    }
-
-    unsigned prev = 1;
-    buf->selection.beg = buf->selection.end = 0;
-    buf_logstart(buf);
-    while (prev != buf->selection.end)
-    {
-        int r = gapbuf_getb(&buf->contents, buf->selection.end);
-        /* If we reached a newline, then delete whatever we have selected */
-        if (r == '\r' || r == '\n')
-        {
-            buf->selection.beg = buf_byrune(buf, buf->selection.beg, +1);
-            Sel del = buf->selection;
-            sel.beg -= (del.beg < sel.beg ? (min(del.end, sel.beg) - del.beg) : 0);
-            sel.end -= (del.beg < sel.end ? (min(del.end, sel.end) - del.beg) : 0);
-            buf_del(buf);
-        }
-
-        /* if current char is not whitespace, then shrink the selection */
-        if (r != ' ' && r != '\t')
-        {
-            buf->selection.beg = buf->selection.end;
-        }
-
-        /* move to the next character */
-        prev = buf->selection.end;
-        buf->selection.end = buf_byrune(buf, buf->selection.end, +1);
-    }
-    buf_logstop(buf);
-    if (swapped)
-    {
-        sel = selswap(sel);
-    }
-    selset(buf, sel);
-}
-
-int buf_save(Buf* buf, char* path)
-{
-    require(buf != NULL);
-    buf_setpath(buf, path);
-    if (buf_end(buf) > 0)
-    {
-        if (TrimOnSave && (buf_end(buf) > 0))
-        {
-            trim_whitespace(buf);
-        }
-
-        long nwrite = gapbuf_save(&buf->contents, buf->path);
-        buf->status = (nwrite >= 0 ? NORMAL : ERRORED);
-
-        if (buf->status == NORMAL)
-        {
-            buf->log.save = buf->log.undo;
-        }
-    }
-    ensure(buf_valid(buf));
-    return buf->status;
-}
-
-/* Undo/Redo Operations
- ******************************************************************************/
-void buf_logstart(Buf* buf)
-{
-    editlog_seqstart(&(buf->log));
-}
-
-void buf_logstop(Buf* buf)
-{
-    editlog_seqstop(&(buf->log));
-}
-
-void buf_logclear(Buf* buf)
-{
-    editlog_clear(&(buf->log));
-}
-
-void buf_lastins(Buf* buf)
-{
-    editlog_lastins(&(buf->log), &(buf->selection));
-}
-
-void buf_undo(Buf* buf)
-{
-    editlog_undo(buf);
-}
-
-void buf_redo(Buf* buf)
-{
-    editlog_redo(buf);
-}
-
-/* Basic Operations and Accessors
- ******************************************************************************/
-size_t buf_end(Buf* buf)
-{
-    return gapbuf_end(&buf->contents);
-}
-
-int buf_getrat(Buf* buf, size_t off)
-{
-    require(buf != NULL);
-    Int rlen = 0;
-    Rune rune = 0;
-    if (gapbuf_getb(&buf->contents, off) == '\r' && gapbuf_getb(&buf->contents, off+1) == '\n')
-    {
-        rune = '\n';
-    }
-    else
-    {
-        while ( !UTF8_Decode(&rune, &rlen, gapbuf_getb(&buf->contents, off++)) )
-        {
-        }
-    }
-    return rune;
-}
-
-void buf_putc(Buf* buf, int c)
-{
-    require(buf != NULL);
-    Byte utf8buf[UTF_MAX+1] = {0};
-    (void)UTF8_Encode(utf8buf, c);
-    buf_puts(buf, (char*)utf8buf);
-    ensure(buf_valid(buf));
-}
-
-void buf_puts(Buf* buf, char* s)
-{
-    require(buf != NULL);
-    buf_del(buf);
-    size_t beg = buf_selbeg(buf);
-    if (s && *s)
-    {
-        for (; *s; s++)
-        {
-            putch(buf, *s, &(buf->selection));
-            if (buf->oninsert)
-            {
-                buf->oninsert(*s);
-            }
-        }
-        editlog_add(buf, beg, buf_selend(buf), NULL);
-    }
-    ensure(buf_valid(buf));
-}
-
-int buf_getc(Buf* buf)
-{
-    require(buf != NULL);
-    return buf_getrat(buf, buf->selection.end);
-}
-
-char* buf_gets(Buf* buf)
-{
-    require(buf != NULL);
-    Sel sel = selget(buf);
-    size_t nbytes = sel.end - sel.beg;
-    char* str = malloc(nbytes+1);
-    for (size_t i = 0; i < nbytes; i++)
-    {
-        str[i] = gapbuf_getb(&buf->contents, sel.beg + i);
-    }
-    str[nbytes] = '\0';
-    return str;
-}
-
-char* buf_getsat(Buf* buf, size_t beg, size_t end)
-{
-    require(buf != NULL);
-    Sel sel = selget(buf);
-    buf->selection = (Sel){ .beg = beg, .end = end };
-    char* str = buf_gets(buf);
-    buf->selection = sel;
-    return str;
-}
-
-void buf_del(Buf* buf)
-{
-    require(buf != NULL);
-    Sel sel = selget(buf);
-    size_t nbytes = sel.end - sel.beg;
-    if (nbytes > 0)
-    {
-        /* perform the delete */
-        buf->status = MODIFIED;
-        char* str = buf_gets(buf);
-        range_del(&(buf->point), sel.beg, sel.end);
-        gapbuf_del(&buf->contents, sel.beg, nbytes);
-        sel.end = sel.beg;
-        buf->selection = sel;
-        editlog_add(buf, sel.beg, sel.end, str);
-    }
-    ensure(buf_valid(buf));
-}
-
-/* Positional and Movement Operations
- ******************************************************************************/
-static Rune nextrune(Buf* buf, size_t off, int move, bool (*testfn)(Rune))
-{
-    bool ret = false;
-    size_t end = buf_end(buf);
-    if (move < 0 && off > 0)
-    {
-        ret = testfn(buf_getrat(buf, off-1));
-    }
-    else if (move > 0 && off < end)
-    {
-        ret = testfn(buf_getrat(buf, off+1));
-    }
-    return ret;
-}
-
-static void selline(Buf* buf)
-{
-    Sel sel = selget(buf);
-    sel.beg = buf_bol(buf, sel.end);
-    sel.end = buf_eol(buf, sel.end);
-    sel.end = buf_byrune(buf, sel.end, RIGHT);
-    selset(buf, sel);
-}
-
-static void selblock(Buf* buf, Rune first, Rune last)
-{
-    Sel sel = selget(buf);
-    int balance = 0, dir = 0;
-    size_t beg, end = sel.end;
-
-    /* figure out which end of the block we're starting at */
-    if (buf_getrat(buf, end) == first)
-    {
-        dir = +1, balance++, beg = end++;
-    }
-    else if (buf_getrat(buf, end) == last)
-    {
-        dir = -1, balance--, beg = end--;
-    }
-    else
-    {
-        /* do nothing */
-    }
-
-    if (dir != 0)
-    {
-        /* scan for a blanced set of braces */
-        while (true)
-        {
-            if (buf_getrat(buf, end) == first)
-            {
-                balance++;
-            }
-            else if (buf_getrat(buf, end) == last)
-            {
-                balance--;
-            }
-
-            if (balance == 0 || end >= buf_end(buf) || end == 0)
-            {
-                break;
-            }
-            else
-            {
-                end += dir;
-            }
-        }
-
-        /* update the selection if we found a block */
-        if (balance == 0)
-        {
-            if (end > beg)
-            {
-                beg++;
-            }
-            else
-            {
-                end++;
-            }
-            buf->selection.beg = beg;
-            buf->selection.end = end;
-        }
-    }
-}
-
-static int bytes_match(Buf* buf, size_t mbeg, size_t mend, char* str)
-{
-    int ret = 0;
-    for (; *str && mbeg < mend; str++, mbeg++)
-    {
-        int cmp = *str - gapbuf_getb(&buf->contents, mbeg);
-        if (cmp != 0)
-        {
-            ret = cmp;
-            break;
-        }
-    }
-    return ret;
-}
-
-bool buf_isbol(Buf* buf, size_t off)
-{
-    require(buf != NULL);
-    size_t bol = buf_bol(buf, off);
-    return (bol == off);
-}
-
-bool buf_iseol(Buf* buf, size_t off)
-{
-    require(buf != NULL);
-    Rune r = buf_getrat(buf, off);
-    return (r == '\r' || r == '\n');
-}
-
-size_t buf_bol(Buf* buf, size_t off)
-{
-    require(buf != NULL);
-    for (; !buf_iseol(buf, off-1); off--)
-    {
-    }
-    return off;
-}
-
-size_t buf_eol(Buf* buf, size_t off)
-{
-    require(buf != NULL);
-    for (; !buf_iseol(buf, off); off++)
-    {
-    }
-    return off;
-}
-
-void buf_selword(Buf* buf, bool (*isword)(Rune))
-{
-    require(buf != NULL);
-    Sel sel = selget(buf);
-    for (; isword(buf_getrat(buf, sel.beg-1)); sel.beg--)
-    {
-    }
-    for (; isword(buf_getrat(buf, sel.end));   sel.end++)
-    {
-    }
-    buf->selection = sel;
-}
-
-void buf_selall(Buf* buf)
-{
-    require(buf != NULL);
-    buf->selection = (Sel){ .beg = 0, .end = buf_end(buf) };
-}
-
-static bool selquote(Buf* buf, Rune c)
-{
-    bool selected = false;
-    Rune curr = buf_getc(buf);
-    size_t nextoff = buf_byrune(buf, buf->selection.end, RIGHT);
-    Rune prev = buf_getrat(buf, buf_byrune(buf, buf->selection.end, LEFT));
-    Rune next = buf_getrat(buf, buf_byrune(buf, buf->selection.end, RIGHT));
-    if (prev == c || curr == c)
-    {
-        size_t bend = buf_end(buf);
-        buf->selection.beg = buf->selection.end = (prev == c ? buf->selection.end : nextoff);
-        size_t selend = buf->selection.end;
-        for (; selend < bend && buf_getrat(buf, selend) != c; selend = buf_byrune(buf, selend, RIGHT))
-        {
-        }
-        if (buf_getrat(buf, selend) == c)
-        {
-            buf->selection.end = selend;
-        }
-        selected = true;
-    }
-    else if (next == c)
-    {
-        buf->selection.beg = buf->selection.end;
-        buf->selection.end = nextoff;
-        size_t selbeg = buf->selection.beg;
-        for (; selbeg > 0 && buf_getrat(buf, selbeg) != c; selbeg = buf_byrune(buf, selbeg, LEFT))
-        {
-        }
-        if (buf_getrat(buf, selbeg) == c)
-        {
-            buf->selection.beg = buf_byrune(buf, selbeg, RIGHT);
-        }
-        selected = true;
-    }
-    return selected;
-}
-
-void buf_selctx(Buf* buf, bool (*isword)(Rune))
-{
-    require(buf != NULL);
-    size_t bol = buf_bol(buf, buf->selection.end);
-    Rune curr = buf_getc(buf);
-    if (curr == '(' || curr == ')')
-    {
-        selblock(buf, '(', ')');
-    }
-    else if (curr == '[' || curr == ']')
-    {
-        selblock(buf, '[', ']');
-    }
-    else if (curr == '{' || curr == '}')
-    {
-        selblock(buf, '{', '}');
-    }
-    else if (curr == '<' || curr == '>')
-    {
-        selblock(buf, '<', '>');
-    }
-    else if (buf->selection.end == bol || curr == '\n')
-    {
-        selline(buf);
-    }
-    else if (selquote(buf, '"') || selquote(buf, '`') || selquote(buf, '\''))
-    {
-        ; /* condition performs selection */
-    }
-    else if (isword(curr))
-    {
-        buf_selword(buf, isword);
-    }
-    else
-    {
-        buf_selword(buf, risbigword);
-    }
-    getcol(buf);
-}
-
-size_t buf_byrune(Buf* buf, size_t pos, int count)
-{
-    require(buf != NULL);
-    int move = (count < 0 ? -1 : 1);
-    count *= move; // remove the sign if there is one
-    for (; count > 0; count--)
-    {
-        if (pos > 0 && move < 0)
-        {
-            if (gapbuf_getb(&buf->contents, pos-2) == '\r' && gapbuf_getb(&buf->contents, pos-1) == '\n')
-            {
-                pos -= 2;
-            }
-            else
-            {
-                pos += move;
-            }
-        }
-        else if (pos < buf_end(buf) && move > 0)
-        {
-            if (gapbuf_getb(&buf->contents, pos) == '\r' && gapbuf_getb(&buf->contents, pos+1) == '\n')
-            {
-                pos += 2;
-            }
-            else
-            {
-                pos += move;
-            }
-        }
-    }
-    return pos;
-}
-
-static size_t byword(Buf* buf, size_t off, int count)
-{
-    require(buf != NULL);
-    int move = (count < 0 ? -1 : 1);
-    count *= move; // remove the sign if there is one
-
-    for (; count > 0; count--)
-    {
-        while (nextrune(buf, off, move, risblank))
-        {
-            off = buf_byrune(buf, off, move);
-        }
-
-        if (nextrune(buf, off, move, risword))
-        {
-            while (nextrune(buf, off, move, risword))
-            {
-                off = buf_byrune(buf, off, move);
-            }
-
-            if (move > 0)
-            {
-                off = buf_byrune(buf, off, move);
-            }
-        }
-        else
-        {
-            off = buf_byrune(buf, off, move);
-        }
-    }
-    return off;
-}
-
-static size_t byline(Buf* buf, size_t pos, int count)
-{
-    require(buf != NULL);
-    int move = (count < 0 ? -1 : 1);
-    count *= move; // remove the sign if there is one
-    for (; count > 0; count--)
-    {
-        if (move < 0)
-        {
-            if (pos > buf_eol(buf, 0))
-            {
-                pos = buf_byrune(buf, buf_bol(buf, pos), LEFT);
-            }
-        }
-        else
-        {
-            size_t next = buf_byrune(buf, buf_eol(buf, pos), RIGHT);
-            if (next <= buf_end(buf))
-            {
-                pos = next;
-            }
-        }
-    }
-    return pos;
-}
-
-bool buf_findstr(Buf* buf, int dir, char* str)
-{
-    require(buf != NULL);
-    bool found = false;
-    size_t len = strlen(str);
-    size_t start = buf->selection.beg;
-    size_t mbeg = (start + dir);
-    size_t mend = (mbeg + len);
-    size_t nleft = buf_end(buf);
-    for (; (mbeg != start) && nleft; nleft--)
-    {
-        if ((gapbuf_getb(&buf->contents, mbeg) == str[0]) &&
-            (gapbuf_getb(&buf->contents, mend-1) == str[len-1]) &&
-            (0 == bytes_match(buf, mbeg, mend, str)))
-        {
-            buf->selection.beg = mbeg, buf->selection.end = mend;
-            found = true;
-            break;
-        }
-        mbeg += dir, mend += dir;
-        if (mend > buf_end(buf))
-        {
-            mbeg = (dir < 0 ? buf_end(buf)-len : 0), mend = mbeg + len;
-        }
-    }
-    return found;
-}
-
-void buf_setln(Buf* buf, size_t line)
-{
-    require(buf != NULL);
-    size_t curr = 0, end = buf_end(buf);
-    while (line > 1 && curr < end)
-    {
-        size_t next = byline(buf, curr, DOWN);
-        if (curr == next)
-        {
-            break;
-        }
-        line--, curr = next;
-    }
-    buf->selection.beg = curr;
-    buf->selection.end = curr;
-}
-
-void buf_getln(Buf* buf, size_t* begln, size_t* endln)
-{
-    require(buf != NULL);
-    size_t line = 1, curr = 0, end = buf_end(buf);
-    size_t sbeg = buf_selbeg(buf), send = buf_selend(buf);
-    while (curr < end)
-    {
-        size_t next = byline(buf, curr, DOWN);
-
-        if (curr <= sbeg && sbeg < next)
-        {
-            *begln = line, *endln = line;
-        }
-
-        if (curr <= send && send < next)
-        {
-            *endln = line;
-            break;
-        }
-
-        if (curr == next)
-        {
-            break;
-        }
-        line++;
-        curr = next;
-    }
-}
-
-size_t buf_selbeg(Buf* buf)
-{
-    require(buf != NULL);
-    return selget(buf).beg;
-}
-
-size_t buf_selend(Buf* buf)
-{
-    require(buf != NULL);
-    return selget(buf).end;
-}
-
-size_t buf_selsz(Buf* buf)
-{
-    require(buf != NULL);
-    return (selget(buf).end - selget(buf).beg);
-}
-
-void buf_selln(Buf* buf)
-{
-    require(buf != NULL);
-    /* Expand the selection to completely select the lines covered */
-    Sel sel = selget(buf);
-    sel.beg = buf_bol(buf, sel.beg);
-    if (!buf_iseol(buf, sel.end-1) || sel.end == sel.beg)
-    {
-        sel.end = buf_eol(buf, sel.end);
-        sel.end = buf_byrune(buf, sel.end, RIGHT);
-    }
-    selset(buf, sel);
-}
-
-void buf_selclr(Buf* buf, int dir)
-{
-    require(buf != NULL);
-    Sel sel = selget(buf);
-    if (dir > 0)
-    {
-        sel.beg = sel.end;
-    }
-    else
-    {
-        sel.end = sel.beg;
-    }
-    selset(buf, sel);
-}
-
-bool buf_insel(Buf* buf, size_t off)
-{
-    require(buf != NULL);
-    return (off >= buf_selbeg(buf) && off < buf_selend(buf));
-}
-
-bool buf_inpoint(Buf* buf, size_t off)
-{
-    require(buf != NULL);
-    bool empty_point = (buf->point.beg == buf->point.end) && (off == buf->point.beg);
-    bool in_range = (off >= buf->point.beg && off < buf->point.end);
-    return (buf->oninsert && (empty_point || in_range));
-}
-
-char* buf_fetch(Buf* buf, bool (*isword)(Rune), size_t off)
-{
-    require(buf != NULL);
-    require(isword != NULL);
-    char* str = NULL;
-    Sel prev = buf->selection;
-    if (!buf_insel(buf, off))
-    {
-        buf->selection = (Sel){ .beg = off, .end = off };
-        buf_selword(buf, isword);
-    }
-    str = buf_gets(buf);
-    buf->selection = prev;
-    return str;
-}
-
-size_t buf_moveby(Buf* buf, int bything, size_t pos, int count)
-{
-    size_t newpos = pos;
-    switch (bything)
-    {
-        case BY_WORD:
-            newpos = byword(buf, pos, count);
-            break;
-        case BY_LINE:
-            newpos = byline(buf, pos, count);
-            break;
-        case BY_RUNE:
-        default:
-            newpos = buf_byrune(buf, pos, count);
-            break;
-    }
-    return newpos;
-}
-
-void buf_selmove(Buf* buf, bool extsel, int move, int bything)
-{
-    if (buf_selsz(buf) && !extsel)
-    {
-        buf_selclr(buf, move);
-        if (bything == BY_LINE)
-        {
-            /* we perform one less move if we are going down but selection
-                ends on the beginning of the next line */
-            if (move > 0 && buf_isbol(buf, buf_selend(buf)))
-            {
-                move--;
-            }
-            buf->selection.end = buf_moveby(buf, bything, buf->selection.end, move);
-        }
-    }
-    else
-    {
-        buf->selection.end = buf_moveby(buf, bything, buf->selection.end, move);
-    }
-
-    if (bything == BY_LINE)
-    {
-        setcol(buf); // set cursor to correct column
-    }
-    else
-    {
-        getcol(buf); // update column tracking with cursor position
-    }
-
-    /* collapse the selection if necessary, without updating column */
-    if (!extsel)
-    {
-        Sel sel = selget(buf);
-        if (move > 0)
-        {
-            sel.beg = sel.end;
-        }
-        else
-        {
-            sel.end = sel.beg;
-        }
-        buf->selection = sel;
-    }
-}
-
-void buf_selmoveto(Buf* buf, bool extsel, size_t off)
-{
-    buf->selection.end = (off > buf_end(buf) ? buf_end(buf) : off);
-    if (!extsel)
-    {
-        buf->selection.beg = buf->selection.end;
-    }
-    getcol(buf);
-}
diff --git a/bin/editor/config.h b/bin/editor/config.h
deleted file mode 100644 (file)
index e1ab943..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/** @file */
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-variable"
-
-enum { Off = 0, On = 1 };
-
-enum { /* Color Names */
-    Red, Purple, Orange,
-    EditBg, EditFg, EditSel,
-    TagsBg, TagsFg, TagsSel,
-    ScrollBg, ScrollFg,
-    VerBdr, HorBdr, Point,
-    ClrCount
-};
-
-#define CMD_TIDE      "!tide"
-#define CMD_PICKFILE  "!pickfile ."
-#define CMD_COMPLETE  "picktag print tags"
-#define CMD_FCOMPLETE "fcomplete"
-#define CMD_GOTO_TAG  "!picktag fetch tags"
-
-/* Command used to open file in editor at a given line */
-static char* EditCmd[] = { "tide", "-l", 0, 0, 0 };
-
-/* The shell: Filled in with $SHELL. Used to execute commands */
-static char* ShellCmd[] = { 0, "-c", 0, 0 };
-
-/* Sed command used to execute commands marked with ':' sigil */
-static char* SedCmd[] = { "sed", "-Ee", 0, 0 };
-
-/* Command used to fetch some text based on a set of rules */
-static char* FetchCmd[] = { "fetch", 0, 0 };
-
-/* Default tag region text in editor windows */
-static char* TagString = "Del Put Get | Font Tabs Eol | x+ w+ !st !term | Find ";
-
-/* List of font patterns available to the editor */
-static char* Fonts[2] = {
-    "Verdana:size=12",
-    "Liberation Mono:size=12"
-};
-
-#ifdef INCLUDE_DEFS
-/* Integer config options */
-int WinWidth    = 640; /* default window width */
-int WinHeight   = 480; /* default window height */
-int ScrollWidth = 8;   /* width in pixels of the scrollbar */
-int Timeout     = 100; /* number of milliseconds to wait before poll() times out */
-int TabWidth    = 4;   /* number of spaces tab characters will be expanded to */
-int ScrollBy    = 1;   /* number of lines to scroll by on mouse wheel  events */
-int ClickTime   = 500; /* number of milliseconds after a click wehre multi-clicks will be recognized */
-int CopyIndent  = On;  /* whether indentation should be copied from previous line or not */
-int TrimOnSave  = On;  /* whether trailing whitespace should be removed on save or not */
-int ExpandTabs  = On;  /* whether tab characters should be expanded to spaces or not */
-int DosLineFeed = Off; /* use \r\n line endings by default */
-int Margin      = 50;
-#else
-extern int WinWidth, WinHeight, ScrollWidth, Timeout, TabWidth, ScrollBy,
-    ClickTime, CopyIndent, TrimOnSave, ExpandTabs, DosLineFeed, Margin;
-#endif
-
-static int Palette[ClrCount] = {
-#if 0 /* Original Acme Colors */
-    [EditBg]   = 0xFFFFEA, /* Edit region background */
-    [EditFg]   = 0x000000, /* Edit region text */
-    [EditSel]  = 0xEEEE9E, /* Edit region selection */
-    [TagsBg]   = 0xEAFFFF, /* Tags region background */
-    [TagsFg]   = 0x000000, /* Tags region text */
-    [TagsSel]  = 0x9EEEEE, /* Tags region selection */
-    [ScrollBg] = 0x99994C, /* Scroll region background */
-    [ScrollFg] = 0xFFFFEA, /* Scroll region foreground */
-    [VerBdr]   = 0x99994C, /* Vertical border */
-    [HorBdr]   = 0x000000, /* Horizontal border */
-    [Point]    = 0xEFEFDA, /* Point background */
-    [Purple]   = 0x6666CC, /* Purple */
-    [Red]      = 0xCC0000, /* Red */
-    [Orange]   = 0xFF7700, /* Orange */
-#else
-    [EditBg]   = 0xF5F5F0, /* Edit region background */
-    [EditFg]   = 0x222222, /* Edit region text */
-    [EditSel]  = 0xAACCEE, /* Edit region selection */
-
-    [TagsBg]   = 0xF5F5F0, /* Tags region background */
-    [TagsFg]   = 0x222222, /* Tags region text */
-    [TagsSel]  = 0xAACCEE, /* Tags region selection */
-
-    [ScrollBg] = 0x959590, /* Scroll region background */
-    [ScrollFg] = 0xF5F5F0, /* Scroll region foreground */
-
-    [VerBdr]   = 0x959590, /* Vertical border */
-    [HorBdr]   = 0x222222, /* Horizontal border */
-
-    [Point]    = 0xD5D5D0, /* Point background */
-    [Purple]   = 0x6666CC, /* Purple */
-    [Red]      = 0xCC0000, /* Red */
-    [Orange]   = 0xFF7700, /* Orange */
-#endif
-};
-
-#pragma GCC diagnostic pop
diff --git a/bin/editor/dbc.c b/bin/editor/dbc.c
deleted file mode 100644 (file)
index e772611..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-#include <liba.h>
-#include <stdc.h>
-#include "dbc.h"
-#include <stdio.h>
-#include <signal.h>
-
-#ifndef NDEBUG
-
-static char ErrMsg[8192];
-static char* DumpPath = NULL;
-static void (*DumpFn)(FILE*) = NULL;
-
-static void dump_and_abort(char* msg)
-{
-    Telemetry_Send("%s", msg);
-    FILE* f = (DumpPath ? fopen(DumpPath, "w") : stderr);
-    fprintf(f, "%s\n\n", msg);
-    if (DumpFn)
-    {
-        DumpFn(f);
-    }
-    fprintf(f, "\n%s\n", msg);
-    fclose(f);
-    _Exit(1);
-}
-
-static void handle_signal(int sig)
-{
-    if (SIGABRT == sig)
-    {
-        dump_and_abort("SIGABRT - Process abort signal");
-    }
-    else if (SIGBUS == sig)
-    {
-        dump_and_abort("SIGBUS - Access to an undefined portion of a memory object");
-    }
-    else if (SIGFPE == sig)
-    {
-        dump_and_abort("SIGFPE - Erroneous arithmetic operation");
-    }
-    else if (SIGILL == sig)
-    {
-        dump_and_abort("SIGILL - Illegal instruction");
-    }
-    else if (SIGSEGV == sig)
-    {
-        dump_and_abort("SIGSEGV - Invalid memory reference");
-    }
-    else if (SIGALRM == sig)
-    {
-        dump_and_abort("SIGALRM - Watchdog timer expired");
-    }
-}
-
-void dbc_init(char* path, void (*dumpfn)(FILE*))
-{
-    DumpPath = path;
-    DumpFn = dumpfn;
-    signal(SIGABRT,  handle_signal);
-    signal(SIGBUS,  handle_signal);
-    signal(SIGFPE,  handle_signal);
-    signal(SIGILL,  handle_signal);
-    signal(SIGSEGV, handle_signal);
-}
-
-void dbc_require(bool success, char* text, char* file, int line)
-{
-    if (!success)
-    {
-        snprintf(ErrMsg, sizeof(ErrMsg), "%s:%d: pre-condition failed (%s)", file, line, text);
-        dump_and_abort(ErrMsg);
-    }
-}
-
-void dbc_ensure(bool success, char* text, char* file, int line)
-{
-    if (!success)
-    {
-        snprintf(ErrMsg, sizeof(ErrMsg), "%s:%d: post-condition failed (%s)", file, line, text);
-        dump_and_abort(ErrMsg);
-    }
-}
-
-#endif
diff --git a/bin/editor/dbc.h b/bin/editor/dbc.h
deleted file mode 100644 (file)
index 5dc1575..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/** @file */
-#define require(cond) \
-    dbc_require(cond, #cond, __FILE__, __LINE__)
-
-#define ensure(cond) \
-    dbc_ensure(cond, #cond, __FILE__, __LINE__)
-
-#ifndef NDEBUG
-    void dbc_init(char* path, void (*dumpfn)(FILE*));
-    void dbc_require(bool success, char* text, char* file, int line);
-    void dbc_ensure(bool success, char* text, char* file, int line);
-#else
-    #define dbc_init(a,b) ((void)0)
-    #define dbc_require(a,b,c,d) ((void)0)
-    #define dbc_ensure(a,b,c,d) ((void)0)
-#endif
diff --git a/bin/editor/draw.c b/bin/editor/draw.c
deleted file mode 100644 (file)
index b90560c..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-#include <liba.h>
-#include <stdc.h>
-
-#include "tide.h"
-#include "config.h"
-
-void draw_rect(XConf* x, int color, int posx, int posy, int width, int height)
-{
-    x11_draw_rect(x, Palette[color], posx, posy, width, height);
-}
-
-void draw_statbox(XConf* x, int status)
-{
-    draw_rect(x, VerBdr, ScrollWidth, 0, 1, x->height/4);
-    switch (status) {
-        case NORMAL:   draw_rect(x, TagsBg, 0, 0, ScrollWidth, x->height/4); break;
-        case MODIFIED: draw_rect(x, Purple, 0, 0, ScrollWidth, x->height/4); break;
-        case OUTDATED: draw_rect(x, Orange, 0, 0, ScrollWidth, x->height/4); break;
-        case ERRORED:  draw_rect(x, Red, 0, 0, ScrollWidth, x->height/4);    break;
-    }
-}
-
-int draw_hrule(XConf* x, drawcsr* csr)
-{
-    draw_rect(x, HorBdr, 0, csr->y + 1, x->width, 1);
-    csr->y += 2;
-    return (csr->y - 2);
-}
-
-void draw_view(XConf* x, View* view, XftFont* font, size_t nrows, drawcsr* csr, int bg, int fg, int sel, bool csrsync)
-{
-    int nspecs = 0;
-    XftGlyphSpec* specs = NULL;
-    size_t fheight = font->height;
-    bool csr_drawn = false;
-    /* draw the view to the window */
-    view_resize(view, (csr->w - csr->x - 2) - (2* Margin), nrows);
-    view_update(view);
-    draw_rect(x, bg, csr->x, csr->y, csr->w, ((nrows + 1) * fheight) + 9);
-    for (size_t i = 0; i < nrows; i++)
-    {
-        Row* row = view_getrow(view, i + view->index);
-        size_t posx = (csr->x + 2 + Margin), y = (csr->y + 2 + (i * fheight));
-        if (row->off == buf_end(&(view->buffer)))
-        {
-            if (buf_end(&(view->buffer)) == buf_selend(&(view->buffer)))
-            {
-                draw_csr(x, view, fg, fheight, posx, y, csr_drawn);
-            }
-            break;
-        }
-        else
-        {
-            for (size_t i = 0; i < row->len; i++)
-            {
-                int rune = row->cols[i].rune;
-                if (rune == '\r' || rune == '\n' ||  rune == '\t')
-                    rune = ' ';
-                if (buf_inpoint(&(view->buffer), row->cols[i].off))
-                    draw_rect(x, Point, posx, y, row->cols[i].width, fheight);
-                if (buf_insel(&(view->buffer), row->cols[i].off))
-                    draw_rect(x, sel, posx, y, row->cols[i].width, fheight);
-                if (row->cols[i].off == view->buffer.selection.end)
-                    csr_drawn = draw_csr(x, view, fg, fheight, posx, y, csr_drawn);
-                if (csrsync && row->cols[i].off == view->buffer.selection.beg)
-                {
-                    //XWarpPointer(x->display, None, x->self, 0, 0, x->width, x->height, posx + row->cols[i].width/2, y + fheight*3/4);
-                    csrsync = false;
-                }
-                specs = realloc(specs, sizeof(XftGlyphSpec) * ++nspecs);
-                specs[nspecs-1].glyph = XftCharIndex(x->display, font, rune);
-                specs[nspecs-1].x = posx;
-                specs[nspecs-1].y = y + font->ascent;
-                posx += row->cols[i].width;
-            }
-        }
-    }
-    x11_draw_glyphs(x, Palette[fg], font, specs, nspecs);
-    csr->y += (nrows * fheight) + 3;
-    free(specs);
-}
-
-bool draw_csr(XConf* x, View* view, int fg, size_t fheight, int posx, int posy, bool csrdrawn)
-{
-    if (!csrdrawn && !view_selsize(view))
-    {
-        draw_rect(x, fg, posx-1, posy, 3, 3);
-        draw_rect(x, fg, posx, posy, 1, fheight);
-        draw_rect(x, fg, posx-1, posy+fheight-3, 3, 3);
-        csrdrawn = true;
-    }
-    return csrdrawn;
-}
-
-void draw_scroll(XConf* x, drawcsr* csr, View* view, int divider)
-{
-    size_t bend = buf_end(&(view->buffer));
-    if (bend == 0) bend = 1;
-    if (!view->rows || !view->nrows) return;
-    size_t vbeg = view->rows[0]->off;
-    size_t vend = view->rows[view->nrows-1]->off + view->rows[view->nrows-1]->len;
-    double scroll_vis = (double)(vend - vbeg) / (double)bend;
-    double scroll_off = ((double)vbeg / (double)bend);
-    size_t thumbreg = (csr->h - divider) + 4;
-    size_t thumboff = (size_t)((thumbreg * scroll_off) + divider);
-    size_t thumbsz  = (size_t)(thumbreg * scroll_vis);
-    if (thumbsz < 5) thumbsz = 5;
-    draw_rect(x, VerBdr,   ScrollWidth, divider + 2,  1,           thumbreg);
-    draw_rect(x, ScrollBg, 0,           divider + 2,  ScrollWidth, thumbreg);
-    draw_rect(x, ScrollFg, 0,           thumboff + 2, ScrollWidth, thumbsz);
-}
diff --git a/bin/editor/editlog.c b/bin/editor/editlog.c
deleted file mode 100644 (file)
index f83dfad..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-#include <liba.h>
-#include <stdc.h>
-#include "dbc.h"
-
-#include "tide.h"
-#include "config.h"
-
-static Log* mklog(Buf* buf, size_t beg, size_t end, char* data, Log* next)
-{
-    Log* log = calloc(1, sizeof(Log));
-    log->transid = (buf->log.transid < 0 ? 0 : buf->log.transid);
-    log->beg = beg;
-    log->end = end;
-    log->data = data;
-    log->next = next;
-    return log;
-}
-
-static void log_swap(Buf* buf, Log** src, Log** dest)
-{
-    Log* item = *src;
-    if (item)
-    {
-        *src = item->next;
-        buf->selection.beg = item->beg;
-        buf->selection.end = item->end;
-        if (item->data)
-        {
-            /* reinsert deleted bytes */
-            for (char* s = item->data; s && *s; s++, item->end++)
-            {
-                range_add(&(buf->point), buf->selection.end);
-                gapbuf_putb(&buf->contents, *s, &(buf->selection));
-                buf->status = MODIFIED;
-            }
-            free(item->data);
-            item->data = NULL;
-            buf->selection.beg = item->beg;
-            buf->selection.end = item->end;
-       }
-       else
-       {
-            /* delete the added bytes */
-            Sel sel = buf->selection;
-            item->data = buf_gets(buf);
-            range_del(&(buf->point), item->beg, item->end);
-            gapbuf_del(&buf->contents, sel.beg, (item->end - item->beg));
-            sel.end = sel.beg;
-            buf->selection = sel;
-            item->beg = sel.beg;
-            item->end = sel.end;
-        }
-
-        /* push item onto destination stack */
-        item->next = *dest;
-        *dest = item;
-        /* undo recursively if this is part of a transaction */
-        if (*src && item->transid && item->transid == (*src)->transid)
-        {
-            log_swap(buf, src, dest);
-        }
-
-        if (buf->log.save == buf->log.undo)
-        {
-            buf->status = NORMAL;
-        }
-    }
-}
-
-static void log_clear(Log** list)
-{
-    while (*list)
-    {
-        Log* deadite = *list;
-        *list = (*list)->next;
-        if (deadite->data)
-        {
-            free(deadite->data);
-        }
-        free(deadite);
-    }
-}
-
-void editlog_seqstart(EditLog* log)
-{
-    require(log != NULL);
-    log->transid = abs(log->transid);
-}
-
-void editlog_seqstop(EditLog* log)
-{
-    require(log != NULL);
-    if (log->transid > 0)
-    {
-        log->transid = -(log->transid + 1);
-    }
-}
-
-void editlog_clear(EditLog* log)
-{
-    require(log != NULL);
-    log_clear(&(log->redo));
-    log_clear(&(log->undo));
-}
-
-void editlog_lastins(EditLog* elog, Sel* p_sel)
-{
-    require(elog != NULL);
-    Log* log = elog->undo;
-    if (log)
-    {
-        Sel sel = { .beg = log->beg, .end = log->end };
-        size_t delsize = 0;
-        int transid = log->transid;
-
-        /* try and expand the selected region to encompass related inserts */
-        for (; log && (log->transid == transid); log = log->next)
-        {
-            if (!log->data)
-            {
-                size_t ibeg = log->beg, iend = log->end - delsize;
-                if (iend < ibeg || ibeg > sel.beg || iend < sel.beg)
-                {
-                    break;
-                }
-                if (ibeg < sel.beg && iend > sel.end)
-                {
-                    break;
-                }
-                sel.beg = ibeg, delsize = 0;
-            }
-            else
-            {
-                /* bail if the delete doesnt overlap */
-                if (log->beg != sel.beg)
-                {
-                    break;
-                }
-                delsize = strlen(log->data);
-            }
-        }
-        *p_sel = sel;
-    }
-}
-
-void editlog_undo(Buf* buf)
-{
-    require(buf != NULL);
-    log_swap(buf, &(buf->log.undo), &(buf->log.redo));
-}
-
-void editlog_redo(Buf* buf)
-{
-    require(buf != NULL);
-    log_swap(buf, &(buf->log.redo), &(buf->log.undo));
-}
-
-void editlog_add(Buf* buf, size_t beg, size_t end, char* data)
-{
-    Log* prev = buf->log.undo;
-    log_clear(&(buf->log.redo));
-
-    /* check if this is new transaction or the first entry */
-    if (!prev || (buf->log.transid > 0 && buf->log.transid != prev->transid))
-    {
-        buf->log.undo = mklog(buf, beg, end, data, prev);
-    }
-    /* check if this is a sequential insert, just expand the previous one */
-    else if (!data && !prev->data && prev->end == beg)
-    {
-        prev->end = end;
-    }
-    /* check if this is a sequential delete, append to deleted text */
-    else if (prev->data && data && prev->beg == beg)
-    {
-        char* newdata = strmcat(prev->data, data, 0);
-        free(data);
-        free(prev->data);
-        prev->data = newdata;
-    }
-    /* check if this is a delete before the previous operation, prepend to deleted text */
-    else if (prev->data && data && prev->beg == beg+1)
-    {
-        char* newdata = strmcat(data, prev->data, 0);
-        free(data);
-        free(prev->data);
-        prev->data = newdata;
-        prev->end = --prev->beg;
-    }
-    /* otherwise, make a fresh delete operation */
-    else
-    {
-        buf->log.undo = mklog(buf, beg, end, data, prev);
-    }
-}
diff --git a/bin/editor/exec.c b/bin/editor/exec.c
deleted file mode 100644 (file)
index e06ec70..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-#define _XOPEN_SOURCE 700
-#include <liba.h>
-#include <stdc.h>
-#include "dbc.h"
-
-#include "tide.h"
-#include "config.h"
-
-static Tag* Builtins = NULL;
-
-void exec_init(Tag* p_tags)
-{
-    Builtins = p_tags;
-    /* setup the shell */
-    if (!ShellCmd[0]) ShellCmd[0] = getenv("SHELL");
-    if (!ShellCmd[0]) ShellCmd[0] = "/bin/sh";
-    require(ShellCmd[0]);
-}
-
-static Tag* tag_lookup(char* cmd)
-{
-    size_t len = 0;
-    Tag* tags = Builtins;
-
-    for (char* tag = cmd; *tag && !isspace(*tag); tag++, len++)
-    {
-        /* do nothing */
-    }
-
-    while (tags->tag)
-    {
-        if (!strncmp(tags->tag, cmd, len))
-            break;
-        tags++;
-    }
-    return (tags->tag ? tags : NULL);
-}
-
-static void shell_exec(char* cmd)
-{
-    /* parse the command sigils */
-    char op = '\0', **execcmd = NULL;
-    if (rissigil(*cmd)) op = *(cmd++);
-    execcmd = (op == ':' ? SedCmd : ShellCmd);
-    execcmd[2] = cmd;
-
-    /* get the selection that the command will operate on */
-    if (op && op != '<' && op != '!' && op != '&' && !view_selsize(win_view(EDIT)))
-    {
-        view_selectall(win_view(EDIT));
-    }
-    char* input = view_getstr(win_view(EDIT));
-    size_t len = (input ? strlen(input) : 0);
-    View *tags = win_view(TAGS), *edit = win_view(EDIT), *curr = win_view(FOCUSED);
-
-    /* execute the job */
-    if (op == '!' || op == '&')
-    {
-        free(input);
-        if (op == '&')
-        {
-            xpty_run(win_view(EDIT), execcmd);
-        }
-        else
-        {
-            job_start(execcmd, NULL, 0, NULL);
-        }
-    }
-    else if (op == '>')
-    {
-        job_start(execcmd, input, len, tags);
-    }
-    else if (op == '|' || op == ':')
-    {
-        job_start(execcmd, input, len, edit);
-    }
-    else
-    {
-        job_start(execcmd, input, len, (op != '<' ? curr : edit));
-    }
-}
-
-void exec_cmd(char* str)
-{
-    if (str && *str)
-    {
-        bool shellcmd = (str[0] == ':' && str[1] == ';');
-        if (xpty_active() && (!rissigil(*str) || shellcmd))
-        {
-            xpty_send(str);
-        }
-        else
-        {
-            shell_exec(str);
-        }
-    }
-}
-
-void exec_cmdwarg(char* cmd, char* arg)
-{
-    /* skip leading space */
-    for (; *cmd && isspace(*cmd); cmd++);
-    if (!*cmd) return;
-    /* see if it matches a builtin tag */
-    Tag* tag = tag_lookup(cmd);
-    if (tag)
-    {
-        for (; *cmd && !isspace(*cmd); cmd++); /* strip off tag name */
-        for (; *cmd && isspace(*cmd); cmd++);  /* strip off leading space */
-        arg = (*cmd ? strdup(cmd) : arg);
-        tag->action(!arg || !*arg ? NULL : arg);
-    }
-    else if (arg)
-    {
-        cmd = (arg ? strmcat(cmd, " '", arg, "'", 0) : strmcat(cmd));
-        exec_cmd(cmd);
-        free(cmd);
-    }
-    else
-    {
-        exec_cmd(cmd);
-    }
-}
-
-void exec_rawwarg(char* cmd, char* arg)
-{
-    cmd = (arg ? strmcat(cmd, " '", arg, "'", 0) : strmcat(cmd));
-    shell_exec(cmd);
-    free(cmd);
-}
diff --git a/bin/editor/gapbuf.c b/bin/editor/gapbuf.c
deleted file mode 100644 (file)
index 3851751..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-#define _XOPEN_SOURCE 700
-#include <liba.h>
-
-#include <stdc.h>
-#include "dbc.h"
-#include <unistd.h>
-#include <dirent.h>
-#include <vec.h>
-
-#include "tide.h"
-#include "config.h"
-
-size_t gapbuf_end(GapBuf* buf)
-{
-    require(buf != NULL);
-    size_t bufsz = buf->bufend - buf->bufstart;
-    size_t gapsz = buf->gapend - buf->gapstart;
-    return (bufsz - gapsz);
-}
-
-static size_t pagealign(size_t sz)
-{
-    size_t pgsize = sysconf(_SC_PAGE_SIZE);
-    size_t alignmask = (pgsize - 1);
-    if (sz & alignmask)
-    {
-        sz += pgsize - (sz & alignmask);
-    }
-    return sz;
-}
-
-static void resize(GapBuf* buf, size_t sz)
-{
-    /* allocate the new buffer and gap */
-    GapBuf copy = *buf;
-    copy.bufsize  = sz;
-    copy.bufstart = (char*)malloc(copy.bufsize);
-    copy.bufend   = copy.bufstart + copy.bufsize;
-    copy.gapstart = copy.bufstart;
-    copy.gapend   = copy.bufend;
-
-    /* copy the data from the old buffer to the new one */
-    for (char* curr = buf->bufstart; curr < buf->gapstart; curr++)
-    {
-        *(copy.gapstart++) = *(curr);
-    }
-    for (char* curr = buf->gapend; curr < buf->bufend; curr++)
-    {
-        *(copy.gapstart++) = *(curr);
-    }
-
-    /* free the buffer and commit the changes */
-    free(buf->bufstart);
-    memcpy(buf, &copy, sizeof(GapBuf));
-}
-
-static void syncgap(GapBuf* buf, size_t off)
-{
-    assert(off <= gapbuf_end(buf));
-    /* If the buffer is full, resize it before syncing */
-    if (0 == (buf->gapend - buf->gapstart))
-    {
-        resize(buf, buf->bufsize << 1);
-    }
-
-    /* Move the gap to the desired offset */
-    char* newpos = (buf->bufstart + off);
-    if (newpos < buf->gapstart)
-    {
-        while (newpos < buf->gapstart)
-        {
-            *(--buf->gapend) = *(--buf->gapstart);
-        }
-    }
-    else
-    {
-        while (newpos > buf->gapstart)
-        {
-            *(buf->gapstart++) = *(buf->gapend++);
-        }
-    }
-}
-
-static int cmpnames(const void* a, const void* b)
-{
-    char *sa = *((char**)a), *sb = *((char**)b);
-    return strcmp(sa, sb);
-}
-
-static void loaddir(GapBuf* buf, char* path, int fd)
-{
-    Sel sel = { 0 };
-    vec_t entries;
-    vec_init(&entries, sizeof(char*));
-    DIR* dir = fdopendir(fd);
-    struct dirent* entry = NULL;
-    struct stat attrs = {0};
-    while ( (entry = readdir(dir)) )
-    {
-        char* epath = strmcat(path, "/", entry->d_name, 0);
-        memset(&attrs, 0, sizeof(attrs));
-        stat(epath, &attrs);
-        char* ename = strmcat(entry->d_name, (S_ISDIR(attrs.st_mode) ? "/" : 0), 0);
-        vec_push_back(&entries, &ename);
-        free(epath);
-    }
-    vec_sort(&entries, cmpnames);
-    for (size_t i = 0; i < vec_size(&entries); i++)
-    {
-        char* name = *((char**)vec_at(&entries, i));
-        for (int i = 0; name[i]; i++)
-        {
-            gapbuf_putb(buf, name[i], &sel);
-        }
-        gapbuf_putb(buf, '\n', &sel);
-        free(name);
-    }
-    free(entries.elem_buffer);
-    int res = chdir(path);
-    (void)res;
-}
-
-void gapbuf_init(GapBuf* buf)
-{
-    require(buf != NULL);
-    buf->bufsize   = 8192;
-    buf->bufstart  = malloc(buf->bufsize);
-    buf->bufend    = buf->bufstart + buf->bufsize;
-    buf->gapstart  = buf->bufstart;
-    buf->gapend    = buf->bufend;
-}
-
-long gapbuf_save(GapBuf* buf, char* path)
-{
-    require(buf != NULL);
-    File fd;
-    long nwrite = 0;
-    if (path && (fd = File_OpenForWrite(path)) >= 0)
-    {
-        nwrite = File_Write(fd, buf->bufstart, (buf->gapstart - buf->bufstart));
-        if (nwrite >= 0)
-        {
-            nwrite = File_Write(fd, buf->gapend, (buf->bufend - buf->gapend));
-        }
-        File_Close(fd);
-    }
-    else
-    {
-        nwrite = -1;
-    }
-    return nwrite;
-}
-
-void gapbuf_load(GapBuf* buf, char* path)
-{
-    require(buf != NULL);
-    require(path != NULL);
-    /* load the contents from the file */
-    File fd;
-    struct stat sb = {0};
-    if (((fd = File_OpenForRead(path)) >= 0) && (fstat((int)fd, &sb) >= 0) && (sb.st_size > 0))
-    {
-        /* allocate the buffer in advance */
-        free(buf->bufstart);
-        buf->bufsize  = pagealign(sb.st_size);
-        buf->bufstart = malloc(buf->bufsize);
-        buf->bufend   = buf->bufstart + buf->bufsize;
-        buf->gapstart = buf->bufstart;
-        buf->gapend   = buf->bufend;
-
-        if (S_ISDIR(sb.st_mode))
-        {
-            loaddir(buf, path, fd);
-        }
-        else
-        {
-            buf->gapstart += sb.st_size;
-            (void)File_Read(fd, buf->bufstart, sb.st_size);
-        }
-    }
-    if (fd > 0)
-    {
-        close(fd);
-    }
-}
-
-char gapbuf_getb(GapBuf* buf, size_t off)
-{
-    require(buf != NULL);
-    int c = '\n'; // TODO: get rid of this hack
-    if (off < gapbuf_end(buf))
-    {
-        size_t bsz = (buf->gapstart - buf->bufstart);
-        if (off < bsz)
-        {
-            c = *(buf->bufstart + off);
-        }
-        else
-        {
-            c = *(buf->gapend + (off - bsz));
-        }
-    }
-    return c;
-}
-
-void gapbuf_putb(GapBuf* buf, char b, Sel* p_sel)
-{
-    require(buf != NULL);
-    require(p_sel != NULL);
-    syncgap(buf, p_sel->end);
-    *(buf->gapstart++) = b;
-    p_sel->end = p_sel->end + 1u;
-    p_sel->beg = p_sel->end;
-}
-
-void gapbuf_del(GapBuf* buf, size_t off, size_t len)
-{
-    require(buf != NULL);
-    syncgap(buf, off);
-    buf->gapend += len;
-}
diff --git a/bin/editor/job.c b/bin/editor/job.c
deleted file mode 100644 (file)
index ba81ffa..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-#define _XOPEN_SOURCE 700
-#include <liba.h>
-#include <stdc.h>
-#include <unistd.h>
-#include <sys/wait.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <poll.h>
-#include <fcntl.h>
-
-#include "tide.h"
-
-struct PipeData {
-    char* data;
-    ssize_t ndata;
-    size_t nwrite;
-    View* dest;
-};
-
-#define MAX_JOBS 256
-static struct pollfd JobFds[MAX_JOBS];
-static Job* JobList = NULL;
-
-static void pipe_read(Job* job)
-{
-    struct PipeData* pipedata = job->data;
-    char buffer[32769];
-    errno = 0;
-    long nread = read(job->fd, buffer, sizeof(buffer)-1);
-    Telemetry_Send("PIPE_READ(fd : %d, ret: %ld)\n", job->fd, nread);
-    if (nread <= 0)
-    {
-        job->readfn = NULL;
-        buf_logstop(&pipedata->dest->buffer);
-        if (view_selsize(pipedata->dest))
-            view_delete(pipedata->dest, RIGHT, false);
-        else
-            view_selprev(pipedata->dest);
-    }
-    else if (nread > 0)
-    {
-        buffer[nread] = '\0';
-        buf_logstart(&pipedata->dest->buffer);
-        view_putraw(pipedata->dest, buffer);
-    }
-}
-
-static void pipe_write(Job* job)
-{
-    struct PipeData* pipedata = job->data;
-    char* chunk = pipedata->data + pipedata->nwrite;
-    errno = 0;
-    long nwrite = File_Write(job->fd, chunk, pipedata->ndata);
-    if (nwrite >= 0)
-    {
-        pipedata->ndata  -= nwrite;
-        pipedata->nwrite += nwrite;
-    }
-    if ((nwrite < 0 && errno != EWOULDBLOCK) || pipedata->ndata <= 0)
-    {
-        free(pipedata->data);
-        pipedata->data = NULL;
-        job->writefn = NULL;
-        shutdown(job->fd, SHUT_WR);
-    }
-}
-
-static Job* job_remove(Job* list, Job* job)
-{
-    Job* ret = NULL;
-    if (list == job)
-    {
-        ret = job->next;
-    }
-    else
-    {
-        list->next = job_remove(list->next, job);
-        ret = list;
-    }
-    return ret;
-}
-
-static void job_finish(Job* job)
-{
-    JobList = job_remove(JobList, job);
-    close(job->fd);
-    free(job->data);
-    free(job);
-}
-
-static void job_process(int fd, int events)
-{
-    Job* job = JobList; // Get job by fd
-    while (job && job->fd != fd)
-        job = job->next;
-    if (!job || !events) return;
-    Telemetry_Send("JOB(fd: %d, events: 0x%x)\n", fd, events);
-    if (job->readfn && (events & (POLLIN|POLLHUP)))
-    {
-        Telemetry_Send("JOB_READ(fd: %d)\n", job->fd);
-        job->readfn(job);
-    }
-    if (job->writefn && (events & POLLOUT))
-    {
-        Telemetry_Send("JOB_WRITE(fd: %d)\n", job->fd);
-        job->writefn(job);
-    }
-    if ((events & POLLERR) || (!job->readfn && !job->writefn))
-    {
-        Telemetry_Send("JOB_FINISH(fd: %d)\n", job->fd);
-        job_finish(job);
-    }
-}
-
-static int job_exec(char** cmd, int* p_pid)
-{
-    int pid, fds[2] = {-1,-1};
-    /* create the sockets */
-    if (!socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
-    {
-        /* create the process */
-        if ((pid = fork()) < 0)
-        {
-            close(fds[0]), close(fds[1]), fds[0] = -1;
-        }
-        else if (0 == pid)
-        {
-            /* redirect child process's io to the pipes */
-            if ((dup2(fds[1], 0) < 0) || (dup2(fds[1], 1) < 0) || (dup2(fds[1], 2) < 0))
-            {
-                perror("failed to pipe");
-                exit(1);
-            }
-            /* execute the process */
-            close(fds[0]);
-            exit(execvp(cmd[0], cmd));
-        }
-        else
-        {
-            close(fds[1]);
-            fcntl(fds[0], F_SETFL, fcntl(fds[0], F_GETFL, 0) | O_NONBLOCK);
-        }
-        if (p_pid) *p_pid = pid;
-    }
-    return fds[0];
-}
-
-Job* job_list(void)
-{
-    return JobList;
-}
-
-void job_kill(Job* job)
-{
-    job->readfn = NULL;
-    job->writefn = NULL;
-}
-
-bool job_poll(int ms)
-{
-    int njobs = 0;
-    /* Add jobs from the job list */
-    for (Job *job = JobList; job && njobs < MAX_JOBS; job = job->next)
-    {
-        JobFds[njobs].fd = job->fd;
-        JobFds[njobs].events = 0;
-        JobFds[njobs].revents = 0;
-        if (job->readfn) JobFds[njobs].events |= POLLIN;
-        if (job->writefn) JobFds[njobs].events |= POLLOUT;
-        if (JobFds[njobs].events) njobs++;
-    }
-
-    /* Poll until a job is ready, call the functions based on events */
-    long ret = poll(JobFds, njobs, ms);
-    if (ret != 0)
-    {
-        Telemetry_Send("POLL(njobs: %d, ms: %d, ret: %d)\n", njobs, ms, ret);
-    }
-
-    /* process all jobs with events reported */
-    for (int i = 0; i < njobs; i++)
-    {
-        job_process(JobFds[i].fd, JobFds[i].revents);
-    }
-
-    /* reap zombie processes */
-    for (int status; waitpid(-1, &status, WNOHANG) > 0;);
-    return (ret > 0);
-}
-
-void job_spawn(int fd, jobfn_t readfn, jobfn_t writefn, void* data)
-{
-    Job *job = calloc(1, sizeof(Job));
-    job->fd = fd;
-    job->readfn = readfn;
-    job->writefn = writefn;
-    job->data = data;
-    job->next = JobList;
-    JobList = job;
-}
-
-void job_start(char** cmd, char* data, size_t ndata, View* dest)
-{
-    int fd = job_exec(cmd, 0);
-    if (fd >= 0 && (data || dest))
-    {
-        struct PipeData* pipedata = NULL;
-        if (data)
-        {
-            pipedata = calloc(1, sizeof(struct PipeData));
-            pipedata->data = data;
-            pipedata->ndata = ndata;
-            pipedata->dest = dest;
-        }
-        job_spawn(fd, (data ? pipe_read : NULL), (dest ? pipe_write : NULL), pipedata);
-    }
-    else
-    {
-        close(fd);
-    }
-}
-
-int job_run(char** cmd)
-{
-    int pid = -1, status = 0;
-    job_exec(cmd, &pid);
-    do
-    {
-        waitpid(pid, &status, WUNTRACED|WCONTINUED);
-    } while (!WIFEXITED(status) && !WIFSIGNALED(status));
-    return WEXITSTATUS(status);
-}
-
-void job_readfd(int fd, View* view)
-{
-    struct PipeData* pipedata = calloc(1, sizeof(struct PipeData));
-    pipedata->dest = view;
-    job_spawn(fd, pipe_read, NULL, pipedata);
-}
diff --git a/bin/editor/leap.c b/bin/editor/leap.c
deleted file mode 100644 (file)
index 0de287c..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-#include <liba.h>
-#include <stdc.h>
-#include "tide.h"
-
-static void leap_process_keysym(LeapState_T* state, unsigned long keysym)
-{
-    uint32_t key = x11_getkey(keysym);
-    if (key != RUNE_ERR)
-    {
-        Byte utf8buf[UTF_MAX+1] = {0};
-        size_t sz = UTF8_Encode(utf8buf, key);
-        for (size_t i = 0; i < sz; i++)
-        {
-            state->buf[state->nbuf++] = utf8buf[i];
-            state->buf[state->nbuf] = '\0';
-        }
-        win_buf(EDIT)->selection = state->selection;
-        view_sync(win_view(EDIT));
-        view_findstr(win_view(EDIT), (state->key == XK_Alt_L ? LEFT : RIGHT), state->buf);
-    }
-}
-
-static bool leap_process_down(LeapState_T* state, unsigned long keysym)
-{
-    bool ret = true;
-    /* check if we are just entering leap mode */
-    if (!state->key && (keysym == XK_Alt_L || keysym == XK_Alt_R))
-    {
-        state->key = keysym;
-        state->selection = win_buf(EDIT)->selection;
-        state->repeat = true;
-    }
-    /* or we're already in it */
-    else if (state->key)
-    {
-        /* we got a non-alt key so this is a new search, not a repeat */
-        if (state->repeat)
-        {
-            state->nbuf = 0;
-            state->buf[0] = '\0';
-            state->repeat = false;
-        }
-        leap_process_keysym(state, keysym);
-    }
-    else
-    {
-        ret = false;
-    }
-    return ret;
-}
-
-static bool leap_process_up(LeapState_T* state, unsigned long keysym)
-{
-    bool ret = false;
-    if (keysym == state->key)
-    {
-        if (state->repeat)
-        {
-            win_buf(EDIT)->selection = state->selection;
-            view_sync(win_view(EDIT));
-            view_findstr(win_view(EDIT), (state->key == XK_Alt_L ? LEFT : RIGHT), state->buf);
-        }
-        state->key = 0;
-        ret = true;
-    }
-    return ret;
-}
-
-bool leap_process(LeapState_T* state, unsigned long keysym, bool pressed)
-{
-    bool ret;
-    if (pressed)
-    {
-        ret = leap_process_down(state, keysym);
-    }
-    else
-    {
-        ret = leap_process_up(state, keysym);
-    }
-    return ret;
-}
diff --git a/bin/editor/main.c b/bin/editor/main.c
deleted file mode 100644 (file)
index 90e49c7..0000000
+++ /dev/null
@@ -1,765 +0,0 @@
-#define _XOPEN_SOURCE 700
-#include <liba.h>
-#include <stdc.h>
-#include "dbc.h"
-#include <locale.h>
-#include <sys/wait.h>
-
-#include "tide.h"
-
-#define INCLUDE_DEFS
-#include "config.h"
-
-/* predeclare some things */
-void cut(char* arg);
-void paste(char* arg);
-
-char* ARGV0;
-Tag* Builtins;
-static KeyBinding* Bindings;
-static WinRegion Focused = EDIT;
-static View Regions[NREGIONS];
-static int Divider;
-static int FontSel;
-static bool SyncMouse = false;
-static int SearchDir = DOWN;
-static char* SearchTerm = NULL;
-static LeapState_T LeapState = {0};
-
-static int PRESSED(int mods, int btn)
-{
-    return ((mods & (1 << (btn + 7))) == (1 << (btn + 7)));
-}
-
-/* Crash Dump Handling
- ******************************************************************************/
-#ifndef NDEBUG
-static void dumpdata(FILE* f)
-{
-    fprintf(f, "Focused:\t%d\n",      Focused);
-    fprintf(f, "Divider:\t%d\n",      Divider);
-    fprintf(f, "FontSel:\t%d\n",      FontSel);
-    fprintf(f, "SyncMouse:\t%d\n",    SyncMouse);
-    fprintf(f, "SearchDir:\t%d\n",    SearchDir);
-    fprintf(f, "SearchTerm:\t'%s'\n", SearchTerm);
-    for (int i = 0; i < NREGIONS; i++)
-    {
-        fprintf(f, "Region[%d]:\n", i);
-        fprintf(f, "\t.sync_flags:\t%d\n", Regions[i].sync_flags);
-        fprintf(f, "\t.index:\t\t%zu\n",   Regions[i].index);
-        fprintf(f, "\t.width:\t\t%zu\n",   Regions[i].width);
-        fprintf(f, "\t.nvisible:\t%zu\n",  Regions[i].nvisible);
-        fprintf(f, "\t.nrows:\t\t%zu\n",   Regions[i].nrows);
-        fprintf(f, "\t.rows:\t\t%p\n",     (void*)Regions[i].rows);
-        fprintf(f, "\t.buffer:\n");
-        fprintf(f, "\t\t.status:\t%d\n",   Regions[i].buffer.status);
-        fprintf(f, "\t\t.bufsize:\t%zu\n", Regions[i].buffer.contents.bufsize);
-        fprintf(f, "\t\t.bufstart:\t%p\n", (void*)Regions[i].buffer.contents.bufstart);
-        fprintf(f, "\t\t.bufend:\t%p\n",   (void*)Regions[i].buffer.contents.bufend);
-        fprintf(f, "\t\t.gapstart:\t%p\n", (void*)Regions[i].buffer.contents.gapstart);
-        fprintf(f, "\t\t.gapend:\t%p\n",   (void*)Regions[i].buffer.contents.gapend);
-        fprintf(f, "\t\t.undo:\t\t%p\n",   (void*)Regions[i].buffer.log.undo);
-        fprintf(f, "\t\t.redo:\t\t%p\n",   (void*)Regions[i].buffer.log.redo);
-        fprintf(f, "\t\t.save:\t\t%p\n",   (void*)Regions[i].buffer.log.save);
-        fprintf(f, "\t\t.transid:\t%d\n",  Regions[i].buffer.log.transid);
-        fprintf(f, "\t\t.selbeg:\t%zu\n",  Regions[i].buffer.selection.beg);
-        fprintf(f, "\t\t.selend:\t%zu\n",  Regions[i].buffer.selection.end);
-        fprintf(f, "\t\t.selcol:\t%zu\n",  Regions[i].buffer.selection.col);
-    }
-}
-#endif
-
-/* X11 Window Code
- ******************************************************************************/
-static void font_load(char* name)
-{
-    XftFont* font = x11_font_load(&X, name);
-    X.font = (font ? font : X.font); // Update if we found a new font
-}
-
-static void get_position(WinRegion id, int x, int y, size_t* row, size_t* col)
-{
-    int starty = (id == EDIT ? Divider+3 : 0);
-    int startx = ScrollWidth + 3 + Margin;
-    int maxy = (id == EDIT
-        ? (Divider + (int)(win_view(EDIT)->nrows * X.font->height))
-        : Divider - 4
-    );
-    x = (x < 0 ? 0 : (x > X.width ? X.width : x));
-    y = (y < starty ? starty : (y > maxy ? maxy : y));
-    *row = (y - starty) / X.font->height;
-    *col = (startx <= x ? x - startx : 0);
-}
-
-static void tide_send(char* type)
-{
-    XEvent ev;
-    memset(&ev, 0, sizeof (ev));
-    Atom xa_registrar = XInternAtom(X.display, "TIDE_REGISTRAR", 0);
-    Window regwin = XGetSelectionOwner(X.display, xa_registrar);
-    if (None != regwin)
-    {
-        ev.xclient.type = ClientMessage;
-        ev.xclient.window = X.self;
-        ev.xclient.message_type = xa_registrar;
-        ev.xclient.format = 32;
-        ev.xclient.data.l[0] = XInternAtom(X.display, type, 0);
-        XSendEvent(X.display, regwin, False, NoEventMask, &ev);
-        XFlush(X.display);
-    }
-}
-
-size_t glyph_width(View* view, int c)
-{
-    size_t ret;
-    FcChar32 rune = (FcChar32)c;
-    XGlyphInfo extents;
-    XftFont* font = (&Regions[TAGS] == view ? X.tagfont : X.font);
-    XftTextExtents32(X.display, font, &rune, 1, &extents);
-    if (c == '\t')
-    {
-        ret = (TabWidth *  extents.xOff);
-    }
-    else
-    {
-        ret = extents.xOff;
-    }
-    return ret;
-}
-
-static void xkeydn(XConf* x, XEvent* e)
-{
-    KeySym keysym = x11_getkeysym(x,e);
-    if (!leap_process(&LeapState, keysym, true))
-    {
-        Focused = (e->xkey.y <= Divider ? TAGS : EDIT);
-        uint32_t key = x11_process_key(x, e, Bindings);
-        Telemetry_Send("KEY(reg: %d, key: 0x%x)\n", Focused, key);
-        if (key != RUNE_ERR)
-        {
-            view_insert(win_view(FOCUSED), key);
-        }
-    }
-}
-
-static void xkeyup(XConf* x, XEvent* e)
-{
-    KeySym keysym = x11_getkeysym(x,e);
-    (void)leap_process(&LeapState, keysym, false);
-}
-
-static void xmousebtn(XConf* x, XEvent* e)
-{
-    (void)x;
-    size_t row, col;
-    Focused = (e->xbutton.y <= Divider ? TAGS : EDIT);
-    get_position(Focused, e->xbutton.x,  e->xbutton.y, &row, &col);
-    int action = process_mouse(e->xbutton.button, (e->type == ButtonPress));
-    Telemetry_Send("BTNPRESS(reg: %d, btn: %d, press: %d, act: %d)\n",
-        Focused, e->xbutton.button, (e->type == ButtonPress), action);
-    switch (action)
-    {
-        case MouseActNone:
-            break;
-        case MouseActSel:
-            view_setcursor(win_view(Focused), row, col, win_keymodsset(ModShift));
-            break;
-        case MouseActSelCtx:
-            view_select(win_view(Focused), row, col);
-            break;
-        case MouseActSelWord:
-            view_selword(win_view(Focused), row, col);
-            break;
-        case MouseActCut:
-            cut(NULL);
-            break;
-        case MouseActPaste:
-            paste(NULL);
-            break;
-        case MouseActExec:
-        {
-            char* str = view_fetch(win_view(Focused), row, col, riscmd);
-            exec_cmdwarg(str, NULL);
-            free(str);
-            break;
-        }
-        case MouseActExecArg:
-        {
-            /* if we didnt get an arg, find one in the selection */
-            char* arg = NULL;
-            if (!arg || !*arg) arg = view_getstr(win_view(EDIT));
-            if (!arg || !*arg) arg = view_getstr(win_view(TAGS));
-            char* str = view_fetch(win_view(Focused), row, col, riscmd);
-            if (str) exec_cmdwarg(str, arg);
-            free(str);
-            free(arg);
-            break;
-        }
-        case MouseActFetch:
-        {
-            FetchCmd[1] = view_fetch(win_view(Focused), row, col, risfile);
-            if (job_run(FetchCmd) != 0)
-            {
-                SearchDir *= (win_keymodsset(ModShift) ? -1 : +1);
-                free(SearchTerm);
-                SearchTerm = view_fetch(win_view(Focused), row, col, risfile);
-                view_findstr(win_view(EDIT), SearchDir, SearchTerm);
-                SyncMouse = true;
-            }
-            free(FetchCmd[1]);
-            break;
-        }
-        case MouseActScrollUp:
-            view_scroll(win_view(Focused), -ScrollBy);
-            break;
-        case MouseActScrollDn:
-            view_scroll(win_view(Focused), +ScrollBy);
-            break;
-    }
-}
-
-static void xbtnmotion(XConf* x, XEvent* e)
-{
-    XMotionEvent *ev = &e->xmotion;
-    while (XCheckTypedWindowEvent(x->display, ev->window, ev->type, e));
-    size_t row, col;
-    int xpos = ev->x, ypos = ev->y;
-    get_position(Focused, xpos, ypos, &row, &col);
-    Telemetry_Send("BTNMOVE(reg: %d, btn: 0x%x, x: %d, y: %d, r: %d, c: %d)\n",
-        Focused, ev->state, xpos, ypos, row, col);
-    if (PRESSED(ev->state, MouseLeft))
-        view_setcursor(win_view(Focused), row, col, true);
-}
-
-static void xclientmsg(XConf* x, XEvent* e)
-{
-    if ((Atom)(e->xclient.data.l[0]) == XInternAtom(x->display, "WM_DELETE_WINDOW", False))
-    {
-        win_quit();
-    }
-    else if (e->xclient.message_type == XInternAtom(x->display, "GOTO", False))
-    {
-        x11_seturgent(x, 1);
-        win_setln(e->xclient.data.l[0]);
-    }
-}
-
-void xresize(XConf* x, XEvent* e)
-{
-    if (e->xconfigure.width != x->width || e->xconfigure.height != x->height)
-    {
-        view_sync(win_view(EDIT));
-    }
-    x11_resize(x, e);
-}
-
-static void xredraw(XConf* x)
-{
-    /* force update the title */
-    win_title(NULL);
-
-    /* determine draw height such that we can draw both regions */
-    int height = x->tagfont->height * 2 + 7;
-    if (height < x->height) height = x->height;
-
-    /* determine the size of the regions */
-    size_t maxtagrows = ((height/4) / x->tagfont->height);
-    size_t tagrows = view_limitrows(win_view(TAGS), maxtagrows);
-    size_t tagregsz = (tagrows * x->tagfont->height) + 7;
-    size_t editrows = (height - tagregsz) / x->font->height ;
-    Telemetry_Send("REDRAW(tagrows: %d, editrows: %d)\n", tagrows, editrows);
-
-    /* draw the regions to the window */
-    int olddiv = Divider;
-    drawcsr csr = { .w = x->width, .h = x->height };
-    csr.x += ScrollWidth + 1;
-    draw_statbox(x, win_view(EDIT)->buffer.status);
-    draw_view(x, &Regions[TAGS], x->tagfont, tagrows, &csr, TagsBg, TagsFg, TagsSel, false);
-    Divider = draw_hrule(x, &csr);
-    draw_view(x, &Regions[EDIT], x->font, editrows, &csr, EditBg, EditFg, EditSel, SyncMouse);
-    draw_scroll(x, &csr, win_view(EDIT), Divider);
-    XCopyArea(x->display, x->pixmap, x->self, x->gc, 0, 0, x->width, x->height, 0, 0);
-    SyncMouse = false;
-    if (Divider < olddiv && Focused == TAGS)
-    {
-        int ptrx = 0, ptry = 0;
-        x11_getptr(x, &ptrx, &ptry);
-        XWarpPointer(X.display, X.self, X.self, 0, 0, X.width, X.height, ptrx, Divider-2);
-    }
-    XFlush(x->display);
-}
-
-static void xupdate(Job* job)
-{
-    /* redraw if we have changes or if we have input from a job */
-    x11_process_events(&X);
-    if (!job && X.state == RUNNING)
-    {
-        xredraw(&X);
-    }
-}
-
-void win_init(void)
-{
-    signal(SIGPIPE, SIG_IGN); // Ignore the SIGPIPE signal
-    setlocale(LC_CTYPE, "");
-    XSetLocaleModifiers("");
-
-    /* open the X display and get basic attributes */
-    x11_init(&X);
-    font_load(Fonts[FontSel = 0]);
-    X.tagfont = X.font;
-    if (!X.font)
-    {
-        perror("unable to load base font");
-        exit(EXIT_FAILURE);
-    }
-    x11_mkwin(&X, 640, 480, 0
-        | KeyPressMask
-        | KeyReleaseMask
-        | ButtonPressMask
-        | ButtonReleaseMask
-        | ButtonMotionMask
-        | PropertyChangeMask
-    );
-    x11_init_gc(&X);
-    x11_sel_init(&X);
-    /* register event handlers */
-    X.eventfns[KeyPress] = xkeydn;
-    X.eventfns[KeyRelease] = xkeyup;
-    X.eventfns[ButtonPress] = xmousebtn;
-    X.eventfns[ButtonRelease] = xmousebtn;
-    X.eventfns[MotionNotify] = xbtnmotion;
-    X.eventfns[ClientMessage] = xclientmsg;
-    X.eventfns[ConfigureNotify] = xresize;
-}
-
-void win_title(char* path)
-{
-    static char prevtitle[4096] = {0};
-    char title[4096] = {0};
-    if (!path) path = win_view(EDIT)->buffer.path;
-    if (!path) path = "*scratch*";
-    snprintf(title, sizeof(title)-1, "[%c%c] %s",
-        (DosLineFeed ? 'C' : 'N'),
-        (ExpandTabs ? 'S' : 'T'),
-        path);
-    if (strcmp(prevtitle, title))
-        XStoreName(X.display, X.self, title);
-    memcpy(prevtitle, title, sizeof(title));
-}
-
-void win_font(char* font)
-{
-    font_load(font ? font : Fonts[++FontSel % nelem(Fonts)]);
-}
-
-void win_prop_set(char* xname, char* ename, char* value)
-{
-    if (!value) return;
-    Atom propname = XInternAtom(X.display, xname, 0);
-    XChangeProperty(X.display, X.self, propname, XA_STRING, 8, PropModeReplace,
-        (const unsigned char *)value, strlen(value));
-    if (ename) setenv(ename, value, 1);
-}
-
-void win_loop(void)
-{
-    tide_send("ADD");
-    job_spawn(ConnectionNumber(X.display), xupdate, 0, 0);
-    XSync(X.display, False);
-    int maxcount = 1000 / Timeout;
-    int count = 0;
-    while (X.state != QUITTING)
-    {
-        bool ready = job_poll(Timeout);
-        count += (ready ? -count : 1);
-        if (count < maxcount)
-        {
-            xupdate(NULL);
-        }
-    }
-}
-
-void win_quit(void)
-{
-    static uint64_t before = 0;
-    if ((win_buf(EDIT)->status != MODIFIED) || (X.now - before) <= (uint64_t)ClickTime)
-    {
-        tide_send("DEL");
-        XWithdrawWindow(X.display, X.self, X.screen);
-        X.state = QUITTING;
-        if (x11_sel_ready(&X))
-        {
-            X.state = SERVE_SEL;
-            x11_sel_serve(&X);
-        }
-    }
-    before = X.now;
-}
-
-void win_togglefocus(void)
-{
-    int ypos = (Focused == EDIT ? Divider/2 : (X.height - ((X.height-Divider) / 2)));
-    XWarpPointer(X.display, X.self, X.self, 0, 0, X.width, X.height, X.width/2, ypos);
-}
-
-View* win_view(WinRegion id)
-{
-    return &(Regions[id == FOCUSED ? Focused : id]);
-}
-
-Buf* win_buf(WinRegion id)
-{
-    return &(Regions[id == FOCUSED ? Focused : id].buffer);
-}
-
-bool win_keymodsset(int mask)
-{
-    return ((X.mods & mask) == mask);
-}
-
-void win_setln(int line_num)
-{
-    view_setln(win_view(EDIT), line_num);
-    SyncMouse = true;
-}
-
-/* Keyboard and Tag Handlers
- ******************************************************************************/
-static void change_focus(char* arg)
-{
-    (void)arg;
-    win_togglefocus();
-}
-
-static void quit(char* arg)
-{
-    (void)arg;
-    win_quit();
-}
-
-static void put(char* arg)
-{
-    Buf* buf = win_buf(EDIT);
-    if (buf_save(buf, arg) == NORMAL)
-    {
-        /* convert saved path to absolute path */
-        char* path = File_AbsolutePath(buf->path);
-        buf_setpath(buf, path);
-        free(path);
-    }
-    char* path = (buf->path ? buf->path : "*scratch*");
-    win_title(path);
-    win_prop_set("FILE", "file", path);
-}
-
-static void get(char* arg)
-{
-    if (arg)
-        view_init(win_view(EDIT), arg);
-    else
-        view_reload(win_view(EDIT));
-}
-
-static void tag_undo(char* arg)
-{
-    (void)arg;
-    view_undo(win_view(EDIT));
-}
-
-static void tag_redo(char* arg)
-{
-    (void)arg;
-    view_redo(win_view(EDIT));
-}
-
-static void search(char* arg)
-{
-    (void)arg;
-    char* str;
-    SearchDir *= (win_keymodsset(ModShift) ? UP : DOWN);
-    if (win_keymodsset(ModAlt) && SearchTerm)
-        str = strdup(SearchTerm);
-    else
-        str = view_getctx(win_view(FOCUSED));
-    SyncMouse = view_findstr(win_view(EDIT), SearchDir, str);
-    free(SearchTerm);
-    SearchTerm = str;
-}
-
-static void execute(char* arg)
-{
-    (void)arg;
-    char* str = view_getcmd(win_view(FOCUSED));
-    exec_cmdwarg(str, NULL);
-    free(str);
-}
-
-static void find(char* arg)
-{
-    SearchDir *= (win_keymodsset(ModShift) ? UP : DOWN);
-    view_findstr(win_view(EDIT), SearchDir, arg);
-}
-
-static void open_file(char* arg)
-{
-    (void)arg;
-    exec_cmd(CMD_PICKFILE);
-}
-
-static void pick_symbol(char* symbol)
-{
-    exec_rawwarg(CMD_GOTO_TAG, symbol);
-}
-
-static void pick_ctag(char* arg)
-{
-    (void)arg;
-    pick_symbol(NULL);
-}
-
-static void complete(char* arg)
-{
-    (void)arg;
-    View* view = win_view(FOCUSED);
-    view_selectobj(view, risword);
-    exec_rawwarg(CMD_COMPLETE, view_getstr(view));
-}
-
-static void fcomplete(char* arg)
-{
-    (void)arg;
-    View* view = win_view(FOCUSED);
-    view_selectobj(view, risfile);
-    exec_rawwarg(CMD_FCOMPLETE, view_getstr(view));
-}
-
-static void jump_to(char* arg)
-{
-    if (arg)
-    {
-        size_t line = strtoul(arg, NULL, 0);
-        if (line)
-            win_setln(line);
-        else
-            pick_symbol(arg);
-    }
-}
-
-static void goto_ctag(char* arg)
-{
-    (void)arg;
-    char* str = view_getctx(win_view(FOCUSED));
-    jump_to(str);
-    free(str);
-}
-
-static void tabs(char* arg)
-{
-    (void)arg;
-    ExpandTabs = !ExpandTabs;
-}
-
-static void new_win(char* arg)
-{
-    (void)arg;
-    exec_cmd(CMD_TIDE);
-}
-
-static void lnexec(char* cmd)
-{
-    select_line(NULL);
-    exec_cmdwarg(cmd, NULL);
-}
-
-static void tag_line(char* cmd)
-{
-    (void)cmd;
-    char buf[256] = {0};
-    size_t lnbeg = 1, lnend = 1;
-    buf_getln(win_buf(EDIT), &lnbeg, &lnend);
-    if (lnbeg == lnend)
-        snprintf(buf, sizeof(buf)-1, "%lu", lnbeg);
-    else
-        snprintf(buf, sizeof(buf)-1, "%lu:%lu", lnbeg, lnend);
-    view_paste(win_view(TAGS), buf);
-}
-
-static void do_scroll(char* arg)
-{
-    (void)arg;
-    xpty_togglescroll();
-}
-
-/* Main Routine
- ******************************************************************************/
-Tag* Builtins = (Tag[]){
-    { .tag = "Cut",    .action = cut       },
-    { .tag = "Copy",   .action = copy      },
-    { .tag = "Del",    .action = quit      },
-    { .tag = "Find",   .action = find      },
-    { .tag = "GoTo",   .action = jump_to   },
-    { .tag = "Get",    .action = get       },
-    { .tag = "New",    .action = new_win   },
-    { .tag = "Paste",  .action = paste     },
-    { .tag = "Put",    .action = put       },
-    { .tag = "Redo",   .action = tag_redo  },
-    { .tag = "Tabs",   .action = tabs      },
-    { .tag = "Undo",   .action = tag_undo  },
-    { .tag = "Font",   .action = win_font  },
-    { .tag = "Line",   .action = tag_line  },
-    { .tag = "Scroll", .action = do_scroll },
-    { .tag = NULL,     .action = NULL      }
-};
-
-static KeyBinding* Bindings = (KeyBinding[]){
-    /* Cursor Movements */
-    { .mods = ModAny,  .key = KEY_HOME,  .fn = cursor_home  },
-    { .mods = ModAny,  .key = KEY_END,   .fn = cursor_end   },
-    { .mods = ModAny,  .key = KEY_UP,    .fn = cursor_up    },
-    { .mods = ModAny,  .key = KEY_DOWN,  .fn = cursor_dn    },
-    { .mods = ModAny,  .key = KEY_LEFT,  .fn = cursor_left  },
-    { .mods = ModAny,  .key = KEY_RIGHT, .fn = cursor_right },
-
-    /* Standard Unix Shortcuts */
-    { .mods = ModCtrl, .key = 'u', .fn = del_to_bol  },
-    { .mods = ModCtrl, .key = 'k', .fn = del_to_eol  },
-    { .mods = ModCtrl, .key = 'w', .fn = del_to_bow  },
-    { .mods = ModCtrl, .key = 'a', .fn = cursor_bol  },
-    { .mods = ModCtrl, .key = 'e', .fn = cursor_eol  },
-
-    /* Standard Text Editing Shortcuts */
-    { .mods = ModCtrl, .key = 's', .fn = put         },
-    { .mods = ModCtrl, .key = 'z', .fn = undo        },
-    { .mods = ModCtrl, .key = 'y', .fn = redo        },
-    { .mods = ModCtrl, .key = 'x', .fn = cut         },
-    { .mods = ModCtrl, .key = 'c', .fn = copy        },
-    { .mods = ModCtrl, .key = 'v', .fn = paste       },
-    { .mods = ModCtrl, .key = 'j', .fn = join_lines  },
-    { .mods = ModCtrl, .key = 'l', .fn = select_line },
-
-    /* Common Special Keys */
-    { .mods = ModNone, .key = KEY_PGUP,      .fn = page_up   },
-    { .mods = ModNone, .key = KEY_PGDN,      .fn = page_dn   },
-    { .mods = ModAny,  .key = KEY_DELETE,    .fn = delete    },
-    { .mods = ModAny,  .key = KEY_BACKSPACE, .fn = backspace },
-
-    /* External command shortcuts */
-    { .mods = ModCtrl,          .key = '[', .fn = lnexec, .arg = "|i-" },
-    { .mods = ModCtrl,          .key = ']', .fn = lnexec, .arg = "|i+" },
-    { .mods = ModCtrl,          .key = '/', .fn = lnexec, .arg = "|c+" },
-    { .mods = ModCtrl|ModShift, .key = '?', .fn = lnexec, .arg = "|c-" },
-
-    /* Implementation Specific */
-    { .mods = ModNone,          .key = KEY_ESCAPE, .fn = select_prev  },
-    { .mods = ModCtrl,          .key = 't',        .fn = change_focus },
-    { .mods = ModCtrl,          .key = 'q',        .fn = quit         },
-    { .mods = ModCtrl,          .key = 'h',        .fn = highlight    },
-    { .mods = ModOneOrMore,     .key = 'f',        .fn = search       },
-    { .mods = ModCtrl,          .key = 'd',        .fn = execute      },
-    { .mods = ModOneOrMore,     .key = 'o',        .fn = open_file    },
-    { .mods = ModCtrl,          .key = 'p',        .fn = pick_ctag    },
-    { .mods = ModOneOrMore,     .key = 'g',        .fn = goto_ctag    },
-    { .mods = ModCtrl,          .key = 'n',        .fn = new_win      },
-    { .mods = ModOneOrMore,     .key = '\n',       .fn = newline      },
-    { .mods = ModCtrl,          .key = ' ',        .fn = complete     },
-    { .mods = ModCtrl|ModShift, .key = ' ',        .fn = fcomplete    },
-
-    /* xpty commands */
-    { .mods = ModCtrl|ModShift, .key = 'c', .fn = xpty_rawsend, .arg = "\x03" },
-    { .mods = ModCtrl|ModShift, .key = 'd', .fn = xpty_rawsend, .arg = "\x04" },
-    { .mods = ModCtrl|ModShift, .key = 'z', .fn = xpty_rawsend, .arg = "\x1A" },
-
-    { 0, 0, 0, 0 }
-};
-
-#ifndef TEST
-static void edit_file(char* file, int line_num)
-{
-    printf("%s\n", file);
-    file = File_AbsolutePath(file);
-    printf("%s\n", file);
-    if (!strcmp("-", file))
-    {
-        job_readfd(STDIN_FILENO, win_view(EDIT));
-    }
-    else
-    {
-        view_init(win_view(EDIT), file);
-        win_setln(line_num);
-        win_title(file);
-        win_prop_set("FILE", "file", file);
-    }
-    free(file);
-}
-
-/* Main Routine
- ***************************************************************************/
-
-char* termcmd = NULL;
-long int line_num = 0;
-
-Option_T Options[] = {
-    { .s = 'h', .l = "help",  .a = 0, .d = "print this help message" },
-    { .s = 'T', .l = "tags",  .a = 1, .d = "set tag region contents" },
-    { .s = 'S', .l = "shell", .a = 1, .d = "command interpreter to use" },
-    { .s = 'c', .l = "cmd",   .a = 1, .d = "execute given command" },
-    { .s = 'l', .l = "line",  .a = 1, .d = "jump to specified line" },
-    {0}
-};
-
-void set_option(Int s, char* l, char* arg)
-{
-    switch(s)
-    {
-        case 'T': TagString   = arg;              break;
-        case 'S': ShellCmd[0] = arg;              break;
-        case 'c': termcmd     = arg;              break;
-        case 'l': line_num    = strtoul(arg,0,0); break;
-    }
-}
-
-int usermain(int argc, char** argv)
-{
-    /* Initialize the window and views */
-    exec_init(Builtins);
-    win_init();
-    view_init(&Regions[TAGS], NULL);
-    view_init(&Regions[EDIT], NULL);
-    view_putstr(win_view(TAGS), TagString);
-    view_resize(win_view(TAGS), 640, 1);
-    buf_logclear(win_buf(TAGS));
-    win_prop_set("TIDE", "", "tide");
-    dbc_init(NULL, dumpdata);
-
-    printf("%s\n", *argv);
-
-    /* if we still have args left we're going to open it in this instance */
-    if (*argv)
-    {
-        edit_file(*argv, line_num);
-    }
-
-    /* set host name property */
-    char buf[8192];
-    if (!gethostname(buf, sizeof(buf)))
-        win_prop_set("HOST", "host", buf);
-
-    /* exit */
-    if (termcmd)
-    {
-        termcmd = strmcat("&", termcmd, 0);
-        exec_cmd(termcmd);
-        free(termcmd);
-    }
-
-    /* now create the window and start the event loop */
-#ifndef TEST
-    x11_show(&X);
-#endif
-    xupdate(NULL);
-    win_loop();
-    return 0;
-}
-#endif
diff --git a/bin/editor/mouse.c b/bin/editor/mouse.c
deleted file mode 100644 (file)
index ee9f126..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-#include <liba.h>
-#include <stdc.h>
-#include "dbc.h"
-
-#include "tide.h"
-#include "config.h"
-
-static inline int PRESSED(int mods, int btn)
-{
-    return ((mods & (1 << (btn + 7))) == (1 << (btn + 7)));
-}
-
-static int ExecRequest = 0;
-
-static int mouse_left(bool pressed)
-{
-    static int count = 0;
-    static Time before = 0;
-    int ret = MouseActNone;
-    if (pressed)
-    {
-        count = ((X.now - before) <= (uint64_t)ClickTime ? count+1 : 1);
-        before = X.now;
-        if (PRESSED(X.mods, MouseRight))
-        {
-            ret = MouseActNone;
-        }
-        else if (PRESSED(X.mods, MouseMiddle))
-        {
-            ExecRequest = 0;
-            ret = MouseActExecArg;
-        }
-        else  if (count == 1)
-        {
-            ret = MouseActSel;
-        }
-        else if (count == 2)
-        {
-            ret = MouseActSelCtx;
-        }
-        else if (count == 3)
-        {
-            ret = MouseActSelWord;
-        }
-        else
-        {
-            ret = MouseActNone;
-        }
-    }
-    return ret;
-}
-
-static int mouse_middle(bool pressed)
-{
-    int ret;
-    if (pressed)
-    {
-        ExecRequest = 1;
-        ret = MouseActNone;
-    }
-    else if (PRESSED(X.mods, MouseLeft))
-    {
-        ret = MouseActCut;
-    }
-    else if (ExecRequest)
-    {
-        ret = MouseActExec;
-    }
-    else
-    {
-        ret = MouseActNone;
-    }
-    return ret;
-}
-
-static int mouse_right(bool pressed)
-{
-    int ret;
-    if (pressed)
-    {
-        ret = MouseActNone;
-    }
-    else if (PRESSED(X.mods, MouseLeft))
-    {
-        ret = MouseActPaste;
-    }
-    else
-    {
-        ret = MouseActFetch;
-    }
-    return ret;
-}
-
-int process_mouse(int btn, bool pressed)
-{
-    int ret = MouseActNone;
-    switch(btn)
-    {
-        case MouseLeft:    ret = mouse_left(pressed);   break;
-        case MouseMiddle:  ret = mouse_middle(pressed); break;
-        case MouseRight:   ret = mouse_right(pressed);  break;
-        case MouseWheelUp: ret = (pressed ? MouseActScrollUp : MouseActNone); break;
-        case MouseWheelDn: ret = (pressed ? MouseActScrollDn : MouseActNone); break;
-    }
-    return ret;
-}
diff --git a/bin/editor/range.c b/bin/editor/range.c
deleted file mode 100644 (file)
index 4206d29..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#include <liba.h>
-#include <stdc.h>
-
-#include "tide.h"
-
-void range_add(Sel* p_range, size_t off)
-{
-    if (off < p_range->beg)
-    {
-        p_range->beg++;
-    }
-    if (off <= p_range->end)
-    {
-        p_range->end++;
-    }
-}
-
-void range_del(Sel* p_range, size_t beg, size_t end)
-{
-    /* adjust the point according to the characters deleted */
-    size_t nbytes = end - beg;
-    size_t bpoint = 0;
-    if (beg <= p_range->beg)
-    {
-        bpoint = min(nbytes, p_range->beg - beg);
-    }
-    size_t inpoint = 0;
-    if (end >= p_range->beg)
-    {
-        inpoint = min(end, p_range->end) - max(beg, p_range->beg);
-    }
-    p_range->beg -= bpoint;
-    p_range->end -= (bpoint + inpoint);
-}
diff --git a/bin/editor/shortcuts.c b/bin/editor/shortcuts.c
deleted file mode 100644 (file)
index c7583da..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-#include <liba.h>
-#include <stdc.h>
-
-#include "tide.h"
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-parameter"
-
-void select_line(char* arg)
-{
-    buf_selln(win_buf(FOCUSED));
-}
-
-void join_lines(char* arg)
-{
-    View* view = win_view(FOCUSED);
-    buf_logstart(win_buf(FOCUSED));
-    view_eol(view, false);
-    view_delete(view, RIGHT, false);
-    Rune r = view_getrune(view);
-    for (; r == '\t' || r == ' '; r = view_getrune(view))
-    {
-        view_byrune(view, RIGHT, true);
-    }
-    if (r != '\n')
-    {
-        buf_putc(win_buf(FOCUSED), ' ');
-    }
-    buf_logstop(win_buf(FOCUSED));
-}
-
-void delete(char* arg)
-{
-    bool byword = win_keymodsset(ModCtrl);
-    view_delete(win_view(FOCUSED), RIGHT, byword);
-}
-
-static void onpaste(char* text)
-{
-    view_paste(win_view(FOCUSED), text);
-}
-
-void cut(char* arg)
-{
-    View* view = win_view(FOCUSED);
-    /* select the current line if no selection */
-    if (!view_selsize(view))
-    {
-        select_line(arg);
-    }
-    /* now perform the cut */
-    char* str = view_getstr(view);
-    x11_sel_set(&X, CLIPBOARD, str);
-    if (str && *str)
-    {
-        delete(arg);
-    }
-}
-
-void paste(char* arg)
-{
-    int pasted = x11_sel_get(&X, CLIPBOARD, onpaste);
-    assert(pasted);
-    (void)pasted;
-}
-
-void copy(char* arg)
-{
-    /* select the current line if no selection */
-    if (!view_selsize(win_view(FOCUSED)))
-    {
-        select_line(arg);
-    }
-    char* str = view_getstr(win_view(FOCUSED));
-    x11_sel_set(&X, CLIPBOARD, str);
-}
-
-static void del_to(void (*tofn)(View*, bool))
-{
-    tofn(win_view(FOCUSED), true);
-    if (view_selsize(win_view(FOCUSED)) > 0)
-    {
-        delete(NULL);
-    }
-}
-
-void del_to_bol(char* arg)
-{
-    del_to(view_bol);
-}
-
-void del_to_eol(char* arg)
-{
-    del_to(view_eol);
-}
-
-void del_to_bow(char* arg)
-{
-    view_byword(win_view(FOCUSED), LEFT, true);
-    if (view_selsize(win_view(FOCUSED)) > 0)
-    {
-        delete(arg);
-    }
-}
-
-void backspace(char* arg)
-{
-    view_delete(win_view(FOCUSED), LEFT, win_keymodsset(ModCtrl));
-}
-
-void cursor_bol(char* arg)
-{
-    view_bol(win_view(FOCUSED), false);
-}
-
-void cursor_eol(char* arg)
-{
-    view_eol(win_view(FOCUSED), false);
-}
-
-void cursor_mvlr(int dir)
-{
-    bool extsel = win_keymodsset(ModShift);
-    if (win_keymodsset(ModCtrl))
-    {
-        view_byword(win_view(FOCUSED), dir, extsel);
-    }
-    else
-    {
-        view_byrune(win_view(FOCUSED), dir, extsel);
-    }
-}
-
-void cursor_mvupdn(int dir)
-{
-    bool extsel = win_keymodsset(ModShift);
-    view_byline(win_view(FOCUSED), dir, extsel);
-}
-
-static void cursor_home_end(
-    void (*docfn)(View*, bool),
-    void (*linefn)(View*, bool)
-)
-{
-    bool extsel = win_keymodsset(ModShift);
-    if (win_keymodsset(ModCtrl))
-    {
-        docfn(win_view(FOCUSED), extsel);
-    }
-    else
-    {
-        linefn(win_view(FOCUSED), extsel);
-    }
-}
-
-void cursor_home(char* arg)
-{
-    cursor_home_end(view_bof, view_bol);
-}
-
-void cursor_end(char* arg)
-{
-    cursor_home_end(view_eof, view_eol);
-}
-
-void cursor_up(char* arg)
-{
-    cursor_mvupdn(UP);
-}
-
-void cursor_dn(char* arg)
-{
-    cursor_mvupdn(DOWN);
-}
-
-void cursor_left(char* arg)
-{
-    cursor_mvlr(LEFT);
-}
-
-void cursor_right(char* arg)
-{
-    cursor_mvlr(RIGHT);
-}
-
-void page_up(char* arg)
-{
-    view_scrollpage(win_view(FOCUSED), UP);
-}
-
-void page_dn(char* arg)
-{
-    view_scrollpage(win_view(FOCUSED), DOWN);
-}
-
-void select_prev(char* arg)
-{
-    view_selprev(win_view(FOCUSED));
-}
-
-void undo(char* arg)
-{
-    view_undo(win_view(FOCUSED));
-}
-
-void redo(char* arg)
-{
-    view_redo(win_view(FOCUSED));
-}
-
-void newline(char* arg)
-{
-    (void)arg;
-    View* view = win_view(FOCUSED);
-    if (win_keymodsset(ModShift))
-    {
-        view_byline(view, UP, false);
-        view_bol(view, false);
-    }
-    view_eol(view, false);
-    view_insert(view, '\n');
-}
-
-void highlight(char* arg)
-{
-    view_selctx(win_view(FOCUSED));
-}
-
-#pragma GCC diagnostic pop
diff --git a/bin/editor/tide.h b/bin/editor/tide.h
deleted file mode 100644 (file)
index f6fa72b..0000000
+++ /dev/null
@@ -1,361 +0,0 @@
-#include <libx11.h>
-
-/* undo/redo list item */
-typedef struct Log {
-    struct Log* next; /* pointer to next operation in the stack */
-    size_t beg;       /* beginning of affected region */
-    size_t end;       /* end of affected region*/
-    char* data;       /* pointer to deleted character data */
-    int transid;      /* id of transaction this item is a part of */
-} Log;
-
-/* cursor/selection representation */
-typedef struct {
-    size_t beg;
-    size_t end;
-    size_t col;
-} Sel;
-
-typedef struct {
-    size_t bufsize; /* size of the buffer in runes */
-    char* bufstart; /* start of the data buffer */
-    char* bufend;   /* end of the data buffer */
-    char* gapstart; /* start of the gap */
-    char* gapend;   /* end of the gap */
-} GapBuf;
-
-typedef struct {
-    int transid; /* id number of the current transaction */
-    Log* undo;   /* undo list */
-    Log* redo;   /* redo list */
-    Log* save;   /* pointer to last save position */
-} EditLog;
-
-/* gap buffer main data structure */
-typedef struct {
-    enum {
-        NORMAL = 0, MODIFIED, OUTDATED, ERRORED
-    } status;
-    char* path;       /* the path to the open file */
-    GapBuf contents;  /* underlying sequence data structure */
-    EditLog log;      /* underlying log of edit operations */
-    Sel selection;    /* the currently selected text */
-    Sel point;    /* tracks external command I/O */
-    void (*oninsert)(int byte);
-} Buf;
-
-enum {
-    BY_RUNE = 0,
-    BY_WORD,
-    BY_LINE
-};
-
-void range_add(Sel* p_range, size_t off);
-void range_del(Sel* p_range, size_t beg, size_t end);
-
-void gapbuf_init(GapBuf* buf);
-size_t gapbuf_end(GapBuf* buf);
-long gapbuf_save(GapBuf* buf, char* path);
-void gapbuf_load(GapBuf* buf, char* path);
-char gapbuf_getb(GapBuf* buf, size_t off);
-void gapbuf_putb(GapBuf* buf, char b, Sel* p_sel);
-void gapbuf_del(GapBuf* buf, size_t off, size_t len);
-
-void editlog_seqstart(EditLog* log);
-void editlog_seqstop(EditLog* log);
-void editlog_clear(EditLog* log);
-void editlog_lastins(EditLog* log, Sel* p_sel);
-void editlog_undo(Buf* log);
-void editlog_redo(Buf* log);
-void editlog_add(Buf* buf, size_t beg, size_t end, char* data);
-
-void buf_init(Buf* buf);
-void buf_setpath(Buf* buf, char* path);
-void buf_load(Buf* buf, char* path);
-void buf_reload(Buf* buf);
-int buf_save(Buf* buf, char* path);
-size_t buf_end(Buf* buf);
-
-int buf_getrat(Buf* buf, size_t off);
-void buf_putc(Buf* buf, int c);
-void buf_puts(Buf* buf, char* s);
-int buf_getc(Buf* buf);
-char* buf_gets(Buf* buf);
-char* buf_getsat(Buf* buf, size_t beg, size_t end);
-void buf_del(Buf* buf);
-
-void buf_logstart(Buf* buf);
-void buf_logstop(Buf* buf);
-void buf_logclear(Buf* buf);
-void buf_lastins(Buf* buf);
-void buf_undo(Buf* buf);
-void buf_redo(Buf* buf);
-
-bool buf_isbol(Buf* buf, size_t pos);
-bool buf_iseol(Buf* buf, size_t pos);
-size_t buf_bol(Buf* buf, size_t pos);
-size_t buf_eol(Buf* buf, size_t pos);
-
-bool buf_findstr(Buf* buf, int dir, char* str);
-char* buf_fetch(Buf* buf, bool (*isword)(Rune), size_t off);
-
-void buf_setln(Buf* buf, size_t line);
-void buf_getln(Buf* buf, size_t* begln, size_t* endln);
-
-size_t buf_selbeg(Buf* buf);
-size_t buf_selend(Buf* buf);
-size_t buf_selsz(Buf* buf);
-void buf_selln(Buf* buf);
-void buf_selclr(Buf* buf, int dir);
-bool buf_insel(Buf* buf, size_t off);
-bool buf_inpoint(Buf* buf, size_t off);
-void buf_selword(Buf* buf, bool (*isword)(Rune));
-void buf_selall(Buf* buf);
-void buf_selctx(Buf* buf, bool (*isword)(Rune));
-
-size_t buf_byrune(Buf* buf, size_t pos, int count);
-size_t buf_moveby(Buf* buf, int bything, size_t pos, int count);
-void buf_selmove(Buf* buf, bool extsel, int move, int bything);
-void buf_selmoveto(Buf* buf, bool extsel, size_t off);
-
-/* Screen management functions
- *****************************************************************************/
-typedef struct {
-    size_t off;   /* offset of the rune in the buffer */
-    size_t width; /* width of the glyph on screen */
-    Rune rune;    /* rune value for the cell */
-} UGlyph;
-
-typedef struct {
-    size_t off;    /* offset of the first rune in the row */
-    size_t len;    /* number of runes displayed in the row */
-    UGlyph cols[]; /* row data */
-} Row;
-
-typedef struct {
-    enum {
-        CURSOR = (1 << 0),
-        CENTER = (1 << 1),
-    } sync_flags;    /* flags controlling how the view is synced to cursor */
-    Buf buffer;      /* the buffer used to populate the view */
-    size_t index;    /*  */
-    size_t width;    /* width of the view in pixels */
-    size_t nvisible; /* number of visible lines */
-    size_t nrows;    /* number of rows and columns in the view */
-    Row** rows;      /* array of row data structures */
-} View;
-
-enum {
-    LEFT  = -1,
-    RIGHT = +1,
-    UP    = -1,
-    DOWN  = +1
-};
-
-void view_init(View* view, char* file);
-void view_sync(View* view);
-void view_reload(View* view);
-size_t view_limitrows(View* view, size_t maxrows);
-void view_resize(View* view, size_t width, size_t nrows);
-void view_update(View* view);
-Row* view_getrow(View* view, size_t row);
-void view_byrune(View* view, int move, bool extsel);
-void view_byword(View* view, int move, bool extsel);
-void view_byline(View* view, int move, bool extsel);
-char* view_fetch(View* view, size_t row, size_t col, bool (*isword)(Rune));
-bool view_findstr(View* view, int dir, char* str);
-void view_insert(View* view, Rune rune);
-void view_delete(View* view, int dir, bool byword);
-void view_bol(View* view, bool extsel);
-void view_eol(View* view, bool extsel);
-void view_bof(View* view, bool extsel);
-void view_eof(View* view, bool extsel);
-void view_undo(View* view);
-void view_redo(View* view);
-void view_paste(View* view, char* str);
-void view_putstr(View* view, char* str);
-void view_putraw(View* view, char* str);
-char* view_getstr(View* view);
-char* view_getcmd(View* view);
-char* view_getword(View* view);
-char* view_getctx(View* view);
-void view_selctx(View* view);
-void view_scroll(View* view, int move);
-void view_scrollpage(View* view, int move);
-void view_setln(View* view, size_t line);
-size_t view_selsize(View* view);
-void view_selprev(View* view);
-void view_setcursor(View* view, size_t row, size_t col, bool extsel);
-void view_selextend(View* view, size_t row, size_t col);
-void view_selword(View* view, size_t row, size_t col);
-void view_select(View* view, size_t row, size_t col);
-void view_jumpto(View* view, bool extsel, size_t off);
-void view_scrollto(View* view, size_t csr);
-Rune view_getrune(View* view);
-void view_selectall(View* view);
-void view_selectobj(View* view, bool (*istype)(Rune));
-
-/* Command Executions
- *****************************************************************************/
-/* src/tide/job.c */
-
-typedef struct Job Job;
-
-typedef void (*jobfn_t)(Job* job);
-
-struct Job {
-    Job *next;
-    int pid, fd;
-    void *data;
-    void (*writefn)(Job *job);
-    void (*readfn)(Job *job);
-};
-
-Job* job_list(void);
-void job_kill(Job* job);
-bool job_poll(int ms);
-void job_spawn(int fd, jobfn_t readfn, jobfn_t writefn, void* data);
-void job_start(char** cmd, char* data, size_t ndata, View* dest);
-int job_run(char** cmd);
-void job_readfd(int fd, View* view);
-
-/* Common Shortcuts
- *****************************************************************************/
-/* src/tide/shortcuts.c */
-
-void select_line(char* arg);
-void join_lines(char* arg);
-void delete(char* arg);
-void cut(char* arg);
-void paste(char* arg);
-void copy(char* arg);
-void del_to_bol(char* arg);
-void del_to_eol(char* arg);
-void del_to_bow(char* arg);
-void backspace(char* arg);
-void cursor_bol(char* arg);
-void cursor_eol(char* arg);
-void cursor_mvlr(int dir);
-void cursor_mvupdn(int dir);
-void cursor_home(char* arg);
-void cursor_end(char* arg);
-void cursor_up(char* arg);
-void cursor_dn(char* arg);
-void cursor_left(char* arg);
-void cursor_right(char* arg);
-void page_up(char* arg);
-void page_dn(char* arg);
-void select_prev(char* arg);
-void undo(char* arg);
-void redo(char* arg);
-void newline(char* arg);
-void highlight(char* arg);
-
-enum {
-    MouseActNone,
-    MouseActSel,
-    MouseActSelCtx,
-    MouseActSelWord,
-    MouseActCut,
-    MouseActPaste,
-    MouseActExec,
-    MouseActExecArg,
-    MouseActFetch,
-    MouseActScrollUp,
-    MouseActScrollDn,
-};
-
-int process_mouse(int btn, bool pressed);
-
-/* Command and Tag Exectuion
- *****************************************************************************/
-/* src/tide/exec.c */
-
-typedef struct {
-    char* tag;
-    void (*action)(char*);
-} Tag;
-
-void exec_init(Tag* p_tags);
-void exec_cmd(char* cmd);
-void exec_cmdwarg(char* cmd, char* arg);
-void exec_rawwarg(char* cmd, char* arg);
-
-/* UI Window Control
- *****************************************************************************/
-/* src/tide/main.c */
-
-typedef struct XFont XFont;
-
-typedef struct {
-    uint32_t attr; /* attributes applied to this cell */
-    uint32_t rune; /* rune value for the cell */
-} XGlyph;
-
-typedef struct {
-    void* font;
-    uint32_t glyph;
-    short x;
-    short y;
-} XGlyphSpec;
-
-enum {
-    MouseLeft    = 1,
-    MouseMiddle  = 2,
-    MouseRight   = 3,
-    MouseWheelUp = 4,
-    MouseWheelDn = 5
-};
-
-typedef enum {
-    TAGS     = 0,
-    EDIT     = 1,
-    NREGIONS = 2,
-    FOCUSED  = 2
-} WinRegion;
-
-void win_init(void);
-void win_title(char* path);
-void win_font(char* font);
-void win_prop_set(char* xname, char* ename, char* value);
-void win_loop(void);
-void win_quit(void);
-void win_togglefocus(void);
-View* win_view(WinRegion id);
-Buf* win_buf(WinRegion id);
-bool win_keymodsset(int mask);
-void win_setln(int line_num);
-
-typedef struct {
-    int x, y;
-    int h, w;
-} drawcsr;
-
-/* UI Drawing Routines
- *****************************************************************************/
-void draw_rect(XConf* x, int color, int posx, int posy, int width, int height);
-void draw_statbox(XConf* x, int status);
-int draw_hrule(XConf* x, drawcsr* csr);
-void draw_view(XConf* x, View* view, XftFont* font, size_t nrows, drawcsr* csr, int bg, int fg, int sel, bool csrsync);
-bool draw_csr(XConf* x, View* view, int fg, size_t fheight, int posx, int posy, bool csrdrawn);
-void draw_scroll(XConf* x, drawcsr* csr, View* view, int divider);
-
-/* Pseudo Terminal Routines
- *****************************************************************************/
-bool xpty_active(void);
-void xpty_togglescroll(void);
-int xpty_run(View* view, char** cmd);
-void xpty_send(char* cmd);
-void xpty_rawsend(char* cmd);
-
-/* Leap Processing Routines
- *****************************************************************************/
-typedef struct {
-    KeySym key;
-    bool repeat;
-    Sel selection;
-    size_t nbuf;
-    char buf[8192];
-} LeapState_T;
-
-bool leap_process(LeapState_T* state, unsigned long keysym, bool pressed);
diff --git a/bin/editor/view.c b/bin/editor/view.c
deleted file mode 100644 (file)
index 4314fe7..0000000
+++ /dev/null
@@ -1,635 +0,0 @@
-#include <liba.h>
-#include <stdc.h>
-#include "dbc.h"
-#include <ctype.h>
-
-#include "tide.h"
-#include "config.h"
-
-#ifndef NDEBUG
-static bool view_valid(View* view)
-{
-    return (
-           (view->sync_flags <= 3u)
-        && (!view->nrows || view->index < view->nrows)
-//        && (view->width > 0)
-//        && (view->nvisible > 0)
-//        && (view->nrows > 0)
-//        && (view->rows != NULL)
-    );
-}
-#endif
-
-/* Provided by x11.c */
-extern size_t glyph_width(View* view, int c);
-
-#define BUF    (&(view->buffer))
-#define CSRPOS (view->buffer.selection.end)
-
-static void move_selection(View* view, bool extsel, int move, int bything)
-{
-    view->sync_flags |= CURSOR;
-    buf_selmove(BUF, extsel, move, bything);
-}
-
-static void move_to(View* view, bool extsel, size_t off)
-{
-    view->sync_flags |= CURSOR;
-    buf_selmoveto(BUF, extsel, off);
-}
-
-static bool selection_visible(View* view)
-{
-    bool visible = true;
-    if (view->rows && view->nrows)
-    {
-        size_t csr = CSRPOS;
-        size_t beg = view->rows[0]->off;
-        size_t end = view->rows[view->nrows-1]->off
-                   + view->rows[view->nrows-1]->len;
-        visible = (beg <= csr && csr <= end);
-    }
-    return visible;
-}
-
-static Sel* getsel(View* view)
-{
-    return &(view->buffer.selection);
-}
-
-static void clear_rows(View* view, size_t startidx)
-{
-    if (view->rows)
-    {
-        /* Free and clear invalid rows now */
-        for (size_t i = startidx; i < view->nrows; i++)
-        {
-            free(view->rows[i]);
-            view->rows[i] = NULL;
-        }
-        /* grow row array if needed */
-        if (startidx > view->nrows)
-        {
-            view->rows = realloc(view->rows, startidx);
-        }
-        /* zero out newly created slots */
-        for (size_t i = view->nrows; i < startidx; i++)
-        {
-            view->rows[i] = NULL;
-        }
-        view->nrows = startidx;
-    }
-}
-
-void view_init(View* view, char* file)
-{
-    require(view != NULL);
-    clear_rows(view, 0);
-    view->sync_flags |= (CURSOR|CENTER);
-    view->index = 0;
-    view->width = 0;
-    view->nvisible = 0;
-    /* load the file and jump to the address returned from the load function */
-    buf_init(BUF);
-    if (file)
-    {
-        buf_load(BUF, file);
-    }
-    ensure(view_valid(view));
-}
-
-void view_reload(View* view)
-{
-    require(view != NULL);
-    if (view->buffer.path)
-    {
-        buf_reload(BUF);
-        view->sync_flags |= (CURSOR|CENTER);
-    }
-    ensure(view_valid(view));
-}
-
-void view_sync(View* view)
-{
-    require(view != NULL);
-    view->sync_flags |= (CURSOR|CENTER);
-    ensure(view_valid(view));
-}
-
-static size_t rune_width(View* view, int c, size_t xpos, size_t width)
-{
-    size_t sz;
-    if (c == '\r')
-    {
-        sz = 0;
-    }
-    else if (c == '\n')
-    {
-        sz = (width-xpos);
-    }
-    else if (c == '\t')
-    {
-        sz = (glyph_width(view, c) - (xpos % glyph_width(view, c)));
-    }
-    else
-    {
-        sz = glyph_width(view, c);
-    }
-    return sz;
-}
-
-size_t view_limitrows(View* view, size_t maxrows)
-{
-    require(view != NULL);
-    size_t nrows = 1, off = 0, xpos = 0;
-    while (nrows < maxrows && off < buf_end(&(view->buffer)))
-    {
-        Rune rune = buf_getrat(&(view->buffer), off);
-        xpos += rune_width(view, rune, xpos, view->width);
-        /* if the line is full, reset the line and increase row count */
-        if (xpos > view->width)
-        {
-            xpos = 0, nrows++;
-        }
-        else
-        {
-            if (rune == '\n')
-            {
-                xpos = 0;
-                nrows++;
-            }
-            off = buf_byrune(&(view->buffer), off, RIGHT);
-        }
-    }
-    ensure(nrows >= 1);
-    return nrows;
-}
-
-static size_t add_row(View* view, size_t off)
-{
-    /* allocate a new row */
-    view->nrows++;
-    view->rows = realloc(view->rows, sizeof(Row*) * view->nrows);
-    view->rows[view->nrows-1] = calloc(1, sizeof(Row));
-    view->rows[view->nrows-1]->off = off;
-
-    /* populate the row with characters */
-    for (size_t xpos = 0; xpos < view->width;)
-    {
-        int rune = buf_getrat(&(view->buffer), off);
-        size_t rwidth = rune_width(view, rune, xpos, view->width);
-        xpos += rwidth;
-        if (xpos <= view->width)
-        {
-            size_t len = view->rows[view->nrows-1]->len + 1;
-            view->rows[view->nrows-1] = realloc(
-                view->rows[view->nrows-1], sizeof(Row) + (len * sizeof(UGlyph)));
-            view->rows[view->nrows-1]->len = len;
-            view->rows[view->nrows-1]->cols[len-1].rune  = rune;
-            view->rows[view->nrows-1]->cols[len-1].width = rwidth;
-            view->rows[view->nrows-1]->cols[len-1].off   = off;
-            off = buf_byrune(&(view->buffer), off, RIGHT);
-        }
-    }
-    return off;
-}
-
-static void resize(View* view, size_t width, size_t nrows, size_t off)
-{
-    bool first_line_done = false;
-    clear_rows(view, 0);
-    view->width = width;
-    view->nvisible = nrows;
-    view->index = 0;
-    size_t beg = off, bend = buf_end(&(view->buffer));
-    off = buf_bol(&(view->buffer), off);
-    if (off > bend)
-    {
-        off = bend;
-    }
-
-    for (size_t i = 0; nrows > 0; i++)
-    {
-        off = add_row(view, off);
-        Row* row = view->rows[view->nrows-1];
-        first_line_done = (first_line_done || (row->cols[row->len-1].rune == '\n'));
-        if (first_line_done)
-        {
-            nrows--;
-        }
-        if (beg < bend && beg >= row->off && beg <= row->cols[row->len-1].off)
-        {
-            view->index = i;
-        }
-    }
-}
-
-void view_resize(View* view, size_t width, size_t nrows)
-{
-    require(view != NULL);
-    require(width > 0);
-    require(nrows > 0);
-    if (view->width == width && view->nvisible == nrows)
-    {
-        return;
-    }
-    size_t off = (view->nrows && view->index < view->nrows ? view->rows[view->index]->off : 0);
-    resize(view, width, nrows, off);
-    ensure(view_valid(view));
-}
-
-void view_update(View* view)
-{
-    require(view != NULL);
-    /* refill the view contents to make sure updates are visible */
-    size_t off = view->rows[view->index]->off;
-    clear_rows(view, view->index);
-    for (size_t i = 0; i < view->nvisible; i++)
-    {
-        off = add_row(view, off);
-    }
-    /* sync up the view with the cursor */
-    if (view->sync_flags)
-    {
-        if (view->sync_flags & CENTER)
-        {
-            resize(view, view->width, view->nrows, CSRPOS);
-            view_scroll(view, UP * (view->nvisible/2));
-        }
-        else
-        {
-            Row* lastrow = view->rows[view->nrows-1];
-            size_t last_off = lastrow->cols[lastrow->len-1].off;
-            view_scrollto(view, CSRPOS);
-            if (last_off < CSRPOS)
-            {
-                view_scroll(view, UP * (view->nvisible-1));
-            }
-        }
-        view->sync_flags = 0;
-    }
-    ensure(view_valid(view));
-}
-
-Row* view_getrow(View* view, size_t row)
-{
-    return (row < view->nrows ? view->rows[row] : NULL);
-}
-
-void view_byrune(View* view, int move, bool extsel)
-{
-    require(view != NULL);
-    move_selection(view, extsel, move, BY_RUNE);
-    ensure(view_valid(view));
-}
-
-void view_byword(View* view, int move, bool extsel)
-{
-    require(view != NULL);
-    move_selection(view, extsel, move, BY_WORD);
-    ensure(view_valid(view));
-}
-
-void view_byline(View* view, int move, bool extsel)
-{
-    require(view != NULL);
-    move_selection(view, extsel, move, BY_LINE);
-    ensure(view_valid(view));
-}
-
-static size_t getoffset(View* view, size_t row, size_t col)
-{
-    size_t ret = 0, i = 0, y = 0, idx = view->index + row;
-    if (idx < view->nrows)
-    {
-        Row* selrow = view->rows[idx];
-        for (; i < selrow->len; i++)
-        {
-            y += selrow->cols[i].width;
-            if (col < y)
-            {
-                break;
-            }
-        }
-        ret = selrow->cols[i].off;
-    }
-    return ret;
-}
-
-void view_setcursor(View* view, size_t row, size_t col, bool extsel)
-{
-    buf_selmoveto(BUF, extsel, getoffset(view, row, col));
-    ensure(view_valid(view));
-}
-
-void view_selword(View* view, size_t row, size_t col)
-{
-    if (row != SIZE_MAX && col != SIZE_MAX)
-    {
-        view_setcursor(view, row, col, false);
-    }
-    buf_selword(BUF, risbigword);
-    ensure(view_valid(view));
-}
-
-void view_selprev(View* view)
-{
-    if (!view_selsize(view))
-    {
-        buf_lastins(BUF);
-    }
-    else
-    {
-        buf_selclr(BUF, RIGHT);
-    }
-    ensure(view_valid(view));
-}
-
-void view_select(View* view, size_t row, size_t col)
-{
-    view_setcursor(view, row, col, false);
-    buf_selctx(BUF, risword);
-    ensure(view_valid(view));
-}
-
-size_t view_selsize(View* view)
-{
-    return buf_selsz(BUF);
-}
-
-char* view_fetch(View* view, size_t row, size_t col, bool (*isword)(Rune))
-{
-    char* str = NULL;
-    size_t off = getoffset(view, row, col);
-    if (off != SIZE_MAX)
-    {
-        str = buf_fetch(BUF, isword, off);
-    }
-    ensure(view_valid(view));
-    return str;
-}
-
-bool view_findstr(View* view, int dir, char* str)
-{
-    bool found = buf_findstr(BUF, dir, str);
-    view->sync_flags |= (CURSOR|CENTER);
-    ensure(view_valid(view));
-    return found;
-}
-
-void view_insert(View* view, Rune rune)
-{
-    /* ignore non-printable control characters */
-    if (!isspace(rune) && (rune >= 0 && rune < 0x20))
-    {
-        return;
-    }
-    if (ExpandTabs && rune == '\t')
-    {
-        size_t off = buf_selbeg(BUF);
-        size_t n = (TabWidth - ((off - buf_bol(BUF, off)) % TabWidth));
-        for (; n > 0; n--) buf_putc(BUF, ' ');
-    }
-    else if (CopyIndent && rune == '\n')
-    {
-        size_t off = buf_selbeg(BUF);
-        size_t beg = buf_bol(BUF, off), end = beg;
-        for (; end < buf_end(BUF) && end < off && (' ' == buf_getrat(BUF, end) || '\t' == buf_getrat(BUF, end)); end++)
-        {
-        }
-        char* str = buf_getsat(BUF, beg, end);
-        buf_putc(BUF, '\n');
-        buf_puts(BUF, str);
-        free(str);
-    }
-    else
-    {
-        buf_putc(BUF, rune);
-    }
-    move_to(view, false, CSRPOS);
-    ensure(view_valid(view));
-}
-
-void view_delete(View* view, int dir, bool byword)
-{
-    if (!view_selsize(view))
-    {
-        (byword ? view_byword : view_byrune)(view, dir, true);
-    }
-    buf_del(BUF);
-    move_to(view, false, CSRPOS);
-    ensure(view_valid(view));
-}
-
-void view_jumpto(View* view, bool extsel, size_t off)
-{
-    move_to(view, extsel, off);
-    ensure(view_valid(view));
-}
-
-void view_bol(View* view, bool extsel)
-{
-    /* determine whether we are jumping to start of content or line */
-    Buf* buf = BUF;
-    unsigned bol = buf_bol(buf, CSRPOS);
-    unsigned boi = bol;
-    for (; ' '  == buf_getrat(buf, boi) || '\t' == buf_getrat(buf, boi); boi++);
-    unsigned pos = CSRPOS;
-    pos = (pos == bol || pos > boi ? boi : bol);
-    move_to(view, extsel, pos);
-    ensure(view_valid(view));
-}
-
-void view_eol(View* view, bool extsel)
-{
-    move_to(view, extsel, buf_eol(BUF, CSRPOS));
-    getsel(view)->col = -1; // Peg cursor to line end
-    ensure(view_valid(view));
-}
-
-void view_bof(View* view, bool extsel)
-{
-    view_jumpto(view, extsel, 0);
-    ensure(view_valid(view));
-}
-
-void view_eof(View* view, bool extsel)
-{
-    view_jumpto(view, extsel, buf_end(BUF));
-    ensure(view_valid(view));
-}
-
-void view_setln(View* view, size_t line)
-{
-    view->sync_flags |= CENTER;
-    if (line)
-    {
-        buf_setln(BUF, line);
-        buf_selln(BUF);
-    }
-    ensure(view_valid(view));
-}
-
-static void cursor_sync(View* view)
-{
-    view->sync_flags |= CURSOR;
-    if (!selection_visible(view))
-    {
-        view->sync_flags |= CENTER;
-    }
-}
-
-void view_undo(View* view)
-{
-    buf_undo(BUF);
-    cursor_sync(view);
-    ensure(view_valid(view));
-}
-
-void view_redo(View* view)
-{
-    buf_redo(BUF);
-    cursor_sync(view);
-    ensure(view_valid(view));
-}
-
-void view_paste(View* view, char* str)
-{
-    buf_logstart(BUF);
-    view_putstr(view, str);
-    buf_logstop(BUF);
-    view_selprev(view);
-    ensure(view_valid(view));
-}
-
-void view_putstr(View* view, char* str)
-{
-    buf_puts(BUF, str);
-    ensure(view_valid(view));
-}
-
-void view_putraw(View* view, char* str)
-{
-    void (*fn)(int) = BUF->oninsert;
-    BUF->oninsert = NULL;
-    buf_puts(BUF, str);
-    BUF->oninsert = fn;
-    ensure(view_valid(view));
-}
-
-char* view_getstr(View* view)
-{
-    return buf_gets(BUF);
-}
-
-char* view_getcmd(View* view)
-{
-    if (!view_selsize(view))
-    {
-        buf_selctx(BUF, riscmd);
-    }
-    ensure(view_valid(view));
-    return view_getstr(view);
-}
-
-void view_selctx(View* view)
-{
-    if (!view_selsize(view))
-    {
-        buf_selctx(BUF, risword);
-    }
-    ensure(view_valid(view));
-}
-
-char* view_getctx(View* view)
-{
-    view_selctx(view);
-    ensure(view_valid(view));
-    return view_getstr(view);
-}
-
-static void scroll_up(View* view)
-{
-    if (view->index > 0)
-    {
-        view->index--;
-    }
-    else if (view->rows[0]->off > 0)
-    {
-        resize(view, view->width, view->nvisible, buf_byrune(BUF, view->rows[0]->off, LEFT));
-    }
-}
-
-static void scroll_dn(View* view)
-{
-    if (view->nrows <= 1)
-    {
-        return;
-    }
-    size_t nleft = (view->nrows - view->index);
-    if (nleft <= view->nvisible)
-    {
-        size_t off = view->rows[view->index+1]->off;
-        resize(view, view->width, view->nvisible, off);
-    }
-    else
-    {
-        view->index++;
-    }
-}
-
-void view_scroll(View* view, int move)
-{
-    int dir = (move < 0 ? -1 : 1);
-    move *= dir;
-    for (int i = 0; i < move; i++)
-    {
-        if (dir < 0)
-        {
-            scroll_up(view);
-        }
-        else
-        {
-            scroll_dn(view);
-        }
-    }
-    ensure(view_valid(view));
-}
-
-void view_scrollpage(View* view, int move)
-{
-    move = (move < 0 ? -1 : 1) * view->nrows;
-    view_scroll(view, move);
-    ensure(view_valid(view));
-}
-
-Rune view_getrune(View* view)
-{
-    return buf_getc(BUF);
-}
-
-void view_scrollto(View* view, size_t csr)
-{
-    Row* lastrow = view->rows[view->nrows-1];
-    size_t first = view->rows[view->index]->off;
-    size_t last  = lastrow->cols[lastrow->len-1].off;
-    if (csr < first || csr > last)
-    {
-        resize(view, view->width, view->nrows, csr);
-    }
-    ensure(view_valid(view));
-}
-
-void view_selectall(View* view)
-{
-    buf_selall(BUF);
-    view->sync_flags |= CURSOR;
-    ensure(view_valid(view));
-}
-
-void view_selectobj(View* view, bool (*istype)(Rune))
-{
-    buf_selword(BUF, istype);
-    view->sync_flags |= CURSOR;
-    ensure(view_valid(view));
-}
diff --git a/bin/editor/xpty.c b/bin/editor/xpty.c
deleted file mode 100644 (file)
index b74e79a..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-#define _XOPEN_SOURCE 700
-#include <liba.h>
-#include <stdc.h>
-#include <sys/socket.h>
-#ifdef __linux__
-    #include <pty.h>
-#else
-    #include <util.h>
-#endif
-#include "tide.h"
-
-#define BUFFERSZ 16384
-
-static View* EditView = NULL;
-static int Pty_Fd = -1;
-static bool DoScroll = 0;
-static char* PromptStr = NULL;
-static char ReadBuf[BUFFERSZ+1] = {0};
-static char ArgsBuf[BUFFERSZ+1] = {0};
-static char InputBuf[BUFFERSZ+1] = {0};
-static ssize_t ArgsPos = 0;
-static ssize_t InputPos = 0;
-static ssize_t IgnoreCount = 0;
-static enum {
-    READ_ECHO = 0,
-    READ_CHAR,
-    READ_ESC,
-    READ_OSC,
-    READ_OSI,
-} State = READ_CHAR;
-
-static void read_echo(char c)
-{
-    (void)c;
-    IgnoreCount--;
-    if (IgnoreCount <= 0)
-    {
-        State = READ_CHAR;
-    }
-}
-
-static void read_char(char c)
-{
-    if (c == '\033')
-    {
-        State = READ_ESC;
-    }
-    else
-    {
-        InputBuf[InputPos++] = c;
-        InputBuf[InputPos] = '\0';
-    }
-}
-
-static void read_esc(char c)
-{
-    ArgsBuf[(ArgsPos = 0)] = '\0';
-    if (c == '[')
-   {
-        State = READ_OSI;
-   }
-   else if (c == ']')
-   {
-        State = READ_OSC;
-   }
-   else
-   {
-        State = READ_CHAR;
-   }
-}
-
-static void read_osc(char c)
-{
-    if (c == '\a')
-    {
-        State = READ_CHAR;
-        if (ArgsBuf[0] == '7' && ArgsBuf[1] == ';')
-        {
-            chdir(&ArgsBuf[2]);
-        }
-        else if (ArgsBuf[0] == '0' && ArgsBuf[1] == ';')
-        {
-            free(PromptStr);
-            PromptStr = strdup(&ArgsBuf[2]);
-        }
-    }
-    else
-    {
-        ArgsBuf[ArgsPos++] = c;
-        ArgsBuf[ArgsPos] = '\0';
-    }
-}
-
-static void read_osi(char c)
-{
-    if (isalpha(c))
-    {
-        State = READ_CHAR;
-    }
-}
-
-static void (*Handlers[])(char c) = {
-    [READ_ECHO] = read_echo,
-    [READ_CHAR] = read_char,
-    [READ_ESC] = read_esc,
-    [READ_OSC] = read_osc,
-    [READ_OSI] = read_osi,
-};
-
-static void putb(int byte)
-{
-    struct termios tio = {0};
-    tcgetattr(Pty_Fd, &tio);
-
-    if ((tio.c_lflag & ICANON) == ICANON)
-    {
-        char b = byte;
-        File_Write(Pty_Fd, &b, 1);
-        if (byte == '\n')
-        {
-            *((char*)(EditView->buffer.contents.gapstart-1)) = ' ';
-            EditView->buffer.point.beg = EditView->buffer.point.end;
-        }
-        else if ((tio.c_lflag & ECHO) != ECHO)
-        {
-            *((char*)(EditView->buffer.contents.gapstart-1)) = '*';
-        }
-        else
-        {
-            File_Read(Pty_Fd, &b, 1);
-        }
-    }
-    else if (byte == '\n' && (EditView->buffer.selection.end == EditView->buffer.point.end))
-    {
-        /* get the input string and update the point */
-        char* str = buf_getsat(&(EditView->buffer), EditView->buffer.point.beg, EditView->buffer.point.end);
-        size_t slen = strlen(str);
-        EditView->buffer.point.beg = EditView->buffer.point.end;
-
-        /* write the data and read back to discard the echoed chars */
-//        printf("write: '%s'\n", str);
-        File_Write(Pty_Fd, str, slen);
-        State = READ_ECHO;
-        IgnoreCount = slen+1;
-        InputBuf[(InputPos = 0)] = '\0';
-
-        free(str);
-    }
-}
-
-static void writedata(char* buf, long n)
-{
-    InputBuf[0] = '\0';
-    InputPos = 0;
-//    printf("read: '%s'\n", ReadBuf);
-    for (long i = 0; i < n; i++)
-    {
-        Handlers[State](buf[i]);
-    }
-    view_putraw(EditView, InputBuf);
-    if (DoScroll)
-    {
-        EditView->sync_flags |= CURSOR;
-    }
-}
-
-static void xpty_read(Job* job)
-{
-    long nread = File_Read(job->fd, ReadBuf, sizeof(ReadBuf)-1);
-    if (nread <= 0)
-    {
-        job->readfn = NULL;
-        Pty_Fd = -1;
-        EditView->buffer.oninsert = NULL;
-        EditView = NULL;
-    }
-    else if (nread > 0)
-    {
-        ReadBuf[nread] = '\0';
-
-        /* swap the point and selection to perform the insert */
-        size_t start = EditView->buffer.point.beg;
-        Sel sel = {
-            .col = EditView->buffer.selection.col,
-            .beg = buf_selbeg(&(EditView->buffer)),
-            .end = buf_selend(&(EditView->buffer))
-        };
-        EditView->buffer.selection.beg = EditView->buffer.point.beg;
-        EditView->buffer.selection.end = EditView->buffer.point.beg;
-        EditView->buffer.point = sel;
-
-        /* insert the text */
-        writedata(ReadBuf, nread);
-
-        /* adjust the original selection and swap it back */
-        nread = (EditView->buffer.point.end - start);
-        if (start <= sel.beg)
-        {
-            sel.beg += nread;
-        }
-        if (start <= sel.end)
-        {
-            sel.end += nread;
-        }
-        Sel point = EditView->buffer.selection;
-        EditView->buffer.selection = sel;
-        EditView->buffer.point = point;
-    }
-}
-
-bool xpty_active(void)
-{
-    return (Pty_Fd >= 0);
-}
-
-void xpty_togglescroll(void)
-{
-    DoScroll = !DoScroll;
-}
-
-int xpty_run(View* view, char** cmd)
-{
-    (void)view;
-    int fd = -1;
-    if (Pty_Fd < 0)
-    {
-        pid_t pid = forkpty(&fd, NULL, NULL, NULL);
-        if (pid == 0)
-        {
-            exit(execvp(cmd[0], cmd));
-        }
-        else if (pid < 0 )
-        {
-            fd = -1;
-        }
-        else
-        {
-            Pty_Fd = fd;
-            EditView = view;
-            if (view_selsize(view))
-            {
-                view_delete(view, LEFT, false);
-            }
-            view->buffer.oninsert = putb;
-            view->buffer.point.beg = view->buffer.selection.end;
-            view->buffer.point.end = view->buffer.selection.end;
-            job_spawn(Pty_Fd, xpty_read, NULL, NULL);
-        }
-    }
-    return fd;
-}
-
-void xpty_send(char* cmd)
-{
-    if (EditView)
-    {
-        EditView->buffer.selection.beg = EditView->buffer.point.end;
-        EditView->buffer.selection.end = EditView->buffer.point.end;
-        if (PromptStr)
-        {
-            size_t plen = strlen(PromptStr);
-            if (!strncmp(PromptStr, cmd, plen))
-            {
-                cmd += strlen(PromptStr);
-            }
-        }
-        view_putstr(EditView, cmd);
-        if (*cmd && cmd[strlen(cmd)-1] != '\n')
-        {
-            view_insert(EditView, '\n');
-        }
-    }
-}
-
-void xpty_rawsend(char* str)
-{
-    (void)File_Write(Pty_Fd, str, strlen(str));
-}
index e9dbda0986656ceee5bbf40297e949fc364d7317..f3df8a16ccbc10562590ef5404f986f05f12396e 100644 (file)
@@ -1,5 +1,5 @@
 $(BINDIR)/edit:       LIBS += -lX11
-$(BINDIR)/editor:     LIBS += -lx11 -lX11 -lXft -lfontconfig -lXinerama
+$(BINDIR)/editor:     LIBS += $(GTK_LIBS)
 $(BINDIR)/pick:       LIBS += -lx11 -lX11 -lXft -lfontconfig -lXinerama
 $(BINDIR)/screenlock: LIBS += -lui -lX11 -lXft -lfontconfig -lcrypt -lXrandr
 $(BINDIR)/terminal:   LIBS += -lui -lX11 -lXft -lfontconfig
index 73ec3662ed828224273fd1d4472eb747374fce19..784304767baf0664d4b310b50f8fbdd143ae4da1 100644 (file)
--- a/config.mk
+++ b/config.mk
@@ -3,8 +3,16 @@ OUTDIR = build
 BINDIR = $(OUTDIR)/bin
 
 CC = cc
-CFLAGS = -g -O2 --std=c11 -pedantic -Wall -Wextra -Werror -Wno-unused-result -Wno-sign-compare -Wno-type-limits -Wno-unused-parameter
-CPPFLAGS = -Iinc/ -I/usr/include/freetype2
+CFLAGS = -g -O2 --std=c11 -pedantic -Wall -Wextra -Wno-unused-result -Wno-sign-compare -Wno-type-limits -Wno-unused-parameter
+
+
+FREETYPE_INCS = $(shell pkg-config freetype2 --cflags)
+FREETYPE_LIBS = $(shell pkg-config freetype2 --libs)
+
+GTK_INCS = $(shell pkg-config gtk+-3.0 --cflags)
+GTK_LIBS = $(shell pkg-config gtk+-3.0 --libs)
+
+CPPFLAGS = -Iinc/ $(FREETYPE_INCS) $(GTK_INCS)
 
 AR = ar
 ARFLAGS = rs