home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d3xx / d352 / mg.lha / MG / src.LZH / mg / match.c < prev    next >
C/C++ Source or Header  |  1990-05-23  |  5KB  |  204 lines

  1. /*
  2.  * Name:    MicroEMACS Limited parenthesis matching routines
  3.  * 
  4.  * The hacks in this file implement automatic matching of (), [], {}, and other
  5.  * characters.     It would be better to have a full-blown syntax table, but
  6.  * there's enough overhead in the editor as it is.
  7.  * 
  8.  * Since I often edit Scribe code, I've made it possible to blink arbitrary
  9.  * characters -- just bind delimiter characters to
  10.  * "blink-matching-paren-hack"
  11.  */
  12. #include    "notab.h"
  13.  
  14. #include    "def.h"
  15. #include    "key.h"
  16. #include    "line.h"
  17. #include    "buffer.h"
  18. #include    "window.h"
  19.  
  20. static int balance PROTO((void));
  21. static VOID displaymatch PROTO((struct line * clp, int cbo));
  22.  
  23. /*
  24.  * Balance table. When balance() encounters a character that is to be
  25.  * matched, it first searches this table for a balancing left-side character.
  26.  * f the character is not in the table, the character is balanced by itself.
  27.  * This is to allow delimiters in Scribe documents to be matched.
  28.  */
  29.  
  30. static struct balance {
  31.     char            left, right;
  32. }               bal[] = {
  33.     {
  34.         '(', ')'
  35.     },
  36.     {
  37.         '[', ']'
  38.     },
  39.     {
  40.         '{', '}'
  41.     },
  42.     {
  43.         '<', '>'
  44.     },
  45.     {
  46.         '\0', '\0'
  47.     }
  48. };
  49.  
  50. /*
  51.  * Self-insert character, then show matching character, if any.  Bound to
  52.  * "blink-matching-paren-command".
  53.  */
  54.  
  55. showmatch(f, n)
  56. {
  57.     register int    i, s;
  58.  
  59.     if (f & FFRAND)
  60.         return FALSE;
  61.     for (i = 0; i < n; i++) {
  62.         if ((s = selfinsert(FFRAND, 1)) != TRUE)
  63.             return s;
  64.         if (balance() != TRUE)    /* unbalanced -- warn user */
  65.             ttbeep();
  66.     }
  67.     return TRUE;
  68. }
  69.  
  70. /*
  71.  * Search for and display a matching character.
  72.  * 
  73.  * This routine does the real work of searching backward for a balancing
  74.  * character.  If such a balancing character is found, it uses displaymatch()
  75.  * to display the match.
  76.  */
  77.  
  78. static 
  79. balance()
  80. {
  81.     register struct line *clp;
  82.     register int    cbo;
  83.     int             c;
  84.     int             i;
  85.     int             rbal, lbal;
  86.     int             depth;
  87.  
  88.     rbal = key.k_chars[key.k_count - 1];
  89.  
  90.     /* See if there is a matching character -- default to the same */
  91.  
  92.     lbal = rbal;
  93.     for (i = 0; bal[i].right != '\0'; i++)
  94.         if (bal[i].right == rbal) {
  95.             lbal = bal[i].left;
  96.             break;
  97.         }
  98.     /* Move behind the inserted character.    We are always guaranteed    */
  99.     /* that there is at least one character on the line, since one was  */
  100.     /* just self-inserted by blinkparen.                    */
  101.  
  102.     clp = curwp->w_dotp;
  103.     cbo = curwp->w_doto - 1;
  104.  
  105.     depth = 0;        /* init nesting depth         */
  106.  
  107.     for (;;) {
  108.         if (cbo == 0) {    /* beginning of line     */
  109.             clp = lback(clp);
  110.             if (clp == curbp->b_linep)
  111.                 return (FALSE);
  112.             cbo = llength(clp) + 1;
  113.         }
  114.         if (--cbo == llength(clp))    /* end of line         */
  115.             c = '\n';
  116.         else
  117.             c = lgetc(clp, cbo);    /* somewhere in middle     */
  118.  
  119.         /* Check for a matching character.  If still in a nested */
  120.         /* level, pop out of it and continue search.  This check */
  121.         /* is done before the nesting check so single-character     */
  122.         /* matches will work too.                 */
  123.         if (c == lbal) {
  124.             if (depth == 0) {
  125.                 displaymatch(clp, cbo);
  126.                 return (TRUE);
  127.             } else
  128.                 depth--;
  129.         }
  130.         /* Check for another level of nesting.     */
  131.         if (c == rbal)
  132.             depth++;
  133.     }
  134.     /* NOTREACHED */
  135. }
  136.  
  137.  
  138. /*
  139.  * Display matching character. Matching characters that are not in the
  140.  * current window are displayed in the echo line. If in the current window,
  141.  * move dot to the matching character, sit there a while, then move back.
  142.  */
  143.  
  144. static VOID 
  145. displaymatch(clp, cbo)
  146.     register struct line *clp;
  147.     register int    cbo;
  148. {
  149.     register struct line *tlp;
  150.     register int    tbo;
  151.     register int    cp;
  152.     register int    bufo;
  153.     register int    c;
  154.     int             inwindow;
  155.     char            buf[NLINE];
  156.  
  157.     /* Figure out if matching char is in current window by     */
  158.     /* searching from the top of the window to dot.         */
  159.  
  160.     inwindow = FALSE;
  161.     for (tlp = curwp->w_linep; tlp != lforw(curwp->w_dotp); tlp = lforw(tlp))
  162.         if (tlp == clp)
  163.             inwindow = TRUE;
  164.  
  165.     if (inwindow == TRUE) {
  166.         tlp = curwp->w_dotp;    /* save current position */
  167.         tbo = curwp->w_doto;
  168.  
  169.         curwp->w_dotp = clp;    /* move to new position */
  170.         curwp->w_doto = cbo;
  171.         curwp->w_flag |= WFMOVE;
  172.  
  173.         update();    /* show match */
  174.         sleep(1);    /* wait a bit */
  175.  
  176.         curwp->w_dotp = tlp;    /* return to old position */
  177.         curwp->w_doto = tbo;
  178.         curwp->w_flag |= WFMOVE;
  179.         update();
  180.     } else {        /* match not in this window so display line
  181.                  * in echo area */
  182.         bufo = 0;
  183.         for (cp = 0; cp < llength(clp); cp++) {    /* expand tabs     */
  184.             c = lgetc(clp, cp);
  185.             if (c != '\t'
  186. #ifdef    NOTAB
  187.                 || (curbp->b_flag & BFNOTAB)
  188. #endif
  189.                 )
  190.                 if (ISCTRL(c)) {
  191.                     buf[bufo++] = '^';
  192.                     buf[bufo++] = CCHR(c);
  193.                 } else
  194.                     buf[bufo++] = c;
  195.             else
  196.                 do {
  197.                     buf[bufo++] = ' ';
  198.                 } while (bufo & 7);
  199.         }
  200.         buf[bufo++] = '\0';
  201.         ewprintf("Matches %s", buf);
  202.     }
  203. }
  204.