[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.10

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