aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config.def.h74
-rw-r--r--editor.h26
-rw-r--r--register.c10
-rw-r--r--register.h10
-rw-r--r--syntax.h12
-rw-r--r--text-motions.c2
-rw-r--r--text-motions.h19
-rw-r--r--text-objects.h13
-rw-r--r--text.c4
-rw-r--r--text.h2
-rw-r--r--util.h4
-rw-r--r--vis.c183
-rw-r--r--window.c18
-rw-r--r--window.h18
14 files changed, 272 insertions, 123 deletions
diff --git a/config.def.h b/config.def.h
index df35f2a..49a87fd 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,3 +1,6 @@
+/** start by reading from the top of vis.c up until config.h is included */
+
+/* macros used to specify keys for key bindings */
#define ESC 0x1B
#define NONE(k) { .str = { k }, .code = 0 }
#define KEY(k) { .str = { '\0' }, .code = KEY_##k }
@@ -9,6 +12,16 @@
{ { NONE(127) }, (func), { .name = (arg) } }, \
{ { CONTROL('B') }, (func), { .name = (arg) } }
+/* 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.
+ */
static Mode vis_modes[];
enum {
@@ -31,26 +44,6 @@ enum {
VIS_MODE_REPLACE,
};
-/* operators */
-static void op_change(OperatorContext *c);
-static void op_yank(OperatorContext *c);
-static void op_paste(OperatorContext *c);
-static void op_delete(OperatorContext *c);
-
-enum {
- OP_DELETE,
- OP_CHANGE,
- OP_YANK,
- OP_PASTE,
-};
-
-static Operator ops[] = {
- [OP_DELETE] = { op_delete, false },
- [OP_CHANGE] = { op_change, false },
- [OP_YANK] = { op_yank, false },
- [OP_PASTE] = { op_paste, true },
-};
-
/* command recognized at the ':'-prompt, matched using a greedy top to bottom,
* regex search. make sure the longer commands are listed before the shorter ones
* e.g. 'sp' before 's' and 'wq' before 'w'.
@@ -333,7 +326,7 @@ static KeyBinding vis_marks_set[] = {
};
static KeyBinding vis_normal[] = {
- { { CONTROL('w'), NONE('c') }, split, { .s = NULL } },
+ { { CONTROL('w'), NONE('s') }, split, { NULL } },
{ { CONTROL('w'), NONE('j') }, call, { .f = editor_window_next } },
{ { CONTROL('w'), NONE('k') }, call, { .f = editor_window_prev } },
{ { CONTROL('F') }, cursor, { .m = window_page_up } },
@@ -456,6 +449,45 @@ static void vis_replace_input(const char *str, size_t len) {
editor_replace_key(vis, str, len);
}
+/*
+ * the tree of modes currently looks like this. the double line between OPERATOR-OPTION
+ * and OPERATOR is only in effect once an operator is detected. that is when entering the
+ * OPERATOR mode its parent is set to OPERATOR-OPTION which makes {INNER-,}TEXTOBJ
+ * reachable. once the operator is processed (i.e. the OPERATOR mode is left) its parent
+ * mode is reset back to MOVE.
+ *
+ *
+ * BASIC
+ * (arrow keys etc.)
+ * / |
+ * /-------------------/ |
+ * READLINE MARK
+ * / \ (` [a-z])
+ * / \ |
+ * / \ |
+ * INSERT-REGISTER PROMPT MARK-LINE
+ * (Ctrl+R [a-z]) (history etc) (' [a-z])
+ * | |
+ * | |
+ * INSERT MOVE
+ * | (h,j,k,l ...)
+ * | | \-----------------\
+ * | | |
+ * REPLACE OPERATOR ======\\ INNER-TEXTOBJ
+ * (d,c,y,p ..) || (i [wsp[]()b<>{}B"'`] )
+ * | || |
+ * | || |
+ * REGISTER || TEXTOBJ
+ * (" [a-z]) || (a [wsp[]()b<>{}B"'`] )
+ * /-----------/ | \\
+ * / | \\
+ * VISUAL MARK-SET \\ OPERATOR-OPTION
+ * (m [a-z]) \\ (v,V)
+ * | \\ //
+ * | \\======//
+ * NORMAL
+ */
+
static Mode vis_modes[] = {
[VIS_MODE_BASIC] = {
.name = "BASIC",
diff --git a/editor.h b/editor.h
index 1aa98ff..109ea32 100644
--- a/editor.h
+++ b/editor.h
@@ -108,6 +108,9 @@ void editor_free(Editor*);
void editor_resize(Editor*, int width, int height);
void editor_draw(Editor*);
void editor_update(Editor*);
+
+/* 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 *c, size_t len);
void editor_replace_key(Editor*, const char *c, size_t len);
void editor_backspace_key(Editor*);
@@ -115,18 +118,33 @@ void editor_delete_key(Editor*);
void editor_insert(Editor*, size_t pos, const char *data, size_t len);
void editor_delete(Editor*, size_t pos, size_t len);
-// TODO comment
+/* load a set of syntax highlighting definitions which will be associated
+ * to the underlying window based on the file type loaded.
+ *
+ * both *syntaxes and *colors must point to a NULL terminated array.
+ * it the i-th syntax definition does not specifiy a fore ground color
+ * then the i-th entry of the color array will be used instead
+ */
bool editor_syntax_load(Editor*, Syntax *syntaxes, Color *colors);
void editor_syntax_unload(Editor*);
+/* creates a new window, and loads the given file. if filename is NULL
+ * an unamed / empty buffer is created */
bool editor_window_new(Editor*, const char *filename);
void editor_window_close(Editor *vis);
+/* if filename is non NULL it is equivalent to window_new call above.
+ * if however filename is NULL a new window is created and linked to the
+ * same underlying text as the currently selected one. changes will
+ * thus be visible in both windows. */
void editor_window_split(Editor*, const char *filename);
void editor_window_vsplit(Editor*, const char *filename);
+/* focus the next / previous window */
void editor_window_next(Editor*);
void editor_window_prev(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 *vis);
+/* replace the current command line content with the one given */
void editor_prompt_set(Editor *vis, const char *line);
void editor_prompt_show(Editor *vis, const char *title);
void editor_prompt_hide(Editor *vis);
@@ -134,9 +152,13 @@ void editor_prompt_hide(Editor *vis);
void editor_statusbar_set(Editor*, editor_statusbar_t);
+// TODO cleanup this mess only 1 function should suffice? move perform
+// lazy initialization on first call
/* library initialization code, should be run at startup */
void editor_init(void);
short editor_color_reserve(short fg, short bg);
+/* 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/register.c b/register.c
index bcce594..db43d71 100644
--- a/register.c
+++ b/register.c
@@ -6,7 +6,7 @@
#define REG_SIZE 1024
-bool register_alloc(Register *reg, size_t size) {
+static bool register_alloc(Register *reg, size_t size) {
if (size < REG_SIZE)
size = REG_SIZE;
if (reg->size < size) {
@@ -30,14 +30,6 @@ void register_free(Register *reg) {
reg->size = 0;
}
-bool register_store(Register *reg, const char *data, size_t len) {
- if (!register_alloc(reg, len))
- return false;
- memcpy(reg->data, data, len);
- reg->len = len;
- return true;
-}
-
bool register_put(Register *reg, Text *txt, Filerange *range) {
size_t len = range->end - range->start;
if (!register_alloc(reg, len))
diff --git a/register.h b/register.h
index 51fcd25..506b86a 100644
--- a/register.h
+++ b/register.h
@@ -6,15 +6,13 @@
#include "text.h"
typedef struct {
- char *data;
- size_t len;
- size_t size;
- bool linewise;
+ char *data; /* NULL if empty */
+ size_t len; /* current length of data */
+ size_t size; /* maximal capacity of the register */
+ bool linewise; /* place register content on a new line when inserting? */
} Register;
-bool register_alloc(Register *reg, size_t size);
void register_free(Register *reg);
-bool register_store(Register *reg, const char *data, size_t len);
bool register_put(Register *reg, Text *txt, Filerange *range);
bool register_append(Register *reg, Text *txt, Filerange *range);
diff --git a/syntax.h b/syntax.h
index a945389..accae9f 100644
--- a/syntax.h
+++ b/syntax.h
@@ -3,7 +3,7 @@
#include <regex.h>
-#define SYNTAX_REGEX_RULES 10
+#define SYNTAX_RULES 10 /* maximal number of syntax rules per file type */
typedef struct {
short fg, bg; /* fore and background color */
@@ -18,11 +18,11 @@ typedef struct {
} SyntaxRule;
typedef struct Syntax Syntax;
-struct Syntax { /* a syntax definition */
- char *name; /* syntax name */
- char *file; /* apply to files matching this regex */
- regex_t file_regex; /* compiled file name regex */
- SyntaxRule rules[SYNTAX_REGEX_RULES]; /* all rules for this file type */
+struct Syntax { /* a syntax definition */
+ char *name; /* syntax name */
+ char *file; /* apply to files matching this regex */
+ regex_t file_regex; /* compiled file name regex */
+ SyntaxRule rules[SYNTAX_RULES]; /* all rules for this file type */
};
#endif
diff --git a/text-motions.c b/text-motions.c
index b2785d8..c453cab 100644
--- a/text-motions.c
+++ b/text-motions.c
@@ -89,7 +89,7 @@ size_t text_line_finish(Text *txt, size_t pos) {
Iterator it = text_iterator_get(txt, text_line_end(txt, pos));
do text_iterator_byte_prev(&it, NULL);
while (text_iterator_byte_get(&it, &c) && c != '\n' && c != '\r' && isspace(c));
- if (!isutf8(c))
+ if (!ISUTF8(c))
text_iterator_char_prev(&it, NULL);
return it.pos;
}
diff --git a/text-motions.h b/text-motions.h
index 81b5b61..84f6ecc 100644
--- a/text-motions.h
+++ b/text-motions.h
@@ -1,15 +1,22 @@
#ifndef TEXT_MOTIONS_H
#define TEXT_MOTIONS_H
+/* these function all take a position in bytes from the start of the file,
+ * perform a certain movement and return the new postion. if the movement
+ * is not possible the original position is returned unchanged. */
+
#include <stddef.h>
#include "text.h"
size_t text_begin(Text*, size_t pos);
size_t text_end(Text*, size_t pos);
+/* move to start of next / previous UTF-8 character */
size_t text_char_next(Text*, size_t pos);
size_t text_char_prev(Text*, size_t pos);
+/* find the given substring either in forward or backward direction.
+ * does not wrap around at file start / end. */
size_t text_find_char_next(Text*, size_t pos, const char *s, size_t len);
size_t text_find_char_prev(Text*, size_t pos, const char *s, size_t len);
@@ -25,9 +32,9 @@ size_t text_line_finish(Text*, size_t pos);
size_t text_line_end(Text*, size_t pos);
size_t text_line_next(Text*, size_t pos);
/*
- * A word consists of a sequence of non-blank characters, separated with white space.
- * TODO?: An empty line is also considered to be a word. This is equivalant to a WORD
- * in vim terminology.
+ * A word consists of a sequence of non-blank characters, separated with white
+ * space. TODO?: An empty line is also considered to be a word.
+ * This is equivalant to a WORD in vim terminology.
*/
size_t text_word_end_next(Text*, size_t pos);
size_t text_word_end_prev(Text*, size_t pos);
@@ -35,8 +42,8 @@ size_t text_word_start_next(Text*, size_t pos);
size_t text_word_start_prev(Text*, size_t pos);
/*
* These are variants of the above with the additional possibility to implement
- * a custom word detection logic. Can be used to implment the equivalent of a what
- * vim reconizes as a word (lowercase).
+ * a custom word detection logic. Can be used to implment the equivalent of a
+ * what vim reconizes as a word (lowercase).
*/
size_t text_word_boundry_end_next(Text*, size_t pos, int (*isboundry)(int));
size_t text_word_boundry_end_prev(Text*, size_t pos, int (*isboundry)(int));
@@ -65,6 +72,8 @@ size_t text_section_prev(Text*, size_t pos);
/* search coresponding '(', ')', '{', '}', '[', ']', '>', '<', '"', ''' */
size_t text_bracket_match(Text*, size_t pos);
+/* search the given regex pattern in either forward or backward direction,
+ * starting from pos. does wrap around if no match was found. */
size_t text_search_forward(Text *txt, size_t pos, Regex *regex);
size_t text_search_backward(Text *txt, size_t pos, Regex *regex);
diff --git a/text-objects.h b/text-objects.h
index 5b3895d..a1e30f9 100644
--- a/text-objects.h
+++ b/text-objects.h
@@ -1,18 +1,25 @@
#ifndef TEXT_OBJECTS_H
#define TEXT_OBJECTS_H
+/* these functions all take a file position. if this position is part of the
+ * respective text-object, a corresponding range is returned. if there is no
+ * such text-object at the given location, an empty range is returned.
+ */
+
#include <stddef.h>
#include "text.h"
-/* word which happens to be at pos, includes trailing white spaces. if at pos happens to
- * be a whitespace include all neighbouring leading whitespaces and the following word. */
+/* word which happens to be at pos, includes trailing white spaces. if at pos
+ * happens to be a whitespace include all neighbouring leading whitespaces
+ * and the following word. */
Filerange text_object_word(Text*, size_t pos);
Filerange text_object_word_boundry(Text*, size_t pos, int (*isboundry)(int));
Filerange text_object_line(Text*, size_t pos);
Filerange text_object_sentence(Text*, size_t pos);
Filerange text_object_paragraph(Text*, size_t pos);
-/* the delimiters themself are not included in the range */
+/* these are inner text objects i.e. the delimiters themself are not
+ * included in the range */
Filerange text_object_square_bracket(Text*, size_t pos);
Filerange text_object_curly_bracket(Text*, size_t pos);
Filerange text_object_angle_bracket(Text*, size_t pos);
diff --git a/text.c b/text.c
index dac2b41..9879f98 100644
--- a/text.c
+++ b/text.c
@@ -871,7 +871,7 @@ bool text_iterator_byte_prev(Iterator *it, char *b) {
bool text_iterator_char_next(Iterator *it, char *c) {
while (text_iterator_byte_next(it, NULL)) {
- if (isutf8(*it->text)) {
+ if (ISUTF8(*it->text)) {
if (c)
*c = *it->text;
return true;
@@ -882,7 +882,7 @@ bool text_iterator_char_next(Iterator *it, char *c) {
bool text_iterator_char_prev(Iterator *it, char *c) {
while (text_iterator_byte_prev(it, NULL)) {
- if (isutf8(*it->text)) {
+ if (ISUTF8(*it->text)) {
if (c)
*c = *it->text;
return true;
diff --git a/text.h b/text.h
index 1b4bc2b..e133af0 100644
--- a/text.h
+++ b/text.h
@@ -7,7 +7,7 @@
typedef size_t Filepos;
typedef struct {
- size_t start, end; /* range in bytes from start of file */
+ size_t start, end; /* range in bytes from start of the file */
} Filerange;
typedef struct Text Text;
diff --git a/util.h b/util.h
index b2446a7..f2e3d65 100644
--- a/util.h
+++ b/util.h
@@ -6,7 +6,7 @@
#define MAX(a, b) ((a) < (b) ? (b) : (a))
/* is c the start of a utf8 sequence? */
-#define isutf8(c) (((c)&0xC0)!=0x80)
-#define ISASCII(ch) ((unsigned char)ch < 0x80)
+#define ISUTF8(c) (((c)&0xC0)!=0x80)
+#define ISASCII(ch) ((unsigned char)ch < 0x80)
#endif
diff --git a/vis.c b/vis.c
index 3afa2fa..3aefc9a 100644
--- a/vis.c
+++ b/vis.c
@@ -28,13 +28,13 @@ typedef union {
bool b;
size_t i;
const char *s;
- size_t (*m)(Win*);
- void (*f)(Editor*);
+ size_t (*m)(Win*); /* cursor movement based on window content */
+ void (*f)(Editor*); /* generic editor commands */
} Arg;
typedef struct {
- char str[6];
- int code;
+ char str[6]; /* UTF8 character or terminal escape code */
+ int code; /* curses KEY_* constant */
} Key;
typedef struct {
@@ -45,29 +45,30 @@ typedef struct {
typedef struct Mode Mode;
struct Mode {
- Mode *parent;
- KeyBinding *bindings;
- const char *name;
- bool common_prefix;
- void (*enter)(Mode *old);
- void (*leave)(Mode *new);
- bool (*unknown)(Key *key0, Key *key1); /* unknown key for this mode, return value determines whether parent modes will be checked */
- void (*input)(const char *str, size_t len); /* unknown key for this an all parent modes */
- void (*idle)(void);
+ 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 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)(Key*, Key*); /* called whenever a key 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 */
};
typedef struct {
- char *name;
- Mode *mode;
- editor_statusbar_t statusbar;
+ char *name; /* is used to match against argv[0] to enable this config */
+ Mode *mode; /* default mode in which the editor should start in */
+ editor_statusbar_t statusbar; /* routine which is called whenever the cursor is moved within a window */
} Config;
typedef struct {
- int count;
- Register *reg;
- Filerange range;
- size_t pos;
- bool linewise;
+ 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? */
} OperatorContext;
typedef struct {
@@ -76,9 +77,9 @@ typedef struct {
} Operator;
typedef struct {
- size_t (*cmd)(const Arg*);
- size_t (*win)(Win*);
- size_t (*txt)(Text*, size_t pos);
+ 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,
@@ -89,14 +90,14 @@ typedef struct {
} Movement;
typedef struct {
- Filerange (*range)(Text*, size_t pos);
+ Filerange (*range)(Text*, size_t pos); /* a text object from text-objects.h */
enum {
INNER,
OUTER,
} type;
} TextObject;
-typedef struct {
+typedef struct { /** collects all information until an operator is executed */
int count;
bool linewise;
Operator *op;
@@ -108,31 +109,43 @@ typedef struct {
Arg arg;
} Action;
-typedef struct {
- const char *name;
- bool (*cmd)(const char *argv[]);
- regex_t regex;
+typedef struct { /* command definitions for the ':'-prompt */
+ const char *name; /* regular expression pattern to match command */
+ bool (*cmd)(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. */
+ regex_t regex; /* compiled form of the pattern in 'name' */
} Command;
-/* global variables */
-static Editor *vis; /* global editor instance, keeps track of all windows etc. */
+/** global variables */
+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; /* mode which was active previously */
static Action action; /* current action which is in progress */
static Action action_prev; /* last operator action used by the repeat '.' key */
-/* movements which can be used besides the one in text-motions.h and window.h */
-static size_t search_forward(const Arg *arg);
-static size_t search_backward(const Arg *arg);
-static size_t mark_goto(const Arg *arg);
-static size_t mark_line_goto(const Arg *arg);
-static size_t to(const Arg *arg);
-static size_t till(const Arg *arg);
-static size_t to_left(const Arg *arg);
-static size_t till_left(const Arg *arg);
-static size_t line(const Arg *arg);
-static size_t column(const Arg *arg);
+/** operators */
+static void op_change(OperatorContext *c);
+static void op_yank(OperatorContext *c);
+static void op_paste(OperatorContext *c);
+static void op_delete(OperatorContext *c);
+
+/* these can be passed as int argument to operator(&(const Arg){ .i = OP_*}) */
+enum {
+ OP_DELETE,
+ OP_CHANGE,
+ OP_YANK,
+ OP_PASTE,
+};
+static Operator ops[] = {
+ [OP_DELETE] = { op_delete, false },
+ [OP_CHANGE] = { op_change, false },
+ [OP_YANK] = { op_yank, false },
+ [OP_PASTE] = { op_paste, true },
+};
+
+/* these can be passed as int argument to movement(&(const Arg){ .i = MOVE_* }) */
enum {
MOVE_LINE_UP,
MOVE_LINE_DOWN,
@@ -165,6 +178,27 @@ enum {
MOVE_SEARCH_BACKWARD,
};
+/** movements which can be used besides the one in text-motions.h and window.h */
+/* 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, or if zero to end of file */
+static size_t line(const Arg *arg);
+/* goto to byte action.count on current line */
+static size_t column(const Arg *arg);
+
static Movement moves[] = {
[MOVE_LINE_UP] = { .win = window_line_up },
[MOVE_LINE_DOWN] = { .win = window_line_down },
@@ -197,7 +231,7 @@ static Movement moves[] = {
[MOVE_SEARCH_BACKWARD] = { .cmd = search_backward, .type = LINEWISE },
};
-/* available text objects */
+/* these can be passed as int argument to textobj(&(const Arg){ .i = TEXT_OBJ_* }) */
enum {
TEXT_OBJ_WORD,
TEXT_OBJ_LINE_UP,
@@ -248,46 +282,84 @@ static TextObject *moves_linewise[] = {
[MOVE_LINE_DOWN] = &textobjs[TEXT_OBJ_LINE_DOWN],
};
-/* functions to be called from keybindings */
+/** functions to be called from keybindings */
+/* 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 \n\r depending on file type) */
static void insert_newline(const Arg *arg);
+/* split current window horizontally (default) or vertically (if arg->b is set) */
static void split(const Arg *arg);
-static void quit(const Arg *arg);
+/* perform last action i.e. action_prev again */
static void repeat(const Arg *arg);
+/* adjust action.count by arg->i */
static void count(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);
+/* 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);
+/* delete from the current cursor position to the start of the previous word */
static void delete_word(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(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);
+/* blocks to read 3 consecutive digits and inserts the corresponding byte value */
static void insert_verbatim(const Arg *arg);
+/* cursor movement based on the current window content as indicated by arg->m
+ * which should point to a function from window.h */
static void cursor(const Arg *arg);
+/* call editor function as indicated by arg->f */
static void call(const Arg *arg);
+static void quit(const Arg *arg);
-/* commands to enter at the ':'-prompt */
+/** commands to enter at the ':'-prompt */
+/* goto line indicated by argv[0] */
static bool cmd_gotoline(const char *argv[]);
+/* for each argument create a new window and open the corresponding file */
static bool cmd_open(const char *argv[]);
+/* close the current window, if argv[0] contains a '!' discard modifications */
static bool cmd_quit(const char *argv[]);
+/* for each argument try to insert the file content at current cursor postion */
static bool cmd_read(const char *argv[]);
static bool cmd_substitute(const char *argv[]);
+/* if no argument are given, split the current window horizontally,
+ * otherwise open the file */
static bool cmd_split(const char *argv[]);
+/* if no argument are given, split the current window vertically,
+ * otherwise open the file */
static bool cmd_vsplit(const char *argv[]);
+/* save the file displayed in the current window and close it */
static bool cmd_wq(const char *argv[]);
+/* save the file displayed in the current window to the name given */
static bool cmd_write(const char *argv[]);
static void action_reset(Action *a);
@@ -299,7 +371,7 @@ static Key getkey(void);
static void action_do(Action *a);
static bool exec_command(char *cmdline);
-/* operator implementations of type: void (*op)(OperatorContext*) */
+/** operator implementations of type: void (*op)(OperatorContext*) */
static void op_delete(OperatorContext *c) {
size_t len = c->range.end - c->range.start;
@@ -327,7 +399,7 @@ static void op_paste(OperatorContext *c) {
window_cursor_to(vis->win->win, pos + c->reg->len);
}
-/* movement implementations of type: size_t (*move)(const Arg*) */
+/** movement implementations of type: size_t (*move)(const Arg*) */
static size_t search_forward(const Arg *arg) {
size_t pos = window_cursor_get(vis->win->win);
@@ -388,7 +460,7 @@ static size_t column(const Arg *arg) {
return it.pos;
}
-/* key bindings functions of type: void (*func)(const Arg*) */
+/** key bindings functions of type: void (*func)(const Arg*) */
static void repeat(const Arg *arg) {
action = action_prev;
@@ -542,7 +614,10 @@ static void quit(const Arg *arg) {
}
static void split(const Arg *arg) {
- editor_window_split(vis, arg->s);
+ if (arg->b)
+ editor_window_vsplit(vis, arg->s);
+ else
+ editor_window_split(vis, arg->s);
}
static void cursor(const Arg *arg) {
@@ -570,7 +645,7 @@ static void switchmode(const Arg *arg) {
switchmode_to(&vis_modes[arg->i]);
}
-/* action processing, executed the operator / movement / text object */
+/** action processing: execut the operator / movement / text object */
static void action_do(Action *a) {
Text *txt = vis->win->text;
@@ -684,9 +759,7 @@ static void switchmode_to(Mode *new_mode) {
}
-
-
-/* ':'-command implementations */
+/** ':'-command implementations */
static bool cmd_gotoline(const char *argv[]) {
action.count = strtoul(argv[0], NULL, 10);
diff --git a/window.c b/window.c
index a2209de..bdb5ce3 100644
--- a/window.c
+++ b/window.c
@@ -68,12 +68,10 @@ struct Win { /* window showing part of a file */
Line *bottomline; /* bottom of screen, might be unused if lastline < bottomline */
Filerange sel; /* selected text range in bytes from start of file */
Cursor cursor; /* current window cursor position */
- void (*cursor_moved)(Win*, void *);
- void *cursor_moved_data;
-
- Line *line; // TODO: rename to something more descriptive, these are the current drawing pos
- int col;
-
+ void (*cursor_moved)(Win*, void *); /* registered callback, fires whenever the cursor moved */
+ void *cursor_moved_data; /* user supplied data, passed as second argument to the above callback */
+ Line *line; /* used while drawing window content, line where next char will be drawn */
+ int col; /* used while drawing window content, column where next char will be drawn */
Syntax *syntax; /* syntax highlighting definitions for this window or NULL */
int tabwidth; /* how many spaces should be used to display a tab character */
};
@@ -92,6 +90,7 @@ void window_selection_clear(Win *win) {
window_cursor_update(win);
}
+/* reset internal window data structures (cell matrix, line offsets etc.) */
static void window_clear(Win *win) {
size_t line_size = sizeof(Line) + win->width*sizeof(Cell);
win->topline = win->lines;
@@ -129,6 +128,7 @@ Filerange window_selection_get(Win *win) {
Filerange window_viewport_get(Win *win) {
return (Filerange){ .start = win->start, .end = win->end };
}
+
/* try to add another character to the window, return whether there was space left */
static bool window_addch(Win *win, Char *c) {
if (!win->line)
@@ -249,7 +249,7 @@ void window_cursor_getxy(Win *win, size_t *lineno, size_t *col) {
}
/* place the cursor according to the screen coordinates in win->{row,col} and
- * update the statusbar. if a selection is active, redraw the window to reflect
+ * fire user callback. if a selection is active, redraw the window to reflect
* its changes. */
static size_t window_cursor_update(Win *win) {
Cursor *cursor = &win->cursor;
@@ -341,7 +341,7 @@ void window_draw(Win *win) {
/* current selection */
Filerange sel = window_selection_get(win);
/* matched tokens for each syntax rule */
- regmatch_t match[SYNTAX_REGEX_RULES][1];
+ regmatch_t match[SYNTAX_RULES][1];
if (win->syntax) {
for (int i = 0; i < LENGTH(win->syntax->rules); i++) {
SyntaxRule *rule = &win->syntax->rules[i];
@@ -394,7 +394,7 @@ void window_draw(Win *win) {
/* ok, we encountered an invalid multibyte sequence,
* replace it with the Unicode Replacement Character
* (FFFD) and skip until the start of the next utf8 char */
- for (len = 1; rem > len && !isutf8(cur[len]); len++);
+ for (len = 1; rem > len && !ISUTF8(cur[len]); len++);
c = (Char){ .c = "\xEF\xBF\xBD", .wchar = 0xFFFD, .len = len };
} else if (len == (size_t)-2) {
/* not enough bytes available to convert to a
diff --git a/window.h b/window.h
index 2f5d5ee..fc9cd43 100644
--- a/window.h
+++ b/window.h
@@ -23,7 +23,8 @@ void window_draw(Win*);
/* flush all changes made to the ncurses windows to the screen */
void window_update(Win*);
-/* cursor movements, also updates selection if one is active, returns new cursor postion */
+/* cursor movements which also update selection if one is active.
+ * they return new cursor postion */
size_t window_page_down(Win*);
size_t window_page_up(Win*);
size_t window_char_next(Win*);
@@ -31,17 +32,32 @@ size_t window_char_prev(Win*);
size_t window_line_down(Win*);
size_t window_line_up(Win*);
+/* get cursor position in bytes from start of the file */
size_t window_cursor_get(Win*);
+/* get cursor position in terms of screen coordinates */
void window_cursor_getxy(Win*, size_t *lineno, size_t *col);
+/* moves window viewport in direction until pos is visible. should only be
+ * used for short distances between current cursor position and destination */
void window_scroll_to(Win*, size_t pos);
+/* move cursor to a given position. changes the viewport to make sure that
+ * position is visible. if the position is in the middle of a line, try to
+ * adjust the viewport in such a way that the whole line is displayed */
void window_cursor_to(Win*, size_t pos);
+/* start selected area at current cursor position. further cursor movements will
+ * affect the selected region. */
void window_selection_start(Win*);
void window_selection_end(Win*);
+/* returns the currently selected text region, is either empty or well defined,
+ * i.e. sel.start <= sel.end */
Filerange window_selection_get(Win*);
+/* clear selection and redraw window */
void window_selection_clear(Win*);
+/* get the currently displayed area in bytes from the start of the file */
Filerange window_viewport_get(Win*);
+/* associate a set of syntax highlighting rules to this window. */
void window_syntax_set(Win*, Syntax*);
Syntax *window_syntax_get(Win*);
+/* register a user defined function which will be called whenever the cursor has moved */
void window_cursor_watch(Win *win, void (*cursor_moved)(Win*, void*), void *data);
#endif