home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / editors / elvis1_5.arj / MOVE1.C < prev    next >
C/C++ Source or Header  |  1992-04-09  |  11KB  |  586 lines

  1. /* move1.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains most movement functions */
  12.  
  13. #include "config.h"
  14. #include "vi.h"
  15. #include "ctype.h"
  16.  
  17. MARK    m_updnto(m, cnt, cmd)
  18.     MARK    m;    /* movement is relative to this mark */
  19.     long    cnt;    /* a numeric argument */
  20.     char    cmd;    /* the command character */
  21. {
  22.     DEFAULT(cmd == 'G' ? nlines : 1L);
  23.  
  24.     /* move up or down 'cnt' lines */
  25.     switch (cmd)
  26.     {
  27.       case ctrl('P'):
  28.       case '-':
  29.       case 'k':
  30.         m -= MARK_AT_LINE(cnt);
  31.         break;
  32.  
  33.       case 'G':
  34.         if (cnt < 1L || cnt > nlines)
  35.         {
  36.             msg("Only %ld lines", nlines);
  37.             return MARK_UNSET;
  38.         }
  39.         m = MARK_AT_LINE(cnt);
  40.         break;
  41.  
  42.       case '_':
  43.         cnt--;
  44.         /* fall through... */
  45.  
  46.       default:
  47.         m += MARK_AT_LINE(cnt);
  48.     }
  49.  
  50.     /* if that left us screwed up, then fail */
  51.     if (m < MARK_FIRST || markline(m) > nlines)
  52.     {
  53.         return MARK_UNSET;
  54.     }
  55.  
  56.     return m;
  57. }
  58.  
  59. /*ARGSUSED*/
  60. MARK    m_right(m, cnt, key, prevkey)
  61.     MARK    m;    /* movement is relative to this mark */
  62.     long    cnt;    /* a numeric argument */
  63.     int    key;    /* movement keystroke */
  64.     int    prevkey;/* operator keystroke, or 0 if none */
  65. {
  66.     int        idx;    /* index of the new cursor position */
  67.  
  68.     DEFAULT(1);
  69.  
  70.     /* If used with an operator, then move 1 less character, since the 'l'
  71.      * command includes the character that it moves onto.
  72.      */
  73.     if (prevkey != '\0')
  74.     {
  75.         cnt--;
  76.     }
  77.  
  78.     /* move to right, if that's OK */
  79.     pfetch(markline(m));
  80.     idx = markidx(m) + cnt;
  81.     if (idx < plen)
  82.     {
  83.         m += cnt;
  84.     }
  85.     else
  86.     {
  87.         return MARK_UNSET;
  88.     }
  89.  
  90.     return m;
  91. }
  92.  
  93. /*ARGSUSED*/
  94. MARK    m_left(m, cnt)
  95.     MARK    m;    /* movement is relative to this mark */
  96.     long    cnt;    /* a numeric argument */
  97. {
  98.     DEFAULT(1);
  99.  
  100.     /* move to the left, if that's OK */
  101.     if (markidx(m) >= cnt)
  102.     {
  103.         m -= cnt;
  104.     }
  105.     else
  106.     {
  107.         return MARK_UNSET;
  108.     }
  109.  
  110.     return m;
  111. }
  112.  
  113. /*ARGSUSED*/
  114. MARK    m_tocol(m, cnt, cmd)
  115.     MARK    m;    /* movement is relative to this mark */
  116.     long    cnt;    /* a numeric argument */
  117.     int    cmd;    /* either ctrl('X') or '|' */
  118. {
  119.     char    *text;    /* text of the line */
  120.     int    col;    /* column number */
  121.     int    idx;    /* index into the line */
  122.  
  123.  
  124.     /* if doing ^X, then adjust for sideways scrolling */
  125.     if (cmd == ctrl('X'))
  126.     {
  127.         DEFAULT(*o_columns & 0xff);
  128.         cnt += leftcol;
  129.     }
  130.     else
  131.     {
  132.         DEFAULT(1);
  133.     }
  134.  
  135.     /* internally, columns are numbered 0..COLS-1, not 1..COLS */
  136.     cnt--;
  137.  
  138.     /* if 0, that's easy */
  139.     if (cnt == 0)
  140.     {
  141.         m &= ~(BLKSIZE - 1);
  142.         return m;
  143.     }
  144.  
  145.     /* find that column within the line */
  146.     pfetch(markline(m));
  147.     text = ptext;
  148.     for (col = idx = 0; col < cnt && *text; text++, idx++)
  149.     {
  150.         if (*text == '\t' && !*o_list)
  151.         {
  152.             col += *o_tabstop;
  153.             col -= col % *o_tabstop;
  154.         }
  155.         else if (UCHAR(*text) < ' ' || *text == '\177')
  156.         {
  157.             col += 2;
  158.         }
  159. #ifndef NO_CHARATTR
  160.         else if (text[0] == '\\' && text[1] == 'f' && text[2] && *o_charattr)
  161.         {
  162.             text += 2; /* plus one more as part of for loop */
  163.         }
  164. #endif
  165.         else
  166.         {
  167.             col++;
  168.         }
  169.     }
  170.     if (!*text)
  171.     {
  172.         /* the desired column was past the end of the line, so
  173.          * act like the user pressed "$" instead.
  174.          */
  175.         return m | (BLKSIZE - 1);
  176.     }
  177.     else
  178.     {
  179.         m = (m & ~(BLKSIZE - 1)) + idx;
  180.     }
  181.     return m;
  182. }
  183.  
  184. /*ARGSUSED*/
  185. MARK    m_front(m, cnt)
  186.     MARK    m;    /* movement is relative to this mark */
  187.     long    cnt;    /* a numeric argument (ignored) */
  188. {
  189.     char    *scan;
  190.  
  191.     /* move to the first non-whitespace character */
  192.     pfetch(markline(m));
  193.     scan = ptext;
  194.     m &= ~(BLKSIZE - 1);
  195.     while (*scan == ' ' || *scan == '\t')
  196.     {
  197.         scan++;
  198.         m++;
  199.     }
  200.  
  201.     return m;
  202. }
  203.  
  204. /*ARGSUSED*/
  205. MARK    m_rear(m, cnt)
  206.     MARK    m;    /* movement is relative to this mark */
  207.     long    cnt;    /* a numeric argument (ignored) */
  208. {
  209.     /* Try to move *EXTREMELY* far to the right.  It is fervently hoped
  210.      * that other code will convert this to a more reasonable MARK before
  211.      * anything tries to actually use it.  (See adjmove() in vi.c)
  212.      */
  213.     return m | (BLKSIZE - 1);
  214. }
  215.  
  216. #ifndef NO_SENTENCE
  217. static int isperiod(ptr)
  218.     char    *ptr;    /* pointer to possible sentence-ender */
  219. {
  220.     /* if not '.', '?', or '!', then it isn't a sentence ender */
  221.     if (*ptr != '.' && *ptr != '?' && *ptr != '!')
  222.     {
  223.         return FALSE;
  224.     }
  225.  
  226.     /* skip any intervening ')', ']', or '"' characters */
  227.     do
  228.     {
  229.         ptr++;
  230.     } while (*ptr == ')' || *ptr == ']' || *ptr == '"');
  231.  
  232.     /* do we have two spaces or EOL? */
  233.     if (!*ptr || ptr[0] == ' ' && ptr[1] == ' ')
  234.     {
  235.         return TRUE;
  236.     }
  237.     return FALSE;
  238. }
  239.  
  240. /*ARGSUSED*/
  241. MARK    m_sentence(m, cnt, cmd)
  242.     MARK    m;    /* movement is relative to this mark */
  243.     long    cnt;    /* a numeric argument */
  244.     int    cmd;    /* either '(' or ')' */
  245. {
  246.     REG char    *text;
  247.     REG long    l;
  248.  
  249.     DEFAULT(1);
  250.  
  251.     /* If '(' command, then move back one word, so that if we hit '(' at
  252.      * the start of a sentence we don't simply stop at the end of the
  253.      * previous sentence and bounce back to the start of this one again.
  254.      */
  255.     if (cmd == '(')
  256.     {
  257.         m = m_bword(m, 1L, 'b');
  258.         if (!m)
  259.         {
  260.             return m;
  261.         }
  262.     }
  263.  
  264.     /* get the current line */
  265.     l = markline(m);
  266.     pfetch(l);
  267.     text = ptext + markidx(m);
  268.  
  269.     /* for each requested sentence... */
  270.     while (cnt-- > 0)
  271.     {
  272.         /* search forward for one of [.?!] followed by spaces or EOL */
  273.         do
  274.         {
  275.             if (cmd == ')')
  276.             {
  277.                 /* move forward, wrap at end of line */
  278.                 if (!text[0])
  279.                 {
  280.                     if (l >= nlines)
  281.                     {
  282.                         return MARK_UNSET;
  283.                     }
  284.                     l++;
  285.                     pfetch(l);
  286.                     text = ptext;
  287.                 }
  288.                 else
  289.                 {
  290.                     text++;
  291.                 }
  292.             }
  293.             else
  294.             {
  295.                 /* move backward, wrap at beginning of line */
  296.                 if (text == ptext)
  297.                 {
  298.                     do
  299.                     {
  300.                         if (l <= 1)
  301.                         {
  302.                             return MARK_FIRST;
  303.                         }
  304.                         l--;
  305.                         pfetch(l);
  306.                     } while (!*ptext);
  307.                     text = ptext + plen - 1;
  308.                 }
  309.                 else
  310.                 {
  311.                     text--;
  312.                 }
  313.             }
  314.         } while (!isperiod(text));
  315.     }
  316.  
  317.     /* construct a mark for this location */
  318.     m = buildmark(text);
  319.  
  320.     /* move forward to the first word of the next sentence */
  321.     m = m_fword(m, 1L, 'w', '\0');
  322.  
  323.     return m;
  324. }
  325. #endif
  326.  
  327. MARK    m_paragraph(m, cnt, cmd)
  328.     MARK    m;    /* movement is relative to this mark */
  329.     long    cnt;    /* a numeric argument */
  330.     int    cmd;    /* either '{' or '}' */
  331. {
  332.     char    *text;    /* text of the current line */
  333.     char    *pscn;    /* used to scan thru value of "paragraphs" option */
  334.     long    l, ol;    /* current line number, original line number */
  335.     int    dir;    /* -1 if we're moving up, or 1 if down */
  336.     char    col0;    /* character to expect in column 0 */
  337. #ifndef NO_SENTENCE
  338. # define SENTENCE(x)    (x)
  339.     char    *list;    /* either o_sections or o_paragraph */
  340. #else
  341. # define SENTENCE(x)
  342. #endif
  343.  
  344.     DEFAULT(1);
  345.  
  346.     /* set the direction, based on the command */
  347.     switch (cmd)
  348.     {
  349.       case '{':
  350.         dir = -1;
  351.         col0 = '\0';
  352.         SENTENCE(list = o_paragraphs); 
  353.         break;
  354.  
  355.       case '}':
  356.         dir = 1;
  357.         col0 = '\0';
  358.         SENTENCE(list = o_paragraphs); 
  359.         break;
  360.  
  361.       case '[':
  362.         if (getkey(0) != '[')
  363.         {
  364.             return MARK_UNSET;
  365.         }
  366.         dir = -1;
  367.         col0 = '{';
  368.         SENTENCE(list = o_sections); 
  369.         break;
  370.  
  371.       case ']':
  372.         if (getkey(0) != ']')
  373.         {
  374.             return MARK_UNSET;
  375.         }
  376.         dir = 1;
  377.         col0 = '{';
  378.         SENTENCE(list = o_sections); 
  379.         break;
  380.     }
  381.     ol = l = markline(m);
  382.  
  383.     /* for each paragraph that we want to travel through... */
  384.     while (l > 0 && l <= nlines && cnt-- > 0)
  385.     {
  386.         /* skip blank lines between paragraphs */
  387.         while (l > 0 && l <= nlines && col0 == *(text = fetchline(l)))
  388.         {
  389.             l += dir;
  390.         }
  391.  
  392.         /* skip non-blank lines that aren't paragraph separators
  393.          */
  394.         do
  395.         {
  396. #ifndef NO_SENTENCE
  397.             if (*text == '.' && l != ol)
  398.             {
  399.                 for (pscn = list; pscn[0] && pscn[1]; pscn += 2)
  400.                 {
  401.                     if (pscn[0] == text[1] && pscn[1] == text[2])
  402.                     {
  403.                         pscn = (char *)0;
  404.                         goto BreakBreak;
  405.                     }
  406.                 }
  407.             }
  408. #endif
  409.             l += dir;
  410.         } while (l > 0 && l <= nlines && col0 != *(text = fetchline(l)));
  411. BreakBreak:    ;
  412.     }
  413.  
  414.     if (l > nlines)
  415.     {
  416.         m = MARK_LAST;
  417.     }
  418.     else if (l <= 0)
  419.     {
  420.         m = MARK_FIRST;
  421.     }
  422.     else
  423.     {
  424.         m = MARK_AT_LINE(l);
  425.     }
  426.     return m;
  427. }
  428.  
  429.  
  430. /*ARGSUSED*/
  431. MARK    m_match(m, cnt)
  432.     MARK    m;    /* movement is relative to this mark */
  433.     long    cnt;    /* a numeric argument (normally 0) */
  434. {
  435.     long    l;
  436.     REG char    *text;
  437.     REG char    match;
  438.     REG char    nest;
  439.     REG int        count;
  440.  
  441. #ifndef NO_EXTENSIONS
  442.     /* if we're given a number, then treat it as a percentage of the file */
  443.     if (cnt > 0)
  444.     {
  445.         /* make sure it is a reasonable number */
  446.         if (cnt > 100)
  447.         {
  448.             msg("can only be from 1%% to 100%%");
  449.             return MARK_UNSET;
  450.         }
  451.  
  452.         /* return the appropriate line number */
  453.         l = (nlines - 1L) * cnt / 100L + 1L;
  454.         return MARK_AT_LINE(l);
  455.     }
  456. #endif /* undef NO_EXTENSIONS */
  457.  
  458.     /* get the current line */
  459.     l = markline(m);
  460.     pfetch(l);
  461.     text = ptext + markidx(m);
  462.  
  463.     /* search forward within line for one of "[](){}" */
  464.     for (match = '\0'; !match && *text; text++)
  465.     {
  466.         /* tricky way to recognize 'em in ASCII */
  467.         nest = *text;
  468.         if ((nest & 0xdf) == ']' || (nest & 0xdf) == '[')
  469.         {
  470.             match = nest ^ ('[' ^ ']');
  471.         }
  472.         else if ((nest & 0xfe) == '(')
  473.         {
  474.             match = nest ^ ('(' ^ ')');
  475.         }
  476.         else
  477.         {
  478.             match = 0;
  479.         }
  480.     }
  481.     if (!match)
  482.     {
  483.         return MARK_UNSET;
  484.     }
  485.     text--;
  486.  
  487.     /* search forward or backward for match */
  488.     if (match == '(' || match == '[' || match == '{')
  489.     {
  490.         /* search backward */
  491.         for (count = 1; count > 0; )
  492.         {
  493.             /* wrap at beginning of line */
  494.             if (text == ptext)
  495.             {
  496.                 do
  497.                 {
  498.                     if (l <= 1L)
  499.                     {
  500.                         return MARK_UNSET;
  501.                     }
  502.                     l--;
  503.                     pfetch(l);
  504.                 } while (!*ptext);
  505.                 text = ptext + plen - 1;
  506.             }
  507.             else
  508.             {
  509.                 text--;
  510.             }
  511.  
  512.             /* check the char */
  513.             if (*text == match)
  514.                 count--;
  515.             else if (*text == nest)
  516.                 count++;
  517.         }
  518.     }
  519.     else
  520.     {
  521.         /* search forward */
  522.         for (count = 1; count > 0; )
  523.         {
  524.             /* wrap at end of line */
  525.             if (!*text)
  526.             {
  527.                 if (l >= nlines)
  528.                 {
  529.                     return MARK_UNSET;
  530.                 }
  531.                 l++;
  532.                 pfetch(l);
  533.                 text = ptext;
  534.             }
  535.             else
  536.             {
  537.                 text++;
  538.             }
  539.  
  540.             /* check the char */
  541.             if (*text == match)
  542.                 count--;
  543.             else if (*text == nest)
  544.                 count++;
  545.         }
  546.     }
  547.  
  548.     /* construct a mark for this place */
  549.     m = buildmark(text);
  550.     return m;
  551. }
  552.  
  553. /*ARGSUSED*/
  554. MARK    m_tomark(m, cnt, key)
  555.     MARK    m;    /* movement is relative to this mark */
  556.     long    cnt;    /* (ignored) */
  557.     int    key;    /* keystroke - the mark to move to */
  558. {
  559.     /* mark '' is a special case */
  560.     if (key == '\'' || key == '`')
  561.     {
  562.         if (mark[26] == MARK_UNSET)
  563.         {
  564.             return MARK_FIRST;
  565.         }
  566.         else
  567.         {
  568.             return mark[26];
  569.         }
  570.     }
  571.  
  572.     /* if not a valid mark number, don't move */
  573.     if (key < 'a' || key > 'z')
  574.     {
  575.         return MARK_UNSET;
  576.     }
  577.  
  578.     /* return the selected mark -- may be MARK_UNSET */
  579.     if (!mark[key - 'a'])
  580.     {
  581.         msg("mark '%c is unset", key);
  582.     }
  583.     return mark[key - 'a'];
  584. }
  585.  
  586.