5 * 14407 SW Teal Blvd. #C
11 /* This file contains the input() function, which implements vi's INPUT mode.
12 * It also contains the code that supports digraphs.
30 char digraph(key1
, key2
)
31 char key1
; /* the underlying character */
32 char key2
; /* the second character */
37 /* if digraphs are disabled, then just return the new char */
43 /* remember the new key, so we can return it if this isn't a digraph */
46 /* sort key1 and key2, so that their original order won't matter */
53 /* scan through the digraph chart */
55 dp
&& (dp
->key1
!= key1
|| dp
->key2
!= key2
);
60 /* if this combination isn't in there, just use the new key */
66 /* else use the digraph key */
70 /* this function lists or defines digraphs */
71 void do_digraph(bang
, extra
)
78 static int user_defined
= FALSE
; /* boolean: are all later digraphs user-defined? */
81 /* if "extra" is NULL, then we've reached the end of the built-ins */
88 /* if no args, then display the existing digraphs */
91 listbuf
[0] = listbuf
[1] = listbuf
[2] = listbuf
[5] = ' ';
93 for (dig
= 0, dp
= digs
; dp
; dp
= dp
->next
)
104 listbuf
[3] = dp
->key1
;
105 listbuf
[4] = dp
->key2
;
106 listbuf
[6] = dp
->dig
;
115 /* make sure we have at least two characters */
118 msg("Digraphs must be composed of two characters");
122 /* sort key1 and key2, so that their original order won't matter */
123 if (extra
[0] > extra
[1])
130 /* locate the new digraph character */
131 for (dig
= 2; extra
[dig
] == ' ' || extra
[dig
] == '\t'; dig
++)
140 /* search for the digraph */
141 for (prev
= (struct _DIG
*)0, dp
= digs
;
142 dp
&& (dp
->key1
!= extra
[0] || dp
->key2
!= extra
[1]);
143 prev
= dp
, dp
= dp
->next
)
147 /* deleting the digraph? */
153 msg("%c%c not a digraph", extra
[0], extra
[1]);
158 prev
->next
= dp
->next
;
165 /* if necessary, create a new digraph struct for the new digraph */
168 dp
= (struct _DIG
*)malloc(sizeof *dp
);
171 msg("Out of space in the digraph table");
178 dp
->next
= (struct _DIG
*)0;
181 /* assign it the new digraph value */
185 dp
->save
= user_defined
;
192 static char buf
[] = "digraph! XX Y\n";
195 for (dp
= digs
; dp
; dp
= dp
->next
)
202 write(fd
, buf
, (unsigned)14);
210 /* This function allows the user to replace an existing (possibly zero-length)
211 * chunk of text with typed-in text. It returns the MARK of the last character
212 * that the user typed in.
214 MARK
input(from
, to
, when
, above
)
215 MARK from
; /* where to start inserting text */
216 MARK to
; /* extent of text to delete */
217 int when
; /* either WHEN_VIINP or WHEN_VIREP */
218 int above
; /* boolean: take indentation from lower line? */
220 char key
[2]; /* key char followed by '\0' char */
221 char *build
; /* used in building a newline+indent string */
222 char *scan
; /* used while looking at the indent chars of a line */
223 MARK m
; /* some place in the text */
224 #ifndef NO_EXTENSIONS
225 int quit
= FALSE
; /* boolean: are we exiting after this? */
226 int inchg
; /* boolean: have we done a "beforedo()" yet? */
230 /* if "from" and "to" are reversed, complain */
233 msg("ERROR: input(%ld:%d, %ld:%d)",
234 markline(from
), markidx(from
),
235 markline(to
), markidx(to
));
242 /* if we're replacing text with new text, save the old stuff */
243 /* (Alas, there is no easy way to save text for replace mode) */
249 /* if doing a dot command, then reuse the previous text */
254 /* delete the text that's there now */
260 /* insert the previous text */
262 cursor
= paste(from
, FALSE
, TRUE
) + 1L;
265 else /* interactive version */
267 /* assume that whoever called this already did a beforedo() */
268 #ifndef NO_EXTENSIONS
272 /* if doing a change within the line... */
273 if (from
!= to
&& markline(from
) == markline(to
))
275 /* mark the end of the text with a "$" */
276 change(to
- 1, to
, "$");
280 /* delete the old text right off */
288 /* handle autoindent of the first line, maybe */
290 m
= (above
? (cursor
+ BLKSIZE
) : (cursor
- BLKSIZE
));
291 if (*o_autoindent
&& markidx(m
) == 0
292 && markline(m
) >= 1L && markline(m
) <= nlines
)
294 /* Only autoindent blank lines. */
295 pfetch(markline(cursor
));
298 /* Okay, we really want to autoindent */
300 for (scan
= ptext
, build
= tmpblk
.c
;
301 *scan
== ' ' || *scan
== '\t';
306 if (build
> tmpblk
.c
)
309 add(cursor
, tmpblk
.c
);
310 cursor
+= (build
- tmpblk
.c
);
317 /* repeatedly add characters from the user */
320 /* Get a character */
321 redraw(cursor
, TRUE
);
323 msg("cursor=%ld.%d, to=%ld.%d",
324 markline(cursor
), markidx(cursor
),
325 markline(to
), markidx(to
));
328 pfetch(markline(cursor
));
330 if (pline
== markline(from
))
331 build
+= markidx(from
);
332 for (scan
= ptext
+ markidx(cursor
); --scan
>= build
&& isalnum(*scan
); )
336 key
[0] = getabkey(when
, scan
, (int)(ptext
+ markidx(cursor
) - scan
));
338 key
[0] = getkey(when
);
341 if (key
[0] != '\0' && V_from
!= MARK_UNSET
)
343 msg("Can't modify text during a selection");
349 #ifndef NO_EXTENSIONS
350 if (key
[0] == ctrl('O'))
357 redraw(cursor
, TRUE
);
363 else if (key
[0] != ctrl('['))
374 /* if wrapmargin is set & we're past the
375 * warpmargin, then change the last whitespace
376 * characters on line into a newline
378 if (*o_wrapmargin
!= 0)
380 pfetch(markline(cursor
));
381 if (idx2col(cursor
, ptext
, TRUE
) > COLS
- (*o_wrapmargin
& 0xff))
387 /* figure out indent for next line */
388 for (scan
= ptext
; *scan
== ' ' || *scan
== '\t'; )
396 m
= cursor
& ~(BLKSIZE
- 1);
400 if (*scan
!= ' ' && *scan
!= '\t')
403 /*break up line, and we do autoindent if needed*/
404 change(m
+ (scan
- ptext
), m
+ (scan
- ptext
) + 1, tmpblk
.c
);
405 cursor
= (cursor
& ~(BLKSIZE
- 1))
407 + strlen(tmpblk
.c
) - 1
408 + plen
- (scan
- ptext
) - 1;
410 /*remove trailing spaces on previous line*/
416 if (*scan
!= ' ' && *scan
!= '\t')
419 delete(m
+ (scan
-ptext
) + 1, m
+ plen
);
430 #ifndef NO_EXTENSIONS
431 case ctrl('O'): /* special movement mapped keys */
435 case 'h': m
= m_left(cursor
, 0L); break;
437 case 'k': m
= m_updnto(cursor
, 0L, *key
); break;
438 case 'l': m
= cursor
+ 1; break;
440 case 'b': m
= m_bword(cursor
, 0L, *key
); break;
442 case 'w': m
= m_fword(cursor
, 0L, *key
, '\0'); break;
443 case '^': m
= m_front(cursor
, 0L); break;
444 case '$': m
= m_rear(cursor
, 0L); break;
447 m
= m_scroll(cursor
, 0L, *key
); break;
456 m
= v_xchar(cursor
, 0L, 'x');
459 case 'i': m
= to
= from
= cursor
;
460 when
= WHEN_VIINP
+ WHEN_VIREP
- when
;
463 pfetch(markline(cursor
));
464 changes
++; /* <- after this, we can alter ptext */
465 ptext
[markidx(cursor
)] = 0;
466 for (scan
= ptext
+ markidx(cursor
) - 1;
467 scan
>= ptext
&& isalnum(*scan
);
472 m
= (*scan
? v_keyword(scan
, cursor
, 0L) : cursor
);
482 m
= from
= to
= cursor
;
483 V_linemd
= (*key
== 'V');
489 /* do nothing if unmarked */
492 msg("You must mark the text first");
497 /* "from" must come before "to" */
509 /* we don't need V_from anymore */
514 /* adjust for line mode */
515 from
&= ~(BLKSIZE
- 1);
520 /* in character mode, we must
521 * worry about deleting the newline
522 * at the end of the last line
524 pfetch(markline(to
));
525 if (markidx(to
) == plen
)
549 cursor
= v_popup(from
, to
);
554 m
= from
= to
= cursor
;
562 m
= from
= to
= cursor
= paste(cursor
, (*key
== 'p'), FALSE
);
565 # endif /* !NO_VISIBLE */
566 default: m
= MARK_UNSET
;
569 /* adjust the moved cursor */
572 m
= adjmove(cursor
, m
, (*key
== 'j' || *key
== 'k' ? 0x20 : 0));
573 if (*key
== '$' || (*key
== 'l' && m
<= cursor
))
579 /* if the cursor is reasonable, use it */
586 from
= to
= cursor
= m
;
591 if (getkey(0) == ctrl('Z'))
600 /* if last line contains only whitespace, then remove whitespace */
603 pfetch(markline(cursor
));
604 for (scan
= ptext
; isspace(*scan
); scan
++)
607 if (scan
> ptext
&& !*scan
)
609 cursor
&= ~(BLKSIZE
- 1L);
610 if (to
< cursor
+ plen
)
619 if (markline(cursor
) == markline(from
))
625 cursor
&= ~(BLKSIZE
- 1);
636 cmd_shift(cursor
, cursor
, *key
== ctrl('D') ? CMD_SHIFTL
: CMD_SHIFTR
, TRUE
, "");
643 cursor
= m_front(cursor
, 0L);
653 else if (markidx(cursor
) == 0)
656 pfetch(markline(cursor
));
666 m
= m_bword(cursor
, 1L, 'b');
667 if (markline(m
) == markline(cursor
) && m
>= from
)
691 /* figure out indent for next line */
692 pfetch(markline(cursor
));
693 for (scan
= ptext
; *scan
== ' ' || *scan
== '\t'; )
698 /* remove indent from this line, if blank */
699 if ((scan
- ptext
) >= markidx(cursor
) && plen
> 0)
701 to
= cursor
&= ~(BLKSIZE
- 1);
702 delete(cursor
, cursor
+ plen
);
706 if (cursor
>= to
&& when
!= WHEN_VIREP
)
708 add(cursor
, tmpblk
.c
);
712 change(cursor
, to
, tmpblk
.c
);
714 redraw(cursor
, TRUE
);
715 to
= cursor
= (cursor
& ~(BLKSIZE
- 1))
717 + (int)(build
- tmpblk
.c
) - 1;
726 if (*key
== ctrl('A'))
730 to
= cursor
= paste(cursor
, FALSE
, TRUE
) + 1L;
734 if (cursor
>= to
&& when
!= WHEN_VIREP
)
740 change(cursor
, to
, "^");
743 redraw(cursor
, TRUE
);
747 /* '\n' too hard to handle */
754 change(cursor
, cursor
+ 1, key
);
764 redraw(MARK_UNSET
, FALSE
);
768 if (cursor
>= to
&& when
!= WHEN_VIREP
)
776 pfetch(markline(cursor
));
777 if (markidx(cursor
) == plen
)
784 *key
= digraph(ptext
[markidx(cursor
)], *key
);
786 change(cursor
, cursor
+ 1, key
);
791 /* show matching "({[" if necessary */
792 if (*o_showmatch
&& strchr(")}]", *key
))
794 redraw(cursor
, TRUE
);
795 m
= m_match(cursor
- 1, 0L);
796 if (markline(m
) >= topline
797 && markline(m
) <= botline
)
805 } /* end switch(*key) */
808 /* delete any excess characters */
811 #ifndef NO_EXTENSIONS
812 /* if we aren't in the middle of a change, start one! */
822 } /* end if doingdot else */
824 /* put the new text into a cut buffer for possible reuse */
832 /* move to last char that we inputted, unless it was newline */
833 if (markidx(cursor
) != 0)
837 redraw(cursor
, FALSE
);
839 #ifndef NO_EXTENSIONS
842 /* if this is a nested "do", then cut it short */
845 /* exit, unless we can't write out the file */
846 cursor
= v_xit(cursor
, 0L, 'Z');