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

1.23    ! op          1: /*     $OpenBSD: match.c,v 1.22 2021/03/01 10:51:14 lum Exp $  */
1.11      kjell       2:
                      3: /* This file is in the public domain. */
1.4       niklas      4:
1.1       deraadt     5: /*
1.3       millert     6:  *     Limited parenthesis matching routines
1.1       deraadt     7:  *
1.7       mickey      8:  * The hacks in this file implement automatic matching * of (), [], {}, and
                      9:  * other characters.  It would be better to have a full-blown syntax table,
1.3       millert    10:  * but there's enough overhead in the editor as it is.
1.1       deraadt    11:  */
1.18      bcallah    12:
                     13: #include <sys/queue.h>
                     14: #include <signal.h>
                     15: #include <stdio.h>
1.1       deraadt    16:
1.3       millert    17: #include "def.h"
                     18: #include "key.h"
                     19:
1.8       millert    20: static int     balance(void);
1.12      deraadt    21: static void    displaymatch(struct line *, int);
1.1       deraadt    22:
1.2       millert    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.
1.3       millert    26:  * If the character is not in the table, the character is balanced by itself.
1.1       deraadt    27:  */
                     28: static struct balance {
1.3       millert    29:        char    left, right;
                     30: } bal[] = {
1.14      kjell      31:        { '(', ')' },
                     32:        { '[', ']' },
                     33:        { '{', '}' },
                     34:        { '<', '>' },
                     35:        { '\0', '\0' }
1.1       deraadt    36: };
                     37:
                     38: /*
1.21      lum        39:  * Hack to show matching paren.  Self-insert character, then show matching
                     40:  * character, if any.  Bound to "blink-and-insert".  Used in the mg startup
                     41:  * file to amend the default cursor behaviour of a key press, e.g:
                     42:  *   global-set-key "%" blink-and-insert
1.1       deraadt    43:  */
1.3       millert    44: int
1.9       cloder     45: showmatch(int f, int n)
1.1       deraadt    46: {
1.3       millert    47:        int     i, s;
1.1       deraadt    48:
                     49:        for (i = 0; i < n; i++) {
                     50:                if ((s = selfinsert(FFRAND, 1)) != TRUE)
1.10      db         51:                        return (s);
1.3       millert    52:                /* unbalanced -- warn user */
                     53:                if (balance() != TRUE)
1.17      lum        54:                        dobeep();
1.1       deraadt    55:        }
1.10      db         56:        return (TRUE);
1.1       deraadt    57: }
                     58:
                     59: /*
                     60:  * Search for and display a matching character.
                     61:  *
                     62:  * This routine does the real work of searching backward
                     63:  * for a balancing character.  If such a balancing character
                     64:  * is found, it uses displaymatch() to display the match.
                     65:  */
1.3       millert    66: static int
1.9       cloder     67: balance(void)
1.1       deraadt    68: {
1.12      deraadt    69:        struct line     *clp;
1.3       millert    70:        int      cbo;
1.10      db         71:        int      c, i, depth;
                     72:        int      rbal, lbal;
1.1       deraadt    73:
1.2       millert    74:        rbal = key.k_chars[key.k_count - 1];
1.1       deraadt    75:
                     76:        /* See if there is a matching character -- default to the same */
                     77:        lbal = rbal;
                     78:        for (i = 0; bal[i].right != '\0'; i++)
                     79:                if (bal[i].right == rbal) {
                     80:                        lbal = bal[i].left;
                     81:                        break;
                     82:                }
                     83:
1.3       millert    84:        /*
                     85:         * Move behind the inserted character.  We are always guaranteed
1.19      bcallah    86:         * that there is at least one character on the line.
1.3       millert    87:         */
1.1       deraadt    88:        clp = curwp->w_dotp;
                     89:        cbo = curwp->w_doto - 1;
                     90:
1.3       millert    91:        /* init nesting depth */
                     92:        depth = 0;
1.1       deraadt    93:
                     94:        for (;;) {
1.3       millert    95:                if (cbo == 0) {
                     96:                        clp = lback(clp);       /* beginning of line    */
1.13      kjell      97:                        if (clp == curbp->b_headp)
1.1       deraadt    98:                                return (FALSE);
1.2       millert    99:                        cbo = llength(clp) + 1;
1.1       deraadt   100:                }
1.3       millert   101:                if (--cbo == llength(clp))
1.22      lum       102:                        c = *curbp->b_nlchr;    /* end of line          */
1.1       deraadt   103:                else
1.3       millert   104:                        c = lgetc(clp, cbo);    /* somewhere in middle  */
1.1       deraadt   105:
1.3       millert   106:                /*
                    107:                 * Check for a matching character.  If still in a nested
                    108:                 * level, pop out of it and continue search.  This check
                    109:                 * is done before the nesting check so single-character
                    110:                 * matches will work too.
                    111:                 */
1.1       deraadt   112:                if (c == lbal) {
                    113:                        if (depth == 0) {
1.2       millert   114:                                displaymatch(clp, cbo);
1.1       deraadt   115:                                return (TRUE);
1.2       millert   116:                        } else
1.1       deraadt   117:                                depth--;
                    118:                }
1.2       millert   119:                /* Check for another level of nesting.   */
1.1       deraadt   120:                if (c == rbal)
                    121:                        depth++;
                    122:        }
1.2       millert   123:        /* NOTREACHED */
1.1       deraadt   124: }
                    125:
                    126: /*
1.7       mickey    127:  * Display matching character.  Matching characters that are not in the
                    128:  * current window are displayed in the echo line. If in the current window,
1.3       millert   129:  * move dot to the matching character, sit there a while, then move back.
1.1       deraadt   130:  */
1.6       art       131: static void
1.12      deraadt   132: displaymatch(struct line *clp, int cbo)
1.1       deraadt   133: {
1.12      deraadt   134:        struct line     *tlp;
1.3       millert   135:        int      tbo;
                    136:        int      cp;
                    137:        int      bufo;
                    138:        int      c;
                    139:        int      inwindow;
                    140:        char     buf[NLINE];
                    141:
                    142:        /*
                    143:         * Figure out if matching char is in current window by
                    144:         * searching from the top of the window to dot.
                    145:         */
1.1       deraadt   146:        inwindow = FALSE;
1.7       mickey    147:        for (tlp = curwp->w_linep; tlp != lforw(curwp->w_dotp);
1.3       millert   148:            tlp = lforw(tlp))
1.1       deraadt   149:                if (tlp == clp)
                    150:                        inwindow = TRUE;
                    151:
                    152:        if (inwindow == TRUE) {
1.5       art       153:                tlp = curwp->w_dotp;    /* save current position */
1.1       deraadt   154:                tbo = curwp->w_doto;
                    155:
1.5       art       156:                curwp->w_dotp = clp;    /* move to new position */
1.2       millert   157:                curwp->w_doto = cbo;
1.16      kjell     158:                curwp->w_rflag |= WFMOVE;
1.1       deraadt   159:
1.17      lum       160:                update(CMODE);          /* show match */
1.5       art       161:                ttwait(1000);           /* wait for key or 1 second */
1.1       deraadt   162:
1.5       art       163:                curwp->w_dotp = tlp;    /* return to old position */
1.2       millert   164:                curwp->w_doto = tbo;
1.16      kjell     165:                curwp->w_rflag |= WFMOVE;
1.17      lum       166:                update(CMODE);
1.3       millert   167:        } else {
                    168:                /* match is not in this window, so display line in echo area */
1.1       deraadt   169:                bufo = 0;
1.3       millert   170:                for (cp = 0; cp < llength(clp); cp++) {
1.2       millert   171:                        c = lgetc(clp, cp);
1.23    ! op        172:                        if (c != '\t')
1.2       millert   173:                                if (ISCTRL(c)) {
                    174:                                        buf[bufo++] = '^';
                    175:                                        buf[bufo++] = CCHR(c);
                    176:                                } else
                    177:                                        buf[bufo++] = c;
1.1       deraadt   178:                        else
                    179:                                do {
                    180:                                        buf[bufo++] = ' ';
                    181:                                } while (bufo & 7);
                    182:                }
                    183:                buf[bufo++] = '\0';
1.2       millert   184:                ewprintf("Matches %s", buf);
1.1       deraadt   185:        }
                    186: }