[BACK]Return to match.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mg

Annotation of src/usr.bin/mg/match.c, Revision 1.6

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