--- 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.1Received 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