home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume37 / vim / part15 < prev    next >
Encoding:
Text File  |  1993-04-23  |  32.3 KB  |  1,622 lines

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