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