add svi_column so svi can return sc_col to vi/v_ntext.c
[nvi.git] / vi / v_txt.c
blob7674afe2072cb8b67376dbf0d0fad3f1f0d7abf0
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.55 1993/11/22 17:29:27 bostic Exp $ (Berkeley) $Date: 1993/11/22 17:29:27 $";
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 "vcmd.h"
24 static int txt_abbrev __P((SCR *, TEXT *, int *, ARG_CHAR_T));
25 static void txt_ai_resolve __P((SCR *, TEXT *));
26 static TEXT *txt_backup __P((SCR *, EXF *, TEXTH *, TEXT *, u_int));
27 static void txt_err __P((SCR *, EXF *, TEXTH *));
28 static int txt_hex __P((SCR *, TEXT *, int *, ARG_CHAR_T));
29 static int txt_indent __P((SCR *, TEXT *));
30 static int txt_margin __P((SCR *, TEXT *, int *, ARG_CHAR_T));
31 static int txt_outdent __P((SCR *, TEXT *));
32 static void txt_showmatch __P((SCR *, EXF *));
33 static int txt_resolve __P((SCR *, EXF *, TEXTH *));
35 /* Cursor character (space is hard to track on the screen). */
36 #if defined(DEBUG) && 0
37 #undef CURSOR_CH
38 #define CURSOR_CH '+'
39 #endif
41 /* Error jump. */
42 #define ERR { \
43 eval = 1; \
44 txt_err(sp, ep, tiqh); \
45 goto ret; \
48 /* Local version of BINC. */
49 #define TBINC(sp, lp, llen, nlen) { \
50 if ((nlen) > llen && binc(sp, &(lp), &(llen), nlen)) \
51 ERR; \
55 * newtext --
56 * Read in text from the user.
58 * !!!
59 * Historic vi always used:
61 * ^D: autoindent deletion
62 * ^H: last character deletion
63 * ^W: last word deletion
64 * ^V: quote the next character
66 * regardless of the user's choices for these characters. The user's erase
67 * and kill characters worked in addition to these characters. Ex was not
68 * completely consistent with this, as it did map the scroll command to the
69 * user's EOF character.
71 * This implementation does not use fixed characters, but uses whatever the
72 * user specified as described by the termios structure. I'm getting away
73 * with something here, but I think I'm unlikely to get caught.
75 int
76 v_ntext(sp, ep, tiqh, tm, lp, len, rp, prompt, ai_line, flags)
77 SCR *sp;
78 EXF *ep;
79 TEXTH *tiqh;
80 MARK *tm; /* To MARK. */
81 const char *lp; /* Input line. */
82 const size_t len; /* Input line length. */
83 MARK *rp; /* Return MARK. */
84 int prompt; /* Prompt to display. */
85 recno_t ai_line; /* Line number to use for autoindent count. */
86 u_int flags; /* TXT_ flags. */
88 /* State of abbreviation checks. */
89 enum { A_NOTSET, A_SPACE, A_NOTSPACE } abb;
90 /* State of the "[^0]^D" sequences. */
91 enum { C_NOTSET, C_CARATSET, C_NOCHANGE, C_ZEROSET } carat_st;
92 /* State of the hex input character. */
93 enum { H_NOTSET, H_NEXTCHAR, H_INHEX } hex;
94 /* State of quotation. */
95 enum { Q_NOTSET, Q_NEXTCHAR, Q_THISCHAR } quoted;
96 CHAR_T ch; /* Input character. */
97 GS *gp; /* Global pointer. */
98 TEXT *tp, *ntp, ait; /* Input and autoindent text structures. */
99 size_t rcol; /* 0-N: insert offset in the replay buffer. */
100 size_t col; /* Current column. */
101 u_long margin; /* Wrapmargin value. */
102 int eval; /* Routine return value. */
103 int replay; /* If replaying a set of input. */
104 int showmatch; /* Showmatch set on this character. */
105 int max, tmp;
106 char *p;
109 * Set the input flag, so tabs get displayed correctly
110 * and everyone knows that the text buffer is in use.
112 F_SET(sp, S_INPUT);
114 /* Set return value. */
115 eval = 0;
118 * Get one TEXT structure with some initial buffer space, reusing
119 * the last one if it's big enough. (All TEXT bookkeeping fields
120 * default to 0 -- text_init() handles this.) If changing a line,
121 * copy it into the TEXT buffer.
123 if (tiqh->cqh_first != (void *)tiqh) {
124 tp = tiqh->cqh_first;
125 if (tp->q.cqe_next != (void *)tiqh || tp->lb_len < len + 32) {
126 text_lfree(tiqh);
127 goto newtp;
129 tp->ai = tp->insert = tp->offset = tp->owrite = 0;
130 if (lp != NULL) {
131 tp->len = len;
132 memmove(tp->lb, lp, len);
133 } else
134 tp->len = 0;
135 } else {
136 newtp: if ((tp = text_init(sp, lp, len, len + 32)) == NULL)
137 return (1);
138 CIRCLEQ_INSERT_HEAD(tiqh, tp, q);
141 /* Set the starting line number. */
142 tp->lno = sp->lno;
145 * Set the insert and overwrite counts. If overwriting characters,
146 * do insertion afterward. If not overwriting characters, assume
147 * doing insertion. If change is to a mark, emphasize it with an
148 * END_CH.
150 if (len) {
151 if (LF_ISSET(TXT_OVERWRITE)) {
152 tp->owrite = tm->cno - sp->cno;
153 tp->insert = len - tm->cno;
154 } else
155 tp->insert = len - sp->cno;
157 if (LF_ISSET(TXT_EMARK))
158 tp->lb[tm->cno - 1] = END_CH;
162 * Many of the special cases in this routine are to handle autoindent
163 * support. Somebody decided that it would be a good idea if "^^D"
164 * and "0^D" deleted all of the autoindented characters. In an editor
165 * that takes single character input from the user, this wasn't a very
166 * good idea. Note also that "^^D" resets the next lines' autoindent,
167 * but "0^D" doesn't.
169 * We assume that autoindent only happens on empty lines, so insert
170 * and overwrite will be zero. If doing autoindent, figure out how
171 * much indentation we need and fill it in. Update input column and
172 * screen cursor as necessary.
174 if (LF_ISSET(TXT_AUTOINDENT) && ai_line != OOBLNO) {
175 if (txt_auto(sp, ep, ai_line, NULL, 0, tp))
176 return (1);
177 sp->cno = tp->ai;
178 } else {
180 * The cc and S commands have a special feature -- leading
181 * <blank> characters are handled as autoindent characters.
182 * Beauty!
184 if (LF_ISSET(TXT_AICHARS)) {
185 tp->offset = 0;
186 tp->ai = sp->cno;
187 } else
188 tp->offset = sp->cno;
191 /* If getting a command buffer from the user, there may be a prompt. */
192 if (LF_ISSET(TXT_PROMPT)) {
193 tp->lb[sp->cno++] = prompt;
194 ++tp->len;
195 ++tp->offset;
199 * If appending after the end-of-line, add a space into the buffer
200 * and move the cursor right. This space is inserted, i.e. pushed
201 * along, and then deleted when the line is resolved. Assumes that
202 * the cursor is already positioned at the end of the line. This
203 * avoids the nastiness of having the cursor reside on a magical
204 * column, i.e. a column that doesn't really exist. The only down
205 * side is that we may wrap lines or scroll the screen before it's
206 * strictly necessary. Not a big deal.
208 if (LF_ISSET(TXT_APPENDEOL)) {
209 tp->lb[sp->cno] = CURSOR_CH;
210 ++tp->len;
211 ++tp->insert;
215 * Historic practice is that the wrapmargin value was a distance
216 * from the RIGHT-HAND column, not the left. It's more useful to
217 * us as a distance from the left-hand column.
219 * XXX
220 * Setting margin causes a significant performance hit. Normally
221 * we don't update the screen if there are keys waiting, but we
222 * have to if margin is set, otherwise the screen routines don't
223 * know where the cursor is.
225 if (!LF_ISSET(TXT_WRAPMARGIN))
226 margin = 0;
227 else if ((margin = O_VAL(sp, O_WRAPMARGIN)) != 0)
228 margin = sp->cols - margin;
231 * Set up the dot command. Dot commands are done by saving the
232 * actual characters and replaying the input. We have to push
233 * the characters onto the key stack and then handle them normally,
234 * otherwise things like wrapmargin will fail.
236 * XXX
237 * It would be nice if we could swallow backspaces and such, but
238 * it's not all that easy to do. Another possibility would be to
239 * recognize full line insertions, which could be performed quickly,
240 * without replay.
242 rcol = 0;
243 if (replay = LF_ISSET(TXT_REPLAY)) {
244 if (term_push(sp, sp->gp->key, VIP(sp)->rep, VIP(sp)->rep_cnt))
245 return (1);
246 LF_CLR(TXT_RECORD);
249 /* Initialize abbreviations check. */
250 abb = F_ISSET(sp, S_ABBREV) &&
251 LF_ISSET(TXT_MAPINPUT) ? A_NOTSPACE : A_NOTSET;
253 gp = sp->gp;
254 for (carat_st = C_NOTSET,
255 hex = H_NOTSET, showmatch = 0, quoted = Q_NOTSET;;) {
257 * Reset the line and update the screen. (The txt_showmatch()
258 * code refreshes the screen for us.) Don't refresh unless
259 * we're about to wait on a character or we need to know where
260 * the cursor really is.
262 if (showmatch || margin ||
263 !TERM_MORE(gp->key) && !TERM_MORE(gp->tty)) {
264 if (sp->s_change(sp, ep, tp->lno, LINE_RESET))
265 ERR;
266 if (showmatch) {
267 showmatch = 0;
268 txt_showmatch(sp, ep);
269 } else if (sp->s_refresh(sp, ep))
270 ERR;
274 * Get the character. Check to see if the character fits
275 * into the input (and replay, if necessary) buffers. It
276 * isn't necessary to have tp->len bytes, since it doesn't
277 * consider the overwrite characters, but not worth fixing.
279 next_ch: if (term_key(sp, &ch, flags & TXT_GETKEY_MASK) != INP_OK)
280 ERR;
281 if (LF_ISSET(TXT_RECORD)) {
282 TBINC(sp, VIP(sp)->rep, VIP(sp)->rep_len, rcol + 1);
283 VIP(sp)->rep[rcol++] = ch;
285 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
288 * If the character was quoted, replace the last character
289 * (the literal mark) with the new character.
291 * !!!
292 * Extension -- if the quoted character is HEX_CH, enter hex
293 * mode. If the user enters "<HEX_CH>[isxdigit()]*" we will
294 * try to use the value as a character. Anything else resets
295 * hex mode.
297 if (quoted == Q_THISCHAR) {
298 --sp->cno;
299 ++tp->owrite;
300 quoted = Q_NOTSET;
302 if (ch == HEX_CH)
303 hex = H_NEXTCHAR;
304 goto ins_ch;
307 switch (sp->special[ch]) {
308 case K_CR:
309 case K_NL: /* New line. */
310 #define LINE_RESOLVE { \
311 /* \
312 * Handle abbreviations. If there was one, \
313 * discard the replay characters. \
314 */ \
315 if (abb == A_NOTSPACE && !replay) { \
316 if (txt_abbrev(sp, tp, &tmp, ch)) \
317 ERR; \
318 if (tmp) { \
319 if (LF_ISSET(TXT_RECORD)) \
320 rcol -= tmp; \
321 goto next_ch; \
324 if (abb != A_NOTSET) \
325 abb = A_SPACE; \
326 /* Handle hex numbers. */ \
327 if (hex == H_INHEX) { \
328 if (txt_hex(sp, tp, &tmp, ch)) \
329 ERR; \
330 if (tmp) { \
331 hex = H_NOTSET; \
332 goto next_ch; \
335 /* \
336 * The 'R' command returns any overwriteable \
337 * characters in the first line to the original \
338 * characters.
339 */ \
340 if (LF_ISSET(TXT_REPLACE) && tp->owrite && \
341 tp == tiqh->cqh_first) { \
342 memmove(tp->lb + sp->cno, \
343 lp + sp->cno, tp->owrite); \
344 tp->insert += tp->owrite; \
345 tp->owrite = 0; \
347 /* Delete any appended cursor. */ \
348 if (LF_ISSET(TXT_APPENDEOL)) { \
349 --tp->len; \
350 --tp->insert; \
353 LINE_RESOLVE;
355 /* CR returns from the vi command line. */
356 if (LF_ISSET(TXT_CR)) {
357 if (F_ISSET(sp, S_SCRIPT))
358 (void)term_push(sp, gp->key, "\r", 1);
359 goto k_escape;
363 * Historic practice was to delete any <blank>
364 * characters following the inserted newline.
365 * This affects the 'R', 'c', and 's' commands.
367 for (p = tp->lb + sp->cno + tp->owrite;
368 tp->insert && isblank(*p);
369 ++p, ++tp->owrite, --tp->insert);
372 * Move any remaining insert characters into
373 * a new TEXT structure.
375 if ((ntp = text_init(sp,
376 tp->lb + sp->cno + tp->owrite,
377 tp->insert, tp->insert + 32)) == NULL)
378 ERR;
379 CIRCLEQ_INSERT_TAIL(tiqh, ntp, q);
381 /* Set bookkeeping for the new line. */
382 ntp->lno = tp->lno + 1;
383 ntp->insert = tp->insert;
386 * Resolve autoindented characters for the old line.
387 * Reset the autoindent line value. 0^D keeps the ai
388 * line from changing, ^D changes the level, even if
389 * there are no characters in the old line. Note,
390 * if using the current tp structure, use the cursor
391 * as the length, the user may have erased autoindent
392 * characters.
394 if (LF_ISSET(TXT_AUTOINDENT)) {
395 txt_ai_resolve(sp, tp);
397 if (carat_st == C_NOCHANGE) {
398 if (txt_auto(sp, ep,
399 OOBLNO, &ait, ait.ai, ntp))
400 ERR;
401 FREE_SPACE(sp, ait.lb, ait.lb_len);
402 } else
403 if (txt_auto(sp, ep,
404 OOBLNO, tp, sp->cno, ntp))
405 ERR;
406 carat_st = C_NOTSET;
410 * If the user hasn't entered any characters, delete
411 * autoindent characters.
413 * !!!
414 * Historic vi didn't get the insert test right, if
415 * there were characters being inserted, entering a
416 * <cr> left the autoindent characters on the line.
418 if (sp->cno <= tp->ai)
419 sp->cno = 0;
421 /* Reset bookkeeping for the old line. */
422 tp->len = sp->cno;
423 tp->ai = tp->insert = tp->owrite = 0;
425 /* New cursor position. */
426 sp->cno = ntp->ai;
428 /* New lines are TXT_APPENDEOL if nothing to insert. */
429 if (ntp->insert == 0) {
430 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
431 LF_SET(TXT_APPENDEOL);
432 ntp->lb[sp->cno] = CURSOR_CH;
433 ++ntp->insert;
434 ++ntp->len;
437 /* Update the old line. */
438 if (sp->s_change(sp, ep, tp->lno, LINE_RESET))
439 ERR;
441 /* Swap old and new TEXT's. */
442 tp = ntp;
444 /* Reset the cursor. */
445 sp->lno = tp->lno;
447 /* Update the new line. */
448 if (sp->s_change(sp, ep, tp->lno, LINE_INSERT))
449 ERR;
451 /* Set the renumber bit. */
452 F_SET(sp, S_RENUMBER);
454 /* Refresh if nothing waiting. */
455 if ((margin ||
456 !TERM_MORE(gp->key) && !TERM_MORE(gp->tty)) &&
457 sp->s_refresh(sp, ep))
458 ERR;
459 goto next_ch;
460 case K_ESCAPE: /* Escape. */
461 if (!LF_ISSET(TXT_ESCAPE))
462 goto ins_ch;
464 LINE_RESOLVE;
467 * If there aren't any trailing characters in the line
468 * and the user hasn't entered any characters, delete
469 * the autoindent characters.
471 if (!tp->insert && sp->cno <= tp->ai) {
472 tp->len = tp->owrite = 0;
473 sp->cno = 0;
474 } else if (LF_ISSET(TXT_AUTOINDENT))
475 txt_ai_resolve(sp, tp);
477 /* If there are insert characters, copy them down. */
478 k_escape: if (tp->insert && tp->owrite)
479 memmove(tp->lb + sp->cno,
480 tp->lb + sp->cno + tp->owrite, tp->insert);
481 tp->len -= tp->owrite;
484 * Delete any lines that were inserted into the text
485 * structure and then erased.
487 while (tp->q.cqe_next != (void *)tiqh) {
488 ntp = tp->q.cqe_next;
489 CIRCLEQ_REMOVE(tiqh, ntp, q);
490 text_free(ntp);
494 * If not resolving the lines into the file, end
495 * it with a nul.
497 * XXX
498 * This is wrong, should pass back a length.
500 if (LF_ISSET(TXT_RESOLVE)) {
501 if (txt_resolve(sp, ep, tiqh))
502 ERR;
503 } else {
504 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
505 tp->lb[tp->len] = '\0';
509 * Set the return cursor position to rest on the last
510 * inserted character.
512 if (rp != NULL) {
513 rp->lno = tp->lno;
514 rp->cno = sp->cno ? sp->cno - 1 : 0;
515 if (sp->s_change(sp, ep, rp->lno, LINE_RESET))
516 ERR;
518 goto ret;
519 case K_CARAT: /* Delete autoindent chars. */
520 if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai)
521 carat_st = C_CARATSET;
522 goto ins_ch;
523 case K_ZERO: /* Delete autoindent chars. */
524 if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai)
525 carat_st = C_ZEROSET;
526 goto ins_ch;
527 case K_VEOF: /* Delete autoindent char. */
529 * If not doing autoindent, in the first column, no
530 * characters to erase, or already inserted non-ai
531 * characters, it's a literal. The last test is done
532 * in the switch, as the CARAT forms are N + 1, not N.
534 if (!LF_ISSET(TXT_AUTOINDENT) ||
535 sp->cno == 0 || tp->ai == 0)
536 goto ins_ch;
537 switch (carat_st) {
538 case C_CARATSET: /* ^^D */
539 if (sp->cno > tp->ai + tp->offset + 1)
540 goto ins_ch;
542 /* Save the ai string for later. */
543 ait.lb = NULL;
544 ait.lb_len = 0;
545 TBINC(sp, ait.lb, ait.lb_len, tp->ai);
546 memmove(ait.lb, tp->lb, tp->ai);
547 ait.ai = ait.len = tp->ai;
549 carat_st = C_NOCHANGE;
550 goto leftmargin;
551 case C_ZEROSET: /* 0^D */
552 if (sp->cno > tp->ai + tp->offset + 1)
553 goto ins_ch;
554 carat_st = C_NOTSET;
555 leftmargin: tp->lb[sp->cno - 1] = ' ';
556 tp->owrite += sp->cno - tp->offset;
557 tp->ai = 0;
558 sp->cno = tp->offset;
559 break;
560 case C_NOTSET: /* ^D */
561 if (sp->cno > tp->ai + tp->offset)
562 goto ins_ch;
563 (void)txt_outdent(sp, tp);
564 break;
565 default:
566 abort();
568 break;
569 case K_VERASE: /* Erase the last character. */
571 * If can erase over the prompt, return. Len is 0
572 * if backspaced over the prompt, 1 if only CR entered.
574 if (LF_ISSET(TXT_BS) && sp->cno <= tp->offset) {
575 tp->len = 0;
576 goto ret;
580 * If at the beginning of the line, try and drop back
581 * to a previously inserted line.
583 if (sp->cno == 0) {
584 if ((ntp = txt_backup(sp,
585 ep, tiqh, tp, flags)) == NULL)
586 ERR;
587 tp = ntp;
588 break;
591 /* If nothing to erase, bell the user. */
592 if (sp->cno <= tp->offset) {
593 msgq(sp, M_BERR,
594 "No more characters to erase.");
595 break;
598 /* Drop back one character. */
599 --sp->cno;
602 * Increment overwrite, decrement ai if deleted.
604 * !!!
605 * Historic vi did not permit users to use erase
606 * characters to delete autoindent characters.
608 ++tp->owrite;
609 if (sp->cno < tp->ai)
610 --tp->ai;
611 break;
612 case K_VWERASE: /* Skip back one word. */
614 * If at the beginning of the line, try and drop back
615 * to a previously inserted line.
617 if (sp->cno == 0) {
618 if ((ntp = txt_backup(sp,
619 ep, tiqh, tp, flags)) == NULL)
620 ERR;
621 tp = ntp;
625 * If at offset, nothing to erase so bell the user.
627 if (sp->cno <= tp->offset) {
628 msgq(sp, M_BERR,
629 "No more characters to erase.");
630 break;
634 * First werase goes back to any autoindent
635 * and second werase goes back to the offset.
637 * !!!
638 * Historic vi did not permit users to use erase
639 * characters to delete autoindent characters.
641 if (tp->ai && sp->cno > tp->ai)
642 max = tp->ai;
643 else {
644 tp->ai = 0;
645 max = tp->offset;
648 /* Skip over trailing space characters. */
649 while (sp->cno > max && isblank(tp->lb[sp->cno - 1])) {
650 --sp->cno;
651 ++tp->owrite;
653 if (sp->cno == max)
654 break;
656 * There are three types of word erase found on UNIX
657 * systems. They can be identified by how the string
658 * /a/b/c is treated -- as 1, 3, or 6 words. Historic
659 * vi had two classes of characters, and strings were
660 * delimited by them and <blank>'s, so, 6 words. The
661 * historic tty interface used <blank>'s to delimit
662 * strings, so, 1 word. The algorithm offered in the
663 * 4.4BSD tty interface (as stty altwerase) treats it
664 * as 3 words -- there are two classes of characters,
665 * and strings are delimited by them and <blank>'s.
666 * The difference is that the type of the first erased
667 * character erased is ignored, which is exactly right
668 * when erasing pathname components. Here, the options
669 * TXT_ALTWERASE and TXT_TTYWERASE specify the 4.4BSD
670 * tty interface and the historic tty driver behavior,
671 * respectively, and the default is the same as the
672 * historic vi behavior.
674 if (LF_ISSET(TXT_TTYWERASE))
675 while (sp->cno > max) {
676 --sp->cno;
677 ++tp->owrite;
678 if (isblank(tp->lb[sp->cno - 1]))
679 break;
681 else {
682 if (LF_ISSET(TXT_ALTWERASE)) {
683 --sp->cno;
684 ++tp->owrite;
685 if (isblank(tp->lb[sp->cno - 1]))
686 break;
688 if (sp->cno > max)
689 tmp = inword(tp->lb[sp->cno - 1]);
690 while (sp->cno > max) {
691 --sp->cno;
692 ++tp->owrite;
693 if (tmp != inword(tp->lb[sp->cno - 1])
694 || isblank(tp->lb[sp->cno - 1]))
695 break;
698 break;
699 case K_VKILL: /* Restart this line. */
701 * If at the beginning of the line, try and drop back
702 * to a previously inserted line.
704 if (sp->cno == 0) {
705 if ((ntp = txt_backup(sp,
706 ep, tiqh, tp, flags)) == NULL)
707 ERR;
708 tp = ntp;
711 /* If at offset, nothing to erase so bell the user. */
712 if (sp->cno <= tp->offset) {
713 msgq(sp, M_BERR,
714 "No more characters to erase.");
715 break;
719 * First kill goes back to any autoindent
720 * and second kill goes back to the offset.
722 * !!!
723 * Historic vi did not permit users to use erase
724 * characters to delete autoindent characters.
726 if (tp->ai && sp->cno > tp->ai)
727 max = tp->ai;
728 else {
729 tp->ai = 0;
730 max = tp->offset;
732 tp->owrite += sp->cno - max;
733 sp->cno = max;
734 break;
735 case K_CNTRLT: /* Add autoindent char. */
736 if (!LF_ISSET(TXT_CNTRLT))
737 goto ins_ch;
738 if (txt_indent(sp, tp))
739 ERR;
740 goto ebuf_chk;
741 case K_CNTRLZ:
742 (void)sp->s_suspend(sp);
743 break;
744 #ifdef HISTORIC_PRACTICE_IS_TO_INSERT_NOT_REPAINT
745 case K_FORMFEED:
746 F_SET(sp, S_REFRESH);
747 break;
748 #endif
749 case K_RIGHTBRACE:
750 case K_RIGHTPAREN:
751 showmatch = LF_ISSET(TXT_SHOWMATCH);
752 goto ins_ch;
753 case K_VLNEXT: /* Quote the next character. */
754 /* If in hex mode, see if we've entered a hex value. */
755 if (hex == H_INHEX) {
756 if (txt_hex(sp, tp, &tmp, ch))
757 ERR;
758 if (tmp) {
759 hex = H_NOTSET;
760 goto next_ch;
763 ch = '^';
764 quoted = Q_NEXTCHAR;
765 /* FALLTHROUGH */
766 default: /* Insert the character. */
767 ins_ch: /*
768 * If entering a space character after a word, check
769 * for abbreviations. If there was one, discard the
770 * replay characters.
772 if (isblank(ch) && abb == A_NOTSPACE && !replay) {
773 if (txt_abbrev(sp, tp, &tmp, ch))
774 ERR;
775 if (tmp) {
776 if (LF_ISSET(TXT_RECORD))
777 rcol -= tmp;
778 goto next_ch;
781 /* If in hex mode, see if we've entered a hex value. */
782 if (hex == H_INHEX && !isxdigit(ch)) {
783 if (txt_hex(sp, tp, &tmp, ch))
784 ERR;
785 if (tmp) {
786 hex = H_NOTSET;
787 goto next_ch;
790 /* Check to see if we've crossed the margin. */
791 if (margin) {
792 if (sp->s_column(sp, ep, &col))
793 ERR;
794 if (col >= margin) {
795 if (txt_margin(sp, tp, &tmp, ch))
796 ERR;
797 if (tmp)
798 goto next_ch;
801 if (abb != A_NOTSET)
802 abb = isblank(ch) ? A_SPACE : A_NOTSPACE;
804 if (tp->owrite) /* Overwrite a character. */
805 --tp->owrite;
806 else if (tp->insert) { /* Insert a character. */
807 ++tp->len;
808 if (tp->insert == 1)
809 tp->lb[sp->cno + 1] = tp->lb[sp->cno];
810 else
811 memmove(tp->lb + sp->cno + 1,
812 tp->lb + sp->cno, tp->insert);
815 tp->lb[sp->cno++] = ch;
818 * If we've reached the end of the buffer, then we
819 * need to switch into insert mode. This happens
820 * when there's a change to a mark and the user puts
821 * in more characters than the length of the motion.
823 ebuf_chk: if (sp->cno >= tp->len) {
824 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
825 LF_SET(TXT_APPENDEOL);
826 tp->lb[sp->cno] = CURSOR_CH;
827 ++tp->insert;
828 ++tp->len;
831 if (hex == H_NEXTCHAR)
832 hex = H_INHEX;
833 if (quoted == Q_NEXTCHAR)
834 quoted = Q_THISCHAR;
835 break;
837 #if defined(DEBUG) && 1
838 if (sp->cno + tp->insert + tp->owrite != tp->len)
839 msgq(sp, M_ERR,
840 "len %u != cno: %u ai: %u insert %u overwrite %u",
841 tp->len, sp->cno, tp->ai, tp->insert, tp->owrite);
842 tp->len = sp->cno + tp->insert + tp->owrite;
843 #endif
846 /* Clear input flag. */
847 ret: F_CLR(sp, S_INPUT);
849 if (LF_ISSET(TXT_RECORD))
850 VIP(sp)->rep_cnt = rcol;
851 return (eval);
855 * txt_abbrev --
856 * Handle abbreviations.
858 static int
859 txt_abbrev(sp, tp, didsubp, pushc)
860 SCR *sp;
861 TEXT *tp;
862 int *didsubp;
863 ARG_CHAR_T pushc;
865 CHAR_T ch;
866 SEQ *qp;
867 size_t len, off;
868 char *p;
870 /* Find the beginning of this "word". */
871 for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
872 if (isblank(*p)) {
873 ++p;
874 break;
876 ++len;
877 if (off == tp->ai || off == tp->offset)
878 break;
881 /* Check for any abbreviations. */
882 if ((qp = seq_find(sp, p, len, SEQ_ABBREV, NULL)) == NULL) {
883 *didsubp = 0;
884 return (0);
888 * Push the abbreviation onto the tty stack. Historically, characters
889 * resulting from an abbreviation expansion were themselves subject to
890 * map expansions, O_SHOWMATCH matching etc. This means the expanded
891 * characters will be re-tested for abbreviations. It's difficult to
892 * know what historic practice in this case was, since abbreviations
893 * were applied to :colon command lines, so entering abbreviations that
894 * looped was tricky, if not impossible. In addition, obvious loops
895 * don't work as expected. (The command ':ab a b|ab b c|ab c a' will
896 * silently only implement the last of the abbreviations.)
898 * XXX
899 * There obvious infinite loop, if a abbreviates to b and b to a, is
900 * "fixed" by the looping code in the terminal read routines. It's
901 * an ugly fix, though because it forces the user out of input mode
902 * when it returns an error, flushing the queued characters. My guess
903 * is that the correct fix is to tag each character with the number of
904 * times it has been abbreviated, and permit only a single abbreviation.
905 * This requires a major rework of what an input character looks like.
907 ch = pushc;
908 if (term_push(sp, sp->gp->tty, &ch, 1))
909 return (1);
910 if (term_push(sp, sp->gp->tty, qp->output, qp->olen))
911 return (1);
913 /* Move the cursor to the start of the hex value, adjust the length. */
914 sp->cno -= len;
915 tp->len -= len;
917 /* Copy any insert characters back. */
918 if (tp->insert)
919 memmove(tp->lb + sp->cno + tp->owrite,
920 tp->lb + sp->cno + tp->owrite + len, tp->insert);
923 * We return the length of the abbreviated characters. This is so
924 * the calling routine can replace the replay characters with the
925 * abbreviation. This means that subsequent '.' commands will produce
926 * the same text, regardless of intervening :[un]abbreviate commands.
927 * This is historic practice.
929 *didsubp = len;
930 return (0);
933 /* Offset to next column of stop size. */
934 #define STOP_OFF(c, stop) (stop - (c) % stop)
937 * txt_ai_resolve --
938 * When a line is resolved by <esc> or <cr>, review autoindent
939 * characters.
941 static void
942 txt_ai_resolve(sp, tp)
943 SCR *sp;
944 TEXT *tp;
946 u_long ts;
947 size_t cno, len, new, old, scno, spaces, tab_after_sp, tabs;
948 char *p;
951 * If the line is empty, has an offset, or no autoindent
952 * characters, we're done.
954 if (!tp->len || tp->offset || !tp->ai)
955 return;
958 * The autoindent characters plus any leading <blank> characters
959 * in the line are resolved into the minimum number of characters.
960 * Historic practice.
962 ts = O_VAL(sp, O_TABSTOP);
964 /* Figure out the last <blank> screen column. */
965 for (p = tp->lb, scno = 0, len = tp->len,
966 spaces = tab_after_sp = 0; len-- && isblank(*p); ++p)
967 if (*p == '\t') {
968 if (spaces)
969 tab_after_sp = 1;
970 scno += STOP_OFF(scno, ts);
971 } else {
972 ++spaces;
973 ++scno;
977 * If there are no spaces, or no tabs after spaces and less than
978 * ts spaces, it's already minimal.
980 if (!spaces || !tab_after_sp && spaces < ts)
981 return;
983 /* Count up spaces/tabs needed to get to the target. */
984 for (cno = 0, tabs = 0; cno + STOP_OFF(cno, ts) <= scno; ++tabs)
985 cno += STOP_OFF(cno, ts);
986 spaces = scno - cno;
989 * Figure out how many characters we're dropping -- if we're not
990 * dropping any, it's already minimal, we're done.
992 old = p - tp->lb;
993 new = spaces + tabs;
994 if (old == new)
995 return;
997 /* Shift the rest of the characters down. */
998 memmove(p - (old - new), p, tp->len - old);
999 tp->len -= (old - new);
1000 sp->cno -= (old - new);
1002 /* Fill in space/tab characters. */
1003 for (p = tp->lb; tabs--;)
1004 *p++ = '\t';
1005 while (spaces--)
1006 *p++ = ' ';
1010 * txt_auto --
1011 * Handle autoindent. If aitp isn't NULL, use it, otherwise,
1012 * retrieve the line.
1015 txt_auto(sp, ep, lno, aitp, len, tp)
1016 SCR *sp;
1017 EXF *ep;
1018 recno_t lno;
1019 size_t len;
1020 TEXT *aitp, *tp;
1022 size_t nlen;
1023 char *p, *t;
1025 if (aitp == NULL) {
1026 if ((p = t = file_gline(sp, ep, lno, &len)) == NULL)
1027 return (0);
1028 } else
1029 p = t = aitp->lb;
1030 for (nlen = 0; len; ++p) {
1031 if (!isblank(*p))
1032 break;
1033 /* If last character is a space, it counts. */
1034 if (--len == 0) {
1035 ++p;
1036 break;
1040 /* No indentation. */
1041 if (p == t)
1042 return (0);
1044 /* Set count. */
1045 nlen = p - t;
1047 /* Make sure the buffer's big enough. */
1048 BINC(sp, tp->lb, tp->lb_len, tp->len + nlen);
1050 /* Copy the indentation into the new buffer. */
1051 memmove(tp->lb + nlen, tp->lb, tp->len);
1052 memmove(tp->lb, t, nlen);
1053 tp->len += nlen;
1055 /* Return the additional length. */
1056 tp->ai = nlen;
1057 return (0);
1061 * txt_backup --
1062 * Back up to the previously edited line.
1064 static TEXT *
1065 txt_backup(sp, ep, tiqh, tp, flags)
1066 SCR *sp;
1067 EXF *ep;
1068 TEXTH *tiqh;
1069 TEXT *tp;
1070 u_int flags;
1072 TEXT *ntp;
1073 size_t col;
1075 if (tp->q.cqe_prev == (void *)tiqh) {
1076 msgq(sp, M_BERR, "Already at the beginning of the insert");
1077 return (tp);
1080 /* Update the old line on the screen. */
1081 if (sp->s_change(sp, ep, tp->lno, LINE_DELETE))
1082 return (NULL);
1084 /* Get a handle on the previous TEXT structure. */
1085 ntp = tp->q.cqe_prev;
1087 /* Make sure that we can get enough space. */
1088 if (LF_ISSET(TXT_APPENDEOL) && ntp->len + 1 > ntp->lb_len &&
1089 binc(sp, &ntp->lb, &ntp->lb_len, ntp->len + 1))
1090 return (NULL);
1093 * Release current TEXT; now committed to the swap, nothing
1094 * better fail.
1096 CIRCLEQ_REMOVE(tiqh, tp, q);
1097 text_free(tp);
1099 /* Swap TEXT's. */
1100 tp = ntp;
1102 /* Set bookkeeping information. */
1103 col = tp->len;
1104 if (LF_ISSET(TXT_APPENDEOL)) {
1105 tp->lb[col] = CURSOR_CH;
1106 ++tp->insert;
1107 ++tp->len;
1109 sp->lno = tp->lno;
1110 sp->cno = col;
1111 return (tp);
1115 * txt_err --
1116 * Handle an error during input processing.
1118 static void
1119 txt_err(sp, ep, tiqh)
1120 SCR *sp;
1121 EXF *ep;
1122 TEXTH *tiqh;
1124 recno_t lno;
1125 size_t len;
1128 * The problem with input processing is that the cursor is at an
1129 * indeterminate position since some input may have been lost due
1130 * to a malloc error. So, try to go back to the place from which
1131 * the cursor started, knowing that it may no longer be available.
1133 * We depend on at least one line number being set in the text
1134 * chain.
1136 for (lno = tiqh->cqh_first->lno;
1137 file_gline(sp, ep, lno, &len) == NULL && lno > 0; --lno);
1139 sp->lno = lno == 0 ? 1 : lno;
1140 sp->cno = 0;
1142 /* Redraw the screen, just in case. */
1143 F_SET(sp, S_REDRAW);
1147 * txt_hex --
1148 * Let the user insert any character value they want.
1150 * !!!
1151 * This is an extension. The pattern "^Vx[0-9a-fA-F]*" is a way
1152 * for the user to specify a character value which their keyboard
1153 * may not be able to enter.
1155 static int
1156 txt_hex(sp, tp, was_hex, pushc)
1157 SCR *sp;
1158 TEXT *tp;
1159 int *was_hex;
1160 ARG_CHAR_T pushc;
1162 CHAR_T ch, savec;
1163 size_t len, off;
1164 u_long value;
1165 char *p, *wp;
1168 * Null-terminate the string. Since nul isn't a legal hex value,
1169 * this should be okay, and lets us use a local routine, which
1170 * presumably understands the character set, to convert the value.
1172 savec = tp->lb[sp->cno];
1173 tp->lb[sp->cno] = 0;
1175 /* Find the previous HEX_CH. */
1176 for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
1177 if (*p == HEX_CH) {
1178 wp = p + 1;
1179 break;
1181 ++len;
1182 /* If not on this line, there's nothing to do. */
1183 if (off == tp->ai || off == tp->offset)
1184 goto nothex;
1187 /* If no length, then it wasn't a hex value. */
1188 if (len == 0)
1189 goto nothex;
1191 /* Get the value. */
1192 value = strtol(wp, NULL, 16);
1193 if (value == LONG_MIN || value == LONG_MAX || value > MAX_CHAR_T) {
1194 nothex: tp->lb[sp->cno] = savec;
1195 *was_hex = 0;
1196 return (0);
1199 ch = pushc;
1200 if (term_push(sp, sp->gp->tty, &ch, 1))
1201 return (1);
1202 ch = value;
1203 if (term_push(sp, sp->gp->tty, &ch, 1))
1204 return (1);
1206 tp->lb[sp->cno] = savec;
1208 /* Move the cursor to the start of the hex value, adjust the length. */
1209 sp->cno -= len + 1;
1210 tp->len -= len + 1;
1212 /* Copy any insert characters back. */
1213 if (tp->insert)
1214 memmove(tp->lb + sp->cno + tp->owrite,
1215 tp->lb + sp->cno + tp->owrite + len + 1, tp->insert);
1217 *was_hex = 1;
1218 return (0);
1222 * Txt_indent and txt_outdent are truly strange. ^T and ^D do movements
1223 * to the next or previous shiftwidth value, i.e. for a 1-based numbering,
1224 * with shiftwidth=3, ^T moves a cursor on the 7th, 8th or 9th column to
1225 * the 10th column, and ^D moves it back.
1227 * !!!
1228 * The ^T and ^D characters in historical vi only had special meaning when
1229 * they were the first characters typed after entering text input mode.
1230 * Since normal erase characters couldn't erase autoindent (in this case
1231 * ^T) characters, this meant that inserting text into previously existing
1232 * text was quite strange, ^T only worked if it was the first keystroke,
1233 * and then it could only be erased by using ^D. This implementation treats
1234 * ^T specially anywhere it occurs in the input, and permits the standard
1235 * erase characters to erase characters inserted using it.
1237 * XXX
1238 * Technically, txt_indent, txt_outdent should part of the screen interface,
1239 * as they require knowledge of the size of a space character on the screen.
1240 * (Not the size of tabs, because tabs are logically composed of spaces.)
1241 * They're left in the text code because they're complicated, not to mention
1242 * the gruesome awareness that if spaces aren't a single column on the screen
1243 * for any language, we're into some serious, ah, for lack of a better word,
1244 * "issues".
1248 * txt_indent --
1249 * Handle ^T indents.
1251 static int
1252 txt_indent(sp, tp)
1253 SCR *sp;
1254 TEXT *tp;
1256 u_long sw, ts;
1257 size_t cno, off, scno, spaces, tabs;
1259 ts = O_VAL(sp, O_TABSTOP);
1260 sw = O_VAL(sp, O_SHIFTWIDTH);
1262 /* Get the current screen column. */
1263 for (off = scno = 0; off < sp->cno; ++off)
1264 if (tp->lb[off] == '\t')
1265 scno += STOP_OFF(scno, ts);
1266 else
1267 ++scno;
1269 /* Count up spaces/tabs needed to get to the target. */
1270 for (cno = scno, scno += STOP_OFF(scno, sw), tabs = 0;
1271 cno + STOP_OFF(cno, ts) <= scno; ++tabs)
1272 cno += STOP_OFF(cno, ts);
1273 spaces = scno - cno;
1275 /* Put space/tab characters in place of any overwrite characters. */
1276 for (; tp->owrite && tabs; --tp->owrite, --tabs, ++tp->ai)
1277 tp->lb[sp->cno++] = '\t';
1278 for (; tp->owrite && spaces; --tp->owrite, --spaces, ++tp->ai)
1279 tp->lb[sp->cno++] = ' ';
1281 if (!tabs && !spaces)
1282 return (0);
1284 /* Make sure there's enough room. */
1285 BINC(sp, tp->lb, tp->lb_len, tp->len + spaces + tabs);
1287 /* Move the insert characters out of the way. */
1288 if (tp->insert)
1289 memmove(tp->lb + sp->cno + spaces + tabs,
1290 tp->lb + sp->cno, tp->insert);
1292 /* Add new space/tab characters. */
1293 for (; tabs--; ++tp->len, ++tp->ai)
1294 tp->lb[sp->cno++] = '\t';
1295 for (; spaces--; ++tp->len, ++tp->ai)
1296 tp->lb[sp->cno++] = ' ';
1297 return (0);
1301 * txt_outdent --
1302 * Handle ^D outdents.
1305 static int
1306 txt_outdent(sp, tp)
1307 SCR *sp;
1308 TEXT *tp;
1310 u_long sw, ts;
1311 size_t cno, off, scno, spaces;
1313 ts = O_VAL(sp, O_TABSTOP);
1314 sw = O_VAL(sp, O_SHIFTWIDTH);
1316 /* Get the current screen column. */
1317 for (off = scno = 0; off < sp->cno; ++off)
1318 if (tp->lb[off] == '\t')
1319 scno += STOP_OFF(scno, ts);
1320 else
1321 ++scno;
1323 /* Get the previous shiftwidth column. */
1324 for (cno = scno; --scno % sw != 0;);
1326 /* Decrement characters until less than or equal to that slot. */
1327 for (; cno > scno; --sp->cno, --tp->ai, ++tp->owrite)
1328 if (tp->lb[--off] == '\t')
1329 cno -= STOP_OFF(cno, ts);
1330 else
1331 --cno;
1333 /* Spaces needed to get to the target. */
1334 spaces = scno - cno;
1336 /* Maybe just a delete. */
1337 if (spaces == 0)
1338 return (0);
1340 /* Make sure there's enough room. */
1341 BINC(sp, tp->lb, tp->lb_len, tp->len + spaces);
1343 /* Use up any overwrite characters. */
1344 for (; tp->owrite && spaces; --spaces, ++tp->ai, --tp->owrite)
1345 tp->lb[sp->cno++] = ' ';
1347 /* Maybe that was enough. */
1348 if (spaces == 0)
1349 return (0);
1351 /* Move the insert characters out of the way. */
1352 if (tp->insert)
1353 memmove(tp->lb + sp->cno + spaces,
1354 tp->lb + sp->cno, tp->insert);
1356 /* Add new space characters. */
1357 for (; spaces--; ++tp->len, ++tp->ai)
1358 tp->lb[sp->cno++] = ' ';
1359 return (0);
1363 * txt_resolve --
1364 * Resolve the input text chain into the file.
1366 static int
1367 txt_resolve(sp, ep, tiqh)
1368 SCR *sp;
1369 EXF *ep;
1370 TEXTH *tiqh;
1372 TEXT *tp;
1373 recno_t lno;
1375 /* The first line replaces a current line. */
1376 tp = tiqh->cqh_first;
1377 if (file_sline(sp, ep, tp->lno, tp->lb, tp->len))
1378 return (1);
1380 /* All subsequent lines are appended into the file. */
1381 for (lno = tp->lno; (tp = tp->q.cqe_next) != (void *)&sp->tiq; ++lno)
1382 if (file_aline(sp, ep, 0, lno, tp->lb, tp->len))
1383 return (1);
1384 return (0);
1388 * txt_showmatch --
1389 * Show a character match.
1391 * !!!
1392 * Historic vi tried to display matches even in the :colon command line.
1393 * I think not.
1395 static void
1396 txt_showmatch(sp, ep)
1397 SCR *sp;
1398 EXF *ep;
1400 struct timeval second;
1401 VCS cs;
1402 MARK m;
1403 fd_set zero;
1404 int cnt, endc, startc;
1407 * Do a refresh first, in case the v_ntext() code hasn't done
1408 * one in awhile, so the user can see what we're complaining
1409 * about.
1411 if (sp->s_refresh(sp, ep))
1412 return;
1414 * We don't display the match if it's not on the screen. Find
1415 * out what the first character on the screen is.
1417 if (sp->s_position(sp, ep, &m, 0, P_TOP))
1418 return;
1420 /* Initialize the getc() interface. */
1421 cs.cs_lno = sp->lno;
1422 cs.cs_cno = sp->cno - 1;
1423 if (cs_init(sp, ep, &cs))
1424 return;
1425 startc = (endc = cs.cs_ch) == ')' ? '(' : '{';
1427 /* Search for the match. */
1428 for (cnt = 1;;) {
1429 if (cs_prev(sp, ep, &cs))
1430 return;
1431 if (cs.cs_lno < m.lno ||
1432 cs.cs_lno == m.lno && cs.cs_cno < m.cno)
1433 return;
1434 if (cs.cs_flags != 0) {
1435 if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF) {
1436 (void)sp->s_bell(sp);
1437 return;
1439 continue;
1441 if (cs.cs_ch == endc)
1442 ++cnt;
1443 else if (cs.cs_ch == startc && --cnt == 0)
1444 break;
1447 /* Move to the match. */
1448 m.lno = sp->lno;
1449 m.cno = sp->cno;
1450 sp->lno = cs.cs_lno;
1451 sp->cno = cs.cs_cno;
1452 (void)sp->s_refresh(sp, ep);
1455 * Sleep(3) is eight system calls. Do it fast -- besides,
1456 * I don't want to wait an entire second.
1458 FD_ZERO(&zero);
1459 second.tv_sec = O_VAL(sp, O_MATCHTIME) / 10;
1460 second.tv_usec = (O_VAL(sp, O_MATCHTIME) % 10) * 100000L;
1461 (void)select(0, &zero, &zero, &zero, &second);
1463 /* Return to the current location. */
1464 sp->lno = m.lno;
1465 sp->cno = m.cno;
1466 (void)sp->s_refresh(sp, ep);
1470 * txt_margin --
1471 * Handle margin wrap.
1473 * !!!
1474 * Historic vi belled the user each time a character was entered after
1475 * crossing the margin until a space was entered which could be used to
1476 * break the line. I don't, it tends to wake the cats.
1478 static int
1479 txt_margin(sp, tp, didbreak, pushc)
1480 SCR *sp;
1481 TEXT *tp;
1482 int *didbreak;
1483 ARG_CHAR_T pushc;
1485 CHAR_T ch;
1486 size_t len, off, tlen;
1487 char *p, *wp;
1489 /* Find the closest previous blank. */
1490 for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
1491 if (isblank(*p)) {
1492 wp = p + 1;
1493 break;
1495 ++len;
1496 /* If it's the beginning of the line, there's nothing to do. */
1497 if (off == tp->ai || off == tp->offset) {
1498 *didbreak = 0;
1499 return (0);
1504 * Historic practice is to delete any trailing whitespace
1505 * from the previous line.
1507 for (tlen = len;; --p, --off) {
1508 if (!isblank(*p))
1509 break;
1510 ++tlen;
1511 if (off == tp->ai || off == tp->offset)
1512 break;
1515 ch = pushc;
1516 if (term_push(sp, sp->gp->key, &ch, 1))
1517 return (1);
1518 if (len && term_push(sp, sp->gp->key, wp, len))
1519 return (1);
1520 ch = '\n';
1521 if (term_push(sp, sp->gp->key, &ch, 1))
1522 return (1);
1524 sp->cno -= tlen;
1525 tp->owrite += tlen;
1526 *didbreak = 1;
1527 return (0);