4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 /* Copyright (c) 1981 Regents of the University of California */
32 #pragma ident "%Z%%M% %I% %E% SMI"
39 /* Undef putchar/getchar if they're defined. */
46 #endif /* PRESUNEUC */
49 * This is the main routine for visual.
50 * We here decode the count and possible named buffer specification
51 * preceding a command and interpret a few of the commands.
52 * Commands which involve a target (i.e. an operator) are decoded
53 * in the routine operate in ex_voperate.c.
56 #define forbid(a) { if (a) goto fonfon; }
61 int redisplay
; /* XPG6 assertion 313 [count]r\n : Also used in ex_vops2.c */
63 void redraw(), windowinit();
66 extern int P_cursor_offset
;
73 wchar_t esave
[TUBECOLS
];
74 extern wchar_t atube
[];
75 unsigned char *oglobp
;
80 int tag_reset_wrap
= 0;
81 int onumber
, olist
, (*OPline
)(), (*OPutchar
)();
84 vch_mac
= VC_NOTINMAC
;
88 * If we started as a vi command (on the command line)
89 * then go process initial commands (recover, next or tag).
100 vshowmode(""); /* As a precaution */
104 * The current line is always in the line buffer linebuf,
105 * and the cursor at the position cursor. You should do
106 * a vsave() before moving off the line to make sure the disk
107 * copy is updated if it has changed, and a getDOT() to get
108 * the line back if you mung linebuf. The motion
109 * routines in ex_vwind.c handle most of this.
113 * Decode a visual command.
114 * First sync the temp file if there has been a reasonable
115 * amount of change. Clear state for decoding of next
124 Xhadcnt
= hadcnt
= 0;
127 if (i
= holdupd
&& !windowchg
) {
128 if (state
== VISUAL
) {
136 if (LINE(0) < ZERO) {
142 if (state
!= VISUAL
) {
156 /* XPG6 assertion 313 & 254 : after [count]r\n */
162 * Gobble up counts and named buffer specifications.
168 fprintf(trace
, "pc=%c",peekkey());
173 if (isdigit(peekkey()) && peekkey() != '0') {
178 if (peekkey() != '"')
180 (void)getkey(), c
= getkey();
182 * Buffer names be letters or digits.
183 * But not '0' as that is the source of
184 * an 'empty' named buffer spec in the routine
185 * kshift (see ex_temp.c).
187 if(!isascii(c
) && MB_CUR_MAX
> 1) {
188 /* get rest of character */
190 char multic
[MULTI_BYTE_MAX
];
192 (void)_mbftowc(multic
, &wchar
, getkey
, &Peekkey
);
194 forbid (c
== '0' || !isalpha(c
) && !isascii(c
) && !isdigit(c
));
199 * Come to reread from below after some macro expansions.
200 * The call to map allows use of function key pads
201 * by performing a terminal dependent mapping of inputs.
205 fprintf(trace
,"pcb=%c,",peekkey());
211 * Keep mapping the char as long as it changes.
212 * This allows for double mappings, e.g., q to #,
213 * #1 to something else.
216 op
= map(c
, arrows
, 0);
219 fprintf(trace
,"pca=%c,",c
);
222 * Maybe the mapped to char is a count. If so, we have
223 * to go back to the "for" to interpret it. Likewise
226 if ((isdigit(c
) && c
!='0') || c
== '"') {
230 if (!value(vi_REMAP
)) {
234 if (++maphopcnt
> 256)
235 error(gettext("Infinite macro loop"));
239 * Begin to build an image of this command for possible
240 * later repeat in the buffer workcmd. It will be copied
241 * to lastcmd by the routine setLAST
242 * if/when completely specified.
249 * First level command decode.
254 * ^L Clear screen e.g. after transmission error.
258 * ^R Retype screen, getting rid of @ lines.
259 * If in open, equivalent to ^L.
260 * On terminals where the right arrow key sends
261 * ^L we make ^R act like ^L, since there is no
262 * way to get ^L. These terminals (adm31, tvi)
263 * are intelligent so ^R is useless. Soroc
264 * will probably foul this up, but nobody has
269 if (c
== CTRL('l') || (key_right
&& *key_right
==CTRL('l'))) {
273 if (state
!= VISUAL
) {
275 * Get a clean line, throw away the
276 * memory of what is displayed now,
277 * and move back onto the current line.
281 vmoveto(dot
, cursor
, 0);
286 * Weird glitch -- when we enter visual
287 * in a very small window we may end up with
288 * no lines on the screen because the line
289 * at the top is too long. This forces the screen
290 * to be expanded to make room for it (after
291 * we have printed @'s ick showing we goofed).
299 * $ Escape just cancels the current command
300 * with a little feedback.
307 * @ Macros. Bring in the macro and put it
308 * in vmacbuf, point vglobp there and punt.
322 unsigned char tmpbuf
[BUFSIZE
];
324 regbuf(c
, tmpbuf
, sizeof (vmacbuf
));
337 * . Repeat the last (modifying) open/visual command.
341 * Check that there was a last command, and
342 * take its count and named buffer unless they
343 * were given anew. Special case if last command
344 * referenced a numeric named buffer -- increment
345 * the number and go to a named buffer again.
346 * This allows a sequence like "1pu.u.u...
347 * to successively look for stuff in the kill chain
348 * much as one does in EMACS with C-Y and M-Y.
350 forbid (lastcmd
[0] == 0);
355 else if (isdigit(lastreg
) && lastreg
< '9')
364 * ^U Scroll up. A count sticks around for
365 * future scrolls as the scroll amount.
366 * Attempt to hold the indentation from the
367 * top of the screen (in logical lines).
369 * BUG: A ^U near the bottom of the screen
370 * on a dumb terminal (which can't roll back)
371 * causes the screen to be cleared and then
372 * redrawn almost as it was. In this case
373 * one should simply move the cursor.
380 ind
= vcline
, cnt
+= ind
;
385 vnline((unsigned char *)NOSTR
);
389 * ^D Scroll down. Like scroll up.
394 fprintf(trace
, "before vdown in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot
), lineno(wdot
), lineno(dol
));
400 ind
= vcnt
- vcline
- 1, cnt
+= ind
;
407 fprintf(trace
, "before vnline in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot
), lineno(wdot
), lineno(dol
));
409 vnline((unsigned char *)NOSTR
);
412 fprintf(trace
, "after vnline in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot
), lineno(wdot
), lineno(dol
));
417 * ^E Glitch the screen down (one) line.
418 * Cursor left on same line in file.
425 /* Bottom line of file already on screen */
426 forbid(lineDOL()-lineDOT() <= vcnt
-1-vcline
);
427 ind
= vcnt
- vcline
- 1 + cnt
;
440 forbid(lineDOT()-1<=vcline
); /* line 1 already there */
448 * m Mark position in mark register given
449 * by following letter. Return is
450 * accomplished via ' or `; former
451 * to beginning of line where mark
452 * was set, latter to column where marked.
456 * Getesc is generally used when a character
457 * is read as a latter part of a command
458 * to allow one to hit rubout/escape to cancel
459 * what you have typed so far. These characters
460 * are mapped to 0 by the subroutine.
467 * Markreg checks that argument is a letter
468 * and also maps ' and ` to the end of the range
469 * to allow '' or `` to reference the previous
475 names
[c
- 'a'] = (*dot
&~ 01);
476 ncols
[c
- 'a'] = cursor
;
481 * ^F Window forwards, with 2 lines of continuity.
487 addr
= dot
+ (vcnt
- vcline
) - 2 + (cnt
-1)*basWLINES
;
496 * ^B Window backwards, with 2 lines of continuity.
501 if (one
+ vcline
!= dot
&& vcnt
> 2) {
502 addr
= dot
- vcline
+ 2 - (cnt
-1)*basWLINES
;
503 forbid (addr
<= zero
);
511 * z Screen adjustment, taking a following character:
512 * zcarriage_return current line to top
513 * z<NL> like zcarriage_return
514 * z- current line to bottom
515 * also z+, z^ like ^F and ^B.
516 * A preceding count is line to use rather
517 * than current line. A count between z and
518 * specifier character changes the screen size
523 if (state
== VISUAL
) {
532 vzop(hadcnt
, cnt
, c
);
536 * Y Yank lines, abbreviation for y_ or yy.
537 * Yanked lines can be put later if no
538 * changes intervene, or can be put in named
539 * buffers and put anytime in this session.
547 * J Join lines, 2 by default. Count is number
548 * of lines to join (no join operator sorry.)
554 if (cnt
> (i
= dol
- dot
+ 1))
559 cursor
= strend(linebuf
);
560 vremote(cnt
, join
, 0);
561 notenam
= (unsigned char *)"join";
564 vreplace(vcline
, cnt
, 1);
565 if (!*cursor
&& cursor
> linebuf
)
573 * S Substitute text for whole lines, abbrev for c_.
574 * Count is number of lines to change.
582 * O Create a new line above current and accept new
583 * input text, to an escape, there.
584 * A count specifies, for dumb terminals when
585 * slowopen is not set, the number of physical
586 * line space to open on the screen.
588 * o Like O, but opens lines below.
597 * C Change text to end of line, short for c$.
601 ungetkey('$'), c
= 'c';
607 * ~ Switch case of letter under cursor
611 unsigned char mbuf
[2049];
612 unsigned char *ccursor
= cursor
;
619 #endif /* PRESUNEUC */
622 for (tmp
= 0; tmp
+ 3 < 2048; ) {
624 * Use multiple 'r' commands to replace
625 * alpha with alternate case.
631 length
= mbtowc(&wchar
, (char *)ccursor
, MULTI_BYTE_MAX
);
633 len
= mbtowc(&wc
, (char *)ccursor
, MULTI_BYTE_MAX
);
634 #endif /* PRESUNEUC */
639 if(len
> 1 && !iswalpha(wc
)) {
640 #endif /* PRESUNEUC */
647 #endif /* PRESUNEUC */
652 mbuf
[tmp
+1] = *ccursor
++;
654 ccursor
+= ((len
> 0) ? len
: 1);
655 #endif /* PRESUNEUC */
657 * If pointing to an alpha character,
663 if (isupper((unsigned char)tmp1
))
664 mbuf
[tmp
+1] = tolower((unsigned char)tmp1
);
666 mbuf
[tmp
+1] = toupper((unsigned char)tmp1
);
669 len
= wctomb((char *)(mbuf
+ tmp
+ 1),
670 (wc
= towlower(wc
)));
672 len
= wctomb((char *)(mbuf
+ tmp
+ 1),
673 (wc
= towupper(wc
)));
675 #endif /* PRESUNEUC */
678 * If at end of line do not advance
679 * to the next character, else use a
680 * space to advance 1 column.
698 * A Append at end of line, short for $a.
707 * a Appends text after cursor. Text can continue
708 * through arbitrary number of lines.
713 int length
= mbtowc(&wchar
, (char *)cursor
, MULTI_BYTE_MAX
);
714 if (state
== HARDOPEN
) {
730 * I Insert at beginning of whitespace of line,
739 * R Replace characters, one for one, by input
740 * (logically), like repeated r commands.
742 * BUG: This is like the typeover mode of many other
743 * editors, and is only rarely useful. Its
744 * implementation is a hack in a low level
745 * routine and it doesn't work very well, e.g.
746 * you can't move around within a R, etc.
752 * i Insert text to an escape in the buffer.
753 * Text is arbitrary. This command reminds of
754 * the i command in bare teco.
759 * Common code for all the insertion commands.
760 * Save for redo, position cursor, prepare for append
761 * at command and in visual undo. Note that nothing
762 * is doomed, unless R when all is, and save the
763 * current line in a the undo temporary buffer.
770 doomed
= c
== 'R' ? 10000 : 0;
777 * If this is a repeated command, then suppress
778 * fake insert mode on dumb terminals which looks
779 * ridiculous and wastes lots of time even at 9600B.
787 * An attention, normally a DEL, just beeps.
788 * If you are a vi command within ex, then
789 * two ATTN's will drop you back to command mode.
793 if (initev
|| peekkey() != ATTN
)
798 * ^\ A quit always gets command mode.
802 * Have to be careful if we were called
804 * since a return will just start up again.
805 * So we simulate an interrupt.
813 * q Quit back to command mode, unless called as
814 * vi on command line in which case dont do it
820 error(gettext("Q gets ex command mode, :q leaves vi"));
831 * Q Is like q, but always gets to command mode
832 * even if command line invocation was as vi.
837 * If we are in the middle of a macro, throw away
838 * the rest and fix up undo.
839 * This code copied from getbr().
843 if (inopen
== -1) /* don't mess up undo for esc esc */
845 inopen
= 1; /* restore old setting now that macro done */
855 forbid(getkey() != 'Z');
857 globp
= (unsigned char *)"x";
862 * P Put back text before cursor or before current
863 * line. If text was whole lines goes back
864 * as whole lines. If part of a single line
865 * or parts of whole lines splits up current
866 * line to form many new lines.
867 * May specify a named buffer, or the delete
868 * saving buffers 1-9.
870 * p Like P but after rather than before.
879 forbid (!vreg
&& value(vi_UNDOMACRO
) && inopen
< 0);
882 * If previous delete was partial line, use an
883 * append or insert to put it back so as to
884 * use insert mode on intelligent terminals.
886 if (!vreg
&& DEL
[0]) {
888 forbid ((unsigned char)DEL
[128] == 0200);
890 ungetkey(c
== 'p' ? 'a' : 'i');
895 * If a register wasn't specified, then make
896 * sure there is something to put back.
898 forbid (!vreg
&& unddol
== dol
);
900 * If we just did a macro the whole buffer is in
901 * the undo save area. We don't want to put THAT.
903 forbid (vundkind
== VMANY
&& undkind
==UNDALL
);
908 if (vreg
&& partreg(vreg
) || !vreg
&& pkill
[0]) {
910 * Restoring multiple lines which were partial
911 * lines; will leave cursor in middle
912 * of line after shoving restored text in to
913 * split the current line.
916 if (c
== 'p' && *cursor
)
917 cursor
= nextchr(cursor
);
920 * In whole line case, have to back up dot
921 * for P; also want to clear cursor so
922 * cursor will eventually be positioned
923 * at the beginning of the first put line.
934 * The call to putreg can potentially
935 * bomb since there may be nothing in a named buffer.
936 * We thus put a catch in here. If we didn't and
937 * there was an error we would end up in command mode.
939 addr
= dol
; /* old dol */
942 vreg
? (int (*)())putreg
: put
, vreg
);
952 nlput
= dol
- addr
+ 1;
955 * Increment undap1, undap2 to make up
956 * for their incorrect initialization in the
957 * routine vremote before calling put/putreg.
965 * After a put want current line first line,
966 * and dot was made the last line put in code
967 * run so far. This is why we increment vcline
968 * above and decrease dot here.
974 fprintf(trace
, "vreplace(%d, %d, %d), undap1=%d, undap2=%d, dot=%d\n", vcline
, i
, nlput
, lineno(undap1
), lineno(undap2
), lineno(dot
));
976 vreplace(vcline
, i
, nlput
);
978 if (op
== 'P' && i
> 0) {
981 cursor
+= P_cursor_offset
;
984 if (state
!= VISUAL
) {
986 * Special case in open mode.
987 * Force action on the screen when a single
988 * line is put even if it is identical to
989 * the current line, e.g. on YP; otherwise
990 * you can't tell anything happened.
992 vjumpto(dot
, cursor
, '.');
1001 * ^^ Return to previous file.
1002 * Like a :e #, and thus can be used after a
1003 * "No Write" diagnostic.
1010 if (value(vi_AUTOWRITE
) && !value(vi_READONLY
))
1011 globp
= (unsigned char *)"e! #";
1013 globp
= (unsigned char *)"e #";
1018 * ^T Pop the tag stack if enabled or else reset it
1025 globp
= (unsigned char *) "pop";
1029 * ^] Takes word after cursor as tag, and then does
1030 * tag command. Read ``go right to''.
1031 * This is not a search, so the wrapscan setting
1032 * must be ignored. If set, then it is unset
1033 * here and restored later.
1038 if (value(vi_WRAPSCAN
) == 0) {
1040 value(vi_WRAPSCAN
) = 1;
1042 globp
= (unsigned char *)"tag";
1050 globp
= (unsigned char *)"&";
1054 * ^G Bring up a status line at the bottom of
1055 * the screen, like a :file command.
1057 * BUG: Was ^S but doesn't work in cbreak mode
1061 globp
= (unsigned char *)"file";
1069 * ^Z: suspend editor session and temporarily return
1070 * to shell. Only works with Berkeley/IIASA process
1071 * control in kernel.
1074 forbid(dosusp
== 0);
1077 globp
= (unsigned char *)"stop";
1082 * : Read a command from the echo area and
1083 * execute it in command mode.
1096 * Use the visual undo buffer to store the global
1097 * string for command mode, since it is idle right now.
1099 oglobp
= globp
; strcpy(vutmp
, genbuf
+1); globp
= vutmp
;
1105 * Have to finagle around not to lose last
1106 * character after this command (when run from ex
1107 * command mode). This is clumsy.
1109 d
= peekc
; ungetchar(0);
1112 * So after a "Hit return..." ":", we do
1113 * another "Hit return..." the next time
1120 * Save old values of options so we can
1121 * notice when they change; switch into
1122 * cooked mode so we are interruptible.
1124 onumber
= value(vi_NUMBER
);
1125 olist
= value(vi_LIST
);
1132 if (dot
== zero
&& dol
> zero
)
1141 copy(esave
, vtube
[WECHO
], TUBECOLS
* sizeof(wchar_t));
1150 * If we ended up with no lines in the buffer, make
1159 * Special case: did list/number options change?
1161 if (onumber
!= value(vi_NUMBER
))
1162 setnumb(value(vi_NUMBER
));
1163 if (olist
!= value(vi_LIST
))
1164 setlist(value(vi_LIST
));
1168 * If a change occurred, other than
1169 * a write which clears changes, then
1170 * we should allow an undo even if .
1173 * BUG: You can make this wrong by
1174 * tricking around with multiple commands
1175 * on one line of : escape, and including
1176 * a write command there, but it's not
1177 * worth worrying about.
1179 if (FIXUNDO
&& tchng
&& tchng
!= i
)
1180 vundkind
= VMANY
, cursor
= 0;
1183 * If we are about to do another :, hold off
1184 * updating of screen.
1186 if (vcnt
< 0 && Peekkey
== ':') {
1194 * In the case where the file being edited is
1195 * new; e.g. if the initial state hasn't been
1196 * saved yet, then do so now.
1198 if (unddol
== truedol
) {
1206 copy(esave
, vtube
[WECHO
], TUBECOLS
* sizeof(wchar_t));
1210 * If the current line moved reset the cursor position.
1218 * If current line is not on screen or if we are
1219 * in open mode and . moved, then redraw.
1221 i
= vcline
+ (dot
- addr
);
1224 if (i
< 0 || i
>= vcnt
&& i
>= -vcnt
|| state
!= VISUAL
&& dot
!= addr
) {
1225 if (state
== CRTOPEN
)
1229 vjumpto(dot
, (unsigned char *) 0, '.');
1232 * Current line IS on screen.
1233 * If we did a [Hit return...] then
1234 * restore vcnt and clear screen if in visual
1239 if (state
== VISUAL
)
1241 else if (state
== CRTOPEN
) {
1247 * Limit max value of vcnt based on $
1249 i
= vcline
+ lineDOL() - lineDOT() + 1;
1254 * Dirty and repaint.
1261 * If in visual, put back the echo area
1262 * if it was clobbered.
1264 if (state
== VISUAL
) {
1265 int sdc
= destcol
, sdl
= destline
;
1269 for (i
= 0; i
< TUBECOLS
- 1; i
++) {
1272 if(esave
[i
] != FILLER
)
1273 (void) vputchar(esave
[i
]);
1278 if (tag_reset_wrap
== 1) {
1280 value(vi_WRAPSCAN
) = 0;
1285 * u undo the last changing command.
1292 * U restore current line to initial state.
1301 inopen
= 1; /* might have been -1 */
1306 * Rest of commands are decoded by the operate
1314 * Grab the word after the cursor so we can look for it as a tag.
1319 unsigned char *cp
, *dp
;
1321 cp
= vpastwh(cursor
);
1325 if (dp
< &lasttag
[sizeof lasttag
- 2])
1328 /* only allow ascii alphabetics */
1329 } while ((isascii(*cp
) && isalpha(*cp
)) || isdigit(*cp
) || *cp
== '_');
1335 * Before appending lines, set up addr1 and
1336 * the command mode undo information.
1349 * Execute function f with the address bounds addr1
1350 * and addr2 surrounding cnt lines starting at dot.
1353 vremote(cnt
, f
, arg
)
1354 int cnt
, (*f
)(), arg
;
1356 int oing
= inglobal
;
1359 addr2
= dot
+ cnt
- 1;
1362 undap1
= undap2
= dot
;
1368 * XPG6 assertion 273: For the following commands, don't set vmcurs
1369 * to 0, so that undo positions the cursor column correctly when
1370 * we've moved off the initial line that was changed eg. when G has
1371 * moved us off the line, or when a multi-line change was done.
1373 if (lastcmd
[0] != 'C' && lastcmd
[0] != 'c' && lastcmd
[0] != 'o' &&
1374 lastcmd
[0] != 'R' && lastcmd
[0] != 'S' && lastcmd
[0] != 's' &&
1375 lastcmd
[0] != 'i' && lastcmd
[0] != 'a' && lastcmd
[0] != 'A') {
1381 * Save the current contents of linebuf, if it has changed.
1386 unsigned char temp
[LBSIZE
];
1388 strncpy(temp
, linebuf
, sizeof (temp
));
1389 if (FIXUNDO
&& vundkind
== VCHNG
|| vundkind
== VCAPU
) {
1391 * If the undo state is saved in the temporary buffer
1392 * vutmp, then we sync this into the temp file so that
1393 * we will be able to undo even after we have moved off
1394 * the line. It would be possible to associate a line
1395 * with vutmp but we assume that vutmp is only associated
1396 * with line dot (e.g. in case ':') above, so beware.
1401 vremote(1, yank
, 0);
1404 undkind
= UNDCHANGE
;
1407 * Get the line out of the temp file and do nothing if it hasn't
1408 * changed. This may seem like a loss, but the line will
1409 * almost always be in a read buffer so this may well avoid disk i/o.
1412 if (strncmp(linebuf
, temp
, sizeof (temp
)) == 0)
1419 #define forbid(a) if (a) { (void) beep(); return; }
1423 * Code here is rather long, and very uninteresting.
1426 vzop(bool hadcnt
, int cnt
, int c
)
1430 if (state
!= VISUAL
) {
1432 * Z from open; always like a z=.
1433 * This code is a mess and should be cleaned up.
1442 zop2(Xhadcnt
? Xcnt
: value(vi_WINDOW
) - 1, '=');
1443 if (state
== CRTOPEN
)
1450 outline
= destline
= 0;
1451 vjumpto(dot
, cursor
, 0);
1465 addr
= dot
+ vcnt
- vcline
;
1469 addr
= dot
- vcline
- 1;
1470 forbid (addr
< one
);
1485 forbid (addr
<= one
);
1489 forbid (addr
>= dol
);
1502 vjumpto(addr
, (unsigned char *)NOSTR
, c
);