[9] | 1 | /* vi.c */
|
---|
| 2 |
|
---|
| 3 | /* Author:
|
---|
| 4 | * Steve Kirkendall
|
---|
| 5 | * Beaverton, OR 97005
|
---|
| 6 | * kirkenda@cs.pdx.edu
|
---|
| 7 | */
|
---|
| 8 |
|
---|
| 9 |
|
---|
| 10 | #include "config.h"
|
---|
| 11 | #include "ctype.h"
|
---|
| 12 | #include "vi.h"
|
---|
| 13 |
|
---|
| 14 |
|
---|
| 15 |
|
---|
| 16 | /* This array describes what each key does */
|
---|
| 17 | #define NO_FUNC (MARK (*)())0
|
---|
| 18 |
|
---|
| 19 | #define NO_ARGS 0
|
---|
| 20 | #define CURSOR 1
|
---|
| 21 | #define CURSOR_CNT_KEY 2
|
---|
| 22 | #define CURSOR_MOVED 3
|
---|
| 23 | #define CURSOR_EOL 4
|
---|
| 24 | #define ZERO 5
|
---|
| 25 | #define DIGIT 6
|
---|
| 26 | #define CURSOR_TEXT 7
|
---|
| 27 | #define KEYWORD 8
|
---|
| 28 | #define ARGSMASK 0x0f
|
---|
| 29 | #define C_C_K_REP1 (CURSOR_CNT_KEY | 0x10)
|
---|
| 30 | #define C_C_K_CUT (CURSOR_CNT_KEY | 0x20)
|
---|
| 31 | #define C_C_K_MARK (CURSOR_CNT_KEY | 0x30)
|
---|
| 32 | #define C_C_K_CHAR (CURSOR_CNT_KEY | 0x40)
|
---|
| 33 | #ifndef NO_SHOWMODE
|
---|
| 34 | static int keymodes[] = {0, WHEN_REP1, WHEN_CUT, WHEN_MARK, WHEN_CHAR};
|
---|
| 35 | # define KEYMODE(args) (keymodes[(args) >> 4])
|
---|
| 36 | #else
|
---|
| 37 | # define KEYMODE(args) 0
|
---|
| 38 | #endif
|
---|
| 39 |
|
---|
| 40 | static struct keystru
|
---|
| 41 | {
|
---|
| 42 | MARK (*func)(); /* the function to run */
|
---|
| 43 | uchar args; /* description of the args needed */
|
---|
| 44 | #ifndef NO_VISIBLE
|
---|
| 45 | short flags;
|
---|
| 46 | #else
|
---|
| 47 | uchar flags; /* other stuff */
|
---|
| 48 | #endif
|
---|
| 49 | }
|
---|
| 50 | vikeys[] =
|
---|
| 51 | {
|
---|
| 52 | /* NUL not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 53 | #ifndef NO_EXTENSIONS
|
---|
| 54 | /* ^A find cursor word */ {m_wsrch, KEYWORD, MVMT|NREL|VIZ},
|
---|
| 55 | #else
|
---|
| 56 | /* ^A not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 57 | #endif
|
---|
| 58 | /* ^B page backward */ {m_scroll, CURSOR, FRNT|VIZ},
|
---|
| 59 | /* ^C not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 60 | /* ^D scroll dn 1/2page*/ {m_scroll, CURSOR, NCOL|VIZ},
|
---|
| 61 | /* ^E scroll up */ {m_scroll, CURSOR, NCOL|VIZ},
|
---|
| 62 | /* ^F page forward */ {m_scroll, CURSOR, FRNT|VIZ},
|
---|
| 63 | /* ^G show file status */ {v_status, NO_ARGS, NO_FLAGS},
|
---|
| 64 | /* ^H move left, like h*/ {m_left, CURSOR, MVMT|VIZ},
|
---|
| 65 | /* ^I not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 66 | /* ^J move down */ {m_updnto, CURSOR, MVMT|LNMD|VIZ|INCL},
|
---|
| 67 | /* ^K not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 68 | /* ^L redraw screen */ {v_redraw, NO_ARGS, NO_FLAGS|VIZ},
|
---|
| 69 | /* ^M mv front next ln */ {m_updnto, CURSOR, MVMT|FRNT|LNMD|VIZ|INCL},
|
---|
| 70 | /* ^N move down */ {m_updnto, CURSOR, MVMT|LNMD|VIZ|INCL|NCOL},
|
---|
| 71 | /* ^O not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 72 | /* ^P move up */ {m_updnto, CURSOR, MVMT|LNMD|VIZ|INCL|NCOL},
|
---|
| 73 | /* ^Q not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 74 | /* ^R redraw screen */ {v_redraw, NO_ARGS, NO_FLAGS|VIZ},
|
---|
| 75 | /* ^S not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 76 | /* ^T not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 77 | /* ^U scroll up 1/2page*/ {m_scroll, CURSOR, NCOL|VIZ},
|
---|
| 78 | /* ^V not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 79 | /* ^W not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 80 | /* ^X move to phys col */ {m_tocol, CURSOR, MVMT|NREL|VIZ},
|
---|
| 81 | /* ^Y scroll down */ {m_scroll, CURSOR, NCOL|VIZ},
|
---|
| 82 | #ifdef SIGTSTP
|
---|
| 83 | /* ^Z suspend elvis */ {v_suspend, NO_ARGS, NO_FLAGS},
|
---|
| 84 | #else
|
---|
| 85 | /* ^Z not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 86 | #endif
|
---|
| 87 | /* ESC not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 88 | /* ^\ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 89 | /* ^] keyword is tag */ {v_tag, KEYWORD, NO_FLAGS},
|
---|
| 90 | /* ^^ previous file */ {v_switch, CURSOR, NO_FLAGS},
|
---|
| 91 | /* ^_ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 92 | /* SPC move right,like l*/ {m_right, CURSOR, MVMT|INCL|VIZ},
|
---|
| 93 | /* ! run thru filter */ {v_filter, CURSOR_MOVED, FRNT|LNMD|INCL|VIZ},
|
---|
| 94 | /* " select cut buffer*/ {v_selcut, C_C_K_CUT, PTMV|VIZ},
|
---|
| 95 | #ifndef NO_EXTENSIONS
|
---|
| 96 | /* # increment number */ {v_increment, KEYWORD, SDOT},
|
---|
| 97 | #else
|
---|
| 98 | /* # not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 99 | #endif
|
---|
| 100 | /* $ move to rear */ {m_rear, CURSOR, MVMT|INCL|VIZ},
|
---|
| 101 | /* % move to match */ {m_match, CURSOR, MVMT|INCL|VIZ},
|
---|
| 102 | /* & repeat subst */ {v_again, CURSOR_MOVED, SDOT|NCOL|LNMD|INCL},
|
---|
| 103 | /* ' move to a mark */ {m_tomark, C_C_K_MARK, MVMT|FRNT|NREL|LNMD|INCL|VIZ},
|
---|
| 104 | #ifndef NO_SENTENCE
|
---|
| 105 | /* ( mv back sentence */ {m_sentence, CURSOR, MVMT|VIZ},
|
---|
| 106 | /* ) mv fwd sentence */ {m_sentence, CURSOR, MVMT|VIZ},
|
---|
| 107 | #else
|
---|
| 108 | /* ( not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 109 | /* ) not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 110 | #endif
|
---|
| 111 | #ifndef NO_ERRLIST
|
---|
| 112 | /* * errlist */ {v_errlist, CURSOR, FRNT|NREL},
|
---|
| 113 | #else
|
---|
| 114 | /* * not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 115 | #endif
|
---|
| 116 | /* + mv front next ln */ {m_updnto, CURSOR, MVMT|FRNT|LNMD|VIZ|INCL},
|
---|
| 117 | #ifndef NO_CHARSEARCH
|
---|
| 118 | /* , reverse [fFtT] cmd*/ {m__ch, CURSOR, MVMT|INCL|VIZ},
|
---|
| 119 | #else
|
---|
| 120 | /* , not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 121 | #endif
|
---|
| 122 | /* - mv front prev ln */ {m_updnto, CURSOR, MVMT|FRNT|LNMD|VIZ|INCL},
|
---|
| 123 | /* . special... */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 124 | /* / forward search */ {m_fsrch, CURSOR_TEXT, MVMT|NREL|VIZ},
|
---|
| 125 | /* 0 part of count? */ {NO_FUNC, ZERO, MVMT|PTMV|VIZ},
|
---|
| 126 | /* 1 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
|
---|
| 127 | /* 2 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
|
---|
| 128 | /* 3 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
|
---|
| 129 | /* 4 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
|
---|
| 130 | /* 5 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
|
---|
| 131 | /* 6 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
|
---|
| 132 | /* 7 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
|
---|
| 133 | /* 8 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
|
---|
| 134 | /* 9 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
|
---|
| 135 | /* : run single EX cmd*/ {v_1ex, CURSOR_TEXT, NO_FLAGS},
|
---|
| 136 | #ifndef NO_CHARSEARCH
|
---|
| 137 | /* ; repeat [fFtT] cmd*/ {m__ch, CURSOR, MVMT|INCL|VIZ},
|
---|
| 138 | #else
|
---|
| 139 | /* ; not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS|VIZ},
|
---|
| 140 | #endif
|
---|
| 141 | /* < shift text left */ {v_lshift, CURSOR_MOVED, SDOT|FRNT|LNMD|INCL|VIZ},
|
---|
| 142 | /* = preset filter */ {v_reformat, CURSOR_MOVED, SDOT|FRNT|LNMD|INCL|VIZ},
|
---|
| 143 | /* > shift text right */ {v_rshift, CURSOR_MOVED, SDOT|FRNT|LNMD|INCL|VIZ},
|
---|
| 144 | /* ? backward search */ {m_bsrch, CURSOR_TEXT, MVMT|NREL|VIZ},
|
---|
| 145 | #ifndef NO_AT
|
---|
| 146 | /* @ execute a cutbuf */ {v_at, C_C_K_CUT, NO_FLAGS},
|
---|
| 147 | #else
|
---|
| 148 | /* @ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 149 | #endif
|
---|
| 150 | /* A append at EOL */ {v_insert, CURSOR, SDOT},
|
---|
| 151 | /* B move back Word */ {m_bword, CURSOR, MVMT|VIZ},
|
---|
| 152 | /* C change to EOL */ {v_change, CURSOR_EOL, SDOT},
|
---|
| 153 | /* D delete to EOL */ {v_delete, CURSOR_EOL, SDOT},
|
---|
| 154 | /* E move end of Word */ {m_eword, CURSOR, MVMT|INCL|VIZ},
|
---|
| 155 | #ifndef NO_CHARSEARCH
|
---|
| 156 | /* F move bk to char */ {m_Fch, C_C_K_CHAR, MVMT|INCL|VIZ},
|
---|
| 157 | #else
|
---|
| 158 | /* F not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 159 | #endif
|
---|
| 160 | /* G move to line # */ {m_updnto, CURSOR, MVMT|NREL|LNMD|FRNT|INCL|VIZ},
|
---|
| 161 | /* H move to row */ {m_row, CURSOR, MVMT|LNMD|FRNT|VIZ|INCL},
|
---|
| 162 | /* I insert at front */ {v_insert, CURSOR, SDOT},
|
---|
| 163 | /* J join lines */ {v_join, CURSOR, SDOT},
|
---|
| 164 | #ifndef NO_EXTENSIONS
|
---|
| 165 | /* K look up keyword */ {v_keyword, KEYWORD, NO_FLAGS},
|
---|
| 166 | #else
|
---|
| 167 | /* K not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 168 | #endif
|
---|
| 169 | /* L move to last row */ {m_row, CURSOR, MVMT|LNMD|FRNT|VIZ|INCL},
|
---|
| 170 | /* M move to mid row */ {m_row, CURSOR, MVMT|LNMD|FRNT|VIZ|INCL},
|
---|
| 171 | /* N reverse prev srch*/ {m_Nsrch, CURSOR, MVMT|NREL|VIZ},
|
---|
| 172 | /* O insert above line*/ {v_insert, CURSOR, SDOT},
|
---|
| 173 | /* P paste before */ {v_paste, CURSOR, SDOT},
|
---|
| 174 | /* Q quit to EX mode */ {v_quit, NO_ARGS, NO_FLAGS},
|
---|
| 175 | /* R overtype */ {v_overtype, CURSOR, SDOT},
|
---|
| 176 | /* S change line */ {v_change, CURSOR_MOVED, SDOT},
|
---|
| 177 | #ifndef NO_CHARSEARCH
|
---|
| 178 | /* T move bk to char */ {m_Tch, C_C_K_CHAR, MVMT|INCL|VIZ},
|
---|
| 179 | #else
|
---|
| 180 | /* T not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 181 | #endif
|
---|
| 182 | /* U undo whole line */ {v_undoline, CURSOR, FRNT},
|
---|
| 183 | #ifndef NO_VISIBLE
|
---|
| 184 | /* V start visible */ {v_start, CURSOR, INCL|LNMD|VIZ},
|
---|
| 185 | #else
|
---|
| 186 | /* V not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 187 | #endif
|
---|
| 188 | /* W move forward Word*/ {m_fword, CURSOR, MVMT|INCL|VIZ},
|
---|
| 189 | /* X delete to left */ {v_xchar, CURSOR, SDOT},
|
---|
| 190 | /* Y yank text */ {v_yank, CURSOR_MOVED, NCOL},
|
---|
| 191 | /* Z save file & exit */ {v_xit, CURSOR_CNT_KEY, NO_FLAGS},
|
---|
| 192 | /* [ move back section*/ {m_paragraph, CURSOR, MVMT|LNMD|NREL|VIZ},
|
---|
| 193 | #ifndef NO_POPUP
|
---|
| 194 | /* \ pop-up menu */ {v_popup, CURSOR_MOVED, VIZ},
|
---|
| 195 | #else
|
---|
| 196 | /* \ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 197 | #endif
|
---|
| 198 | /* ] move fwd section */ {m_paragraph, CURSOR, MVMT|LNMD|NREL|VIZ},
|
---|
| 199 | /* ^ move to front */ {m_front, CURSOR, MVMT|VIZ},
|
---|
| 200 | /* _ current line */ {m_updnto, CURSOR, MVMT|LNMD|FRNT|INCL},
|
---|
| 201 | /* ` move to mark */ {m_tomark, C_C_K_MARK, MVMT|NREL|VIZ},
|
---|
| 202 | /* a append at cursor */ {v_insert, CURSOR, SDOT},
|
---|
| 203 | /* b move back word */ {m_bword, CURSOR, MVMT|VIZ},
|
---|
| 204 | /* c change text */ {v_change, CURSOR_MOVED, SDOT|VIZ},
|
---|
| 205 | /* d delete op */ {v_delete, CURSOR_MOVED, SDOT|VIZ},
|
---|
| 206 | /* e move end word */ {m_eword, CURSOR, MVMT|INCL|VIZ},
|
---|
| 207 | #ifndef NO_CHARSEARCH
|
---|
| 208 | /* f move fwd for char*/ {m_fch, C_C_K_CHAR, MVMT|INCL|VIZ},
|
---|
| 209 | #else
|
---|
| 210 | /* f not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 211 | #endif
|
---|
| 212 | /* g not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 213 | /* h move left */ {m_left, CURSOR, MVMT|VIZ},
|
---|
| 214 | /* i insert at cursor */ {v_insert, CURSOR, SDOT},
|
---|
| 215 | /* j move down */ {m_updnto, CURSOR, MVMT|NCOL|LNMD|VIZ|INCL},
|
---|
| 216 | /* k move up */ {m_updnto, CURSOR, MVMT|NCOL|LNMD|VIZ|INCL},
|
---|
| 217 | /* l move right */ {m_right, CURSOR, MVMT|INCL|VIZ},
|
---|
| 218 | /* m define a mark */ {v_mark, C_C_K_MARK, NO_FLAGS},
|
---|
| 219 | /* n repeat prev srch */ {m_nsrch, CURSOR, MVMT|NREL|VIZ},
|
---|
| 220 | /* o insert below line*/ {v_insert, CURSOR, SDOT},
|
---|
| 221 | /* p paste after */ {v_paste, CURSOR, SDOT},
|
---|
| 222 | /* q not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 223 | /* r replace chars */ {v_replace, C_C_K_REP1, SDOT},
|
---|
| 224 | /* s subst N chars */ {v_subst, CURSOR, SDOT},
|
---|
| 225 | #ifndef NO_CHARSEARCH
|
---|
| 226 | /* t move fwd to char */ {m_tch, C_C_K_CHAR, MVMT|INCL|VIZ},
|
---|
| 227 | #else
|
---|
| 228 | /* t not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 229 | #endif
|
---|
| 230 | /* u undo */ {v_undo, CURSOR, NO_FLAGS},
|
---|
| 231 | #ifndef NO_VISIBLE
|
---|
| 232 | /* v start visible */ {v_start, CURSOR, INCL|VIZ},
|
---|
| 233 | #else
|
---|
| 234 | /* v not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
|
---|
| 235 | #endif
|
---|
| 236 | /* w move fwd word */ {m_fword, CURSOR, MVMT|INCL|VIZ},
|
---|
| 237 | /* x delete character */ {v_xchar, CURSOR, SDOT},
|
---|
| 238 | /* y yank text */ {v_yank, CURSOR_MOVED, NCOL|VIZ},
|
---|
| 239 | /* z adjust scrn row */ {m_z, CURSOR_CNT_KEY, NCOL|VIZ},
|
---|
| 240 | /* { back paragraph */ {m_paragraph, CURSOR, MVMT|LNMD|VIZ},
|
---|
| 241 | /* | move to column */ {m_tocol, CURSOR, MVMT|NREL|VIZ},
|
---|
| 242 | /* } fwd paragraph */ {m_paragraph, CURSOR, MVMT|LNMD|VIZ},
|
---|
| 243 | /* ~ upper/lowercase */ {v_ulcase, CURSOR, SDOT},
|
---|
| 244 | /* DEL not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}
|
---|
| 245 | };
|
---|
| 246 |
|
---|
| 247 |
|
---|
| 248 |
|
---|
| 249 | void vi()
|
---|
| 250 | {
|
---|
| 251 | REG int key; /* keystroke from user */
|
---|
| 252 | long count; /* numeric argument to some functions */
|
---|
| 253 | REG struct keystru *keyptr;/* pointer to vikeys[] element */
|
---|
| 254 | MARK tcurs; /* temporary cursor */
|
---|
| 255 | int prevkey;/* previous key, if d/c/y/</>/! */
|
---|
| 256 | MARK range; /* start of range for d/c/y/</>/! */
|
---|
| 257 | char text[132];
|
---|
| 258 | int dotkey; /* last "key" of a change */
|
---|
| 259 | int dotpkey;/* last "prevkey" of a change */
|
---|
| 260 | int dotkey2;/* last extra "getkey()" of a change */
|
---|
| 261 | int dotcnt; /* last "count" of a change */
|
---|
| 262 | int firstkey;
|
---|
| 263 | REG int i;
|
---|
| 264 |
|
---|
| 265 | /* tell the redraw() function to start from scratch */
|
---|
| 266 | redraw(MARK_UNSET, FALSE);
|
---|
| 267 |
|
---|
| 268 | #ifdef lint
|
---|
| 269 | /* lint says that "range" might be used before it is set. This
|
---|
| 270 | * can't really happen due to the way "range" and "prevkey" are used,
|
---|
| 271 | * but lint doesn't know that. This line is here ONLY to keep lint
|
---|
| 272 | * happy.
|
---|
| 273 | */
|
---|
| 274 | range = 0L;
|
---|
| 275 | #endif
|
---|
| 276 |
|
---|
| 277 | /* safeguard against '.' with no previous command */
|
---|
| 278 | dotkey = dotpkey = dotkey2 = dotcnt = 0;
|
---|
| 279 |
|
---|
| 280 | /* go immediately into insert mode, if ":set inputmode" */
|
---|
| 281 | firstkey = 0;
|
---|
| 282 | #ifndef NO_EXTENSIONS
|
---|
| 283 | if (*o_inputmode)
|
---|
| 284 | {
|
---|
| 285 | firstkey = 'i';
|
---|
| 286 | }
|
---|
| 287 | #endif
|
---|
| 288 |
|
---|
| 289 | /* Repeatedly handle VI commands */
|
---|
| 290 | for (count = 0, prevkey = '\0'; mode == MODE_VI; )
|
---|
| 291 | {
|
---|
| 292 | /* if we've moved off the undoable line, then we can't undo it at all */
|
---|
| 293 | if (markline(cursor) != U_line)
|
---|
| 294 | {
|
---|
| 295 | U_line = 0L;
|
---|
| 296 | }
|
---|
| 297 |
|
---|
| 298 | /* report any changes from the previous command */
|
---|
| 299 | if (rptlines >= *o_report)
|
---|
| 300 | {
|
---|
| 301 | redraw(cursor, FALSE);
|
---|
| 302 | msg("%ld line%s %s", rptlines, (rptlines==1?"":"s"), rptlabel);
|
---|
| 303 | }
|
---|
| 304 | rptlines = 0L;
|
---|
| 305 |
|
---|
| 306 | /* get the next command key. It must be ASCII */
|
---|
| 307 | if (firstkey)
|
---|
| 308 | {
|
---|
| 309 | key = firstkey;
|
---|
| 310 | firstkey = 0;
|
---|
| 311 | }
|
---|
| 312 | else
|
---|
| 313 | {
|
---|
| 314 | do
|
---|
| 315 | {
|
---|
| 316 | key = getkey(WHEN_VICMD);
|
---|
| 317 | } while (key < 0 || key > 127);
|
---|
| 318 | }
|
---|
| 319 |
|
---|
| 320 | /* Convert a doubled-up operator such as "dd" into "d_" */
|
---|
| 321 | if (prevkey && key == prevkey)
|
---|
| 322 | {
|
---|
| 323 | key = '_';
|
---|
| 324 | }
|
---|
| 325 |
|
---|
| 326 | /* look up the structure describing this command */
|
---|
| 327 | keyptr = &vikeys[key];
|
---|
| 328 |
|
---|
| 329 | /* '&' and uppercase operators always act like doubled */
|
---|
| 330 | if (!prevkey && keyptr->args == CURSOR_MOVED
|
---|
| 331 | && (key == '&' || isupper(key)))
|
---|
| 332 | {
|
---|
| 333 | range = cursor;
|
---|
| 334 | prevkey = key;
|
---|
| 335 | key = '_';
|
---|
| 336 | keyptr = &vikeys[key];
|
---|
| 337 | }
|
---|
| 338 |
|
---|
| 339 | #ifndef NO_VISIBLE
|
---|
| 340 | /* if we're in the middle of a v/V command, reject commands
|
---|
| 341 | * that aren't operators or movement commands
|
---|
| 342 | */
|
---|
| 343 | if (V_from && !(keyptr->flags & VIZ))
|
---|
| 344 | {
|
---|
| 345 | beep();
|
---|
| 346 | prevkey = 0;
|
---|
| 347 | count = 0;
|
---|
| 348 | continue;
|
---|
| 349 | }
|
---|
| 350 | #endif
|
---|
| 351 |
|
---|
| 352 | /* if we're in the middle of a d/c/y/</>/! command, reject
|
---|
| 353 | * anything but movement.
|
---|
| 354 | */
|
---|
| 355 | if (prevkey && !(keyptr->flags & (MVMT|PTMV)))
|
---|
| 356 | {
|
---|
| 357 | beep();
|
---|
| 358 | prevkey = 0;
|
---|
| 359 | count = 0;
|
---|
| 360 | continue;
|
---|
| 361 | }
|
---|
| 362 |
|
---|
| 363 | /* set the "dot" variables, if we're supposed to */
|
---|
| 364 | if (((keyptr->flags & SDOT)
|
---|
| 365 | || (prevkey && vikeys[prevkey].flags & SDOT))
|
---|
| 366 | #ifndef NO_VISIBLE
|
---|
| 367 | && !V_from
|
---|
| 368 | #endif
|
---|
| 369 | )
|
---|
| 370 | {
|
---|
| 371 | dotkey = key;
|
---|
| 372 | dotpkey = prevkey;
|
---|
| 373 | dotkey2 = '\0';
|
---|
| 374 | dotcnt = count;
|
---|
| 375 |
|
---|
| 376 | /* remember the line before any changes are made */
|
---|
| 377 | if (U_line != markline(cursor))
|
---|
| 378 | {
|
---|
| 379 | U_line = markline(cursor);
|
---|
| 380 | strcpy(U_text, fetchline(U_line));
|
---|
| 381 | }
|
---|
| 382 | }
|
---|
| 383 |
|
---|
| 384 | /* if this is "." then set other vars from the "dot" vars */
|
---|
| 385 | if (key == '.')
|
---|
| 386 | {
|
---|
| 387 | key = dotkey;
|
---|
| 388 | keyptr = &vikeys[key];
|
---|
| 389 | prevkey = dotpkey;
|
---|
| 390 | if (prevkey)
|
---|
| 391 | {
|
---|
| 392 | range = cursor;
|
---|
| 393 | }
|
---|
| 394 | if (count == 0)
|
---|
| 395 | {
|
---|
| 396 | count = dotcnt;
|
---|
| 397 | }
|
---|
| 398 | doingdot = TRUE;
|
---|
| 399 |
|
---|
| 400 | /* remember the line before any changes are made */
|
---|
| 401 | if (U_line != markline(cursor))
|
---|
| 402 | {
|
---|
| 403 | U_line = markline(cursor);
|
---|
| 404 | strcpy(U_text, fetchline(U_line));
|
---|
| 405 | }
|
---|
| 406 | }
|
---|
| 407 | else
|
---|
| 408 | {
|
---|
| 409 | doingdot = FALSE;
|
---|
| 410 | }
|
---|
| 411 |
|
---|
| 412 | /* process the key as a command */
|
---|
| 413 | tcurs = cursor;
|
---|
| 414 | force_flags = NO_FLAGS;
|
---|
| 415 | switch (keyptr->args & ARGSMASK)
|
---|
| 416 | {
|
---|
| 417 | case ZERO:
|
---|
| 418 | if (count == 0)
|
---|
| 419 | {
|
---|
| 420 | tcurs = cursor & ~(BLKSIZE - 1);
|
---|
| 421 | break;
|
---|
| 422 | }
|
---|
| 423 | /* else fall through & treat like other digits... */
|
---|
| 424 |
|
---|
| 425 | case DIGIT:
|
---|
| 426 | count = count * 10 + key - '0';
|
---|
| 427 | break;
|
---|
| 428 |
|
---|
| 429 | case KEYWORD:
|
---|
| 430 | /* if not on a keyword, fail */
|
---|
| 431 | pfetch(markline(cursor));
|
---|
| 432 | key = markidx(cursor);
|
---|
| 433 | if (!isalnum(ptext[key]))
|
---|
| 434 | {
|
---|
| 435 | tcurs = MARK_UNSET;
|
---|
| 436 | break;
|
---|
| 437 | }
|
---|
| 438 |
|
---|
| 439 | /* find the start of the keyword */
|
---|
| 440 | while (key > 0 && isalnum(ptext[key - 1]))
|
---|
| 441 | {
|
---|
| 442 | key--;
|
---|
| 443 | }
|
---|
| 444 | tcurs = (cursor & ~(BLKSIZE - 1)) + key;
|
---|
| 445 |
|
---|
| 446 | /* copy it into a buffer, and NUL-terminate it */
|
---|
| 447 | i = 0;
|
---|
| 448 | do
|
---|
| 449 | {
|
---|
| 450 | text[i++] = ptext[key++];
|
---|
| 451 | } while (isalnum(ptext[key]));
|
---|
| 452 | text[i] = '\0';
|
---|
| 453 |
|
---|
| 454 | /* call the function */
|
---|
| 455 | tcurs = (*keyptr->func)(text, tcurs, count);
|
---|
| 456 | count = 0L;
|
---|
| 457 | break;
|
---|
| 458 |
|
---|
| 459 | case NO_ARGS:
|
---|
| 460 | if (keyptr->func)
|
---|
| 461 | {
|
---|
| 462 | (*keyptr->func)();
|
---|
| 463 | }
|
---|
| 464 | else
|
---|
| 465 | {
|
---|
| 466 | beep();
|
---|
| 467 | }
|
---|
| 468 | count = 0L;
|
---|
| 469 | break;
|
---|
| 470 |
|
---|
| 471 | case CURSOR:
|
---|
| 472 | tcurs = (*keyptr->func)(cursor, count, key, prevkey);
|
---|
| 473 | count = 0L;
|
---|
| 474 | break;
|
---|
| 475 |
|
---|
| 476 | case CURSOR_CNT_KEY:
|
---|
| 477 | if (doingdot)
|
---|
| 478 | {
|
---|
| 479 | tcurs = (*keyptr->func)(cursor, count, dotkey2);
|
---|
| 480 | }
|
---|
| 481 | else
|
---|
| 482 | {
|
---|
| 483 | /* get a key */
|
---|
| 484 | i = getkey(KEYMODE(keyptr->args));
|
---|
| 485 | if (i == '\033') /* ESC */
|
---|
| 486 | {
|
---|
| 487 | count = 0;
|
---|
| 488 | tcurs = MARK_UNSET;
|
---|
| 489 | break; /* exit from "case CURSOR_CNT_KEY" */
|
---|
| 490 | }
|
---|
| 491 | else if (i == ctrl('V'))
|
---|
| 492 | {
|
---|
| 493 | i = getkey(0);
|
---|
| 494 | }
|
---|
| 495 |
|
---|
| 496 | /* if part of an SDOT command, remember it */
|
---|
| 497 | if (keyptr->flags & SDOT
|
---|
| 498 | || (prevkey && vikeys[prevkey].flags & SDOT))
|
---|
| 499 | {
|
---|
| 500 | dotkey2 = i;
|
---|
| 501 | }
|
---|
| 502 |
|
---|
| 503 | /* do it */
|
---|
| 504 | tcurs = (*keyptr->func)(cursor, count, i);
|
---|
| 505 | }
|
---|
| 506 | count = 0L;
|
---|
| 507 | break;
|
---|
| 508 |
|
---|
| 509 | case CURSOR_MOVED:
|
---|
| 510 | #ifndef NO_VISIBLE
|
---|
| 511 | if (V_from)
|
---|
| 512 | {
|
---|
| 513 | range = cursor;
|
---|
| 514 | tcurs = V_from;
|
---|
| 515 | count = 0L;
|
---|
| 516 | prevkey = key;
|
---|
| 517 | key = (V_linemd ? 'V' : 'v');
|
---|
| 518 | keyptr = &vikeys[key];
|
---|
| 519 | }
|
---|
| 520 | else
|
---|
| 521 | #endif
|
---|
| 522 | {
|
---|
| 523 | prevkey = key;
|
---|
| 524 | range = cursor;
|
---|
| 525 | force_flags = LNMD|INCL;
|
---|
| 526 | }
|
---|
| 527 | break;
|
---|
| 528 |
|
---|
| 529 | case CURSOR_EOL:
|
---|
| 530 | prevkey = key;
|
---|
| 531 | /* a zero-length line needs special treatment */
|
---|
| 532 | pfetch(markline(cursor));
|
---|
| 533 | if (plen == 0)
|
---|
| 534 | {
|
---|
| 535 | /* act on a zero-length section of text */
|
---|
| 536 | range = tcurs = cursor;
|
---|
| 537 | key = '0';
|
---|
| 538 | }
|
---|
| 539 | else
|
---|
| 540 | {
|
---|
| 541 | /* act like CURSOR_MOVED with '$' movement */
|
---|
| 542 | range = cursor;
|
---|
| 543 | tcurs = m_rear(cursor, 1L);
|
---|
| 544 | key = '$';
|
---|
| 545 | }
|
---|
| 546 | count = 0L;
|
---|
| 547 | keyptr = &vikeys[key];
|
---|
| 548 | break;
|
---|
| 549 |
|
---|
| 550 | case CURSOR_TEXT:
|
---|
| 551 | do
|
---|
| 552 | {
|
---|
| 553 | text[0] = key;
|
---|
| 554 | if (vgets(key, text + 1, sizeof text - 1) >= 0)
|
---|
| 555 | {
|
---|
| 556 | /* reassure user that <CR> was hit */
|
---|
| 557 | qaddch('\r');
|
---|
| 558 | refresh();
|
---|
| 559 |
|
---|
| 560 | /* call the function with the text */
|
---|
| 561 | tcurs = (*keyptr->func)(cursor, text);
|
---|
| 562 | }
|
---|
| 563 | else
|
---|
| 564 | {
|
---|
| 565 | if (exwrote || mode == MODE_COLON)
|
---|
| 566 | {
|
---|
| 567 | redraw(MARK_UNSET, FALSE);
|
---|
| 568 | }
|
---|
| 569 | mode = MODE_VI;
|
---|
| 570 | }
|
---|
| 571 | } while (mode == MODE_COLON);
|
---|
| 572 | count = 0L;
|
---|
| 573 | break;
|
---|
| 574 | }
|
---|
| 575 |
|
---|
| 576 | /* if that command took us out of vi mode, then exit the loop
|
---|
| 577 | * NOW, without tweaking the cursor or anything. This is very
|
---|
| 578 | * important when mode == MODE_QUIT.
|
---|
| 579 | */
|
---|
| 580 | if (mode != MODE_VI)
|
---|
| 581 | {
|
---|
| 582 | break;
|
---|
| 583 | }
|
---|
| 584 |
|
---|
| 585 | /* now move the cursor, as appropriate */
|
---|
| 586 | if (keyptr->args == CURSOR_MOVED)
|
---|
| 587 | {
|
---|
| 588 | /* the < and > keys have FRNT,
|
---|
| 589 | * but it shouldn't be applied yet
|
---|
| 590 | */
|
---|
| 591 | tcurs = adjmove(cursor, tcurs, 0);
|
---|
| 592 | }
|
---|
| 593 | else
|
---|
| 594 | {
|
---|
| 595 | tcurs = adjmove(cursor, tcurs, (int)keyptr->flags | force_flags);
|
---|
| 596 | }
|
---|
| 597 |
|
---|
| 598 | /* was that the end of a d/c/y/</>/! command? */
|
---|
| 599 | if (prevkey && ((keyptr->flags & MVMT)
|
---|
| 600 | #ifndef NO_VISIBLE
|
---|
| 601 | || V_from
|
---|
| 602 | #endif
|
---|
| 603 | ) && count == 0L)
|
---|
| 604 | {
|
---|
| 605 | #ifndef NO_VISIBLE
|
---|
| 606 | /* turn off the hilight */
|
---|
| 607 | V_from = 0L;
|
---|
| 608 | #endif
|
---|
| 609 |
|
---|
| 610 | /* if the movement command failed, cancel operation */
|
---|
| 611 | if (tcurs == MARK_UNSET)
|
---|
| 612 | {
|
---|
| 613 | prevkey = 0;
|
---|
| 614 | count = 0;
|
---|
| 615 | continue;
|
---|
| 616 | }
|
---|
| 617 |
|
---|
| 618 | /* make sure range=front and tcurs=rear. Either way,
|
---|
| 619 | * leave cursor=range since that's where we started.
|
---|
| 620 | */
|
---|
| 621 | cursor = range;
|
---|
| 622 | if (tcurs < range)
|
---|
| 623 | {
|
---|
| 624 | range = tcurs;
|
---|
| 625 | tcurs = cursor;
|
---|
| 626 | }
|
---|
| 627 |
|
---|
| 628 | /* The 'w' and 'W' destinations should never take us
|
---|
| 629 | * to the front of a line. Instead, they should take
|
---|
| 630 | * us only to the end of the preceding line.
|
---|
| 631 | */
|
---|
| 632 | if ((keyptr->flags & (MVMT|NREL|LNMD|FRNT|INCL)) == MVMT
|
---|
| 633 | && markline(range) < markline(tcurs)
|
---|
| 634 | && (markline(tcurs) > nlines || tcurs == m_front(tcurs, 0L)))
|
---|
| 635 | {
|
---|
| 636 | tcurs = (tcurs & ~(BLKSIZE - 1)) - BLKSIZE;
|
---|
| 637 | pfetch(markline(tcurs));
|
---|
| 638 | tcurs += plen;
|
---|
| 639 | }
|
---|
| 640 |
|
---|
| 641 | /* adjust for line mode & inclusion of last char/line */
|
---|
| 642 | i = (keyptr->flags | vikeys[prevkey].flags);
|
---|
| 643 | switch ((i | force_flags) & (INCL|LNMD))
|
---|
| 644 | {
|
---|
| 645 | case INCL:
|
---|
| 646 | tcurs++;
|
---|
| 647 | break;
|
---|
| 648 |
|
---|
| 649 | case INCL|LNMD:
|
---|
| 650 | tcurs += BLKSIZE;
|
---|
| 651 | /* fall through... */
|
---|
| 652 |
|
---|
| 653 | case LNMD:
|
---|
| 654 | range &= ~(BLKSIZE - 1);
|
---|
| 655 | tcurs &= ~(BLKSIZE - 1);
|
---|
| 656 | break;
|
---|
| 657 | }
|
---|
| 658 |
|
---|
| 659 | /* run the function */
|
---|
| 660 | tcurs = (*vikeys[prevkey].func)(range, tcurs);
|
---|
| 661 | if (mode == MODE_VI)
|
---|
| 662 | {
|
---|
| 663 | (void)adjmove(cursor, cursor, 0);
|
---|
| 664 | cursor = adjmove(cursor, tcurs, (int)vikeys[prevkey].flags);
|
---|
| 665 | }
|
---|
| 666 |
|
---|
| 667 | /* cleanup */
|
---|
| 668 | prevkey = 0;
|
---|
| 669 | }
|
---|
| 670 | else if (!prevkey)
|
---|
| 671 | {
|
---|
| 672 | if (tcurs != MARK_UNSET)
|
---|
| 673 | cursor = tcurs;
|
---|
| 674 | }
|
---|
| 675 | }
|
---|
| 676 | }
|
---|
| 677 |
|
---|
| 678 | /* This function adjusts the MARK value that they return; here we make sure
|
---|
| 679 | * it isn't past the end of the line, and that the column hasn't been
|
---|
| 680 | * *accidentally* changed.
|
---|
| 681 | */
|
---|
| 682 | MARK adjmove(old, new, flags)
|
---|
| 683 | MARK old; /* the cursor position before the command */
|
---|
| 684 | REG MARK new; /* the cursor position after the command */
|
---|
| 685 | int flags; /* various flags regarding cursor mvmt */
|
---|
| 686 | {
|
---|
| 687 | static int colno; /* the column number that we want */
|
---|
| 688 | REG char *text; /* used to scan through the line's text */
|
---|
| 689 | REG int i;
|
---|
| 690 |
|
---|
| 691 | #ifdef DEBUG
|
---|
| 692 | watch();
|
---|
| 693 | #endif
|
---|
| 694 |
|
---|
| 695 | /* if the command failed, bag it! */
|
---|
| 696 | if (new == MARK_UNSET)
|
---|
| 697 | {
|
---|
| 698 | beep();
|
---|
| 699 | return old;
|
---|
| 700 | }
|
---|
| 701 |
|
---|
| 702 | /* if this is a non-relative movement, set the '' mark */
|
---|
| 703 | if (flags & NREL)
|
---|
| 704 | {
|
---|
| 705 | mark[26] = old;
|
---|
| 706 | }
|
---|
| 707 |
|
---|
| 708 | /* make sure it isn't past the end of the file */
|
---|
| 709 | if (markline(new) < 1)
|
---|
| 710 | {
|
---|
| 711 | new = MARK_FIRST;
|
---|
| 712 | }
|
---|
| 713 | else if (markline(new) > nlines)
|
---|
| 714 | {
|
---|
| 715 | new = MARK_LAST;
|
---|
| 716 | }
|
---|
| 717 |
|
---|
| 718 | /* fetch the new line */
|
---|
| 719 | pfetch(markline(new));
|
---|
| 720 |
|
---|
| 721 | /* move to the front, if we're supposed to */
|
---|
| 722 | if (flags & FRNT)
|
---|
| 723 | {
|
---|
| 724 | new = m_front(new, 1L);
|
---|
| 725 | }
|
---|
| 726 |
|
---|
| 727 | /* change the column#, or change the mark to suit the column# */
|
---|
| 728 | if (!(flags & NCOL))
|
---|
| 729 | {
|
---|
| 730 | /* change the column# */
|
---|
| 731 | i = markidx(new);
|
---|
| 732 | if (i == BLKSIZE - 1)
|
---|
| 733 | {
|
---|
| 734 | new &= ~(BLKSIZE - 1);
|
---|
| 735 | if (plen > 0)
|
---|
| 736 | {
|
---|
| 737 | new += plen - 1;
|
---|
| 738 | }
|
---|
| 739 | colno = BLKSIZE * 8; /* one heck of a big colno */
|
---|
| 740 | }
|
---|
| 741 | else if (plen > 0)
|
---|
| 742 | {
|
---|
| 743 | if (i >= plen)
|
---|
| 744 | {
|
---|
| 745 | new = (new & ~(BLKSIZE - 1)) + plen - 1;
|
---|
| 746 | }
|
---|
| 747 | colno = idx2col(new, ptext, FALSE);
|
---|
| 748 | }
|
---|
| 749 | else
|
---|
| 750 | {
|
---|
| 751 | new &= ~(BLKSIZE - 1);
|
---|
| 752 | colno = 0;
|
---|
| 753 | }
|
---|
| 754 | }
|
---|
| 755 | else
|
---|
| 756 | {
|
---|
| 757 | /* adjust the mark to get as close as possible to column# */
|
---|
| 758 | for (i = 0, text = ptext; i <= colno && *text; text++)
|
---|
| 759 | {
|
---|
| 760 | if (*text == '\t' && !*o_list)
|
---|
| 761 | {
|
---|
| 762 | i += *o_tabstop - (i % *o_tabstop);
|
---|
| 763 | }
|
---|
| 764 | else if (UCHAR(*text) < ' ' || *text == 127)
|
---|
| 765 | {
|
---|
| 766 | i += 2;
|
---|
| 767 | }
|
---|
| 768 | #ifndef NO_CHARATTR
|
---|
| 769 | else if (*o_charattr && text[0] == '\\' && text[1] == 'f' && text[2])
|
---|
| 770 | {
|
---|
| 771 | text += 2; /* plus one more in "for()" stmt */
|
---|
| 772 | }
|
---|
| 773 | #endif
|
---|
| 774 | else
|
---|
| 775 | {
|
---|
| 776 | i++;
|
---|
| 777 | }
|
---|
| 778 | }
|
---|
| 779 | if (text > ptext)
|
---|
| 780 | {
|
---|
| 781 | text--;
|
---|
| 782 | }
|
---|
| 783 | new = (new & ~(BLKSIZE - 1)) + (int)(text - ptext);
|
---|
| 784 | }
|
---|
| 785 |
|
---|
| 786 | return new;
|
---|
| 787 | }
|
---|
| 788 |
|
---|
| 789 |
|
---|
| 790 | #ifdef DEBUG
|
---|
| 791 | watch()
|
---|
| 792 | {
|
---|
| 793 | static wasset;
|
---|
| 794 |
|
---|
| 795 | if (*origname)
|
---|
| 796 | {
|
---|
| 797 | wasset = TRUE;
|
---|
| 798 | }
|
---|
| 799 | else if (wasset)
|
---|
| 800 | {
|
---|
| 801 | mode = MODE_EX;
|
---|
| 802 | msg("origname was clobbered");
|
---|
| 803 | endwin();
|
---|
| 804 | abort();
|
---|
| 805 | }
|
---|
| 806 |
|
---|
| 807 | if (wasset && nlines == 0)
|
---|
| 808 | {
|
---|
| 809 | mode = MODE_EX;
|
---|
| 810 | msg("nlines=0");
|
---|
| 811 | endwin();
|
---|
| 812 | abort();
|
---|
| 813 | }
|
---|
| 814 | }
|
---|
| 815 | #endif
|
---|