From 182e2b461a89d79dd14b35bc4c61bfbcd0045b67 Mon Sep 17 00:00:00 2001 From: Mike Lowis Date: Tue, 8 Jul 2025 13:30:13 -0400 Subject: [PATCH] switch editor over to GTK based --- Makefile | 7 +- bin/editor.c | 558 +++++++++++++++++++++++++ bin/editor/buf.c | 918 ----------------------------------------- bin/editor/config.h | 100 ----- bin/editor/dbc.c | 84 ---- bin/editor/dbc.h | 16 - bin/editor/draw.c | 111 ----- bin/editor/editlog.c | 195 --------- bin/editor/exec.c | 130 ------ bin/editor/gapbuf.c | 221 ---------- bin/editor/job.c | 239 ----------- bin/editor/leap.c | 81 ---- bin/editor/main.c | 765 ---------------------------------- bin/editor/mouse.c | 106 ----- bin/editor/range.c | 34 -- bin/editor/shortcuts.c | 229 ---------- bin/editor/tide.h | 361 ---------------- bin/editor/view.c | 635 ---------------------------- bin/editor/xpty.c | 278 ------------- bin/rules.mk | 2 +- config.mk | 12 +- 21 files changed, 575 insertions(+), 4507 deletions(-) create mode 100644 bin/editor.c delete mode 100644 bin/editor/buf.c delete mode 100644 bin/editor/config.h delete mode 100644 bin/editor/dbc.c delete mode 100644 bin/editor/dbc.h delete mode 100644 bin/editor/draw.c delete mode 100644 bin/editor/editlog.c delete mode 100644 bin/editor/exec.c delete mode 100644 bin/editor/gapbuf.c delete mode 100644 bin/editor/job.c delete mode 100644 bin/editor/leap.c delete mode 100644 bin/editor/main.c delete mode 100644 bin/editor/mouse.c delete mode 100644 bin/editor/range.c delete mode 100644 bin/editor/shortcuts.c delete mode 100644 bin/editor/tide.h delete mode 100644 bin/editor/view.c delete mode 100644 bin/editor/xpty.c diff --git a/Makefile b/Makefile index 371b9e6..936e7b1 100644 --- 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 index 0000000..be189be --- /dev/null +++ b/bin/editor.c @@ -0,0 +1,558 @@ +#include +#include + +// 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 index 3447e8b..0000000 --- a/bin/editor/buf.c +++ /dev/null @@ -1,918 +0,0 @@ -#define _XOPEN_SOURCE 700 -#include -#include -#include "dbc.h" -#include -#include -#include -#include - -#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 index e1ab943..0000000 --- a/bin/editor/config.h +++ /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 index e772611..0000000 --- a/bin/editor/dbc.c +++ /dev/null @@ -1,84 +0,0 @@ -#include -#include -#include "dbc.h" -#include -#include - -#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 index 5dc1575..0000000 --- a/bin/editor/dbc.h +++ /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 index b90560c..0000000 --- a/bin/editor/draw.c +++ /dev/null @@ -1,111 +0,0 @@ -#include -#include - -#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 index f83dfad..0000000 --- a/bin/editor/editlog.c +++ /dev/null @@ -1,195 +0,0 @@ -#include -#include -#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 index e06ec70..0000000 --- a/bin/editor/exec.c +++ /dev/null @@ -1,130 +0,0 @@ -#define _XOPEN_SOURCE 700 -#include -#include -#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 index 3851751..0000000 --- a/bin/editor/gapbuf.c +++ /dev/null @@ -1,221 +0,0 @@ -#define _XOPEN_SOURCE 700 -#include - -#include -#include "dbc.h" -#include -#include -#include - -#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, ©, 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 index ba81ffa..0000000 --- a/bin/editor/job.c +++ /dev/null @@ -1,239 +0,0 @@ -#define _XOPEN_SOURCE 700 -#include -#include -#include -#include -#include -#include -#include -#include - -#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 index 0de287c..0000000 --- a/bin/editor/leap.c +++ /dev/null @@ -1,81 +0,0 @@ -#include -#include -#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 index 90e49c7..0000000 --- a/bin/editor/main.c +++ /dev/null @@ -1,765 +0,0 @@ -#define _XOPEN_SOURCE 700 -#include -#include -#include "dbc.h" -#include -#include - -#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 index ee9f126..0000000 --- a/bin/editor/mouse.c +++ /dev/null @@ -1,106 +0,0 @@ -#include -#include -#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 index 4206d29..0000000 --- a/bin/editor/range.c +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include - -#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 index c7583da..0000000 --- a/bin/editor/shortcuts.c +++ /dev/null @@ -1,229 +0,0 @@ -#include -#include - -#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 index f6fa72b..0000000 --- a/bin/editor/tide.h +++ /dev/null @@ -1,361 +0,0 @@ -#include - -/* 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 index 4314fe7..0000000 --- a/bin/editor/view.c +++ /dev/null @@ -1,635 +0,0 @@ -#include -#include -#include "dbc.h" -#include - -#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 index b74e79a..0000000 --- a/bin/editor/xpty.c +++ /dev/null @@ -1,278 +0,0 @@ -#define _XOPEN_SOURCE 700 -#include -#include -#include -#ifdef __linux__ - #include -#else - #include -#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)); -} diff --git a/bin/rules.mk b/bin/rules.mk index e9dbda0..f3df8a1 100644 --- a/bin/rules.mk +++ b/bin/rules.mk @@ -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 diff --git a/config.mk b/config.mk index 73ec366..7843047 100644 --- 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 -- 2.52.0