diff options
| -rw-r--r-- | doc/index.rst | 1 | ||||
| -rw-r--r-- | doc/vis.rst | 187 | ||||
| -rw-r--r-- | main.c | 2 | ||||
| -rw-r--r-- | vis-cmds.c | 4 | ||||
| -rw-r--r-- | vis-motions.c | 3 | ||||
| -rw-r--r-- | vis-text-objects.c | 3 | ||||
| -rw-r--r-- | vis.c | 9 | ||||
| -rw-r--r-- | vis.h | 698 |
8 files changed, 731 insertions, 176 deletions
diff --git a/doc/index.rst b/doc/index.rst index c7f8b10..ef53ca8 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -4,6 +4,7 @@ Vis Editor API Documenation .. toctree:: :maxdepth: 2 + vis text buffer array diff --git a/doc/vis.rst b/doc/vis.rst new file mode 100644 index 0000000..1774552 --- /dev/null +++ b/doc/vis.rst @@ -0,0 +1,187 @@ +Vis +=== + +The core Vis API. + +Lifecycle +--------- + +.. doxygengroup:: vis_lifecycle + :content-only: + +Draw +---- + +.. doxygengroup:: vis_draw + :content-only: + +Windows +------- + +.. doxygengroup:: vis_windows + :content-only: + +Input +----- + +The editor core processes input through a sequences of symbolic keys: + + * Special keys such as ``<Enter>``, ``<Tab>`` or ``<Backspace>`` as reported by + `termkey_strfkey <http://www.leonerd.org.uk/code/libtermkey/doc/termkey_strfkey.3.html>`_. + + .. note:: The prefixes ``C-``, ``S-`` and ``M-`` are used to denote the ``Ctrl``, + ``Shift`` and ``Alt`` modifiers, respectively. + + * Key action names as registered with `vis_action_register`. + + .. note:: By convention they are prefixed with ``vis-`` as in ``<vis-nop>``. + + * Regular UTF-8 encoded input. + +.. note:: An exhaustive list of the first two types is displayed in the ``:help`` output. + +.. doxygengroup:: vis_keys + :content-only: + +Key Map +------- + +The key map is used to translate keys in non-input modes, *before* any key +bindings are evaluated. It is intended to facilitate usage of non-latin keyboard +layouts. + +.. doxygengroup:: vis_keymap + :content-only: + +Key Binding +----------- + +Each mode has a set of key bindings. A key binding maps a key to either +another key (referred to as an alias) or a key action (implementing an +editor operation). + +If a key sequence is ambiguous (i.e. it is a prefix of multiple mappings) +more input is awaited, until a unique mapping can be resolved. + +.. warning:: Key aliases are always evaluated recursively. + +.. doxygengroup:: vis_keybind + :content-only: + +Key Action +---------- + +A key action is invoked by a key binding and implements a certain editor function. + +The editor operates like a finite state machine with key sequences as +transition labels. Once a prefix of the input queue uniquely refers to a +key action, it is invoked with the remainder of the input queue passed as argument. + +.. note:: A triggered key action currently does not know through which key binding + it was invoked. TODO: change that? + +.. doxygengroup:: vis_action + :content-only: + +Modes +----- + +A mode defines *enter*, *leave* and *idle* actions and captures a set of +key bindings. + +Modes are hierarchical, key bindings are searched recursively towards +the top of the hierarchy stopping at the first match. + +.. doxygenenum:: VisMode +.. doxygengroup:: vis_modes + :content-only: + +Count +----- + +Dictates how many times a motion or text object is evaluated. If none +is specified, a minimal count of 1 is assumed. + +.. doxygengroup:: vis_count + :content-only: + +Operators +--------- + +.. doxygengroup:: vis_operators + :content-only: + +Motions +------- + +.. doxygengroup:: vis_motions + :content-only: + +Text Objects +------------ + +.. doxygengroup:: vis_textobjs + :content-only: + +Marks +----- + +Marks keep track of a given text position. + +.. note:: Marks are currently file local. + +.. doxygengroup:: vis_marks + :content-only: + +Registers +--------- + +.. doxygengroup:: vis_registers + :content-only: + +Macros +------ + +Macros are a sequence of keys stored in a Register which can be reprocessed +as if entered by the user. + +.. warning:: Macro support is currently half-baked. If you do something stupid + (e.g. use mutually recursive macros), you will likely encounter + stack overflows. + +.. doxygengroup:: vis_macros + :content-only: + +Commands +-------- + +.. doxygengroup:: vis_cmds + :content-only: + +Options +------- + +.. doxygengroup:: vis_options + :content-only: + +Modification +------------ + +These function operate on the currently focused window but ensure that +all windows which show the affected region are redrawn too. + +.. doxygengroup:: vis_changes + :content-only: + +Interaction +----------- + +.. doxygengroup:: vis_info + :content-only: + +Miscellaneous +------------- + +.. doxygengroup:: vis_misc + :content-only: + @@ -2167,7 +2167,7 @@ int main(int argc, char *argv[]) { vis_prompt_cmd(vis, cmd); } - int status = vis_run(vis, argc, argv); + int status = vis_run(vis); vis_free(vis); return status; } @@ -6,7 +6,7 @@ // FIXME: avoid this redirection? typedef struct { CommandDef def; - CmdFunc *func; + VisCommandFunction *func; void *data; } CmdUser; @@ -18,7 +18,7 @@ static void cmdfree(CmdUser *cmd) { free(cmd); } -bool vis_cmd_register(Vis *vis, const char *name, const char *help, void *data, CmdFunc *func) { +bool vis_cmd_register(Vis *vis, const char *name, const char *help, void *data, VisCommandFunction *func) { if (!name) return false; if (!vis->usercmds && !(vis->usercmds = map_new())) diff --git a/vis-motions.c b/vis-motions.c index 92ab995..9917ce5 100644 --- a/vis-motions.c +++ b/vis-motions.c @@ -293,8 +293,7 @@ void vis_motion_type(Vis *vis, enum VisMotionType type) { vis->action.type = type; } -int vis_motion_register(Vis *vis, enum VisMotionType type, void *data, - size_t (*motion)(Vis*, Win*, void*, size_t pos)) { +int vis_motion_register(Vis *vis, enum VisMotionType type, void *data, VisMotionFunction *motion) { Movement *move = calloc(1, sizeof *move); if (!move) diff --git a/vis-text-objects.c b/vis-text-objects.c index 467c101..446ac6d 100644 --- a/vis-text-objects.c +++ b/vis-text-objects.c @@ -2,8 +2,7 @@ #include "text-objects.h" #include "util.h" -int vis_textobject_register(Vis *vis, int type, void *data, - Filerange (*textobject)(Vis*, Win*, void*, size_t pos)) { +int vis_textobject_register(Vis *vis, int type, void *data, VisTextObjectFunction *textobject) { TextObject *obj = calloc(1, sizeof *obj); if (!obj) @@ -558,6 +558,10 @@ void vis_suspend(Vis *vis) { vis->ui->suspend(vis->ui); } +void vis_resume(Vis *vis) { + vis->ui->resume(vis->ui); +} + bool vis_window_new(Vis *vis, const char *filename) { File *file = file_new(vis, filename); if (!file) @@ -1298,7 +1302,7 @@ bool vis_signal_handler(Vis *vis, int signum, const siginfo_t *siginfo, const vo return false; } -int vis_run(Vis *vis, int argc, char *argv[]) { +int vis_run(Vis *vis) { if (!vis->windows) return EXIT_SUCCESS; if (vis->exit_status != -1) @@ -1347,9 +1351,10 @@ int vis_run(Vis *vis, int argc, char *argv[]) { } if (vis->resume) { - vis->ui->resume(vis->ui); + vis_resume(vis); vis->resume = false; } + if (vis->need_resize) { vis->ui->resize(vis->ui); vis->need_resize = false; @@ -39,6 +39,9 @@ typedef struct Win Win; /* maximum bytes needed for string representation of a (pseudo) key */ #define VIS_KEY_LENGTH_MAX 64 +/** + * Editor event handlers. + */ typedef struct { void (*init)(Vis*); void (*start)(Vis*); @@ -55,7 +58,8 @@ typedef struct { void (*win_status)(Vis*, Win*); } VisEvent; -typedef union { /* various types of arguments passed to key action functions */ +/** Union used to pass arguments to key action functions. */ +typedef union { bool b; int i; const char *s; @@ -64,145 +68,298 @@ typedef union { /* various types of arguments passed to key action functions */ void (*f)(Vis*); } Arg; -/* action handling function, keys refers to the next characters found in the input queue - * (an empty string "" indicates an empty queue). The return value of func has to point to - * the first non consumed key. Returning NULL indicates that not enough keys were available - * to complete the action. In this case the function will be called again when more input - * becomes available */ +/** + * Key action handling function. + * @param keys Input queue content *after* the binding which invoked this function. + * @rst + * .. note:: An empty string ``""`` indicates that no further input is available. + * @endrst + * @return Pointer to first non-cosumed key. + * @rst + * .. warning:: Must be in range ``[keys, keys+strlen(keys)]`` or ``NULL`` to + * indicate that not enough input was available. In the latter case + * the function will be called again once more input has been received. + * @endrst + * @ingroup vis_action + */ typedef const char *KeyActionFunction(Vis*, const char *keys, const Arg*); -typedef struct { /* a KeyAction can be bound to a key binding */ - const char *name; /* aliases can refer to this action by means of a pseudo key <name> */ - VIS_HELP_DECL(const char *help;) /* short (one line) human readable description, displayed by :help */ - KeyActionFunction *func; /* action implementation */ - Arg arg; /* additional arguments which will be passed as to func */ +/** Key action definition. */ +typedef struct { + const char *name; /**< Name of a pseudo key ``<name>`` which can be used in mappings. */ + VIS_HELP_DECL(const char *help;) /**< One line human readable description, displayed by ``:help``. */ + KeyActionFunction *func; /**< Key action implementation function. */ + Arg arg; /**< Options passes as last argument to ``func``. */ } KeyAction; -typedef struct { /* a key binding either refers to an action or an alias */ - const char *key; /* symbolic key to trigger this binding */ - const KeyAction *action; /* action to launch upon triggering this binding */ - const char *alias; /* replaces key with alias in the input queue */ +/** + * A key binding, refers to an action or an alias + * @rst + * .. note:: Either ``action`` or ``alias`` must be ``NULL``. + * @endrst + */ +typedef struct { + const char *key; /**< Symbolic key to trigger this binding. */ + const KeyAction *action; /**< Action to invoke when triggering this binding. */ + const char *alias; /**< Replaces ``key`` with ``alias`` at the front of the input queue. */ } KeyBinding; -/* creates a new editor instance using the specified user interface */ +/** + * @defgroup vis_lifecycle + * @{ + */ +/** Create a new editor instance using the given user interface and event handlers. */ Vis *vis_new(Ui*, VisEvent*); -/* frees all resources associated with this editor instance, terminates ui */ +/** Free all resources associated with this editor instance, terminates UI. */ void vis_free(Vis*); -/* instructs the user interface to draw to an internal buffer */ +/** + * Enter main loop, start processing user input. + * @return The editor exit status code. + */ +int vis_run(Vis*); +/** Terminate editing session, the given ``status`` will be the return value of `vis_run`. */ +void vis_exit(Vis*, int status); +/** + * Emergency exit, print given message, perform minimal UI cleanup and exit process. + * @rst + * .. note:: This function does not return. + * @endrst + */ +void vis_die(Vis*, const char *msg, ...) __attribute__((noreturn,format(printf, 2, 3))); + +/** + * Temporarily supsend the editor process. + * @rst + * .. note:: This function will generate a ``SIGTSTP`` signal. + * @endrst + **/ +void vis_suspend(Vis*); +/** + * Resume editor process. + * @rst + * .. note:: This function is usually called in response to a ``SIGCONT`` signal. + * @endrst + */ +void vis_resume(Vis*); +/** + * Inform the editor core that a signal occured. + * @return Whether the signal was handled. + * @rst + * .. note:: Being designed as a library the editor core does *not* register any + * signal handlers on its own. + * .. note:: The remaining arguments match the prototype of ``sa_sigaction`` as + * specified in `sigaction(2)`. + * @endrst + */ +bool vis_signal_handler(Vis*, int signum, const siginfo_t *siginfo, const void *context); +/** + * @} + * @defgroup vis_draw + * @{ + */ +/** Draw user interface. */ void vis_draw(Vis*); +/** Completely redraw user interface. */ void vis_redraw(Vis*); -/* flushes the state of the internal buffer to the output device */ +/** Blit user interface state to output device. */ void vis_update(Vis*); -/* temporarily supsend the editor process, resumes upon receiving SIGCONT */ -void vis_suspend(Vis*); -void vis_resume(Vis*); - -/* creates a new window, and loads the given file. if filename is NULL - * an unamed / empty buffer is created. If the given file is already opened - * in another window, share the underlying text that is changes will be - * visible in both windows */ +/** + * @} + * @defgroup vis_windows + * @{ + */ +/** + * Create a new window and load the given file. + * @param filename If ``NULL`` a unamed, empty buffer is created. + * @rst + * .. note:: If the given file name is already opened in another window, + * the underlying File object is shared. + * .. warning:: This duplication detection is currently based on normalized, + * absolute file names. TODO: compare inodes instead. + * @endrst + */ bool vis_window_new(Vis*, const char *filename); -/* Creates a new window and underlying file object associated with the - * given output file descriptor. No data is read from `fd`, but write - * commands without an explicit filename will instead write to the file - * descriptor */ +/** + * Create a new window associated with a file descriptor. + * @rst + * .. note:: No data is read from `fd`, but write commands without an + * explicit filename will instead write to the file descriptor. + * @endrst + */ bool vis_window_new_fd(Vis*, int fd); -/* reload the file currently displayed in the window from disk */ +/** Reload the file currently displayed in the window from disk. */ bool vis_window_reload(Win*); -/* check whether closing the window would loose unsaved changes */ +/** Check whether closing the window would loose unsaved changes. */ bool vis_window_closable(Win*); -/* close window, redraw user interface */ +/** Close window, redraw user interface. */ void vis_window_close(Win*); -/* split the given window. changes to the displayed text will be reflected - * in both windows */ +/** Split the window, shares the underlying file object. */ bool vis_window_split(Win*); -/* change status message of this window */ +/** Change status message of this window. */ void vis_window_status(Win*, const char *status); void vis_window_draw(Win*); void vis_window_invalidate(Win*); -/* focus the next / previous window */ +/** Focus next window. */ void vis_window_next(Vis*); +/** Focus previous window. */ void vis_window_prev(Vis*); -/* change currently focused window, receiving user input */ +/** Change currently focused window, receiving user input. */ void vis_window_focus(Win*); -/* swap location of two windows */ +/** Swap location of two windows. */ void vis_window_swap(Win*, Win*); - +/** Query window dimension. */ int vis_window_width_get(const Win*); +/** Query window dimension. */ int vis_window_height_get(const Win*); - -/* take an undo snaphost to which we can later revert to */ -void vis_file_snapshot(Vis*, File*); - -/* display a user prompt with a certain title and default text */ +/** + * @} + * @defgroup vis_info + * @{ + */ +/** + * Display a user prompt with a certain title. + * @rst + * .. note:: The prompt is currently implemented as a single line height window. + * @endrst + */ void vis_prompt_show(Vis*, const char *title); -/* display a one line message to the user, will be hidden upon keypress */ +/** + * Display a single line message. + * @rst + * .. note:: The message will automatically be hidden upon next input. + * @endrst + */ void vis_info_show(Vis*, const char *msg, ...) __attribute__((format(printf, 2, 3))); +/** Hide informational message. */ void vis_info_hide(Vis*); -/* display an arbitrary long message in a special window/file */ +/** Display arbitrary long message in a dedicated window. */ void vis_message_show(Vis*, const char *msg); +/** Close message window. */ void vis_message_hide(Vis*); - -/* these function operate on the currently focused window but make sure - * that all windows which show the affected region are redrawn too. */ +/** + * @} + * @defgroup vis_changes + * @{ + */ void vis_insert(Vis*, size_t pos, const char *data, size_t len); void vis_delete(Vis*, size_t pos, size_t len); void vis_replace(Vis*, size_t pos, const char *data, size_t len); -/* these functions perform their operation at the current cursor position(s) */ +/** Perform insertion at all cursor positions. */ void vis_insert_key(Vis*, const char *data, size_t len); +/** + * Perform character subsitution at all cursor positions. + * @rst + * .. note:: Does not replace new line characters. + * @endrst + */ void vis_replace_key(Vis*, const char *data, size_t len); -/* inserts a tab (peforms tab expansion based on current editing settings), - * at all current cursor positions */ +/** + * Insert a tab at all cursor positions. + * @rst + * .. note:: Performs tab expansion according to current settings. + * @endrst + */ void vis_insert_tab(Vis*); -/* inserts a \n character at every cursor position */ +/** + * Inserts a new line character at every cursor position. + * @rst + * .. note:: Performs auto indentation according to current settings. + * @endrst + */ void vis_insert_nl(Vis*); -/* processes the given command line arguments and starts the main loop, won't - * return until editing session is terminated */ -int vis_run(Vis*, int argc, char *argv[]); -/* terminate editing session, given status will be the return value of vis_run */ -void vis_exit(Vis*, int status); -/* emergency exit, print given message, perform minimal ui cleanup and exit process */ -void vis_die(Vis*, const char *msg, ...) __attribute__((noreturn,format(printf, 2, 3))); - -KeyBinding *vis_binding_new(Vis*); -void vis_binding_free(Vis*, KeyBinding*); - +/** @} */ +/** Mode specifiers. */ enum VisMode { VIS_MODE_NORMAL, VIS_MODE_OPERATOR_PENDING, VIS_MODE_VISUAL, - VIS_MODE_VISUAL_LINE, + VIS_MODE_VISUAL_LINE, /**< Sub mode of `VIS_MODE_VISUAL`. */ VIS_MODE_INSERT, - VIS_MODE_REPLACE, + VIS_MODE_REPLACE, /**< Sub mode of `VIS_MODE_INSERT`. */ VIS_MODE_INVALID, }; +/** + * @defgroup vis_modes + * @{ + */ +/** + * Switch mode. + * @rst + * .. note:: Will first trigger the leave event of the currently active + * mode, followed by an enter event of the new mode. + * No events are emitted, if the specified mode is already active. + * @endrst + */ void vis_mode_switch(Vis*, enum VisMode); +/** Get currently active mode. */ enum VisMode vis_mode_get(Vis*); +/** Translate human readable mode name to constant. */ enum VisMode vis_mode_from(Vis*, const char *name); -/* In the specified mode: map a given key to a binding (binding->key is ignored). - * Fails if a prefix of `key' is already mapped and `force' is false. Otherwise - * all such prefixes are unmapped. */ + +/** + * @} + * @defgroup vis_keybind + * @{ + */ +KeyBinding *vis_binding_new(Vis*); +void vis_binding_free(Vis*, KeyBinding*); + +/** + * Set up a key binding. + * @param force Whether an existing mapping should be discarded. + * @param key The symbolic key to map. + * @param binding The binding to map. + * @rst + * .. note:: ``binding->key`` is always ignored in favor of ``key``. + * @endrst + */ bool vis_mode_map(Vis*, enum VisMode, bool force, const char *key, const KeyBinding*); +/** Analogous to `vis_mode_map`, but window specific. */ bool vis_window_mode_map(Win*, enum VisMode, bool force, const char *key, const KeyBinding*); -/* in the specified mode: unmap a given key, fails if the key is not currently mapped */ +/** Unmap a symbolic key in a given mode. */ bool vis_mode_unmap(Vis*, enum VisMode, const char *key); +/** Analogous to `vis_mode_unmap`, but window specific. */ bool vis_window_mode_unmap(Win*, enum VisMode, const char *key); - +/** + * @} + * @defgroup vis_action + * @{ + */ +/** + * Create new key action. + * @param name The name to be used as symbolic key when registering. + * @param help Optional single line help text. + * @param func The function implementing the key action logic. + * @param arg Argument passed to function. + */ KeyAction *vis_action_new(Vis*, const char *name, const char *help, KeyActionFunction*, Arg); void vis_action_free(Vis*, KeyAction*); -/* associates the special pseudo key <keyaction->name> with the given key action. - * after successfull registration the pseudo key can be used key binding aliases */ +/** + * Register key action. + * @rst + * .. note:: Makes the key action available under the pseudo key name specified + * in ``keyaction->name``. + * @endrst + */ bool vis_action_register(Vis*, const KeyAction*); -/* add a key mapping which is applied for all modes except insert/replace - * before any key bindings are evaluated */ + +/** + * @} + * @defgroup vis_keymap + * @{ + */ + +/** Add a key translation. */ bool vis_keymap_add(Vis*, const char *key, const char *mapping); -/* disable the keymap for the next key press */ +/** Temporarily disable the keymap for the next key press. */ void vis_keymap_disable(Vis*); +/** @} */ +/** Operator specifiers. */ enum VisOperator { VIS_OP_DELETE, VIS_OP_CHANGE, @@ -227,26 +384,57 @@ enum VisOperator { VIS_OP_LAST, /* has to be last enum member */ }; -/* set operator to execute, has immediate effect if - * - a visual mode is active - * - the same operator was already set (range will be the current line) - * otherwise waits until a range is determinded i.e. - * - a motion is provided (see vis_motion) - * - a text object is provided (vis_textobject) +/** + * @defgroup vis_operators + * @{ + */ +typedef struct OperatorContext OperatorContext; + +/** + * An operator performs a certain function on a given text range. + * @rst + * .. note:: The operator must return the new cursor position or ``EPOS`` if + * the cursor should be disposed. + * .. note:: The last used operator can be repeated using `vis_repeat`. + * @endrst + */ +typedef size_t (VisOperatorFunction)(Vis*, Text*, OperatorContext*); + +/** + * Register an operator. + * @return Operator ID. Negative values indicate an error, positive ones can be + * used with `vis_operator`. + */ +int vis_operator_register(Vis*, VisOperatorFunction*, void *context); + +/** + * Set operator to execute. + * + * Has immediate effect if: + * - A visual mode is active. + * - The same operator was already set (range will be the current line). * - * the expected varying arguments are as follows: + * Otherwise the operator will be executed on the range determinded by: + * - A motion (see `vis_motion`). + * - A text object (`vis_textobject`). * - * - VIS_OP_FILTER a char pointer referring to the command to run - * - VIS_OP_JOIN a char pointer referring to the text to insert between lines - * - VIS_OP_MODESWITCH a enum VisMode constant indicating the mode to switch to - * - VIS_OP_REPLACE a char pointer reffering to the replacement character + * The expected varying arguments are: + * + * - `VIS_OP_FILTER` a char pointer referring to the command to run. + * - `VIS_OP_JOIN` a char pointer referring to the text to insert between lines. + * - `VIS_OP_MODESWITCH` an ``enum VisMode`` indicating the mode to switch to. + * - `VIS_OP_REPLACE` a char pointer reffering to the replacement character. */ bool vis_operator(Vis*, enum VisOperator, ...); -typedef struct OperatorContext OperatorContext; -typedef size_t (VisOperatorFunction)(Vis*, Text*, OperatorContext*); -int vis_operator_register(Vis*, VisOperatorFunction*, void *context); +/** Repeat last operator, possibly with a new count if one was provided in the meantime. */ +void vis_repeat(Vis*); + +/** Cancel pending operator, reset count, motion, text object, register etc. */ +void vis_cancel(Vis*); +/** @} */ +/** Motion specifiers. */ enum VisMotion { VIS_MOVE_LINE_DOWN, VIS_MOVE_LINE_UP, @@ -328,28 +516,65 @@ enum VisMotion { VIS_MOVE_LAST, /* denotes the end of all motions */ }; -/* set motion to perform, the following take an additional argument: +/** + * @defgroup vis_motions + * @{ + */ +/** + * Set motion to perform. + * + * The following motions take an additional argument: * - * - VIS_MOVE_SEARCH_FORWARD and VIS_MOVE_SEARCH_BACKWARD + * - `VIS_MOVE_SEARCH_FORWARD` and `VIS_MOVE_SEARCH_BACKWARD` * - * expect the search pattern as const char * + * The search pattern as ``const char *``. * - * - VIS_MOVE_{LEFT,RIGHT}_{TO,TILL} + * - ``VIS_MOVE_{LEFT,RIGHT}_{TO,TILL}`` * - * expect the character to search for as const char * + * The character to search for as ``const char *``. * - * - VIS_MOVE_MARK and VIS_MOVE_MARK_LINE + * - `VIS_MOVE_MARK` and `VIS_MOVE_MARK_LINE` * - * expect a valid enum VisMark + * A valid ``enum VisMark``. */ bool vis_motion(Vis*, enum VisMotion, ...); -/* If no count is explicitly specified, operators, motions and - * text object will always perform their function as if a minimal - * count of 1 was given */ +enum VisMotionType { + VIS_MOTIONTYPE_LINEWISE = 1 << 0, + VIS_MOTIONTYPE_CHARWISE = 1 << 1, +}; + +/** Force currently specified motion to behave in line or character wise mode. */ +void vis_motion_type(Vis *vis, enum VisMotionType); + +/** + * Motions take a starting position and transform it to an end position. + * @rst + * .. note:: Should a motion not be possible, the original position must be returned. + * TODO: we might want to change that to ``EPOS``? + * @endrst + */ +typedef size_t (VisMotionFunction)(Vis*, Win*, void *context, size_t pos); + +/** + * Register a motion function. + * @return Motion ID. Negative values indicate an error, positive ones can be + * used with `vis_motion`. + */ +int vis_motion_register(Vis*, enum VisMotionType, void *context, VisMotionFunction*); + +/** + * @} + * @defgroup vis_count + * @{ + */ +/** No count was specified. */ #define VIS_COUNT_UNKNOWN (-1) +/** Get count, might return `VIS_COUNT_UNKNOWN`. */ int vis_count_get(Vis*); +/** Get count, if none was specified, return ``def``. */ int vis_count_get_default(Vis*, int def); +/** Set a count. */ void vis_count_set(Vis*, int count); typedef struct { @@ -358,23 +583,22 @@ typedef struct { int count; } VisCountIterator; +/** Get iterator initialized with current count or ``def`` if not specified. */ VisCountIterator vis_count_iterator_get(Vis*, int def); +/** Get iterator initialized with a count value. */ VisCountIterator vis_count_iterator_init(Vis*, int count); +/** + * Increment iterator counter. + * @return Whether iteration should continue. + * @rst + * .. note:: Terminates iteration if the edtior was + * `interrupted <vis_interrupt>`_ in the meantime. + * @endrst + */ bool vis_count_iterator_next(VisCountIterator*); -enum VisMotionType { - VIS_MOTIONTYPE_LINEWISE = 1 << 0, - VIS_MOTIONTYPE_CHARWISE = 1 << 1, -}; -/* force certain motion to behave in line or character wise mode */ -void vis_motion_type(Vis *vis, enum VisMotionType); - -/* register a motion function, if positive the return value can be used - * as an id for the vis_motion funntion. A negative return value indicates - * an error */ -int vis_motion_register(Vis*, enum VisMotionType, void *data, - size_t (*motion)(Vis*, Win*, void*, size_t pos)); - +/** @} */ +/** Text object specifier. */ enum VisTextObject { VIS_TEXTOBJECT_INNER_WORD, VIS_TEXTOBJECT_OUTER_WORD, @@ -408,14 +632,32 @@ enum VisTextObject { VIS_TEXTOBJECT_INVALID, }; -bool vis_textobject(Vis*, enum VisTextObject); +/** + * @defgroup vis_textobjs + * @{ + */ + +/** + * Text objects take a starting position and return a text range. + * @rst + * .. note:: The originating position does not necessarily have to be contained in + * the resulting range. + * @endrst + */ +typedef Filerange (VisTextObjectFunction)(Vis*, Win*, void *context, size_t pos); -/* register a new text object, if successful the returned id is positive - * and can be used as argument for the vis_textobject function. */ -int vis_textobject_register(Vis*, int type, void *data, - Filerange (*textobject)(Vis*, Win*, void*, size_t pos)); +/** + * Register a new text object. + * @return Text object ID. Negative values indicate an error, positive ones can be + * used with `vis_textobject`. + */ +int vis_textobject_register(Vis*, int type, void *data, VisTextObjectFunction*); +/** Set text object to use. */ +bool vis_textobject(Vis*, enum VisTextObject); +/** @} */ +/** Mark specifiers. */ enum VisMark { VIS_MARK_SELECTION_START, /* '< */ VIS_MARK_SELECTION_END, /* '> */ @@ -428,9 +670,23 @@ enum VisMark { VIS_MARK_INVALID, /* has to be the last enum member */ }; +/** + * @} + * @defgroup vis_marks + * @{ + */ +/** Translate single character mark name to corresponding constant. */ enum VisMark vis_mark_from(Vis*, char mark); +/** + * Set a mark. + * @rst + * .. note:: The same semantics as for `text_mark_set` apply. + * @endrst + */ void vis_mark_set(Vis*, enum VisMark mark, size_t pos); +/** @} */ +/** Register specifiers. */ enum VisRegister { VIS_REG_DEFAULT, /* used when no other register is specified */ VIS_REG_ZERO, /* yank register */ @@ -469,41 +725,82 @@ enum VisRegister { VIS_MACRO_LAST_RECORDED, /* pseudo macro referring to last recorded one */ }; +/** + * @defgroup vis_registers + * @{ + */ +/** Translate single character register name to corresponding constant. */ enum VisRegister vis_register_from(Vis*, char reg); -/* set the register to use, if none is given the DEFAULT register is used */ +/** + * Specify register to use. + * @rst + * .. note:: If none is specified `VIS_REG_DEFAULT` will be used. + * @endrst + */ void vis_register(Vis*, enum VisRegister); -/* get register content */ +/** Get register content. */ const char *vis_register_get(Vis*, enum VisRegister, size_t *len); const char *vis_register_slot_get(Vis*, enum VisRegister, size_t slot, size_t *len); +/** Set register content. */ bool vis_register_put(Vis*, enum VisRegister, const char *data, size_t len); bool vis_register_slot_put(Vis*, enum VisRegister, size_t slot, const char *data, size_t len); - -/* start a macro recording, fails if a recording is already on going */ +/** + * @} + * @defgroup vis_macros + * @{ + */ +/** + * Start recording a macro. + * @rst + * .. note:: Fails if a recording is already ongoing. + * @endrst + */ bool vis_macro_record(Vis*, enum VisRegister); -/* stop recording, fails if there is nothing to stop */ +/** Stop recording, fails if there is nothing to stop. */ bool vis_macro_record_stop(Vis*); -/* check whether a recording is currently on going */ +/** Check whether a recording is currently ongoing. */ bool vis_macro_recording(Vis*); -/* replay a macro. a macro currently being recorded can't be replayed */ +/** + * Replay a macro. + * @rst + * .. note:: A macro currently being recorded can not be replayed. + * @endrst + */ bool vis_macro_replay(Vis*, enum VisRegister); -/* repeat last operator, possibly with a new count if one was provided in the meantime */ -void vis_repeat(Vis*); - -/* cancel pending operator, reset count, motion, text object, register etc. */ -void vis_cancel(Vis*); +/** + * @} + * @defgroup vis_cmds + * @{ + */ -/* execute a :-command (including an optinal range specifier) */ +/** Execute a ``:``-command. */ bool vis_cmd(Vis*, const char *cmd); -/* type of user defined function which can be registered */ -typedef bool (CmdFunc)(Vis*, Win*, void *data, bool force, +/** Command handler function. */ +typedef bool (VisCommandFunction)(Vis*, Win*, void *data, bool force, const char *argv[], Cursor*, Filerange*); -/* the function will be invoked whenever a command which matches a - * unique prefix of the given name is executed */ -bool vis_cmd_register(Vis*, const char *name, const char *help, void *data, CmdFunc*); +/** + * Register new ``:``-command. + * @param name The command name. + * @param help Optional single line help text. + * @param context User supplied context pointer passed to the handler function. + * @param func The function implementing the command logic. + * @rst + * .. note:: Any unique prefix of the command name will invoke the command. + * @endrst + */ +bool vis_cmd_register(Vis*, const char *name, const char *help, void *context, VisCommandFunction*); + +/** Unregister ``:``-command. */ bool vis_cmd_unregister(Vis*, const char *name); +/** + * @} + * @defgroup vis_options + * @{ + */ +/** Option properties. */ enum VisOption { VIS_OPTION_TYPE_BOOL = 1 << 0, VIS_OPTION_TYPE_STRING = 1 << 1, @@ -512,62 +809,129 @@ enum VisOption { VIS_OPTION_NEED_WINDOW = 1 << 4, }; +/** + * Option handler function. + * @param win The window to which option should apply, might be ``NULL``. + * @param context User provided context pointer as given to `vis_option_register`. + * @param force Whether the option was specfied with a bang ``!``. + * @param name Name of option which was set. + * @param arg The new option value. + */ typedef bool (VisOptionFunction)(Vis*, Win*, void *context, bool toggle, enum VisOption, const char *name, Arg *value); + +/** + * Register a new ``:set`` option. + * @param names A ``NULL`` terminated array of option names. + * @param option Option properties. + * @param func The function handling the option. + * @param context User supplied context pointer passed to the handler function. + * @param help Optional single line help text. + * @rst + * .. note:: Fails if any of the given option names is already registered. + * @endrst + */ bool vis_option_register(Vis*, const char *names[], enum VisOption, VisOptionFunction*, void *context, const char *help); +/** + * Unregister an existing ``:set`` option. + * @rst + * .. note:: Also unregisters all aliases as given to `vis_option_register`. + * @endrst + */ bool vis_option_unregister(Vis*, const char *name); -/* execute any kind (:,?,/) of prompt command */ +/** Execute any kind (``:``, ``?``, ``/``) of prompt command */ bool vis_prompt_cmd(Vis*, const char *cmd); -/* pipe a given file range to an external process +/** + * Pipe a given file range to an external process. * - * if the range is invalid 'interactive' mode is enabled, meaning that + * If the range is invalid 'interactive' mode is enabled, meaning that * stdin and stderr are passed through the underlying command, stdout * points to vis' stderr. * - * if argv contains only one non-NULL element the command is executed using - * /bin/sh -c (i.e. argument expansion is performed by the shell). In contrast - * if argv contains more than one non-NULL element execvp(argv[0], argv); will - * be used. + * If ``argv`` contains only one non-NULL element the command is executed + * through an intermediate shell (using ``/bin/sh -c argv[0]``) that is + * argument expansion is performed by the shell. Otherwise the argument + * list will be passed unmodified to ``execvp(argv[0], argv)``. + * + * If the ``read_stdout`` and ``read_stderr`` callbacks are non-NULL they + * will be invoked when output from the forked process is available. * - * if read_std{out,err} are non-NULL they will be called when output from - * the forked process is available. + * @rst + * .. warning:: The editor core is blocked until this function returns. + * @endrst + * + * @return The exit status of the forked process. */ int vis_pipe(Vis*, File*, Filerange*, const char *argv[], void *stdout_context, ssize_t (*read_stdout)(void *stdout_context, char *data, size_t len), void *stderr_context, ssize_t (*read_stderr)(void *stderr_context, char *data, size_t len)); -/* pipe a range to an external application, return its exit status and store - * everything that is written to stdout/stderr in the gitven char pointers - * which have to be free(3)-ed by the caller */ +/** + * Pipe a Filerange to an external process, return its exit status and capture + * everything that is written to stdout/stderr. + * @param argv Argument list, must be ``NULL`` terminated. + * @param out Data written to ``stdout``, will be ``NUL`` terminated. + * @param err Data written to ``stderr``, will be ``NUL`` terminated. + * @rst + * .. warning:: The pointers stored in ``out`` and ``err`` need to be `free(3)`-ed + * by the caller. + * @endrst + */ int vis_pipe_collect(Vis*, File*, Filerange*, const char *argv[], char **out, char **err); -/* given the start of a key, returns a pointer to the start of the one immediately - * following as will be processed by the input system. skips over special keys - * such as <Enter> as well as pseudo keys registered via vis_action_register. */ +/** + * @} + * @defgroup vis_keys + * @{ + */ +/** + * Advance to the start of the next symbolic key. + * + * Given the start of a symbolic key, returns a pointer to the start of the one + * immediately following it. + */ const char *vis_keys_next(Vis*, const char *keys); -/* Tries to convert next symbolic key to a raw code point, returns -1 for unknown keys */ +/** Convert next symbolic key to an Unicode code point, returns ``-1`` for unknown keys. */ long vis_keys_codepoint(Vis*, const char *keys); -/* Tries to convert next symbolic key to a UTF-8 sequence. Returns false for unknown keys - * and leaves `utf8` untouched. Guarantees that `utf8` is NUL terminated on success */ +/** + * Convert next symbolic key to a UTF-8 sequence. + * @return Whether conversion was successful, if not ``utf8`` is left unmodified. + * @rst + * .. note:: Guarantees that ``utf8`` is NUL terminated on success. + * @endrst + */ bool vis_keys_utf8(Vis*, const char *keys, char utf8[static UTFmax+1]); -/* vis operates as a finite state machine (FSM), feeding keys from an input - * queue (or a previously recorded macro) to key handling functions (see struct - * KeyAction) which consume the input. - * - * this functions pushes/appends further input to the end of the input queue - * and immediately interprets them as if they were entered by a user. */ +/** Process symbolic keys as if they were user originated input. */ void vis_keys_feed(Vis*, const char *keys); +/** + * @} + * @defgroup vis_misc + * @{ + */ -/* inform vis that a signal occured, the return value indicates whether the signal - * was handled by vis */ -bool vis_signal_handler(Vis*, int signum, const siginfo_t *siginfo, const void *context); - -/* remember last search pattern, freeing the regex is the callers responsibility */ +/** + * Get a regex object matching pattern. + * @param regex The regex pattern to compile, if ``NULL`` the most recently used + * one is substituted. + * @return A Regex object or ``NULL`` in case of an error. + * @rst + * .. warning:: The caller must free the regex object using `text_regex_free`. + * @endrst + */ Regex *vis_regex(Vis*, const char *pattern); +/** + * Take an undo snaphost to which we can later revert to. + * @rst + * .. note:: Does nothing when invoked while replaying a macro. + * @endrst + */ +void vis_file_snapshot(Vis*, File*); +/** @} */ + /* TODO: expose proper API to iterate through files etc */ Text *vis_text(Vis*); View *vis_view(Vis*); |
