+++ /dev/null
-/**
- @file
- @brief Collection of useful C types and functions.
- @author Michael D. Lowis
- @license BSD 2-clause License
-*/
-#define _POSIX_C_SOURCE 200809L
-#define _XOPEN_SOURCE 700
-#define AUTOLIB(n) \
- int __autolib_##n __attribute__ ((weak));
-#include <stddef.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <signal.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-function"
-
-static char* strmcat(char* first, ...) {
- va_list args;
- /* calculate the length of the final string */
- size_t len = strlen(first);
- va_start(args, first);
- for (char* s = NULL; (s = va_arg(args, char*));)
- len += strlen(s);
- va_end(args);
- /* allocate the final string and copy the args into it */
- char *str = malloc(len+1), *curr = str;
- while (first && *first) *(curr++) = *(first++);
- va_start(args, first);
- for (char* s = NULL; (s = va_arg(args, char*));)
- while (s && *s) *(curr++) = *(s++);
- va_end(args);
- /* null terminate and return */
- *curr = '\0';
- return str;
-}
-
-/* Option Parsing
- *
- * This following macros implement a simple POSIX-style option parsing strategy.
- * They are heavily influenced and inspired by the arg.h file from suckless.org
- * (http://git.suckless.org/libsl/tree/arg.h). That file is in turn inspired by
- * the corresponding macros defined in plan9.
- *
- * The interface assumes that the main function will have the following
- * prototype:
- *
- * int main(int argc, char** argv);
- *
- * An example usage of the interface would look something like the follwoing:
- *
- * char* ARGV0;
- * int main(int argc, char** argv) {
- * OPTBEGIN {
- * case 'a': printf("Simple option\n"); break;
- * case 'b': printf("Option with arg: %s\n", OPTARG()); break;
- * default: printf("Unknown option!\n");
- * } OPTEND;
- * return 0;
- * }
- */
-
-/* This variable contains the value of argv[0] so that it can be referenced
- * again once the option parsing is done. This variable must be defined by the
- * program.
- *
- * NOTE: Ensure that you define this variable with external linkage (i.e. not
- * static) */
-extern char* ARGV0;
-
-/* This is a helper function used by the following macros to parse the next
- * option from the command line. */
-static inline char* _getopt_(int* p_argc, char*** p_argv) {
- if (!(*p_argv)[0][1] && !(*p_argv)[1]) {
- return (char*)0;
- } else if ((*p_argv)[0][1]) {
- return &(*p_argv)[0][1];
- } else {
- *p_argv = *p_argv + 1;
- *p_argc = *p_argc - 1;
- return (*p_argv)[0];
- }
-}
-
-/* This macro is almost identical to the ARGBEGIN macro from suckless.org. If
- * it ain't broke, don't fix it. */
-#define OPTBEGIN \
- for ( \
- ARGV0 = *argv, argc--, argv++; \
- argv[0] && argv[0][1] && argv[0][0] == '-'; \
- argc--, argv++ \
- ) { \
- int brk_; char argc_ , **argv_, *optarg_; \
- if (argv[0][1] == '-' && !argv[0][2]) { \
- (void)optarg_; argv++, argc--; break; \
- } \
- for (brk_=0, argv[0]++, argv_=argv; argv[0][0] && !brk_; argv[0]++) { \
- if (argv_ != argv) break; \
- argc_ = argv[0][0]; \
- switch (argc_)
-
-/* Terminate the option parsing. */
-#define OPTEND }}
-
-/* Get the current option character */
-#define OPTC() (argc_)
-
-/* Get an argument from the command line and return it as a string. If no
- * argument is available, this macro returns NULL */
-#define OPTARG() \
- (optarg_ = _getopt_(&argc,&argv), brk_ = (optarg_!=0), optarg_)
-
-/* Get an argument from the command line and return it as a string. If no
- * argument is available, this macro executes the provided code. If that code
- * returns, then abort is called. */
-#define EOPTARG(code) \
- (optarg_ = _getopt_(&argc,&argv), \
- (!optarg_ ? ((code), abort(), (char*)0) : (brk_ = 1, optarg_)))
-
-/* Helper macro to recognize number options */
-#define OPTNUM \
- case '0': \
- case '1': \
- case '2': \
- case '3': \
- case '4': \
- case '5': \
- case '6': \
- case '7': \
- case '8': \
- case '9'
-
-/* Helper macro to recognize "long" options ala GNU style. */
-#define OPTLONG \
- case '-'
-
-/* Miscellaneous
- *****************************************************************************/
-#ifndef nelem
- #define nelem(x) \
- (sizeof(x)/sizeof((x)[0]))
-#endif
-
-#ifndef container_of
- #define container_of(obj, type, member) \
- ((type*)((uintptr_t)obj - offsetof(type, member)))
-#endif
-
-#ifndef min
- #define min(x,y) \
- ((x) < (y) ? (x) : (y))
-#endif
-
-#ifndef max
- #define max(x,y) \
- ((x) > (y) ? (x) : (y))
-#endif
-
-#pragma GCC diagnostic pop
+++ /dev/null
-= tide(1)
-:doctype: manpage
-
-
-== NAME
-
-tide - a text editor inspired by acme(1) from Plan 9 and Inferno
-
-== SYNOPSIS
-
-*tide* [FILE...]
-
-== DESCRIPTION
-
-*tide* is a text editor inspired by the Acme editor from the Plan 9 and Inferno
-operating systems. Unlike Acme, *tide* is a single window, single file editor.
-Instead of baking a window manager into the editor, this job is relegated to an
-X11 window manager. It is recommended that *tide* be used with a tiling window
-manager such as dwm(1) or spectrwm(1). These window managers will make dealing
-with multiple windows much easier and more efficient.
-
-=== Windows
-
-*tide* windows are divided into three basic regions: an expanding tags region, a
-main content region and an adjacent scroll region. The tags region acts as
-scratch buffer for commands that can be executed to affect the file or the state
-of the editor. As the content of this region grows it will expand up to a
-quarter of the size of the window, shrinking the main content region in kind.
-The main content region displays a view of the file currently being edited. To
-the left of the content region is a narrow vertical region matching the height
-of the content region. This region gives the user visibility into how much of
-the document is currently visible as well as their position in the document.
-
-=== Typing and Editing
-
-Typed characters in *tide* are delivered to the currently active region. The
-active region is the one currently under the mouse cursor. That is to say, the
-focus follows the mouse much as it does in acme(1) but there is a keyboard
-shortcut that allows users to toggle focus between the content region and the
-tag region by warping the mouse cursor from one region to the next.
-
-The mechanics of editing text in the tag and content region is identical with
-the exception of searching and saving. Edited content in the tag region is not
-saved to disk while the content region is. This region is considered a scratch
-buffer for commands, notes, and other bits of text that are placed there
-temporarily. The content region displays the current view of the file being
-edited and can be flushed to disk when requested.
-
-Searching with a term selected in the tags region will search for the term in
-the content region rather than the tags region. In this way a user can edit the
-search term incrementally and perform repeated searches through the content
-region. Searching for a term in the content region will search for the term in
-the content region however.
-
-=== Text Selection
-
-*tide* uses a series of rules to determine how much text to select when the user
-executes a context sensitive selection, a search, or a context sensitive
-execution. The following rules are applied in order until a match is found.
-
-1. *Cursor over '(' or ')':*
- Highlight text between the parentheses including nested parentheses.
-
-2. *Cursor over '[' or ']':*
- Highlight text between the brackets including nested brackets.
-
-3. *Cursor over '{' or '}':*
- Highlight text between the braces including nested braces.
-
-4. *Cursor at beginning or end of line:*
- Highlight the entire line (including the newline)
-
-5. *Cursor over alphanumeric character or underscore:*
- Highlight the word under the cursor consisting of only alphanumeric and
- underscore characters.
-
-If none of the above rules match, *tide* will simply highlight the block of
-non-whitespace characters under the cursor.
-
-=== Mouse Handling
-
-*Left Button*::
- The left mouse button is used for selecting text or moving the cursor. A
- single-click will move the mose to the clicked location. A double-click will
- will select the object under the clicked location based on context as
- described in <<Text Selection>>. A triple-click will select the largest
- contiguous chunk of non-whitespace characters at the clicked location.
-
-*Middle Button*::
- The middle mouse button is used for executing text at the clicked location.
- The command to be executed is determined by the context rules defined in the
- <<Text Selection>> section. The cursor position is not changed on a
- middle click.
-
-*Right Button*::
- The right button is used to search for the next occurrence of the clicked
- text. The search term is determined by the context rules defined in the
- <<Text Selection>> section. The search direction follows the direction of
- the previous search operation. The *Shift* key can be held in combination
- with a click of the right mosue button in order to reverse the search
- direction.
-
-=== Command Execution
-
-*tide* allows for the execution of any arbitrary text as a command. The input
-and output to/from each command executed can be controlled by prepending one of
-a set of sigils defined below. These sigils instruct *tide* from where the
-command will receive its input and where it will place its output (both standard
-and errors).
-
-*! - Run command detached from editor*::
- The command will be executed in the background and all of its input and
- output file descriptors will be closed.
-
-*< - Input from command*:
- The command will be executed in the background and its standard output will
- be placed in the content region. Its error output will be placed in the tags
- region.
-
-*> - Output to command*::
- The command will be executed in the background. The currently selected text
- will be written to the command's standard input. The command's standard
- output and standard error content will be written to the tags region.
-
-*| - Pipe through command*::
- The command will be executed in the background. The currently selected text
- will be written to the command's standard input. The command's standard
- output will replace the currently selected text. Any error output will be
- placed in the tags region.
-
-*: - Pipe through sed(1)*::
- Identical to '|' except that the command is always sed(1). This is a
- convenience shortcut to allow quick and easy access to sed for editing
- blocks of text.
-
-*Commands with no sigil*::
- Commands with none of the aforementioned sigils will be executed in the
- background and have their standard output placed in the content region and
- their error output placed in the tags region.
-
-=== Keyboard Shortcuts
-
-*Unix Standard Shortcuts:*
-
-*Ctrl+u*::
- Delete from the cursor position to the beginning of the line.
-
-*Ctrl+k*::
- Delete from the cursor position to the end of the line.
-
-*Ctrl+w*::
- Delete the word to the left.
-
-*Ctrl+a*::
- Move cursor to the beginning of the line.
-
-*Ctrl+e*::
- Move cursor to the end of the line.
-
-*Cursor Movement and Selection:*
-
-The key combinations below are responsible for moving the cursor around the
-document by character, by word, or by line. The *Shift* modifier key can be
-applied to any of them to also extend the current selection to the new cursor
-position.
-
-*Escape*::
- Highlight the last contiguous block of inserted text or clear the current
- selection (deselect the currently selected text).
-
-*Left*::
- Move the cursor one character to the left.
-
-*Right*::
- Move the cursor one character to the right.
-
-*Up*::
- Move the cursor to the previous line.
-
-*Down*::
- Move the cursor to the next line.
-
-*Ctrl+Up*::
- Move the current line or selection up a line.
-
-*Ctrl+Down*::
- Move the current line or selection down a line.
-
-*Ctrl+Left*::
- Move the cursor to the beginning of the word to the left.
-
-*Ctrl+Right*::
- Move the cursor to the end of the word to the right.
-
-*Modern Text Editing Shortcuts:*
-
-*Ctrl+s*::
- Save the contents of the content region to disk.
-
-*Ctrl+z*::
- Undo the last change performed on the active region.
-
-*Ctrl+y*::
- Redo the previously undone change on the active region.
-
-*Ctrl+x*::
- Cut the selected text to the X11 CLIPBOARD selection. If no text is selected
- then the current line is cut.
-
-*Ctrl+c*::
- Copy the selected text to the X11 CLIPBOARD selection. If no text is
- selected then the current line is copied.
-
-*Ctrl+v*::
- Paste the contents of the X11 CLIPBOARD selection to the active region.
-
-*Ctrl+j*::
- Join the current line and the next line.
-
-*Ctrl+l*::
- Select the current line.
-
-*Ctrl+Shift+a*::
- Select all text in the buffer.
-
-*Delete*::
- Delete the character to the right.
-
-*Ctrl+Delete*::
- Delete the word to the right.
-
-*Backspace*::
- Delete the character to the left.
-
-*Ctrl+Backspace*::
- Delete the word to the left.
-
-*Ctrl+Enter*::
- Create a new line after the current line and place the cursor there.
-
-*Ctrl+Shift+Enter*::
- Create a new line before the current line and place the cursor there.
-
-*PageUp*::
- Scroll the active region up by one screenful of text. The cursor is not
- affected by this operation.
-
-*PageDn*::
- Scroll the active region down by one screenful of text. The cursor is not
- affected by this operation.
-
-*Search Shortcuts:*
-
-The shortcuts below allow the user to search for selected text or by context.
-The direction of the search defaults to the forward direction with regard to the
-position in the file. Each search follows the direction of the previous search
-unless the *Shift* modifier is applied. The *Shift* modifier causes the current
-search operation to be applied in the opposite direction of the previous.
-
-*Ctrl+f*::
- Search for the next occurrence of the selected text in the content region.
- If no text is currently selected, the text under the cursor is selected
- based on context as described in <<Text Selection>>.
-
-*Ctrl+Alt+f*::
- Search for the next occurence previous search term in the content region.
-
-*Implementation-specific Shortcuts*
-
-*Ctrl+[*::
- Decrease the indent level of the selected text.
-
-*Ctrl+]*::
- Increase the indent level of the selected text.
-
-*Ctrl+h*::
- Highlight the item under cursor following the rules in <<Text Selection>>
-
-*Ctrl+t*::
- Toggle focus between the tags region and the content region.
-
-*Ctrl+q*::
- Quit the editor. If the file is modified a warning will be printed in the
- tags region and the editor will not quit. Executing the shortcut twice
- within 250ms will ignore the warning and quit the editor without saving.
-
-*Ctrl+d*::
- Execute the selected text as described in <<Command Execution>>. If no text is
- selected, the text under cursor is selecte dbased on context as described in
- <<Text Selection>>.
-
-*Ctrl+o*::
- Launch pickfile(1) to choose a file from a recursive list of files in the
- current directory and sub directories. This file will be opened in a new
- instance of *tide*.
-
-*Ctrl+p*::
- Launch picktag(1) to select a tag from a ctags(1) generated index file.
- *tide* will jump to the selected ctag definition in the current window if
- the file is currently being edited. Otherwise, a new instance of *tide* will
- be launched with the target file and the cursor set to the line containing
- the definition.
-
-*Ctrl+g*::
- Lookup the selected symbol or symbol under the cursor in a ctags(1)
- generated index file. Jump to the location of the definition if it exist in
- the current file. Otherwise, a new instance of *tide* will be launched with
- the target file and the cursor set to the line containing the definition.
-
-*Ctrl+n*::
- Open a new instance of *tide* with no filename.
-
-=== Builtin Tags
-
-*Cut*::
- Cut the selection to the X11 CLIPBOARD selection.
-
-*Copy*::
- Copy the selection to the X11 CLIPBOARD selection.
-
-*Eol*::
- Toggle the line-ending style for the buffers contents between LF and CRLF
-
-*Find [term]*::
- Find the next occurrence of the selected text.
-
-*GoTo [arg]*::
- Jump to a specific line number or symbol.
-
-*Indent*::
- Toggle the autoindent feature on or off.
-
-*Overwrite*::
- Save the file to disk even if the file has been modified externally.
-
-*Paste*::
- Paste the contents of the X11 CLIPBOARD selection into the buffer.
-
-*Quit*::
- Quit the editor.
-
-*Redo*::
- Redo the last undone change.
-
-*Reload*::
- Reload the buffer contents from the on-disk file.
-
-*Save*::
- Save the contents of the buffer to disk.
-
-*SaveAs [path]*::
- Save the contents of the buffer to disk. If a path argument is provided, the
- buffer will be saved to the new path.
-
-*Tabs*::
- Toggle the expand tabs featuer on or off.
-
-*Undo*::
- Undo the previous edit.
-
-== OPTIONS
-
-*-I _OPT_*::
- Turn on/off auto indenting of new lines.
-
-*-W _OPT_*::
- Turn on/off trimming of trailing whitespace on save.
-
-*-E _OPT_*::
- Turn on/off expanding tabs to spaces.
-
-*-N _OPT_*::
- Turn on/off DOS line ending styles (<CR><LF>)
-
-*-T _STRING_*::
- Sets the text of the tags region.
-
-*-S _SHELL_*::
- Sets the shell to be used for all external command invocation. The shell
- must use the -c flag to receive commands to execute
-
-*-c _CMD_*::
- Executes the given command in a new tide window.
-
-*-l _LINENUM_*::
- Jumps the view to LINENUM in the document.
-
-== ENVIRONMENT
-
-*SHELL*::
- The contents of this variable are used as the shell in which all non-builtin
- commands are executed. If this variable is not defined, sh(1) is used as a
- fallback shell.
-
-== SEE ALSO
-
-acme(1), edit(1), pick(1), pickfile(1), picktag(1)
+++ /dev/null
-/**
- @file
- @brief Generic vector implementation.
- @author Michael D. Lowis
- @license BSD 2-clause License
-*/
-#ifndef VEC_H
-#define VEC_H
-
-#include <stddef.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-function"
-
-typedef struct {
- size_t elem_count;
- size_t elem_size;
- size_t elem_capacity;
- uint8_t* elem_buffer;
-} vec_t;
-
-typedef int (*vec_cmpfn_t)(const void*,const void*);
-
-#ifndef DEFAULT_VEC_CAPACITY
-#define DEFAULT_VEC_CAPACITY (size_t)8
-#endif
-
-static void vec_init(vec_t* vec, size_t elem_size) {
- vec->elem_size = elem_size;
- vec->elem_count = 0;
- vec->elem_capacity = DEFAULT_VEC_CAPACITY;
- vec->elem_buffer = malloc(elem_size * vec->elem_capacity);
-}
-
-static size_t vec_size(vec_t* vec) {
- return vec->elem_count;
-}
-
-static bool vec_empty(vec_t* vec) {
- return (vec->elem_count == 0);
-}
-
-static size_t vec_capacity(vec_t* vec) {
- return vec->elem_capacity;
-}
-
-static size_t vec_next_capacity(size_t req_size) {
- size_t next_power = req_size;
- size_t num_bits = sizeof(size_t) * 8;
- size_t bit_n;
-
- /* Find the next highest power of 2 */
- next_power--;
- for (bit_n = 1; bit_n < num_bits; bit_n = bit_n << 1)
- next_power = next_power | (next_power >> bit_n);
- next_power++;
-
- return next_power;
-}
-
-static void vec_reserve(vec_t* vec, size_t size) {
- vec->elem_buffer = realloc(vec->elem_buffer, size * vec->elem_size);
- vec->elem_capacity = size;
-}
-
-static void vec_resize(vec_t* vec, size_t count, void* fillval) {
- if (count > vec->elem_count) {
- vec_reserve(vec, vec_next_capacity(count+1));
- for (; vec->elem_count < count; vec->elem_count++)
- memcpy(&(vec->elem_buffer[vec->elem_count * vec->elem_size]), fillval, vec->elem_size);
- } else if (count < vec->elem_count) {
- vec->elem_count = count;
- }
-}
-
-static void vec_shrink_to_fit(vec_t* vec) {
- vec->elem_buffer = realloc(vec->elem_buffer, vec->elem_count * vec->elem_size);
- vec->elem_capacity = vec->elem_count;
-}
-
-static void* vec_at(vec_t* vec, size_t index) {
- return &(vec->elem_buffer[index * vec->elem_size]);
-}
-
-static void vec_set(vec_t* vec, size_t index, void* data) {
- memcpy(&(vec->elem_buffer[index * vec->elem_size]), data, vec->elem_size);
-}
-
-static bool vec_insert(vec_t* vec, size_t index, size_t num_elements, ...) {
- (void)vec;
- (void)index;
- (void)num_elements;
- return false;
-}
-
-static bool vec_erase(vec_t* vec, size_t start_idx, size_t end_idx) {
- (void)vec;
- (void)start_idx;
- (void)end_idx;
- return false;
-}
-
-static void vec_push_back(vec_t* vec, void* data) {
- vec_resize(vec, vec->elem_count+1, data);
-}
-
-static void vec_pop_back(vec_t* vec, void* outdata) {
- vec->elem_count--;
- memcpy(outdata, &(vec->elem_buffer[vec->elem_count * vec->elem_size]), vec->elem_size);
-}
-
-static void vec_clear(vec_t* vec) {
- vec->elem_count = 0;
-}
-
-static void vec_sort(vec_t* vec, int (*cmpfn)(const void*,const void*)) {
- qsort(vec->elem_buffer, vec->elem_count, vec->elem_size, cmpfn);
-}
-
-#pragma GCC diagnostic pop
-
-#endif /* VEC_H */