Annotation of src/usr.bin/mg/match.c, Revision 1.24
1.24 ! op 1: /* $OpenBSD: match.c,v 1.23 2023/04/17 09:49:04 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;
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.24 ! op 171: if (bufo >= sizeof(buf) - 1)
! 172: break;
! 173:
1.2 millert 174: c = lgetc(clp, cp);
1.24 ! op 175: if (c != '\t') {
1.2 millert 176: if (ISCTRL(c)) {
1.24 ! op 177: if (bufo >= sizeof(buf) - 3)
! 178: break;
1.2 millert 179: buf[bufo++] = '^';
180: buf[bufo++] = CCHR(c);
181: } else
182: buf[bufo++] = c;
1.24 ! op 183: } else {
1.1 deraadt 184: do {
185: buf[bufo++] = ' ';
1.24 ! op 186: } while ((bufo & 7) && bufo < sizeof(buf) - 1);
! 187: }
1.1 deraadt 188: }
189: buf[bufo++] = '\0';
1.2 millert 190: ewprintf("Matches %s", buf);
1.1 deraadt 191: }
192: }