11 #include "ui-curses.h"
14 #include "text-util.h"
15 #include "text-motions.h"
16 #include "text-objects.h"
22 #define PAGE_HALF (INT_MAX-1)
24 /** functions to be called from keybindings */
25 /* ignore key, do nothing */
26 static const char *nop(Vis
*, const char *keys
, const Arg
*arg
);
27 /* record/replay macro indicated by keys */
28 static const char *macro_record(Vis
*, const char *keys
, const Arg
*arg
);
29 static const char *macro_replay(Vis
*, const char *keys
, const Arg
*arg
);
30 /* temporarily suspend the editor and return to the shell, type 'fg' to get back */
31 static const char *suspend(Vis
*, const char *keys
, const Arg
*arg
);
32 /* switch to mode indicated by arg->i */
33 static const char *switchmode(Vis
*, const char *keys
, const Arg
*arg
);
34 /* switch to insert mode after performing movement indicated by arg->i */
35 static const char *insertmode(Vis
*, const char *keys
, const Arg
*arg
);
36 /* set mark indicated by keys to current cursor position */
37 static const char *mark_set(Vis
*, const char *keys
, const Arg
*arg
);
38 /* add a new line either before or after the one where the cursor currently is */
39 static const char *openline(Vis
*, const char *keys
, const Arg
*arg
);
40 /* join lines from current cursor position to movement indicated by arg */
41 static const char *join(Vis
*, const char *keys
, const Arg
*arg
);
42 /* perform last action i.e. action_prev again */
43 static const char *repeat(Vis
*, const char *keys
, const Arg
*arg
);
44 /* replace character at cursor with one from keys */
45 static const char *replace(Vis
*, const char *keys
, const Arg
*arg
);
46 /* create a new cursor on the previous (arg->i < 0) or next (arg->i > 0) line */
47 static const char *cursors_new(Vis
*, const char *keys
, const Arg
*arg
);
48 /* try to align all cursors on the same column */
49 static const char *cursors_align(Vis
*, const char *keys
, const Arg
*arg
);
50 /* try to align all cursors by inserting the correct amount of white spaces */
51 static const char *cursors_align_indent(Vis
*, const char *keys
, const Arg
*arg
);
52 /* remove all but the primary cursor and their selections */
53 static const char *cursors_clear(Vis
*, const char *keys
, const Arg
*arg
);
54 /* remove the least recently added cursor */
55 static const char *cursors_remove(Vis
*, const char *keys
, const Arg
*arg
);
56 /* remove count (or arg->i)-th cursor column */
57 static const char *cursors_remove_column(Vis
*, const char *keys
, const Arg
*arg
);
58 /* remove all but the count (or arg->i)-th cursor column */
59 static const char *cursors_remove_column_except(Vis
*, const char *keys
, const Arg
*arg
);
60 /* move to the previous (arg->i < 0) or next (arg->i > 0) cursor */
61 static const char *cursors_navigate(Vis
*, const char *keys
, const Arg
*arg
);
62 /* select the word the cursor is currently over */
63 static const char *cursors_select(Vis
*, const char *keys
, const Arg
*arg
);
64 /* select the next region matching the current selection */
65 static const char *cursors_select_next(Vis
*, const char *keys
, const Arg
*arg
);
66 /* clear current selection but select next match */
67 static const char *cursors_select_skip(Vis
*, const char *keys
, const Arg
*arg
);
68 /* rotate selection content count times left (arg->i < 0) or right (arg->i > 0) */
69 static const char *selections_rotate(Vis
*, const char *keys
, const Arg
*arg
);
70 /* remove leading and trailing white spaces from selections */
71 static const char *selections_trim(Vis
*, const char *keys
, const Arg
*arg
);
72 /* adjust current used count according to keys */
73 static const char *count(Vis
*, const char *keys
, const Arg
*arg
);
74 /* move to the count-th line or if not given either to the first (arg->i < 0)
75 * or last (arg->i > 0) line of file */
76 static const char *gotoline(Vis
*, const char *keys
, const Arg
*arg
);
77 /* set motion type either LINEWISE or CHARWISE via arg->i */
78 static const char *motiontype(Vis
*, const char *keys
, const Arg
*arg
);
79 /* make the current action use the operator indicated by arg->i */
80 static const char *operator(Vis
*, const char *keys
, const Arg
*arg
);
81 /* use arg->s as command for the filter operator */
82 static const char *operator_filter(Vis
*, const char *keys
, const Arg
*arg
);
83 /* blocks to read a key and performs movement indicated by arg->i which
84 * should be one of VIS_MOVE_{RIGHT,LEFT}_{TO,TILL} */
85 static const char *movement_key(Vis
*, const char *keys
, const Arg
*arg
);
86 /* perform the movement as indicated by arg->i */
87 static const char *movement(Vis
*, const char *keys
, const Arg
*arg
);
88 /* let the current operator affect the range indicated by the text object arg->i */
89 static const char *textobj(Vis
*, const char *keys
, const Arg
*arg
);
90 /* move to the other end of selected text */
91 static const char *selection_end(Vis
*, const char *keys
, const Arg
*arg
);
92 /* restore least recently used selection */
93 static const char *selection_restore(Vis
*, const char *keys
, const Arg
*arg
);
94 /* use register indicated by keys for the current operator */
95 static const char *reg(Vis
*, const char *keys
, const Arg
*arg
);
96 /* perform arg->i motion with a mark indicated by keys as argument */
97 static const char *mark_motion(Vis
*, const char *keys
, const Arg
*arg
);
98 /* {un,re}do last action, redraw window */
99 static const char *undo(Vis
*, const char *keys
, const Arg
*arg
);
100 static const char *redo(Vis
*, const char *keys
, const Arg
*arg
);
101 /* earlier, later action chronologically, redraw window */
102 static const char *earlier(Vis
*, const char *keys
, const Arg
*arg
);
103 static const char *later(Vis
*, const char *keys
, const Arg
*arg
);
104 /* delete from the current cursor position to the end of
105 * movement as indicated by arg->i */
106 static const char *delete(Vis
*, const char *keys
, const Arg
*arg
);
107 /* insert register content indicated by keys at current cursor position */
108 static const char *insert_register(Vis
*, const char *keys
, const Arg
*arg
);
109 /* show a user prompt to get input with title arg->s */
110 static const char *prompt_show(Vis
*, const char *keys
, const Arg
*arg
);
111 /* blocks to read 3 consecutive digits and inserts the corresponding byte value */
112 static const char *insert_verbatim(Vis
*, const char *keys
, const Arg
*arg
);
113 /* scroll window content according to arg->i which can be either PAGE, PAGE_HALF,
114 * or an arbitrary number of lines. a multiplier overrides what is given in arg->i.
115 * negative values scroll back, positive forward. */
116 static const char *wscroll(Vis
*, const char *keys
, const Arg
*arg
);
117 /* similar to scroll, but do only move window content not cursor position */
118 static const char *wslide(Vis
*, const char *keys
, const Arg
*arg
);
119 /* call editor function as indicated by arg->f */
120 static const char *call(Vis
*, const char *keys
, const Arg
*arg
);
121 /* call window function as indicated by arg->w */
122 static const char *window(Vis
*, const char *keys
, const Arg
*arg
);
123 /* show info about Unicode character at cursor position */
124 static const char *unicode_info(Vis
*, const char *keys
, const Arg
*arg
);
125 /* either go to count % of ile or to matching item */
126 static const char *percent(Vis
*, const char *keys
, const Arg
*arg
);
127 /* either increment (arg->i > 0) or decrement (arg->i < 0) number under cursor */
128 static const char *number_increment_decrement(Vis
*, const char *keys
, const Arg
*arg
);
129 /* open a filename under cursor in same (!arg->b) or new (arg->b) window */
130 static const char *open_file_under_cursor(Vis
*, const char *keys
, const Arg
*arg
);
131 /* complete input text at cursor based on the words in the current file */
132 static const char *complete_word(Vis
*, const char *keys
, const Arg
*arg
);
133 /* complete input text at cursor based on file names of the current directory */
134 static const char *complete_filename(Vis
*, const char *keys
, const Arg
*arg
);
137 VIS_ACTION_EDITOR_SUSPEND
,
138 VIS_ACTION_CURSOR_CHAR_PREV
,
139 VIS_ACTION_CURSOR_CHAR_NEXT
,
140 VIS_ACTION_CURSOR_LINE_CHAR_PREV
,
141 VIS_ACTION_CURSOR_LINE_CHAR_NEXT
,
142 VIS_ACTION_CURSOR_WORD_START_PREV
,
143 VIS_ACTION_CURSOR_WORD_START_NEXT
,
144 VIS_ACTION_CURSOR_WORD_END_PREV
,
145 VIS_ACTION_CURSOR_WORD_END_NEXT
,
146 VIS_ACTION_CURSOR_LONGWORD_START_PREV
,
147 VIS_ACTION_CURSOR_LONGWORD_START_NEXT
,
148 VIS_ACTION_CURSOR_LONGWORD_END_PREV
,
149 VIS_ACTION_CURSOR_LONGWORD_END_NEXT
,
150 VIS_ACTION_CURSOR_LINE_UP
,
151 VIS_ACTION_CURSOR_LINE_DOWN
,
152 VIS_ACTION_CURSOR_LINE_START
,
153 VIS_ACTION_CURSOR_LINE_FINISH
,
154 VIS_ACTION_CURSOR_LINE_BEGIN
,
155 VIS_ACTION_CURSOR_LINE_END
,
156 VIS_ACTION_CURSOR_LINE_LASTCHAR
,
157 VIS_ACTION_CURSOR_SCREEN_LINE_UP
,
158 VIS_ACTION_CURSOR_SCREEN_LINE_DOWN
,
159 VIS_ACTION_CURSOR_SCREEN_LINE_BEGIN
,
160 VIS_ACTION_CURSOR_SCREEN_LINE_MIDDLE
,
161 VIS_ACTION_CURSOR_SCREEN_LINE_END
,
162 VIS_ACTION_CURSOR_PERCENT
,
163 VIS_ACTION_CURSOR_BYTE
,
164 VIS_ACTION_CURSOR_BYTE_LEFT
,
165 VIS_ACTION_CURSOR_BYTE_RIGHT
,
166 VIS_ACTION_CURSOR_PARAGRAPH_PREV
,
167 VIS_ACTION_CURSOR_PARAGRAPH_NEXT
,
168 VIS_ACTION_CURSOR_SENTENCE_PREV
,
169 VIS_ACTION_CURSOR_SENTENCE_NEXT
,
170 VIS_ACTION_CURSOR_FUNCTION_START_PREV
,
171 VIS_ACTION_CURSOR_FUNCTION_END_PREV
,
172 VIS_ACTION_CURSOR_FUNCTION_START_NEXT
,
173 VIS_ACTION_CURSOR_FUNCTION_END_NEXT
,
174 VIS_ACTION_CURSOR_BLOCK_START
,
175 VIS_ACTION_CURSOR_BLOCK_END
,
176 VIS_ACTION_CURSOR_PARENTHESE_START
,
177 VIS_ACTION_CURSOR_PARENTHESE_END
,
178 VIS_ACTION_CURSOR_COLUMN
,
179 VIS_ACTION_CURSOR_LINE_FIRST
,
180 VIS_ACTION_CURSOR_LINE_LAST
,
181 VIS_ACTION_CURSOR_WINDOW_LINE_TOP
,
182 VIS_ACTION_CURSOR_WINDOW_LINE_MIDDLE
,
183 VIS_ACTION_CURSOR_WINDOW_LINE_BOTTOM
,
184 VIS_ACTION_CURSOR_SEARCH_NEXT
,
185 VIS_ACTION_CURSOR_SEARCH_PREV
,
186 VIS_ACTION_CURSOR_SEARCH_WORD_FORWARD
,
187 VIS_ACTION_CURSOR_SEARCH_WORD_BACKWARD
,
188 VIS_ACTION_WINDOW_PAGE_UP
,
189 VIS_ACTION_WINDOW_PAGE_DOWN
,
190 VIS_ACTION_WINDOW_HALFPAGE_UP
,
191 VIS_ACTION_WINDOW_HALFPAGE_DOWN
,
192 VIS_ACTION_MODE_NORMAL
,
193 VIS_ACTION_MODE_VISUAL
,
194 VIS_ACTION_MODE_VISUAL_LINE
,
195 VIS_ACTION_MODE_INSERT
,
196 VIS_ACTION_MODE_REPLACE
,
197 VIS_ACTION_MODE_OPERATOR_PENDING
,
198 VIS_ACTION_DELETE_CHAR_PREV
,
199 VIS_ACTION_DELETE_CHAR_NEXT
,
200 VIS_ACTION_DELETE_LINE_BEGIN
,
201 VIS_ACTION_DELETE_WORD_PREV
,
202 VIS_ACTION_JUMPLIST_PREV
,
203 VIS_ACTION_JUMPLIST_NEXT
,
204 VIS_ACTION_CHANGELIST_PREV
,
205 VIS_ACTION_CHANGELIST_NEXT
,
210 VIS_ACTION_MACRO_RECORD
,
211 VIS_ACTION_MACRO_REPLAY
,
213 VIS_ACTION_MARK_GOTO
,
214 VIS_ACTION_MARK_GOTO_LINE
,
216 VIS_ACTION_REPLACE_CHAR
,
217 VIS_ACTION_TOTILL_REPEAT
,
218 VIS_ACTION_TOTILL_REVERSE
,
219 VIS_ACTION_PROMPT_SEARCH_FORWARD
,
220 VIS_ACTION_PROMPT_SEARCH_BACKWARD
,
221 VIS_ACTION_TILL_LEFT
,
222 VIS_ACTION_TILL_RIGHT
,
226 VIS_ACTION_OPERATOR_CHANGE
,
227 VIS_ACTION_OPERATOR_DELETE
,
228 VIS_ACTION_OPERATOR_YANK
,
229 VIS_ACTION_OPERATOR_SHIFT_LEFT
,
230 VIS_ACTION_OPERATOR_SHIFT_RIGHT
,
231 VIS_ACTION_OPERATOR_CASE_LOWER
,
232 VIS_ACTION_OPERATOR_CASE_UPPER
,
233 VIS_ACTION_OPERATOR_CASE_SWAP
,
234 VIS_ACTION_OPERATOR_FILTER
,
235 VIS_ACTION_OPERATOR_FILTER_FMT
,
237 VIS_ACTION_INSERT_NEWLINE
,
238 VIS_ACTION_INSERT_TAB
,
239 VIS_ACTION_INSERT_VERBATIM
,
240 VIS_ACTION_INSERT_REGISTER
,
241 VIS_ACTION_WINDOW_NEXT
,
242 VIS_ACTION_WINDOW_PREV
,
243 VIS_ACTION_APPEND_CHAR_NEXT
,
244 VIS_ACTION_APPEND_LINE_END
,
245 VIS_ACTION_INSERT_LINE_START
,
246 VIS_ACTION_OPEN_LINE_ABOVE
,
247 VIS_ACTION_OPEN_LINE_BELOW
,
248 VIS_ACTION_JOIN_LINES
,
249 VIS_ACTION_JOIN_LINES_TRIM
,
250 VIS_ACTION_PROMPT_SHOW
,
252 VIS_ACTION_SELECTION_FLIP
,
253 VIS_ACTION_SELECTION_RESTORE
,
254 VIS_ACTION_WINDOW_REDRAW_TOP
,
255 VIS_ACTION_WINDOW_REDRAW_CENTER
,
256 VIS_ACTION_WINDOW_REDRAW_BOTTOM
,
257 VIS_ACTION_WINDOW_SLIDE_UP
,
258 VIS_ACTION_WINDOW_SLIDE_DOWN
,
259 VIS_ACTION_PUT_AFTER
,
260 VIS_ACTION_PUT_BEFORE
,
261 VIS_ACTION_PUT_AFTER_END
,
262 VIS_ACTION_PUT_BEFORE_END
,
263 VIS_ACTION_CURSOR_SELECT_WORD
,
264 VIS_ACTION_CURSORS_NEW_LINE_ABOVE
,
265 VIS_ACTION_CURSORS_NEW_LINE_ABOVE_FIRST
,
266 VIS_ACTION_CURSORS_NEW_LINE_BELOW
,
267 VIS_ACTION_CURSORS_NEW_LINE_BELOW_LAST
,
268 VIS_ACTION_CURSORS_NEW_LINES_BEGIN
,
269 VIS_ACTION_CURSORS_NEW_LINES_END
,
270 VIS_ACTION_CURSORS_NEW_MATCH_NEXT
,
271 VIS_ACTION_CURSORS_NEW_MATCH_SKIP
,
272 VIS_ACTION_CURSORS_ALIGN
,
273 VIS_ACTION_CURSORS_ALIGN_INDENT_LEFT
,
274 VIS_ACTION_CURSORS_ALIGN_INDENT_RIGHT
,
275 VIS_ACTION_CURSORS_REMOVE_ALL
,
276 VIS_ACTION_CURSORS_REMOVE_LAST
,
277 VIS_ACTION_CURSORS_REMOVE_COLUMN
,
278 VIS_ACTION_CURSORS_REMOVE_COLUMN_EXCEPT
,
279 VIS_ACTION_CURSORS_PREV
,
280 VIS_ACTION_CURSORS_NEXT
,
281 VIS_ACTION_SELECTIONS_ROTATE_LEFT
,
282 VIS_ACTION_SELECTIONS_ROTATE_RIGHT
,
283 VIS_ACTION_SELECTIONS_TRIM
,
284 VIS_ACTION_TEXT_OBJECT_WORD_OUTER
,
285 VIS_ACTION_TEXT_OBJECT_WORD_INNER
,
286 VIS_ACTION_TEXT_OBJECT_LONGWORD_OUTER
,
287 VIS_ACTION_TEXT_OBJECT_LONGWORD_INNER
,
288 VIS_ACTION_TEXT_OBJECT_SENTENCE
,
289 VIS_ACTION_TEXT_OBJECT_PARAGRAPH
,
290 VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_OUTER
,
291 VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_INNER
,
292 VIS_ACTION_TEXT_OBJECT_PARANTHESE_OUTER
,
293 VIS_ACTION_TEXT_OBJECT_PARANTHESE_INNER
,
294 VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_OUTER
,
295 VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_INNER
,
296 VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_OUTER
,
297 VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_INNER
,
298 VIS_ACTION_TEXT_OBJECT_QUOTE_OUTER
,
299 VIS_ACTION_TEXT_OBJECT_QUOTE_INNER
,
300 VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_OUTER
,
301 VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_INNER
,
302 VIS_ACTION_TEXT_OBJECT_BACKTICK_OUTER
,
303 VIS_ACTION_TEXT_OBJECT_BACKTICK_INNER
,
304 VIS_ACTION_TEXT_OBJECT_ENTIRE_OUTER
,
305 VIS_ACTION_TEXT_OBJECT_ENTIRE_INNER
,
306 VIS_ACTION_TEXT_OBJECT_FUNCTION_OUTER
,
307 VIS_ACTION_TEXT_OBJECT_FUNCTION_INNER
,
308 VIS_ACTION_TEXT_OBJECT_LINE_OUTER
,
309 VIS_ACTION_TEXT_OBJECT_LINE_INNER
,
310 VIS_ACTION_TEXT_OBJECT_INDENTATION
,
311 VIS_ACTION_TEXT_OBJECT_SEARCH_FORWARD
,
312 VIS_ACTION_TEXT_OBJECT_SEARCH_BACKWARD
,
313 VIS_ACTION_MOTION_CHARWISE
,
314 VIS_ACTION_MOTION_LINEWISE
,
315 VIS_ACTION_UNICODE_INFO
,
316 VIS_ACTION_UTF8_INFO
,
317 VIS_ACTION_NUMBER_INCREMENT
,
318 VIS_ACTION_NUMBER_DECREMENT
,
319 VIS_ACTION_OPEN_FILE_UNDER_CURSOR
,
320 VIS_ACTION_OPEN_FILE_UNDER_CURSOR_NEW_WINDOW
,
321 VIS_ACTION_COMPLETE_WORD
,
322 VIS_ACTION_COMPLETE_FILENAME
,
326 static const KeyAction vis_action
[] = {
327 [VIS_ACTION_EDITOR_SUSPEND
] = {
329 "Suspend the editor",
332 [VIS_ACTION_CURSOR_CHAR_PREV
] = {
334 "Move cursor left, to the previous character",
335 movement
, { .i
= VIS_MOVE_CHAR_PREV
}
337 [VIS_ACTION_CURSOR_CHAR_NEXT
] = {
339 "Move cursor right, to the next character",
340 movement
, { .i
= VIS_MOVE_CHAR_NEXT
}
342 [VIS_ACTION_CURSOR_LINE_CHAR_PREV
] = {
343 "cursor-line-char-prev",
344 "Move cursor left, to the previous character on the same line",
345 movement
, { .i
= VIS_MOVE_LINE_CHAR_PREV
}
347 [VIS_ACTION_CURSOR_LINE_CHAR_NEXT
] = {
348 "cursor-line-char-next",
349 "Move cursor right, to the next character on the same line",
350 movement
, { .i
= VIS_MOVE_LINE_CHAR_NEXT
}
352 [VIS_ACTION_CURSOR_WORD_START_PREV
] = {
353 "cursor-word-start-prev",
354 "Move cursor words backwards",
355 movement
, { .i
= VIS_MOVE_WORD_START_PREV
}
357 [VIS_ACTION_CURSOR_WORD_START_NEXT
] = {
358 "cursor-word-start-next",
359 "Move cursor words forwards",
360 movement
, { .i
= VIS_MOVE_WORD_START_NEXT
}
362 [VIS_ACTION_CURSOR_WORD_END_PREV
] = {
363 "cursor-word-end-prev",
364 "Move cursor backwards to the end of word",
365 movement
, { .i
= VIS_MOVE_WORD_END_PREV
}
367 [VIS_ACTION_CURSOR_WORD_END_NEXT
] = {
368 "cursor-word-end-next",
369 "Move cursor forward to the end of word",
370 movement
, { .i
= VIS_MOVE_WORD_END_NEXT
}
372 [VIS_ACTION_CURSOR_LONGWORD_START_PREV
] = {
373 "cursor-longword-start-prev",
374 "Move cursor WORDS backwards",
375 movement
, { .i
= VIS_MOVE_LONGWORD_START_PREV
}
377 [VIS_ACTION_CURSOR_LONGWORD_START_NEXT
] = {
378 "cursor-longword-start-next",
379 "Move cursor WORDS forwards",
380 movement
, { .i
= VIS_MOVE_LONGWORD_START_NEXT
}
382 [VIS_ACTION_CURSOR_LONGWORD_END_PREV
] = {
383 "cursor-longword-end-prev",
384 "Move cursor backwards to the end of WORD",
385 movement
, { .i
= VIS_MOVE_LONGWORD_END_PREV
}
387 [VIS_ACTION_CURSOR_LONGWORD_END_NEXT
] = {
388 "cursor-longword-end-next",
389 "Move cursor forward to the end of WORD",
390 movement
, { .i
= VIS_MOVE_LONGWORD_END_NEXT
}
392 [VIS_ACTION_CURSOR_LINE_UP
] = {
394 "Move cursor line upwards",
395 movement
, { .i
= VIS_MOVE_LINE_UP
}
397 [VIS_ACTION_CURSOR_LINE_DOWN
] = {
399 "Move cursor line downwards",
400 movement
, { .i
= VIS_MOVE_LINE_DOWN
}
402 [VIS_ACTION_CURSOR_LINE_START
] = {
404 "Move cursor to first non-blank character of the line",
405 movement
, { .i
= VIS_MOVE_LINE_START
}
407 [VIS_ACTION_CURSOR_LINE_FINISH
] = {
408 "cursor-line-finish",
409 "Move cursor to last non-blank character of the line",
410 movement
, { .i
= VIS_MOVE_LINE_FINISH
}
412 [VIS_ACTION_CURSOR_LINE_BEGIN
] = {
414 "Move cursor to first character of the line",
415 movement
, { .i
= VIS_MOVE_LINE_BEGIN
}
417 [VIS_ACTION_CURSOR_LINE_END
] = {
419 "Move cursor to end of the line",
420 movement
, { .i
= VIS_MOVE_LINE_END
}
422 [VIS_ACTION_CURSOR_LINE_LASTCHAR
] = {
423 "cursor-line-lastchar",
424 "Move cursor to last character of the line",
425 movement
, { .i
= VIS_MOVE_LINE_LASTCHAR
}
427 [VIS_ACTION_CURSOR_SCREEN_LINE_UP
] = {
428 "cursor-screenline-up",
429 "Move cursor screen/display line upwards",
430 movement
, { .i
= VIS_MOVE_SCREEN_LINE_UP
}
432 [VIS_ACTION_CURSOR_SCREEN_LINE_DOWN
] = {
433 "cursor-screenline-down",
434 "Move cursor screen/display line downwards",
435 movement
, { .i
= VIS_MOVE_SCREEN_LINE_DOWN
}
437 [VIS_ACTION_CURSOR_SCREEN_LINE_BEGIN
] = {
438 "cursor-screenline-begin",
439 "Move cursor to beginning of screen/display line",
440 movement
, { .i
= VIS_MOVE_SCREEN_LINE_BEGIN
}
442 [VIS_ACTION_CURSOR_SCREEN_LINE_MIDDLE
] = {
443 "cursor-screenline-middle",
444 "Move cursor to middle of screen/display line",
445 movement
, { .i
= VIS_MOVE_SCREEN_LINE_MIDDLE
}
447 [VIS_ACTION_CURSOR_SCREEN_LINE_END
] = {
448 "cursor-screenline-end",
449 "Move cursor to end of screen/display line",
450 movement
, { .i
= VIS_MOVE_SCREEN_LINE_END
}
452 [VIS_ACTION_CURSOR_PERCENT
] = {
454 "Move to count % of file or matching item",
457 [VIS_ACTION_CURSOR_BYTE
] = {
459 "Move to absolute byte position",
460 movement
, { .i
= VIS_MOVE_BYTE
}
462 [VIS_ACTION_CURSOR_BYTE_LEFT
] = {
464 "Move count bytes to the left",
465 movement
, { .i
= VIS_MOVE_BYTE_LEFT
}
467 [VIS_ACTION_CURSOR_BYTE_RIGHT
] = {
469 "Move count bytes to the right",
470 movement
, { .i
= VIS_MOVE_BYTE_RIGHT
}
472 [VIS_ACTION_CURSOR_PARAGRAPH_PREV
] = {
473 "cursor-paragraph-prev",
474 "Move cursor paragraph backward",
475 movement
, { .i
= VIS_MOVE_PARAGRAPH_PREV
}
477 [VIS_ACTION_CURSOR_PARAGRAPH_NEXT
] = {
478 "cursor-paragraph-next",
479 "Move cursor paragraph forward",
480 movement
, { .i
= VIS_MOVE_PARAGRAPH_NEXT
}
482 [VIS_ACTION_CURSOR_SENTENCE_PREV
] = {
483 "cursor-sentence-prev",
484 "Move cursor sentence backward",
485 movement
, { .i
= VIS_MOVE_SENTENCE_PREV
}
487 [VIS_ACTION_CURSOR_SENTENCE_NEXT
] = {
488 "cursor-sentence-next",
489 "Move cursor sentence forward",
490 movement
, { .i
= VIS_MOVE_SENTENCE_NEXT
}
492 [VIS_ACTION_CURSOR_FUNCTION_START_PREV
] = {
493 "cursor-function-start-prev",
494 "Move cursor backwards to start of function",
495 movement
, { .i
= VIS_MOVE_FUNCTION_START_PREV
}
497 [VIS_ACTION_CURSOR_FUNCTION_START_NEXT
] = {
498 "cursor-function-start-next",
499 "Move cursor forwards to start of function",
500 movement
, { .i
= VIS_MOVE_FUNCTION_START_NEXT
}
502 [VIS_ACTION_CURSOR_FUNCTION_END_PREV
] = {
503 "cursor-function-end-prev",
504 "Move cursor backwards to end of function",
505 movement
, { .i
= VIS_MOVE_FUNCTION_END_PREV
}
507 [VIS_ACTION_CURSOR_FUNCTION_END_NEXT
] = {
508 "cursor-function-end-next",
509 "Move cursor forwards to end of function",
510 movement
, { .i
= VIS_MOVE_FUNCTION_END_NEXT
}
512 [VIS_ACTION_CURSOR_BLOCK_START
] = {
513 "cursor-block-start",
514 "Move cursor to the opening curly brace in a block",
515 movement
, { .i
= VIS_MOVE_BLOCK_START
}
517 [VIS_ACTION_CURSOR_BLOCK_END
] = {
519 "Move cursor to the closing curly brace in a block",
520 movement
, { .i
= VIS_MOVE_BLOCK_END
}
522 [VIS_ACTION_CURSOR_PARENTHESE_START
] = {
523 "cursor-parenthese-start",
524 "Move cursor to the opening parenthese inside a pair of parentheses",
525 movement
, { .i
= VIS_MOVE_PARENTHESE_START
}
527 [VIS_ACTION_CURSOR_PARENTHESE_END
] = {
528 "cursor-parenthese-end",
529 "Move cursor to the closing parenthese inside a pair of parentheses",
530 movement
, { .i
= VIS_MOVE_PARENTHESE_END
}
532 [VIS_ACTION_CURSOR_COLUMN
] = {
534 "Move cursor to given column of current line",
535 movement
, { .i
= VIS_MOVE_COLUMN
}
537 [VIS_ACTION_CURSOR_LINE_FIRST
] = {
539 "Move cursor to given line (defaults to first)",
540 gotoline
, { .i
= -1 }
542 [VIS_ACTION_CURSOR_LINE_LAST
] = {
544 "Move cursor to given line (defaults to last)",
545 gotoline
, { .i
= +1 }
547 [VIS_ACTION_CURSOR_WINDOW_LINE_TOP
] = {
548 "cursor-window-line-top",
549 "Move cursor to top line of the window",
550 movement
, { .i
= VIS_MOVE_WINDOW_LINE_TOP
}
552 [VIS_ACTION_CURSOR_WINDOW_LINE_MIDDLE
] = {
553 "cursor-window-line-middle",
554 "Move cursor to middle line of the window",
555 movement
, { .i
= VIS_MOVE_WINDOW_LINE_MIDDLE
}
557 [VIS_ACTION_CURSOR_WINDOW_LINE_BOTTOM
] = {
558 "cursor-window-line-bottom",
559 "Move cursor to bottom line of the window",
560 movement
, { .i
= VIS_MOVE_WINDOW_LINE_BOTTOM
}
562 [VIS_ACTION_CURSOR_SEARCH_NEXT
] = {
563 "cursor-search-forward",
564 "Move cursor to next match",
565 movement
, { .i
= VIS_MOVE_SEARCH_NEXT
}
567 [VIS_ACTION_CURSOR_SEARCH_PREV
] = {
568 "cursor-search-backward",
569 "Move cursor to previous match",
570 movement
, { .i
= VIS_MOVE_SEARCH_PREV
}
572 [VIS_ACTION_CURSOR_SEARCH_WORD_FORWARD
] = {
573 "cursor-search-word-forward",
574 "Move cursor to next occurence of the word under cursor",
575 movement
, { .i
= VIS_MOVE_SEARCH_WORD_FORWARD
}
577 [VIS_ACTION_CURSOR_SEARCH_WORD_BACKWARD
] = {
578 "cursor-search-word-backward",
579 "Move cursor to previous occurence of the word under cursor",
580 movement
, { .i
= VIS_MOVE_SEARCH_WORD_BACKWARD
}
582 [VIS_ACTION_WINDOW_PAGE_UP
] = {
584 "Scroll window pages backwards (upwards)",
585 wscroll
, { .i
= -PAGE
}
587 [VIS_ACTION_WINDOW_HALFPAGE_UP
] = {
588 "window-halfpage-up",
589 "Scroll window half pages backwards (upwards)",
590 wscroll
, { .i
= -PAGE_HALF
}
592 [VIS_ACTION_WINDOW_PAGE_DOWN
] = {
594 "Scroll window pages forwards (downwards)",
595 wscroll
, { .i
= +PAGE
}
597 [VIS_ACTION_WINDOW_HALFPAGE_DOWN
] = {
598 "window-halfpage-down",
599 "Scroll window half pages forwards (downwards)",
600 wscroll
, { .i
= +PAGE_HALF
}
602 [VIS_ACTION_MODE_NORMAL
] = {
605 switchmode
, { .i
= VIS_MODE_NORMAL
}
607 [VIS_ACTION_MODE_VISUAL
] = {
608 "vis-mode-visual-charwise",
609 "Enter characterwise visual mode",
610 switchmode
, { .i
= VIS_MODE_VISUAL
}
612 [VIS_ACTION_MODE_VISUAL_LINE
] = {
613 "vis-mode-visual-linewise",
614 "Enter linewise visual mode",
615 switchmode
, { .i
= VIS_MODE_VISUAL_LINE
}
617 [VIS_ACTION_MODE_INSERT
] = {
620 switchmode
, { .i
= VIS_MODE_INSERT
}
622 [VIS_ACTION_MODE_REPLACE
] = {
624 "Enter replace mode",
625 switchmode
, { .i
= VIS_MODE_REPLACE
}
627 [VIS_ACTION_MODE_OPERATOR_PENDING
] = {
628 "vis-mode-operator-pending",
629 "Enter to operator pending mode",
630 switchmode
, { .i
= VIS_MODE_OPERATOR_PENDING
}
632 [VIS_ACTION_DELETE_CHAR_PREV
] = {
634 "Delete the previous character",
635 delete, { .i
= VIS_MOVE_CHAR_PREV
}
637 [VIS_ACTION_DELETE_CHAR_NEXT
] = {
639 "Delete the next character",
640 delete, { .i
= VIS_MOVE_CHAR_NEXT
}
642 [VIS_ACTION_DELETE_LINE_BEGIN
] = {
644 "Delete until the start of the current line",
645 delete, { .i
= VIS_MOVE_LINE_BEGIN
}
647 [VIS_ACTION_DELETE_WORD_PREV
] = {
649 "Delete the previous WORD",
650 delete, { .i
= VIS_MOVE_WORD_START_PREV
}
652 [VIS_ACTION_JUMPLIST_PREV
] = {
654 "Go to older cursor position in jump list",
655 movement
, { .i
= VIS_MOVE_JUMPLIST_PREV
}
657 [VIS_ACTION_JUMPLIST_NEXT
] = {
659 "Go to newer cursor position in jump list",
660 movement
, { .i
= VIS_MOVE_JUMPLIST_NEXT
}
662 [VIS_ACTION_CHANGELIST_PREV
] = {
664 "Go to older cursor position in change list",
665 movement
, { .i
= VIS_MOVE_CHANGELIST_PREV
}
667 [VIS_ACTION_CHANGELIST_NEXT
] = {
669 "Go to newer cursor position in change list",
670 movement
, { .i
= VIS_MOVE_CHANGELIST_NEXT
}
672 [VIS_ACTION_UNDO
] = {
677 [VIS_ACTION_REDO
] = {
682 [VIS_ACTION_EARLIER
] = {
684 "Goto older text state",
687 [VIS_ACTION_LATER
] = {
689 "Goto newer text state",
692 [VIS_ACTION_MACRO_RECORD
] = {
694 "Record macro into given register",
697 [VIS_ACTION_MACRO_REPLAY
] = {
699 "Replay macro, execute the content of the given register",
702 [VIS_ACTION_MARK_SET
] = {
704 "Set given mark at current cursor position",
707 [VIS_ACTION_MARK_GOTO
] = {
709 "Goto the position of the given mark",
710 mark_motion
, { .i
= VIS_MOVE_MARK
}
712 [VIS_ACTION_MARK_GOTO_LINE
] = {
714 "Goto first non-blank character of the line containing the given mark",
715 mark_motion
, { .i
= VIS_MOVE_MARK_LINE
}
717 [VIS_ACTION_REDRAW
] = {
719 "Redraw current editor content",
720 call
, { .f
= vis_redraw
}
722 [VIS_ACTION_REPLACE_CHAR
] = {
724 "Replace the character under the cursor",
727 [VIS_ACTION_TOTILL_REPEAT
] = {
729 "Repeat latest to/till motion",
730 movement
, { .i
= VIS_MOVE_TOTILL_REPEAT
}
732 [VIS_ACTION_TOTILL_REVERSE
] = {
734 "Repeat latest to/till motion but in opposite direction",
735 movement
, { .i
= VIS_MOVE_TOTILL_REVERSE
}
737 [VIS_ACTION_PROMPT_SEARCH_FORWARD
] = {
740 prompt_show
, { .s
= "/" }
742 [VIS_ACTION_PROMPT_SEARCH_BACKWARD
] = {
745 prompt_show
, { .s
= "?" }
747 [VIS_ACTION_TILL_LEFT
] = {
749 "Till after the occurrence of character to the left",
750 movement_key
, { .i
= VIS_MOVE_LEFT_TILL
}
752 [VIS_ACTION_TILL_RIGHT
] = {
754 "Till before the occurrence of character to the right",
755 movement_key
, { .i
= VIS_MOVE_RIGHT_TILL
}
757 [VIS_ACTION_TO_LEFT
] = {
759 "To the first occurrence of character to the left",
760 movement_key
, { .i
= VIS_MOVE_LEFT_TO
}
762 [VIS_ACTION_TO_RIGHT
] = {
764 "To the first occurrence of character to the right",
765 movement_key
, { .i
= VIS_MOVE_RIGHT_TO
}
767 [VIS_ACTION_REGISTER
] = {
769 "Use given register for next operator",
772 [VIS_ACTION_OPERATOR_CHANGE
] = {
773 "vis-operator-change",
775 operator, { .i
= VIS_OP_CHANGE
}
777 [VIS_ACTION_OPERATOR_DELETE
] = {
778 "vis-operator-delete",
780 operator, { .i
= VIS_OP_DELETE
}
782 [VIS_ACTION_OPERATOR_YANK
] = {
785 operator, { .i
= VIS_OP_YANK
}
787 [VIS_ACTION_OPERATOR_SHIFT_LEFT
] = {
788 "vis-operator-shift-left",
789 "Shift left operator",
790 operator, { .i
= VIS_OP_SHIFT_LEFT
}
792 [VIS_ACTION_OPERATOR_SHIFT_RIGHT
] = {
793 "vis-operator-shift-right",
794 "Shift right operator",
795 operator, { .i
= VIS_OP_SHIFT_RIGHT
}
797 [VIS_ACTION_OPERATOR_CASE_LOWER
] = {
798 "vis-operator-case-lower",
799 "Lowercase operator",
800 operator, { .i
= VIS_OP_CASE_LOWER
}
802 [VIS_ACTION_OPERATOR_CASE_UPPER
] = {
803 "vis-operator-case-upper",
804 "Uppercase operator",
805 operator, { .i
= VIS_OP_CASE_UPPER
}
807 [VIS_ACTION_OPERATOR_CASE_SWAP
] = {
808 "vis-operator-case-swap",
809 "Swap case operator",
810 operator, { .i
= VIS_OP_CASE_SWAP
}
812 [VIS_ACTION_OPERATOR_FILTER
] = {
813 "vis-operator-filter",
817 [VIS_ACTION_OPERATOR_FILTER_FMT
] = {
818 "vis-operator-filter-format",
819 "Formating operator, filter range through fmt(1)",
820 operator_filter
, { .s
= "|fmt" }
822 [VIS_ACTION_COUNT
] = {
827 [VIS_ACTION_INSERT_NEWLINE
] = {
829 "Insert a line break (depending on file type)",
830 call
, { .f
= vis_insert_nl
}
832 [VIS_ACTION_INSERT_TAB
] = {
834 "Insert a tab (might be converted to spaces)",
835 call
, { .f
= vis_insert_tab
}
837 [VIS_ACTION_INSERT_VERBATIM
] = {
839 "Insert Unicode character based on code point",
842 [VIS_ACTION_INSERT_REGISTER
] = {
844 "Insert specified register content",
847 [VIS_ACTION_WINDOW_NEXT
] = {
850 call
, { .f
= vis_window_next
}
852 [VIS_ACTION_WINDOW_PREV
] = {
854 "Focus previous window",
855 call
, { .f
= vis_window_prev
}
857 [VIS_ACTION_APPEND_CHAR_NEXT
] = {
859 "Append text after the cursor",
860 insertmode
, { .i
= VIS_MOVE_LINE_CHAR_NEXT
}
862 [VIS_ACTION_APPEND_LINE_END
] = {
864 "Append text after the end of the line",
865 insertmode
, { .i
= VIS_MOVE_LINE_END
},
867 [VIS_ACTION_INSERT_LINE_START
] = {
869 "Insert text before the first non-blank in the line",
870 insertmode
, { .i
= VIS_MOVE_LINE_START
},
872 [VIS_ACTION_OPEN_LINE_ABOVE
] = {
874 "Begin a new line above the cursor",
875 openline
, { .i
= -1 }
877 [VIS_ACTION_OPEN_LINE_BELOW
] = {
879 "Begin a new line below the cursor",
880 openline
, { .i
= +1 }
882 [VIS_ACTION_JOIN_LINES
] = {
884 "Join selected lines",
887 [VIS_ACTION_JOIN_LINES_TRIM
] = {
889 "Join selected lines, remove white space",
892 [VIS_ACTION_PROMPT_SHOW
] = {
894 "Show editor command line prompt",
895 prompt_show
, { .s
= ":" }
897 [VIS_ACTION_REPEAT
] = {
899 "Repeat latest editor command",
902 [VIS_ACTION_SELECTION_FLIP
] = {
904 "Flip selection, move cursor to other end",
907 [VIS_ACTION_SELECTION_RESTORE
] = {
909 "Restore last selection",
912 [VIS_ACTION_WINDOW_REDRAW_TOP
] = {
914 "Redraw cursor line at the top of the window",
915 window
, { .w
= view_redraw_top
}
917 [VIS_ACTION_WINDOW_REDRAW_CENTER
] = {
918 "window-redraw-center",
919 "Redraw cursor line at the center of the window",
920 window
, { .w
= view_redraw_center
}
922 [VIS_ACTION_WINDOW_REDRAW_BOTTOM
] = {
923 "window-redraw-bottom",
924 "Redraw cursor line at the bottom of the window",
925 window
, { .w
= view_redraw_bottom
}
927 [VIS_ACTION_WINDOW_SLIDE_UP
] = {
929 "Slide window content upwards",
932 [VIS_ACTION_WINDOW_SLIDE_DOWN
] = {
934 "Slide window content downwards",
937 [VIS_ACTION_PUT_AFTER
] = {
939 "Put text after the cursor",
940 operator, { .i
= VIS_OP_PUT_AFTER
}
942 [VIS_ACTION_PUT_BEFORE
] = {
944 "Put text before the cursor",
945 operator, { .i
= VIS_OP_PUT_BEFORE
}
947 [VIS_ACTION_PUT_AFTER_END
] = {
949 "Put text after the cursor, place cursor after new text",
950 operator, { .i
= VIS_OP_PUT_AFTER_END
}
952 [VIS_ACTION_PUT_BEFORE_END
] = {
954 "Put text before the cursor, place cursor after new text",
955 operator, { .i
= VIS_OP_PUT_BEFORE_END
}
957 [VIS_ACTION_CURSOR_SELECT_WORD
] = {
958 "cursors-select-word",
959 "Select word under cursor",
962 [VIS_ACTION_CURSORS_NEW_LINE_ABOVE
] = {
963 "cursors-new-lines-above",
964 "Create a new cursor on the line above",
965 cursors_new
, { .i
= -1 }
967 [VIS_ACTION_CURSORS_NEW_LINE_ABOVE_FIRST
] = {
968 "cursors-new-lines-above-first",
969 "Create a new cursor on the line above the first cursor",
970 cursors_new
, { .i
= INT_MIN
}
972 [VIS_ACTION_CURSORS_NEW_LINE_BELOW
] = {
973 "cursor-new-lines-below",
974 "Create a new cursor on the line below",
975 cursors_new
, { .i
= +1 }
977 [VIS_ACTION_CURSORS_NEW_LINE_BELOW_LAST
] = {
978 "cursor-new-lines-below-last",
979 "Create a new cursor on the line below the last cursor",
980 cursors_new
, { .i
= INT_MAX
}
982 [VIS_ACTION_CURSORS_NEW_LINES_BEGIN
] = {
983 "cursors-new-lines-begin",
984 "Create a new cursor at the start of every line covered by selection",
985 operator, { .i
= VIS_OP_CURSOR_SOL
}
987 [VIS_ACTION_CURSORS_NEW_LINES_END
] = {
988 "cursors-new-lines-end",
989 "Create a new cursor at the end of every line covered by selection",
990 operator, { .i
= VIS_OP_CURSOR_EOL
}
992 [VIS_ACTION_CURSORS_NEW_MATCH_NEXT
] = {
993 "cursors-new-match-next",
994 "Select the next region matching the current selection",
997 [VIS_ACTION_CURSORS_NEW_MATCH_SKIP
] = {
998 "cursors-new-match-skip",
999 "Clear current selection, but select next match",
1000 cursors_select_skip
,
1002 [VIS_ACTION_CURSORS_ALIGN
] = {
1004 "Try to align all cursors on the same column",
1007 [VIS_ACTION_CURSORS_ALIGN_INDENT_LEFT
] = {
1008 "cursors-align-indent-left",
1009 "Left align all cursors/selections by inserting spaces",
1010 cursors_align_indent
, { .i
= -1 }
1012 [VIS_ACTION_CURSORS_ALIGN_INDENT_RIGHT
] = {
1013 "cursors-align-indent-right",
1014 "Right align all cursors/selections by inserting spaces",
1015 cursors_align_indent
, { .i
= +1 }
1017 [VIS_ACTION_CURSORS_REMOVE_ALL
] = {
1018 "cursors-remove-all",
1019 "Remove all but the primary cursor",
1022 [VIS_ACTION_CURSORS_REMOVE_LAST
] = {
1023 "cursors-remove-last",
1024 "Remove least recently created cursor",
1027 [VIS_ACTION_CURSORS_REMOVE_COLUMN
] = {
1028 "cursors-remove-column",
1029 "Remove count cursor column",
1030 cursors_remove_column
, { .i
= 1 }
1032 [VIS_ACTION_CURSORS_REMOVE_COLUMN_EXCEPT
] = {
1033 "cursors-remove-column-except",
1034 "Remove all but the count cursor column",
1035 cursors_remove_column_except
, { .i
= 1 }
1037 [VIS_ACTION_CURSORS_PREV
] = {
1039 "Move to the previous cursor",
1040 cursors_navigate
, { .i
= -PAGE_HALF
}
1042 [VIS_ACTION_CURSORS_NEXT
] = {
1044 "Move to the next cursor",
1045 cursors_navigate
, { .i
= +PAGE_HALF
}
1047 [VIS_ACTION_SELECTIONS_ROTATE_LEFT
] = {
1048 "selections-rotate-left",
1049 "Rotate selections left",
1050 selections_rotate
, { .i
= -1 }
1052 [VIS_ACTION_SELECTIONS_ROTATE_RIGHT
] = {
1053 "selections-rotate-right",
1054 "Rotate selections right",
1055 selections_rotate
, { .i
= +1 }
1057 [VIS_ACTION_SELECTIONS_TRIM
] = {
1059 "Remove leading and trailing white space from selections",
1062 [VIS_ACTION_TEXT_OBJECT_WORD_OUTER
] = {
1063 "text-object-word-outer",
1064 "A word leading and trailing whitespace included",
1065 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_WORD
}
1067 [VIS_ACTION_TEXT_OBJECT_WORD_INNER
] = {
1068 "text-object-word-inner",
1069 "A word leading and trailing whitespace excluded",
1070 textobj
, { .i
= VIS_TEXTOBJECT_INNER_WORD
}
1072 [VIS_ACTION_TEXT_OBJECT_LONGWORD_OUTER
] = {
1073 "text-object-longword-outer",
1074 "A WORD leading and trailing whitespace included",
1075 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_LONGWORD
}
1077 [VIS_ACTION_TEXT_OBJECT_LONGWORD_INNER
] = {
1078 "text-object-longword-inner",
1079 "A WORD leading and trailing whitespace excluded",
1080 textobj
, { .i
= VIS_TEXTOBJECT_INNER_LONGWORD
}
1082 [VIS_ACTION_TEXT_OBJECT_SENTENCE
] = {
1083 "text-object-sentence",
1085 textobj
, { .i
= VIS_TEXTOBJECT_SENTENCE
}
1087 [VIS_ACTION_TEXT_OBJECT_PARAGRAPH
] = {
1088 "text-object-paragraph",
1090 textobj
, { .i
= VIS_TEXTOBJECT_PARAGRAPH
}
1092 [VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_OUTER
] = {
1093 "text-object-square-bracket-outer",
1094 "[] block (outer variant)",
1095 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_SQUARE_BRACKET
}
1097 [VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_INNER
] = {
1098 "text-object-square-bracket-inner",
1099 "[] block (inner variant)",
1100 textobj
, { .i
= VIS_TEXTOBJECT_INNER_SQUARE_BRACKET
}
1102 [VIS_ACTION_TEXT_OBJECT_PARANTHESE_OUTER
] = {
1103 "text-object-parentheses-outer",
1104 "() block (outer variant)",
1105 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_PARANTHESE
}
1107 [VIS_ACTION_TEXT_OBJECT_PARANTHESE_INNER
] = {
1108 "text-object-parentheses-inner",
1109 "() block (inner variant)",
1110 textobj
, { .i
= VIS_TEXTOBJECT_INNER_PARANTHESE
}
1112 [VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_OUTER
] = {
1113 "text-object-angle-bracket-outer",
1114 "<> block (outer variant)",
1115 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_ANGLE_BRACKET
}
1117 [VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_INNER
] = {
1118 "text-object-angle-bracket-inner",
1119 "<> block (inner variant)",
1120 textobj
, { .i
= VIS_TEXTOBJECT_INNER_ANGLE_BRACKET
}
1122 [VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_OUTER
] = {
1123 "text-object-curly-bracket-outer",
1124 "{} block (outer variant)",
1125 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_CURLY_BRACKET
}
1127 [VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_INNER
] = {
1128 "text-object-curly-bracket-inner",
1129 "{} block (inner variant)",
1130 textobj
, { .i
= VIS_TEXTOBJECT_INNER_CURLY_BRACKET
}
1132 [VIS_ACTION_TEXT_OBJECT_QUOTE_OUTER
] = {
1133 "text-object-quote-outer",
1134 "A quoted string, including the quotation marks",
1135 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_QUOTE
}
1137 [VIS_ACTION_TEXT_OBJECT_QUOTE_INNER
] = {
1138 "text-object-quote-inner",
1139 "A quoted string, excluding the quotation marks",
1140 textobj
, { .i
= VIS_TEXTOBJECT_INNER_QUOTE
}
1142 [VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_OUTER
] = {
1143 "text-object-single-quote-outer",
1144 "A single quoted string, including the quotation marks",
1145 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_SINGLE_QUOTE
}
1147 [VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_INNER
] = {
1148 "text-object-single-quote-inner",
1149 "A single quoted string, excluding the quotation marks",
1150 textobj
, { .i
= VIS_TEXTOBJECT_INNER_SINGLE_QUOTE
}
1152 [VIS_ACTION_TEXT_OBJECT_BACKTICK_OUTER
] = {
1153 "text-object-backtick-outer",
1154 "A backtick delimited string (outer variant)",
1155 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_BACKTICK
}
1157 [VIS_ACTION_TEXT_OBJECT_BACKTICK_INNER
] = {
1158 "text-object-backtick-inner",
1159 "A backtick delimited string (inner variant)",
1160 textobj
, { .i
= VIS_TEXTOBJECT_INNER_BACKTICK
}
1162 [VIS_ACTION_TEXT_OBJECT_ENTIRE_OUTER
] = {
1163 "text-object-entire-outer",
1164 "The whole text content",
1165 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_ENTIRE
}
1167 [VIS_ACTION_TEXT_OBJECT_ENTIRE_INNER
] = {
1168 "text-object-entire-inner",
1169 "The whole text content, except for leading and trailing empty lines",
1170 textobj
, { .i
= VIS_TEXTOBJECT_INNER_ENTIRE
}
1172 [VIS_ACTION_TEXT_OBJECT_FUNCTION_OUTER
] = {
1173 "text-object-function-outer",
1174 "A whole C-like function",
1175 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_FUNCTION
}
1177 [VIS_ACTION_TEXT_OBJECT_FUNCTION_INNER
] = {
1178 "text-object-function-inner",
1179 "A whole C-like function body",
1180 textobj
, { .i
= VIS_TEXTOBJECT_INNER_FUNCTION
}
1182 [VIS_ACTION_TEXT_OBJECT_LINE_OUTER
] = {
1183 "text-object-line-outer",
1185 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_LINE
}
1187 [VIS_ACTION_TEXT_OBJECT_LINE_INNER
] = {
1188 "text-object-line-inner",
1189 "The whole line, excluding leading and trailing whitespace",
1190 textobj
, { .i
= VIS_TEXTOBJECT_INNER_LINE
}
1192 [VIS_ACTION_TEXT_OBJECT_INDENTATION
] = {
1193 "text-object-indentation",
1194 "All adjacent lines with the same indentation level as the current one",
1195 textobj
, { .i
= VIS_TEXTOBJECT_INDENTATION
}
1197 [VIS_ACTION_TEXT_OBJECT_SEARCH_FORWARD
] = {
1198 "text-object-search-forward",
1199 "The next search match in forward direction",
1200 textobj
, { .i
= VIS_TEXTOBJECT_SEARCH_FORWARD
}
1202 [VIS_ACTION_TEXT_OBJECT_SEARCH_BACKWARD
] = {
1203 "text-object-search-backward",
1204 "The next search match in backward direction",
1205 textobj
, { .i
= VIS_TEXTOBJECT_SEARCH_BACKWARD
}
1207 [VIS_ACTION_MOTION_CHARWISE
] = {
1209 "Force motion to be charwise",
1210 motiontype
, { .i
= VIS_MOTIONTYPE_CHARWISE
}
1212 [VIS_ACTION_MOTION_LINEWISE
] = {
1214 "Force motion to be linewise",
1215 motiontype
, { .i
= VIS_MOTIONTYPE_LINEWISE
}
1217 [VIS_ACTION_UNICODE_INFO
] = {
1219 "Show Unicode codepoint(s) of character under cursor",
1220 unicode_info
, { .i
= VIS_ACTION_UNICODE_INFO
}
1222 [VIS_ACTION_UTF8_INFO
] = {
1224 "Show UTF-8 encoded codepoint(s) of character under cursor",
1225 unicode_info
, { .i
= VIS_ACTION_UTF8_INFO
}
1227 [VIS_ACTION_NUMBER_INCREMENT
] = {
1229 "Increment number under cursor",
1230 number_increment_decrement
, { .i
= +1 }
1232 [VIS_ACTION_NUMBER_DECREMENT
] = {
1234 "Decrement number under cursor",
1235 number_increment_decrement
, { .i
= -1 }
1237 [VIS_ACTION_OPEN_FILE_UNDER_CURSOR
] = {
1238 "open-file-under-cursor",
1239 "Open file under the cursor",
1240 open_file_under_cursor
, { .b
= false }
1242 [VIS_ACTION_OPEN_FILE_UNDER_CURSOR_NEW_WINDOW
] = {
1243 "open-file-under-cursor-new-window",
1244 "Open file under the cursor in a new window",
1245 open_file_under_cursor
, { .b
= true }
1247 [VIS_ACTION_COMPLETE_WORD
] = {
1249 "Complete word in file",
1252 [VIS_ACTION_COMPLETE_FILENAME
] = {
1253 "complete-filename",
1254 "Complete file name",
1257 [VIS_ACTION_NOP
] = {
1259 "Ignore key, do nothing",
1266 /** key bindings functions */
1268 static const char *nop(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1272 static const char *macro_record(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1273 if (!vis_macro_record_stop(vis
)) {
1276 enum VisRegister reg
= vis_register_from(vis
, keys
[0]);
1277 vis_macro_record(vis
, reg
);
1284 static const char *macro_replay(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1287 enum VisRegister reg
= vis_register_from(vis
, keys
[0]);
1288 vis_macro_replay(vis
, reg
);
1292 static const char *suspend(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1297 static const char *repeat(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1302 static const char *cursors_new(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1303 View
*view
= vis_view(vis
);
1304 for (int count
= vis_count_get_default(vis
, 1); count
> 0; count
--) {
1305 Cursor
*cursor
= NULL
;
1309 cursor
= view_cursors_primary_get(view
);
1312 cursor
= view_cursors(view
);
1315 for (Cursor
*c
= view_cursors(view
); c
; c
= view_cursors_next(c
))
1321 size_t oldpos
= view_cursors_pos(cursor
);
1323 view_line_down(cursor
);
1324 else if (arg
->i
< 0)
1325 view_line_up(cursor
);
1326 size_t newpos
= view_cursors_pos(cursor
);
1327 view_cursors_to(cursor
, oldpos
);
1328 if (!view_cursors_new(view
, newpos
)) {
1330 cursor
= view_cursors_prev(cursor
);
1331 } else if (arg
->i
== +1) {
1332 cursor
= view_cursors_next(cursor
);
1334 view_cursors_primary_set(cursor
);
1337 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
1341 static const char *cursors_align(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1342 View
*view
= vis_view(vis
);
1343 Text
*txt
= vis_text(vis
);
1344 int mincol
= INT_MAX
;
1345 for (Cursor
*c
= view_cursors(view
); c
; c
= view_cursors_next(c
)) {
1346 int col
= view_cursors_cell_get(c
);
1347 if (col
>= 0 && col
< mincol
)
1350 for (Cursor
*c
= view_cursors(view
); c
; c
= view_cursors_next(c
)) {
1351 if (view_cursors_cell_set(c
, mincol
) == -1) {
1352 size_t pos
= view_cursors_pos(c
);
1353 size_t col
= text_line_width_set(txt
, pos
, mincol
);
1354 view_cursors_to(c
, col
);
1360 static const char *cursors_align_indent(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1361 View
*view
= vis_view(vis
);
1362 Text
*txt
= vis_text(vis
);
1363 bool left_align
= arg
->i
< 0;
1364 int columns
= view_cursors_column_count(view
);
1366 for (int i
= 0; i
< columns
; i
++) {
1367 int mincol
= INT_MAX
, maxcol
= 0;
1368 for (Cursor
*c
= view_cursors_column(view
, i
); c
; c
= view_cursors_column_next(c
, i
)) {
1370 Filerange sel
= view_cursors_selection_get(c
);
1371 if (text_range_valid(&sel
))
1372 pos
= left_align
? sel
.start
: sel
.end
;
1374 pos
= view_cursors_pos(c
);
1375 int col
= text_line_width_get(txt
, pos
);
1382 size_t len
= maxcol
- mincol
;
1383 char *buf
= malloc(len
+1);
1386 memset(buf
, ' ', len
);
1388 for (Cursor
*c
= view_cursors_column(view
, i
); c
; c
= view_cursors_column_next(c
, i
)) {
1390 Filerange sel
= view_cursors_selection_get(c
);
1391 if (text_range_valid(&sel
)) {
1392 pos
= left_align
? sel
.start
: sel
.end
;
1395 pos
= view_cursors_pos(c
);
1398 int col
= text_line_width_get(txt
, pos
);
1400 size_t off
= maxcol
- col
;
1402 text_insert(txt
, ipos
, buf
, off
);
1413 static const char *cursors_clear(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1414 View
*view
= vis_view(vis
);
1415 if (view_cursors_multiple(view
))
1416 view_cursors_clear(view
);
1418 view_cursors_selection_clear(view_cursors_primary_get(view
));
1422 static const char *cursors_select(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1423 Text
*txt
= vis_text(vis
);
1424 View
*view
= vis_view(vis
);
1425 for (Cursor
*cursor
= view_cursors(view
); cursor
; cursor
= view_cursors_next(cursor
)) {
1426 Filerange sel
= view_cursors_selection_get(cursor
);
1427 Filerange word
= text_object_word(txt
, view_cursors_pos(cursor
));
1428 if (!text_range_valid(&sel
) && text_range_valid(&word
)) {
1429 view_cursors_selection_set(cursor
, &word
);
1430 view_cursors_to(cursor
, text_char_prev(txt
, word
.end
));
1433 vis_mode_switch(vis
, VIS_MODE_VISUAL
);
1437 static const char *cursors_select_next(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1438 Text
*txt
= vis_text(vis
);
1439 View
*view
= vis_view(vis
);
1440 Cursor
*cursor
= view_cursors_primary_get(view
);
1441 Filerange sel
= view_cursors_selection_get(cursor
);
1442 if (!text_range_valid(&sel
))
1445 char *buf
= text_bytes_alloc0(txt
, sel
.start
, text_range_size(&sel
));
1448 Filerange word
= text_object_word_find_next(txt
, sel
.end
, buf
);
1451 if (text_range_valid(&word
)) {
1452 size_t pos
= text_char_prev(txt
, word
.end
);
1453 cursor
= view_cursors_new(view
, pos
);
1456 view_cursors_selection_set(cursor
, &word
);
1461 static const char *cursors_select_skip(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1462 View
*view
= vis_view(vis
);
1463 Cursor
*cursor
= view_cursors_primary_get(view
);
1464 keys
= cursors_select_next(vis
, keys
, arg
);
1465 if (cursor
!= view_cursors_primary_get(view
))
1466 view_cursors_dispose(cursor
);
1470 static const char *cursors_remove(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1471 View
*view
= vis_view(vis
);
1472 view_cursors_dispose(view_cursors_primary_get(view
));
1473 view_cursor_to(view
, view_cursor_get(view
));
1477 static const char *cursors_remove_column(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1478 View
*view
= vis_view(vis
);
1479 int max
= view_cursors_column_count(view
);
1480 int column
= vis_count_get_default(vis
, arg
->i
) - 1;
1483 if (!view_cursors_multiple(view
)) {
1484 vis_mode_switch(vis
, VIS_MODE_NORMAL
);
1488 for (Cursor
*c
= view_cursors_column(view
, column
), *next
; c
; c
= next
) {
1489 next
= view_cursors_column_next(c
, column
);
1490 view_cursors_dispose(c
);
1493 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
1497 static const char *cursors_remove_column_except(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1498 View
*view
= vis_view(vis
);
1499 int max
= view_cursors_column_count(view
);
1500 int column
= vis_count_get_default(vis
, arg
->i
) - 1;
1503 if (!view_cursors_multiple(view
)) {
1508 Cursor
*cur
= view_cursors(view
);
1509 Cursor
*col
= view_cursors_column(view
, column
);
1510 for (Cursor
*next
; cur
; cur
= next
) {
1511 next
= view_cursors_next(cur
);
1513 col
= view_cursors_column_next(col
, column
);
1515 view_cursors_dispose(cur
);
1518 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
1522 static const char *cursors_navigate(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1523 View
*view
= vis_view(vis
);
1524 if (!view_cursors_multiple(view
)) {
1525 Filerange sel
= view_selection_get(view
);
1526 if (!text_range_valid(&sel
))
1527 return wscroll(vis
, keys
, arg
);
1530 Cursor
*c
= view_cursors_primary_get(view
);
1531 for (int count
= vis_count_get_default(vis
, 1); count
> 0; count
--) {
1533 c
= view_cursors_next(c
);
1535 c
= view_cursors(view
);
1537 c
= view_cursors_prev(c
);
1539 c
= view_cursors(view
);
1540 for (Cursor
*n
= c
; n
; n
= view_cursors_next(n
))
1545 view_cursors_primary_set(c
);
1546 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
1550 static const char *selections_rotate(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1559 Text
*txt
= vis_text(vis
);
1560 View
*view
= vis_view(vis
);
1561 int columns
= view_cursors_column_count(view
);
1562 int selections
= columns
== 1 ? view_cursors_count(view
) : columns
;
1563 int count
= vis_count_get_default(vis
, 1);
1564 array_init_sized(&arr
, sizeof(Rotate
));
1565 if (!array_reserve(&arr
, selections
))
1569 for (Cursor
*c
= view_cursors(view
), *next
; c
; c
= next
) {
1570 next
= view_cursors_next(c
);
1571 size_t line_next
= 0;
1573 Filerange sel
= view_cursors_selection_get(c
);
1576 rot
.len
= text_range_size(&sel
);
1577 if ((rot
.data
= malloc(rot
.len
)))
1578 rot
.len
= text_bytes_get(txt
, sel
.start
, rot
.len
, rot
.data
);
1581 array_add(&arr
, &rot
);
1584 line
= text_lineno_by_pos(txt
, view_cursors_pos(c
));
1586 line_next
= text_lineno_by_pos(txt
, view_cursors_pos(next
));
1587 if (!next
|| (columns
> 1 && line
!= line_next
)) {
1588 size_t len
= array_length(&arr
);
1589 size_t off
= arg
->i
> 0 ? count
% len
: len
- (count
% len
);
1590 for (size_t i
= 0; i
< len
; i
++) {
1591 size_t j
= (i
+ off
) % len
;
1592 Rotate
*oldrot
= array_get(&arr
, i
);
1593 Rotate
*newrot
= array_get(&arr
, j
);
1594 if (!oldrot
|| !newrot
|| oldrot
== newrot
)
1596 Filerange newsel
= view_cursors_selection_get(newrot
->cursor
);
1597 if (!text_range_valid(&newsel
))
1599 if (!text_delete_range(txt
, &newsel
))
1601 if (!text_insert(txt
, newsel
.start
, oldrot
->data
, oldrot
->len
))
1603 newsel
.end
= newsel
.start
+ oldrot
->len
;
1604 view_cursors_selection_set(newrot
->cursor
, &newsel
);
1605 view_cursors_selection_sync(newrot
->cursor
);
1613 vis_count_set(vis
, VIS_COUNT_UNKNOWN
);
1617 static const char *selections_trim(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1618 Text
*txt
= vis_text(vis
);
1619 View
*view
= vis_view(vis
);
1620 for (Cursor
*c
= view_cursors(view
), *next
; c
; c
= next
) {
1621 next
= view_cursors_next(c
);
1622 Filerange sel
= view_cursors_selection_get(c
);
1623 if (!text_range_valid(&sel
))
1625 for (char b
; sel
.start
< sel
.end
&& text_byte_get(txt
, sel
.end
-1, &b
)
1626 && isspace((unsigned char)b
); sel
.end
--);
1627 for (char b
; sel
.start
<= sel
.end
&& text_byte_get(txt
, sel
.start
, &b
)
1628 && isspace((unsigned char)b
); sel
.start
++);
1629 if (sel
.start
< sel
.end
) {
1630 view_cursors_selection_set(c
, &sel
);
1631 view_cursors_selection_sync(c
);
1632 } else if (!view_cursors_dispose(c
)) {
1633 vis_mode_switch(vis
, VIS_MODE_NORMAL
);
1639 static const char *replace(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1641 vis_keymap_disable(vis
);
1645 const char *next
= vis_keys_next(vis
, keys
);
1649 char replacement
[64];
1650 size_t len
= next
- keys
;
1651 if (len
>= sizeof(replacement
))
1654 memcpy(replacement
, keys
, len
);
1655 replacement
[len
] = '\0';
1657 if (strcmp("<Escape>", replacement
) == 0)
1660 if (vis_mode_get(vis
) == VIS_MODE_NORMAL
) {
1661 int count
= vis_count_get_default(vis
, 1);
1662 vis_operator(vis
, VIS_OP_CHANGE
);
1663 vis_motion(vis
, VIS_MOVE_CHAR_NEXT
);
1664 for (; count
> 0; count
--)
1665 vis_keys_feed(vis
, replacement
);
1667 vis_operator(vis
, VIS_OP_REPLACE
, replacement
);
1670 vis_keys_feed(vis
, "<Escape>");
1674 static const char *count(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1675 int digit
= keys
[-1] - '0';
1676 int count
= vis_count_get_default(vis
, 0);
1677 if (0 <= digit
&& digit
<= 9) {
1678 if (digit
== 0 && count
== 0)
1679 vis_motion(vis
, VIS_MOVE_LINE_BEGIN
);
1680 vis_count_set(vis
, count
* 10 + digit
);
1685 static const char *gotoline(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1686 if (vis_count_get(vis
) != VIS_COUNT_UNKNOWN
)
1687 vis_motion(vis
, VIS_MOVE_LINE
);
1688 else if (arg
->i
< 0)
1689 vis_motion(vis
, VIS_MOVE_FILE_BEGIN
);
1691 vis_motion(vis
, VIS_MOVE_FILE_END
);
1695 static const char *motiontype(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1696 vis_motion_type(vis
, arg
->i
);
1700 static const char *operator(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1701 vis_operator(vis
, arg
->i
);
1705 static const char *operator_filter(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1706 vis_operator(vis
, VIS_OP_FILTER
, arg
->s
);
1710 static const char *movement_key(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1713 if (!keys
[0] || !(next
= vis_keys_next(vis
, keys
)))
1715 size_t len
= next
- keys
;
1716 if (len
< sizeof key
) {
1717 strncpy(key
, keys
, len
);
1719 vis_motion(vis
, arg
->i
, key
);
1724 static const char *movement(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1725 vis_motion(vis
, arg
->i
);
1729 static const char *textobj(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1730 vis_textobject(vis
, arg
->i
);
1734 static const char *selection_end(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1735 for (Cursor
*c
= view_cursors(vis_view(vis
)); c
; c
= view_cursors_next(c
))
1736 view_cursors_selection_swap(c
);
1740 static const char *selection_restore(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1741 Text
*txt
= vis_text(vis
);
1742 View
*view
= vis_view(vis
);
1743 for (Cursor
*c
= view_cursors(view
); c
; c
= view_cursors_next(c
))
1744 view_cursors_selection_restore(c
);
1745 Filerange sel
= view_selection_get(view
);
1746 if (text_range_is_linewise(txt
, &sel
))
1747 vis_mode_switch(vis
, VIS_MODE_VISUAL_LINE
);
1749 vis_mode_switch(vis
, VIS_MODE_VISUAL
);
1753 static const char *reg(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1756 enum VisRegister reg
= vis_register_from(vis
, keys
[0]);
1757 vis_register_set(vis
, reg
);
1761 static const char *mark_set(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1764 vis_mark_set(vis
, vis_mark_from(vis
, keys
[0]), view_cursor_get(vis_view(vis
)));
1768 static const char *mark_motion(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1771 vis_motion(vis
, arg
->i
, vis_mark_from(vis
, keys
[0]));
1775 static const char *undo(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1776 size_t pos
= text_undo(vis_text(vis
));
1778 View
*view
= vis_view(vis
);
1779 if (!view_cursors_multiple(view
))
1780 view_cursor_to(view
, pos
);
1781 /* redraw all windows in case some display the same file */
1787 static const char *redo(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1788 size_t pos
= text_redo(vis_text(vis
));
1790 View
*view
= vis_view(vis
);
1791 if (!view_cursors_multiple(view
))
1792 view_cursor_to(view
, pos
);
1793 /* redraw all windows in case some display the same file */
1799 static const char *earlier(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1800 size_t pos
= text_earlier(vis_text(vis
), vis_count_get_default(vis
, 1));
1802 view_cursor_to(vis_view(vis
), pos
);
1803 /* redraw all windows in case some display the same file */
1809 static const char *later(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1810 size_t pos
= text_later(vis_text(vis
), vis_count_get_default(vis
, 1));
1812 view_cursor_to(vis_view(vis
), pos
);
1813 /* redraw all windows in case some display the same file */
1819 static const char *delete(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1820 vis_operator(vis
, VIS_OP_DELETE
);
1821 vis_motion(vis
, arg
->i
);
1825 static const char *insert_register(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1828 enum VisRegister reg
= vis_register_from(vis
, keys
[0]);
1830 const char *data
= vis_register_get(vis
, reg
, &len
);
1831 vis_insert_key(vis
, data
, len
);
1835 static const char *prompt_show(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1836 vis_prompt_show(vis
, arg
->s
);
1840 static const char *insert_verbatim(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1842 char buf
[4], type
= keys
[0];
1843 const char *data
= NULL
;
1844 int len
= 0, count
= 0, base
= 0;
1866 if ('0' <= type
&& type
<= '9') {
1875 for (keys
++; keys
[0] && count
> 0; keys
++, count
--) {
1877 if (base
== 8 && '0' <= keys
[0] && keys
[0] <= '7') {
1879 } else if ((base
== 10 || base
== 16) && '0' <= keys
[0] && keys
[0] <= '9') {
1881 } else if (base
== 16 && 'a' <= keys
[0] && keys
[0] <= 'f') {
1882 v
= 10 + keys
[0] - 'a';
1883 } else if (base
== 16 && 'A' <= keys
[0] && keys
[0] <= 'F') {
1884 v
= 10 + keys
[0] - 'A';
1889 rune
= rune
* base
+ v
;
1894 if (type
== 'u' || type
== 'U') {
1895 len
= runetochar(buf
, &rune
);
1903 const char *next
= vis_keys_next(vis
, keys
);
1906 if ((rune
= vis_keys_codepoint(vis
, keys
)) != (Rune
)-1) {
1907 len
= runetochar(buf
, &rune
);
1910 vis_info_show(vis
, "Unknown key");
1916 vis_insert_key(vis
, data
, len
);
1920 static const char *wscroll(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1921 View
*view
= vis_view(vis
);
1922 int count
= vis_count_get(vis
);
1925 view_scroll_page_up(view
);
1928 view_scroll_page_down(view
);
1931 view_scroll_halfpage_up(view
);
1934 view_scroll_halfpage_down(view
);
1937 if (count
== VIS_COUNT_UNKNOWN
)
1938 count
= arg
->i
< 0 ? -arg
->i
: arg
->i
;
1940 view_scroll_up(view
, count
);
1942 view_scroll_down(view
, count
);
1948 static const char *wslide(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1949 View
*view
= vis_view(vis
);
1950 int count
= vis_count_get(vis
);
1951 if (count
== VIS_COUNT_UNKNOWN
)
1952 count
= arg
->i
< 0 ? -arg
->i
: arg
->i
;
1954 view_slide_down(view
, count
);
1956 view_slide_up(view
, count
);
1960 static const char *call(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1965 static const char *window(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1966 arg
->w(vis_view(vis
));
1970 static const char *openline(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1971 vis_operator(vis
, VIS_OP_MODESWITCH
, VIS_MODE_INSERT
);
1973 vis_motion(vis
, VIS_MOVE_LINE_END
);
1974 vis_keys_feed(vis
, "<insert-newline>");
1976 if (vis_get_autoindent(vis
)) {
1977 vis_motion(vis
, VIS_MOVE_LINE_START
);
1979 vis_motion(vis
, VIS_MOVE_LINE_BEGIN
);
1981 vis_keys_feed(vis
, "<insert-newline><Up>");
1986 static const char *join(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1987 bool normal
= (vis_mode_get(vis
) == VIS_MODE_NORMAL
);
1988 vis_operator(vis
, VIS_OP_JOIN
, arg
->s
);
1990 int count
= vis_count_get_default(vis
, 0);
1992 vis_count_set(vis
, count
-1);
1993 vis_motion(vis
, VIS_MOVE_LINE_NEXT
);
1998 static const char *switchmode(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1999 vis_mode_switch(vis
, arg
->i
);
2003 static const char *insertmode(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2004 vis_operator(vis
, VIS_OP_MODESWITCH
, VIS_MODE_INSERT
);
2005 vis_motion(vis
, arg
->i
);
2009 static const char *unicode_info(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2010 View
*view
= vis_view(vis
);
2011 Text
*txt
= vis_text(vis
);
2012 size_t start
= view_cursor_get(view
);
2013 size_t end
= text_char_next(txt
, start
);
2014 char *grapheme
= text_bytes_alloc0(txt
, start
, end
-start
), *codepoint
= grapheme
;
2019 mbstate_t ps
= { 0 };
2020 Iterator it
= text_iterator_get(txt
, start
);
2021 for (size_t pos
= start
; it
.pos
< end
; pos
= it
.pos
) {
2022 text_iterator_codepoint_next(&it
, NULL
);
2023 size_t len
= it
.pos
- pos
;
2024 wchar_t wc
= 0xFFFD;
2025 size_t res
= mbrtowc(&wc
, codepoint
, len
, &ps
);
2026 bool combining
= false;
2027 if (res
!= (size_t)-1 && res
!= (size_t)-2)
2028 combining
= (wc
!= L
'\0' && wcwidth(wc
) == 0);
2029 unsigned char ch
= *codepoint
;
2030 if (ch
< 128 && !isprint(ch
))
2031 buffer_appendf(&info
, "<^%c> ", ch
== 127 ? '?' : ch
+ 64);
2033 buffer_appendf(&info
, "<%s%.*s> ", combining
? " " : "", (int)len
, codepoint
);
2034 if (arg
->i
== VIS_ACTION_UNICODE_INFO
) {
2035 buffer_appendf(&info
, "U+%04x ", wc
);
2037 for (size_t i
= 0; i
< len
; i
++)
2038 buffer_appendf(&info
, "%02x ", (uint8_t)codepoint
[i
]);
2042 vis_info_show(vis
, "%s", buffer_content0(&info
));
2044 buffer_release(&info
);
2048 static const char *percent(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2049 if (vis_count_get(vis
) == VIS_COUNT_UNKNOWN
)
2050 vis_motion(vis
, VIS_MOVE_BRACKET_MATCH
);
2052 vis_motion(vis
, VIS_MOVE_PERCENT
);
2056 static const char *number_increment_decrement(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2057 View
*view
= vis_view(vis
);
2058 Text
*txt
= vis_text(vis
);
2061 int count
= vis_count_get(vis
);
2062 if (count
!= 0 && count
!= VIS_COUNT_UNKNOWN
)
2065 for (Cursor
*c
= view_cursors(view
); c
; c
= view_cursors_next(c
)) {
2066 Filerange r
= text_object_number(txt
, view_cursors_pos(c
));
2067 if (!text_range_valid(&r
))
2069 char *buf
= text_bytes_alloc0(txt
, r
.start
, text_range_size(&r
));
2071 char *number
= buf
, fmt
[255];
2072 if (number
[0] == '-')
2074 bool octal
= number
[0] == '0' && ('0' <= number
[1] && number
[1] <= '7');
2075 bool hex
= number
[0] == '0' && (number
[1] == 'x' || number
[1] == 'X');
2076 bool dec
= !hex
&& !octal
;
2078 long long value
= strtoll(buf
, NULL
, 0);
2081 snprintf(fmt
, sizeof fmt
, "%lld", value
);
2083 size_t len
= strlen(number
) - 2;
2084 snprintf(fmt
, sizeof fmt
, "0x%0*llx", (int)len
, value
);
2086 size_t len
= strlen(number
) - 1;
2087 snprintf(fmt
, sizeof fmt
, "0%0*llo", (int)len
, value
);
2089 text_delete_range(txt
, &r
);
2090 text_insert(txt
, r
.start
, fmt
, strlen(fmt
));
2091 view_cursors_to(c
, r
.start
);
2101 static const char *open_file_under_cursor(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2102 View
*view
= vis_view(vis
);
2103 Text
*txt
= vis_text(vis
);
2104 char cmd
[PATH_MAX
], name
[PATH_MAX
];
2106 for (Cursor
*c
= view_cursors(view
); c
; c
= view_cursors_next(c
)) {
2107 Filerange r
= text_object_filename(txt
, view_cursors_pos(c
));
2108 if (!text_range_valid(&r
))
2110 size_t len
= text_range_size(&r
);
2111 if (len
>= sizeof(cmd
)-10)
2113 len
= text_bytes_get(txt
, r
.start
, text_range_size(&r
), name
);
2115 snprintf(cmd
, sizeof cmd
, "%s '%s'", arg
->b
? "o" : "e", name
);
2116 if (vis_cmd(vis
, cmd
) && !arg
->b
)
2123 static char *get_completion_prefix(Vis
*vis
, Filerange (*text_object
)(Text
*, size_t)) {
2124 View
*view
= vis_view(vis
);
2125 Text
*txt
= vis_text(vis
);
2126 size_t pos
= view_cursor_get(view
);
2127 Filerange r
= text_object(txt
, pos
-1);
2128 r
= text_range_inner(txt
, &r
);
2131 size_t size
= text_range_size(&r
);
2133 vis_info_show(vis
, "No valid prefix found for completion");
2137 return text_bytes_alloc0(txt
, r
.start
, size
);
2140 static void insert_dialog_selection(Vis
*vis
, Filerange
*range
, const char *argv
[]) {
2141 char *out
= NULL
, *err
= NULL
;
2142 if (vis_pipe_collect(vis
, range
, argv
, &out
, &err
) == 0) {
2143 View
*view
= vis_view(vis
);
2144 size_t len
= out
? strlen(out
) : 0;
2145 for (Cursor
*c
= view_cursors(view
); c
; c
= view_cursors_next(c
)) {
2146 size_t pos
= view_cursors_pos(c
);
2147 vis_insert(vis
, pos
, out
, len
);
2148 view_cursors_scroll_to(c
, pos
+ len
);
2151 vis_info_show(vis
, "Completion command failed, is vis-menu in $PATH?");
2158 static const char *complete_word(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2159 Text
*txt
= vis_text(vis
);
2162 char *prefix
= get_completion_prefix(vis
, text_object_word
);
2163 if (prefix
&& buffer_printf(&cmd
, VIS_COMPLETE
" --word '%s'", prefix
)) {
2164 Filerange all
= text_range_new(0, text_size(txt
));
2165 insert_dialog_selection(vis
, &all
, (const char*[]){ buffer_content0(&cmd
), NULL
});
2167 buffer_release(&cmd
);
2172 static const char *complete_filename(Vis
*vis
, const char *keys
, const Arg
*arg
) {
2175 char *prefix
= get_completion_prefix(vis
, text_object_filename
);
2176 if (prefix
&& buffer_printf(&cmd
, VIS_COMPLETE
" --file '%s'", prefix
)) {
2177 Filerange empty
= text_range_new(0, 0);
2178 insert_dialog_selection(vis
, &empty
, (const char*[]){ buffer_content0(&cmd
), NULL
});
2180 buffer_release(&cmd
);
2187 static void signal_handler(int signum
, siginfo_t
*siginfo
, void *context
) {
2188 vis_signal_handler(vis
, signum
, siginfo
, context
);
2191 int main(int argc
, char *argv
[]) {
2194 .init
= vis_lua_init
,
2195 .start
= vis_lua_start
,
2196 .quit
= vis_lua_quit
,
2197 .mode_insert_input
= vis_lua_mode_insert_input
,
2198 .mode_replace_input
= vis_lua_mode_replace_input
,
2199 .file_open
= vis_lua_file_open
,
2200 .file_save_pre
= vis_lua_file_save_pre
,
2201 .file_save_post
= vis_lua_file_save_post
,
2202 .file_close
= vis_lua_file_close
,
2203 .win_open
= vis_lua_win_open
,
2204 .win_close
= vis_lua_win_close
,
2205 .win_highlight
= vis_lua_win_highlight
,
2206 .win_syntax
= vis_lua_win_syntax
,
2207 .win_status
= vis_lua_win_status
,
2210 vis
= vis_new(ui_curses_new(), &event
);
2212 return EXIT_FAILURE
;
2214 for (int i
= 0; i
< LENGTH(vis_action
); i
++) {
2215 const KeyAction
*action
= &vis_action
[i
];
2216 if (!vis_action_register(vis
, action
))
2217 vis_die(vis
, "Could not register action: %s\n", action
->name
);
2220 for (int i
= 0; i
< LENGTH(default_bindings
); i
++) {
2221 for (const KeyBinding
**binding
= default_bindings
[i
]; binding
&& *binding
; binding
++) {
2222 for (const KeyBinding
*kb
= *binding
; kb
->key
; kb
++) {
2223 vis_mode_map(vis
, i
, false, kb
->key
, kb
);
2228 for (const char **k
= keymaps
; k
[0]; k
+= 2)
2229 vis_keymap_add(vis
, k
[0], k
[1]);
2231 /* install signal handlers etc. */
2232 struct sigaction sa
;
2233 memset(&sa
, 0, sizeof sa
);
2234 sigfillset(&sa
.sa_mask
);
2235 sa
.sa_flags
= SA_SIGINFO
;
2236 sa
.sa_sigaction
= signal_handler
;
2237 if (sigaction(SIGBUS
, &sa
, NULL
) == -1 ||
2238 sigaction(SIGINT
, &sa
, NULL
) == -1 ||
2239 sigaction(SIGCONT
, &sa
, NULL
) == -1 ||
2240 sigaction(SIGWINCH
, &sa
, NULL
) == -1 ||
2241 sigaction(SIGTERM
, &sa
, NULL
) == -1 ||
2242 sigaction(SIGHUP
, &sa
, NULL
) == -1) {
2243 vis_die(vis
, "Failed to set signal handler: %s\n", strerror(errno
));
2246 sa
.sa_handler
= SIG_IGN
;
2247 if (sigaction(SIGPIPE
, &sa
, NULL
) == -1)
2248 vis_die(vis
, "Failed to ignore SIGPIPE\n");
2251 sigemptyset(&blockset
);
2252 sigaddset(&blockset
, SIGBUS
);
2253 sigaddset(&blockset
, SIGINT
);
2254 sigaddset(&blockset
, SIGCONT
);
2255 sigaddset(&blockset
, SIGWINCH
);
2256 sigaddset(&blockset
, SIGTERM
);
2257 sigaddset(&blockset
, SIGHUP
);
2258 if (sigprocmask(SIG_BLOCK
, &blockset
, NULL
) == -1)
2259 vis_die(vis
, "Failed to block signals\n");
2261 for (int i
= 1; i
< argc
; i
++) {
2262 if (argv
[i
][0] != '-') {
2264 } else if (strcmp(argv
[i
], "-") == 0) {
2266 } else if (strcmp(argv
[i
], "--") == 0) {
2268 } else if (strcmp(argv
[i
], "-v") == 0) {
2269 puts("vis " VERSION
);
2272 fprintf(stderr
, "Unknown command option: %s\n", argv
[i
]);
2278 bool end_of_options
= false, win_created
= false;
2280 for (int i
= 1; i
< argc
; i
++) {
2281 if (argv
[i
][0] == '-' && !end_of_options
) {
2282 if (strcmp(argv
[i
], "-") == 0) {
2283 if (!vis_window_new_fd(vis
, STDOUT_FILENO
))
2284 vis_die(vis
, "Can not create empty buffer\n");
2287 Text
*txt
= vis_text(vis
);
2288 while ((len
= read(STDIN_FILENO
, buf
, sizeof buf
)) > 0)
2289 text_insert(txt
, text_size(txt
), buf
, len
);
2291 vis_die(vis
, "Can not read from stdin\n");
2293 int fd
= open("/dev/tty", O_RDWR
);
2295 vis_die(vis
, "Can not reopen stdin\n");
2296 dup2(fd
, STDIN_FILENO
);
2298 } else if (strcmp(argv
[i
], "--") == 0) {
2299 end_of_options
= true;
2301 } else if (argv
[i
][0] == '+' && !end_of_options
) {
2302 cmd
= argv
[i
] + (argv
[i
][1] == '/' || argv
[i
][1] == '?');
2303 } else if (!vis_window_new(vis
, argv
[i
])) {
2304 vis_die(vis
, "Can not load `%s': %s\n", argv
[i
], strerror(errno
));
2308 vis_prompt_cmd(vis
, cmd
);
2314 if (!vis_window(vis
) && !win_created
) {
2315 if (!vis_window_new(vis
, NULL
))
2316 vis_die(vis
, "Can not create empty buffer\n");
2318 vis_prompt_cmd(vis
, cmd
);
2321 int status
= vis_run(vis
, argc
, argv
);