wordsmithing
[nvi.git] / vi / v_txt.c
blobcbd6a4345ea5e7d4a2dc6077ca9e409d77d51ab7
1 /*-
2 * Copyright (c) 1993
3 * The Regents of the University of California. All rights reserved.
5 * %sccs.include.redist.c%
6 */
8 #ifndef lint
9 static char sccsid[] = "$Id: v_txt.c,v 8.72 1993/12/22 18:56:47 bostic Exp $ (Berkeley) $Date: 1993/12/22 18:56:47 $";
10 #endif /* not lint */
12 #include <sys/types.h>
13 #include <sys/time.h>
15 #include <ctype.h>
16 #include <errno.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
21 #include "vi.h"
22 #include "seq.h"
23 #include "vcmd.h"
25 static int txt_abbrev __P((SCR *, TEXT *, ARG_CHAR_T, int, int *, int *));
26 static void txt_ai_resolve __P((SCR *, TEXT *));
27 static TEXT *txt_backup __P((SCR *, EXF *, TEXTH *, TEXT *, u_int));
28 static void txt_err __P((SCR *, EXF *, TEXTH *));
29 static int txt_hex __P((SCR *, TEXT *, int *, ARG_CHAR_T));
30 static int txt_indent __P((SCR *, TEXT *));
31 static int txt_margin __P((SCR *, TEXT *, int *, ARG_CHAR_T));
32 static int txt_outdent __P((SCR *, TEXT *));
33 static void txt_showmatch __P((SCR *, EXF *));
34 static int txt_resolve __P((SCR *, EXF *, TEXTH *));
36 /* Cursor character (space is hard to track on the screen). */
37 #if defined(DEBUG) && 0
38 #undef CURSOR_CH
39 #define CURSOR_CH '+'
40 #endif
42 /* Local version of BINC. */
43 #define TBINC(sp, lp, llen, nlen) { \
44 if ((nlen) > llen && binc(sp, &(lp), &(llen), nlen)) \
45 goto err; \
49 * newtext --
50 * Read in text from the user.
52 * !!!
53 * Historic vi always used:
55 * ^D: autoindent deletion
56 * ^H: last character deletion
57 * ^W: last word deletion
58 * ^V: quote the next character
60 * regardless of the user's choices for these characters. The user's erase
61 * and kill characters worked in addition to these characters. Ex was not
62 * completely consistent with this, as it did map the scroll command to the
63 * user's EOF character.
65 * This implementation does not use fixed characters, but uses whatever the
66 * user specified as described by the termios structure. I'm getting away
67 * with something here, but I think I'm unlikely to get caught.
69 * !!!
70 * Historic vi did a special screen optimization for tab characters. For
71 * the keystrokes "iabcd<esc>0C<tab>", the tab would overwrite the rest of
72 * the string when it was displayed. Because this implementation redisplays
73 * the entire line on each keystroke, the "bcd" gets pushed to the right as
74 * we ignore that the user has "promised" to change the rest of the characters.
75 * Users have noticed, but this isn't worth fixing, and, the way that the
76 * historic vi did it results in an even worse bug. Given the keystrokes
77 * "iabcd<esc>0R<tab><esc>", the "bcd" disappears, and magically reappears
78 * on the second <esc> key.
80 int
81 v_ntext(sp, ep, tiqh, tm, lp, len, rp, prompt, ai_line, flags)
82 SCR *sp;
83 EXF *ep;
84 TEXTH *tiqh;
85 MARK *tm; /* To MARK. */
86 const char *lp; /* Input line. */
87 const size_t len; /* Input line length. */
88 MARK *rp; /* Return MARK. */
89 int prompt; /* Prompt to display. */
90 recno_t ai_line; /* Line number to use for autoindent count. */
91 u_int flags; /* TXT_ flags. */
93 /* State of abbreviation checks. */
94 enum { A_NOTSET, A_SPACE, A_NOTSPACE } abb;
95 /* State of the "[^0]^D" sequences. */
96 enum { C_NOTSET, C_CARATSET, C_NOCHANGE, C_ZEROSET } carat_st;
97 /* State of the hex input character. */
98 enum { H_NOTSET, H_NEXTCHAR, H_INHEX } hex;
99 /* State of quotation. */
100 enum { Q_NOTSET, Q_NEXTCHAR, Q_THISCHAR } quoted;
101 CH ikey; /* Input character structure. */
102 CHAR_T ch; /* Input character. */
103 GS *gp; /* Global pointer. */
104 TEXT *tp, *ntp, ait; /* Input and autoindent text structures. */
105 size_t rcol; /* 0-N: insert offset in the replay buffer. */
106 size_t col; /* Current column. */
107 u_long margin; /* Wrapmargin value. */
108 u_int iflags; /* Input flags. */
109 int ab_cnt, ab_turnoff; /* Abbreviation count, if turned off. */
110 int eval; /* Routine return value. */
111 int replay; /* If replaying a set of input. */
112 int showmatch; /* Showmatch set on this character. */
113 int testnr; /* Test first character for nul replay. */
114 int max, tmp;
115 char *p;
118 * Set the input flag, so tabs get displayed correctly
119 * and everyone knows that the text buffer is in use.
121 F_SET(sp, S_INPUT);
123 /* Local initialization. */
124 eval = 0;
125 gp = sp->gp;
128 * Get one TEXT structure with some initial buffer space, reusing
129 * the last one if it's big enough. (All TEXT bookkeeping fields
130 * default to 0 -- text_init() handles this.) If changing a line,
131 * copy it into the TEXT buffer.
133 if (tiqh->cqh_first != (void *)tiqh) {
134 tp = tiqh->cqh_first;
135 if (tp->q.cqe_next != (void *)tiqh || tp->lb_len < len + 32) {
136 text_lfree(tiqh);
137 goto newtp;
139 tp->ai = tp->insert = tp->offset = tp->owrite = 0;
140 if (lp != NULL) {
141 tp->len = len;
142 memmove(tp->lb, lp, len);
143 } else
144 tp->len = 0;
145 } else {
146 newtp: if ((tp = text_init(sp, lp, len, len + 32)) == NULL)
147 return (1);
148 CIRCLEQ_INSERT_HEAD(tiqh, tp, q);
151 /* Set the starting line number. */
152 tp->lno = sp->lno;
155 * Set the insert and overwrite counts. If overwriting characters,
156 * do insertion afterward. If not overwriting characters, assume
157 * doing insertion. If change is to a mark, emphasize it with an
158 * END_CH.
160 if (len) {
161 if (LF_ISSET(TXT_OVERWRITE)) {
162 tp->owrite = tm->cno - sp->cno;
163 tp->insert = len - tm->cno;
164 } else
165 tp->insert = len - sp->cno;
167 if (LF_ISSET(TXT_EMARK))
168 tp->lb[tm->cno - 1] = END_CH;
172 * Many of the special cases in this routine are to handle autoindent
173 * support. Somebody decided that it would be a good idea if "^^D"
174 * and "0^D" deleted all of the autoindented characters. In an editor
175 * that takes single character input from the user, this wasn't a very
176 * good idea. Note also that "^^D" resets the next lines' autoindent,
177 * but "0^D" doesn't.
179 * We assume that autoindent only happens on empty lines, so insert
180 * and overwrite will be zero. If doing autoindent, figure out how
181 * much indentation we need and fill it in. Update input column and
182 * screen cursor as necessary.
184 if (LF_ISSET(TXT_AUTOINDENT) && ai_line != OOBLNO) {
185 if (txt_auto(sp, ep, ai_line, NULL, 0, tp))
186 return (1);
187 sp->cno = tp->ai;
188 } else {
190 * The cc and S commands have a special feature -- leading
191 * <blank> characters are handled as autoindent characters.
192 * Beauty!
194 if (LF_ISSET(TXT_AICHARS)) {
195 tp->offset = 0;
196 tp->ai = sp->cno;
197 } else
198 tp->offset = sp->cno;
201 /* If getting a command buffer from the user, there may be a prompt. */
202 if (LF_ISSET(TXT_PROMPT)) {
203 tp->lb[sp->cno++] = prompt;
204 ++tp->len;
205 ++tp->offset;
209 * If appending after the end-of-line, add a space into the buffer
210 * and move the cursor right. This space is inserted, i.e. pushed
211 * along, and then deleted when the line is resolved. Assumes that
212 * the cursor is already positioned at the end of the line. This
213 * avoids the nastiness of having the cursor reside on a magical
214 * column, i.e. a column that doesn't really exist. The only down
215 * side is that we may wrap lines or scroll the screen before it's
216 * strictly necessary. Not a big deal.
218 if (LF_ISSET(TXT_APPENDEOL)) {
219 tp->lb[sp->cno] = CURSOR_CH;
220 ++tp->len;
221 ++tp->insert;
225 * Historic practice is that the wrapmargin value was a distance
226 * from the RIGHT-HAND column, not the left. It's more useful to
227 * us as a distance from the left-hand column.
229 * !!!
230 * Replay commands are not affected by wrapmargin values. What
231 * I found surprising was that people actually depend on it, as
232 * in this gem of a macro which centers lines:
234 * map #c $mq81a ^V^[81^V|D`qld0:s/ / /g^V^M$p
236 * XXX
237 * Setting margin causes a significant performance hit. Normally
238 * we don't update the screen if there are keys waiting, but we
239 * have to if margin is set, otherwise the screen routines don't
240 * know where the cursor is.
242 if (LF_ISSET(TXT_REPLAY) || !LF_ISSET(TXT_WRAPMARGIN))
243 margin = 0;
244 else if ((margin = O_VAL(sp, O_WRAPMARGIN)) != 0)
245 margin = sp->cols - margin;
247 /* Initialize abbreviations checks. */
248 if (F_ISSET(gp, G_ABBREV) && LF_ISSET(TXT_MAPINPUT)) {
249 abb = A_NOTSPACE;
250 ab_cnt = ab_turnoff = 0;
251 } else
252 abb = A_NOTSET;
255 * Set up the dot command. Dot commands are done by saving the
256 * actual characters and replaying the input. We have to push
257 * the characters onto the key stack and then handle them normally,
258 * otherwise things like wrapmargin will fail.
260 * XXX
261 * It would be nice if we could swallow backspaces and such, but
262 * it's not all that easy to do. Another possibility would be to
263 * recognize full line insertions, which could be performed quickly,
264 * without replay.
266 nullreplay:
267 rcol = 0;
268 if (replay = LF_ISSET(TXT_REPLAY)) {
270 * !!!
271 * Historically, it wasn't an error to replay non-existent
272 * input. This test is necessary, we get here by the user
273 * doing an input command followed by a nul.
275 * !!!
276 * Historically, vi did not remap or reabbreviate replayed
277 * input. It did, however, beep at you if you changed an
278 * abbreviation and then replayed the input. We're not that
279 * compatible.
281 if (VIP(sp)->rep == NULL)
282 return (0);
283 if (term_push(sp, VIP(sp)->rep, VIP(sp)->rep_cnt, 0, CH_NOMAP))
284 return (1);
285 testnr = 0;
286 abb = A_NOTSET;
287 LF_CLR(TXT_RECORD);
288 } else
289 testnr = 1;
291 iflags = LF_ISSET(TXT_MAPCOMMAND | TXT_MAPINPUT);
292 for (gp, showmatch = 0,
293 carat_st = C_NOTSET, hex = H_NOTSET, quoted = Q_NOTSET;;) {
295 * Reset the line and update the screen. (The txt_showmatch()
296 * code refreshes the screen for us.) Don't refresh unless
297 * we're about to wait on a character or we need to know where
298 * the cursor really is.
300 if (showmatch || margin || !KEYS_WAITING(sp)) {
301 if (sp->s_change(sp, ep, tp->lno, LINE_RESET))
302 goto err;
303 if (showmatch) {
304 showmatch = 0;
305 txt_showmatch(sp, ep);
306 } else if (sp->s_refresh(sp, ep))
307 goto err;
310 /* Get the next character. */
311 next_ch: if (term_key(sp, &ikey, iflags) != INP_OK)
312 goto err;
313 ch = ikey.ch;
315 /* Abbreviation check. See comment in txt_abbrev(). */
316 #define MAX_ABBREVIATION_EXPANSION 256
317 if (ikey.flags & CH_ABBREVIATED) {
318 if (++ab_cnt > MAX_ABBREVIATION_EXPANSION) {
319 term_ab_flush(sp,
320 "Abbreviation exceeded maximum number of characters");
321 ab_cnt = 0;
322 continue;
324 } else
325 ab_cnt = 0;
328 * !!!
329 * Historic feature. If the first character of the input is
330 * a nul, replay the previous input. This isn't documented
331 * anywhere, and is a great test of vi clones.
333 if (ch == '\0' && testnr) {
334 LF_SET(TXT_REPLAY);
335 goto nullreplay;
337 testnr = 0;
340 * Check to see if the character fits into the input (and
341 * replay, if necessary) buffers. It isn't necessary to
342 * have tp->len bytes, since it doesn't consider overwrite
343 * characters, but not worth fixing.
345 if (LF_ISSET(TXT_RECORD)) {
346 TBINC(sp, VIP(sp)->rep, VIP(sp)->rep_len, rcol + 1);
347 VIP(sp)->rep[rcol++] = ch;
349 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
352 * If the character was quoted, replace the last character
353 * (the literal mark) with the new character. If quoted
354 * by someone else, simply insert the character.
356 * !!!
357 * Extension -- if the quoted character is HEX_CH, enter hex
358 * mode. If the user enters "<HEX_CH>[isxdigit()]*" we will
359 * try to use the value as a character. Anything else resets
360 * hex mode.
362 if (ikey.flags & CH_QUOTED)
363 goto ins_ch;
364 if (quoted == Q_THISCHAR) {
365 --sp->cno;
366 ++tp->owrite;
367 quoted = Q_NOTSET;
369 if (ch == HEX_CH)
370 hex = H_NEXTCHAR;
371 goto ins_ch;
374 switch (ikey.value) {
375 case K_CR:
376 case K_NL: /* New line. */
377 #define LINE_RESOLVE { \
378 /* \
379 * Handle abbreviations. If there was one, \
380 * discard the replay characters. \
381 */ \
382 if (abb == A_NOTSPACE && !replay) { \
383 if (txt_abbrev(sp, tp, ch, \
384 LF_ISSET(TXT_INFOLINE), &tmp, \
385 &ab_turnoff)) \
386 goto err; \
387 if (tmp) { \
388 if (LF_ISSET(TXT_RECORD)) \
389 rcol -= tmp; \
390 goto next_ch; \
393 if (abb != A_NOTSET) \
394 abb = A_SPACE; \
395 /* Handle hex numbers. */ \
396 if (hex == H_INHEX) { \
397 if (txt_hex(sp, tp, &tmp, ch)) \
398 goto err; \
399 if (tmp) { \
400 hex = H_NOTSET; \
401 goto next_ch; \
404 /* \
405 * The 'R' command returns any overwriteable \
406 * characters in the first line to the original \
407 * characters.
408 */ \
409 if (LF_ISSET(TXT_REPLACE) && tp->owrite && \
410 tp == tiqh->cqh_first) { \
411 memmove(tp->lb + sp->cno, \
412 lp + sp->cno, tp->owrite); \
413 tp->insert += tp->owrite; \
414 tp->owrite = 0; \
416 /* Delete any appended cursor. */ \
417 if (LF_ISSET(TXT_APPENDEOL)) { \
418 --tp->len; \
419 --tp->insert; \
422 LINE_RESOLVE;
424 /* CR returns from the vi command line. */
425 if (LF_ISSET(TXT_CR)) {
427 * If a script window and not the colon
428 * line, push a <cr> so it gets executed.
430 if (F_ISSET(sp, S_SCRIPT) &&
431 !LF_ISSET(TXT_INFOLINE))
432 (void)term_push(sp,
433 "\r", 1, 0, CH_NOMAP);
434 goto k_escape;
438 * Historic practice was to delete any <blank>
439 * characters following the inserted newline.
440 * This affects the 'R', 'c', and 's' commands.
442 for (p = tp->lb + sp->cno + tp->owrite;
443 tp->insert && isblank(*p);
444 ++p, ++tp->owrite, --tp->insert);
447 * Move any remaining insert characters into
448 * a new TEXT structure.
450 if ((ntp = text_init(sp,
451 tp->lb + sp->cno + tp->owrite,
452 tp->insert, tp->insert + 32)) == NULL)
453 goto err;
454 CIRCLEQ_INSERT_TAIL(tiqh, ntp, q);
456 /* Set bookkeeping for the new line. */
457 ntp->lno = tp->lno + 1;
458 ntp->insert = tp->insert;
461 * Note if the user inserted any characters on this
462 * line. Done before calling txt_ai_resolve() because
463 * it changes the value of sp->cno without making the
464 * corresponding changes to tp->ai.
466 tmp = sp->cno <= tp->ai;
469 * Resolve autoindented characters for the old line.
470 * Reset the autoindent line value. 0^D keeps the ai
471 * line from changing, ^D changes the level, even if
472 * there are no characters in the old line. Note,
473 * if using the current tp structure, use the cursor
474 * as the length, the user may have erased autoindent
475 * characters.
477 if (LF_ISSET(TXT_AUTOINDENT)) {
478 txt_ai_resolve(sp, tp);
480 if (carat_st == C_NOCHANGE) {
481 if (txt_auto(sp, ep,
482 OOBLNO, &ait, ait.ai, ntp))
483 goto err;
484 FREE_SPACE(sp, ait.lb, ait.lb_len);
485 } else
486 if (txt_auto(sp, ep,
487 OOBLNO, tp, sp->cno, ntp))
488 goto err;
489 carat_st = C_NOTSET;
493 * If the user hasn't entered any characters, delete
494 * any autoindent characters.
496 * !!!
497 * Historic vi didn't get the insert test right, if
498 * there were characters after the cursor, entering
499 * a <cr> left the autoindent characters on the line.
501 if (tmp)
502 sp->cno = 0;
504 /* Reset bookkeeping for the old line. */
505 tp->len = sp->cno;
506 tp->ai = tp->insert = tp->owrite = 0;
508 /* New cursor position. */
509 sp->cno = ntp->ai;
511 /* New lines are TXT_APPENDEOL if nothing to insert. */
512 if (ntp->insert == 0) {
513 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
514 LF_SET(TXT_APPENDEOL);
515 ntp->lb[sp->cno] = CURSOR_CH;
516 ++ntp->insert;
517 ++ntp->len;
520 /* Update the old line. */
521 if (sp->s_change(sp, ep, tp->lno, LINE_RESET))
522 goto err;
524 /* Swap old and new TEXT's. */
525 tp = ntp;
527 /* Reset the cursor. */
528 sp->lno = tp->lno;
530 /* Update the new line. */
531 if (sp->s_change(sp, ep, tp->lno, LINE_INSERT))
532 goto err;
534 /* Set the renumber bit. */
535 F_SET(sp, S_RENUMBER);
537 /* Refresh if nothing waiting. */
538 if ((margin || !KEYS_WAITING(sp)) &&
539 sp->s_refresh(sp, ep))
540 goto err;
541 goto next_ch;
542 case K_ESCAPE: /* Escape. */
543 if (!LF_ISSET(TXT_ESCAPE))
544 goto ins_ch;
546 LINE_RESOLVE;
549 * If there aren't any trailing characters in the line
550 * and the user hasn't entered any characters, delete
551 * the autoindent characters.
553 if (!tp->insert && sp->cno <= tp->ai) {
554 tp->len = tp->owrite = 0;
555 sp->cno = 0;
556 } else if (LF_ISSET(TXT_AUTOINDENT))
557 txt_ai_resolve(sp, tp);
559 /* If there are insert characters, copy them down. */
560 k_escape: if (tp->insert && tp->owrite)
561 memmove(tp->lb + sp->cno,
562 tp->lb + sp->cno + tp->owrite, tp->insert);
563 tp->len -= tp->owrite;
566 * Delete any lines that were inserted into the text
567 * structure and then erased.
569 while (tp->q.cqe_next != (void *)tiqh) {
570 ntp = tp->q.cqe_next;
571 CIRCLEQ_REMOVE(tiqh, ntp, q);
572 text_free(ntp);
576 * If not resolving the lines into the file, end
577 * it with a nul.
579 * XXX
580 * This is wrong, should pass back a length.
582 if (LF_ISSET(TXT_RESOLVE)) {
583 if (txt_resolve(sp, ep, tiqh))
584 goto err;
586 * Clear input flag -- input buffer no longer
587 * valid.
589 F_CLR(sp, S_INPUT);
590 } else {
591 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
592 tp->lb[tp->len] = '\0';
596 * Set the return cursor position to rest on the last
597 * inserted character.
599 if (rp != NULL) {
600 rp->lno = tp->lno;
601 rp->cno = sp->cno ? sp->cno - 1 : 0;
602 if (sp->s_change(sp, ep, rp->lno, LINE_RESET))
603 goto err;
605 goto ret;
606 case K_CARAT: /* Delete autoindent chars. */
607 if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai)
608 carat_st = C_CARATSET;
609 goto ins_ch;
610 case K_ZERO: /* Delete autoindent chars. */
611 if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai)
612 carat_st = C_ZEROSET;
613 goto ins_ch;
614 case K_VEOF: /* Delete autoindent char. */
616 * If in the first column or no characters to erase,
617 * ignore the ^D (this matches historic practice). If
618 * not doing autoindent or already inserted non-ai
619 * characters, it's a literal. The latter test is done
620 * in the switch, as the CARAT forms are N + 1, not N.
622 if (!LF_ISSET(TXT_AUTOINDENT))
623 goto ins_ch;
624 if (sp->cno == 0 || tp->ai == 0)
625 break;
626 switch (carat_st) {
627 case C_CARATSET: /* ^^D */
628 if (sp->cno > tp->ai + tp->offset + 1)
629 goto ins_ch;
631 /* Save the ai string for later. */
632 ait.lb = NULL;
633 ait.lb_len = 0;
634 TBINC(sp, ait.lb, ait.lb_len, tp->ai);
635 memmove(ait.lb, tp->lb, tp->ai);
636 ait.ai = ait.len = tp->ai;
638 carat_st = C_NOCHANGE;
639 goto leftmargin;
640 case C_ZEROSET: /* 0^D */
641 if (sp->cno > tp->ai + tp->offset + 1)
642 goto ins_ch;
643 carat_st = C_NOTSET;
644 leftmargin: tp->lb[sp->cno - 1] = ' ';
645 tp->owrite += sp->cno - tp->offset;
646 tp->ai = 0;
647 sp->cno = tp->offset;
648 break;
649 case C_NOTSET: /* ^D */
650 if (sp->cno > tp->ai + tp->offset)
651 goto ins_ch;
652 (void)txt_outdent(sp, tp);
653 break;
654 default:
655 abort();
657 break;
658 case K_VERASE: /* Erase the last character. */
660 * If can erase over the prompt, return. Len is 0
661 * if backspaced over the prompt, 1 if only CR entered.
663 if (LF_ISSET(TXT_BS) && sp->cno <= tp->offset) {
664 tp->len = 0;
665 goto ret;
669 * If at the beginning of the line, try and drop back
670 * to a previously inserted line.
672 if (sp->cno == 0) {
673 if ((ntp = txt_backup(sp,
674 ep, tiqh, tp, flags)) == NULL)
675 goto err;
676 tp = ntp;
677 break;
680 /* If nothing to erase, bell the user. */
681 if (sp->cno <= tp->offset) {
682 msgq(sp, M_BERR,
683 "No more characters to erase.");
684 break;
687 /* Drop back one character. */
688 --sp->cno;
691 * Increment overwrite, decrement ai if deleted.
693 * !!!
694 * Historic vi did not permit users to use erase
695 * characters to delete autoindent characters.
697 ++tp->owrite;
698 if (sp->cno < tp->ai)
699 --tp->ai;
700 break;
701 case K_VWERASE: /* Skip back one word. */
703 * If at the beginning of the line, try and drop back
704 * to a previously inserted line.
706 if (sp->cno == 0) {
707 if ((ntp = txt_backup(sp,
708 ep, tiqh, tp, flags)) == NULL)
709 goto err;
710 tp = ntp;
714 * If at offset, nothing to erase so bell the user.
716 if (sp->cno <= tp->offset) {
717 msgq(sp, M_BERR,
718 "No more characters to erase.");
719 break;
723 * First werase goes back to any autoindent
724 * and second werase goes back to the offset.
726 * !!!
727 * Historic vi did not permit users to use erase
728 * characters to delete autoindent characters.
730 if (tp->ai && sp->cno > tp->ai)
731 max = tp->ai;
732 else {
733 tp->ai = 0;
734 max = tp->offset;
737 /* Skip over trailing space characters. */
738 while (sp->cno > max && isblank(tp->lb[sp->cno - 1])) {
739 --sp->cno;
740 ++tp->owrite;
742 if (sp->cno == max)
743 break;
745 * There are three types of word erase found on UNIX
746 * systems. They can be identified by how the string
747 * /a/b/c is treated -- as 1, 3, or 6 words. Historic
748 * vi had two classes of characters, and strings were
749 * delimited by them and <blank>'s, so, 6 words. The
750 * historic tty interface used <blank>'s to delimit
751 * strings, so, 1 word. The algorithm offered in the
752 * 4.4BSD tty interface (as stty altwerase) treats it
753 * as 3 words -- there are two classes of characters,
754 * and strings are delimited by them and <blank>'s.
755 * The difference is that the type of the first erased
756 * character erased is ignored, which is exactly right
757 * when erasing pathname components. Here, the options
758 * TXT_ALTWERASE and TXT_TTYWERASE specify the 4.4BSD
759 * tty interface and the historic tty driver behavior,
760 * respectively, and the default is the same as the
761 * historic vi behavior.
763 if (LF_ISSET(TXT_TTYWERASE))
764 while (sp->cno > max) {
765 --sp->cno;
766 ++tp->owrite;
767 if (isblank(tp->lb[sp->cno - 1]))
768 break;
770 else {
771 if (LF_ISSET(TXT_ALTWERASE)) {
772 --sp->cno;
773 ++tp->owrite;
774 if (isblank(tp->lb[sp->cno - 1]))
775 break;
777 if (sp->cno > max)
778 tmp = inword(tp->lb[sp->cno - 1]);
779 while (sp->cno > max) {
780 --sp->cno;
781 ++tp->owrite;
782 if (tmp != inword(tp->lb[sp->cno - 1])
783 || isblank(tp->lb[sp->cno - 1]))
784 break;
787 break;
788 case K_VKILL: /* Restart this line. */
790 * If at the beginning of the line, try and drop back
791 * to a previously inserted line.
793 if (sp->cno == 0) {
794 if ((ntp = txt_backup(sp,
795 ep, tiqh, tp, flags)) == NULL)
796 goto err;
797 tp = ntp;
800 /* If at offset, nothing to erase so bell the user. */
801 if (sp->cno <= tp->offset) {
802 msgq(sp, M_BERR,
803 "No more characters to erase.");
804 break;
808 * First kill goes back to any autoindent
809 * and second kill goes back to the offset.
811 * !!!
812 * Historic vi did not permit users to use erase
813 * characters to delete autoindent characters.
815 if (tp->ai && sp->cno > tp->ai)
816 max = tp->ai;
817 else {
818 tp->ai = 0;
819 max = tp->offset;
821 tp->owrite += sp->cno - max;
822 sp->cno = max;
823 break;
824 case K_CNTRLT: /* Add autoindent char. */
825 if (!LF_ISSET(TXT_CNTRLT))
826 goto ins_ch;
827 if (txt_indent(sp, tp))
828 goto err;
829 goto ebuf_chk;
830 case K_CNTRLZ:
831 (void)sp->s_suspend(sp);
832 break;
833 #ifdef HISTORIC_PRACTICE_IS_TO_INSERT_NOT_REPAINT
834 case K_FORMFEED:
835 F_SET(sp, S_REFRESH);
836 break;
837 #endif
838 case K_RIGHTBRACE:
839 case K_RIGHTPAREN:
840 showmatch = LF_ISSET(TXT_SHOWMATCH);
841 goto ins_ch;
842 case K_VLNEXT: /* Quote the next character. */
843 /* If in hex mode, see if we've entered a hex value. */
844 if (hex == H_INHEX) {
845 if (txt_hex(sp, tp, &tmp, ch))
846 goto err;
847 if (tmp) {
848 hex = H_NOTSET;
849 goto next_ch;
852 ch = '^';
853 quoted = Q_NEXTCHAR;
854 /* FALLTHROUGH */
855 default: /* Insert the character. */
856 ins_ch: /*
857 * If entering a space character after a word, check
858 * for abbreviations. If there was one, discard the
859 * replay characters.
861 if (isblank(ch) && abb == A_NOTSPACE && !replay) {
862 if (txt_abbrev(sp, tp, ch,
863 LF_ISSET(TXT_INFOLINE), &tmp, &ab_turnoff))
864 goto err;
865 if (tmp) {
866 if (LF_ISSET(TXT_RECORD))
867 rcol -= tmp;
868 goto next_ch;
871 /* If in hex mode, see if we've entered a hex value. */
872 if (hex == H_INHEX && !isxdigit(ch)) {
873 if (txt_hex(sp, tp, &tmp, ch))
874 goto err;
875 if (tmp) {
876 hex = H_NOTSET;
877 goto next_ch;
880 /* Check to see if we've crossed the margin. */
881 if (margin) {
882 if (sp->s_column(sp, ep, &col))
883 goto err;
884 if (col >= margin) {
885 if (txt_margin(sp, tp, &tmp, ch))
886 goto err;
887 if (tmp)
888 goto next_ch;
891 if (abb != A_NOTSET)
892 abb = isblank(ch) ? A_SPACE : A_NOTSPACE;
894 if (tp->owrite) /* Overwrite a character. */
895 --tp->owrite;
896 else if (tp->insert) { /* Insert a character. */
897 ++tp->len;
898 if (tp->insert == 1)
899 tp->lb[sp->cno + 1] = tp->lb[sp->cno];
900 else
901 memmove(tp->lb + sp->cno + 1,
902 tp->lb + sp->cno, tp->insert);
905 tp->lb[sp->cno++] = ch;
908 * If we've reached the end of the buffer, then we
909 * need to switch into insert mode. This happens
910 * when there's a change to a mark and the user puts
911 * in more characters than the length of the motion.
913 ebuf_chk: if (sp->cno >= tp->len) {
914 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
915 LF_SET(TXT_APPENDEOL);
916 tp->lb[sp->cno] = CURSOR_CH;
917 ++tp->insert;
918 ++tp->len;
921 if (hex == H_NEXTCHAR)
922 hex = H_INHEX;
923 if (quoted == Q_NEXTCHAR)
924 quoted = Q_THISCHAR;
925 break;
927 #if defined(DEBUG) && 1
928 if (sp->cno + tp->insert + tp->owrite != tp->len)
929 msgq(sp, M_ERR,
930 "len %u != cno: %u ai: %u insert %u overwrite %u",
931 tp->len, sp->cno, tp->ai, tp->insert, tp->owrite);
932 tp->len = sp->cno + tp->insert + tp->owrite;
933 #endif
936 /* Clear input flag. */
937 ret: F_CLR(sp, S_INPUT);
939 if (LF_ISSET(TXT_RECORD))
940 VIP(sp)->rep_cnt = rcol;
941 return (eval);
943 /* Error jump. */
944 err: eval = 1;
945 txt_err(sp, ep, tiqh);
946 goto ret;
950 * txt_abbrev --
951 * Handle abbreviations.
953 static int
954 txt_abbrev(sp, tp, pushc, isinfoline, didsubp, turnoffp)
955 SCR *sp;
956 TEXT *tp;
957 ARG_CHAR_T pushc;
958 int isinfoline, *didsubp, *turnoffp;
960 CHAR_T ch;
961 SEQ *qp;
962 size_t len, off;
963 char *p;
965 /* Find the beginning of this "word". */
966 for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
967 if (isblank(*p)) {
968 ++p;
969 break;
971 ++len;
972 if (off == tp->ai || off == tp->offset)
973 break;
977 * !!!
978 * Historic vi exploded abbreviations on the command line. This has
979 * obvious problems in that unabbreviating the string can be extremely
980 * tricky, particularly if the string has, say, an embedded escape
981 * character. Personally, I think it's a stunningly bad idea. Other
982 * examples of problems this caused in historic vi are:
983 * :ab foo bar
984 * :ab foo baz
985 * results in "bar" abbreviated to "baz", which wasn't what the user
986 * had in mind at all. Also, the commands:
987 * :ab foo bar
988 * :unab foo<space>
989 * resulted in an error message that "bar" wasn't mapped. Finally,
990 * since the string was already exploded by the time the unabbreviate
991 * command got it, all it knew was that an abbreviation had occurred.
992 * Cleverly, it check the replacement string for a match, which means
993 * that:
994 * :ab foo1 bar
995 * :ab foo2 bar
996 * :unab foo2
997 * unabbreviates "foo1".
999 * Anyway, people neglected to first ask my opinion before they wrote
1000 * macros that depend on this stuff, so, we make this work as follows.
1001 * When checking for an abbreviation on the command line, if we get a
1002 * string which is <blank> terminated and which starts at the beginning
1003 * of the line, we check to see it is the abbreviate or unabbreviate
1004 * commands. If it is, turn abbreviations off and return as if no
1005 * abbreviation was found. Note also, minor trickiness, so that if the
1006 * user erases the line and starts another command, we go ahead an turn
1007 * abbreviations back on.
1009 * This makes the layering look like a Nachos Supreme.
1011 *didsubp = 0;
1012 if (isinfoline)
1013 if (off == tp->ai || off == tp->offset)
1014 if (ex_is_abbrev(p, len)) {
1015 *turnoffp = 1;
1016 return (0);
1017 } else
1018 *turnoffp = 0;
1019 else
1020 if (*turnoffp)
1021 return (0);
1023 /* Check for any abbreviations. */
1024 if ((qp = seq_find(sp, NULL, p, len, SEQ_ABBREV, NULL)) == NULL)
1025 return (0);
1028 * Push the abbreviation onto the tty stack. Historically, characters
1029 * resulting from an abbreviation expansion were themselves subject to
1030 * map expansions, O_SHOWMATCH matching etc. This means the expanded
1031 * characters will be re-tested for abbreviations. It's difficult to
1032 * know what historic practice in this case was, since abbreviations
1033 * were applied to :colon command lines, so entering abbreviations that
1034 * looped was tricky, although possible. In addition, obvious loops
1035 * didn't work as expected. (The command ':ab a b|ab b c|ab c a' will
1036 * silently only implement and/or display the last abbreviation.)
1038 * This implementation doesn't recover well from such abbreviations.
1039 * The main input loop counts abbreviated characters, and, when it
1040 * reaches a limit, discards any abbreviated characters on the queue.
1041 * It's difficult to back up to the original position, as the replay
1042 * queue would have to be adjusted, and the line state when an initial
1043 * abbreviated character was received would have to be saved.
1045 ch = pushc;
1046 if (term_push(sp, &ch, 1, 0, CH_ABBREVIATED))
1047 return (1);
1048 if (term_push(sp, qp->output, qp->olen, 0, CH_ABBREVIATED))
1049 return (1);
1052 * Move the cursor to the start of the abbreviation,
1053 * adjust the length.
1055 sp->cno -= len;
1056 tp->len -= len;
1058 /* Copy any insert characters back. */
1059 if (tp->insert)
1060 memmove(tp->lb + sp->cno + tp->owrite,
1061 tp->lb + sp->cno + tp->owrite + len, tp->insert);
1064 * We return the length of the abbreviated characters. This is so
1065 * the calling routine can replace the replay characters with the
1066 * abbreviation. This means that subsequent '.' commands will produce
1067 * the same text, regardless of intervening :[un]abbreviate commands.
1068 * This is historic practice.
1070 *didsubp = len;
1071 return (0);
1074 /* Offset to next column of stop size. */
1075 #define STOP_OFF(c, stop) (stop - (c) % stop)
1078 * txt_ai_resolve --
1079 * When a line is resolved by <esc> or <cr>, review autoindent
1080 * characters.
1082 static void
1083 txt_ai_resolve(sp, tp)
1084 SCR *sp;
1085 TEXT *tp;
1087 u_long ts;
1088 int del;
1089 size_t cno, len, new, old, scno, spaces, tab_after_sp, tabs;
1090 char *p;
1093 * If the line is empty, has an offset, or no autoindent
1094 * characters, we're done.
1096 if (!tp->len || tp->offset || !tp->ai)
1097 return;
1100 * The autoindent characters plus any leading <blank> characters
1101 * in the line are resolved into the minimum number of characters.
1102 * Historic practice.
1104 ts = O_VAL(sp, O_TABSTOP);
1106 /* Figure out the last <blank> screen column. */
1107 for (p = tp->lb, scno = 0, len = tp->len,
1108 spaces = tab_after_sp = 0; len-- && isblank(*p); ++p)
1109 if (*p == '\t') {
1110 if (spaces)
1111 tab_after_sp = 1;
1112 scno += STOP_OFF(scno, ts);
1113 } else {
1114 ++spaces;
1115 ++scno;
1119 * If there are no spaces, or no tabs after spaces and less than
1120 * ts spaces, it's already minimal.
1122 if (!spaces || !tab_after_sp && spaces < ts)
1123 return;
1125 /* Count up spaces/tabs needed to get to the target. */
1126 for (cno = 0, tabs = 0; cno + STOP_OFF(cno, ts) <= scno; ++tabs)
1127 cno += STOP_OFF(cno, ts);
1128 spaces = scno - cno;
1131 * Figure out how many characters we're dropping -- if we're not
1132 * dropping any, it's already minimal, we're done.
1134 old = p - tp->lb;
1135 new = spaces + tabs;
1136 if (old == new)
1137 return;
1139 /* Shift the rest of the characters down, adjust the counts. */
1140 del = old - new;
1141 memmove(p - del, p, tp->len - old);
1142 sp->cno -= del;
1143 tp->len -= del;
1145 /* Fill in space/tab characters. */
1146 for (p = tp->lb; tabs--;)
1147 *p++ = '\t';
1148 while (spaces--)
1149 *p++ = ' ';
1153 * txt_auto --
1154 * Handle autoindent. If aitp isn't NULL, use it, otherwise,
1155 * retrieve the line.
1158 txt_auto(sp, ep, lno, aitp, len, tp)
1159 SCR *sp;
1160 EXF *ep;
1161 recno_t lno;
1162 size_t len;
1163 TEXT *aitp, *tp;
1165 size_t nlen;
1166 char *p, *t;
1168 if (aitp == NULL) {
1169 if ((p = t = file_gline(sp, ep, lno, &len)) == NULL)
1170 return (0);
1171 } else
1172 p = t = aitp->lb;
1173 for (nlen = 0; len; ++p) {
1174 if (!isblank(*p))
1175 break;
1176 /* If last character is a space, it counts. */
1177 if (--len == 0) {
1178 ++p;
1179 break;
1183 /* No indentation. */
1184 if (p == t)
1185 return (0);
1187 /* Set count. */
1188 nlen = p - t;
1190 /* Make sure the buffer's big enough. */
1191 BINC_RET(sp, tp->lb, tp->lb_len, tp->len + nlen);
1193 /* Copy the indentation into the new buffer. */
1194 memmove(tp->lb + nlen, tp->lb, tp->len);
1195 memmove(tp->lb, t, nlen);
1196 tp->len += nlen;
1198 /* Return the additional length. */
1199 tp->ai = nlen;
1200 return (0);
1204 * txt_backup --
1205 * Back up to the previously edited line.
1207 static TEXT *
1208 txt_backup(sp, ep, tiqh, tp, flags)
1209 SCR *sp;
1210 EXF *ep;
1211 TEXTH *tiqh;
1212 TEXT *tp;
1213 u_int flags;
1215 TEXT *ntp;
1216 size_t col;
1218 if (tp->q.cqe_prev == (void *)tiqh) {
1219 msgq(sp, M_BERR, "Already at the beginning of the insert");
1220 return (tp);
1223 /* Update the old line on the screen. */
1224 if (sp->s_change(sp, ep, tp->lno, LINE_DELETE))
1225 return (NULL);
1227 /* Get a handle on the previous TEXT structure. */
1228 ntp = tp->q.cqe_prev;
1230 /* Make sure that we can get enough space. */
1231 if (LF_ISSET(TXT_APPENDEOL) && ntp->len + 1 > ntp->lb_len &&
1232 binc(sp, &ntp->lb, &ntp->lb_len, ntp->len + 1))
1233 return (NULL);
1236 * Release current TEXT; now committed to the swap, nothing
1237 * better fail.
1239 CIRCLEQ_REMOVE(tiqh, tp, q);
1240 text_free(tp);
1242 /* Swap TEXT's. */
1243 tp = ntp;
1245 /* Set bookkeeping information. */
1246 col = tp->len;
1247 if (LF_ISSET(TXT_APPENDEOL)) {
1248 tp->lb[col] = CURSOR_CH;
1249 ++tp->insert;
1250 ++tp->len;
1252 sp->lno = tp->lno;
1253 sp->cno = col;
1254 return (tp);
1258 * txt_err --
1259 * Handle an error during input processing.
1261 static void
1262 txt_err(sp, ep, tiqh)
1263 SCR *sp;
1264 EXF *ep;
1265 TEXTH *tiqh;
1267 recno_t lno;
1268 size_t len;
1271 * The problem with input processing is that the cursor is at an
1272 * indeterminate position since some input may have been lost due
1273 * to a malloc error. So, try to go back to the place from which
1274 * the cursor started, knowing that it may no longer be available.
1276 * We depend on at least one line number being set in the text
1277 * chain.
1279 for (lno = tiqh->cqh_first->lno;
1280 file_gline(sp, ep, lno, &len) == NULL && lno > 0; --lno);
1282 sp->lno = lno == 0 ? 1 : lno;
1283 sp->cno = 0;
1285 /* Redraw the screen, just in case. */
1286 F_SET(sp, S_REDRAW);
1290 * txt_hex --
1291 * Let the user insert any character value they want.
1293 * !!!
1294 * This is an extension. The pattern "^Vx[0-9a-fA-F]*" is a way
1295 * for the user to specify a character value which their keyboard
1296 * may not be able to enter.
1298 static int
1299 txt_hex(sp, tp, was_hex, pushc)
1300 SCR *sp;
1301 TEXT *tp;
1302 int *was_hex;
1303 ARG_CHAR_T pushc;
1305 CHAR_T ch, savec;
1306 size_t len, off;
1307 u_long value;
1308 char *p, *wp;
1311 * Null-terminate the string. Since nul isn't a legal hex value,
1312 * this should be okay, and lets us use a local routine, which
1313 * presumably understands the character set, to convert the value.
1315 savec = tp->lb[sp->cno];
1316 tp->lb[sp->cno] = 0;
1318 /* Find the previous HEX_CH. */
1319 for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
1320 if (*p == HEX_CH) {
1321 wp = p + 1;
1322 break;
1324 ++len;
1325 /* If not on this line, there's nothing to do. */
1326 if (off == tp->ai || off == tp->offset)
1327 goto nothex;
1330 /* If no length, then it wasn't a hex value. */
1331 if (len == 0)
1332 goto nothex;
1334 /* Get the value. */
1335 value = strtol(wp, NULL, 16);
1336 if (value == LONG_MIN || value == LONG_MAX || value > MAX_CHAR_T) {
1337 nothex: tp->lb[sp->cno] = savec;
1338 *was_hex = 0;
1339 return (0);
1342 ch = pushc;
1343 if (term_push(sp, &ch, 1, 0, CH_NOMAP | CH_QUOTED))
1344 return (1);
1345 ch = value;
1346 if (term_push(sp, &ch, 1, 0, CH_NOMAP | CH_QUOTED))
1347 return (1);
1349 tp->lb[sp->cno] = savec;
1351 /* Move the cursor to the start of the hex value, adjust the length. */
1352 sp->cno -= len + 1;
1353 tp->len -= len + 1;
1355 /* Copy any insert characters back. */
1356 if (tp->insert)
1357 memmove(tp->lb + sp->cno + tp->owrite,
1358 tp->lb + sp->cno + tp->owrite + len + 1, tp->insert);
1360 *was_hex = 1;
1361 return (0);
1365 * Txt_indent and txt_outdent are truly strange. ^T and ^D do movements
1366 * to the next or previous shiftwidth value, i.e. for a 1-based numbering,
1367 * with shiftwidth=3, ^T moves a cursor on the 7th, 8th or 9th column to
1368 * the 10th column, and ^D moves it back.
1370 * !!!
1371 * The ^T and ^D characters in historical vi only had special meaning when
1372 * they were the first characters typed after entering text input mode.
1373 * Since normal erase characters couldn't erase autoindent (in this case
1374 * ^T) characters, this meant that inserting text into previously existing
1375 * text was quite strange, ^T only worked if it was the first keystroke,
1376 * and then it could only be erased by using ^D. This implementation treats
1377 * ^T specially anywhere it occurs in the input, and permits the standard
1378 * erase characters to erase characters inserted using it.
1380 * XXX
1381 * Technically, txt_indent, txt_outdent should part of the screen interface,
1382 * as they require knowledge of the size of a space character on the screen.
1383 * (Not the size of tabs, because tabs are logically composed of spaces.)
1384 * They're left in the text code because they're complicated, not to mention
1385 * the gruesome awareness that if spaces aren't a single column on the screen
1386 * for any language, we're into some serious, ah, for lack of a better word,
1387 * "issues".
1391 * txt_indent --
1392 * Handle ^T indents.
1394 static int
1395 txt_indent(sp, tp)
1396 SCR *sp;
1397 TEXT *tp;
1399 u_long sw, ts;
1400 size_t cno, off, scno, spaces, tabs;
1402 ts = O_VAL(sp, O_TABSTOP);
1403 sw = O_VAL(sp, O_SHIFTWIDTH);
1405 /* Get the current screen column. */
1406 for (off = scno = 0; off < sp->cno; ++off)
1407 if (tp->lb[off] == '\t')
1408 scno += STOP_OFF(scno, ts);
1409 else
1410 ++scno;
1412 /* Count up spaces/tabs needed to get to the target. */
1413 for (cno = scno, scno += STOP_OFF(scno, sw), tabs = 0;
1414 cno + STOP_OFF(cno, ts) <= scno; ++tabs)
1415 cno += STOP_OFF(cno, ts);
1416 spaces = scno - cno;
1418 /* Put space/tab characters in place of any overwrite characters. */
1419 for (; tp->owrite && tabs; --tp->owrite, --tabs, ++tp->ai)
1420 tp->lb[sp->cno++] = '\t';
1421 for (; tp->owrite && spaces; --tp->owrite, --spaces, ++tp->ai)
1422 tp->lb[sp->cno++] = ' ';
1424 if (!tabs && !spaces)
1425 return (0);
1427 /* Make sure there's enough room. */
1428 BINC_RET(sp, tp->lb, tp->lb_len, tp->len + spaces + tabs);
1430 /* Move the insert characters out of the way. */
1431 if (tp->insert)
1432 memmove(tp->lb + sp->cno + spaces + tabs,
1433 tp->lb + sp->cno, tp->insert);
1435 /* Add new space/tab characters. */
1436 for (; tabs--; ++tp->len, ++tp->ai)
1437 tp->lb[sp->cno++] = '\t';
1438 for (; spaces--; ++tp->len, ++tp->ai)
1439 tp->lb[sp->cno++] = ' ';
1440 return (0);
1444 * txt_outdent --
1445 * Handle ^D outdents.
1448 static int
1449 txt_outdent(sp, tp)
1450 SCR *sp;
1451 TEXT *tp;
1453 u_long sw, ts;
1454 size_t cno, off, scno, spaces;
1456 ts = O_VAL(sp, O_TABSTOP);
1457 sw = O_VAL(sp, O_SHIFTWIDTH);
1459 /* Get the current screen column. */
1460 for (off = scno = 0; off < sp->cno; ++off)
1461 if (tp->lb[off] == '\t')
1462 scno += STOP_OFF(scno, ts);
1463 else
1464 ++scno;
1466 /* Get the previous shiftwidth column. */
1467 for (cno = scno; --scno % sw != 0;);
1469 /* Decrement characters until less than or equal to that slot. */
1470 for (; cno > scno; --sp->cno, --tp->ai, ++tp->owrite)
1471 if (tp->lb[--off] == '\t')
1472 cno -= STOP_OFF(cno, ts);
1473 else
1474 --cno;
1476 /* Spaces needed to get to the target. */
1477 spaces = scno - cno;
1479 /* Maybe just a delete. */
1480 if (spaces == 0)
1481 return (0);
1483 /* Make sure there's enough room. */
1484 BINC_RET(sp, tp->lb, tp->lb_len, tp->len + spaces);
1486 /* Use up any overwrite characters. */
1487 for (; tp->owrite && spaces; --spaces, ++tp->ai, --tp->owrite)
1488 tp->lb[sp->cno++] = ' ';
1490 /* Maybe that was enough. */
1491 if (spaces == 0)
1492 return (0);
1494 /* Move the insert characters out of the way. */
1495 if (tp->insert)
1496 memmove(tp->lb + sp->cno + spaces,
1497 tp->lb + sp->cno, tp->insert);
1499 /* Add new space characters. */
1500 for (; spaces--; ++tp->len, ++tp->ai)
1501 tp->lb[sp->cno++] = ' ';
1502 return (0);
1506 * txt_resolve --
1507 * Resolve the input text chain into the file.
1509 static int
1510 txt_resolve(sp, ep, tiqh)
1511 SCR *sp;
1512 EXF *ep;
1513 TEXTH *tiqh;
1515 TEXT *tp;
1516 recno_t lno;
1518 /* The first line replaces a current line. */
1519 tp = tiqh->cqh_first;
1520 if (file_sline(sp, ep, tp->lno, tp->lb, tp->len))
1521 return (1);
1523 /* All subsequent lines are appended into the file. */
1524 for (lno = tp->lno; (tp = tp->q.cqe_next) != (void *)&sp->tiq; ++lno)
1525 if (file_aline(sp, ep, 0, lno, tp->lb, tp->len))
1526 return (1);
1527 return (0);
1531 * txt_showmatch --
1532 * Show a character match.
1534 * !!!
1535 * Historic vi tried to display matches even in the :colon command line.
1536 * I think not.
1538 static void
1539 txt_showmatch(sp, ep)
1540 SCR *sp;
1541 EXF *ep;
1543 struct timeval second;
1544 VCS cs;
1545 MARK m;
1546 fd_set zero;
1547 int cnt, endc, startc;
1550 * Do a refresh first, in case the v_ntext() code hasn't done
1551 * one in awhile, so the user can see what we're complaining
1552 * about.
1554 if (sp->s_refresh(sp, ep))
1555 return;
1557 * We don't display the match if it's not on the screen. Find
1558 * out what the first character on the screen is.
1560 if (sp->s_position(sp, ep, &m, 0, P_TOP))
1561 return;
1563 /* Initialize the getc() interface. */
1564 cs.cs_lno = sp->lno;
1565 cs.cs_cno = sp->cno - 1;
1566 if (cs_init(sp, ep, &cs))
1567 return;
1568 startc = (endc = cs.cs_ch) == ')' ? '(' : '{';
1570 /* Search for the match. */
1571 for (cnt = 1;;) {
1572 if (cs_prev(sp, ep, &cs))
1573 return;
1574 if (cs.cs_lno < m.lno ||
1575 cs.cs_lno == m.lno && cs.cs_cno < m.cno)
1576 return;
1577 if (cs.cs_flags != 0) {
1578 if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF) {
1579 (void)sp->s_bell(sp);
1580 return;
1582 continue;
1584 if (cs.cs_ch == endc)
1585 ++cnt;
1586 else if (cs.cs_ch == startc && --cnt == 0)
1587 break;
1590 /* Move to the match. */
1591 m.lno = sp->lno;
1592 m.cno = sp->cno;
1593 sp->lno = cs.cs_lno;
1594 sp->cno = cs.cs_cno;
1595 (void)sp->s_refresh(sp, ep);
1598 * Sleep(3) is eight system calls. Do it fast -- besides,
1599 * I don't want to wait an entire second.
1601 FD_ZERO(&zero);
1602 second.tv_sec = O_VAL(sp, O_MATCHTIME) / 10;
1603 second.tv_usec = (O_VAL(sp, O_MATCHTIME) % 10) * 100000L;
1604 (void)select(0, &zero, &zero, &zero, &second);
1606 /* Return to the current location. */
1607 sp->lno = m.lno;
1608 sp->cno = m.cno;
1609 (void)sp->s_refresh(sp, ep);
1613 * txt_margin --
1614 * Handle margin wrap.
1616 * !!!
1617 * Historic vi belled the user each time a character was entered after
1618 * crossing the margin until a space was entered which could be used to
1619 * break the line. I don't, it tends to wake the cats.
1621 static int
1622 txt_margin(sp, tp, didbreak, pushc)
1623 SCR *sp;
1624 TEXT *tp;
1625 int *didbreak;
1626 ARG_CHAR_T pushc;
1628 CHAR_T ch;
1629 size_t len, off, tlen;
1630 char *p, *wp;
1632 /* Find the closest previous blank. */
1633 for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
1634 if (isblank(*p)) {
1635 wp = p + 1;
1636 break;
1638 ++len;
1639 /* If it's the beginning of the line, there's nothing to do. */
1640 if (off == tp->ai || off == tp->offset) {
1641 *didbreak = 0;
1642 return (0);
1647 * Historic practice is to delete any trailing whitespace
1648 * from the previous line.
1650 for (tlen = len;; --p, --off) {
1651 if (!isblank(*p))
1652 break;
1653 ++tlen;
1654 if (off == tp->ai || off == tp->offset)
1655 break;
1658 ch = pushc;
1659 if (term_push(sp, &ch, 1, 0, CH_NOMAP | CH_QUOTED))
1660 return (1);
1661 if (len && term_push(sp, wp, len, 0, CH_NOMAP | CH_QUOTED))
1662 return (1);
1663 ch = '\n';
1664 if (term_push(sp, &ch, 1, 0, CH_NOMAP))
1665 return (1);
1667 sp->cno -= tlen;
1668 tp->owrite += tlen;
1669 *didbreak = 1;
1670 return (0);