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 /* switch to mode indicated by arg->i */
36 static const char *switchmode(Vis
*, const char *keys
, const Arg
*arg
);
37 /* switch to insert mode after performing movement indicated by arg->i */
38 static const char *insertmode(Vis
*, const char *keys
, const Arg
*arg
);
39 /* switch to replace mode after performing movement indicated by arg->i */
40 static const char *replacemode(Vis
*, const char *keys
, const Arg
*arg
);
41 /* set mark indicated by keys to current cursor position */
42 static const char *mark_set(Vis
*, const char *keys
, const Arg
*arg
);
43 /* add a new line either before or after the one where the cursor currently is */
44 static const char *openline(Vis
*, const char *keys
, const Arg
*arg
);
45 /* join lines from current cursor position to movement indicated by arg */
46 static const char *join(Vis
*, const char *keys
, const Arg
*arg
);
47 /* perform last action i.e. action_prev again */
48 static const char *repeat(Vis
*, const char *keys
, const Arg
*arg
);
49 /* replace character at cursor with one from keys */
50 static const char *replace(Vis
*, const char *keys
, const Arg
*arg
);
51 /* create a new cursor on the previous (arg->i < 0) or next (arg->i > 0) line */
52 static const char *cursors_new(Vis
*, const char *keys
, const Arg
*arg
);
53 /* try to align all cursors on the same column */
54 static const char *cursors_align(Vis
*, const char *keys
, const Arg
*arg
);
55 /* try to align all cursors by inserting the correct amount of white spaces */
56 static const char *cursors_align_indent(Vis
*, const char *keys
, const Arg
*arg
);
57 /* remove all but the primary cursor and their selections */
58 static const char *cursors_clear(Vis
*, const char *keys
, const Arg
*arg
);
59 /* remove the least recently added cursor */
60 static const char *cursors_remove(Vis
*, const char *keys
, const Arg
*arg
);
61 /* remove count (or arg->i)-th cursor column */
62 static const char *cursors_remove_column(Vis
*, const char *keys
, const Arg
*arg
);
63 /* remove all but the count (or arg->i)-th cursor column */
64 static const char *cursors_remove_column_except(Vis
*, const char *keys
, const Arg
*arg
);
65 /* move to the previous (arg->i < 0) or next (arg->i > 0) cursor */
66 static const char *cursors_navigate(Vis
*, const char *keys
, const Arg
*arg
);
67 /* select the word the cursor is currently over */
68 static const char *cursors_select(Vis
*, const char *keys
, const Arg
*arg
);
69 /* select the next region matching the current selection */
70 static const char *cursors_select_next(Vis
*, const char *keys
, const Arg
*arg
);
71 /* clear current selection but select next match */
72 static const char *cursors_select_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 register */
78 static const char *selections_save(Vis
*, const char *keys
, const Arg
*arg
);
79 /* restore selections from register */
80 static const char *selections_restore(Vis
*, const char *keys
, const Arg
*arg
);
81 /* union selections */
82 static const char *selections_union(Vis
*, const char *keys
, const Arg
*arg
);
83 /* intersect selections */
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 /* adjust current used count according to keys */
88 static const char *count(Vis
*, const char *keys
, const Arg
*arg
);
89 /* move to the count-th line or if not given either to the first (arg->i < 0)
90 * or last (arg->i > 0) line of file */
91 static const char *gotoline(Vis
*, const char *keys
, const Arg
*arg
);
92 /* set motion type either LINEWISE or CHARWISE via arg->i */
93 static const char *motiontype(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 /* use arg->s as command for the filter operator */
97 static const char *operator_filter(Vis
*, const char *keys
, const Arg
*arg
);
98 /* blocks to read a key and performs movement indicated by arg->i which
99 * should be one of VIS_MOVE_{RIGHT,LEFT}_{TO,TILL} */
100 static const char *movement_key(Vis
*, const char *keys
, const Arg
*arg
);
101 /* perform the movement as indicated by arg->i */
102 static const char *movement(Vis
*, const char *keys
, const Arg
*arg
);
103 /* let the current operator affect the range indicated by the text object arg->i */
104 static const char *textobj(Vis
*, const char *keys
, const Arg
*arg
);
105 /* move to the other end of selected text */
106 static const char *selection_end(Vis
*, const char *keys
, const Arg
*arg
);
107 /* restore least recently used selection */
108 static const char *selection_restore(Vis
*, const char *keys
, const Arg
*arg
);
109 /* use register indicated by keys for the current operator */
110 static const char *reg(Vis
*, const char *keys
, const Arg
*arg
);
111 /* perform arg->i motion with a mark indicated by keys as argument */
112 static const char *mark_motion(Vis
*, const char *keys
, const Arg
*arg
);
113 /* {un,re}do last action, redraw window */
114 static const char *undo(Vis
*, const char *keys
, const Arg
*arg
);
115 static const char *redo(Vis
*, const char *keys
, const Arg
*arg
);
116 /* earlier, later action chronologically, redraw window */
117 static const char *earlier(Vis
*, const char *keys
, const Arg
*arg
);
118 static const char *later(Vis
*, const char *keys
, const Arg
*arg
);
119 /* delete from the current cursor position to the end of
120 * movement as indicated by arg->i */
121 static const char *delete(Vis
*, const char *keys
, const Arg
*arg
);
122 /* insert register content indicated by keys at current cursor position */
123 static const char *insert_register(Vis
*, const char *keys
, const Arg
*arg
);
124 /* show a user prompt to get input with title arg->s */
125 static const char *prompt_show(Vis
*, const char *keys
, const Arg
*arg
);
126 /* blocks to read 3 consecutive digits and inserts the corresponding byte value */
127 static const char *insert_verbatim(Vis
*, const char *keys
, const Arg
*arg
);
128 /* scroll window content according to arg->i which can be either PAGE, PAGE_HALF,
129 * or an arbitrary number of lines. a multiplier overrides what is given in arg->i.
130 * negative values scroll back, positive forward. */
131 static const char *wscroll(Vis
*, const char *keys
, const Arg
*arg
);
132 /* similar to scroll, but do only move window content not cursor position */
133 static const char *wslide(Vis
*, const char *keys
, const Arg
*arg
);
134 /* call editor function as indicated by arg->f */
135 static const char *call(Vis
*, const char *keys
, const Arg
*arg
);
136 /* call window function as indicated by arg->w */
137 static const char *window(Vis
*, const char *keys
, const Arg
*arg
);
138 /* show info about Unicode character at cursor position */
139 static const char *unicode_info(Vis
*, const char *keys
, const Arg
*arg
);
140 /* either go to count % of ile or to matching item */
141 static const char *percent(Vis
*, const char *keys
, const Arg
*arg
);
144 VIS_ACTION_EDITOR_SUSPEND
,
145 VIS_ACTION_CURSOR_CHAR_PREV
,
146 VIS_ACTION_CURSOR_CHAR_NEXT
,
147 VIS_ACTION_CURSOR_LINE_CHAR_PREV
,
148 VIS_ACTION_CURSOR_LINE_CHAR_NEXT
,
149 VIS_ACTION_CURSOR_CODEPOINT_PREV
,
150 VIS_ACTION_CURSOR_CODEPOINT_NEXT
,
151 VIS_ACTION_CURSOR_WORD_START_PREV
,
152 VIS_ACTION_CURSOR_WORD_START_NEXT
,
153 VIS_ACTION_CURSOR_WORD_END_PREV
,
154 VIS_ACTION_CURSOR_WORD_END_NEXT
,
155 VIS_ACTION_CURSOR_LONGWORD_START_PREV
,
156 VIS_ACTION_CURSOR_LONGWORD_START_NEXT
,
157 VIS_ACTION_CURSOR_LONGWORD_END_PREV
,
158 VIS_ACTION_CURSOR_LONGWORD_END_NEXT
,
159 VIS_ACTION_CURSOR_LINE_UP
,
160 VIS_ACTION_CURSOR_LINE_DOWN
,
161 VIS_ACTION_CURSOR_LINE_START
,
162 VIS_ACTION_CURSOR_LINE_FINISH
,
163 VIS_ACTION_CURSOR_LINE_BEGIN
,
164 VIS_ACTION_CURSOR_LINE_END
,
165 VIS_ACTION_CURSOR_SCREEN_LINE_UP
,
166 VIS_ACTION_CURSOR_SCREEN_LINE_DOWN
,
167 VIS_ACTION_CURSOR_SCREEN_LINE_BEGIN
,
168 VIS_ACTION_CURSOR_SCREEN_LINE_MIDDLE
,
169 VIS_ACTION_CURSOR_SCREEN_LINE_END
,
170 VIS_ACTION_CURSOR_PERCENT
,
171 VIS_ACTION_CURSOR_BYTE
,
172 VIS_ACTION_CURSOR_BYTE_LEFT
,
173 VIS_ACTION_CURSOR_BYTE_RIGHT
,
174 VIS_ACTION_CURSOR_PARAGRAPH_PREV
,
175 VIS_ACTION_CURSOR_PARAGRAPH_NEXT
,
176 VIS_ACTION_CURSOR_SENTENCE_PREV
,
177 VIS_ACTION_CURSOR_SENTENCE_NEXT
,
178 VIS_ACTION_CURSOR_BLOCK_START
,
179 VIS_ACTION_CURSOR_BLOCK_END
,
180 VIS_ACTION_CURSOR_PARENTHESE_START
,
181 VIS_ACTION_CURSOR_PARENTHESE_END
,
182 VIS_ACTION_CURSOR_COLUMN
,
183 VIS_ACTION_CURSOR_LINE_FIRST
,
184 VIS_ACTION_CURSOR_LINE_LAST
,
185 VIS_ACTION_CURSOR_WINDOW_LINE_TOP
,
186 VIS_ACTION_CURSOR_WINDOW_LINE_MIDDLE
,
187 VIS_ACTION_CURSOR_WINDOW_LINE_BOTTOM
,
188 VIS_ACTION_CURSOR_SEARCH_REPEAT_FORWARD
,
189 VIS_ACTION_CURSOR_SEARCH_REPEAT_BACKWARD
,
190 VIS_ACTION_CURSOR_SEARCH_REPEAT
,
191 VIS_ACTION_CURSOR_SEARCH_REPEAT_REVERSE
,
192 VIS_ACTION_CURSOR_SEARCH_WORD_FORWARD
,
193 VIS_ACTION_CURSOR_SEARCH_WORD_BACKWARD
,
194 VIS_ACTION_WINDOW_PAGE_UP
,
195 VIS_ACTION_WINDOW_PAGE_DOWN
,
196 VIS_ACTION_WINDOW_HALFPAGE_UP
,
197 VIS_ACTION_WINDOW_HALFPAGE_DOWN
,
198 VIS_ACTION_MODE_NORMAL
,
199 VIS_ACTION_MODE_VISUAL
,
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_CHANGELIST_PREV
,
210 VIS_ACTION_CHANGELIST_NEXT
,
215 VIS_ACTION_MACRO_RECORD
,
216 VIS_ACTION_MACRO_REPLAY
,
218 VIS_ACTION_MARK_GOTO
,
219 VIS_ACTION_MARK_GOTO_LINE
,
221 VIS_ACTION_REPLACE_CHAR
,
222 VIS_ACTION_TOTILL_REPEAT
,
223 VIS_ACTION_TOTILL_REVERSE
,
224 VIS_ACTION_PROMPT_SEARCH_FORWARD
,
225 VIS_ACTION_PROMPT_SEARCH_BACKWARD
,
226 VIS_ACTION_TILL_LEFT
,
227 VIS_ACTION_TILL_RIGHT
,
231 VIS_ACTION_OPERATOR_CHANGE
,
232 VIS_ACTION_OPERATOR_DELETE
,
233 VIS_ACTION_OPERATOR_YANK
,
234 VIS_ACTION_OPERATOR_SHIFT_LEFT
,
235 VIS_ACTION_OPERATOR_SHIFT_RIGHT
,
236 VIS_ACTION_OPERATOR_CASE_LOWER
,
237 VIS_ACTION_OPERATOR_CASE_UPPER
,
238 VIS_ACTION_OPERATOR_CASE_SWAP
,
239 VIS_ACTION_OPERATOR_FILTER
,
240 VIS_ACTION_OPERATOR_FILTER_FMT
,
242 VIS_ACTION_INSERT_NEWLINE
,
243 VIS_ACTION_INSERT_TAB
,
244 VIS_ACTION_INSERT_VERBATIM
,
245 VIS_ACTION_INSERT_REGISTER
,
246 VIS_ACTION_WINDOW_NEXT
,
247 VIS_ACTION_WINDOW_PREV
,
248 VIS_ACTION_APPEND_CHAR_NEXT
,
249 VIS_ACTION_APPEND_LINE_END
,
250 VIS_ACTION_INSERT_LINE_START
,
251 VIS_ACTION_OPEN_LINE_ABOVE
,
252 VIS_ACTION_OPEN_LINE_BELOW
,
253 VIS_ACTION_JOIN_LINES
,
254 VIS_ACTION_JOIN_LINES_TRIM
,
255 VIS_ACTION_PROMPT_SHOW
,
257 VIS_ACTION_SELECTION_FLIP
,
258 VIS_ACTION_SELECTION_RESTORE
,
259 VIS_ACTION_WINDOW_REDRAW_TOP
,
260 VIS_ACTION_WINDOW_REDRAW_CENTER
,
261 VIS_ACTION_WINDOW_REDRAW_BOTTOM
,
262 VIS_ACTION_WINDOW_SLIDE_UP
,
263 VIS_ACTION_WINDOW_SLIDE_DOWN
,
264 VIS_ACTION_PUT_AFTER
,
265 VIS_ACTION_PUT_BEFORE
,
266 VIS_ACTION_PUT_AFTER_END
,
267 VIS_ACTION_PUT_BEFORE_END
,
268 VIS_ACTION_CURSOR_SELECT_WORD
,
269 VIS_ACTION_CURSORS_NEW_LINE_ABOVE
,
270 VIS_ACTION_CURSORS_NEW_LINE_ABOVE_FIRST
,
271 VIS_ACTION_CURSORS_NEW_LINE_BELOW
,
272 VIS_ACTION_CURSORS_NEW_LINE_BELOW_LAST
,
273 VIS_ACTION_CURSORS_NEW_LINES_BEGIN
,
274 VIS_ACTION_CURSORS_NEW_LINES_END
,
275 VIS_ACTION_CURSORS_NEW_MATCH_NEXT
,
276 VIS_ACTION_CURSORS_NEW_MATCH_SKIP
,
277 VIS_ACTION_CURSORS_ALIGN
,
278 VIS_ACTION_CURSORS_ALIGN_INDENT_LEFT
,
279 VIS_ACTION_CURSORS_ALIGN_INDENT_RIGHT
,
280 VIS_ACTION_CURSORS_REMOVE_ALL
,
281 VIS_ACTION_CURSORS_REMOVE_LAST
,
282 VIS_ACTION_CURSORS_REMOVE_COLUMN
,
283 VIS_ACTION_CURSORS_REMOVE_COLUMN_EXCEPT
,
284 VIS_ACTION_CURSORS_PREV
,
285 VIS_ACTION_CURSORS_NEXT
,
286 VIS_ACTION_SELECTIONS_ROTATE_LEFT
,
287 VIS_ACTION_SELECTIONS_ROTATE_RIGHT
,
288 VIS_ACTION_SELECTIONS_TRIM
,
289 VIS_ACTION_SELECTIONS_SAVE
,
290 VIS_ACTION_SELECTIONS_RESTORE
,
291 VIS_ACTION_SELECTIONS_UNION
,
292 VIS_ACTION_SELECTIONS_INTERSECT
,
293 VIS_ACTION_SELECTIONS_COMPLEMENT
,
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_SQUARE_BRACKET_OUTER
,
301 VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_INNER
,
302 VIS_ACTION_TEXT_OBJECT_PARANTHESE_OUTER
,
303 VIS_ACTION_TEXT_OBJECT_PARANTHESE_INNER
,
304 VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_OUTER
,
305 VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_INNER
,
306 VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_OUTER
,
307 VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_INNER
,
308 VIS_ACTION_TEXT_OBJECT_QUOTE_OUTER
,
309 VIS_ACTION_TEXT_OBJECT_QUOTE_INNER
,
310 VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_OUTER
,
311 VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_INNER
,
312 VIS_ACTION_TEXT_OBJECT_BACKTICK_OUTER
,
313 VIS_ACTION_TEXT_OBJECT_BACKTICK_INNER
,
314 VIS_ACTION_TEXT_OBJECT_ENTIRE_OUTER
,
315 VIS_ACTION_TEXT_OBJECT_ENTIRE_INNER
,
316 VIS_ACTION_TEXT_OBJECT_LINE_OUTER
,
317 VIS_ACTION_TEXT_OBJECT_LINE_INNER
,
318 VIS_ACTION_TEXT_OBJECT_INDENTATION
,
319 VIS_ACTION_TEXT_OBJECT_SEARCH_FORWARD
,
320 VIS_ACTION_TEXT_OBJECT_SEARCH_BACKWARD
,
321 VIS_ACTION_MOTION_CHARWISE
,
322 VIS_ACTION_MOTION_LINEWISE
,
323 VIS_ACTION_UNICODE_INFO
,
324 VIS_ACTION_UTF8_INFO
,
328 static const KeyAction vis_action
[] = {
329 [VIS_ACTION_EDITOR_SUSPEND
] = {
331 VIS_HELP("Suspend the editor")
334 [VIS_ACTION_CURSOR_CHAR_PREV
] = {
335 "vis-motion-char-prev",
336 VIS_HELP("Move cursor left, to the previous character")
337 movement
, { .i
= VIS_MOVE_CHAR_PREV
}
339 [VIS_ACTION_CURSOR_CHAR_NEXT
] = {
340 "vis-motion-char-next",
341 VIS_HELP("Move cursor right, to the next character")
342 movement
, { .i
= VIS_MOVE_CHAR_NEXT
}
344 [VIS_ACTION_CURSOR_LINE_CHAR_PREV
] = {
345 "vis-motion-line-char-prev",
346 VIS_HELP("Move cursor left, to the previous character on the same line")
347 movement
, { .i
= VIS_MOVE_LINE_CHAR_PREV
}
349 [VIS_ACTION_CURSOR_LINE_CHAR_NEXT
] = {
350 "vis-motion-line-char-next",
351 VIS_HELP("Move cursor right, to the next character on the same line")
352 movement
, { .i
= VIS_MOVE_LINE_CHAR_NEXT
}
354 [VIS_ACTION_CURSOR_CODEPOINT_PREV
] = {
355 "vis-motion-codepoint-prev",
356 VIS_HELP("Move to the previous Unicode codepoint")
357 movement
, { .i
= VIS_MOVE_CODEPOINT_PREV
}
359 [VIS_ACTION_CURSOR_CODEPOINT_NEXT
] = {
360 "vis-motion-codepoint-next",
361 VIS_HELP("Move to the next Unicode codepoint")
362 movement
, { .i
= VIS_MOVE_CODEPOINT_NEXT
}
364 [VIS_ACTION_CURSOR_WORD_START_PREV
] = {
365 "vis-motion-word-start-prev",
366 VIS_HELP("Move cursor words backwards")
367 movement
, { .i
= VIS_MOVE_WORD_START_PREV
}
369 [VIS_ACTION_CURSOR_WORD_START_NEXT
] = {
370 "vis-motion-word-start-next",
371 VIS_HELP("Move cursor words forwards")
372 movement
, { .i
= VIS_MOVE_WORD_START_NEXT
}
374 [VIS_ACTION_CURSOR_WORD_END_PREV
] = {
375 "vis-motion-word-end-prev",
376 VIS_HELP("Move cursor backwards to the end of word")
377 movement
, { .i
= VIS_MOVE_WORD_END_PREV
}
379 [VIS_ACTION_CURSOR_WORD_END_NEXT
] = {
380 "vis-motion-word-end-next",
381 VIS_HELP("Move cursor forward to the end of word")
382 movement
, { .i
= VIS_MOVE_WORD_END_NEXT
}
384 [VIS_ACTION_CURSOR_LONGWORD_START_PREV
] = {
385 "vis-motion-bigword-start-prev",
386 VIS_HELP("Move cursor WORDS backwards")
387 movement
, { .i
= VIS_MOVE_LONGWORD_START_PREV
}
389 [VIS_ACTION_CURSOR_LONGWORD_START_NEXT
] = {
390 "vis-motion-bigword-start-next",
391 VIS_HELP("Move cursor WORDS forwards")
392 movement
, { .i
= VIS_MOVE_LONGWORD_START_NEXT
}
394 [VIS_ACTION_CURSOR_LONGWORD_END_PREV
] = {
395 "vis-motion-bigword-end-prev",
396 VIS_HELP("Move cursor backwards to the end of WORD")
397 movement
, { .i
= VIS_MOVE_LONGWORD_END_PREV
}
399 [VIS_ACTION_CURSOR_LONGWORD_END_NEXT
] = {
400 "vis-motion-bigword-end-next",
401 VIS_HELP("Move cursor forward to the end of WORD")
402 movement
, { .i
= VIS_MOVE_LONGWORD_END_NEXT
}
404 [VIS_ACTION_CURSOR_LINE_UP
] = {
405 "vis-motion-line-up",
406 VIS_HELP("Move cursor line upwards")
407 movement
, { .i
= VIS_MOVE_LINE_UP
}
409 [VIS_ACTION_CURSOR_LINE_DOWN
] = {
410 "vis-motion-line-down",
411 VIS_HELP("Move cursor line downwards")
412 movement
, { .i
= VIS_MOVE_LINE_DOWN
}
414 [VIS_ACTION_CURSOR_LINE_START
] = {
415 "vis-motion-line-start",
416 VIS_HELP("Move cursor to first non-blank character of the line")
417 movement
, { .i
= VIS_MOVE_LINE_START
}
419 [VIS_ACTION_CURSOR_LINE_FINISH
] = {
420 "vis-motion-line-finish",
421 VIS_HELP("Move cursor to last non-blank character of the line")
422 movement
, { .i
= VIS_MOVE_LINE_FINISH
}
424 [VIS_ACTION_CURSOR_LINE_BEGIN
] = {
425 "vis-motion-line-begin",
426 VIS_HELP("Move cursor to first character of the line")
427 movement
, { .i
= VIS_MOVE_LINE_BEGIN
}
429 [VIS_ACTION_CURSOR_LINE_END
] = {
430 "vis-motion-line-end",
431 VIS_HELP("Move cursor to end of the line")
432 movement
, { .i
= VIS_MOVE_LINE_END
}
434 [VIS_ACTION_CURSOR_SCREEN_LINE_UP
] = {
435 "vis-motion-screenline-up",
436 VIS_HELP("Move cursor screen/display line upwards")
437 movement
, { .i
= VIS_MOVE_SCREEN_LINE_UP
}
439 [VIS_ACTION_CURSOR_SCREEN_LINE_DOWN
] = {
440 "vis-motion-screenline-down",
441 VIS_HELP("Move cursor screen/display line downwards")
442 movement
, { .i
= VIS_MOVE_SCREEN_LINE_DOWN
}
444 [VIS_ACTION_CURSOR_SCREEN_LINE_BEGIN
] = {
445 "vis-motion-screenline-begin",
446 VIS_HELP("Move cursor to beginning of screen/display line")
447 movement
, { .i
= VIS_MOVE_SCREEN_LINE_BEGIN
}
449 [VIS_ACTION_CURSOR_SCREEN_LINE_MIDDLE
] = {
450 "vis-motion-screenline-middle",
451 VIS_HELP("Move cursor to middle of screen/display line")
452 movement
, { .i
= VIS_MOVE_SCREEN_LINE_MIDDLE
}
454 [VIS_ACTION_CURSOR_SCREEN_LINE_END
] = {
455 "vis-motion-screenline-end",
456 VIS_HELP("Move cursor to end of screen/display line")
457 movement
, { .i
= VIS_MOVE_SCREEN_LINE_END
}
459 [VIS_ACTION_CURSOR_PERCENT
] = {
460 "vis-motion-percent",
461 VIS_HELP("Move to count % of file or matching item")
464 [VIS_ACTION_CURSOR_BYTE
] = {
466 VIS_HELP("Move to absolute byte position")
467 movement
, { .i
= VIS_MOVE_BYTE
}
469 [VIS_ACTION_CURSOR_BYTE_LEFT
] = {
470 "vis-motion-byte-left",
471 VIS_HELP("Move count bytes to the left")
472 movement
, { .i
= VIS_MOVE_BYTE_LEFT
}
474 [VIS_ACTION_CURSOR_BYTE_RIGHT
] = {
475 "vis-motion-byte-right",
476 VIS_HELP("Move count bytes to the right")
477 movement
, { .i
= VIS_MOVE_BYTE_RIGHT
}
479 [VIS_ACTION_CURSOR_PARAGRAPH_PREV
] = {
480 "vis-motion-paragraph-prev",
481 VIS_HELP("Move cursor paragraph backward")
482 movement
, { .i
= VIS_MOVE_PARAGRAPH_PREV
}
484 [VIS_ACTION_CURSOR_PARAGRAPH_NEXT
] = {
485 "vis-motion-paragraph-next",
486 VIS_HELP("Move cursor paragraph forward")
487 movement
, { .i
= VIS_MOVE_PARAGRAPH_NEXT
}
489 [VIS_ACTION_CURSOR_SENTENCE_PREV
] = {
490 "vis-motion-sentence-prev",
491 VIS_HELP("Move cursor sentence backward")
492 movement
, { .i
= VIS_MOVE_SENTENCE_PREV
}
494 [VIS_ACTION_CURSOR_SENTENCE_NEXT
] = {
495 "vis-motion-sentence-next",
496 VIS_HELP("Move cursor sentence forward")
497 movement
, { .i
= VIS_MOVE_SENTENCE_NEXT
}
499 [VIS_ACTION_CURSOR_BLOCK_START
] = {
500 "vis-motion-block-start",
501 VIS_HELP("Move cursor to the opening curly brace in a block")
502 movement
, { .i
= VIS_MOVE_BLOCK_START
}
504 [VIS_ACTION_CURSOR_BLOCK_END
] = {
505 "vis-motion-block-end",
506 VIS_HELP("Move cursor to the closing curly brace in a block")
507 movement
, { .i
= VIS_MOVE_BLOCK_END
}
509 [VIS_ACTION_CURSOR_PARENTHESE_START
] = {
510 "vis-motion-parenthese-start",
511 VIS_HELP("Move cursor to the opening parenthese inside a pair of parentheses")
512 movement
, { .i
= VIS_MOVE_PARENTHESE_START
}
514 [VIS_ACTION_CURSOR_PARENTHESE_END
] = {
515 "vis-motion-parenthese-end",
516 VIS_HELP("Move cursor to the closing parenthese inside a pair of parentheses")
517 movement
, { .i
= VIS_MOVE_PARENTHESE_END
}
519 [VIS_ACTION_CURSOR_COLUMN
] = {
521 VIS_HELP("Move cursor to given column of current line")
522 movement
, { .i
= VIS_MOVE_COLUMN
}
524 [VIS_ACTION_CURSOR_LINE_FIRST
] = {
525 "vis-motion-line-first",
526 VIS_HELP("Move cursor to given line (defaults to first)")
527 gotoline
, { .i
= -1 }
529 [VIS_ACTION_CURSOR_LINE_LAST
] = {
530 "vis-motion-line-last",
531 VIS_HELP("Move cursor to given line (defaults to last)")
532 gotoline
, { .i
= +1 }
534 [VIS_ACTION_CURSOR_WINDOW_LINE_TOP
] = {
535 "vis-motion-window-line-top",
536 VIS_HELP("Move cursor to top line of the window")
537 movement
, { .i
= VIS_MOVE_WINDOW_LINE_TOP
}
539 [VIS_ACTION_CURSOR_WINDOW_LINE_MIDDLE
] = {
540 "vis-motion-window-line-middle",
541 VIS_HELP("Move cursor to middle line of the window")
542 movement
, { .i
= VIS_MOVE_WINDOW_LINE_MIDDLE
}
544 [VIS_ACTION_CURSOR_WINDOW_LINE_BOTTOM
] = {
545 "vis-motion-window-line-bottom",
546 VIS_HELP("Move cursor to bottom line of the window")
547 movement
, { .i
= VIS_MOVE_WINDOW_LINE_BOTTOM
}
549 [VIS_ACTION_CURSOR_SEARCH_REPEAT_FORWARD
] = {
550 "vis-motion-search-repeat-forward",
551 VIS_HELP("Move cursor to next match in forward direction")
552 movement
, { .i
= VIS_MOVE_SEARCH_REPEAT_FORWARD
}
554 [VIS_ACTION_CURSOR_SEARCH_REPEAT_BACKWARD
] = {
555 "vis-motion-search-repeat-backward",
556 VIS_HELP("Move cursor to previous match in backward direction")
557 movement
, { .i
= VIS_MOVE_SEARCH_REPEAT_BACKWARD
}
559 [VIS_ACTION_CURSOR_SEARCH_REPEAT
] = {
560 "vis-motion-search-repeat",
561 VIS_HELP("Move cursor to next match")
562 movement
, { .i
= VIS_MOVE_SEARCH_REPEAT
}
564 [VIS_ACTION_CURSOR_SEARCH_REPEAT_REVERSE
] = {
565 "vis-motion-search-repeat-reverse",
566 VIS_HELP("Move cursor to next match in opposite direction")
567 movement
, { .i
= VIS_MOVE_SEARCH_REPEAT_REVERSE
}
569 [VIS_ACTION_CURSOR_SEARCH_WORD_FORWARD
] = {
570 "vis-motion-search-word-forward",
571 VIS_HELP("Move cursor to next occurrence of the word under cursor")
572 movement
, { .i
= VIS_MOVE_SEARCH_WORD_FORWARD
}
574 [VIS_ACTION_CURSOR_SEARCH_WORD_BACKWARD
] = {
575 "vis-motion-search-word-backward",
576 VIS_HELP("Move cursor to previous occurrence of the word under cursor")
577 movement
, { .i
= VIS_MOVE_SEARCH_WORD_BACKWARD
}
579 [VIS_ACTION_WINDOW_PAGE_UP
] = {
580 "vis-window-page-up",
581 VIS_HELP("Scroll window pages backwards (upwards)")
582 wscroll
, { .i
= -PAGE
}
584 [VIS_ACTION_WINDOW_HALFPAGE_UP
] = {
585 "vis-window-halfpage-up",
586 VIS_HELP("Scroll window half pages backwards (upwards)")
587 wscroll
, { .i
= -PAGE_HALF
}
589 [VIS_ACTION_WINDOW_PAGE_DOWN
] = {
590 "vis-window-page-down",
591 VIS_HELP("Scroll window pages forwards (downwards)")
592 wscroll
, { .i
= +PAGE
}
594 [VIS_ACTION_WINDOW_HALFPAGE_DOWN
] = {
595 "vis-window-halfpage-down",
596 VIS_HELP("Scroll window half pages forwards (downwards)")
597 wscroll
, { .i
= +PAGE_HALF
}
599 [VIS_ACTION_MODE_NORMAL
] = {
601 VIS_HELP("Enter normal mode")
602 switchmode
, { .i
= VIS_MODE_NORMAL
}
604 [VIS_ACTION_MODE_VISUAL
] = {
605 "vis-mode-visual-charwise",
606 VIS_HELP("Enter characterwise visual mode")
607 switchmode
, { .i
= VIS_MODE_VISUAL
}
609 [VIS_ACTION_MODE_VISUAL_LINE
] = {
610 "vis-mode-visual-linewise",
611 VIS_HELP("Enter linewise visual mode")
612 switchmode
, { .i
= VIS_MODE_VISUAL_LINE
}
614 [VIS_ACTION_MODE_INSERT
] = {
616 VIS_HELP("Enter insert mode")
617 insertmode
, { .i
= VIS_MOVE_NOP
}
619 [VIS_ACTION_MODE_REPLACE
] = {
621 VIS_HELP("Enter replace mode")
622 replacemode
, { .i
= VIS_MOVE_NOP
}
624 [VIS_ACTION_DELETE_CHAR_PREV
] = {
625 "vis-delete-char-prev",
626 VIS_HELP("Delete the previous character")
627 delete, { .i
= VIS_MOVE_CHAR_PREV
}
629 [VIS_ACTION_DELETE_CHAR_NEXT
] = {
630 "vis-delete-char-next",
631 VIS_HELP("Delete the next character")
632 delete, { .i
= VIS_MOVE_CHAR_NEXT
}
634 [VIS_ACTION_DELETE_LINE_BEGIN
] = {
635 "vis-delete-line-begin",
636 VIS_HELP("Delete until the start of the current line")
637 delete, { .i
= VIS_MOVE_LINE_BEGIN
}
639 [VIS_ACTION_DELETE_WORD_PREV
] = {
640 "vis-delete-word-prev",
641 VIS_HELP("Delete the previous WORD")
642 delete, { .i
= VIS_MOVE_WORD_START_PREV
}
644 [VIS_ACTION_JUMPLIST_PREV
] = {
646 VIS_HELP("Go to older cursor position in jump list")
647 movement
, { .i
= VIS_MOVE_JUMPLIST_PREV
}
649 [VIS_ACTION_JUMPLIST_NEXT
] = {
651 VIS_HELP("Go to newer cursor position in jump list")
652 movement
, { .i
= VIS_MOVE_JUMPLIST_NEXT
}
654 [VIS_ACTION_CHANGELIST_PREV
] = {
655 "vis-changelist-prev",
656 VIS_HELP("Go to older cursor position in change list")
657 movement
, { .i
= VIS_MOVE_CHANGELIST_PREV
}
659 [VIS_ACTION_CHANGELIST_NEXT
] = {
660 "vis-changelist-next",
661 VIS_HELP("Go to newer cursor position in change list")
662 movement
, { .i
= VIS_MOVE_CHANGELIST_NEXT
}
664 [VIS_ACTION_UNDO
] = {
666 VIS_HELP("Undo last change")
669 [VIS_ACTION_REDO
] = {
671 VIS_HELP("Redo last change")
674 [VIS_ACTION_EARLIER
] = {
676 VIS_HELP("Goto older text state")
679 [VIS_ACTION_LATER
] = {
681 VIS_HELP("Goto newer text state")
684 [VIS_ACTION_MACRO_RECORD
] = {
686 VIS_HELP("Record macro into given register")
689 [VIS_ACTION_MACRO_REPLAY
] = {
691 VIS_HELP("Replay macro, execute the content of the given register")
694 [VIS_ACTION_MARK_SET
] = {
696 VIS_HELP("Set given mark at current cursor position")
699 [VIS_ACTION_MARK_GOTO
] = {
701 VIS_HELP("Goto the position of the given mark")
702 mark_motion
, { .i
= VIS_MOVE_MARK
}
704 [VIS_ACTION_MARK_GOTO_LINE
] = {
705 "vis-mark-goto-line",
706 VIS_HELP("Goto first non-blank character of the line containing the given mark")
707 mark_motion
, { .i
= VIS_MOVE_MARK_LINE
}
709 [VIS_ACTION_REDRAW
] = {
711 VIS_HELP("Redraw current editor content")
712 call
, { .f
= vis_redraw
}
714 [VIS_ACTION_REPLACE_CHAR
] = {
716 VIS_HELP("Replace the character under the cursor")
719 [VIS_ACTION_TOTILL_REPEAT
] = {
720 "vis-motion-totill-repeat",
721 VIS_HELP("Repeat latest to/till motion")
722 movement
, { .i
= VIS_MOVE_TOTILL_REPEAT
}
724 [VIS_ACTION_TOTILL_REVERSE
] = {
725 "vis-motion-totill-reverse",
726 VIS_HELP("Repeat latest to/till motion but in opposite direction")
727 movement
, { .i
= VIS_MOVE_TOTILL_REVERSE
}
729 [VIS_ACTION_PROMPT_SEARCH_FORWARD
] = {
730 "vis-search-forward",
731 VIS_HELP("Search forward")
732 prompt_show
, { .s
= "/" }
734 [VIS_ACTION_PROMPT_SEARCH_BACKWARD
] = {
735 "vis-search-backward",
736 VIS_HELP("Search backward")
737 prompt_show
, { .s
= "?" }
739 [VIS_ACTION_TILL_LEFT
] = {
740 "vis-motion-till-left",
741 VIS_HELP("Till after the occurrence of character to the left")
742 movement_key
, { .i
= VIS_MOVE_LEFT_TILL
}
744 [VIS_ACTION_TILL_RIGHT
] = {
745 "vis-motion-till-right",
746 VIS_HELP("Till before the occurrence of character to the right")
747 movement_key
, { .i
= VIS_MOVE_RIGHT_TILL
}
749 [VIS_ACTION_TO_LEFT
] = {
750 "vis-motion-to-left",
751 VIS_HELP("To the first occurrence of character to the left")
752 movement_key
, { .i
= VIS_MOVE_LEFT_TO
}
754 [VIS_ACTION_TO_RIGHT
] = {
755 "vis-motion-to-right",
756 VIS_HELP("To the first occurrence of character to the right")
757 movement_key
, { .i
= VIS_MOVE_RIGHT_TO
}
759 [VIS_ACTION_REGISTER
] = {
761 VIS_HELP("Use given register for next operator")
764 [VIS_ACTION_OPERATOR_CHANGE
] = {
765 "vis-operator-change",
766 VIS_HELP("Change operator")
767 operator, { .i
= VIS_OP_CHANGE
}
769 [VIS_ACTION_OPERATOR_DELETE
] = {
770 "vis-operator-delete",
771 VIS_HELP("Delete operator")
772 operator, { .i
= VIS_OP_DELETE
}
774 [VIS_ACTION_OPERATOR_YANK
] = {
776 VIS_HELP("Yank operator")
777 operator, { .i
= VIS_OP_YANK
}
779 [VIS_ACTION_OPERATOR_SHIFT_LEFT
] = {
780 "vis-operator-shift-left",
781 VIS_HELP("Shift left operator")
782 operator, { .i
= VIS_OP_SHIFT_LEFT
}
784 [VIS_ACTION_OPERATOR_SHIFT_RIGHT
] = {
785 "vis-operator-shift-right",
786 VIS_HELP("Shift right operator")
787 operator, { .i
= VIS_OP_SHIFT_RIGHT
}
789 [VIS_ACTION_OPERATOR_CASE_LOWER
] = {
790 "vis-operator-case-lower",
791 VIS_HELP("Lowercase operator")
792 operator, { .i
= VIS_OP_CASE_LOWER
}
794 [VIS_ACTION_OPERATOR_CASE_UPPER
] = {
795 "vis-operator-case-upper",
796 VIS_HELP("Uppercase operator")
797 operator, { .i
= VIS_OP_CASE_UPPER
}
799 [VIS_ACTION_OPERATOR_CASE_SWAP
] = {
800 "vis-operator-case-swap",
801 VIS_HELP("Swap case operator")
802 operator, { .i
= VIS_OP_CASE_SWAP
}
804 [VIS_ACTION_OPERATOR_FILTER
] = {
805 "vis-operator-filter",
806 VIS_HELP("Filter operator")
809 [VIS_ACTION_OPERATOR_FILTER_FMT
] = {
810 "vis-operator-filter-format",
811 VIS_HELP("Formatting operator, filter range through fmt(1)")
812 operator_filter
, { .s
= "|fmt" }
814 [VIS_ACTION_COUNT
] = {
816 VIS_HELP("Count specifier")
819 [VIS_ACTION_INSERT_NEWLINE
] = {
820 "vis-insert-newline",
821 VIS_HELP("Insert a line break (depending on file type)")
822 call
, { .f
= vis_insert_nl
}
824 [VIS_ACTION_INSERT_TAB
] = {
826 VIS_HELP("Insert a tab (might be converted to spaces)")
827 call
, { .f
= vis_insert_tab
}
829 [VIS_ACTION_INSERT_VERBATIM
] = {
830 "vis-insert-verbatim",
831 VIS_HELP("Insert Unicode character based on code point")
834 [VIS_ACTION_INSERT_REGISTER
] = {
835 "vis-insert-register",
836 VIS_HELP("Insert specified register content")
839 [VIS_ACTION_WINDOW_NEXT
] = {
841 VIS_HELP("Focus next window")
842 call
, { .f
= vis_window_next
}
844 [VIS_ACTION_WINDOW_PREV
] = {
846 VIS_HELP("Focus previous window")
847 call
, { .f
= vis_window_prev
}
849 [VIS_ACTION_APPEND_CHAR_NEXT
] = {
850 "vis-append-char-next",
851 VIS_HELP("Append text after the cursor")
852 insertmode
, { .i
= VIS_MOVE_LINE_CHAR_NEXT
}
854 [VIS_ACTION_APPEND_LINE_END
] = {
855 "vis-append-line-end",
856 VIS_HELP("Append text after the end of the line")
857 insertmode
, { .i
= VIS_MOVE_LINE_END
},
859 [VIS_ACTION_INSERT_LINE_START
] = {
860 "vis-insert-line-start",
861 VIS_HELP("Insert text before the first non-blank in the line")
862 insertmode
, { .i
= VIS_MOVE_LINE_START
},
864 [VIS_ACTION_OPEN_LINE_ABOVE
] = {
865 "vis-open-line-above",
866 VIS_HELP("Begin a new line above the cursor")
867 openline
, { .i
= -1 }
869 [VIS_ACTION_OPEN_LINE_BELOW
] = {
870 "vis-open-line-below",
871 VIS_HELP("Begin a new line below the cursor")
872 openline
, { .i
= +1 }
874 [VIS_ACTION_JOIN_LINES
] = {
876 VIS_HELP("Join selected lines")
879 [VIS_ACTION_JOIN_LINES_TRIM
] = {
880 "vis-join-lines-trim",
881 VIS_HELP("Join selected lines, remove white space")
884 [VIS_ACTION_PROMPT_SHOW
] = {
886 VIS_HELP("Show editor command line prompt")
887 prompt_show
, { .s
= ":" }
889 [VIS_ACTION_REPEAT
] = {
891 VIS_HELP("Repeat latest editor command")
894 [VIS_ACTION_SELECTION_FLIP
] = {
895 "vis-selection-flip",
896 VIS_HELP("Flip selection, move cursor to other end")
899 [VIS_ACTION_SELECTION_RESTORE
] = {
900 "vis-selection-restore",
901 VIS_HELP("Restore last selection")
904 [VIS_ACTION_WINDOW_REDRAW_TOP
] = {
905 "vis-window-redraw-top",
906 VIS_HELP("Redraw cursor line at the top of the window")
907 window
, { .w
= view_redraw_top
}
909 [VIS_ACTION_WINDOW_REDRAW_CENTER
] = {
910 "vis-window-redraw-center",
911 VIS_HELP("Redraw cursor line at the center of the window")
912 window
, { .w
= view_redraw_center
}
914 [VIS_ACTION_WINDOW_REDRAW_BOTTOM
] = {
915 "vis-window-redraw-bottom",
916 VIS_HELP("Redraw cursor line at the bottom of the window")
917 window
, { .w
= view_redraw_bottom
}
919 [VIS_ACTION_WINDOW_SLIDE_UP
] = {
920 "vis-window-slide-up",
921 VIS_HELP("Slide window content upwards")
924 [VIS_ACTION_WINDOW_SLIDE_DOWN
] = {
925 "vis-window-slide-down",
926 VIS_HELP("Slide window content downwards")
929 [VIS_ACTION_PUT_AFTER
] = {
931 VIS_HELP("Put text after the cursor")
932 operator, { .i
= VIS_OP_PUT_AFTER
}
934 [VIS_ACTION_PUT_BEFORE
] = {
936 VIS_HELP("Put text before the cursor")
937 operator, { .i
= VIS_OP_PUT_BEFORE
}
939 [VIS_ACTION_PUT_AFTER_END
] = {
941 VIS_HELP("Put text after the cursor, place cursor after new text")
942 operator, { .i
= VIS_OP_PUT_AFTER_END
}
944 [VIS_ACTION_PUT_BEFORE_END
] = {
945 "vis-put-before-end",
946 VIS_HELP("Put text before the cursor, place cursor after new text")
947 operator, { .i
= VIS_OP_PUT_BEFORE_END
}
949 [VIS_ACTION_CURSOR_SELECT_WORD
] = {
950 "vis-cursor-select-word",
951 VIS_HELP("Select word under cursor")
954 [VIS_ACTION_CURSORS_NEW_LINE_ABOVE
] = {
955 "vis-cursor-new-lines-above",
956 VIS_HELP("Create a new cursor on the line above")
957 cursors_new
, { .i
= -1 }
959 [VIS_ACTION_CURSORS_NEW_LINE_ABOVE_FIRST
] = {
960 "vis-cursor-new-lines-above-first",
961 VIS_HELP("Create a new cursor on the line above the first cursor")
962 cursors_new
, { .i
= INT_MIN
}
964 [VIS_ACTION_CURSORS_NEW_LINE_BELOW
] = {
965 "vis-cursor-new-lines-below",
966 VIS_HELP("Create a new cursor on the line below")
967 cursors_new
, { .i
= +1 }
969 [VIS_ACTION_CURSORS_NEW_LINE_BELOW_LAST
] = {
970 "vis-cursor-new-lines-below-last",
971 VIS_HELP("Create a new cursor on the line below the last cursor")
972 cursors_new
, { .i
= INT_MAX
}
974 [VIS_ACTION_CURSORS_NEW_LINES_BEGIN
] = {
975 "vis-cursor-new-lines-begin",
976 VIS_HELP("Create a new cursor at the start of every line covered by selection")
977 operator, { .i
= VIS_OP_CURSOR_SOL
}
979 [VIS_ACTION_CURSORS_NEW_LINES_END
] = {
980 "vis-cursor-new-lines-end",
981 VIS_HELP("Create a new cursor at the end of every line covered by selection")
982 operator, { .i
= VIS_OP_CURSOR_EOL
}
984 [VIS_ACTION_CURSORS_NEW_MATCH_NEXT
] = {
985 "vis-cursor-new-match-next",
986 VIS_HELP("Select the next region matching the current selection")
989 [VIS_ACTION_CURSORS_NEW_MATCH_SKIP
] = {
990 "vis-cursor-new-match-skip",
991 VIS_HELP("Clear current selection, but select next match")
994 [VIS_ACTION_CURSORS_ALIGN
] = {
996 VIS_HELP("Try to align all cursors on the same column")
999 [VIS_ACTION_CURSORS_ALIGN_INDENT_LEFT
] = {
1000 "vis-cursors-align-indent-left",
1001 VIS_HELP("Left align all cursors/selections by inserting spaces")
1002 cursors_align_indent
, { .i
= -1 }
1004 [VIS_ACTION_CURSORS_ALIGN_INDENT_RIGHT
] = {
1005 "vis-cursors-align-indent-right",
1006 VIS_HELP("Right align all cursors/selections by inserting spaces")
1007 cursors_align_indent
, { .i
= +1 }
1009 [VIS_ACTION_CURSORS_REMOVE_ALL
] = {
1010 "vis-cursors-remove-all",
1011 VIS_HELP("Remove all but the primary cursor")
1014 [VIS_ACTION_CURSORS_REMOVE_LAST
] = {
1015 "vis-cursors-remove-last",
1016 VIS_HELP("Remove least recently created cursor")
1019 [VIS_ACTION_CURSORS_REMOVE_COLUMN
] = {
1020 "vis-cursors-remove-column",
1021 VIS_HELP("Remove count cursor column")
1022 cursors_remove_column
, { .i
= 1 }
1024 [VIS_ACTION_CURSORS_REMOVE_COLUMN_EXCEPT
] = {
1025 "vis-cursors-remove-column-except",
1026 VIS_HELP("Remove all but the count cursor column")
1027 cursors_remove_column_except
, { .i
= 1 }
1029 [VIS_ACTION_CURSORS_PREV
] = {
1031 VIS_HELP("Move to the previous cursor")
1032 cursors_navigate
, { .i
= -PAGE_HALF
}
1034 [VIS_ACTION_CURSORS_NEXT
] = {
1036 VIS_HELP("Move to the next cursor")
1037 cursors_navigate
, { .i
= +PAGE_HALF
}
1039 [VIS_ACTION_SELECTIONS_ROTATE_LEFT
] = {
1040 "vis-selections-rotate-left",
1041 VIS_HELP("Rotate selections left")
1042 selections_rotate
, { .i
= -1 }
1044 [VIS_ACTION_SELECTIONS_ROTATE_RIGHT
] = {
1045 "vis-selections-rotate-right",
1046 VIS_HELP("Rotate selections right")
1047 selections_rotate
, { .i
= +1 }
1049 [VIS_ACTION_SELECTIONS_TRIM
] = {
1050 "vis-selections-trim",
1051 VIS_HELP("Remove leading and trailing white space from selections")
1054 [VIS_ACTION_SELECTIONS_SAVE
] = {
1055 "vis-selections-save",
1056 VIS_HELP("Save currently active selections to register")
1059 [VIS_ACTION_SELECTIONS_RESTORE
] = {
1060 "vis-selections-restore",
1061 VIS_HELP("Restore selections from register")
1064 [VIS_ACTION_SELECTIONS_UNION
] = {
1065 "vis-selections-union",
1066 VIS_HELP("Add selections from register")
1069 [VIS_ACTION_SELECTIONS_INTERSECT
] = {
1070 "vis-selections-intersect",
1071 VIS_HELP("Intersect selections with register")
1072 selections_intersect
1074 [VIS_ACTION_SELECTIONS_COMPLEMENT
] = {
1075 "vis-selections-complement",
1076 VIS_HELP("Complement selections")
1077 selections_complement
1079 [VIS_ACTION_TEXT_OBJECT_WORD_OUTER
] = {
1080 "vis-textobject-word-outer",
1081 VIS_HELP("A word leading and trailing whitespace included")
1082 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_WORD
}
1084 [VIS_ACTION_TEXT_OBJECT_WORD_INNER
] = {
1085 "vis-textobject-word-inner",
1086 VIS_HELP("A word leading and trailing whitespace excluded")
1087 textobj
, { .i
= VIS_TEXTOBJECT_INNER_WORD
}
1089 [VIS_ACTION_TEXT_OBJECT_LONGWORD_OUTER
] = {
1090 "vis-textobject-bigword-outer",
1091 VIS_HELP("A WORD leading and trailing whitespace included")
1092 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_LONGWORD
}
1094 [VIS_ACTION_TEXT_OBJECT_LONGWORD_INNER
] = {
1095 "vis-textobject-bigword-inner",
1096 VIS_HELP("A WORD leading and trailing whitespace excluded")
1097 textobj
, { .i
= VIS_TEXTOBJECT_INNER_LONGWORD
}
1099 [VIS_ACTION_TEXT_OBJECT_SENTENCE
] = {
1100 "vis-textobject-sentence",
1101 VIS_HELP("A sentence")
1102 textobj
, { .i
= VIS_TEXTOBJECT_SENTENCE
}
1104 [VIS_ACTION_TEXT_OBJECT_PARAGRAPH
] = {
1105 "vis-textobject-paragraph",
1106 VIS_HELP("A paragraph")
1107 textobj
, { .i
= VIS_TEXTOBJECT_PARAGRAPH
}
1109 [VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_OUTER
] = {
1110 "vis-textobject-square-bracket-outer",
1111 VIS_HELP("[] block (outer variant)")
1112 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_SQUARE_BRACKET
}
1114 [VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_INNER
] = {
1115 "vis-textobject-square-bracket-inner",
1116 VIS_HELP("[] block (inner variant)")
1117 textobj
, { .i
= VIS_TEXTOBJECT_INNER_SQUARE_BRACKET
}
1119 [VIS_ACTION_TEXT_OBJECT_PARANTHESE_OUTER
] = {
1120 "vis-textobject-parentheses-outer",
1121 VIS_HELP("() block (outer variant)")
1122 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_PARANTHESE
}
1124 [VIS_ACTION_TEXT_OBJECT_PARANTHESE_INNER
] = {
1125 "vis-textobject-parentheses-inner",
1126 VIS_HELP("() block (inner variant)")
1127 textobj
, { .i
= VIS_TEXTOBJECT_INNER_PARANTHESE
}
1129 [VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_OUTER
] = {
1130 "vis-textobject-angle-bracket-outer",
1131 VIS_HELP("<> block (outer variant)")
1132 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_ANGLE_BRACKET
}
1134 [VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_INNER
] = {
1135 "vis-textobject-angle-bracket-inner",
1136 VIS_HELP("<> block (inner variant)")
1137 textobj
, { .i
= VIS_TEXTOBJECT_INNER_ANGLE_BRACKET
}
1139 [VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_OUTER
] = {
1140 "vis-textobject-curly-bracket-outer",
1141 VIS_HELP("{} block (outer variant)")
1142 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_CURLY_BRACKET
}
1144 [VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_INNER
] = {
1145 "vis-textobject-curly-bracket-inner",
1146 VIS_HELP("{} block (inner variant)")
1147 textobj
, { .i
= VIS_TEXTOBJECT_INNER_CURLY_BRACKET
}
1149 [VIS_ACTION_TEXT_OBJECT_QUOTE_OUTER
] = {
1150 "vis-textobject-quote-outer",
1151 VIS_HELP("A quoted string, including the quotation marks")
1152 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_QUOTE
}
1154 [VIS_ACTION_TEXT_OBJECT_QUOTE_INNER
] = {
1155 "vis-textobject-quote-inner",
1156 VIS_HELP("A quoted string, excluding the quotation marks")
1157 textobj
, { .i
= VIS_TEXTOBJECT_INNER_QUOTE
}
1159 [VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_OUTER
] = {
1160 "vis-textobject-single-quote-outer",
1161 VIS_HELP("A single quoted string, including the quotation marks")
1162 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_SINGLE_QUOTE
}
1164 [VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_INNER
] = {
1165 "vis-textobject-single-quote-inner",
1166 VIS_HELP("A single quoted string, excluding the quotation marks")
1167 textobj
, { .i
= VIS_TEXTOBJECT_INNER_SINGLE_QUOTE
}
1169 [VIS_ACTION_TEXT_OBJECT_BACKTICK_OUTER
] = {
1170 "vis-textobject-backtick-outer",
1171 VIS_HELP("A backtick delimited string (outer variant)")
1172 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_BACKTICK
}
1174 [VIS_ACTION_TEXT_OBJECT_BACKTICK_INNER
] = {
1175 "vis-textobject-backtick-inner",
1176 VIS_HELP("A backtick delimited string (inner variant)")
1177 textobj
, { .i
= VIS_TEXTOBJECT_INNER_BACKTICK
}
1179 [VIS_ACTION_TEXT_OBJECT_ENTIRE_OUTER
] = {
1180 "vis-textobject-entire-outer",
1181 VIS_HELP("The whole text content")
1182 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_ENTIRE
}
1184 [VIS_ACTION_TEXT_OBJECT_ENTIRE_INNER
] = {
1185 "vis-textobject-entire-inner",
1186 VIS_HELP("The whole text content, except for leading and trailing empty lines")
1187 textobj
, { .i
= VIS_TEXTOBJECT_INNER_ENTIRE
}
1189 [VIS_ACTION_TEXT_OBJECT_LINE_OUTER
] = {
1190 "vis-textobject-line-outer",
1191 VIS_HELP("The whole line")
1192 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_LINE
}
1194 [VIS_ACTION_TEXT_OBJECT_LINE_INNER
] = {
1195 "vis-textobject-line-inner",
1196 VIS_HELP("The whole line, excluding leading and trailing whitespace")
1197 textobj
, { .i
= VIS_TEXTOBJECT_INNER_LINE
}
1199 [VIS_ACTION_TEXT_OBJECT_INDENTATION
] = {
1200 "vis-textobject-indentation",
1201 VIS_HELP("All adjacent lines with the same indentation level as the current one")
1202 textobj
, { .i
= VIS_TEXTOBJECT_INDENTATION
}
1204 [VIS_ACTION_TEXT_OBJECT_SEARCH_FORWARD
] = {
1205 "vis-textobject-search-forward",
1206 VIS_HELP("The next search match in forward direction")
1207 textobj
, { .i
= VIS_TEXTOBJECT_SEARCH_FORWARD
}
1209 [VIS_ACTION_TEXT_OBJECT_SEARCH_BACKWARD
] = {
1210 "vis-textobject-search-backward",
1211 VIS_HELP("The next search match in backward direction")
1212 textobj
, { .i
= VIS_TEXTOBJECT_SEARCH_BACKWARD
}
1214 [VIS_ACTION_MOTION_CHARWISE
] = {
1215 "vis-motion-charwise",
1216 VIS_HELP("Force motion to be charwise")
1217 motiontype
, { .i
= VIS_MOTIONTYPE_CHARWISE
}
1219 [VIS_ACTION_MOTION_LINEWISE
] = {
1220 "vis-motion-linewise",
1221 VIS_HELP("Force motion to be linewise")
1222 motiontype
, { .i
= VIS_MOTIONTYPE_LINEWISE
}
1224 [VIS_ACTION_UNICODE_INFO
] = {
1226 VIS_HELP("Show Unicode codepoint(s) of character under cursor")
1227 unicode_info
, { .i
= VIS_ACTION_UNICODE_INFO
}
1229 [VIS_ACTION_UTF8_INFO
] = {
1231 VIS_HELP("Show UTF-8 encoded codepoint(s) of character under cursor")
1232 unicode_info
, { .i
= VIS_ACTION_UTF8_INFO
}
1234 [VIS_ACTION_NOP
] = {
1236 VIS_HELP("Ignore key, do nothing")
1243 /** key bindings functions */
1245 static const char *nop(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1249 static const char *macro_record(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1250 if (!vis_macro_record_stop(vis
)) {
1254 return vis_keys_next(vis
, keys
);
1255 enum VisRegister reg
= vis_register_from(vis
, keys
[0]);
1256 vis_macro_record(vis
, reg
);
1263 static const char *macro_replay(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1267 return vis_keys_next(vis
, keys
);
1268 enum VisRegister reg
= vis_register_from(vis
, keys
[0]);
1269 vis_macro_replay(vis
, reg
);
1273 static const char *suspend(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1278 static const char *repeat(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1283 static const char *cursors_new(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1284 View
*view
= vis_view(vis
);
1285 VisCountIterator it
= vis_count_iterator_get(vis
, 1);
1286 while (vis_count_iterator_next(&it
)) {
1287 Selection
*sel
= NULL
;
1291 sel
= view_selections_primary_get(view
);
1294 sel
= view_selections(view
);
1297 for (Selection
*s
= view_selections(view
); s
; s
= view_selections_next(s
))
1303 size_t oldpos
= view_cursors_pos(sel
);
1305 view_line_down(sel
);
1306 else if (arg
->i
< 0)
1308 size_t newpos
= view_cursors_pos(sel
);
1309 view_cursors_to(sel
, oldpos
);
1310 Selection
*sel_new
= view_selections_new(view
, newpos
);
1313 sel_new
= view_selections_prev(sel
);
1314 else if (arg
->i
== +1)
1315 sel_new
= view_selections_next(sel
);
1318 view_selections_primary_set(sel_new
);
1320 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
1324 static const char *cursors_align(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1325 View
*view
= vis_view(vis
);
1326 Text
*txt
= vis_text(vis
);
1327 int mincol
= INT_MAX
;
1328 for (Selection
*s
= view_selections(view
); s
; s
= view_selections_next(s
)) {
1329 int col
= view_cursors_cell_get(s
);
1330 if (col
>= 0 && col
< mincol
)
1333 for (Selection
*s
= view_selections(view
); s
; s
= view_selections_next(s
)) {
1334 if (view_cursors_cell_set(s
, mincol
) == -1) {
1335 size_t pos
= view_cursors_pos(s
);
1336 size_t col
= text_line_width_set(txt
, pos
, mincol
);
1337 view_cursors_to(s
, col
);
1343 static const char *cursors_align_indent(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1344 View
*view
= vis_view(vis
);
1345 Text
*txt
= vis_text(vis
);
1346 bool left_align
= arg
->i
< 0;
1347 int columns
= view_selections_column_count(view
);
1349 for (int i
= 0; i
< columns
; i
++) {
1350 int mincol
= INT_MAX
, maxcol
= 0;
1351 for (Selection
*s
= view_selections_column(view
, i
); s
; s
= view_selections_column_next(s
, i
)) {
1352 Filerange sel
= view_selections_get(s
);
1353 size_t pos
= left_align
? sel
.start
: sel
.end
;
1354 int col
= text_line_width_get(txt
, pos
);
1361 size_t len
= maxcol
- mincol
;
1362 char *buf
= malloc(len
+1);
1365 memset(buf
, ' ', len
);
1367 for (Selection
*s
= view_selections_column(view
, i
); s
; s
= view_selections_column_next(s
, i
)) {
1368 Filerange sel
= view_selections_get(s
);
1369 size_t pos
= left_align
? sel
.start
: sel
.end
;
1370 size_t ipos
= sel
.start
;
1371 int col
= text_line_width_get(txt
, pos
);
1373 size_t off
= maxcol
- col
;
1375 text_insert(txt
, ipos
, buf
, off
);
1386 static const char *cursors_clear(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1387 View
*view
= vis_view(vis
);
1388 if (view_selections_count(view
) > 1)
1389 view_selections_dispose_all(view
);
1391 view_selection_clear(view_selections_primary_get(view
));
1395 static const char *cursors_select(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1396 Text
*txt
= vis_text(vis
);
1397 View
*view
= vis_view(vis
);
1398 for (Selection
*s
= view_selections(view
); s
; s
= view_selections_next(s
)) {
1399 Filerange word
= text_object_word(txt
, view_cursors_pos(s
));
1400 if (text_range_valid(&word
))
1401 view_selections_set(s
, &word
);
1403 vis_mode_switch(vis
, VIS_MODE_VISUAL
);
1407 static const char *cursors_select_next(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1408 Text
*txt
= vis_text(vis
);
1409 View
*view
= vis_view(vis
);
1410 Selection
*s
= view_selections_primary_get(view
);
1411 Filerange sel
= view_selections_get(s
);
1412 if (!text_range_valid(&sel
))
1415 char *buf
= text_bytes_alloc0(txt
, sel
.start
, text_range_size(&sel
));
1418 Filerange word
= text_object_word_find_next(txt
, sel
.end
, buf
);
1419 if (text_range_valid(&word
)) {
1420 size_t pos
= text_char_prev(txt
, word
.end
);
1421 if ((s
= view_selections_new(view
, pos
))) {
1422 view_selections_set(s
, &word
);
1423 view_selections_anchor(s
);
1424 view_selections_primary_set(s
);
1429 sel
= view_selections_get(view_selections(view
));
1430 word
= text_object_word_find_prev(txt
, sel
.start
, buf
);
1431 if (!text_range_valid(&word
))
1433 size_t pos
= text_char_prev(txt
, word
.end
);
1434 if ((s
= view_selections_new(view
, pos
))) {
1435 view_selections_set(s
, &word
);
1436 view_selections_anchor(s
);
1437 view_selections_primary_set(s
);
1445 static const char *cursors_select_skip(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1446 View
*view
= vis_view(vis
);
1447 Selection
*sel
= view_selections_primary_get(view
);
1448 keys
= cursors_select_next(vis
, keys
, arg
);
1449 if (sel
!= view_selections_primary_get(view
))
1450 view_selections_dispose(sel
);
1454 static const char *cursors_remove(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1455 View
*view
= vis_view(vis
);
1456 view_selections_dispose(view_selections_primary_get(view
));
1457 view_cursor_to(view
, view_cursor_get(view
));
1461 static const char *cursors_remove_column(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1462 View
*view
= vis_view(vis
);
1463 int max
= view_selections_column_count(view
);
1464 int column
= vis_count_get_default(vis
, arg
->i
) - 1;
1467 if (view_selections_count(view
) == 1) {
1468 vis_mode_switch(vis
, VIS_MODE_NORMAL
);
1472 for (Selection
*s
= view_selections_column(view
, column
), *next
; s
; s
= next
) {
1473 next
= view_selections_column_next(s
, column
);
1474 view_selections_dispose(s
);
1477 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
1481 static const char *cursors_remove_column_except(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1482 View
*view
= vis_view(vis
);
1483 int max
= view_selections_column_count(view
);
1484 int column
= vis_count_get_default(vis
, arg
->i
) - 1;
1487 if (view_selections_count(view
) == 1) {
1492 Selection
*sel
= view_selections(view
);
1493 Selection
*col
= view_selections_column(view
, column
);
1494 for (Selection
*next
; sel
; sel
= next
) {
1495 next
= view_selections_next(sel
);
1497 col
= view_selections_column_next(col
, column
);
1499 view_selections_dispose(sel
);
1502 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
1506 static const char *cursors_navigate(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1507 View
*view
= vis_view(vis
);
1508 if (view_selections_count(view
) == 1)
1509 return wscroll(vis
, keys
, arg
);
1510 Selection
*s
= view_selections_primary_get(view
);
1511 VisCountIterator it
= vis_count_iterator_get(vis
, 1);
1512 while (vis_count_iterator_next(&it
)) {
1514 s
= view_selections_next(s
);
1516 s
= view_selections(view
);
1518 s
= view_selections_prev(s
);
1520 s
= view_selections(view
);
1521 for (Selection
*n
= s
; n
; n
= view_selections_next(n
))
1526 view_selections_primary_set(s
);
1527 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
1531 static const char *selections_rotate(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1540 Text
*txt
= vis_text(vis
);
1541 View
*view
= vis_view(vis
);
1542 int columns
= view_selections_column_count(view
);
1543 int selections
= columns
== 1 ? view_selections_count(view
) : columns
;
1544 int count
= vis_count_get_default(vis
, 1);
1545 array_init_sized(&arr
, sizeof(Rotate
));
1546 if (!array_reserve(&arr
, selections
))
1550 for (Selection
*s
= view_selections(view
), *next
; s
; s
= next
) {
1551 next
= view_selections_next(s
);
1552 size_t line_next
= 0;
1554 Filerange sel
= view_selections_get(s
);
1557 rot
.len
= text_range_size(&sel
);
1558 if ((rot
.data
= malloc(rot
.len
)))
1559 rot
.len
= text_bytes_get(txt
, sel
.start
, rot
.len
, rot
.data
);
1562 array_add(&arr
, &rot
);
1565 line
= text_lineno_by_pos(txt
, view_cursors_pos(s
));
1567 line_next
= text_lineno_by_pos(txt
, view_cursors_pos(next
));
1568 if (!next
|| (columns
> 1 && line
!= line_next
)) {
1569 size_t len
= array_length(&arr
);
1570 size_t off
= arg
->i
> 0 ? count
% len
: len
- (count
% len
);
1571 for (size_t i
= 0; i
< len
; i
++) {
1572 size_t j
= (i
+ off
) % len
;
1573 Rotate
*oldrot
= array_get(&arr
, i
);
1574 Rotate
*newrot
= array_get(&arr
, j
);
1575 if (!oldrot
|| !newrot
|| oldrot
== newrot
)
1577 Filerange newsel
= view_selections_get(newrot
->sel
);
1578 if (!text_range_valid(&newsel
))
1580 if (!text_delete_range(txt
, &newsel
))
1582 if (!text_insert(txt
, newsel
.start
, oldrot
->data
, oldrot
->len
))
1584 newsel
.end
= newsel
.start
+ oldrot
->len
;
1585 view_selections_set(newrot
->sel
, &newsel
);
1593 array_release(&arr
);
1594 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
1598 static const char *selections_trim(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1599 Text
*txt
= vis_text(vis
);
1600 View
*view
= vis_view(vis
);
1601 for (Selection
*s
= view_selections(view
), *next
; s
; s
= next
) {
1602 next
= view_selections_next(s
);
1603 Filerange sel
= view_selections_get(s
);
1604 if (!text_range_valid(&sel
))
1606 for (char b
; sel
.start
< sel
.end
&& text_byte_get(txt
, sel
.end
-1, &b
)
1607 && isspace((unsigned char)b
); sel
.end
--);
1608 for (char b
; sel
.start
<= sel
.end
&& text_byte_get(txt
, sel
.start
, &b
)
1609 && isspace((unsigned char)b
); sel
.start
++);
1610 if (sel
.start
< sel
.end
) {
1611 view_selections_set(s
, &sel
);
1612 } else if (!view_selections_dispose(s
)) {
1613 vis_mode_switch(vis
, VIS_MODE_NORMAL
);
1619 static const char *selections_save(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1620 View
*view
= vis_view(vis
);
1621 enum VisRegister reg
= vis_register_used(vis
);
1622 Array sel
= view_selections_get_all(view
);
1623 vis_register_selections_set(vis
, reg
, &sel
);
1624 array_release(&sel
);
1629 static const char *selections_restore(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1630 View
*view
= vis_view(vis
);
1631 enum VisRegister reg
= vis_register_used(vis
);
1632 Array sel
= vis_register_selections_get(vis
, reg
);
1633 view_selections_set_all(view
, &sel
);
1634 array_release(&sel
);
1639 static const char *selections_union(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1640 View
*view
= vis_view(vis
);
1641 enum VisRegister reg
= vis_register_used(vis
);
1642 Array a
= vis_register_selections_get(vis
, reg
);
1643 Array b
= view_selections_get_all(view
);
1645 array_init_from(&sel
, &a
);
1647 size_t i
= 0, j
= 0;
1648 Filerange
*r1
= array_get(&a
, i
), *r2
= array_get(&b
, j
), cur
= text_range_empty();
1650 if (r1
&& text_range_overlap(r1
, &cur
)) {
1651 cur
= text_range_union(r1
, &cur
);
1652 r1
= array_get(&a
, ++i
);
1653 } else if (r2
&& text_range_overlap(r2
, &cur
)) {
1654 cur
= text_range_union(r2
, &cur
);
1655 r2
= array_get(&b
, ++j
);
1657 if (text_range_valid(&cur
))
1658 array_add(&sel
, &cur
);
1661 r2
= array_get(&b
, ++j
);
1664 r1
= array_get(&a
, ++i
);
1666 if (r1
->start
< r2
->start
) {
1668 r1
= array_get(&a
, ++i
);
1671 r2
= array_get(&b
, ++j
);
1677 if (text_range_valid(&cur
))
1678 array_add(&sel
, &cur
);
1680 view_selections_set_all(view
, &sel
);
1685 array_release(&sel
);
1690 static void intersect(Array
*ret
, Array
*a
, Array
*b
) {
1691 size_t i
= 0, j
= 0;
1692 Filerange
*r1
= array_get(a
, i
), *r2
= array_get(b
, j
);
1694 if (text_range_overlap(r1
, r2
)) {
1695 Filerange
new = text_range_intersect(r1
, r2
);
1696 array_add(ret
, &new);
1698 if (r1
->end
< r2
->end
)
1699 r1
= array_get(a
, ++i
);
1701 r2
= array_get(b
, ++j
);
1705 static const char *selections_intersect(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1706 View
*view
= vis_view(vis
);
1707 enum VisRegister reg
= vis_register_used(vis
);
1708 Array a
= vis_register_selections_get(vis
, reg
);
1709 Array b
= view_selections_get_all(view
);
1711 array_init_from(&sel
, &a
);
1713 intersect(&sel
, &a
, &b
);
1714 view_selections_set_all(view
, &sel
);
1719 array_release(&sel
);
1724 static void complement(Array
*ret
, Array
*a
, Filerange
*universe
) {
1726 for (size_t i
= 0, len
= array_length(a
); i
< len
; i
++) {
1727 Filerange
*r
= array_get(a
, i
);
1728 if (pos
< r
->start
) {
1729 Filerange
new = text_range_new(pos
, r
->start
);
1730 array_add(ret
, &new);
1734 if (pos
< universe
->end
) {
1735 Filerange
new = text_range_new(pos
, universe
->end
);
1736 array_add(ret
, &new);
1740 static const char *selections_complement(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1741 Text
*txt
= vis_text(vis
);
1742 View
*view
= vis_view(vis
);
1743 Filerange universe
= text_object_entire(txt
, 0);
1744 Array a
= view_selections_get_all(view
);
1746 array_init_from(&sel
, &a
);
1748 complement(&sel
, &a
, &universe
);
1750 view_selections_set_all(view
, &sel
);
1752 array_release(&sel
);
1756 static const char *replace(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1758 vis_keymap_disable(vis
);
1762 const char *next
= vis_keys_next(vis
, keys
);
1766 char replacement
[UTFmax
+1];
1767 if (!vis_keys_utf8(vis
, keys
, replacement
))
1770 if (replacement
[0] == 0x1b) /* <Escape> */
1773 vis_operator(vis
, VIS_OP_REPLACE
, replacement
);
1774 if (vis_mode_get(vis
) == VIS_MODE_OPERATOR_PENDING
)
1775 vis_motion(vis
, VIS_MOVE_CHAR_NEXT
);
1779 static const char *count(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1780 int digit
= keys
[-1] - '0';
1781 int count
= vis_count_get_default(vis
, 0);
1782 if (0 <= digit
&& digit
<= 9) {
1783 if (digit
== 0 && count
== 0)
1784 vis_motion(vis
, VIS_MOVE_LINE_BEGIN
);
1786 vis_count_set(vis
, count
* 10 + digit
);
1791 static const char *gotoline(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1792 if (vis_count_get(vis
) != VIS_COUNT_UNKNOWN
)
1793 vis_motion(vis
, VIS_MOVE_LINE
);
1794 else if (arg
->i
< 0)
1795 vis_motion(vis
, VIS_MOVE_FILE_BEGIN
);
1797 vis_motion(vis
, VIS_MOVE_FILE_END
);
1801 static const char *motiontype(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1802 vis_motion_type(vis
, arg
->i
);
1806 static const char *operator(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1807 vis_operator(vis
, arg
->i
);
1811 static const char *operator_filter(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1812 vis_operator(vis
, VIS_OP_FILTER
, arg
->s
);
1816 static const char *movement_key(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1818 vis_keymap_disable(vis
);
1822 const char *next
= vis_keys_next(vis
, keys
);
1825 char utf8
[UTFmax
+1];
1826 if (vis_keys_utf8(vis
, keys
, utf8
))
1827 vis_motion(vis
, arg
->i
, utf8
);
1831 static const char *movement(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1832 vis_motion(vis
, arg
->i
);
1836 static const char *textobj(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1837 vis_textobject(vis
, arg
->i
);
1841 static const char *selection_end(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1842 for (Selection
*s
= view_selections(vis_view(vis
)); s
; s
= view_selections_next(s
))
1843 view_selections_flip(s
);
1847 static const char *selection_restore(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1848 Text
*txt
= vis_text(vis
);
1849 View
*view
= vis_view(vis
);
1850 for (Selection
*s
= view_selections(view
); s
; s
= view_selections_next(s
))
1851 view_selections_restore(s
);
1852 Filerange sel
= view_selection_get(view
);
1853 if (text_range_is_linewise(txt
, &sel
))
1854 vis_mode_switch(vis
, VIS_MODE_VISUAL_LINE
);
1856 vis_mode_switch(vis
, VIS_MODE_VISUAL
);
1860 static const char *reg(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1864 return vis_keys_next(vis
, keys
);
1865 enum VisRegister reg
= vis_register_from(vis
, keys
[0]);
1866 vis_register(vis
, reg
);
1870 static const char *mark_set(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1874 return vis_keys_next(vis
, keys
);
1875 vis_mark_set(vis
, vis_mark_from(vis
, keys
[0]), view_cursor_get(vis_view(vis
)));
1879 static const char *mark_motion(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1883 return vis_keys_next(vis
, keys
);
1884 vis_motion(vis
, arg
->i
, vis_mark_from(vis
, keys
[0]));
1888 static const char *undo(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1889 size_t pos
= text_undo(vis_text(vis
));
1891 View
*view
= vis_view(vis
);
1892 if (view_selections_count(view
) == 1)
1893 view_cursor_to(view
, pos
);
1894 /* redraw all windows in case some display the same file */
1900 static const char *redo(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1901 size_t pos
= text_redo(vis_text(vis
));
1903 View
*view
= vis_view(vis
);
1904 if (view_selections_count(view
) == 1)
1905 view_cursor_to(view
, pos
);
1906 /* redraw all windows in case some display the same file */
1912 static const char *earlier(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1914 VisCountIterator it
= vis_count_iterator_get(vis
, 1);
1915 while (vis_count_iterator_next(&it
))
1916 pos
= text_earlier(vis_text(vis
));
1918 view_cursor_to(vis_view(vis
), pos
);
1919 /* redraw all windows in case some display the same file */
1925 static const char *later(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1927 VisCountIterator it
= vis_count_iterator_get(vis
, 1);
1928 while (vis_count_iterator_next(&it
))
1929 pos
= text_later(vis_text(vis
));
1931 view_cursor_to(vis_view(vis
), pos
);
1932 /* redraw all windows in case some display the same file */
1938 static const char *delete(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1939 vis_operator(vis
, VIS_OP_DELETE
);
1940 vis_motion(vis
, arg
->i
);
1944 static const char *insert_register(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1948 return vis_keys_next(vis
, keys
);
1949 enum VisRegister reg
= vis_register_from(vis
, keys
[0]);
1950 if (reg
!= VIS_REG_INVALID
) {
1951 vis_register(vis
, reg
);
1952 vis_operator(vis
, VIS_OP_PUT_BEFORE_END
);
1957 static const char *prompt_show(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1958 vis_prompt_show(vis
, arg
->s
);
1962 static const char *insert_verbatim(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1964 char buf
[4], type
= keys
[0];
1965 const char *data
= NULL
;
1966 int len
= 0, count
= 0, base
= 0;
1988 if ('0' <= type
&& type
<= '9') {
1997 for (keys
++; keys
[0] && count
> 0; keys
++, count
--) {
1999 if (base
== 8 && '0' <= keys
[0] && keys
[0] <= '7') {
2001 } else if ((base
== 10 || base
== 16) && '0' <= keys
[0] && keys
[0] <= '9') {
2003 } else if (base
== 16 && 'a' <= keys
[0] && keys
[0] <= 'f') {
2004 v
= 10 + keys
[0] - 'a';
2005 } else if (base
== 16 && 'A' <= keys
[0] && keys
[0] <= 'F') {
2006 v
= 10 + keys
[0] - 'A';
2011 rune
= rune
* base
+ v
;
2016 if (type
== 'u' || type
== 'U') {
2017 len
= runetochar(buf
, &rune
);
2025 const char *next
= vis_keys_next(vis
, keys
);
2028 if ((rune
= vis_keys_codepoint(vis
, keys
)) != (Rune
)-1) {
2029 len
= runetochar(buf
, &rune
);
2032 vis_info_show(vis
, "Unknown key");
2038 vis_insert_key(vis
, data
, len
);
2042 static const char *wscroll(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2043 View
*view
= vis_view(vis
);
2044 int count
= vis_count_get(vis
);
2047 view_scroll_page_up(view
);
2050 view_scroll_page_down(view
);
2053 view_scroll_halfpage_up(view
);
2056 view_scroll_halfpage_down(view
);
2059 if (count
== VIS_COUNT_UNKNOWN
)
2060 count
= arg
->i
< 0 ? -arg
->i
: arg
->i
;
2062 view_scroll_up(view
, count
);
2064 view_scroll_down(view
, count
);
2070 static const char *wslide(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2071 View
*view
= vis_view(vis
);
2072 int count
= vis_count_get(vis
);
2073 if (count
== VIS_COUNT_UNKNOWN
)
2074 count
= arg
->i
< 0 ? -arg
->i
: arg
->i
;
2076 view_slide_down(view
, count
);
2078 view_slide_up(view
, count
);
2082 static const char *call(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2087 static const char *window(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2088 arg
->w(vis_view(vis
));
2092 static const char *openline(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2093 vis_operator(vis
, VIS_OP_MODESWITCH
, VIS_MODE_INSERT
);
2095 vis_motion(vis
, VIS_MOVE_LINE_END
);
2096 vis_keys_feed(vis
, "<Enter>");
2098 if (vis_get_autoindent(vis
)) {
2099 vis_motion(vis
, VIS_MOVE_LINE_START
);
2100 vis_keys_feed(vis
, "<vis-motion-line-start>");
2102 vis_motion(vis
, VIS_MOVE_LINE_BEGIN
);
2103 vis_keys_feed(vis
, "<vis-motion-line-begin>");
2105 vis_keys_feed(vis
, "<Enter><Up>");
2110 static const char *join(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2111 bool normal
= (vis_mode_get(vis
) == VIS_MODE_NORMAL
);
2112 vis_operator(vis
, VIS_OP_JOIN
, arg
->s
);
2114 int count
= vis_count_get_default(vis
, 0);
2116 vis_count_set(vis
, count
-1);
2117 vis_motion(vis
, VIS_MOVE_LINE_NEXT
);
2122 static const char *switchmode(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2123 vis_mode_switch(vis
, arg
->i
);
2127 static const char *insertmode(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2128 vis_operator(vis
, VIS_OP_MODESWITCH
, VIS_MODE_INSERT
);
2129 vis_motion(vis
, arg
->i
);
2133 static const char *replacemode(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2134 vis_operator(vis
, VIS_OP_MODESWITCH
, VIS_MODE_REPLACE
);
2135 vis_motion(vis
, arg
->i
);
2139 static const char *unicode_info(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2140 View
*view
= vis_view(vis
);
2141 Text
*txt
= vis_text(vis
);
2142 size_t start
= view_cursor_get(view
);
2143 size_t end
= text_char_next(txt
, start
);
2144 char *grapheme
= text_bytes_alloc0(txt
, start
, end
-start
), *codepoint
= grapheme
;
2149 mbstate_t ps
= { 0 };
2150 Iterator it
= text_iterator_get(txt
, start
);
2151 for (size_t pos
= start
; it
.pos
< end
; pos
= it
.pos
) {
2152 if (!text_iterator_codepoint_next(&it
, NULL
)) {
2153 vis_info_show(vis
, "Failed to parse code point");
2156 size_t len
= it
.pos
- pos
;
2157 wchar_t wc
= 0xFFFD;
2158 size_t res
= mbrtowc(&wc
, codepoint
, len
, &ps
);
2159 bool combining
= false;
2160 if (res
!= (size_t)-1 && res
!= (size_t)-2)
2161 combining
= (wc
!= L
'\0' && wcwidth(wc
) == 0);
2162 unsigned char ch
= *codepoint
;
2163 if (ch
< 128 && !isprint(ch
))
2164 buffer_appendf(&info
, "<^%c> ", ch
== 127 ? '?' : ch
+ 64);
2166 buffer_appendf(&info
, "<%s%.*s> ", combining
? " " : "", (int)len
, codepoint
);
2167 if (arg
->i
== VIS_ACTION_UNICODE_INFO
) {
2168 buffer_appendf(&info
, "U+%04"PRIX32
" ", (uint32_t)wc
);
2170 for (size_t i
= 0; i
< len
; i
++)
2171 buffer_appendf(&info
, "%02x ", (uint8_t)codepoint
[i
]);
2175 vis_info_show(vis
, "%s", buffer_content0(&info
));
2178 buffer_release(&info
);
2182 static const char *percent(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2183 if (vis_count_get(vis
) == VIS_COUNT_UNKNOWN
)
2184 vis_motion(vis
, VIS_MOVE_BRACKET_MATCH
);
2186 vis_motion(vis
, VIS_MOVE_PERCENT
);
2192 static void signal_handler(int signum
, siginfo_t
*siginfo
, void *context
) {
2193 vis_signal_handler(vis
, signum
, siginfo
, context
);
2196 int main(int argc
, char *argv
[]) {
2199 .init
= vis_lua_init
,
2200 .start
= vis_lua_start
,
2201 .quit
= vis_lua_quit
,
2202 .mode_insert_input
= vis_lua_mode_insert_input
,
2203 .mode_replace_input
= vis_lua_mode_replace_input
,
2204 .file_open
= vis_lua_file_open
,
2205 .file_save_pre
= vis_lua_file_save_pre
,
2206 .file_save_post
= vis_lua_file_save_post
,
2207 .file_close
= vis_lua_file_close
,
2208 .win_open
= vis_lua_win_open
,
2209 .win_close
= vis_lua_win_close
,
2210 .win_highlight
= vis_lua_win_highlight
,
2211 .win_status
= vis_lua_win_status
,
2214 vis
= vis_new(ui_term_new(), &event
);
2216 return EXIT_FAILURE
;
2218 for (int i
= 0; i
< LENGTH(vis_action
); i
++) {
2219 const KeyAction
*action
= &vis_action
[i
];
2220 if (!vis_action_register(vis
, action
))
2221 vis_die(vis
, "Could not register action: %s\n", action
->name
);
2224 for (int i
= 0; i
< LENGTH(default_bindings
); i
++) {
2225 for (const KeyBinding
**binding
= default_bindings
[i
]; binding
&& *binding
; binding
++) {
2226 for (const KeyBinding
*kb
= *binding
; kb
->key
; kb
++) {
2227 vis_mode_map(vis
, i
, false, kb
->key
, kb
);
2232 for (const char **k
= keymaps
; k
[0]; k
+= 2)
2233 vis_keymap_add(vis
, k
[0], k
[1]);
2235 /* install signal handlers etc. */
2236 struct sigaction sa
;
2237 memset(&sa
, 0, sizeof sa
);
2238 sigfillset(&sa
.sa_mask
);
2239 sa
.sa_flags
= SA_SIGINFO
;
2240 sa
.sa_sigaction
= signal_handler
;
2241 if (sigaction(SIGBUS
, &sa
, NULL
) == -1 ||
2242 sigaction(SIGINT
, &sa
, NULL
) == -1 ||
2243 sigaction(SIGCONT
, &sa
, NULL
) == -1 ||
2244 sigaction(SIGWINCH
, &sa
, NULL
) == -1 ||
2245 sigaction(SIGTERM
, &sa
, NULL
) == -1 ||
2246 sigaction(SIGHUP
, &sa
, NULL
) == -1) {
2247 vis_die(vis
, "Failed to set signal handler: %s\n", strerror(errno
));
2250 sa
.sa_handler
= SIG_IGN
;
2251 if (sigaction(SIGPIPE
, &sa
, NULL
) == -1)
2252 vis_die(vis
, "Failed to ignore SIGPIPE\n");
2255 sigemptyset(&blockset
);
2256 sigaddset(&blockset
, SIGBUS
);
2257 sigaddset(&blockset
, SIGCONT
);
2258 sigaddset(&blockset
, SIGWINCH
);
2259 sigaddset(&blockset
, SIGTERM
);
2260 sigaddset(&blockset
, SIGHUP
);
2261 if (sigprocmask(SIG_BLOCK
, &blockset
, NULL
) == -1)
2262 vis_die(vis
, "Failed to block signals\n");
2264 for (int i
= 1; i
< argc
; i
++) {
2265 if (argv
[i
][0] != '-') {
2267 } else if (strcmp(argv
[i
], "-") == 0) {
2269 } else if (strcmp(argv
[i
], "--") == 0) {
2271 } else if (strcmp(argv
[i
], "-v") == 0) {
2272 printf("vis %s%s%s%s%s%s%s\n", VERSION
,
2273 CONFIG_CURSES
? " +curses" : "",
2274 CONFIG_LUA
? " +lua" : "",
2275 CONFIG_LPEG
? " +lpeg" : "",
2276 CONFIG_TRE
? " +tre" : "",
2277 CONFIG_ACL
? " +acl" : "",
2278 CONFIG_SELINUX
? " +selinux" : "");
2281 fprintf(stderr
, "Unknown command option: %s\n", argv
[i
]);
2287 bool end_of_options
= false, win_created
= false;
2289 for (int i
= 1; i
< argc
; i
++) {
2290 if (argv
[i
][0] == '-' && !end_of_options
) {
2291 if (strcmp(argv
[i
], "-") == 0) {
2292 if (!vis_window_new_fd(vis
, STDOUT_FILENO
))
2293 vis_die(vis
, "Can not create empty buffer\n");
2296 Text
*txt
= vis_text(vis
);
2297 while ((len
= read(STDIN_FILENO
, buf
, sizeof buf
)) > 0)
2298 text_insert(txt
, text_size(txt
), buf
, len
);
2300 vis_die(vis
, "Can not read from stdin\n");
2302 int fd
= open("/dev/tty", O_RDWR
);
2304 vis_die(vis
, "Can not reopen stdin\n");
2305 dup2(fd
, STDIN_FILENO
);
2307 } else if (strcmp(argv
[i
], "--") == 0) {
2308 end_of_options
= true;
2311 } else if (argv
[i
][0] == '+' && !end_of_options
) {
2312 cmd
= argv
[i
] + (argv
[i
][1] == '/' || argv
[i
][1] == '?');
2314 } else if (!vis_window_new(vis
, argv
[i
])) {
2315 vis_die(vis
, "Can not load `%s': %s\n", argv
[i
], strerror(errno
));
2319 vis_prompt_cmd(vis
, cmd
);
2324 if (!vis_window(vis
) && !win_created
) {
2325 if (!vis_window_new(vis
, NULL
))
2326 vis_die(vis
, "Can not create empty buffer\n");
2328 vis_prompt_cmd(vis
, cmd
);
2331 int status
= vis_run(vis
);