12 #include "text-util.h"
13 #include "text-motions.h"
14 #include "text-objects.h"
20 #define PAGE_HALF (INT_MAX-1)
22 /** functions to be called from keybindings */
23 /* ignore key, do nothing */
24 static const char *nop(Vis
*, const char *keys
, const Arg
*arg
);
25 /* record/replay macro indicated by keys */
26 static const char *macro_record(Vis
*, const char *keys
, const Arg
*arg
);
27 static const char *macro_replay(Vis
*, const char *keys
, const Arg
*arg
);
28 /* temporarily suspend the editor and return to the shell, type 'fg' to get back */
29 static const char *suspend(Vis
*, const char *keys
, const Arg
*arg
);
30 /* switch to mode indicated by arg->i */
31 static const char *switchmode(Vis
*, const char *keys
, const Arg
*arg
);
32 /* switch to insert mode after performing movement indicated by arg->i */
33 static const char *insertmode(Vis
*, const char *keys
, const Arg
*arg
);
34 /* set mark indicated by keys to current cursor position */
35 static const char *mark_set(Vis
*, const char *keys
, const Arg
*arg
);
36 /* add a new line either before or after the one where the cursor currently is */
37 static const char *openline(Vis
*, const char *keys
, const Arg
*arg
);
38 /* join lines from current cursor position to movement indicated by arg */
39 static const char *join(Vis
*, const char *keys
, const Arg
*arg
);
40 /* perform last action i.e. action_prev again */
41 static const char *repeat(Vis
*, const char *keys
, const Arg
*arg
);
42 /* replace character at cursor with one from keys */
43 static const char *replace(Vis
*, const char *keys
, const Arg
*arg
);
44 /* create a new cursor on the previous (arg->i < 0) or next (arg->i > 0) line */
45 static const char *cursors_new(Vis
*, const char *keys
, const Arg
*arg
);
46 /* try to align all cursors on the same column */
47 static const char *cursors_align(Vis
*, const char *keys
, const Arg
*arg
);
48 /* try to align all cursors by inserting the correct amount of white spaces */
49 static const char *cursors_align_indent(Vis
*, const char *keys
, const Arg
*arg
);
50 /* remove all but the primary cursor and their selections */
51 static const char *cursors_clear(Vis
*, const char *keys
, const Arg
*arg
);
52 /* remove the least recently added cursor */
53 static const char *cursors_remove(Vis
*, const char *keys
, const Arg
*arg
);
54 /* remove count (or arg->i)-th cursor column */
55 static const char *cursors_remove_column(Vis
*, const char *keys
, const Arg
*arg
);
56 /* remove all but the count (or arg->i)-th cursor column */
57 static const char *cursors_remove_column_except(Vis
*, const char *keys
, const Arg
*arg
);
58 /* move to the previous (arg->i < 0) or next (arg->i > 0) cursor */
59 static const char *cursors_navigate(Vis
*, const char *keys
, const Arg
*arg
);
60 /* select the word the cursor is currently over */
61 static const char *cursors_select(Vis
*, const char *keys
, const Arg
*arg
);
62 /* select the next region matching the current selection */
63 static const char *cursors_select_next(Vis
*, const char *keys
, const Arg
*arg
);
64 /* clear current selection but select next match */
65 static const char *cursors_select_skip(Vis
*, const char *keys
, const Arg
*arg
);
66 /* rotate selection content count times left (arg->i < 0) or right (arg->i > 0) */
67 static const char *selections_rotate(Vis
*, const char *keys
, const Arg
*arg
);
68 /* remove leading and trailing white spaces from selections */
69 static const char *selections_trim(Vis
*, const char *keys
, const Arg
*arg
);
70 /* adjust current used count according to keys */
71 static const char *count(Vis
*, const char *keys
, const Arg
*arg
);
72 /* move to the count-th line or if not given either to the first (arg->i < 0)
73 * or last (arg->i > 0) line of file */
74 static const char *gotoline(Vis
*, const char *keys
, const Arg
*arg
);
75 /* set motion type either LINEWISE or CHARWISE via arg->i */
76 static const char *motiontype(Vis
*, const char *keys
, const Arg
*arg
);
77 /* make the current action use the operator indicated by arg->i */
78 static const char *operator(Vis
*, const char *keys
, const Arg
*arg
);
79 /* use arg->s as command for the filter operator */
80 static const char *operator_filter(Vis
*, const char *keys
, const Arg
*arg
);
81 /* blocks to read a key and performs movement indicated by arg->i which
82 * should be one of VIS_MOVE_{RIGHT,LEFT}_{TO,TILL} */
83 static const char *movement_key(Vis
*, const char *keys
, const Arg
*arg
);
84 /* perform the movement as indicated by arg->i */
85 static const char *movement(Vis
*, const char *keys
, const Arg
*arg
);
86 /* let the current operator affect the range indicated by the text object arg->i */
87 static const char *textobj(Vis
*, const char *keys
, const Arg
*arg
);
88 /* move to the other end of selected text */
89 static const char *selection_end(Vis
*, const char *keys
, const Arg
*arg
);
90 /* restore least recently used selection */
91 static const char *selection_restore(Vis
*, const char *keys
, const Arg
*arg
);
92 /* use register indicated by keys for the current operator */
93 static const char *reg(Vis
*, const char *keys
, const Arg
*arg
);
94 /* perform arg->i motion with a mark indicated by keys as argument */
95 static const char *mark_motion(Vis
*, const char *keys
, const Arg
*arg
);
96 /* {un,re}do last action, redraw window */
97 static const char *undo(Vis
*, const char *keys
, const Arg
*arg
);
98 static const char *redo(Vis
*, const char *keys
, const Arg
*arg
);
99 /* earlier, later action chronologically, redraw window */
100 static const char *earlier(Vis
*, const char *keys
, const Arg
*arg
);
101 static const char *later(Vis
*, const char *keys
, const Arg
*arg
);
102 /* delete from the current cursor position to the end of
103 * movement as indicated by arg->i */
104 static const char *delete(Vis
*, const char *keys
, const Arg
*arg
);
105 /* insert register content indicated by keys at current cursor position */
106 static const char *insert_register(Vis
*, const char *keys
, const Arg
*arg
);
107 /* show a user prompt to get input with title arg->s */
108 static const char *prompt_show(Vis
*, const char *keys
, const Arg
*arg
);
109 /* blocks to read 3 consecutive digits and inserts the corresponding byte value */
110 static const char *insert_verbatim(Vis
*, const char *keys
, const Arg
*arg
);
111 /* scroll window content according to arg->i which can be either PAGE, PAGE_HALF,
112 * or an arbitrary number of lines. a multiplier overrides what is given in arg->i.
113 * negative values scroll back, positive forward. */
114 static const char *wscroll(Vis
*, const char *keys
, const Arg
*arg
);
115 /* similar to scroll, but do only move window content not cursor position */
116 static const char *wslide(Vis
*, const char *keys
, const Arg
*arg
);
117 /* call editor function as indicated by arg->f */
118 static const char *call(Vis
*, const char *keys
, const Arg
*arg
);
119 /* call window function as indicated by arg->w */
120 static const char *window(Vis
*, const char *keys
, const Arg
*arg
);
121 /* show info about Unicode character at cursor position */
122 static const char *unicode_info(Vis
*, const char *keys
, const Arg
*arg
);
123 /* either go to count % of ile or to matching item */
124 static const char *percent(Vis
*, const char *keys
, const Arg
*arg
);
125 /* either increment (arg->i > 0) or decrement (arg->i < 0) number under cursor */
126 static const char *number_increment_decrement(Vis
*, const char *keys
, const Arg
*arg
);
127 /* open a filename under cursor in same (!arg->b) or new (arg->b) window */
128 static const char *open_file_under_cursor(Vis
*, const char *keys
, const Arg
*arg
);
131 VIS_ACTION_EDITOR_SUSPEND
,
132 VIS_ACTION_CURSOR_CHAR_PREV
,
133 VIS_ACTION_CURSOR_CHAR_NEXT
,
134 VIS_ACTION_CURSOR_LINE_CHAR_PREV
,
135 VIS_ACTION_CURSOR_LINE_CHAR_NEXT
,
136 VIS_ACTION_CURSOR_WORD_START_PREV
,
137 VIS_ACTION_CURSOR_WORD_START_NEXT
,
138 VIS_ACTION_CURSOR_WORD_END_PREV
,
139 VIS_ACTION_CURSOR_WORD_END_NEXT
,
140 VIS_ACTION_CURSOR_LONGWORD_START_PREV
,
141 VIS_ACTION_CURSOR_LONGWORD_START_NEXT
,
142 VIS_ACTION_CURSOR_LONGWORD_END_PREV
,
143 VIS_ACTION_CURSOR_LONGWORD_END_NEXT
,
144 VIS_ACTION_CURSOR_LINE_UP
,
145 VIS_ACTION_CURSOR_LINE_DOWN
,
146 VIS_ACTION_CURSOR_LINE_START
,
147 VIS_ACTION_CURSOR_LINE_FINISH
,
148 VIS_ACTION_CURSOR_LINE_BEGIN
,
149 VIS_ACTION_CURSOR_LINE_END
,
150 VIS_ACTION_CURSOR_LINE_LASTCHAR
,
151 VIS_ACTION_CURSOR_SCREEN_LINE_UP
,
152 VIS_ACTION_CURSOR_SCREEN_LINE_DOWN
,
153 VIS_ACTION_CURSOR_SCREEN_LINE_BEGIN
,
154 VIS_ACTION_CURSOR_SCREEN_LINE_MIDDLE
,
155 VIS_ACTION_CURSOR_SCREEN_LINE_END
,
156 VIS_ACTION_CURSOR_PERCENT
,
157 VIS_ACTION_CURSOR_PARAGRAPH_PREV
,
158 VIS_ACTION_CURSOR_PARAGRAPH_NEXT
,
159 VIS_ACTION_CURSOR_SENTENCE_PREV
,
160 VIS_ACTION_CURSOR_SENTENCE_NEXT
,
161 VIS_ACTION_CURSOR_FUNCTION_START_PREV
,
162 VIS_ACTION_CURSOR_FUNCTION_END_PREV
,
163 VIS_ACTION_CURSOR_FUNCTION_START_NEXT
,
164 VIS_ACTION_CURSOR_FUNCTION_END_NEXT
,
165 VIS_ACTION_CURSOR_BLOCK_START
,
166 VIS_ACTION_CURSOR_BLOCK_END
,
167 VIS_ACTION_CURSOR_PARENTHESE_START
,
168 VIS_ACTION_CURSOR_PARENTHESE_END
,
169 VIS_ACTION_CURSOR_COLUMN
,
170 VIS_ACTION_CURSOR_LINE_FIRST
,
171 VIS_ACTION_CURSOR_LINE_LAST
,
172 VIS_ACTION_CURSOR_WINDOW_LINE_TOP
,
173 VIS_ACTION_CURSOR_WINDOW_LINE_MIDDLE
,
174 VIS_ACTION_CURSOR_WINDOW_LINE_BOTTOM
,
175 VIS_ACTION_CURSOR_SEARCH_NEXT
,
176 VIS_ACTION_CURSOR_SEARCH_PREV
,
177 VIS_ACTION_CURSOR_SEARCH_WORD_FORWARD
,
178 VIS_ACTION_CURSOR_SEARCH_WORD_BACKWARD
,
179 VIS_ACTION_WINDOW_PAGE_UP
,
180 VIS_ACTION_WINDOW_PAGE_DOWN
,
181 VIS_ACTION_WINDOW_HALFPAGE_UP
,
182 VIS_ACTION_WINDOW_HALFPAGE_DOWN
,
183 VIS_ACTION_MODE_NORMAL
,
184 VIS_ACTION_MODE_VISUAL
,
185 VIS_ACTION_MODE_VISUAL_LINE
,
186 VIS_ACTION_MODE_INSERT
,
187 VIS_ACTION_MODE_REPLACE
,
188 VIS_ACTION_MODE_OPERATOR_PENDING
,
189 VIS_ACTION_DELETE_CHAR_PREV
,
190 VIS_ACTION_DELETE_CHAR_NEXT
,
191 VIS_ACTION_DELETE_LINE_BEGIN
,
192 VIS_ACTION_DELETE_WORD_PREV
,
193 VIS_ACTION_JUMPLIST_PREV
,
194 VIS_ACTION_JUMPLIST_NEXT
,
195 VIS_ACTION_CHANGELIST_PREV
,
196 VIS_ACTION_CHANGELIST_NEXT
,
201 VIS_ACTION_MACRO_RECORD
,
202 VIS_ACTION_MACRO_REPLAY
,
204 VIS_ACTION_MARK_GOTO
,
205 VIS_ACTION_MARK_GOTO_LINE
,
207 VIS_ACTION_REPLACE_CHAR
,
208 VIS_ACTION_TOTILL_REPEAT
,
209 VIS_ACTION_TOTILL_REVERSE
,
210 VIS_ACTION_PROMPT_SEARCH_FORWARD
,
211 VIS_ACTION_PROMPT_SEARCH_BACKWARD
,
212 VIS_ACTION_TILL_LEFT
,
213 VIS_ACTION_TILL_RIGHT
,
217 VIS_ACTION_OPERATOR_CHANGE
,
218 VIS_ACTION_OPERATOR_DELETE
,
219 VIS_ACTION_OPERATOR_YANK
,
220 VIS_ACTION_OPERATOR_SHIFT_LEFT
,
221 VIS_ACTION_OPERATOR_SHIFT_RIGHT
,
222 VIS_ACTION_OPERATOR_CASE_LOWER
,
223 VIS_ACTION_OPERATOR_CASE_UPPER
,
224 VIS_ACTION_OPERATOR_CASE_SWAP
,
225 VIS_ACTION_OPERATOR_FILTER
,
226 VIS_ACTION_OPERATOR_FILTER_FMT
,
228 VIS_ACTION_INSERT_NEWLINE
,
229 VIS_ACTION_INSERT_TAB
,
230 VIS_ACTION_INSERT_VERBATIM
,
231 VIS_ACTION_INSERT_REGISTER
,
232 VIS_ACTION_WINDOW_NEXT
,
233 VIS_ACTION_WINDOW_PREV
,
234 VIS_ACTION_APPEND_CHAR_NEXT
,
235 VIS_ACTION_APPEND_LINE_END
,
236 VIS_ACTION_INSERT_LINE_START
,
237 VIS_ACTION_OPEN_LINE_ABOVE
,
238 VIS_ACTION_OPEN_LINE_BELOW
,
239 VIS_ACTION_JOIN_LINE_BELOW
,
240 VIS_ACTION_JOIN_LINES
,
241 VIS_ACTION_PROMPT_SHOW
,
243 VIS_ACTION_SELECTION_FLIP
,
244 VIS_ACTION_SELECTION_RESTORE
,
245 VIS_ACTION_WINDOW_REDRAW_TOP
,
246 VIS_ACTION_WINDOW_REDRAW_CENTER
,
247 VIS_ACTION_WINDOW_REDRAW_BOTTOM
,
248 VIS_ACTION_WINDOW_SLIDE_UP
,
249 VIS_ACTION_WINDOW_SLIDE_DOWN
,
250 VIS_ACTION_PUT_AFTER
,
251 VIS_ACTION_PUT_BEFORE
,
252 VIS_ACTION_PUT_AFTER_END
,
253 VIS_ACTION_PUT_BEFORE_END
,
254 VIS_ACTION_CURSOR_SELECT_WORD
,
255 VIS_ACTION_CURSORS_NEW_LINE_ABOVE
,
256 VIS_ACTION_CURSORS_NEW_LINE_ABOVE_FIRST
,
257 VIS_ACTION_CURSORS_NEW_LINE_BELOW
,
258 VIS_ACTION_CURSORS_NEW_LINE_BELOW_LAST
,
259 VIS_ACTION_CURSORS_NEW_LINES_BEGIN
,
260 VIS_ACTION_CURSORS_NEW_LINES_END
,
261 VIS_ACTION_CURSORS_NEW_MATCH_NEXT
,
262 VIS_ACTION_CURSORS_NEW_MATCH_SKIP
,
263 VIS_ACTION_CURSORS_ALIGN
,
264 VIS_ACTION_CURSORS_ALIGN_INDENT_LEFT
,
265 VIS_ACTION_CURSORS_ALIGN_INDENT_RIGHT
,
266 VIS_ACTION_CURSORS_REMOVE_ALL
,
267 VIS_ACTION_CURSORS_REMOVE_LAST
,
268 VIS_ACTION_CURSORS_REMOVE_COLUMN
,
269 VIS_ACTION_CURSORS_REMOVE_COLUMN_EXCEPT
,
270 VIS_ACTION_CURSORS_PREV
,
271 VIS_ACTION_CURSORS_NEXT
,
272 VIS_ACTION_SELECTIONS_ROTATE_LEFT
,
273 VIS_ACTION_SELECTIONS_ROTATE_RIGHT
,
274 VIS_ACTION_SELECTIONS_TRIM
,
275 VIS_ACTION_TEXT_OBJECT_WORD_OUTER
,
276 VIS_ACTION_TEXT_OBJECT_WORD_INNER
,
277 VIS_ACTION_TEXT_OBJECT_LONGWORD_OUTER
,
278 VIS_ACTION_TEXT_OBJECT_LONGWORD_INNER
,
279 VIS_ACTION_TEXT_OBJECT_SENTENCE
,
280 VIS_ACTION_TEXT_OBJECT_PARAGRAPH
,
281 VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_OUTER
,
282 VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_INNER
,
283 VIS_ACTION_TEXT_OBJECT_PARANTHESE_OUTER
,
284 VIS_ACTION_TEXT_OBJECT_PARANTHESE_INNER
,
285 VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_OUTER
,
286 VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_INNER
,
287 VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_OUTER
,
288 VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_INNER
,
289 VIS_ACTION_TEXT_OBJECT_QUOTE_OUTER
,
290 VIS_ACTION_TEXT_OBJECT_QUOTE_INNER
,
291 VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_OUTER
,
292 VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_INNER
,
293 VIS_ACTION_TEXT_OBJECT_BACKTICK_OUTER
,
294 VIS_ACTION_TEXT_OBJECT_BACKTICK_INNER
,
295 VIS_ACTION_TEXT_OBJECT_ENTIRE_OUTER
,
296 VIS_ACTION_TEXT_OBJECT_ENTIRE_INNER
,
297 VIS_ACTION_TEXT_OBJECT_FUNCTION_OUTER
,
298 VIS_ACTION_TEXT_OBJECT_FUNCTION_INNER
,
299 VIS_ACTION_TEXT_OBJECT_LINE_OUTER
,
300 VIS_ACTION_TEXT_OBJECT_LINE_INNER
,
301 VIS_ACTION_TEXT_OBJECT_INDENTATION
,
302 VIS_ACTION_TEXT_OBJECT_SEARCH_FORWARD
,
303 VIS_ACTION_TEXT_OBJECT_SEARCH_BACKWARD
,
304 VIS_ACTION_MOTION_CHARWISE
,
305 VIS_ACTION_MOTION_LINEWISE
,
306 VIS_ACTION_UNICODE_INFO
,
307 VIS_ACTION_NUMBER_INCREMENT
,
308 VIS_ACTION_NUMBER_DECREMENT
,
309 VIS_ACTION_OPEN_FILE_UNDER_CURSOR
,
310 VIS_ACTION_OPEN_FILE_UNDER_CURSOR_NEW_WINDOW
,
314 static const KeyAction vis_action
[] = {
315 [VIS_ACTION_EDITOR_SUSPEND
] = {
317 "Suspend the editor",
320 [VIS_ACTION_CURSOR_CHAR_PREV
] = {
322 "Move cursor left, to the previous character",
323 movement
, { .i
= VIS_MOVE_CHAR_PREV
}
325 [VIS_ACTION_CURSOR_CHAR_NEXT
] = {
327 "Move cursor right, to the next character",
328 movement
, { .i
= VIS_MOVE_CHAR_NEXT
}
330 [VIS_ACTION_CURSOR_LINE_CHAR_PREV
] = {
331 "cursor-line-char-prev",
332 "Move cursor left, to the previous character on the same line",
333 movement
, { .i
= VIS_MOVE_LINE_CHAR_PREV
}
335 [VIS_ACTION_CURSOR_LINE_CHAR_NEXT
] = {
336 "cursor-line-char-next",
337 "Move cursor right, to the next character on the same line",
338 movement
, { .i
= VIS_MOVE_LINE_CHAR_NEXT
}
340 [VIS_ACTION_CURSOR_WORD_START_PREV
] = {
341 "cursor-word-start-prev",
342 "Move cursor words backwards",
343 movement
, { .i
= VIS_MOVE_WORD_START_PREV
}
345 [VIS_ACTION_CURSOR_WORD_START_NEXT
] = {
346 "cursor-word-start-next",
347 "Move cursor words forwards",
348 movement
, { .i
= VIS_MOVE_WORD_START_NEXT
}
350 [VIS_ACTION_CURSOR_WORD_END_PREV
] = {
351 "cursor-word-end-prev",
352 "Move cursor backwards to the end of word",
353 movement
, { .i
= VIS_MOVE_WORD_END_PREV
}
355 [VIS_ACTION_CURSOR_WORD_END_NEXT
] = {
356 "cursor-word-end-next",
357 "Move cursor forward to the end of word",
358 movement
, { .i
= VIS_MOVE_WORD_END_NEXT
}
360 [VIS_ACTION_CURSOR_LONGWORD_START_PREV
] = {
361 "cursor-longword-start-prev",
362 "Move cursor WORDS backwards",
363 movement
, { .i
= VIS_MOVE_LONGWORD_START_PREV
}
365 [VIS_ACTION_CURSOR_LONGWORD_START_NEXT
] = {
366 "cursor-longword-start-next",
367 "Move cursor WORDS forwards",
368 movement
, { .i
= VIS_MOVE_LONGWORD_START_NEXT
}
370 [VIS_ACTION_CURSOR_LONGWORD_END_PREV
] = {
371 "cursor-longword-end-prev",
372 "Move cursor backwards to the end of WORD",
373 movement
, { .i
= VIS_MOVE_LONGWORD_END_PREV
}
375 [VIS_ACTION_CURSOR_LONGWORD_END_NEXT
] = {
376 "cursor-longword-end-next",
377 "Move cursor forward to the end of WORD",
378 movement
, { .i
= VIS_MOVE_LONGWORD_END_NEXT
}
380 [VIS_ACTION_CURSOR_LINE_UP
] = {
382 "Move cursor line upwards",
383 movement
, { .i
= VIS_MOVE_LINE_UP
}
385 [VIS_ACTION_CURSOR_LINE_DOWN
] = {
387 "Move cursor line downwards",
388 movement
, { .i
= VIS_MOVE_LINE_DOWN
}
390 [VIS_ACTION_CURSOR_LINE_START
] = {
392 "Move cursor to first non-blank character of the line",
393 movement
, { .i
= VIS_MOVE_LINE_START
}
395 [VIS_ACTION_CURSOR_LINE_FINISH
] = {
396 "cursor-line-finish",
397 "Move cursor to last non-blank character of the line",
398 movement
, { .i
= VIS_MOVE_LINE_FINISH
}
400 [VIS_ACTION_CURSOR_LINE_BEGIN
] = {
402 "Move cursor to first character of the line",
403 movement
, { .i
= VIS_MOVE_LINE_BEGIN
}
405 [VIS_ACTION_CURSOR_LINE_END
] = {
407 "Move cursor to end of the line",
408 movement
, { .i
= VIS_MOVE_LINE_END
}
410 [VIS_ACTION_CURSOR_LINE_LASTCHAR
] = {
411 "cursor-line-lastchar",
412 "Move cursor to last character of the line",
413 movement
, { .i
= VIS_MOVE_LINE_LASTCHAR
}
415 [VIS_ACTION_CURSOR_SCREEN_LINE_UP
] = {
416 "cursor-screenline-up",
417 "Move cursor screen/display line upwards",
418 movement
, { .i
= VIS_MOVE_SCREEN_LINE_UP
}
420 [VIS_ACTION_CURSOR_SCREEN_LINE_DOWN
] = {
421 "cursor-screenline-down",
422 "Move cursor screen/display line downwards",
423 movement
, { .i
= VIS_MOVE_SCREEN_LINE_DOWN
}
425 [VIS_ACTION_CURSOR_SCREEN_LINE_BEGIN
] = {
426 "cursor-screenline-begin",
427 "Move cursor to beginning of screen/display line",
428 movement
, { .i
= VIS_MOVE_SCREEN_LINE_BEGIN
}
430 [VIS_ACTION_CURSOR_SCREEN_LINE_MIDDLE
] = {
431 "cursor-screenline-middle",
432 "Move cursor to middle of screen/display line",
433 movement
, { .i
= VIS_MOVE_SCREEN_LINE_MIDDLE
}
435 [VIS_ACTION_CURSOR_SCREEN_LINE_END
] = {
436 "cursor-screenline-end",
437 "Move cursor to end of screen/display line",
438 movement
, { .i
= VIS_MOVE_SCREEN_LINE_END
}
440 [VIS_ACTION_CURSOR_PERCENT
] = {
442 "Move to count % of file or matching item",
445 [VIS_ACTION_CURSOR_PARAGRAPH_PREV
] = {
446 "cursor-paragraph-prev",
447 "Move cursor paragraph backward",
448 movement
, { .i
= VIS_MOVE_PARAGRAPH_PREV
}
450 [VIS_ACTION_CURSOR_PARAGRAPH_NEXT
] = {
451 "cursor-paragraph-next",
452 "Move cursor paragraph forward",
453 movement
, { .i
= VIS_MOVE_PARAGRAPH_NEXT
}
455 [VIS_ACTION_CURSOR_SENTENCE_PREV
] = {
456 "cursor-sentence-prev",
457 "Move cursor sentence backward",
458 movement
, { .i
= VIS_MOVE_SENTENCE_PREV
}
460 [VIS_ACTION_CURSOR_SENTENCE_NEXT
] = {
461 "cursor-sentence-next",
462 "Move cursor sentence forward",
463 movement
, { .i
= VIS_MOVE_SENTENCE_NEXT
}
465 [VIS_ACTION_CURSOR_FUNCTION_START_PREV
] = {
466 "cursor-function-start-prev",
467 "Move cursor backwards to start of function",
468 movement
, { .i
= VIS_MOVE_FUNCTION_START_PREV
}
470 [VIS_ACTION_CURSOR_FUNCTION_START_NEXT
] = {
471 "cursor-function-start-next",
472 "Move cursor forwards to start of function",
473 movement
, { .i
= VIS_MOVE_FUNCTION_START_NEXT
}
475 [VIS_ACTION_CURSOR_FUNCTION_END_PREV
] = {
476 "cursor-function-end-prev",
477 "Move cursor backwards to end of function",
478 movement
, { .i
= VIS_MOVE_FUNCTION_END_PREV
}
480 [VIS_ACTION_CURSOR_FUNCTION_END_NEXT
] = {
481 "cursor-function-end-next",
482 "Move cursor forwards to end of function",
483 movement
, { .i
= VIS_MOVE_FUNCTION_END_NEXT
}
485 [VIS_ACTION_CURSOR_BLOCK_START
] = {
486 "cursor-block-start",
487 "Move cursor to the opening curly brace in a block",
488 movement
, { .i
= VIS_MOVE_BLOCK_START
}
490 [VIS_ACTION_CURSOR_BLOCK_END
] = {
492 "Move cursor to the closing curly brace in a block",
493 movement
, { .i
= VIS_MOVE_BLOCK_END
}
495 [VIS_ACTION_CURSOR_PARENTHESE_START
] = {
496 "cursor-parenthese-start",
497 "Move cursor to the opening parenthese inside a pair of parentheses",
498 movement
, { .i
= VIS_MOVE_PARENTHESE_START
}
500 [VIS_ACTION_CURSOR_PARENTHESE_END
] = {
501 "cursor-parenthese-end",
502 "Move cursor to the closing parenthese inside a pair of parentheses",
503 movement
, { .i
= VIS_MOVE_PARENTHESE_END
}
505 [VIS_ACTION_CURSOR_COLUMN
] = {
507 "Move cursor to given column of current line",
508 movement
, { .i
= VIS_MOVE_COLUMN
}
510 [VIS_ACTION_CURSOR_LINE_FIRST
] = {
512 "Move cursor to given line (defaults to first)",
513 gotoline
, { .i
= -1 }
515 [VIS_ACTION_CURSOR_LINE_LAST
] = {
517 "Move cursor to given line (defaults to last)",
518 gotoline
, { .i
= +1 }
520 [VIS_ACTION_CURSOR_WINDOW_LINE_TOP
] = {
521 "cursor-window-line-top",
522 "Move cursor to top line of the window",
523 movement
, { .i
= VIS_MOVE_WINDOW_LINE_TOP
}
525 [VIS_ACTION_CURSOR_WINDOW_LINE_MIDDLE
] = {
526 "cursor-window-line-middle",
527 "Move cursor to middle line of the window",
528 movement
, { .i
= VIS_MOVE_WINDOW_LINE_MIDDLE
}
530 [VIS_ACTION_CURSOR_WINDOW_LINE_BOTTOM
] = {
531 "cursor-window-line-bottom",
532 "Move cursor to bottom line of the window",
533 movement
, { .i
= VIS_MOVE_WINDOW_LINE_BOTTOM
}
535 [VIS_ACTION_CURSOR_SEARCH_NEXT
] = {
536 "cursor-search-forward",
537 "Move cursor to bottom line of the window",
538 movement
, { .i
= VIS_MOVE_SEARCH_NEXT
}
540 [VIS_ACTION_CURSOR_SEARCH_PREV
] = {
541 "cursor-search-backward",
542 "Move cursor to bottom line of the window",
543 movement
, { .i
= VIS_MOVE_SEARCH_PREV
}
545 [VIS_ACTION_CURSOR_SEARCH_WORD_FORWARD
] = {
546 "cursor-search-word-forward",
547 "Move cursor to next occurence of the word under cursor",
548 movement
, { .i
= VIS_MOVE_SEARCH_WORD_FORWARD
}
550 [VIS_ACTION_CURSOR_SEARCH_WORD_BACKWARD
] = {
551 "cursor-search-word-backward",
552 "Move cursor to previous occurence of the word under cursor",
553 movement
, { .i
= VIS_MOVE_SEARCH_WORD_BACKWARD
}
555 [VIS_ACTION_WINDOW_PAGE_UP
] = {
557 "Scroll window pages backwards (upwards)",
558 wscroll
, { .i
= -PAGE
}
560 [VIS_ACTION_WINDOW_HALFPAGE_UP
] = {
561 "window-halfpage-up",
562 "Scroll window half pages backwards (upwards)",
563 wscroll
, { .i
= -PAGE_HALF
}
565 [VIS_ACTION_WINDOW_PAGE_DOWN
] = {
567 "Scroll window pages forwards (downwards)",
568 wscroll
, { .i
= +PAGE
}
570 [VIS_ACTION_WINDOW_HALFPAGE_DOWN
] = {
571 "window-halfpage-down",
572 "Scroll window half pages forwards (downwards)",
573 wscroll
, { .i
= +PAGE_HALF
}
575 [VIS_ACTION_MODE_NORMAL
] = {
578 switchmode
, { .i
= VIS_MODE_NORMAL
}
580 [VIS_ACTION_MODE_VISUAL
] = {
581 "vis-mode-visual-charwise",
582 "Enter characterwise visual mode",
583 switchmode
, { .i
= VIS_MODE_VISUAL
}
585 [VIS_ACTION_MODE_VISUAL_LINE
] = {
586 "vis-mode-visual-linewise",
587 "Enter linewise visual mode",
588 switchmode
, { .i
= VIS_MODE_VISUAL_LINE
}
590 [VIS_ACTION_MODE_INSERT
] = {
593 switchmode
, { .i
= VIS_MODE_INSERT
}
595 [VIS_ACTION_MODE_REPLACE
] = {
597 "Enter replace mode",
598 switchmode
, { .i
= VIS_MODE_REPLACE
}
600 [VIS_ACTION_MODE_OPERATOR_PENDING
] = {
601 "vis-mode-operator-pending",
602 "Enter to operator pending mode",
603 switchmode
, { .i
= VIS_MODE_OPERATOR_PENDING
}
605 [VIS_ACTION_DELETE_CHAR_PREV
] = {
607 "Delete the previous character",
608 delete, { .i
= VIS_MOVE_CHAR_PREV
}
610 [VIS_ACTION_DELETE_CHAR_NEXT
] = {
612 "Delete the next character",
613 delete, { .i
= VIS_MOVE_CHAR_NEXT
}
615 [VIS_ACTION_DELETE_LINE_BEGIN
] = {
617 "Delete until the start of the current line",
618 delete, { .i
= VIS_MOVE_LINE_BEGIN
}
620 [VIS_ACTION_DELETE_WORD_PREV
] = {
622 "Delete the previous WORD",
623 delete, { .i
= VIS_MOVE_LONGWORD_START_PREV
}
625 [VIS_ACTION_JUMPLIST_PREV
] = {
627 "Go to older cursor position in jump list",
628 movement
, { .i
= VIS_MOVE_JUMPLIST_PREV
}
630 [VIS_ACTION_JUMPLIST_NEXT
] = {
632 "Go to newer cursor position in jump list",
633 movement
, { .i
= VIS_MOVE_JUMPLIST_NEXT
}
635 [VIS_ACTION_CHANGELIST_PREV
] = {
637 "Go to older cursor position in change list",
638 movement
, { .i
= VIS_MOVE_CHANGELIST_PREV
}
640 [VIS_ACTION_CHANGELIST_NEXT
] = {
642 "Go to newer cursor position in change list",
643 movement
, { .i
= VIS_MOVE_CHANGELIST_NEXT
}
645 [VIS_ACTION_UNDO
] = {
650 [VIS_ACTION_REDO
] = {
655 [VIS_ACTION_EARLIER
] = {
657 "Goto older text state",
660 [VIS_ACTION_LATER
] = {
662 "Goto newer text state",
665 [VIS_ACTION_MACRO_RECORD
] = {
667 "Record macro into given register",
670 [VIS_ACTION_MACRO_REPLAY
] = {
672 "Replay macro, execute the content of the given register",
675 [VIS_ACTION_MARK_SET
] = {
677 "Set given mark at current cursor position",
680 [VIS_ACTION_MARK_GOTO
] = {
682 "Goto the position of the given mark",
683 mark_motion
, { .i
= VIS_MOVE_MARK
}
685 [VIS_ACTION_MARK_GOTO_LINE
] = {
687 "Goto first non-blank character of the line containing the given mark",
688 mark_motion
, { .i
= VIS_MOVE_MARK_LINE
}
690 [VIS_ACTION_REDRAW
] = {
692 "Redraw current editor content",
693 call
, { .f
= vis_redraw
}
695 [VIS_ACTION_REPLACE_CHAR
] = {
697 "Replace the character under the cursor",
700 [VIS_ACTION_TOTILL_REPEAT
] = {
702 "Repeat latest to/till motion",
703 movement
, { .i
= VIS_MOVE_TOTILL_REPEAT
}
705 [VIS_ACTION_TOTILL_REVERSE
] = {
707 "Repeat latest to/till motion but in opposite direction",
708 movement
, { .i
= VIS_MOVE_TOTILL_REVERSE
}
710 [VIS_ACTION_PROMPT_SEARCH_FORWARD
] = {
713 prompt_show
, { .s
= "/" }
715 [VIS_ACTION_PROMPT_SEARCH_BACKWARD
] = {
718 prompt_show
, { .s
= "?" }
720 [VIS_ACTION_TILL_LEFT
] = {
722 "Till after the occurrence of character to the left",
723 movement_key
, { .i
= VIS_MOVE_LEFT_TILL
}
725 [VIS_ACTION_TILL_RIGHT
] = {
727 "Till before the occurrence of character to the right",
728 movement_key
, { .i
= VIS_MOVE_RIGHT_TILL
}
730 [VIS_ACTION_TO_LEFT
] = {
732 "To the first occurrence of character to the left",
733 movement_key
, { .i
= VIS_MOVE_LEFT_TO
}
735 [VIS_ACTION_TO_RIGHT
] = {
737 "To the first occurrence of character to the right",
738 movement_key
, { .i
= VIS_MOVE_RIGHT_TO
}
740 [VIS_ACTION_REGISTER
] = {
742 "Use given register for next operator",
745 [VIS_ACTION_OPERATOR_CHANGE
] = {
746 "vis-operator-change",
748 operator, { .i
= VIS_OP_CHANGE
}
750 [VIS_ACTION_OPERATOR_DELETE
] = {
751 "vis-operator-delete",
753 operator, { .i
= VIS_OP_DELETE
}
755 [VIS_ACTION_OPERATOR_YANK
] = {
758 operator, { .i
= VIS_OP_YANK
}
760 [VIS_ACTION_OPERATOR_SHIFT_LEFT
] = {
761 "vis-operator-shift-left",
762 "Shift left operator",
763 operator, { .i
= VIS_OP_SHIFT_LEFT
}
765 [VIS_ACTION_OPERATOR_SHIFT_RIGHT
] = {
766 "vis-operator-shift-right",
767 "Shift right operator",
768 operator, { .i
= VIS_OP_SHIFT_RIGHT
}
770 [VIS_ACTION_OPERATOR_CASE_LOWER
] = {
771 "vis-operator-case-lower",
772 "Lowercase operator",
773 operator, { .i
= VIS_OP_CASE_LOWER
}
775 [VIS_ACTION_OPERATOR_CASE_UPPER
] = {
776 "vis-operator-case-upper",
777 "Uppercase operator",
778 operator, { .i
= VIS_OP_CASE_UPPER
}
780 [VIS_ACTION_OPERATOR_CASE_SWAP
] = {
781 "vis-operator-case-swap",
782 "Swap case operator",
783 operator, { .i
= VIS_OP_CASE_SWAP
}
785 [VIS_ACTION_OPERATOR_FILTER
] = {
786 "vis-operator-filter",
790 [VIS_ACTION_OPERATOR_FILTER_FMT
] = {
791 "vis-operator-filter-format",
792 "Formating operator, filter range through fmt(1)",
793 operator_filter
, { .s
= "|fmt" }
795 [VIS_ACTION_COUNT
] = {
800 [VIS_ACTION_INSERT_NEWLINE
] = {
802 "Insert a line break (depending on file type)",
803 call
, { .f
= vis_insert_nl
}
805 [VIS_ACTION_INSERT_TAB
] = {
807 "Insert a tab (might be converted to spaces)",
808 call
, { .f
= vis_insert_tab
}
810 [VIS_ACTION_INSERT_VERBATIM
] = {
812 "Insert Unicode character based on code point",
815 [VIS_ACTION_INSERT_REGISTER
] = {
817 "Insert specified register content",
820 [VIS_ACTION_WINDOW_NEXT
] = {
823 call
, { .f
= vis_window_next
}
825 [VIS_ACTION_WINDOW_PREV
] = {
827 "Focus previous window",
828 call
, { .f
= vis_window_prev
}
830 [VIS_ACTION_APPEND_CHAR_NEXT
] = {
832 "Append text after the cursor",
833 insertmode
, { .i
= VIS_MOVE_LINE_CHAR_NEXT
}
835 [VIS_ACTION_APPEND_LINE_END
] = {
837 "Append text after the end of the line",
838 insertmode
, { .i
= VIS_MOVE_LINE_END
},
840 [VIS_ACTION_INSERT_LINE_START
] = {
842 "Insert text before the first non-blank in the line",
843 insertmode
, { .i
= VIS_MOVE_LINE_START
},
845 [VIS_ACTION_OPEN_LINE_ABOVE
] = {
847 "Begin a new line above the cursor",
848 openline
, { .i
= -1 }
850 [VIS_ACTION_OPEN_LINE_BELOW
] = {
852 "Begin a new line below the cursor",
853 openline
, { .i
= +1 }
855 [VIS_ACTION_JOIN_LINE_BELOW
] = {
858 join
, { .i
= VIS_MOVE_LINE_NEXT
},
860 [VIS_ACTION_JOIN_LINES
] = {
862 "Join selected lines",
863 operator, { .i
= VIS_OP_JOIN
}
865 [VIS_ACTION_PROMPT_SHOW
] = {
867 "Show editor command line prompt",
868 prompt_show
, { .s
= ":" }
870 [VIS_ACTION_REPEAT
] = {
872 "Repeat latest editor command",
875 [VIS_ACTION_SELECTION_FLIP
] = {
877 "Flip selection, move cursor to other end",
880 [VIS_ACTION_SELECTION_RESTORE
] = {
882 "Restore last selection",
885 [VIS_ACTION_WINDOW_REDRAW_TOP
] = {
887 "Redraw cursor line at the top of the window",
888 window
, { .w
= view_redraw_top
}
890 [VIS_ACTION_WINDOW_REDRAW_CENTER
] = {
891 "window-redraw-center",
892 "Redraw cursor line at the center of the window",
893 window
, { .w
= view_redraw_center
}
895 [VIS_ACTION_WINDOW_REDRAW_BOTTOM
] = {
896 "window-redraw-bottom",
897 "Redraw cursor line at the bottom of the window",
898 window
, { .w
= view_redraw_bottom
}
900 [VIS_ACTION_WINDOW_SLIDE_UP
] = {
902 "Slide window content upwards",
905 [VIS_ACTION_WINDOW_SLIDE_DOWN
] = {
907 "Slide window content downwards",
910 [VIS_ACTION_PUT_AFTER
] = {
912 "Put text after the cursor",
913 operator, { .i
= VIS_OP_PUT_AFTER
}
915 [VIS_ACTION_PUT_BEFORE
] = {
917 "Put text before the cursor",
918 operator, { .i
= VIS_OP_PUT_BEFORE
}
920 [VIS_ACTION_PUT_AFTER_END
] = {
922 "Put text after the cursor, place cursor after new text",
923 operator, { .i
= VIS_OP_PUT_AFTER_END
}
925 [VIS_ACTION_PUT_BEFORE_END
] = {
927 "Put text before the cursor, place cursor after new text",
928 operator, { .i
= VIS_OP_PUT_BEFORE_END
}
930 [VIS_ACTION_CURSOR_SELECT_WORD
] = {
931 "cursors-select-word",
932 "Select word under cursor",
935 [VIS_ACTION_CURSORS_NEW_LINE_ABOVE
] = {
936 "cursors-new-lines-above",
937 "Create a new cursor on the line above",
938 cursors_new
, { .i
= -1 }
940 [VIS_ACTION_CURSORS_NEW_LINE_ABOVE_FIRST
] = {
941 "cursors-new-lines-above-first",
942 "Create a new cursor on the line above the first cursor",
943 cursors_new
, { .i
= INT_MIN
}
945 [VIS_ACTION_CURSORS_NEW_LINE_BELOW
] = {
946 "cursor-new-lines-below",
947 "Create a new cursor on the line below",
948 cursors_new
, { .i
= +1 }
950 [VIS_ACTION_CURSORS_NEW_LINE_BELOW_LAST
] = {
951 "cursor-new-lines-below-last",
952 "Create a new cursor on the line below the last cursor",
953 cursors_new
, { .i
= INT_MAX
}
955 [VIS_ACTION_CURSORS_NEW_LINES_BEGIN
] = {
956 "cursors-new-lines-begin",
957 "Create a new cursor at the start of every line covered by selection",
958 operator, { .i
= VIS_OP_CURSOR_SOL
}
960 [VIS_ACTION_CURSORS_NEW_LINES_END
] = {
961 "cursors-new-lines-end",
962 "Create a new cursor at the end of every line covered by selection",
963 operator, { .i
= VIS_OP_CURSOR_EOL
}
965 [VIS_ACTION_CURSORS_NEW_MATCH_NEXT
] = {
966 "cursors-new-match-next",
967 "Select the next region matching the current selection",
970 [VIS_ACTION_CURSORS_NEW_MATCH_SKIP
] = {
971 "cursors-new-match-skip",
972 "Clear current selection, but select next match",
975 [VIS_ACTION_CURSORS_ALIGN
] = {
977 "Try to align all cursors on the same column",
980 [VIS_ACTION_CURSORS_ALIGN_INDENT_LEFT
] = {
981 "cursors-align-indent-left",
982 "Left align all cursors/selections by inserting spaces",
983 cursors_align_indent
, { .i
= -1 }
985 [VIS_ACTION_CURSORS_ALIGN_INDENT_RIGHT
] = {
986 "cursors-align-indent-right",
987 "Right align all cursors/selections by inserting spaces",
988 cursors_align_indent
, { .i
= +1 }
990 [VIS_ACTION_CURSORS_REMOVE_ALL
] = {
991 "cursors-remove-all",
992 "Remove all but the primary cursor",
995 [VIS_ACTION_CURSORS_REMOVE_LAST
] = {
996 "cursors-remove-last",
997 "Remove least recently created cursor",
1000 [VIS_ACTION_CURSORS_REMOVE_COLUMN
] = {
1001 "cursors-remove-column",
1002 "Remove count cursor column",
1003 cursors_remove_column
, { .i
= 1 }
1005 [VIS_ACTION_CURSORS_REMOVE_COLUMN_EXCEPT
] = {
1006 "cursors-remove-column-except",
1007 "Remove all but the count cursor column",
1008 cursors_remove_column_except
, { .i
= 1 }
1010 [VIS_ACTION_CURSORS_PREV
] = {
1012 "Move to the previous cursor",
1013 cursors_navigate
, { .i
= -PAGE_HALF
}
1015 [VIS_ACTION_CURSORS_NEXT
] = {
1017 "Move to the next cursor",
1018 cursors_navigate
, { .i
= +PAGE_HALF
}
1020 [VIS_ACTION_SELECTIONS_ROTATE_LEFT
] = {
1021 "selections-rotate-left",
1022 "Rotate selections left",
1023 selections_rotate
, { .i
= -1 }
1025 [VIS_ACTION_SELECTIONS_ROTATE_RIGHT
] = {
1026 "selections-rotate-right",
1027 "Rotate selections right",
1028 selections_rotate
, { .i
= +1 }
1030 [VIS_ACTION_SELECTIONS_TRIM
] = {
1032 "Remove leading and trailing white space from selections",
1035 [VIS_ACTION_TEXT_OBJECT_WORD_OUTER
] = {
1036 "text-object-word-outer",
1037 "A word leading and trailing whitespace included",
1038 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_WORD
}
1040 [VIS_ACTION_TEXT_OBJECT_WORD_INNER
] = {
1041 "text-object-word-inner",
1042 "A word leading and trailing whitespace excluded",
1043 textobj
, { .i
= VIS_TEXTOBJECT_INNER_WORD
}
1045 [VIS_ACTION_TEXT_OBJECT_LONGWORD_OUTER
] = {
1046 "text-object-longword-outer",
1047 "A WORD leading and trailing whitespace included",
1048 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_LONGWORD
}
1050 [VIS_ACTION_TEXT_OBJECT_LONGWORD_INNER
] = {
1051 "text-object-longword-inner",
1052 "A WORD leading and trailing whitespace excluded",
1053 textobj
, { .i
= VIS_TEXTOBJECT_INNER_LONGWORD
}
1055 [VIS_ACTION_TEXT_OBJECT_SENTENCE
] = {
1056 "text-object-sentence",
1058 textobj
, { .i
= VIS_TEXTOBJECT_SENTENCE
}
1060 [VIS_ACTION_TEXT_OBJECT_PARAGRAPH
] = {
1061 "text-object-paragraph",
1063 textobj
, { .i
= VIS_TEXTOBJECT_PARAGRAPH
}
1065 [VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_OUTER
] = {
1066 "text-object-square-bracket-outer",
1067 "[] block (outer variant)",
1068 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_SQUARE_BRACKET
}
1070 [VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_INNER
] = {
1071 "text-object-square-bracket-inner",
1072 "[] block (inner variant)",
1073 textobj
, { .i
= VIS_TEXTOBJECT_INNER_SQUARE_BRACKET
}
1075 [VIS_ACTION_TEXT_OBJECT_PARANTHESE_OUTER
] = {
1076 "text-object-parentheses-outer",
1077 "() block (outer variant)",
1078 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_PARANTHESE
}
1080 [VIS_ACTION_TEXT_OBJECT_PARANTHESE_INNER
] = {
1081 "text-object-parentheses-inner",
1082 "() block (inner variant)",
1083 textobj
, { .i
= VIS_TEXTOBJECT_INNER_PARANTHESE
}
1085 [VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_OUTER
] = {
1086 "text-object-angle-bracket-outer",
1087 "<> block (outer variant)",
1088 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_ANGLE_BRACKET
}
1090 [VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_INNER
] = {
1091 "text-object-angle-bracket-inner",
1092 "<> block (inner variant)",
1093 textobj
, { .i
= VIS_TEXTOBJECT_INNER_ANGLE_BRACKET
}
1095 [VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_OUTER
] = {
1096 "text-object-curly-bracket-outer",
1097 "{} block (outer variant)",
1098 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_CURLY_BRACKET
}
1100 [VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_INNER
] = {
1101 "text-object-curly-bracket-inner",
1102 "{} block (inner variant)",
1103 textobj
, { .i
= VIS_TEXTOBJECT_INNER_CURLY_BRACKET
}
1105 [VIS_ACTION_TEXT_OBJECT_QUOTE_OUTER
] = {
1106 "text-object-quote-outer",
1107 "A quoted string, including the quotation marks",
1108 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_QUOTE
}
1110 [VIS_ACTION_TEXT_OBJECT_QUOTE_INNER
] = {
1111 "text-object-quote-inner",
1112 "A quoted string, excluding the quotation marks",
1113 textobj
, { .i
= VIS_TEXTOBJECT_INNER_QUOTE
}
1115 [VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_OUTER
] = {
1116 "text-object-single-quote-outer",
1117 "A single quoted string, including the quotation marks",
1118 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_SINGLE_QUOTE
}
1120 [VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_INNER
] = {
1121 "text-object-single-quote-inner",
1122 "A single quoted string, excluding the quotation marks",
1123 textobj
, { .i
= VIS_TEXTOBJECT_INNER_SINGLE_QUOTE
}
1125 [VIS_ACTION_TEXT_OBJECT_BACKTICK_OUTER
] = {
1126 "text-object-backtick-outer",
1127 "A backtick delimited string (outer variant)",
1128 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_BACKTICK
}
1130 [VIS_ACTION_TEXT_OBJECT_BACKTICK_INNER
] = {
1131 "text-object-backtick-inner",
1132 "A backtick delimited string (inner variant)",
1133 textobj
, { .i
= VIS_TEXTOBJECT_INNER_BACKTICK
}
1135 [VIS_ACTION_TEXT_OBJECT_ENTIRE_OUTER
] = {
1136 "text-object-entire-outer",
1137 "The whole text content",
1138 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_ENTIRE
}
1140 [VIS_ACTION_TEXT_OBJECT_ENTIRE_INNER
] = {
1141 "text-object-entire-inner",
1142 "The whole text content, except for leading and trailing empty lines",
1143 textobj
, { .i
= VIS_TEXTOBJECT_INNER_ENTIRE
}
1145 [VIS_ACTION_TEXT_OBJECT_FUNCTION_OUTER
] = {
1146 "text-object-function-outer",
1147 "A whole C-like function",
1148 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_FUNCTION
}
1150 [VIS_ACTION_TEXT_OBJECT_FUNCTION_INNER
] = {
1151 "text-object-function-inner",
1152 "A whole C-like function body",
1153 textobj
, { .i
= VIS_TEXTOBJECT_INNER_FUNCTION
}
1155 [VIS_ACTION_TEXT_OBJECT_LINE_OUTER
] = {
1156 "text-object-line-outer",
1158 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_LINE
}
1160 [VIS_ACTION_TEXT_OBJECT_LINE_INNER
] = {
1161 "text-object-line-inner",
1162 "The whole line, excluding leading and trailing whitespace",
1163 textobj
, { .i
= VIS_TEXTOBJECT_INNER_LINE
}
1165 [VIS_ACTION_TEXT_OBJECT_INDENTATION
] = {
1166 "text-object-indentation",
1167 "All adjacent lines with the same indentation level as the current one",
1168 textobj
, { .i
= VIS_TEXTOBJECT_INDENTATION
}
1170 [VIS_ACTION_TEXT_OBJECT_SEARCH_FORWARD
] = {
1171 "text-object-search-forward",
1172 "The next search match in forward direction",
1173 textobj
, { .i
= VIS_TEXTOBJECT_SEARCH_FORWARD
}
1175 [VIS_ACTION_TEXT_OBJECT_SEARCH_BACKWARD
] = {
1176 "text-object-search-backward",
1177 "The next search match in backward direction",
1178 textobj
, { .i
= VIS_TEXTOBJECT_SEARCH_BACKWARD
}
1180 [VIS_ACTION_MOTION_CHARWISE
] = {
1182 "Force motion to be charwise",
1183 motiontype
, { .i
= VIS_MOTIONTYPE_CHARWISE
}
1185 [VIS_ACTION_MOTION_LINEWISE
] = {
1187 "Force motion to be linewise",
1188 motiontype
, { .i
= VIS_MOTIONTYPE_LINEWISE
}
1190 [VIS_ACTION_UNICODE_INFO
] = {
1192 "Show Unicode codepoint(s) of character under cursor",
1195 [VIS_ACTION_NUMBER_INCREMENT
] = {
1197 "Increment number under cursor",
1198 number_increment_decrement
, { .i
= +1 }
1200 [VIS_ACTION_NUMBER_DECREMENT
] = {
1202 "Decrement number under cursor",
1203 number_increment_decrement
, { .i
= -1 }
1205 [VIS_ACTION_OPEN_FILE_UNDER_CURSOR
] = {
1206 "open-file-under-cursor",
1207 "Open file under the cursor",
1208 open_file_under_cursor
, { .b
= false }
1210 [VIS_ACTION_OPEN_FILE_UNDER_CURSOR_NEW_WINDOW
] = {
1211 "open-file-under-cursor-new-window",
1212 "Open file under the cursor in a new window",
1213 open_file_under_cursor
, { .b
= true }
1215 [VIS_ACTION_NOP
] = {
1217 "Ignore key, do nothing",
1224 /** key bindings functions */
1226 static const char *nop(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1230 static const char *key2register(Vis
*vis
, const char *keys
, enum VisRegister
*reg
) {
1231 *reg
= VIS_REG_INVALID
;
1234 if ('a' <= keys
[0] && keys
[0] <= 'z')
1235 *reg
= keys
[0] - 'a';
1236 else if ('A' <= keys
[0] && keys
[0] <= 'Z')
1237 *reg
= VIS_REG_A
+ keys
[0] - 'A';
1238 else if (keys
[0] == '*' || keys
[0] == '+')
1239 *reg
= VIS_REG_CLIPBOARD
;
1240 else if (keys
[0] == '_')
1241 *reg
= VIS_REG_BLACKHOLE
;
1242 else if (keys
[0] == '0')
1243 *reg
= VIS_REG_ZERO
;
1244 else if (keys
[0] == '@')
1245 *reg
= VIS_MACRO_LAST_RECORDED
;
1246 else if (keys
[0] == '/')
1247 *reg
= VIS_REG_SEARCH
;
1248 else if (keys
[0] == ':')
1249 *reg
= VIS_REG_COMMAND
;
1253 static const char *macro_record(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1254 if (!vis_macro_record_stop(vis
)) {
1255 enum VisRegister reg
;
1256 keys
= key2register(vis
, keys
, ®
);
1257 vis_macro_record(vis
, reg
);
1263 static const char *macro_replay(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1264 enum VisRegister reg
;
1265 keys
= key2register(vis
, keys
, ®
);
1266 vis_macro_replay(vis
, reg
);
1270 static const char *suspend(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1275 static const char *repeat(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1280 static const char *cursors_new(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1281 View
*view
= vis_view(vis
);
1282 for (int count
= vis_count_get_default(vis
, 1); count
> 0; count
--) {
1283 Cursor
*cursor
= NULL
;
1287 cursor
= view_cursors_primary_get(view
);
1290 cursor
= view_cursors(view
);
1293 for (Cursor
*c
= view_cursors(view
); c
; c
= view_cursors_next(c
))
1299 size_t oldpos
= view_cursors_pos(cursor
);
1301 view_line_down(cursor
);
1302 else if (arg
->i
< 0)
1303 view_line_up(cursor
);
1304 size_t newpos
= view_cursors_pos(cursor
);
1305 view_cursors_to(cursor
, oldpos
);
1306 if (!view_cursors_new(view
, newpos
)) {
1308 cursor
= view_cursors_prev(cursor
);
1309 } else if (arg
->i
== +1) {
1310 cursor
= view_cursors_next(cursor
);
1312 view_cursors_primary_set(cursor
);
1315 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
1319 static const char *cursors_align(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1320 View
*view
= vis_view(vis
);
1321 Text
*txt
= vis_text(vis
);
1322 int mincol
= INT_MAX
;
1323 for (Cursor
*c
= view_cursors(view
); c
; c
= view_cursors_next(c
)) {
1324 int col
= view_cursors_cell_get(c
);
1325 if (col
>= 0 && col
< mincol
)
1328 for (Cursor
*c
= view_cursors(view
); c
; c
= view_cursors_next(c
)) {
1329 if (view_cursors_cell_set(c
, mincol
) == -1) {
1330 size_t pos
= view_cursors_pos(c
);
1331 size_t col
= text_line_width_set(txt
, pos
, mincol
);
1332 view_cursors_to(c
, col
);
1338 static const char *cursors_align_indent(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1339 View
*view
= vis_view(vis
);
1340 Text
*txt
= vis_text(vis
);
1341 bool left_align
= arg
->i
< 0;
1342 int columns
= view_cursors_column_count(view
);
1344 for (int i
= 0; i
< columns
; i
++) {
1345 int mincol
= INT_MAX
, maxcol
= 0;
1346 for (Cursor
*c
= view_cursors_column(view
, i
); c
; c
= view_cursors_column_next(c
, i
)) {
1348 Filerange sel
= view_cursors_selection_get(c
);
1349 if (text_range_valid(&sel
))
1350 pos
= left_align
? sel
.start
: sel
.end
;
1352 pos
= view_cursors_pos(c
);
1353 int col
= text_line_width_get(txt
, pos
);
1360 size_t len
= maxcol
- mincol
;
1361 char *buf
= malloc(len
+1);
1364 memset(buf
, ' ', len
);
1366 for (Cursor
*c
= view_cursors_column(view
, i
); c
; c
= view_cursors_column_next(c
, i
)) {
1368 Filerange sel
= view_cursors_selection_get(c
);
1369 if (text_range_valid(&sel
)) {
1370 pos
= left_align
? sel
.start
: sel
.end
;
1373 pos
= view_cursors_pos(c
);
1376 int col
= text_line_width_get(txt
, pos
);
1378 size_t off
= maxcol
- col
;
1380 text_insert(txt
, ipos
, buf
, off
);
1391 static const char *cursors_clear(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1392 View
*view
= vis_view(vis
);
1393 if (view_cursors_multiple(view
))
1394 view_cursors_clear(view
);
1396 view_cursors_selection_clear(view_cursors_primary_get(view
));
1400 static const char *cursors_select(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1401 Text
*txt
= vis_text(vis
);
1402 View
*view
= vis_view(vis
);
1403 for (Cursor
*cursor
= view_cursors(view
); cursor
; cursor
= view_cursors_next(cursor
)) {
1404 Filerange sel
= view_cursors_selection_get(cursor
);
1405 Filerange word
= text_object_word(txt
, view_cursors_pos(cursor
));
1406 if (!text_range_valid(&sel
) && text_range_valid(&word
)) {
1407 view_cursors_selection_set(cursor
, &word
);
1408 view_cursors_to(cursor
, text_char_prev(txt
, word
.end
));
1411 vis_mode_switch(vis
, VIS_MODE_VISUAL
);
1415 static const char *cursors_select_next(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1416 Text
*txt
= vis_text(vis
);
1417 View
*view
= vis_view(vis
);
1418 Cursor
*cursor
= view_cursors_primary_get(view
);
1419 Filerange sel
= view_cursors_selection_get(cursor
);
1420 if (!text_range_valid(&sel
))
1423 char *buf
= text_bytes_alloc0(txt
, sel
.start
, text_range_size(&sel
));
1426 Filerange word
= text_object_word_find_next(txt
, sel
.end
, buf
);
1429 if (text_range_valid(&word
)) {
1430 size_t pos
= text_char_prev(txt
, word
.end
);
1431 cursor
= view_cursors_new(view
, pos
);
1434 view_cursors_selection_set(cursor
, &word
);
1439 static const char *cursors_select_skip(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1440 View
*view
= vis_view(vis
);
1441 Cursor
*cursor
= view_cursors_primary_get(view
);
1442 keys
= cursors_select_next(vis
, keys
, arg
);
1443 if (cursor
!= view_cursors_primary_get(view
))
1444 view_cursors_dispose(cursor
);
1448 static const char *cursors_remove(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1449 View
*view
= vis_view(vis
);
1450 view_cursors_dispose(view_cursors_primary_get(view
));
1451 view_cursor_to(view
, view_cursor_get(view
));
1455 static const char *cursors_remove_column(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1456 View
*view
= vis_view(vis
);
1457 int max
= view_cursors_column_count(view
);
1458 int column
= vis_count_get_default(vis
, arg
->i
) - 1;
1461 if (!view_cursors_multiple(view
)) {
1462 vis_mode_switch(vis
, VIS_MODE_NORMAL
);
1466 for (Cursor
*c
= view_cursors_column(view
, column
), *next
; c
; c
= next
) {
1467 next
= view_cursors_column_next(c
, column
);
1468 view_cursors_dispose(c
);
1471 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
1475 static const char *cursors_remove_column_except(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1476 View
*view
= vis_view(vis
);
1477 int max
= view_cursors_column_count(view
);
1478 int column
= vis_count_get_default(vis
, arg
->i
) - 1;
1481 if (!view_cursors_multiple(view
)) {
1486 Cursor
*cur
= view_cursors(view
);
1487 Cursor
*col
= view_cursors_column(view
, column
);
1488 for (Cursor
*next
; cur
; cur
= next
) {
1489 next
= view_cursors_next(cur
);
1491 col
= view_cursors_column_next(col
, column
);
1493 view_cursors_dispose(cur
);
1496 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
1500 static const char *cursors_navigate(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1501 View
*view
= vis_view(vis
);
1502 if (!view_cursors_multiple(view
)) {
1503 Filerange sel
= view_selection_get(view
);
1504 if (!text_range_valid(&sel
))
1505 return wscroll(vis
, keys
, arg
);
1508 Cursor
*c
= view_cursors_primary_get(view
);
1509 for (int count
= vis_count_get_default(vis
, 1); count
> 0; count
--) {
1511 c
= view_cursors_next(c
);
1513 c
= view_cursors(view
);
1515 c
= view_cursors_prev(c
);
1517 c
= view_cursors(view
);
1518 for (Cursor
*n
= c
; n
; n
= view_cursors_next(n
))
1523 view_cursors_primary_set(c
);
1524 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
1528 static const char *selections_rotate(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1537 Text
*txt
= vis_text(vis
);
1538 View
*view
= vis_view(vis
);
1539 int columns
= view_cursors_column_count(view
);
1540 int selections
= columns
== 1 ? view_cursors_count(view
) : columns
;
1541 int count
= vis_count_get_default(vis
, 1);
1542 array_init_sized(&arr
, sizeof(Rotate
));
1543 if (!array_reserve(&arr
, selections
))
1547 for (Cursor
*c
= view_cursors(view
), *next
; c
; c
= next
) {
1548 next
= view_cursors_next(c
);
1549 size_t line_next
= 0;
1551 Filerange sel
= view_cursors_selection_get(c
);
1554 rot
.len
= text_range_size(&sel
);
1555 if ((rot
.data
= malloc(rot
.len
)))
1556 rot
.len
= text_bytes_get(txt
, sel
.start
, rot
.len
, rot
.data
);
1559 array_add(&arr
, &rot
);
1562 line
= text_lineno_by_pos(txt
, view_cursors_pos(c
));
1564 line_next
= text_lineno_by_pos(txt
, view_cursors_pos(next
));
1565 if (!next
|| (columns
> 1 && line
!= line_next
)) {
1566 size_t len
= array_length(&arr
);
1567 size_t off
= arg
->i
> 0 ? count
% len
: len
- (count
% len
);
1568 for (size_t i
= 0; i
< len
; i
++) {
1569 size_t j
= (i
+ off
) % len
;
1570 Rotate
*oldrot
= array_get(&arr
, i
);
1571 Rotate
*newrot
= array_get(&arr
, j
);
1572 if (!oldrot
|| !newrot
|| oldrot
== newrot
)
1574 Filerange newsel
= view_cursors_selection_get(newrot
->cursor
);
1575 if (!text_range_valid(&newsel
))
1577 if (!text_delete_range(txt
, &newsel
))
1579 if (!text_insert(txt
, newsel
.start
, oldrot
->data
, oldrot
->len
))
1581 newsel
.end
= newsel
.start
+ oldrot
->len
;
1582 view_cursors_selection_set(newrot
->cursor
, &newsel
);
1583 view_cursors_selection_sync(newrot
->cursor
);
1591 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
1595 static const char *selections_trim(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1596 Text
*txt
= vis_text(vis
);
1597 View
*view
= vis_view(vis
);
1598 for (Cursor
*c
= view_cursors(view
), *next
; c
; c
= next
) {
1599 next
= view_cursors_next(c
);
1600 Filerange sel
= view_cursors_selection_get(c
);
1601 if (!text_range_valid(&sel
))
1603 for (char b
; sel
.start
< sel
.end
&& text_byte_get(txt
, sel
.end
-1, &b
)
1604 && isspace((unsigned char)b
); sel
.end
--);
1605 for (char b
; sel
.start
<= sel
.end
&& text_byte_get(txt
, sel
.start
, &b
)
1606 && isspace((unsigned char)b
); sel
.start
++);
1607 if (sel
.start
< sel
.end
) {
1608 view_cursors_selection_set(c
, &sel
);
1609 view_cursors_selection_sync(c
);
1610 } else if (!view_cursors_dispose(c
)) {
1611 vis_mode_switch(vis
, VIS_MODE_NORMAL
);
1617 static const char *replace(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1620 const char *next
= vis_keys_next(vis
, keys
);
1623 vis_operator(vis
, VIS_OP_REPLACE
);
1624 vis_motion(vis
, VIS_MOVE_NOP
);
1625 vis_keys_feed(vis
, keys
);
1626 vis_keys_feed(vis
, "<Escape>");
1630 static const char *count(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1631 int digit
= keys
[-1] - '0';
1632 int count
= vis_count_get_default(vis
, 0);
1633 if (0 <= digit
&& digit
<= 9) {
1634 if (digit
== 0 && count
== 0)
1635 vis_motion(vis
, VIS_MOVE_LINE_BEGIN
);
1636 vis_count_set(vis
, count
* 10 + digit
);
1641 static const char *gotoline(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1642 if (vis_count_get(vis
) != VIS_COUNT_UNKNOWN
)
1643 vis_motion(vis
, VIS_MOVE_LINE
);
1644 else if (arg
->i
< 0)
1645 vis_motion(vis
, VIS_MOVE_FILE_BEGIN
);
1647 vis_motion(vis
, VIS_MOVE_FILE_END
);
1651 static const char *motiontype(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1652 vis_motion_type(vis
, arg
->i
);
1656 static const char *operator(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1657 vis_operator(vis
, arg
->i
);
1661 static const char *operator_filter(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1662 vis_operator(vis
, VIS_OP_FILTER
, arg
->s
);
1666 static const char *movement_key(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1669 if (!keys
[0] || !(next
= vis_keys_next(vis
, keys
)))
1671 size_t len
= next
- keys
;
1672 if (len
< sizeof key
) {
1673 strncpy(key
, keys
, len
);
1675 vis_motion(vis
, arg
->i
, key
);
1680 static const char *movement(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1681 vis_motion(vis
, arg
->i
);
1685 static const char *textobj(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1686 vis_textobject(vis
, arg
->i
);
1690 static const char *selection_end(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1691 for (Cursor
*c
= view_cursors(vis_view(vis
)); c
; c
= view_cursors_next(c
))
1692 view_cursors_selection_swap(c
);
1696 static const char *selection_restore(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1697 Text
*txt
= vis_text(vis
);
1698 View
*view
= vis_view(vis
);
1699 for (Cursor
*c
= view_cursors(view
); c
; c
= view_cursors_next(c
))
1700 view_cursors_selection_restore(c
);
1701 Filerange sel
= view_selection_get(view
);
1702 if (text_range_is_linewise(txt
, &sel
))
1703 vis_mode_switch(vis
, VIS_MODE_VISUAL_LINE
);
1705 vis_mode_switch(vis
, VIS_MODE_VISUAL
);
1709 static const char *reg(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1710 enum VisRegister reg
;
1711 keys
= key2register(vis
, keys
, ®
);
1712 vis_register_set(vis
, reg
);
1716 static const char *key2mark(Vis
*vis
, const char *keys
, int *mark
) {
1717 *mark
= VIS_MARK_INVALID
;
1720 if (keys
[0] >= 'a' && keys
[0] <= 'z')
1721 *mark
= keys
[0] - 'a';
1722 else if (keys
[0] == '<')
1723 *mark
= VIS_MARK_SELECTION_START
;
1724 else if (keys
[0] == '>')
1725 *mark
= VIS_MARK_SELECTION_END
;
1729 static const char *mark_set(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1731 keys
= key2mark(vis
, keys
, &mark
);
1732 vis_mark_set(vis
, mark
, view_cursor_get(vis_view(vis
)));
1736 static const char *mark_motion(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1738 keys
= key2mark(vis
, keys
, &mark
);
1739 vis_motion(vis
, arg
->i
, mark
);
1743 static const char *undo(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1744 size_t pos
= text_undo(vis_text(vis
));
1746 View
*view
= vis_view(vis
);
1747 if (!view_cursors_multiple(view
))
1748 view_cursor_to(view
, pos
);
1749 /* redraw all windows in case some display the same file */
1755 static const char *redo(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1756 size_t pos
= text_redo(vis_text(vis
));
1758 View
*view
= vis_view(vis
);
1759 if (!view_cursors_multiple(view
))
1760 view_cursor_to(view
, pos
);
1761 /* redraw all windows in case some display the same file */
1767 static const char *earlier(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1768 size_t pos
= text_earlier(vis_text(vis
), vis_count_get_default(vis
, 1));
1770 view_cursor_to(vis_view(vis
), pos
);
1771 /* redraw all windows in case some display the same file */
1777 static const char *later(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1778 size_t pos
= text_later(vis_text(vis
), vis_count_get_default(vis
, 1));
1780 view_cursor_to(vis_view(vis
), pos
);
1781 /* redraw all windows in case some display the same file */
1787 static const char *delete(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1788 vis_operator(vis
, VIS_OP_DELETE
);
1789 vis_motion(vis
, arg
->i
);
1793 static const char *insert_register(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1794 enum VisRegister regid
;
1795 keys
= key2register(vis
, keys
, ®id
);
1797 const char *data
= vis_register_get(vis
, regid
, &len
);
1798 vis_insert_key(vis
, data
, len
);
1802 static const char *prompt_show(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1803 vis_prompt_show(vis
, arg
->s
);
1807 static const char *insert_verbatim(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1809 char buf
[4], type
= keys
[0];
1810 const char *data
= NULL
;
1811 int len
= 0, count
= 0, base
= 0;
1833 if ('0' <= type
&& type
<= '9') {
1842 for (keys
++; keys
[0] && count
> 0; keys
++, count
--) {
1844 if (base
== 8 && '0' <= keys
[0] && keys
[0] <= '7') {
1846 } else if ((base
== 10 || base
== 16) && '0' <= keys
[0] && keys
[0] <= '9') {
1848 } else if (base
== 16 && 'a' <= keys
[0] && keys
[0] <= 'f') {
1849 v
= 10 + keys
[0] - 'a';
1850 } else if (base
== 16 && 'A' <= keys
[0] && keys
[0] <= 'F') {
1851 v
= 10 + keys
[0] - 'A';
1856 rune
= rune
* base
+ v
;
1861 if (type
== 'u' || type
== 'U') {
1862 len
= runetochar(buf
, &rune
);
1870 const char *next
= vis_keys_next(vis
, keys
);
1873 size_t keylen
= next
- keys
;
1875 memcpy(key
, keys
, keylen
);
1878 static const char *keysym
[] = {
1881 "<Backspace>", "\b",
1887 for (const char **k
= keysym
; k
[0]; k
+= 2) {
1888 if (strcmp(k
[0], key
) == 0) {
1898 vis_insert_key(vis
, data
, len
);
1902 static int argi2lines(Vis
*vis
, const Arg
*arg
) {
1903 int count
= vis_count_get(vis
);
1907 return view_height_get(vis_view(vis
));
1910 return view_height_get(vis_view(vis
))/2;
1912 if (count
!= VIS_COUNT_UNKNOWN
)
1914 return arg
->i
< 0 ? -arg
->i
: arg
->i
;
1918 static const char *wscroll(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1920 view_scroll_down(vis_view(vis
), argi2lines(vis
, arg
));
1922 view_scroll_up(vis_view(vis
), argi2lines(vis
, arg
));
1926 static const char *wslide(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1928 view_slide_down(vis_view(vis
), argi2lines(vis
, arg
));
1930 view_slide_up(vis_view(vis
), argi2lines(vis
, arg
));
1934 static const char *call(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1939 static const char *window(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1940 arg
->w(vis_view(vis
));
1944 static const char *openline(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1945 vis_operator(vis
, VIS_OP_INSERT
);
1947 vis_motion(vis
, VIS_MOVE_LINE_END
);
1948 vis_keys_feed(vis
, "<insert-newline>");
1950 vis_motion(vis
, VIS_MOVE_LINE_BEGIN
);
1951 vis_keys_feed(vis
, "<insert-newline><Up>");
1956 static const char *join(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1957 int count
= vis_count_get_default(vis
, 0);
1959 vis_count_set(vis
, count
-1);
1960 vis_operator(vis
, VIS_OP_JOIN
);
1961 vis_motion(vis
, arg
->i
);
1965 static const char *switchmode(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1966 vis_mode_switch(vis
, arg
->i
);
1970 static const char *insertmode(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1971 vis_operator(vis
, VIS_OP_INSERT
);
1972 vis_motion(vis
, arg
->i
);
1976 static const char *unicode_info(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1977 View
*view
= vis_view(vis
);
1978 Text
*txt
= vis_text(vis
);
1979 size_t start
= view_cursor_get(view
);
1980 size_t end
= text_char_next(txt
, start
);
1981 char data
[end
-start
], *data_cur
= data
;
1982 text_bytes_get(txt
, start
, end
- start
, data
);
1983 Iterator it
= text_iterator_get(txt
, start
);
1984 char info
[255] = "", *info_cur
= info
;
1985 for (size_t pos
= start
; it
.pos
< end
; pos
= it
.pos
) {
1986 text_iterator_codepoint_next(&it
, NULL
);
1987 size_t len
= it
.pos
- pos
;
1988 wchar_t wc
= 0xFFFD;
1989 mbtowc(&wc
, data_cur
, len
);
1990 int width
= wcwidth(wc
);
1991 info_cur
+= snprintf(info_cur
, sizeof(info
) - (info_cur
- info
) - 1,
1992 "<%s%.*s> U+%04x ", width
== 0 ? " " : "", (int)len
, data_cur
, wc
);
1995 vis_info_show(vis
, "%s", info
);
1999 static const char *percent(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2000 if (vis_count_get(vis
) == VIS_COUNT_UNKNOWN
)
2001 vis_motion(vis
, VIS_MOVE_BRACKET_MATCH
);
2003 vis_motion(vis
, VIS_MOVE_PERCENT
);
2007 static const char *number_increment_decrement(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2008 View
*view
= vis_view(vis
);
2009 Text
*txt
= vis_text(vis
);
2012 int count
= vis_count_get(vis
);
2013 if (count
!= 0 && count
!= VIS_COUNT_UNKNOWN
)
2016 for (Cursor
*c
= view_cursors(view
); c
; c
= view_cursors_next(c
)) {
2017 Filerange r
= text_object_number(txt
, view_cursors_pos(c
));
2018 if (!text_range_valid(&r
))
2020 char *buf
= text_bytes_alloc0(txt
, r
.start
, text_range_size(&r
));
2022 char *number
= buf
, fmt
[255];
2023 if (number
[0] == '-')
2025 bool octal
= number
[0] == '0' && ('0' <= number
[1] && number
[1] <= '7');
2026 bool hex
= number
[0] == '0' && (number
[1] == 'x' || number
[1] == 'X');
2027 bool dec
= !hex
&& !octal
;
2029 long long value
= strtoll(buf
, NULL
, 0);
2032 snprintf(fmt
, sizeof fmt
, "%lld", value
);
2034 size_t len
= strlen(number
) - 2;
2035 snprintf(fmt
, sizeof fmt
, "0x%0*llx", (int)len
, value
);
2037 size_t len
= strlen(number
) - 1;
2038 snprintf(fmt
, sizeof fmt
, "0%0*llo", (int)len
, value
);
2040 text_delete_range(txt
, &r
);
2041 text_insert(txt
, r
.start
, fmt
, strlen(fmt
));
2042 view_cursors_to(c
, r
.start
);
2052 static const char *open_file_under_cursor(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2053 Win
*win
= vis_window(vis
);
2054 View
*view
= vis_view(vis
);
2055 Text
*txt
= vis_text(vis
);
2057 if (!arg
->b
&& !vis_window_closable(win
)) {
2058 vis_info_show(vis
, "No write since last change");
2062 for (Cursor
*c
= view_cursors(view
); c
; c
= view_cursors_next(c
)) {
2063 Filerange r
= text_object_filename(txt
, view_cursors_pos(c
));
2064 if (!text_range_valid(&r
))
2066 char *name
= text_bytes_alloc0(txt
, r
.start
, text_range_size(&r
));
2071 if (stat(name
, &st
) == -1) {
2072 vis_info_show(vis
, "File `%s' not found", name
);
2077 if (!vis_window_new(vis
, name
)) {
2078 vis_info_show(vis
, "Failed to open `%s': %s", name
, strerror(errno
));
2081 } else if (!arg
->b
) {
2082 vis_window_close(win
);
2095 static void signal_handler(int signum
, siginfo_t
*siginfo
, void *context
) {
2096 vis_signal_handler(vis
, signum
, siginfo
, context
);
2099 int main(int argc
, char *argv
[]) {
2102 .vis_init
= vis_lua_init
,
2103 .vis_start
= vis_lua_start
,
2104 .vis_quit
= vis_lua_quit
,
2105 .file_open
= vis_lua_file_open
,
2106 .file_save
= vis_lua_file_save
,
2107 .file_close
= vis_lua_file_close
,
2108 .win_open
= vis_lua_win_open
,
2109 .win_close
= vis_lua_win_close
,
2112 vis
= vis_new(ui_curses_new(), &event
);
2114 return EXIT_FAILURE
;
2116 for (int i
= 0; i
< LENGTH(vis_action
); i
++) {
2117 const KeyAction
*action
= &vis_action
[i
];
2118 if (!vis_action_register(vis
, action
))
2119 vis_die(vis
, "Could not register action: %s\n", action
->name
);
2122 for (int i
= 0; i
< LENGTH(default_bindings
); i
++) {
2123 for (const KeyBinding
**binding
= default_bindings
[i
]; binding
&& *binding
; binding
++) {
2124 for (const KeyBinding
*kb
= *binding
; kb
->key
; kb
++) {
2125 vis_mode_map(vis
, i
, kb
->key
, kb
);
2130 for (const char **k
= keymaps
; k
[0]; k
+= 2)
2131 vis_keymap_add(vis
, k
[0], k
[1]);
2133 /* install signal handlers etc. */
2134 struct sigaction sa
;
2135 memset(&sa
, 0, sizeof sa
);
2136 sa
.sa_flags
= SA_SIGINFO
;
2137 sa
.sa_sigaction
= signal_handler
;
2138 if (sigaction(SIGBUS
, &sa
, NULL
) || sigaction(SIGINT
, &sa
, NULL
))
2139 vis_die(vis
, "sigaction: %s", strerror(errno
));
2142 sigemptyset(&blockset
);
2143 sigaddset(&blockset
, SIGWINCH
);
2144 sigprocmask(SIG_BLOCK
, &blockset
, NULL
);
2145 signal(SIGPIPE
, SIG_IGN
);
2147 int status
= vis_run(vis
, argc
, argv
);