/* This file contains the input() function, which implements vi's INPUT mode.
* It also contains the code that supports digraphs.
int key1
; /* the underlying character */
int key2
; /* the second character */
/* if digraphs are disabled, then just return the new char */
/* remember the new key, so we can return it if this isn't a digraph */
/* sort key1 and key2, so that their original order won't matter */
/* scan through the digraph chart */
dp
&& (dp
->key1
!= key1
|| dp
->key2
!= key2
);
/* if this combination isn't in there, just use the new key */
/* else use the digraph key */
/* this function lists or defines digraphs */
void do_digraph(bang
, extra
)
static int user_defined
= FALSE
; /* boolean: are all later digraphs user-defined? */
/* if "extra" is NULL, then we've reached the end of the built-ins */
/* if no args, then display the existing digraphs */
listbuf
[0] = listbuf
[1] = listbuf
[2] = listbuf
[5] = ' ';
for (dig
= 0, dp
= digs
; dp
; dp
= dp
->next
)
/* make sure we have at least two characters */
msg("Digraphs must be composed of two characters");
/* sort key1 and key2, so that their original order won't matter */
/* locate the new digraph character */
for (dig
= 2; extra
[dig
] == ' ' || extra
[dig
] == '\t'; dig
++)
/* search for the digraph */
for (prev
= (struct _DIG
*)0, dp
= digs
;
dp
&& (dp
->key1
!= extra
[0] || dp
->key2
!= extra
[1]);
prev
= dp
, dp
= dp
->next
)
/* deleting the digraph? */
msg("%c%c not a digraph", extra
[0], extra
[1]);
/* if necessary, create a new digraph struct for the new digraph */
dp
= (struct _DIG
*)malloc(sizeof *dp
);
msg("Out of space in the digraph table");
dp
->next
= (struct _DIG
*)0;
/* assign it the new digraph value */
static char buf
[] = "digraph! XX Y\n";
for (dp
= digs
; dp
; dp
= dp
->next
)
write(fd
, buf
, (unsigned)14);
/* This function allows the user to replace an existing (possibly zero-length)
* chunk of text with typed-in text. It returns the MARK of the last character
* that the user typed in.
MARK
input(from
, to
, when
, delta
)
MARK from
; /* where to start inserting text */
MARK to
; /* extent of text to delete */
int when
; /* either WHEN_VIINP or WHEN_VIREP */
int delta
; /* 1 to take indent from lower line, -1 for upper, 0 for none */
char key
[2]; /* key char followed by '\0' char */
char *build
; /* used in building a newline+indent string */
char *scan
; /* used while looking at the indent chars of a line */
MARK m
; /* some place in the text */
int quit
= FALSE
; /* boolean: are we exiting after this? */
int inchg
; /* boolean: have we done a "beforedo()" yet? */
/* if "from" and "to" are reversed, complain */
msg("ERROR: input(%ld:%d, %ld:%d)",
markline(from
), markidx(from
),
markline(to
), markidx(to
));
/* if we're replacing text with new text, save the old stuff */
/* (Alas, there is no easy way to save text for replace mode) */
/* if doing a dot command, then reuse the previous text */
/* delete the text that's there now */
/* insert the previous text */
cursor
= paste(from
, FALSE
, TRUE
) + 1L;
else /* interactive version */
/* assume that whoever called this already did a beforedo() */
/* if doing a change within the line... */
if (from
!= to
&& markline(from
) == markline(to
))
/* mark the end of the text with a "$" */
/* delete the old text right off */
/* handle autoindent of the first line, maybe */
m
= cursor
+ MARK_AT_LINE(delta
);
if (delta
!= 0 && *o_autoindent
&& markidx(m
) == 0
&& markline(m
) >= 1L && markline(m
) <= nlines
)
/* Only autoindent blank lines. */
pfetch(markline(cursor
));
/* Okay, we really want to autoindent */
for (scan
= ptext
, build
= tmpblk
.c
;
*scan
== ' ' || *scan
== '\t';
cursor
+= (int)(build
- tmpblk
.c
);
/* repeatedly add characters from the user */
msg("cursor=%ld.%d, to=%ld.%d",
markline(cursor
), markidx(cursor
),
markline(to
), markidx(to
));
pfetch(markline(cursor
));
if (pline
== markline(from
))
for (scan
= ptext
+ markidx(cursor
); --scan
>= build
&& !isspace(*scan
); )
key
[0] = getabkey(when
, scan
, (int)(ptext
+ markidx(cursor
) - scan
));
if (key
[0] != ctrl('O') && V_from
!= MARK_UNSET
)
msg("Can't modify text during a selection");
else if (key
[0] != ctrl('['))
/* if wrapmargin is set & we're past the
* warpmargin, then change the last whitespace
* characters on line into a newline
pfetch(markline(cursor
));
if (plen
== idx2col(cursor
, ptext
, TRUE
)
&& plen
> COLS
- (*o_wrapmargin
& 0xff))
/* figure out indent for next line */
for (scan
= ptext
; *scan
== ' ' || *scan
== '\t'; )
m
= cursor
& ~(BLKSIZE
- 1);
if (*scan
!= ' ' && *scan
!= '\t')
/*break up line, and we do autoindent if needed*/
change(m
+ (int)(scan
- ptext
), m
+ (int)(scan
- ptext
) + 1, tmpblk
.c
);
/* NOTE: for some reason, MSC 5.10 doesn't
* like for these lines to be combined!!!
cursor
= (cursor
& ~(BLKSIZE
- 1));
cursor
+= strlen(tmpblk
.c
) - 1;
cursor
+= plen
- (int)(scan
- ptext
) - 1;
/*remove trailing spaces on previous line*/
if (*scan
!= ' ' && *scan
!= '\t')
delete(m
+ (int)(scan
- ptext
) + 1, m
+ plen
);
case ctrl('O'): /* special movement mapped keys */
case 'h': m
= m_left(cursor
, 0L); break;
case 'k': m
= m_updnto(cursor
, 0L, *key
); break;
case 'l': m
= cursor
+ 1; break;
case 'b': m
= m_bword(cursor
, 0L, *key
); break;
case 'w': m
= m_fword(cursor
, 0L, *key
, '\0'); break;
case '^': m
= m_front(cursor
, 0L); break;
case '$': m
= m_rear(cursor
, 0L); break;
m
= m_scroll(cursor
, 0L, *key
); break;
m
= v_xchar(cursor
, 0L, 'x');
case 'i': m
= to
= from
= cursor
;
when
= WHEN_VIINP
+ WHEN_VIREP
- when
;
pfetch(markline(cursor
));
changes
++; /* <- after this, we can alter ptext */
ptext
[markidx(cursor
)] = 0;
for (scan
= ptext
+ markidx(cursor
) - 1;
scan
>= ptext
&& isalnum(*scan
);
m
= (*scan
? v_keyword(scan
, cursor
, 0L) : cursor
);
V_linemd
= (*key
== 'V');
/* do nothing if unmarked */
msg("You must mark the text first");
/* "from" must come before "to" */
/* we don't need V_from anymore */
/* adjust for line mode */
/* in character mode, we must
* worry about deleting the newline
* at the end of the last line
cursor
= v_popup(from
, to
);
m
= paste(cursor
, (*key
== 'p'), FALSE
);
# endif /* !NO_VISIBLE */
/* adjust the moved cursor */
m
= adjmove(cursor
, m
, (*key
== 'j' || *key
== 'k' ? NCOL
|FINL
: FINL
));
if (plen
&& (*key
== '$' || (*key
== 'l' && m
<= cursor
)))
/* if the cursor is reasonable, use it */
if (getkey(0) == ctrl('Z'))
/* if last line contains only whitespace, then remove whitespace */
pfetch(markline(cursor
));
for (scan
= ptext
; isspace(*scan
); scan
++)
if (scan
> ptext
&& !*scan
)
cursor
&= ~(BLKSIZE
- 1L);
if (markline(cursor
) == markline(from
))
cursor
&= ~(BLKSIZE
- 1);
cmd_shift(cursor
, cursor
, *key
== ctrl('D') ? CMD_SHIFTL
: CMD_SHIFTR
, TRUE
, "");
cursor
= m_front(cursor
, 0L);
else if (markidx(cursor
) == 0)
pfetch(markline(cursor
));
m
= m_bword(cursor
, 1L, 'b');
if (markline(m
) == markline(cursor
) && m
>= from
)
/* figure out indent for next line */
pfetch(markline(cursor
));
for (scan
= ptext
; *scan
== ' ' || *scan
== '\t'; )
/* remove indent from this line, if blank */
if ((int)(scan
- ptext
) >= markidx(cursor
) && plen
> 0)
to
= cursor
&= ~(BLKSIZE
- 1);
delete(cursor
, cursor
+ (int)(scan
- ptext
));
/* advance "to" past whitespace at the cursor */
for (scan
= ptext
+ markidx(cursor
), to
= cursor
; *scan
== ' ' || *scan
== '\t'; scan
++, to
++)
if (cursor
>= to
&& when
!= WHEN_VIREP
)
change(cursor
, to
, tmpblk
.c
);
to
= cursor
= (cursor
& ~(BLKSIZE
- 1))
+ (int)(build
- tmpblk
.c
) - 1;
m
= paste(cursor
, FALSE
, TRUE
);
if (cursor
>= to
&& when
!= WHEN_VIREP
)
/* '\n' too hard to handle */
change(cursor
, cursor
+ 1, key
);
redraw(MARK_UNSET
, FALSE
);
if (cursor
>= to
&& when
!= WHEN_VIREP
)
pfetch(markline(cursor
));
if (markidx(cursor
) == plen
)
*key
= digraph(ptext
[markidx(cursor
)], *key
);
change(cursor
, cursor
+ 1, key
);
/* show matching "({[" if necessary */
if (*o_showmatch
&& strchr(")}]", *key
))
m
= m_match(cursor
- 1, 0L);
if (markline(m
) >= topline
&& markline(m
) <= botline
)
/* delete any excess characters */
/* if we aren't in the middle of a change, start one! */
} /* end if doingdot else */
/* put the new text into a cut buffer for possible reuse */
/* move to last char that we inputted, unless it was newline */
if (markidx(cursor
) != 0)
/* if this is a nested "do", then cut it short */
/* exit, unless we can't write out the file */
cursor
= v_xit(cursor
, 0L, 'Z');