X-Git-Url: https://pd.if.org/git/?p=pd_readline;a=blobdiff_plain;f=mg%2Fmatch.c;fp=mg%2Fmatch.c;h=4c5d0c31d0b841f1c26750a5a3ea7e6899b31a1e;hp=0000000000000000000000000000000000000000;hb=a9843085ec916c175bd245a8398f30e6cc03f984;hpb=26fe4e09c6c3c250334fdeed60ce3061febecde2 diff --git a/mg/match.c b/mg/match.c new file mode 100644 index 0000000..4c5d0c3 --- /dev/null +++ b/mg/match.c @@ -0,0 +1,185 @@ +/* $OpenBSD: match.c,v 1.16 2009/06/04 02:23:37 kjell Exp $ */ + +/* This file is in the public domain. */ + +/* + * Limited parenthesis matching routines + * + * The hacks in this file implement automatic matching * of (), [], {}, and + * other characters. It would be better to have a full-blown syntax table, + * but there's enough overhead in the editor as it is. + */ + +#include "def.h" +#include "key.h" + +static int balance(void); +static void displaymatch(struct line *, int); + +/* + * Balance table. When balance() encounters a character that is to be + * matched, it first searches this table for a balancing left-side character. + * If the character is not in the table, the character is balanced by itself. + */ +static struct balance { + char left, right; +} bal[] = { + { '(', ')' }, + { '[', ']' }, + { '{', '}' }, + { '<', '>' }, + { '\0', '\0' } +}; + +/* + * Hack to show matching paren. Self-insert character, then show matching + * character, if any. Bound to "blink-and-insert". + */ +int +showmatch(int f, int n) +{ + int i, s; + + for (i = 0; i < n; i++) { + if ((s = selfinsert(FFRAND, 1)) != TRUE) + return (s); + /* unbalanced -- warn user */ + if (balance() != TRUE) + ttbeep(); + } + return (TRUE); +} + +/* + * Search for and display a matching character. + * + * This routine does the real work of searching backward + * for a balancing character. If such a balancing character + * is found, it uses displaymatch() to display the match. + */ +static int +balance(void) +{ + struct line *clp; + int cbo; + int c, i, depth; + int rbal, lbal; + + rbal = key.k_chars[key.k_count - 1]; + + /* See if there is a matching character -- default to the same */ + lbal = rbal; + for (i = 0; bal[i].right != '\0'; i++) + if (bal[i].right == rbal) { + lbal = bal[i].left; + break; + } + + /* + * Move behind the inserted character. We are always guaranteed + * that there is at least one character on the line, since one was + * just self-inserted by blinkparen. + */ + clp = curwp->w_dotp; + cbo = curwp->w_doto - 1; + + /* init nesting depth */ + depth = 0; + + for (;;) { + if (cbo == 0) { + clp = lback(clp); /* beginning of line */ + if (clp == curbp->b_headp) + return (FALSE); + cbo = llength(clp) + 1; + } + if (--cbo == llength(clp)) + c = '\n'; /* end of line */ + else + c = lgetc(clp, cbo); /* somewhere in middle */ + + /* + * Check for a matching character. If still in a nested + * level, pop out of it and continue search. This check + * is done before the nesting check so single-character + * matches will work too. + */ + if (c == lbal) { + if (depth == 0) { + displaymatch(clp, cbo); + return (TRUE); + } else + depth--; + } + /* Check for another level of nesting. */ + if (c == rbal) + depth++; + } + /* NOTREACHED */ +} + +/* + * Display matching character. Matching characters that are not in the + * current window are displayed in the echo line. If in the current window, + * move dot to the matching character, sit there a while, then move back. + */ +static void +displaymatch(struct line *clp, int cbo) +{ + struct line *tlp; + int tbo; + int cp; + int bufo; + int c; + int inwindow; + char buf[NLINE]; + + /* + * Figure out if matching char is in current window by + * searching from the top of the window to dot. + */ + inwindow = FALSE; + for (tlp = curwp->w_linep; tlp != lforw(curwp->w_dotp); + tlp = lforw(tlp)) + if (tlp == clp) + inwindow = TRUE; + + if (inwindow == TRUE) { + tlp = curwp->w_dotp; /* save current position */ + tbo = curwp->w_doto; + + curwp->w_dotp = clp; /* move to new position */ + curwp->w_doto = cbo; + curwp->w_rflag |= WFMOVE; + + update(); /* show match */ + ttwait(1000); /* wait for key or 1 second */ + + curwp->w_dotp = tlp; /* return to old position */ + curwp->w_doto = tbo; + curwp->w_rflag |= WFMOVE; + update(); + } else { + /* match is not in this window, so display line in echo area */ + bufo = 0; + for (cp = 0; cp < llength(clp); cp++) { + c = lgetc(clp, cp); + if (c != '\t' +#ifdef NOTAB + || (curbp->b_flag & BFNOTAB) +#endif + ) + if (ISCTRL(c)) { + buf[bufo++] = '^'; + buf[bufo++] = CCHR(c); + } else + buf[bufo++] = c; + else + do { + buf[bufo++] = ' '; + } while (bufo & 7); + } + buf[bufo++] = '\0'; + ewprintf("Matches %s", buf); + } +}