---
config.def.h | 8 +
editor.c | 5 +-
vis.c | 482 +---------------------------------------------------------
vis.h | 486 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 498 insertions(+), 483 deletions(-)
create mode 100644 vis.h
diff --git a/config.def.h b/config.def.h
index aac28a8..cc6192d 100644
--- a/config.def.h
+++ b/config.def.h
_AT_@ -1,3 +1,7 @@
+#ifndef CONFIG_H
+#define CONFIG_H
+#include "vis.h"
+
/** start by reading from the top of vis.c up until config.h is included */
#define DEFAULT_TERM "xterm" /* default term to use if $TERM isn't set */
/* macros used to specify keys for key bindings */
_AT_@ -12,6 +16,9 @@
{ { NONE(127) }, (func), { .name = (arg) } }, \
{ { CONTROL('B') }, (func), { .name = (arg) } }
+#define TABWIDTH 8
+#define EXPANDTAB false
+
/* 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
_AT_@ -1208,3 +1215,4 @@ static Syntax syntaxes[] = {{
},{
/* empty last element, array terminator */
}};
+#endif
diff --git a/editor.c b/editor.c
index ef59242..902e383 100644
--- a/editor.c
+++ b/editor.c
_AT_@ -4,6 +4,7 @@
#include <unistd.h>
#include "editor.h"
#include "util.h"
+#include "config.h"
#ifdef NCURSES_VERSION
# ifndef NCURSES_EXT_COLORS
_AT_@ -441,8 +442,8 @@ Editor *editor_new(int width, int height) {
goto err;
ed->width = width;
ed->height = height;
- ed->tabwidth = 8;
- ed->expandtab = false;
+ ed->tabwidth = TABWIDTH;
+ ed->expandtab = EXPANDTAB;
ed->windows_arrange = windows_arrange_horizontal;
return ed;
err:
diff --git a/vis.c b/vis.c
index 7ccfa22..bad309e 100644
--- a/vis.c
+++ b/vis.c
_AT_@ -40,487 +40,7 @@ int ESCDELAY;
# define set_escdelay(d) (ESCDELAY = (d))
#endif
-typedef union {
- bool b;
- int i;
- const char *s;
- void (*w)(Win*); /* generic window commands */
- void (*f)(Editor*); /* generic editor commands */
-} Arg;
-
-typedef struct {
- char str[6]; /* UTF8 character or terminal escape code */
- int code; /* curses KEY_* constant */
-} Key;
-
-#define MAX_KEYS 2
-typedef Key KeyCombo[MAX_KEYS];
-
-typedef struct {
- KeyCombo key;
- void (*func)(const Arg *arg);
- const Arg arg;
-} KeyBinding;
-
-typedef struct Mode Mode;
-struct Mode {
- Mode *parent; /* if no match is found in this mode, search will continue there */
- KeyBinding *bindings; /* NULL terminated array of keybindings for this mode */
- const char *name; /* descriptive, user facing name of the mode */
- bool isuser; /* whether this is a user or internal mode */
- bool common_prefix; /* whether the first key in this mode is always the same */
- void (*enter)(Mode *old); /* called right before the mode becomes active */
- void (*leave)(Mode *new); /* called right before the mode becomes inactive */
- bool (*unknown)(KeyCombo); /* called whenever a key combination is not found in this mode,
- the return value determines whether parent modes will be searched */
- void (*input)(const char*, size_t); /* called whenever a key is not found in this mode and all its parent modes */
- void (*idle)(void); /* 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 {
- char *name; /* is used to match against argv[0] to enable this config */
- Mode *mode; /* default mode in which the editor should start in */
- void (*statusbar)(EditorWin*); /* routine which is called whenever the cursor is moved within a window */
- bool (*keypress)(Key*); /* called before any other keybindings are checked,
- * return value decides whether key should be ignored */
-} Config;
-
-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 {
- void (*func)(OperatorContext*); /* function implementing the operator logic */
-} Operator;
-
-typedef struct {
- size_t (*cmd)(const Arg*); /* a custom movement based on user input from vis.c */
- size_t (*win)(Win*); /* a movement based on current window content from window.h */
- size_t (*txt)(Text*, size_t pos); /* a movement form text-motions.h */
- 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;
- bool linewise;
- Operator *op;
- Movement *movement;
- TextObject *textobj;
- Register *reg;
- MarkIntern mark;
- Key key;
- Arg arg;
-} Action;
-
-typedef struct { /* command definitions for the ':'-prompt */
- const char *name; /* regular expression pattern to match command */
- bool (*cmd)(Filerange*, const char *argv[]);
- /* command logic called with a NULL terminated array
- * of arguments. argv[0] will be the command name,
- * as matched by the regex. */
- bool args; /* whether argv should be populated with words
- * separated by spaces. if false, argv[1] will
- * contain the remaining command line unmodified */
- regex_t regex; /* compiled form of the pattern in 'name' */
-} Command;
-
-/** global variables */
-static volatile bool running = true; /* exit main loop once this becomes false */
-static Editor *vis; /* global editor instance, keeps track of all windows etc. */
-static Mode *mode; /* currently active mode, used to search for keybindings */
-static Mode *mode_prev; /* previsouly active user mode */
-static Mode *mode_before_prompt; /* user mode which was active before entering prompt */
-static Action action; /* current action which is in progress */
-static Action action_prev; /* last operator action used by the repeat '.' key */
-static Buffer buffer_repeat;/* repeat last modification i.e. insertion/replacement */
-
-/** operators */
-static void op_change(OperatorContext *c);
-static void op_yank(OperatorContext *c);
-static void op_put(OperatorContext *c);
-static void op_delete(OperatorContext *c);
-static void op_shift_right(OperatorContext *c);
-static void op_shift_left(OperatorContext *c);
-static void op_case_change(OperatorContext *c);
-static void op_join(OperatorContext *c);
-static void op_repeat_insert(OperatorContext *c);
-static void op_repeat_replace(OperatorContext *c);
-
-/* these can be passed as int argument to operator(&(const Arg){ .i = OP_*}) */
-enum {
- OP_DELETE,
- OP_CHANGE,
- OP_YANK,
- OP_PUT,
- OP_SHIFT_RIGHT,
- OP_SHIFT_LEFT,
- OP_CASE_CHANGE,
- OP_JOIN,
- OP_REPEAT_INSERT,
- OP_REPEAT_REPLACE,
-};
-
-static Operator ops[] = {
- [OP_DELETE] = { op_delete },
- [OP_CHANGE] = { op_change },
- [OP_YANK] = { op_yank },
- [OP_PUT] = { op_put },
- [OP_SHIFT_RIGHT] = { op_shift_right },
- [OP_SHIFT_LEFT] = { op_shift_left },
- [OP_CASE_CHANGE] = { op_case_change },
- [OP_JOIN] = { op_join },
- [OP_REPEAT_INSERT] = { op_repeat_insert },
- [OP_REPEAT_REPLACE] = { op_repeat_replace },
-};
-
-#define PAGE INT_MAX
-#define PAGE_HALF (INT_MAX-1)
-
-/* these can be passed as int argument to movement(&(const Arg){ .i = MOVE_* }) */
-enum {
- MOVE_SCREEN_LINE_UP,
- MOVE_SCREEN_LINE_DOWN,
- MOVE_SCREEN_LINE_BEGIN,
- MOVE_SCREEN_LINE_MIDDLE,
- MOVE_SCREEN_LINE_END,
- MOVE_LINE_PREV,
- MOVE_LINE_BEGIN,
- MOVE_LINE_START,
- MOVE_LINE_FINISH,
- MOVE_LINE_LASTCHAR,
- MOVE_LINE_END,
- MOVE_LINE_NEXT,
- MOVE_LINE,
- MOVE_COLUMN,
- MOVE_CHAR_PREV,
- MOVE_CHAR_NEXT,
- MOVE_WORD_START_NEXT,
- MOVE_WORD_END_PREV,
- MOVE_WORD_END_NEXT,
- MOVE_WORD_START_PREV,
- MOVE_LONGWORD_START_PREV,
- MOVE_LONGWORD_START_NEXT,
- MOVE_LONGWORD_END_PREV,
- MOVE_LONGWORD_END_NEXT,
- MOVE_SENTENCE_PREV,
- MOVE_SENTENCE_NEXT,
- MOVE_PARAGRAPH_PREV,
- MOVE_PARAGRAPH_NEXT,
- MOVE_BRACKET_MATCH,
- MOVE_LEFT_TO,
- MOVE_RIGHT_TO,
- MOVE_LEFT_TILL,
- MOVE_RIGHT_TILL,
- MOVE_FILE_BEGIN,
- MOVE_FILE_END,
- MOVE_MARK,
- MOVE_MARK_LINE,
- MOVE_SEARCH_WORD_FORWARD,
- MOVE_SEARCH_WORD_BACKWARD,
- MOVE_SEARCH_FORWARD,
- MOVE_SEARCH_BACKWARD,
- MOVE_WINDOW_LINE_TOP,
- MOVE_WINDOW_LINE_MIDDLE,
- MOVE_WINDOW_LINE_BOTTOM,
-};
-
-/** movements which can be used besides the one in text-motions.h and window.h */
-
-/* search in forward direction for the word under the cursor */
-static size_t search_word_forward(const Arg *arg);
-/* search in backward direction for the word under the cursor */
-static size_t search_word_backward(const Arg *arg);
-/* search again for the last used search pattern */
-static size_t search_forward(const Arg *arg);
-static size_t search_backward(const Arg *arg);
-/* goto action.mark */
-static size_t mark_goto(const Arg *arg);
-/* goto first non-blank char on line pointed by action.mark */
-static size_t mark_line_goto(const Arg *arg);
-/* goto to next occurence of action.key to the right */
-static size_t to(const Arg *arg);
-/* goto to position before next occurence of action.key to the right */
-static size_t till(const Arg *arg);
-/* goto to next occurence of action.key to the left */
-static size_t to_left(const Arg *arg);
-/* goto to position after next occurence of action.key to the left */
-static size_t till_left(const Arg *arg);
-/* goto line number action.count */
-static size_t line(const Arg *arg);
-/* goto to byte action.count on current line */
-static size_t column(const Arg *arg);
-/* goto the action.count-th line from top of the focused window */
-static size_t window_lines_top(const Arg *arg);
-/* goto the start of middle line of the focused window */
-static size_t window_lines_middle(const Arg *arg);
-/* goto the action.count-th line from bottom of the focused window */
-static size_t window_lines_bottom(const Arg *arg);
-
-static Movement moves[] = {
- [MOVE_SCREEN_LINE_UP] = { .win = window_line_up },
- [MOVE_SCREEN_LINE_DOWN] = { .win = window_line_down },
- [MOVE_SCREEN_LINE_BEGIN] = { .win = window_line_begin, .type = CHARWISE },
- [MOVE_SCREEN_LINE_MIDDLE] = { .win = window_line_middle, .type = CHARWISE },
- [MOVE_SCREEN_LINE_END] = { .win = window_line_end, .type = CHARWISE|INCLUSIVE },
- [MOVE_LINE_PREV] = { .txt = text_line_prev, .type = LINEWISE },
- [MOVE_LINE_BEGIN] = { .txt = text_line_begin, .type = LINEWISE },
- [MOVE_LINE_START] = { .txt = text_line_start, .type = LINEWISE },
- [MOVE_LINE_FINISH] = { .txt = text_line_finish, .type = LINEWISE|INCLUSIVE },
- [MOVE_LINE_LASTCHAR] = { .txt = text_line_lastchar, .type = LINEWISE|INCLUSIVE },
- [MOVE_LINE_END] = { .txt = text_line_end, .type = LINEWISE },
- [MOVE_LINE_NEXT] = { .txt = text_line_next, .type = LINEWISE },
- [MOVE_LINE] = { .cmd = line, .type = LINEWISE|IDEMPOTENT|JUMP},
- [MOVE_COLUMN] = { .cmd = column, .type = CHARWISE|IDEMPOTENT},
- [MOVE_CHAR_PREV] = { .win = window_char_prev },
- [MOVE_CHAR_NEXT] = { .win = window_char_next },
- [MOVE_WORD_START_PREV] = { .txt = text_word_start_prev, .type = CHARWISE },
- [MOVE_WORD_START_NEXT] = { .txt = text_word_start_next, .type = CHARWISE },
- [MOVE_WORD_END_PREV] = { .txt = text_word_end_prev, .type = CHARWISE|INCLUSIVE },
- [MOVE_WORD_END_NEXT] = { .txt = text_word_end_next, .type = CHARWISE|INCLUSIVE },
- [MOVE_LONGWORD_START_PREV] = { .txt = text_longword_start_prev, .type = CHARWISE },
- [MOVE_LONGWORD_START_NEXT] = { .txt = text_longword_start_next, .type = CHARWISE },
- [MOVE_LONGWORD_END_PREV] = { .txt = text_longword_end_prev, .type = CHARWISE|INCLUSIVE },
- [MOVE_LONGWORD_END_NEXT] = { .txt = text_longword_end_next, .type = CHARWISE|INCLUSIVE },
- [MOVE_SENTENCE_PREV] = { .txt = text_sentence_prev, .type = LINEWISE },
- [MOVE_SENTENCE_NEXT] = { .txt = text_sentence_next, .type = LINEWISE },
- [MOVE_PARAGRAPH_PREV] = { .txt = text_paragraph_prev, .type = LINEWISE|JUMP },
- [MOVE_PARAGRAPH_NEXT] = { .txt = text_paragraph_next, .type = LINEWISE|JUMP },
- [MOVE_BRACKET_MATCH] = { .txt = text_bracket_match, .type = LINEWISE|INCLUSIVE|JUMP },
- [MOVE_FILE_BEGIN] = { .txt = text_begin, .type = LINEWISE|JUMP },
- [MOVE_FILE_END] = { .txt = text_end, .type = LINEWISE|JUMP },
- [MOVE_LEFT_TO] = { .cmd = to_left, .type = LINEWISE },
- [MOVE_RIGHT_TO] = { .cmd = to, .type = LINEWISE|INCLUSIVE },
- [MOVE_LEFT_TILL] = { .cmd = till_left, .type = LINEWISE },
- [MOVE_RIGHT_TILL] = { .cmd = till, .type = LINEWISE|INCLUSIVE },
- [MOVE_MARK] = { .cmd = mark_goto, .type = LINEWISE|JUMP },
- [MOVE_MARK_LINE] = { .cmd = mark_line_goto, .type = LINEWISE|JUMP },
- [MOVE_SEARCH_WORD_FORWARD] = { .cmd = search_word_forward, .type = LINEWISE|JUMP },
- [MOVE_SEARCH_WORD_BACKWARD]= { .cmd = search_word_backward, .type = LINEWISE|JUMP },
- [MOVE_SEARCH_FORWARD] = { .cmd = search_forward, .type = LINEWISE|JUMP },
- [MOVE_SEARCH_BACKWARD] = { .cmd = search_backward, .type = LINEWISE|JUMP },
- [MOVE_WINDOW_LINE_TOP] = { .cmd = window_lines_top, .type = LINEWISE|JUMP },
- [MOVE_WINDOW_LINE_MIDDLE] = { .cmd = window_lines_middle, .type = LINEWISE|JUMP },
- [MOVE_WINDOW_LINE_BOTTOM] = { .cmd = window_lines_bottom, .type = LINEWISE|JUMP },
-};
-
-/* these can be passed as int argument to textobj(&(const Arg){ .i = TEXT_OBJ_* }) */
-enum {
- TEXT_OBJ_INNER_WORD,
- TEXT_OBJ_OUTER_WORD,
- TEXT_OBJ_INNER_LONGWORD,
- TEXT_OBJ_OUTER_LONGWORD,
- TEXT_OBJ_LINE_UP,
- TEXT_OBJ_LINE_DOWN,
- TEXT_OBJ_SENTENCE,
- TEXT_OBJ_PARAGRAPH,
- TEXT_OBJ_OUTER_SQUARE_BRACKET,
- TEXT_OBJ_INNER_SQUARE_BRACKET,
- TEXT_OBJ_OUTER_CURLY_BRACKET,
- TEXT_OBJ_INNER_CURLY_BRACKET,
- TEXT_OBJ_OUTER_ANGLE_BRACKET,
- TEXT_OBJ_INNER_ANGLE_BRACKET,
- TEXT_OBJ_OUTER_PARANTHESE,
- TEXT_OBJ_INNER_PARANTHESE,
- TEXT_OBJ_OUTER_QUOTE,
- TEXT_OBJ_INNER_QUOTE,
- TEXT_OBJ_OUTER_SINGLE_QUOTE,
- TEXT_OBJ_INNER_SINGLE_QUOTE,
- TEXT_OBJ_OUTER_BACKTICK,
- TEXT_OBJ_INNER_BACKTICK,
-};
-
-static TextObject textobjs[] = {
- [TEXT_OBJ_INNER_WORD] = { text_object_word },
- [TEXT_OBJ_OUTER_WORD] = { text_object_word_outer },
- [TEXT_OBJ_INNER_LONGWORD] = { text_object_longword },
- [TEXT_OBJ_OUTER_LONGWORD] = { text_object_longword_outer },
- [TEXT_OBJ_LINE_UP] = { text_object_line },
- [TEXT_OBJ_LINE_DOWN] = { text_object_line },
- [TEXT_OBJ_SENTENCE] = { text_object_sentence },
- [TEXT_OBJ_PARAGRAPH] = { text_object_paragraph },
- [TEXT_OBJ_OUTER_SQUARE_BRACKET] = { text_object_square_bracket, OUTER },
- [TEXT_OBJ_INNER_SQUARE_BRACKET] = { text_object_square_bracket, INNER },
- [TEXT_OBJ_OUTER_CURLY_BRACKET] = { text_object_curly_bracket, OUTER },
- [TEXT_OBJ_INNER_CURLY_BRACKET] = { text_object_curly_bracket, INNER },
- [TEXT_OBJ_OUTER_ANGLE_BRACKET] = { text_object_angle_bracket, OUTER },
- [TEXT_OBJ_INNER_ANGLE_BRACKET] = { text_object_angle_bracket, INNER },
- [TEXT_OBJ_OUTER_PARANTHESE] = { text_object_paranthese, OUTER },
- [TEXT_OBJ_INNER_PARANTHESE] = { text_object_paranthese, INNER },
- [TEXT_OBJ_OUTER_QUOTE] = { text_object_quote, OUTER },
- [TEXT_OBJ_INNER_QUOTE] = { text_object_quote, INNER },
- [TEXT_OBJ_OUTER_SINGLE_QUOTE] = { text_object_single_quote, OUTER },
- [TEXT_OBJ_INNER_SINGLE_QUOTE] = { text_object_single_quote, INNER },
- [TEXT_OBJ_OUTER_BACKTICK] = { text_object_backtick, OUTER },
- [TEXT_OBJ_INNER_BACKTICK] = { text_object_backtick, INNER },
-};
-
-/* if some movements are forced to be linewise, they are translated to text objects */
-static TextObject *moves_linewise[] = {
- [MOVE_SCREEN_LINE_UP] = &textobjs[TEXT_OBJ_LINE_UP],
- [MOVE_SCREEN_LINE_DOWN] = &textobjs[TEXT_OBJ_LINE_DOWN],
-};
-
-/** functions to be called from keybindings */
-/* navigate jumplist either in forward (arg->i>0) or backward (arg->i<0) direction */
-static void jumplist(const Arg *arg);
-static void macro_record(const Arg *arg);
-static void macro_replay(const Arg *arg);
-/* temporarily suspend the editor and return to the shell, type 'fg' to get back */
-static void suspend(const Arg *arg);
-/* switch to mode indicated by arg->i */
-static void switchmode(const Arg *arg);
-/* set mark indicated by arg->i to current cursor position */
-static void mark_set(const Arg *arg);
-/* insert arg->s at the current cursor position */
-static void insert(const Arg *arg);
-/* insert a tab or the needed amount of spaces at the current cursor position */
-static void insert_tab(const Arg *arg);
-/* inserts a newline (either \n or \r\n depending on file type) */
-static void insert_newline(const Arg *arg);
-/* put register content either before (if arg->i < 0) or after (if arg->i > 0)
- * current cursor position */
-static void put(const Arg *arg);
-/* add a new line either before or after the one where the cursor currently is */
-static void openline(const Arg *arg);
-/* join lines from current cursor position to movement indicated by arg */
-static void join(const Arg *arg);
-/* create a new window with the filename arg->s */
-static void winnew(const Arg *arg);
-/* execute arg->s as if it was typed on command prompt */
-static void cmd(const Arg *arg);
-/* perform last action i.e. action_prev again */
-static void repeat(const Arg *arg);
-/* replace character at cursor with one read form keyboard */
-static void replace(const Arg *arg);
-/* adjust action.count by arg->i */
-static void count(const Arg *arg);
-/* move to the action.count-th line or if not given either to the first (arg->i < 0)
- * or last (arg->i > 0) line of file */
-static void gotoline(const Arg *arg);
-/* force operator to linewise (if arg->b is set) */
-static void linewise(const Arg *arg);
-/* make the current action use the operator indicated by arg->i */
-static void operator(const Arg *arg);
-/* execute operator twice useful for synonyms (e.g. 'cc') */
-static void operator_twice(const Arg *arg);
-/* change case of a file range to upper (arg->i > 0) or lowercase (arg->i < 0) */
-static void changecase(const Arg *arg);
-/* blocks to read a key and performs movement indicated by arg->i which
- * should be one of MOVE_{RIGHT,LEFT}_{TO,TILL} */
-static void movement_key(const Arg *arg);
-/* perform the movement as indicated by arg->i */
-static void movement(const Arg *arg);
-/* let the current operator affect the range indicated by the text object arg->i */
-static void textobj(const Arg *arg);
-/* use register indicated by arg->i for the current operator */
-static void reg(const Arg *arg);
-/* perform a movement to mark arg->i */
-static void mark(const Arg *arg);
-/* perform a movement to the first non-blank on the line pointed by mark arg->i */
-static void mark_line(const Arg *arg);
-/* {un,re}do last action, redraw window */
-static void undo(const Arg *arg);
-static void redo(const Arg *arg);
-/* either part of multiplier or a movement to begin of line */
-static void zero(const Arg *arg);
-/* hange/delete from the current cursor position to the end of
- * movement as indicated by arg->i */
-static void change(const Arg *arg);
-static void delete(const Arg *arg);
-/* perform movement according to arg->i, then switch to insert mode */
-static void insertmode(const Arg *arg);
-/* insert register content indicated by arg->i at current cursor position */
-static void insert_register(const Arg *arg);
-/* show a user prompt to get input with title arg->s */
-static void prompt_search(const Arg *arg);
-static void prompt_cmd(const Arg *arg);
-/* evaluate user input at prompt, perform search or execute a command */
-static void prompt_enter(const Arg *arg);
-/* cycle through past user inputs */
-static void prompt_up(const Arg *arg);
-static void prompt_down(const Arg *arg);
-/* exit command mode if the last char is deleted */
-static void prompt_backspace(const Arg *arg);
-/* blocks to read 3 consecutive digits and inserts the corresponding byte value */
-static void insert_verbatim(const Arg *arg);
-/* scroll window content according to arg->i which can be either PAGE, PAGE_HALF,
- * or an arbitrary number of lines. a multiplier overrides what is given in arg->i.
- * negative values scroll back, positive forward. */
-static void wscroll(const Arg *arg);
-/* similar to scroll, but do only move window content not cursor position */
-static void wslide(const Arg *arg);
-/* call editor function as indicated by arg->f */
-static void call(const Arg *arg);
-/* call window function as indicated by arg->w */
-static void window(const Arg *arg);
-/* quit editor, discard all changes */
-static void quit(const Arg *arg);
-
-/** commands to enter at the ':'-prompt */
-/* set various runtime options */
-static bool cmd_set(Filerange*, const char *argv[]);
-/* goto line indicated by argv[0] */
-static bool cmd_gotoline(Filerange*, const char *argv[]);
-/* for each argument create a new window and open the corresponding file */
-static bool cmd_open(Filerange*, const char *argv[]);
-/* close current window (discard modifications if argv[0] contains '!')
- * and open argv[1], if no argv[1] is given re-read to current file from disk */
-static bool cmd_edit(Filerange*, const char *argv[]);
-/* close the current window, if argv[0] contains a '!' discard modifications */
-static bool cmd_quit(Filerange*, const char *argv[]);
-/* close all windows which show current file. if argv[0] contains a '!' discard modifications */
-static bool cmd_bdelete(Filerange*, const char *argv[]);
-/* close all windows, exit editor, if argv[0] contains a '!' discard modifications */
-static bool cmd_qall(Filerange*, const char *argv[]);
-/* for each argument try to insert the file content at current cursor postion */
-static bool cmd_read(Filerange*, const char *argv[]);
-static bool cmd_substitute(Filerange*, const char *argv[]);
-/* if no argument are given, split the current window horizontally,
- * otherwise open the file */
-static bool cmd_split(Filerange*, const char *argv[]);
-/* if no argument are given, split the current window vertically,
- * otherwise open the file */
-static bool cmd_vsplit(Filerange*, const char *argv[]);
-/* create a new empty window and arrange all windows either horizontally or vertically */
-static bool cmd_new(Filerange*, const char *argv[]);
-static bool cmd_vnew(Filerange*, const char *argv[]);
-/* save the file displayed in the current window and close it */
-static bool cmd_wq(Filerange*, const char *argv[]);
-/* save the file displayed in the current window to the name given.
- * do not change internal filname association. further :w commands
- * without arguments will still write to the old filename */
-static bool cmd_write(Filerange*, const char *argv[]);
-/* save the file displayed in the current window to the name given,
- * associate the new name with the buffer. further :w commands
- * without arguments will write to the new filename */
-static bool cmd_saveas(Filerange*, const char *argv[]);
-
-static void action_reset(Action *a);
-static void switchmode_to(Mode *new_mode);
-
+#include "vis.h"
#include "config.h"
static Key getkey(void);
diff --git a/vis.h b/vis.h
new file mode 100644
index 0000000..bad4213
--- /dev/null
+++ b/vis.h
_AT_@ -0,0 +1,486 @@
+#ifndef VIS_H
+#define VIS_H
+#include "text-motions.h"
+#include "text-objects.h"
+#include <limits.h>
+typedef union {
+ bool b;
+ int i;
+ const char *s;
+ void (*w)(Win*); /* generic window commands */
+ void (*f)(Editor*); /* generic editor commands */
+} Arg;
+
+typedef struct {
+ char str[6]; /* UTF8 character or terminal escape code */
+ int code; /* curses KEY_* constant */
+} Key;
+
+#define MAX_KEYS 2
+typedef Key KeyCombo[MAX_KEYS];
+
+typedef struct {
+ KeyCombo key;
+ void (*func)(const Arg *arg);
+ const Arg arg;
+} KeyBinding;
+
+typedef struct Mode Mode;
+struct Mode {
+ Mode *parent; /* if no match is found in this mode, search will continue there */
+ KeyBinding *bindings; /* NULL terminated array of keybindings for this mode */
+ const char *name; /* descriptive, user facing name of the mode */
+ bool isuser; /* whether this is a user or internal mode */
+ bool common_prefix; /* whether the first key in this mode is always the same */
+ void (*enter)(Mode *old); /* called right before the mode becomes active */
+ void (*leave)(Mode *new); /* called right before the mode becomes inactive */
+ bool (*unknown)(KeyCombo); /* called whenever a key combination is not found in this mode,
+ the return value determines whether parent modes will be searched */
+ void (*input)(const char*, size_t); /* called whenever a key is not found in this mode and all its parent modes */
+ void (*idle)(void); /* 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 {
+ char *name; /* is used to match against argv[0] to enable this config */
+ Mode *mode; /* default mode in which the editor should start in */
+ void (*statusbar)(EditorWin*); /* routine which is called whenever the cursor is moved within a window */
+ bool (*keypress)(Key*); /* called before any other keybindings are checked,
+ * return value decides whether key should be ignored */
+} Config;
+
+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 {
+ void (*func)(OperatorContext*); /* function implementing the operator logic */
+} Operator;
+
+typedef struct {
+ size_t (*cmd)(const Arg*); /* a custom movement based on user input from vis.c */
+ size_t (*win)(Win*); /* a movement based on current window content from window.h */
+ size_t (*txt)(Text*, size_t pos); /* a movement form text-motions.h */
+ 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;
+ bool linewise;
+ Operator *op;
+ Movement *movement;
+ TextObject *textobj;
+ Register *reg;
+ MarkIntern mark;
+ Key key;
+ Arg arg;
+} Action;
+
+typedef struct { /* command definitions for the ':'-prompt */
+ const char *name; /* regular expression pattern to match command */
+ bool (*cmd)(Filerange*, const char *argv[]);
+ /* command logic called with a NULL terminated array
+ * of arguments. argv[0] will be the command name,
+ * as matched by the regex. */
+ bool args; /* whether argv should be populated with words
+ * separated by spaces. if false, argv[1] will
+ * contain the remaining command line unmodified */
+ regex_t regex; /* compiled form of the pattern in 'name' */
+} Command;
+
+/** global variables */
+static volatile bool running = true; /* exit main loop once this becomes false */
+static Editor *vis; /* global editor instance, keeps track of all windows etc. */
+static Mode *mode; /* currently active mode, used to search for keybindings */
+static Mode *mode_prev; /* previsouly active user mode */
+static Mode *mode_before_prompt; /* user mode which was active before entering prompt */
+static Action action; /* current action which is in progress */
+static Action action_prev; /* last operator action used by the repeat '.' key */
+static Buffer buffer_repeat;/* repeat last modification i.e. insertion/replacement */
+
+/** operators */
+static void op_change(OperatorContext *c);
+static void op_yank(OperatorContext *c);
+static void op_put(OperatorContext *c);
+static void op_delete(OperatorContext *c);
+static void op_shift_right(OperatorContext *c);
+static void op_shift_left(OperatorContext *c);
+static void op_case_change(OperatorContext *c);
+static void op_join(OperatorContext *c);
+static void op_repeat_insert(OperatorContext *c);
+static void op_repeat_replace(OperatorContext *c);
+
+/* these can be passed as int argument to operator(&(const Arg){ .i = OP_*}) */
+enum {
+ OP_DELETE,
+ OP_CHANGE,
+ OP_YANK,
+ OP_PUT,
+ OP_SHIFT_RIGHT,
+ OP_SHIFT_LEFT,
+ OP_CASE_CHANGE,
+ OP_JOIN,
+ OP_REPEAT_INSERT,
+ OP_REPEAT_REPLACE,
+};
+
+static Operator ops[] = {
+ [OP_DELETE] = { op_delete },
+ [OP_CHANGE] = { op_change },
+ [OP_YANK] = { op_yank },
+ [OP_PUT] = { op_put },
+ [OP_SHIFT_RIGHT] = { op_shift_right },
+ [OP_SHIFT_LEFT] = { op_shift_left },
+ [OP_CASE_CHANGE] = { op_case_change },
+ [OP_JOIN] = { op_join },
+ [OP_REPEAT_INSERT] = { op_repeat_insert },
+ [OP_REPEAT_REPLACE] = { op_repeat_replace },
+};
+
+#define PAGE INT_MAX
+#define PAGE_HALF (INT_MAX-1)
+
+/* these can be passed as int argument to movement(&(const Arg){ .i = MOVE_* }) */
+enum {
+ MOVE_SCREEN_LINE_UP,
+ MOVE_SCREEN_LINE_DOWN,
+ MOVE_SCREEN_LINE_BEGIN,
+ MOVE_SCREEN_LINE_MIDDLE,
+ MOVE_SCREEN_LINE_END,
+ MOVE_LINE_PREV,
+ MOVE_LINE_BEGIN,
+ MOVE_LINE_START,
+ MOVE_LINE_FINISH,
+ MOVE_LINE_LASTCHAR,
+ MOVE_LINE_END,
+ MOVE_LINE_NEXT,
+ MOVE_LINE,
+ MOVE_COLUMN,
+ MOVE_CHAR_PREV,
+ MOVE_CHAR_NEXT,
+ MOVE_WORD_START_NEXT,
+ MOVE_WORD_END_PREV,
+ MOVE_WORD_END_NEXT,
+ MOVE_WORD_START_PREV,
+ MOVE_LONGWORD_START_PREV,
+ MOVE_LONGWORD_START_NEXT,
+ MOVE_LONGWORD_END_PREV,
+ MOVE_LONGWORD_END_NEXT,
+ MOVE_SENTENCE_PREV,
+ MOVE_SENTENCE_NEXT,
+ MOVE_PARAGRAPH_PREV,
+ MOVE_PARAGRAPH_NEXT,
+ MOVE_BRACKET_MATCH,
+ MOVE_LEFT_TO,
+ MOVE_RIGHT_TO,
+ MOVE_LEFT_TILL,
+ MOVE_RIGHT_TILL,
+ MOVE_FILE_BEGIN,
+ MOVE_FILE_END,
+ MOVE_MARK,
+ MOVE_MARK_LINE,
+ MOVE_SEARCH_WORD_FORWARD,
+ MOVE_SEARCH_WORD_BACKWARD,
+ MOVE_SEARCH_FORWARD,
+ MOVE_SEARCH_BACKWARD,
+ MOVE_WINDOW_LINE_TOP,
+ MOVE_WINDOW_LINE_MIDDLE,
+ MOVE_WINDOW_LINE_BOTTOM,
+};
+
+/** movements which can be used besides the one in text-motions.h and window.h */
+
+/* search in forward direction for the word under the cursor */
+static size_t search_word_forward(const Arg *arg);
+/* search in backward direction for the word under the cursor */
+static size_t search_word_backward(const Arg *arg);
+/* search again for the last used search pattern */
+static size_t search_forward(const Arg *arg);
+static size_t search_backward(const Arg *arg);
+/* goto action.mark */
+static size_t mark_goto(const Arg *arg);
+/* goto first non-blank char on line pointed by action.mark */
+static size_t mark_line_goto(const Arg *arg);
+/* goto to next occurence of action.key to the right */
+static size_t to(const Arg *arg);
+/* goto to position before next occurence of action.key to the right */
+static size_t till(const Arg *arg);
+/* goto to next occurence of action.key to the left */
+static size_t to_left(const Arg *arg);
+/* goto to position after next occurence of action.key to the left */
+static size_t till_left(const Arg *arg);
+/* goto line number action.count */
+static size_t line(const Arg *arg);
+/* goto to byte action.count on current line */
+static size_t column(const Arg *arg);
+/* goto the action.count-th line from top of the focused window */
+static size_t window_lines_top(const Arg *arg);
+/* goto the start of middle line of the focused window */
+static size_t window_lines_middle(const Arg *arg);
+/* goto the action.count-th line from bottom of the focused window */
+static size_t window_lines_bottom(const Arg *arg);
+
+static Movement moves[] = {
+ [MOVE_SCREEN_LINE_UP] = { .win = window_line_up },
+ [MOVE_SCREEN_LINE_DOWN] = { .win = window_line_down },
+ [MOVE_SCREEN_LINE_BEGIN] = { .win = window_line_begin, .type = CHARWISE },
+ [MOVE_SCREEN_LINE_MIDDLE] = { .win = window_line_middle, .type = CHARWISE },
+ [MOVE_SCREEN_LINE_END] = { .win = window_line_end, .type = CHARWISE|INCLUSIVE },
+ [MOVE_LINE_PREV] = { .txt = text_line_prev, .type = LINEWISE },
+ [MOVE_LINE_BEGIN] = { .txt = text_line_begin, .type = LINEWISE },
+ [MOVE_LINE_START] = { .txt = text_line_start, .type = LINEWISE },
+ [MOVE_LINE_FINISH] = { .txt = text_line_finish, .type = LINEWISE|INCLUSIVE },
+ [MOVE_LINE_LASTCHAR] = { .txt = text_line_lastchar, .type = LINEWISE|INCLUSIVE },
+ [MOVE_LINE_END] = { .txt = text_line_end, .type = LINEWISE },
+ [MOVE_LINE_NEXT] = { .txt = text_line_next, .type = LINEWISE },
+ [MOVE_LINE] = { .cmd = line, .type = LINEWISE|IDEMPOTENT|JUMP},
+ [MOVE_COLUMN] = { .cmd = column, .type = CHARWISE|IDEMPOTENT},
+ [MOVE_CHAR_PREV] = { .win = window_char_prev },
+ [MOVE_CHAR_NEXT] = { .win = window_char_next },
+ [MOVE_WORD_START_PREV] = { .txt = text_word_start_prev, .type = CHARWISE },
+ [MOVE_WORD_START_NEXT] = { .txt = text_word_start_next, .type = CHARWISE },
+ [MOVE_WORD_END_PREV] = { .txt = text_word_end_prev, .type = CHARWISE|INCLUSIVE },
+ [MOVE_WORD_END_NEXT] = { .txt = text_word_end_next, .type = CHARWISE|INCLUSIVE },
+ [MOVE_LONGWORD_START_PREV] = { .txt = text_longword_start_prev, .type = CHARWISE },
+ [MOVE_LONGWORD_START_NEXT] = { .txt = text_longword_start_next, .type = CHARWISE },
+ [MOVE_LONGWORD_END_PREV] = { .txt = text_longword_end_prev, .type = CHARWISE|INCLUSIVE },
+ [MOVE_LONGWORD_END_NEXT] = { .txt = text_longword_end_next, .type = CHARWISE|INCLUSIVE },
+ [MOVE_SENTENCE_PREV] = { .txt = text_sentence_prev, .type = LINEWISE },
+ [MOVE_SENTENCE_NEXT] = { .txt = text_sentence_next, .type = LINEWISE },
+ [MOVE_PARAGRAPH_PREV] = { .txt = text_paragraph_prev, .type = LINEWISE|JUMP },
+ [MOVE_PARAGRAPH_NEXT] = { .txt = text_paragraph_next, .type = LINEWISE|JUMP },
+ [MOVE_BRACKET_MATCH] = { .txt = text_bracket_match, .type = LINEWISE|INCLUSIVE|JUMP },
+ [MOVE_FILE_BEGIN] = { .txt = text_begin, .type = LINEWISE|JUMP },
+ [MOVE_FILE_END] = { .txt = text_end, .type = LINEWISE|JUMP },
+ [MOVE_LEFT_TO] = { .cmd = to_left, .type = LINEWISE },
+ [MOVE_RIGHT_TO] = { .cmd = to, .type = LINEWISE|INCLUSIVE },
+ [MOVE_LEFT_TILL] = { .cmd = till_left, .type = LINEWISE },
+ [MOVE_RIGHT_TILL] = { .cmd = till, .type = LINEWISE|INCLUSIVE },
+ [MOVE_MARK] = { .cmd = mark_goto, .type = LINEWISE|JUMP },
+ [MOVE_MARK_LINE] = { .cmd = mark_line_goto, .type = LINEWISE|JUMP },
+ [MOVE_SEARCH_WORD_FORWARD] = { .cmd = search_word_forward, .type = LINEWISE|JUMP },
+ [MOVE_SEARCH_WORD_BACKWARD]= { .cmd = search_word_backward, .type = LINEWISE|JUMP },
+ [MOVE_SEARCH_FORWARD] = { .cmd = search_forward, .type = LINEWISE|JUMP },
+ [MOVE_SEARCH_BACKWARD] = { .cmd = search_backward, .type = LINEWISE|JUMP },
+ [MOVE_WINDOW_LINE_TOP] = { .cmd = window_lines_top, .type = LINEWISE|JUMP },
+ [MOVE_WINDOW_LINE_MIDDLE] = { .cmd = window_lines_middle, .type = LINEWISE|JUMP },
+ [MOVE_WINDOW_LINE_BOTTOM] = { .cmd = window_lines_bottom, .type = LINEWISE|JUMP },
+};
+
+/* these can be passed as int argument to textobj(&(const Arg){ .i = TEXT_OBJ_* }) */
+enum {
+ TEXT_OBJ_INNER_WORD,
+ TEXT_OBJ_OUTER_WORD,
+ TEXT_OBJ_INNER_LONGWORD,
+ TEXT_OBJ_OUTER_LONGWORD,
+ TEXT_OBJ_LINE_UP,
+ TEXT_OBJ_LINE_DOWN,
+ TEXT_OBJ_SENTENCE,
+ TEXT_OBJ_PARAGRAPH,
+ TEXT_OBJ_OUTER_SQUARE_BRACKET,
+ TEXT_OBJ_INNER_SQUARE_BRACKET,
+ TEXT_OBJ_OUTER_CURLY_BRACKET,
+ TEXT_OBJ_INNER_CURLY_BRACKET,
+ TEXT_OBJ_OUTER_ANGLE_BRACKET,
+ TEXT_OBJ_INNER_ANGLE_BRACKET,
+ TEXT_OBJ_OUTER_PARANTHESE,
+ TEXT_OBJ_INNER_PARANTHESE,
+ TEXT_OBJ_OUTER_QUOTE,
+ TEXT_OBJ_INNER_QUOTE,
+ TEXT_OBJ_OUTER_SINGLE_QUOTE,
+ TEXT_OBJ_INNER_SINGLE_QUOTE,
+ TEXT_OBJ_OUTER_BACKTICK,
+ TEXT_OBJ_INNER_BACKTICK,
+};
+
+static TextObject textobjs[] = {
+ [TEXT_OBJ_INNER_WORD] = { text_object_word },
+ [TEXT_OBJ_OUTER_WORD] = { text_object_word_outer },
+ [TEXT_OBJ_INNER_LONGWORD] = { text_object_longword },
+ [TEXT_OBJ_OUTER_LONGWORD] = { text_object_longword_outer },
+ [TEXT_OBJ_LINE_UP] = { text_object_line },
+ [TEXT_OBJ_LINE_DOWN] = { text_object_line },
+ [TEXT_OBJ_SENTENCE] = { text_object_sentence },
+ [TEXT_OBJ_PARAGRAPH] = { text_object_paragraph },
+ [TEXT_OBJ_OUTER_SQUARE_BRACKET] = { text_object_square_bracket, OUTER },
+ [TEXT_OBJ_INNER_SQUARE_BRACKET] = { text_object_square_bracket, INNER },
+ [TEXT_OBJ_OUTER_CURLY_BRACKET] = { text_object_curly_bracket, OUTER },
+ [TEXT_OBJ_INNER_CURLY_BRACKET] = { text_object_curly_bracket, INNER },
+ [TEXT_OBJ_OUTER_ANGLE_BRACKET] = { text_object_angle_bracket, OUTER },
+ [TEXT_OBJ_INNER_ANGLE_BRACKET] = { text_object_angle_bracket, INNER },
+ [TEXT_OBJ_OUTER_PARANTHESE] = { text_object_paranthese, OUTER },
+ [TEXT_OBJ_INNER_PARANTHESE] = { text_object_paranthese, INNER },
+ [TEXT_OBJ_OUTER_QUOTE] = { text_object_quote, OUTER },
+ [TEXT_OBJ_INNER_QUOTE] = { text_object_quote, INNER },
+ [TEXT_OBJ_OUTER_SINGLE_QUOTE] = { text_object_single_quote, OUTER },
+ [TEXT_OBJ_INNER_SINGLE_QUOTE] = { text_object_single_quote, INNER },
+ [TEXT_OBJ_OUTER_BACKTICK] = { text_object_backtick, OUTER },
+ [TEXT_OBJ_INNER_BACKTICK] = { text_object_backtick, INNER },
+};
+
+/* if some movements are forced to be linewise, they are translated to text objects */
+static TextObject *moves_linewise[] = {
+ [MOVE_SCREEN_LINE_UP] = &textobjs[TEXT_OBJ_LINE_UP],
+ [MOVE_SCREEN_LINE_DOWN] = &textobjs[TEXT_OBJ_LINE_DOWN],
+};
+
+/** functions to be called from keybindings */
+/* navigate jumplist either in forward (arg->i>0) or backward (arg->i<0) direction */
+static void jumplist(const Arg *arg);
+static void macro_record(const Arg *arg);
+static void macro_replay(const Arg *arg);
+/* temporarily suspend the editor and return to the shell, type 'fg' to get back */
+static void suspend(const Arg *arg);
+/* switch to mode indicated by arg->i */
+static void switchmode(const Arg *arg);
+/* set mark indicated by arg->i to current cursor position */
+static void mark_set(const Arg *arg);
+/* insert arg->s at the current cursor position */
+static void insert(const Arg *arg);
+/* insert a tab or the needed amount of spaces at the current cursor position */
+static void insert_tab(const Arg *arg);
+/* inserts a newline (either \n or \r\n depending on file type) */
+static void insert_newline(const Arg *arg);
+/* put register content either before (if arg->i < 0) or after (if arg->i > 0)
+ * current cursor position */
+static void put(const Arg *arg);
+/* add a new line either before or after the one where the cursor currently is */
+static void openline(const Arg *arg);
+/* join lines from current cursor position to movement indicated by arg */
+static void join(const Arg *arg);
+/* create a new window with the filename arg->s */
+static void winnew(const Arg *arg);
+/* execute arg->s as if it was typed on command prompt */
+static void cmd(const Arg *arg);
+/* perform last action i.e. action_prev again */
+static void repeat(const Arg *arg);
+/* replace character at cursor with one read form keyboard */
+static void replace(const Arg *arg);
+/* adjust action.count by arg->i */
+static void count(const Arg *arg);
+/* move to the action.count-th line or if not given either to the first (arg->i < 0)
+ * or last (arg->i > 0) line of file */
+static void gotoline(const Arg *arg);
+/* force operator to linewise (if arg->b is set) */
+static void linewise(const Arg *arg);
+/* make the current action use the operator indicated by arg->i */
+static void operator(const Arg *arg);
+/* execute operator twice useful for synonyms (e.g. 'cc') */
+static void operator_twice(const Arg *arg);
+/* change case of a file range to upper (arg->i > 0) or lowercase (arg->i < 0) */
+static void changecase(const Arg *arg);
+/* blocks to read a key and performs movement indicated by arg->i which
+ * should be one of MOVE_{RIGHT,LEFT}_{TO,TILL} */
+static void movement_key(const Arg *arg);
+/* perform the movement as indicated by arg->i */
+static void movement(const Arg *arg);
+/* let the current operator affect the range indicated by the text object arg->i */
+static void textobj(const Arg *arg);
+/* use register indicated by arg->i for the current operator */
+static void reg(const Arg *arg);
+/* perform a movement to mark arg->i */
+static void mark(const Arg *arg);
+/* perform a movement to the first non-blank on the line pointed by mark arg->i */
+static void mark_line(const Arg *arg);
+/* {un,re}do last action, redraw window */
+static void undo(const Arg *arg);
+static void redo(const Arg *arg);
+/* either part of multiplier or a movement to begin of line */
+static void zero(const Arg *arg);
+/* hange/delete from the current cursor position to the end of
+ * movement as indicated by arg->i */
+static void change(const Arg *arg);
+static void delete(const Arg *arg);
+/* perform movement according to arg->i, then switch to insert mode */
+static void insertmode(const Arg *arg);
+/* insert register content indicated by arg->i at current cursor position */
+static void insert_register(const Arg *arg);
+/* show a user prompt to get input with title arg->s */
+static void prompt_search(const Arg *arg);
+static void prompt_cmd(const Arg *arg);
+/* evaluate user input at prompt, perform search or execute a command */
+static void prompt_enter(const Arg *arg);
+/* cycle through past user inputs */
+static void prompt_up(const Arg *arg);
+static void prompt_down(const Arg *arg);
+/* exit command mode if the last char is deleted */
+static void prompt_backspace(const Arg *arg);
+/* blocks to read 3 consecutive digits and inserts the corresponding byte value */
+static void insert_verbatim(const Arg *arg);
+/* scroll window content according to arg->i which can be either PAGE, PAGE_HALF,
+ * or an arbitrary number of lines. a multiplier overrides what is given in arg->i.
+ * negative values scroll back, positive forward. */
+static void wscroll(const Arg *arg);
+/* similar to scroll, but do only move window content not cursor position */
+static void wslide(const Arg *arg);
+/* call editor function as indicated by arg->f */
+static void call(const Arg *arg);
+/* call window function as indicated by arg->w */
+static void window(const Arg *arg);
+/* quit editor, discard all changes */
+static void quit(const Arg *arg);
+
+/** commands to enter at the ':'-prompt */
+/* set various runtime options */
+static bool cmd_set(Filerange*, const char *argv[]);
+/* goto line indicated by argv[0] */
+static bool cmd_gotoline(Filerange*, const char *argv[]);
+/* for each argument create a new window and open the corresponding file */
+static bool cmd_open(Filerange*, const char *argv[]);
+/* close current window (discard modifications if argv[0] contains '!')
+ * and open argv[1], if no argv[1] is given re-read to current file from disk */
+static bool cmd_edit(Filerange*, const char *argv[]);
+/* close the current window, if argv[0] contains a '!' discard modifications */
+static bool cmd_quit(Filerange*, const char *argv[]);
+/* close all windows which show current file. if argv[0] contains a '!' discard modifications */
+static bool cmd_bdelete(Filerange*, const char *argv[]);
+/* close all windows, exit editor, if argv[0] contains a '!' discard modifications */
+static bool cmd_qall(Filerange*, const char *argv[]);
+/* for each argument try to insert the file content at current cursor postion */
+static bool cmd_read(Filerange*, const char *argv[]);
+static bool cmd_substitute(Filerange*, const char *argv[]);
+/* if no argument are given, split the current window horizontally,
+ * otherwise open the file */
+static bool cmd_split(Filerange*, const char *argv[]);
+/* if no argument are given, split the current window vertically,
+ * otherwise open the file */
+static bool cmd_vsplit(Filerange*, const char *argv[]);
+/* create a new empty window and arrange all windows either horizontally or vertically */
+static bool cmd_new(Filerange*, const char *argv[]);
+static bool cmd_vnew(Filerange*, const char *argv[]);
+/* save the file displayed in the current window and close it */
+static bool cmd_wq(Filerange*, const char *argv[]);
+/* save the file displayed in the current window to the name given.
+ * do not change internal filname association. further :w commands
+ * without arguments will still write to the old filename */
+static bool cmd_write(Filerange*, const char *argv[]);
+/* save the file displayed in the current window to the name given,
+ * associate the new name with the buffer. further :w commands
+ * without arguments will write to the new filename */
+static bool cmd_saveas(Filerange*, const char *argv[]);
+
+static void action_reset(Action *a);
+static void switchmode_to(Mode *new_mode);
+#endif
--
2.2.1
Received on Sat Jan 03 2015 - 22:41:19 CET
This archive was generated by hypermail 2.3.0 : Sat Jan 03 2015 - 22:48:07 CET