3 * The Regents of the University of California. All rights reserved.
5 * %sccs.include.redist.c%
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 $";
12 #include <sys/types.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
44 txt_err(sp, ep, tiqh); \
48 /* Local version of BINC. */
49 #define TBINC(sp, lp, llen, nlen) { \
50 if ((nlen) > llen && binc(sp, &(lp), &(llen), nlen)) \
56 * Read in text from the user.
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.
76 v_ntext(sp
, ep
, tiqh
, tm
, lp
, len
, rp
, prompt
, ai_line
, flags
)
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. */
109 * Set the input flag, so tabs get displayed correctly
110 * and everyone knows that the text buffer is in use.
114 /* Set return value. */
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) {
129 tp
->ai
= tp
->insert
= tp
->offset
= tp
->owrite
= 0;
132 memmove(tp
->lb
, lp
, len
);
136 newtp
: if ((tp
= text_init(sp
, lp
, len
, len
+ 32)) == NULL
)
138 CIRCLEQ_INSERT_HEAD(tiqh
, tp
, q
);
141 /* Set the starting line number. */
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
151 if (LF_ISSET(TXT_OVERWRITE
)) {
152 tp
->owrite
= tm
->cno
- sp
->cno
;
153 tp
->insert
= len
- tm
->cno
;
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,
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
))
180 * The cc and S commands have a special feature -- leading
181 * <blank> characters are handled as autoindent characters.
184 if (LF_ISSET(TXT_AICHARS
)) {
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
;
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
;
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.
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
))
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.
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,
243 if (replay
= LF_ISSET(TXT_REPLAY
)) {
244 if (term_push(sp
, sp
->gp
->key
, VIP(sp
)->rep
, VIP(sp
)->rep_cnt
))
249 /* Initialize abbreviations check. */
250 abb
= F_ISSET(sp
, S_ABBREV
) &&
251 LF_ISSET(TXT_MAPINPUT
) ? A_NOTSPACE
: A_NOTSET
;
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
))
268 txt_showmatch(sp
, ep
);
269 } else if (sp
->s_refresh(sp
, ep
))
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
)
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.
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
297 if (quoted
== Q_THISCHAR
) {
307 switch (sp
->special
[ch
]) {
309 case K_NL
: /* New line. */
310 #define LINE_RESOLVE { \
312 * Handle abbreviations. If there was one, \
313 * discard the replay characters. \
315 if (abb == A_NOTSPACE && !replay) { \
316 if (txt_abbrev(sp, tp, &tmp, ch)) \
319 if (LF_ISSET(TXT_RECORD)) \
324 if (abb != A_NOTSET) \
326 /* Handle hex numbers. */ \
327 if (hex == H_INHEX) { \
328 if (txt_hex(sp, tp, &tmp, ch)) \
336 * The 'R' command returns any overwriteable \
337 * characters in the first line to the original \
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; \
347 /* Delete any appended cursor. */ \
348 if (LF_ISSET(TXT_APPENDEOL)) { \
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);
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
)
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
394 if (LF_ISSET(TXT_AUTOINDENT
)) {
395 txt_ai_resolve(sp
, tp
);
397 if (carat_st
== C_NOCHANGE
) {
399 OOBLNO
, &ait
, ait
.ai
, ntp
))
401 FREE_SPACE(sp
, ait
.lb
, ait
.lb_len
);
404 OOBLNO
, tp
, sp
->cno
, ntp
))
410 * If the user hasn't entered any characters, delete
411 * autoindent characters.
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
)
421 /* Reset bookkeeping for the old line. */
423 tp
->ai
= tp
->insert
= tp
->owrite
= 0;
425 /* New cursor position. */
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
;
437 /* Update the old line. */
438 if (sp
->s_change(sp
, ep
, tp
->lno
, LINE_RESET
))
441 /* Swap old and new TEXT's. */
444 /* Reset the cursor. */
447 /* Update the new line. */
448 if (sp
->s_change(sp
, ep
, tp
->lno
, LINE_INSERT
))
451 /* Set the renumber bit. */
452 F_SET(sp
, S_RENUMBER
);
454 /* Refresh if nothing waiting. */
456 !TERM_MORE(gp
->key
) && !TERM_MORE(gp
->tty
)) &&
457 sp
->s_refresh(sp
, ep
))
460 case K_ESCAPE
: /* Escape. */
461 if (!LF_ISSET(TXT_ESCAPE
))
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;
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
);
494 * If not resolving the lines into the file, end
498 * This is wrong, should pass back a length.
500 if (LF_ISSET(TXT_RESOLVE
)) {
501 if (txt_resolve(sp
, ep
, tiqh
))
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.
514 rp
->cno
= sp
->cno
? sp
->cno
- 1 : 0;
515 if (sp
->s_change(sp
, ep
, rp
->lno
, LINE_RESET
))
519 case K_CARAT
: /* Delete autoindent chars. */
520 if (LF_ISSET(TXT_AUTOINDENT
) && sp
->cno
<= tp
->ai
)
521 carat_st
= C_CARATSET
;
523 case K_ZERO
: /* Delete autoindent chars. */
524 if (LF_ISSET(TXT_AUTOINDENT
) && sp
->cno
<= tp
->ai
)
525 carat_st
= C_ZEROSET
;
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)
538 case C_CARATSET
: /* ^^D */
539 if (sp
->cno
> tp
->ai
+ tp
->offset
+ 1)
542 /* Save the ai string for later. */
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
;
551 case C_ZEROSET
: /* 0^D */
552 if (sp
->cno
> tp
->ai
+ tp
->offset
+ 1)
555 leftmargin
: tp
->lb
[sp
->cno
- 1] = ' ';
556 tp
->owrite
+= sp
->cno
- tp
->offset
;
558 sp
->cno
= tp
->offset
;
560 case C_NOTSET
: /* ^D */
561 if (sp
->cno
> tp
->ai
+ tp
->offset
)
563 (void)txt_outdent(sp
, tp
);
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
) {
580 * If at the beginning of the line, try and drop back
581 * to a previously inserted line.
584 if ((ntp
= txt_backup(sp
,
585 ep
, tiqh
, tp
, flags
)) == NULL
)
591 /* If nothing to erase, bell the user. */
592 if (sp
->cno
<= tp
->offset
) {
594 "No more characters to erase.");
598 /* Drop back one character. */
602 * Increment overwrite, decrement ai if deleted.
605 * Historic vi did not permit users to use erase
606 * characters to delete autoindent characters.
609 if (sp
->cno
< tp
->ai
)
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.
618 if ((ntp
= txt_backup(sp
,
619 ep
, tiqh
, tp
, flags
)) == NULL
)
625 * If at offset, nothing to erase so bell the user.
627 if (sp
->cno
<= tp
->offset
) {
629 "No more characters to erase.");
634 * First werase goes back to any autoindent
635 * and second werase goes back to the offset.
638 * Historic vi did not permit users to use erase
639 * characters to delete autoindent characters.
641 if (tp
->ai
&& sp
->cno
> tp
->ai
)
648 /* Skip over trailing space characters. */
649 while (sp
->cno
> max
&& isblank(tp
->lb
[sp
->cno
- 1])) {
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
) {
678 if (isblank(tp
->lb
[sp
->cno
- 1]))
682 if (LF_ISSET(TXT_ALTWERASE
)) {
685 if (isblank(tp
->lb
[sp
->cno
- 1]))
689 tmp
= inword(tp
->lb
[sp
->cno
- 1]);
690 while (sp
->cno
> max
) {
693 if (tmp
!= inword(tp
->lb
[sp
->cno
- 1])
694 || isblank(tp
->lb
[sp
->cno
- 1]))
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.
705 if ((ntp
= txt_backup(sp
,
706 ep
, tiqh
, tp
, flags
)) == NULL
)
711 /* If at offset, nothing to erase so bell the user. */
712 if (sp
->cno
<= tp
->offset
) {
714 "No more characters to erase.");
719 * First kill goes back to any autoindent
720 * and second kill goes back to the offset.
723 * Historic vi did not permit users to use erase
724 * characters to delete autoindent characters.
726 if (tp
->ai
&& sp
->cno
> tp
->ai
)
732 tp
->owrite
+= sp
->cno
- max
;
735 case K_CNTRLT
: /* Add autoindent char. */
736 if (!LF_ISSET(TXT_CNTRLT
))
738 if (txt_indent(sp
, tp
))
742 (void)sp
->s_suspend(sp
);
744 #ifdef HISTORIC_PRACTICE_IS_TO_INSERT_NOT_REPAINT
746 F_SET(sp
, S_REFRESH
);
751 showmatch
= LF_ISSET(TXT_SHOWMATCH
);
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
))
766 default: /* Insert the character. */
768 * If entering a space character after a word, check
769 * for abbreviations. If there was one, discard the
772 if (isblank(ch
) && abb
== A_NOTSPACE
&& !replay
) {
773 if (txt_abbrev(sp
, tp
, &tmp
, ch
))
776 if (LF_ISSET(TXT_RECORD
))
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
))
790 /* Check to see if we've crossed the margin. */
792 if (sp
->s_column(sp
, ep
, &col
))
795 if (txt_margin(sp
, tp
, &tmp
, ch
))
802 abb
= isblank(ch
) ? A_SPACE
: A_NOTSPACE
;
804 if (tp
->owrite
) /* Overwrite a character. */
806 else if (tp
->insert
) { /* Insert a character. */
809 tp
->lb
[sp
->cno
+ 1] = tp
->lb
[sp
->cno
];
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
;
831 if (hex
== H_NEXTCHAR
)
833 if (quoted
== Q_NEXTCHAR
)
837 #if defined(DEBUG) && 1
838 if (sp
->cno
+ tp
->insert
+ tp
->owrite
!= tp
->len
)
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
;
846 /* Clear input flag. */
847 ret
: F_CLR(sp
, S_INPUT
);
849 if (LF_ISSET(TXT_RECORD
))
850 VIP(sp
)->rep_cnt
= rcol
;
856 * Handle abbreviations.
859 txt_abbrev(sp
, tp
, didsubp
, pushc
)
870 /* Find the beginning of this "word". */
871 for (off
= sp
->cno
- 1, p
= tp
->lb
+ off
, len
= 0;; --p
, --off
) {
877 if (off
== tp
->ai
|| off
== tp
->offset
)
881 /* Check for any abbreviations. */
882 if ((qp
= seq_find(sp
, p
, len
, SEQ_ABBREV
, NULL
)) == NULL
) {
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.)
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.
908 if (term_push(sp
, sp
->gp
->tty
, &ch
, 1))
910 if (term_push(sp
, sp
->gp
->tty
, qp
->output
, qp
->olen
))
913 /* Move the cursor to the start of the hex value, adjust the length. */
917 /* Copy any insert characters back. */
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.
933 /* Offset to next column of stop size. */
934 #define STOP_OFF(c, stop) (stop - (c) % stop)
938 * When a line is resolved by <esc> or <cr>, review autoindent
942 txt_ai_resolve(sp
, tp
)
947 size_t cno
, len
, new, old
, scno
, spaces
, tab_after_sp
, tabs
;
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
)
958 * The autoindent characters plus any leading <blank> characters
959 * in the line are resolved into the minimum number of characters.
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
)
970 scno
+= STOP_OFF(scno
, ts
);
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
)
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
);
989 * Figure out how many characters we're dropping -- if we're not
990 * dropping any, it's already minimal, we're done.
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
--;)
1011 * Handle autoindent. If aitp isn't NULL, use it, otherwise,
1012 * retrieve the line.
1015 txt_auto(sp
, ep
, lno
, aitp
, len
, tp
)
1026 if ((p
= t
= file_gline(sp
, ep
, lno
, &len
)) == NULL
)
1030 for (nlen
= 0; len
; ++p
) {
1033 /* If last character is a space, it counts. */
1040 /* No indentation. */
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
);
1055 /* Return the additional length. */
1062 * Back up to the previously edited line.
1065 txt_backup(sp
, ep
, tiqh
, tp
, flags
)
1075 if (tp
->q
.cqe_prev
== (void *)tiqh
) {
1076 msgq(sp
, M_BERR
, "Already at the beginning of the insert");
1080 /* Update the old line on the screen. */
1081 if (sp
->s_change(sp
, ep
, tp
->lno
, LINE_DELETE
))
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))
1093 * Release current TEXT; now committed to the swap, nothing
1096 CIRCLEQ_REMOVE(tiqh
, tp
, q
);
1102 /* Set bookkeeping information. */
1104 if (LF_ISSET(TXT_APPENDEOL
)) {
1105 tp
->lb
[col
] = CURSOR_CH
;
1116 * Handle an error during input processing.
1119 txt_err(sp
, ep
, tiqh
)
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
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
;
1142 /* Redraw the screen, just in case. */
1143 F_SET(sp
, S_REDRAW
);
1148 * Let the user insert any character value they want.
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.
1156 txt_hex(sp
, tp
, was_hex
, pushc
)
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
) {
1182 /* If not on this line, there's nothing to do. */
1183 if (off
== tp
->ai
|| off
== tp
->offset
)
1187 /* If no length, then it wasn't a hex value. */
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
;
1200 if (term_push(sp
, sp
->gp
->tty
, &ch
, 1))
1203 if (term_push(sp
, sp
->gp
->tty
, &ch
, 1))
1206 tp
->lb
[sp
->cno
] = savec
;
1208 /* Move the cursor to the start of the hex value, adjust the length. */
1212 /* Copy any insert characters back. */
1214 memmove(tp
->lb
+ sp
->cno
+ tp
->owrite
,
1215 tp
->lb
+ sp
->cno
+ tp
->owrite
+ len
+ 1, tp
->insert
);
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.
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.
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,
1249 * Handle ^T indents.
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
);
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
)
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. */
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
++] = ' ';
1302 * Handle ^D outdents.
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
);
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
);
1333 /* Spaces needed to get to the target. */
1334 spaces
= scno
- cno
;
1336 /* Maybe just a delete. */
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. */
1351 /* Move the insert characters out of the way. */
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
++] = ' ';
1364 * Resolve the input text chain into the file.
1367 txt_resolve(sp
, ep
, tiqh
)
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
))
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
))
1389 * Show a character match.
1392 * Historic vi tried to display matches even in the :colon command line.
1396 txt_showmatch(sp
, ep
)
1400 struct timeval second
;
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
1411 if (sp
->s_refresh(sp
, ep
))
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
))
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
))
1425 startc
= (endc
= cs
.cs_ch
) == ')' ? '(' : '{';
1427 /* Search for the match. */
1429 if (cs_prev(sp
, ep
, &cs
))
1431 if (cs
.cs_lno
< m
.lno
||
1432 cs
.cs_lno
== m
.lno
&& cs
.cs_cno
< m
.cno
)
1434 if (cs
.cs_flags
!= 0) {
1435 if (cs
.cs_flags
== CS_EOF
|| cs
.cs_flags
== CS_SOF
) {
1436 (void)sp
->s_bell(sp
);
1441 if (cs
.cs_ch
== endc
)
1443 else if (cs
.cs_ch
== startc
&& --cnt
== 0)
1447 /* Move to the match. */
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.
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. */
1466 (void)sp
->s_refresh(sp
, ep
);
1471 * Handle margin wrap.
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.
1479 txt_margin(sp
, tp
, didbreak
, pushc
)
1486 size_t len
, off
, tlen
;
1489 /* Find the closest previous blank. */
1490 for (off
= sp
->cno
- 1, p
= tp
->lb
+ off
, len
= 0;; --p
, --off
) {
1496 /* If it's the beginning of the line, there's nothing to do. */
1497 if (off
== tp
->ai
|| off
== tp
->offset
) {
1504 * Historic practice is to delete any trailing whitespace
1505 * from the previous line.
1507 for (tlen
= len
;; --p
, --off
) {
1511 if (off
== tp
->ai
|| off
== tp
->offset
)
1516 if (term_push(sp
, sp
->gp
->key
, &ch
, 1))
1518 if (len
&& term_push(sp
, sp
->gp
->key
, wp
, len
))
1521 if (term_push(sp
, sp
->gp
->key
, &ch
, 1))