9 #include "text-motions.h"
10 #include "text-objects.h"
15 #define PAGE_HALF (INT_MAX-1)
17 /** functions to be called from keybindings */
18 /* ignore key, do nothing */
19 static const char *nop(Vis
*, const char *keys
, const Arg
*arg
);
20 /* record/replay macro indicated by keys */
21 static const char *macro_record(Vis
*, const char *keys
, const Arg
*arg
);
22 static const char *macro_replay(Vis
*, const char *keys
, const Arg
*arg
);
23 /* temporarily suspend the editor and return to the shell, type 'fg' to get back */
24 static const char *suspend(Vis
*, const char *keys
, const Arg
*arg
);
25 /* switch to mode indicated by arg->i */
26 static const char *switchmode(Vis
*, const char *keys
, const Arg
*arg
);
27 /* switch to insert mode after performing movement indicated by arg->i */
28 static const char *insertmode(Vis
*, const char *keys
, const Arg
*arg
);
29 /* set mark indicated by keys to current cursor position */
30 static const char *mark_set(Vis
*, const char *keys
, const Arg
*arg
);
31 /* add a new line either before or after the one where the cursor currently is */
32 static const char *openline(Vis
*, const char *keys
, const Arg
*arg
);
33 /* join lines from current cursor position to movement indicated by arg */
34 static const char *join(Vis
*, const char *keys
, const Arg
*arg
);
35 /* execute arg->s as if it was typed on command prompt */
36 static const char *cmd(Vis
*, const char *keys
, const Arg
*arg
);
37 /* perform last action i.e. action_prev again */
38 static const char *repeat(Vis
*, const char *keys
, const Arg
*arg
);
39 /* replace character at cursor with one from keys */
40 static const char *replace(Vis
*, const char *keys
, const Arg
*arg
);
41 /* create a new cursor on the previous (arg->i < 0) or next (arg->i > 0) line */
42 static const char *cursors_new(Vis
*, const char *keys
, const Arg
*arg
);
43 /* try to align all cursors on the same column */
44 static const char *cursors_align(Vis
*, const char *keys
, const Arg
*arg
);
45 /* remove all but the primary cursor and their selections */
46 static const char *cursors_clear(Vis
*, const char *keys
, const Arg
*arg
);
47 /* remove the least recently added cursor */
48 static const char *cursors_remove(Vis
*, const char *keys
, const Arg
*arg
);
49 /* select the word the cursor is currently over */
50 static const char *cursors_select(Vis
*, const char *keys
, const Arg
*arg
);
51 /* select the next region matching the current selection */
52 static const char *cursors_select_next(Vis
*, const char *keys
, const Arg
*arg
);
53 /* clear current selection but select next match */
54 static const char *cursors_select_skip(Vis
*, const char *keys
, const Arg
*arg
);
55 /* adjust current used count according to keys */
56 static const char *count(Vis
*, const char *keys
, const Arg
*arg
);
57 /* move to the count-th line or if not given either to the first (arg->i < 0)
58 * or last (arg->i > 0) line of file */
59 static const char *gotoline(Vis
*, const char *keys
, const Arg
*arg
);
60 /* set motion type either LINEWISE or CHARWISE via arg->i */
61 static const char *motiontype(Vis
*, const char *keys
, const Arg
*arg
);
62 /* make the current action use the operator indicated by arg->i */
63 static const char *operator(Vis
*, const char *keys
, const Arg
*arg
);
64 /* blocks to read a key and performs movement indicated by arg->i which
65 * should be one of VIS_MOVE_{RIGHT,LEFT}_{TO,TILL} */
66 static const char *movement_key(Vis
*, const char *keys
, const Arg
*arg
);
67 /* perform the movement as indicated by arg->i */
68 static const char *movement(Vis
*, const char *keys
, const Arg
*arg
);
69 /* let the current operator affect the range indicated by the text object arg->i */
70 static const char *textobj(Vis
*, const char *keys
, const Arg
*arg
);
71 /* move to the other end of selected text */
72 static const char *selection_end(Vis
*, const char *keys
, const Arg
*arg
);
73 /* restore least recently used selection */
74 static const char *selection_restore(Vis
*, const char *keys
, const Arg
*arg
);
75 /* use register indicated by keys for the current operator */
76 static const char *reg(Vis
*, const char *keys
, const Arg
*arg
);
77 /* perform arg->i motion with a mark indicated by keys as argument */
78 static const char *mark_motion(Vis
*, const char *keys
, const Arg
*arg
);
79 /* {un,re}do last action, redraw window */
80 static const char *undo(Vis
*, const char *keys
, const Arg
*arg
);
81 static const char *redo(Vis
*, const char *keys
, const Arg
*arg
);
82 /* earlier, later action chronologically, redraw window */
83 static const char *earlier(Vis
*, const char *keys
, const Arg
*arg
);
84 static const char *later(Vis
*, const char *keys
, const Arg
*arg
);
85 /* delete from the current cursor position to the end of
86 * movement as indicated by arg->i */
87 static const char *delete(Vis
*, const char *keys
, const Arg
*arg
);
88 /* insert register content indicated by keys at current cursor position */
89 static const char *insert_register(Vis
*, const char *keys
, const Arg
*arg
);
90 /* show a user prompt to get input with title arg->s */
91 static const char *prompt_search(Vis
*, const char *keys
, const Arg
*arg
);
92 static const char *prompt_cmd(Vis
*, const char *keys
, const Arg
*arg
);
93 /* exit command mode if the last char is deleted */
94 static const char *prompt_backspace(Vis
*, const char *keys
, const Arg
*arg
);
95 /* blocks to read 3 consecutive digits and inserts the corresponding byte value */
96 static const char *insert_verbatim(Vis
*, const char *keys
, const Arg
*arg
);
97 /* scroll window content according to arg->i which can be either PAGE, PAGE_HALF,
98 * or an arbitrary number of lines. a multiplier overrides what is given in arg->i.
99 * negative values scroll back, positive forward. */
100 static const char *wscroll(Vis
*, const char *keys
, const Arg
*arg
);
101 /* similar to scroll, but do only move window content not cursor position */
102 static const char *wslide(Vis
*, const char *keys
, const Arg
*arg
);
103 /* call editor function as indicated by arg->f */
104 static const char *call(Vis
*, const char *keys
, const Arg
*arg
);
105 /* call window function as indicated by arg->w */
106 static const char *window(Vis
*, const char *keys
, const Arg
*arg
);
109 VIS_ACTION_EDITOR_SUSPEND
,
110 VIS_ACTION_CURSOR_CHAR_PREV
,
111 VIS_ACTION_CURSOR_CHAR_NEXT
,
112 VIS_ACTION_CURSOR_WORD_START_PREV
,
113 VIS_ACTION_CURSOR_WORD_START_NEXT
,
114 VIS_ACTION_CURSOR_WORD_END_PREV
,
115 VIS_ACTION_CURSOR_WORD_END_NEXT
,
116 VIS_ACTION_CURSOR_LONGWORD_START_PREV
,
117 VIS_ACTION_CURSOR_LONGWORD_START_NEXT
,
118 VIS_ACTION_CURSOR_LONGWORD_END_PREV
,
119 VIS_ACTION_CURSOR_LONGWORD_END_NEXT
,
120 VIS_ACTION_CURSOR_LINE_UP
,
121 VIS_ACTION_CURSOR_LINE_DOWN
,
122 VIS_ACTION_CURSOR_LINE_START
,
123 VIS_ACTION_CURSOR_LINE_FINISH
,
124 VIS_ACTION_CURSOR_LINE_BEGIN
,
125 VIS_ACTION_CURSOR_LINE_END
,
126 VIS_ACTION_CURSOR_SCREEN_LINE_UP
,
127 VIS_ACTION_CURSOR_SCREEN_LINE_DOWN
,
128 VIS_ACTION_CURSOR_SCREEN_LINE_BEGIN
,
129 VIS_ACTION_CURSOR_SCREEN_LINE_MIDDLE
,
130 VIS_ACTION_CURSOR_SCREEN_LINE_END
,
131 VIS_ACTION_CURSOR_BRACKET_MATCH
,
132 VIS_ACTION_CURSOR_PARAGRAPH_PREV
,
133 VIS_ACTION_CURSOR_PARAGRAPH_NEXT
,
134 VIS_ACTION_CURSOR_SENTENCE_PREV
,
135 VIS_ACTION_CURSOR_SENTENCE_NEXT
,
136 VIS_ACTION_CURSOR_FUNCTION_START_PREV
,
137 VIS_ACTION_CURSOR_FUNCTION_END_PREV
,
138 VIS_ACTION_CURSOR_FUNCTION_START_NEXT
,
139 VIS_ACTION_CURSOR_FUNCTION_END_NEXT
,
140 VIS_ACTION_CURSOR_COLUMN
,
141 VIS_ACTION_CURSOR_LINE_FIRST
,
142 VIS_ACTION_CURSOR_LINE_LAST
,
143 VIS_ACTION_CURSOR_WINDOW_LINE_TOP
,
144 VIS_ACTION_CURSOR_WINDOW_LINE_MIDDLE
,
145 VIS_ACTION_CURSOR_WINDOW_LINE_BOTTOM
,
146 VIS_ACTION_CURSOR_SEARCH_NEXT
,
147 VIS_ACTION_CURSOR_SEARCH_PREV
,
148 VIS_ACTION_CURSOR_SEARCH_WORD_FORWARD
,
149 VIS_ACTION_CURSOR_SEARCH_WORD_BACKWARD
,
150 VIS_ACTION_WINDOW_PAGE_UP
,
151 VIS_ACTION_WINDOW_PAGE_DOWN
,
152 VIS_ACTION_WINDOW_HALFPAGE_UP
,
153 VIS_ACTION_WINDOW_HALFPAGE_DOWN
,
154 VIS_ACTION_MODE_NORMAL
,
155 VIS_ACTION_MODE_VISUAL
,
156 VIS_ACTION_MODE_VISUAL_LINE
,
157 VIS_ACTION_MODE_INSERT
,
158 VIS_ACTION_MODE_REPLACE
,
159 VIS_ACTION_MODE_OPERATOR_PENDING
,
160 VIS_ACTION_DELETE_CHAR_PREV
,
161 VIS_ACTION_DELETE_CHAR_NEXT
,
162 VIS_ACTION_DELETE_LINE_BEGIN
,
163 VIS_ACTION_DELETE_WORD_PREV
,
164 VIS_ACTION_JUMPLIST_PREV
,
165 VIS_ACTION_JUMPLIST_NEXT
,
166 VIS_ACTION_CHANGELIST_PREV
,
167 VIS_ACTION_CHANGELIST_NEXT
,
172 VIS_ACTION_MACRO_RECORD
,
173 VIS_ACTION_MACRO_REPLAY
,
175 VIS_ACTION_MARK_GOTO
,
176 VIS_ACTION_MARK_GOTO_LINE
,
178 VIS_ACTION_REPLACE_CHAR
,
179 VIS_ACTION_TOTILL_REPEAT
,
180 VIS_ACTION_TOTILL_REVERSE
,
181 VIS_ACTION_PROMPT_SEARCH_FORWARD
,
182 VIS_ACTION_PROMPT_SEARCH_BACKWARD
,
183 VIS_ACTION_TILL_LEFT
,
184 VIS_ACTION_TILL_RIGHT
,
188 VIS_ACTION_OPERATOR_CHANGE
,
189 VIS_ACTION_OPERATOR_DELETE
,
190 VIS_ACTION_OPERATOR_YANK
,
191 VIS_ACTION_OPERATOR_SHIFT_LEFT
,
192 VIS_ACTION_OPERATOR_SHIFT_RIGHT
,
193 VIS_ACTION_OPERATOR_CASE_LOWER
,
194 VIS_ACTION_OPERATOR_CASE_UPPER
,
195 VIS_ACTION_OPERATOR_CASE_SWAP
,
197 VIS_ACTION_INSERT_NEWLINE
,
198 VIS_ACTION_INSERT_TAB
,
199 VIS_ACTION_INSERT_VERBATIM
,
200 VIS_ACTION_INSERT_REGISTER
,
201 VIS_ACTION_WINDOW_NEXT
,
202 VIS_ACTION_WINDOW_PREV
,
203 VIS_ACTION_APPEND_CHAR_NEXT
,
204 VIS_ACTION_APPEND_LINE_END
,
205 VIS_ACTION_INSERT_LINE_START
,
206 VIS_ACTION_OPEN_LINE_ABOVE
,
207 VIS_ACTION_OPEN_LINE_BELOW
,
208 VIS_ACTION_JOIN_LINE_BELOW
,
209 VIS_ACTION_JOIN_LINES
,
210 VIS_ACTION_PROMPT_SHOW
,
211 VIS_ACTION_PROMPT_BACKSPACE
,
212 VIS_ACTION_PROMPT_ENTER
,
213 VIS_ACTION_PROMPT_SHOW_VISUAL
,
215 VIS_ACTION_SELECTION_FLIP
,
216 VIS_ACTION_SELECTION_RESTORE
,
217 VIS_ACTION_WINDOW_REDRAW_TOP
,
218 VIS_ACTION_WINDOW_REDRAW_CENTER
,
219 VIS_ACTION_WINDOW_REDRAW_BOTTOM
,
220 VIS_ACTION_WINDOW_SLIDE_UP
,
221 VIS_ACTION_WINDOW_SLIDE_DOWN
,
222 VIS_ACTION_PUT_AFTER
,
223 VIS_ACTION_PUT_BEFORE
,
224 VIS_ACTION_PUT_AFTER_END
,
225 VIS_ACTION_PUT_BEFORE_END
,
226 VIS_ACTION_CURSOR_SELECT_WORD
,
227 VIS_ACTION_CURSORS_NEW_LINE_ABOVE
,
228 VIS_ACTION_CURSORS_NEW_LINE_BELOW
,
229 VIS_ACTION_CURSORS_NEW_LINES_BEGIN
,
230 VIS_ACTION_CURSORS_NEW_LINES_END
,
231 VIS_ACTION_CURSORS_NEW_MATCH_NEXT
,
232 VIS_ACTION_CURSORS_NEW_MATCH_SKIP
,
233 VIS_ACTION_CURSORS_ALIGN
,
234 VIS_ACTION_CURSORS_REMOVE_ALL
,
235 VIS_ACTION_CURSORS_REMOVE_LAST
,
236 VIS_ACTION_TEXT_OBJECT_WORD_OUTER
,
237 VIS_ACTION_TEXT_OBJECT_WORD_INNER
,
238 VIS_ACTION_TEXT_OBJECT_LONGWORD_OUTER
,
239 VIS_ACTION_TEXT_OBJECT_LONGWORD_INNER
,
240 VIS_ACTION_TEXT_OBJECT_SENTENCE
,
241 VIS_ACTION_TEXT_OBJECT_PARAGRAPH
,
242 VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_OUTER
,
243 VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_INNER
,
244 VIS_ACTION_TEXT_OBJECT_PARANTHESE_OUTER
,
245 VIS_ACTION_TEXT_OBJECT_PARANTHESE_INNER
,
246 VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_OUTER
,
247 VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_INNER
,
248 VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_OUTER
,
249 VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_INNER
,
250 VIS_ACTION_TEXT_OBJECT_QUOTE_OUTER
,
251 VIS_ACTION_TEXT_OBJECT_QUOTE_INNER
,
252 VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_OUTER
,
253 VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_INNER
,
254 VIS_ACTION_TEXT_OBJECT_BACKTICK_OUTER
,
255 VIS_ACTION_TEXT_OBJECT_BACKTICK_INNER
,
256 VIS_ACTION_TEXT_OBJECT_ENTIRE_OUTER
,
257 VIS_ACTION_TEXT_OBJECT_ENTIRE_INNER
,
258 VIS_ACTION_TEXT_OBJECT_FUNCTION_OUTER
,
259 VIS_ACTION_TEXT_OBJECT_FUNCTION_INNER
,
260 VIS_ACTION_TEXT_OBJECT_LINE_OUTER
,
261 VIS_ACTION_TEXT_OBJECT_LINE_INNER
,
262 VIS_ACTION_MOTION_CHARWISE
,
263 VIS_ACTION_MOTION_LINEWISE
,
267 static KeyAction vis_action
[] = {
268 [VIS_ACTION_EDITOR_SUSPEND
] = {
270 "Suspend the editor",
273 [VIS_ACTION_CURSOR_CHAR_PREV
] = {
275 "Move cursor left, to the previous character",
276 movement
, { .i
= VIS_MOVE_CHAR_PREV
}
278 [VIS_ACTION_CURSOR_CHAR_NEXT
] = {
280 "Move cursor right, to the next character",
281 movement
, { .i
= VIS_MOVE_CHAR_NEXT
}
283 [VIS_ACTION_CURSOR_WORD_START_PREV
] = {
284 "cursor-word-start-prev",
285 "Move cursor words backwards",
286 movement
, { .i
= VIS_MOVE_WORD_START_PREV
}
288 [VIS_ACTION_CURSOR_WORD_START_NEXT
] = {
289 "cursor-word-start-next",
290 "Move cursor words forwards",
291 movement
, { .i
= VIS_MOVE_WORD_START_NEXT
}
293 [VIS_ACTION_CURSOR_WORD_END_PREV
] = {
294 "cursor-word-end-prev",
295 "Move cursor backwards to the end of word",
296 movement
, { .i
= VIS_MOVE_WORD_END_PREV
}
298 [VIS_ACTION_CURSOR_WORD_END_NEXT
] = {
299 "cursor-word-end-next",
300 "Move cursor forward to the end of word",
301 movement
, { .i
= VIS_MOVE_WORD_END_NEXT
}
303 [VIS_ACTION_CURSOR_LONGWORD_START_PREV
] = {
304 "cursor-longword-start-prev",
305 "Move cursor WORDS backwards",
306 movement
, { .i
= VIS_MOVE_LONGWORD_START_PREV
}
308 [VIS_ACTION_CURSOR_LONGWORD_START_NEXT
] = {
309 "cursor-longword-start-next",
310 "Move cursor WORDS forwards",
311 movement
, { .i
= VIS_MOVE_LONGWORD_START_NEXT
}
313 [VIS_ACTION_CURSOR_LONGWORD_END_PREV
] = {
314 "cursor-longword-end-prev",
315 "Move cursor backwards to the end of WORD",
316 movement
, { .i
= VIS_MOVE_LONGWORD_END_PREV
}
318 [VIS_ACTION_CURSOR_LONGWORD_END_NEXT
] = {
319 "cursor-longword-end-next",
320 "Move cursor forward to the end of WORD",
321 movement
, { .i
= VIS_MOVE_LONGWORD_END_NEXT
}
323 [VIS_ACTION_CURSOR_LINE_UP
] = {
325 "Move cursor line upwards",
326 movement
, { .i
= VIS_MOVE_LINE_UP
}
328 [VIS_ACTION_CURSOR_LINE_DOWN
] = {
330 "Move cursor line downwards",
331 movement
, { .i
= VIS_MOVE_LINE_DOWN
}
333 [VIS_ACTION_CURSOR_LINE_START
] = {
335 "Move cursor to first non-blank character of the line",
336 movement
, { .i
= VIS_MOVE_LINE_START
}
338 [VIS_ACTION_CURSOR_LINE_FINISH
] = {
339 "cursor-line-finish",
340 "Move cursor to last non-blank character of the line",
341 movement
, { .i
= VIS_MOVE_LINE_FINISH
}
343 [VIS_ACTION_CURSOR_LINE_BEGIN
] = {
345 "Move cursor to first character of the line",
346 movement
, { .i
= VIS_MOVE_LINE_BEGIN
}
348 [VIS_ACTION_CURSOR_LINE_END
] = {
350 "Move cursor to end of the line",
351 movement
, { .i
= VIS_MOVE_LINE_LASTCHAR
}
353 [VIS_ACTION_CURSOR_SCREEN_LINE_UP
] = {
354 "cursor-sceenline-up",
355 "Move cursor screen/display line upwards",
356 movement
, { .i
= VIS_MOVE_SCREEN_LINE_UP
}
358 [VIS_ACTION_CURSOR_SCREEN_LINE_DOWN
] = {
359 "cursor-screenline-down",
360 "Move cursor screen/display line downwards",
361 movement
, { .i
= VIS_MOVE_SCREEN_LINE_DOWN
}
363 [VIS_ACTION_CURSOR_SCREEN_LINE_BEGIN
] = {
364 "cursor-screenline-begin",
365 "Move cursor to beginning of screen/display line",
366 movement
, { .i
= VIS_MOVE_SCREEN_LINE_BEGIN
}
368 [VIS_ACTION_CURSOR_SCREEN_LINE_MIDDLE
] = {
369 "cursor-screenline-middle",
370 "Move cursor to middle of screen/display line",
371 movement
, { .i
= VIS_MOVE_SCREEN_LINE_MIDDLE
}
373 [VIS_ACTION_CURSOR_SCREEN_LINE_END
] = {
374 "cursor-screenline-end",
375 "Move cursor to end of screen/display line",
376 movement
, { .i
= VIS_MOVE_SCREEN_LINE_END
}
378 [VIS_ACTION_CURSOR_BRACKET_MATCH
] = {
379 "cursor-match-bracket",
380 "Match corresponding symbol if cursor is on a bracket character",
381 movement
, { .i
= VIS_MOVE_BRACKET_MATCH
}
383 [VIS_ACTION_CURSOR_PARAGRAPH_PREV
] = {
384 "cursor-paragraph-prev",
385 "Move cursor paragraph backward",
386 movement
, { .i
= VIS_MOVE_PARAGRAPH_PREV
}
388 [VIS_ACTION_CURSOR_PARAGRAPH_NEXT
] = {
389 "cursor-paragraph-next",
390 "Move cursor paragraph forward",
391 movement
, { .i
= VIS_MOVE_PARAGRAPH_NEXT
}
393 [VIS_ACTION_CURSOR_SENTENCE_PREV
] = {
394 "cursor-sentence-prev",
395 "Move cursor sentence backward",
396 movement
, { .i
= VIS_MOVE_SENTENCE_PREV
}
398 [VIS_ACTION_CURSOR_SENTENCE_NEXT
] = {
399 "cursor-sentence-next",
400 "Move cursor sentence forward",
401 movement
, { .i
= VIS_MOVE_SENTENCE_NEXT
}
403 [VIS_ACTION_CURSOR_FUNCTION_START_PREV
] = {
404 "cursor-function-start-prev",
405 "Move cursor backwards to start of function",
406 movement
, { .i
= VIS_MOVE_FUNCTION_START_PREV
}
408 [VIS_ACTION_CURSOR_FUNCTION_START_NEXT
] = {
409 "cursor-function-start-next",
410 "Move cursor forwards to start of function",
411 movement
, { .i
= VIS_MOVE_FUNCTION_START_NEXT
}
413 [VIS_ACTION_CURSOR_FUNCTION_END_PREV
] = {
414 "cursor-function-end-prev",
415 "Move cursor backwards to end of function",
416 movement
, { .i
= VIS_MOVE_FUNCTION_END_PREV
}
418 [VIS_ACTION_CURSOR_FUNCTION_END_NEXT
] = {
419 "cursor-function-end-next",
420 "Move cursor forwards to end of function",
421 movement
, { .i
= VIS_MOVE_FUNCTION_END_NEXT
}
423 [VIS_ACTION_CURSOR_COLUMN
] = {
425 "Move cursor to given column of current line",
426 movement
, { .i
= VIS_MOVE_COLUMN
}
428 [VIS_ACTION_CURSOR_LINE_FIRST
] = {
430 "Move cursor to given line (defaults to first)",
431 gotoline
, { .i
= -1 }
433 [VIS_ACTION_CURSOR_LINE_LAST
] = {
435 "Move cursor to given line (defaults to last)",
436 gotoline
, { .i
= +1 }
438 [VIS_ACTION_CURSOR_WINDOW_LINE_TOP
] = {
439 "cursor-window-line-top",
440 "Move cursor to top line of the window",
441 movement
, { .i
= VIS_MOVE_WINDOW_LINE_TOP
}
443 [VIS_ACTION_CURSOR_WINDOW_LINE_MIDDLE
] = {
444 "cursor-window-line-middle",
445 "Move cursor to middle line of the window",
446 movement
, { .i
= VIS_MOVE_WINDOW_LINE_MIDDLE
}
448 [VIS_ACTION_CURSOR_WINDOW_LINE_BOTTOM
] = {
449 "cursor-window-line-bottom",
450 "Move cursor to bottom line of the window",
451 movement
, { .i
= VIS_MOVE_WINDOW_LINE_BOTTOM
}
453 [VIS_ACTION_CURSOR_SEARCH_NEXT
] = {
454 "cursor-search-forward",
455 "Move cursor to bottom line of the window",
456 movement
, { .i
= VIS_MOVE_SEARCH_NEXT
}
458 [VIS_ACTION_CURSOR_SEARCH_PREV
] = {
459 "cursor-search-backward",
460 "Move cursor to bottom line of the window",
461 movement
, { .i
= VIS_MOVE_SEARCH_PREV
}
463 [VIS_ACTION_CURSOR_SEARCH_WORD_FORWARD
] = {
464 "cursor-search-word-forward",
465 "Move cursor to next occurence of the word under cursor",
466 movement
, { .i
= VIS_MOVE_SEARCH_WORD_FORWARD
}
468 [VIS_ACTION_CURSOR_SEARCH_WORD_BACKWARD
] = {
469 "cursor-search-word-backward",
470 "Move cursor to previous occurence of the word under cursor",
471 movement
, { .i
= VIS_MOVE_SEARCH_WORD_BACKWARD
}
473 [VIS_ACTION_WINDOW_PAGE_UP
] = {
475 "Scroll window pages backwards (upwards)",
476 wscroll
, { .i
= -PAGE
}
478 [VIS_ACTION_WINDOW_HALFPAGE_UP
] = {
479 "window-halfpage-up",
480 "Scroll window half pages backwards (upwards)",
481 wscroll
, { .i
= -PAGE_HALF
}
483 [VIS_ACTION_WINDOW_PAGE_DOWN
] = {
485 "Scroll window pages forwards (downwards)",
486 wscroll
, { .i
= +PAGE
}
488 [VIS_ACTION_WINDOW_HALFPAGE_DOWN
] = {
489 "window-halfpage-down",
490 "Scroll window half pages forwards (downwards)",
491 wscroll
, { .i
= +PAGE_HALF
}
493 [VIS_ACTION_MODE_NORMAL
] = {
496 switchmode
, { .i
= VIS_MODE_NORMAL
}
498 [VIS_ACTION_MODE_VISUAL
] = {
499 "vis-mode-visual-charwise",
500 "Enter characterwise visual mode",
501 switchmode
, { .i
= VIS_MODE_VISUAL
}
503 [VIS_ACTION_MODE_VISUAL_LINE
] = {
504 "vis-mode-visual-linewise",
505 "Enter linewise visual mode",
506 switchmode
, { .i
= VIS_MODE_VISUAL_LINE
}
508 [VIS_ACTION_MODE_INSERT
] = {
511 switchmode
, { .i
= VIS_MODE_INSERT
}
513 [VIS_ACTION_MODE_REPLACE
] = {
515 "Enter replace mode",
516 switchmode
, { .i
= VIS_MODE_REPLACE
}
518 [VIS_ACTION_MODE_OPERATOR_PENDING
] = {
519 "vis-mode-operator-pending",
520 "Enter to operator pending mode",
521 switchmode
, { .i
= VIS_MODE_OPERATOR
}
523 [VIS_ACTION_DELETE_CHAR_PREV
] = {
525 "Delete the previous character",
526 delete, { .i
= VIS_MOVE_CHAR_PREV
}
528 [VIS_ACTION_DELETE_CHAR_NEXT
] = {
530 "Delete the next character",
531 delete, { .i
= VIS_MOVE_CHAR_NEXT
}
533 [VIS_ACTION_DELETE_LINE_BEGIN
] = {
535 "Delete until the start of the current line",
536 delete, { .i
= VIS_MOVE_LINE_BEGIN
}
538 [VIS_ACTION_DELETE_WORD_PREV
] = {
540 "Delete the previous WORD",
541 delete, { .i
= VIS_MOVE_LONGWORD_START_PREV
}
543 [VIS_ACTION_JUMPLIST_PREV
] = {
545 "Go to older cursor position in jump list",
546 movement
, { .i
= VIS_MOVE_JUMPLIST_PREV
}
548 [VIS_ACTION_JUMPLIST_NEXT
] = {
550 "Go to newer cursor position in jump list",
551 movement
, { .i
= VIS_MOVE_JUMPLIST_NEXT
}
553 [VIS_ACTION_CHANGELIST_PREV
] = {
555 "Go to older cursor position in change list",
556 movement
, { .i
= VIS_MOVE_CHANGELIST_PREV
}
558 [VIS_ACTION_CHANGELIST_NEXT
] = {
560 "Go to newer cursor position in change list",
561 movement
, { .i
= VIS_MOVE_CHANGELIST_NEXT
}
563 [VIS_ACTION_UNDO
] = {
568 [VIS_ACTION_REDO
] = {
573 [VIS_ACTION_EARLIER
] = {
575 "Goto older text state",
578 [VIS_ACTION_LATER
] = {
580 "Goto newer text state",
583 [VIS_ACTION_MACRO_RECORD
] = {
585 "Record macro into given register",
588 [VIS_ACTION_MACRO_REPLAY
] = {
590 "Replay macro, execute the content of the given register",
593 [VIS_ACTION_MARK_SET
] = {
595 "Set given mark at current cursor position",
598 [VIS_ACTION_MARK_GOTO
] = {
600 "Goto the position of the given mark",
601 mark_motion
, { .i
= VIS_MOVE_MARK
}
603 [VIS_ACTION_MARK_GOTO_LINE
] = {
605 "Goto first non-blank character of the line containing the given mark",
606 mark_motion
, { .i
= VIS_MOVE_MARK_LINE
}
608 [VIS_ACTION_REDRAW
] = {
610 "Redraw current editor content",
611 call
, { .f
= vis_draw
}
613 [VIS_ACTION_REPLACE_CHAR
] = {
615 "Replace the character under the cursor",
618 [VIS_ACTION_TOTILL_REPEAT
] = {
620 "Repeat latest to/till motion",
621 movement
, { .i
= VIS_MOVE_TOTILL_REPEAT
}
623 [VIS_ACTION_TOTILL_REVERSE
] = {
625 "Repeat latest to/till motion but in opposite direction",
626 movement
, { .i
= VIS_MOVE_TOTILL_REVERSE
}
628 [VIS_ACTION_PROMPT_SEARCH_FORWARD
] = {
631 prompt_search
, { .s
= "/" }
633 [VIS_ACTION_PROMPT_SEARCH_BACKWARD
] = {
636 prompt_search
, { .s
= "?" }
638 [VIS_ACTION_TILL_LEFT
] = {
640 "Till after the occurrence of character to the left",
641 movement_key
, { .i
= VIS_MOVE_LEFT_TILL
}
643 [VIS_ACTION_TILL_RIGHT
] = {
645 "Till before the occurrence of character to the right",
646 movement_key
, { .i
= VIS_MOVE_RIGHT_TILL
}
648 [VIS_ACTION_TO_LEFT
] = {
650 "To the first occurrence of character to the left",
651 movement_key
, { .i
= VIS_MOVE_LEFT_TO
}
653 [VIS_ACTION_TO_RIGHT
] = {
655 "To the first occurrence of character to the right",
656 movement_key
, { .i
= VIS_MOVE_RIGHT_TO
}
658 [VIS_ACTION_REGISTER
] = {
660 "Use given register for next operator",
663 [VIS_ACTION_OPERATOR_CHANGE
] = {
664 "vis-operator-change",
666 operator, { .i
= VIS_OP_CHANGE
}
668 [VIS_ACTION_OPERATOR_DELETE
] = {
669 "vis-operator-delete",
671 operator, { .i
= VIS_OP_DELETE
}
673 [VIS_ACTION_OPERATOR_YANK
] = {
676 operator, { .i
= VIS_OP_YANK
}
678 [VIS_ACTION_OPERATOR_SHIFT_LEFT
] = {
679 "vis-operator-shift-left",
680 "Shift left operator",
681 operator, { .i
= VIS_OP_SHIFT_LEFT
}
683 [VIS_ACTION_OPERATOR_SHIFT_RIGHT
] = {
684 "vis-operator-shift-right",
685 "Shift right operator",
686 operator, { .i
= VIS_OP_SHIFT_RIGHT
}
688 [VIS_ACTION_OPERATOR_CASE_LOWER
] = {
689 "vis-operator-case-lower",
690 "Lowercase operator",
691 operator, { .i
= VIS_OP_CASE_LOWER
}
693 [VIS_ACTION_OPERATOR_CASE_UPPER
] = {
694 "vis-operator-case-upper",
695 "Uppercase operator",
696 operator, { .i
= VIS_OP_CASE_UPPER
}
698 [VIS_ACTION_OPERATOR_CASE_SWAP
] = {
699 "vis-operator-case-swap",
700 "Swap case operator",
701 operator, { .i
= VIS_OP_CASE_SWAP
}
703 [VIS_ACTION_COUNT
] = {
708 [VIS_ACTION_INSERT_NEWLINE
] = {
710 "Insert a line break (depending on file type)",
711 call
, { .f
= vis_insert_nl
}
713 [VIS_ACTION_INSERT_TAB
] = {
715 "Insert a tab (might be converted to spaces)",
716 call
, { .f
= vis_insert_tab
}
718 [VIS_ACTION_INSERT_VERBATIM
] = {
720 "Insert Unicode character based on code point",
723 [VIS_ACTION_INSERT_REGISTER
] = {
725 "Insert specified register content",
728 [VIS_ACTION_WINDOW_NEXT
] = {
731 call
, { .f
= vis_window_next
}
733 [VIS_ACTION_WINDOW_PREV
] = {
735 "Focus previous window",
736 call
, { .f
= vis_window_prev
}
738 [VIS_ACTION_APPEND_CHAR_NEXT
] = {
740 "Append text after the cursor",
741 insertmode
, { .i
= VIS_MOVE_CHAR_NEXT
}
743 [VIS_ACTION_APPEND_LINE_END
] = {
745 "Append text after the end of the line",
746 insertmode
, { .i
= VIS_MOVE_LINE_END
},
748 [VIS_ACTION_INSERT_LINE_START
] = {
750 "Insert text before the first non-blank in the line",
751 insertmode
, { .i
= VIS_MOVE_LINE_START
},
753 [VIS_ACTION_OPEN_LINE_ABOVE
] = {
755 "Begin a new line above the cursor",
756 openline
, { .i
= -1 }
758 [VIS_ACTION_OPEN_LINE_BELOW
] = {
760 "Begin a new line below the cursor",
761 openline
, { .i
= +1 }
763 [VIS_ACTION_JOIN_LINE_BELOW
] = {
766 join
, { .i
= VIS_MOVE_LINE_NEXT
},
768 [VIS_ACTION_JOIN_LINES
] = {
770 "Join selected lines",
771 operator, { .i
= VIS_OP_JOIN
}
773 [VIS_ACTION_PROMPT_SHOW
] = {
775 "Show editor command line prompt",
776 prompt_cmd
, { .s
= "" }
778 [VIS_ACTION_PROMPT_BACKSPACE
] = {
780 "Delete previous character in prompt",
783 [VIS_ACTION_PROMPT_ENTER
] = {
785 "Execute current prompt content",
786 call
, { .f
= vis_prompt_enter
}
788 [VIS_ACTION_PROMPT_SHOW_VISUAL
] = {
789 "prompt-show-visual",
790 "Show editor command line prompt in visual mode",
791 prompt_cmd
, { .s
= "'<,'>" }
793 [VIS_ACTION_REPEAT
] = {
795 "Repeat latest editor command",
798 [VIS_ACTION_SELECTION_FLIP
] = {
800 "Flip selection, move cursor to other end",
803 [VIS_ACTION_SELECTION_RESTORE
] = {
805 "Restore last selection",
808 [VIS_ACTION_WINDOW_REDRAW_TOP
] = {
810 "Redraw cursor line at the top of the window",
811 window
, { .w
= view_redraw_top
}
813 [VIS_ACTION_WINDOW_REDRAW_CENTER
] = {
814 "window-redraw-center",
815 "Redraw cursor line at the center of the window",
816 window
, { .w
= view_redraw_center
}
818 [VIS_ACTION_WINDOW_REDRAW_BOTTOM
] = {
819 "window-redraw-bottom",
820 "Redraw cursor line at the bottom of the window",
821 window
, { .w
= view_redraw_bottom
}
823 [VIS_ACTION_WINDOW_SLIDE_UP
] = {
825 "Slide window content upwards",
828 [VIS_ACTION_WINDOW_SLIDE_DOWN
] = {
830 "Slide window content downwards",
833 [VIS_ACTION_PUT_AFTER
] = {
835 "Put text after the cursor",
836 operator, { .i
= VIS_OP_PUT_AFTER
}
838 [VIS_ACTION_PUT_BEFORE
] = {
840 "Put text before the cursor",
841 operator, { .i
= VIS_OP_PUT_BEFORE
}
843 [VIS_ACTION_PUT_AFTER_END
] = {
845 "Put text after the cursor, place cursor after new text",
846 operator, { .i
= VIS_OP_PUT_AFTER_END
}
848 [VIS_ACTION_PUT_BEFORE_END
] = {
850 "Put text before the cursor, place cursor after new text",
851 operator, { .i
= VIS_OP_PUT_BEFORE_END
}
853 [VIS_ACTION_CURSOR_SELECT_WORD
] = {
854 "cursors-select-word",
855 "Select word under cursor",
858 [VIS_ACTION_CURSORS_NEW_LINE_ABOVE
] = {
859 "cursors-new-lines-above",
860 "Create a new cursor on the line above",
861 cursors_new
, { .i
= -1 }
863 [VIS_ACTION_CURSORS_NEW_LINE_BELOW
] = {
864 "cursor-new-lines-below",
865 "Create a new cursor on the line below",
866 cursors_new
, { .i
= +1 }
868 [VIS_ACTION_CURSORS_NEW_LINES_BEGIN
] = {
869 "cursors-new-lines-begin",
870 "Create a new cursor at the start of every line covered by selection",
871 operator, { .i
= VIS_OP_CURSOR_SOL
}
873 [VIS_ACTION_CURSORS_NEW_LINES_END
] = {
874 "cursors-new-lines-end",
875 "Create a new cursor at the end of every line covered by selection",
876 operator, { .i
= VIS_OP_CURSOR_EOL
}
878 [VIS_ACTION_CURSORS_NEW_MATCH_NEXT
] = {
879 "cursors-new-match-next",
880 "Select the next region matching the current selection",
883 [VIS_ACTION_CURSORS_NEW_MATCH_SKIP
] = {
884 "cursors-new-match-skip",
885 "Clear current selection, but select next match",
888 [VIS_ACTION_CURSORS_ALIGN
] = {
890 "Try to align all cursors on the same column",
893 [VIS_ACTION_CURSORS_REMOVE_ALL
] = {
894 "cursors-remove-all",
895 "Remove all but the primary cursor",
898 [VIS_ACTION_CURSORS_REMOVE_LAST
] = {
899 "cursors-remove-last",
900 "Remove least recently created cursor",
903 [VIS_ACTION_TEXT_OBJECT_WORD_OUTER
] = {
904 "text-object-word-outer",
905 "A word leading and trailing whitespace included",
906 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_WORD
}
908 [VIS_ACTION_TEXT_OBJECT_WORD_INNER
] = {
909 "text-object-word-inner",
910 "A word leading and trailing whitespace excluded",
911 textobj
, { .i
= VIS_TEXTOBJECT_INNER_WORD
}
913 [VIS_ACTION_TEXT_OBJECT_LONGWORD_OUTER
] = {
914 "text-object-longword-outer",
915 "A WORD leading and trailing whitespace included",
916 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_LONGWORD
}
918 [VIS_ACTION_TEXT_OBJECT_LONGWORD_INNER
] = {
919 "text-object-longword-inner",
920 "A WORD leading and trailing whitespace excluded",
921 textobj
, { .i
= VIS_TEXTOBJECT_INNER_LONGWORD
}
923 [VIS_ACTION_TEXT_OBJECT_SENTENCE
] = {
924 "text-object-sentence",
926 textobj
, { .i
= VIS_TEXTOBJECT_SENTENCE
}
928 [VIS_ACTION_TEXT_OBJECT_PARAGRAPH
] = {
929 "text-object-paragraph",
931 textobj
, { .i
= VIS_TEXTOBJECT_PARAGRAPH
}
933 [VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_OUTER
] = {
934 "text-object-square-bracket-outer",
935 "[] block (outer variant)",
936 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_SQUARE_BRACKET
}
938 [VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_INNER
] = {
939 "text-object-square-bracket-inner",
940 "[] block (inner variant)",
941 textobj
, { .i
= VIS_TEXTOBJECT_INNER_SQUARE_BRACKET
}
943 [VIS_ACTION_TEXT_OBJECT_PARANTHESE_OUTER
] = {
944 "text-object-parentheses-outer",
945 "() block (outer variant)",
946 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_PARANTHESE
}
948 [VIS_ACTION_TEXT_OBJECT_PARANTHESE_INNER
] = {
949 "text-object-parentheses-inner",
950 "() block (inner variant)",
951 textobj
, { .i
= VIS_TEXTOBJECT_INNER_PARANTHESE
}
953 [VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_OUTER
] = {
954 "text-object-angle-bracket-outer",
955 "<> block (outer variant)",
956 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_ANGLE_BRACKET
}
958 [VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_INNER
] = {
959 "text-object-angle-bracket-inner",
960 "<> block (inner variant)",
961 textobj
, { .i
= VIS_TEXTOBJECT_INNER_ANGLE_BRACKET
}
963 [VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_OUTER
] = {
964 "text-object-curly-bracket-outer",
965 "{} block (outer variant)",
966 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_CURLY_BRACKET
}
968 [VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_INNER
] = {
969 "text-object-curly-bracket-inner",
970 "{} block (inner variant)",
971 textobj
, { .i
= VIS_TEXTOBJECT_INNER_CURLY_BRACKET
}
973 [VIS_ACTION_TEXT_OBJECT_QUOTE_OUTER
] = {
974 "text-object-quote-outer",
975 "A quoted string, including the quotation marks",
976 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_QUOTE
}
978 [VIS_ACTION_TEXT_OBJECT_QUOTE_INNER
] = {
979 "text-object-quote-inner",
980 "A quoted string, excluding the quotation marks",
981 textobj
, { .i
= VIS_TEXTOBJECT_INNER_QUOTE
}
983 [VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_OUTER
] = {
984 "text-object-single-quote-outer",
985 "A single quoted string, including the quotation marks",
986 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_SINGLE_QUOTE
}
988 [VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_INNER
] = {
989 "text-object-single-quote-inner",
990 "A single quoted string, excluding the quotation marks",
991 textobj
, { .i
= VIS_TEXTOBJECT_INNER_SINGLE_QUOTE
}
993 [VIS_ACTION_TEXT_OBJECT_BACKTICK_OUTER
] = {
994 "text-object-backtick-outer",
995 "A backtick delimited string (outer variant)",
996 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_BACKTICK
}
998 [VIS_ACTION_TEXT_OBJECT_BACKTICK_INNER
] = {
999 "text-object-backtick-inner",
1000 "A backtick delimited string (inner variant)",
1001 textobj
, { .i
= VIS_TEXTOBJECT_INNER_BACKTICK
}
1003 [VIS_ACTION_TEXT_OBJECT_ENTIRE_OUTER
] = {
1004 "text-object-entire-outer",
1005 "The whole text content",
1006 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_ENTIRE
}
1008 [VIS_ACTION_TEXT_OBJECT_ENTIRE_INNER
] = {
1009 "text-object-entire-inner",
1010 "The whole text content, except for leading and trailing empty lines",
1011 textobj
, { .i
= VIS_TEXTOBJECT_INNER_ENTIRE
}
1013 [VIS_ACTION_TEXT_OBJECT_FUNCTION_OUTER
] = {
1014 "text-object-function-outer",
1015 "A whole C-like function",
1016 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_FUNCTION
}
1018 [VIS_ACTION_TEXT_OBJECT_FUNCTION_INNER
] = {
1019 "text-object-function-inner",
1020 "A whole C-like function body",
1021 textobj
, { .i
= VIS_TEXTOBJECT_INNER_FUNCTION
}
1023 [VIS_ACTION_TEXT_OBJECT_LINE_OUTER
] = {
1024 "text-object-line-outer",
1026 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_LINE
}
1028 [VIS_ACTION_TEXT_OBJECT_LINE_INNER
] = {
1029 "text-object-line-inner",
1030 "The whole line, excluding leading and trailing whitespace",
1031 textobj
, { .i
= VIS_TEXTOBJECT_INNER_LINE
}
1033 [VIS_ACTION_MOTION_CHARWISE
] = {
1035 "Force motion to be charwise",
1036 motiontype
, { .i
= VIS_MOTIONTYPE_CHARWISE
}
1038 [VIS_ACTION_MOTION_LINEWISE
] = {
1040 "Force motion to be linewise",
1041 motiontype
, { .i
= VIS_MOTIONTYPE_LINEWISE
}
1043 [VIS_ACTION_NOP
] = {
1045 "Ignore key, do nothing",
1052 /** key bindings functions */
1054 static const char *nop(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1058 static const char *key2macro(Vis
*vis
, const char *keys
, enum VisMacro
*macro
) {
1059 *macro
= VIS_MACRO_INVALID
;
1060 if (keys
[0] >= 'a' && keys
[0] <= 'z')
1061 *macro
= keys
[0] - 'a';
1062 else if (keys
[0] == '@')
1063 *macro
= VIS_MACRO_LAST_RECORDED
;
1064 else if (keys
[0] == '\0')
1069 static const char *macro_record(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1070 if (vis_macro_record_stop(vis
))
1072 enum VisMacro macro
;
1073 keys
= key2macro(vis
, keys
, ¯o
);
1074 vis_macro_record(vis
, macro
);
1079 static const char *macro_replay(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1080 enum VisMacro macro
;
1081 keys
= key2macro(vis
, keys
, ¯o
);
1082 vis_macro_replay(vis
, macro
);
1086 static const char *suspend(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1091 static const char *repeat(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1096 static const char *cursors_new(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1097 View
*view
= vis_view(vis
);
1098 Text
*txt
= vis_text(vis
);
1099 size_t pos
= view_cursor_get(view
);
1101 pos
= text_line_down(txt
, pos
);
1102 else if (arg
->i
< 0)
1103 pos
= text_line_up(txt
, pos
);
1104 Cursor
*cursor
= view_cursors_new(view
);
1106 view_cursors_to(cursor
, pos
);
1110 static const char *cursors_align(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1111 View
*view
= vis_view(vis
);
1112 Text
*txt
= vis_text(vis
);
1113 int mincol
= INT_MAX
;
1114 for (Cursor
*c
= view_cursors(view
); c
; c
= view_cursors_next(c
)) {
1115 size_t pos
= view_cursors_pos(c
);
1116 int col
= text_line_char_get(txt
, pos
);
1120 for (Cursor
*c
= view_cursors(view
); c
; c
= view_cursors_next(c
)) {
1121 size_t pos
= view_cursors_pos(c
);
1122 size_t col
= text_line_char_set(txt
, pos
, mincol
);
1123 view_cursors_to(c
, col
);
1128 static const char *cursors_clear(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1129 View
*view
= vis_view(vis
);
1130 if (view_cursors_count(view
) > 1)
1131 view_cursors_clear(view
);
1133 view_cursors_selection_clear(view_cursor(view
));
1137 static const char *cursors_select(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1138 Text
*txt
= vis_text(vis
);
1139 View
*view
= vis_view(vis
);
1140 for (Cursor
*cursor
= view_cursors(view
); cursor
; cursor
= view_cursors_next(cursor
)) {
1141 Filerange sel
= view_cursors_selection_get(cursor
);
1142 Filerange word
= text_object_word(txt
, view_cursors_pos(cursor
));
1143 if (!text_range_valid(&sel
) && text_range_valid(&word
)) {
1144 view_cursors_selection_set(cursor
, &word
);
1145 view_cursors_to(cursor
, text_char_prev(txt
, word
.end
));
1148 vis_mode_switch(vis
, VIS_MODE_VISUAL
);
1152 static const char *cursors_select_next(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1153 Text
*txt
= vis_text(vis
);
1154 View
*view
= vis_view(vis
);
1155 Cursor
*cursor
= view_cursor(view
);
1156 Filerange sel
= view_cursors_selection_get(cursor
);
1157 if (!text_range_valid(&sel
))
1160 size_t len
= text_range_size(&sel
);
1161 char *buf
= malloc(len
+1);
1164 len
= text_bytes_get(txt
, sel
.start
, len
, buf
);
1166 Filerange word
= text_object_word_find_next(txt
, sel
.end
, buf
);
1169 if (text_range_valid(&word
)) {
1170 cursor
= view_cursors_new(view
);
1173 view_cursors_selection_set(cursor
, &word
);
1174 view_cursors_to(cursor
, text_char_prev(txt
, word
.end
));
1179 static const char *cursors_select_skip(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1180 View
*view
= vis_view(vis
);
1181 Cursor
*cursor
= view_cursor(view
);
1182 keys
= cursors_select_next(vis
, keys
, arg
);
1183 if (cursor
!= view_cursor(view
))
1184 view_cursors_dispose(cursor
);
1188 static const char *cursors_remove(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1189 View
*view
= vis_view(vis
);
1190 view_cursors_dispose(view_cursor(view
));
1194 static const char *replace(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1197 const char *next
= vis_keys_next(vis
, keys
);
1200 size_t len
= next
- keys
;
1202 memcpy(key
, keys
, len
);
1204 vis_operator(vis
, VIS_OP_REPLACE
);
1205 vis_motion(vis
, VIS_MOVE_NOP
);
1206 vis_keys_inject(vis
, next
, key
);
1207 vis_keys_inject(vis
, next
+len
, "<Escape>");
1211 static const char *count(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1212 int digit
= keys
[-1] - '0';
1213 int count
= vis_count_get(vis
);
1214 if (0 <= digit
&& digit
<= 9) {
1215 if (digit
== 0 && count
== 0)
1216 vis_motion(vis
, VIS_MOVE_LINE_BEGIN
);
1217 vis_count_set(vis
, count
* 10 + digit
);
1222 static const char *gotoline(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1223 if (vis_count_get(vis
))
1224 vis_motion(vis
, VIS_MOVE_LINE
);
1225 else if (arg
->i
< 0)
1226 vis_motion(vis
, VIS_MOVE_FILE_BEGIN
);
1228 vis_motion(vis
, VIS_MOVE_FILE_END
);
1232 static const char *motiontype(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1233 vis_motion_type(vis
, arg
->i
);
1237 static const char *operator(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1238 vis_operator(vis
, arg
->i
);
1242 static const char *movement_key(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1246 const char *next
= vis_keys_next(vis
, keys
);
1247 strncpy(key
, keys
, next
- keys
+ 1);
1248 key
[sizeof(key
)-1] = '\0';
1249 vis_motion(vis
, arg
->i
, key
);
1253 static const char *movement(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1254 vis_motion(vis
, arg
->i
);
1258 static const char *textobj(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1259 vis_textobject(vis
, arg
->i
);
1263 static const char *selection_end(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1264 for (Cursor
*c
= view_cursors(vis_view(vis
)); c
; c
= view_cursors_next(c
))
1265 view_cursors_selection_swap(c
);
1269 static const char *selection_restore(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1270 for (Cursor
*c
= view_cursors(vis_view(vis
)); c
; c
= view_cursors_next(c
))
1271 view_cursors_selection_restore(c
);
1272 vis_mode_switch(vis
, VIS_MODE_VISUAL
);
1276 static const char *key2register(Vis
*vis
, const char *keys
, enum VisRegister
*reg
) {
1277 *reg
= VIS_REG_INVALID
;
1280 if (keys
[0] >= 'a' && keys
[0] <= 'z')
1281 *reg
= keys
[0] - 'a';
1285 static const char *reg(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1286 enum VisRegister reg
;
1287 keys
= key2register(vis
, keys
, ®
);
1288 vis_register_set(vis
, reg
);
1292 static const char *key2mark(Vis
*vis
, const char *keys
, int *mark
) {
1293 *mark
= VIS_MARK_INVALID
;
1296 if (keys
[0] >= 'a' && keys
[0] <= 'z')
1297 *mark
= keys
[0] - 'a';
1298 else if (keys
[0] == '<')
1299 *mark
= MARK_SELECTION_START
;
1300 else if (keys
[0] == '>')
1301 *mark
= MARK_SELECTION_END
;
1305 static const char *mark_set(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1307 keys
= key2mark(vis
, keys
, &mark
);
1308 vis_mark_set(vis
, mark
, view_cursor_get(vis_view(vis
)));
1312 static const char *mark_motion(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1314 keys
= key2mark(vis
, keys
, &mark
);
1315 vis_motion(vis
, arg
->i
, mark
);
1319 static const char *undo(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1320 size_t pos
= text_undo(vis_text(vis
));
1322 View
*view
= vis_view(vis
);
1323 if (view_cursors_count(view
) == 1)
1324 view_cursor_to(view
, pos
);
1325 /* redraw all windows in case some display the same file */
1331 static const char *redo(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1332 size_t pos
= text_redo(vis_text(vis
));
1334 View
*view
= vis_view(vis
);
1335 if (view_cursors_count(view
) == 1)
1336 view_cursor_to(view
, pos
);
1337 /* redraw all windows in case some display the same file */
1343 static const char *earlier(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1344 size_t pos
= text_earlier(vis_text(vis
), MAX(vis_count_get(vis
), 1));
1346 view_cursor_to(vis_view(vis
), pos
);
1347 /* redraw all windows in case some display the same file */
1353 static const char *later(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1354 size_t pos
= text_later(vis_text(vis
), MAX(vis_count_get(vis
), 1));
1356 view_cursor_to(vis_view(vis
), pos
);
1357 /* redraw all windows in case some display the same file */
1363 static const char *delete(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1364 vis_operator(vis
, VIS_OP_DELETE
);
1365 vis_motion(vis
, arg
->i
);
1369 static const char *insert_register(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1370 enum VisRegister regid
;
1371 keys
= key2register(vis
, keys
, ®id
);
1372 Register
*reg
= vis_register_get(vis
, regid
);
1374 int pos
= view_cursor_get(vis_view(vis
));
1375 vis_insert(vis
, pos
, reg
->data
, reg
->len
);
1376 view_cursor_to(vis_view(vis
), pos
+ reg
->len
);
1381 static const char *prompt_search(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1382 vis_prompt_show(vis
, arg
->s
, "");
1383 vis_mode_switch(vis
, VIS_MODE_PROMPT
);
1387 static const char *prompt_cmd(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1388 vis_prompt_show(vis
, ":", arg
->s
);
1389 vis_mode_switch(vis
, VIS_MODE_PROMPT
);
1393 static const char *prompt_backspace(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1394 char *cmd
= vis_prompt_get(vis
);
1396 vis_mode_switch(vis
, VIS_MODE_NORMAL
);
1398 delete(vis
, keys
, &(const Arg
){ .i
= VIS_MOVE_CHAR_PREV
});
1403 static const char *insert_verbatim(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1405 char buf
[4], type
= keys
[0];
1406 int len
= 0, count
= 0, base
;
1428 if (type
< '0' || type
> '9')
1436 for (keys
++; keys
[0] && count
> 0; keys
++, count
--) {
1438 if (base
== 8 && '0' <= keys
[0] && keys
[0] <= '7') {
1440 } else if ((base
== 10 || base
== 16) && '0' <= keys
[0] && keys
[0] <= '9') {
1442 } else if (base
== 16 && 'a' <= keys
[0] && keys
[0] <= 'f') {
1443 v
= 10 + keys
[0] - 'a';
1444 } else if (base
== 16 && 'A' <= keys
[0] && keys
[0] <= 'F') {
1445 v
= 10 + keys
[0] - 'A';
1450 rune
= rune
* base
+ v
;
1456 if (type
== 'u' || type
== 'U') {
1457 len
= runetochar(buf
, &rune
);
1464 size_t pos
= view_cursor_get(vis_view(vis
));
1465 vis_insert(vis
, pos
, buf
, len
);
1466 view_cursor_to(vis_view(vis
), pos
+ len
);
1471 static const char *cmd(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1472 vis_cmd(vis
, arg
->s
);
1476 static int argi2lines(Vis
*vis
, const Arg
*arg
) {
1480 return view_height_get(vis_view(vis
));
1483 return view_height_get(vis_view(vis
))/2;
1485 if (vis_count_get(vis
) > 0)
1486 return vis_count_get(vis
);
1487 return arg
->i
< 0 ? -arg
->i
: arg
->i
;
1491 static const char *wscroll(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1493 view_scroll_down(vis_view(vis
), argi2lines(vis
, arg
));
1495 view_scroll_up(vis_view(vis
), argi2lines(vis
, arg
));
1499 static const char *wslide(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1501 view_slide_down(vis_view(vis
), argi2lines(vis
, arg
));
1503 view_slide_up(vis_view(vis
), argi2lines(vis
, arg
));
1507 static const char *call(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1512 static const char *window(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1513 arg
->w(vis_view(vis
));
1517 static const char *openline(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1518 vis_operator(vis
, VIS_OP_INSERT
);
1520 vis_motion(vis
, VIS_MOVE_LINE_END
);
1521 vis_keys_inject(vis
, keys
, "<Enter>");
1523 vis_motion(vis
, VIS_MOVE_LINE_BEGIN
);
1524 vis_keys_inject(vis
, keys
, "<Enter><Up>");
1529 static const char *join(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1530 int count
= vis_count_get(vis
);
1532 vis_count_set(vis
, count
-1);
1533 vis_operator(vis
, VIS_OP_JOIN
);
1534 vis_motion(vis
, arg
->i
);
1538 static const char *switchmode(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1539 vis_mode_switch(vis
, arg
->i
);
1543 static const char *insertmode(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1544 vis_operator(vis
, VIS_OP_INSERT
);
1545 vis_motion(vis
, arg
->i
);
1551 static KeyBinding
*default_bindings
[] = {
1552 [VIS_MODE_BASIC
] = basic_movement
,
1553 [VIS_MODE_MOVE
] = vis_movements
,
1554 [VIS_MODE_TEXTOBJ
] = vis_textobjs
,
1555 [VIS_MODE_OPERATOR_OPTION
] = vis_operator_options
,
1556 [VIS_MODE_OPERATOR
] = vis_operators
,
1557 [VIS_MODE_NORMAL
] = vis_mode_normal
,
1558 [VIS_MODE_VISUAL
] = vis_mode_visual
,
1559 [VIS_MODE_VISUAL_LINE
] = vis_mode_visual_line
,
1560 [VIS_MODE_READLINE
] = vis_mode_readline
,
1561 [VIS_MODE_PROMPT
] = vis_mode_prompt
,
1562 [VIS_MODE_INSERT
] = vis_mode_insert
,
1563 [VIS_MODE_REPLACE
] = vis_mode_replace
,
1566 static void signal_handler(int signum
, siginfo_t
*siginfo
, void *context
) {
1567 vis_signal_handler(vis
, signum
, siginfo
, context
);
1570 int main(int argc
, char *argv
[]) {
1572 vis
= vis_new(ui_curses_new());
1574 return EXIT_FAILURE
;
1576 for (int i
= 0; i
< LENGTH(vis_action
); i
++) {
1577 KeyAction
*action
= &vis_action
[i
];
1578 if (!vis_action_register(vis
, action
))
1579 vis_die(vis
, "Could not register action: %s\n", action
->name
);
1582 for (int i
= 0; i
< LENGTH(default_bindings
); i
++) {
1583 if (!vis_mode_bindings(vis
, i
, &default_bindings
[i
]))
1584 vis_die(vis
, "Could not load default bindings\n");
1587 /* install signal handlers etc. */
1588 struct sigaction sa
;
1589 memset(&sa
, 0, sizeof sa
);
1590 sa
.sa_flags
= SA_SIGINFO
;
1591 sa
.sa_sigaction
= signal_handler
;
1592 if (sigaction(SIGBUS
, &sa
, NULL
) || sigaction(SIGINT
, &sa
, NULL
))
1593 vis_die(vis
, "sigaction: %s", strerror(errno
));
1596 sigemptyset(&blockset
);
1597 sigaddset(&blockset
, SIGWINCH
);
1598 sigprocmask(SIG_BLOCK
, &blockset
, NULL
);
1599 signal(SIGPIPE
, SIG_IGN
);
1601 int status
= vis_run(vis
, argc
, argv
);