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 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
);
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
,
214 VIS_ACTION_MACRO_RECORD
,
215 VIS_ACTION_MACRO_REPLAY
,
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
,
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
,
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
,
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
,
315 static const KeyAction vis_action
[] = {
316 [VIS_ACTION_EDITOR_SUSPEND
] = {
318 VIS_HELP("Suspend the editor")
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")
451 [VIS_ACTION_CURSOR_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
] = {
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
] = {
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")
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")
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
] = {
613 VIS_HELP("Enter insert mode")
614 insertmode
, { .i
= VIS_MOVE_NOP
}
616 [VIS_ACTION_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
] = {
643 VIS_HELP("Go to older cursor position in jump list")
644 jumplist
, { .i
= -1 }
646 [VIS_ACTION_JUMPLIST_NEXT
] = {
648 VIS_HELP("Go to newer cursor position in jump list")
649 jumplist
, { .i
= +1 }
651 [VIS_ACTION_JUMPLIST_SAVE
] = {
653 VIS_HELP("Save current selections in jump list")
656 [VIS_ACTION_UNDO
] = {
658 VIS_HELP("Undo last change")
661 [VIS_ACTION_REDO
] = {
663 VIS_HELP("Redo last change")
666 [VIS_ACTION_EARLIER
] = {
668 VIS_HELP("Goto older text state")
671 [VIS_ACTION_LATER
] = {
673 VIS_HELP("Goto newer text state")
676 [VIS_ACTION_MACRO_RECORD
] = {
678 VIS_HELP("Record macro into given register")
681 [VIS_ACTION_MACRO_REPLAY
] = {
683 VIS_HELP("Replay macro, execute the content of the given register")
686 [VIS_ACTION_MARK
] = {
688 VIS_HELP("Use given mark for next action")
691 [VIS_ACTION_REDRAW
] = {
693 VIS_HELP("Redraw current editor content")
694 call
, { .f
= vis_redraw
}
696 [VIS_ACTION_REPLACE_CHAR
] = {
698 VIS_HELP("Replace the character under the cursor")
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
] = {
743 VIS_HELP("Use given register for next operator")
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
] = {
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
] = {
773 VIS_HELP("Count specifier")
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
] = {
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")
791 [VIS_ACTION_INSERT_REGISTER
] = {
792 "vis-insert-register",
793 VIS_HELP("Insert specified register content")
796 [VIS_ACTION_WINDOW_NEXT
] = {
798 VIS_HELP("Focus next window")
799 call
, { .f
= vis_window_next
}
801 [VIS_ACTION_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
] = {
833 VIS_HELP("Join selected lines")
836 [VIS_ACTION_JOIN_LINES_TRIM
] = {
837 "vis-join-lines-trim",
838 VIS_HELP("Join selected lines, remove white space")
841 [VIS_ACTION_PROMPT_SHOW
] = {
843 VIS_HELP("Show editor command line prompt")
844 prompt_show
, { .s
= ":" }
846 [VIS_ACTION_REPEAT
] = {
848 VIS_HELP("Repeat latest editor command")
851 [VIS_ACTION_SELECTION_FLIP
] = {
852 "vis-selection-flip",
853 VIS_HELP("Flip selection, move cursor to other 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")
876 [VIS_ACTION_WINDOW_SLIDE_DOWN
] = {
877 "vis-window-slide-down",
878 VIS_HELP("Slide window content downwards")
881 [VIS_ACTION_PUT_AFTER
] = {
883 VIS_HELP("Put text after the cursor")
884 operator, { .i
= VIS_OP_PUT_AFTER
}
886 [VIS_ACTION_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")
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")
956 [VIS_ACTION_SELECTIONS_REMOVE_LAST
] = {
957 "vis-selections-remove-last",
958 VIS_HELP("Remove primary selection")
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")
996 [VIS_ACTION_SELECTIONS_SAVE
] = {
997 "vis-selections-save",
998 VIS_HELP("Save currently active selections to mark")
1001 [VIS_ACTION_SELECTIONS_RESTORE
] = {
1002 "vis-selections-restore",
1003 VIS_HELP("Restore selections from mark")
1006 [VIS_ACTION_SELECTIONS_UNION
] = {
1007 "vis-selections-union",
1008 VIS_HELP("Add selections from mark")
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")
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
] = {
1158 VIS_HELP("Show Unicode codepoint(s) of character under cursor")
1159 unicode_info
, { .i
= VIS_ACTION_UNICODE_INFO
}
1161 [VIS_ACTION_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
] = {
1168 VIS_HELP("Ignore key, do nothing")
1175 /** key bindings functions */
1177 static const char *nop(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1181 static const char *macro_record(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1182 if (!vis_macro_record_stop(vis
)) {
1185 const char *next
= vis_keys_next(vis
, keys
);
1186 if (next
- keys
> 1)
1188 enum VisRegister reg
= vis_register_from(vis
, keys
[0]);
1189 vis_macro_record(vis
, reg
);
1196 static const char *macro_replay(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1199 const char *next
= vis_keys_next(vis
, keys
);
1200 if (next
- keys
> 1)
1202 enum VisRegister reg
= vis_register_from(vis
, keys
[0]);
1203 vis_macro_replay(vis
, reg
);
1207 static const char *suspend(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1212 static const char *repeat(Vis
*vis
, const char *keys
, const Arg
*arg
) {
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
;
1226 sel
= view_selections_primary_get(view
);
1229 sel
= view_selections(view
);
1232 for (Selection
*s
= view_selections(view
); s
; s
= view_selections_next(s
))
1240 size_t oldpos
= view_cursors_pos(sel
);
1242 view_line_down(sel
);
1243 else if (arg
->i
< 0)
1245 size_t newpos
= view_cursors_pos(sel
);
1246 view_cursors_to(sel
, oldpos
);
1247 Selection
*sel_new
= view_selections_new(view
, newpos
);
1250 sel_new
= view_selections_prev(sel
);
1251 else if (arg
->i
== +1)
1252 sel_new
= view_selections_next(sel
);
1255 view_selections_primary_set(sel_new
);
1256 view_selections_anchor(sel_new
, anchored
);
1259 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
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
)
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
);
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
);
1300 size_t len
= maxcol
- mincol
;
1301 char *buf
= malloc(len
+1);
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
);
1312 size_t off
= maxcol
- col
;
1314 text_insert(txt
, ipos
, buf
, off
);
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
);
1330 view_selection_clear(view_selections_primary_get(view
));
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
);
1340 view_selections_set(s
, r
);
1341 view_selections_anchor(s
, true);
1343 view_selections_primary_set(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
))
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
;
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
));
1373 bool match_all
= arg
->b
;
1374 Filerange primary
= sel
;
1377 sel
= find_next(txt
, sel
.end
, buf
);
1378 if (!text_range_valid(&sel
))
1380 if (selection_new(view
, &sel
, !match_all
) && !match_all
)
1387 sel
= find_prev(txt
, sel
.start
, buf
);
1388 if (!text_range_valid(&sel
))
1390 if (selection_new(view
, &sel
, !match_all
) && !match_all
)
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
);
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
));
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;
1421 if (view_selections_count(view
) == 1) {
1422 vis_keys_feed(vis
, "<Escape>");
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
);
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;
1441 if (view_selections_count(view
) == 1) {
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
);
1451 col
= view_selections_column_next(col
, column
);
1453 view_selections_dispose(sel
);
1456 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
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
)) {
1468 s
= view_selections_next(s
);
1470 s
= view_selections(view
);
1472 s
= view_selections_prev(s
);
1474 s
= view_selections(view
);
1475 for (Selection
*n
= s
; n
; n
= view_selections_next(n
))
1480 view_selections_primary_set(s
);
1481 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
1485 static const char *selections_rotate(Vis
*vis
, const char *keys
, const Arg
*arg
) {
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
))
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
);
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
);
1516 array_add(&arr
, &rot
);
1519 line
= text_lineno_by_pos(txt
, view_cursors_pos(s
));
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
)
1531 Filerange newsel
= view_selections_get(newrot
->sel
);
1532 if (!text_range_valid(&newsel
))
1534 if (!text_delete_range(txt
, &newsel
))
1536 if (!text_insert(txt
, newsel
.start
, oldrot
->data
, oldrot
->len
))
1538 newsel
.end
= newsel
.start
+ oldrot
->len
;
1539 view_selections_set(newrot
->sel
, &newsel
);
1547 array_release(&arr
);
1548 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
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
))
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
);
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
);
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
);
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
);
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
);
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();
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
);
1622 if (text_range_valid(&cur
))
1623 array_add(&sel
, &cur
);
1626 r2
= array_get(&b
, ++j
);
1629 r1
= array_get(&a
, ++i
);
1631 if (r1
->start
< r2
->start
) {
1633 r1
= array_get(&a
, ++i
);
1636 r2
= array_get(&b
, ++j
);
1642 if (text_range_valid(&cur
))
1643 array_add(&sel
, &cur
);
1645 selections_set(vis
, view
, &sel
);
1650 array_release(&sel
);
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
);
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
);
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
);
1677 array_init_from(&sel
, &a
);
1679 intersect(&sel
, &a
, &b
);
1680 selections_set(vis
, view
, &sel
);
1685 array_release(&sel
);
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);
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
);
1712 array_init_from(&sel
, &a
);
1714 complement(&sel
, &a
, &universe
);
1716 selections_set(vis
, view
, &sel
);
1718 array_release(&sel
);
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
);
1730 array_init_from(&sel
, &a
);
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
);
1743 array_release(&b_complement
);
1744 array_release(&sel
);
1749 static const char *replace(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1751 vis_keymap_disable(vis
);
1755 const char *next
= vis_keys_next(vis
, keys
);
1759 char replacement
[UTFmax
+1];
1760 if (!vis_keys_utf8(vis
, keys
, replacement
))
1763 if (replacement
[0] == 0x1b) /* <Escape> */
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
);
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
);
1779 vis_count_set(vis
, count
* 10 + digit
);
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
);
1790 vis_motion(vis
, VIS_MOVE_FILE_END
);
1794 static const char *operator(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1795 vis_operator(vis
, arg
->i
);
1799 static const char *movement_key(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1801 vis_keymap_disable(vis
);
1805 const char *next
= vis_keys_next(vis
, keys
);
1808 char utf8
[UTFmax
+1];
1809 if (vis_keys_utf8(vis
, keys
, utf8
))
1810 vis_motion(vis
, arg
->i
, utf8
);
1814 static const char *movement(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1815 vis_motion(vis
, arg
->i
);
1819 static const char *textobj(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1820 vis_textobject(vis
, arg
->i
);
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
);
1830 static const char *reg(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1833 const char *next
= vis_keys_next(vis
, keys
);
1834 if (next
- keys
> 1)
1836 enum VisRegister reg
= vis_register_from(vis
, keys
[0]);
1837 vis_register(vis
, reg
);
1841 static const char *mark(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1844 const char *next
= vis_keys_next(vis
, keys
);
1845 if (next
- keys
> 1)
1847 enum VisMark mark
= vis_mark_from(vis
, keys
[0]);
1848 vis_mark(vis
, mark
);
1852 static const char *undo(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1853 size_t pos
= text_undo(vis_text(vis
));
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 */
1864 static const char *redo(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1865 size_t pos
= text_redo(vis_text(vis
));
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 */
1876 static const char *earlier(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1878 VisCountIterator it
= vis_count_iterator_get(vis
, 1);
1879 while (vis_count_iterator_next(&it
))
1880 pos
= text_earlier(vis_text(vis
));
1882 view_cursor_to(vis_view(vis
), pos
);
1883 /* redraw all windows in case some display the same file */
1889 static const char *later(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1891 VisCountIterator it
= vis_count_iterator_get(vis
, 1);
1892 while (vis_count_iterator_next(&it
))
1893 pos
= text_later(vis_text(vis
));
1895 view_cursor_to(vis_view(vis
), pos
);
1896 /* redraw all windows in case some display the same file */
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
);
1908 static const char *insert_register(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1911 const char *next
= vis_keys_next(vis
, keys
);
1912 if (next
- keys
> 1)
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
);
1922 static const char *prompt_show(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1923 vis_prompt_show(vis
, arg
->s
);
1927 static const char *insert_verbatim(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1929 char buf
[4], type
= keys
[0];
1930 const char *data
= NULL
;
1931 int len
= 0, count
= 0, base
= 0;
1953 if ('0' <= type
&& type
<= '9') {
1962 for (keys
++; keys
[0] && count
> 0; keys
++, count
--) {
1964 if (base
== 8 && '0' <= keys
[0] && keys
[0] <= '7') {
1966 } else if ((base
== 10 || base
== 16) && '0' <= keys
[0] && keys
[0] <= '9') {
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';
1976 rune
= rune
* base
+ v
;
1981 if (type
== 'u' || type
== 'U') {
1982 len
= runetochar(buf
, &rune
);
1990 const char *next
= vis_keys_next(vis
, keys
);
1993 if ((rune
= vis_keys_codepoint(vis
, keys
)) != (Rune
)-1) {
1994 len
= runetochar(buf
, &rune
);
1999 vis_info_show(vis
, "Unknown key");
2005 vis_insert_key(vis
, data
, len
);
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
);
2014 view_scroll_page_up(view
);
2017 view_scroll_page_down(view
);
2020 view_scroll_halfpage_up(view
);
2023 view_scroll_halfpage_down(view
);
2026 if (count
== VIS_COUNT_UNKNOWN
)
2027 count
= arg
->i
< 0 ? -arg
->i
: arg
->i
;
2029 view_scroll_up(view
, count
);
2031 view_scroll_down(view
, count
);
2034 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
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
;
2044 view_slide_down(view
, count
);
2046 view_slide_up(view
, count
);
2047 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
2051 static const char *call(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2056 static const char *window(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2057 arg
->w(vis_view(vis
));
2061 static const char *openline(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2062 vis_operator(vis
, VIS_OP_MODESWITCH
, VIS_MODE_INSERT
);
2064 vis_motion(vis
, VIS_MOVE_LINE_END
);
2065 vis_keys_feed(vis
, "<Enter>");
2067 if (vis_get_autoindent(vis
)) {
2068 vis_motion(vis
, VIS_MOVE_LINE_START
);
2069 vis_keys_feed(vis
, "<vis-motion-line-start>");
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>");
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
);
2083 int count
= vis_count_get_default(vis
, 0);
2085 vis_count_set(vis
, count
-1);
2086 vis_motion(vis
, VIS_MOVE_LINE_NEXT
);
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
);
2095 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
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
);
2103 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
2107 static const char *switchmode(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2108 vis_mode_switch(vis
, arg
->i
);
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
);
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
);
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
;
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");
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);
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
);
2155 for (size_t i
= 0; i
< len
; i
++)
2156 buffer_appendf(&info
, "%02x ", (uint8_t)codepoint
[i
]);
2160 vis_info_show(vis
, "%s", buffer_content0(&info
));
2163 buffer_release(&info
);
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
);
2171 vis_motion(vis
, VIS_MOVE_PERCENT
);
2175 static const char *jumplist(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2177 vis_jumplist_prev(vis
);
2178 else if (arg
->i
> 0)
2179 vis_jumplist_next(vis
);
2181 vis_jumplist_save(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
[]) {
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
);
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");
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] != '-') {
2263 } else if (strcmp(argv
[i
], "-") == 0) {
2265 } else if (strcmp(argv
[i
], "--") == 0) {
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" : "");
2277 fprintf(stderr
, "Unknown command option: %s\n", argv
[i
]);
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");
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
);
2296 vis_die(vis
, "Can not read from stdin\n");
2298 int fd
= open("/dev/tty", O_RDWR
);
2300 vis_die(vis
, "Can not reopen stdin\n");
2301 dup2(fd
, STDIN_FILENO
);
2303 } else if (strcmp(argv
[i
], "--") == 0) {
2304 end_of_options
= true;
2307 } else if (argv
[i
][0] == '+' && !end_of_options
) {
2308 cmd
= argv
[i
] + (argv
[i
][1] == '/' || argv
[i
][1] == '?');
2310 } else if (!vis_window_new(vis
, argv
[i
])) {
2311 vis_die(vis
, "Can not load `%s': %s\n", argv
[i
], strerror(errno
));
2315 vis_prompt_cmd(vis
, cmd
);
2320 if (!vis_window(vis
) && !win_created
) {
2321 if (!vis_window_new(vis
, NULL
))
2322 vis_die(vis
, "Can not create empty buffer\n");
2324 vis_prompt_cmd(vis
, cmd
);
2327 int status
= vis_run(vis
);