aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc André Tanner <mat@brain-dump.org>2015-10-26 09:23:48 +0100
committerMarc André Tanner <mat@brain-dump.org>2015-10-26 15:04:42 +0100
commite912a488cbb9065700316ff0f34cde183c90cbfc (patch)
tree870de5f63a4c1ce501b72897bd0d0f91f65ce4ca
parent5958d1e993298920deb02bf61eeb351ca768e3e4 (diff)
downloadvis-e912a488cbb9065700316ff0f34cde183c90cbfc.tar.gz
vis-e912a488cbb9065700316ff0f34cde183c90cbfc.tar.xz
vis: merge editor.c into vis.c
-rw-r--r--config.def.h14
-rw-r--r--editor.c453
-rw-r--r--editor.h339
-rw-r--r--ui-curses.c8
-rw-r--r--ui.h4
-rw-r--r--view.c2
-rw-r--r--vis.c690
-rw-r--r--vis.h240
8 files changed, 837 insertions, 913 deletions
diff --git a/config.def.h b/config.def.h
index 9d049fb..722dc07 100644
--- a/config.def.h
+++ b/config.def.h
@@ -534,7 +534,7 @@ static KeyAction vis_action[] = {
[VIS_ACTION_REDRAW] = {
"editor-redraw",
"Redraw current editor content",
- call, { .f = editor_draw }
+ call, { .f = vis_draw }
},
[VIS_ACTION_REPLACE_CHAR] = {
"replace-char",
@@ -654,12 +654,12 @@ static KeyAction vis_action[] = {
[VIS_ACTION_WINDOW_NEXT] = {
"window-next",
"Focus next window",
- call, { .f = editor_window_next }
+ call, { .f = vis_window_next }
},
[VIS_ACTION_WINDOW_PREV] = {
"window-prev",
"Focus previous window",
- call, { .f = editor_window_prev }
+ call, { .f = vis_window_prev }
},
[VIS_ACTION_OPEN_LINE_ABOVE] = {
"open-line-above",
@@ -1279,7 +1279,7 @@ static KeyBinding vis_mode_prompt[] = {
};
static void vis_mode_prompt_input(Vis *vis, const char *str, size_t len) {
- editor_insert_key(vis, str, len);
+ vis_insert_key(vis, str, len);
}
static void vis_mode_prompt_enter(Vis *vis, Mode *old) {
@@ -1289,7 +1289,7 @@ static void vis_mode_prompt_enter(Vis *vis, Mode *old) {
static void vis_mode_prompt_leave(Vis *vis, Mode *new) {
if (new->isuser)
- editor_prompt_hide(vis);
+ vis_prompt_hide(vis);
}
static KeyBinding vis_mode_insert[] = {
@@ -1328,7 +1328,7 @@ static void vis_mode_insert_input(Vis *vis, const char *str, size_t len) {
oldpos = pos + len;
action_reset(vis, &vis->action_prev);
vis->action_prev.op = &ops[OP_REPEAT_INSERT];
- editor_insert_key(vis, str, len);
+ vis_insert_key(vis, str, len);
}
static KeyBinding vis_mode_replace[] = {
@@ -1349,7 +1349,7 @@ static void vis_mode_replace_input(Vis *vis, const char *str, size_t len) {
oldpos = pos + len;
action_reset(vis, &vis->action_prev);
vis->action_prev.op = &ops[OP_REPEAT_REPLACE];
- editor_replace_key(vis, str, len);
+ vis_replace_key(vis, str, len);
}
/*
diff --git a/editor.c b/editor.c
deleted file mode 100644
index 8a17805..0000000
--- a/editor.c
+++ /dev/null
@@ -1,453 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <errno.h>
-#include "editor.h"
-#include "util.h"
-#include "text-motions.h"
-#include "text-util.h"
-
-static void file_free(Editor *ed, File *file);
-static File *file_new(Editor *ed, const char *filename);
-static Win *window_new_file(Editor *ed, File *file);
-static void window_free(Win *win);
-static void editor_windows_invalidate(Editor *ed, size_t start, size_t end);
-
-static void window_selection_changed(void *win, Filerange *sel) {
- File *file = ((Win*)win)->file;
- if (text_range_valid(sel)) {
- file->marks[MARK_SELECTION_START] = text_mark_set(file->text, sel->start);
- file->marks[MARK_SELECTION_END] = text_mark_set(file->text, sel->end);
- }
-}
-
-void editor_window_name(Win *win, const char *filename) {
- File *file = win->file;
- free((char*)file->name);
- file->name = filename ? strdup(filename) : NULL;
-
- if (filename) {
- for (Syntax *syn = win->editor->syntaxes; syn && syn->name; syn++) {
- if (!regexec(&syn->file_regex, filename, 0, NULL, 0)) {
- view_syntax_set(win->view, syn);
- break;
- }
- }
- }
-}
-
-void editor_windows_arrange(Editor *ed, enum UiLayout layout) {
- ed->ui->arrange(ed->ui, layout);
-}
-
-bool editor_window_reload(Win *win) {
- const char *name = win->file->name;
- if (!name)
- return false; /* can't reload unsaved file */
- /* temporarily unset file name, otherwise file_new returns the same File */
- win->file->name = NULL;
- File *file = file_new(win->editor, name);
- win->file->name = name;
- if (!file)
- return false;
- file_free(win->editor, win->file);
- win->file = file;
- win->ui->reload(win->ui, file);
- return true;
-}
-
-bool editor_window_split(Win *original) {
- Win *win = window_new_file(original->editor, original->file);
- if (!win)
- return false;
- win->file = original->file;
- win->file->refcount++;
- view_syntax_set(win->view, view_syntax_get(original->view));
- view_options_set(win->view, view_options_get(original->view));
- view_cursor_to(win->view, view_cursor_get(original->view));
- editor_draw(win->editor);
- return true;
-}
-
-void editor_resize(Editor *ed) {
- ed->ui->resize(ed->ui);
-}
-
-void editor_window_next(Editor *ed) {
- Win *sel = ed->win;
- if (!sel)
- return;
- ed->win = ed->win->next;
- if (!ed->win)
- ed->win = ed->windows;
- ed->ui->window_focus(ed->win->ui);
-}
-
-void editor_window_prev(Editor *ed) {
- Win *sel = ed->win;
- if (!sel)
- return;
- ed->win = ed->win->prev;
- if (!ed->win)
- for (ed->win = ed->windows; ed->win->next; ed->win = ed->win->next);
- ed->ui->window_focus(ed->win->ui);
-}
-
-static void editor_windows_invalidate(Editor *ed, size_t start, size_t end) {
- for (Win *win = ed->windows; win; win = win->next) {
- if (ed->win != win && ed->win->file == win->file) {
- Filerange view = view_viewport_get(win->view);
- if ((view.start <= start && start <= view.end) ||
- (view.start <= end && end <= view.end))
- view_draw(win->view);
- }
- }
- view_draw(ed->win->view);
-}
-
-int editor_tabwidth_get(Editor *ed) {
- return ed->tabwidth;
-}
-
-void editor_tabwidth_set(Editor *ed, int tabwidth) {
- if (tabwidth < 1 || tabwidth > 8)
- return;
- for (Win *win = ed->windows; win; win = win->next)
- view_tabwidth_set(win->view, tabwidth);
- ed->tabwidth = tabwidth;
-}
-
-bool editor_syntax_load(Editor *ed, Syntax *syntaxes) {
- bool success = true;
- ed->syntaxes = syntaxes;
-
- for (Syntax *syn = syntaxes; syn && syn->name; syn++) {
- if (regcomp(&syn->file_regex, syn->file, REG_EXTENDED|REG_NOSUB|REG_ICASE|REG_NEWLINE))
- success = false;
- for (int j = 0; j < LENGTH(syn->rules); j++) {
- SyntaxRule *rule = &syn->rules[j];
- if (!rule->rule)
- break;
- int cflags = REG_EXTENDED;
- if (!rule->multiline)
- cflags |= REG_NEWLINE;
- if (regcomp(&rule->regex, rule->rule, cflags))
- success = false;
- }
- }
-
- return success;
-}
-
-void editor_syntax_unload(Editor *ed) {
- for (Syntax *syn = ed->syntaxes; syn && syn->name; syn++) {
- regfree(&syn->file_regex);
- for (int j = 0; j < LENGTH(syn->rules); j++) {
- SyntaxRule *rule = &syn->rules[j];
- if (!rule->rule)
- break;
- regfree(&rule->regex);
- }
- }
-
- ed->syntaxes = NULL;
-}
-
-void editor_draw(Editor *ed) {
- ed->ui->draw(ed->ui);
-}
-
-void editor_update(Editor *ed) {
- ed->ui->update(ed->ui);
-}
-
-void editor_suspend(Editor *ed) {
- ed->ui->suspend(ed->ui);
-}
-
-bool editor_mode_map(Mode *mode, const char *name, KeyBinding *binding) {
- return map_put(mode->bindings, name, binding);
-}
-
-bool editor_mode_bindings(Mode *mode, KeyBinding **bindings) {
- if (!mode->bindings)
- mode->bindings = map_new();
- if (!mode->bindings)
- return false;
- bool success = true;
- for (KeyBinding *kb = *bindings; kb->key; kb++) {
- if (!editor_mode_map(mode, kb->key, kb))
- success = false;
- }
- return success;
-}
-
-bool editor_mode_unmap(Mode *mode, const char *name) {
- return map_delete(mode->bindings, name);
-}
-
-bool editor_action_register(Editor *ed, KeyAction *action) {
- if (!ed->actions)
- ed->actions = map_new();
- if (!ed->actions)
- return false;
- return map_put(ed->actions, action->name, action);
-}
-
-static void window_free(Win *win) {
- if (!win)
- return;
- Editor *ed = win->editor;
- if (ed && ed->ui)
- ed->ui->window_free(win->ui);
- view_free(win->view);
- ringbuf_free(win->jumplist);
- free(win);
-}
-
-static Win *window_new_file(Editor *ed, File *file) {
- Win *win = calloc(1, sizeof(Win));
- if (!win)
- return NULL;
- win->editor = ed;
- win->file = file;
- win->events = (ViewEvent) {
- .data = win,
- .selection = window_selection_changed,
- };
- win->jumplist = ringbuf_alloc(31);
- win->view = view_new(file->text, &win->events);
- win->ui = ed->ui->window_new(ed->ui, win->view, file);
- if (!win->jumplist || !win->view || !win->ui) {
- window_free(win);
- return NULL;
- }
- view_tabwidth_set(win->view, ed->tabwidth);
- if (ed->windows)
- ed->windows->prev = win;
- win->next = ed->windows;
- ed->windows = win;
- ed->win = win;
- ed->ui->window_focus(win->ui);
- return win;
-}
-
-static void file_free(Editor *ed, File *file) {
- if (!file)
- return;
- if (--file->refcount > 0)
- return;
-
- text_free(file->text);
- free((char*)file->name);
-
- if (file->prev)
- file->prev->next = file->next;
- if (file->next)
- file->next->prev = file->prev;
- if (ed->files == file)
- ed->files = file->next;
- free(file);
-}
-
-static File *file_new_text(Editor *ed, Text *text) {
- File *file = calloc(1, sizeof(*file));
- if (!file)
- return NULL;
- file->text = text;
- file->stat = text_stat(text);
- file->refcount++;
- if (ed->files)
- ed->files->prev = file;
- file->next = ed->files;
- ed->files = file;
- return file;
-}
-
-static File *file_new(Editor *ed, const char *filename) {
- if (filename) {
- /* try to detect whether the same file is already open in another window
- * TODO: do this based on inodes */
- for (File *file = ed->files; file; file = file->next) {
- if (file->name && strcmp(file->name, filename) == 0) {
- file->refcount++;
- return file;
- }
- }
- }
-
- Text *text = text_load(filename);
- if (!text && filename && errno == ENOENT)
- text = text_load(NULL);
- if (!text)
- return NULL;
-
- File *file = file_new_text(ed, text);
- if (!file) {
- text_free(text);
- return NULL;
- }
-
- if (filename)
- file->name = strdup(filename);
- return file;
-}
-
-bool editor_window_new(Editor *ed, const char *filename) {
- File *file = file_new(ed, filename);
- if (!file)
- return false;
- Win *win = window_new_file(ed, file);
- if (!win) {
- file_free(ed, file);
- return false;
- }
-
- editor_window_name(win, filename);
- editor_draw(ed);
-
- return true;
-}
-
-void editor_window_close(Win *win) {
- Editor *ed = win->editor;
- file_free(ed, win->file);
- if (win->prev)
- win->prev->next = win->next;
- if (win->next)
- win->next->prev = win->prev;
- if (ed->windows == win)
- ed->windows = win->next;
- if (ed->win == win)
- ed->win = win->next ? win->next : win->prev;
- if (ed->prompt_window == win)
- ed->prompt_window = NULL;
- window_free(win);
- if (ed->win)
- ed->ui->window_focus(ed->win->ui);
- editor_draw(ed);
-}
-
-Editor *editor_new(Ui *ui) {
- if (!ui)
- return NULL;
- Editor *ed = calloc(1, sizeof(Editor));
- if (!ed)
- return NULL;
- ed->ui = ui;
- ed->ui->init(ed->ui, ed);
- ed->tabwidth = 8;
- ed->expandtab = false;
- if (!(ed->prompt = calloc(1, sizeof(Win))))
- goto err;
- if (!(ed->prompt->file = calloc(1, sizeof(File))))
- goto err;
- if (!(ed->prompt->file->text = text_load(NULL)))
- goto err;
- if (!(ed->prompt->view = view_new(ed->prompt->file->text, NULL)))
- goto err;
- if (!(ed->prompt->ui = ed->ui->prompt_new(ed->ui, ed->prompt->view, ed->prompt->file)))
- goto err;
- if (!(ed->search_pattern = text_regex_new()))
- goto err;
- return ed;
-err:
- editor_free(ed);
- return NULL;
-}
-
-void editor_free(Editor *ed) {
- if (!ed)
- return;
- while (ed->windows)
- editor_window_close(ed->windows);
- file_free(ed, ed->prompt->file);
- window_free(ed->prompt);
- text_regex_free(ed->search_pattern);
- for (int i = 0; i < REG_LAST; i++)
- register_release(&ed->registers[i]);
- for (int i = 0; i < MACRO_LAST; i++)
- macro_release(&ed->macros[i]);
- editor_syntax_unload(ed);
- ed->ui->free(ed->ui);
- map_free(ed->cmds);
- map_free(ed->options);
- map_free(ed->actions);
- buffer_release(&ed->buffer_repeat);
- free(ed);
-}
-
-void editor_insert(Editor *ed, size_t pos, const char *data, size_t len) {
- text_insert(ed->win->file->text, pos, data, len);
- editor_windows_invalidate(ed, pos, pos + len);
-}
-
-void editor_insert_key(Editor *ed, const char *data, size_t len) {
- for (Cursor *c = view_cursors(ed->win->view); c; c = view_cursors_next(c)) {
- size_t pos = view_cursors_pos(c);
- editor_insert(ed, pos, data, len);
- view_cursors_scroll_to(c, pos + len);
- }
-}
-
-void editor_replace(Editor *ed, size_t pos, const char *data, size_t len) {
- size_t chars = 0;
- for (size_t i = 0; i < len; i++) {
- if (ISUTF8(data[i]))
- chars++;
- }
-
- Text *txt = ed->win->file->text;
- Iterator it = text_iterator_get(txt, pos);
- for (char c; chars-- > 0 && text_iterator_byte_get(&it, &c) && c != '\r' && c != '\n'; )
- text_iterator_char_next(&it, NULL);
-
- text_delete(txt, pos, it.pos - pos);
- editor_insert(ed, pos, data, len);
-}
-
-void editor_replace_key(Editor *ed, const char *data, size_t len) {
- for (Cursor *c = view_cursors(ed->win->view); c; c = view_cursors_next(c)) {
- size_t pos = view_cursors_pos(c);
- editor_replace(ed, pos, data, len);
- view_cursors_scroll_to(c, pos + len);
- }
-}
-
-void editor_delete(Editor *ed, size_t pos, size_t len) {
- text_delete(ed->win->file->text, pos, len);
- editor_windows_invalidate(ed, pos, pos + len);
-}
-
-void editor_prompt_show(Editor *ed, const char *title, const char *text) {
- if (ed->prompt_window)
- return;
- ed->prompt_window = ed->win;
- ed->win = ed->prompt;
- ed->prompt_type = title[0];
- ed->ui->prompt(ed->ui, title, text);
-}
-
-void editor_prompt_hide(Editor *ed) {
- if (!ed->prompt_window)
- return;
- ed->ui->prompt_hide(ed->ui);
- ed->win = ed->prompt_window;
- ed->prompt_window = NULL;
-}
-
-char *editor_prompt_get(Editor *ed) {
- return ed->ui->prompt_input(ed->ui);
-}
-
-void editor_info_show(Editor *ed, const char *msg, ...) {
- va_list ap;
- va_start(ap, msg);
- ed->ui->info(ed->ui, msg, ap);
- va_end(ap);
-}
-
-void editor_info_hide(Editor *ed) {
- ed->ui->info_hide(ed->ui);
-}
diff --git a/editor.h b/editor.h
deleted file mode 100644
index abb0b57..0000000
--- a/editor.h
+++ /dev/null
@@ -1,339 +0,0 @@
-#ifndef EDITOR_H
-#define EDITOR_H
-
-#include <signal.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <setjmp.h>
-
-typedef struct Editor Editor;
-typedef Editor Vis;
-typedef struct File File;
-typedef struct Win Win;
-
-#include "ui.h"
-#include "view.h"
-#include "register.h"
-#include "macro.h"
-#include "syntax.h"
-#include "ring-buffer.h"
-#include "map.h"
-#include "text-regex.h"
-
-typedef union {
- bool b;
- int i;
- const char *s;
- void (*w)(View*); /* generic window commands */
- void (*f)(Editor*); /* generic editor commands */
-} Arg;
-
-typedef struct {
- const char *name;
- const char *help;
- const char* (*func)(Vis*, const char *keys, const Arg*);
- /* returns a pointer to the first not consumed character in keys
- * or NULL if not enough input was available to complete the command */
- const Arg arg;
-
-} KeyAction;
-
-typedef struct {
- const char *key;
- KeyAction *action;
- const char *alias;
-} KeyBinding;
-
-/* a mode contains a set of key bindings which are currently valid.
- *
- * each mode can specify one parent mode which is consultated if a given key
- * is not found in the current mode. hence the modes form a tree which is
- * searched from the current mode up towards the root mode until a valid binding
- * is found.
- *
- * if no binding is found, mode->input(...) is called and the user entered
- * keys are passed as argument. this is used to change the document content.
- */
-typedef struct Mode Mode;
-struct Mode {
- Mode *parent; /* if no match is found in this mode, search will continue there */
- Map *bindings;
- KeyBinding *default_bindings;
- const char *name; /* descriptive, user facing name of the mode */
- const char *status; /* name displayed in the window status bar */
- const char *help; /* short description used by :help */
- bool isuser; /* whether this is a user or internal mode */
- void (*enter)(Vis*, Mode *old); /* called right before the mode becomes active */
- void (*leave)(Vis*, Mode *new); /* called right before the mode becomes inactive */
- void (*input)(Vis*, const char*, size_t); /* called whenever a key is not found in this mode and all its parent modes */
- void (*idle)(Vis*); /* called whenever a certain idle time i.e. without any user input elapsed */
- time_t idle_timeout; /* idle time in seconds after which the registered function will be called */
- bool visual; /* whether text selection is possible in this mode */
-};
-
-typedef struct {
- int count; /* how many times should the command be executed? */
- Register *reg; /* always non-NULL, set to a default register */
- Filerange range; /* which part of the file should be affected by the operator */
- size_t pos; /* at which byte from the start of the file should the operation start? */
- bool linewise; /* should the changes always affect whole lines? */
- const Arg *arg; /* arbitrary arguments */
-} OperatorContext;
-
-typedef struct {
- size_t (*func)(Vis*, Text*, OperatorContext*); /* operator logic, returns new cursor position */
-} Operator;
-
-typedef struct {
- /* TODO: merge types / use union to save space */
- size_t (*cur)(Cursor*); /* a movement based on current window content from view.h */
- size_t (*txt)(Text*, size_t pos); /* a movement form text-motions.h */
- size_t (*file)(Vis*, File*, size_t pos);
- size_t (*vis)(Vis*, Text*, size_t pos);
- size_t (*view)(Vis*, View*);
- size_t (*win)(Vis*, Win*, size_t pos);
- enum {
- LINEWISE = 1 << 0,
- CHARWISE = 1 << 1,
- INCLUSIVE = 1 << 2,
- EXCLUSIVE = 1 << 3,
- IDEMPOTENT = 1 << 4,
- JUMP = 1 << 5,
- } type;
- int count;
-} Movement;
-
-typedef struct {
- Filerange (*range)(Text*, size_t pos); /* a text object from text-objects.h */
- enum {
- INNER,
- OUTER,
- } type;
-} TextObject;
-
-typedef struct { /** collects all information until an operator is executed */
- int count;
- int type;
- const Operator *op;
- const Movement *movement;
- const TextObject *textobj;
- Register *reg;
- int mark;
- Arg arg;
-} Action;
-
-enum CmdOpt { /* option flags for command definitions */
- CMD_OPT_NONE, /* no option (default value) */
- CMD_OPT_FORCE, /* whether the command can be forced by appending '!' */
- CMD_OPT_ARGS, /* whether the command line should be parsed in to space
- * separated arguments to placed into argv, otherwise argv[1]
- * will contain the remaining command line unmodified */
-};
-
-typedef struct { /* command definitions for the ':'-prompt */
- const char *name[3]; /* name and optional alias for the command */
- /* command logic called with a NULL terminated array of arguments.
- * argv[0] will be the command name */
- bool (*cmd)(Vis*, Filerange*, enum CmdOpt opt, const char *argv[]);
- enum CmdOpt opt; /* command option flags */
-} Command;
-
-enum Reg {
- REG_a,
- REG_b,
- REG_c,
- REG_d,
- REG_e,
- REG_f,
- REG_g,
- REG_h,
- REG_i,
- REG_j,
- REG_k,
- REG_l,
- REG_m,
- REG_n,
- REG_o,
- REG_p,
- REG_q,
- REG_r,
- REG_s,
- REG_t,
- REG_u,
- REG_v,
- REG_w,
- REG_x,
- REG_y,
- REG_z,
- REG_DEFAULT,
- REG_LAST,
-};
-
-enum Mark {
- MARK_a,
- MARK_b,
- MARK_c,
- MARK_d,
- MARK_e,
- MARK_f,
- MARK_g,
- MARK_h,
- MARK_i,
- MARK_j,
- MARK_k,
- MARK_l,
- MARK_m,
- MARK_n,
- MARK_o,
- MARK_p,
- MARK_q,
- MARK_r,
- MARK_s,
- MARK_t,
- MARK_u,
- MARK_v,
- MARK_w,
- MARK_x,
- MARK_y,
- MARK_z,
- MARK_SELECTION_START,
- MARK_SELECTION_END,
- MARK_INVALID,
-};
-
-struct File {
- Text *text;
- const char *name;
- volatile sig_atomic_t truncated;
- bool is_stdin;
- struct stat stat;
- int refcount;
- Mark marks[MARK_INVALID];
- File *next, *prev;
-};
-
-typedef struct {
- time_t state; /* state of the text, used to invalidate change list */
- size_t index; /* #number of changes */
- size_t pos; /* where the current change occured */
-} ChangeList;
-
-struct Win {
- Editor *editor; /* editor instance to which this window belongs */
- UiWin *ui;
- File *file; /* file being displayed in this window */
- View *view; /* currently displayed part of underlying text */
- ViewEvent events;
- RingBuffer *jumplist; /* LRU jump management */
- ChangeList changelist; /* state for iterating through least recently changes */
- Win *prev, *next; /* neighbouring windows */
-};
-
-#define MACRO_LAST 26
-
-struct Editor {
- Ui *ui;
- File *files;
- Win *windows; /* list of windows */
- Win *win; /* currently active window */
- Syntax *syntaxes; /* NULL terminated array of syntax definitions */
- Register registers[REG_LAST]; /* register used for copy and paste */
- Macro macros[MACRO_LAST]; /* recorded macros */
- Macro *recording, *last_recording;/* currently and least recently recorded macro */
- Win *prompt; /* 1-line height window to get user input */
- Win *prompt_window; /* window which was focused before prompt was shown */
- char prompt_type; /* command ':' or search '/','?' prompt */
- Regex *search_pattern; /* last used search pattern */
- char search_char[8]; /* last used character to search for via 'f', 'F', 't', 'T' */
- int last_totill; /* last to/till movement used for ';' and ',' */
- int tabwidth; /* how many spaces should be used to display a tab */
- bool expandtab; /* whether typed tabs should be converted to spaces */
- bool autoindent; /* whether indentation should be copied from previous line on newline */
- Map *cmds; /* ":"-commands, used for unique prefix queries */
- Map *options; /* ":set"-options */
- Buffer buffer_repeat; /* holds data to repeat last insertion/replacement */
- Buffer input_queue; /* holds pending input keys */
-
- Action action; /* current action which is in progress */
- Action action_prev; /* last operator action used by the repeat '.' key */
- Mode *mode; /* currently active mode, used to search for keybindings */
- Mode *mode_prev; /* previsouly active user mode */
- Mode *mode_before_prompt; /* user mode which was active before entering prompt */
- volatile bool running; /* exit main loop once this becomes false */
- volatile sig_atomic_t cancel_filter; /* abort external command */
- volatile sig_atomic_t sigbus;
- sigjmp_buf sigbus_jmpbuf;
- Map *actions; /* built in special editor keys / commands */
-};
-
-Editor *editor_new(Ui*);
-void editor_free(Editor*);
-void editor_resize(Editor*);
-void editor_draw(Editor*);
-void editor_update(Editor*);
-void editor_suspend(Editor*);
-
-bool editor_mode_bindings(Mode*, KeyBinding**);
-bool editor_mode_map(Mode*, const char *name, KeyBinding*);
-bool editor_mode_unmap(Mode*, const char *name);
-
-bool editor_action_register(Editor*, KeyAction*);
-
-/* these function operate on the currently focused window but make sure
- * that all windows which show the affected region are redrawn too. */
-void editor_insert_key(Editor*, const char *data, size_t len);
-void editor_replace_key(Editor*, const char *data, size_t len);
-void editor_insert(Editor*, size_t pos, const char *data, size_t len);
-void editor_delete(Editor*, size_t pos, size_t len);
-void editor_replace(Editor*, size_t pos, const char *data, size_t len);
-
-/* set tabwidth (must be in range [1, 8], affects all windows */
-void editor_tabwidth_set(Editor*, int tabwidth);
-int editor_tabwidth_get(Editor*);
-
-/* load a set of syntax highlighting definitions which will be associated
- * to the underlying window based on the file type loaded.
- *
- * The parameter `syntaxes' has to point to a NULL terminated array.
- */
-bool editor_syntax_load(Editor*, Syntax *syntaxes);
-void editor_syntax_unload(Editor*);
-
-/* creates a new window, and loads the given file. if filename is NULL
- * an unamed / empty buffer is created. If the given file is already opened
- * in another window, share the underlying text that is changes will be
- * visible in both windows */
-bool editor_window_new(Editor*, const char *filename);
-/* reload the file currently displayed in the window from disk */
-bool editor_window_reload(Win*);
-void editor_window_close(Win*);
-/* split the given window. changes to the displayed text will be reflected
- * in both windows */
-bool editor_window_split(Win*);
-/* focus the next / previous window */
-void editor_window_next(Editor*);
-void editor_window_prev(Editor*);
-/* set the filename of the file displayed in this window */
-void editor_window_name(Win*, const char *filename);
-
-/* rearrange all windows either vertically or horizontally */
-void editor_windows_arrange(Editor*, enum UiLayout);
-/* display a user prompt with a certain title and default text */
-void editor_prompt_show(Editor*, const char *title, const char *text);
-/* hide the user prompt if it is currently shown */
-void editor_prompt_hide(Editor*);
-/* return the content of the command prompt in a malloc(3)-ed string
- * which the call site has to free. */
-char *editor_prompt_get(Editor*);
-/* replace the current command line content with the one given */
-void editor_prompt_set(Editor*, const char *line);
-
-/* display a message to the user */
-void editor_info_show(Editor*, const char *msg, ...);
-void editor_info_hide(Editor*);
-
-/* look up a curses color pair for the given combination of fore and
- * background color */
-short editor_color_get(short fg, short bg);
-
-#endif
diff --git a/ui-curses.c b/ui-curses.c
index 9e67e92..1e3c925 100644
--- a/ui-curses.c
+++ b/ui-curses.c
@@ -63,7 +63,7 @@ typedef struct UiCursesWin UiCursesWin;
typedef struct {
Ui ui; /* generic ui interface, has to be the first struct member */
- Editor *ed; /* editor instance to which this ui belongs */
+ Vis *vis; /* editor instance to which this ui belongs */
UiCursesWin *windows; /* all windows managed by this ui */
UiCursesWin *selwin; /* the currently selected layout */
char prompt_title[255]; /* prompt_title[0] == '\0' if prompt isn't shown */
@@ -606,7 +606,7 @@ static void ui_window_draw_status(UiWin *w) {
if (!win->winstatus)
return;
UiCurses *uic = win->ui;
- Editor *vis = uic->ed;
+ Vis *vis = uic->vis;
bool focused = uic->selwin == win;
const char *filename = win->file->name;
CursorPos pos = view_cursor_getpos(win->view);
@@ -925,9 +925,9 @@ static void ui_prompt_hide(Ui *ui) {
ui_resize_to(ui, uic->width, uic->height);
}
-static bool ui_init(Ui *ui, Editor *ed) {
+static bool ui_init(Ui *ui, Vis *vis) {
UiCurses *uic = (UiCurses*)ui;
- uic->ed = ed;
+ uic->vis = vis;
return true;
}
diff --git a/ui.h b/ui.h
index b1c35ed..0549db3 100644
--- a/ui.h
+++ b/ui.h
@@ -27,10 +27,10 @@ enum UiOption {
#include "text.h"
#include "view.h"
-#include "editor.h"
+#include "vis.h"
struct Ui {
- bool (*init)(Ui*, Editor*);
+ bool (*init)(Ui*, Vis*);
void (*free)(Ui*);
void (*resize)(Ui*);
UiWin* (*window_new)(Ui*, View*, File*);
diff --git a/view.c b/view.c
index 533061c..e7f9d4d 100644
--- a/view.c
+++ b/view.c
@@ -19,7 +19,7 @@
#include <ctype.h>
#include <errno.h>
#include <regex.h>
-#include "editor.h"
+#include "vis.h"
#include "view.h"
#include "syntax.h"
#include "text.h"
diff --git a/vis.c b/vis.c
index 6916947..d88c980 100644
--- a/vis.c
+++ b/vis.c
@@ -42,6 +42,478 @@
#include "map.h"
#include "libutf.h"
+typedef struct {
+ int count; /* how many times should the command be executed? */
+ Register *reg; /* always non-NULL, set to a default register */
+ Filerange range; /* which part of the file should be affected by the operator */
+ size_t pos; /* at which byte from the start of the file should the operation start? */
+ bool linewise; /* should the changes always affect whole lines? */
+ const Arg *arg; /* arbitrary arguments */
+} OperatorContext;
+
+struct Operator {
+ size_t (*func)(Vis*, Text*, OperatorContext*); /* operator logic, returns new cursor position */
+};
+
+struct Movement {
+ /* TODO: merge types / use union to save space */
+ size_t (*cur)(Cursor*); /* a movement based on current window content from view.h */
+ size_t (*txt)(Text*, size_t pos); /* a movement form text-motions.h */
+ size_t (*file)(Vis*, File*, size_t pos);
+ size_t (*vis)(Vis*, Text*, size_t pos);
+ size_t (*view)(Vis*, View*);
+ size_t (*win)(Vis*, Win*, size_t pos);
+ enum {
+ LINEWISE = 1 << 0,
+ CHARWISE = 1 << 1,
+ INCLUSIVE = 1 << 2,
+ EXCLUSIVE = 1 << 3,
+ IDEMPOTENT = 1 << 4,
+ JUMP = 1 << 5,
+ } type;
+ int count;
+};
+
+struct TextObject {
+ Filerange (*range)(Text*, size_t pos); /* a text object from text-objects.h */
+ enum {
+ INNER,
+ OUTER,
+ } type;
+};
+
+enum CmdOpt { /* option flags for command definitions */
+ CMD_OPT_NONE, /* no option (default value) */
+ CMD_OPT_FORCE, /* whether the command can be forced by appending '!' */
+ CMD_OPT_ARGS, /* whether the command line should be parsed in to space
+ * separated arguments to placed into argv, otherwise argv[1]
+ * will contain the remaining command line unmodified */
+};
+
+typedef struct { /* command definitions for the ':'-prompt */
+ const char *name[3]; /* name and optional alias for the command */
+ /* command logic called with a NULL terminated array of arguments.
+ * argv[0] will be the command name */
+ bool (*cmd)(Vis*, Filerange*, enum CmdOpt opt, const char *argv[]);
+ enum CmdOpt opt; /* command option flags */
+} Command;
+
+/** window / file handling */
+
+static void file_free(Vis *vis, File *file) {
+ if (!file)
+ return;
+ if (--file->refcount > 0)
+ return;
+
+ text_free(file->text);
+ free((char*)file->name);
+
+ if (file->prev)
+ file->prev->next = file->next;
+ if (file->next)
+ file->next->prev = file->prev;
+ if (vis->files == file)
+ vis->files = file->next;
+ free(file);
+}
+
+static File *file_new_text(Vis *vis, Text *text) {
+ File *file = calloc(1, sizeof(*file));
+ if (!file)
+ return NULL;
+ file->text = text;
+ file->stat = text_stat(text);
+ file->refcount++;
+ if (vis->files)
+ vis->files->prev = file;
+ file->next = vis->files;
+ vis->files = file;
+ return file;
+}
+
+static File *file_new(Vis *vis, const char *filename) {
+ if (filename) {
+ /* try to detect whether the same file is already open in another window
+ * TODO: do this based on inodes */
+ for (File *file = vis->files; file; file = file->next) {
+ if (file->name && strcmp(file->name, filename) == 0) {
+ file->refcount++;
+ return file;
+ }
+ }
+ }
+
+ Text *text = text_load(filename);
+ if (!text && filename && errno == ENOENT)
+ text = text_load(NULL);
+ if (!text)
+ return NULL;
+
+ File *file = file_new_text(vis, text);
+ if (!file) {
+ text_free(text);
+ return NULL;
+ }
+
+ if (filename)
+ file->name = strdup(filename);
+ return file;
+}
+
+static void window_name(Win *win, const char *filename) {
+ File *file = win->file;
+ if (filename != file->name) {
+ free((char*)file->name);
+ file->name = filename ? strdup(filename) : NULL;
+ }
+
+ if (filename) {
+ Vis *vis = win->editor;
+ for (Syntax *syn = vis->syntaxes; syn && syn->name; syn++) {
+ if (!regexec(&syn->file_regex, filename, 0, NULL, 0)) {
+ view_syntax_set(win->view, syn);
+ for (const char **opt = syn->settings; opt && *opt; opt++)
+ vis_cmd(vis, *opt);
+ break;
+ }
+ }
+ }
+}
+
+static void windows_invalidate(Vis *vis, size_t start, size_t end) {
+ for (Win *win = vis->windows; win; win = win->next) {
+ if (vis->win != win && vis->win->file == win->file) {
+ Filerange view = view_viewport_get(win->view);
+ if ((view.start <= start && start <= view.end) ||
+ (view.start <= end && end <= view.end))
+ view_draw(win->view);
+ }
+ }
+ view_draw(vis->win->view);
+}
+
+static void window_selection_changed(void *win, Filerange *sel) {
+ File *file = ((Win*)win)->file;
+ if (text_range_valid(sel)) {
+ file->marks[MARK_SELECTION_START] = text_mark_set(file->text, sel->start);
+ file->marks[MARK_SELECTION_END] = text_mark_set(file->text, sel->end);
+ }
+}
+
+static void windows_arrange(Vis *vis, enum UiLayout layout) {
+ vis->ui->arrange(vis->ui, layout);
+}
+
+static void window_free(Win *win) {
+ if (!win)
+ return;
+ Vis *vis = win->editor;
+ if (vis && vis->ui)
+ vis->ui->window_free(win->ui);
+ view_free(win->view);
+ ringbuf_free(win->jumplist);
+ free(win);
+}
+
+static Win *window_new_file(Vis *vis, File *file) {
+ Win *win = calloc(1, sizeof(Win));
+ if (!win)
+ return NULL;
+ win->editor = vis;
+ win->file = file;
+ win->events = (ViewEvent) {
+ .data = win,
+ .selection = window_selection_changed,
+ };
+ win->jumplist = ringbuf_alloc(31);
+ win->view = view_new(file->text, &win->events);
+ win->ui = vis->ui->window_new(vis->ui, win->view, file);
+ if (!win->jumplist || !win->view || !win->ui) {
+ window_free(win);
+ return NULL;
+ }
+ view_tabwidth_set(win->view, vis->tabwidth);
+ if (vis->windows)
+ vis->windows->prev = win;
+ win->next = vis->windows;
+ vis->windows = win;
+ vis->win = win;
+ vis->ui->window_focus(win->ui);
+ return win;
+}
+
+bool vis_window_reload(Win *win) {
+ const char *name = win->file->name;
+ if (!name)
+ return false; /* can't reload unsaved file */
+ /* temporarily unset file name, otherwise file_new returns the same File */
+ win->file->name = NULL;
+ File *file = file_new(win->editor, name);
+ win->file->name = name;
+ if (!file)
+ return false;
+ file_free(win->editor, win->file);
+ win->file = file;
+ win->ui->reload(win->ui, file);
+ return true;
+}
+
+bool vis_window_split(Win *original) {
+ Win *win = window_new_file(original->editor, original->file);
+ if (!win)
+ return false;
+ win->file = original->file;
+ win->file->refcount++;
+ view_syntax_set(win->view, view_syntax_get(original->view));
+ view_options_set(win->view, view_options_get(original->view));
+ view_cursor_to(win->view, view_cursor_get(original->view));
+ vis_draw(win->editor);
+ return true;
+}
+
+void vis_resize(Vis *vis) {
+ vis->ui->resize(vis->ui);
+}
+
+void vis_window_next(Vis *vis) {
+ Win *sel = vis->win;
+ if (!sel)
+ return;
+ vis->win = vis->win->next;
+ if (!vis->win)
+ vis->win = vis->windows;
+ vis->ui->window_focus(vis->win->ui);
+}
+
+void vis_window_prev(Vis *vis) {
+ Win *sel = vis->win;
+ if (!sel)
+ return;
+ vis->win = vis->win->prev;
+ if (!vis->win)
+ for (vis->win = vis->windows; vis->win->next; vis->win = vis->win->next);
+ vis->ui->window_focus(vis->win->ui);
+}
+
+static int tabwidth_get(Vis *vis) {
+ return vis->tabwidth;
+}
+
+static void tabwidth_set(Vis *vis, int tabwidth) {
+ if (tabwidth < 1 || tabwidth > 8)
+ return;
+ for (Win *win = vis->windows; win; win = win->next)
+ view_tabwidth_set(win->view, tabwidth);
+ vis->tabwidth = tabwidth;
+}
+
+bool vis_syntax_load(Vis *vis, Syntax *syntaxes) {
+ bool success = true;
+ vis->syntaxes = syntaxes;
+
+ for (Syntax *syn = syntaxes; syn && syn->name; syn++) {
+ if (regcomp(&syn->file_regex, syn->file, REG_EXTENDED|REG_NOSUB|REG_ICASE|REG_NEWLINE))
+ success = false;
+ for (int j = 0; j < LENGTH(syn->rules); j++) {
+ SyntaxRule *rule = &syn->rules[j];
+ if (!rule->rule)
+ break;
+ int cflags = REG_EXTENDED;
+ if (!rule->multiline)
+ cflags |= REG_NEWLINE;
+ if (regcomp(&rule->regex, rule->rule, cflags))
+ success = false;
+ }
+ }
+
+ return success;
+}
+
+void vis_syntax_unload(Vis *vis) {
+ for (Syntax *syn = vis->syntaxes; syn && syn->name; syn++) {
+ regfree(&syn->file_regex);
+ for (int j = 0; j < LENGTH(syn->rules); j++) {
+ SyntaxRule *rule = &syn->rules[j];
+ if (!rule->rule)
+ break;
+ regfree(&rule->regex);
+ }
+ }
+
+ vis->syntaxes = NULL;
+}
+
+void vis_draw(Vis *vis) {
+ vis->ui->draw(vis->ui);
+}
+
+void vis_update(Vis *vis) {
+ vis->ui->update(vis->ui);
+}
+
+void vis_suspend(Vis *vis) {
+ vis->ui->suspend(vis->ui);
+}
+
+bool vis_window_new(Vis *vis, const char *filename) {
+ File *file = file_new(vis, filename);
+ if (!file)
+ return false;
+ Win *win = window_new_file(vis, file);
+ if (!win) {
+ file_free(vis, file);
+ return false;
+ }
+
+ window_name(win, filename);
+ vis_draw(vis);
+
+ return true;
+}
+
+void vis_window_close(Win *win) {
+ Vis *vis = win->editor;
+ file_free(vis, win->file);
+ if (win->prev)
+ win->prev->next = win->next;
+ if (win->next)
+ win->next->prev = win->prev;
+ if (vis->windows == win)
+ vis->windows = win->next;
+ if (vis->win == win)
+ vis->win = win->next ? win->next : win->prev;
+ if (vis->prompt_window == win)
+ vis->prompt_window = NULL;
+ window_free(win);
+ if (vis->win)
+ vis->ui->window_focus(vis->win->ui);
+ vis_draw(vis);
+}
+
+Vis *vis_new0(Ui *ui) {
+ if (!ui)
+ return NULL;
+ Vis *vis = calloc(1, sizeof(Vis));
+ if (!vis)
+ return NULL;
+ vis->ui = ui;
+ vis->ui->init(vis->ui, vis);
+ vis->tabwidth = 8;
+ vis->expandtab = false;
+ if (!(vis->prompt = calloc(1, sizeof(Win))))
+ goto err;
+ if (!(vis->prompt->file = calloc(1, sizeof(File))))
+ goto err;
+ if (!(vis->prompt->file->text = text_load(NULL)))
+ goto err;
+ if (!(vis->prompt->view = view_new(vis->prompt->file->text, NULL)))
+ goto err;
+ if (!(vis->prompt->ui = vis->ui->prompt_new(vis->ui, vis->prompt->view, vis->prompt->file)))
+ goto err;
+ if (!(vis->search_pattern = text_regex_new()))
+ goto err;
+ return vis;
+err:
+ vis_free(vis);
+ return NULL;
+}
+
+void vis_free(Vis *vis) {
+ if (!vis)
+ return;
+ while (vis->windows)
+ vis_window_close(vis->windows);
+ file_free(vis, vis->prompt->file);
+ window_free(vis->prompt);
+ text_regex_free(vis->search_pattern);
+ for (int i = 0; i < LENGTH(vis->registers); i++)
+ register_release(&vis->registers[i]);
+ for (int i = 0; i < LENGTH(vis->macros); i++)
+ macro_release(&vis->macros[i]);
+ vis_syntax_unload(vis);
+ vis->ui->free(vis->ui);
+ map_free(vis->cmds);
+ map_free(vis->options);
+ map_free(vis->actions);
+ buffer_release(&vis->buffer_repeat);
+ free(vis);
+}
+
+void vis_insert(Vis *vis, size_t pos, const char *data, size_t len) {
+ text_insert(vis->win->file->text, pos, data, len);
+ windows_invalidate(vis, pos, pos + len);
+}
+
+void vis_insert_key(Vis *vis, const char *data, size_t len) {
+ for (Cursor *c = view_cursors(vis->win->view); c; c = view_cursors_next(c)) {
+ size_t pos = view_cursors_pos(c);
+ vis_insert(vis, pos, data, len);
+ view_cursors_scroll_to(c, pos + len);
+ }
+}
+
+void vis_replace(Vis *vis, size_t pos, const char *data, size_t len) {
+ size_t chars = 0;
+ for (size_t i = 0; i < len; i++) {
+ if (ISUTF8(data[i]))
+ chars++;
+ }
+
+ Text *txt = vis->win->file->text;
+ Iterator it = text_iterator_get(txt, pos);
+ for (char c; chars-- > 0 && text_iterator_byte_get(&it, &c) && c != '\r' && c != '\n'; )
+ text_iterator_char_next(&it, NULL);
+
+ text_delete(txt, pos, it.pos - pos);
+ vis_insert(vis, pos, data, len);
+}
+
+void vis_replace_key(Vis *vis, const char *data, size_t len) {
+ for (Cursor *c = view_cursors(vis->win->view); c; c = view_cursors_next(c)) {
+ size_t pos = view_cursors_pos(c);
+ vis_replace(vis, pos, data, len);
+ view_cursors_scroll_to(c, pos + len);
+ }
+}
+
+void vis_delete(Vis *vis, size_t pos, size_t len) {
+ text_delete(vis->win->file->text, pos, len);
+ windows_invalidate(vis, pos, pos + len);
+}
+
+void vis_prompt_show(Vis *vis, const char *title, const char *text) {
+ if (vis->prompt_window)
+ return;
+ vis->prompt_window = vis->win;
+ vis->win = vis->prompt;
+ vis->prompt_type = title[0];
+ vis->ui->prompt(vis->ui, title, text);
+}
+
+void vis_prompt_hide(Vis *vis) {
+ if (!vis->prompt_window)
+ return;
+ vis->ui->prompt_hide(vis->ui);
+ vis->win = vis->prompt_window;
+ vis->prompt_window = NULL;
+}
+
+char *vis_prompt_get(Vis *vis) {
+ return vis->ui->prompt_input(vis->ui);
+}
+
+void vis_info_show(Vis *vis, const char *msg, ...) {
+ va_list ap;
+ va_start(ap, msg);
+ vis->ui->info(vis->ui, msg, ap);
+ va_end(ap);
+}
+
+void vis_info_hide(Vis *vis) {
+ vis->ui->info_hide(vis->ui);
+}
+
/** operators */
static size_t op_change(Vis*, Text*, OperatorContext *c);
static size_t op_yank(Vis*, Text*, OperatorContext *c);
@@ -338,7 +810,7 @@ static bool cmd_new(Vis*, Filerange*, enum CmdOpt, const char *argv[]);
static bool cmd_vnew(Vis*, Filerange*, enum CmdOpt, const char *argv[]);
/* save the file displayed in the current window and close it */
static bool cmd_wq(Vis*, Filerange*, enum CmdOpt, const char *argv[]);
-/* save the file displayed in the current window if it was changed, then close the window */
+/* save the file displayed in the current window if it was changvis, then close the window */
static bool cmd_xit(Vis*, Filerange*, enum CmdOpt, const char *argv[]);
/* save the file displayed in the current window to the name given.
* do not change internal filname association. further :w commands
@@ -357,11 +829,50 @@ static bool cmd_help(Vis*, Filerange*, enum CmdOpt, const char *argv[]);
static void action_reset(Vis*, Action *a);
static void vis_mode_set(Vis*, Mode *new_mode);
-static bool vis_window_new(Vis*, const char *file);
-static bool vis_window_split(Win *win);
#include "config.h"
+static Mode *mode_get(Vis *vis, enum VisMode mode) {
+ if (mode < LENGTH(vis_modes))
+ return &vis_modes[mode];
+ return NULL;
+}
+
+static bool mode_map(Mode *mode, const char *name, KeyBinding *binding) {
+ return map_put(mode->bindings, name, binding);
+}
+
+bool vis_mode_map(Vis *vis, enum VisMode modeid, const char *name, KeyBinding *binding) {
+ Mode *mode = mode_get(vis, modeid);
+ return mode && map_put(mode->bindings, name, binding);
+}
+
+static bool mode_bindings(Mode *mode, KeyBinding **bindings) {
+ if (!mode->bindings)
+ mode->bindings = map_new();
+ if (!mode->bindings)
+ return false;
+ bool success = true;
+ for (KeyBinding *kb = *bindings; kb->key; kb++) {
+ if (!mode_map(mode, kb->key, kb))
+ success = false;
+ }
+ return success;
+}
+
+bool vis_mode_unmap(Vis *vis, enum VisMode modeid, const char *name) {
+ Mode *mode = mode_get(vis, modeid);
+ return mode && map_delete(mode->bindings, name);
+}
+
+bool vis_action_register(Vis *vis, KeyAction *action) {
+ if (!vis->actions)
+ vis->actions = map_new();
+ if (!vis->actions)
+ return false;
+ return map_put(vis->actions, action->name, action);
+}
+
static const char *getkey(Vis*);
static void action_do(Vis*, Action *a);
static bool exec_command(Vis *vis, char type, const char *cmdline);
@@ -431,7 +942,7 @@ static size_t op_put(Vis *vis, Text *txt, OperatorContext *c) {
static const char *expand_tab(Vis *vis) {
static char spaces[9];
- int tabwidth = editor_tabwidth_get(vis);
+ int tabwidth = tabwidth_get(vis);
tabwidth = MIN(tabwidth, LENGTH(spaces) - 1);
for (int i = 0; i < tabwidth; i++)
spaces[i] = ' ';
@@ -459,7 +970,7 @@ static size_t op_shift_right(Vis *vis, Text *txt, OperatorContext *c) {
static size_t op_shift_left(Vis *vis, Text *txt, OperatorContext *c) {
size_t pos = text_line_begin(txt, c->range.end), prev_pos;
- size_t tabwidth = editor_tabwidth_get(vis), tablen;
+ size_t tabwidth = tabwidth_get(vis), tablen;
/* if range ends at the begin of a line, skip line break */
if (pos == c->range.end)
@@ -563,7 +1074,7 @@ static size_t op_repeat_insert(Vis *vis, Text *txt, OperatorContext *c) {
static size_t op_repeat_replace(Vis *vis, Text *txt, OperatorContext *c) {
const char *data = vis->buffer_repeat.data;
size_t len = vis->buffer_repeat.len;
- editor_replace(vis, c->pos, data, len);
+ vis_replace(vis, c->pos, data, len);
return c->pos + len;
}
@@ -748,7 +1259,7 @@ static const char *macro_record(Vis *vis, const char *keys, const Arg *arg) {
enum VisMacro macro;
keys = key2macro(vis, keys, &macro);
vis_macro_record(vis, macro);
- editor_draw(vis);
+ vis_draw(vis);
return keys;
}
@@ -760,7 +1271,7 @@ static const char *macro_replay(Vis *vis, const char *keys, const Arg *arg) {
}
static const char *suspend(Vis *vis, const char *keys, const Arg *arg) {
- editor_suspend(vis);
+ vis_suspend(vis);
return keys;
}
@@ -881,7 +1392,7 @@ static const char *replace(Vis *vis, const char *keys, const Arg *arg) {
action_reset(vis, &vis->action_prev);
vis->action_prev.op = &ops[OP_REPEAT_REPLACE];
buffer_put(&vis->buffer_repeat, keys, len);
- editor_replace_key(vis, keys, len);
+ vis_replace_key(vis, keys, len);
text_snapshot(vis->win->file->text);
return next;
}
@@ -974,7 +1485,7 @@ static const char *reg(Vis *vis, const char *keys, const Arg *arg) {
}
static const char *key2mark(Vis *vis, const char *keys, int *mark) {
- *mark = MARK_INVALID;
+ *mark = VIS_MARK_INVALID;
if (!keys[0])
return NULL;
if (keys[0] >= 'a' && keys[0] <= 'z')
@@ -1007,7 +1518,7 @@ static const char *undo(Vis *vis, const char *keys, const Arg *arg) {
if (view_cursors_count(view) == 1)
view_cursor_to(view, pos);
/* redraw all windows in case some display the same file */
- editor_draw(vis);
+ vis_draw(vis);
}
return keys;
}
@@ -1019,7 +1530,7 @@ static const char *redo(Vis *vis, const char *keys, const Arg *arg) {
if (view_cursors_count(view) == 1)
view_cursor_to(view, pos);
/* redraw all windows in case some display the same file */
- editor_draw(vis);
+ vis_draw(vis);
}
return keys;
}
@@ -1029,7 +1540,7 @@ static const char *earlier(Vis *vis, const char *keys, const Arg *arg) {
if (pos != EPOS) {
view_cursor_to(vis->win->view, pos);
/* redraw all windows in case some display the same file */
- editor_draw(vis);
+ vis_draw(vis);
}
return keys;
}
@@ -1039,7 +1550,7 @@ static const char *later(Vis *vis, const char *keys, const Arg *arg) {
if (pos != EPOS) {
view_cursor_to(vis->win->view, pos);
/* redraw all windows in case some display the same file */
- editor_draw(vis);
+ vis_draw(vis);
}
return keys;
}
@@ -1056,26 +1567,26 @@ static const char *insert_register(Vis *vis, const char *keys, const Arg *arg) {
Register *reg = vis_register_get(vis, regid);
if (reg) {
int pos = view_cursor_get(vis->win->view);
- editor_insert(vis, pos, reg->data, reg->len);
+ vis_insert(vis, pos, reg->data, reg->len);
view_cursor_to(vis->win->view, pos + reg->len);
}
return keys;
}
static const char *prompt_search(Vis *vis, const char *keys, const Arg *arg) {
- editor_prompt_show(vis, arg->s, "");
+ vis_prompt_show(vis, arg->s, "");
vis_mode_switch(vis, VIS_MODE_PROMPT);
return keys;
}
static const char *prompt_cmd(Vis *vis, const char *keys, const Arg *arg) {
- editor_prompt_show(vis, ":", arg->s);
+ vis_prompt_show(vis, ":", arg->s);
vis_mode_switch(vis, VIS_MODE_PROMPT);
return keys;
}
static const char *prompt_enter(Vis *vis, const char *keys, const Arg *arg) {
- char *s = editor_prompt_get(vis);
+ char *s = vis_prompt_get(vis);
/* it is important to switch back to the previous mode, which hides
* the prompt and more importantly resets vis->win to the currently
* focused editor window *before* anything is executed which depends
@@ -1085,12 +1596,12 @@ static const char *prompt_enter(Vis *vis, const char *keys, const Arg *arg) {
if (s && *s && exec_command(vis, vis->prompt_type, s) && vis->running)
vis_mode_switch(vis, VIS_MODE_NORMAL);
free(s);
- editor_draw(vis);
+ vis_draw(vis);
return keys;
}
static const char *prompt_backspace(Vis *vis, const char *keys, const Arg *arg) {
- char *cmd = editor_prompt_get(vis);
+ char *cmd = vis_prompt_get(vis);
if (!cmd || !*cmd)
prompt_enter(vis, keys, NULL);
else
@@ -1161,7 +1672,7 @@ static const char *insert_verbatim(Vis *vis, const char *keys, const Arg *arg) {
if (len > 0) {
size_t pos = view_cursor_get(vis->win->view);
- editor_insert(vis, pos, buf, len);
+ vis_insert(vis, pos, buf, len);
view_cursor_to(vis->win->view, pos + len);
}
return keys;
@@ -1219,7 +1730,7 @@ static const char *window(Vis *vis, const char *keys, const Arg *arg) {
}
static const char *insert(Vis *vis, const char *keys, const Arg *arg) {
- editor_insert_key(vis, arg->s, arg->s ? strlen(arg->s) : 0);
+ vis_insert_key(vis, arg->s, arg->s ? strlen(arg->s) : 0);
return keys;
}
@@ -1242,7 +1753,7 @@ static void copy_indent_from_previous_line(Win *win) {
if (!buf)
return;
len = text_bytes_get(text, begin, len, buf);
- editor_insert_key(win->editor, buf, len);
+ vis_insert_key(win->editor, buf, len);
free(buf);
}
@@ -1431,7 +1942,7 @@ static void action_do(Vis *vis, Action *a) {
else if (vis->mode->visual)
vis_mode_switch(vis, VIS_MODE_NORMAL);
text_snapshot(txt);
- editor_draw(vis);
+ vis_draw(vis);
}
if (a != &vis->action_prev) {
@@ -1530,7 +2041,7 @@ static bool cmd_set(Vis *vis, Filerange *range, enum CmdOpt cmdopt, const char *
}
if (!argv[1]) {
- editor_info_show(vis, "Expecting: set option [value]");
+ vis_info_show(vis, "Expecting: set option [value]");
return false;
}
@@ -1549,14 +2060,14 @@ static bool cmd_set(Vis *vis, Filerange *range, enum CmdOpt cmdopt, const char *
if (!opt)
opt = map_closest(vis->options, argv[1]);
if (!opt) {
- editor_info_show(vis, "Unknown option: `%s'", argv[1]);
+ vis_info_show(vis, "Unknown option: `%s'", argv[1]);
return false;
}
switch (opt->type) {
case OPTION_TYPE_STRING:
if (!opt->optional && !argv[2]) {
- editor_info_show(vis, "Expecting string option value");
+ vis_info_show(vis, "Expecting string option value");
return false;
}
break;
@@ -1564,7 +2075,7 @@ static bool cmd_set(Vis *vis, Filerange *range, enum CmdOpt cmdopt, const char *
if (!argv[2]) {
arg.b = true;
} else if (!parse_bool(argv[2], &arg.b)) {
- editor_info_show(vis, "Expecting boolean option value not: `%s'", argv[2]);
+ vis_info_show(vis, "Expecting boolean option value not: `%s'", argv[2]);
return false;
}
if (invert)
@@ -1572,7 +2083,7 @@ static bool cmd_set(Vis *vis, Filerange *range, enum CmdOpt cmdopt, const char *
break;
case OPTION_TYPE_NUMBER:
if (!argv[2]) {
- editor_info_show(vis, "Expecting number");
+ vis_info_show(vis, "Expecting number");
return false;
}
/* TODO: error checking? long type */
@@ -1588,15 +2099,15 @@ static bool cmd_set(Vis *vis, Filerange *range, enum CmdOpt cmdopt, const char *
vis->autoindent = arg.b;
break;
case OPTION_TABWIDTH:
- editor_tabwidth_set(vis, arg.i);
+ tabwidth_set(vis, arg.i);
break;
case OPTION_SYNTAX:
if (!argv[2]) {
Syntax *syntax = view_syntax_get(vis->win->view);
if (syntax)
- editor_info_show(vis, "Syntax definition in use: `%s'", syntax->name);
+ vis_info_show(vis, "Syntax definition in use: `%s'", syntax->name);
else
- editor_info_show(vis, "No syntax definition in use");
+ vis_info_show(vis, "No syntax definition in use");
return true;
}
@@ -1610,11 +2121,11 @@ static bool cmd_set(Vis *vis, Filerange *range, enum CmdOpt cmdopt, const char *
if (parse_bool(argv[2], &arg.b) && !arg.b)
view_syntax_set(vis->win->view, NULL);
else
- editor_info_show(vis, "Unknown syntax definition: `%s'", argv[2]);
+ vis_info_show(vis, "Unknown syntax definition: `%s'", argv[2]);
break;
case OPTION_SHOW:
if (!argv[2]) {
- editor_info_show(vis, "Expecting: spaces, tabs, newlines");
+ vis_info_show(vis, "Expecting: spaces, tabs, newlines");
return false;
}
char *keys[] = { "spaces", "tabs", "newlines" };
@@ -1720,7 +2231,7 @@ static bool openfiles(Vis *vis, const char **files) {
return false;
errno = 0;
if (!vis_window_new(vis, file)) {
- editor_info_show(vis, "Could not open `%s' %s", file,
+ vis_info_show(vis, "Could not open `%s' %s", file,
errno ? strerror(errno) : "");
return false;
}
@@ -1741,7 +2252,7 @@ static bool is_view_closeable(Win *win) {
}
static void info_unsaved_changes(Vis *vis) {
- editor_info_show(vis, "No write since last change (add ! to override)");
+ vis_info_show(vis, "No write since last change (add ! to override)");
}
static bool cmd_edit(Vis *vis, Filerange *range, enum CmdOpt opt, const char *argv[]) {
@@ -1751,11 +2262,11 @@ static bool cmd_edit(Vis *vis, Filerange *range, enum CmdOpt opt, const char *ar
return false;
}
if (!argv[1])
- return editor_window_reload(oldwin);
+ return vis_window_reload(oldwin);
if (!openfiles(vis, &argv[1]))
return false;
if (vis->win != oldwin)
- editor_window_close(oldwin);
+ vis_window_close(oldwin);
return vis->win != oldwin;
}
@@ -1764,7 +2275,7 @@ static bool cmd_quit(Vis *vis, Filerange *range, enum CmdOpt opt, const char *ar
info_unsaved_changes(vis);
return false;
}
- editor_window_close(vis->win);
+ vis_window_close(vis->win);
if (!vis->windows)
quit(vis, NULL, NULL);
return true;
@@ -1787,7 +2298,7 @@ static bool cmd_bdelete(Vis *vis, Filerange *range, enum CmdOpt opt, const char
for (Win *next, *win = vis->windows; win; win = next) {
next = win->next;
if (win->file->text == txt)
- editor_window_close(win);
+ vis_window_close(win);
}
if (!vis->windows)
quit(vis, NULL, NULL);
@@ -1798,7 +2309,7 @@ static bool cmd_qall(Vis *vis, Filerange *range, enum CmdOpt opt, const char *ar
for (Win *next, *win = vis->windows; win; win = next) {
next = win->next;
if (!text_modified(vis->win->file->text) || (opt & CMD_OPT_FORCE))
- editor_window_close(win);
+ vis_window_close(win);
}
if (!vis->windows)
quit(vis, NULL, NULL);
@@ -1811,7 +2322,7 @@ static bool cmd_read(Vis *vis, Filerange *range, enum CmdOpt opt, const char *ar
char cmd[255];
if (!argv[1]) {
- editor_info_show(vis, "Filename or command expected");
+ vis_info_show(vis, "Filename or command expected");
return false;
}
@@ -1841,7 +2352,7 @@ static bool cmd_substitute(Vis *vis, Filerange *range, enum CmdOpt opt, const ch
static bool cmd_split(Vis *vis, Filerange *range, enum CmdOpt opt, const char *argv[]) {
enum UiOption options = view_options_get(vis->win->view);
- editor_windows_arrange(vis, UI_LAYOUT_HORIZONTAL);
+ windows_arrange(vis, UI_LAYOUT_HORIZONTAL);
if (!argv[1])
return vis_window_split(vis->win);
bool ret = openfiles(vis, &argv[1]);
@@ -1851,7 +2362,7 @@ static bool cmd_split(Vis *vis, Filerange *range, enum CmdOpt opt, const char *a
static bool cmd_vsplit(Vis *vis, Filerange *range, enum CmdOpt opt, const char *argv[]) {
enum UiOption options = view_options_get(vis->win->view);
- editor_windows_arrange(vis, UI_LAYOUT_VERTICAL);
+ windows_arrange(vis, UI_LAYOUT_VERTICAL);
if (!argv[1])
return vis_window_split(vis->win);
bool ret = openfiles(vis, &argv[1]);
@@ -1860,12 +2371,12 @@ static bool cmd_vsplit(Vis *vis, Filerange *range, enum CmdOpt opt, const char *
}
static bool cmd_new(Vis *vis, Filerange *range, enum CmdOpt opt, const char *argv[]) {
- editor_windows_arrange(vis, UI_LAYOUT_HORIZONTAL);
+ windows_arrange(vis, UI_LAYOUT_HORIZONTAL);
return vis_window_new(vis, NULL);
}
static bool cmd_vnew(Vis *vis, Filerange *range, enum CmdOpt opt, const char *argv[]) {
- editor_windows_arrange(vis, UI_LAYOUT_VERTICAL);
+ windows_arrange(vis, UI_LAYOUT_VERTICAL);
return vis_window_new(vis, NULL);
}
@@ -1887,32 +2398,32 @@ static bool cmd_write(Vis *vis, Filerange *range, enum CmdOpt opt, const char *a
if (strchr(argv[0], 'q')) {
ssize_t written = text_write_range(text, range, STDOUT_FILENO);
if (written == -1 || (size_t)written != text_range_size(range)) {
- editor_info_show(vis, "Can not write to stdout");
+ vis_info_show(vis, "Can not write to stdout");
return false;
}
/* make sure the file is marked as saved i.e. not modified */
text_save_range(text, range, NULL);
return true;
}
- editor_info_show(vis, "No filename given, use 'wq' to write to stdout");
+ vis_info_show(vis, "No filename given, use 'wq' to write to stdout");
return false;
}
- editor_info_show(vis, "Filename expected");
+ vis_info_show(vis, "Filename expected");
return false;
}
for (const char **name = &argv[1]; *name; name++) {
struct stat meta;
if (!(opt & CMD_OPT_FORCE) && file->stat.st_mtime && stat(*name, &meta) == 0 &&
file->stat.st_mtime < meta.st_mtime) {
- editor_info_show(vis, "WARNING: file has been changed since reading it");
+ vis_info_show(vis, "WARNING: file has been changed since reading it");
return false;
}
if (!text_save_range(text, range, *name)) {
- editor_info_show(vis, "Can't write `%s'", *name);
+ vis_info_show(vis, "Can't write `%s'", *name);
return false;
}
if (!file->name) {
- editor_window_name(vis->win, *name);
+ window_name(vis->win, *name);
file->name = vis->win->file->name;
}
if (strcmp(file->name, *name) == 0)
@@ -1923,7 +2434,7 @@ static bool cmd_write(Vis *vis, Filerange *range, enum CmdOpt opt, const char *a
static bool cmd_saveas(Vis *vis, Filerange *range, enum CmdOpt opt, const char *argv[]) {
if (cmd_write(vis, range, opt, argv)) {
- editor_window_name(vis->win, argv[1]);
+ window_name(vis->win, argv[1]);
vis->win->file->stat = text_stat(vis->win->file->text);
return true;
}
@@ -1965,7 +2476,7 @@ static bool cmd_filter(Vis *vis, Filerange *range, enum CmdOpt opt, const char *
close(pout[1]);
close(perr[0]);
close(perr[1]);
- editor_info_show(vis, "fork failure: %s", strerror(errno));
+ vis_info_show(vis, "fork failure: %s", strerror(errno));
return false;
} else if (pid == 0) { /* child i.e filter */
if (!interactive)
@@ -1983,7 +2494,7 @@ static bool cmd_filter(Vis *vis, Filerange *range, enum CmdOpt opt, const char *
execl("/bin/sh", "sh", "-c", argv[1], NULL);
else
execvp(argv[1], (char**)argv+1);
- editor_info_show(vis, "exec failure: %s", strerror(errno));
+ vis_info_show(vis, "exec failure: %s", strerror(errno));
exit(EXIT_FAILURE);
}
@@ -2024,7 +2535,7 @@ static bool cmd_filter(Vis *vis, Filerange *range, enum CmdOpt opt, const char *
do {
if (vis->cancel_filter) {
kill(-pid, SIGTERM);
- editor_info_show(vis, "Command cancelled");
+ vis_info_show(vis, "Command cancelled");
break;
}
@@ -2040,7 +2551,7 @@ static bool cmd_filter(Vis *vis, Filerange *range, enum CmdOpt opt, const char *
if (select(FD_SETSIZE, &rfds, &wfds, NULL, NULL) == -1) {
if (errno == EINTR)
continue;
- editor_info_show(vis, "Select failure");
+ vis_info_show(vis, "Select failure");
break;
}
@@ -2059,7 +2570,7 @@ static bool cmd_filter(Vis *vis, Filerange *range, enum CmdOpt opt, const char *
close(pin[1]);
pin[1] = -1;
if (len == -1)
- editor_info_show(vis, "Error writing to external command");
+ vis_info_show(vis, "Error writing to external command");
}
}
@@ -2073,7 +2584,7 @@ static bool cmd_filter(Vis *vis, Filerange *range, enum CmdOpt opt, const char *
close(pout[0]);
pout[0] = -1;
} else if (errno != EINTR && errno != EWOULDBLOCK) {
- editor_info_show(vis, "Error reading from filter stdout");
+ vis_info_show(vis, "Error reading from filter stdout");
close(pout[0]);
pout[0] = -1;
}
@@ -2088,7 +2599,7 @@ static bool cmd_filter(Vis *vis, Filerange *range, enum CmdOpt opt, const char *
close(perr[0]);
perr[0] = -1;
} else if (errno != EINTR && errno != EWOULDBLOCK) {
- editor_info_show(vis, "Error reading from filter stderr");
+ vis_info_show(vis, "Error reading from filter stderr");
close(pout[0]);
pout[0] = -1;
}
@@ -2116,11 +2627,11 @@ static bool cmd_filter(Vis *vis, Filerange *range, enum CmdOpt opt, const char *
if (!vis->cancel_filter) {
if (status == 0)
- editor_info_show(vis, "Command succeded");
+ vis_info_show(vis, "Command succeded");
else if (errmsg.len > 0)
- editor_info_show(vis, "Command failed: %s", errmsg.data);
+ vis_info_show(vis, "Command failed: %s", errmsg.data);
else
- editor_info_show(vis, "Command failed");
+ vis_info_show(vis, "Command failed");
}
vis->ui->terminal_restore(vis->ui);
@@ -2136,7 +2647,7 @@ static bool cmd_earlier_later(Vis *vis, Filerange *range, enum CmdOpt opt, const
errno = 0;
count = strtol(argv[1], &unit, 10);
if (errno || unit == argv[1] || count < 0) {
- editor_info_show(vis, "Invalid number");
+ vis_info_show(vis, "Invalid number");
return false;
}
@@ -2149,7 +2660,7 @@ static bool cmd_earlier_later(Vis *vis, Filerange *range, enum CmdOpt opt, const
case 'm': count *= 60; /* fall through */
case 's': break;
default:
- editor_info_show(vis, "Unknown time specifier (use: s,m,h or d)");
+ vis_info_show(vis, "Unknown time specifier (use: s,m,h or d)");
return false;
}
@@ -2170,7 +2681,7 @@ static bool cmd_earlier_later(Vis *vis, Filerange *range, enum CmdOpt opt, const
time_t state = text_state(txt);
char buf[32];
strftime(buf, sizeof buf, "State from %H:%M", localtime(&state));
- editor_info_show(vis, "%s", buf);
+ vis_info_show(vis, "%s", buf);
return pos != EPOS;
}
@@ -2348,7 +2859,7 @@ bool vis_cmd(Vis *vis, const char *cmdline) {
}
if (name != line) {
- editor_info_show(vis, "Invalid range\n");
+ vis_info_show(vis, "Invalid range\n");
free(line);
return false;
}
@@ -2374,7 +2885,7 @@ bool vis_cmd(Vis *vis, const char *cmdline) {
Command *cmd = lookup_cmd(vis, name);
if (!cmd) {
- editor_info_show(vis, "Not an editor command");
+ vis_info_show(vis, "Not an editor command");
free(line);
return false;
}
@@ -2429,29 +2940,6 @@ static bool exec_command(Vis *vis, char type, const char *cmd) {
return false;
}
-static void settings_apply(Vis *vis, const char **settings) {
- for (const char **opt = settings; opt && *opt; opt++)
- vis_cmd(vis, *opt);
-}
-
-static bool vis_window_new(Vis *vis, const char *file) {
- if (!editor_window_new(vis, file))
- return false;
- Syntax *s = view_syntax_get(vis->win->view);
- if (s)
- settings_apply(vis, s->settings);
- return true;
-}
-
-static bool vis_window_split(Win *win) {
- if (!editor_window_split(win))
- return false;
- Syntax *s = view_syntax_get(win->view);
- if (s)
- settings_apply(win->editor, s->settings);
- return true;
-}
-
void vis_die(Vis *vis, const char *msg, ...) {
va_list ap;
va_start(ap, msg);
@@ -2566,7 +3054,7 @@ static const char *getkey(Vis *vis) {
const char *key = vis->ui->getkey(vis->ui);
if (!key)
return NULL;
- editor_info_hide(vis);
+ vis_info_hide(vis);
if (vis->recording)
macro_append(vis->recording, key);
return key;
@@ -2652,7 +3140,7 @@ void vis_run(Vis *vis, int argc, char *argv[]) {
sigset_t emptyset;
sigemptyset(&emptyset);
- editor_draw(vis);
+ vis_draw(vis);
vis->running = true;
sigsetjmp(vis->sigbus_jmpbuf, 1);
@@ -2669,18 +3157,18 @@ void vis_run(Vis *vis, int argc, char *argv[]) {
if (win->file->truncated) {
free(name);
name = strdup(win->file->name);
- editor_window_close(win);
+ vis_window_close(win);
}
}
if (!vis->windows)
vis_die(vis, "WARNING: file `%s' truncated!\n", name ? name : "-");
else
- editor_info_show(vis, "WARNING: file `%s' truncated!\n", name ? name : "-");
+ vis_info_show(vis, "WARNING: file `%s' truncated!\n", name ? name : "-");
vis->sigbus = false;
free(name);
}
- editor_update(vis);
+ vis_update(vis);
idle.tv_sec = vis->mode->idle_timeout;
int r = pselect(1, &fds, NULL, NULL, timeout, &emptyset);
if (r == -1 && errno == EINTR)
@@ -2711,24 +3199,24 @@ void vis_run(Vis *vis, int argc, char *argv[]) {
}
Vis *vis_new(Ui *ui) {
- Vis *vis = editor_new(ui);
+ Vis *vis = vis_new0(ui);
if (!vis)
return NULL;
for (int i = 0; i < LENGTH(vis_modes); i++) {
Mode *mode = &vis_modes[i];
- if (!editor_mode_bindings(mode, &mode->default_bindings))
+ if (!mode_bindings(mode, &mode->default_bindings))
vis_die(vis, "Could not load bindings for mode: %s\n", mode->name);
}
vis->mode_prev = vis->mode = &vis_modes[VIS_MODE_NORMAL];
- if (!editor_syntax_load(vis, syntaxes))
+ if (!vis_syntax_load(vis, syntaxes))
vis_die(vis, "Could not load syntax highlighting definitions\n");
for (int i = 0; i < LENGTH(vis_action); i++) {
KeyAction *action = &vis_action[i];
- if (!editor_action_register(vis, action))
+ if (!vis_action_register(vis, action))
vis_die(vis, "Could not register action: %s\n", action->name);
}
@@ -2812,7 +3300,7 @@ void vis_motion(Vis *vis, enum VisMotion motion, ...) {
case MOVE_MARK_LINE:
{
int mark = va_arg(ap, int);
- if (MARK_a <= mark && mark < MARK_INVALID)
+ if (MARK_a <= mark && mark < VIS_MARK_INVALID)
vis->action.mark = mark;
else
goto out;
diff --git a/vis.h b/vis.h
index 6a3b710..71a0b78 100644
--- a/vis.h
+++ b/vis.h
@@ -1,13 +1,101 @@
#ifndef VIS_H
#define VIS_H
+#include <signal.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <setjmp.h>
+
+typedef struct Vis Vis;
+typedef struct File File;
+typedef struct Win Win;
+
#include "ui.h"
-#include "editor.h"
+#include "view.h"
+#include "register.h"
+#include "macro.h"
+#include "syntax.h"
+#include "ring-buffer.h"
+#include "map.h"
+#include "text-regex.h"
+
+
+typedef union {
+ bool b;
+ int i;
+ const char *s;
+ void (*w)(View*); /* generic window commands */
+ void (*f)(Vis*); /* generic editor commands */
+} Arg;
+
+typedef struct {
+ const char *name;
+ const char *help;
+ const char* (*func)(Vis*, const char *keys, const Arg*);
+ /* returns a pointer to the first not consumed character in keys
+ * or NULL if not enough input was available to complete the command */
+ const Arg arg;
+
+} KeyAction;
+
+typedef struct {
+ const char *key;
+ KeyAction *action;
+ const char *alias;
+} KeyBinding;
+
-typedef Editor Vis;
Vis *vis_new(Ui*);
-#define vis_free editor_free
+void vis_free(Vis*);
+void vis_resize(Vis*);
+void vis_draw(Vis*);
+void vis_update(Vis*);
+void vis_suspend(Vis*);
+
+/* load a set of syntax highlighting definitions which will be associated
+ * to the underlying window based on the file type loaded.
+ *
+ * The parameter `syntaxes' has to point to a NULL terminated array.
+ */
+bool vis_syntax_load(Vis*, Syntax *syntaxes);
+void vis_syntax_unload(Vis*);
+
+/* creates a new window, and loads the given file. if filename is NULL
+ * an unamed / empty buffer is created. If the given file is already opened
+ * in another window, share the underlying text that is changes will be
+ * visible in both windows */
+bool vis_window_new(Vis*, const char *filename);
+/* reload the file currently displayed in the window from disk */
+bool vis_window_reload(Win*);
+void vis_window_close(Win*);
+/* split the given window. changes to the displayed text will be reflected
+ * in both windows */
+bool vis_window_split(Win*);
+/* focus the next / previous window */
+void vis_window_next(Vis*);
+void vis_window_prev(Vis*);
+/* display a user prompt with a certain title and default text */
+void vis_prompt_show(Vis*, const char *title, const char *text);
+/* hide the user prompt if it is currently shown */
+void vis_prompt_hide(Vis*);
+/* return the content of the command prompt in a malloc(3)-ed string
+ * which the call site has to free. */
+char *vis_prompt_get(Vis*);
+/* replace the current command line content with the one given */
+void vis_prompt_set(Vis*, const char *line);
+
+/* display a message to the user */
+void vis_info_show(Vis*, const char *msg, ...);
+void vis_info_hide(Vis*);
+
+/* these function operate on the currently focused window but make sure
+ * that all windows which show the affected region are redrawn too. */
+void vis_insert_key(Vis*, const char *data, size_t len);
+void vis_replace_key(Vis*, const char *data, size_t len);
+void vis_insert(Vis*, size_t pos, const char *data, size_t len);
+void vis_delete(Vis*, size_t pos, size_t len);
+void vis_replace(Vis*, size_t pos, const char *data, size_t len);
void vis_run(Vis*, int argc, char *argv[]);
void vis_die(Vis*, const char *msg, ...);
@@ -29,6 +117,10 @@ enum VisMode {
};
void vis_mode_switch(Vis*, enum VisMode);
+bool vis_mode_map(Vis*, enum VisMode, const char *name, KeyBinding*);
+bool vis_mode_unmap(Vis*, enum VisMode, const char *name);
+
+bool vis_action_register(Vis*, KeyAction*);
enum VisOperator {
OP_DELETE,
@@ -162,15 +254,45 @@ bool vis_macro_record_stop(Vis*);
bool vis_macro_replay(Vis*, enum VisMacro);
enum VisMark {
- /* TODO: temporary */
+ MARK_a,
+ MARK_b,
+ MARK_c,
+ MARK_d,
+ MARK_e,
+ MARK_f,
+ MARK_g,
+ MARK_h,
+ MARK_i,
+ MARK_j,
+ MARK_k,
+ MARK_l,
+ MARK_m,
+ MARK_n,
+ MARK_o,
+ MARK_p,
+ MARK_q,
+ MARK_r,
+ MARK_s,
+ MARK_t,
+ MARK_u,
+ MARK_v,
+ MARK_w,
+ MARK_x,
+ MARK_y,
+ MARK_z,
+ MARK_SELECTION_START,
+ MARK_SELECTION_END,
VIS_MARK_INVALID,
};
void vis_mark_set(Vis*, enum VisMark mark, size_t pos);
enum VisRegister {
- /* TODO: temporary */
- VIS_REGISTER_INVALID = REG_LAST,
+ REG_a, REG_b, REG_c, REG_d, REG_e, REG_f, REG_g, REG_h, REG_i,
+ REG_j, REG_k, REG_l, REG_m, REG_n, REG_o, REG_p, REG_q, REG_r,
+ REG_s, REG_t, REG_u, REG_v, REG_w, REG_x, REG_y, REG_z,
+ REG_DEFAULT,
+ VIS_REGISTER_INVALID,
};
void vis_register_set(Vis*, enum VisRegister);
@@ -186,4 +308,110 @@ const char *vis_keys(Vis*, const char *input);
bool vis_signal_handler(Vis*, int signum, const siginfo_t *siginfo,
const void *context);
+/* TODO: temporary */
+typedef struct Operator Operator;
+typedef struct Movement Movement;
+typedef struct TextObject TextObject;
+
+typedef struct { /** collects all information until an operator is executed */
+ int count;
+ enum VisMotionType type;
+ const Operator *op;
+ const Movement *movement;
+ const TextObject *textobj;
+ Register *reg;
+ enum VisMark mark;
+ Arg arg;
+} Action;
+
+/* a mode contains a set of key bindings which are currently valid.
+ *
+ * each mode can specify one parent mode which is consultated if a given key
+ * is not found in the current mode. hence the modes form a tree which is
+ * searched from the current mode up towards the root mode until a valid binding
+ * is found.
+ *
+ * if no binding is found, mode->input(...) is called and the user entered
+ * keys are passed as argument. this is used to change the document content.
+ */
+typedef struct Mode Mode;
+struct Mode {
+ Mode *parent; /* if no match is found in this mode, search will continue there */
+ Map *bindings;
+ KeyBinding *default_bindings;
+ const char *name; /* descriptive, user facing name of the mode */
+ const char *status; /* name displayed in the window status bar */
+ const char *help; /* short description used by :help */
+ bool isuser; /* whether this is a user or internal mode */
+ void (*enter)(Vis*, Mode *old); /* called right before the mode becomes active */
+ void (*leave)(Vis*, Mode *new); /* called right before the mode becomes inactive */
+ void (*input)(Vis*, const char*, size_t); /* called whenever a key is not found in this mode and all its parent modes */
+ void (*idle)(Vis*); /* called whenever a certain idle time i.e. without any user input elapsed */
+ time_t idle_timeout; /* idle time in seconds after which the registered function will be called */
+ bool visual; /* whether text selection is possible in this mode */
+};
+
+struct File {
+ Text *text;
+ const char *name;
+ volatile sig_atomic_t truncated;
+ bool is_stdin;
+ struct stat stat;
+ int refcount;
+ Mark marks[VIS_MARK_INVALID];
+ File *next, *prev;
+};
+
+typedef struct {
+ time_t state; /* state of the text, used to invalidate change list */
+ size_t index; /* #number of changes */
+ size_t pos; /* where the current change occured */
+} ChangeList;
+
+struct Win {
+ Vis *editor; /* editor instance to which this window belongs */
+ UiWin *ui;
+ File *file; /* file being displayed in this window */
+ View *view; /* currently displayed part of underlying text */
+ ViewEvent events;
+ RingBuffer *jumplist; /* LRU jump management */
+ ChangeList changelist; /* state for iterating through least recently changes */
+ Win *prev, *next; /* neighbouring windows */
+};
+
+struct Vis {
+ Ui *ui;
+ File *files;
+ Win *windows; /* list of windows */
+ Win *win; /* currently active window */
+ Syntax *syntaxes; /* NULL terminated array of syntax definitions */
+ Register registers[VIS_REGISTER_INVALID]; /* register used for copy and paste */
+ Macro macros[VIS_MACRO_INVALID]; /* recorded macros */
+ Macro *recording, *last_recording;/* currently and least recently recorded macro */
+ Win *prompt; /* 1-line height window to get user input */
+ Win *prompt_window; /* window which was focused before prompt was shown */
+ char prompt_type; /* command ':' or search '/','?' prompt */
+ Regex *search_pattern; /* last used search pattern */
+ char search_char[8]; /* last used character to search for via 'f', 'F', 't', 'T' */
+ int last_totill; /* last to/till movement used for ';' and ',' */
+ int tabwidth; /* how many spaces should be used to display a tab */
+ bool expandtab; /* whether typed tabs should be converted to spaces */
+ bool autoindent; /* whether indentation should be copied from previous line on newline */
+ Map *cmds; /* ":"-commands, used for unique prefix queries */
+ Map *options; /* ":set"-options */
+ Buffer buffer_repeat; /* holds data to repeat last insertion/replacement */
+ Buffer input_queue; /* holds pending input keys */
+
+ Action action; /* current action which is in progress */
+ Action action_prev; /* last operator action used by the repeat '.' key */
+ Mode *mode; /* currently active mode, used to search for keybindings */
+ Mode *mode_prev; /* previsouly active user mode */
+ Mode *mode_before_prompt; /* user mode which was active before entering prompt */
+ volatile bool running; /* exit main loop once this becomes false */
+ volatile sig_atomic_t cancel_filter; /* abort external command */
+ volatile sig_atomic_t sigbus;
+ sigjmp_buf sigbus_jmpbuf;
+ Map *actions; /* built in special editor keys / commands */
+};
+
#endif