vis

a vi-like editor based on Plan 9's structural regular expressions

git clone https://9o.is/git/vis.git

vis-core.h

(14120B)


      1 #ifndef VIS_CORE_H
      2 #define VIS_CORE_H
      3 
      4 #include <setjmp.h>
      5 #include "vis.h"
      6 #include "sam.h"
      7 #include "vis-lua.h"
      8 #include "text.h"
      9 #include "text-util.h"
     10 #include "map.h"
     11 #include "array.h"
     12 #include "buffer.h"
     13 #include "util.h"
     14 
     15 /* a mode contains a set of key bindings which are currently valid.
     16  *
     17  * each mode can specify one parent mode which is consulted if a given key
     18  * is not found in the current mode. hence the modes form a tree which is
     19  * searched from the current mode up towards the root mode until a valid binding
     20  * is found.
     21  *
     22  * if no binding is found, mode->input(...) is called and the user entered
     23  * keys are passed as argument. this is used to change the document content.
     24  */
     25 typedef struct Mode Mode;
     26 struct Mode {
     27 	enum VisMode id;
     28 	Mode *parent;                       /* if no match is found in this mode, search will continue there */
     29 	Map *bindings;
     30 	const char *name;                   /* descriptive, user facing name of the mode */
     31 	const char *status;                 /* name displayed in the window status bar */
     32 	const char *help;                   /* short description used by :help */
     33 	void (*enter)(Vis*, Mode *old);           /* called right before the mode becomes active */
     34 	void (*leave)(Vis*, Mode *new);           /* called right before the mode becomes inactive */
     35 	void (*input)(Vis*, const char*, size_t); /* called whenever a key is not found in this mode and all its parent modes */
     36 	void (*idle)(Vis*);                 /* called whenever a certain idle time i.e. without any user input elapsed */
     37 	time_t idle_timeout;                /* idle time in seconds after which the registered function will be called */
     38 	bool visual;                        /* whether text selection is possible in this mode */
     39 };
     40 
     41 typedef struct {
     42 	Array values;
     43 	bool linewise; /* place register content on a new line when inserting? */
     44 	bool append;
     45 	enum {
     46 		REGISTER_NORMAL,
     47 		REGISTER_NUMBER,
     48 		REGISTER_BLACKHOLE,
     49 		REGISTER_CLIPBOARD,
     50 	} type;
     51 } Register;
     52 
     53 struct OperatorContext {
     54 	int count;        /* how many times should the command be executed? */
     55 	Register *reg;    /* always non-NULL, set to a default register */
     56 	size_t reg_slot;  /* register slot to use */
     57 	Filerange range;  /* which part of the file should be affected by the operator */
     58 	size_t pos;       /* at which byte from the start of the file should the operation start? */
     59 	size_t newpos;    /* new position after motion or EPOS if none given */
     60 	bool linewise;    /* should the changes always affect whole lines? */
     61 	const Arg *arg;   /* arbitrary arguments */
     62 	void *context;    /* used by user-registered operators */
     63 };
     64 
     65 typedef struct {
     66 	/* operator logic, returns new cursor position, if EPOS
     67 	 * the cursor is disposed (except if it is the primary one) */
     68 	VisOperatorFunction *func;
     69 	void *context;
     70 } Operator;
     71 
     72 typedef struct { /* Motion implementation, takes a cursor position and returns a new one */
     73 	/* TODO: merge types / use union to save space */
     74 	size_t (*cur)(Selection*);
     75 	size_t (*txt)(Text*, size_t pos);
     76 	size_t (*file)(Vis*, File*, Selection*);
     77 	size_t (*vis)(Vis*, Text*, size_t pos);
     78 	size_t (*view)(Vis*, View*);
     79 	size_t (*win)(Vis*, Win*, size_t pos);
     80 	size_t (*user)(Vis*, Win*, void*, size_t pos);
     81 	enum {
     82 		LINEWISE  = VIS_MOTIONTYPE_LINEWISE,  /* should the covered range be extended to whole lines? */
     83 		CHARWISE  = VIS_MOTIONTYPE_CHARWISE,  /* scrolls window content until position is visible */
     84 		INCLUSIVE = 1 << 2,  /* should new position be included in operator range? */
     85 		LINEWISE_INCLUSIVE = 1 << 3,  /* inclusive, but only if motion is linewise? */
     86 		IDEMPOTENT = 1 << 4, /* does the returned position remain the same if called multiple times? */
     87 		JUMP = 1 << 5, /* should the resulting position of the motion be recorded in the jump list? */
     88 		COUNT_EXACT = 1 << 6, /* fail (keep initial position) if count can not be satisfied exactly */
     89 	} type;
     90 	void *data;
     91 } Movement;
     92 
     93 typedef struct {
     94 	/* gets a cursor position and returns a file range (or text_range_empty())
     95 	 * representing the text object containing the position. */
     96 	Filerange (*txt)(Text*, size_t pos);
     97 	Filerange (*vis)(Vis*, Text*, size_t pos);
     98 	Filerange (*user)(Vis*, Win*, void *data, size_t pos);
     99 	enum {
    100 		TEXTOBJECT_DELIMITED_INNER = 1 << 0, /* single byte delimited, inner variant */
    101 		TEXTOBJECT_DELIMITED_OUTER = 1 << 1, /* single byte delimited, outer variant */
    102 		TEXTOBJECT_NON_CONTIGUOUS  = 1 << 2, /* multiple applications yield a split range */
    103 		TEXTOBJECT_EXTEND_FORWARD  = 1 << 3, /* multiple applications extend towards the end of file (default) */
    104 		TEXTOBJECT_EXTEND_BACKWARD = 1 << 4, /* multiple applications extend towards the begin of file */
    105 	} type;
    106 	void *data;
    107 } TextObject;
    108 
    109 /* a macro is just a sequence of symbolic keys as received from ui->getkey */
    110 typedef Buffer Macro;
    111 #define macro_release buffer_release
    112 #define macro_append buffer_append0
    113 
    114 typedef struct {             /** collects all information until an operator is executed */
    115 	int count;
    116 	enum VisMode mode;
    117 	enum VisMotionType type;
    118 	const Operator *op;
    119 	const Movement *movement;
    120 	const TextObject *textobj;
    121 	const Macro *macro;
    122 	Register *reg;
    123 	enum VisMark mark;
    124 	Arg arg;
    125 } Action;
    126 
    127 typedef struct Change Change;
    128 typedef struct {
    129 	Change *changes;      /* all changes in monotonically increasing file position */
    130 	Change *latest;       /* most recent change */
    131 	enum SamError error;  /* non-zero in case something went wrong */
    132 } Transcript;
    133 
    134 typedef struct {
    135 	Array prev;
    136 	Array next;
    137 	size_t max;
    138 } MarkList;
    139 
    140 struct File { /* shared state among windows displaying the same file */
    141 	Text *text;                      /* data structure holding the file content */
    142 	const char *name;                /* file name used when loading/saving */
    143 	volatile sig_atomic_t truncated; /* whether the underlying memory mapped region became invalid (SIGBUS) */
    144 	int fd;                          /* output file descriptor associated with this file or -1 if loaded by file name */
    145 	bool internal;                   /* whether it is an internal file (e.g. used for the prompt) */
    146 	struct stat stat;                /* filesystem information when loaded/saved, used to detect changes outside the editor */
    147 	int refcount;                    /* how many windows are displaying this file? (always >= 1) */
    148 	Array marks[VIS_MARK_INVALID];   /* marks which are shared across windows */
    149 	enum TextSaveMethod save_method; /* whether the file is saved using rename(2) or overwritten */
    150 	Transcript transcript;           /* keeps track of changes performed by sam commands */
    151 	File *next, *prev;
    152 };
    153 
    154 struct Win {
    155 	int id;                 /* unique identifier for this window */
    156 	int width, height;      /* window dimension including status bar */
    157 	int x, y;               /* window position */
    158 	int sidebar_width;      /* width of the sidebar showing line numbers etc. */
    159 	enum UiOption options;  /* display settings for this window */
    160 	View view;              /* currently displayed part of underlying text */
    161 	bool expandtab;         /* whether typed tabs should be converted to spaces in this window*/
    162 	Vis *vis;               /* editor instance to which this window belongs */
    163 	File *file;             /* file being displayed in this window */
    164 	MarkList jumplist;      /* LRU jump management */
    165 	Array saved_selections; /* register used to store selections */
    166 	Mode modes[VIS_MODE_INVALID]; /* overlay mods used for per window key bindings */
    167 	Win *parent;            /* window which was active when showing the command prompt */
    168 	Mode *parent_mode;      /* mode which was active when showing the command prompt */
    169 	Win *prev, *next;       /* neighbouring windows */
    170 };
    171 
    172 struct Vis {
    173 	File *files;                         /* all files currently managed by this editor instance */
    174 	File *command_file;                  /* special internal file used to store :-command prompt */
    175 	File *search_file;                   /* special internal file used to store /,? search prompt */
    176 	File *error_file;                    /* special internal file used to store lua error messages */
    177 	Win *windows;                        /* all windows currently managed by this editor instance */
    178 	Win *win;                            /* currently active/focused window */
    179 	Win *message_window;                 /* special window to display multi line messages */
    180 	Ui ui;                               /* user interface responsible for visual appearance */
    181 	Register registers[VIS_REG_INVALID]; /* registers used for text manipulations yank/put etc. and macros */
    182 	Macro *recording, *last_recording;   /* currently (if non NULL) and least recently recorded macro */
    183 	const Macro *replaying;              /* macro currently being replayed */
    184 	Macro *macro_operator;               /* special macro used to repeat certain operators */
    185 	Mode *mode_before_prompt;            /* user mode which was active before entering prompt */
    186 	char search_char[8];                 /* last used character to search for via 'f', 'F', 't', 'T' */
    187 	int last_totill;                     /* last to/till movement used for ';' and ',' */
    188 	int search_direction;                /* used for `n` and `N` */
    189 	bool autoindent;                     /* whether indentation should be copied from previous line on newline */
    190 	bool change_colors;                  /* whether to adjust 256 color palette for true colors */
    191 	char *shell;                         /* shell used to launch external commands */
    192 	Map *cmds;                           /* ":"-commands, used for unique prefix queries */
    193 	Map *usercmds;                       /* user registered ":"-commands */
    194 	Map *options;                        /* ":set"-options */
    195 	Map *keymap;                         /* key translation before any bindings are matched */
    196 	bool keymap_disabled;                /* ignore key map for next key press, gets automatically re-enabled */
    197 	char key[VIS_KEY_LENGTH_MAX];        /* last pressed key as reported from the UI */
    198 	char key_current[VIS_KEY_LENGTH_MAX];/* current key being processed by the input queue */
    199 	char key_prev[VIS_KEY_LENGTH_MAX];   /* previous key which was processed by the input queue */
    200 	Buffer input_queue;                  /* holds pending input keys */
    201 	bool errorhandler;                   /* whether we are currently in an error handler, used to avoid recursion */
    202 	Action action;                       /* current action which is in progress */
    203 	Action action_prev;                  /* last operator action used by the repeat (dot) command */
    204 	Mode *mode;                          /* currently active mode, used to search for keybindings */
    205 	Mode *mode_prev;                     /* previously active user mode */
    206 	int nesting_level;                   /* parsing state to hold keep track of { } nesting level */
    207 	volatile bool running;               /* exit main loop once this becomes false */
    208 	int exit_status;                     /* exit status when terminating main loop */
    209 	volatile sig_atomic_t interrupted;   /* abort command (SIGINT occurred) */
    210 	volatile sig_atomic_t sigbus;        /* one of the memory mapped regions became unavailable (SIGBUS) */
    211 	volatile sig_atomic_t need_resize;   /* need to resize UI (SIGWINCH occurred) */
    212 	volatile sig_atomic_t resume;        /* need to resume UI (SIGCONT occurred) */
    213 	volatile sig_atomic_t terminate;     /* need to terminate we were being killed by SIGTERM */
    214 	sigjmp_buf sigbus_jmpbuf;            /* used to jump back to a known good state in the mainloop after (SIGBUS) */
    215 	Map *actions;                        /* registered editor actions / special keys commands */
    216 	Array actions_user;                  /* dynamically allocated editor actions */
    217 	lua_State *lua;                      /* lua context used for syntax highlighting */
    218 	enum TextLoadMethod load_method;     /* how existing files should be loaded */
    219 	Array operators;
    220 	Array motions;
    221 	Array textobjects;
    222 	Array bindings;
    223 	bool ignorecase;                     /* whether to ignore case when searching */
    224 };
    225 
    226 enum VisEvents {
    227 	VIS_EVENT_INIT,
    228 	VIS_EVENT_START,
    229 	VIS_EVENT_QUIT,
    230 	VIS_EVENT_FILE_OPEN,
    231 	VIS_EVENT_FILE_SAVE_PRE,
    232 	VIS_EVENT_FILE_SAVE_POST,
    233 	VIS_EVENT_FILE_CLOSE,
    234 	VIS_EVENT_WIN_OPEN,
    235 	VIS_EVENT_WIN_CLOSE,
    236 	VIS_EVENT_WIN_HIGHLIGHT,
    237 	VIS_EVENT_WIN_STATUS,
    238 	VIS_EVENT_TERM_CSI,
    239 	VIS_EVENT_UI_DRAW,
    240 };
    241 
    242 bool vis_event_emit(Vis*, enum VisEvents, ...);
    243 
    244 typedef struct {
    245 	char name;
    246 	VIS_HELP_DECL(const char *help;)
    247 } MarkDef;
    248 
    249 typedef MarkDef RegisterDef;
    250 
    251 /** stuff used by several of the vis-* files */
    252 
    253 extern Mode vis_modes[VIS_MODE_INVALID];
    254 extern const Movement vis_motions[VIS_MOVE_INVALID];
    255 extern const Operator vis_operators[VIS_OP_INVALID];
    256 extern const TextObject vis_textobjects[VIS_TEXTOBJECT_INVALID];
    257 extern const MarkDef vis_marks[VIS_MARK_a];
    258 extern const RegisterDef vis_registers[VIS_REG_a];
    259 
    260 void macro_operator_stop(Vis *vis);
    261 void macro_operator_record(Vis *vis);
    262 
    263 void vis_do(Vis *vis);
    264 void action_reset(Action*);
    265 size_t vis_text_insert_nl(Vis*, Text*, size_t pos);
    266 
    267 Mode *mode_get(Vis*, enum VisMode);
    268 void mode_set(Vis *vis, Mode *new_mode);
    269 Macro *macro_get(Vis *vis, enum VisRegister);
    270 
    271 Win *window_new_file(Vis*, File*, enum UiOption);
    272 void window_selection_save(Win *win);
    273 void window_status_update(Vis *vis, Win *win);
    274 
    275 char *absolute_path(const char *path);
    276 
    277 const char *file_name_get(File*);
    278 void file_name_set(File*, const char *name);
    279 
    280 bool register_init(Register*);
    281 void register_release(Register*);
    282 
    283 void mark_init(Array*);
    284 void mark_release(Array*);
    285 
    286 void marklist_init(MarkList*, size_t max);
    287 void marklist_release(MarkList*);
    288 
    289 const char *register_get(Vis*, Register*, size_t *len);
    290 const char *register_slot_get(Vis*, Register*, size_t slot, size_t *len);
    291 
    292 bool register_put0(Vis*, Register*, const char *data);
    293 bool register_put(Vis*, Register*, const char *data, size_t len);
    294 bool register_slot_put(Vis*, Register*, size_t slot, const char *data, size_t len);
    295 
    296 bool register_put_range(Vis*, Register*, Text*, Filerange*);
    297 bool register_slot_put_range(Vis*, Register*, size_t slot, Text*, Filerange*);
    298 
    299 size_t vis_register_count(Vis*, Register*);
    300 bool register_resize(Register*, size_t count);
    301 
    302 #endif