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: }