vis: make O implementation independent of <Up> mapping
[vis.git] / main.c
bloba6212b2e889bde5b19cd3134533be0e3db640335
1 #include <signal.h>
2 #include <limits.h>
3 #include <string.h>
4 #include <stdio.h>
5 #include <wchar.h>
6 #include <ctype.h>
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <inttypes.h>
10 #include <sys/stat.h>
11 #include <sys/types.h>
13 #include "ui-terminal.h"
14 #include "vis.h"
15 #include "vis-lua.h"
16 #include "text-util.h"
17 #include "text-motions.h"
18 #include "text-objects.h"
19 #include "util.h"
20 #include "libutf.h"
21 #include "array.h"
22 #include "buffer.h"
24 #define PAGE INT_MAX
25 #define PAGE_HALF (INT_MAX-1)
27 /** functions to be called from keybindings */
28 /* ignore key, do nothing */
29 static const char *nop(Vis*, const char *keys, const Arg *arg);
30 /* record/replay macro indicated by keys */
31 static const char *macro_record(Vis*, const char *keys, const Arg *arg);
32 static const char *macro_replay(Vis*, const char *keys, const Arg *arg);
33 /* temporarily suspend the editor and return to the shell, type 'fg' to get back */
34 static const char *suspend(Vis*, const char *keys, const Arg *arg);
35 /* reset count if set, otherwise remove all but the primary selection */
36 static const char *normalmode_escape(Vis*, const char *keys, const Arg *arg);
37 /* reset count if set, otherwise switch to normal mode */
38 static const char *visualmode_escape(Vis*, const char *keys, const Arg *arg);
39 /* switch to mode indicated by arg->i */
40 static const char *switchmode(Vis*, const char *keys, const Arg *arg);
41 /* switch to insert mode after performing movement indicated by arg->i */
42 static const char *insertmode(Vis*, const char *keys, const Arg *arg);
43 /* switch to replace mode after performing movement indicated by arg->i */
44 static const char *replacemode(Vis*, const char *keys, const Arg *arg);
45 /* add a new line either before or after the one where the cursor currently is */
46 static const char *openline(Vis*, const char *keys, const Arg *arg);
47 /* join lines from current cursor position to movement indicated by arg */
48 static const char *join(Vis*, const char *keys, const Arg *arg);
49 /* perform last action i.e. action_prev again */
50 static const char *repeat(Vis*, const char *keys, const Arg *arg);
51 /* replace character at cursor with one from keys */
52 static const char *replace(Vis*, const char *keys, const Arg *arg);
53 /* create a new cursor on the previous (arg->i < 0) or next (arg->i > 0) line */
54 static const char *selections_new(Vis*, const char *keys, const Arg *arg);
55 /* try to align all selections on the same column */
56 static const char *selections_align(Vis*, const char *keys, const Arg *arg);
57 /* try to align all selections by inserting the correct amount of white spaces */
58 static const char *selections_align_indent(Vis*, const char *keys, const Arg *arg);
59 /* remove all but the primary cursor and their selections */
60 static const char *selections_clear(Vis*, const char *keys, const Arg *arg);
61 /* remove the least recently added selection */
62 static const char *selections_remove(Vis*, const char *keys, const Arg *arg);
63 /* remove count (or arg->i)-th selection column */
64 static const char *selections_remove_column(Vis*, const char *keys, const Arg *arg);
65 /* remove all but the count (or arg->i)-th selection column */
66 static const char *selections_remove_column_except(Vis*, const char *keys, const Arg *arg);
67 /* move to the previous (arg->i < 0) or next (arg->i > 0) selection */
68 static const char *selections_navigate(Vis*, const char *keys, const Arg *arg);
69 /* select the next region matching the current selection */
70 static const char *selections_match_next(Vis*, const char *keys, const Arg *arg);
71 /* clear current selection but select next match */
72 static const char *selections_match_skip(Vis*, const char *keys, const Arg *arg);
73 /* rotate selection content count times left (arg->i < 0) or right (arg->i > 0) */
74 static const char *selections_rotate(Vis*, const char *keys, const Arg *arg);
75 /* remove leading and trailing white spaces from selections */
76 static const char *selections_trim(Vis*, const char *keys, const Arg *arg);
77 /* save active selections to mark */
78 static const char *selections_save(Vis*, const char *keys, const Arg *arg);
79 /* restore selections from mark */
80 static const char *selections_restore(Vis*, const char *keys, const Arg *arg);
81 /* union selections from mark */
82 static const char *selections_union(Vis*, const char *keys, const Arg *arg);
83 /* intersect selections from mark */
84 static const char *selections_intersect(Vis*, const char *keys, const Arg *arg);
85 /* perform complement of current active selections */
86 static const char *selections_complement(Vis*, const char *keys, const Arg *arg);
87 /* subtract selections from mark */
88 static const char *selections_minus(Vis*, const char *keys, const Arg *arg);
89 /* adjust current used count according to keys */
90 static const char *count(Vis*, const char *keys, const Arg *arg);
91 /* move to the count-th line or if not given either to the first (arg->i < 0)
92 * or last (arg->i > 0) line of file */
93 static const char *gotoline(Vis*, const char *keys, const Arg *arg);
94 /* make the current action use the operator indicated by arg->i */
95 static const char *operator(Vis*, const char *keys, const Arg *arg);
96 /* blocks to read a key and performs movement indicated by arg->i which
97 * should be one of VIS_MOVE_{RIGHT,LEFT}_{TO,TILL} */
98 static const char *movement_key(Vis*, const char *keys, const Arg *arg);
99 /* perform the movement as indicated by arg->i */
100 static const char *movement(Vis*, const char *keys, const Arg *arg);
101 /* let the current operator affect the range indicated by the text object arg->i */
102 static const char *textobj(Vis*, const char *keys, const Arg *arg);
103 /* move to the other end of selected text */
104 static const char *selection_end(Vis*, const char *keys, const Arg *arg);
105 /* use register indicated by keys for the current operator */
106 static const char *reg(Vis*, const char *keys, const Arg *arg);
107 /* use mark indicated by keys for the current action */
108 static const char *mark(Vis*, const char *keys, const Arg *arg);
109 /* {un,re}do last action, redraw window */
110 static const char *undo(Vis*, const char *keys, const Arg *arg);
111 static const char *redo(Vis*, const char *keys, const Arg *arg);
112 /* earlier, later action chronologically, redraw window */
113 static const char *earlier(Vis*, const char *keys, const Arg *arg);
114 static const char *later(Vis*, const char *keys, const Arg *arg);
115 /* delete from the current cursor position to the end of
116 * movement as indicated by arg->i */
117 static const char *delete(Vis*, const char *keys, const Arg *arg);
118 /* insert register content indicated by keys at current cursor position */
119 static const char *insert_register(Vis*, const char *keys, const Arg *arg);
120 /* show a user prompt to get input with title arg->s */
121 static const char *prompt_show(Vis*, const char *keys, const Arg *arg);
122 /* blocks to read 3 consecutive digits and inserts the corresponding byte value */
123 static const char *insert_verbatim(Vis*, const char *keys, const Arg *arg);
124 /* scroll window content according to arg->i which can be either PAGE, PAGE_HALF,
125 * or an arbitrary number of lines. a multiplier overrides what is given in arg->i.
126 * negative values scroll back, positive forward. */
127 static const char *wscroll(Vis*, const char *keys, const Arg *arg);
128 /* similar to scroll, but do only move window content not cursor position */
129 static const char *wslide(Vis*, const char *keys, const Arg *arg);
130 /* call editor function as indicated by arg->f */
131 static const char *call(Vis*, const char *keys, const Arg *arg);
132 /* call window function as indicated by arg->w */
133 static const char *window(Vis*, const char *keys, const Arg *arg);
134 /* show info about Unicode character at cursor position */
135 static const char *unicode_info(Vis*, const char *keys, const Arg *arg);
136 /* either go to count % of file or to matching item */
137 static const char *percent(Vis*, const char *keys, const Arg *arg);
138 /* navigate jumplist next (arg->i > 0), prev (arg->i < 0), save (arg->i = 0) */
139 static const char *jumplist(Vis*, const char *keys, const Arg *arg);
141 enum {
142 VIS_ACTION_EDITOR_SUSPEND,
143 VIS_ACTION_CURSOR_CHAR_PREV,
144 VIS_ACTION_CURSOR_CHAR_NEXT,
145 VIS_ACTION_CURSOR_LINE_CHAR_PREV,
146 VIS_ACTION_CURSOR_LINE_CHAR_NEXT,
147 VIS_ACTION_CURSOR_CODEPOINT_PREV,
148 VIS_ACTION_CURSOR_CODEPOINT_NEXT,
149 VIS_ACTION_CURSOR_WORD_START_PREV,
150 VIS_ACTION_CURSOR_WORD_START_NEXT,
151 VIS_ACTION_CURSOR_WORD_END_PREV,
152 VIS_ACTION_CURSOR_WORD_END_NEXT,
153 VIS_ACTION_CURSOR_LONGWORD_START_PREV,
154 VIS_ACTION_CURSOR_LONGWORD_START_NEXT,
155 VIS_ACTION_CURSOR_LONGWORD_END_PREV,
156 VIS_ACTION_CURSOR_LONGWORD_END_NEXT,
157 VIS_ACTION_CURSOR_LINE_UP,
158 VIS_ACTION_CURSOR_LINE_DOWN,
159 VIS_ACTION_CURSOR_LINE_START,
160 VIS_ACTION_CURSOR_LINE_FINISH,
161 VIS_ACTION_CURSOR_LINE_BEGIN,
162 VIS_ACTION_CURSOR_LINE_END,
163 VIS_ACTION_CURSOR_SCREEN_LINE_UP,
164 VIS_ACTION_CURSOR_SCREEN_LINE_DOWN,
165 VIS_ACTION_CURSOR_SCREEN_LINE_BEGIN,
166 VIS_ACTION_CURSOR_SCREEN_LINE_MIDDLE,
167 VIS_ACTION_CURSOR_SCREEN_LINE_END,
168 VIS_ACTION_CURSOR_PERCENT,
169 VIS_ACTION_CURSOR_BYTE,
170 VIS_ACTION_CURSOR_BYTE_LEFT,
171 VIS_ACTION_CURSOR_BYTE_RIGHT,
172 VIS_ACTION_CURSOR_PARAGRAPH_PREV,
173 VIS_ACTION_CURSOR_PARAGRAPH_NEXT,
174 VIS_ACTION_CURSOR_SENTENCE_PREV,
175 VIS_ACTION_CURSOR_SENTENCE_NEXT,
176 VIS_ACTION_CURSOR_BLOCK_START,
177 VIS_ACTION_CURSOR_BLOCK_END,
178 VIS_ACTION_CURSOR_PARENTHESIS_START,
179 VIS_ACTION_CURSOR_PARENTHESIS_END,
180 VIS_ACTION_CURSOR_COLUMN,
181 VIS_ACTION_CURSOR_LINE_FIRST,
182 VIS_ACTION_CURSOR_LINE_LAST,
183 VIS_ACTION_CURSOR_WINDOW_LINE_TOP,
184 VIS_ACTION_CURSOR_WINDOW_LINE_MIDDLE,
185 VIS_ACTION_CURSOR_WINDOW_LINE_BOTTOM,
186 VIS_ACTION_CURSOR_SEARCH_REPEAT_FORWARD,
187 VIS_ACTION_CURSOR_SEARCH_REPEAT_BACKWARD,
188 VIS_ACTION_CURSOR_SEARCH_REPEAT,
189 VIS_ACTION_CURSOR_SEARCH_REPEAT_REVERSE,
190 VIS_ACTION_CURSOR_SEARCH_WORD_FORWARD,
191 VIS_ACTION_CURSOR_SEARCH_WORD_BACKWARD,
192 VIS_ACTION_WINDOW_PAGE_UP,
193 VIS_ACTION_WINDOW_PAGE_DOWN,
194 VIS_ACTION_WINDOW_HALFPAGE_UP,
195 VIS_ACTION_WINDOW_HALFPAGE_DOWN,
196 VIS_ACTION_MODE_NORMAL,
197 VIS_ACTION_MODE_NORMAL_ESCAPE,
198 VIS_ACTION_MODE_VISUAL,
199 VIS_ACTION_MODE_VISUAL_ESCAPE,
200 VIS_ACTION_MODE_VISUAL_LINE,
201 VIS_ACTION_MODE_INSERT,
202 VIS_ACTION_MODE_REPLACE,
203 VIS_ACTION_DELETE_CHAR_PREV,
204 VIS_ACTION_DELETE_CHAR_NEXT,
205 VIS_ACTION_DELETE_LINE_BEGIN,
206 VIS_ACTION_DELETE_WORD_PREV,
207 VIS_ACTION_JUMPLIST_PREV,
208 VIS_ACTION_JUMPLIST_NEXT,
209 VIS_ACTION_JUMPLIST_SAVE,
210 VIS_ACTION_UNDO,
211 VIS_ACTION_REDO,
212 VIS_ACTION_EARLIER,
213 VIS_ACTION_LATER,
214 VIS_ACTION_MACRO_RECORD,
215 VIS_ACTION_MACRO_REPLAY,
216 VIS_ACTION_MARK,
217 VIS_ACTION_REDRAW,
218 VIS_ACTION_REPLACE_CHAR,
219 VIS_ACTION_TOTILL_REPEAT,
220 VIS_ACTION_TOTILL_REVERSE,
221 VIS_ACTION_PROMPT_SEARCH_FORWARD,
222 VIS_ACTION_PROMPT_SEARCH_BACKWARD,
223 VIS_ACTION_TILL_LEFT,
224 VIS_ACTION_TILL_RIGHT,
225 VIS_ACTION_TO_LEFT,
226 VIS_ACTION_TO_RIGHT,
227 VIS_ACTION_REGISTER,
228 VIS_ACTION_OPERATOR_CHANGE,
229 VIS_ACTION_OPERATOR_DELETE,
230 VIS_ACTION_OPERATOR_YANK,
231 VIS_ACTION_OPERATOR_SHIFT_LEFT,
232 VIS_ACTION_OPERATOR_SHIFT_RIGHT,
233 VIS_ACTION_COUNT,
234 VIS_ACTION_INSERT_NEWLINE,
235 VIS_ACTION_INSERT_TAB,
236 VIS_ACTION_INSERT_VERBATIM,
237 VIS_ACTION_INSERT_REGISTER,
238 VIS_ACTION_WINDOW_NEXT,
239 VIS_ACTION_WINDOW_PREV,
240 VIS_ACTION_APPEND_CHAR_NEXT,
241 VIS_ACTION_APPEND_LINE_END,
242 VIS_ACTION_INSERT_LINE_START,
243 VIS_ACTION_OPEN_LINE_ABOVE,
244 VIS_ACTION_OPEN_LINE_BELOW,
245 VIS_ACTION_JOIN_LINES,
246 VIS_ACTION_JOIN_LINES_TRIM,
247 VIS_ACTION_PROMPT_SHOW,
248 VIS_ACTION_REPEAT,
249 VIS_ACTION_SELECTION_FLIP,
250 VIS_ACTION_WINDOW_REDRAW_TOP,
251 VIS_ACTION_WINDOW_REDRAW_CENTER,
252 VIS_ACTION_WINDOW_REDRAW_BOTTOM,
253 VIS_ACTION_WINDOW_SLIDE_UP,
254 VIS_ACTION_WINDOW_SLIDE_DOWN,
255 VIS_ACTION_PUT_AFTER,
256 VIS_ACTION_PUT_BEFORE,
257 VIS_ACTION_SELECTIONS_NEW_LINE_ABOVE,
258 VIS_ACTION_SELECTIONS_NEW_LINE_ABOVE_FIRST,
259 VIS_ACTION_SELECTIONS_NEW_LINE_BELOW,
260 VIS_ACTION_SELECTIONS_NEW_LINE_BELOW_LAST,
261 VIS_ACTION_SELECTIONS_NEW_LINES_BEGIN,
262 VIS_ACTION_SELECTIONS_NEW_LINES_END,
263 VIS_ACTION_SELECTIONS_NEW_MATCH_ALL,
264 VIS_ACTION_SELECTIONS_NEW_MATCH_NEXT,
265 VIS_ACTION_SELECTIONS_NEW_MATCH_SKIP,
266 VIS_ACTION_SELECTIONS_ALIGN,
267 VIS_ACTION_SELECTIONS_ALIGN_INDENT_LEFT,
268 VIS_ACTION_SELECTIONS_ALIGN_INDENT_RIGHT,
269 VIS_ACTION_SELECTIONS_REMOVE_ALL,
270 VIS_ACTION_SELECTIONS_REMOVE_LAST,
271 VIS_ACTION_SELECTIONS_REMOVE_COLUMN,
272 VIS_ACTION_SELECTIONS_REMOVE_COLUMN_EXCEPT,
273 VIS_ACTION_SELECTIONS_PREV,
274 VIS_ACTION_SELECTIONS_NEXT,
275 VIS_ACTION_SELECTIONS_ROTATE_LEFT,
276 VIS_ACTION_SELECTIONS_ROTATE_RIGHT,
277 VIS_ACTION_SELECTIONS_TRIM,
278 VIS_ACTION_SELECTIONS_SAVE,
279 VIS_ACTION_SELECTIONS_RESTORE,
280 VIS_ACTION_SELECTIONS_UNION,
281 VIS_ACTION_SELECTIONS_INTERSECT,
282 VIS_ACTION_SELECTIONS_COMPLEMENT,
283 VIS_ACTION_SELECTIONS_MINUS,
284 VIS_ACTION_TEXT_OBJECT_WORD_OUTER,
285 VIS_ACTION_TEXT_OBJECT_WORD_INNER,
286 VIS_ACTION_TEXT_OBJECT_LONGWORD_OUTER,
287 VIS_ACTION_TEXT_OBJECT_LONGWORD_INNER,
288 VIS_ACTION_TEXT_OBJECT_SENTENCE,
289 VIS_ACTION_TEXT_OBJECT_PARAGRAPH,
290 VIS_ACTION_TEXT_OBJECT_PARAGRAPH_OUTER,
291 VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_OUTER,
292 VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_INNER,
293 VIS_ACTION_TEXT_OBJECT_PARENTHESIS_OUTER,
294 VIS_ACTION_TEXT_OBJECT_PARENTHESIS_INNER,
295 VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_OUTER,
296 VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_INNER,
297 VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_OUTER,
298 VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_INNER,
299 VIS_ACTION_TEXT_OBJECT_QUOTE_OUTER,
300 VIS_ACTION_TEXT_OBJECT_QUOTE_INNER,
301 VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_OUTER,
302 VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_INNER,
303 VIS_ACTION_TEXT_OBJECT_BACKTICK_OUTER,
304 VIS_ACTION_TEXT_OBJECT_BACKTICK_INNER,
305 VIS_ACTION_TEXT_OBJECT_LINE_OUTER,
306 VIS_ACTION_TEXT_OBJECT_LINE_INNER,
307 VIS_ACTION_TEXT_OBJECT_INDENTATION,
308 VIS_ACTION_TEXT_OBJECT_SEARCH_FORWARD,
309 VIS_ACTION_TEXT_OBJECT_SEARCH_BACKWARD,
310 VIS_ACTION_UNICODE_INFO,
311 VIS_ACTION_UTF8_INFO,
312 VIS_ACTION_NOP,
315 static const KeyAction vis_action[] = {
316 [VIS_ACTION_EDITOR_SUSPEND] = {
317 "vis-suspend",
318 VIS_HELP("Suspend the editor")
319 suspend,
321 [VIS_ACTION_CURSOR_CHAR_PREV] = {
322 "vis-motion-char-prev",
323 VIS_HELP("Move cursor left, to the previous character")
324 movement, { .i = VIS_MOVE_CHAR_PREV }
326 [VIS_ACTION_CURSOR_CHAR_NEXT] = {
327 "vis-motion-char-next",
328 VIS_HELP("Move cursor right, to the next character")
329 movement, { .i = VIS_MOVE_CHAR_NEXT }
331 [VIS_ACTION_CURSOR_LINE_CHAR_PREV] = {
332 "vis-motion-line-char-prev",
333 VIS_HELP("Move cursor left, to the previous character on the same line")
334 movement, { .i = VIS_MOVE_LINE_CHAR_PREV }
336 [VIS_ACTION_CURSOR_LINE_CHAR_NEXT] = {
337 "vis-motion-line-char-next",
338 VIS_HELP("Move cursor right, to the next character on the same line")
339 movement, { .i = VIS_MOVE_LINE_CHAR_NEXT }
341 [VIS_ACTION_CURSOR_CODEPOINT_PREV] = {
342 "vis-motion-codepoint-prev",
343 VIS_HELP("Move to the previous Unicode codepoint")
344 movement, { .i = VIS_MOVE_CODEPOINT_PREV }
346 [VIS_ACTION_CURSOR_CODEPOINT_NEXT] = {
347 "vis-motion-codepoint-next",
348 VIS_HELP("Move to the next Unicode codepoint")
349 movement, { .i = VIS_MOVE_CODEPOINT_NEXT }
351 [VIS_ACTION_CURSOR_WORD_START_PREV] = {
352 "vis-motion-word-start-prev",
353 VIS_HELP("Move cursor words backwards")
354 movement, { .i = VIS_MOVE_WORD_START_PREV }
356 [VIS_ACTION_CURSOR_WORD_START_NEXT] = {
357 "vis-motion-word-start-next",
358 VIS_HELP("Move cursor words forwards")
359 movement, { .i = VIS_MOVE_WORD_START_NEXT }
361 [VIS_ACTION_CURSOR_WORD_END_PREV] = {
362 "vis-motion-word-end-prev",
363 VIS_HELP("Move cursor backwards to the end of word")
364 movement, { .i = VIS_MOVE_WORD_END_PREV }
366 [VIS_ACTION_CURSOR_WORD_END_NEXT] = {
367 "vis-motion-word-end-next",
368 VIS_HELP("Move cursor forward to the end of word")
369 movement, { .i = VIS_MOVE_WORD_END_NEXT }
371 [VIS_ACTION_CURSOR_LONGWORD_START_PREV] = {
372 "vis-motion-bigword-start-prev",
373 VIS_HELP("Move cursor WORDS backwards")
374 movement, { .i = VIS_MOVE_LONGWORD_START_PREV }
376 [VIS_ACTION_CURSOR_LONGWORD_START_NEXT] = {
377 "vis-motion-bigword-start-next",
378 VIS_HELP("Move cursor WORDS forwards")
379 movement, { .i = VIS_MOVE_LONGWORD_START_NEXT }
381 [VIS_ACTION_CURSOR_LONGWORD_END_PREV] = {
382 "vis-motion-bigword-end-prev",
383 VIS_HELP("Move cursor backwards to the end of WORD")
384 movement, { .i = VIS_MOVE_LONGWORD_END_PREV }
386 [VIS_ACTION_CURSOR_LONGWORD_END_NEXT] = {
387 "vis-motion-bigword-end-next",
388 VIS_HELP("Move cursor forward to the end of WORD")
389 movement, { .i = VIS_MOVE_LONGWORD_END_NEXT }
391 [VIS_ACTION_CURSOR_LINE_UP] = {
392 "vis-motion-line-up",
393 VIS_HELP("Move cursor line upwards")
394 movement, { .i = VIS_MOVE_LINE_UP }
396 [VIS_ACTION_CURSOR_LINE_DOWN] = {
397 "vis-motion-line-down",
398 VIS_HELP("Move cursor line downwards")
399 movement, { .i = VIS_MOVE_LINE_DOWN }
401 [VIS_ACTION_CURSOR_LINE_START] = {
402 "vis-motion-line-start",
403 VIS_HELP("Move cursor to first non-blank character of the line")
404 movement, { .i = VIS_MOVE_LINE_START }
406 [VIS_ACTION_CURSOR_LINE_FINISH] = {
407 "vis-motion-line-finish",
408 VIS_HELP("Move cursor to last non-blank character of the line")
409 movement, { .i = VIS_MOVE_LINE_FINISH }
411 [VIS_ACTION_CURSOR_LINE_BEGIN] = {
412 "vis-motion-line-begin",
413 VIS_HELP("Move cursor to first character of the line")
414 movement, { .i = VIS_MOVE_LINE_BEGIN }
416 [VIS_ACTION_CURSOR_LINE_END] = {
417 "vis-motion-line-end",
418 VIS_HELP("Move cursor to end of the line")
419 movement, { .i = VIS_MOVE_LINE_END }
421 [VIS_ACTION_CURSOR_SCREEN_LINE_UP] = {
422 "vis-motion-screenline-up",
423 VIS_HELP("Move cursor screen/display line upwards")
424 movement, { .i = VIS_MOVE_SCREEN_LINE_UP }
426 [VIS_ACTION_CURSOR_SCREEN_LINE_DOWN] = {
427 "vis-motion-screenline-down",
428 VIS_HELP("Move cursor screen/display line downwards")
429 movement, { .i = VIS_MOVE_SCREEN_LINE_DOWN }
431 [VIS_ACTION_CURSOR_SCREEN_LINE_BEGIN] = {
432 "vis-motion-screenline-begin",
433 VIS_HELP("Move cursor to beginning of screen/display line")
434 movement, { .i = VIS_MOVE_SCREEN_LINE_BEGIN }
436 [VIS_ACTION_CURSOR_SCREEN_LINE_MIDDLE] = {
437 "vis-motion-screenline-middle",
438 VIS_HELP("Move cursor to middle of screen/display line")
439 movement, { .i = VIS_MOVE_SCREEN_LINE_MIDDLE }
441 [VIS_ACTION_CURSOR_SCREEN_LINE_END] = {
442 "vis-motion-screenline-end",
443 VIS_HELP("Move cursor to end of screen/display line")
444 movement, { .i = VIS_MOVE_SCREEN_LINE_END }
446 [VIS_ACTION_CURSOR_PERCENT] = {
447 "vis-motion-percent",
448 VIS_HELP("Move to count % of file or matching item")
449 percent
451 [VIS_ACTION_CURSOR_BYTE] = {
452 "vis-motion-byte",
453 VIS_HELP("Move to absolute byte position")
454 movement, { .i = VIS_MOVE_BYTE }
456 [VIS_ACTION_CURSOR_BYTE_LEFT] = {
457 "vis-motion-byte-left",
458 VIS_HELP("Move count bytes to the left")
459 movement, { .i = VIS_MOVE_BYTE_LEFT }
461 [VIS_ACTION_CURSOR_BYTE_RIGHT] = {
462 "vis-motion-byte-right",
463 VIS_HELP("Move count bytes to the right")
464 movement, { .i = VIS_MOVE_BYTE_RIGHT }
466 [VIS_ACTION_CURSOR_PARAGRAPH_PREV] = {
467 "vis-motion-paragraph-prev",
468 VIS_HELP("Move cursor paragraph backward")
469 movement, { .i = VIS_MOVE_PARAGRAPH_PREV }
471 [VIS_ACTION_CURSOR_PARAGRAPH_NEXT] = {
472 "vis-motion-paragraph-next",
473 VIS_HELP("Move cursor paragraph forward")
474 movement, { .i = VIS_MOVE_PARAGRAPH_NEXT }
476 [VIS_ACTION_CURSOR_SENTENCE_PREV] = {
477 "vis-motion-sentence-prev",
478 VIS_HELP("Move cursor sentence backward")
479 movement, { .i = VIS_MOVE_SENTENCE_PREV }
481 [VIS_ACTION_CURSOR_SENTENCE_NEXT] = {
482 "vis-motion-sentence-next",
483 VIS_HELP("Move cursor sentence forward")
484 movement, { .i = VIS_MOVE_SENTENCE_NEXT }
486 [VIS_ACTION_CURSOR_BLOCK_START] = {
487 "vis-motion-block-start",
488 VIS_HELP("Move cursor to the opening curly brace in a block")
489 movement, { .i = VIS_MOVE_BLOCK_START }
491 [VIS_ACTION_CURSOR_BLOCK_END] = {
492 "vis-motion-block-end",
493 VIS_HELP("Move cursor to the closing curly brace in a block")
494 movement, { .i = VIS_MOVE_BLOCK_END }
496 [VIS_ACTION_CURSOR_PARENTHESIS_START] = {
497 "vis-motion-parenthesis-start",
498 VIS_HELP("Move cursor to the opening parenthesis inside a pair of parentheses")
499 movement, { .i = VIS_MOVE_PARENTHESIS_START }
501 [VIS_ACTION_CURSOR_PARENTHESIS_END] = {
502 "vis-motion-parenthesis-end",
503 VIS_HELP("Move cursor to the closing parenthesis inside a pair of parentheses")
504 movement, { .i = VIS_MOVE_PARENTHESIS_END }
506 [VIS_ACTION_CURSOR_COLUMN] = {
507 "vis-motion-column",
508 VIS_HELP("Move cursor to given column of current line")
509 movement, { .i = VIS_MOVE_COLUMN }
511 [VIS_ACTION_CURSOR_LINE_FIRST] = {
512 "vis-motion-line-first",
513 VIS_HELP("Move cursor to given line (defaults to first)")
514 gotoline, { .i = -1 }
516 [VIS_ACTION_CURSOR_LINE_LAST] = {
517 "vis-motion-line-last",
518 VIS_HELP("Move cursor to given line (defaults to last)")
519 gotoline, { .i = +1 }
521 [VIS_ACTION_CURSOR_WINDOW_LINE_TOP] = {
522 "vis-motion-window-line-top",
523 VIS_HELP("Move cursor to top line of the window")
524 movement, { .i = VIS_MOVE_WINDOW_LINE_TOP }
526 [VIS_ACTION_CURSOR_WINDOW_LINE_MIDDLE] = {
527 "vis-motion-window-line-middle",
528 VIS_HELP("Move cursor to middle line of the window")
529 movement, { .i = VIS_MOVE_WINDOW_LINE_MIDDLE }
531 [VIS_ACTION_CURSOR_WINDOW_LINE_BOTTOM] = {
532 "vis-motion-window-line-bottom",
533 VIS_HELP("Move cursor to bottom line of the window")
534 movement, { .i = VIS_MOVE_WINDOW_LINE_BOTTOM }
536 [VIS_ACTION_CURSOR_SEARCH_REPEAT_FORWARD] = {
537 "vis-motion-search-repeat-forward",
538 VIS_HELP("Move cursor to next match in forward direction")
539 movement, { .i = VIS_MOVE_SEARCH_REPEAT_FORWARD }
541 [VIS_ACTION_CURSOR_SEARCH_REPEAT_BACKWARD] = {
542 "vis-motion-search-repeat-backward",
543 VIS_HELP("Move cursor to previous match in backward direction")
544 movement, { .i = VIS_MOVE_SEARCH_REPEAT_BACKWARD }
546 [VIS_ACTION_CURSOR_SEARCH_REPEAT] = {
547 "vis-motion-search-repeat",
548 VIS_HELP("Move cursor to next match")
549 movement, { .i = VIS_MOVE_SEARCH_REPEAT }
551 [VIS_ACTION_CURSOR_SEARCH_REPEAT_REVERSE] = {
552 "vis-motion-search-repeat-reverse",
553 VIS_HELP("Move cursor to next match in opposite direction")
554 movement, { .i = VIS_MOVE_SEARCH_REPEAT_REVERSE }
556 [VIS_ACTION_CURSOR_SEARCH_WORD_FORWARD] = {
557 "vis-motion-search-word-forward",
558 VIS_HELP("Move cursor to next occurrence of the word under cursor")
559 movement, { .i = VIS_MOVE_SEARCH_WORD_FORWARD }
561 [VIS_ACTION_CURSOR_SEARCH_WORD_BACKWARD] = {
562 "vis-motion-search-word-backward",
563 VIS_HELP("Move cursor to previous occurrence of the word under cursor")
564 movement, { .i = VIS_MOVE_SEARCH_WORD_BACKWARD }
566 [VIS_ACTION_WINDOW_PAGE_UP] = {
567 "vis-window-page-up",
568 VIS_HELP("Scroll window pages backwards (upwards)")
569 wscroll, { .i = -PAGE }
571 [VIS_ACTION_WINDOW_HALFPAGE_UP] = {
572 "vis-window-halfpage-up",
573 VIS_HELP("Scroll window half pages backwards (upwards)")
574 wscroll, { .i = -PAGE_HALF }
576 [VIS_ACTION_WINDOW_PAGE_DOWN] = {
577 "vis-window-page-down",
578 VIS_HELP("Scroll window pages forwards (downwards)")
579 wscroll, { .i = +PAGE }
581 [VIS_ACTION_WINDOW_HALFPAGE_DOWN] = {
582 "vis-window-halfpage-down",
583 VIS_HELP("Scroll window half pages forwards (downwards)")
584 wscroll, { .i = +PAGE_HALF }
586 [VIS_ACTION_MODE_NORMAL] = {
587 "vis-mode-normal",
588 VIS_HELP("Enter normal mode")
589 switchmode, { .i = VIS_MODE_NORMAL }
591 [VIS_ACTION_MODE_NORMAL_ESCAPE] = {
592 "vis-mode-normal-escape",
593 VIS_HELP("Reset count or remove all non-primary selections")
594 normalmode_escape,
596 [VIS_ACTION_MODE_VISUAL] = {
597 "vis-mode-visual-charwise",
598 VIS_HELP("Enter characterwise visual mode")
599 switchmode, { .i = VIS_MODE_VISUAL }
601 [VIS_ACTION_MODE_VISUAL_ESCAPE] = {
602 "vis-mode-visual-escape",
603 VIS_HELP("Reset count or switch to normal mode")
604 visualmode_escape,
606 [VIS_ACTION_MODE_VISUAL_LINE] = {
607 "vis-mode-visual-linewise",
608 VIS_HELP("Enter linewise visual mode")
609 switchmode, { .i = VIS_MODE_VISUAL_LINE }
611 [VIS_ACTION_MODE_INSERT] = {
612 "vis-mode-insert",
613 VIS_HELP("Enter insert mode")
614 insertmode, { .i = VIS_MOVE_NOP }
616 [VIS_ACTION_MODE_REPLACE] = {
617 "vis-mode-replace",
618 VIS_HELP("Enter replace mode")
619 replacemode, { .i = VIS_MOVE_NOP }
621 [VIS_ACTION_DELETE_CHAR_PREV] = {
622 "vis-delete-char-prev",
623 VIS_HELP("Delete the previous character")
624 delete, { .i = VIS_MOVE_CHAR_PREV }
626 [VIS_ACTION_DELETE_CHAR_NEXT] = {
627 "vis-delete-char-next",
628 VIS_HELP("Delete the next character")
629 delete, { .i = VIS_MOVE_CHAR_NEXT }
631 [VIS_ACTION_DELETE_LINE_BEGIN] = {
632 "vis-delete-line-begin",
633 VIS_HELP("Delete until the start of the current line")
634 delete, { .i = VIS_MOVE_LINE_BEGIN }
636 [VIS_ACTION_DELETE_WORD_PREV] = {
637 "vis-delete-word-prev",
638 VIS_HELP("Delete the previous WORD")
639 delete, { .i = VIS_MOVE_WORD_START_PREV }
641 [VIS_ACTION_JUMPLIST_PREV] = {
642 "vis-jumplist-prev",
643 VIS_HELP("Go to older cursor position in jump list")
644 jumplist, { .i = -1 }
646 [VIS_ACTION_JUMPLIST_NEXT] = {
647 "vis-jumplist-next",
648 VIS_HELP("Go to newer cursor position in jump list")
649 jumplist, { .i = +1 }
651 [VIS_ACTION_JUMPLIST_SAVE] = {
652 "vis-jumplist-save",
653 VIS_HELP("Save current selections in jump list")
654 jumplist, { .i = 0 }
656 [VIS_ACTION_UNDO] = {
657 "vis-undo",
658 VIS_HELP("Undo last change")
659 undo,
661 [VIS_ACTION_REDO] = {
662 "vis-redo",
663 VIS_HELP("Redo last change")
664 redo,
666 [VIS_ACTION_EARLIER] = {
667 "vis-earlier",
668 VIS_HELP("Goto older text state")
669 earlier,
671 [VIS_ACTION_LATER] = {
672 "vis-later",
673 VIS_HELP("Goto newer text state")
674 later,
676 [VIS_ACTION_MACRO_RECORD] = {
677 "vis-macro-record",
678 VIS_HELP("Record macro into given register")
679 macro_record,
681 [VIS_ACTION_MACRO_REPLAY] = {
682 "vis-macro-replay",
683 VIS_HELP("Replay macro, execute the content of the given register")
684 macro_replay,
686 [VIS_ACTION_MARK] = {
687 "vis-mark",
688 VIS_HELP("Use given mark for next action")
689 mark,
691 [VIS_ACTION_REDRAW] = {
692 "vis-redraw",
693 VIS_HELP("Redraw current editor content")
694 call, { .f = vis_redraw }
696 [VIS_ACTION_REPLACE_CHAR] = {
697 "vis-replace-char",
698 VIS_HELP("Replace the character under the cursor")
699 replace,
701 [VIS_ACTION_TOTILL_REPEAT] = {
702 "vis-motion-totill-repeat",
703 VIS_HELP("Repeat latest to/till motion")
704 movement, { .i = VIS_MOVE_TOTILL_REPEAT }
706 [VIS_ACTION_TOTILL_REVERSE] = {
707 "vis-motion-totill-reverse",
708 VIS_HELP("Repeat latest to/till motion but in opposite direction")
709 movement, { .i = VIS_MOVE_TOTILL_REVERSE }
711 [VIS_ACTION_PROMPT_SEARCH_FORWARD] = {
712 "vis-search-forward",
713 VIS_HELP("Search forward")
714 prompt_show, { .s = "/" }
716 [VIS_ACTION_PROMPT_SEARCH_BACKWARD] = {
717 "vis-search-backward",
718 VIS_HELP("Search backward")
719 prompt_show, { .s = "?" }
721 [VIS_ACTION_TILL_LEFT] = {
722 "vis-motion-till-left",
723 VIS_HELP("Till after the occurrence of character to the left")
724 movement_key, { .i = VIS_MOVE_LEFT_TILL }
726 [VIS_ACTION_TILL_RIGHT] = {
727 "vis-motion-till-right",
728 VIS_HELP("Till before the occurrence of character to the right")
729 movement_key, { .i = VIS_MOVE_RIGHT_TILL }
731 [VIS_ACTION_TO_LEFT] = {
732 "vis-motion-to-left",
733 VIS_HELP("To the first occurrence of character to the left")
734 movement_key, { .i = VIS_MOVE_LEFT_TO }
736 [VIS_ACTION_TO_RIGHT] = {
737 "vis-motion-to-right",
738 VIS_HELP("To the first occurrence of character to the right")
739 movement_key, { .i = VIS_MOVE_RIGHT_TO }
741 [VIS_ACTION_REGISTER] = {
742 "vis-register",
743 VIS_HELP("Use given register for next operator")
744 reg,
746 [VIS_ACTION_OPERATOR_CHANGE] = {
747 "vis-operator-change",
748 VIS_HELP("Change operator")
749 operator, { .i = VIS_OP_CHANGE }
751 [VIS_ACTION_OPERATOR_DELETE] = {
752 "vis-operator-delete",
753 VIS_HELP("Delete operator")
754 operator, { .i = VIS_OP_DELETE }
756 [VIS_ACTION_OPERATOR_YANK] = {
757 "vis-operator-yank",
758 VIS_HELP("Yank operator")
759 operator, { .i = VIS_OP_YANK }
761 [VIS_ACTION_OPERATOR_SHIFT_LEFT] = {
762 "vis-operator-shift-left",
763 VIS_HELP("Shift left operator")
764 operator, { .i = VIS_OP_SHIFT_LEFT }
766 [VIS_ACTION_OPERATOR_SHIFT_RIGHT] = {
767 "vis-operator-shift-right",
768 VIS_HELP("Shift right operator")
769 operator, { .i = VIS_OP_SHIFT_RIGHT }
771 [VIS_ACTION_COUNT] = {
772 "vis-count",
773 VIS_HELP("Count specifier")
774 count,
776 [VIS_ACTION_INSERT_NEWLINE] = {
777 "vis-insert-newline",
778 VIS_HELP("Insert a line break (depending on file type)")
779 call, { .f = vis_insert_nl }
781 [VIS_ACTION_INSERT_TAB] = {
782 "vis-insert-tab",
783 VIS_HELP("Insert a tab (might be converted to spaces)")
784 call, { .f = vis_insert_tab }
786 [VIS_ACTION_INSERT_VERBATIM] = {
787 "vis-insert-verbatim",
788 VIS_HELP("Insert Unicode character based on code point")
789 insert_verbatim,
791 [VIS_ACTION_INSERT_REGISTER] = {
792 "vis-insert-register",
793 VIS_HELP("Insert specified register content")
794 insert_register,
796 [VIS_ACTION_WINDOW_NEXT] = {
797 "vis-window-next",
798 VIS_HELP("Focus next window")
799 call, { .f = vis_window_next }
801 [VIS_ACTION_WINDOW_PREV] = {
802 "vis-window-prev",
803 VIS_HELP("Focus previous window")
804 call, { .f = vis_window_prev }
806 [VIS_ACTION_APPEND_CHAR_NEXT] = {
807 "vis-append-char-next",
808 VIS_HELP("Append text after the cursor")
809 insertmode, { .i = VIS_MOVE_LINE_CHAR_NEXT }
811 [VIS_ACTION_APPEND_LINE_END] = {
812 "vis-append-line-end",
813 VIS_HELP("Append text after the end of the line")
814 insertmode, { .i = VIS_MOVE_LINE_END },
816 [VIS_ACTION_INSERT_LINE_START] = {
817 "vis-insert-line-start",
818 VIS_HELP("Insert text before the first non-blank in the line")
819 insertmode, { .i = VIS_MOVE_LINE_START },
821 [VIS_ACTION_OPEN_LINE_ABOVE] = {
822 "vis-open-line-above",
823 VIS_HELP("Begin a new line above the cursor")
824 openline, { .i = -1 }
826 [VIS_ACTION_OPEN_LINE_BELOW] = {
827 "vis-open-line-below",
828 VIS_HELP("Begin a new line below the cursor")
829 openline, { .i = +1 }
831 [VIS_ACTION_JOIN_LINES] = {
832 "vis-join-lines",
833 VIS_HELP("Join selected lines")
834 join, { .s = " " }
836 [VIS_ACTION_JOIN_LINES_TRIM] = {
837 "vis-join-lines-trim",
838 VIS_HELP("Join selected lines, remove white space")
839 join, { .s = "" }
841 [VIS_ACTION_PROMPT_SHOW] = {
842 "vis-prompt-show",
843 VIS_HELP("Show editor command line prompt")
844 prompt_show, { .s = ":" }
846 [VIS_ACTION_REPEAT] = {
847 "vis-repeat",
848 VIS_HELP("Repeat latest editor command")
849 repeat
851 [VIS_ACTION_SELECTION_FLIP] = {
852 "vis-selection-flip",
853 VIS_HELP("Flip selection, move cursor to other end")
854 selection_end,
856 [VIS_ACTION_WINDOW_REDRAW_TOP] = {
857 "vis-window-redraw-top",
858 VIS_HELP("Redraw cursor line at the top of the window")
859 window, { .w = view_redraw_top }
861 [VIS_ACTION_WINDOW_REDRAW_CENTER] = {
862 "vis-window-redraw-center",
863 VIS_HELP("Redraw cursor line at the center of the window")
864 window, { .w = view_redraw_center }
866 [VIS_ACTION_WINDOW_REDRAW_BOTTOM] = {
867 "vis-window-redraw-bottom",
868 VIS_HELP("Redraw cursor line at the bottom of the window")
869 window, { .w = view_redraw_bottom }
871 [VIS_ACTION_WINDOW_SLIDE_UP] = {
872 "vis-window-slide-up",
873 VIS_HELP("Slide window content upwards")
874 wslide, { .i = -1 }
876 [VIS_ACTION_WINDOW_SLIDE_DOWN] = {
877 "vis-window-slide-down",
878 VIS_HELP("Slide window content downwards")
879 wslide, { .i = +1 }
881 [VIS_ACTION_PUT_AFTER] = {
882 "vis-put-after",
883 VIS_HELP("Put text after the cursor")
884 operator, { .i = VIS_OP_PUT_AFTER }
886 [VIS_ACTION_PUT_BEFORE] = {
887 "vis-put-before",
888 VIS_HELP("Put text before the cursor")
889 operator, { .i = VIS_OP_PUT_BEFORE }
891 [VIS_ACTION_SELECTIONS_NEW_LINE_ABOVE] = {
892 "vis-selection-new-lines-above",
893 VIS_HELP("Create a new selection on the line above")
894 selections_new, { .i = -1 }
896 [VIS_ACTION_SELECTIONS_NEW_LINE_ABOVE_FIRST] = {
897 "vis-selection-new-lines-above-first",
898 VIS_HELP("Create a new selection on the line above the first selection")
899 selections_new, { .i = INT_MIN }
901 [VIS_ACTION_SELECTIONS_NEW_LINE_BELOW] = {
902 "vis-selection-new-lines-below",
903 VIS_HELP("Create a new selection on the line below")
904 selections_new, { .i = +1 }
906 [VIS_ACTION_SELECTIONS_NEW_LINE_BELOW_LAST] = {
907 "vis-selection-new-lines-below-last",
908 VIS_HELP("Create a new selection on the line below the last selection")
909 selections_new, { .i = INT_MAX }
911 [VIS_ACTION_SELECTIONS_NEW_LINES_BEGIN] = {
912 "vis-selection-new-lines-begin",
913 VIS_HELP("Create a new selection at the start of every line covered by selection")
914 operator, { .i = VIS_OP_CURSOR_SOL }
916 [VIS_ACTION_SELECTIONS_NEW_LINES_END] = {
917 "vis-selection-new-lines-end",
918 VIS_HELP("Create a new selection at the end of every line covered by selection")
919 operator, { .i = VIS_OP_CURSOR_EOL }
921 [VIS_ACTION_SELECTIONS_NEW_MATCH_ALL] = {
922 "vis-selection-new-match-all",
923 VIS_HELP("Select all regions matching the current selection")
924 selections_match_next, { .b = true }
926 [VIS_ACTION_SELECTIONS_NEW_MATCH_NEXT] = {
927 "vis-selection-new-match-next",
928 VIS_HELP("Select the next region matching the current selection")
929 selections_match_next,
931 [VIS_ACTION_SELECTIONS_NEW_MATCH_SKIP] = {
932 "vis-selection-new-match-skip",
933 VIS_HELP("Clear current selection, but select next match")
934 selections_match_skip,
936 [VIS_ACTION_SELECTIONS_ALIGN] = {
937 "vis-selections-align",
938 VIS_HELP("Try to align all selections on the same column")
939 selections_align,
941 [VIS_ACTION_SELECTIONS_ALIGN_INDENT_LEFT] = {
942 "vis-selections-align-indent-left",
943 VIS_HELP("Left-align all selections by inserting spaces")
944 selections_align_indent, { .i = -1 }
946 [VIS_ACTION_SELECTIONS_ALIGN_INDENT_RIGHT] = {
947 "vis-selections-align-indent-right",
948 VIS_HELP("Right-align all selections by inserting spaces")
949 selections_align_indent, { .i = +1 }
951 [VIS_ACTION_SELECTIONS_REMOVE_ALL] = {
952 "vis-selections-remove-all",
953 VIS_HELP("Remove all but the primary selection")
954 selections_clear,
956 [VIS_ACTION_SELECTIONS_REMOVE_LAST] = {
957 "vis-selections-remove-last",
958 VIS_HELP("Remove primary selection")
959 selections_remove,
961 [VIS_ACTION_SELECTIONS_REMOVE_COLUMN] = {
962 "vis-selections-remove-column",
963 VIS_HELP("Remove count selection column")
964 selections_remove_column, { .i = 1 }
966 [VIS_ACTION_SELECTIONS_REMOVE_COLUMN_EXCEPT] = {
967 "vis-selections-remove-column-except",
968 VIS_HELP("Remove all but the count selection column")
969 selections_remove_column_except, { .i = 1 }
971 [VIS_ACTION_SELECTIONS_PREV] = {
972 "vis-selection-prev",
973 VIS_HELP("Move to the previous selection")
974 selections_navigate, { .i = -PAGE_HALF }
976 [VIS_ACTION_SELECTIONS_NEXT] = {
977 "vis-selection-next",
978 VIS_HELP("Move to the next selection")
979 selections_navigate, { .i = +PAGE_HALF }
981 [VIS_ACTION_SELECTIONS_ROTATE_LEFT] = {
982 "vis-selections-rotate-left",
983 VIS_HELP("Rotate selections left")
984 selections_rotate, { .i = -1 }
986 [VIS_ACTION_SELECTIONS_ROTATE_RIGHT] = {
987 "vis-selections-rotate-right",
988 VIS_HELP("Rotate selections right")
989 selections_rotate, { .i = +1 }
991 [VIS_ACTION_SELECTIONS_TRIM] = {
992 "vis-selections-trim",
993 VIS_HELP("Remove leading and trailing white space from selections")
994 selections_trim
996 [VIS_ACTION_SELECTIONS_SAVE] = {
997 "vis-selections-save",
998 VIS_HELP("Save currently active selections to mark")
999 selections_save
1001 [VIS_ACTION_SELECTIONS_RESTORE] = {
1002 "vis-selections-restore",
1003 VIS_HELP("Restore selections from mark")
1004 selections_restore
1006 [VIS_ACTION_SELECTIONS_UNION] = {
1007 "vis-selections-union",
1008 VIS_HELP("Add selections from mark")
1009 selections_union
1011 [VIS_ACTION_SELECTIONS_INTERSECT] = {
1012 "vis-selections-intersect",
1013 VIS_HELP("Intersect with selections from mark")
1014 selections_intersect
1016 [VIS_ACTION_SELECTIONS_COMPLEMENT] = {
1017 "vis-selections-complement",
1018 VIS_HELP("Complement selections")
1019 selections_complement
1021 [VIS_ACTION_SELECTIONS_MINUS] = {
1022 "vis-selections-minus",
1023 VIS_HELP("Subtract selections from mark")
1024 selections_minus
1026 [VIS_ACTION_TEXT_OBJECT_WORD_OUTER] = {
1027 "vis-textobject-word-outer",
1028 VIS_HELP("A word leading and trailing whitespace included")
1029 textobj, { .i = VIS_TEXTOBJECT_OUTER_WORD }
1031 [VIS_ACTION_TEXT_OBJECT_WORD_INNER] = {
1032 "vis-textobject-word-inner",
1033 VIS_HELP("A word leading and trailing whitespace excluded")
1034 textobj, { .i = VIS_TEXTOBJECT_INNER_WORD }
1036 [VIS_ACTION_TEXT_OBJECT_LONGWORD_OUTER] = {
1037 "vis-textobject-bigword-outer",
1038 VIS_HELP("A WORD leading and trailing whitespace included")
1039 textobj, { .i = VIS_TEXTOBJECT_OUTER_LONGWORD }
1041 [VIS_ACTION_TEXT_OBJECT_LONGWORD_INNER] = {
1042 "vis-textobject-bigword-inner",
1043 VIS_HELP("A WORD leading and trailing whitespace excluded")
1044 textobj, { .i = VIS_TEXTOBJECT_INNER_LONGWORD }
1046 [VIS_ACTION_TEXT_OBJECT_SENTENCE] = {
1047 "vis-textobject-sentence",
1048 VIS_HELP("A sentence")
1049 textobj, { .i = VIS_TEXTOBJECT_SENTENCE }
1051 [VIS_ACTION_TEXT_OBJECT_PARAGRAPH] = {
1052 "vis-textobject-paragraph",
1053 VIS_HELP("A paragraph")
1054 textobj, { .i = VIS_TEXTOBJECT_PARAGRAPH }
1056 [VIS_ACTION_TEXT_OBJECT_PARAGRAPH_OUTER] = {
1057 "vis-textobject-paragraph-outer",
1058 VIS_HELP("A paragraph (outer variant)")
1059 textobj, { .i = VIS_TEXTOBJECT_PARAGRAPH_OUTER }
1061 [VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_OUTER] = {
1062 "vis-textobject-square-bracket-outer",
1063 VIS_HELP("[] block (outer variant)")
1064 textobj, { .i = VIS_TEXTOBJECT_OUTER_SQUARE_BRACKET }
1066 [VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_INNER] = {
1067 "vis-textobject-square-bracket-inner",
1068 VIS_HELP("[] block (inner variant)")
1069 textobj, { .i = VIS_TEXTOBJECT_INNER_SQUARE_BRACKET }
1071 [VIS_ACTION_TEXT_OBJECT_PARENTHESIS_OUTER] = {
1072 "vis-textobject-parenthesis-outer",
1073 VIS_HELP("() block (outer variant)")
1074 textobj, { .i = VIS_TEXTOBJECT_OUTER_PARENTHESIS }
1076 [VIS_ACTION_TEXT_OBJECT_PARENTHESIS_INNER] = {
1077 "vis-textobject-parenthesis-inner",
1078 VIS_HELP("() block (inner variant)")
1079 textobj, { .i = VIS_TEXTOBJECT_INNER_PARENTHESIS }
1081 [VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_OUTER] = {
1082 "vis-textobject-angle-bracket-outer",
1083 VIS_HELP("<> block (outer variant)")
1084 textobj, { .i = VIS_TEXTOBJECT_OUTER_ANGLE_BRACKET }
1086 [VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_INNER] = {
1087 "vis-textobject-angle-bracket-inner",
1088 VIS_HELP("<> block (inner variant)")
1089 textobj, { .i = VIS_TEXTOBJECT_INNER_ANGLE_BRACKET }
1091 [VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_OUTER] = {
1092 "vis-textobject-curly-bracket-outer",
1093 VIS_HELP("{} block (outer variant)")
1094 textobj, { .i = VIS_TEXTOBJECT_OUTER_CURLY_BRACKET }
1096 [VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_INNER] = {
1097 "vis-textobject-curly-bracket-inner",
1098 VIS_HELP("{} block (inner variant)")
1099 textobj, { .i = VIS_TEXTOBJECT_INNER_CURLY_BRACKET }
1101 [VIS_ACTION_TEXT_OBJECT_QUOTE_OUTER] = {
1102 "vis-textobject-quote-outer",
1103 VIS_HELP("A quoted string, including the quotation marks")
1104 textobj, { .i = VIS_TEXTOBJECT_OUTER_QUOTE }
1106 [VIS_ACTION_TEXT_OBJECT_QUOTE_INNER] = {
1107 "vis-textobject-quote-inner",
1108 VIS_HELP("A quoted string, excluding the quotation marks")
1109 textobj, { .i = VIS_TEXTOBJECT_INNER_QUOTE }
1111 [VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_OUTER] = {
1112 "vis-textobject-single-quote-outer",
1113 VIS_HELP("A single quoted string, including the quotation marks")
1114 textobj, { .i = VIS_TEXTOBJECT_OUTER_SINGLE_QUOTE }
1116 [VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_INNER] = {
1117 "vis-textobject-single-quote-inner",
1118 VIS_HELP("A single quoted string, excluding the quotation marks")
1119 textobj, { .i = VIS_TEXTOBJECT_INNER_SINGLE_QUOTE }
1121 [VIS_ACTION_TEXT_OBJECT_BACKTICK_OUTER] = {
1122 "vis-textobject-backtick-outer",
1123 VIS_HELP("A backtick delimited string (outer variant)")
1124 textobj, { .i = VIS_TEXTOBJECT_OUTER_BACKTICK }
1126 [VIS_ACTION_TEXT_OBJECT_BACKTICK_INNER] = {
1127 "vis-textobject-backtick-inner",
1128 VIS_HELP("A backtick delimited string (inner variant)")
1129 textobj, { .i = VIS_TEXTOBJECT_INNER_BACKTICK }
1131 [VIS_ACTION_TEXT_OBJECT_LINE_OUTER] = {
1132 "vis-textobject-line-outer",
1133 VIS_HELP("The whole line")
1134 textobj, { .i = VIS_TEXTOBJECT_OUTER_LINE }
1136 [VIS_ACTION_TEXT_OBJECT_LINE_INNER] = {
1137 "vis-textobject-line-inner",
1138 VIS_HELP("The whole line, excluding leading and trailing whitespace")
1139 textobj, { .i = VIS_TEXTOBJECT_INNER_LINE }
1141 [VIS_ACTION_TEXT_OBJECT_INDENTATION] = {
1142 "vis-textobject-indentation",
1143 VIS_HELP("All adjacent lines with the same indentation level as the current one")
1144 textobj, { .i = VIS_TEXTOBJECT_INDENTATION }
1146 [VIS_ACTION_TEXT_OBJECT_SEARCH_FORWARD] = {
1147 "vis-textobject-search-forward",
1148 VIS_HELP("The next search match in forward direction")
1149 textobj, { .i = VIS_TEXTOBJECT_SEARCH_FORWARD }
1151 [VIS_ACTION_TEXT_OBJECT_SEARCH_BACKWARD] = {
1152 "vis-textobject-search-backward",
1153 VIS_HELP("The next search match in backward direction")
1154 textobj, { .i = VIS_TEXTOBJECT_SEARCH_BACKWARD }
1156 [VIS_ACTION_UNICODE_INFO] = {
1157 "vis-unicode-info",
1158 VIS_HELP("Show Unicode codepoint(s) of character under cursor")
1159 unicode_info, { .i = VIS_ACTION_UNICODE_INFO }
1161 [VIS_ACTION_UTF8_INFO] = {
1162 "vis-utf8-info",
1163 VIS_HELP("Show UTF-8 encoded codepoint(s) of character under cursor")
1164 unicode_info, { .i = VIS_ACTION_UTF8_INFO }
1166 [VIS_ACTION_NOP] = {
1167 "vis-nop",
1168 VIS_HELP("Ignore key, do nothing")
1169 nop,
1173 #include "config.h"
1175 /** key bindings functions */
1177 static const char *nop(Vis *vis, const char *keys, const Arg *arg) {
1178 return keys;
1181 static const char *macro_record(Vis *vis, const char *keys, const Arg *arg) {
1182 if (!vis_macro_record_stop(vis)) {
1183 if (!keys[0])
1184 return NULL;
1185 const char *next = vis_keys_next(vis, keys);
1186 if (next - keys > 1)
1187 return next;
1188 enum VisRegister reg = vis_register_from(vis, keys[0]);
1189 vis_macro_record(vis, reg);
1190 keys++;
1192 vis_draw(vis);
1193 return keys;
1196 static const char *macro_replay(Vis *vis, const char *keys, const Arg *arg) {
1197 if (!keys[0])
1198 return NULL;
1199 const char *next = vis_keys_next(vis, keys);
1200 if (next - keys > 1)
1201 return next;
1202 enum VisRegister reg = vis_register_from(vis, keys[0]);
1203 vis_macro_replay(vis, reg);
1204 return keys+1;
1207 static const char *suspend(Vis *vis, const char *keys, const Arg *arg) {
1208 vis_suspend(vis);
1209 return keys;
1212 static const char *repeat(Vis *vis, const char *keys, const Arg *arg) {
1213 vis_repeat(vis);
1214 return keys;
1217 static const char *selections_new(Vis *vis, const char *keys, const Arg *arg) {
1218 View *view = vis_view(vis);
1219 bool anchored = view_selections_anchored(view_selections_primary_get(view));
1220 VisCountIterator it = vis_count_iterator_get(vis, 1);
1221 while (vis_count_iterator_next(&it)) {
1222 Selection *sel = NULL;
1223 switch (arg->i) {
1224 case -1:
1225 case +1:
1226 sel = view_selections_primary_get(view);
1227 break;
1228 case INT_MIN:
1229 sel = view_selections(view);
1230 break;
1231 case INT_MAX:
1232 for (Selection *s = view_selections(view); s; s = view_selections_next(s))
1233 sel = s;
1234 break;
1237 if (!sel)
1238 return keys;
1240 size_t oldpos = view_cursors_pos(sel);
1241 if (arg->i > 0)
1242 view_line_down(sel);
1243 else if (arg->i < 0)
1244 view_line_up(sel);
1245 size_t newpos = view_cursors_pos(sel);
1246 view_cursors_to(sel, oldpos);
1247 Selection *sel_new = view_selections_new(view, newpos);
1248 if (!sel_new) {
1249 if (arg->i == -1)
1250 sel_new = view_selections_prev(sel);
1251 else if (arg->i == +1)
1252 sel_new = view_selections_next(sel);
1254 if (sel_new) {
1255 view_selections_primary_set(sel_new);
1256 view_selections_anchor(sel_new, anchored);
1259 vis_count_set(vis, VIS_COUNT_UNKNOWN);
1260 return keys;
1263 static const char *selections_align(Vis *vis, const char *keys, const Arg *arg) {
1264 View *view = vis_view(vis);
1265 Text *txt = vis_text(vis);
1266 int mincol = INT_MAX;
1267 for (Selection *s = view_selections(view); s; s = view_selections_next(s)) {
1268 int col = view_cursors_cell_get(s);
1269 if (col >= 0 && col < mincol)
1270 mincol = col;
1272 for (Selection *s = view_selections(view); s; s = view_selections_next(s)) {
1273 if (view_cursors_cell_set(s, mincol) == -1) {
1274 size_t pos = view_cursors_pos(s);
1275 size_t col = text_line_width_set(txt, pos, mincol);
1276 view_cursors_to(s, col);
1279 return keys;
1282 static const char *selections_align_indent(Vis *vis, const char *keys, const Arg *arg) {
1283 View *view = vis_view(vis);
1284 Text *txt = vis_text(vis);
1285 bool left_align = arg->i < 0;
1286 int columns = view_selections_column_count(view);
1288 for (int i = 0; i < columns; i++) {
1289 int mincol = INT_MAX, maxcol = 0;
1290 for (Selection *s = view_selections_column(view, i); s; s = view_selections_column_next(s, i)) {
1291 Filerange sel = view_selections_get(s);
1292 size_t pos = left_align ? sel.start : sel.end;
1293 int col = text_line_width_get(txt, pos);
1294 if (col < mincol)
1295 mincol = col;
1296 if (col > maxcol)
1297 maxcol = col;
1300 size_t len = maxcol - mincol;
1301 char *buf = malloc(len+1);
1302 if (!buf)
1303 return keys;
1304 memset(buf, ' ', len);
1306 for (Selection *s = view_selections_column(view, i); s; s = view_selections_column_next(s, i)) {
1307 Filerange sel = view_selections_get(s);
1308 size_t pos = left_align ? sel.start : sel.end;
1309 size_t ipos = sel.start;
1310 int col = text_line_width_get(txt, pos);
1311 if (col < maxcol) {
1312 size_t off = maxcol - col;
1313 if (off <= len)
1314 text_insert(txt, ipos, buf, off);
1318 free(buf);
1321 view_draw(view);
1322 return keys;
1325 static const char *selections_clear(Vis *vis, const char *keys, const Arg *arg) {
1326 View *view = vis_view(vis);
1327 if (view_selections_count(view) > 1)
1328 view_selections_dispose_all(view);
1329 else
1330 view_selection_clear(view_selections_primary_get(view));
1331 return keys;
1334 static Selection *selection_new(View *view, Filerange *r, bool isprimary) {
1335 Text *txt = view_text(view);
1336 size_t pos = text_char_prev(txt, r->end);
1337 Selection *s = view_selections_new(view, pos);
1338 if (!s)
1339 return NULL;
1340 view_selections_set(s, r);
1341 view_selections_anchor(s, true);
1342 if (isprimary)
1343 view_selections_primary_set(s);
1344 return s;
1347 static const char *selections_match_next(Vis *vis, const char *keys, const Arg *arg) {
1348 Text *txt = vis_text(vis);
1349 View *view = vis_view(vis);
1350 Selection *s = view_selections_primary_get(view);
1351 Filerange sel = view_selections_get(s);
1352 if (!text_range_valid(&sel))
1353 return keys;
1355 static bool match_word;
1357 if (view_selections_count(view) == 1) {
1358 Filerange word = text_object_word(txt, view_cursors_pos(s));
1359 match_word = text_range_equal(&sel, &word);
1362 Filerange (*find_next)(Text *, size_t, const char *) = text_object_word_find_next;
1363 Filerange (*find_prev)(Text *, size_t, const char *) = text_object_word_find_prev;
1364 if (!match_word) {
1365 find_next = text_object_find_next;
1366 find_prev = text_object_find_prev;
1369 char *buf = text_bytes_alloc0(txt, sel.start, text_range_size(&sel));
1370 if (!buf)
1371 return keys;
1373 bool match_all = arg->b;
1374 Filerange primary = sel;
1376 for (;;) {
1377 sel = find_next(txt, sel.end, buf);
1378 if (!text_range_valid(&sel))
1379 break;
1380 if (selection_new(view, &sel, !match_all) && !match_all)
1381 goto out;
1384 sel = primary;
1386 for (;;) {
1387 sel = find_prev(txt, sel.start, buf);
1388 if (!text_range_valid(&sel))
1389 break;
1390 if (selection_new(view, &sel, !match_all) && !match_all)
1391 break;
1394 out:
1395 free(buf);
1396 return keys;
1399 static const char *selections_match_skip(Vis *vis, const char *keys, const Arg *arg) {
1400 View *view = vis_view(vis);
1401 Selection *sel = view_selections_primary_get(view);
1402 keys = selections_match_next(vis, keys, arg);
1403 if (sel != view_selections_primary_get(view))
1404 view_selections_dispose(sel);
1405 return keys;
1408 static const char *selections_remove(Vis *vis, const char *keys, const Arg *arg) {
1409 View *view = vis_view(vis);
1410 view_selections_dispose(view_selections_primary_get(view));
1411 view_cursor_to(view, view_cursor_get(view));
1412 return keys;
1415 static const char *selections_remove_column(Vis *vis, const char *keys, const Arg *arg) {
1416 View *view = vis_view(vis);
1417 int max = view_selections_column_count(view);
1418 int column = vis_count_get_default(vis, arg->i) - 1;
1419 if (column >= max)
1420 column = max - 1;
1421 if (view_selections_count(view) == 1) {
1422 vis_keys_feed(vis, "<Escape>");
1423 return keys;
1426 for (Selection *s = view_selections_column(view, column), *next; s; s = next) {
1427 next = view_selections_column_next(s, column);
1428 view_selections_dispose(s);
1431 vis_count_set(vis, VIS_COUNT_UNKNOWN);
1432 return keys;
1435 static const char *selections_remove_column_except(Vis *vis, const char *keys, const Arg *arg) {
1436 View *view = vis_view(vis);
1437 int max = view_selections_column_count(view);
1438 int column = vis_count_get_default(vis, arg->i) - 1;
1439 if (column >= max)
1440 column = max - 1;
1441 if (view_selections_count(view) == 1) {
1442 vis_redraw(vis);
1443 return keys;
1446 Selection *sel = view_selections(view);
1447 Selection *col = view_selections_column(view, column);
1448 for (Selection *next; sel; sel = next) {
1449 next = view_selections_next(sel);
1450 if (sel == col)
1451 col = view_selections_column_next(col, column);
1452 else
1453 view_selections_dispose(sel);
1456 vis_count_set(vis, VIS_COUNT_UNKNOWN);
1457 return keys;
1460 static const char *selections_navigate(Vis *vis, const char *keys, const Arg *arg) {
1461 View *view = vis_view(vis);
1462 if (view_selections_count(view) == 1)
1463 return wscroll(vis, keys, arg);
1464 Selection *s = view_selections_primary_get(view);
1465 VisCountIterator it = vis_count_iterator_get(vis, 1);
1466 while (vis_count_iterator_next(&it)) {
1467 if (arg->i > 0) {
1468 s = view_selections_next(s);
1469 if (!s)
1470 s = view_selections(view);
1471 } else {
1472 s = view_selections_prev(s);
1473 if (!s) {
1474 s = view_selections(view);
1475 for (Selection *n = s; n; n = view_selections_next(n))
1476 s = n;
1480 view_selections_primary_set(s);
1481 vis_count_set(vis, VIS_COUNT_UNKNOWN);
1482 return keys;
1485 static const char *selections_rotate(Vis *vis, const char *keys, const Arg *arg) {
1487 typedef struct {
1488 Selection *sel;
1489 char *data;
1490 size_t len;
1491 } Rotate;
1493 Array arr;
1494 Text *txt = vis_text(vis);
1495 View *view = vis_view(vis);
1496 int columns = view_selections_column_count(view);
1497 int selections = columns == 1 ? view_selections_count(view) : columns;
1498 int count = vis_count_get_default(vis, 1);
1499 array_init_sized(&arr, sizeof(Rotate));
1500 if (!array_reserve(&arr, selections))
1501 return keys;
1502 size_t line = 0;
1504 for (Selection *s = view_selections(view), *next; s; s = next) {
1505 next = view_selections_next(s);
1506 size_t line_next = 0;
1508 Filerange sel = view_selections_get(s);
1509 Rotate rot;
1510 rot.sel = s;
1511 rot.len = text_range_size(&sel);
1512 if ((rot.data = malloc(rot.len)))
1513 rot.len = text_bytes_get(txt, sel.start, rot.len, rot.data);
1514 else
1515 rot.len = 0;
1516 array_add(&arr, &rot);
1518 if (!line)
1519 line = text_lineno_by_pos(txt, view_cursors_pos(s));
1520 if (next)
1521 line_next = text_lineno_by_pos(txt, view_cursors_pos(next));
1522 if (!next || (columns > 1 && line != line_next)) {
1523 size_t len = array_length(&arr);
1524 size_t off = arg->i > 0 ? count % len : len - (count % len);
1525 for (size_t i = 0; i < len; i++) {
1526 size_t j = (i + off) % len;
1527 Rotate *oldrot = array_get(&arr, i);
1528 Rotate *newrot = array_get(&arr, j);
1529 if (!oldrot || !newrot || oldrot == newrot)
1530 continue;
1531 Filerange newsel = view_selections_get(newrot->sel);
1532 if (!text_range_valid(&newsel))
1533 continue;
1534 if (!text_delete_range(txt, &newsel))
1535 continue;
1536 if (!text_insert(txt, newsel.start, oldrot->data, oldrot->len))
1537 continue;
1538 newsel.end = newsel.start + oldrot->len;
1539 view_selections_set(newrot->sel, &newsel);
1540 free(oldrot->data);
1542 array_clear(&arr);
1544 line = line_next;
1547 array_release(&arr);
1548 vis_count_set(vis, VIS_COUNT_UNKNOWN);
1549 return keys;
1552 static const char *selections_trim(Vis *vis, const char *keys, const Arg *arg) {
1553 Text *txt = vis_text(vis);
1554 View *view = vis_view(vis);
1555 for (Selection *s = view_selections(view), *next; s; s = next) {
1556 next = view_selections_next(s);
1557 Filerange sel = view_selections_get(s);
1558 if (!text_range_valid(&sel))
1559 continue;
1560 for (char b; sel.start < sel.end && text_byte_get(txt, sel.end-1, &b)
1561 && isspace((unsigned char)b); sel.end--);
1562 for (char b; sel.start <= sel.end && text_byte_get(txt, sel.start, &b)
1563 && isspace((unsigned char)b); sel.start++);
1564 if (sel.start < sel.end) {
1565 view_selections_set(s, &sel);
1566 } else if (!view_selections_dispose(s)) {
1567 vis_mode_switch(vis, VIS_MODE_NORMAL);
1570 return keys;
1573 static void selections_set(Vis *vis, View *view, Array *sel) {
1574 enum VisMode mode = vis_mode_get(vis);
1575 bool anchored = mode == VIS_MODE_VISUAL || mode == VIS_MODE_VISUAL_LINE;
1576 view_selections_set_all(view, sel, anchored);
1577 if (!anchored)
1578 view_selections_clear_all(view);
1581 static const char *selections_save(Vis *vis, const char *keys, const Arg *arg) {
1582 Win *win = vis_window(vis);
1583 View *view = vis_view(vis);
1584 enum VisMark mark = vis_mark_used(vis);
1585 Array sel = view_selections_get_all(view);
1586 vis_mark_set(win, mark, &sel);
1587 array_release(&sel);
1588 vis_cancel(vis);
1589 return keys;
1592 static const char *selections_restore(Vis *vis, const char *keys, const Arg *arg) {
1593 Win *win = vis_window(vis);
1594 View *view = vis_view(vis);
1595 enum VisMark mark = vis_mark_used(vis);
1596 Array sel = vis_mark_get(win, mark);
1597 selections_set(vis, view, &sel);
1598 array_release(&sel);
1599 vis_cancel(vis);
1600 return keys;
1603 static const char *selections_union(Vis *vis, const char *keys, const Arg *arg) {
1604 Win *win = vis_window(vis);
1605 View *view = vis_view(vis);
1606 enum VisMark mark = vis_mark_used(vis);
1607 Array a = vis_mark_get(win, mark);
1608 Array b = view_selections_get_all(view);
1609 Array sel;
1610 array_init_from(&sel, &a);
1612 size_t i = 0, j = 0;
1613 Filerange *r1 = array_get(&a, i), *r2 = array_get(&b, j), cur = text_range_empty();
1614 while (r1 || r2) {
1615 if (r1 && text_range_overlap(r1, &cur)) {
1616 cur = text_range_union(r1, &cur);
1617 r1 = array_get(&a, ++i);
1618 } else if (r2 && text_range_overlap(r2, &cur)) {
1619 cur = text_range_union(r2, &cur);
1620 r2 = array_get(&b, ++j);
1621 } else {
1622 if (text_range_valid(&cur))
1623 array_add(&sel, &cur);
1624 if (!r1) {
1625 cur = *r2;
1626 r2 = array_get(&b, ++j);
1627 } else if (!r2) {
1628 cur = *r1;
1629 r1 = array_get(&a, ++i);
1630 } else {
1631 if (r1->start < r2->start) {
1632 cur = *r1;
1633 r1 = array_get(&a, ++i);
1634 } else {
1635 cur = *r2;
1636 r2 = array_get(&b, ++j);
1642 if (text_range_valid(&cur))
1643 array_add(&sel, &cur);
1645 selections_set(vis, view, &sel);
1646 vis_cancel(vis);
1648 array_release(&a);
1649 array_release(&b);
1650 array_release(&sel);
1652 return keys;
1655 static void intersect(Array *ret, Array *a, Array *b) {
1656 size_t i = 0, j = 0;
1657 Filerange *r1 = array_get(a, i), *r2 = array_get(b, j);
1658 while (r1 && r2) {
1659 if (text_range_overlap(r1, r2)) {
1660 Filerange new = text_range_intersect(r1, r2);
1661 array_add(ret, &new);
1663 if (r1->end < r2->end)
1664 r1 = array_get(a, ++i);
1665 else
1666 r2 = array_get(b, ++j);
1670 static const char *selections_intersect(Vis *vis, const char *keys, const Arg *arg) {
1671 Win *win = vis_window(vis);
1672 View *view = vis_view(vis);
1673 enum VisMark mark = vis_mark_used(vis);
1674 Array a = vis_mark_get(win, mark);
1675 Array b = view_selections_get_all(view);
1676 Array sel;
1677 array_init_from(&sel, &a);
1679 intersect(&sel, &a, &b);
1680 selections_set(vis, view, &sel);
1681 vis_cancel(vis);
1683 array_release(&a);
1684 array_release(&b);
1685 array_release(&sel);
1687 return keys;
1690 static void complement(Array *ret, Array *a, Filerange *universe) {
1691 size_t pos = universe->start;
1692 for (size_t i = 0, len = array_length(a); i < len; i++) {
1693 Filerange *r = array_get(a, i);
1694 if (pos < r->start) {
1695 Filerange new = text_range_new(pos, r->start);
1696 array_add(ret, &new);
1698 pos = r->end;
1700 if (pos < universe->end) {
1701 Filerange new = text_range_new(pos, universe->end);
1702 array_add(ret, &new);
1706 static const char *selections_complement(Vis *vis, const char *keys, const Arg *arg) {
1707 Text *txt = vis_text(vis);
1708 View *view = vis_view(vis);
1709 Filerange universe = text_object_entire(txt, 0);
1710 Array a = view_selections_get_all(view);
1711 Array sel;
1712 array_init_from(&sel, &a);
1714 complement(&sel, &a, &universe);
1716 selections_set(vis, view, &sel);
1717 array_release(&a);
1718 array_release(&sel);
1719 return keys;
1722 static const char *selections_minus(Vis *vis, const char *keys, const Arg *arg) {
1723 Text *txt = vis_text(vis);
1724 Win *win = vis_window(vis);
1725 View *view = vis_view(vis);
1726 enum VisMark mark = vis_mark_used(vis);
1727 Array a = view_selections_get_all(view);
1728 Array b = vis_mark_get(win, mark);
1729 Array sel;
1730 array_init_from(&sel, &a);
1731 Array b_complement;
1732 array_init_from(&b_complement, &b);
1734 Filerange universe = text_object_entire(txt, 0);
1735 complement(&b_complement, &b, &universe);
1736 intersect(&sel, &a, &b_complement);
1738 selections_set(vis, view, &sel);
1739 vis_cancel(vis);
1741 array_release(&a);
1742 array_release(&b);
1743 array_release(&b_complement);
1744 array_release(&sel);
1746 return keys;
1749 static const char *replace(Vis *vis, const char *keys, const Arg *arg) {
1750 if (!keys[0]) {
1751 vis_keymap_disable(vis);
1752 return NULL;
1755 const char *next = vis_keys_next(vis, keys);
1756 if (!next)
1757 return NULL;
1759 char replacement[UTFmax+1];
1760 if (!vis_keys_utf8(vis, keys, replacement))
1761 return next;
1763 if (replacement[0] == 0x1b) /* <Escape> */
1764 return next;
1766 vis_operator(vis, VIS_OP_REPLACE, replacement);
1767 if (vis_mode_get(vis) == VIS_MODE_OPERATOR_PENDING)
1768 vis_motion(vis, VIS_MOVE_CHAR_NEXT);
1769 return next;
1772 static const char *count(Vis *vis, const char *keys, const Arg *arg) {
1773 int digit = keys[-1] - '0';
1774 int count = vis_count_get_default(vis, 0);
1775 if (0 <= digit && digit <= 9) {
1776 if (digit == 0 && count == 0)
1777 vis_motion(vis, VIS_MOVE_LINE_BEGIN);
1778 else
1779 vis_count_set(vis, count * 10 + digit);
1781 return keys;
1784 static const char *gotoline(Vis *vis, const char *keys, const Arg *arg) {
1785 if (vis_count_get(vis) != VIS_COUNT_UNKNOWN)
1786 vis_motion(vis, VIS_MOVE_LINE);
1787 else if (arg->i < 0)
1788 vis_motion(vis, VIS_MOVE_FILE_BEGIN);
1789 else
1790 vis_motion(vis, VIS_MOVE_FILE_END);
1791 return keys;
1794 static const char *operator(Vis *vis, const char *keys, const Arg *arg) {
1795 vis_operator(vis, arg->i);
1796 return keys;
1799 static const char *movement_key(Vis *vis, const char *keys, const Arg *arg) {
1800 if (!keys[0]) {
1801 vis_keymap_disable(vis);
1802 return NULL;
1805 const char *next = vis_keys_next(vis, keys);
1806 if (!next)
1807 return NULL;
1808 char utf8[UTFmax+1];
1809 if (vis_keys_utf8(vis, keys, utf8))
1810 vis_motion(vis, arg->i, utf8);
1811 return next;
1814 static const char *movement(Vis *vis, const char *keys, const Arg *arg) {
1815 vis_motion(vis, arg->i);
1816 return keys;
1819 static const char *textobj(Vis *vis, const char *keys, const Arg *arg) {
1820 vis_textobject(vis, arg->i);
1821 return keys;
1824 static const char *selection_end(Vis *vis, const char *keys, const Arg *arg) {
1825 for (Selection *s = view_selections(vis_view(vis)); s; s = view_selections_next(s))
1826 view_selections_flip(s);
1827 return keys;
1830 static const char *reg(Vis *vis, const char *keys, const Arg *arg) {
1831 if (!keys[0])
1832 return NULL;
1833 const char *next = vis_keys_next(vis, keys);
1834 if (next - keys > 1)
1835 return next;
1836 enum VisRegister reg = vis_register_from(vis, keys[0]);
1837 vis_register(vis, reg);
1838 return keys+1;
1841 static const char *mark(Vis *vis, const char *keys, const Arg *arg) {
1842 if (!keys[0])
1843 return NULL;
1844 const char *next = vis_keys_next(vis, keys);
1845 if (next - keys > 1)
1846 return next;
1847 enum VisMark mark = vis_mark_from(vis, keys[0]);
1848 vis_mark(vis, mark);
1849 return keys+1;
1852 static const char *undo(Vis *vis, const char *keys, const Arg *arg) {
1853 size_t pos = text_undo(vis_text(vis));
1854 if (pos != EPOS) {
1855 View *view = vis_view(vis);
1856 if (view_selections_count(view) == 1)
1857 view_cursor_to(view, pos);
1858 /* redraw all windows in case some display the same file */
1859 vis_draw(vis);
1861 return keys;
1864 static const char *redo(Vis *vis, const char *keys, const Arg *arg) {
1865 size_t pos = text_redo(vis_text(vis));
1866 if (pos != EPOS) {
1867 View *view = vis_view(vis);
1868 if (view_selections_count(view) == 1)
1869 view_cursor_to(view, pos);
1870 /* redraw all windows in case some display the same file */
1871 vis_draw(vis);
1873 return keys;
1876 static const char *earlier(Vis *vis, const char *keys, const Arg *arg) {
1877 size_t pos = EPOS;
1878 VisCountIterator it = vis_count_iterator_get(vis, 1);
1879 while (vis_count_iterator_next(&it))
1880 pos = text_earlier(vis_text(vis));
1881 if (pos != EPOS) {
1882 view_cursor_to(vis_view(vis), pos);
1883 /* redraw all windows in case some display the same file */
1884 vis_draw(vis);
1886 return keys;
1889 static const char *later(Vis *vis, const char *keys, const Arg *arg) {
1890 size_t pos = EPOS;
1891 VisCountIterator it = vis_count_iterator_get(vis, 1);
1892 while (vis_count_iterator_next(&it))
1893 pos = text_later(vis_text(vis));
1894 if (pos != EPOS) {
1895 view_cursor_to(vis_view(vis), pos);
1896 /* redraw all windows in case some display the same file */
1897 vis_draw(vis);
1899 return keys;
1902 static const char *delete(Vis *vis, const char *keys, const Arg *arg) {
1903 vis_operator(vis, VIS_OP_DELETE);
1904 vis_motion(vis, arg->i);
1905 return keys;
1908 static const char *insert_register(Vis *vis, const char *keys, const Arg *arg) {
1909 if (!keys[0])
1910 return NULL;
1911 const char *next = vis_keys_next(vis, keys);
1912 if (next - keys > 1)
1913 return next;
1914 enum VisRegister reg = vis_register_from(vis, keys[0]);
1915 if (reg != VIS_REG_INVALID) {
1916 vis_register(vis, reg);
1917 vis_operator(vis, VIS_OP_PUT_BEFORE_END);
1919 return keys+1;
1922 static const char *prompt_show(Vis *vis, const char *keys, const Arg *arg) {
1923 vis_prompt_show(vis, arg->s);
1924 return keys;
1927 static const char *insert_verbatim(Vis *vis, const char *keys, const Arg *arg) {
1928 Rune rune = 0;
1929 char buf[4], type = keys[0];
1930 const char *data = NULL;
1931 int len = 0, count = 0, base = 0;
1932 switch (type) {
1933 case '\0':
1934 return NULL;
1935 case 'o':
1936 case 'O':
1937 count = 3;
1938 base = 8;
1939 break;
1940 case 'U':
1941 count = 4;
1942 /* fall through */
1943 case 'u':
1944 count += 4;
1945 base = 16;
1946 break;
1947 case 'x':
1948 case 'X':
1949 count = 2;
1950 base = 16;
1951 break;
1952 default:
1953 if ('0' <= type && type <= '9') {
1954 rune = type - '0';
1955 count = 2;
1956 base = 10;
1958 break;
1961 if (base) {
1962 for (keys++; keys[0] && count > 0; keys++, count--) {
1963 int v = 0;
1964 if (base == 8 && '0' <= keys[0] && keys[0] <= '7') {
1965 v = keys[0] - '0';
1966 } else if ((base == 10 || base == 16) && '0' <= keys[0] && keys[0] <= '9') {
1967 v = keys[0] - '0';
1968 } else if (base == 16 && 'a' <= keys[0] && keys[0] <= 'f') {
1969 v = 10 + keys[0] - 'a';
1970 } else if (base == 16 && 'A' <= keys[0] && keys[0] <= 'F') {
1971 v = 10 + keys[0] - 'A';
1972 } else {
1973 count = 0;
1974 break;
1976 rune = rune * base + v;
1979 if (count > 0)
1980 return NULL;
1981 if (type == 'u' || type == 'U') {
1982 len = runetochar(buf, &rune);
1983 } else {
1984 buf[0] = rune;
1985 len = 1;
1988 data = buf;
1989 } else {
1990 const char *next = vis_keys_next(vis, keys);
1991 if (!next)
1992 return NULL;
1993 if ((rune = vis_keys_codepoint(vis, keys)) != (Rune)-1) {
1994 len = runetochar(buf, &rune);
1995 if (buf[0] == '\n')
1996 buf[0] = '\r';
1997 data = buf;
1998 } else {
1999 vis_info_show(vis, "Unknown key");
2001 keys = next;
2004 if (len > 0)
2005 vis_insert_key(vis, data, len);
2006 return keys;
2009 static const char *wscroll(Vis *vis, const char *keys, const Arg *arg) {
2010 View *view = vis_view(vis);
2011 int count = vis_count_get(vis);
2012 switch (arg->i) {
2013 case -PAGE:
2014 view_scroll_page_up(view);
2015 break;
2016 case +PAGE:
2017 view_scroll_page_down(view);
2018 break;
2019 case -PAGE_HALF:
2020 view_scroll_halfpage_up(view);
2021 break;
2022 case +PAGE_HALF:
2023 view_scroll_halfpage_down(view);
2024 break;
2025 default:
2026 if (count == VIS_COUNT_UNKNOWN)
2027 count = arg->i < 0 ? -arg->i : arg->i;
2028 if (arg->i < 0)
2029 view_scroll_up(view, count);
2030 else
2031 view_scroll_down(view, count);
2032 break;
2034 vis_count_set(vis, VIS_COUNT_UNKNOWN);
2035 return keys;
2038 static const char *wslide(Vis *vis, const char *keys, const Arg *arg) {
2039 View *view = vis_view(vis);
2040 int count = vis_count_get(vis);
2041 if (count == VIS_COUNT_UNKNOWN)
2042 count = arg->i < 0 ? -arg->i : arg->i;
2043 if (arg->i >= 0)
2044 view_slide_down(view, count);
2045 else
2046 view_slide_up(view, count);
2047 vis_count_set(vis, VIS_COUNT_UNKNOWN);
2048 return keys;
2051 static const char *call(Vis *vis, const char *keys, const Arg *arg) {
2052 arg->f(vis);
2053 return keys;
2056 static const char *window(Vis *vis, const char *keys, const Arg *arg) {
2057 arg->w(vis_view(vis));
2058 return keys;
2061 static const char *openline(Vis *vis, const char *keys, const Arg *arg) {
2062 vis_operator(vis, VIS_OP_MODESWITCH, VIS_MODE_INSERT);
2063 if (arg->i > 0) {
2064 vis_motion(vis, VIS_MOVE_LINE_END);
2065 vis_keys_feed(vis, "<Enter>");
2066 } else {
2067 if (vis_get_autoindent(vis)) {
2068 vis_motion(vis, VIS_MOVE_LINE_START);
2069 vis_keys_feed(vis, "<vis-motion-line-start>");
2070 } else {
2071 vis_motion(vis, VIS_MOVE_LINE_BEGIN);
2072 vis_keys_feed(vis, "<vis-motion-line-begin>");
2074 vis_keys_feed(vis, "<Enter><vis-motion-line-up>");
2076 return keys;
2079 static const char *join(Vis *vis, const char *keys, const Arg *arg) {
2080 bool normal = (vis_mode_get(vis) == VIS_MODE_NORMAL);
2081 vis_operator(vis, VIS_OP_JOIN, arg->s);
2082 if (normal) {
2083 int count = vis_count_get_default(vis, 0);
2084 if (count)
2085 vis_count_set(vis, count-1);
2086 vis_motion(vis, VIS_MOVE_LINE_NEXT);
2088 return keys;
2091 static const char *normalmode_escape(Vis *vis, const char *keys, const Arg *arg) {
2092 if (vis_count_get(vis) == VIS_COUNT_UNKNOWN)
2093 selections_clear(vis, keys, arg);
2094 else
2095 vis_count_set(vis, VIS_COUNT_UNKNOWN);
2096 return keys;
2099 static const char *visualmode_escape(Vis *vis, const char *keys, const Arg *arg) {
2100 if (vis_count_get(vis) == VIS_COUNT_UNKNOWN)
2101 vis_mode_switch(vis, VIS_MODE_NORMAL);
2102 else
2103 vis_count_set(vis, VIS_COUNT_UNKNOWN);
2104 return keys;
2107 static const char *switchmode(Vis *vis, const char *keys, const Arg *arg) {
2108 vis_mode_switch(vis, arg->i);
2109 return keys;
2112 static const char *insertmode(Vis *vis, const char *keys, const Arg *arg) {
2113 vis_operator(vis, VIS_OP_MODESWITCH, VIS_MODE_INSERT);
2114 vis_motion(vis, arg->i);
2115 return keys;
2118 static const char *replacemode(Vis *vis, const char *keys, const Arg *arg) {
2119 vis_operator(vis, VIS_OP_MODESWITCH, VIS_MODE_REPLACE);
2120 vis_motion(vis, arg->i);
2121 return keys;
2124 static const char *unicode_info(Vis *vis, const char *keys, const Arg *arg) {
2125 View *view = vis_view(vis);
2126 Text *txt = vis_text(vis);
2127 size_t start = view_cursor_get(view);
2128 size_t end = text_char_next(txt, start);
2129 char *grapheme = text_bytes_alloc0(txt, start, end-start), *codepoint = grapheme;
2130 if (!grapheme)
2131 return keys;
2132 Buffer info;
2133 buffer_init(&info);
2134 mbstate_t ps = { 0 };
2135 Iterator it = text_iterator_get(txt, start);
2136 for (size_t pos = start; it.pos < end; pos = it.pos) {
2137 if (!text_iterator_codepoint_next(&it, NULL)) {
2138 vis_info_show(vis, "Failed to parse code point");
2139 goto err;
2141 size_t len = it.pos - pos;
2142 wchar_t wc = 0xFFFD;
2143 size_t res = mbrtowc(&wc, codepoint, len, &ps);
2144 bool combining = false;
2145 if (res != (size_t)-1 && res != (size_t)-2)
2146 combining = (wc != L'\0' && wcwidth(wc) == 0);
2147 unsigned char ch = *codepoint;
2148 if (ch < 128 && !isprint(ch))
2149 buffer_appendf(&info, "<^%c> ", ch == 127 ? '?' : ch + 64);
2150 else
2151 buffer_appendf(&info, "<%s%.*s> ", combining ? " " : "", (int)len, codepoint);
2152 if (arg->i == VIS_ACTION_UNICODE_INFO) {
2153 buffer_appendf(&info, "U+%04"PRIX32" ", (uint32_t)wc);
2154 } else {
2155 for (size_t i = 0; i < len; i++)
2156 buffer_appendf(&info, "%02x ", (uint8_t)codepoint[i]);
2158 codepoint += len;
2160 vis_info_show(vis, "%s", buffer_content0(&info));
2161 err:
2162 free(grapheme);
2163 buffer_release(&info);
2164 return keys;
2167 static const char *percent(Vis *vis, const char *keys, const Arg *arg) {
2168 if (vis_count_get(vis) == VIS_COUNT_UNKNOWN)
2169 vis_motion(vis, VIS_MOVE_BRACKET_MATCH);
2170 else
2171 vis_motion(vis, VIS_MOVE_PERCENT);
2172 return keys;
2175 static const char *jumplist(Vis *vis, const char *keys, const Arg *arg) {
2176 if (arg->i < 0)
2177 vis_jumplist_prev(vis);
2178 else if (arg->i > 0)
2179 vis_jumplist_next(vis);
2180 else
2181 vis_jumplist_save(vis);
2182 return keys;
2185 static Vis *vis;
2187 static void signal_handler(int signum, siginfo_t *siginfo, void *context) {
2188 vis_signal_handler(vis, signum, siginfo, context);
2191 int main(int argc, char *argv[]) {
2193 VisEvent event = {
2194 .init = vis_lua_init,
2195 .start = vis_lua_start,
2196 .quit = vis_lua_quit,
2197 .mode_insert_input = vis_lua_mode_insert_input,
2198 .mode_replace_input = vis_lua_mode_replace_input,
2199 .file_open = vis_lua_file_open,
2200 .file_save_pre = vis_lua_file_save_pre,
2201 .file_save_post = vis_lua_file_save_post,
2202 .file_close = vis_lua_file_close,
2203 .win_open = vis_lua_win_open,
2204 .win_close = vis_lua_win_close,
2205 .win_highlight = vis_lua_win_highlight,
2206 .win_status = vis_lua_win_status,
2207 .term_csi = vis_lua_term_csi,
2210 vis = vis_new(ui_term_new(), &event);
2211 if (!vis)
2212 return EXIT_FAILURE;
2214 for (int i = 0; i < LENGTH(vis_action); i++) {
2215 const KeyAction *action = &vis_action[i];
2216 if (!vis_action_register(vis, action))
2217 vis_die(vis, "Could not register action: %s\n", action->name);
2220 for (int i = 0; i < LENGTH(default_bindings); i++) {
2221 for (const KeyBinding **binding = default_bindings[i]; binding && *binding; binding++) {
2222 for (const KeyBinding *kb = *binding; kb->key; kb++) {
2223 vis_mode_map(vis, i, false, kb->key, kb);
2228 for (const char **k = keymaps; k[0]; k += 2)
2229 vis_keymap_add(vis, k[0], k[1]);
2231 /* install signal handlers etc. */
2232 struct sigaction sa;
2233 memset(&sa, 0, sizeof sa);
2234 sigfillset(&sa.sa_mask);
2235 sa.sa_flags = SA_SIGINFO;
2236 sa.sa_sigaction = signal_handler;
2237 if (sigaction(SIGBUS, &sa, NULL) == -1 ||
2238 sigaction(SIGINT, &sa, NULL) == -1 ||
2239 sigaction(SIGCONT, &sa, NULL) == -1 ||
2240 sigaction(SIGWINCH, &sa, NULL) == -1 ||
2241 sigaction(SIGTERM, &sa, NULL) == -1 ||
2242 sigaction(SIGHUP, &sa, NULL) == -1) {
2243 vis_die(vis, "Failed to set signal handler: %s\n", strerror(errno));
2246 sa.sa_handler = SIG_IGN;
2247 if (sigaction(SIGPIPE, &sa, NULL) == -1 || sigaction(SIGQUIT, &sa, NULL) == -1)
2248 vis_die(vis, "Failed to ignore signals\n");
2250 sigset_t blockset;
2251 sigemptyset(&blockset);
2252 sigaddset(&blockset, SIGBUS);
2253 sigaddset(&blockset, SIGCONT);
2254 sigaddset(&blockset, SIGWINCH);
2255 sigaddset(&blockset, SIGTERM);
2256 sigaddset(&blockset, SIGHUP);
2257 if (sigprocmask(SIG_BLOCK, &blockset, NULL) == -1)
2258 vis_die(vis, "Failed to block signals\n");
2260 for (int i = 1; i < argc; i++) {
2261 if (argv[i][0] != '-') {
2262 continue;
2263 } else if (strcmp(argv[i], "-") == 0) {
2264 continue;
2265 } else if (strcmp(argv[i], "--") == 0) {
2266 break;
2267 } else if (strcmp(argv[i], "-v") == 0) {
2268 printf("vis %s%s%s%s%s%s%s\n", VERSION,
2269 CONFIG_CURSES ? " +curses" : "",
2270 CONFIG_LUA ? " +lua" : "",
2271 CONFIG_LPEG ? " +lpeg" : "",
2272 CONFIG_TRE ? " +tre" : "",
2273 CONFIG_ACL ? " +acl" : "",
2274 CONFIG_SELINUX ? " +selinux" : "");
2275 return 0;
2276 } else {
2277 fprintf(stderr, "Unknown command option: %s\n", argv[i]);
2278 return 1;
2282 char *cmd = NULL;
2283 bool end_of_options = false, win_created = false;
2285 for (int i = 1; i < argc; i++) {
2286 if (argv[i][0] == '-' && !end_of_options) {
2287 if (strcmp(argv[i], "-") == 0) {
2288 if (!vis_window_new_fd(vis, STDOUT_FILENO))
2289 vis_die(vis, "Can not create empty buffer\n");
2290 ssize_t len = 0;
2291 char buf[PIPE_BUF];
2292 Text *txt = vis_text(vis);
2293 while ((len = read(STDIN_FILENO, buf, sizeof buf)) > 0)
2294 text_insert(txt, text_size(txt), buf, len);
2295 if (len == -1)
2296 vis_die(vis, "Can not read from stdin\n");
2297 text_snapshot(txt);
2298 int fd = open("/dev/tty", O_RDWR);
2299 if (fd == -1)
2300 vis_die(vis, "Can not reopen stdin\n");
2301 dup2(fd, STDIN_FILENO);
2302 close(fd);
2303 } else if (strcmp(argv[i], "--") == 0) {
2304 end_of_options = true;
2305 continue;
2307 } else if (argv[i][0] == '+' && !end_of_options) {
2308 cmd = argv[i] + (argv[i][1] == '/' || argv[i][1] == '?');
2309 continue;
2310 } else if (!vis_window_new(vis, argv[i])) {
2311 vis_die(vis, "Can not load `%s': %s\n", argv[i], strerror(errno));
2313 win_created = true;
2314 if (cmd) {
2315 vis_prompt_cmd(vis, cmd);
2316 cmd = NULL;
2320 if (!vis_window(vis) && !win_created) {
2321 if (!vis_window_new(vis, NULL))
2322 vis_die(vis, "Can not create empty buffer\n");
2323 if (cmd)
2324 vis_prompt_cmd(vis, cmd);
2327 int status = vis_run(vis);
2328 vis_free(vis);
2329 return status;