X-Git-Url: https://pd.if.org/git/?p=pd_readline;a=blobdiff_plain;f=mg%2Fparagraph.c;fp=mg%2Fparagraph.c;h=57ce412e8505eebbf701d4cb40a955e2b1ff839f;hp=0000000000000000000000000000000000000000;hb=a9843085ec916c175bd245a8398f30e6cc03f984;hpb=26fe4e09c6c3c250334fdeed60ce3061febecde2 diff --git a/mg/paragraph.c b/mg/paragraph.c new file mode 100644 index 0000000..57ce412 --- /dev/null +++ b/mg/paragraph.c @@ -0,0 +1,362 @@ +/* $OpenBSD: paragraph.c,v 1.22 2011/11/29 05:59:54 lum Exp $ */ + +/* This file is in the public domain. */ + +/* + * Code for dealing with paragraphs and filling. Adapted from MicroEMACS 3.6 + * and GNU-ified by mwm@ucbvax. Several bug fixes by blarson@usc-oberon. + */ + +#include "def.h" + +static int fillcol = 70; + +#define MAXWORD 256 + +/* + * Move to start of paragraph. Go back to the beginning of the current + * paragraph here we look for a or or + * combination to delimit the beginning of a paragraph. + */ +/* ARGSUSED */ +int +gotobop(int f, int n) +{ + /* the other way... */ + if (n < 0) + return (gotoeop(f, -n)); + + while (n-- > 0) { + /* first scan back until we are in a word */ + while (backchar(FFRAND, 1) && inword() == 0); + + /* and go to the B-O-Line */ + curwp->w_doto = 0; + + /* + * and scan back until we hit a or + * + */ + while (lback(curwp->w_dotp) != curbp->b_headp) + if (llength(lback(curwp->w_dotp)) && + lgetc(curwp->w_dotp, 0) != ' ' && + lgetc(curwp->w_dotp, 0) != '.' && + lgetc(curwp->w_dotp, 0) != '\t') + curwp->w_dotp = lback(curwp->w_dotp); + else { + if (llength(lback(curwp->w_dotp)) && + lgetc(curwp->w_dotp, 0) == '.') { + curwp->w_dotp = lforw(curwp->w_dotp); + if (curwp->w_dotp == curbp->b_headp) { + /* + * beyond end of buffer, + * cleanup time + */ + curwp->w_dotp = + lback(curwp->w_dotp); + curwp->w_doto = + llength(curwp->w_dotp); + } + } + break; + } + } + /* force screen update */ + curwp->w_rflag |= WFMOVE; + return (TRUE); +} + +/* + * Move to end of paragraph. Go forward to the end of the current paragraph + * here we look for a or or combination to + * delimit the beginning of a paragraph. + */ +/* ARGSUSED */ +int +gotoeop(int f, int n) +{ + /* the other way... */ + if (n < 0) + return (gotobop(f, -n)); + + /* for each one asked for */ + while (n-- > 0) { + /* Find the first word on/after the current line */ + curwp->w_doto = 0; + while (forwchar(FFRAND, 1) && inword() == 0); + + curwp->w_doto = 0; + curwp->w_dotp = lforw(curwp->w_dotp); + + /* and scan forword until we hit a or ... */ + while (curwp->w_dotp != curbp->b_headp) { + if (llength(curwp->w_dotp) && + lgetc(curwp->w_dotp, 0) != ' ' && + lgetc(curwp->w_dotp, 0) != '.' && + lgetc(curwp->w_dotp, 0) != '\t') + curwp->w_dotp = lforw(curwp->w_dotp); + else + break; + } + if (curwp->w_dotp == curbp->b_headp) { + /* beyond end of buffer, cleanup time */ + curwp->w_dotp = lback(curwp->w_dotp); + curwp->w_doto = llength(curwp->w_dotp); + break; + } + } + /* force screen update */ + curwp->w_rflag |= WFMOVE; + return (TRUE); +} + +/* + * Justify a paragraph. Fill the current paragraph according to the current + * fill column. + */ +/* ARGSUSED */ +int +fillpara(int f, int n) +{ + int c; /* current char during scan */ + int wordlen; /* length of current word */ + int clength; /* position on line during fill */ + int i; /* index during word copy */ + int eopflag; /* Are we at the End-Of-Paragraph? */ + int firstflag; /* first word? (needs no space) */ + int newlength; /* tentative new line length */ + int eolflag; /* was at end of line */ + int retval; /* return value */ + struct line *eopline; /* pointer to line just past EOP */ + char wbuf[MAXWORD]; /* buffer for current word */ + + undo_boundary_enable(FFRAND, 0); + + /* record the pointer to the line just past the EOP */ + (void)gotoeop(FFRAND, 1); + if (curwp->w_doto != 0) { + /* paragraph ends at end of buffer */ + (void)lnewline(); + eopline = lforw(curwp->w_dotp); + } else + eopline = curwp->w_dotp; + + /* and back top the begining of the paragraph */ + (void)gotobop(FFRAND, 1); + + /* initialize various info */ + while (inword() == 0 && forwchar(FFRAND, 1)); + + clength = curwp->w_doto; + wordlen = 0; + + /* scan through lines, filling words */ + firstflag = TRUE; + eopflag = FALSE; + while (!eopflag) { + + /* get the next character in the paragraph */ + if ((eolflag = (curwp->w_doto == llength(curwp->w_dotp)))) { + c = ' '; + if (lforw(curwp->w_dotp) == eopline) + eopflag = TRUE; + } else + c = lgetc(curwp->w_dotp, curwp->w_doto); + + /* and then delete it */ + if (ldelete((RSIZE) 1, KNONE) == FALSE && !eopflag) { + retval = FALSE; + goto cleanup; + } + + /* if not a separator, just add it in */ + if (c != ' ' && c != '\t') { + if (wordlen < MAXWORD - 1) + wbuf[wordlen++] = c; + else { + /* + * You lose chars beyond MAXWORD if the word + * is too long. I'm too lazy to fix it now; it + * just silently truncated the word before, + * so I get to feel smug. + */ + ewprintf("Word too long!"); + } + } else if (wordlen) { + + /* calculate tentative new length with word added */ + newlength = clength + 1 + wordlen; + + /* + * if at end of line or at doublespace and previous + * character was one of '.','?','!' doublespace here. + * behave the same way if a ')' is preceded by a + * [.?!] and followed by a doublespace. + */ + if ((eolflag || + curwp->w_doto == llength(curwp->w_dotp) || + (c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ' + || c == '\t') && (ISEOSP(wbuf[wordlen - 1]) || + (wbuf[wordlen - 1] == ')' && wordlen >= 2 && + ISEOSP(wbuf[wordlen - 2]))) && + wordlen < MAXWORD - 1) + wbuf[wordlen++] = ' '; + + /* at a word break with a word waiting */ + if (newlength <= fillcol) { + /* add word to current line */ + if (!firstflag) { + (void)linsert(1, ' '); + ++clength; + } + firstflag = FALSE; + } else { + if (curwp->w_doto > 0 && + lgetc(curwp->w_dotp, curwp->w_doto - 1) == ' ') { + curwp->w_doto -= 1; + (void)ldelete((RSIZE) 1, KNONE); + } + /* start a new line */ + (void)lnewline(); + clength = 0; + } + + /* and add the word in in either case */ + for (i = 0; i < wordlen; i++) { + (void)linsert(1, wbuf[i]); + ++clength; + } + wordlen = 0; + } + } + /* and add a last newline for the end of our new paragraph */ + (void)lnewline(); + + /* + * We really should wind up where we started, (which is hard to keep + * track of) but I think the end of the last line is better than the + * beginning of the blank line. + */ + (void)backchar(FFRAND, 1); + retval = TRUE; +cleanup: + undo_boundary_enable(FFRAND, 1); + return (retval); +} + +/* + * Delete a paragraph. Delete n paragraphs starting with the current one. + */ +/* ARGSUSED */ +int +killpara(int f, int n) +{ + int status; /* returned status of functions */ + + /* for each paragraph to delete */ + while (n--) { + + /* mark out the end and beginning of the para to delete */ + (void)gotoeop(FFRAND, 1); + + /* set the mark here */ + curwp->w_markp = curwp->w_dotp; + curwp->w_marko = curwp->w_doto; + + /* go to the beginning of the paragraph */ + (void)gotobop(FFRAND, 1); + + /* force us to the beginning of line */ + curwp->w_doto = 0; + + /* and delete it */ + if ((status = killregion(FFRAND, 1)) != TRUE) + return (status); + + /* and clean up the 2 extra lines */ + (void)ldelete((RSIZE) 1, KFORW); + } + return (TRUE); +} + +/* + * Insert char with work wrap. Check to see if we're past fillcol, and if so, + * justify this line. As a last step, justify the line. + */ +/* ARGSUSED */ +int +fillword(int f, int n) +{ + char c; + int col, i, nce; + + for (i = col = 0; col <= fillcol; ++i, ++col) { + if (i == curwp->w_doto) + return selfinsert(f, n); + c = lgetc(curwp->w_dotp, i); + if (c == '\t' +#ifdef NOTAB + && !(curbp->b_flag & BFNOTAB) +#endif + ) + col |= 0x07; + else if (ISCTRL(c) != FALSE) + ++col; + } + if (curwp->w_doto != llength(curwp->w_dotp)) { + (void)selfinsert(f, n); + nce = llength(curwp->w_dotp) - curwp->w_doto; + } else + nce = 0; + curwp->w_doto = i; + + if ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && c != '\t') + do { + (void)backchar(FFRAND, 1); + } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && + c != '\t' && curwp->w_doto > 0); + + if (curwp->w_doto == 0) + do { + (void)forwchar(FFRAND, 1); + } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && + c != '\t' && curwp->w_doto < llength(curwp->w_dotp)); + + (void)delwhite(FFRAND, 1); + (void)lnewline(); + i = llength(curwp->w_dotp) - nce; + curwp->w_doto = i > 0 ? i : 0; + curwp->w_rflag |= WFMOVE; + if (nce == 0 && curwp->w_doto != 0) + return (fillword(f, n)); + return (TRUE); +} + +/* + * Set fill column to n for justify. + */ +int +setfillcol(int f, int n) +{ + char buf[32], *rep; + const char *es; + int nfill; + + if ((f & FFARG) != 0) { + fillcol = n; + } else { + if ((rep = eread("Set fill-column: ", buf, sizeof(buf), + EFNEW | EFCR)) == NULL) + return (ABORT); + else if (rep[0] == '\0') + return (FALSE); + nfill = strtonum(rep, 0, INT_MAX, &es); + if (es != NULL) { + ewprintf("Invalid fill column: %s", rep); + return (FALSE); + } + fillcol = nfill; + ewprintf("Fill column set to %d", fillcol); + } + return (TRUE); +}