]> pd.if.org Git - pd_readline/blobdiff - mg/match.c
Added mg from an OpenBSD mirror site. Many thanks to the OpenBSD team and the mg...
[pd_readline] / mg / match.c
diff --git a/mg/match.c b/mg/match.c
new file mode 100644 (file)
index 0000000..4c5d0c3
--- /dev/null
@@ -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);
+       }
+}