X-Git-Url: https://pd.if.org/git/?p=pd_readline;a=blobdiff_plain;f=mg%2Fbasic.c;fp=mg%2Fbasic.c;h=160d9c1c9e3d27125fc8fc81767596d36214d4a2;hp=0000000000000000000000000000000000000000;hb=a9843085ec916c175bd245a8398f30e6cc03f984;hpb=26fe4e09c6c3c250334fdeed60ce3061febecde2 diff --git a/mg/basic.c b/mg/basic.c new file mode 100644 index 0000000..160d9c1 --- /dev/null +++ b/mg/basic.c @@ -0,0 +1,532 @@ +/* $OpenBSD: basic.c,v 1.37 2012/06/18 09:26:03 lum Exp $ */ + +/* This file is in the public domain */ + +/* + * Basic cursor motion commands. + * + * The routines in this file are the basic + * command functions for moving the cursor around on + * the screen, setting mark, and swapping dot with + * mark. Only moves between lines, which might make the + * current buffer framing bad, are hard. + */ +#include "def.h" + +#include + +/* + * Go to beginning of line. + */ +/* ARGSUSED */ +int +gotobol(int f, int n) +{ + curwp->w_doto = 0; + return (TRUE); +} + +/* + * Move cursor backwards. Do the + * right thing if the count is less than + * 0. Error if you try to move back from + * the beginning of the buffer. + */ +/* ARGSUSED */ +int +backchar(int f, int n) +{ + struct line *lp; + + if (n < 0) + return (forwchar(f, -n)); + while (n--) { + if (curwp->w_doto == 0) { + if ((lp = lback(curwp->w_dotp)) == curbp->b_headp) { + if (!(f & FFRAND)) + ewprintf("Beginning of buffer"); + return (FALSE); + } + curwp->w_dotp = lp; + curwp->w_doto = llength(lp); + curwp->w_rflag |= WFMOVE; + curwp->w_dotline--; + } else + curwp->w_doto--; + } + return (TRUE); +} + +/* + * Go to end of line. + */ +/* ARGSUSED */ +int +gotoeol(int f, int n) +{ + curwp->w_doto = llength(curwp->w_dotp); + return (TRUE); +} + +/* + * Move cursor forwards. Do the + * right thing if the count is less than + * 0. Error if you try to move forward + * from the end of the buffer. + */ +/* ARGSUSED */ +int +forwchar(int f, int n) +{ + if (n < 0) + return (backchar(f, -n)); + while (n--) { + if (curwp->w_doto == llength(curwp->w_dotp)) { + curwp->w_dotp = lforw(curwp->w_dotp); + if (curwp->w_dotp == curbp->b_headp) { + curwp->w_dotp = lback(curwp->w_dotp); + if (!(f & FFRAND)) + ewprintf("End of buffer"); + return (FALSE); + } + curwp->w_doto = 0; + curwp->w_dotline++; + curwp->w_rflag |= WFMOVE; + } else + curwp->w_doto++; + } + return (TRUE); +} + +/* + * Go to the beginning of the + * buffer. Setting WFFULL is conservative, + * but almost always the case. + */ +int +gotobob(int f, int n) +{ + (void) setmark(f, n); + curwp->w_dotp = bfirstlp(curbp); + curwp->w_doto = 0; + curwp->w_rflag |= WFFULL; + curwp->w_dotline = 1; + return (TRUE); +} + +/* + * Go to the end of the buffer. Leave dot 3 lines from the bottom of the + * window if buffer length is longer than window length; same as emacs. + * Setting WFFULL is conservative, but almost always the case. + */ +int +gotoeob(int f, int n) +{ + struct line *lp; + + (void) setmark(f, n); + curwp->w_dotp = blastlp(curbp); + curwp->w_doto = llength(curwp->w_dotp); + curwp->w_dotline = curwp->w_bufp->b_lines; + + lp = curwp->w_dotp; + n = curwp->w_ntrows - 3; + + if (n < curwp->w_bufp->b_lines && n >= 3) { + while (n--) + curwp->w_dotp = lback(curwp->w_dotp); + + curwp->w_linep = curwp->w_dotp; + curwp->w_dotp = lp; + } + curwp->w_rflag |= WFFULL; + return (TRUE); +} + +/* + * Move forward by full lines. + * If the number of lines to move is less + * than zero, call the backward line function to + * actually do it. The last command controls how + * the goal column is set. + */ +/* ARGSUSED */ +int +forwline(int f, int n) +{ + struct line *dlp; + + if (n < 0) + return (backline(f | FFRAND, -n)); + if ((dlp = curwp->w_dotp) == curbp->b_headp) + return(TRUE); + if ((lastflag & CFCPCN) == 0) /* Fix goal. */ + setgoal(); + thisflag |= CFCPCN; + if (n == 0) + return (TRUE); + while (n--) { + dlp = lforw(dlp); + if (dlp == curbp->b_headp) { + curwp->w_dotp = lback(dlp); + curwp->w_doto = llength(curwp->w_dotp); + curwp->w_rflag |= WFMOVE; + return (TRUE); + } + curwp->w_dotline++; + } + curwp->w_rflag |= WFMOVE; + curwp->w_dotp = dlp; + curwp->w_doto = getgoal(dlp); + + return (TRUE); +} + +/* + * This function is like "forwline", but + * goes backwards. The scheme is exactly the same. + * Check for arguments that are less than zero and + * call your alternate. Figure out the new line and + * call "movedot" to perform the motion. + */ +/* ARGSUSED */ +int +backline(int f, int n) +{ + struct line *dlp; + + if (n < 0) + return (forwline(f | FFRAND, -n)); + if ((lastflag & CFCPCN) == 0) /* Fix goal. */ + setgoal(); + thisflag |= CFCPCN; + dlp = curwp->w_dotp; + while (n-- && lback(dlp) != curbp->b_headp) { + dlp = lback(dlp); + curwp->w_dotline--; + } + curwp->w_dotp = dlp; + curwp->w_doto = getgoal(dlp); + curwp->w_rflag |= WFMOVE; + return (TRUE); +} + +/* + * Set the current goal column, which is saved in the external variable + * "curgoal", to the current cursor column. The column is never off + * the edge of the screen; it's more like display then show position. + */ +void +setgoal(void) +{ + curgoal = getcolpos(); /* Get the position. */ + /* we can now display past end of display, don't chop! */ +} + +/* + * This routine looks at a line (pointed + * to by the LINE pointer "dlp") and the current + * vertical motion goal column (set by the "setgoal" + * routine above) and returns the best offset to use + * when a vertical motion is made into the line. + */ +int +getgoal(struct line *dlp) +{ + int c, i, col = 0; + char tmp[5]; + + + for (i = 0; i < llength(dlp); i++) { + c = lgetc(dlp, i); + if (c == '\t' +#ifdef NOTAB + && !(curbp->b_flag & BFNOTAB) +#endif + ) { + col |= 0x07; + col++; + } else if (ISCTRL(c) != FALSE) { + col += 2; + } else if (isprint(c)) + col++; + else { + col += snprintf(tmp, sizeof(tmp), "\\%o", c); + } + if (col > curgoal) + break; + } + return (i); +} + +/* + * Scroll forward by a specified number + * of lines, or by a full page if no argument. + * The "2" is the window overlap (this is the default + * value from ITS EMACS). Because the top line in + * the window is zapped, we have to do a hard + * update and get it back. + */ +/* ARGSUSED */ +int +forwpage(int f, int n) +{ + struct line *lp; + + if (!(f & FFARG)) { + n = curwp->w_ntrows - 2; /* Default scroll. */ + if (n <= 0) /* Forget the overlap */ + n = 1; /* if tiny window. */ + } else if (n < 0) + return (backpage(f | FFRAND, -n)); + + lp = curwp->w_linep; + while (n--) + if ((lp = lforw(lp)) == curbp->b_headp) { + ttbeep(); + ewprintf("End of buffer"); + return(TRUE); + } + + curwp->w_linep = lp; + curwp->w_rflag |= WFFULL; + + /* if in current window, don't move dot */ + for (n = curwp->w_ntrows; n-- && lp != curbp->b_headp; lp = lforw(lp)) + if (lp == curwp->w_dotp) + return (TRUE); + + /* Advance the dot the slow way, for line nos */ + while (curwp->w_dotp != curwp->w_linep) { + curwp->w_dotp = lforw(curwp->w_dotp); + curwp->w_dotline++; + } + curwp->w_doto = 0; + return (TRUE); +} + +/* + * This command is like "forwpage", + * but it goes backwards. The "2", like above, + * is the overlap between the two windows. The + * value is from the ITS EMACS manual. The + * hard update is done because the top line in + * the window is zapped. + */ +/* ARGSUSED */ +int +backpage(int f, int n) +{ + struct line *lp, *lp2; + + if (!(f & FFARG)) { + n = curwp->w_ntrows - 2; /* Default scroll. */ + if (n <= 0) /* Don't blow up if the */ + return (backline(f, 1));/* window is tiny. */ + } else if (n < 0) + return (forwpage(f | FFRAND, -n)); + + lp = lp2 = curwp->w_linep; + + while (n-- && lback(lp) != curbp->b_headp) { + lp = lback(lp); + } + if (lp == curwp->w_linep) { + ttbeep(); + ewprintf("Beginning of buffer"); + } + curwp->w_linep = lp; + curwp->w_rflag |= WFFULL; + + /* if in current window, don't move dot */ + for (n = curwp->w_ntrows; n-- && lp != curbp->b_headp; lp = lforw(lp)) + if (lp == curwp->w_dotp) + return (TRUE); + + lp2 = lforw(lp2); + + /* Move the dot the slow way, for line nos */ + while (curwp->w_dotp != lp2) { + if (curwp->w_dotline <= curwp->w_ntrows) + return (TRUE); + curwp->w_dotp = lback(curwp->w_dotp); + curwp->w_dotline--; + } + curwp->w_doto = 0; + return (TRUE); +} + +/* + * These functions are provided for compatibility with Gosling's Emacs. They + * are used to scroll the display up (or down) one line at a time. + */ +int +forw1page(int f, int n) +{ + if (!(f & FFARG)) { + n = 1; + f = FFUNIV; + } + forwpage(f | FFRAND, n); + return (TRUE); +} + +int +back1page(int f, int n) +{ + if (!(f & FFARG)) { + n = 1; + f = FFUNIV; + } + backpage(f | FFRAND, n); + return (TRUE); +} + +/* + * Page the other window. Check to make sure it exists, then + * nextwind, forwpage and restore window pointers. + */ +int +pagenext(int f, int n) +{ + struct mgwin *wp; + + if (wheadp->w_wndp == NULL) { + ewprintf("No other window"); + return (FALSE); + } + wp = curwp; + (void) nextwind(f, n); + (void) forwpage(f, n); + curwp = wp; + curbp = wp->w_bufp; + return (TRUE); +} + +/* + * Internal set mark routine, used by other functions (daveb). + */ +void +isetmark(void) +{ + curwp->w_markp = curwp->w_dotp; + curwp->w_marko = curwp->w_doto; + curwp->w_markline = curwp->w_dotline; +} + +/* + * Set the mark in the current window + * to the value of dot. A message is written to + * the echo line. (ewprintf knows about macros) + */ +/* ARGSUSED */ +int +setmark(int f, int n) +{ + isetmark(); + ewprintf("Mark set"); + return (TRUE); +} + +/* Clear the mark, if set. */ +/* ARGSUSED */ +int +clearmark(int f, int n) +{ + if (!curwp->w_markp) + return (FALSE); + + curwp->w_markp = NULL; + curwp->w_marko = 0; + curwp->w_markline = 0; + + return (TRUE); +} + +/* + * Swap the values of "dot" and "mark" in + * the current window. This is pretty easy, because + * all of the hard work gets done by the standard routine + * that moves the mark about. The only possible + * error is "no mark". + */ +/* ARGSUSED */ +int +swapmark(int f, int n) +{ + struct line *odotp; + int odoto, odotline; + + if (curwp->w_markp == NULL) { + ewprintf("No mark in this window"); + return (FALSE); + } + odotp = curwp->w_dotp; + odoto = curwp->w_doto; + odotline = curwp->w_dotline; + curwp->w_dotp = curwp->w_markp; + curwp->w_doto = curwp->w_marko; + curwp->w_dotline = curwp->w_markline; + curwp->w_markp = odotp; + curwp->w_marko = odoto; + curwp->w_markline = odotline; + curwp->w_rflag |= WFMOVE; + return (TRUE); +} + +/* + * Go to a specific line, mostly for + * looking up errors in C programs, which give the + * error a line number. If an argument is present, then + * it is the line number, else prompt for a line number + * to use. + */ +/* ARGSUSED */ +int +gotoline(int f, int n) +{ + struct line *clp; + char buf[32], *bufp; + const char *err; + + if (!(f & FFARG)) { + if ((bufp = eread("Goto line: ", buf, sizeof(buf), + EFNUL | EFNEW | EFCR)) == NULL) + return (ABORT); + if (bufp[0] == '\0') + return (ABORT); + n = (int)strtonum(buf, INT_MIN, INT_MAX, &err); + if (err) { + ewprintf("Line number %s", err); + return (FALSE); + } + } + if (n >= 0) { + if (n == 0) + n++; + curwp->w_dotline = n; + clp = lforw(curbp->b_headp); /* "clp" is first line */ + while (--n > 0) { + if (lforw(clp) == curbp->b_headp) { + curwp->w_dotline = curwp->w_bufp->b_lines; + break; + } + clp = lforw(clp); + } + } else { + curwp->w_dotline = curwp->w_bufp->b_lines + n; + clp = lback(curbp->b_headp); /* "clp" is last line */ + while (n < 0) { + if (lback(clp) == curbp->b_headp) { + curwp->w_dotline = 1; + break; + } + clp = lback(clp); + n++; + } + } + curwp->w_dotp = clp; + curwp->w_doto = 0; + curwp->w_rflag |= WFMOVE; + return (TRUE); +}