home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume44 / vim / part10 < prev    next >
Internet Message Format  |  1994-08-16  |  71KB

  1. From: mool@oce.nl (Bram Moolenaar)
  2. Newsgroups: comp.sources.misc
  3. Subject: v44i029:  vim - Vi IMproved editor, v3.0, Part10/26
  4. Date: 16 Aug 1994 21:18:14 -0500
  5. Organization: Sterling Software
  6. Sender: kent@sparky.sterling.com
  7. Approved: kent@sparky.sterling.com
  8. Message-ID: <32rs16$ke4@sparky.sterling.com>
  9. X-Md4-Signature: 645cc39459ac34c1a4813dce9d1e3c86
  10.  
  11. Submitted-by: mool@oce.nl (Bram Moolenaar)
  12. Posting-number: Volume 44, Issue 29
  13. Archive-name: vim/part10
  14. Environment: UNIX, AMIGA, MS-DOS, Windows NT
  15. Supersedes: vim: Volume 41, Issue 50-75
  16.  
  17. #! /bin/sh
  18. # This is a shell archive.  Remove anything before this line, then feed it
  19. # into a shell via "sh file" or similar.  To overwrite existing files,
  20. # type "sh file -c".
  21. # Contents:  vim/doc/digraph.doc.UU vim/src/misccmds.c vim/src/normal.c
  22. # Wrapped by kent@sparky on Mon Aug 15 21:44:04 1994
  23. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
  24. echo If this archive is complete, you will see the following message:
  25. echo '          "shar: End of archive 10 (of 26)."'
  26. if test -f 'vim/doc/digraph.doc.UU' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'vim/doc/digraph.doc.UU'\"
  28. else
  29.   echo shar: Extracting \"'vim/doc/digraph.doc.UU'\" \(3112 characters\)
  30.   sed "s/^X//" >'vim/doc/digraph.doc.UU' <<'END_OF_FILE'
  31. Xbegin 644 vim/doc/digraph.doc
  32. XM5&AE<V4@87)E('1H92!D969A=6QT(&1I9W)A<&@@8VAA<F%C=&5R<R!F;W(@
  33. XM5FEM+@H*0F5S:61E<R!T:&4@9&EG<F%P:',@;&ES=&5D(&)E;&]W+"!M971A
  34. XM(&-H87)A8W1E<G,@8V%N(&)E(&5N=&5R960@=VET:"!#5%),+4L*/%-004-%
  35. XM/B![8VAA<GTN($]N;'D@15-#(&-A;FYO="!B92!U<V5D(&9O<B![8VAA<GTN
  36. XM(%5S92!#5%),+58@,34U(&9O<B!T:&ES+@H*5&AE(&9I<G-T('1W;R!C:&%R
  37. XM86-T97)S(&EN(&5A8V@@8V]L=6UN(&%R92!T:&4@8VAA<F%C=&5R<R!Y;W4@
  38. XM:&%V92!T;R!T>7!E('1O"F5N=&5R(&$@9&EG<F%P:"X*"DEN('1H92!M:61D
  39. XM;&4@;V8@96%C:"!C;VQU;6X@:7,@=&AE(')E<W5L=&EN9R!C:&%R86-T97(N
  40. XM(%1H:7,@;6%Y(&)E(&UA;F=L960*:68@>6]U(&QO;VL@870@=&AI<R!F:6QE
  41. XM(&]N('-O;65T:&EN9R!E;'-E('1H86X@=&AE('-Y<W1E;2!T:&%T('1H97D@
  42. XM=V5R90IM96%N="!F;W(@;W(@=VAE;B!Y;W4@<')I;G0@:70N"@I4:&4@9&5C
  43. XM:6UA;"!N=6UB97(@:7,@=&AE($%30TE)(&-O9&4@9F]R('1H92!C:&%R86-T
  44. XM97(N"@I$969A=6QT(&1I9W)A<&AS(&]N('1H92!!;6EG83H*?B$@H2 Q-C$@
  45. XM("!C?""B(#$V,B @("0D(*,@,38S(" @;W@@I" Q-C0@("!9+2"E(#$V-2 @
  46. XM('Q\(*8@,38V(" @<&$@IR Q-C<*(B(@J" Q-C@@("!C3R"I(#$V.2 @(&$M
  47. XM(*H@,3<P(" @/#P@JR Q-S$@(" M+2"M(#$W,R @(')/(*X@,3<T(" @+3T@
  48. XMKR Q-S4*?F\@L" Q-S8@(" K+2"Q(#$W-R @(#(R(+(@,3<X(" @,S,@LR Q
  49. XM-SD@(" G)R"T(#$X," @(&IU(+4@,3@Q(" @<' @MB Q.#(*?BX@MR Q.#,@
  50. XM(" L+""X(#$X-" @(#$Q(+D@,3@U(" @;RT@NB Q.#8@(" ^/B"[(#$X-R @
  51. XM(#$T(+P@,3@X(" @,3(@O2 Q.#D*,S0@OB Q.3 @("!^/R"_(#$Y,2 @($%@
  52. XM(, @,3DR(" @02<@P2 Q.3,@("!!7B#"(#$Y-" @($%^(,,@,3DU(" @02(@
  53. XMQ" Q.38*04 @Q2 Q.3<@("!!12#&(#$Y." @($,L(,<@,3DY(" @16 @R" R
  54. XM,# @("!%)R#)(#(P,2 @($5>(,H@,C R(" @12(@RR R,#,*26 @S" R,#0@
  55. XM("!))R#-(#(P-2 @($E>(,X@,C V(" @22(@SR R,#<@(" M1"#0(#(P." @
  56. XM($Y^(-$@,C Y(" @3V @TB R,3 *3R<@TR R,3$@("!/7B#4(#(Q,B @($]^
  57. XM(-4@,C$S(" @3R(@UB R,30@(" O7"#7(#(Q-2 @($\O(-@@,C$V(" @56 @
  58. XMV2 R,3<*52<@VB R,3@@("!57B#;(#(Q.2 @(%4B(-P@,C(P(" @62<@W2 R
  59. XM,C$@("!)<"#>(#(R,B @('-S(-\@,C(S(" @86 @X" R,C0*82<@X2 R,C4@
  60. XM("!A7B#B(#(R-B @(&%^(.,@,C(W(" @82(@Y" R,C@@("!A0"#E(#(R.2 @
  61. XM(&%E(.8@,C,P(" @8RP@YR R,S$*96 @Z" R,S(@("!E)R#I(#(S,R @(&5>
  62. XM(.H@,C,T(" @92(@ZR R,S4@("!I8"#L(#(S-B @(&DG(.T@,C,W(" @:5X@
  63. XM[B R,S@*:2(@[R R,SD@(" M9"#P(#(T," @(&Y^(/$@,C0Q(" @;V @\B R
  64. XM-#(@("!O)R#S(#(T,R @(&]>(/0@,C0T(" @;WX@]2 R-#4*;R(@]B R-#8@
  65. XM(" Z+2#W(#(T-R @(&\O(/@@,C0X(" @=6 @^2 R-#D@("!U)R#Z(#(U," @
  66. XM('5>(/L@,C4Q(" @=2(@_" R-3(*>2<@_2 R-3,@("!I<"#^(#(U-" @('DB
  67. XM(/\@,C4U"@I$969A=6QT(&1I9W)A<&AS(&]N($U31$]3.@I#+"" (#$R." @
  68. XM('4B(($@,3(Y(" @92<@@B Q,S @("!A7B"#(#$S,2 @(&$B((0@,3,R(" @
  69. XM86 @A2 Q,S,@("!A0""&(#$S- IC+""'(#$S-2 @(&5>((@@,3,V(" @92(@
  70. XMB2 Q,S<@("!E8""*(#$S." @(&DB((L@,3,Y(" @:5X@C" Q-# @("!I8""-
  71. XM(#$T,0I!(B".(#$T,B @($% ((\@,30S(" @12<@D" Q-#0@("!A92"1(#$T
  72. XM-2 @($%%()(@,30V(" @;UX@DR Q-#<@("!O(B"4(#$T. IO8""5(#$T.2 @
  73. XM('5>()8@,34P(" @=6 @ER Q-3$@("!Y(B"8(#$U,B @($\B()D@,34S(" @
  74. XM52(@FB Q-30@("!C?"";(#$U-0HD)""<(#$U-B @(%DM()T@,34W(" @4'0@
  75. XMGB Q-3@@("!F9B"?(#$U.2 @(&$G(* @,38P(" @:2<@H2 Q-C$@("!O)R"B
  76. XM(#$V,@IU)R"C(#$V,R @(&Y^(*0@,38T(" @3GX@I2 Q-C4@("!A82"F(#$V
  77. XM-B @(&]O(*<@,38W(" @?C\@J" Q-C@@(" M82"I(#$V.0IA+2"J(#$W," @
  78. XM(#$R(*L@,3<Q(" @,30@K" Q-S(@("!^(2"M(#$W,R @(#P\(*X@,3<T(" @
  79. XM/CX@KR Q-S4@("!S<R#A(#(R-0IJ=2#F(#(S," @(&\O(.T@,C,W(" @*RT@
  80. XM\2 R-#$@(" ^/2#R(#(T,B @(#P](/,@,C0S(" @.BT@]B R-#8@("!^?B#W
  81. X9(#(T-PI^;R#X(#(T." @(#(R(/T@,C4S"C0S
  82. Xend
  83. END_OF_FILE
  84.   if test 3112 -ne `wc -c <'vim/doc/digraph.doc.UU'`; then
  85.     echo shar: \"'vim/doc/digraph.doc.UU'\" unpacked with wrong size!
  86.   else
  87.     echo shar: Uudecoding \"'vim/doc/digraph.doc'\" \(2230 characters\)
  88.     cat vim/doc/digraph.doc.UU | uudecode
  89.     if test 2230 -ne `wc -c <'vim/doc/digraph.doc'`; then
  90.       echo shar: \"'vim/doc/digraph.doc'\" uudecoded with wrong size!
  91.     else
  92.       rm vim/doc/digraph.doc.UU
  93.     fi
  94.   fi
  95.   # end of 'vim/doc/digraph.doc.UU'
  96. fi
  97. if test -f 'vim/src/misccmds.c' -a "${1}" != "-c" ; then 
  98.   echo shar: Will not clobber existing file \"'vim/src/misccmds.c'\"
  99. else
  100.   echo shar: Extracting \"'vim/src/misccmds.c'\" \(20128 characters\)
  101.   sed "s/^X//" >'vim/src/misccmds.c' <<'END_OF_FILE'
  102. X/* vi:ts=4:sw=4
  103. X *
  104. X * VIM - Vi IMproved        by Bram Moolenaar
  105. X *
  106. X * Read the file "credits.txt" for a list of people who contributed.
  107. X * Read the file "uganda.txt" for copying and usage conditions.
  108. X */
  109. X
  110. X/*
  111. X * misccmds.c: functions that didn't seem to fit elsewhere
  112. X */
  113. X
  114. X#include "vim.h"
  115. X#include "globals.h"
  116. X#include "proto.h"
  117. X#include "param.h"
  118. X
  119. Xstatic void check_status __ARGS((BUF *));
  120. X
  121. Xstatic char_u *(si_tab[]) = {(char_u *)"if", (char_u *)"else", (char_u *)"while", (char_u *)"for", (char_u *)"do"};
  122. X
  123. X/*
  124. X * count the size of the indent in the current line
  125. X */
  126. X    int
  127. Xget_indent()
  128. X{
  129. X    register char_u *ptr;
  130. X    register int count = 0;
  131. X
  132. X    for (ptr = ml_get(curwin->w_cursor.lnum); *ptr; ++ptr)
  133. X    {
  134. X        if (*ptr == TAB)    /* count a tab for what it is worth */
  135. X            count += (int)curbuf->b_p_ts - (count % (int)curbuf->b_p_ts);
  136. X        else if (*ptr == ' ')
  137. X            ++count;            /* count a space for one */
  138. X        else
  139. X            break;
  140. X    }
  141. X    return (count);
  142. X}
  143. X
  144. X/*
  145. X * set the indent of the current line
  146. X * leaves the cursor on the first non-blank in the line
  147. X */
  148. X    void
  149. Xset_indent(size, delete)
  150. X    register int size;
  151. X    int delete;
  152. X{
  153. X    int                oldstate = State;
  154. X    register int    c;
  155. X
  156. X    State = INSERT;        /* don't want REPLACE for State */
  157. X    curwin->w_cursor.col = 0;
  158. X    if (delete)                            /* delete old indent */
  159. X    {
  160. X        while ((c = gchar_cursor()), iswhite(c))
  161. X            (void)delchar(FALSE);
  162. X    }
  163. X    if (!curbuf->b_p_et)            /* if 'expandtab' is set, don't use TABs */
  164. X        while (size >= (int)curbuf->b_p_ts)
  165. X        {
  166. X            inschar(TAB);
  167. X            size -= (int)curbuf->b_p_ts;
  168. X        }
  169. X    while (size)
  170. X    {
  171. X        inschar(' ');
  172. X        --size;
  173. X    }
  174. X    State = oldstate;
  175. X}
  176. X
  177. X/*
  178. X * Opencmd
  179. X *
  180. X * Add a blank line below or above the current line.
  181. X *
  182. X * Return TRUE for success, FALSE for failure
  183. X */
  184. X
  185. X    int
  186. XOpencmd(dir, redraw, delspaces)
  187. X    int         dir;
  188. X    int            redraw;
  189. X    int            delspaces;
  190. X{
  191. X    char_u   *ptr, *p_extra;
  192. X    FPOS    old_cursor;             /* old cursor position */
  193. X    int        newcol = 0;            /* new cursor column */
  194. X    int     newindent = 0;        /* auto-indent of the new line */
  195. X    int        n;
  196. X    int        truncate = FALSE;    /* truncate current line afterwards */
  197. X    int        no_si = FALSE;        /* reset did_si afterwards */
  198. X    int        retval = FALSE;        /* return value, default is FAIL */
  199. X
  200. X    ptr = strsave(ml_get(curwin->w_cursor.lnum));
  201. X    if (ptr == NULL)            /* out of memory! */
  202. X        return FALSE;
  203. X
  204. X    u_clearline();                /* cannot do "U" command when adding lines */
  205. X    did_si = FALSE;
  206. X    if (curbuf->b_p_ai || curbuf->b_p_si)
  207. X    {
  208. X        /*
  209. X         * count white space on current line
  210. X         */
  211. X        newindent = get_indent();
  212. X        if (newindent == 0)
  213. X            newindent = old_indent;        /* for ^^D command in insert mode */
  214. X        old_indent = 0;
  215. X
  216. X            /*
  217. X             * If we just did an auto-indent, then we didn't type anything on the
  218. X             * prior line, and it should be truncated.
  219. X             */
  220. X        if (dir == FORWARD && did_ai)
  221. X            truncate = TRUE;
  222. X        else if (curbuf->b_p_si && *ptr != NUL)
  223. X        {
  224. X            char_u    *p;
  225. X            char_u    *pp;
  226. X            int        i, save;
  227. X
  228. X            if (dir == FORWARD)
  229. X            {
  230. X                p = ptr + STRLEN(ptr) - 1;
  231. X                while (p > ptr && isspace(*p))    /* find last non-blank in line */
  232. X                    --p;
  233. X                if (*p == '{')                    /* line ends in '{': do indent */
  234. X                {
  235. X                    did_si = TRUE;
  236. X                    no_si = TRUE;
  237. X                }
  238. X                else                            /* look for "if" and the like */
  239. X                {
  240. X                    p = ptr;
  241. X                    skipspace(&p);
  242. X                    for (pp = p; islower(*pp); ++pp)
  243. X                        ;
  244. X                    if (!isidchar(*pp))            /* careful for vars starting with "if" */
  245. X                    {
  246. X                        save = *pp;
  247. X                        *pp = NUL;
  248. X                        for (i = sizeof(si_tab)/sizeof(char_u *); --i >= 0; )
  249. X                            if (STRCMP(p, si_tab[i]) == 0)
  250. X                            {
  251. X                                did_si = TRUE;
  252. X                                break;
  253. X                            }
  254. X                        *pp = save;
  255. X                    }
  256. X                }
  257. X            }
  258. X            else
  259. X            {
  260. X                p = ptr;
  261. X                skipspace(&p);
  262. X                if (*p == '}')            /* if line starts with '}': do indent */
  263. X                    did_si = TRUE;
  264. X            }
  265. X        }
  266. X        did_ai = TRUE;
  267. X        if (curbuf->b_p_si)
  268. X            can_si = TRUE;
  269. X    }
  270. X    if (State == INSERT || State == REPLACE)    /* only when dir == FORWARD */
  271. X    {
  272. X        p_extra = ptr + curwin->w_cursor.col;
  273. X        if (curbuf->b_p_ai && delspaces)
  274. X            skipspace(&p_extra);
  275. X        if (*p_extra != NUL)
  276. X            did_ai = FALSE;         /* append some text, don't trucate now */
  277. X    }
  278. X    else
  279. X        p_extra = (char_u *)"";                /* append empty line */
  280. X
  281. X    old_cursor = curwin->w_cursor;
  282. X    if (dir == BACKWARD)
  283. X        --curwin->w_cursor.lnum;
  284. X    if (ml_append(curwin->w_cursor.lnum, p_extra, (colnr_t)0, FALSE) == FAIL)
  285. X        goto theend;
  286. X    mark_adjust(curwin->w_cursor.lnum + 1, MAXLNUM, 1L);
  287. X    if (newindent || did_si)
  288. X    {
  289. X        ++curwin->w_cursor.lnum;
  290. X        if (did_si)
  291. X        {
  292. X            if (p_sr)
  293. X                newindent -= newindent % (int)curbuf->b_p_sw;
  294. X            newindent += (int)curbuf->b_p_sw;
  295. X        }
  296. X        set_indent(newindent, FALSE);
  297. X        newcol = curwin->w_cursor.col;
  298. X        if (no_si)
  299. X            did_si = FALSE;
  300. X    }
  301. X    curwin->w_cursor = old_cursor;
  302. X
  303. X    if (dir == FORWARD)
  304. X    {
  305. X        if (truncate || State == INSERT || State == REPLACE)
  306. X        {
  307. X            if (truncate)
  308. X                *ptr = NUL;
  309. X            else
  310. X                *(ptr + curwin->w_cursor.col) = NUL;    /* truncate current line at cursor */
  311. X            ml_replace(curwin->w_cursor.lnum, ptr, FALSE);
  312. X            ptr = NULL;
  313. X        }
  314. X
  315. X        /*
  316. X         * Get the cursor to the start of the line, so that 'curwin->w_row' gets
  317. X         * set to the right physical line number for the stuff that
  318. X         * follows...
  319. X         */
  320. X        curwin->w_cursor.col = 0;
  321. X
  322. X        if (redraw)
  323. X        {
  324. X            n = RedrawingDisabled;
  325. X            RedrawingDisabled = TRUE;
  326. X            cursupdate();                /* don't want it to update srceen */
  327. X            RedrawingDisabled = n;
  328. X
  329. X            /*
  330. X             * If we're doing an open on the last logical line, then go ahead and
  331. X             * scroll the screen up. Otherwise, just insert a blank line at the
  332. X             * right place. We use calls to plines() in case the cursor is
  333. X             * resting on a long line.
  334. X             */
  335. X            n = curwin->w_row + plines(curwin->w_cursor.lnum);
  336. X            if (n == curwin->w_height)
  337. X                scrollup(1L);
  338. X            else
  339. X                win_ins_lines(curwin, n, 1, TRUE, TRUE);
  340. X        }
  341. X        ++curwin->w_cursor.lnum;    /* cursor moves down */
  342. X    }
  343. X    else if (redraw)                 /* insert physical line above current line */
  344. X        win_ins_lines(curwin, curwin->w_row, 1, TRUE, TRUE);
  345. X
  346. X    curwin->w_cursor.col = newcol;
  347. X    if (redraw)
  348. X    {
  349. X        updateScreen(VALID_TO_CURSCHAR);
  350. X        cursupdate();            /* update curwin->w_row */
  351. X    }
  352. X    CHANGED;
  353. X
  354. X    retval = TRUE;                /* success! */
  355. Xtheend:
  356. X    free(ptr);
  357. X    return retval;
  358. X}
  359. X
  360. X/*
  361. X * plines(p) - return the number of physical screen lines taken by line 'p'
  362. X */
  363. X    int
  364. Xplines(p)
  365. X    linenr_t    p;
  366. X{
  367. X    return plines_win(curwin, p);
  368. X}
  369. X    
  370. X    int
  371. Xplines_win(wp, p)
  372. X    WIN            *wp;
  373. X    linenr_t    p;
  374. X{
  375. X    register long        col = 0;
  376. X    register char_u        *s;
  377. X    register int        lines;
  378. X
  379. X    if (!wp->w_p_wrap)
  380. X        return 1;
  381. X
  382. X    s = ml_get_buf(wp->w_buffer, p, FALSE);
  383. X    if (*s == NUL)                /* empty line */
  384. X        return 1;
  385. X
  386. X    while (*s != NUL)
  387. X        col += chartabsize(*s++, col);
  388. X
  389. X    /*
  390. X     * If list mode is on, then the '$' at the end of the line takes up one
  391. X     * extra column.
  392. X     */
  393. X    if (wp->w_p_list)
  394. X        col += 1;
  395. X
  396. X    /*
  397. X     * If 'number' mode is on, add another 8.
  398. X     */
  399. X    if (wp->w_p_nu)
  400. X        col += 8;
  401. X
  402. X    lines = (col + (Columns - 1)) / Columns;
  403. X    if (lines <= wp->w_height)
  404. X        return lines;
  405. X    return (int)(wp->w_height);        /* maximum length */
  406. X}
  407. X
  408. X/*
  409. X * Count the physical lines (rows) for the lines "first" to "last" inclusive.
  410. X */
  411. X    int
  412. Xplines_m(first, last)
  413. X    linenr_t        first, last;
  414. X{
  415. X    return plines_m_win(curwin, first, last);
  416. X}
  417. X
  418. X    int
  419. Xplines_m_win(wp, first, last)
  420. X    WIN                *wp;
  421. X    linenr_t        first, last;
  422. X{
  423. X    int count = 0;
  424. X
  425. X    while (first <= last)
  426. X        count += plines_win(wp, first++);
  427. X    return (count);
  428. X}
  429. X
  430. X/*
  431. X * insert or replace a single character at the cursor position
  432. X */
  433. X    void
  434. Xinschar(c)
  435. X    int            c;
  436. X{
  437. X    register char_u  *p;
  438. X    int                rir0;        /* reverse replace in column 0 */
  439. X    char_u            *new;
  440. X    char_u            *old;
  441. X    int                oldlen;
  442. X    int                extra;
  443. X    colnr_t            col = curwin->w_cursor.col;
  444. X    linenr_t        lnum = curwin->w_cursor.lnum;
  445. X
  446. X    old = ml_get(lnum);
  447. X    oldlen = STRLEN(old) + 1;
  448. X
  449. X    rir0 = (State == REPLACE && p_ri && col == 0);
  450. X    if (rir0 || State != REPLACE || *(old + col) == NUL)
  451. X        extra = 1;
  452. X    else
  453. X        extra = 0;
  454. X
  455. X    new = alloc((unsigned)(oldlen + extra));
  456. X    if (new == NULL)
  457. X        return;
  458. X    memmove((char *)new, (char *)old, (size_t)col);
  459. X    p = new + col;
  460. X    memmove((char *)p + extra, (char *)old + col, (size_t)(oldlen - col));
  461. X    if (rir0)                    /* reverse replace in column 0 */
  462. X    {
  463. X        *(p + 1) = c;            /* replace the char that was in column 0 */
  464. X        c = ' ';                /* insert a space */
  465. X        extraspace = TRUE;
  466. X    }
  467. X    *p = c;
  468. X    ml_replace(lnum, new, FALSE);
  469. X
  470. X    /*
  471. X     * If we're in insert mode and showmatch mode is set, then check for
  472. X     * right parens and braces. If there isn't a match, then beep. If there
  473. X     * is a match AND it's on the screen, then flash to it briefly. If it
  474. X     * isn't on the screen, don't do anything.
  475. X     */
  476. X    if (p_sm && State == INSERT && (c == ')' || c == '}' || c == ']'))
  477. X    {
  478. X        FPOS           *lpos, csave;
  479. X
  480. X        if ((lpos = showmatch(NUL)) == NULL)        /* no match, so beep */
  481. X            beep();
  482. X        else if (lpos->lnum >= curwin->w_topline)
  483. X        {
  484. X            updateScreen(VALID_TO_CURSCHAR); /* show the new char first */
  485. X            csave = curwin->w_cursor;
  486. X            curwin->w_cursor = *lpos;     /* move to matching char */
  487. X            cursupdate();
  488. X            showruler(0);
  489. X            setcursor();
  490. X            cursor_on();        /* make sure that the cursor is shown */
  491. X            flushbuf();
  492. X            vim_delay();        /* brief pause */
  493. X            curwin->w_cursor = csave;     /* restore cursor position */
  494. X            cursupdate();
  495. X        }
  496. X    }
  497. X    if (!p_ri)                            /* normal insert: cursor right */
  498. X        ++curwin->w_cursor.col;
  499. X    else if (State == REPLACE && !rir0)    /* reverse replace mode: cursor left */
  500. X        --curwin->w_cursor.col;
  501. X    CHANGED;
  502. X}
  503. X
  504. X/*
  505. X * insert a string at the cursor position
  506. X */
  507. X    void
  508. Xinsstr(s)
  509. X    register char_u  *s;
  510. X{
  511. X    register char_u        *old, *new;
  512. X    register int        newlen = STRLEN(s);
  513. X    int                    oldlen;
  514. X    colnr_t                col = curwin->w_cursor.col;
  515. X    linenr_t            lnum = curwin->w_cursor.lnum;
  516. X
  517. X    old = ml_get(lnum);
  518. X    oldlen = STRLEN(old);
  519. X    new = alloc((unsigned)(oldlen + newlen + 1));
  520. X    if (new == NULL)
  521. X        return;
  522. X    memmove((char *)new, (char *)old, (size_t)col);
  523. X    memmove((char *)new + col, (char *)s, (size_t)newlen);
  524. X    memmove((char *)new + col + newlen, (char *)old + col, (size_t)(oldlen - col + 1));
  525. X    ml_replace(lnum, new, FALSE);
  526. X    curwin->w_cursor.col += newlen;
  527. X    CHANGED;
  528. X}
  529. X
  530. X/*
  531. X * delete one character under the cursor
  532. X *
  533. X * return FAIL for failure, OK otherwise
  534. X */
  535. X    int
  536. Xdelchar(fixpos)
  537. X    int            fixpos;     /* if TRUE fix the cursor position when done */
  538. X{
  539. X    char_u        *old, *new;
  540. X    int            oldlen;
  541. X    linenr_t    lnum = curwin->w_cursor.lnum;
  542. X    colnr_t        col = curwin->w_cursor.col;
  543. X    int            was_alloced;
  544. X
  545. X    old = ml_get(lnum);
  546. X    oldlen = STRLEN(old);
  547. X
  548. X    if (col >= oldlen)    /* can't do anything (happens with replace mode) */
  549. X        return FAIL;
  550. X
  551. X/*
  552. X * If the old line has been allocated the deleteion can be done in the
  553. X * existing line. Otherwise a new line has to be allocated
  554. X */
  555. X    was_alloced = ml_line_alloced();        /* check if old was allocated */
  556. X    if (was_alloced)
  557. X        new = old;                            /* use same allocated memory */
  558. X    else
  559. X    {
  560. X        new = alloc((unsigned)oldlen);        /* need to allocated a new line */
  561. X        if (new == NULL)
  562. X            return FAIL;
  563. X        memmove((char *)new, (char *)old, (size_t)col);
  564. X    }
  565. X    memmove((char *)new + col, (char *)old + col + 1, (size_t)(oldlen - col));
  566. X    if (!was_alloced)
  567. X        ml_replace(lnum, new, FALSE);
  568. X
  569. X    /*
  570. X     * If we just took off the last character of a non-blank line, we don't
  571. X     * want to end up positioned at the newline.
  572. X     */
  573. X    if (fixpos && curwin->w_cursor.col > 0 && col == oldlen - 1)
  574. X        --curwin->w_cursor.col;
  575. X
  576. X    CHANGED;
  577. X    return OK;
  578. X}
  579. X
  580. X    void
  581. Xdellines(nlines, dowindow, undo)
  582. X    long             nlines;            /* number of lines to delete */
  583. X    int             dowindow;        /* if true, update the window */
  584. X    int                undo;            /* if true, prepare for undo */
  585. X{
  586. X    int             num_plines = 0;
  587. X
  588. X    if (nlines <= 0)
  589. X        return;
  590. X    /*
  591. X     * There's no point in keeping the window updated if we're deleting more
  592. X     * than a window's worth of lines.
  593. X     */
  594. X    if (nlines > (curwin->w_height - curwin->w_row) && dowindow)
  595. X    {
  596. X        dowindow = FALSE;
  597. X        /* flaky way to clear rest of window */
  598. X        win_del_lines(curwin, curwin->w_row, curwin->w_height, TRUE, TRUE);
  599. X    }
  600. X    if (undo && !u_savedel(curwin->w_cursor.lnum, nlines))
  601. X        return;
  602. X
  603. X    mark_adjust(curwin->w_cursor.lnum, curwin->w_cursor.lnum + nlines - 1, MAXLNUM);
  604. X    mark_adjust(curwin->w_cursor.lnum + nlines, MAXLNUM, -nlines);
  605. X
  606. X    while (nlines-- > 0)
  607. X    {
  608. X        if (bufempty())         /* nothing to delete */
  609. X            break;
  610. X
  611. X        /*
  612. X         * Set up to delete the correct number of physical lines on the
  613. X         * window
  614. X         */
  615. X        if (dowindow)
  616. X            num_plines += plines(curwin->w_cursor.lnum);
  617. X
  618. X        ml_delete(curwin->w_cursor.lnum);
  619. X
  620. X        CHANGED;
  621. X
  622. X        /* If we delete the last line in the file, stop */
  623. X        if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  624. X        {
  625. X            curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  626. X            break;
  627. X        }
  628. X    }
  629. X    curwin->w_cursor.col = 0;
  630. X    /*
  631. X     * Delete the correct number of physical lines on the window
  632. X     */
  633. X    if (dowindow && num_plines > 0)
  634. X        win_del_lines(curwin, curwin->w_row, num_plines, TRUE, TRUE);
  635. X}
  636. X
  637. X    int
  638. Xgchar(pos)
  639. X    FPOS *pos;
  640. X{
  641. X    return (int)(*(ml_get_pos(pos)));
  642. X}
  643. X
  644. X    int
  645. Xgchar_cursor()
  646. X{
  647. X    return (int)(*(ml_get_cursor()));
  648. X}
  649. X
  650. X/*
  651. X * Write a character at the current cursor position.
  652. X * It is directly written into the block.
  653. X */
  654. X    void
  655. Xpchar_cursor(c)
  656. X    int c;
  657. X{
  658. X    *(ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE) + curwin->w_cursor.col) = c;
  659. X}
  660. X
  661. X/*
  662. X * return TRUE if the cursor is before or on the first non-blank in the line
  663. X */
  664. X    int
  665. Xinindent()
  666. X{
  667. X    register char_u *ptr;
  668. X    register int col;
  669. X
  670. X    for (col = 0, ptr = ml_get(curwin->w_cursor.lnum); iswhite(*ptr); ++col)
  671. X        ++ptr;
  672. X    if (col >= curwin->w_cursor.col)
  673. X        return TRUE;
  674. X    else
  675. X        return FALSE;
  676. X}
  677. X
  678. X/*
  679. X * skipspace: skip over ' ' and '\t'.
  680. X *
  681. X * note: you must give a pointer to a char_u pointer!
  682. X */
  683. X    void
  684. Xskipspace(pp)
  685. X    char_u **pp;
  686. X{
  687. X    register char_u *p;
  688. X    
  689. X    for (p = *pp; *p == ' ' || *p == '\t'; ++p)    /* skip to next non-white */
  690. X        ;
  691. X    *pp = p;
  692. X}
  693. X
  694. X/*
  695. X * skiptospace: skip over text until ' ' or '\t'.
  696. X *
  697. X * note: you must give a pointer to a char_u pointer!
  698. X */
  699. X    void
  700. Xskiptospace(pp)
  701. X    char_u **pp;
  702. X{
  703. X    register char_u *p;
  704. X
  705. X    for (p = *pp; *p != ' ' && *p != '\t' && *p != NUL; ++p)
  706. X        ;
  707. X    *pp = p;
  708. X}
  709. X
  710. X/*
  711. X * skiptodigit: skip over text until digit found
  712. X *
  713. X * note: you must give a pointer to a char_u pointer!
  714. X */
  715. X    void
  716. Xskiptodigit(pp)
  717. X    char_u **pp;
  718. X{
  719. X    register char_u *p;
  720. X
  721. X    for (p = *pp; !isdigit(*p) && *p != NUL; ++p)
  722. X        ;
  723. X    *pp = p;
  724. X}
  725. X
  726. X/*
  727. X * getdigits: get a number from a string and skip over it
  728. X *
  729. X * note: you must give a pointer to a char_u pointer!
  730. X */
  731. X
  732. X    long
  733. Xgetdigits(pp)
  734. X    char_u **pp;
  735. X{
  736. X    register char_u *p;
  737. X    long retval;
  738. X    
  739. X    p = *pp;
  740. X    retval = atol((char *)p);
  741. X    while (isdigit(*p))    /* skip to next non-digit */
  742. X        ++p;
  743. X    *pp = p;
  744. X    return retval;
  745. X}
  746. X
  747. X    char_u *
  748. Xplural(n)
  749. X    long n;
  750. X{
  751. X    static char_u buf[2] = "s";
  752. X
  753. X    if (n == 1)
  754. X        return &(buf[1]);
  755. X    return &(buf[0]);
  756. X}
  757. X
  758. X/*
  759. X * set_Changed is called when something in the current buffer is changed
  760. X */
  761. X    void
  762. Xset_Changed()
  763. X{
  764. X    if (!curbuf->b_changed)
  765. X    {
  766. X        change_warning();
  767. X        curbuf->b_changed = TRUE;
  768. X        check_status(curbuf);
  769. X    }
  770. X}
  771. X
  772. X/*
  773. X * unset_Changed is called when the changed flag must be reset for buffer 'buf'
  774. X */
  775. X    void
  776. Xunset_Changed(buf)
  777. X    BUF        *buf;
  778. X{
  779. X    if (buf->b_changed)
  780. X    {
  781. X        buf->b_changed = 0;
  782. X        check_status(buf);
  783. X    }
  784. X}
  785. X
  786. X/*
  787. X * check_status: called when the status bars for the buffer 'buf'
  788. X *                 need to be updated
  789. X */
  790. X    static void
  791. Xcheck_status(buf)
  792. X    BUF        *buf;
  793. X{
  794. X    WIN        *wp;
  795. X    int        i;
  796. X
  797. X    i = 0;
  798. X    for (wp = firstwin; wp != NULL; wp = wp->w_next)
  799. X        if (wp->w_buffer == buf && wp->w_status_height)
  800. X        {
  801. X            wp->w_redr_status = TRUE;
  802. X            ++i;
  803. X        }
  804. X    if (i && must_redraw < NOT_VALID)        /* redraw later */
  805. X        must_redraw = NOT_VALID;
  806. X}
  807. X
  808. X/*
  809. X * If the file is readonly, give a warning message with the first change.
  810. X * Don't use emsg(), because it flushes the macro buffer.
  811. X * If we have undone all changes b_changed will be FALSE, but b_did_warn
  812. X * will be TRUE.
  813. X */
  814. X    void
  815. Xchange_warning()
  816. X{
  817. X    if (curbuf->b_did_warn == FALSE && curbuf->b_changed == 0 && curbuf->b_p_ro)
  818. X    {
  819. X        curbuf->b_did_warn = TRUE;
  820. X        MSG("Warning: Changing a readonly file");
  821. X        sleep(1);            /* give him some time to think about it */
  822. X    }
  823. X}
  824. X
  825. X/*
  826. X * ask for a reply from the user, a 'y' or a 'n'.
  827. X * No other characters are accepted, the message is repeated until a valid
  828. X * reply is entered or CTRL-C is hit.
  829. X *
  830. X * return the 'y' or 'n'
  831. X */
  832. X    int
  833. Xask_yesno(str)
  834. X    char_u *str;
  835. X{
  836. X    int r = ' ';
  837. X
  838. X    while (r != 'y' && r != 'n')
  839. X    {
  840. X        (void)set_highlight('r');        /* same highlighting as for wait_return */
  841. X        msg_highlight = TRUE;
  842. X        smsg((char_u *)"%s (y/n)?", str);
  843. X        r = vgetc();
  844. X        if (r == Ctrl('C'))
  845. X            r = 'n';
  846. X        msg_outchar(r);        /* show what you typed */
  847. X        flushbuf();
  848. X    }
  849. X    return r;
  850. X}
  851. X
  852. X    void
  853. Xmsgmore(n)
  854. X    long n;
  855. X{
  856. X    long pn;
  857. X
  858. X    if (global_busy)        /* no messages now, wait until global is finished */
  859. X        return;
  860. X
  861. X    if (n > 0)
  862. X        pn = n;
  863. X    else
  864. X        pn = -n;
  865. X
  866. X    if (pn > p_report)
  867. X        smsg((char_u *)"%ld %s line%s %s", pn, n > 0 ? "more" : "fewer", plural(pn),
  868. X                                            got_int ? "(Interrupted)" : "");
  869. X}
  870. X
  871. X/*
  872. X * give a warning for an error
  873. X */
  874. X    void
  875. Xbeep()
  876. X{
  877. X    flush_buffers(FALSE);        /* flush internal buffers */
  878. X    if (p_vb)
  879. X    {
  880. X        if (T_VB && *T_VB)
  881. X            outstr(T_VB);
  882. X        else
  883. X        {                        /* very primitive visual bell */
  884. X            MSG("    ^G");
  885. X            MSG("     ^G");
  886. X            MSG("    ^G ");
  887. X            MSG("     ^G");
  888. X            MSG("       ");
  889. X            showmode();            /* may have deleted the mode message */
  890. X        }
  891. X    }
  892. X    else
  893. X        outchar('\007');
  894. X}
  895. X
  896. X/* 
  897. X * Expand environment variable with path name.
  898. X * "~/" is also expanded, like $HOME.
  899. X * If anything fails no expansion is done and dst equals src.
  900. X */
  901. X    void
  902. Xexpand_env(src, dst, dstlen)
  903. X    char_u    *src;            /* input string e.g. "$HOME/vim.hlp" */
  904. X    char_u    *dst;            /* where to put the result */
  905. X    int        dstlen;            /* maximum length of the result */
  906. X{
  907. X    char_u    *tail;
  908. X    int        c;
  909. X    char_u    *var;
  910. X
  911. X    if (*src == '$' || (*src == '~' && STRCHR("/ \t\n", src[1]) != NULL))
  912. X    {
  913. X/*
  914. X * The variable name is copied into dst temporarily, because it may be
  915. X * a string in read-only memory.
  916. X */
  917. X        if (*src == '$')
  918. X        {
  919. X            tail = src + 1;
  920. X            var = dst;
  921. X            c = dstlen - 1;
  922. X            while (c-- > 0 && *tail && isidchar(*tail))
  923. X                *var++ = *tail++;
  924. X            *var = NUL;
  925. X/*
  926. X * It is possible that vimgetenv() uses IObuff for the expansion, and that the
  927. X * 'dst' is also IObuff. This works, as long as 'var' is the first to be copied
  928. X * to 'dst'!
  929. X */
  930. X            var = vimgetenv(dst);
  931. X        }
  932. X        else
  933. X        {
  934. X            var = vimgetenv((char_u *)"HOME");
  935. X            tail = src + 1;
  936. X        }
  937. X        if (var && (STRLEN(var) + STRLEN(tail) + 1 < (unsigned)dstlen))
  938. X        {
  939. X            STRCPY(dst, var);
  940. X            STRCAT(dst, tail);
  941. X            return;
  942. X        }
  943. X    }
  944. X    STRNCPY(dst, src, (size_t)dstlen);
  945. X}
  946. X
  947. X/* 
  948. X * Replace home directory by "~/"
  949. X * If anything fails dst equals src.
  950. X */
  951. X    void
  952. Xhome_replace(src, dst, dstlen)
  953. X    char_u    *src;            /* input file name */
  954. X    char_u    *dst;            /* where to put the result */
  955. X    int        dstlen;            /* maximum length of the result */
  956. X{
  957. X    char_u    *home;
  958. X    size_t    len;
  959. X
  960. X    /*
  961. X     * If there is no "HOME" environment variable, or when it
  962. X     * is very short, don't replace anything.
  963. X     */
  964. X    if ((home = vimgetenv((char_u *)"HOME")) == NULL || (len = STRLEN(home)) <= 1)
  965. X        STRNCPY(dst, src, (size_t)dstlen);
  966. X    else
  967. X    {
  968. X        skipspace(&src);
  969. X        while (*src && dstlen > 0)
  970. X        {
  971. X            if (STRNCMP(src, home, len) == 0)
  972. X            {
  973. X                src += len;
  974. X                if (--dstlen > 0)
  975. X                    *dst++ = '~';
  976. X            }
  977. X            while (*src && *src != ' ' && --dstlen > 0)
  978. X                *dst++ = *src++;
  979. X            while (*src == ' ' && --dstlen > 0)
  980. X                *dst++ = *src++;
  981. X        }
  982. X        *dst = NUL;
  983. X    }
  984. X}
  985. X
  986. X/*
  987. X * Compare two file names and return TRUE if they are different files.
  988. X * For the first name environment variables are expanded
  989. X */
  990. X    int
  991. Xfullpathcmp(s1, s2)
  992. X    char_u *s1, *s2;
  993. X{
  994. X#ifdef UNIX
  995. X    struct stat st1, st2;
  996. X    char_u buf1[MAXPATHL];
  997. X
  998. X    expand_env(s1, buf1, MAXPATHL);
  999. X    if (stat((char *)buf1, &st1) == 0 && stat((char *)s2, &st2) == 0 &&
  1000. X                st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino)
  1001. X        return FALSE;
  1002. X    return TRUE;
  1003. X#else
  1004. X    char_u buf1[MAXPATHL];
  1005. X    char_u buf2[MAXPATHL];
  1006. X
  1007. X    expand_env(s1, buf2, MAXPATHL);
  1008. X    if (FullName(buf2, buf1, MAXPATHL) == OK && FullName(s2, buf2, MAXPATHL) == OK)
  1009. X        return STRCMP(buf1, buf2);
  1010. X    /*
  1011. X     * one of the FullNames() failed, file probably doesn't exist.
  1012. X     */
  1013. X    return TRUE;
  1014. X#endif
  1015. X}
  1016. X
  1017. X/*
  1018. X * get the tail of a path: the file name.
  1019. X */
  1020. X    char_u *
  1021. Xgettail(fname)
  1022. X    char_u *fname;
  1023. X{
  1024. X    register char_u *p1, *p2;
  1025. X
  1026. X    for (p1 = p2 = fname; *p2; ++p2)    /* find last part of path */
  1027. X    {
  1028. X        if (ispathsep(*p2))
  1029. X            p1 = p2 + 1;
  1030. X    }
  1031. X    return p1;
  1032. X}
  1033. X
  1034. X/*
  1035. X * return TRUE if 'c' is a path separator.
  1036. X */
  1037. X    int
  1038. Xispathsep(c)
  1039. X    int c;
  1040. X{
  1041. X#ifdef UNIX
  1042. X    return (c == PATHSEP);        /* UNIX has ':' inside file names */
  1043. X#else
  1044. X# ifdef MSDOS
  1045. X    return (c == ':' || c == PATHSEP || c == '/');
  1046. X# else
  1047. X    return (c == ':' || c == PATHSEP);
  1048. X# endif
  1049. X#endif
  1050. X}
  1051. END_OF_FILE
  1052.   if test 20128 -ne `wc -c <'vim/src/misccmds.c'`; then
  1053.     echo shar: \"'vim/src/misccmds.c'\" unpacked with wrong size!
  1054.   fi
  1055.   # end of 'vim/src/misccmds.c'
  1056. fi
  1057. if test -f 'vim/src/normal.c' -a "${1}" != "-c" ; then 
  1058.   echo shar: Will not clobber existing file \"'vim/src/normal.c'\"
  1059. else
  1060.   echo shar: Extracting \"'vim/src/normal.c'\" \(41440 characters\)
  1061.   sed "s/^X//" >'vim/src/normal.c' <<'END_OF_FILE'
  1062. X/* vi:ts=4:sw=4
  1063. X *
  1064. X * VIM - Vi IMproved        by Bram Moolenaar
  1065. X *
  1066. X * Read the file "credits.txt" for a list of people who contributed.
  1067. X * Read the file "uganda.txt" for copying and usage conditions.
  1068. X */
  1069. X
  1070. X/*
  1071. X * Contains the main routine for processing characters in command mode.
  1072. X * Communicates closely with the code in ops.c to handle the operators.
  1073. X */
  1074. X
  1075. X#include "vim.h"
  1076. X#include "globals.h"
  1077. X#include "proto.h"
  1078. X#include "param.h"
  1079. X
  1080. X#undef EXTERN
  1081. X#undef INIT
  1082. X#define EXTERN
  1083. X#define INIT(x) x
  1084. X#include "ops.h"
  1085. X
  1086. X/*
  1087. X * Generally speaking, every command in normal() should either clear any
  1088. X * pending operator (with CLEAROP), or set the motion type variable.
  1089. X */
  1090. X
  1091. X#define CLEAROP (operator = NOP)        /* clear any pending operator */
  1092. X#define CLEAROPBEEP     clearopbeep()    /* CLEAROP plus a beep() */
  1093. X#define CHECKCLEAROP    if (checkclearop()) break;
  1094. X#define CHECKCLEAROPQ    if (checkclearopq()) break;
  1095. X
  1096. X/*
  1097. X * If a count is given before the operator, it is saved in opnum.
  1098. X */
  1099. Xstatic linenr_t    opnum = 0;
  1100. Xstatic linenr_t    Prenum;         /* The (optional) number before a command. */
  1101. Xint                redo_Visual_busy = FALSE;    /* TRUE when redo-ing a visual */
  1102. X
  1103. Xstatic void        prep_redo __ARGS((long, int, int, int));
  1104. Xstatic int        checkclearop __ARGS((void));
  1105. Xstatic int        checkclearopq __ARGS((void));
  1106. Xstatic void        clearopbeep __ARGS((void));
  1107. Xstatic void        premsg __ARGS((int, int));
  1108. X
  1109. Xextern int        restart_edit;    /* this is in edit.c */
  1110. X
  1111. X/*
  1112. X * normal
  1113. X *
  1114. X * Execute a command in normal mode.
  1115. X *
  1116. X * This is basically a big switch with the cases arranged in rough categories
  1117. X * in the following order:
  1118. X *
  1119. X *      0. Macros (q, @)
  1120. X *      1. Screen positioning commands (^U, ^D, ^F, ^B, ^E, ^Y, z)
  1121. X *      2. Control commands (:, <help>, ^L, ^G, ^^, ZZ, *, ^], ^T)
  1122. 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)
  1123. X *      4. Searches (?, /, n, N, T, t, F, f, ,, ;, ], [, %, (, ), {, })
  1124. X *      5. Edits (., u, K_UNDO, ^R, U, r, J, p, P, ^A, ^S)
  1125. X *      6. Inserts (A, a, I, i, o, O, R)
  1126. X *      7. Operators (~, d, c, y, >, <, !, =, Q)
  1127. X *      8. Abbreviations (x, X, D, C, s, S, Y, &)
  1128. X *      9. Marks (m, ', `, ^O, ^I)
  1129. X *     10. Buffer setting (")
  1130. X *     11. Visual (v, V, ^V)
  1131. X *   12. Suspend (^Z)
  1132. X *   13. Window commands (^W)
  1133. X *   14. extended commands (starting with 'g')
  1134. X */
  1135. X
  1136. X    void
  1137. Xnormal()
  1138. X{
  1139. X    register int    c;
  1140. X    long             n;
  1141. X    int                flag = FALSE;
  1142. X    int                flag2 = FALSE;
  1143. X    int             type = 0;                /* type of operation */
  1144. X    int             dir = FORWARD;            /* search direction */
  1145. X    int                nchar = NUL;
  1146. X    int                finish_op;
  1147. X    linenr_t        Prenum1;
  1148. X    char_u            searchbuff[CMDBUFFSIZE];/* buffer for search string */
  1149. X    FPOS            *pos = NULL;            /* init for gcc */
  1150. X    register char_u    *ptr;
  1151. X    int                command_busy = FALSE;
  1152. X    static int        didwarn = FALSE;        /* warned for broken inversion */
  1153. X    int                modified = FALSE;        /* changed current buffer */
  1154. X    int                ctrl_w = FALSE;            /* got CTRL-W command */
  1155. X
  1156. X        /* the visual area is remembered for reselection */
  1157. X    static linenr_t    resel_Visual_nlines;        /* number of lines */
  1158. X    static int        resel_Visual_type = 0;    /* type 'v', 'V' or CTRL-V */
  1159. X    static colnr_t    resel_Visual_col;        /* number of columns or end column */
  1160. X        /* the visual area is remembered for redo */
  1161. X    static linenr_t    redo_Visual_nlines;        /* number of lines */
  1162. X    static int        redo_Visual_type = 0;    /* type 'v', 'V' or CTRL-V */
  1163. X    static colnr_t    redo_Visual_col;        /* number of columns or end column */
  1164. X    static long        redo_Visual_Prenum;        /* Prenum for operator */
  1165. X
  1166. X    Prenum = 0;
  1167. X    /*
  1168. X     * If there is an operator pending, then the command we take this time
  1169. X     * will terminate it. Finish_op tells us to finish the operation before
  1170. X     * returning this time (unless the operation was cancelled).
  1171. X     */
  1172. X    finish_op = (operator != NOP);
  1173. X
  1174. X    if (!finish_op && !yankbuffer)
  1175. X        opnum = 0;
  1176. X
  1177. X    if (p_sc && (vpeekc() == NUL || KeyTyped == TRUE))
  1178. X        premsg(NUL, NUL);
  1179. X    State = NORMAL_BUSY;
  1180. X    c = vgetc();
  1181. X
  1182. Xgetcount:
  1183. X    /* Pick up any leading digits and compute 'Prenum' */
  1184. X    while ((c >= '1' && c <= '9') || (Prenum != 0 && (c == DEL || c == '0')))
  1185. X    {
  1186. X        if (c == DEL)
  1187. X                Prenum /= 10;
  1188. X        else
  1189. X                Prenum = Prenum * 10 + (c - '0');
  1190. X        if (Prenum < 0)            /* got too large! */
  1191. X            Prenum = 999999999;
  1192. X        premsg(ctrl_w ? Ctrl('W') : ' ', NUL);
  1193. X        c = vgetc();
  1194. X    }
  1195. X
  1196. X/*
  1197. X * If we got CTRL-W there may be a/another count
  1198. X */
  1199. X    if (c == Ctrl('W') && !ctrl_w)
  1200. X    {
  1201. X        ctrl_w = TRUE;
  1202. X        opnum = Prenum;                        /* remember first count */
  1203. X        Prenum = 0;
  1204. X        State = ONLYKEY;                    /* no mapping for nchar, but keys */
  1205. X        premsg(c, NUL);
  1206. X        c = vgetc();                        /* get next character */
  1207. X        goto getcount;                        /* jump back */
  1208. X    }
  1209. X
  1210. X    /*
  1211. X     * If we're in the middle of an operator (including after entering a yank
  1212. X     * buffer with ") AND we had a count before the
  1213. X     * operator, then that count overrides the current value of Prenum. What
  1214. X     * this means effectively, is that commands like "3dw" get turned into
  1215. X     * "d3w" which makes things fall into place pretty neatly.
  1216. X     * If you give a count before AND after the operator, they are multiplied.
  1217. X     */
  1218. X    if (opnum != 0)
  1219. X    {
  1220. X            if (Prenum)
  1221. X                Prenum *= opnum;
  1222. X            else
  1223. X                Prenum = opnum;
  1224. X            opnum = 0;
  1225. X    }
  1226. X
  1227. X    Prenum1 = (Prenum == 0 ? 1 : Prenum);        /* Prenum often defaults to 1 */
  1228. X    premsg(c, NUL);
  1229. X
  1230. X    /*
  1231. X     * get an additional character if we need one
  1232. X     * for CTRL-W we already got it when looking for a count
  1233. X     */
  1234. X    if (ctrl_w)
  1235. X    {
  1236. X        nchar = c;
  1237. X        c = Ctrl('W');
  1238. X        premsg(c, nchar);
  1239. X    }
  1240. X    else if (strchr("@zZtTfF[]mg'`\"", c) || (c == 'q' && !Recording && !Exec_reg) ||
  1241. X                                        (c == 'r' && !VIsual.lnum))
  1242. X    {
  1243. X        State = NOMAPPING;
  1244. X        nchar = vgetc();        /* no macro mapping for this char */
  1245. X        premsg(c, nchar);
  1246. X    }
  1247. X    if (p_sc)
  1248. X        flushbuf();        /* flush the premsg() characters onto the screen so we can
  1249. X                            see them while the command is being executed */
  1250. X
  1251. X/*
  1252. X * For commands that don't get another character we can put the State back to
  1253. X * NORMAL and check for a window size change.
  1254. X */
  1255. X    if (STRCHR("z:/?", c) == NULL)
  1256. X        State = NORMAL;
  1257. X    if (nchar == ESC)
  1258. X    {
  1259. X        CLEAROP;
  1260. X        goto normal_end;
  1261. X    }
  1262. X    switch (c)
  1263. X    {
  1264. X
  1265. X/*
  1266. X * 0: Macros
  1267. X */
  1268. X      case 'q':         /* (stop) recording into a named register */
  1269. X        CHECKCLEAROP;
  1270. X                        /* command is ignored while executing a register */
  1271. X        if (!Exec_reg && dorecord(nchar) == FAIL)
  1272. X            CLEAROPBEEP;
  1273. X        break;
  1274. X
  1275. X     case '@':            /* execute a named buffer */
  1276. X        CHECKCLEAROP;
  1277. X        while (Prenum1--)
  1278. X        {
  1279. X            if (doexecbuf(nchar) == FAIL)
  1280. X            {
  1281. X                CLEAROPBEEP;
  1282. X                break;
  1283. X            }
  1284. X        }
  1285. X        break;
  1286. X
  1287. X/*
  1288. X * 1: Screen positioning commands
  1289. X */
  1290. X      case Ctrl('D'):
  1291. X        flag = TRUE;
  1292. X
  1293. X      case Ctrl('U'):
  1294. X        CHECKCLEAROP;
  1295. X        if (Prenum)
  1296. X            curwin->w_p_scroll = (Prenum > curwin->w_height) ? curwin->w_height : Prenum;
  1297. X        n = (curwin->w_p_scroll <= curwin->w_height) ? curwin->w_p_scroll : curwin->w_height;
  1298. X        if (flag)
  1299. X        {
  1300. X                curwin->w_topline += n;
  1301. X                if (curwin->w_topline > curbuf->b_ml.ml_line_count)
  1302. X                    curwin->w_topline = curbuf->b_ml.ml_line_count;
  1303. X                comp_Botline(curwin);        /* compute curwin->w_botline */
  1304. X                (void)onedown(n);
  1305. X        }
  1306. X        else
  1307. X        {
  1308. X                if (n >= curwin->w_cursor.lnum)
  1309. X                    n = curwin->w_cursor.lnum - 1;
  1310. X                Prenum1 = curwin->w_cursor.lnum - n;
  1311. X                scrolldown(n);
  1312. X                if (Prenum1 < curwin->w_cursor.lnum)
  1313. X                    curwin->w_cursor.lnum = Prenum1;
  1314. X        }
  1315. X        beginline(TRUE);
  1316. X        updateScreen(VALID);
  1317. X        break;
  1318. X
  1319. X      case Ctrl('B'):
  1320. X      case K_SUARROW:
  1321. X        dir = BACKWARD;
  1322. X
  1323. X      case Ctrl('F'):
  1324. X      case K_SDARROW:
  1325. X        CHECKCLEAROP;
  1326. X        (void)onepage(dir, Prenum1);
  1327. X        break;
  1328. X
  1329. X      case Ctrl('E'):
  1330. X        CHECKCLEAROP;
  1331. X        scrollup(Prenum1);
  1332. X                /* We may have moved to another line -- webb */
  1333. X        coladvance(curwin->w_curswant);
  1334. X        updateScreen(VALID);
  1335. X        break;
  1336. X
  1337. X      case Ctrl('Y'):
  1338. X        CHECKCLEAROP;
  1339. X        scrolldown(Prenum1);
  1340. X                /* We may have moved to another line -- webb */
  1341. X        coladvance(curwin->w_curswant);
  1342. X        updateScreen(VALID);
  1343. X        break;
  1344. X
  1345. X      case 'z':
  1346. X        CHECKCLEAROP;
  1347. X        if (isdigit(nchar))
  1348. X        {
  1349. X            /*
  1350. X             * we misuse some variables to be able to call premsg()
  1351. X             */
  1352. X            operator = c;
  1353. X            opnum = Prenum;
  1354. X            Prenum = nchar - '0';
  1355. X            for (;;)
  1356. X            {
  1357. X                premsg(' ', NUL);
  1358. X                nchar = vgetc();
  1359. X                State = NORMAL;
  1360. X                if (nchar == DEL)
  1361. X                    Prenum /= 10;
  1362. X                else if (isdigit(nchar))
  1363. X                    Prenum = Prenum * 10 + (nchar - '0');
  1364. X                else if (nchar == CR)
  1365. X                {
  1366. X                    win_setheight((int)Prenum);
  1367. X                    break;
  1368. X                }
  1369. X                else
  1370. X                {
  1371. X                    CLEAROPBEEP;
  1372. X                    break;
  1373. X                }
  1374. X            }
  1375. X            operator = NOP;
  1376. X            break;
  1377. X        }
  1378. X
  1379. X        if (Prenum && Prenum != curwin->w_cursor.lnum)    /* line number given */
  1380. X        {
  1381. X            setpcmark();
  1382. X            if (Prenum > curbuf->b_ml.ml_line_count)
  1383. X                curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  1384. X            else
  1385. X                curwin->w_cursor.lnum = Prenum;
  1386. X        }
  1387. X        State = NORMAL;            /* for updateScreen() */
  1388. X        switch (nchar)
  1389. X        {
  1390. X          case NL:                /* put curwin->w_cursor at top of screen */
  1391. X          case CR:
  1392. X            beginline(TRUE);
  1393. X          case 't':
  1394. X            curwin->w_topline = curwin->w_cursor.lnum;
  1395. X            break;
  1396. X
  1397. X          case '.':             /* put curwin->w_cursor in middle of screen */
  1398. X          case 'z':
  1399. X            n = (curwin->w_height + plines(curwin->w_cursor.lnum)) / 2;
  1400. X            goto dozcmd;
  1401. X
  1402. X          case '-':             /* put curwin->w_cursor at bottom of screen */
  1403. X          case 'b':
  1404. X            n = curwin->w_height;
  1405. X            /* FALLTHROUGH */
  1406. X
  1407. X    dozcmd:
  1408. X            {
  1409. X                register linenr_t    lp = curwin->w_cursor.lnum;
  1410. X                register long        l = plines(lp);
  1411. X
  1412. X                do
  1413. X                {
  1414. X                    curwin->w_topline = lp;
  1415. X                    if (--lp == 0)
  1416. X                        break;
  1417. X                    l += plines(lp);
  1418. X                } while (l <= n);
  1419. X            }
  1420. X            if (nchar != 'z' && nchar != 'b')
  1421. X                beginline(TRUE);
  1422. X            break;
  1423. X
  1424. X          case Ctrl('S'):    /* ignore CTRL-S and CTRL-Q to avoid problems */
  1425. X          case Ctrl('Q'):    /* with terminals that use xon/xoff */
  1426. X              break;
  1427. X
  1428. X          default:
  1429. X            CLEAROPBEEP;
  1430. X        }
  1431. X        updateScreen(VALID);
  1432. X        break;
  1433. X
  1434. X/*
  1435. X *      2: Control commands
  1436. X */
  1437. X      case ':':
  1438. X        if (VIsual.lnum)
  1439. X            goto dooperator;
  1440. X        CHECKCLEAROP;
  1441. X        /*
  1442. X         * translate "count:" into ":.,.+(count - 1)"
  1443. X         */
  1444. X        if (Prenum)
  1445. X        {
  1446. X            stuffReadbuff((char_u *)".");
  1447. X            if (Prenum > 1)
  1448. X            {
  1449. X                stuffReadbuff((char_u *)",.+");
  1450. X                stuffnumReadbuff((long)Prenum - 1L);
  1451. X            }
  1452. X        }
  1453. X        docmdline(NULL);
  1454. X        modified = TRUE;
  1455. X        break;
  1456. X
  1457. X      case K_HELP:
  1458. X        CHECKCLEAROP;
  1459. X        help();
  1460. X        break;
  1461. X
  1462. X      case Ctrl('L'):
  1463. X        CHECKCLEAROP;
  1464. X        updateScreen(CLEAR);
  1465. X        break;
  1466. X
  1467. X      case Ctrl('G'):
  1468. X        CHECKCLEAROP;
  1469. X        fileinfo(did_cd || Prenum);    /* print full name if count given or :cd used */
  1470. X        break;
  1471. X
  1472. X      case K_CCIRCM:            /* CTRL-^, short for ":e #" */
  1473. X        CHECKCLEAROPQ;
  1474. X        (void)buflist_getfile((int)Prenum, (linenr_t)0, TRUE);
  1475. X        break;
  1476. X
  1477. X      case 'Z':         /* write, if changed, and exit */
  1478. X        CHECKCLEAROPQ;
  1479. X        if (nchar != 'Z')
  1480. X        {
  1481. X            CLEAROPBEEP;
  1482. X            break;
  1483. X        }
  1484. X        stuffReadbuff((char_u *)":x\n");
  1485. X        break;
  1486. X
  1487. X      case Ctrl(']'):            /* :ta to current identifier */
  1488. X        CHECKCLEAROPQ;
  1489. X      case '*':                 /* / to current identifier or string */
  1490. X      case '#':                 /* ? to current identifier or string */
  1491. X      case 'K':                    /* run program for current identifier */
  1492. X        {
  1493. X            register int     col;
  1494. X            register int    i;
  1495. X
  1496. X            /*
  1497. X             * if i == 0: try to find an identifier
  1498. X             * if i == 1: try to find any string
  1499. X             */
  1500. X            ptr = ml_get(curwin->w_cursor.lnum);
  1501. X            for (i = 0;    i < 2; ++i)
  1502. X            {
  1503. X                /*
  1504. X                 * skip to start of identifier/string
  1505. X                 */
  1506. X                col = curwin->w_cursor.col;
  1507. X                while (ptr[col] != NUL &&
  1508. X                            (i == 0 ? !isidchar(ptr[col]) : iswhite(ptr[col])))
  1509. X                    ++col;
  1510. X
  1511. X                /*
  1512. X                 * Back up to start of identifier/string. This doesn't match the
  1513. X                 * real vi but I like it a little better and it shouldn't bother
  1514. X                 * anyone.
  1515. X                 */
  1516. X                while (col > 0 && (i == 0 ? isidchar(ptr[col - 1]) :
  1517. X                            (!iswhite(ptr[col - 1]) && !isidchar(ptr[col - 1]))))
  1518. X                    --col;
  1519. X
  1520. X                /*
  1521. X                 * if identifier found or not '*' or '#' command, stop searching
  1522. X                 */
  1523. X                if (isidchar(ptr[col]) || (c != '*' && c != '#'))
  1524. X                    break;
  1525. X            }
  1526. X            /*
  1527. X             * did't find an identifier of string
  1528. X             */
  1529. X            if (ptr[col] == NUL || (!isidchar(ptr[col]) && i == 0))
  1530. X            {
  1531. X                CLEAROPBEEP;
  1532. X                break;
  1533. X            }
  1534. X
  1535. X            if (Prenum)
  1536. X                stuffnumReadbuff(Prenum);
  1537. X            switch (c)
  1538. X            {
  1539. X                case '*':
  1540. X                    stuffReadbuff((char_u *)"/");
  1541. X                    goto sow;
  1542. X
  1543. X                case '#':
  1544. X                    stuffReadbuff((char_u *)"?");
  1545. Xsow:                if (i == 0)
  1546. X                        stuffReadbuff((char_u *)"\\<");
  1547. X                    break;
  1548. X
  1549. X                case 'K':
  1550. X                    stuffReadbuff((char_u *)":! ");
  1551. X                    stuffReadbuff(p_kp);
  1552. X                    stuffReadbuff((char_u *)" ");
  1553. X                    break;
  1554. X                default:
  1555. X                    stuffReadbuff((char_u *)":ta ");
  1556. X            }
  1557. X
  1558. X            /*
  1559. X             * Now grab the chars in the identifier
  1560. X             */
  1561. X            while (i == 0 ? isidchar(ptr[col]) :
  1562. X                                (ptr[col] != NUL && !iswhite(ptr[col])))
  1563. X            {
  1564. X                stuffcharReadbuff(ptr[col]);
  1565. X                ++col;
  1566. X            }
  1567. X            if ((c == '*' || c == '#') && i == 0)
  1568. X                stuffReadbuff((char_u *)"\\>");
  1569. X            stuffReadbuff((char_u *)"\n");
  1570. X        }
  1571. X        break;
  1572. X
  1573. X      case Ctrl('T'):        /* backwards in tag stack */
  1574. X            CHECKCLEAROPQ;
  1575. X              dotag((char_u *)"", 2, (int)Prenum1);
  1576. X            break;
  1577. X
  1578. X/*
  1579. X * Cursor motions
  1580. X */
  1581. X      case 'G':
  1582. X        mtype = MLINE;
  1583. X        setpcmark();
  1584. X        if (Prenum == 0 || Prenum > curbuf->b_ml.ml_line_count)
  1585. X                curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  1586. X        else
  1587. X                curwin->w_cursor.lnum = Prenum;
  1588. X        beginline(TRUE);
  1589. X        break;
  1590. X
  1591. X      case 'H':
  1592. X      case 'M':
  1593. X        if (c == 'M')
  1594. X                n = (curwin->w_height - curwin->w_empty_rows) / 2;
  1595. X        else
  1596. X                n = Prenum;
  1597. X        mtype = MLINE;
  1598. X        setpcmark();
  1599. X        curwin->w_cursor.lnum = curwin->w_topline;
  1600. X        while (n && onedown((long)1) == OK)
  1601. X                --n;
  1602. X        beginline(TRUE);
  1603. X        break;
  1604. X
  1605. X      case 'L':
  1606. X        mtype = MLINE;
  1607. X        setpcmark();
  1608. X        curwin->w_cursor.lnum = curwin->w_botline - 1;
  1609. X        for (n = Prenum; n && oneup((long)1) == OK; n--)
  1610. X                ;
  1611. X        beginline(TRUE);
  1612. X        break;
  1613. X
  1614. X      case 'l':
  1615. X      case K_RARROW:
  1616. X      case ' ':
  1617. X        mtype = MCHAR;
  1618. X        mincl = FALSE;
  1619. X        n = Prenum1;
  1620. X        while (n--)
  1621. X        {
  1622. X            if (oneright() == FAIL)
  1623. X            {
  1624. X                    /* space wraps to next line if 'whichwrap' bit 1 set */
  1625. X                    /* 'l' wraps to next line if 'whichwrap' bit 2 set */
  1626. X                    /* CURS_RIGHT wraps to next line if 'whichwrap' bit 3 set */
  1627. X                if (((c == ' ' && (p_ww & 2)) ||
  1628. X                     (c == 'l' && (p_ww & 4)) ||
  1629. X                     (c == K_RARROW && (p_ww & 8))) &&
  1630. X                         curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
  1631. X                {
  1632. X                    ++curwin->w_cursor.lnum;
  1633. X                    curwin->w_cursor.col = 0;
  1634. X                    curwin->w_set_curswant = TRUE;
  1635. X                    continue;
  1636. X                }
  1637. X                if (operator == NOP)
  1638. X                    beep();
  1639. X                else
  1640. X                {
  1641. X                    if (lineempty(curwin->w_cursor.lnum))
  1642. X                        CLEAROPBEEP;
  1643. X                    else
  1644. X                    {
  1645. X                        mincl = TRUE;
  1646. X                        if (n)
  1647. X                            beep();
  1648. X                    }
  1649. X                }
  1650. X                break;
  1651. X            }
  1652. X        }
  1653. X        break;
  1654. X
  1655. X      case Ctrl('H'):
  1656. X      case 'h':
  1657. X      case K_LARROW:
  1658. X      case DEL:
  1659. X        mtype = MCHAR;
  1660. X        mincl = FALSE;
  1661. X        n = Prenum1;
  1662. X        while (n--)
  1663. X        {
  1664. X            if (oneleft() == FAIL)
  1665. X            {
  1666. X                    /* backspace and del wrap to previous line if 'whichwrap'
  1667. X                     *                                            bit 0 set */
  1668. X                    /* 'h' wraps to previous line if 'whichwrap' bit 2 set */
  1669. X                    /* CURS_LEFT wraps to previous line if 'whichwrap' bit 3 set */
  1670. X                if ((((c == Ctrl('H') || c == DEL) && (p_ww & 1)) ||
  1671. X                     (c == 'h' && (p_ww & 4)) ||
  1672. X                     (c == K_LARROW && (p_ww & 8))) &&
  1673. X                            curwin->w_cursor.lnum > 1)
  1674. X                {
  1675. X                    --(curwin->w_cursor.lnum);
  1676. X                    coladvance(MAXCOL);
  1677. X                    curwin->w_set_curswant = TRUE;
  1678. X                    continue;
  1679. X                }
  1680. X                else if (operator != DELETE && operator != CHANGE)
  1681. X                    beep();
  1682. X                else if (Prenum1 == 1)
  1683. X                    CLEAROPBEEP;
  1684. X                break;
  1685. X            }
  1686. X        }
  1687. X        break;
  1688. X
  1689. X      case '-':
  1690. X        flag = TRUE;
  1691. X        /* FALLTHROUGH */
  1692. X
  1693. X      case 'k':
  1694. X      case K_UARROW:
  1695. X      case Ctrl('P'):
  1696. X        mtype = MLINE;
  1697. X        if (oneup(Prenum1) == FAIL)
  1698. X            CLEAROPBEEP;
  1699. X        else if (flag)
  1700. X            beginline(TRUE);
  1701. X        break;
  1702. X
  1703. X      case '+':
  1704. X      case CR:
  1705. X        flag = TRUE;
  1706. X        /* FALLTHROUGH */
  1707. X
  1708. X      case 'j':
  1709. X      case K_DARROW:
  1710. X      case Ctrl('N'):
  1711. X      case NL:
  1712. X        mtype = MLINE;
  1713. X        if (onedown(Prenum1) == FAIL)
  1714. X            CLEAROPBEEP;
  1715. X        else if (flag)
  1716. X            beginline(TRUE);
  1717. X        break;
  1718. X
  1719. X        /*
  1720. X         * This is a strange motion command that helps make operators more
  1721. X         * logical. It is actually implemented, but not documented in the
  1722. X         * real 'vi'. This motion command actually refers to "the current
  1723. X         * line". Commands like "dd" and "yy" are really an alternate form of
  1724. X         * "d_" and "y_". It does accept a count, so "d3_" works to delete 3
  1725. X         * lines.
  1726. X         */
  1727. X      case '_':
  1728. Xlineop:
  1729. X        mtype = MLINE;
  1730. X        if (onedown((long)(Prenum1 - 1)) == FAIL)
  1731. X            CLEAROPBEEP;
  1732. X        if (operator != YANK)            /* 'Y' does not move cursor */
  1733. X            beginline(TRUE);
  1734. X        break;
  1735. X
  1736. X      case '|':
  1737. X        mtype = MCHAR;
  1738. X        mincl = TRUE;
  1739. X        beginline(FALSE);
  1740. X        if (Prenum > 0)
  1741. X            coladvance((colnr_t)(Prenum - 1));
  1742. X        curwin->w_curswant = (colnr_t)(Prenum - 1);
  1743. X            /* keep curswant at the column where we wanted to go, not where
  1744. X                we ended; differs is line is too short */
  1745. X        curwin->w_set_curswant = FALSE;
  1746. X        break;
  1747. X
  1748. X        /*
  1749. X         * Word Motions
  1750. X         */
  1751. X
  1752. X      case 'B':
  1753. X        type = 1;
  1754. X        /* FALLTHROUGH */
  1755. X
  1756. X      case 'b':
  1757. X      case K_SLARROW:
  1758. X        mtype = MCHAR;
  1759. X        mincl = FALSE;
  1760. X        curwin->w_set_curswant = TRUE;
  1761. X        if (bck_word(Prenum1, type))
  1762. X            CLEAROPBEEP;
  1763. X        break;
  1764. X
  1765. X      case 'E':
  1766. X        type = 1;
  1767. X        /* FALLTHROUGH */
  1768. X
  1769. X      case 'e':
  1770. X        mincl = TRUE;
  1771. X        goto dowrdcmd;
  1772. X
  1773. X      case 'W':
  1774. X        type = 1;
  1775. X        /* FALLTHROUGH */
  1776. X
  1777. X      case 'w':
  1778. X      case K_SRARROW:
  1779. X        mincl = FALSE;
  1780. X        flag = TRUE;
  1781. X        /*
  1782. X         * This is a little strange. To match what the real vi does, we
  1783. X         * effectively map 'cw' to 'ce', and 'cW' to 'cE', provided that we are
  1784. X         * not on a space or a TAB. This seems
  1785. X         * impolite at first, but it's really more what we mean when we say
  1786. X         * 'cw'.
  1787. X         * Another strangeness: When standing on the end of a word "ce" will
  1788. X         * change until the end of the next wordt, but "cw" will change only
  1789. X         * one character! This is done by setting type to 2.
  1790. X         */
  1791. X        if (operator == CHANGE && (n = gchar_cursor()) != ' ' && n != TAB &&
  1792. X                                                                n != NUL)
  1793. X        {
  1794. X            mincl = TRUE;
  1795. X            flag = FALSE;
  1796. X            flag2 = TRUE;
  1797. X        }
  1798. X
  1799. Xdowrdcmd:
  1800. X        mtype = MCHAR;
  1801. X        curwin->w_set_curswant = TRUE;
  1802. X        if (flag)
  1803. X            n = fwd_word(Prenum1, type, operator != NOP);
  1804. X        else
  1805. X            n = end_word(Prenum1, type, flag2);
  1806. X        if (n)
  1807. X        {
  1808. X            CLEAROPBEEP;
  1809. X            break;
  1810. X        }
  1811. X#if 0
  1812. X        /*
  1813. X         * If we do a 'dw' for the last word in a line, we only delete the rest
  1814. X         * of the line, not joining the two lines, unless the current line is empty.
  1815. X         */
  1816. X        if (operator == DELETE && Prenum1 == 1 &&
  1817. X                curbuf->b_startop.lnum != curwin->w_cursor.lnum && !lineempty(startop.lnum))
  1818. X        {
  1819. X                curwin->w_cursor = curbuf->b_startop;
  1820. X                while (oneright() == OK)
  1821. X                    ;
  1822. X                mincl = TRUE;
  1823. X        }
  1824. X#endif
  1825. X        break;
  1826. X
  1827. X      case '$':
  1828. X        mtype = MCHAR;
  1829. X        mincl = TRUE;
  1830. X        curwin->w_curswant = MAXCOL;                /* so we stay at the end */
  1831. X        if (onedown((long)(Prenum1 - 1)) == FAIL)
  1832. X        {
  1833. X            CLEAROPBEEP;
  1834. X            break;
  1835. X        }
  1836. X        break;
  1837. X
  1838. X      case '^':
  1839. X        flag = TRUE;
  1840. X        /* FALLTHROUGH */
  1841. X
  1842. X      case '0':
  1843. X        mtype = MCHAR;
  1844. X        mincl = FALSE;
  1845. X        beginline(flag);
  1846. X        break;
  1847. X
  1848. X/*
  1849. X * 4: Searches
  1850. X */
  1851. X      case '?':
  1852. X      case '/':
  1853. X        if (!getcmdline(c, searchbuff))
  1854. X        {
  1855. X            CLEAROP;
  1856. X            break;
  1857. X        }
  1858. X        mtype = MCHAR;
  1859. X        mincl = FALSE;
  1860. X        curwin->w_set_curswant = TRUE;
  1861. X
  1862. X        n = dosearch(c, searchbuff, FALSE, Prenum1, TRUE, TRUE);
  1863. X        if (n == 0)
  1864. X            CLEAROP;
  1865. X        else if (n == 2)
  1866. X            mtype = MLINE;
  1867. X        break;
  1868. X
  1869. X      case 'N':
  1870. X        flag = 1;
  1871. X
  1872. X      case 'n':
  1873. X        mtype = MCHAR;
  1874. X        mincl = FALSE;
  1875. X        curwin->w_set_curswant = TRUE;
  1876. X        if (!dosearch(0, NULL, flag, Prenum1, TRUE, TRUE))
  1877. X            CLEAROP;
  1878. X        break;
  1879. X
  1880. X        /*
  1881. X         * Character searches
  1882. X         */
  1883. X      case 'T':
  1884. X        dir = BACKWARD;
  1885. X        /* FALLTHROUGH */
  1886. X
  1887. X      case 't':
  1888. X        type = 1;
  1889. X        goto docsearch;
  1890. X
  1891. X      case 'F':
  1892. X        dir = BACKWARD;
  1893. X        /* FALLTHROUGH */
  1894. X
  1895. X      case 'f':
  1896. Xdocsearch:
  1897. X        mtype = MCHAR;
  1898. X        if (dir == BACKWARD)
  1899. X            mincl = FALSE;
  1900. X        else
  1901. X            mincl = TRUE;
  1902. X        curwin->w_set_curswant = TRUE;
  1903. X        if (!searchc(nchar, dir, type, Prenum1))
  1904. X            CLEAROPBEEP;
  1905. X        break;
  1906. X
  1907. X      case ',':
  1908. X        flag = 1;
  1909. X        /* FALLTHROUGH */
  1910. X
  1911. X      case ';':
  1912. X        dir = flag;
  1913. X        goto docsearch;        /* nchar == NUL, thus repeat previous search */
  1914. X
  1915. X        /*
  1916. X         * section or C function searches
  1917. X         */
  1918. X      case '[':
  1919. X        dir = BACKWARD;
  1920. X        /* FALLTHROUGH */
  1921. X
  1922. X      case ']':
  1923. X        mtype = MCHAR;
  1924. X        mincl = FALSE;
  1925. X
  1926. X        /*
  1927. X         * "[f" or "]f" : Edit file under the cursor (same as "gf")
  1928. X         */
  1929. X        if ((c == ']' || c == '[') && nchar == 'f')
  1930. X            goto gotofile;
  1931. X
  1932. X        /*
  1933. X         * "[{", "[(", "]}" or "])": go to Nth unclosed '{', '(', '}' or ')'
  1934. X         */
  1935. X        if ((c == '[' && (nchar == '{' || nchar == '(')) ||
  1936. X           ((c == ']' && (nchar == '}' || nchar == ')'))))
  1937. X        {
  1938. X            FPOS old_pos;
  1939. X
  1940. X            old_pos = curwin->w_cursor;
  1941. X            while (Prenum1--)
  1942. X            {
  1943. X                if ((pos = showmatch(nchar)) == NULL)
  1944. X                {
  1945. X                    CLEAROPBEEP;
  1946. X                    break;
  1947. X                }
  1948. X                curwin->w_cursor = *pos;
  1949. X            }
  1950. X            curwin->w_cursor = old_pos;
  1951. X            if (pos != NULL)
  1952. X            {
  1953. X                setpcmark();
  1954. X                curwin->w_cursor = *pos;
  1955. X                curwin->w_set_curswant = TRUE;
  1956. X            }
  1957. X            break;
  1958. X        }
  1959. X
  1960. X        /*
  1961. X         * "[[", "[]", "]]" and "][": move to start or end of function
  1962. X         */
  1963. X        if (nchar == '[' || nchar == ']')
  1964. X        {
  1965. X            if (nchar == c)                /* "]]" or "[[" */
  1966. X                flag = '{';
  1967. X            else
  1968. X                flag = '}';                /* "][" or "[]" */
  1969. X
  1970. X            curwin->w_set_curswant = TRUE;
  1971. X            /*
  1972. X             * Imitate strange vi behaviour: When using "]]" with an operator we
  1973. X             * also stop at '}'.
  1974. X             */
  1975. X            if (!findpar(dir, Prenum1, flag,
  1976. X                            (operator != NOP && dir == FORWARD && flag == '{')))
  1977. X                CLEAROPBEEP;
  1978. X            break;
  1979. X        }
  1980. X
  1981. X        /*
  1982. X         * "[p" and "]p": put with indent adjustment
  1983. X         */
  1984. X        if (nchar == 'p')
  1985. X        {
  1986. X            doput((c == ']') ? FORWARD : BACKWARD, Prenum1, TRUE);
  1987. X            modified = TRUE;
  1988. X            break;
  1989. X        }
  1990. X
  1991. X        /*
  1992. X         * end of '[' and ']': not a valid nchar
  1993. X         */
  1994. X        CLEAROPBEEP;
  1995. X        break;
  1996. X
  1997. X      case '%':
  1998. X        mincl = TRUE;
  1999. X        if (Prenum)        /* {cnt}% : goto {cnt} percentage in file */
  2000. X        {
  2001. X            if (Prenum > 100)
  2002. X                CLEAROPBEEP;
  2003. X            else
  2004. X            {
  2005. X                mtype = MLINE;
  2006. X                setpcmark();
  2007. X                        /* round up, so CTRL-G will give same value */
  2008. X                curwin->w_cursor.lnum = (curbuf->b_ml.ml_line_count * Prenum + 99) / 100;
  2009. X                beginline(TRUE);
  2010. X            }
  2011. X        }
  2012. X        else            /* % : go to matching paren */
  2013. X        {
  2014. X            mtype = MCHAR;
  2015. X            if ((pos = showmatch(NUL)) == NULL)
  2016. X                CLEAROPBEEP;
  2017. X            else
  2018. X            {
  2019. X                setpcmark();
  2020. X                curwin->w_cursor = *pos;
  2021. X                curwin->w_set_curswant = TRUE;
  2022. X            }
  2023. X        }
  2024. X        break;
  2025. X
  2026. X      case '(':
  2027. X        dir = BACKWARD;
  2028. X        /* FALLTHROUGH */
  2029. X
  2030. X      case ')':
  2031. X        mtype = MCHAR;
  2032. X        if (c == ')')
  2033. X            mincl = FALSE;
  2034. X        else
  2035. X            mincl = TRUE;
  2036. X        curwin->w_set_curswant = TRUE;
  2037. X
  2038. X        if (!findsent(dir, Prenum1))
  2039. X            CLEAROPBEEP;
  2040. X        break;
  2041. X
  2042. X      case '{':
  2043. X        dir = BACKWARD;
  2044. X        /* FALLTHROUGH */
  2045. X
  2046. X      case '}':
  2047. X        mtype = MCHAR;
  2048. X        mincl = FALSE;
  2049. X        curwin->w_set_curswant = TRUE;
  2050. X        if (!findpar(dir, Prenum1, NUL, FALSE))
  2051. X            CLEAROPBEEP;
  2052. X        break;
  2053. X
  2054. X/*
  2055. X * 5: Edits
  2056. X */
  2057. X      case '.':
  2058. X        CHECKCLEAROPQ;
  2059. X        if (start_redo(Prenum) == FAIL)
  2060. X            CLEAROPBEEP;
  2061. X        modified = TRUE;
  2062. X        break;
  2063. X
  2064. X      case 'u':
  2065. X        if (VIsual.lnum)
  2066. X            goto dooperator;
  2067. X      case K_UNDO:
  2068. X        CHECKCLEAROPQ;
  2069. X        u_undo((int)Prenum1);
  2070. X        curwin->w_set_curswant = TRUE;
  2071. X        modified = TRUE;
  2072. X        break;
  2073. X
  2074. X      case Ctrl('R'):
  2075. X        CHECKCLEAROPQ;
  2076. X          u_redo((int)Prenum1);
  2077. X        curwin->w_set_curswant = TRUE;
  2078. X        modified = TRUE;
  2079. X        break;
  2080. X
  2081. X      case 'U':
  2082. X        if (VIsual.lnum)
  2083. X            goto dooperator;
  2084. X        CHECKCLEAROPQ;
  2085. X        u_undoline();
  2086. X        curwin->w_set_curswant = TRUE;
  2087. X        modified = TRUE;
  2088. X        break;
  2089. X
  2090. X      case 'r':
  2091. X        if (VIsual.lnum)
  2092. X        {
  2093. X            c = 'c';
  2094. X            goto dooperator;
  2095. X        }
  2096. X        CHECKCLEAROPQ;
  2097. X        ptr = ml_get_cursor();
  2098. X        if (STRLEN(ptr) < (unsigned)Prenum1)    /* not enough characters to replace */
  2099. X        {
  2100. X            CLEAROPBEEP;
  2101. X            break;
  2102. X        }
  2103. X        /*
  2104. X         * Replacing with a line break or tab is done by edit(), because it
  2105. X         * is complicated.
  2106. X         * Other characters are done below to avoid problems with things like
  2107. X         * CTRL-V 048 (for edit() this would be R CTRL-V 0 ESC).
  2108. X         */
  2109. X        if (nchar == '\r' || nchar == '\n' || nchar == '\t')
  2110. X        {
  2111. X            prep_redo(Prenum1, 'r', nchar, NUL);
  2112. X            stuffnumReadbuff(Prenum1);
  2113. X            stuffcharReadbuff('R');
  2114. X            stuffcharReadbuff(nchar);
  2115. X            stuffcharReadbuff(ESC);
  2116. X            break;
  2117. X        }
  2118. X
  2119. X        if (nchar == Ctrl('V'))                /* get another character */
  2120. X        {
  2121. X            c = Ctrl('V');
  2122. X            nchar = get_literal(&type);
  2123. X            if (type)                        /* typeahead */
  2124. X                stuffcharReadbuff(type);
  2125. X        }
  2126. X        else
  2127. X            c = NUL;
  2128. X        prep_redo(Prenum1, 'r', c, nchar);
  2129. X        if (!u_save_cursor())                /* save line for undo */
  2130. X            break;
  2131. X            /*
  2132. X             * Get ptr again, because u_save will have released the line.
  2133. X             * At the same time we let know that the line will be changed.
  2134. X             */
  2135. X        ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE) + curwin->w_cursor.col;
  2136. X        curwin->w_cursor.col += Prenum1 - 1;
  2137. X        while (Prenum1--)                    /* replace the characters */
  2138. X            *ptr++ = nchar;
  2139. X        curwin->w_set_curswant = TRUE;
  2140. X        CHANGED;
  2141. X        updateline();
  2142. X        modified = TRUE;
  2143. X        break;
  2144. X
  2145. X      case 'J':
  2146. X        if (VIsual.lnum)        /* join the visual lines */
  2147. X        {
  2148. X            if (curwin->w_cursor.lnum > VIsual.lnum)
  2149. X            {
  2150. X                Prenum = curwin->w_cursor.lnum - VIsual.lnum + 1;
  2151. X                curwin->w_cursor.lnum = VIsual.lnum;
  2152. X            }
  2153. X            else
  2154. X                Prenum = VIsual.lnum - curwin->w_cursor.lnum + 1;
  2155. X            VIsual.lnum = 0;
  2156. X        }
  2157. X        CHECKCLEAROP;
  2158. X        if (Prenum <= 1)
  2159. X            Prenum = 2;             /* default for join is two lines! */
  2160. X        if (curwin->w_cursor.lnum + Prenum - 1 > curbuf->b_ml.ml_line_count)    /* beyond last line */
  2161. X        {
  2162. X            CLEAROPBEEP;
  2163. X            break;
  2164. X        }
  2165. X
  2166. X        prep_redo(Prenum, 'J', NUL, NUL);
  2167. X        dodojoin(Prenum, TRUE, TRUE);
  2168. X        modified = TRUE;
  2169. X        break;
  2170. X
  2171. X      case 'P':
  2172. X        dir = BACKWARD;
  2173. X        /* FALLTHROUGH */
  2174. X
  2175. X      case 'p':
  2176. X        CHECKCLEAROPQ;
  2177. X        prep_redo(Prenum, c, NUL, NUL);
  2178. X        doput(dir, Prenum1, FALSE);
  2179. X        modified = TRUE;
  2180. X        break;
  2181. X
  2182. X      case Ctrl('A'):            /* add to number */
  2183. X      case Ctrl('X'):            /* subtract from number */
  2184. X        CHECKCLEAROPQ;
  2185. X        if (doaddsub((int)c, Prenum1) == OK)
  2186. X            prep_redo(Prenum1, c, NUL, NUL);
  2187. X        modified = TRUE;
  2188. X        break;
  2189. X
  2190. X/*
  2191. X * 6: Inserts
  2192. X */
  2193. X      case 'A':
  2194. X        curwin->w_set_curswant = TRUE;
  2195. X        while (oneright() == OK)
  2196. X                ;
  2197. X        /* FALLTHROUGH */
  2198. X
  2199. X      case 'a':
  2200. X        CHECKCLEAROPQ;
  2201. X        /* Works just like an 'i'nsert on the next character. */
  2202. X        if (u_save_cursor())
  2203. X        {
  2204. X            if (!lineempty(curwin->w_cursor.lnum))
  2205. X                inc_cursor();
  2206. X            startinsert(c, FALSE, Prenum1);
  2207. X            modified = TRUE;
  2208. X            command_busy = TRUE;
  2209. X        }
  2210. X        break;
  2211. X
  2212. X      case 'I':
  2213. X        beginline(TRUE);
  2214. X        /* FALLTHROUGH */
  2215. X
  2216. X      case 'i':
  2217. X        CHECKCLEAROPQ;
  2218. X        if (u_save_cursor())
  2219. X        {
  2220. X            startinsert(c, FALSE, Prenum1);
  2221. X            modified = TRUE;
  2222. X            command_busy = TRUE;
  2223. X        }
  2224. X        break;
  2225. X
  2226. X      case 'o':
  2227. X          if (VIsual.lnum)    /* switch start and end of visual */
  2228. X        {
  2229. X            Prenum = VIsual.lnum;
  2230. X            VIsual.lnum = curwin->w_cursor.lnum;
  2231. X            curwin->w_cursor.lnum = Prenum;
  2232. X            if (VIsual.col != VISUALLINE)
  2233. X            {
  2234. X                n = VIsual.col;
  2235. X                VIsual.col = curwin->w_cursor.col;
  2236. X                curwin->w_cursor.col = (int)n;
  2237. X                curwin->w_set_curswant = TRUE;
  2238. X            }
  2239. X            break;
  2240. X        }
  2241. X        CHECKCLEAROP;
  2242. X        if (u_save(curwin->w_cursor.lnum, (linenr_t)(curwin->w_cursor.lnum + 1)) &&
  2243. X                            Opencmd(FORWARD, TRUE, TRUE))
  2244. X        {
  2245. X            startinsert('o', TRUE, Prenum1);
  2246. X            modified = TRUE;
  2247. X            command_busy = TRUE;
  2248. X        }
  2249. X        break;
  2250. X
  2251. X      case 'O':
  2252. X        CHECKCLEAROPQ;
  2253. X        if (u_save((linenr_t)(curwin->w_cursor.lnum - 1), curwin->w_cursor.lnum) && Opencmd(BACKWARD, TRUE, TRUE))
  2254. X        {
  2255. X            startinsert('O', TRUE, Prenum1);
  2256. X            modified = TRUE;
  2257. X            command_busy = TRUE;
  2258. X        }
  2259. X        break;
  2260. X
  2261. X      case 'R':
  2262. X        if (VIsual.lnum)
  2263. X        {
  2264. X            c = 'c';
  2265. X            VIsual.col = VISUALLINE;
  2266. X            goto dooperator;
  2267. X        }
  2268. X        CHECKCLEAROPQ;
  2269. X        if (u_save_cursor())
  2270. X        {
  2271. X            startinsert('R', FALSE, Prenum1);
  2272. X            modified = TRUE;
  2273. X            command_busy = TRUE;
  2274. X        }
  2275. X        break;
  2276. X
  2277. X/*
  2278. X * 7: Operators
  2279. X */
  2280. X      case '~':         /* swap case */
  2281. X      /*
  2282. X       * if tilde is not an operator and Visual is off: swap case
  2283. X       * of a single character
  2284. X       */
  2285. X        if (!p_to && !VIsual.lnum)
  2286. X        {
  2287. X            CHECKCLEAROPQ;
  2288. X            if (lineempty(curwin->w_cursor.lnum))
  2289. X            {
  2290. X                CLEAROPBEEP;
  2291. X                break;
  2292. X            }
  2293. X            prep_redo(Prenum, '~', NUL, NUL);
  2294. X
  2295. X            if (!u_save_cursor())
  2296. X                break;
  2297. X
  2298. X            for (; Prenum1 > 0; --Prenum1)
  2299. X            {
  2300. X                if (gchar_cursor() == NUL)
  2301. X                    break;
  2302. X                swapchar(&curwin->w_cursor);
  2303. X                inc_cursor();
  2304. X            }
  2305. X
  2306. X            curwin->w_set_curswant = TRUE;
  2307. X            CHANGED;
  2308. X            updateline();
  2309. X            modified = TRUE;
  2310. X            break;
  2311. X        }
  2312. X        /*FALLTHROUGH*/
  2313. X
  2314. X      case 'd':
  2315. X      case 'c':
  2316. X      case 'y':
  2317. X      case '>':
  2318. X      case '<':
  2319. X      case '!':
  2320. X      case '=':
  2321. X      case 'Q':
  2322. Xdooperator:
  2323. X        n = STRCHR(opchars, c) - opchars + 1;
  2324. X        if (n == operator)        /* double operator works on lines */
  2325. X            goto lineop;
  2326. X        CHECKCLEAROP;
  2327. X        if (Prenum != 0)
  2328. X            opnum = Prenum;
  2329. X        curbuf->b_startop = curwin->w_cursor;
  2330. X        operator = (int)n;
  2331. X        break;
  2332. X
  2333. X/*
  2334. X * 8: Abbreviations
  2335. X */
  2336. X
  2337. X     /* when Visual the next commands are operators */
  2338. X      case 'S':
  2339. X      case 'Y':
  2340. X      case 'D':
  2341. X      case 'C':
  2342. X      case 'x':
  2343. X      case 'X':
  2344. X      case 's':
  2345. X          if (VIsual.lnum)
  2346. X        {
  2347. X            static char_u trans[] = "ScYyDdCcxdXdsc";
  2348. X
  2349. X            if (isupper(c) && !Visual_block)        /* uppercase means linewise */
  2350. X                VIsual.col = VISUALLINE;
  2351. X            c = *(STRCHR(trans, c) + 1);
  2352. X            goto dooperator;
  2353. X        }
  2354. X
  2355. X      case '&':
  2356. X        CHECKCLEAROPQ;
  2357. X        if (Prenum)
  2358. X            stuffnumReadbuff(Prenum);
  2359. X
  2360. X        if (c == 'Y' && p_ye)
  2361. X            c = 'Z';
  2362. X        {
  2363. X                static char_u *(ar[9]) = {(char_u *)"dl", (char_u *)"dh", (char_u *)"d$", (char_u *)"c$", (char_u *)"cl", (char_u *)"cc", (char_u *)"yy", (char_u *)"y$", (char_u *)":s\r"};
  2364. X                static char_u *str = (char_u *)"xXDCsSYZ&";
  2365. X
  2366. X                stuffReadbuff(ar[(int)(STRCHR(str, c) - str)]);
  2367. X        }
  2368. X        break;
  2369. X
  2370. X/*
  2371. X * 9: Marks
  2372. X */
  2373. X
  2374. X      case 'm':
  2375. X        CHECKCLEAROP;
  2376. X        if (setmark(nchar) == FAIL)
  2377. X            CLEAROPBEEP;
  2378. X        break;
  2379. X
  2380. X      case '\'':
  2381. X        flag = TRUE;
  2382. X        /* FALLTHROUGH */
  2383. X
  2384. X      case '`':
  2385. X        pos = getmark(nchar, (operator == NOP));
  2386. X        if (pos == (FPOS *)-1)    /* jumped to other file */
  2387. X        {
  2388. X            if (flag)
  2389. X                beginline(TRUE);
  2390. X            break;
  2391. X        }
  2392. X
  2393. X        if (pos != NULL)
  2394. X            setpcmark();
  2395. X
  2396. Xcursormark:
  2397. X        if (pos == NULL || pos->lnum == 0)
  2398. X            CLEAROPBEEP;
  2399. X        else
  2400. X        {
  2401. X            curwin->w_cursor = *pos;
  2402. X            if (flag)
  2403. X                beginline(TRUE);
  2404. X        }
  2405. X        mtype = flag ? MLINE : MCHAR;
  2406. X        mincl = FALSE;        /* ignored if not MCHAR */
  2407. X        curwin->w_set_curswant = TRUE;
  2408. X        break;
  2409. X
  2410. X    case Ctrl('O'):            /* goto older pcmark */
  2411. X        Prenum1 = -Prenum1;
  2412. X        /* FALLTHROUGH */
  2413. X
  2414. X    case Ctrl('I'):            /* goto newer pcmark */
  2415. X        CHECKCLEAROPQ;
  2416. X        pos = movemark((int)Prenum1);
  2417. X        if (pos == (FPOS *)-1)    /* jump to other file */
  2418. X        {
  2419. X            curwin->w_set_curswant = TRUE;
  2420. X            break;
  2421. X        }
  2422. X        goto cursormark;
  2423. X
  2424. X/*
  2425. X * 10. Buffer setting
  2426. X */
  2427. X      case '"':
  2428. X        CHECKCLEAROP;
  2429. X        if (nchar != NUL && is_yank_buffer(nchar, FALSE))
  2430. X        {
  2431. X            yankbuffer = nchar;
  2432. X            opnum = Prenum;        /* remember count before '"' */
  2433. X        }
  2434. X        else
  2435. X            CLEAROPBEEP;
  2436. X        break;
  2437. X
  2438. X/*
  2439. X * 11. Visual
  2440. X */
  2441. X       case 'v':
  2442. X      case 'V':
  2443. X      case Ctrl('V'):
  2444. X        CHECKCLEAROP;
  2445. X        Visual_block = FALSE;
  2446. X
  2447. X            /* stop Visual */
  2448. X        if (VIsual.lnum)
  2449. X        {
  2450. X            VIsual.lnum = 0;
  2451. X            updateScreen(NOT_VALID);        /* delete the inversion */
  2452. X        }
  2453. X            /* start Visual */
  2454. X        else
  2455. X        {
  2456. X            if (!didwarn && set_highlight('v') == FAIL)/* cannot highlight */
  2457. X            {
  2458. X                EMSG("Warning: terminal cannot highlight");
  2459. X                didwarn = TRUE;
  2460. X            }
  2461. X            if (Prenum)                        /* use previously selected part */
  2462. X            {
  2463. X                if (!resel_Visual_type)        /* there is none */
  2464. X                {
  2465. X                    beep();
  2466. X                    break;
  2467. X                }
  2468. X                VIsual = curwin->w_cursor;
  2469. X                if (resel_Visual_nlines > 1)
  2470. X                    curwin->w_cursor.lnum += resel_Visual_nlines * Prenum - 1;
  2471. X                switch (resel_Visual_type)
  2472. X                {
  2473. X                case 'V':    VIsual.col = VISUALLINE;
  2474. X                            break;
  2475. X
  2476. X                case Ctrl('V'):
  2477. X                            Visual_block = TRUE;
  2478. X                            break;
  2479. X
  2480. X                case 'v':        
  2481. X                            if (resel_Visual_nlines <= 1)
  2482. X                                curwin->w_cursor.col += resel_Visual_col * Prenum - 1;
  2483. X                            else
  2484. X                                curwin->w_cursor.col = resel_Visual_col;
  2485. X                            break;
  2486. X                }
  2487. X                if (resel_Visual_col == MAXCOL)
  2488. X                {
  2489. X                    curwin->w_curswant = MAXCOL;
  2490. X                    coladvance(MAXCOL);
  2491. X                }
  2492. X                else if (Visual_block)
  2493. X                    coladvance((colnr_t)(curwin->w_virtcol + resel_Visual_col * Prenum - 1));
  2494. X                curs_columns(TRUE);            /* recompute w_virtcol */
  2495. X                updateScreen(NOT_VALID);    /* show the inversion */
  2496. X            }
  2497. X            else
  2498. X            {
  2499. X                VIsual = curwin->w_cursor;
  2500. X                if (c == 'V')                /* linewise */
  2501. X                    VIsual.col = VISUALLINE;
  2502. X                else if (c == Ctrl('V'))    /* blockwise */
  2503. X                    Visual_block = TRUE;
  2504. X                updateline();                /* start the inversion */
  2505. X            }
  2506. X        }
  2507. X        break;
  2508. X
  2509. X/*
  2510. X * 12. Suspend
  2511. X */
  2512. X
  2513. X     case Ctrl('Z'):
  2514. X        CLEAROP;
  2515. X        VIsual.lnum = 0;                    /* stop Visual */
  2516. X        stuffReadbuff((char_u *)":st\r");    /* with autowrite */
  2517. X        break;
  2518. X
  2519. X/*
  2520. X * 13. Window commands
  2521. X */
  2522. X
  2523. X     case Ctrl('W'):
  2524. X        CHECKCLEAROP;
  2525. X        do_window(nchar, Prenum);            /* everything is in window.c */
  2526. X        break;
  2527. X
  2528. X/*
  2529. X *   14. extended commands (starting with 'g')
  2530. X */
  2531. X     case 'g':
  2532. X        switch (nchar)
  2533. X        {
  2534. X                        /*
  2535. X                         * "gf": goto file, edit file under cursor
  2536. X                         * "]f" and "[f": can also be used.
  2537. X                         */
  2538. X            case 'f':
  2539. Xgotofile:
  2540. X                        ptr = file_name_at_cursor();
  2541. X                            /* do autowrite if necessary */
  2542. X                        if (curbuf->b_changed && curbuf->b_nwindows <= 1 && !p_hid)
  2543. X                            autowrite(curbuf);
  2544. X                        if (ptr != NULL)
  2545. X                        {
  2546. X                            setpcmark();
  2547. X                            stuffReadbuff((char_u *) ":e ");
  2548. X                            stuffReadbuff(ptr);
  2549. X                            stuffReadbuff((char_u *) "\n");
  2550. X                            free(ptr);
  2551. X                        }
  2552. X                        else
  2553. X                            CLEAROPBEEP;
  2554. X                        break;
  2555. X
  2556. X                        /*
  2557. X                         * "gs": goto sleep
  2558. X                         */
  2559. X            case 's':    while (Prenum1-- && !got_int)
  2560. X                        {
  2561. X                            sleep(1);
  2562. X                            breakcheck();
  2563. X                        }
  2564. X                        break;
  2565. X
  2566. X            default:    CLEAROPBEEP;
  2567. X                        break;
  2568. X        }
  2569. X        break;
  2570. X
  2571. X/*
  2572. X * The end
  2573. X */
  2574. X      case ESC:
  2575. X        if (VIsual.lnum)
  2576. X        {
  2577. X            VIsual.lnum = 0;            /* stop Visual */
  2578. X            updateScreen(NOT_VALID);
  2579. X            CLEAROP;                    /* don't beep */
  2580. X            break;
  2581. X        }
  2582. X        /* Don't drop through and beep if we are canceling a command: */
  2583. X        else if (operator != NOP || opnum || Prenum || yankbuffer)
  2584. X        {
  2585. X            CLEAROP;                    /* don't beep */
  2586. X            break;
  2587. X        }
  2588. X        /* FALLTHROUGH */
  2589. X
  2590. X      default:                    /* not a known command */
  2591. X        CLEAROPBEEP;
  2592. X        break;
  2593. X
  2594. X    }    /* end of switch on command character */
  2595. X
  2596. X/*
  2597. X * if we didn't start or finish an operator, reset yankbuffer, unless we
  2598. X * need it later.
  2599. X */
  2600. X    if (!finish_op && !operator && strchr("\"DCYSsXx.", c) == NULL)
  2601. X        yankbuffer = 0;
  2602. X
  2603. X    /*
  2604. X     * If an operation is pending, handle it...
  2605. X     */
  2606. X    if ((VIsual.lnum || finish_op) && operator != NOP)
  2607. X    {
  2608. X        if (operator != YANK && !VIsual.lnum)        /* can't redo yank */
  2609. X        {
  2610. X            prep_redo(Prenum, opchars[operator - 1], c, nchar);
  2611. X            if (c == '/' || c == '?')                /* was a search */
  2612. X            {
  2613. X                AppendToRedobuff(searchbuff);
  2614. X                AppendToRedobuff(NL_STR);
  2615. X            }
  2616. X        }
  2617. X
  2618. X        if (redo_Visual_busy)
  2619. X        {
  2620. X            curbuf->b_startop = curwin->w_cursor;
  2621. X            curwin->w_cursor.lnum += redo_Visual_nlines - 1;
  2622. X            switch (redo_Visual_type)
  2623. X            {
  2624. X            case 'V':    VIsual.col = VISUALLINE;
  2625. X                        break;
  2626. X
  2627. X            case Ctrl('V'):
  2628. X                        Visual_block = TRUE;
  2629. X                        break;
  2630. X
  2631. X            case 'v':        
  2632. X                        if (redo_Visual_nlines <= 1)
  2633. X                            curwin->w_cursor.col += redo_Visual_col - 1;
  2634. X                        else
  2635. X                            curwin->w_cursor.col = redo_Visual_col;
  2636. X                        break;
  2637. X            }
  2638. X            if (redo_Visual_col == MAXCOL)
  2639. X            {
  2640. X                curwin->w_curswant = MAXCOL;
  2641. X                coladvance(MAXCOL);
  2642. X            }
  2643. X            Prenum = redo_Visual_Prenum;
  2644. X            if (Prenum == 0)
  2645. X                Prenum1 = 1L;
  2646. X            else
  2647. X                Prenum1 = Prenum;
  2648. X        }
  2649. X        else if (VIsual.lnum)
  2650. X            curbuf->b_startop = VIsual;
  2651. X
  2652. X        if (lt(curbuf->b_startop, curwin->w_cursor))
  2653. X        {
  2654. X            curbuf->b_endop = curwin->w_cursor;
  2655. X            curwin->w_cursor = curbuf->b_startop;
  2656. X        }
  2657. X        else
  2658. X        {
  2659. X            curbuf->b_endop = curbuf->b_startop;
  2660. X            curbuf->b_startop = curwin->w_cursor;
  2661. X        }
  2662. X        nlines = curbuf->b_endop.lnum - curbuf->b_startop.lnum + 1;
  2663. X
  2664. X        if (VIsual.lnum || redo_Visual_busy)
  2665. X        {
  2666. X            if (Visual_block)                /* block mode */
  2667. X            {
  2668. X                startvcol = getvcol(curwin, &(curbuf->b_startop), 2);
  2669. X                n = getvcol(curwin, &(curbuf->b_endop), 2);
  2670. X                if (n < startvcol)
  2671. X                    startvcol = (colnr_t)n;
  2672. X
  2673. X            /* if '$' was used, get endvcol from longest line */
  2674. X                if (curwin->w_curswant == MAXCOL)
  2675. X                {
  2676. X                    curwin->w_cursor.col = MAXCOL;
  2677. X                    endvcol = 0;
  2678. X                    for (curwin->w_cursor.lnum = curbuf->b_startop.lnum; curwin->w_cursor.lnum <= curbuf->b_endop.lnum; ++curwin->w_cursor.lnum)
  2679. X                        if ((n = getvcol(curwin, &curwin->w_cursor, 3)) > endvcol)
  2680. X                            endvcol = (colnr_t)n;
  2681. X                    curwin->w_cursor = curbuf->b_startop;
  2682. X                }
  2683. X                else if (redo_Visual_busy)
  2684. X                    endvcol = startvcol + redo_Visual_col - 1;
  2685. X                else
  2686. X                {
  2687. X                    endvcol = getvcol(curwin, &(curbuf->b_startop), 3);
  2688. X                    n = getvcol(curwin, &(curbuf->b_endop), 3);
  2689. X                    if (n > endvcol)
  2690. X                        endvcol = (colnr_t)n;
  2691. X                }
  2692. X                coladvance(startvcol);
  2693. X            }
  2694. X
  2695. X    /*
  2696. X     * prepare to reselect and redo Visual: this is based on the size
  2697. X     * of the Visual text
  2698. X     */
  2699. X            if (Visual_block)
  2700. X                resel_Visual_type = Ctrl('V');
  2701. X            else if (VIsual.col == VISUALLINE)
  2702. X                resel_Visual_type = 'V';
  2703. X            else
  2704. X                resel_Visual_type = 'v';
  2705. X            if (curwin->w_curswant == MAXCOL)
  2706. X                resel_Visual_col = MAXCOL;
  2707. X            else if (Visual_block)
  2708. X                resel_Visual_col = endvcol - startvcol + 1;
  2709. X            else if (nlines > 1)
  2710. X                resel_Visual_col = curbuf->b_endop.col;
  2711. X            else
  2712. X                resel_Visual_col = curbuf->b_endop.col - curbuf->b_startop.col + 1;
  2713. X            resel_Visual_nlines = nlines;
  2714. X            if (operator != YANK && operator != COLON)    /* can't redo yank and : */
  2715. X            {
  2716. X                prep_redo(0L, 'v', opchars[operator - 1], NUL);
  2717. X                redo_Visual_type = resel_Visual_type;
  2718. X                redo_Visual_col = resel_Visual_col;
  2719. X                redo_Visual_nlines = resel_Visual_nlines;
  2720. X                redo_Visual_Prenum = Prenum;
  2721. X            }
  2722. X
  2723. X            /*
  2724. X             * Mincl defaults to TRUE.
  2725. X             * If endop is on a NUL (empty line) mincl becomes FALSE
  2726. X             * This makes "d}P" and "v}dP" work the same.
  2727. X             */
  2728. X            mincl = TRUE;
  2729. X            if (VIsual.col == VISUALLINE)
  2730. X                mtype = MLINE;
  2731. X            else
  2732. X            {
  2733. X                mtype = MCHAR;
  2734. X                if (*ml_get_pos(&(curbuf->b_endop)) == NUL)
  2735. X                    mincl = FALSE;
  2736. X            }
  2737. X
  2738. X            redo_Visual_busy = FALSE;
  2739. X            /*
  2740. X             * Switch Visual off now, so screen updating does
  2741. X             * not show inverted text when the screen is redrawn.
  2742. X             * With YANK and sometimes with COLON and FILTER there is no screen
  2743. X             * redraw, so it is done here to remove the inverted part.
  2744. X             */
  2745. X            VIsual.lnum = 0;
  2746. X            if (operator == YANK || operator == COLON || operator == FILTER)
  2747. X                updateScreen(NOT_VALID);
  2748. X        }
  2749. X        else if (operator == LSHIFT || operator == RSHIFT)
  2750. X            Prenum1 = 1L;        /* if not visual mode: shift one indent */
  2751. X
  2752. X        curwin->w_set_curswant = 1;
  2753. X
  2754. X            /* no_op is set when start and end are the same */
  2755. X        no_op = (mtype == MCHAR && !mincl && equal(curbuf->b_startop, curbuf->b_endop));
  2756. X
  2757. X    /*
  2758. X     * If the end of an operator is in column one while mtype is MCHAR and mincl
  2759. X     * is FALSE, we put endop after the last character in the previous line.
  2760. X     * If startop is on or before the first non-blank in the line, the operator
  2761. X     * becomes linewise (strange, but that's the way vi does it).
  2762. X     */
  2763. X        if (mtype == MCHAR && mincl == FALSE && curbuf->b_endop.col == 0 && nlines > 1)
  2764. X        {
  2765. X            --nlines;
  2766. X            --curbuf->b_endop.lnum;
  2767. X            if (inindent())
  2768. X                mtype = MLINE;
  2769. X            else
  2770. X            {
  2771. X                curbuf->b_endop.col = STRLEN(ml_get(curbuf->b_endop.lnum));
  2772. X                if (curbuf->b_endop.col)
  2773. X                {
  2774. X                    --curbuf->b_endop.col;
  2775. X                    mincl = TRUE;
  2776. X                }
  2777. X            }
  2778. X        }
  2779. X        switch (operator)
  2780. X        {
  2781. X          case LSHIFT:
  2782. X          case RSHIFT:
  2783. X            doshift(operator, TRUE, (int)Prenum1);
  2784. X            modified = TRUE;
  2785. X            break;
  2786. X
  2787. X          case DELETE:
  2788. X            if (!no_op)
  2789. X            {
  2790. X                dodelete();
  2791. X                modified = TRUE;
  2792. X            }
  2793. X            break;
  2794. X
  2795. X          case YANK:
  2796. X            if (!no_op)
  2797. X                (void)doyank(FALSE);
  2798. X            break;
  2799. X
  2800. X          case CHANGE:
  2801. X            dochange();
  2802. X            modified = TRUE;
  2803. X            command_busy = TRUE;
  2804. X            break;
  2805. X
  2806. X          case FILTER:
  2807. X            bangredo = TRUE;            /* dobang() will put cmd in redo buffer */
  2808. X
  2809. X          case INDENT:
  2810. X          case COLON:
  2811. Xdofilter:
  2812. X            sprintf((char *)IObuff, ":%ld,%ld", (long)curbuf->b_startop.lnum, (long)curbuf->b_endop.lnum);
  2813. X            stuffReadbuff(IObuff);
  2814. X            if (operator != COLON)
  2815. X                stuffReadbuff((char_u *)"!");
  2816. X            if (operator == INDENT)
  2817. X            {
  2818. X                stuffReadbuff(p_ep);
  2819. X                stuffReadbuff((char_u *)"\n");
  2820. X            }
  2821. X            else if (operator == FORMAT)
  2822. X            {
  2823. X                stuffReadbuff(p_fp);
  2824. X                stuffReadbuff((char_u *)"\n");
  2825. X            }
  2826. X                /*    docmdline() does the rest */
  2827. X            break;
  2828. X
  2829. X          case TILDE:
  2830. X          case UPPER:
  2831. X          case LOWER:
  2832. X            if (!no_op)
  2833. X            {
  2834. X                dotilde();
  2835. X                modified = TRUE;
  2836. X            }
  2837. X            break;
  2838. X
  2839. X          case FORMAT:
  2840. X            if (*p_fp != NUL)
  2841. X                goto dofilter;        /* use external command */
  2842. X            doformat();                /* use internal function */
  2843. X            modified = TRUE;
  2844. X            break;
  2845. X
  2846. X          default:
  2847. X            CLEAROPBEEP;
  2848. X        }
  2849. X        operator = NOP;
  2850. X        Visual_block = FALSE;
  2851. X        yankbuffer = 0;
  2852. X    }
  2853. X
  2854. Xnormal_end:
  2855. X    premsg(-1, NUL);
  2856. X
  2857. X    if (restart_edit && operator == NOP && VIsual.lnum == 0 && !command_busy && stuff_empty() && yankbuffer == 0)
  2858. X    {
  2859. X        startinsert(restart_edit, FALSE, 1L);
  2860. X        modified = TRUE;
  2861. X    }
  2862. X
  2863. X    checkpcmark();            /* check if we moved since setting pcmark */
  2864. X
  2865. X/*
  2866. X * TEMPORARY: update the other windows for the current buffer if modified
  2867. X */
  2868. X    if (modified)
  2869. X    {
  2870. X        WIN        *wp;
  2871. X
  2872. X        for (wp = firstwin; wp; wp = wp->w_next)
  2873. X            if (wp != curwin && wp->w_buffer == curbuf)
  2874. X            {
  2875. X                cursor_off();
  2876. X                wp->w_redr_type = NOT_VALID;
  2877. X                win_update(wp);
  2878. X            }
  2879. X    }
  2880. X}
  2881. X
  2882. X    static void
  2883. Xprep_redo(num, cmd, c, nchar)
  2884. X    long     num;
  2885. X    int        cmd;
  2886. X    int        c;
  2887. X    int        nchar;
  2888. X{
  2889. X    ResetRedobuff();
  2890. X    if (yankbuffer != 0)    /* yank from specified buffer */
  2891. X    {
  2892. X        AppendCharToRedobuff('\"');
  2893. X        AppendCharToRedobuff(yankbuffer);
  2894. X    }
  2895. X    if (num)
  2896. X        AppendNumberToRedobuff(num);
  2897. X    AppendCharToRedobuff(cmd);
  2898. X    if (c != NUL)
  2899. X        AppendCharToRedobuff(c);
  2900. X    if (nchar != NUL)
  2901. X        AppendCharToRedobuff(nchar);
  2902. X}
  2903. X
  2904. X/*
  2905. X * check for operator active
  2906. X *
  2907. X * return TRUE if operator was active
  2908. X */
  2909. X    static int
  2910. Xcheckclearop()
  2911. X{
  2912. X    if (operator == NOP)
  2913. X        return (FALSE);
  2914. X    clearopbeep();
  2915. X    return (TRUE);
  2916. X}
  2917. X
  2918. X/*
  2919. X * check for operator or Visual active
  2920. X *
  2921. X * return TRUE if operator was active
  2922. X */
  2923. X    static int
  2924. Xcheckclearopq()
  2925. X{
  2926. X    if (operator == NOP && VIsual.lnum == 0)
  2927. X        return (FALSE);
  2928. X    clearopbeep();
  2929. X    return (TRUE);
  2930. X}
  2931. X
  2932. X    static void
  2933. Xclearopbeep()
  2934. X{
  2935. X    CLEAROP;
  2936. X    beep();
  2937. X}
  2938. X
  2939. X/*
  2940. X * display, on the last line of the window, the characters typed before
  2941. X * the last command character, plus 'c1' and 'c2'
  2942. X */
  2943. X    static void
  2944. Xpremsg(c1, c2)
  2945. X    int c1, c2;
  2946. X{
  2947. X    char_u    buf[40];
  2948. X    char_u    *p;
  2949. X
  2950. X    if (!p_sc || !(KeyTyped || c1 == -1 || c1 == ' '))
  2951. X        return;
  2952. X
  2953. X    cursor_off();
  2954. X    msg_pos((int)Rows - 1, sc_col);
  2955. X    if (c1 == -1)
  2956. X        msg_outstr((char_u *)"          ");    /* look in comp_col() for the number of spaces */
  2957. X    else
  2958. X    {
  2959. X        p = buf;
  2960. X        if (opnum)
  2961. X        {
  2962. X            sprintf((char *)p, "%ld", (long)opnum);
  2963. X            p = p + STRLEN(buf);
  2964. X        }
  2965. X        if (yankbuffer)
  2966. X        {
  2967. X            *p++ = '"';
  2968. X            *p++ = yankbuffer;
  2969. X        }
  2970. X        if (c1 == Ctrl('W'))        /* ^W is in between counts */
  2971. X        {
  2972. X            *p++ = '^';
  2973. X            *p++ = 'W';
  2974. X            c1 = NUL;
  2975. X        }
  2976. X        else if (operator == 'z')
  2977. X            *p++ = 'z';
  2978. X        else if (operator)
  2979. X            *p++ = opchars[operator - 1];
  2980. X        if (Prenum)
  2981. X        {
  2982. X            sprintf((char *)p, "%ld", (long)Prenum);
  2983. X            p = p + STRLEN(p);
  2984. X        }
  2985. X        *p = NUL;
  2986. X        if (c1)
  2987. X            STRCPY(p, transchar(c1));
  2988. X        if (c2)
  2989. X            STRCAT(p, transchar(c2));
  2990. X        buf[10] = NUL;            /* truncate at maximal length */
  2991. X        msg_outstr(buf);
  2992. X    }
  2993. X    setcursor();
  2994. X    /* cursor_on(); */
  2995. X}
  2996. END_OF_FILE
  2997.   if test 41440 -ne `wc -c <'vim/src/normal.c'`; then
  2998.     echo shar: \"'vim/src/normal.c'\" unpacked with wrong size!
  2999.   fi
  3000.   # end of 'vim/src/normal.c'
  3001. fi
  3002. echo shar: End of archive 10 \(of 26\).
  3003. cp /dev/null ark10isdone
  3004. MISSING=""
  3005. 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 26 ; do
  3006.     if test ! -f ark${I}isdone ; then
  3007.     MISSING="${MISSING} ${I}"
  3008.     fi
  3009. done
  3010. if test "${MISSING}" = "" ; then
  3011.     echo You have unpacked all 26 archives.
  3012.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  3013. else
  3014.     echo You still must unpack the following archives:
  3015.     echo "        " ${MISSING}
  3016. fi
  3017. exit 0
  3018. exit 0 # Just in case...
  3019.