Annotation of src/usr.bin/mg/match.c, Revision 1.25
1.25 ! op 1: /* $OpenBSD: match.c,v 1.24 2023/04/17 15:18:25 op 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;
1.25 ! op 139: int col;
1.3 millert 140: int inwindow;
141: char buf[NLINE];
142:
143: /*
144: * Figure out if matching char is in current window by
145: * searching from the top of the window to dot.
146: */
1.1 deraadt 147: inwindow = FALSE;
1.7 mickey 148: for (tlp = curwp->w_linep; tlp != lforw(curwp->w_dotp);
1.3 millert 149: tlp = lforw(tlp))
1.1 deraadt 150: if (tlp == clp)
151: inwindow = TRUE;
152:
153: if (inwindow == TRUE) {
1.5 art 154: tlp = curwp->w_dotp; /* save current position */
1.1 deraadt 155: tbo = curwp->w_doto;
156:
1.5 art 157: curwp->w_dotp = clp; /* move to new position */
1.2 millert 158: curwp->w_doto = cbo;
1.16 kjell 159: curwp->w_rflag |= WFMOVE;
1.1 deraadt 160:
1.17 lum 161: update(CMODE); /* show match */
1.5 art 162: ttwait(1000); /* wait for key or 1 second */
1.1 deraadt 163:
1.5 art 164: curwp->w_dotp = tlp; /* return to old position */
1.2 millert 165: curwp->w_doto = tbo;
1.16 kjell 166: curwp->w_rflag |= WFMOVE;
1.17 lum 167: update(CMODE);
1.3 millert 168: } else {
169: /* match is not in this window, so display line in echo area */
1.1 deraadt 170: bufo = 0;
1.3 millert 171: for (cp = 0; cp < llength(clp); cp++) {
1.24 op 172: if (bufo >= sizeof(buf) - 1)
173: break;
174:
1.2 millert 175: c = lgetc(clp, cp);
1.24 op 176: if (c != '\t') {
1.2 millert 177: if (ISCTRL(c)) {
1.24 op 178: if (bufo >= sizeof(buf) - 3)
179: break;
1.2 millert 180: buf[bufo++] = '^';
181: buf[bufo++] = CCHR(c);
182: } else
183: buf[bufo++] = c;
1.24 op 184: } else {
1.25 ! op 185: col = ntabstop(bufo, curbp->b_tabw);
! 186: while (bufo < col && bufo < sizeof(buf) - 1)
1.1 deraadt 187: buf[bufo++] = ' ';
1.24 op 188: }
1.1 deraadt 189: }
190: buf[bufo++] = '\0';
1.2 millert 191: ewprintf("Matches %s", buf);
1.1 deraadt 192: }
193: }