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 */ 29 VIKEYS 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