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