1/* $OpenBSD: v_cmd.c,v 1.5 2016/03/13 18:30:43 martijn Exp $ */ 2 3/*- 4 * Copyright (c) 1992, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * Copyright (c) 1992, 1993, 1994, 1995, 1996 7 * Keith Bostic. All rights reserved. 8 * 9 * See the LICENSE file for redistribution information. 10 */ 11 12#include "config.h" 13 14#include <sys/types.h> 15#include <sys/queue.h> 16#include <sys/time.h> 17 18#include <bitstring.h> 19#include <limits.h> 20#include <stdio.h> 21 22#include "../common/common.h" 23#include "vi.h" 24 25/* 26 * This array maps keystrokes to vi command functions. It is known 27 * in ex/ex_usage.c that it takes four columns to name a vi character. 28 */ 29VIKEYS const vikeys [MAXVIKEY + 1] = { 30/* 000 NUL -- The code in vi.c expects key 0 to be undefined. */ 31 {NULL}, 32/* 001 ^A */ 33 {v_searchw, V_ABS|V_CNT|V_MOVE|V_KEYW|VM_CUTREQ|VM_RCM_SET, 34 "[count]^A", 35 "^A search forward for cursor word"}, 36/* 002 ^B */ 37 {v_pageup, V_CNT|VM_RCM_SET, 38 "[count]^B", 39 "^B scroll up by screens"}, 40/* 003 ^C */ 41 {NULL, 0, 42 "^C", 43 "^C interrupt an operation (e.g. read, write, search)"}, 44/* 004 ^D */ 45 {v_hpagedown, V_CNT|VM_RCM_SET, 46 "[count]^D", 47 "^D scroll down by half screens (setting count)"}, 48/* 005 ^E */ 49 {v_linedown, V_CNT, 50 "[count]^E", 51 "^E scroll down by lines"}, 52/* 006 ^F */ 53 {v_pagedown, V_CNT|VM_RCM_SET, 54 "[count]^F", 55 "^F scroll down by screens"}, 56/* 007 ^G */ 57 {v_status, 0, 58 "^G", 59 "^G file status"}, 60/* 010 ^H */ 61 {v_left, V_CNT|V_MOVE|VM_RCM_SET, 62 "[count]^H", 63 "^H move left by characters"}, 64/* 011 ^I */ 65 {NULL}, 66/* 012 ^J */ 67 {v_down, V_CNT|V_MOVE|VM_LMODE|VM_RCM, 68 "[count]^J", 69 "^J move down by lines"}, 70/* 013 ^K */ 71 {NULL}, 72/* 014 ^L */ 73 {v_redraw, 0, 74 "^L", 75 "^L redraw screen"}, 76/* 015 ^M */ 77 {v_cr, V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB, 78 "[count]^M", 79 "^M move down by lines (to first non-blank)"}, 80/* 016 ^N */ 81 {v_down, V_CNT|V_MOVE|VM_LMODE|VM_RCM, 82 "[count]^N", 83 "^N move down by lines"}, 84/* 017 ^O */ 85 {NULL}, 86/* 020 ^P */ 87 {v_up, V_CNT|V_MOVE|VM_LMODE|VM_RCM, 88 "[count]^P", 89 "^P move up by lines"}, 90/* 021 ^Q -- same as ^V if not used for hardware flow control. */ 91 {NULL}, 92/* 022 ^R */ 93 {v_redraw, 0, 94 "^R", 95 "^R redraw screen"}, 96/* 023 ^S -- not available, used for hardware flow control. */ 97 {NULL}, 98/* 024 ^T */ 99 {v_tagpop, V_ABS|VM_RCM_SET, 100 "^T", 101 "^T tag pop"}, 102/* 025 ^U */ 103 {v_hpageup, V_CNT|VM_RCM_SET, 104 "[count]^U", 105 "^U half page up (set count)"}, 106/* 026 ^V */ 107 {NULL, 0, 108 "^V", 109 "^V input a literal character"}, 110/* 027 ^W */ 111 {v_screen, 0, 112 "^W", 113 "^W move to next screen"}, 114/* 030 ^X */ 115 {NULL}, 116/* 031 ^Y */ 117 {v_lineup, V_CNT, 118 "[count]^Y", 119 "^Y page up by lines"}, 120/* 032 ^Z */ 121 {v_suspend, V_SECURE, 122 "^Z", 123 "^Z suspend editor"}, 124/* 033 ^[ */ 125 {NULL, 0, 126 "^[ <escape>", 127 "^[ <escape> exit input mode, cancel partial commands"}, 128/* 034 ^\ */ 129 {v_exmode, 0, 130 "^\\", 131 "^\\ switch to ex mode"}, 132/* 035 ^] */ 133 {v_tagpush, V_ABS|V_KEYW|VM_RCM_SET, 134 "^]", 135 "^] tag push cursor word"}, 136/* 036 ^^ */ 137 {v_switch, 0, 138 "^^", 139 "^^ switch to previous file"}, 140/* 037 ^_ */ 141 {NULL}, 142/* 040 ' ' */ 143 {v_right, V_CNT|V_MOVE|VM_RCM_SET, 144 "[count]' '", 145 " <space> move right by columns"}, 146/* 041 ! */ 147 {v_filter, V_CNT|V_DOT|V_MOTION|V_SECURE|VM_RCM_SET, 148 "[count]![count]motion command(s)", 149 " ! filter through command(s) to motion"}, 150/* 042 " */ 151 {NULL}, 152/* 043 # */ 153 {v_increment, V_CHAR|V_CNT|V_DOT|VM_RCM_SET, 154 "[count]# +|-|#", 155 " # number increment/decrement"}, 156/* 044 $ */ 157 {v_dollar, V_CNT|V_MOVE|VM_RCM_SETLAST, 158 " [count]$", 159 " $ move to last column"}, 160/* 045 % */ 161 {v_match, V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET, 162 "%", 163 " % move to match"}, 164/* 046 & */ 165 {v_again, 0, 166 "&", 167 " & repeat substitution"}, 168/* 047 ' */ 169 {v_fmark, V_ABS_L|V_CHAR|V_MOVE|VM_LMODE|VM_RCM_SET, 170 "'['a-z]", 171 " ' move to mark (to first non-blank)"}, 172/* 050 ( */ 173 {v_sentenceb, V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET, 174 "[count](", 175 " ( move back sentence"}, 176/* 051 ) */ 177 {v_sentencef, V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET, 178 "[count])", 179 " ) move forward sentence"}, 180/* 052 * */ 181 {NULL}, 182/* 053 + */ 183 {v_down, V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB, 184 "[count]+", 185 " + move down by lines (to first non-blank)"}, 186/* 054 , */ 187 {v_chrrepeat, V_CNT|V_MOVE|VM_RCM_SET, 188 "[count],", 189 " , reverse last F, f, T or t search"}, 190/* 055 - */ 191 {v_up, V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB, 192 "[count]-", 193 " - move up by lines (to first non-blank)"}, 194/* 056 . */ 195 {NULL, 0, 196 ".", 197 " . repeat the last command"}, 198/* 057 / */ 199 {v_searchf, V_ABS_C|V_MOVE|VM_CUTREQ|VM_RCM_SET, 200 "/RE[/ offset]", 201 " / search forward"}, 202/* 060 0 */ 203 {v_zero, V_MOVE|VM_RCM_SET, 204 "0", 205 " 0 move to first character"}, 206/* 061 1 */ 207 {NULL}, 208/* 062 2 */ 209 {NULL}, 210/* 063 3 */ 211 {NULL}, 212/* 064 4 */ 213 {NULL}, 214/* 065 5 */ 215 {NULL}, 216/* 066 6 */ 217 {NULL}, 218/* 067 7 */ 219 {NULL}, 220/* 070 8 */ 221 {NULL}, 222/* 071 9 */ 223 {NULL}, 224/* 072 : */ 225 {v_ex, 0, 226 ":command [| command] ...", 227 " : ex command"}, 228/* 073 ; */ 229 {v_chrepeat, V_CNT|V_MOVE|VM_RCM_SET, 230 "[count];", 231 " ; repeat last F, f, T or t search"}, 232/* 074 < */ 233 {v_shiftl, V_CNT|V_DOT|V_MOTION|VM_RCM_SET, 234 "[count]<[count]motion", 235 " < shift lines left to motion"}, 236/* 075 = */ 237 {NULL}, 238/* 076 > */ 239 {v_shiftr, V_CNT|V_DOT|V_MOTION|VM_RCM_SET, 240 "[count]>[count]motion", 241 " > shift lines right to motion"}, 242/* 077 ? */ 243 {v_searchb, V_ABS_C|V_MOVE|VM_CUTREQ|VM_RCM_SET, 244 "?RE[? offset]", 245 " ? search backward"}, 246/* 100 @ */ 247 {v_at, V_CNT|V_RBUF|VM_RCM_SET, 248 "@buffer", 249 " @ execute buffer"}, 250/* 101 A */ 251 {v_iA, V_CNT|V_DOT|VM_RCM_SET, 252 "[count]A", 253 " A append to the line"}, 254/* 102 B */ 255 {v_wordB, V_CNT|V_MOVE|VM_RCM_SET, 256 "[count]B", 257 " B move back bigword"}, 258/* 103 C */ 259 {NULL, 0, 260 "[buffer][count]C", 261 " C change to end-of-line"}, 262/* 104 D */ 263 {NULL, 0, 264 "[buffer]D", 265 " D delete to end-of-line"}, 266/* 105 E */ 267 {v_wordE, V_CNT|V_MOVE|VM_RCM_SET, 268 "[count]E", 269 " E move to end of bigword"}, 270/* 106 F */ 271 {v_chF, V_CHAR|V_CNT|V_MOVE|VM_RCM_SET, 272 "[count]F character", 273 " F character in line backward search"}, 274/* 107 G */ 275 {v_lgoto, V_ABS_L|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB, 276 "[count]G", 277 " G move to line"}, 278/* 110 H */ 279 {v_home, V_ABS_L|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETNNB, 280 "[count]H", 281 " H move to count lines from screen top"}, 282/* 111 I */ 283 {v_iI, V_CNT|V_DOT|VM_RCM_SET, 284 "[count]I", 285 " I insert before first nonblank"}, 286/* 112 J */ 287 {v_join, V_CNT|V_DOT|VM_RCM_SET, 288 "[count]J", 289 " J join lines"}, 290/* 113 K */ 291 {NULL}, 292/* 114 L */ 293 {v_bottom, V_ABS_L|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETNNB, 294 "[count]L", 295 " L move to screen bottom"}, 296/* 115 M */ 297 {v_middle, V_ABS_L|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETNNB, 298 "M", 299 " M move to screen middle"}, 300/* 116 N */ 301 {v_searchN, V_ABS_C|V_MOVE|VM_CUTREQ|VM_RCM_SET, 302 "n", 303 " N reverse last search"}, 304/* 117 O */ 305 {v_iO, V_CNT|V_DOT|VM_RCM_SET, 306 "[count]O", 307 " O insert above line"}, 308/* 120 P */ 309 {v_Put, V_CNT|V_DOT|V_OBUF|VM_RCM_SET, 310 "[buffer]P", 311 " P insert before cursor from buffer"}, 312/* 121 Q */ 313 {v_exmode, 0, 314 "Q", 315 " Q switch to ex mode"}, 316/* 122 R */ 317 {v_Replace, V_CNT|V_DOT|VM_RCM_SET, 318 "[count]R", 319 " R replace characters"}, 320/* 123 S */ 321 {NULL, 0, 322 "[buffer][count]S", 323 " S substitute for the line(s)"}, 324/* 124 T */ 325 {v_chT, V_CHAR|V_CNT|V_MOVE|VM_RCM_SET, 326 "[count]T character", 327 " T before character in line backward search"}, 328/* 125 U */ 329 {v_Undo, VM_RCM_SET, 330 "U", 331 " U restore the current line"}, 332/* 126 V */ 333 {NULL}, 334/* 127 W */ 335 {v_wordW, V_CNT|V_MOVE|VM_RCM_SET, 336 "[count]W", 337 " W move to next bigword"}, 338/* 130 X */ 339 {v_Xchar, V_CNT|V_DOT|V_OBUF|VM_RCM_SET, 340 "[buffer][count]X", 341 " X delete character before cursor"}, 342/* 131 Y */ 343 {NULL, 0, 344 "[buffer][count]Y", 345 " Y copy line"}, 346/* 132 Z */ 347 {v_zexit, 0, 348 "ZZ", 349 "ZZ save file and exit"}, 350/* 133 [ */ 351 {v_sectionb, V_ABS|V_CNT|V_MOVE|VM_RCM_SET, 352 "[[", 353 "[[ move back section"}, 354/* 134 \ */ 355 {NULL}, 356/* 135 ] */ 357 {v_sectionf, V_ABS|V_CNT|V_MOVE|VM_RCM_SET, 358 "]]", 359 "]] move forward section"}, 360/* 136 ^ */ 361 /* 362 * DON'T set the VM_RCM_SETFNB flag, the function has to do the work 363 * anyway, in case it's a motion component. DO set VM_RCM_SET, so 364 * that any motion that's part of a command is preserved. 365 */ 366 {v_first, V_CNT|V_MOVE|VM_RCM_SET, 367 "^", 368 " ^ move to first non-blank"}, 369/* 137 _ */ 370 /* 371 * Needs both to set the VM_RCM_SETFNB flag, and to do the work 372 * in the function, in case it's a delete. 373 */ 374 {v_cfirst, V_CNT|V_MOVE|VM_RCM_SETFNB, 375 "_", 376 " _ move to first non-blank"}, 377/* 140 ` */ 378 {v_bmark, V_ABS_C|V_CHAR|V_MOVE|VM_CUTREQ|VM_RCM_SET, 379 "`[`a-z]", 380 " ` move to mark"}, 381/* 141 a */ 382 {v_ia, V_CNT|V_DOT|VM_RCM_SET, 383 "[count]a", 384 " a append after cursor"}, 385/* 142 b */ 386 {v_wordb, V_CNT|V_MOVE|VM_RCM_SET, 387 "[count]b", 388 " b move back word"}, 389/* 143 c */ 390 {v_change, V_CNT|V_DOT|V_MOTION|V_OBUF|VM_RCM_SET, 391 "[buffer][count]c[count]motion", 392 " c change to motion"}, 393/* 144 d */ 394 {v_delete, V_CNT|V_DOT|V_MOTION|V_OBUF|VM_RCM_SET, 395 "[buffer][count]d[count]motion", 396 " d delete to motion"}, 397/* 145 e */ 398 {v_worde, V_CNT|V_MOVE|VM_RCM_SET, 399 "[count]e", 400 " e move to end of word"}, 401/* 146 f */ 402 {v_chf, V_CHAR|V_CNT|V_MOVE|VM_RCM_SET, 403 "[count]f character", 404 " f character in line forward search"}, 405/* 147 g */ 406 {NULL}, 407/* 150 h */ 408 {v_left, V_CNT|V_MOVE|VM_RCM_SET, 409 "[count]h", 410 " h move left by columns"}, 411/* 151 i */ 412 {v_ii, V_CNT|V_DOT|VM_RCM_SET, 413 "[count]i", 414 " i insert before cursor"}, 415/* 152 j */ 416 {v_down, V_CNT|V_MOVE|VM_LMODE|VM_RCM, 417 "[count]j", 418 " j move down by lines"}, 419/* 153 k */ 420 {v_up, V_CNT|V_MOVE|VM_LMODE|VM_RCM, 421 "[count]k", 422 " k move up by lines"}, 423/* 154 l */ 424 {v_right, V_CNT|V_MOVE|VM_RCM_SET, 425 "[count]l", 426 " l move right by columns"}, 427/* 155 m */ 428 {v_mark, V_CHAR, 429 "m[a-z]", 430 " m set mark"}, 431/* 156 n */ 432 {v_searchn, V_ABS_C|V_MOVE|VM_CUTREQ|VM_RCM_SET, 433 "n", 434 " n repeat last search"}, 435/* 157 o */ 436 {v_io, V_CNT|V_DOT|VM_RCM_SET, 437 "[count]o", 438 " o append after line"}, 439/* 160 p */ 440 {v_put, V_CNT|V_DOT|V_OBUF|VM_RCM_SET, 441 "[buffer]p", 442 " p insert after cursor from buffer"}, 443/* 161 q */ 444 {NULL}, 445/* 162 r */ 446 {v_replace, V_CNT|V_DOT|VM_RCM_SET, 447 "[count]r character", 448 " r replace character"}, 449/* 163 s */ 450 {v_subst, V_CNT|V_DOT|V_OBUF|VM_RCM_SET, 451 "[buffer][count]s", 452 " s substitute character"}, 453/* 164 t */ 454 {v_cht, V_CHAR|V_CNT|V_MOVE|VM_RCM_SET, 455 "[count]t character", 456 " t before character in line forward search"}, 457/* 165 u */ 458 /* 459 * DON'T set the V_DOT flag, it' more complicated than that. 460 * See vi/vi.c for details. 461 */ 462 {v_undo, VM_RCM_SET, 463 "u", 464 " u undo last change"}, 465/* 166 v */ 466 {NULL}, 467/* 167 w */ 468 {v_wordw, V_CNT|V_MOVE|VM_RCM_SET, 469 "[count]w", 470 " w move to next word"}, 471/* 170 x */ 472 {v_xchar, V_CNT|V_DOT|V_OBUF|VM_RCM_SET, 473 "[buffer][count]x", 474 " x delete character"}, 475/* 171 y */ 476 {v_yank, V_CNT|V_DOT|V_MOTION|V_OBUF|VM_RCM_SET, 477 "[buffer][count]y[count]motion", 478 " y copy text to motion into a cut buffer"}, 479/* 172 z */ 480 /* 481 * DON'T set the V_CHAR flag, the char isn't required, 482 * so it's handled specially in getcmd(). 483 */ 484 {v_z, V_ABS_L|V_CNT|VM_RCM_SETFNB, 485 "[line]z[window_size][-|.|+|^|<CR>]", 486 " z reposition the screen"}, 487/* 173 { */ 488 {v_paragraphb, V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET, 489 "[count]{", 490 " { move back paragraph"}, 491/* 174 | */ 492 {v_ncol, V_CNT|V_MOVE|VM_RCM_SET, 493 "[count]|", 494 " | move to column"}, 495/* 175 } */ 496 {v_paragraphf, V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET, 497 "[count]}", 498 " } move forward paragraph"}, 499/* 176 ~ */ 500 {v_ulcase, V_CNT|V_DOT|VM_RCM_SET, 501 "[count]~", 502 " ~ reverse case"}, 503}; 504