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

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