1 /* $OpenBSD: paragraph.c,v 1.22 2011/11/29 05:59:54 lum Exp $ */
3 /* This file is in the public domain. */
6 * Code for dealing with paragraphs and filling. Adapted from MicroEMACS 3.6
7 * and GNU-ified by mwm@ucbvax. Several bug fixes by blarson@usc-oberon.
12 static int fillcol = 70;
17 * Move to start of paragraph. Go back to the beginning of the current
18 * paragraph here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
19 * combination to delimit the beginning of a paragraph.
25 /* the other way... */
27 return (gotoeop(f, -n));
30 /* first scan back until we are in a word */
31 while (backchar(FFRAND, 1) && inword() == 0);
33 /* and go to the B-O-Line */
37 * and scan back until we hit a <NL><SP> <NL><TAB> or
40 while (lback(curwp->w_dotp) != curbp->b_headp)
41 if (llength(lback(curwp->w_dotp)) &&
42 lgetc(curwp->w_dotp, 0) != ' ' &&
43 lgetc(curwp->w_dotp, 0) != '.' &&
44 lgetc(curwp->w_dotp, 0) != '\t')
45 curwp->w_dotp = lback(curwp->w_dotp);
47 if (llength(lback(curwp->w_dotp)) &&
48 lgetc(curwp->w_dotp, 0) == '.') {
49 curwp->w_dotp = lforw(curwp->w_dotp);
50 if (curwp->w_dotp == curbp->b_headp) {
52 * beyond end of buffer,
58 llength(curwp->w_dotp);
64 /* force screen update */
65 curwp->w_rflag |= WFMOVE;
70 * Move to end of paragraph. Go forward to the end of the current paragraph
71 * here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE> combination to
72 * delimit the beginning of a paragraph.
78 /* the other way... */
80 return (gotobop(f, -n));
82 /* for each one asked for */
84 /* Find the first word on/after the current line */
86 while (forwchar(FFRAND, 1) && inword() == 0);
89 curwp->w_dotp = lforw(curwp->w_dotp);
91 /* and scan forword until we hit a <NL><SP> or ... */
92 while (curwp->w_dotp != curbp->b_headp) {
93 if (llength(curwp->w_dotp) &&
94 lgetc(curwp->w_dotp, 0) != ' ' &&
95 lgetc(curwp->w_dotp, 0) != '.' &&
96 lgetc(curwp->w_dotp, 0) != '\t')
97 curwp->w_dotp = lforw(curwp->w_dotp);
101 if (curwp->w_dotp == curbp->b_headp) {
102 /* beyond end of buffer, cleanup time */
103 curwp->w_dotp = lback(curwp->w_dotp);
104 curwp->w_doto = llength(curwp->w_dotp);
108 /* force screen update */
109 curwp->w_rflag |= WFMOVE;
114 * Justify a paragraph. Fill the current paragraph according to the current
119 fillpara(int f, int n)
121 int c; /* current char during scan */
122 int wordlen; /* length of current word */
123 int clength; /* position on line during fill */
124 int i; /* index during word copy */
125 int eopflag; /* Are we at the End-Of-Paragraph? */
126 int firstflag; /* first word? (needs no space) */
127 int newlength; /* tentative new line length */
128 int eolflag; /* was at end of line */
129 int retval; /* return value */
130 struct line *eopline; /* pointer to line just past EOP */
131 char wbuf[MAXWORD]; /* buffer for current word */
133 undo_boundary_enable(FFRAND, 0);
135 /* record the pointer to the line just past the EOP */
136 (void)gotoeop(FFRAND, 1);
137 if (curwp->w_doto != 0) {
138 /* paragraph ends at end of buffer */
140 eopline = lforw(curwp->w_dotp);
142 eopline = curwp->w_dotp;
144 /* and back top the begining of the paragraph */
145 (void)gotobop(FFRAND, 1);
147 /* initialize various info */
148 while (inword() == 0 && forwchar(FFRAND, 1));
150 clength = curwp->w_doto;
153 /* scan through lines, filling words */
158 /* get the next character in the paragraph */
159 if ((eolflag = (curwp->w_doto == llength(curwp->w_dotp)))) {
161 if (lforw(curwp->w_dotp) == eopline)
164 c = lgetc(curwp->w_dotp, curwp->w_doto);
166 /* and then delete it */
167 if (ldelete((RSIZE) 1, KNONE) == FALSE && !eopflag) {
172 /* if not a separator, just add it in */
173 if (c != ' ' && c != '\t') {
174 if (wordlen < MAXWORD - 1)
178 * You lose chars beyond MAXWORD if the word
179 * is too long. I'm too lazy to fix it now; it
180 * just silently truncated the word before,
181 * so I get to feel smug.
183 ewprintf("Word too long!");
185 } else if (wordlen) {
187 /* calculate tentative new length with word added */
188 newlength = clength + 1 + wordlen;
191 * if at end of line or at doublespace and previous
192 * character was one of '.','?','!' doublespace here.
193 * behave the same way if a ')' is preceded by a
194 * [.?!] and followed by a doublespace.
197 curwp->w_doto == llength(curwp->w_dotp) ||
198 (c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' '
199 || c == '\t') && (ISEOSP(wbuf[wordlen - 1]) ||
200 (wbuf[wordlen - 1] == ')' && wordlen >= 2 &&
201 ISEOSP(wbuf[wordlen - 2]))) &&
202 wordlen < MAXWORD - 1)
203 wbuf[wordlen++] = ' ';
205 /* at a word break with a word waiting */
206 if (newlength <= fillcol) {
207 /* add word to current line */
209 (void)linsert(1, ' ');
214 if (curwp->w_doto > 0 &&
215 lgetc(curwp->w_dotp, curwp->w_doto - 1) == ' ') {
217 (void)ldelete((RSIZE) 1, KNONE);
219 /* start a new line */
224 /* and add the word in in either case */
225 for (i = 0; i < wordlen; i++) {
226 (void)linsert(1, wbuf[i]);
232 /* and add a last newline for the end of our new paragraph */
236 * We really should wind up where we started, (which is hard to keep
237 * track of) but I think the end of the last line is better than the
238 * beginning of the blank line.
240 (void)backchar(FFRAND, 1);
243 undo_boundary_enable(FFRAND, 1);
248 * Delete a paragraph. Delete n paragraphs starting with the current one.
252 killpara(int f, int n)
254 int status; /* returned status of functions */
256 /* for each paragraph to delete */
259 /* mark out the end and beginning of the para to delete */
260 (void)gotoeop(FFRAND, 1);
262 /* set the mark here */
263 curwp->w_markp = curwp->w_dotp;
264 curwp->w_marko = curwp->w_doto;
266 /* go to the beginning of the paragraph */
267 (void)gotobop(FFRAND, 1);
269 /* force us to the beginning of line */
273 if ((status = killregion(FFRAND, 1)) != TRUE)
276 /* and clean up the 2 extra lines */
277 (void)ldelete((RSIZE) 1, KFORW);
283 * Insert char with work wrap. Check to see if we're past fillcol, and if so,
284 * justify this line. As a last step, justify the line.
288 fillword(int f, int n)
293 for (i = col = 0; col <= fillcol; ++i, ++col) {
294 if (i == curwp->w_doto)
295 return selfinsert(f, n);
296 c = lgetc(curwp->w_dotp, i);
299 && !(curbp->b_flag & BFNOTAB)
303 else if (ISCTRL(c) != FALSE)
306 if (curwp->w_doto != llength(curwp->w_dotp)) {
307 (void)selfinsert(f, n);
308 nce = llength(curwp->w_dotp) - curwp->w_doto;
313 if ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && c != '\t')
315 (void)backchar(FFRAND, 1);
316 } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' &&
317 c != '\t' && curwp->w_doto > 0);
319 if (curwp->w_doto == 0)
321 (void)forwchar(FFRAND, 1);
322 } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' &&
323 c != '\t' && curwp->w_doto < llength(curwp->w_dotp));
325 (void)delwhite(FFRAND, 1);
327 i = llength(curwp->w_dotp) - nce;
328 curwp->w_doto = i > 0 ? i : 0;
329 curwp->w_rflag |= WFMOVE;
330 if (nce == 0 && curwp->w_doto != 0)
331 return (fillword(f, n));
336 * Set fill column to n for justify.
339 setfillcol(int f, int n)
345 if ((f & FFARG) != 0) {
348 if ((rep = eread("Set fill-column: ", buf, sizeof(buf),
349 EFNEW | EFCR)) == NULL)
351 else if (rep[0] == '\0')
353 nfill = strtonum(rep, 0, INT_MAX, &es);
355 ewprintf("Invalid fill column: %s", rep);
359 ewprintf("Fill column set to %d", fillcol);