]> pd.if.org Git - pd_readline/blob - mg/match.c
Added mg from an OpenBSD mirror site. Many thanks to the OpenBSD team and the mg...
[pd_readline] / mg / match.c
1 /*      $OpenBSD: match.c,v 1.16 2009/06/04 02:23:37 kjell Exp $        */
2
3 /* This file is in the public domain. */
4
5 /*
6  *      Limited parenthesis matching routines
7  *
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,
10  * but there's enough overhead in the editor as it is.
11  */
12
13 #include "def.h"
14 #include "key.h"
15
16 static int      balance(void);
17 static void     displaymatch(struct line *, int);
18
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.
22  * If the character is not in the table, the character is balanced by itself.
23  */
24 static struct balance {
25         char    left, right;
26 } bal[] = {
27         { '(', ')' },
28         { '[', ']' },
29         { '{', '}' },
30         { '<', '>' },
31         { '\0', '\0' }
32 };
33
34 /*
35  * Hack to show matching paren.  Self-insert character, then show matching
36  * character, if any.  Bound to "blink-and-insert".
37  */
38 int
39 showmatch(int f, int n)
40 {
41         int     i, s;
42
43         for (i = 0; i < n; i++) {
44                 if ((s = selfinsert(FFRAND, 1)) != TRUE)
45                         return (s);
46                 /* unbalanced -- warn user */
47                 if (balance() != TRUE)
48                         ttbeep();
49         }
50         return (TRUE);
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  */
60 static int
61 balance(void)
62 {
63         struct line     *clp;
64         int      cbo;
65         int      c, i, depth;
66         int      rbal, lbal;
67
68         rbal = key.k_chars[key.k_count - 1];
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
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          */
83         clp = curwp->w_dotp;
84         cbo = curwp->w_doto - 1;
85
86         /* init nesting depth */
87         depth = 0;
88
89         for (;;) {
90                 if (cbo == 0) {
91                         clp = lback(clp);       /* beginning of line    */
92                         if (clp == curbp->b_headp)
93                                 return (FALSE);
94                         cbo = llength(clp) + 1;
95                 }
96                 if (--cbo == llength(clp))
97                         c = '\n';               /* end of line          */
98                 else
99                         c = lgetc(clp, cbo);    /* somewhere in middle  */
100
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                  */
107                 if (c == lbal) {
108                         if (depth == 0) {
109                                 displaymatch(clp, cbo);
110                                 return (TRUE);
111                         } else
112                                 depth--;
113                 }
114                 /* Check for another level of nesting.   */
115                 if (c == rbal)
116                         depth++;
117         }
118         /* NOTREACHED */
119 }
120
121 /*
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,
124  * move dot to the matching character, sit there a while, then move back.
125  */
126 static void
127 displaymatch(struct line *clp, int cbo)
128 {
129         struct line     *tlp;
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          */
141         inwindow = FALSE;
142         for (tlp = curwp->w_linep; tlp != lforw(curwp->w_dotp);
143             tlp = lforw(tlp))
144                 if (tlp == clp)
145                         inwindow = TRUE;
146
147         if (inwindow == TRUE) {
148                 tlp = curwp->w_dotp;    /* save current position */
149                 tbo = curwp->w_doto;
150
151                 curwp->w_dotp = clp;    /* move to new position */
152                 curwp->w_doto = cbo;
153                 curwp->w_rflag |= WFMOVE;
154
155                 update();               /* show match */
156                 ttwait(1000);           /* wait for key or 1 second */
157
158                 curwp->w_dotp = tlp;    /* return to old position */
159                 curwp->w_doto = tbo;
160                 curwp->w_rflag |= WFMOVE;
161                 update();
162         } else {
163                 /* match is not in this window, so display line in echo area */
164                 bufo = 0;
165                 for (cp = 0; cp < llength(clp); cp++) {
166                         c = lgetc(clp, cp);
167                         if (c != '\t'
168 #ifdef NOTAB
169                             || (curbp->b_flag & BFNOTAB)
170 #endif
171                                 )
172                                 if (ISCTRL(c)) {
173                                         buf[bufo++] = '^';
174                                         buf[bufo++] = CCHR(c);
175                                 } else
176                                         buf[bufo++] = c;
177                         else
178                                 do {
179                                         buf[bufo++] = ' ';
180                                 } while (bufo & 7);
181                 }
182                 buf[bufo++] = '\0';
183                 ewprintf("Matches %s", buf);
184         }
185 }