11 #include <sys/types.h>
13 #include "ui-terminal.h"
16 #include "text-util.h"
17 #include "text-motions.h"
18 #include "text-objects.h"
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 word the selection is currently over */
70 static const char *selections_match_word(Vis
*, const char *keys
, const Arg
*arg
);
71 /* select the next region matching the current selection */
72 static const char *selections_match_next(Vis
*, const char *keys
, const Arg
*arg
);
73 /* clear current selection but select next match */
74 static const char *selections_match_skip(Vis
*, const char *keys
, const Arg
*arg
);
75 /* rotate selection content count times left (arg->i < 0) or right (arg->i > 0) */
76 static const char *selections_rotate(Vis
*, const char *keys
, const Arg
*arg
);
77 /* remove leading and trailing white spaces from selections */
78 static const char *selections_trim(Vis
*, const char *keys
, const Arg
*arg
);
79 /* save active selections to mark */
80 static const char *selections_save(Vis
*, const char *keys
, const Arg
*arg
);
81 /* restore selections from mark */
82 static const char *selections_restore(Vis
*, const char *keys
, const Arg
*arg
);
83 /* union selections from mark */
84 static const char *selections_union(Vis
*, const char *keys
, const Arg
*arg
);
85 /* intersect selections from mark */
86 static const char *selections_intersect(Vis
*, const char *keys
, const Arg
*arg
);
87 /* perform complement of current active selections */
88 static const char *selections_complement(Vis
*, const char *keys
, const Arg
*arg
);
89 /* subtract selections from mark */
90 static const char *selections_minus(Vis
*, const char *keys
, const Arg
*arg
);
91 /* pairwise combine selections from mark */
92 static const char *selections_combine(Vis
*, const char *keys
, const Arg
*arg
);
93 static Filerange
combine_shorter(const Filerange
*, const Filerange
*);
94 static Filerange
combine_leftmost(const Filerange
*, const Filerange
*);
95 static Filerange
combine_rightmost(const Filerange
*, const Filerange
*);
96 /* adjust current used count according to keys */
97 static const char *count(Vis
*, const char *keys
, const Arg
*arg
);
98 /* move to the count-th line or if not given either to the first (arg->i < 0)
99 * or last (arg->i > 0) line of file */
100 static const char *gotoline(Vis
*, const char *keys
, const Arg
*arg
);
101 /* make the current action use the operator indicated by arg->i */
102 static const char *operator(Vis
*, const char *keys
, const Arg
*arg
);
103 /* blocks to read a key and performs movement indicated by arg->i which
104 * should be one of VIS_MOVE_{RIGHT,LEFT}_{TO,TILL} */
105 static const char *movement_key(Vis
*, const char *keys
, const Arg
*arg
);
106 /* perform the movement as indicated by arg->i */
107 static const char *movement(Vis
*, const char *keys
, const Arg
*arg
);
108 /* let the current operator affect the range indicated by the text object arg->i */
109 static const char *textobj(Vis
*, const char *keys
, const Arg
*arg
);
110 /* move to the other end of selected text */
111 static const char *selection_end(Vis
*, const char *keys
, const Arg
*arg
);
112 /* use register indicated by keys for the current operator */
113 static const char *reg(Vis
*, const char *keys
, const Arg
*arg
);
114 /* use mark indicated by keys for the current action */
115 static const char *mark(Vis
*, const char *keys
, const Arg
*arg
);
116 /* {un,re}do last action, redraw window */
117 static const char *undo(Vis
*, const char *keys
, const Arg
*arg
);
118 static const char *redo(Vis
*, const char *keys
, const Arg
*arg
);
119 /* earlier, later action chronologically, redraw window */
120 static const char *earlier(Vis
*, const char *keys
, const Arg
*arg
);
121 static const char *later(Vis
*, const char *keys
, const Arg
*arg
);
122 /* delete from the current cursor position to the end of
123 * movement as indicated by arg->i */
124 static const char *delete(Vis
*, const char *keys
, const Arg
*arg
);
125 /* insert register content indicated by keys at current cursor position */
126 static const char *insert_register(Vis
*, const char *keys
, const Arg
*arg
);
127 /* show a user prompt to get input with title arg->s */
128 static const char *prompt_show(Vis
*, const char *keys
, const Arg
*arg
);
129 /* blocks to read 3 consecutive digits and inserts the corresponding byte value */
130 static const char *insert_verbatim(Vis
*, const char *keys
, const Arg
*arg
);
131 /* scroll window content according to arg->i which can be either PAGE, PAGE_HALF,
132 * or an arbitrary number of lines. a multiplier overrides what is given in arg->i.
133 * negative values scroll back, positive forward. */
134 static const char *wscroll(Vis
*, const char *keys
, const Arg
*arg
);
135 /* similar to scroll, but do only move window content not cursor position */
136 static const char *wslide(Vis
*, const char *keys
, const Arg
*arg
);
137 /* call editor function as indicated by arg->f */
138 static const char *call(Vis
*, const char *keys
, const Arg
*arg
);
139 /* call window function as indicated by arg->w */
140 static const char *window(Vis
*, const char *keys
, const Arg
*arg
);
141 /* show info about Unicode character at cursor position */
142 static const char *unicode_info(Vis
*, const char *keys
, const Arg
*arg
);
143 /* either go to count % of file or to matching item */
144 static const char *percent(Vis
*, const char *keys
, const Arg
*arg
);
145 /* navigate jumplist next (arg->i > 0), prev (arg->i < 0), save (arg->i = 0) */
146 static const char *jumplist(Vis
*, const char *keys
, const Arg
*arg
);
149 VIS_ACTION_EDITOR_SUSPEND
,
150 VIS_ACTION_CURSOR_CHAR_PREV
,
151 VIS_ACTION_CURSOR_CHAR_NEXT
,
152 VIS_ACTION_CURSOR_LINE_CHAR_PREV
,
153 VIS_ACTION_CURSOR_LINE_CHAR_NEXT
,
154 VIS_ACTION_CURSOR_CODEPOINT_PREV
,
155 VIS_ACTION_CURSOR_CODEPOINT_NEXT
,
156 VIS_ACTION_CURSOR_WORD_START_PREV
,
157 VIS_ACTION_CURSOR_WORD_START_NEXT
,
158 VIS_ACTION_CURSOR_WORD_END_PREV
,
159 VIS_ACTION_CURSOR_WORD_END_NEXT
,
160 VIS_ACTION_CURSOR_LONGWORD_START_PREV
,
161 VIS_ACTION_CURSOR_LONGWORD_START_NEXT
,
162 VIS_ACTION_CURSOR_LONGWORD_END_PREV
,
163 VIS_ACTION_CURSOR_LONGWORD_END_NEXT
,
164 VIS_ACTION_CURSOR_LINE_UP
,
165 VIS_ACTION_CURSOR_LINE_DOWN
,
166 VIS_ACTION_CURSOR_LINE_START
,
167 VIS_ACTION_CURSOR_LINE_FINISH
,
168 VIS_ACTION_CURSOR_LINE_BEGIN
,
169 VIS_ACTION_CURSOR_LINE_END
,
170 VIS_ACTION_CURSOR_SCREEN_LINE_UP
,
171 VIS_ACTION_CURSOR_SCREEN_LINE_DOWN
,
172 VIS_ACTION_CURSOR_SCREEN_LINE_BEGIN
,
173 VIS_ACTION_CURSOR_SCREEN_LINE_MIDDLE
,
174 VIS_ACTION_CURSOR_SCREEN_LINE_END
,
175 VIS_ACTION_CURSOR_PERCENT
,
176 VIS_ACTION_CURSOR_BYTE
,
177 VIS_ACTION_CURSOR_BYTE_LEFT
,
178 VIS_ACTION_CURSOR_BYTE_RIGHT
,
179 VIS_ACTION_CURSOR_PARAGRAPH_PREV
,
180 VIS_ACTION_CURSOR_PARAGRAPH_NEXT
,
181 VIS_ACTION_CURSOR_SENTENCE_PREV
,
182 VIS_ACTION_CURSOR_SENTENCE_NEXT
,
183 VIS_ACTION_CURSOR_BLOCK_START
,
184 VIS_ACTION_CURSOR_BLOCK_END
,
185 VIS_ACTION_CURSOR_PARENTHESIS_START
,
186 VIS_ACTION_CURSOR_PARENTHESIS_END
,
187 VIS_ACTION_CURSOR_COLUMN
,
188 VIS_ACTION_CURSOR_LINE_FIRST
,
189 VIS_ACTION_CURSOR_LINE_LAST
,
190 VIS_ACTION_CURSOR_WINDOW_LINE_TOP
,
191 VIS_ACTION_CURSOR_WINDOW_LINE_MIDDLE
,
192 VIS_ACTION_CURSOR_WINDOW_LINE_BOTTOM
,
193 VIS_ACTION_CURSOR_SEARCH_REPEAT_FORWARD
,
194 VIS_ACTION_CURSOR_SEARCH_REPEAT_BACKWARD
,
195 VIS_ACTION_CURSOR_SEARCH_REPEAT
,
196 VIS_ACTION_CURSOR_SEARCH_REPEAT_REVERSE
,
197 VIS_ACTION_CURSOR_SEARCH_WORD_FORWARD
,
198 VIS_ACTION_CURSOR_SEARCH_WORD_BACKWARD
,
199 VIS_ACTION_WINDOW_PAGE_UP
,
200 VIS_ACTION_WINDOW_PAGE_DOWN
,
201 VIS_ACTION_WINDOW_HALFPAGE_UP
,
202 VIS_ACTION_WINDOW_HALFPAGE_DOWN
,
203 VIS_ACTION_MODE_NORMAL
,
204 VIS_ACTION_MODE_NORMAL_ESCAPE
,
205 VIS_ACTION_MODE_VISUAL
,
206 VIS_ACTION_MODE_VISUAL_ESCAPE
,
207 VIS_ACTION_MODE_VISUAL_LINE
,
208 VIS_ACTION_MODE_INSERT
,
209 VIS_ACTION_MODE_REPLACE
,
210 VIS_ACTION_DELETE_CHAR_PREV
,
211 VIS_ACTION_DELETE_CHAR_NEXT
,
212 VIS_ACTION_DELETE_LINE_BEGIN
,
213 VIS_ACTION_DELETE_WORD_PREV
,
214 VIS_ACTION_JUMPLIST_PREV
,
215 VIS_ACTION_JUMPLIST_NEXT
,
216 VIS_ACTION_JUMPLIST_SAVE
,
221 VIS_ACTION_MACRO_RECORD
,
222 VIS_ACTION_MACRO_REPLAY
,
225 VIS_ACTION_REPLACE_CHAR
,
226 VIS_ACTION_TOTILL_REPEAT
,
227 VIS_ACTION_TOTILL_REVERSE
,
228 VIS_ACTION_PROMPT_SEARCH_FORWARD
,
229 VIS_ACTION_PROMPT_SEARCH_BACKWARD
,
230 VIS_ACTION_TILL_LEFT
,
231 VIS_ACTION_TILL_RIGHT
,
235 VIS_ACTION_OPERATOR_CHANGE
,
236 VIS_ACTION_OPERATOR_DELETE
,
237 VIS_ACTION_OPERATOR_YANK
,
238 VIS_ACTION_OPERATOR_SHIFT_LEFT
,
239 VIS_ACTION_OPERATOR_SHIFT_RIGHT
,
241 VIS_ACTION_INSERT_NEWLINE
,
242 VIS_ACTION_INSERT_TAB
,
243 VIS_ACTION_INSERT_VERBATIM
,
244 VIS_ACTION_INSERT_REGISTER
,
245 VIS_ACTION_WINDOW_NEXT
,
246 VIS_ACTION_WINDOW_PREV
,
247 VIS_ACTION_APPEND_CHAR_NEXT
,
248 VIS_ACTION_APPEND_LINE_END
,
249 VIS_ACTION_INSERT_LINE_START
,
250 VIS_ACTION_OPEN_LINE_ABOVE
,
251 VIS_ACTION_OPEN_LINE_BELOW
,
252 VIS_ACTION_JOIN_LINES
,
253 VIS_ACTION_JOIN_LINES_TRIM
,
254 VIS_ACTION_PROMPT_SHOW
,
256 VIS_ACTION_SELECTION_FLIP
,
257 VIS_ACTION_WINDOW_REDRAW_TOP
,
258 VIS_ACTION_WINDOW_REDRAW_CENTER
,
259 VIS_ACTION_WINDOW_REDRAW_BOTTOM
,
260 VIS_ACTION_WINDOW_SLIDE_UP
,
261 VIS_ACTION_WINDOW_SLIDE_DOWN
,
262 VIS_ACTION_PUT_AFTER
,
263 VIS_ACTION_PUT_BEFORE
,
264 VIS_ACTION_SELECTIONS_MATCH_WORD
,
265 VIS_ACTION_SELECTIONS_NEW_LINE_ABOVE
,
266 VIS_ACTION_SELECTIONS_NEW_LINE_ABOVE_FIRST
,
267 VIS_ACTION_SELECTIONS_NEW_LINE_BELOW
,
268 VIS_ACTION_SELECTIONS_NEW_LINE_BELOW_LAST
,
269 VIS_ACTION_SELECTIONS_NEW_LINES_BEGIN
,
270 VIS_ACTION_SELECTIONS_NEW_LINES_END
,
271 VIS_ACTION_SELECTIONS_NEW_MATCH_NEXT
,
272 VIS_ACTION_SELECTIONS_NEW_MATCH_SKIP
,
273 VIS_ACTION_SELECTIONS_ALIGN
,
274 VIS_ACTION_SELECTIONS_ALIGN_INDENT_LEFT
,
275 VIS_ACTION_SELECTIONS_ALIGN_INDENT_RIGHT
,
276 VIS_ACTION_SELECTIONS_REMOVE_ALL
,
277 VIS_ACTION_SELECTIONS_REMOVE_LAST
,
278 VIS_ACTION_SELECTIONS_REMOVE_COLUMN
,
279 VIS_ACTION_SELECTIONS_REMOVE_COLUMN_EXCEPT
,
280 VIS_ACTION_SELECTIONS_PREV
,
281 VIS_ACTION_SELECTIONS_NEXT
,
282 VIS_ACTION_SELECTIONS_ROTATE_LEFT
,
283 VIS_ACTION_SELECTIONS_ROTATE_RIGHT
,
284 VIS_ACTION_SELECTIONS_TRIM
,
285 VIS_ACTION_SELECTIONS_SAVE
,
286 VIS_ACTION_SELECTIONS_RESTORE
,
287 VIS_ACTION_SELECTIONS_UNION
,
288 VIS_ACTION_SELECTIONS_INTERSECT
,
289 VIS_ACTION_SELECTIONS_COMPLEMENT
,
290 VIS_ACTION_SELECTIONS_MINUS
,
291 VIS_ACTION_SELECTIONS_COMBINE_SHORTER
,
292 VIS_ACTION_SELECTIONS_COMBINE_LEFTMOST
,
293 VIS_ACTION_SELECTIONS_COMBINE_RIGHTMOST
,
294 VIS_ACTION_TEXT_OBJECT_WORD_OUTER
,
295 VIS_ACTION_TEXT_OBJECT_WORD_INNER
,
296 VIS_ACTION_TEXT_OBJECT_LONGWORD_OUTER
,
297 VIS_ACTION_TEXT_OBJECT_LONGWORD_INNER
,
298 VIS_ACTION_TEXT_OBJECT_SENTENCE
,
299 VIS_ACTION_TEXT_OBJECT_PARAGRAPH
,
300 VIS_ACTION_TEXT_OBJECT_PARAGRAPH_OUTER
,
301 VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_OUTER
,
302 VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_INNER
,
303 VIS_ACTION_TEXT_OBJECT_PARENTHESIS_OUTER
,
304 VIS_ACTION_TEXT_OBJECT_PARENTHESIS_INNER
,
305 VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_OUTER
,
306 VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_INNER
,
307 VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_OUTER
,
308 VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_INNER
,
309 VIS_ACTION_TEXT_OBJECT_QUOTE_OUTER
,
310 VIS_ACTION_TEXT_OBJECT_QUOTE_INNER
,
311 VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_OUTER
,
312 VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_INNER
,
313 VIS_ACTION_TEXT_OBJECT_BACKTICK_OUTER
,
314 VIS_ACTION_TEXT_OBJECT_BACKTICK_INNER
,
315 VIS_ACTION_TEXT_OBJECT_ENTIRE_OUTER
,
316 VIS_ACTION_TEXT_OBJECT_ENTIRE_INNER
,
317 VIS_ACTION_TEXT_OBJECT_LINE_OUTER
,
318 VIS_ACTION_TEXT_OBJECT_LINE_INNER
,
319 VIS_ACTION_TEXT_OBJECT_INDENTATION
,
320 VIS_ACTION_TEXT_OBJECT_SEARCH_FORWARD
,
321 VIS_ACTION_TEXT_OBJECT_SEARCH_BACKWARD
,
322 VIS_ACTION_UNICODE_INFO
,
323 VIS_ACTION_UTF8_INFO
,
327 static const KeyAction vis_action
[] = {
328 [VIS_ACTION_EDITOR_SUSPEND
] = {
330 VIS_HELP("Suspend the editor")
333 [VIS_ACTION_CURSOR_CHAR_PREV
] = {
334 "vis-motion-char-prev",
335 VIS_HELP("Move cursor left, to the previous character")
336 movement
, { .i
= VIS_MOVE_CHAR_PREV
}
338 [VIS_ACTION_CURSOR_CHAR_NEXT
] = {
339 "vis-motion-char-next",
340 VIS_HELP("Move cursor right, to the next character")
341 movement
, { .i
= VIS_MOVE_CHAR_NEXT
}
343 [VIS_ACTION_CURSOR_LINE_CHAR_PREV
] = {
344 "vis-motion-line-char-prev",
345 VIS_HELP("Move cursor left, to the previous character on the same line")
346 movement
, { .i
= VIS_MOVE_LINE_CHAR_PREV
}
348 [VIS_ACTION_CURSOR_LINE_CHAR_NEXT
] = {
349 "vis-motion-line-char-next",
350 VIS_HELP("Move cursor right, to the next character on the same line")
351 movement
, { .i
= VIS_MOVE_LINE_CHAR_NEXT
}
353 [VIS_ACTION_CURSOR_CODEPOINT_PREV
] = {
354 "vis-motion-codepoint-prev",
355 VIS_HELP("Move to the previous Unicode codepoint")
356 movement
, { .i
= VIS_MOVE_CODEPOINT_PREV
}
358 [VIS_ACTION_CURSOR_CODEPOINT_NEXT
] = {
359 "vis-motion-codepoint-next",
360 VIS_HELP("Move to the next Unicode codepoint")
361 movement
, { .i
= VIS_MOVE_CODEPOINT_NEXT
}
363 [VIS_ACTION_CURSOR_WORD_START_PREV
] = {
364 "vis-motion-word-start-prev",
365 VIS_HELP("Move cursor words backwards")
366 movement
, { .i
= VIS_MOVE_WORD_START_PREV
}
368 [VIS_ACTION_CURSOR_WORD_START_NEXT
] = {
369 "vis-motion-word-start-next",
370 VIS_HELP("Move cursor words forwards")
371 movement
, { .i
= VIS_MOVE_WORD_START_NEXT
}
373 [VIS_ACTION_CURSOR_WORD_END_PREV
] = {
374 "vis-motion-word-end-prev",
375 VIS_HELP("Move cursor backwards to the end of word")
376 movement
, { .i
= VIS_MOVE_WORD_END_PREV
}
378 [VIS_ACTION_CURSOR_WORD_END_NEXT
] = {
379 "vis-motion-word-end-next",
380 VIS_HELP("Move cursor forward to the end of word")
381 movement
, { .i
= VIS_MOVE_WORD_END_NEXT
}
383 [VIS_ACTION_CURSOR_LONGWORD_START_PREV
] = {
384 "vis-motion-bigword-start-prev",
385 VIS_HELP("Move cursor WORDS backwards")
386 movement
, { .i
= VIS_MOVE_LONGWORD_START_PREV
}
388 [VIS_ACTION_CURSOR_LONGWORD_START_NEXT
] = {
389 "vis-motion-bigword-start-next",
390 VIS_HELP("Move cursor WORDS forwards")
391 movement
, { .i
= VIS_MOVE_LONGWORD_START_NEXT
}
393 [VIS_ACTION_CURSOR_LONGWORD_END_PREV
] = {
394 "vis-motion-bigword-end-prev",
395 VIS_HELP("Move cursor backwards to the end of WORD")
396 movement
, { .i
= VIS_MOVE_LONGWORD_END_PREV
}
398 [VIS_ACTION_CURSOR_LONGWORD_END_NEXT
] = {
399 "vis-motion-bigword-end-next",
400 VIS_HELP("Move cursor forward to the end of WORD")
401 movement
, { .i
= VIS_MOVE_LONGWORD_END_NEXT
}
403 [VIS_ACTION_CURSOR_LINE_UP
] = {
404 "vis-motion-line-up",
405 VIS_HELP("Move cursor line upwards")
406 movement
, { .i
= VIS_MOVE_LINE_UP
}
408 [VIS_ACTION_CURSOR_LINE_DOWN
] = {
409 "vis-motion-line-down",
410 VIS_HELP("Move cursor line downwards")
411 movement
, { .i
= VIS_MOVE_LINE_DOWN
}
413 [VIS_ACTION_CURSOR_LINE_START
] = {
414 "vis-motion-line-start",
415 VIS_HELP("Move cursor to first non-blank character of the line")
416 movement
, { .i
= VIS_MOVE_LINE_START
}
418 [VIS_ACTION_CURSOR_LINE_FINISH
] = {
419 "vis-motion-line-finish",
420 VIS_HELP("Move cursor to last non-blank character of the line")
421 movement
, { .i
= VIS_MOVE_LINE_FINISH
}
423 [VIS_ACTION_CURSOR_LINE_BEGIN
] = {
424 "vis-motion-line-begin",
425 VIS_HELP("Move cursor to first character of the line")
426 movement
, { .i
= VIS_MOVE_LINE_BEGIN
}
428 [VIS_ACTION_CURSOR_LINE_END
] = {
429 "vis-motion-line-end",
430 VIS_HELP("Move cursor to end of the line")
431 movement
, { .i
= VIS_MOVE_LINE_END
}
433 [VIS_ACTION_CURSOR_SCREEN_LINE_UP
] = {
434 "vis-motion-screenline-up",
435 VIS_HELP("Move cursor screen/display line upwards")
436 movement
, { .i
= VIS_MOVE_SCREEN_LINE_UP
}
438 [VIS_ACTION_CURSOR_SCREEN_LINE_DOWN
] = {
439 "vis-motion-screenline-down",
440 VIS_HELP("Move cursor screen/display line downwards")
441 movement
, { .i
= VIS_MOVE_SCREEN_LINE_DOWN
}
443 [VIS_ACTION_CURSOR_SCREEN_LINE_BEGIN
] = {
444 "vis-motion-screenline-begin",
445 VIS_HELP("Move cursor to beginning of screen/display line")
446 movement
, { .i
= VIS_MOVE_SCREEN_LINE_BEGIN
}
448 [VIS_ACTION_CURSOR_SCREEN_LINE_MIDDLE
] = {
449 "vis-motion-screenline-middle",
450 VIS_HELP("Move cursor to middle of screen/display line")
451 movement
, { .i
= VIS_MOVE_SCREEN_LINE_MIDDLE
}
453 [VIS_ACTION_CURSOR_SCREEN_LINE_END
] = {
454 "vis-motion-screenline-end",
455 VIS_HELP("Move cursor to end of screen/display line")
456 movement
, { .i
= VIS_MOVE_SCREEN_LINE_END
}
458 [VIS_ACTION_CURSOR_PERCENT
] = {
459 "vis-motion-percent",
460 VIS_HELP("Move to count % of file or matching item")
463 [VIS_ACTION_CURSOR_BYTE
] = {
465 VIS_HELP("Move to absolute byte position")
466 movement
, { .i
= VIS_MOVE_BYTE
}
468 [VIS_ACTION_CURSOR_BYTE_LEFT
] = {
469 "vis-motion-byte-left",
470 VIS_HELP("Move count bytes to the left")
471 movement
, { .i
= VIS_MOVE_BYTE_LEFT
}
473 [VIS_ACTION_CURSOR_BYTE_RIGHT
] = {
474 "vis-motion-byte-right",
475 VIS_HELP("Move count bytes to the right")
476 movement
, { .i
= VIS_MOVE_BYTE_RIGHT
}
478 [VIS_ACTION_CURSOR_PARAGRAPH_PREV
] = {
479 "vis-motion-paragraph-prev",
480 VIS_HELP("Move cursor paragraph backward")
481 movement
, { .i
= VIS_MOVE_PARAGRAPH_PREV
}
483 [VIS_ACTION_CURSOR_PARAGRAPH_NEXT
] = {
484 "vis-motion-paragraph-next",
485 VIS_HELP("Move cursor paragraph forward")
486 movement
, { .i
= VIS_MOVE_PARAGRAPH_NEXT
}
488 [VIS_ACTION_CURSOR_SENTENCE_PREV
] = {
489 "vis-motion-sentence-prev",
490 VIS_HELP("Move cursor sentence backward")
491 movement
, { .i
= VIS_MOVE_SENTENCE_PREV
}
493 [VIS_ACTION_CURSOR_SENTENCE_NEXT
] = {
494 "vis-motion-sentence-next",
495 VIS_HELP("Move cursor sentence forward")
496 movement
, { .i
= VIS_MOVE_SENTENCE_NEXT
}
498 [VIS_ACTION_CURSOR_BLOCK_START
] = {
499 "vis-motion-block-start",
500 VIS_HELP("Move cursor to the opening curly brace in a block")
501 movement
, { .i
= VIS_MOVE_BLOCK_START
}
503 [VIS_ACTION_CURSOR_BLOCK_END
] = {
504 "vis-motion-block-end",
505 VIS_HELP("Move cursor to the closing curly brace in a block")
506 movement
, { .i
= VIS_MOVE_BLOCK_END
}
508 [VIS_ACTION_CURSOR_PARENTHESIS_START
] = {
509 "vis-motion-parenthesis-start",
510 VIS_HELP("Move cursor to the opening parenthesis inside a pair of parentheses")
511 movement
, { .i
= VIS_MOVE_PARENTHESIS_START
}
513 [VIS_ACTION_CURSOR_PARENTHESIS_END
] = {
514 "vis-motion-parenthesis-end",
515 VIS_HELP("Move cursor to the closing parenthesis inside a pair of parentheses")
516 movement
, { .i
= VIS_MOVE_PARENTHESIS_END
}
518 [VIS_ACTION_CURSOR_COLUMN
] = {
520 VIS_HELP("Move cursor to given column of current line")
521 movement
, { .i
= VIS_MOVE_COLUMN
}
523 [VIS_ACTION_CURSOR_LINE_FIRST
] = {
524 "vis-motion-line-first",
525 VIS_HELP("Move cursor to given line (defaults to first)")
526 gotoline
, { .i
= -1 }
528 [VIS_ACTION_CURSOR_LINE_LAST
] = {
529 "vis-motion-line-last",
530 VIS_HELP("Move cursor to given line (defaults to last)")
531 gotoline
, { .i
= +1 }
533 [VIS_ACTION_CURSOR_WINDOW_LINE_TOP
] = {
534 "vis-motion-window-line-top",
535 VIS_HELP("Move cursor to top line of the window")
536 movement
, { .i
= VIS_MOVE_WINDOW_LINE_TOP
}
538 [VIS_ACTION_CURSOR_WINDOW_LINE_MIDDLE
] = {
539 "vis-motion-window-line-middle",
540 VIS_HELP("Move cursor to middle line of the window")
541 movement
, { .i
= VIS_MOVE_WINDOW_LINE_MIDDLE
}
543 [VIS_ACTION_CURSOR_WINDOW_LINE_BOTTOM
] = {
544 "vis-motion-window-line-bottom",
545 VIS_HELP("Move cursor to bottom line of the window")
546 movement
, { .i
= VIS_MOVE_WINDOW_LINE_BOTTOM
}
548 [VIS_ACTION_CURSOR_SEARCH_REPEAT_FORWARD
] = {
549 "vis-motion-search-repeat-forward",
550 VIS_HELP("Move cursor to next match in forward direction")
551 movement
, { .i
= VIS_MOVE_SEARCH_REPEAT_FORWARD
}
553 [VIS_ACTION_CURSOR_SEARCH_REPEAT_BACKWARD
] = {
554 "vis-motion-search-repeat-backward",
555 VIS_HELP("Move cursor to previous match in backward direction")
556 movement
, { .i
= VIS_MOVE_SEARCH_REPEAT_BACKWARD
}
558 [VIS_ACTION_CURSOR_SEARCH_REPEAT
] = {
559 "vis-motion-search-repeat",
560 VIS_HELP("Move cursor to next match")
561 movement
, { .i
= VIS_MOVE_SEARCH_REPEAT
}
563 [VIS_ACTION_CURSOR_SEARCH_REPEAT_REVERSE
] = {
564 "vis-motion-search-repeat-reverse",
565 VIS_HELP("Move cursor to next match in opposite direction")
566 movement
, { .i
= VIS_MOVE_SEARCH_REPEAT_REVERSE
}
568 [VIS_ACTION_CURSOR_SEARCH_WORD_FORWARD
] = {
569 "vis-motion-search-word-forward",
570 VIS_HELP("Move cursor to next occurrence of the word under cursor")
571 movement
, { .i
= VIS_MOVE_SEARCH_WORD_FORWARD
}
573 [VIS_ACTION_CURSOR_SEARCH_WORD_BACKWARD
] = {
574 "vis-motion-search-word-backward",
575 VIS_HELP("Move cursor to previous occurrence of the word under cursor")
576 movement
, { .i
= VIS_MOVE_SEARCH_WORD_BACKWARD
}
578 [VIS_ACTION_WINDOW_PAGE_UP
] = {
579 "vis-window-page-up",
580 VIS_HELP("Scroll window pages backwards (upwards)")
581 wscroll
, { .i
= -PAGE
}
583 [VIS_ACTION_WINDOW_HALFPAGE_UP
] = {
584 "vis-window-halfpage-up",
585 VIS_HELP("Scroll window half pages backwards (upwards)")
586 wscroll
, { .i
= -PAGE_HALF
}
588 [VIS_ACTION_WINDOW_PAGE_DOWN
] = {
589 "vis-window-page-down",
590 VIS_HELP("Scroll window pages forwards (downwards)")
591 wscroll
, { .i
= +PAGE
}
593 [VIS_ACTION_WINDOW_HALFPAGE_DOWN
] = {
594 "vis-window-halfpage-down",
595 VIS_HELP("Scroll window half pages forwards (downwards)")
596 wscroll
, { .i
= +PAGE_HALF
}
598 [VIS_ACTION_MODE_NORMAL
] = {
600 VIS_HELP("Enter normal mode")
601 switchmode
, { .i
= VIS_MODE_NORMAL
}
603 [VIS_ACTION_MODE_NORMAL_ESCAPE
] = {
604 "vis-mode-normal-escape",
605 VIS_HELP("Reset count or remove all non-primary selections")
608 [VIS_ACTION_MODE_VISUAL
] = {
609 "vis-mode-visual-charwise",
610 VIS_HELP("Enter characterwise visual mode")
611 switchmode
, { .i
= VIS_MODE_VISUAL
}
613 [VIS_ACTION_MODE_VISUAL_ESCAPE
] = {
614 "vis-mode-visual-escape",
615 VIS_HELP("Reset count or switch to normal mode")
618 [VIS_ACTION_MODE_VISUAL_LINE
] = {
619 "vis-mode-visual-linewise",
620 VIS_HELP("Enter linewise visual mode")
621 switchmode
, { .i
= VIS_MODE_VISUAL_LINE
}
623 [VIS_ACTION_MODE_INSERT
] = {
625 VIS_HELP("Enter insert mode")
626 insertmode
, { .i
= VIS_MOVE_NOP
}
628 [VIS_ACTION_MODE_REPLACE
] = {
630 VIS_HELP("Enter replace mode")
631 replacemode
, { .i
= VIS_MOVE_NOP
}
633 [VIS_ACTION_DELETE_CHAR_PREV
] = {
634 "vis-delete-char-prev",
635 VIS_HELP("Delete the previous character")
636 delete, { .i
= VIS_MOVE_CHAR_PREV
}
638 [VIS_ACTION_DELETE_CHAR_NEXT
] = {
639 "vis-delete-char-next",
640 VIS_HELP("Delete the next character")
641 delete, { .i
= VIS_MOVE_CHAR_NEXT
}
643 [VIS_ACTION_DELETE_LINE_BEGIN
] = {
644 "vis-delete-line-begin",
645 VIS_HELP("Delete until the start of the current line")
646 delete, { .i
= VIS_MOVE_LINE_BEGIN
}
648 [VIS_ACTION_DELETE_WORD_PREV
] = {
649 "vis-delete-word-prev",
650 VIS_HELP("Delete the previous WORD")
651 delete, { .i
= VIS_MOVE_WORD_START_PREV
}
653 [VIS_ACTION_JUMPLIST_PREV
] = {
655 VIS_HELP("Go to older cursor position in jump list")
656 jumplist
, { .i
= -1 }
658 [VIS_ACTION_JUMPLIST_NEXT
] = {
660 VIS_HELP("Go to newer cursor position in jump list")
661 jumplist
, { .i
= +1 }
663 [VIS_ACTION_JUMPLIST_SAVE
] = {
665 VIS_HELP("Save current selections in jump list")
668 [VIS_ACTION_UNDO
] = {
670 VIS_HELP("Undo last change")
673 [VIS_ACTION_REDO
] = {
675 VIS_HELP("Redo last change")
678 [VIS_ACTION_EARLIER
] = {
680 VIS_HELP("Goto older text state")
683 [VIS_ACTION_LATER
] = {
685 VIS_HELP("Goto newer text state")
688 [VIS_ACTION_MACRO_RECORD
] = {
690 VIS_HELP("Record macro into given register")
693 [VIS_ACTION_MACRO_REPLAY
] = {
695 VIS_HELP("Replay macro, execute the content of the given register")
698 [VIS_ACTION_MARK
] = {
700 VIS_HELP("Use given mark for next action")
703 [VIS_ACTION_REDRAW
] = {
705 VIS_HELP("Redraw current editor content")
706 call
, { .f
= vis_redraw
}
708 [VIS_ACTION_REPLACE_CHAR
] = {
710 VIS_HELP("Replace the character under the cursor")
713 [VIS_ACTION_TOTILL_REPEAT
] = {
714 "vis-motion-totill-repeat",
715 VIS_HELP("Repeat latest to/till motion")
716 movement
, { .i
= VIS_MOVE_TOTILL_REPEAT
}
718 [VIS_ACTION_TOTILL_REVERSE
] = {
719 "vis-motion-totill-reverse",
720 VIS_HELP("Repeat latest to/till motion but in opposite direction")
721 movement
, { .i
= VIS_MOVE_TOTILL_REVERSE
}
723 [VIS_ACTION_PROMPT_SEARCH_FORWARD
] = {
724 "vis-search-forward",
725 VIS_HELP("Search forward")
726 prompt_show
, { .s
= "/" }
728 [VIS_ACTION_PROMPT_SEARCH_BACKWARD
] = {
729 "vis-search-backward",
730 VIS_HELP("Search backward")
731 prompt_show
, { .s
= "?" }
733 [VIS_ACTION_TILL_LEFT
] = {
734 "vis-motion-till-left",
735 VIS_HELP("Till after the occurrence of character to the left")
736 movement_key
, { .i
= VIS_MOVE_LEFT_TILL
}
738 [VIS_ACTION_TILL_RIGHT
] = {
739 "vis-motion-till-right",
740 VIS_HELP("Till before the occurrence of character to the right")
741 movement_key
, { .i
= VIS_MOVE_RIGHT_TILL
}
743 [VIS_ACTION_TO_LEFT
] = {
744 "vis-motion-to-left",
745 VIS_HELP("To the first occurrence of character to the left")
746 movement_key
, { .i
= VIS_MOVE_LEFT_TO
}
748 [VIS_ACTION_TO_RIGHT
] = {
749 "vis-motion-to-right",
750 VIS_HELP("To the first occurrence of character to the right")
751 movement_key
, { .i
= VIS_MOVE_RIGHT_TO
}
753 [VIS_ACTION_REGISTER
] = {
755 VIS_HELP("Use given register for next operator")
758 [VIS_ACTION_OPERATOR_CHANGE
] = {
759 "vis-operator-change",
760 VIS_HELP("Change operator")
761 operator, { .i
= VIS_OP_CHANGE
}
763 [VIS_ACTION_OPERATOR_DELETE
] = {
764 "vis-operator-delete",
765 VIS_HELP("Delete operator")
766 operator, { .i
= VIS_OP_DELETE
}
768 [VIS_ACTION_OPERATOR_YANK
] = {
770 VIS_HELP("Yank operator")
771 operator, { .i
= VIS_OP_YANK
}
773 [VIS_ACTION_OPERATOR_SHIFT_LEFT
] = {
774 "vis-operator-shift-left",
775 VIS_HELP("Shift left operator")
776 operator, { .i
= VIS_OP_SHIFT_LEFT
}
778 [VIS_ACTION_OPERATOR_SHIFT_RIGHT
] = {
779 "vis-operator-shift-right",
780 VIS_HELP("Shift right operator")
781 operator, { .i
= VIS_OP_SHIFT_RIGHT
}
783 [VIS_ACTION_COUNT
] = {
785 VIS_HELP("Count specifier")
788 [VIS_ACTION_INSERT_NEWLINE
] = {
789 "vis-insert-newline",
790 VIS_HELP("Insert a line break (depending on file type)")
791 call
, { .f
= vis_insert_nl
}
793 [VIS_ACTION_INSERT_TAB
] = {
795 VIS_HELP("Insert a tab (might be converted to spaces)")
796 call
, { .f
= vis_insert_tab
}
798 [VIS_ACTION_INSERT_VERBATIM
] = {
799 "vis-insert-verbatim",
800 VIS_HELP("Insert Unicode character based on code point")
803 [VIS_ACTION_INSERT_REGISTER
] = {
804 "vis-insert-register",
805 VIS_HELP("Insert specified register content")
808 [VIS_ACTION_WINDOW_NEXT
] = {
810 VIS_HELP("Focus next window")
811 call
, { .f
= vis_window_next
}
813 [VIS_ACTION_WINDOW_PREV
] = {
815 VIS_HELP("Focus previous window")
816 call
, { .f
= vis_window_prev
}
818 [VIS_ACTION_APPEND_CHAR_NEXT
] = {
819 "vis-append-char-next",
820 VIS_HELP("Append text after the cursor")
821 insertmode
, { .i
= VIS_MOVE_LINE_CHAR_NEXT
}
823 [VIS_ACTION_APPEND_LINE_END
] = {
824 "vis-append-line-end",
825 VIS_HELP("Append text after the end of the line")
826 insertmode
, { .i
= VIS_MOVE_LINE_END
},
828 [VIS_ACTION_INSERT_LINE_START
] = {
829 "vis-insert-line-start",
830 VIS_HELP("Insert text before the first non-blank in the line")
831 insertmode
, { .i
= VIS_MOVE_LINE_START
},
833 [VIS_ACTION_OPEN_LINE_ABOVE
] = {
834 "vis-open-line-above",
835 VIS_HELP("Begin a new line above the cursor")
836 openline
, { .i
= -1 }
838 [VIS_ACTION_OPEN_LINE_BELOW
] = {
839 "vis-open-line-below",
840 VIS_HELP("Begin a new line below the cursor")
841 openline
, { .i
= +1 }
843 [VIS_ACTION_JOIN_LINES
] = {
845 VIS_HELP("Join selected lines")
848 [VIS_ACTION_JOIN_LINES_TRIM
] = {
849 "vis-join-lines-trim",
850 VIS_HELP("Join selected lines, remove white space")
853 [VIS_ACTION_PROMPT_SHOW
] = {
855 VIS_HELP("Show editor command line prompt")
856 prompt_show
, { .s
= ":" }
858 [VIS_ACTION_REPEAT
] = {
860 VIS_HELP("Repeat latest editor command")
863 [VIS_ACTION_SELECTION_FLIP
] = {
864 "vis-selection-flip",
865 VIS_HELP("Flip selection, move cursor to other end")
868 [VIS_ACTION_WINDOW_REDRAW_TOP
] = {
869 "vis-window-redraw-top",
870 VIS_HELP("Redraw cursor line at the top of the window")
871 window
, { .w
= view_redraw_top
}
873 [VIS_ACTION_WINDOW_REDRAW_CENTER
] = {
874 "vis-window-redraw-center",
875 VIS_HELP("Redraw cursor line at the center of the window")
876 window
, { .w
= view_redraw_center
}
878 [VIS_ACTION_WINDOW_REDRAW_BOTTOM
] = {
879 "vis-window-redraw-bottom",
880 VIS_HELP("Redraw cursor line at the bottom of the window")
881 window
, { .w
= view_redraw_bottom
}
883 [VIS_ACTION_WINDOW_SLIDE_UP
] = {
884 "vis-window-slide-up",
885 VIS_HELP("Slide window content upwards")
888 [VIS_ACTION_WINDOW_SLIDE_DOWN
] = {
889 "vis-window-slide-down",
890 VIS_HELP("Slide window content downwards")
893 [VIS_ACTION_PUT_AFTER
] = {
895 VIS_HELP("Put text after the cursor")
896 operator, { .i
= VIS_OP_PUT_AFTER
}
898 [VIS_ACTION_PUT_BEFORE
] = {
900 VIS_HELP("Put text before the cursor")
901 operator, { .i
= VIS_OP_PUT_BEFORE
}
903 [VIS_ACTION_SELECTIONS_MATCH_WORD
] = {
904 "vis-selections-select-word",
905 VIS_HELP("Select word under cursor")
906 selections_match_word
,
908 [VIS_ACTION_SELECTIONS_NEW_LINE_ABOVE
] = {
909 "vis-selection-new-lines-above",
910 VIS_HELP("Create a new selection on the line above")
911 selections_new
, { .i
= -1 }
913 [VIS_ACTION_SELECTIONS_NEW_LINE_ABOVE_FIRST
] = {
914 "vis-selection-new-lines-above-first",
915 VIS_HELP("Create a new selection on the line above the first selection")
916 selections_new
, { .i
= INT_MIN
}
918 [VIS_ACTION_SELECTIONS_NEW_LINE_BELOW
] = {
919 "vis-selection-new-lines-below",
920 VIS_HELP("Create a new selection on the line below")
921 selections_new
, { .i
= +1 }
923 [VIS_ACTION_SELECTIONS_NEW_LINE_BELOW_LAST
] = {
924 "vis-selection-new-lines-below-last",
925 VIS_HELP("Create a new selection on the line below the last selection")
926 selections_new
, { .i
= INT_MAX
}
928 [VIS_ACTION_SELECTIONS_NEW_LINES_BEGIN
] = {
929 "vis-selection-new-lines-begin",
930 VIS_HELP("Create a new selection at the start of every line covered by selection")
931 operator, { .i
= VIS_OP_CURSOR_SOL
}
933 [VIS_ACTION_SELECTIONS_NEW_LINES_END
] = {
934 "vis-selection-new-lines-end",
935 VIS_HELP("Create a new selection at the end of every line covered by selection")
936 operator, { .i
= VIS_OP_CURSOR_EOL
}
938 [VIS_ACTION_SELECTIONS_NEW_MATCH_NEXT
] = {
939 "vis-selection-new-match-next",
940 VIS_HELP("Select the next region matching the current selection")
941 selections_match_next
,
943 [VIS_ACTION_SELECTIONS_NEW_MATCH_SKIP
] = {
944 "vis-selection-new-match-skip",
945 VIS_HELP("Clear current selection, but select next match")
946 selections_match_skip
,
948 [VIS_ACTION_SELECTIONS_ALIGN
] = {
949 "vis-selections-align",
950 VIS_HELP("Try to align all selections on the same column")
953 [VIS_ACTION_SELECTIONS_ALIGN_INDENT_LEFT
] = {
954 "vis-selections-align-indent-left",
955 VIS_HELP("Left-align all selections by inserting spaces")
956 selections_align_indent
, { .i
= -1 }
958 [VIS_ACTION_SELECTIONS_ALIGN_INDENT_RIGHT
] = {
959 "vis-selections-align-indent-right",
960 VIS_HELP("Right-align all selections by inserting spaces")
961 selections_align_indent
, { .i
= +1 }
963 [VIS_ACTION_SELECTIONS_REMOVE_ALL
] = {
964 "vis-selections-remove-all",
965 VIS_HELP("Remove all but the primary selection")
968 [VIS_ACTION_SELECTIONS_REMOVE_LAST
] = {
969 "vis-selections-remove-last",
970 VIS_HELP("Remove primary selection")
973 [VIS_ACTION_SELECTIONS_REMOVE_COLUMN
] = {
974 "vis-selections-remove-column",
975 VIS_HELP("Remove count selection column")
976 selections_remove_column
, { .i
= 1 }
978 [VIS_ACTION_SELECTIONS_REMOVE_COLUMN_EXCEPT
] = {
979 "vis-selections-remove-column-except",
980 VIS_HELP("Remove all but the count selection column")
981 selections_remove_column_except
, { .i
= 1 }
983 [VIS_ACTION_SELECTIONS_PREV
] = {
984 "vis-selection-prev",
985 VIS_HELP("Move to the previous selection")
986 selections_navigate
, { .i
= -PAGE_HALF
}
988 [VIS_ACTION_SELECTIONS_NEXT
] = {
989 "vis-selection-next",
990 VIS_HELP("Move to the next selection")
991 selections_navigate
, { .i
= +PAGE_HALF
}
993 [VIS_ACTION_SELECTIONS_ROTATE_LEFT
] = {
994 "vis-selections-rotate-left",
995 VIS_HELP("Rotate selections left")
996 selections_rotate
, { .i
= -1 }
998 [VIS_ACTION_SELECTIONS_ROTATE_RIGHT
] = {
999 "vis-selections-rotate-right",
1000 VIS_HELP("Rotate selections right")
1001 selections_rotate
, { .i
= +1 }
1003 [VIS_ACTION_SELECTIONS_TRIM
] = {
1004 "vis-selections-trim",
1005 VIS_HELP("Remove leading and trailing white space from selections")
1008 [VIS_ACTION_SELECTIONS_SAVE
] = {
1009 "vis-selections-save",
1010 VIS_HELP("Save currently active selections to mark")
1013 [VIS_ACTION_SELECTIONS_RESTORE
] = {
1014 "vis-selections-restore",
1015 VIS_HELP("Restore selections from mark")
1018 [VIS_ACTION_SELECTIONS_UNION
] = {
1019 "vis-selections-union",
1020 VIS_HELP("Add selections from mark")
1023 [VIS_ACTION_SELECTIONS_INTERSECT
] = {
1024 "vis-selections-intersect",
1025 VIS_HELP("Intersect with selections from mark")
1026 selections_intersect
1028 [VIS_ACTION_SELECTIONS_COMPLEMENT
] = {
1029 "vis-selections-complement",
1030 VIS_HELP("Complement selections")
1031 selections_complement
1033 [VIS_ACTION_SELECTIONS_MINUS
] = {
1034 "vis-selections-minus",
1035 VIS_HELP("Subtract selections from mark")
1038 [VIS_ACTION_SELECTIONS_COMBINE_SHORTER
] = {
1039 "vis-selections-combine-shorter",
1040 VIS_HELP("Pairwise combine: take shorter")
1041 selections_combine
, { .combine
= combine_shorter
}
1043 [VIS_ACTION_SELECTIONS_COMBINE_LEFTMOST
] = {
1044 "vis-selections-combine-leftmost",
1045 VIS_HELP("Pairwise combine: leftmost")
1046 selections_combine
, { .combine
= combine_leftmost
}
1048 [VIS_ACTION_SELECTIONS_COMBINE_RIGHTMOST
] = {
1049 "vis-selections-combine-rightmost",
1050 VIS_HELP("Pairwise combine: rightmost")
1051 selections_combine
, { .combine
= combine_rightmost
}
1053 [VIS_ACTION_TEXT_OBJECT_WORD_OUTER
] = {
1054 "vis-textobject-word-outer",
1055 VIS_HELP("A word leading and trailing whitespace included")
1056 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_WORD
}
1058 [VIS_ACTION_TEXT_OBJECT_WORD_INNER
] = {
1059 "vis-textobject-word-inner",
1060 VIS_HELP("A word leading and trailing whitespace excluded")
1061 textobj
, { .i
= VIS_TEXTOBJECT_INNER_WORD
}
1063 [VIS_ACTION_TEXT_OBJECT_LONGWORD_OUTER
] = {
1064 "vis-textobject-bigword-outer",
1065 VIS_HELP("A WORD leading and trailing whitespace included")
1066 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_LONGWORD
}
1068 [VIS_ACTION_TEXT_OBJECT_LONGWORD_INNER
] = {
1069 "vis-textobject-bigword-inner",
1070 VIS_HELP("A WORD leading and trailing whitespace excluded")
1071 textobj
, { .i
= VIS_TEXTOBJECT_INNER_LONGWORD
}
1073 [VIS_ACTION_TEXT_OBJECT_SENTENCE
] = {
1074 "vis-textobject-sentence",
1075 VIS_HELP("A sentence")
1076 textobj
, { .i
= VIS_TEXTOBJECT_SENTENCE
}
1078 [VIS_ACTION_TEXT_OBJECT_PARAGRAPH
] = {
1079 "vis-textobject-paragraph",
1080 VIS_HELP("A paragraph")
1081 textobj
, { .i
= VIS_TEXTOBJECT_PARAGRAPH
}
1083 [VIS_ACTION_TEXT_OBJECT_PARAGRAPH_OUTER
] = {
1084 "vis-textobject-paragraph-outer",
1085 VIS_HELP("A paragraph (outer variant)")
1086 textobj
, { .i
= VIS_TEXTOBJECT_PARAGRAPH_OUTER
}
1088 [VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_OUTER
] = {
1089 "vis-textobject-square-bracket-outer",
1090 VIS_HELP("[] block (outer variant)")
1091 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_SQUARE_BRACKET
}
1093 [VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_INNER
] = {
1094 "vis-textobject-square-bracket-inner",
1095 VIS_HELP("[] block (inner variant)")
1096 textobj
, { .i
= VIS_TEXTOBJECT_INNER_SQUARE_BRACKET
}
1098 [VIS_ACTION_TEXT_OBJECT_PARENTHESIS_OUTER
] = {
1099 "vis-textobject-parenthesis-outer",
1100 VIS_HELP("() block (outer variant)")
1101 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_PARENTHESIS
}
1103 [VIS_ACTION_TEXT_OBJECT_PARENTHESIS_INNER
] = {
1104 "vis-textobject-parenthesis-inner",
1105 VIS_HELP("() block (inner variant)")
1106 textobj
, { .i
= VIS_TEXTOBJECT_INNER_PARENTHESIS
}
1108 [VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_OUTER
] = {
1109 "vis-textobject-angle-bracket-outer",
1110 VIS_HELP("<> block (outer variant)")
1111 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_ANGLE_BRACKET
}
1113 [VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_INNER
] = {
1114 "vis-textobject-angle-bracket-inner",
1115 VIS_HELP("<> block (inner variant)")
1116 textobj
, { .i
= VIS_TEXTOBJECT_INNER_ANGLE_BRACKET
}
1118 [VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_OUTER
] = {
1119 "vis-textobject-curly-bracket-outer",
1120 VIS_HELP("{} block (outer variant)")
1121 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_CURLY_BRACKET
}
1123 [VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_INNER
] = {
1124 "vis-textobject-curly-bracket-inner",
1125 VIS_HELP("{} block (inner variant)")
1126 textobj
, { .i
= VIS_TEXTOBJECT_INNER_CURLY_BRACKET
}
1128 [VIS_ACTION_TEXT_OBJECT_QUOTE_OUTER
] = {
1129 "vis-textobject-quote-outer",
1130 VIS_HELP("A quoted string, including the quotation marks")
1131 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_QUOTE
}
1133 [VIS_ACTION_TEXT_OBJECT_QUOTE_INNER
] = {
1134 "vis-textobject-quote-inner",
1135 VIS_HELP("A quoted string, excluding the quotation marks")
1136 textobj
, { .i
= VIS_TEXTOBJECT_INNER_QUOTE
}
1138 [VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_OUTER
] = {
1139 "vis-textobject-single-quote-outer",
1140 VIS_HELP("A single quoted string, including the quotation marks")
1141 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_SINGLE_QUOTE
}
1143 [VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_INNER
] = {
1144 "vis-textobject-single-quote-inner",
1145 VIS_HELP("A single quoted string, excluding the quotation marks")
1146 textobj
, { .i
= VIS_TEXTOBJECT_INNER_SINGLE_QUOTE
}
1148 [VIS_ACTION_TEXT_OBJECT_BACKTICK_OUTER
] = {
1149 "vis-textobject-backtick-outer",
1150 VIS_HELP("A backtick delimited string (outer variant)")
1151 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_BACKTICK
}
1153 [VIS_ACTION_TEXT_OBJECT_BACKTICK_INNER
] = {
1154 "vis-textobject-backtick-inner",
1155 VIS_HELP("A backtick delimited string (inner variant)")
1156 textobj
, { .i
= VIS_TEXTOBJECT_INNER_BACKTICK
}
1158 [VIS_ACTION_TEXT_OBJECT_ENTIRE_OUTER
] = {
1159 "vis-textobject-entire-outer",
1160 VIS_HELP("The whole text content")
1161 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_ENTIRE
}
1163 [VIS_ACTION_TEXT_OBJECT_ENTIRE_INNER
] = {
1164 "vis-textobject-entire-inner",
1165 VIS_HELP("The whole text content, except for leading and trailing empty lines")
1166 textobj
, { .i
= VIS_TEXTOBJECT_INNER_ENTIRE
}
1168 [VIS_ACTION_TEXT_OBJECT_LINE_OUTER
] = {
1169 "vis-textobject-line-outer",
1170 VIS_HELP("The whole line")
1171 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_LINE
}
1173 [VIS_ACTION_TEXT_OBJECT_LINE_INNER
] = {
1174 "vis-textobject-line-inner",
1175 VIS_HELP("The whole line, excluding leading and trailing whitespace")
1176 textobj
, { .i
= VIS_TEXTOBJECT_INNER_LINE
}
1178 [VIS_ACTION_TEXT_OBJECT_INDENTATION
] = {
1179 "vis-textobject-indentation",
1180 VIS_HELP("All adjacent lines with the same indentation level as the current one")
1181 textobj
, { .i
= VIS_TEXTOBJECT_INDENTATION
}
1183 [VIS_ACTION_TEXT_OBJECT_SEARCH_FORWARD
] = {
1184 "vis-textobject-search-forward",
1185 VIS_HELP("The next search match in forward direction")
1186 textobj
, { .i
= VIS_TEXTOBJECT_SEARCH_FORWARD
}
1188 [VIS_ACTION_TEXT_OBJECT_SEARCH_BACKWARD
] = {
1189 "vis-textobject-search-backward",
1190 VIS_HELP("The next search match in backward direction")
1191 textobj
, { .i
= VIS_TEXTOBJECT_SEARCH_BACKWARD
}
1193 [VIS_ACTION_UNICODE_INFO
] = {
1195 VIS_HELP("Show Unicode codepoint(s) of character under cursor")
1196 unicode_info
, { .i
= VIS_ACTION_UNICODE_INFO
}
1198 [VIS_ACTION_UTF8_INFO
] = {
1200 VIS_HELP("Show UTF-8 encoded codepoint(s) of character under cursor")
1201 unicode_info
, { .i
= VIS_ACTION_UTF8_INFO
}
1203 [VIS_ACTION_NOP
] = {
1205 VIS_HELP("Ignore key, do nothing")
1212 /** key bindings functions */
1214 static const char *nop(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1218 static const char *macro_record(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1219 if (!vis_macro_record_stop(vis
)) {
1222 const char *next
= vis_keys_next(vis
, keys
);
1223 if (next
- keys
> 1)
1225 enum VisRegister reg
= vis_register_from(vis
, keys
[0]);
1226 vis_macro_record(vis
, reg
);
1233 static const char *macro_replay(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1236 const char *next
= vis_keys_next(vis
, keys
);
1237 if (next
- keys
> 1)
1239 enum VisRegister reg
= vis_register_from(vis
, keys
[0]);
1240 vis_macro_replay(vis
, reg
);
1244 static const char *suspend(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1249 static const char *repeat(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1254 static const char *selections_new(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1255 View
*view
= vis_view(vis
);
1256 bool anchored
= view_selections_anchored(view_selections_primary_get(view
));
1257 VisCountIterator it
= vis_count_iterator_get(vis
, 1);
1258 while (vis_count_iterator_next(&it
)) {
1259 Selection
*sel
= NULL
;
1263 sel
= view_selections_primary_get(view
);
1266 sel
= view_selections(view
);
1269 for (Selection
*s
= view_selections(view
); s
; s
= view_selections_next(s
))
1277 size_t oldpos
= view_cursors_pos(sel
);
1279 view_line_down(sel
);
1280 else if (arg
->i
< 0)
1282 size_t newpos
= view_cursors_pos(sel
);
1283 view_cursors_to(sel
, oldpos
);
1284 Selection
*sel_new
= view_selections_new(view
, newpos
);
1287 sel_new
= view_selections_prev(sel
);
1288 else if (arg
->i
== +1)
1289 sel_new
= view_selections_next(sel
);
1292 view_selections_primary_set(sel_new
);
1293 view_selections_anchor(sel_new
, anchored
);
1296 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
1300 static const char *selections_align(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1301 View
*view
= vis_view(vis
);
1302 Text
*txt
= vis_text(vis
);
1303 int mincol
= INT_MAX
;
1304 for (Selection
*s
= view_selections(view
); s
; s
= view_selections_next(s
)) {
1305 int col
= view_cursors_cell_get(s
);
1306 if (col
>= 0 && col
< mincol
)
1309 for (Selection
*s
= view_selections(view
); s
; s
= view_selections_next(s
)) {
1310 if (view_cursors_cell_set(s
, mincol
) == -1) {
1311 size_t pos
= view_cursors_pos(s
);
1312 size_t col
= text_line_width_set(txt
, pos
, mincol
);
1313 view_cursors_to(s
, col
);
1319 static const char *selections_align_indent(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1320 View
*view
= vis_view(vis
);
1321 Text
*txt
= vis_text(vis
);
1322 bool left_align
= arg
->i
< 0;
1323 int columns
= view_selections_column_count(view
);
1325 for (int i
= 0; i
< columns
; i
++) {
1326 int mincol
= INT_MAX
, maxcol
= 0;
1327 for (Selection
*s
= view_selections_column(view
, i
); s
; s
= view_selections_column_next(s
, i
)) {
1328 Filerange sel
= view_selections_get(s
);
1329 size_t pos
= left_align
? sel
.start
: sel
.end
;
1330 int col
= text_line_width_get(txt
, pos
);
1337 size_t len
= maxcol
- mincol
;
1338 char *buf
= malloc(len
+1);
1341 memset(buf
, ' ', len
);
1343 for (Selection
*s
= view_selections_column(view
, i
); s
; s
= view_selections_column_next(s
, i
)) {
1344 Filerange sel
= view_selections_get(s
);
1345 size_t pos
= left_align
? sel
.start
: sel
.end
;
1346 size_t ipos
= sel
.start
;
1347 int col
= text_line_width_get(txt
, pos
);
1349 size_t off
= maxcol
- col
;
1351 text_insert(txt
, ipos
, buf
, off
);
1362 static const char *selections_clear(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1363 View
*view
= vis_view(vis
);
1364 if (view_selections_count(view
) > 1)
1365 view_selections_dispose_all(view
);
1367 view_selection_clear(view_selections_primary_get(view
));
1371 static const char *selections_match_word(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1372 Text
*txt
= vis_text(vis
);
1373 View
*view
= vis_view(vis
);
1374 for (Selection
*s
= view_selections(view
); s
; s
= view_selections_next(s
)) {
1375 Filerange word
= text_object_word(txt
, view_cursors_pos(s
));
1376 if (text_range_valid(&word
))
1377 view_selections_set(s
, &word
);
1379 vis_mode_switch(vis
, VIS_MODE_VISUAL
);
1383 static const Selection
*selection_new_primary(View
*view
, Filerange
*r
) {
1384 Text
*txt
= view_text(view
);
1385 size_t pos
= text_char_prev(txt
, r
->end
);
1386 Selection
*s
= view_selections_new(view
, pos
);
1389 view_selections_set(s
, r
);
1390 view_selections_anchor(s
, true);
1391 view_selections_primary_set(s
);
1395 static const char *selections_match_next_literal(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1396 Text
*txt
= vis_text(vis
);
1397 View
*view
= vis_view(vis
);
1398 Selection
*s
= view_selections_primary_get(view
);
1399 Filerange sel
= view_selections_get(s
);
1400 size_t len
= text_range_size(&sel
);
1404 char *buf
= text_bytes_alloc0(txt
, sel
.start
, len
);
1408 size_t start
= text_find_next(txt
, sel
.end
, buf
);
1409 Filerange match
= text_range_new(start
, start
+len
);
1410 if (start
!= sel
.end
&& selection_new_primary(view
, &match
))
1413 sel
= view_selections_get(view_selections(view
));
1414 start
= text_find_prev(txt
, sel
.start
, buf
);
1415 if (start
== sel
.start
)
1418 match
= text_range_new(start
, start
+len
);
1419 selection_new_primary(view
, &match
);
1426 static const char *selections_match_next(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1427 Text
*txt
= vis_text(vis
);
1428 View
*view
= vis_view(vis
);
1429 Selection
*s
= view_selections_primary_get(view
);
1430 Filerange sel
= view_selections_get(s
);
1431 if (!text_range_valid(&sel
))
1434 Filerange word
= text_object_word(txt
, view_cursors_pos(s
));
1435 if (!text_range_equal(&sel
, &word
))
1436 return selections_match_next_literal(vis
, keys
, arg
);
1438 char *buf
= text_bytes_alloc0(txt
, sel
.start
, text_range_size(&sel
));
1442 word
= text_object_word_find_next(txt
, sel
.end
, buf
);
1443 if (text_range_valid(&word
) && selection_new_primary(view
, &word
))
1446 sel
= view_selections_get(view_selections(view
));
1447 word
= text_object_word_find_prev(txt
, sel
.start
, buf
);
1448 if (!text_range_valid(&word
))
1450 selection_new_primary(view
, &word
);
1457 static const char *selections_match_skip(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1458 View
*view
= vis_view(vis
);
1459 Selection
*sel
= view_selections_primary_get(view
);
1460 keys
= selections_match_next(vis
, keys
, arg
);
1461 if (sel
!= view_selections_primary_get(view
))
1462 view_selections_dispose(sel
);
1466 static const char *selections_remove(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1467 View
*view
= vis_view(vis
);
1468 view_selections_dispose(view_selections_primary_get(view
));
1469 view_cursor_to(view
, view_cursor_get(view
));
1473 static const char *selections_remove_column(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1474 View
*view
= vis_view(vis
);
1475 int max
= view_selections_column_count(view
);
1476 int column
= vis_count_get_default(vis
, arg
->i
) - 1;
1479 if (view_selections_count(view
) == 1) {
1480 vis_keys_feed(vis
, "<Escape>");
1484 for (Selection
*s
= view_selections_column(view
, column
), *next
; s
; s
= next
) {
1485 next
= view_selections_column_next(s
, column
);
1486 view_selections_dispose(s
);
1489 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
1493 static const char *selections_remove_column_except(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1494 View
*view
= vis_view(vis
);
1495 int max
= view_selections_column_count(view
);
1496 int column
= vis_count_get_default(vis
, arg
->i
) - 1;
1499 if (view_selections_count(view
) == 1) {
1504 Selection
*sel
= view_selections(view
);
1505 Selection
*col
= view_selections_column(view
, column
);
1506 for (Selection
*next
; sel
; sel
= next
) {
1507 next
= view_selections_next(sel
);
1509 col
= view_selections_column_next(col
, column
);
1511 view_selections_dispose(sel
);
1514 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
1518 static const char *selections_navigate(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1519 View
*view
= vis_view(vis
);
1520 if (view_selections_count(view
) == 1)
1521 return wscroll(vis
, keys
, arg
);
1522 Selection
*s
= view_selections_primary_get(view
);
1523 VisCountIterator it
= vis_count_iterator_get(vis
, 1);
1524 while (vis_count_iterator_next(&it
)) {
1526 s
= view_selections_next(s
);
1528 s
= view_selections(view
);
1530 s
= view_selections_prev(s
);
1532 s
= view_selections(view
);
1533 for (Selection
*n
= s
; n
; n
= view_selections_next(n
))
1538 view_selections_primary_set(s
);
1539 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
1543 static const char *selections_rotate(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1552 Text
*txt
= vis_text(vis
);
1553 View
*view
= vis_view(vis
);
1554 int columns
= view_selections_column_count(view
);
1555 int selections
= columns
== 1 ? view_selections_count(view
) : columns
;
1556 int count
= vis_count_get_default(vis
, 1);
1557 array_init_sized(&arr
, sizeof(Rotate
));
1558 if (!array_reserve(&arr
, selections
))
1562 for (Selection
*s
= view_selections(view
), *next
; s
; s
= next
) {
1563 next
= view_selections_next(s
);
1564 size_t line_next
= 0;
1566 Filerange sel
= view_selections_get(s
);
1569 rot
.len
= text_range_size(&sel
);
1570 if ((rot
.data
= malloc(rot
.len
)))
1571 rot
.len
= text_bytes_get(txt
, sel
.start
, rot
.len
, rot
.data
);
1574 array_add(&arr
, &rot
);
1577 line
= text_lineno_by_pos(txt
, view_cursors_pos(s
));
1579 line_next
= text_lineno_by_pos(txt
, view_cursors_pos(next
));
1580 if (!next
|| (columns
> 1 && line
!= line_next
)) {
1581 size_t len
= array_length(&arr
);
1582 size_t off
= arg
->i
> 0 ? count
% len
: len
- (count
% len
);
1583 for (size_t i
= 0; i
< len
; i
++) {
1584 size_t j
= (i
+ off
) % len
;
1585 Rotate
*oldrot
= array_get(&arr
, i
);
1586 Rotate
*newrot
= array_get(&arr
, j
);
1587 if (!oldrot
|| !newrot
|| oldrot
== newrot
)
1589 Filerange newsel
= view_selections_get(newrot
->sel
);
1590 if (!text_range_valid(&newsel
))
1592 if (!text_delete_range(txt
, &newsel
))
1594 if (!text_insert(txt
, newsel
.start
, oldrot
->data
, oldrot
->len
))
1596 newsel
.end
= newsel
.start
+ oldrot
->len
;
1597 view_selections_set(newrot
->sel
, &newsel
);
1605 array_release(&arr
);
1606 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
1610 static const char *selections_trim(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1611 Text
*txt
= vis_text(vis
);
1612 View
*view
= vis_view(vis
);
1613 for (Selection
*s
= view_selections(view
), *next
; s
; s
= next
) {
1614 next
= view_selections_next(s
);
1615 Filerange sel
= view_selections_get(s
);
1616 if (!text_range_valid(&sel
))
1618 for (char b
; sel
.start
< sel
.end
&& text_byte_get(txt
, sel
.end
-1, &b
)
1619 && isspace((unsigned char)b
); sel
.end
--);
1620 for (char b
; sel
.start
<= sel
.end
&& text_byte_get(txt
, sel
.start
, &b
)
1621 && isspace((unsigned char)b
); sel
.start
++);
1622 if (sel
.start
< sel
.end
) {
1623 view_selections_set(s
, &sel
);
1624 } else if (!view_selections_dispose(s
)) {
1625 vis_mode_switch(vis
, VIS_MODE_NORMAL
);
1631 static void selections_set(Vis
*vis
, View
*view
, Array
*sel
) {
1632 enum VisMode mode
= vis_mode_get(vis
);
1633 bool anchored
= mode
== VIS_MODE_VISUAL
|| mode
== VIS_MODE_VISUAL_LINE
;
1634 view_selections_set_all(view
, sel
, anchored
);
1636 view_selections_clear_all(view
);
1639 static const char *selections_save(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1640 Win
*win
= vis_window(vis
);
1641 View
*view
= vis_view(vis
);
1642 enum VisMark mark
= vis_mark_used(vis
);
1643 Array sel
= view_selections_get_all(view
);
1644 vis_mark_set(win
, mark
, &sel
);
1645 array_release(&sel
);
1650 static const char *selections_restore(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1651 Win
*win
= vis_window(vis
);
1652 View
*view
= vis_view(vis
);
1653 enum VisMark mark
= vis_mark_used(vis
);
1654 Array sel
= vis_mark_get(win
, mark
);
1655 selections_set(vis
, view
, &sel
);
1656 array_release(&sel
);
1661 static const char *selections_union(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1662 Win
*win
= vis_window(vis
);
1663 View
*view
= vis_view(vis
);
1664 enum VisMark mark
= vis_mark_used(vis
);
1665 Array a
= vis_mark_get(win
, mark
);
1666 Array b
= view_selections_get_all(view
);
1668 array_init_from(&sel
, &a
);
1670 size_t i
= 0, j
= 0;
1671 Filerange
*r1
= array_get(&a
, i
), *r2
= array_get(&b
, j
), cur
= text_range_empty();
1673 if (r1
&& text_range_overlap(r1
, &cur
)) {
1674 cur
= text_range_union(r1
, &cur
);
1675 r1
= array_get(&a
, ++i
);
1676 } else if (r2
&& text_range_overlap(r2
, &cur
)) {
1677 cur
= text_range_union(r2
, &cur
);
1678 r2
= array_get(&b
, ++j
);
1680 if (text_range_valid(&cur
))
1681 array_add(&sel
, &cur
);
1684 r2
= array_get(&b
, ++j
);
1687 r1
= array_get(&a
, ++i
);
1689 if (r1
->start
< r2
->start
) {
1691 r1
= array_get(&a
, ++i
);
1694 r2
= array_get(&b
, ++j
);
1700 if (text_range_valid(&cur
))
1701 array_add(&sel
, &cur
);
1703 selections_set(vis
, view
, &sel
);
1708 array_release(&sel
);
1713 static void intersect(Array
*ret
, Array
*a
, Array
*b
) {
1714 size_t i
= 0, j
= 0;
1715 Filerange
*r1
= array_get(a
, i
), *r2
= array_get(b
, j
);
1717 if (text_range_overlap(r1
, r2
)) {
1718 Filerange
new = text_range_intersect(r1
, r2
);
1719 array_add(ret
, &new);
1721 if (r1
->end
< r2
->end
)
1722 r1
= array_get(a
, ++i
);
1724 r2
= array_get(b
, ++j
);
1728 static const char *selections_intersect(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1729 Win
*win
= vis_window(vis
);
1730 View
*view
= vis_view(vis
);
1731 enum VisMark mark
= vis_mark_used(vis
);
1732 Array a
= vis_mark_get(win
, mark
);
1733 Array b
= view_selections_get_all(view
);
1735 array_init_from(&sel
, &a
);
1737 intersect(&sel
, &a
, &b
);
1738 selections_set(vis
, view
, &sel
);
1743 array_release(&sel
);
1748 static void complement(Array
*ret
, Array
*a
, Filerange
*universe
) {
1749 size_t pos
= universe
->start
;
1750 for (size_t i
= 0, len
= array_length(a
); i
< len
; i
++) {
1751 Filerange
*r
= array_get(a
, i
);
1752 if (pos
< r
->start
) {
1753 Filerange
new = text_range_new(pos
, r
->start
);
1754 array_add(ret
, &new);
1758 if (pos
< universe
->end
) {
1759 Filerange
new = text_range_new(pos
, universe
->end
);
1760 array_add(ret
, &new);
1764 static const char *selections_complement(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1765 Text
*txt
= vis_text(vis
);
1766 View
*view
= vis_view(vis
);
1767 Filerange universe
= text_object_entire(txt
, 0);
1768 Array a
= view_selections_get_all(view
);
1770 array_init_from(&sel
, &a
);
1772 complement(&sel
, &a
, &universe
);
1774 selections_set(vis
, view
, &sel
);
1776 array_release(&sel
);
1780 static const char *selections_minus(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1781 Text
*txt
= vis_text(vis
);
1782 Win
*win
= vis_window(vis
);
1783 View
*view
= vis_view(vis
);
1784 enum VisMark mark
= vis_mark_used(vis
);
1785 Array a
= view_selections_get_all(view
);
1786 Array b
= vis_mark_get(win
, mark
);
1788 array_init_from(&sel
, &a
);
1790 array_init_from(&b_complement
, &b
);
1792 Filerange universe
= text_object_entire(txt
, 0);
1793 complement(&b_complement
, &b
, &universe
);
1794 intersect(&sel
, &a
, &b_complement
);
1796 selections_set(vis
, view
, &sel
);
1801 array_release(&b_complement
);
1802 array_release(&sel
);
1807 static Filerange
combine_shorter(const Filerange
*r1
, const Filerange
*r2
) {
1812 size_t l1
= text_range_size(r1
);
1813 size_t l2
= text_range_size(r2
);
1814 return l1
< l2
? *r1
: *r2
;
1817 static Filerange
combine_leftmost(const Filerange
*r1
, const Filerange
*r2
) {
1822 return r1
->start
< r2
->start
|| (r1
->start
== r2
->start
&& r1
->end
< r2
->end
) ? *r1
: *r2
;
1825 static Filerange
combine_rightmost(const Filerange
*r1
, const Filerange
*r2
) {
1830 return r1
->start
< r2
->start
|| (r1
->start
== r2
->start
&& r1
->end
< r2
->end
) ? *r2
: *r1
;
1833 static const char *selections_combine(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1834 Win
*win
= vis_window(vis
);
1835 View
*view
= vis_view(vis
);
1836 enum VisMark mark
= vis_mark_used(vis
);
1837 Array a
= view_selections_get_all(view
);
1838 Array b
= vis_mark_get(win
, mark
);
1840 array_init_from(&sel
, &a
);
1842 Filerange
*r1
= array_get(&a
, 0), *r2
= array_get(&b
, 0);
1843 for (size_t i
= 0, j
= 0; r1
|| r2
; r1
= array_get(&a
, ++i
), r2
= array_get(&b
, ++j
)) {
1844 Filerange
new = arg
->combine(r1
, r2
);
1845 if (text_range_valid(&new))
1846 array_add(&sel
, &new);
1849 vis_mark_normalize(&sel
);
1850 selections_set(vis
, view
, &sel
);
1855 array_release(&sel
);
1860 static const char *replace(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1862 vis_keymap_disable(vis
);
1866 const char *next
= vis_keys_next(vis
, keys
);
1870 char replacement
[UTFmax
+1];
1871 if (!vis_keys_utf8(vis
, keys
, replacement
))
1874 if (replacement
[0] == 0x1b) /* <Escape> */
1877 vis_operator(vis
, VIS_OP_REPLACE
, replacement
);
1878 if (vis_mode_get(vis
) == VIS_MODE_OPERATOR_PENDING
)
1879 vis_motion(vis
, VIS_MOVE_CHAR_NEXT
);
1883 static const char *count(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1884 int digit
= keys
[-1] - '0';
1885 int count
= vis_count_get_default(vis
, 0);
1886 if (0 <= digit
&& digit
<= 9) {
1887 if (digit
== 0 && count
== 0)
1888 vis_motion(vis
, VIS_MOVE_LINE_BEGIN
);
1890 vis_count_set(vis
, count
* 10 + digit
);
1895 static const char *gotoline(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1896 if (vis_count_get(vis
) != VIS_COUNT_UNKNOWN
)
1897 vis_motion(vis
, VIS_MOVE_LINE
);
1898 else if (arg
->i
< 0)
1899 vis_motion(vis
, VIS_MOVE_FILE_BEGIN
);
1901 vis_motion(vis
, VIS_MOVE_FILE_END
);
1905 static const char *operator(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1906 vis_operator(vis
, arg
->i
);
1910 static const char *movement_key(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1912 vis_keymap_disable(vis
);
1916 const char *next
= vis_keys_next(vis
, keys
);
1919 char utf8
[UTFmax
+1];
1920 if (vis_keys_utf8(vis
, keys
, utf8
))
1921 vis_motion(vis
, arg
->i
, utf8
);
1925 static const char *movement(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1926 vis_motion(vis
, arg
->i
);
1930 static const char *textobj(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1931 vis_textobject(vis
, arg
->i
);
1935 static const char *selection_end(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1936 for (Selection
*s
= view_selections(vis_view(vis
)); s
; s
= view_selections_next(s
))
1937 view_selections_flip(s
);
1941 static const char *reg(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1944 const char *next
= vis_keys_next(vis
, keys
);
1945 if (next
- keys
> 1)
1947 enum VisRegister reg
= vis_register_from(vis
, keys
[0]);
1948 vis_register(vis
, reg
);
1952 static const char *mark(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1955 const char *next
= vis_keys_next(vis
, keys
);
1956 if (next
- keys
> 1)
1958 enum VisMark mark
= vis_mark_from(vis
, keys
[0]);
1959 vis_mark(vis
, mark
);
1963 static const char *undo(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1964 size_t pos
= text_undo(vis_text(vis
));
1966 View
*view
= vis_view(vis
);
1967 if (view_selections_count(view
) == 1)
1968 view_cursor_to(view
, pos
);
1969 /* redraw all windows in case some display the same file */
1975 static const char *redo(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1976 size_t pos
= text_redo(vis_text(vis
));
1978 View
*view
= vis_view(vis
);
1979 if (view_selections_count(view
) == 1)
1980 view_cursor_to(view
, pos
);
1981 /* redraw all windows in case some display the same file */
1987 static const char *earlier(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1989 VisCountIterator it
= vis_count_iterator_get(vis
, 1);
1990 while (vis_count_iterator_next(&it
))
1991 pos
= text_earlier(vis_text(vis
));
1993 view_cursor_to(vis_view(vis
), pos
);
1994 /* redraw all windows in case some display the same file */
2000 static const char *later(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2002 VisCountIterator it
= vis_count_iterator_get(vis
, 1);
2003 while (vis_count_iterator_next(&it
))
2004 pos
= text_later(vis_text(vis
));
2006 view_cursor_to(vis_view(vis
), pos
);
2007 /* redraw all windows in case some display the same file */
2013 static const char *delete(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2014 vis_operator(vis
, VIS_OP_DELETE
);
2015 vis_motion(vis
, arg
->i
);
2019 static const char *insert_register(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2022 const char *next
= vis_keys_next(vis
, keys
);
2023 if (next
- keys
> 1)
2025 enum VisRegister reg
= vis_register_from(vis
, keys
[0]);
2026 if (reg
!= VIS_REG_INVALID
) {
2027 vis_register(vis
, reg
);
2028 vis_operator(vis
, VIS_OP_PUT_BEFORE_END
);
2033 static const char *prompt_show(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2034 vis_prompt_show(vis
, arg
->s
);
2038 static const char *insert_verbatim(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2040 char buf
[4], type
= keys
[0];
2041 const char *data
= NULL
;
2042 int len
= 0, count
= 0, base
= 0;
2064 if ('0' <= type
&& type
<= '9') {
2073 for (keys
++; keys
[0] && count
> 0; keys
++, count
--) {
2075 if (base
== 8 && '0' <= keys
[0] && keys
[0] <= '7') {
2077 } else if ((base
== 10 || base
== 16) && '0' <= keys
[0] && keys
[0] <= '9') {
2079 } else if (base
== 16 && 'a' <= keys
[0] && keys
[0] <= 'f') {
2080 v
= 10 + keys
[0] - 'a';
2081 } else if (base
== 16 && 'A' <= keys
[0] && keys
[0] <= 'F') {
2082 v
= 10 + keys
[0] - 'A';
2087 rune
= rune
* base
+ v
;
2092 if (type
== 'u' || type
== 'U') {
2093 len
= runetochar(buf
, &rune
);
2101 const char *next
= vis_keys_next(vis
, keys
);
2104 if ((rune
= vis_keys_codepoint(vis
, keys
)) != (Rune
)-1) {
2105 len
= runetochar(buf
, &rune
);
2110 vis_info_show(vis
, "Unknown key");
2116 vis_insert_key(vis
, data
, len
);
2120 static const char *wscroll(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2121 View
*view
= vis_view(vis
);
2122 int count
= vis_count_get(vis
);
2125 view_scroll_page_up(view
);
2128 view_scroll_page_down(view
);
2131 view_scroll_halfpage_up(view
);
2134 view_scroll_halfpage_down(view
);
2137 if (count
== VIS_COUNT_UNKNOWN
)
2138 count
= arg
->i
< 0 ? -arg
->i
: arg
->i
;
2140 view_scroll_up(view
, count
);
2142 view_scroll_down(view
, count
);
2145 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
2149 static const char *wslide(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2150 View
*view
= vis_view(vis
);
2151 int count
= vis_count_get(vis
);
2152 if (count
== VIS_COUNT_UNKNOWN
)
2153 count
= arg
->i
< 0 ? -arg
->i
: arg
->i
;
2155 view_slide_down(view
, count
);
2157 view_slide_up(view
, count
);
2158 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
2162 static const char *call(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2167 static const char *window(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2168 arg
->w(vis_view(vis
));
2172 static const char *openline(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2173 vis_operator(vis
, VIS_OP_MODESWITCH
, VIS_MODE_INSERT
);
2175 vis_motion(vis
, VIS_MOVE_LINE_END
);
2176 vis_keys_feed(vis
, "<Enter>");
2178 if (vis_get_autoindent(vis
)) {
2179 vis_motion(vis
, VIS_MOVE_LINE_START
);
2180 vis_keys_feed(vis
, "<vis-motion-line-start>");
2182 vis_motion(vis
, VIS_MOVE_LINE_BEGIN
);
2183 vis_keys_feed(vis
, "<vis-motion-line-begin>");
2185 vis_keys_feed(vis
, "<Enter><Up>");
2190 static const char *join(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2191 bool normal
= (vis_mode_get(vis
) == VIS_MODE_NORMAL
);
2192 vis_operator(vis
, VIS_OP_JOIN
, arg
->s
);
2194 int count
= vis_count_get_default(vis
, 0);
2196 vis_count_set(vis
, count
-1);
2197 vis_motion(vis
, VIS_MOVE_LINE_NEXT
);
2202 static const char *normalmode_escape(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2203 if (vis_count_get(vis
) == VIS_COUNT_UNKNOWN
)
2204 selections_clear(vis
, keys
, arg
);
2206 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
2210 static const char *visualmode_escape(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2211 if (vis_count_get(vis
) == VIS_COUNT_UNKNOWN
)
2212 vis_mode_switch(vis
, VIS_MODE_NORMAL
);
2214 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
2218 static const char *switchmode(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2219 vis_mode_switch(vis
, arg
->i
);
2223 static const char *insertmode(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2224 vis_operator(vis
, VIS_OP_MODESWITCH
, VIS_MODE_INSERT
);
2225 vis_motion(vis
, arg
->i
);
2229 static const char *replacemode(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2230 vis_operator(vis
, VIS_OP_MODESWITCH
, VIS_MODE_REPLACE
);
2231 vis_motion(vis
, arg
->i
);
2235 static const char *unicode_info(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2236 View
*view
= vis_view(vis
);
2237 Text
*txt
= vis_text(vis
);
2238 size_t start
= view_cursor_get(view
);
2239 size_t end
= text_char_next(txt
, start
);
2240 char *grapheme
= text_bytes_alloc0(txt
, start
, end
-start
), *codepoint
= grapheme
;
2245 mbstate_t ps
= { 0 };
2246 Iterator it
= text_iterator_get(txt
, start
);
2247 for (size_t pos
= start
; it
.pos
< end
; pos
= it
.pos
) {
2248 if (!text_iterator_codepoint_next(&it
, NULL
)) {
2249 vis_info_show(vis
, "Failed to parse code point");
2252 size_t len
= it
.pos
- pos
;
2253 wchar_t wc
= 0xFFFD;
2254 size_t res
= mbrtowc(&wc
, codepoint
, len
, &ps
);
2255 bool combining
= false;
2256 if (res
!= (size_t)-1 && res
!= (size_t)-2)
2257 combining
= (wc
!= L
'\0' && wcwidth(wc
) == 0);
2258 unsigned char ch
= *codepoint
;
2259 if (ch
< 128 && !isprint(ch
))
2260 buffer_appendf(&info
, "<^%c> ", ch
== 127 ? '?' : ch
+ 64);
2262 buffer_appendf(&info
, "<%s%.*s> ", combining
? " " : "", (int)len
, codepoint
);
2263 if (arg
->i
== VIS_ACTION_UNICODE_INFO
) {
2264 buffer_appendf(&info
, "U+%04"PRIX32
" ", (uint32_t)wc
);
2266 for (size_t i
= 0; i
< len
; i
++)
2267 buffer_appendf(&info
, "%02x ", (uint8_t)codepoint
[i
]);
2271 vis_info_show(vis
, "%s", buffer_content0(&info
));
2274 buffer_release(&info
);
2278 static const char *percent(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2279 if (vis_count_get(vis
) == VIS_COUNT_UNKNOWN
)
2280 vis_motion(vis
, VIS_MOVE_BRACKET_MATCH
);
2282 vis_motion(vis
, VIS_MOVE_PERCENT
);
2286 static const char *jumplist(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2288 vis_jumplist_prev(vis
);
2289 else if (arg
->i
> 0)
2290 vis_jumplist_next(vis
);
2292 vis_jumplist_save(vis
);
2298 static void signal_handler(int signum
, siginfo_t
*siginfo
, void *context
) {
2299 vis_signal_handler(vis
, signum
, siginfo
, context
);
2302 int main(int argc
, char *argv
[]) {
2305 .init
= vis_lua_init
,
2306 .start
= vis_lua_start
,
2307 .quit
= vis_lua_quit
,
2308 .mode_insert_input
= vis_lua_mode_insert_input
,
2309 .mode_replace_input
= vis_lua_mode_replace_input
,
2310 .file_open
= vis_lua_file_open
,
2311 .file_save_pre
= vis_lua_file_save_pre
,
2312 .file_save_post
= vis_lua_file_save_post
,
2313 .file_close
= vis_lua_file_close
,
2314 .win_open
= vis_lua_win_open
,
2315 .win_close
= vis_lua_win_close
,
2316 .win_highlight
= vis_lua_win_highlight
,
2317 .win_status
= vis_lua_win_status
,
2320 vis
= vis_new(ui_term_new(), &event
);
2322 return EXIT_FAILURE
;
2324 for (int i
= 0; i
< LENGTH(vis_action
); i
++) {
2325 const KeyAction
*action
= &vis_action
[i
];
2326 if (!vis_action_register(vis
, action
))
2327 vis_die(vis
, "Could not register action: %s\n", action
->name
);
2330 for (int i
= 0; i
< LENGTH(default_bindings
); i
++) {
2331 for (const KeyBinding
**binding
= default_bindings
[i
]; binding
&& *binding
; binding
++) {
2332 for (const KeyBinding
*kb
= *binding
; kb
->key
; kb
++) {
2333 vis_mode_map(vis
, i
, false, kb
->key
, kb
);
2338 for (const char **k
= keymaps
; k
[0]; k
+= 2)
2339 vis_keymap_add(vis
, k
[0], k
[1]);
2341 /* install signal handlers etc. */
2342 struct sigaction sa
;
2343 memset(&sa
, 0, sizeof sa
);
2344 sigfillset(&sa
.sa_mask
);
2345 sa
.sa_flags
= SA_SIGINFO
;
2346 sa
.sa_sigaction
= signal_handler
;
2347 if (sigaction(SIGBUS
, &sa
, NULL
) == -1 ||
2348 sigaction(SIGINT
, &sa
, NULL
) == -1 ||
2349 sigaction(SIGCONT
, &sa
, NULL
) == -1 ||
2350 sigaction(SIGWINCH
, &sa
, NULL
) == -1 ||
2351 sigaction(SIGTERM
, &sa
, NULL
) == -1 ||
2352 sigaction(SIGHUP
, &sa
, NULL
) == -1) {
2353 vis_die(vis
, "Failed to set signal handler: %s\n", strerror(errno
));
2356 sa
.sa_handler
= SIG_IGN
;
2357 if (sigaction(SIGPIPE
, &sa
, NULL
) == -1 || sigaction(SIGQUIT
, &sa
, NULL
) == -1)
2358 vis_die(vis
, "Failed to ignore signals\n");
2361 sigemptyset(&blockset
);
2362 sigaddset(&blockset
, SIGBUS
);
2363 sigaddset(&blockset
, SIGCONT
);
2364 sigaddset(&blockset
, SIGWINCH
);
2365 sigaddset(&blockset
, SIGTERM
);
2366 sigaddset(&blockset
, SIGHUP
);
2367 if (sigprocmask(SIG_BLOCK
, &blockset
, NULL
) == -1)
2368 vis_die(vis
, "Failed to block signals\n");
2370 for (int i
= 1; i
< argc
; i
++) {
2371 if (argv
[i
][0] != '-') {
2373 } else if (strcmp(argv
[i
], "-") == 0) {
2375 } else if (strcmp(argv
[i
], "--") == 0) {
2377 } else if (strcmp(argv
[i
], "-v") == 0) {
2378 printf("vis %s%s%s%s%s%s%s\n", VERSION
,
2379 CONFIG_CURSES
? " +curses" : "",
2380 CONFIG_LUA
? " +lua" : "",
2381 CONFIG_LPEG
? " +lpeg" : "",
2382 CONFIG_TRE
? " +tre" : "",
2383 CONFIG_ACL
? " +acl" : "",
2384 CONFIG_SELINUX
? " +selinux" : "");
2387 fprintf(stderr
, "Unknown command option: %s\n", argv
[i
]);
2393 bool end_of_options
= false, win_created
= false;
2395 for (int i
= 1; i
< argc
; i
++) {
2396 if (argv
[i
][0] == '-' && !end_of_options
) {
2397 if (strcmp(argv
[i
], "-") == 0) {
2398 if (!vis_window_new_fd(vis
, STDOUT_FILENO
))
2399 vis_die(vis
, "Can not create empty buffer\n");
2402 Text
*txt
= vis_text(vis
);
2403 while ((len
= read(STDIN_FILENO
, buf
, sizeof buf
)) > 0)
2404 text_insert(txt
, text_size(txt
), buf
, len
);
2406 vis_die(vis
, "Can not read from stdin\n");
2408 int fd
= open("/dev/tty", O_RDWR
);
2410 vis_die(vis
, "Can not reopen stdin\n");
2411 dup2(fd
, STDIN_FILENO
);
2413 } else if (strcmp(argv
[i
], "--") == 0) {
2414 end_of_options
= true;
2417 } else if (argv
[i
][0] == '+' && !end_of_options
) {
2418 cmd
= argv
[i
] + (argv
[i
][1] == '/' || argv
[i
][1] == '?');
2420 } else if (!vis_window_new(vis
, argv
[i
])) {
2421 vis_die(vis
, "Can not load `%s': %s\n", argv
[i
], strerror(errno
));
2425 vis_prompt_cmd(vis
, cmd
);
2430 if (!vis_window(vis
) && !win_created
) {
2431 if (!vis_window_new(vis
, NULL
))
2432 vis_die(vis
, "Can not create empty buffer\n");
2434 vis_prompt_cmd(vis
, cmd
);
2437 int status
= vis_run(vis
);