home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume41 / vim / part16 < prev    next >
Encoding:
Text File  |  1993-12-22  |  35.5 KB  |  1,710 lines

  1. Newsgroups: comp.sources.misc
  2. From: mool@oce.nl (Bram Moolenaar)
  3. Subject: v41i066:  vim - Vi IMitation editor, v2.0, Part16/25
  4. Message-ID: <1993Dec21.172539.1458@sparky.sterling.com>
  5. X-Md4-Signature: 14b33a5603f6ee21c88032376c8f3445
  6. Keywords: utility, editor, vi, vim
  7. Sender: kent@sparky.sterling.com (Kent Landfield)
  8. Organization: Sterling Software
  9. Date: Tue, 21 Dec 1993 17:25:39 GMT
  10. Approved: kent@sparky.sterling.com
  11.  
  12. Submitted-by: mool@oce.nl (Bram Moolenaar)
  13. Posting-number: Volume 41, Issue 66
  14. Archive-name: vim/part16
  15. Environment: UNIX, AMIGA, MS-DOS
  16. Supersedes: vim: Volume 37, Issue 1-24
  17.  
  18. #! /bin/sh
  19. # This is a shell archive.  Remove anything before this line, then unpack
  20. # it by saving it into a file and typing "sh file".  To overwrite existing
  21. # files, type "sh file -c".  You can also feed this as standard input via
  22. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  23. # will see the following message at the end:
  24. #        "End of archive 16 (of 25)."
  25. # Contents:  vim/src/normal.c
  26. # Wrapped by mool@oce-rd2 on Wed Dec 15 09:50:07 1993
  27. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  28. if test -f 'vim/src/normal.c' -a "${1}" != "-c" ; then 
  29.   echo shar: Will not clobber existing file \"'vim/src/normal.c'\"
  30. else
  31. echo shar: Extracting \"'vim/src/normal.c'\" \(32142 characters\)
  32. sed "s/^X//" >'vim/src/normal.c' <<'END_OF_FILE'
  33. X/* vi:ts=4:sw=4
  34. X *
  35. X * VIM - Vi IMproved
  36. X *
  37. X * Code Contributions By:    Bram Moolenaar            mool@oce.nl
  38. X *                            Tim Thompson            twitch!tjt
  39. X *                            Tony Andrews            onecom!wldrdg!tony 
  40. X *                            G. R. (Fred) Walter        watmath!watcgl!grwalter 
  41. X */
  42. X
  43. X/*
  44. X * Contains the main routine for processing characters in command mode.
  45. X * Communicates closely with the code in ops.c to handle the operators.
  46. X */
  47. X
  48. X#include "vim.h"
  49. X#include "globals.h"
  50. X#include "proto.h"
  51. X#include "param.h"
  52. X
  53. X#undef EXTERN
  54. X#undef INIT
  55. X#define EXTERN
  56. X#define INIT(x) x
  57. X#include "ops.h"
  58. X
  59. X/*
  60. X * Generally speaking, every command in normal() should either clear any
  61. X * pending operator (with CLEAROP), or set the motion type variable.
  62. X */
  63. X
  64. X#define CLEAROP (operator = NOP)        /* clear any pending operator */
  65. X#define CLEAROPBEEP     clearopbeep()    /* CLEAROP plus a beep() */
  66. X#define CHECKCLEAROP    if (checkclearop()) break;
  67. X#define CHECKCLEAROPQ    if (checkclearopq()) break;
  68. X
  69. X/*
  70. X * If a count is given before the operator, it is saved in opnum.
  71. X */
  72. Xstatic linenr_t    opnum = 0;
  73. Xstatic linenr_t    Prenum;         /* The (optional) number before a command. */
  74. Xint                redo_Visual_busy = FALSE;    /* TRUE when redo-ing a visual */
  75. X
  76. Xstatic void        prep_redo __ARGS((long, int, int, int));
  77. Xstatic int        checkclearop __ARGS((void));
  78. Xstatic int        checkclearopq __ARGS((void));
  79. Xstatic void        clearopbeep __ARGS((void));
  80. Xstatic void        premsg __ARGS((int, int));
  81. X
  82. Xextern int        restart_edit;    /* this is in edit.c */
  83. X
  84. X/*
  85. X * normal
  86. X *
  87. X * Execute a command in normal mode.
  88. X *
  89. X * This is basically a big switch with the cases arranged in rough categories
  90. X * in the following order:
  91. X *
  92. X *      0. Macros (q, @)
  93. X *      1. Screen positioning commands (^U, ^D, ^F, ^B, ^E, ^Y, z)
  94. X *      2. Control commands (:, <help>, ^L, ^G, ^^, ZZ, *, ^], ^T)
  95. X *      3. Cursor motions (G, H, M, L, l, K_RARROW,  , h, K_LARROW, ^H, k, K_UARROW, ^P, +, CR, LF, j, K_DARROW, ^N, _, |, B, b, W, w, E, e, $, ^, 0)
  96. X *      4. Searches (?, /, n, N, T, t, F, f, ,, ;, ], [, %, (, ), {, })
  97. X *      5. Edits (., u, K_UNDO, ^R, U, r, J, p, P, ^A, ^S)
  98. X *      6. Inserts (A, a, I, i, o, O, R)
  99. X *      7. Operators (~, d, c, y, >, <, !, =, Q)
  100. X *      8. Abbreviations (x, X, D, C, s, S, Y, &)
  101. X *      9. Marks (m, ', `, ^O, ^I)
  102. X *     10. Buffer setting (")
  103. X *     11. Visual (v, V, ^V)
  104. X *   12. Suspend (^Z)
  105. X */
  106. X
  107. X    void
  108. Xnormal()
  109. X{
  110. X    register u_char    c;
  111. X    long             n;
  112. X    int                flag = FALSE;
  113. X    int             type = 0;        /* used in some operations to modify type */
  114. X    int             dir = FORWARD;    /* search direction */
  115. X    u_char            nchar = NUL;
  116. X    int                finish_op;
  117. X    linenr_t        Prenum1;
  118. X    char            searchbuff[CMDBUFFSIZE];        /* buffer for search string */
  119. X    FPOS            *pos;
  120. X    register char    *ptr;
  121. X    int                command_busy = FALSE;
  122. X    static int        didwarn = FALSE;        /* warned for broken inversion */
  123. X
  124. X        /* the visual area is remembered for reselection */
  125. X    static linenr_t    resel_Visual_nlines;        /* number of lines */
  126. X    static int        resel_Visual_type = 0;    /* type 'v', 'V' or CTRL-V */
  127. X    static colnr_t    resel_Visual_col;        /* number of columns or end column */
  128. X        /* the visual area is remembered for redo */
  129. X    static linenr_t    redo_Visual_nlines;        /* number of lines */
  130. X    static int        redo_Visual_type = 0;    /* type 'v', 'V' or CTRL-V */
  131. X    static colnr_t    redo_Visual_col;            /* number of columns or end column */
  132. X
  133. X    Prenum = 0;
  134. X    /*
  135. X     * If there is an operator pending, then the command we take this time
  136. X     * will terminate it. Finish_op tells us to finish the operation before
  137. X     * returning this time (unless the operation was cancelled).
  138. X     */
  139. X    finish_op = (operator != NOP);
  140. X
  141. X    if (!finish_op && !yankbuffer)
  142. X        opnum = 0;
  143. X
  144. X    if (p_sc && (vpeekc() == NUL || KeyTyped == TRUE))
  145. X        premsg(NUL, NUL);
  146. X    State = NORMAL_BUSY;
  147. X    c = vgetc();
  148. X
  149. X    /* Pick up any leading digits and compute 'Prenum' */
  150. X    while ((c >= '1' && c <= '9') || (Prenum != 0 && (c == DEL || c == '0')))
  151. X    {
  152. X        if (c == DEL)
  153. X                Prenum /= 10;
  154. X        else
  155. X                Prenum = Prenum * 10 + (c - '0');
  156. X        if (Prenum < 0)            /* got too large! */
  157. X            Prenum = 999999999;
  158. X        premsg(' ', NUL);
  159. X        c = vgetc();
  160. X    }
  161. X
  162. X    /*
  163. X     * If we're in the middle of an operator (including after entering a yank
  164. X     * buffer with ") AND we had a count before the
  165. X     * operator, then that count overrides the current value of Prenum. What
  166. X     * this means effectively, is that commands like "3dw" get turned into
  167. X     * "d3w" which makes things fall into place pretty neatly.
  168. X     * If you give a count before AND after the operator, they are multiplied.
  169. X     */
  170. X    if (opnum != 0)
  171. X    {
  172. X            if (Prenum)
  173. X                Prenum *= opnum;
  174. X            else
  175. X                Prenum = opnum;
  176. X            opnum = 0;
  177. X    }
  178. X
  179. X    Prenum1 = (Prenum == 0 ? 1 : Prenum);        /* Prenum often defaults to 1 */
  180. X    premsg(c, NUL);
  181. X
  182. X    /*
  183. X     * get an additional character if we need one
  184. X     */
  185. X    if (strchr("@zZtTfF[]m'`\"", c) || (c == 'q' && !Recording && !Exec_reg) ||
  186. X                                        (c == 'r' && !Visual.lnum))
  187. X    {
  188. X        State = NOMAPPING;
  189. X        nchar = vgetc();        /* no macro mapping for this char */
  190. X        premsg(c, nchar);
  191. X    }
  192. X    if (p_sc)
  193. X        flushbuf();        /* flush the premsg() characters onto the screen so we can
  194. X                            see them while the command is being executed */
  195. X
  196. X    if (c != 'z')    /* the 'z' command gets another character */
  197. X    {
  198. X        State = NORMAL;
  199. X        script_winsize_pp();
  200. X    }
  201. X    if (nchar == ESC)
  202. X    {
  203. X        CLEAROP;
  204. X        goto normal_end;
  205. X    }
  206. X    switch (c)
  207. X    {
  208. X
  209. X/*
  210. X * 0: Macros
  211. X */
  212. X      case 'q':         /* (stop) recording into a named register */
  213. X        CHECKCLEAROP;
  214. X                        /* command is ignored while executing a register */
  215. X        if (!Exec_reg && !dorecord(nchar))
  216. X            CLEAROPBEEP;
  217. X        break;
  218. X
  219. X     case '@':            /* execute a named buffer */
  220. X        CHECKCLEAROP;
  221. X        while (Prenum1--)
  222. X            if (!doexecbuf(nchar))
  223. X            {
  224. X                CLEAROPBEEP;
  225. X                break;
  226. X            }
  227. X        break;
  228. X
  229. X/*
  230. X * 1: Screen positioning commands
  231. X */
  232. X      case Ctrl('D'):
  233. X        flag = TRUE;
  234. X
  235. X      case Ctrl('U'):
  236. X        CHECKCLEAROP;
  237. X        if (Prenum)
  238. X            p_scroll = (Prenum > Rows - 1) ? Rows - 1 : Prenum;
  239. X        n = (p_scroll < Rows) ? p_scroll : Rows - 1;
  240. X        if (flag)
  241. X        {
  242. X                Topline += n;
  243. X                if (Topline > line_count)
  244. X                    Topline = line_count;
  245. X                comp_Botline();        /* compute Botline */
  246. X                onedown(n);
  247. X        }
  248. X        else
  249. X        {
  250. X                if (n >= Curpos.lnum)
  251. X                    n = Curpos.lnum - 1;
  252. X                Prenum1 = Curpos.lnum - n;
  253. X                scrolldown(n);
  254. X                if (Prenum1 < Curpos.lnum)
  255. X                    Curpos.lnum = Prenum1;
  256. X        }
  257. X        beginline(TRUE);
  258. X        updateScreen(VALID);
  259. X        break;
  260. X
  261. X      case Ctrl('B'):
  262. X      case K_SUARROW:
  263. X        dir = BACKWARD;
  264. X
  265. X      case Ctrl('F'):
  266. X      case K_SDARROW:
  267. X        CHECKCLEAROP;
  268. X        onepage(dir, Prenum1);
  269. X        break;
  270. X
  271. X      case Ctrl('E'):
  272. X        CHECKCLEAROP;
  273. X        scrollup(Prenum1);
  274. X        updateScreen(VALID);
  275. X        break;
  276. X
  277. X      case Ctrl('Y'):
  278. X        CHECKCLEAROP;
  279. X        scrolldown(Prenum1);
  280. X        updateScreen(VALID);
  281. X        break;
  282. X
  283. X      case 'z':
  284. X        CHECKCLEAROP;
  285. X        if (isdigit(nchar))
  286. X        {
  287. X            /*
  288. X             * we misuse some variables to be able to call premsg()
  289. X             */
  290. X            operator = c;
  291. X            opnum = Prenum;
  292. X            Prenum = nchar - '0';
  293. X            for (;;)
  294. X            {
  295. X                premsg(' ', NUL);
  296. X                nchar = vgetc();
  297. X                State = NORMAL;
  298. X                script_winsize_pp();
  299. X                if (nchar == DEL)
  300. X                    Prenum /= 10;
  301. X                else if (isdigit(nchar))
  302. X                    Prenum = Prenum * 10 + (nchar - '0');
  303. X                else if (nchar == CR)
  304. X                {
  305. X                    set_winheight((int)Prenum);
  306. X                    break;
  307. X                }
  308. X                else
  309. X                {
  310. X                    CLEAROPBEEP;
  311. X                    break;
  312. X                }
  313. X            }
  314. X            operator = NOP;
  315. X            break;
  316. X        }
  317. X
  318. X        if (Prenum)        /* line number given */
  319. X        {
  320. X            setpcmark();
  321. X            if (Prenum > line_count)
  322. X                Curpos.lnum = line_count;
  323. X            else
  324. X                Curpos.lnum = Prenum;
  325. X        }
  326. X        State = NORMAL;
  327. X        script_winsize_pp();
  328. X        switch (nchar)
  329. X        {
  330. X          case NL:                /* put Curpos at top of screen */
  331. X          case CR:
  332. X            Topline = Curpos.lnum;
  333. X            updateScreen(VALID);
  334. X            break;
  335. X
  336. X          case '.':             /* put Curpos in middle of screen */
  337. X            n = (Rows + plines(Curpos.lnum)) / 2;
  338. X            goto dozcmd;
  339. X
  340. X          case '-':             /* put Curpos at bottom of screen */
  341. X            n = Rows - 1;
  342. X            /* FALLTHROUGH */
  343. X
  344. X    dozcmd:
  345. X            {
  346. X                register linenr_t    lp = Curpos.lnum;
  347. X                register long        l = plines(lp);
  348. X
  349. X                do
  350. X                {
  351. X                    Topline = lp;
  352. X                    if (--lp == 0)
  353. X                        break;
  354. X                    l += plines(lp);
  355. X                } while (l <= n);
  356. X            }
  357. X            updateScreen(VALID);
  358. X            beginline(TRUE);
  359. X            break;
  360. X
  361. X          default:
  362. X            CLEAROPBEEP;
  363. X        }
  364. X        break;
  365. X
  366. X/*
  367. X *      2: Control commands
  368. X */
  369. X      case ':':
  370. X        if (Visual.lnum)
  371. X            goto dooperator;
  372. X        CHECKCLEAROP;
  373. X        docmdline(NULL);
  374. X        break;
  375. X
  376. X      case K_HELP:
  377. X        CHECKCLEAROP;
  378. X        help();
  379. X        break;
  380. X
  381. X      case Ctrl('L'):
  382. X        CHECKCLEAROP;
  383. X        updateScreen(CLEAR);
  384. X        break;
  385. X
  386. X      case Ctrl('G'):
  387. X        CHECKCLEAROP;
  388. X        fileinfo(did_cd || Prenum);    /* print full name if count given or :cd used */
  389. X        break;
  390. X
  391. X      case K_CCIRCM:            /* shorthand command */
  392. X        CHECKCLEAROPQ;
  393. X        getaltfile((int)Prenum, (linenr_t)0, TRUE);
  394. X        break;
  395. X
  396. X      case 'Z':         /* write, if changed, and exit */
  397. X        CHECKCLEAROPQ;
  398. X        if (nchar != 'Z')
  399. X        {
  400. X            CLEAROPBEEP;
  401. X            break;
  402. X        }
  403. X        stuffReadbuff(":x\n");
  404. X        break;
  405. X
  406. X      case Ctrl(']'):            /* :ta to current identifier */
  407. X        CHECKCLEAROPQ;
  408. X      case '*':                 /* / to current identifier */
  409. X      case '#':                 /* ? to current identifier */
  410. X      case 'K':                    /* run program for current identifier */
  411. X        {
  412. X            register int     col;
  413. X
  414. X            ptr = nr2ptr(Curpos.lnum);
  415. X            col = Curpos.col;
  416. X
  417. X            /*
  418. X             * skip to start of identifier.
  419. X             */
  420. X            while (ptr[col] != NUL && !isidchar(ptr[col]))
  421. X                ++col;
  422. X
  423. X            /*
  424. X             * Back up to start of identifier. This doesn't match the
  425. X             * real vi but I like it a little better and it shouldn't bother
  426. X             * anyone.
  427. X             */
  428. X            while (col > 0 && isidchar(ptr[col - 1]))
  429. X                --col;
  430. X
  431. X            if (!isidchar(ptr[col]))
  432. X            {
  433. X                CLEAROPBEEP;
  434. X                break;
  435. X            }
  436. X
  437. X            if (Prenum)
  438. X                stuffnumReadbuff(Prenum);
  439. X            switch (c)
  440. X            {
  441. X                case '*':
  442. X                    stuffReadbuff("/");
  443. X                    break;
  444. X                case '#':
  445. X                    stuffReadbuff("?");
  446. X                    break;
  447. X                case 'K':
  448. X                    stuffReadbuff(":! ");
  449. X                    stuffReadbuff(p_kp);
  450. X                    stuffReadbuff(" ");
  451. X                    break;
  452. X                default:
  453. X                    stuffReadbuff(":ta ");
  454. X            }
  455. X
  456. X            /*
  457. X             * Now grab the chars in the identifier
  458. X             */
  459. X            while (isidchar(ptr[col]))
  460. X            {
  461. X                stuffcharReadbuff(ptr[col]);
  462. X                ++col;
  463. X            }
  464. X            stuffReadbuff("\n");
  465. X        }
  466. X        break;
  467. X
  468. X      case Ctrl('T'):        /* backwards in tag stack */
  469. X            CHECKCLEAROPQ;
  470. X              dotag("", 2, (int)Prenum1);
  471. X            break;
  472. X
  473. X/*
  474. X * Cursor motions
  475. X */
  476. X      case 'G':
  477. X        mtype = MLINE;
  478. X        setpcmark();
  479. X        if (Prenum == 0 || Prenum > line_count)
  480. X                Curpos.lnum = line_count;
  481. X        else
  482. X                Curpos.lnum = Prenum;
  483. X        beginline(TRUE);
  484. X        break;
  485. X
  486. X      case 'H':
  487. X      case 'M':
  488. X        if (c == 'M')
  489. X                n = (Rows - emptyrows - 1) / 2;
  490. X        else
  491. X                n = Prenum;
  492. X        mtype = MLINE;
  493. X        setpcmark();
  494. X        Curpos.lnum = Topline;
  495. X        while (n && onedown((long)1))
  496. X                --n;
  497. X        beginline(TRUE);
  498. X        break;
  499. X
  500. X      case 'L':
  501. X        mtype = MLINE;
  502. X        setpcmark();
  503. X        Curpos.lnum = Botline - 1;
  504. X        for (n = Prenum; n && oneup((long)1); n--)
  505. X                ;
  506. X        beginline(TRUE);
  507. X        break;
  508. X
  509. X      case 'l':
  510. X      case K_RARROW:
  511. X      case ' ':
  512. X        mtype = MCHAR;
  513. X        mincl = FALSE;
  514. X        n = Prenum1;
  515. X        while (n--)
  516. X        {
  517. X            if (!oneright())
  518. X            {
  519. X                if (operator == NOP)
  520. X                    beep();
  521. X                else
  522. X                {
  523. X                    if (lineempty(Curpos.lnum))
  524. X                        CLEAROPBEEP;
  525. X                    else
  526. X                    {
  527. X                        mincl = TRUE;
  528. X                        if (n)
  529. X                            beep();
  530. X                    }
  531. X                }
  532. X                break;
  533. X            }
  534. X        }
  535. X        set_want_col = TRUE;
  536. X        break;
  537. X
  538. X      case 'h':
  539. X      case K_LARROW:
  540. X      case Ctrl('H'):
  541. X      case DEL:
  542. X        mtype = MCHAR;
  543. X        mincl = FALSE;
  544. X        n = Prenum1;
  545. X        while (n--)
  546. X        {
  547. X            if (!oneleft())
  548. X            {
  549. X                if (operator != DELETE && operator != CHANGE)
  550. X                    beep();
  551. X                else if (Prenum1 == 1)
  552. X                    CLEAROPBEEP;
  553. X                break;
  554. X            }
  555. X        }
  556. X        set_want_col = TRUE;
  557. X        break;
  558. X
  559. X      case '-':
  560. X        flag = TRUE;
  561. X        /* FALLTHROUGH */
  562. X
  563. X      case 'k':
  564. X      case K_UARROW:
  565. X      case Ctrl('P'):
  566. X        mtype = MLINE;
  567. X        if (!oneup(Prenum1))
  568. X            CLEAROPBEEP;
  569. X        else if (flag)
  570. X            beginline(TRUE);
  571. X        break;
  572. X
  573. X      case '+':
  574. X      case CR:
  575. X        flag = TRUE;
  576. X        /* FALLTHROUGH */
  577. X
  578. X      case 'j':
  579. X      case K_DARROW:
  580. X      case Ctrl('N'):
  581. X      case NL:
  582. X        mtype = MLINE;
  583. X        if (!onedown(Prenum1))
  584. X            CLEAROPBEEP;
  585. X        else if (flag)
  586. X            beginline(TRUE);
  587. X        break;
  588. X
  589. X        /*
  590. X         * This is a strange motion command that helps make operators more
  591. X         * logical. It is actually implemented, but not documented in the
  592. X         * real 'vi'. This motion command actually refers to "the current
  593. X         * line". Commands like "dd" and "yy" are really an alternate form of
  594. X         * "d_" and "y_". It does accept a count, so "d3_" works to delete 3
  595. X         * lines.
  596. X         */
  597. X      case '_':
  598. Xlineop:
  599. X        if (operator == CHANGE && p_ai)        /* do not delete the indent */
  600. X        {
  601. X            beginline(TRUE);
  602. X            startop = Curpos;
  603. X            mtype = MCHAR;
  604. X            mincl = TRUE;
  605. X        }
  606. X        else
  607. X            mtype = MLINE;
  608. X        if (!onedown((long)(Prenum1 - 1)))
  609. X            CLEAROPBEEP;
  610. X        else if (mtype == MCHAR)    /* 'c' with autoindent */
  611. X        {
  612. X            Curpos.col = MAXCOL;    /* put cursor on last char in line */
  613. X            adjustCurpos();
  614. X        }
  615. X        else if (operator != YANK)    /* 'Y' does not move cursor */
  616. X            beginline(TRUE);
  617. X        break;
  618. X
  619. X      case '|':
  620. X        mtype = MCHAR;
  621. X        mincl = TRUE;
  622. X        beginline(FALSE);
  623. X        if (Prenum > 0)
  624. X            coladvance((colnr_t)(Prenum - 1));
  625. X        Curswant = (colnr_t)(Prenum - 1);
  626. X        break;
  627. X
  628. X        /*
  629. X         * Word Motions
  630. X         */
  631. X
  632. X      case 'B':
  633. X        type = 1;
  634. X        /* FALLTHROUGH */
  635. X
  636. X      case 'b':
  637. X      case K_SLARROW:
  638. X        mtype = MCHAR;
  639. X        mincl = FALSE;
  640. X        set_want_col = TRUE;
  641. X        if (bck_word(Prenum1, type))
  642. X            CLEAROPBEEP;
  643. X        break;
  644. X
  645. X      case 'E':
  646. X        type = 1;
  647. X        /* FALLTHROUGH */
  648. X
  649. X      case 'e':
  650. X        mincl = TRUE;
  651. X        goto dowrdcmd;
  652. X
  653. X      case 'W':
  654. X        type = 1;
  655. X        /* FALLTHROUGH */
  656. X
  657. X      case 'w':
  658. X      case K_SRARROW:
  659. X        mincl = FALSE;
  660. X        flag = TRUE;
  661. X        /*
  662. X         * This is a little strange. To match what the real vi does, we
  663. X         * effectively map 'cw' to 'ce', and 'cW' to 'cE', provided that we are
  664. X         * not on a space or a TAB. This seems
  665. X         * impolite at first, but it's really more what we mean when we say
  666. X         * 'cw'.
  667. X         */
  668. X        if (operator == CHANGE && (n = gcharCurpos()) != ' ' && n != TAB &&
  669. X                                                                n != NUL)
  670. X        {
  671. X            mincl = TRUE;
  672. X            flag = FALSE;
  673. X        }
  674. X
  675. Xdowrdcmd:
  676. X        mtype = MCHAR;
  677. X        set_want_col = TRUE;
  678. X        if (flag)
  679. X            n = fwd_word(Prenum1, type, operator != NOP);
  680. X        else
  681. X            n = end_word(Prenum1, type, operator == CHANGE);
  682. X        if (n)
  683. X        {
  684. X            CLEAROPBEEP;
  685. X            break;
  686. X        }
  687. X#if 0
  688. X        /*
  689. X         * If we do a 'dw' for the last word in a line, we only delete the rest
  690. X         * of the line, not joining the two lines, unless the current line is empty.
  691. X         */
  692. X        if (operator == DELETE && Prenum1 == 1 && startop.lnum != Curpos.lnum &&
  693. X            !lineempty(startop.lnum))
  694. X        {
  695. X                Curpos = startop;
  696. X                while (oneright())
  697. X                    ;
  698. X                mincl = TRUE;
  699. X        }
  700. X#endif
  701. X        break;
  702. X
  703. X      case '$':
  704. X        mtype = MCHAR;
  705. X        mincl = TRUE;
  706. X        Curswant = MAXCOL;                /* so we stay at the end */
  707. X        if (!onedown((long)(Prenum1 - 1)))
  708. X        {
  709. X            CLEAROPBEEP;
  710. X            break;
  711. X        }
  712. X        break;
  713. X
  714. X      case '^':
  715. X        flag = TRUE;
  716. X        /* FALLTHROUGH */
  717. X
  718. X      case '0':
  719. X        mtype = MCHAR;
  720. X        mincl = FALSE;
  721. X        beginline(flag);
  722. X        break;
  723. X
  724. X/*
  725. X * 4: Searches
  726. X */
  727. X      case '?':
  728. X      case '/':
  729. X        if (!getcmdline(c, (u_char *)searchbuff))
  730. X        {
  731. X            CLEAROP;
  732. X            break;
  733. X        }
  734. X        mtype = MCHAR;
  735. X        mincl = FALSE;
  736. X        set_want_col = TRUE;
  737. X
  738. X        n = dosearch(c, searchbuff, FALSE, Prenum1, TRUE);
  739. X        if (n == 0)
  740. X            CLEAROP;
  741. X        else if (n == 2)
  742. X            mtype = MLINE;
  743. X        break;
  744. X
  745. X      case 'N':
  746. X        flag = 1;
  747. X
  748. X      case 'n':
  749. X        mtype = MCHAR;
  750. X        mincl = FALSE;
  751. X        set_want_col = TRUE;
  752. X        if (!dosearch(0, NULL, flag, Prenum1, TRUE))
  753. X            CLEAROP;
  754. X        break;
  755. X
  756. X        /*
  757. X         * Character searches
  758. X         */
  759. X      case 'T':
  760. X        dir = BACKWARD;
  761. X        /* FALLTHROUGH */
  762. X
  763. X      case 't':
  764. X        type = 1;
  765. X        goto docsearch;
  766. X
  767. X      case 'F':
  768. X        dir = BACKWARD;
  769. X        /* FALLTHROUGH */
  770. X
  771. X      case 'f':
  772. Xdocsearch:
  773. X        mtype = MCHAR;
  774. X        mincl = TRUE;
  775. X        set_want_col = TRUE;
  776. X        if (!searchc(nchar, dir, type, Prenum1))
  777. X            CLEAROPBEEP;
  778. X        break;
  779. X
  780. X      case ',':
  781. X        flag = 1;
  782. X        /* FALLTHROUGH */
  783. X
  784. X      case ';':
  785. X        dir = flag;
  786. X        goto docsearch;        /* nchar == NUL, thus repeat previous search */
  787. X
  788. X        /*
  789. X         * section or C function searches
  790. X         */
  791. X
  792. X      case '[':
  793. X        dir = BACKWARD;
  794. X        /* FALLTHROUGH */
  795. X
  796. X      case ']':
  797. X        mtype = MLINE;
  798. X        set_want_col = TRUE;
  799. X        flag = '{';
  800. X        if (nchar != c)
  801. X        {
  802. X            if (nchar == '[' || nchar == ']')
  803. X                flag = '}';
  804. X            else
  805. X            {
  806. X                CLEAROPBEEP;
  807. X                break;
  808. X            }
  809. X        }
  810. X        if (dir == FORWARD && operator != NOP)    /* e.g. y]] searches for '}' */
  811. X            flag = '}';
  812. X        if (!findpar(dir, Prenum1, flag))
  813. X        {
  814. X            CLEAROPBEEP;
  815. X        }
  816. X        break;
  817. X
  818. X      case '%':
  819. X        mincl = TRUE;
  820. X        if (Prenum)        /* {cnt}% : goto {cnt} percentage in file */
  821. X        {
  822. X            if (Prenum > 100)
  823. X                CLEAROPBEEP;
  824. X            else
  825. X            {
  826. X                mtype = MLINE;
  827. X                setpcmark();
  828. X                        /* round up, so CTRL-G will give same value */
  829. X                Curpos.lnum = (line_count * Prenum + 99) / 100;
  830. X                Curpos.col = 0;
  831. X            }
  832. X        }
  833. X        else            /* % : go to matching paren */
  834. X        {
  835. X            mtype = MCHAR;
  836. X            if ((pos = showmatch()) == NULL)
  837. X                CLEAROPBEEP;
  838. X            else
  839. X            {
  840. X                setpcmark();
  841. X                Curpos = *pos;
  842. X                set_want_col = TRUE;
  843. X            }
  844. X        }
  845. X        break;
  846. X
  847. X      case '(':
  848. X        dir = BACKWARD;
  849. X        /* FALLTHROUGH */
  850. X
  851. X      case ')':
  852. X        mtype = MCHAR;
  853. X        if (c == ')')
  854. X            mincl = FALSE;
  855. X        else
  856. X            mincl = TRUE;
  857. X        set_want_col = TRUE;
  858. X
  859. X        if (!findsent(dir, Prenum1))
  860. X            CLEAROPBEEP;
  861. X        break;
  862. X
  863. X      case '{':
  864. X        dir = BACKWARD;
  865. X        /* FALLTHROUGH */
  866. X
  867. X      case '}':
  868. X        mtype = MCHAR;
  869. X        mincl = FALSE;
  870. X        set_want_col = TRUE;
  871. X        if (!findpar(dir, Prenum1, NUL))
  872. X            CLEAROPBEEP;
  873. X        break;
  874. X
  875. X/*
  876. X * 5: Edits
  877. X */
  878. X      case '.':
  879. X        CHECKCLEAROPQ;
  880. X        if (!start_redo(Prenum))
  881. X            CLEAROPBEEP;
  882. X        break;
  883. X
  884. X      case 'u':
  885. X        if (Visual.lnum)
  886. X            goto dooperator;
  887. X      case K_UNDO:
  888. X        CHECKCLEAROPQ;
  889. X        u_undo((int)Prenum1);
  890. X        set_want_col = TRUE;
  891. X        break;
  892. X
  893. X      case Ctrl('R'):
  894. X        CHECKCLEAROPQ;
  895. X          u_redo((int)Prenum1);
  896. X        set_want_col = TRUE;
  897. X        break;
  898. X
  899. X      case 'U':
  900. X        if (Visual.lnum)
  901. X            goto dooperator;
  902. X        CHECKCLEAROPQ;
  903. X        u_undoline();
  904. X        set_want_col = TRUE;
  905. X        break;
  906. X
  907. X      case 'r':
  908. X        if (Visual.lnum)
  909. X        {
  910. X            c = 'c';
  911. X            goto dooperator;
  912. X        }
  913. X        CHECKCLEAROPQ;
  914. X        ptr = nr2ptr(Curpos.lnum) + Curpos.col;
  915. X        if (strlen(ptr) < (unsigned)Prenum1)    /* not enough characters to replace */
  916. X        {
  917. X            CLEAROPBEEP;
  918. X            break;
  919. X        }
  920. X        /*
  921. X         * Replacing with a line break or tab is done by edit(), because it
  922. X         * is complicated.
  923. X         * Other characters are done below to avoid problems with things like
  924. X         * CTRL-V 048 (for edit() this would be R CTRL-V 0 ESC).
  925. X         */
  926. X        if (nchar == '\r' || nchar == '\n' || nchar == '\t')
  927. X        {
  928. X            prep_redo(Prenum1, 'r', nchar, NUL);
  929. X            stuffnumReadbuff(Prenum1);
  930. X            stuffcharReadbuff('R');
  931. X            stuffcharReadbuff(nchar);
  932. X            stuffcharReadbuff(ESC);
  933. X            break;
  934. X        }
  935. X
  936. X        if (nchar == Ctrl('V'))                /* get another character */
  937. X        {
  938. X            c = Ctrl('V');
  939. X            nchar = get_literal(&type);
  940. X            if (type)                        /* typeahead */
  941. X                stuffcharReadbuff(type);
  942. X        }
  943. X        else
  944. X            c = NUL;
  945. X        prep_redo(Prenum1, 'r', c, nchar);
  946. X        if (!u_saveCurpos())                /* save line for undo */
  947. X            break;
  948. X        Curpos.col += Prenum1 - 1;
  949. X        while (Prenum1--)                    /* replace the characters */
  950. X            *ptr++ = nchar;
  951. X        set_want_col = TRUE;
  952. X        CHANGED;
  953. X        updateline();
  954. X        break;
  955. X
  956. X      case 'J':
  957. X        if (Visual.lnum)        /* join the visual lines */
  958. X        {
  959. X            if (Curpos.lnum > Visual.lnum)
  960. X            {
  961. X                Prenum = Curpos.lnum - Visual.lnum + 1;
  962. X                Curpos.lnum = Visual.lnum;
  963. X            }
  964. X            else
  965. X                Prenum = Visual.lnum - Curpos.lnum + 1;
  966. X            Visual.lnum = 0;
  967. X        }
  968. X        CHECKCLEAROP;
  969. X        if (Prenum <= 1)
  970. X            Prenum = 2;             /* default for join is two lines! */
  971. X        if (Curpos.lnum + Prenum - 1 > line_count)    /* beyond last line */
  972. X        {
  973. X            CLEAROPBEEP;
  974. X            break;
  975. X        }
  976. X
  977. X        prep_redo(Prenum, 'J', NUL, NUL);
  978. X        dodojoin(Prenum, TRUE, TRUE);
  979. X        break;
  980. X
  981. X      case 'P':
  982. X        dir = BACKWARD;
  983. X        /* FALLTHROUGH */
  984. X
  985. X      case 'p':
  986. X        CHECKCLEAROPQ;
  987. X        prep_redo(Prenum, c, NUL, NUL);
  988. X        doput(dir, Prenum1);
  989. X        break;
  990. X
  991. X      case Ctrl('A'):            /* add to number */
  992. X      case Ctrl('S'):            /* subtract from number */
  993. X        CHECKCLEAROPQ;
  994. X        if (doaddsub((int)c, Prenum1))
  995. X            prep_redo(Prenum1, c, NUL, NUL);
  996. X        break;
  997. X
  998. X/*
  999. X * 6: Inserts
  1000. X */
  1001. X      case 'A':
  1002. X        set_want_col = TRUE;
  1003. X        while (oneright())
  1004. X                ;
  1005. X        /* FALLTHROUGH */
  1006. X
  1007. X      case 'a':
  1008. X        CHECKCLEAROPQ;
  1009. X        /* Works just like an 'i'nsert on the next character. */
  1010. X        if (u_saveCurpos())
  1011. X        {
  1012. X            if (!lineempty(Curpos.lnum))
  1013. X                incCurpos();
  1014. X            startinsert(c, FALSE, Prenum1);
  1015. X            command_busy = TRUE;
  1016. X        }
  1017. X        break;
  1018. X
  1019. X      case 'I':
  1020. X        beginline(TRUE);
  1021. X        /* FALLTHROUGH */
  1022. X
  1023. X      case 'i':
  1024. X        CHECKCLEAROPQ;
  1025. X        if (u_saveCurpos())
  1026. X        {
  1027. X            startinsert(c, FALSE, Prenum1);
  1028. X            command_busy = TRUE;
  1029. X        }
  1030. X        break;
  1031. X
  1032. X      case 'o':
  1033. X          if (Visual.lnum)    /* switch start and end of visual */
  1034. X        {
  1035. X            Prenum = Visual.lnum;
  1036. X            Visual.lnum = Curpos.lnum;
  1037. X            Curpos.lnum = Prenum;
  1038. X            if (Visual.col != VISUALLINE)
  1039. X            {
  1040. X                n = Visual.col;
  1041. X                Visual.col = Curpos.col;
  1042. X                Curpos.col = (int)n;
  1043. X                set_want_col = TRUE;
  1044. X            }
  1045. X            break;
  1046. X        }
  1047. X        CHECKCLEAROP;
  1048. X        if (u_save(Curpos.lnum, (linenr_t)(Curpos.lnum + 1)) && Opencmd(FORWARD, TRUE, TRUE))
  1049. X        {
  1050. X            startinsert('o', TRUE, Prenum1);
  1051. X            command_busy = TRUE;
  1052. X        }
  1053. X        break;
  1054. X
  1055. X      case 'O':
  1056. X        CHECKCLEAROPQ;
  1057. X        if (u_save((linenr_t)(Curpos.lnum - 1), Curpos.lnum) && Opencmd(BACKWARD, TRUE, TRUE))
  1058. X        {
  1059. X            startinsert('O', TRUE, Prenum1);
  1060. X            command_busy = TRUE;
  1061. X        }
  1062. X        break;
  1063. X
  1064. X      case 'R':
  1065. X        if (Visual.lnum)
  1066. X        {
  1067. X            c = 'c';
  1068. X            Visual.col = VISUALLINE;
  1069. X            goto dooperator;
  1070. X        }
  1071. X        CHECKCLEAROPQ;
  1072. X        if (u_saveCurpos())
  1073. X        {
  1074. X            startinsert('R', FALSE, Prenum1);
  1075. X            command_busy = TRUE;
  1076. X        }
  1077. X        break;
  1078. X
  1079. X/*
  1080. X * 7: Operators
  1081. X */
  1082. X      case '~':         /* swap case */
  1083. X      /*
  1084. X       * if tilde is not an operator and Visual is off: swap case
  1085. X       * of a single character
  1086. X       */
  1087. X        if (!p_to && !Visual.lnum)
  1088. X        {
  1089. X            CHECKCLEAROPQ;
  1090. X            if (lineempty(Curpos.lnum))
  1091. X            {
  1092. X                CLEAROPBEEP;
  1093. X                break;
  1094. X            }
  1095. X            prep_redo(Prenum, '~', NUL, NUL);
  1096. X
  1097. X            if (!u_saveCurpos())
  1098. X                break;
  1099. X
  1100. X            for (; Prenum1 > 0; --Prenum1)
  1101. X            {
  1102. X                if (gcharCurpos() == NUL)
  1103. X                    break;
  1104. X                swapchar(&Curpos);
  1105. X                incCurpos();
  1106. X            }
  1107. X
  1108. X            set_want_col = TRUE;
  1109. X            CHANGED;
  1110. X            updateline();
  1111. X            break;
  1112. X        }
  1113. X        /*FALLTHROUGH*/
  1114. X
  1115. X      case 'd':
  1116. X      case 'c':
  1117. X      case 'y':
  1118. X      case '>':
  1119. X      case '<':
  1120. X      case '!':
  1121. X      case '=':
  1122. X      case 'Q':
  1123. Xdooperator:
  1124. X        n = strchr(opchars, c) - opchars + 1;
  1125. X        if (n == operator)        /* double operator works on lines */
  1126. X            goto lineop;
  1127. X        CHECKCLEAROP;
  1128. X        if (Prenum != 0)
  1129. X            opnum = Prenum;
  1130. X        startop = Curpos;
  1131. X        operator = (int)n;
  1132. X        break;
  1133. X
  1134. X/*
  1135. X * 8: Abbreviations
  1136. X */
  1137. X
  1138. X     /* when Visual the next commands are operators */
  1139. X      case 'S':
  1140. X      case 'Y':
  1141. X      case 'D':
  1142. X      case 'C':
  1143. X      case 'x':
  1144. X      case 'X':
  1145. X      case 's':
  1146. X          if (Visual.lnum)
  1147. X        {
  1148. X            static char trans[] = "ScYyDdCcxdXdsc";
  1149. X
  1150. X            if (isupper(c) && !Visual_block)        /* uppercase means linewise */
  1151. X                Visual.col = VISUALLINE;
  1152. X            c = *(strchr(trans, c) + 1);
  1153. X            goto dooperator;
  1154. X        }
  1155. X
  1156. X      case '&':
  1157. X        CHECKCLEAROPQ;
  1158. X        if (Prenum)
  1159. X            stuffnumReadbuff(Prenum);
  1160. X
  1161. X        if (c == 'Y' && p_ye)
  1162. X            c = 'Z';
  1163. X        {
  1164. X                static char *(ar[9]) = {"dl", "dh", "d$", "c$", "cl", "cc", "yy", "y$", ":s\r"};
  1165. X                static char *str = "xXDCsSYZ&";
  1166. X
  1167. X                stuffReadbuff(ar[(int)(strchr(str, c) - str)]);
  1168. X        }
  1169. X        break;
  1170. X
  1171. X/*
  1172. X * 9: Marks
  1173. X */
  1174. X
  1175. X      case 'm':
  1176. X        CHECKCLEAROP;
  1177. X        if (!setmark(nchar))
  1178. X            CLEAROPBEEP;
  1179. X        break;
  1180. X
  1181. X      case '\'':
  1182. X        flag = TRUE;
  1183. X        /* FALLTHROUGH */
  1184. X
  1185. X      case '`':
  1186. X        pos = getmark(nchar, (operator == NOP));
  1187. X        if (pos == (FPOS *)-1)    /* jumped to other file */
  1188. X        {
  1189. X            if (flag)
  1190. X                beginline(TRUE);
  1191. X            break;
  1192. X        }
  1193. X
  1194. X        if (pos != NULL)
  1195. X            setpcmark();
  1196. X
  1197. Xcursormark:
  1198. X        if (pos == NULL)
  1199. X            CLEAROPBEEP;
  1200. X        else
  1201. X        {
  1202. X            Curpos = *pos;
  1203. X            if (flag)
  1204. X                beginline(TRUE);
  1205. X        }
  1206. X        mtype = flag ? MLINE : MCHAR;
  1207. X        mincl = FALSE;        /* ignored if not MCHAR */
  1208. X        set_want_col = TRUE;
  1209. X        break;
  1210. X
  1211. X    case Ctrl('O'):            /* goto older pcmark */
  1212. X        Prenum1 = -Prenum1;
  1213. X        /* FALLTHROUGH */
  1214. X
  1215. X    case Ctrl('I'):            /* goto newer pcmark */
  1216. X        CHECKCLEAROPQ;
  1217. X        pos = movemark((int)Prenum1);
  1218. X        if (pos == (FPOS *)-1)    /* jump to other file */
  1219. X        {
  1220. X            set_want_col = TRUE;
  1221. X            break;
  1222. X        }
  1223. X        goto cursormark;
  1224. X
  1225. X/*
  1226. X * 10. Buffer setting
  1227. X */
  1228. X      case '"':
  1229. X        CHECKCLEAROP;
  1230. X        if (isalnum(nchar) || nchar == '.' || nchar == '%' || nchar == '"')
  1231. X        {
  1232. X            yankbuffer = nchar;
  1233. X            opnum = Prenum;        /* remember count before '"' */
  1234. X        }
  1235. X        else
  1236. X            CLEAROPBEEP;
  1237. X        break;
  1238. X
  1239. X/*
  1240. X * 11. Visual
  1241. X */
  1242. X       case 'v':
  1243. X      case 'V':
  1244. X      case Ctrl('V'):
  1245. X        CHECKCLEAROP;
  1246. X        Visual_block = FALSE;
  1247. X
  1248. X            /* stop Visual */
  1249. X        if (Visual.lnum)
  1250. X        {
  1251. X            Visual.lnum = 0;
  1252. X            updateScreen(NOT_VALID);        /* delete the inversion */
  1253. X        }
  1254. X            /* start Visual */
  1255. X        else
  1256. X        {
  1257. X            if (!didwarn && (T_TI == NULL || *T_TI == NUL))    /* cannot invert */
  1258. X            {
  1259. X                emsg("Warning: terminal cannot invert");
  1260. X                didwarn = TRUE;
  1261. X            }
  1262. X            if (Prenum)                        /* use previously selected part */
  1263. X            {
  1264. X                if (!resel_Visual_type)        /* there is none */
  1265. X                {
  1266. X                    beep();
  1267. X                    break;
  1268. X                }
  1269. X                Visual = Curpos;
  1270. X                if (resel_Visual_nlines > 1)
  1271. X                    Curpos.lnum += resel_Visual_nlines * Prenum - 1;
  1272. X                switch (resel_Visual_type)
  1273. X                {
  1274. X                case 'V':    Visual.col = VISUALLINE;
  1275. X                            break;
  1276. X
  1277. X                case Ctrl('V'):
  1278. X                            Visual_block = TRUE;
  1279. X                            break;
  1280. X
  1281. X                case 'v':        
  1282. X                            if (resel_Visual_nlines <= 1)
  1283. X                                Curpos.col += resel_Visual_col * Prenum - 1;
  1284. X                            else
  1285. X                                Curpos.col = resel_Visual_col;
  1286. X                            break;
  1287. X                }
  1288. X                if (resel_Visual_col == MAXCOL)
  1289. X                {
  1290. X                    Curswant = MAXCOL;
  1291. X                    coladvance(MAXCOL);
  1292. X                }
  1293. X                else if (Visual_block)
  1294. X                    coladvance((colnr_t)(Cursvcol + resel_Visual_col * Prenum - 1));
  1295. X                updateScreen(NOT_VALID);    /* show the inversion */
  1296. X            }
  1297. X            else
  1298. X            {
  1299. X                Visual = Curpos;
  1300. X                if (c == 'V')                /* linewise */
  1301. X                    Visual.col = VISUALLINE;
  1302. X                else if (c == Ctrl('V'))    /* blockwise */
  1303. X                    Visual_block = TRUE;
  1304. X                updateline();                /* start the inversion */
  1305. X            }
  1306. X        }
  1307. X        break;
  1308. X
  1309. X/*
  1310. X * 12. Suspend
  1311. X */
  1312. X
  1313. X     case Ctrl('Z'):
  1314. X        CLEAROP;
  1315. X        Visual.lnum = 0;                    /* stop Visual */
  1316. X        stuffReadbuff(":st\r");                /* with autowrite */
  1317. X        break;
  1318. X
  1319. X/*
  1320. X * The end
  1321. X */
  1322. X      case ESC:
  1323. X        if (Visual.lnum)
  1324. X        {
  1325. X            Visual.lnum = 0;            /* stop Visual */
  1326. X            updateScreen(NOT_VALID);
  1327. X        }
  1328. X
  1329. X      default:                    /* not a known command */
  1330. X        CLEAROPBEEP;
  1331. X        break;
  1332. X
  1333. X    }    /* end of switch on command character */
  1334. X
  1335. X/*
  1336. X * if we didn't start or finish an operator, reset yankbuffer, unless we
  1337. X * need it later.
  1338. X */
  1339. X    if (!finish_op && !operator && strchr("\"DCYSsXx", c) == NULL)
  1340. X        yankbuffer = 0;
  1341. X
  1342. X    /*
  1343. X     * If an operation is pending, handle it...
  1344. X     */
  1345. X    if ((Visual.lnum || finish_op) && operator != NOP)
  1346. X    {
  1347. X        if (operator != YANK && !Visual.lnum)        /* can't redo yank */
  1348. X        {
  1349. X                prep_redo(Prenum, opchars[operator - 1], c, nchar);
  1350. X                if (c == '/' || c == '?')        /* was a search */
  1351. X                {
  1352. X                        AppendToRedobuff(searchbuff);
  1353. X                        AppendToRedobuff(NL_STR);
  1354. X                }
  1355. X        }
  1356. X
  1357. X        if (redo_Visual_busy)
  1358. X        {
  1359. X            startop = Curpos;
  1360. X            Curpos.lnum += redo_Visual_nlines - 1;
  1361. X            switch (redo_Visual_type)
  1362. X            {
  1363. X            case 'V':    Visual.col = VISUALLINE;
  1364. X                        break;
  1365. X
  1366. X            case Ctrl('V'):
  1367. X                        Visual_block = TRUE;
  1368. X                        break;
  1369. X
  1370. X            case 'v':        
  1371. X                        if (redo_Visual_nlines <= 1)
  1372. X                            Curpos.col += redo_Visual_col - 1;
  1373. X                        else
  1374. X                            Curpos.col = redo_Visual_col;
  1375. X                        break;
  1376. X            }
  1377. X            if (redo_Visual_col == MAXCOL)
  1378. X            {
  1379. X                Curswant = MAXCOL;
  1380. X                coladvance(MAXCOL);
  1381. X            }
  1382. X        }
  1383. X        else if (Visual.lnum)
  1384. X            startop = Visual;
  1385. X
  1386. X        if (lt(startop, Curpos))
  1387. X        {
  1388. X            endop = Curpos;
  1389. X            Curpos = startop;
  1390. X        }
  1391. X        else
  1392. X        {
  1393. X            endop = startop;
  1394. X            startop = Curpos;
  1395. X        }
  1396. X        nlines = endop.lnum - startop.lnum + 1;
  1397. X
  1398. X        if (Visual.lnum || redo_Visual_busy)
  1399. X        {
  1400. X            if (Visual_block)                /* block mode */
  1401. X            {
  1402. X                startvcol = getvcol(&startop, 2);
  1403. X                n = getvcol(&endop, 2);
  1404. X                if (n < startvcol)
  1405. X                    startvcol = (colnr_t)n;
  1406. X
  1407. X            /* if '$' was used, get endvcol from longest line */
  1408. X                if (Curswant == MAXCOL)
  1409. X                {
  1410. X                    Curpos.col = MAXCOL;
  1411. X                    endvcol = 0;
  1412. X                    for (Curpos.lnum = startop.lnum; Curpos.lnum <= endop.lnum; ++Curpos.lnum)
  1413. X                        if ((n = getvcol(&Curpos, 3)) > endvcol)
  1414. X                            endvcol = (colnr_t)n;
  1415. X                    Curpos = startop;
  1416. X                }
  1417. X                else if (redo_Visual_busy)
  1418. X                    endvcol = startvcol + redo_Visual_col - 1;
  1419. X                else
  1420. X                {
  1421. X                    endvcol = getvcol(&startop, 3);
  1422. X                    n = getvcol(&endop, 3);
  1423. X                    if (n > endvcol)
  1424. X                        endvcol = (colnr_t)n;
  1425. X                }
  1426. X                coladvance(startvcol);
  1427. X            }
  1428. X
  1429. X    /*
  1430. X     * prepare to reselect and redo Visual: this is based on the size
  1431. X     * of the Visual text
  1432. X     */
  1433. X            if (Visual_block)
  1434. X                resel_Visual_type = Ctrl('V');
  1435. X            else if (Visual.col == VISUALLINE)
  1436. X                resel_Visual_type = 'V';
  1437. X            else
  1438. X                resel_Visual_type = 'v';
  1439. X            if (Curswant == MAXCOL)
  1440. X                resel_Visual_col = MAXCOL;
  1441. X            else if (Visual_block)
  1442. X                resel_Visual_col = endvcol - startvcol + 1;
  1443. X            else if (nlines > 1)
  1444. X                resel_Visual_col = endop.col;
  1445. X            else
  1446. X                resel_Visual_col = endop.col - startop.col + 1;
  1447. X            resel_Visual_nlines = nlines;
  1448. X            if (operator != YANK && operator != COLON)    /* can't redo yank and : */
  1449. X            {
  1450. X                prep_redo(0L, 'v', opchars[operator - 1], NUL);
  1451. X                redo_Visual_type = resel_Visual_type;
  1452. X                redo_Visual_col = resel_Visual_col;
  1453. X                redo_Visual_nlines = resel_Visual_nlines;
  1454. X            }
  1455. X
  1456. X            mincl = TRUE;
  1457. X            if (Visual.col == VISUALLINE)
  1458. X                mtype = MLINE;
  1459. X            else
  1460. X                mtype = MCHAR;
  1461. X
  1462. X            redo_Visual_busy = FALSE;
  1463. X            /*
  1464. X             * Switch Visual off now, so screen updating does
  1465. X             * not show inverted text when the screen is redrawn.
  1466. X             * With YANK and sometimes with COLON and FILTER there is no screen
  1467. X             * redraw, so it is done here to remove the inverted part.
  1468. X             */
  1469. X            Visual.lnum = 0;
  1470. X            if (operator == YANK || operator == COLON || operator == FILTER)
  1471. X                updateScreen(NOT_VALID);
  1472. X        }
  1473. X
  1474. X        set_want_col = 1;
  1475. X
  1476. X            /* no_op is set when start and end are the same */
  1477. X        no_op = (mtype == MCHAR && !mincl && equal(startop, endop));
  1478. X
  1479. X    /*
  1480. X     * If the end of an operator is in column one while mtype is MCHAR and mincl
  1481. X     * is FALSE, we put endop after the last character in the previous line.
  1482. X     * If startop is on or before the first non-blank in the line, the operator
  1483. X     * becomes linewise (strange, but that's the way vi does it).
  1484. X     */
  1485. X        if (mtype == MCHAR && mincl == FALSE && endop.col == 0 && nlines > 1)
  1486. X        {
  1487. X            --nlines;
  1488. X            --endop.lnum;
  1489. X            if (startinmargin())
  1490. X                mtype = MLINE;
  1491. X            else
  1492. X            {
  1493. X                endop.col = strlen(nr2ptr(endop.lnum));
  1494. X                if (endop.col)
  1495. X                {
  1496. X                    --endop.col;
  1497. X                    mincl = TRUE;
  1498. X                }
  1499. X            }
  1500. X        }
  1501. X        switch (operator)
  1502. X        {
  1503. X          case LSHIFT:
  1504. X          case RSHIFT:
  1505. X            doshift(operator);
  1506. X            break;
  1507. X
  1508. X          case DELETE:
  1509. X            if (!no_op)
  1510. X                dodelete();
  1511. X            break;
  1512. X
  1513. X          case YANK:
  1514. X            if (!no_op)
  1515. X                doyank(FALSE);
  1516. X            break;
  1517. X
  1518. X          case CHANGE:
  1519. X            dochange();
  1520. X            command_busy = TRUE;
  1521. X            break;
  1522. X
  1523. X          case FILTER:
  1524. X            bangredo = TRUE;            /* dobang() will put cmd in redo buffer */
  1525. X
  1526. X          case INDENT:
  1527. X          case COLON:
  1528. Xdofilter:
  1529. X            sprintf(IObuff, ":%ld,%ld", (long)startop.lnum, (long)endop.lnum);
  1530. X            stuffReadbuff(IObuff);
  1531. X            if (operator != COLON)
  1532. X                stuffReadbuff("!");
  1533. X            if (operator == INDENT)
  1534. X            {
  1535. X                stuffReadbuff(p_ep);
  1536. X                stuffReadbuff("\n");
  1537. X            }
  1538. X            else if (operator == FORMAT)
  1539. X            {
  1540. X                stuffReadbuff(p_fp);
  1541. X                stuffReadbuff("\n");
  1542. X            }
  1543. X                /*    docmdline() does the rest */
  1544. X            break;
  1545. X
  1546. X          case TILDE:
  1547. X          case UPPER:
  1548. X          case LOWER:
  1549. X            if (!no_op)
  1550. X                dotilde();
  1551. X            break;
  1552. X
  1553. X          case FORMAT:
  1554. X            if (*p_fp != NUL)
  1555. X                goto dofilter;        /* use external command */
  1556. X            doformat();                /* use internal function */
  1557. X            break;
  1558. X
  1559. X          default:
  1560. X            CLEAROPBEEP;
  1561. X        }
  1562. X        operator = NOP;
  1563. X        Visual_block = FALSE;
  1564. X        yankbuffer = 0;
  1565. X    }
  1566. X
  1567. Xnormal_end:
  1568. X    premsg(-1, NUL);
  1569. X    if (restart_edit && operator == NOP && Visual.lnum == 0 && !command_busy && stuff_empty() && yankbuffer == 0)
  1570. X        startinsert(restart_edit, FALSE, 1L);
  1571. X}
  1572. X
  1573. X    static void
  1574. Xprep_redo(num, cmd, c, nchar)
  1575. X    long     num;
  1576. X    int        cmd;
  1577. X    int        c;
  1578. X    int        nchar;
  1579. X{
  1580. X    ResetRedobuff();
  1581. X    if (yankbuffer != 0)    /* yank from specified buffer */
  1582. X    {
  1583. X        AppendCharToRedobuff('\"');
  1584. X        AppendCharToRedobuff(yankbuffer);
  1585. X    }
  1586. X    if (num)
  1587. X        AppendNumberToRedobuff(num);
  1588. X    AppendCharToRedobuff(cmd);
  1589. X    if (c != NUL)
  1590. X        AppendCharToRedobuff(c);
  1591. X    if (nchar != NUL)
  1592. X        AppendCharToRedobuff(nchar);
  1593. X}
  1594. X
  1595. X/*
  1596. X * check for operator active
  1597. X */
  1598. X    static int
  1599. Xcheckclearop()
  1600. X{
  1601. X    if (operator == NOP)
  1602. X        return (FALSE);
  1603. X    clearopbeep();
  1604. X    return (TRUE);
  1605. X}
  1606. X
  1607. X/*
  1608. X * check for operator or Visual active
  1609. X */
  1610. X    static int
  1611. Xcheckclearopq()
  1612. X{
  1613. X    if (operator == NOP && Visual.lnum == 0)
  1614. X        return (FALSE);
  1615. X    clearopbeep();
  1616. X    return (TRUE);
  1617. X}
  1618. X
  1619. X    static void
  1620. Xclearopbeep()
  1621. X{
  1622. X    CLEAROP;
  1623. X    beep();
  1624. X}
  1625. X
  1626. X/*
  1627. X * display, on the last line of the window, the characters typed before
  1628. X * the last command character, plus 'c1' and 'c2'
  1629. X */
  1630. X    static void
  1631. Xpremsg(c1, c2)
  1632. X    int c1, c2;
  1633. X{
  1634. X    char    buf[40];
  1635. X    char    *p;
  1636. X
  1637. X    if (!p_sc || !(KeyTyped || c1 == -1 || c1 == ' '))
  1638. X        return;
  1639. X
  1640. X    cursor_off();
  1641. X    windgoto((int)Rows - 1, sc_col);
  1642. X    if (c1 == -1)
  1643. X        outstrn("          ");    /* look in comp_col() for the number of spaces */
  1644. X    else
  1645. X    {
  1646. X        p = buf;
  1647. X        if (opnum)
  1648. X        {
  1649. X            sprintf(p, "%ld", (long)opnum);
  1650. X            p = p + strlen(buf);
  1651. X        }
  1652. X        if (yankbuffer)
  1653. X        {
  1654. X            *p++ = '"';
  1655. X            *p++ = yankbuffer;
  1656. X        }
  1657. X        if (operator == 'z')
  1658. X            *p++ = 'z';
  1659. X        else if (operator)
  1660. X            *p++ = opchars[operator - 1];
  1661. X        if (Prenum)
  1662. X        {
  1663. X            sprintf(p, "%ld", (long)Prenum);
  1664. X            p = p + strlen(p);
  1665. X        }
  1666. X        *p = NUL;
  1667. X        if (c1)
  1668. X            strcpy(p, transchar(c1));
  1669. X        if (c2)
  1670. X            strcat(p, transchar(c2));
  1671. X        buf[10] = NUL;            /* truncate at maximal length */
  1672. X        outstrn(buf);
  1673. X    }
  1674. X    setcursor();
  1675. X    cursor_on();
  1676. X}
  1677. END_OF_FILE
  1678. if test 32142 -ne `wc -c <'vim/src/normal.c'`; then
  1679.     echo shar: \"'vim/src/normal.c'\" unpacked with wrong size!
  1680. fi
  1681. chmod +x 'vim/src/normal.c'
  1682. # end of 'vim/src/normal.c'
  1683. fi
  1684. echo shar: End of archive 16 \(of 25\).
  1685. cp /dev/null ark16isdone
  1686. MISSING=""
  1687. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 ; do
  1688.     if test ! -f ark${I}isdone ; then
  1689.     MISSING="${MISSING} ${I}"
  1690.     fi
  1691. done
  1692. if test "${MISSING}" = "" ; then
  1693.     echo You have unpacked all 25 archives.
  1694.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1695. else
  1696.     echo You still need to unpack the following archives:
  1697.     echo "        " ${MISSING}
  1698. fi
  1699. ##  End of shell archive.
  1700. exit 0
  1701.  
  1702. ===============================================================================
  1703. Bram Moolenaar                             | DISCLAIMER:  This  note  does  not
  1704. Oce Nederland B.V., Research & Development | necessarily represent the position
  1705. p.o. box 101, 5900 MA  Venlo               | of  Oce-Nederland  B.V.  Therefore
  1706. The Netherlands        phone +31 77 594077 | no liability or responsibility for
  1707. UUCP: mool@oce.nl        fax +31 77 595473 | whatever will be accepted.
  1708.  
  1709. exit 0 # Just in case...
  1710.