home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume8 / micrognu / part02 / match.c < prev   
Encoding:
C/C++ Source or Header  |  1987-01-26  |  4.8 KB  |  211 lines

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