home *** CD-ROM | disk | FTP | other *** search
- #include "jam.h"
- /*
- * Name: MicroEMACS
- * 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.
- *
- * Since I often edit Scribe code, I've made it possible to
- * blink arbitrary characters -- just bind delimiter characters
- * to "blink-matching-paren-hack"
- */
- #include "def.h"
- #include "key.h"
-
- #ifndef WINDOWED
- # include "string.h"
- #endif
-
- static int rn_(balance,(KCHAR kchar, int flag, int dir)); /* new params, jam */
- static VOID rn_(displaymatch,(LINE *lp, int c, int show, int go)); /* JAM */
-
- static BOOL findonly = FALSE;
- static LINE *finddotp;
- static int finddoto;
-
- /* 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.
- * This is to allow delimiters in Scribe documents to be matched.
- */
-
- static struct balance {
- char left, right;
- } bal[] = {
- { '(', ')' },
- { '[', ']' },
- { '{', '}' },
- { '<', '>' },
- { '\0','\0'}
- };
- static struct balance2 {
- char *left, *right;
- } bal2[] = {
- { "/*", "*/"},
- { (char *)0, (char *)0}
- };
-
- /* find the char which matches this char in parent line
- */
- void locatematch(parent, parentdoto, dotp, doto)
- LINE *parent;
- int parentdoto;
- LINE **dotp;
- int *doto;
- {
- LINE *sdotp = curwp->w_dotp;
- int sdoto = curwp->w_doto;
-
- *dotp = finddotp = (LINE *)0;
- findonly = TRUE;
- curwp->w_dotp = parent;
- curwp->w_doto = parentdoto;
- balance(lgetc(parent, parentdoto), 0, 1);
- findonly = FALSE;
- if (finddotp)
- {
- *dotp = finddotp;
- *doto = finddoto;
- }
- curwp->w_dotp = sdotp;
- curwp->w_doto = sdoto;
- }
- /*
- * Self-insert character, then show matching character,
- * if any. Bound to "blink-matching-paren-command".
- */
- showmatch(f, n)
- int f, n;
- {
- register int i, s;
-
- if (f & FFRAND)
- return FALSE;
- for (i = 0; i < n; i++)
- {
- /* insert the char
- */
- if ((s = selfinsert(FFRAND, 1)) != TRUE)
- return s;
- if (isCindent() && (key.k_chars[key.k_count-1] == '}'))
- alignindent(0, 1); /* self align hack */
-
- /* show the match
- */
- if (balance(0, 0, 0) != TRUE) /* unbalanced -- warn user */
- ttbeep();
- }
- return TRUE;
- }
-
- showthematch(f, n)
- int f, n;
- {
- register LINE *clp = curwp->w_dotp;
- register int cbo = curwp->w_doto;
-
- return balance(lgetc(clp,cbo), 0, 0);
- }
- gotomatch(f, n)
- int f, n;
- {
- register LINE *clp = curwp->w_dotp;
- register int cbo = curwp->w_doto;
-
- return balance(lgetc(clp, cbo), 1, 0);
- }
-
- /*
- * 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 balance(kchar, stay, defaultdir)
- KCHAR kchar;
- int stay;
- int defaultdir;
- {
- register LINE *clp;
- register int cbo;
- int c;
- int i;
- int rbal, lbal;
- int depth;
- int dir = -1; /* normally look backward JAM */
- int found = FALSE; /* JAM */
-
- if (kchar)
- rbal = kchar;
- else
- 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 == (char)rbal)
- {
- lbal = bal[i].left;
- found = TRUE;
- break;
- }
-
- /* special case of match either direction..
- */
- if (kchar && !found) /* didn't fin match in table, reverse */
- { /* and try again */
- for (i = 0; bal[i].left != '\0'; i++)
- if (bal[i].left == (char)rbal)
- {
- lbal = bal[i].right;
- dir = 1; /* going forward now */
- found = TRUE;
- break;
- }
- }
-
- /* control search direction
- */
- if (defaultdir)
- dir = defaultdir;
-
- /* 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 - (kchar ? 0 : 1); /* param/behavior change JAM */
- depth = 0; /* init nesting depth */
-
- for (;;)
- {
- if ((cbo == 0) || (cbo == llength(clp)))
- {
- if ((cbo == 0) && (llength(clp) > 0) && (dir > 0))
- ; /* front going ->, ok */
- else if ((cbo > 0) && (cbo == llength(clp)) && (dir < 0))
- ; /* end going <- ok */
- else
- {
- clp = (dir > 0 ? lforw(clp) : lback(clp));
- if (!clp || (clp == curbp->b_linep))
- return (FALSE);
- cbo = (dir > 0 ? -1 : llength(clp)+1);
- }
- }
- cbo += dir;
- if (cbo == llength(clp)) /* end of line */
- c = '\n';
- 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)
- {
- if (findonly)
- {
- finddotp = clp;
- finddoto = cbo;
- return (TRUE);
- }
- displaymatch(clp, cbo, kchar != 0, stay);
- 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.
- *
- * I bashed this big time to support finding a match in
- * either direction (JAM)
- */
- static VOID displaymatch(clp, cbo, show, go)
- register LINE *clp;
- register int cbo;
- register int show, go;
- {
- register LINE *tlp;
- register int tbo;
- register int cp;
- register int bufo;
- register 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) || show) /* if force, move anyway */
- {
- 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_flag |= WFMOVE;
-
- update(); /* show match */
-
- #ifdef WINDOWED
- {
- BOOL wasVis = IsCaretVis();
-
- /* Due to windows issues around cursor, it
- * is erased while processing an event. Special case
- * draw/erase cursor here for feedback.
- */
- if (go)
- return; /* means move and stay */
- SetCaretVis(TRUE);
- ttflush(TRUE);
- sleep(1); /* wait a bit */
- if (!wasVis)
- SetCaretVis(FALSE);
- ttflush(TRUE);
- }
- #else
- sleep(1); /* wait a bit */
- #endif
- curwp->w_dotp = tlp; /* return to old position */
- curwp->w_doto = tbo;
- curwp->w_flag |= WFMOVE;
- update();
- }
- else
- { /* match not in this window so display line in echo area */
- bufo = 0;
- for (cp = 0; cp < llength(clp); cp++) /* expand tabs */
- {
- c = lgetc(clp,cp);
- if (c != '\t'
- #ifdef NOTAB
- || (curbp->b_flag & BFNOTAB)
- #endif
- )
- if(ISCTRL(c))
- {
- buf[bufo++] = '^';
- buf[bufo++] =(char)(CCHR(c));
- }
- else
- buf[bufo++] = (char)c;
- else
- do {
- buf[bufo++] = ' ';
- } while (bufo & 7);
- }
- buf[bufo++] = '\0';
- ewprintf("Matches %s",buf);
- }
- }
- char *matchstr(s)
- char *s;
- {
- register int i;
-
- for (i = 0; bal2[i].right; i++)
- {
- if (strncmp(bal2[i].left, s, strlen(s)) == 0)
- return(bal2[i].right);
- else if (strncmp(bal2[i].right, s, strlen(s)) == 0)
- return(bal2[i].left);
- }
- return((char *)0);
- }
- char matchchar(c)
- char c;
- {
- register int i;
-
- for (i = 0; bal[i].right != '\0'; i++)
- {
- if (bal[i].left == c)
- return(bal[i].right);
- else if (bal[i].right == c)
- return(bal[i].left);
- }
- return(0);
- }
-
-