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