10 #include "text-util.h"
11 #include "text-motions.h"
12 #include "text-objects.h"
17 #define PAGE_HALF (INT_MAX-1)
19 /** functions to be called from keybindings */
20 /* ignore key, do nothing */
21 static const char *nop(Vis
*, const char *keys
, const Arg
*arg
);
22 /* record/replay macro indicated by keys */
23 static const char *macro_record(Vis
*, const char *keys
, const Arg
*arg
);
24 static const char *macro_replay(Vis
*, const char *keys
, const Arg
*arg
);
25 /* temporarily suspend the editor and return to the shell, type 'fg' to get back */
26 static const char *suspend(Vis
*, const char *keys
, const Arg
*arg
);
27 /* switch to mode indicated by arg->i */
28 static const char *switchmode(Vis
*, const char *keys
, const Arg
*arg
);
29 /* switch to insert mode after performing movement indicated by arg->i */
30 static const char *insertmode(Vis
*, const char *keys
, const Arg
*arg
);
31 /* set mark indicated by keys to current cursor position */
32 static const char *mark_set(Vis
*, const char *keys
, const Arg
*arg
);
33 /* add a new line either before or after the one where the cursor currently is */
34 static const char *openline(Vis
*, const char *keys
, const Arg
*arg
);
35 /* join lines from current cursor position to movement indicated by arg */
36 static const char *join(Vis
*, const char *keys
, const Arg
*arg
);
37 /* execute arg->s as if it was typed on command prompt */
38 static const char *cmd(Vis
*, const char *keys
, const Arg
*arg
);
39 /* perform last action i.e. action_prev again */
40 static const char *repeat(Vis
*, const char *keys
, const Arg
*arg
);
41 /* replace character at cursor with one from keys */
42 static const char *replace(Vis
*, const char *keys
, const Arg
*arg
);
43 /* create a new cursor on the previous (arg->i < 0) or next (arg->i > 0) line */
44 static const char *cursors_new(Vis
*, const char *keys
, const Arg
*arg
);
45 /* try to align all cursors on the same column */
46 static const char *cursors_align(Vis
*, const char *keys
, const Arg
*arg
);
47 /* remove all but the primary cursor and their selections */
48 static const char *cursors_clear(Vis
*, const char *keys
, const Arg
*arg
);
49 /* remove the least recently added cursor */
50 static const char *cursors_remove(Vis
*, const char *keys
, const Arg
*arg
);
51 /* select the word the cursor is currently over */
52 static const char *cursors_select(Vis
*, const char *keys
, const Arg
*arg
);
53 /* select the next region matching the current selection */
54 static const char *cursors_select_next(Vis
*, const char *keys
, const Arg
*arg
);
55 /* clear current selection but select next match */
56 static const char *cursors_select_skip(Vis
*, const char *keys
, const Arg
*arg
);
57 /* adjust current used count according to keys */
58 static const char *count(Vis
*, const char *keys
, const Arg
*arg
);
59 /* move to the count-th line or if not given either to the first (arg->i < 0)
60 * or last (arg->i > 0) line of file */
61 static const char *gotoline(Vis
*, const char *keys
, const Arg
*arg
);
62 /* set motion type either LINEWISE or CHARWISE via arg->i */
63 static const char *motiontype(Vis
*, const char *keys
, const Arg
*arg
);
64 /* make the current action use the operator indicated by arg->i */
65 static const char *operator(Vis
*, const char *keys
, const Arg
*arg
);
66 /* use arg->s as command for the filter operator */
67 static const char *operator_filter(Vis
*, const char *keys
, const Arg
*arg
);
68 /* blocks to read a key and performs movement indicated by arg->i which
69 * should be one of VIS_MOVE_{RIGHT,LEFT}_{TO,TILL} */
70 static const char *movement_key(Vis
*, const char *keys
, const Arg
*arg
);
71 /* perform the movement as indicated by arg->i */
72 static const char *movement(Vis
*, const char *keys
, const Arg
*arg
);
73 /* let the current operator affect the range indicated by the text object arg->i */
74 static const char *textobj(Vis
*, const char *keys
, const Arg
*arg
);
75 /* move to the other end of selected text */
76 static const char *selection_end(Vis
*, const char *keys
, const Arg
*arg
);
77 /* restore least recently used selection */
78 static const char *selection_restore(Vis
*, const char *keys
, const Arg
*arg
);
79 /* use register indicated by keys for the current operator */
80 static const char *reg(Vis
*, const char *keys
, const Arg
*arg
);
81 /* perform arg->i motion with a mark indicated by keys as argument */
82 static const char *mark_motion(Vis
*, const char *keys
, const Arg
*arg
);
83 /* {un,re}do last action, redraw window */
84 static const char *undo(Vis
*, const char *keys
, const Arg
*arg
);
85 static const char *redo(Vis
*, const char *keys
, const Arg
*arg
);
86 /* earlier, later action chronologically, redraw window */
87 static const char *earlier(Vis
*, const char *keys
, const Arg
*arg
);
88 static const char *later(Vis
*, const char *keys
, const Arg
*arg
);
89 /* delete from the current cursor position to the end of
90 * movement as indicated by arg->i */
91 static const char *delete(Vis
*, const char *keys
, const Arg
*arg
);
92 /* insert register content indicated by keys at current cursor position */
93 static const char *insert_register(Vis
*, const char *keys
, const Arg
*arg
);
94 /* show a user prompt to get input with title arg->s */
95 static const char *prompt_show(Vis
*, const char *keys
, const Arg
*arg
);
96 /* blocks to read 3 consecutive digits and inserts the corresponding byte value */
97 static const char *insert_verbatim(Vis
*, const char *keys
, const Arg
*arg
);
98 /* scroll window content according to arg->i which can be either PAGE, PAGE_HALF,
99 * or an arbitrary number of lines. a multiplier overrides what is given in arg->i.
100 * negative values scroll back, positive forward. */
101 static const char *wscroll(Vis
*, const char *keys
, const Arg
*arg
);
102 /* similar to scroll, but do only move window content not cursor position */
103 static const char *wslide(Vis
*, const char *keys
, const Arg
*arg
);
104 /* call editor function as indicated by arg->f */
105 static const char *call(Vis
*, const char *keys
, const Arg
*arg
);
106 /* call window function as indicated by arg->w */
107 static const char *window(Vis
*, const char *keys
, const Arg
*arg
);
108 /* show info about Unicode character at cursor position */
109 static const char *unicode_info(Vis
*, const char *keys
, const Arg
*arg
);
112 VIS_ACTION_EDITOR_SUSPEND
,
113 VIS_ACTION_CURSOR_CHAR_PREV
,
114 VIS_ACTION_CURSOR_CHAR_NEXT
,
115 VIS_ACTION_CURSOR_WORD_START_PREV
,
116 VIS_ACTION_CURSOR_WORD_START_NEXT
,
117 VIS_ACTION_CURSOR_WORD_END_PREV
,
118 VIS_ACTION_CURSOR_WORD_END_NEXT
,
119 VIS_ACTION_CURSOR_LONGWORD_START_PREV
,
120 VIS_ACTION_CURSOR_LONGWORD_START_NEXT
,
121 VIS_ACTION_CURSOR_LONGWORD_END_PREV
,
122 VIS_ACTION_CURSOR_LONGWORD_END_NEXT
,
123 VIS_ACTION_CURSOR_LINE_UP
,
124 VIS_ACTION_CURSOR_LINE_DOWN
,
125 VIS_ACTION_CURSOR_LINE_START
,
126 VIS_ACTION_CURSOR_LINE_FINISH
,
127 VIS_ACTION_CURSOR_LINE_BEGIN
,
128 VIS_ACTION_CURSOR_LINE_END
,
129 VIS_ACTION_CURSOR_SCREEN_LINE_UP
,
130 VIS_ACTION_CURSOR_SCREEN_LINE_DOWN
,
131 VIS_ACTION_CURSOR_SCREEN_LINE_BEGIN
,
132 VIS_ACTION_CURSOR_SCREEN_LINE_MIDDLE
,
133 VIS_ACTION_CURSOR_SCREEN_LINE_END
,
134 VIS_ACTION_CURSOR_BRACKET_MATCH
,
135 VIS_ACTION_CURSOR_PARAGRAPH_PREV
,
136 VIS_ACTION_CURSOR_PARAGRAPH_NEXT
,
137 VIS_ACTION_CURSOR_SENTENCE_PREV
,
138 VIS_ACTION_CURSOR_SENTENCE_NEXT
,
139 VIS_ACTION_CURSOR_FUNCTION_START_PREV
,
140 VIS_ACTION_CURSOR_FUNCTION_END_PREV
,
141 VIS_ACTION_CURSOR_FUNCTION_START_NEXT
,
142 VIS_ACTION_CURSOR_FUNCTION_END_NEXT
,
143 VIS_ACTION_CURSOR_COLUMN
,
144 VIS_ACTION_CURSOR_LINE_FIRST
,
145 VIS_ACTION_CURSOR_LINE_LAST
,
146 VIS_ACTION_CURSOR_WINDOW_LINE_TOP
,
147 VIS_ACTION_CURSOR_WINDOW_LINE_MIDDLE
,
148 VIS_ACTION_CURSOR_WINDOW_LINE_BOTTOM
,
149 VIS_ACTION_CURSOR_SEARCH_NEXT
,
150 VIS_ACTION_CURSOR_SEARCH_PREV
,
151 VIS_ACTION_CURSOR_SEARCH_WORD_FORWARD
,
152 VIS_ACTION_CURSOR_SEARCH_WORD_BACKWARD
,
153 VIS_ACTION_WINDOW_PAGE_UP
,
154 VIS_ACTION_WINDOW_PAGE_DOWN
,
155 VIS_ACTION_WINDOW_HALFPAGE_UP
,
156 VIS_ACTION_WINDOW_HALFPAGE_DOWN
,
157 VIS_ACTION_MODE_NORMAL
,
158 VIS_ACTION_MODE_VISUAL
,
159 VIS_ACTION_MODE_VISUAL_LINE
,
160 VIS_ACTION_MODE_INSERT
,
161 VIS_ACTION_MODE_REPLACE
,
162 VIS_ACTION_MODE_OPERATOR_PENDING
,
163 VIS_ACTION_DELETE_CHAR_PREV
,
164 VIS_ACTION_DELETE_CHAR_NEXT
,
165 VIS_ACTION_DELETE_LINE_BEGIN
,
166 VIS_ACTION_DELETE_WORD_PREV
,
167 VIS_ACTION_JUMPLIST_PREV
,
168 VIS_ACTION_JUMPLIST_NEXT
,
169 VIS_ACTION_CHANGELIST_PREV
,
170 VIS_ACTION_CHANGELIST_NEXT
,
175 VIS_ACTION_MACRO_RECORD
,
176 VIS_ACTION_MACRO_REPLAY
,
178 VIS_ACTION_MARK_GOTO
,
179 VIS_ACTION_MARK_GOTO_LINE
,
181 VIS_ACTION_REPLACE_CHAR
,
182 VIS_ACTION_TOTILL_REPEAT
,
183 VIS_ACTION_TOTILL_REVERSE
,
184 VIS_ACTION_PROMPT_SEARCH_FORWARD
,
185 VIS_ACTION_PROMPT_SEARCH_BACKWARD
,
186 VIS_ACTION_TILL_LEFT
,
187 VIS_ACTION_TILL_RIGHT
,
191 VIS_ACTION_OPERATOR_CHANGE
,
192 VIS_ACTION_OPERATOR_DELETE
,
193 VIS_ACTION_OPERATOR_YANK
,
194 VIS_ACTION_OPERATOR_SHIFT_LEFT
,
195 VIS_ACTION_OPERATOR_SHIFT_RIGHT
,
196 VIS_ACTION_OPERATOR_CASE_LOWER
,
197 VIS_ACTION_OPERATOR_CASE_UPPER
,
198 VIS_ACTION_OPERATOR_CASE_SWAP
,
199 VIS_ACTION_OPERATOR_FILTER
,
200 VIS_ACTION_OPERATOR_FILTER_FMT
,
202 VIS_ACTION_INSERT_NEWLINE
,
203 VIS_ACTION_INSERT_TAB
,
204 VIS_ACTION_INSERT_VERBATIM
,
205 VIS_ACTION_INSERT_REGISTER
,
206 VIS_ACTION_WINDOW_NEXT
,
207 VIS_ACTION_WINDOW_PREV
,
208 VIS_ACTION_APPEND_CHAR_NEXT
,
209 VIS_ACTION_APPEND_LINE_END
,
210 VIS_ACTION_INSERT_LINE_START
,
211 VIS_ACTION_OPEN_LINE_ABOVE
,
212 VIS_ACTION_OPEN_LINE_BELOW
,
213 VIS_ACTION_JOIN_LINE_BELOW
,
214 VIS_ACTION_JOIN_LINES
,
215 VIS_ACTION_PROMPT_SHOW
,
216 VIS_ACTION_PROMPT_SHOW_VISUAL
,
218 VIS_ACTION_SELECTION_FLIP
,
219 VIS_ACTION_SELECTION_RESTORE
,
220 VIS_ACTION_WINDOW_REDRAW_TOP
,
221 VIS_ACTION_WINDOW_REDRAW_CENTER
,
222 VIS_ACTION_WINDOW_REDRAW_BOTTOM
,
223 VIS_ACTION_WINDOW_SLIDE_UP
,
224 VIS_ACTION_WINDOW_SLIDE_DOWN
,
225 VIS_ACTION_PUT_AFTER
,
226 VIS_ACTION_PUT_BEFORE
,
227 VIS_ACTION_PUT_AFTER_END
,
228 VIS_ACTION_PUT_BEFORE_END
,
229 VIS_ACTION_CURSOR_SELECT_WORD
,
230 VIS_ACTION_CURSORS_NEW_LINE_ABOVE
,
231 VIS_ACTION_CURSORS_NEW_LINE_BELOW
,
232 VIS_ACTION_CURSORS_NEW_LINES_BEGIN
,
233 VIS_ACTION_CURSORS_NEW_LINES_END
,
234 VIS_ACTION_CURSORS_NEW_MATCH_NEXT
,
235 VIS_ACTION_CURSORS_NEW_MATCH_SKIP
,
236 VIS_ACTION_CURSORS_ALIGN
,
237 VIS_ACTION_CURSORS_REMOVE_ALL
,
238 VIS_ACTION_CURSORS_REMOVE_LAST
,
239 VIS_ACTION_TEXT_OBJECT_WORD_OUTER
,
240 VIS_ACTION_TEXT_OBJECT_WORD_INNER
,
241 VIS_ACTION_TEXT_OBJECT_LONGWORD_OUTER
,
242 VIS_ACTION_TEXT_OBJECT_LONGWORD_INNER
,
243 VIS_ACTION_TEXT_OBJECT_SENTENCE
,
244 VIS_ACTION_TEXT_OBJECT_PARAGRAPH
,
245 VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_OUTER
,
246 VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_INNER
,
247 VIS_ACTION_TEXT_OBJECT_PARANTHESE_OUTER
,
248 VIS_ACTION_TEXT_OBJECT_PARANTHESE_INNER
,
249 VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_OUTER
,
250 VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_INNER
,
251 VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_OUTER
,
252 VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_INNER
,
253 VIS_ACTION_TEXT_OBJECT_QUOTE_OUTER
,
254 VIS_ACTION_TEXT_OBJECT_QUOTE_INNER
,
255 VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_OUTER
,
256 VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_INNER
,
257 VIS_ACTION_TEXT_OBJECT_BACKTICK_OUTER
,
258 VIS_ACTION_TEXT_OBJECT_BACKTICK_INNER
,
259 VIS_ACTION_TEXT_OBJECT_ENTIRE_OUTER
,
260 VIS_ACTION_TEXT_OBJECT_ENTIRE_INNER
,
261 VIS_ACTION_TEXT_OBJECT_FUNCTION_OUTER
,
262 VIS_ACTION_TEXT_OBJECT_FUNCTION_INNER
,
263 VIS_ACTION_TEXT_OBJECT_LINE_OUTER
,
264 VIS_ACTION_TEXT_OBJECT_LINE_INNER
,
265 VIS_ACTION_MOTION_CHARWISE
,
266 VIS_ACTION_MOTION_LINEWISE
,
267 VIS_ACTION_UNICODE_INFO
,
271 static KeyAction vis_action
[] = {
272 [VIS_ACTION_EDITOR_SUSPEND
] = {
274 "Suspend the editor",
277 [VIS_ACTION_CURSOR_CHAR_PREV
] = {
279 "Move cursor left, to the previous character",
280 movement
, { .i
= VIS_MOVE_CHAR_PREV
}
282 [VIS_ACTION_CURSOR_CHAR_NEXT
] = {
284 "Move cursor right, to the next character",
285 movement
, { .i
= VIS_MOVE_CHAR_NEXT
}
287 [VIS_ACTION_CURSOR_WORD_START_PREV
] = {
288 "cursor-word-start-prev",
289 "Move cursor words backwards",
290 movement
, { .i
= VIS_MOVE_WORD_START_PREV
}
292 [VIS_ACTION_CURSOR_WORD_START_NEXT
] = {
293 "cursor-word-start-next",
294 "Move cursor words forwards",
295 movement
, { .i
= VIS_MOVE_WORD_START_NEXT
}
297 [VIS_ACTION_CURSOR_WORD_END_PREV
] = {
298 "cursor-word-end-prev",
299 "Move cursor backwards to the end of word",
300 movement
, { .i
= VIS_MOVE_WORD_END_PREV
}
302 [VIS_ACTION_CURSOR_WORD_END_NEXT
] = {
303 "cursor-word-end-next",
304 "Move cursor forward to the end of word",
305 movement
, { .i
= VIS_MOVE_WORD_END_NEXT
}
307 [VIS_ACTION_CURSOR_LONGWORD_START_PREV
] = {
308 "cursor-longword-start-prev",
309 "Move cursor WORDS backwards",
310 movement
, { .i
= VIS_MOVE_LONGWORD_START_PREV
}
312 [VIS_ACTION_CURSOR_LONGWORD_START_NEXT
] = {
313 "cursor-longword-start-next",
314 "Move cursor WORDS forwards",
315 movement
, { .i
= VIS_MOVE_LONGWORD_START_NEXT
}
317 [VIS_ACTION_CURSOR_LONGWORD_END_PREV
] = {
318 "cursor-longword-end-prev",
319 "Move cursor backwards to the end of WORD",
320 movement
, { .i
= VIS_MOVE_LONGWORD_END_PREV
}
322 [VIS_ACTION_CURSOR_LONGWORD_END_NEXT
] = {
323 "cursor-longword-end-next",
324 "Move cursor forward to the end of WORD",
325 movement
, { .i
= VIS_MOVE_LONGWORD_END_NEXT
}
327 [VIS_ACTION_CURSOR_LINE_UP
] = {
329 "Move cursor line upwards",
330 movement
, { .i
= VIS_MOVE_LINE_UP
}
332 [VIS_ACTION_CURSOR_LINE_DOWN
] = {
334 "Move cursor line downwards",
335 movement
, { .i
= VIS_MOVE_LINE_DOWN
}
337 [VIS_ACTION_CURSOR_LINE_START
] = {
339 "Move cursor to first non-blank character of the line",
340 movement
, { .i
= VIS_MOVE_LINE_START
}
342 [VIS_ACTION_CURSOR_LINE_FINISH
] = {
343 "cursor-line-finish",
344 "Move cursor to last non-blank character of the line",
345 movement
, { .i
= VIS_MOVE_LINE_FINISH
}
347 [VIS_ACTION_CURSOR_LINE_BEGIN
] = {
349 "Move cursor to first character of the line",
350 movement
, { .i
= VIS_MOVE_LINE_BEGIN
}
352 [VIS_ACTION_CURSOR_LINE_END
] = {
354 "Move cursor to end of the line",
355 movement
, { .i
= VIS_MOVE_LINE_LASTCHAR
}
357 [VIS_ACTION_CURSOR_SCREEN_LINE_UP
] = {
358 "cursor-sceenline-up",
359 "Move cursor screen/display line upwards",
360 movement
, { .i
= VIS_MOVE_SCREEN_LINE_UP
}
362 [VIS_ACTION_CURSOR_SCREEN_LINE_DOWN
] = {
363 "cursor-screenline-down",
364 "Move cursor screen/display line downwards",
365 movement
, { .i
= VIS_MOVE_SCREEN_LINE_DOWN
}
367 [VIS_ACTION_CURSOR_SCREEN_LINE_BEGIN
] = {
368 "cursor-screenline-begin",
369 "Move cursor to beginning of screen/display line",
370 movement
, { .i
= VIS_MOVE_SCREEN_LINE_BEGIN
}
372 [VIS_ACTION_CURSOR_SCREEN_LINE_MIDDLE
] = {
373 "cursor-screenline-middle",
374 "Move cursor to middle of screen/display line",
375 movement
, { .i
= VIS_MOVE_SCREEN_LINE_MIDDLE
}
377 [VIS_ACTION_CURSOR_SCREEN_LINE_END
] = {
378 "cursor-screenline-end",
379 "Move cursor to end of screen/display line",
380 movement
, { .i
= VIS_MOVE_SCREEN_LINE_END
}
382 [VIS_ACTION_CURSOR_BRACKET_MATCH
] = {
383 "cursor-match-bracket",
384 "Match corresponding symbol if cursor is on a bracket character",
385 movement
, { .i
= VIS_MOVE_BRACKET_MATCH
}
387 [VIS_ACTION_CURSOR_PARAGRAPH_PREV
] = {
388 "cursor-paragraph-prev",
389 "Move cursor paragraph backward",
390 movement
, { .i
= VIS_MOVE_PARAGRAPH_PREV
}
392 [VIS_ACTION_CURSOR_PARAGRAPH_NEXT
] = {
393 "cursor-paragraph-next",
394 "Move cursor paragraph forward",
395 movement
, { .i
= VIS_MOVE_PARAGRAPH_NEXT
}
397 [VIS_ACTION_CURSOR_SENTENCE_PREV
] = {
398 "cursor-sentence-prev",
399 "Move cursor sentence backward",
400 movement
, { .i
= VIS_MOVE_SENTENCE_PREV
}
402 [VIS_ACTION_CURSOR_SENTENCE_NEXT
] = {
403 "cursor-sentence-next",
404 "Move cursor sentence forward",
405 movement
, { .i
= VIS_MOVE_SENTENCE_NEXT
}
407 [VIS_ACTION_CURSOR_FUNCTION_START_PREV
] = {
408 "cursor-function-start-prev",
409 "Move cursor backwards to start of function",
410 movement
, { .i
= VIS_MOVE_FUNCTION_START_PREV
}
412 [VIS_ACTION_CURSOR_FUNCTION_START_NEXT
] = {
413 "cursor-function-start-next",
414 "Move cursor forwards to start of function",
415 movement
, { .i
= VIS_MOVE_FUNCTION_START_NEXT
}
417 [VIS_ACTION_CURSOR_FUNCTION_END_PREV
] = {
418 "cursor-function-end-prev",
419 "Move cursor backwards to end of function",
420 movement
, { .i
= VIS_MOVE_FUNCTION_END_PREV
}
422 [VIS_ACTION_CURSOR_FUNCTION_END_NEXT
] = {
423 "cursor-function-end-next",
424 "Move cursor forwards to end of function",
425 movement
, { .i
= VIS_MOVE_FUNCTION_END_NEXT
}
427 [VIS_ACTION_CURSOR_COLUMN
] = {
429 "Move cursor to given column of current line",
430 movement
, { .i
= VIS_MOVE_COLUMN
}
432 [VIS_ACTION_CURSOR_LINE_FIRST
] = {
434 "Move cursor to given line (defaults to first)",
435 gotoline
, { .i
= -1 }
437 [VIS_ACTION_CURSOR_LINE_LAST
] = {
439 "Move cursor to given line (defaults to last)",
440 gotoline
, { .i
= +1 }
442 [VIS_ACTION_CURSOR_WINDOW_LINE_TOP
] = {
443 "cursor-window-line-top",
444 "Move cursor to top line of the window",
445 movement
, { .i
= VIS_MOVE_WINDOW_LINE_TOP
}
447 [VIS_ACTION_CURSOR_WINDOW_LINE_MIDDLE
] = {
448 "cursor-window-line-middle",
449 "Move cursor to middle line of the window",
450 movement
, { .i
= VIS_MOVE_WINDOW_LINE_MIDDLE
}
452 [VIS_ACTION_CURSOR_WINDOW_LINE_BOTTOM
] = {
453 "cursor-window-line-bottom",
454 "Move cursor to bottom line of the window",
455 movement
, { .i
= VIS_MOVE_WINDOW_LINE_BOTTOM
}
457 [VIS_ACTION_CURSOR_SEARCH_NEXT
] = {
458 "cursor-search-forward",
459 "Move cursor to bottom line of the window",
460 movement
, { .i
= VIS_MOVE_SEARCH_NEXT
}
462 [VIS_ACTION_CURSOR_SEARCH_PREV
] = {
463 "cursor-search-backward",
464 "Move cursor to bottom line of the window",
465 movement
, { .i
= VIS_MOVE_SEARCH_PREV
}
467 [VIS_ACTION_CURSOR_SEARCH_WORD_FORWARD
] = {
468 "cursor-search-word-forward",
469 "Move cursor to next occurence of the word under cursor",
470 movement
, { .i
= VIS_MOVE_SEARCH_WORD_FORWARD
}
472 [VIS_ACTION_CURSOR_SEARCH_WORD_BACKWARD
] = {
473 "cursor-search-word-backward",
474 "Move cursor to previous occurence of the word under cursor",
475 movement
, { .i
= VIS_MOVE_SEARCH_WORD_BACKWARD
}
477 [VIS_ACTION_WINDOW_PAGE_UP
] = {
479 "Scroll window pages backwards (upwards)",
480 wscroll
, { .i
= -PAGE
}
482 [VIS_ACTION_WINDOW_HALFPAGE_UP
] = {
483 "window-halfpage-up",
484 "Scroll window half pages backwards (upwards)",
485 wscroll
, { .i
= -PAGE_HALF
}
487 [VIS_ACTION_WINDOW_PAGE_DOWN
] = {
489 "Scroll window pages forwards (downwards)",
490 wscroll
, { .i
= +PAGE
}
492 [VIS_ACTION_WINDOW_HALFPAGE_DOWN
] = {
493 "window-halfpage-down",
494 "Scroll window half pages forwards (downwards)",
495 wscroll
, { .i
= +PAGE_HALF
}
497 [VIS_ACTION_MODE_NORMAL
] = {
500 switchmode
, { .i
= VIS_MODE_NORMAL
}
502 [VIS_ACTION_MODE_VISUAL
] = {
503 "vis-mode-visual-charwise",
504 "Enter characterwise visual mode",
505 switchmode
, { .i
= VIS_MODE_VISUAL
}
507 [VIS_ACTION_MODE_VISUAL_LINE
] = {
508 "vis-mode-visual-linewise",
509 "Enter linewise visual mode",
510 switchmode
, { .i
= VIS_MODE_VISUAL_LINE
}
512 [VIS_ACTION_MODE_INSERT
] = {
515 switchmode
, { .i
= VIS_MODE_INSERT
}
517 [VIS_ACTION_MODE_REPLACE
] = {
519 "Enter replace mode",
520 switchmode
, { .i
= VIS_MODE_REPLACE
}
522 [VIS_ACTION_MODE_OPERATOR_PENDING
] = {
523 "vis-mode-operator-pending",
524 "Enter to operator pending mode",
525 switchmode
, { .i
= VIS_MODE_OPERATOR_PENDING
}
527 [VIS_ACTION_DELETE_CHAR_PREV
] = {
529 "Delete the previous character",
530 delete, { .i
= VIS_MOVE_CHAR_PREV
}
532 [VIS_ACTION_DELETE_CHAR_NEXT
] = {
534 "Delete the next character",
535 delete, { .i
= VIS_MOVE_CHAR_NEXT
}
537 [VIS_ACTION_DELETE_LINE_BEGIN
] = {
539 "Delete until the start of the current line",
540 delete, { .i
= VIS_MOVE_LINE_BEGIN
}
542 [VIS_ACTION_DELETE_WORD_PREV
] = {
544 "Delete the previous WORD",
545 delete, { .i
= VIS_MOVE_LONGWORD_START_PREV
}
547 [VIS_ACTION_JUMPLIST_PREV
] = {
549 "Go to older cursor position in jump list",
550 movement
, { .i
= VIS_MOVE_JUMPLIST_PREV
}
552 [VIS_ACTION_JUMPLIST_NEXT
] = {
554 "Go to newer cursor position in jump list",
555 movement
, { .i
= VIS_MOVE_JUMPLIST_NEXT
}
557 [VIS_ACTION_CHANGELIST_PREV
] = {
559 "Go to older cursor position in change list",
560 movement
, { .i
= VIS_MOVE_CHANGELIST_PREV
}
562 [VIS_ACTION_CHANGELIST_NEXT
] = {
564 "Go to newer cursor position in change list",
565 movement
, { .i
= VIS_MOVE_CHANGELIST_NEXT
}
567 [VIS_ACTION_UNDO
] = {
572 [VIS_ACTION_REDO
] = {
577 [VIS_ACTION_EARLIER
] = {
579 "Goto older text state",
582 [VIS_ACTION_LATER
] = {
584 "Goto newer text state",
587 [VIS_ACTION_MACRO_RECORD
] = {
589 "Record macro into given register",
592 [VIS_ACTION_MACRO_REPLAY
] = {
594 "Replay macro, execute the content of the given register",
597 [VIS_ACTION_MARK_SET
] = {
599 "Set given mark at current cursor position",
602 [VIS_ACTION_MARK_GOTO
] = {
604 "Goto the position of the given mark",
605 mark_motion
, { .i
= VIS_MOVE_MARK
}
607 [VIS_ACTION_MARK_GOTO_LINE
] = {
609 "Goto first non-blank character of the line containing the given mark",
610 mark_motion
, { .i
= VIS_MOVE_MARK_LINE
}
612 [VIS_ACTION_REDRAW
] = {
614 "Redraw current editor content",
615 call
, { .f
= vis_redraw
}
617 [VIS_ACTION_REPLACE_CHAR
] = {
619 "Replace the character under the cursor",
622 [VIS_ACTION_TOTILL_REPEAT
] = {
624 "Repeat latest to/till motion",
625 movement
, { .i
= VIS_MOVE_TOTILL_REPEAT
}
627 [VIS_ACTION_TOTILL_REVERSE
] = {
629 "Repeat latest to/till motion but in opposite direction",
630 movement
, { .i
= VIS_MOVE_TOTILL_REVERSE
}
632 [VIS_ACTION_PROMPT_SEARCH_FORWARD
] = {
635 prompt_show
, { .s
= "/" }
637 [VIS_ACTION_PROMPT_SEARCH_BACKWARD
] = {
640 prompt_show
, { .s
= "?" }
642 [VIS_ACTION_TILL_LEFT
] = {
644 "Till after the occurrence of character to the left",
645 movement_key
, { .i
= VIS_MOVE_LEFT_TILL
}
647 [VIS_ACTION_TILL_RIGHT
] = {
649 "Till before the occurrence of character to the right",
650 movement_key
, { .i
= VIS_MOVE_RIGHT_TILL
}
652 [VIS_ACTION_TO_LEFT
] = {
654 "To the first occurrence of character to the left",
655 movement_key
, { .i
= VIS_MOVE_LEFT_TO
}
657 [VIS_ACTION_TO_RIGHT
] = {
659 "To the first occurrence of character to the right",
660 movement_key
, { .i
= VIS_MOVE_RIGHT_TO
}
662 [VIS_ACTION_REGISTER
] = {
664 "Use given register for next operator",
667 [VIS_ACTION_OPERATOR_CHANGE
] = {
668 "vis-operator-change",
670 operator, { .i
= VIS_OP_CHANGE
}
672 [VIS_ACTION_OPERATOR_DELETE
] = {
673 "vis-operator-delete",
675 operator, { .i
= VIS_OP_DELETE
}
677 [VIS_ACTION_OPERATOR_YANK
] = {
680 operator, { .i
= VIS_OP_YANK
}
682 [VIS_ACTION_OPERATOR_SHIFT_LEFT
] = {
683 "vis-operator-shift-left",
684 "Shift left operator",
685 operator, { .i
= VIS_OP_SHIFT_LEFT
}
687 [VIS_ACTION_OPERATOR_SHIFT_RIGHT
] = {
688 "vis-operator-shift-right",
689 "Shift right operator",
690 operator, { .i
= VIS_OP_SHIFT_RIGHT
}
692 [VIS_ACTION_OPERATOR_CASE_LOWER
] = {
693 "vis-operator-case-lower",
694 "Lowercase operator",
695 operator, { .i
= VIS_OP_CASE_LOWER
}
697 [VIS_ACTION_OPERATOR_CASE_UPPER
] = {
698 "vis-operator-case-upper",
699 "Uppercase operator",
700 operator, { .i
= VIS_OP_CASE_UPPER
}
702 [VIS_ACTION_OPERATOR_CASE_SWAP
] = {
703 "vis-operator-case-swap",
704 "Swap case operator",
705 operator, { .i
= VIS_OP_CASE_SWAP
}
707 [VIS_ACTION_OPERATOR_FILTER
] = {
708 "vis-operator-filter",
712 [VIS_ACTION_OPERATOR_FILTER_FMT
] = {
713 "vis-operator-filter-format",
714 "Formating operator, filter range through fmt(1)",
715 operator_filter
, { .s
= "'<,'>!fmt" }
717 [VIS_ACTION_COUNT
] = {
722 [VIS_ACTION_INSERT_NEWLINE
] = {
724 "Insert a line break (depending on file type)",
725 call
, { .f
= vis_insert_nl
}
727 [VIS_ACTION_INSERT_TAB
] = {
729 "Insert a tab (might be converted to spaces)",
730 call
, { .f
= vis_insert_tab
}
732 [VIS_ACTION_INSERT_VERBATIM
] = {
734 "Insert Unicode character based on code point",
737 [VIS_ACTION_INSERT_REGISTER
] = {
739 "Insert specified register content",
742 [VIS_ACTION_WINDOW_NEXT
] = {
745 call
, { .f
= vis_window_next
}
747 [VIS_ACTION_WINDOW_PREV
] = {
749 "Focus previous window",
750 call
, { .f
= vis_window_prev
}
752 [VIS_ACTION_APPEND_CHAR_NEXT
] = {
754 "Append text after the cursor",
755 insertmode
, { .i
= VIS_MOVE_CHAR_NEXT
}
757 [VIS_ACTION_APPEND_LINE_END
] = {
759 "Append text after the end of the line",
760 insertmode
, { .i
= VIS_MOVE_LINE_END
},
762 [VIS_ACTION_INSERT_LINE_START
] = {
764 "Insert text before the first non-blank in the line",
765 insertmode
, { .i
= VIS_MOVE_LINE_START
},
767 [VIS_ACTION_OPEN_LINE_ABOVE
] = {
769 "Begin a new line above the cursor",
770 openline
, { .i
= -1 }
772 [VIS_ACTION_OPEN_LINE_BELOW
] = {
774 "Begin a new line below the cursor",
775 openline
, { .i
= +1 }
777 [VIS_ACTION_JOIN_LINE_BELOW
] = {
780 join
, { .i
= VIS_MOVE_LINE_NEXT
},
782 [VIS_ACTION_JOIN_LINES
] = {
784 "Join selected lines",
785 operator, { .i
= VIS_OP_JOIN
}
787 [VIS_ACTION_PROMPT_SHOW
] = {
789 "Show editor command line prompt",
790 prompt_show
, { .s
= ":" }
792 [VIS_ACTION_PROMPT_SHOW_VISUAL
] = {
793 "prompt-show-visual",
794 "Show editor command line prompt in visual mode",
795 prompt_show
, { .s
= "'<,'>" }
797 [VIS_ACTION_REPEAT
] = {
799 "Repeat latest editor command",
802 [VIS_ACTION_SELECTION_FLIP
] = {
804 "Flip selection, move cursor to other end",
807 [VIS_ACTION_SELECTION_RESTORE
] = {
809 "Restore last selection",
812 [VIS_ACTION_WINDOW_REDRAW_TOP
] = {
814 "Redraw cursor line at the top of the window",
815 window
, { .w
= view_redraw_top
}
817 [VIS_ACTION_WINDOW_REDRAW_CENTER
] = {
818 "window-redraw-center",
819 "Redraw cursor line at the center of the window",
820 window
, { .w
= view_redraw_center
}
822 [VIS_ACTION_WINDOW_REDRAW_BOTTOM
] = {
823 "window-redraw-bottom",
824 "Redraw cursor line at the bottom of the window",
825 window
, { .w
= view_redraw_bottom
}
827 [VIS_ACTION_WINDOW_SLIDE_UP
] = {
829 "Slide window content upwards",
832 [VIS_ACTION_WINDOW_SLIDE_DOWN
] = {
834 "Slide window content downwards",
837 [VIS_ACTION_PUT_AFTER
] = {
839 "Put text after the cursor",
840 operator, { .i
= VIS_OP_PUT_AFTER
}
842 [VIS_ACTION_PUT_BEFORE
] = {
844 "Put text before the cursor",
845 operator, { .i
= VIS_OP_PUT_BEFORE
}
847 [VIS_ACTION_PUT_AFTER_END
] = {
849 "Put text after the cursor, place cursor after new text",
850 operator, { .i
= VIS_OP_PUT_AFTER_END
}
852 [VIS_ACTION_PUT_BEFORE_END
] = {
854 "Put text before the cursor, place cursor after new text",
855 operator, { .i
= VIS_OP_PUT_BEFORE_END
}
857 [VIS_ACTION_CURSOR_SELECT_WORD
] = {
858 "cursors-select-word",
859 "Select word under cursor",
862 [VIS_ACTION_CURSORS_NEW_LINE_ABOVE
] = {
863 "cursors-new-lines-above",
864 "Create a new cursor on the line above",
865 cursors_new
, { .i
= -1 }
867 [VIS_ACTION_CURSORS_NEW_LINE_BELOW
] = {
868 "cursor-new-lines-below",
869 "Create a new cursor on the line below",
870 cursors_new
, { .i
= +1 }
872 [VIS_ACTION_CURSORS_NEW_LINES_BEGIN
] = {
873 "cursors-new-lines-begin",
874 "Create a new cursor at the start of every line covered by selection",
875 operator, { .i
= VIS_OP_CURSOR_SOL
}
877 [VIS_ACTION_CURSORS_NEW_LINES_END
] = {
878 "cursors-new-lines-end",
879 "Create a new cursor at the end of every line covered by selection",
880 operator, { .i
= VIS_OP_CURSOR_EOL
}
882 [VIS_ACTION_CURSORS_NEW_MATCH_NEXT
] = {
883 "cursors-new-match-next",
884 "Select the next region matching the current selection",
887 [VIS_ACTION_CURSORS_NEW_MATCH_SKIP
] = {
888 "cursors-new-match-skip",
889 "Clear current selection, but select next match",
892 [VIS_ACTION_CURSORS_ALIGN
] = {
894 "Try to align all cursors on the same column",
897 [VIS_ACTION_CURSORS_REMOVE_ALL
] = {
898 "cursors-remove-all",
899 "Remove all but the primary cursor",
902 [VIS_ACTION_CURSORS_REMOVE_LAST
] = {
903 "cursors-remove-last",
904 "Remove least recently created cursor",
907 [VIS_ACTION_TEXT_OBJECT_WORD_OUTER
] = {
908 "text-object-word-outer",
909 "A word leading and trailing whitespace included",
910 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_WORD
}
912 [VIS_ACTION_TEXT_OBJECT_WORD_INNER
] = {
913 "text-object-word-inner",
914 "A word leading and trailing whitespace excluded",
915 textobj
, { .i
= VIS_TEXTOBJECT_INNER_WORD
}
917 [VIS_ACTION_TEXT_OBJECT_LONGWORD_OUTER
] = {
918 "text-object-longword-outer",
919 "A WORD leading and trailing whitespace included",
920 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_LONGWORD
}
922 [VIS_ACTION_TEXT_OBJECT_LONGWORD_INNER
] = {
923 "text-object-longword-inner",
924 "A WORD leading and trailing whitespace excluded",
925 textobj
, { .i
= VIS_TEXTOBJECT_INNER_LONGWORD
}
927 [VIS_ACTION_TEXT_OBJECT_SENTENCE
] = {
928 "text-object-sentence",
930 textobj
, { .i
= VIS_TEXTOBJECT_SENTENCE
}
932 [VIS_ACTION_TEXT_OBJECT_PARAGRAPH
] = {
933 "text-object-paragraph",
935 textobj
, { .i
= VIS_TEXTOBJECT_PARAGRAPH
}
937 [VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_OUTER
] = {
938 "text-object-square-bracket-outer",
939 "[] block (outer variant)",
940 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_SQUARE_BRACKET
}
942 [VIS_ACTION_TEXT_OBJECT_SQUARE_BRACKET_INNER
] = {
943 "text-object-square-bracket-inner",
944 "[] block (inner variant)",
945 textobj
, { .i
= VIS_TEXTOBJECT_INNER_SQUARE_BRACKET
}
947 [VIS_ACTION_TEXT_OBJECT_PARANTHESE_OUTER
] = {
948 "text-object-parentheses-outer",
949 "() block (outer variant)",
950 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_PARANTHESE
}
952 [VIS_ACTION_TEXT_OBJECT_PARANTHESE_INNER
] = {
953 "text-object-parentheses-inner",
954 "() block (inner variant)",
955 textobj
, { .i
= VIS_TEXTOBJECT_INNER_PARANTHESE
}
957 [VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_OUTER
] = {
958 "text-object-angle-bracket-outer",
959 "<> block (outer variant)",
960 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_ANGLE_BRACKET
}
962 [VIS_ACTION_TEXT_OBJECT_ANGLE_BRACKET_INNER
] = {
963 "text-object-angle-bracket-inner",
964 "<> block (inner variant)",
965 textobj
, { .i
= VIS_TEXTOBJECT_INNER_ANGLE_BRACKET
}
967 [VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_OUTER
] = {
968 "text-object-curly-bracket-outer",
969 "{} block (outer variant)",
970 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_CURLY_BRACKET
}
972 [VIS_ACTION_TEXT_OBJECT_CURLY_BRACKET_INNER
] = {
973 "text-object-curly-bracket-inner",
974 "{} block (inner variant)",
975 textobj
, { .i
= VIS_TEXTOBJECT_INNER_CURLY_BRACKET
}
977 [VIS_ACTION_TEXT_OBJECT_QUOTE_OUTER
] = {
978 "text-object-quote-outer",
979 "A quoted string, including the quotation marks",
980 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_QUOTE
}
982 [VIS_ACTION_TEXT_OBJECT_QUOTE_INNER
] = {
983 "text-object-quote-inner",
984 "A quoted string, excluding the quotation marks",
985 textobj
, { .i
= VIS_TEXTOBJECT_INNER_QUOTE
}
987 [VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_OUTER
] = {
988 "text-object-single-quote-outer",
989 "A single quoted string, including the quotation marks",
990 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_SINGLE_QUOTE
}
992 [VIS_ACTION_TEXT_OBJECT_SINGLE_QUOTE_INNER
] = {
993 "text-object-single-quote-inner",
994 "A single quoted string, excluding the quotation marks",
995 textobj
, { .i
= VIS_TEXTOBJECT_INNER_SINGLE_QUOTE
}
997 [VIS_ACTION_TEXT_OBJECT_BACKTICK_OUTER
] = {
998 "text-object-backtick-outer",
999 "A backtick delimited string (outer variant)",
1000 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_BACKTICK
}
1002 [VIS_ACTION_TEXT_OBJECT_BACKTICK_INNER
] = {
1003 "text-object-backtick-inner",
1004 "A backtick delimited string (inner variant)",
1005 textobj
, { .i
= VIS_TEXTOBJECT_INNER_BACKTICK
}
1007 [VIS_ACTION_TEXT_OBJECT_ENTIRE_OUTER
] = {
1008 "text-object-entire-outer",
1009 "The whole text content",
1010 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_ENTIRE
}
1012 [VIS_ACTION_TEXT_OBJECT_ENTIRE_INNER
] = {
1013 "text-object-entire-inner",
1014 "The whole text content, except for leading and trailing empty lines",
1015 textobj
, { .i
= VIS_TEXTOBJECT_INNER_ENTIRE
}
1017 [VIS_ACTION_TEXT_OBJECT_FUNCTION_OUTER
] = {
1018 "text-object-function-outer",
1019 "A whole C-like function",
1020 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_FUNCTION
}
1022 [VIS_ACTION_TEXT_OBJECT_FUNCTION_INNER
] = {
1023 "text-object-function-inner",
1024 "A whole C-like function body",
1025 textobj
, { .i
= VIS_TEXTOBJECT_INNER_FUNCTION
}
1027 [VIS_ACTION_TEXT_OBJECT_LINE_OUTER
] = {
1028 "text-object-line-outer",
1030 textobj
, { .i
= VIS_TEXTOBJECT_OUTER_LINE
}
1032 [VIS_ACTION_TEXT_OBJECT_LINE_INNER
] = {
1033 "text-object-line-inner",
1034 "The whole line, excluding leading and trailing whitespace",
1035 textobj
, { .i
= VIS_TEXTOBJECT_INNER_LINE
}
1037 [VIS_ACTION_MOTION_CHARWISE
] = {
1039 "Force motion to be charwise",
1040 motiontype
, { .i
= VIS_MOTIONTYPE_CHARWISE
}
1042 [VIS_ACTION_MOTION_LINEWISE
] = {
1044 "Force motion to be linewise",
1045 motiontype
, { .i
= VIS_MOTIONTYPE_LINEWISE
}
1047 [VIS_ACTION_UNICODE_INFO
] = {
1049 "Show Unicode codepoint(s) of character under cursor",
1052 [VIS_ACTION_NOP
] = {
1054 "Ignore key, do nothing",
1061 /** key bindings functions */
1063 static const char *nop(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1067 static const char *key2macro(Vis
*vis
, const char *keys
, enum VisMacro
*macro
) {
1068 *macro
= VIS_MACRO_INVALID
;
1069 if (keys
[0] >= 'a' && keys
[0] <= 'z')
1070 *macro
= keys
[0] - 'a';
1071 else if (keys
[0] == '@')
1072 *macro
= VIS_MACRO_LAST_RECORDED
;
1073 else if (keys
[0] == '\0')
1078 static const char *macro_record(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1079 if (vis_macro_record_stop(vis
))
1081 enum VisMacro macro
;
1082 keys
= key2macro(vis
, keys
, ¯o
);
1083 vis_macro_record(vis
, macro
);
1088 static const char *macro_replay(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1089 enum VisMacro macro
;
1090 keys
= key2macro(vis
, keys
, ¯o
);
1091 vis_macro_replay(vis
, macro
);
1095 static const char *suspend(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1100 static const char *repeat(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1105 static const char *cursors_new(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1106 View
*view
= vis_view(vis
);
1107 size_t pos
= view_cursor_get(view
);
1108 Cursor
*cursor
= view_cursors_new(view
);
1110 view_cursors_to(cursor
, pos
);
1112 view_line_down(cursor
);
1113 else if (arg
->i
< 0)
1114 view_line_up(cursor
);
1119 static const char *cursors_align(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1120 View
*view
= vis_view(vis
);
1121 Text
*txt
= vis_text(vis
);
1122 int mincol
= INT_MAX
;
1123 for (Cursor
*c
= view_cursors(view
); c
; c
= view_cursors_next(c
)) {
1124 int col
= view_cursors_cell_get(c
);
1125 if (col
>= 0 && col
< mincol
)
1128 for (Cursor
*c
= view_cursors(view
); c
; c
= view_cursors_next(c
)) {
1129 if (view_cursors_cell_set(c
, mincol
) == -1) {
1130 size_t pos
= view_cursors_pos(c
);
1131 size_t col
= text_line_char_set(txt
, pos
, mincol
);
1132 view_cursors_to(c
, col
);
1138 static const char *cursors_clear(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1139 View
*view
= vis_view(vis
);
1140 if (view_cursors_count(view
) > 1)
1141 view_cursors_clear(view
);
1143 view_cursors_selection_clear(view_cursor(view
));
1147 static const char *cursors_select(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1148 Text
*txt
= vis_text(vis
);
1149 View
*view
= vis_view(vis
);
1150 for (Cursor
*cursor
= view_cursors(view
); cursor
; cursor
= view_cursors_next(cursor
)) {
1151 Filerange sel
= view_cursors_selection_get(cursor
);
1152 Filerange word
= text_object_word(txt
, view_cursors_pos(cursor
));
1153 if (!text_range_valid(&sel
) && text_range_valid(&word
)) {
1154 view_cursors_selection_set(cursor
, &word
);
1155 view_cursors_to(cursor
, text_char_prev(txt
, word
.end
));
1158 vis_mode_switch(vis
, VIS_MODE_VISUAL
);
1162 static const char *cursors_select_next(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1163 Text
*txt
= vis_text(vis
);
1164 View
*view
= vis_view(vis
);
1165 Cursor
*cursor
= view_cursor(view
);
1166 Filerange sel
= view_cursors_selection_get(cursor
);
1167 if (!text_range_valid(&sel
))
1170 size_t len
= text_range_size(&sel
);
1171 char *buf
= malloc(len
+1);
1174 len
= text_bytes_get(txt
, sel
.start
, len
, buf
);
1176 Filerange word
= text_object_word_find_next(txt
, sel
.end
, buf
);
1179 if (text_range_valid(&word
)) {
1180 cursor
= view_cursors_new(view
);
1183 view_cursors_selection_set(cursor
, &word
);
1184 view_cursors_to(cursor
, text_char_prev(txt
, word
.end
));
1189 static const char *cursors_select_skip(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1190 View
*view
= vis_view(vis
);
1191 Cursor
*cursor
= view_cursor(view
);
1192 keys
= cursors_select_next(vis
, keys
, arg
);
1193 if (cursor
!= view_cursor(view
))
1194 view_cursors_dispose(cursor
);
1198 static const char *cursors_remove(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1199 View
*view
= vis_view(vis
);
1200 view_cursors_dispose(view_cursor(view
));
1201 view_cursor_to(view
, view_cursor_get(view
));
1205 static const char *replace(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1208 const char *next
= vis_keys_next(vis
, keys
);
1211 size_t len
= next
- keys
;
1213 memcpy(key
, keys
, len
);
1215 vis_operator(vis
, VIS_OP_REPLACE
);
1216 vis_motion(vis
, VIS_MOVE_NOP
);
1217 vis_keys_inject(vis
, next
, key
);
1218 vis_keys_inject(vis
, next
+len
, "<Escape>");
1222 static const char *count(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1223 int digit
= keys
[-1] - '0';
1224 int count
= vis_count_get(vis
);
1225 if (0 <= digit
&& digit
<= 9) {
1226 if (digit
== 0 && count
== 0)
1227 vis_motion(vis
, VIS_MOVE_LINE_BEGIN
);
1228 vis_count_set(vis
, count
* 10 + digit
);
1233 static const char *gotoline(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1234 if (vis_count_get(vis
))
1235 vis_motion(vis
, VIS_MOVE_LINE
);
1236 else if (arg
->i
< 0)
1237 vis_motion(vis
, VIS_MOVE_FILE_BEGIN
);
1239 vis_motion(vis
, VIS_MOVE_FILE_END
);
1243 static const char *motiontype(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1244 vis_motion_type(vis
, arg
->i
);
1248 static const char *operator(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1249 vis_operator(vis
, arg
->i
);
1253 static const char *operator_filter(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1254 vis_operator(vis
, VIS_OP_FILTER
, arg
->s
);
1258 static const char *movement_key(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1262 const char *next
= vis_keys_next(vis
, keys
);
1263 strncpy(key
, keys
, next
- keys
+ 1);
1264 key
[sizeof(key
)-1] = '\0';
1265 vis_motion(vis
, arg
->i
, key
);
1269 static const char *movement(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1270 vis_motion(vis
, arg
->i
);
1274 static const char *textobj(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1275 vis_textobject(vis
, arg
->i
);
1279 static const char *selection_end(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1280 for (Cursor
*c
= view_cursors(vis_view(vis
)); c
; c
= view_cursors_next(c
))
1281 view_cursors_selection_swap(c
);
1285 static const char *selection_restore(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1286 for (Cursor
*c
= view_cursors(vis_view(vis
)); c
; c
= view_cursors_next(c
))
1287 view_cursors_selection_restore(c
);
1288 vis_mode_switch(vis
, VIS_MODE_VISUAL
);
1292 static const char *key2register(Vis
*vis
, const char *keys
, enum VisRegister
*reg
) {
1293 *reg
= VIS_REG_INVALID
;
1296 if (keys
[0] >= 'a' && keys
[0] <= 'z')
1297 *reg
= keys
[0] - 'a';
1301 static const char *reg(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1302 enum VisRegister reg
;
1303 keys
= key2register(vis
, keys
, ®
);
1304 vis_register_set(vis
, reg
);
1308 static const char *key2mark(Vis
*vis
, const char *keys
, int *mark
) {
1309 *mark
= VIS_MARK_INVALID
;
1312 if (keys
[0] >= 'a' && keys
[0] <= 'z')
1313 *mark
= keys
[0] - 'a';
1314 else if (keys
[0] == '<')
1315 *mark
= VIS_MARK_SELECTION_START
;
1316 else if (keys
[0] == '>')
1317 *mark
= VIS_MARK_SELECTION_END
;
1321 static const char *mark_set(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1323 keys
= key2mark(vis
, keys
, &mark
);
1324 vis_mark_set(vis
, mark
, view_cursor_get(vis_view(vis
)));
1328 static const char *mark_motion(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1330 keys
= key2mark(vis
, keys
, &mark
);
1331 vis_motion(vis
, arg
->i
, mark
);
1335 static const char *undo(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1336 size_t pos
= text_undo(vis_text(vis
));
1338 View
*view
= vis_view(vis
);
1339 if (view_cursors_count(view
) == 1)
1340 view_cursor_to(view
, pos
);
1341 /* redraw all windows in case some display the same file */
1347 static const char *redo(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1348 size_t pos
= text_redo(vis_text(vis
));
1350 View
*view
= vis_view(vis
);
1351 if (view_cursors_count(view
) == 1)
1352 view_cursor_to(view
, pos
);
1353 /* redraw all windows in case some display the same file */
1359 static const char *earlier(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1360 size_t pos
= text_earlier(vis_text(vis
), MAX(vis_count_get(vis
), 1));
1362 view_cursor_to(vis_view(vis
), pos
);
1363 /* redraw all windows in case some display the same file */
1369 static const char *later(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1370 size_t pos
= text_later(vis_text(vis
), MAX(vis_count_get(vis
), 1));
1372 view_cursor_to(vis_view(vis
), pos
);
1373 /* redraw all windows in case some display the same file */
1379 static const char *delete(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1380 vis_operator(vis
, VIS_OP_DELETE
);
1381 vis_motion(vis
, arg
->i
);
1385 static const char *insert_register(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1386 enum VisRegister regid
;
1387 keys
= key2register(vis
, keys
, ®id
);
1388 Register
*reg
= vis_register_get(vis
, regid
);
1390 int pos
= view_cursor_get(vis_view(vis
));
1391 vis_insert(vis
, pos
, reg
->data
, reg
->len
);
1392 view_cursor_to(vis_view(vis
), pos
+ reg
->len
);
1397 static const char *prompt_show(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1398 vis_prompt_show(vis
, arg
->s
);
1402 static const char *insert_verbatim(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1404 char buf
[4], type
= keys
[0];
1405 const char *data
= NULL
;
1406 int len
= 0, count
= 0, base
= 0;
1428 if ('0' <= type
&& type
<= '9') {
1437 for (keys
++; keys
[0] && count
> 0; keys
++, count
--) {
1439 if (base
== 8 && '0' <= keys
[0] && keys
[0] <= '7') {
1441 } else if ((base
== 10 || base
== 16) && '0' <= keys
[0] && keys
[0] <= '9') {
1443 } else if (base
== 16 && 'a' <= keys
[0] && keys
[0] <= 'f') {
1444 v
= 10 + keys
[0] - 'a';
1445 } else if (base
== 16 && 'A' <= keys
[0] && keys
[0] <= 'F') {
1446 v
= 10 + keys
[0] - 'A';
1451 rune
= rune
* base
+ v
;
1456 if (type
== 'u' || type
== 'U') {
1457 len
= runetochar(buf
, &rune
);
1465 const char *next
= vis_keys_next(vis
, keys
);
1468 size_t keylen
= next
- keys
;
1470 memcpy(key
, keys
, keylen
);
1473 static const char *keysym
[] = {
1476 "<Backspace>", "\b",
1482 for (const char **k
= keysym
; k
[0]; k
+= 2) {
1483 if (strcmp(k
[0], key
) == 0) {
1493 vis_insert_key(vis
, data
, len
);
1497 static const char *cmd(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1498 vis_cmd(vis
, arg
->s
);
1502 static int argi2lines(Vis
*vis
, const Arg
*arg
) {
1506 return view_height_get(vis_view(vis
));
1509 return view_height_get(vis_view(vis
))/2;
1511 if (vis_count_get(vis
) > 0)
1512 return vis_count_get(vis
);
1513 return arg
->i
< 0 ? -arg
->i
: arg
->i
;
1517 static const char *wscroll(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1519 view_scroll_down(vis_view(vis
), argi2lines(vis
, arg
));
1521 view_scroll_up(vis_view(vis
), argi2lines(vis
, arg
));
1525 static const char *wslide(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1527 view_slide_down(vis_view(vis
), argi2lines(vis
, arg
));
1529 view_slide_up(vis_view(vis
), argi2lines(vis
, arg
));
1533 static const char *call(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1538 static const char *window(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1539 arg
->w(vis_view(vis
));
1543 static const char *openline(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1544 vis_operator(vis
, VIS_OP_INSERT
);
1546 vis_motion(vis
, VIS_MOVE_LINE_END
);
1547 vis_keys_inject(vis
, keys
, "<Enter>");
1549 vis_motion(vis
, VIS_MOVE_LINE_BEGIN
);
1550 vis_keys_inject(vis
, keys
, "<Enter><Up>");
1555 static const char *join(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1556 int count
= vis_count_get(vis
);
1558 vis_count_set(vis
, count
-1);
1559 vis_operator(vis
, VIS_OP_JOIN
);
1560 vis_motion(vis
, arg
->i
);
1564 static const char *switchmode(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1565 vis_mode_switch(vis
, arg
->i
);
1569 static const char *insertmode(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1570 vis_operator(vis
, VIS_OP_INSERT
);
1571 vis_motion(vis
, arg
->i
);
1575 static const char *unicode_info(Vis
*vis
, const char *keys
, const Arg
*arg
) {
1576 View
*view
= vis_view(vis
);
1577 Text
*txt
= vis_text(vis
);
1578 size_t start
= view_cursor_get(view
);
1579 size_t end
= text_char_next(txt
, start
);
1580 char data
[end
-start
], *data_cur
= data
;
1581 text_bytes_get(txt
, start
, end
- start
, data
);
1582 Iterator it
= text_iterator_get(txt
, start
);
1583 char info
[255] = "", *info_cur
= info
;
1584 for (size_t pos
= start
; it
.pos
< end
; pos
= it
.pos
) {
1585 text_iterator_codepoint_next(&it
, NULL
);
1586 size_t len
= it
.pos
- pos
;
1587 wchar_t wc
= 0xFFFD;
1588 mbtowc(&wc
, data_cur
, len
);
1589 int width
= wcwidth(wc
);
1590 info_cur
+= snprintf(info_cur
, sizeof(info
) - (info_cur
- info
) - 1,
1591 "<%s%.*s> U+%04x ", width
== 0 ? " " : "", (int)len
, data_cur
, wc
);
1594 vis_info_show(vis
, "%s", info
);
1600 static void signal_handler(int signum
, siginfo_t
*siginfo
, void *context
) {
1601 vis_signal_handler(vis
, signum
, siginfo
, context
);
1604 int main(int argc
, char *argv
[]) {
1607 .vis_start
= vis_lua_start
,
1608 .vis_quit
= vis_lua_quit
,
1609 .file_open
= vis_lua_file_open
,
1610 .file_save
= vis_lua_file_save
,
1611 .file_close
= vis_lua_file_close
,
1612 .win_open
= vis_lua_win_open
,
1613 .win_close
= vis_lua_win_close
,
1616 vis
= vis_new(ui_curses_new(), &event
);
1618 return EXIT_FAILURE
;
1620 for (int i
= 0; i
< LENGTH(vis_action
); i
++) {
1621 KeyAction
*action
= &vis_action
[i
];
1622 if (!vis_action_register(vis
, action
))
1623 vis_die(vis
, "Could not register action: %s\n", action
->name
);
1626 for (int i
= 0; i
< LENGTH(default_bindings
); i
++) {
1627 for (const KeyBinding
**binding
= default_bindings
[i
]; binding
&& *binding
; binding
++) {
1628 for (const KeyBinding
*kb
= *binding
; kb
->key
; kb
++) {
1629 vis_mode_map(vis
, i
, kb
->key
, kb
);
1634 /* install signal handlers etc. */
1635 struct sigaction sa
;
1636 memset(&sa
, 0, sizeof sa
);
1637 sa
.sa_flags
= SA_SIGINFO
;
1638 sa
.sa_sigaction
= signal_handler
;
1639 if (sigaction(SIGBUS
, &sa
, NULL
) || sigaction(SIGINT
, &sa
, NULL
))
1640 vis_die(vis
, "sigaction: %s", strerror(errno
));
1643 sigemptyset(&blockset
);
1644 sigaddset(&blockset
, SIGWINCH
);
1645 sigprocmask(SIG_BLOCK
, &blockset
, NULL
);
1646 signal(SIGPIPE
, SIG_IGN
);
1648 int status
= vis_run(vis
, argc
, argv
);