2 * Copyright (c) 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 1993, 1994, 1995, 1996
5 * Keith Bostic. All rights reserved.
7 * See the LICENSE file for redistribution information.
13 static const char sccsid[] = "@(#)cl_funcs.c 10.50 (Berkeley) 9/24/96";
16 #include <sys/types.h>
17 #include <sys/queue.h>
20 #include <bitstring.h>
30 #include "../common/common.h"
36 * Add len bytes from the string at the cursor, advancing the cursor.
38 * PUBLIC: int cl_addstr __P((SCR *, const char *, size_t));
41 cl_addstr(sp, str, len)
53 * If ex isn't in control, it's the last line of the screen and
54 * it's a split screen, use inverse video.
57 getyx(stdscr, oldy, oldx);
58 if (!F_ISSET(sp, SC_SCR_EXWROTE) &&
59 oldy == RLNO(sp, LASTLINE(sp)) && IS_SPLIT(sp)) {
64 if (addnstr(str, len) == ERR)
74 * Toggle a screen attribute on/off.
76 * PUBLIC: int cl_attr __P((SCR *, scr_attr_t, int));
79 cl_attr(sp, attribute, on)
92 * There's a major layering violation here. The problem is that the
93 * X11 xterm screen has what's known as an "alternate" screen. Some
94 * xterm termcap/terminfo entries include sequences to switch to/from
95 * that alternate screen as part of the ti/te (smcup/rmcup) strings.
96 * Vi runs in the alternate screen, so that you are returned to the
97 * same screen contents on exit from vi that you had when you entered
98 * vi. Further, when you run :shell, or :!date or similar ex commands,
99 * you also see the original screen contents. This wasn't deliberate
100 * on vi's part, it's just that it historically sent terminal init/end
101 * sequences at those times, and the addition of the alternate screen
102 * sequences to the strings changed the behavior of vi. The problem
103 * caused by this is that we don't want to switch back to the alternate
104 * screen while getting a new command from the user, when the user is
105 * continuing to enter ex commands, e.g.:
107 * :!date <<< switch to original screen
108 * [Hit return to continue] <<< prompt user to continue
109 * :command <<< get command from user
111 * Note that the :command input is a true vi input mode, e.g., input
112 * maps and abbreviations are being done. So, we need to be able to
113 * switch back into the vi screen mode, without flashing the screen.
115 * To make matters worse, the curses initscr() and endwin() calls will
116 * do this automatically -- so, this attribute isn't as controlled by
117 * the higher level screen as closely as one might like.
120 if (clp->ti_te != TI_SENT) {
121 clp->ti_te = TI_SENT;
122 if (clp->smcup == NULL)
123 (void)cl_getcap(sp, "smcup", &clp->smcup);
124 if (clp->smcup != NULL)
125 (void)tputs(clp->smcup, 1, cl_putchar);
128 if (clp->ti_te != TE_SENT) {
129 clp->ti_te = TE_SENT;
130 if (clp->rmcup == NULL)
131 (void)cl_getcap(sp, "rmcup", &clp->rmcup);
132 if (clp->rmcup != NULL)
133 (void)tputs(clp->rmcup, 1, cl_putchar);
134 (void)fflush(stdout);
136 (void)fflush(stdout);
139 if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)) {
140 if (clp->smso == NULL)
143 (void)tputs(clp->smso, 1, cl_putchar);
145 (void)tputs(clp->rmso, 1, cl_putchar);
146 (void)fflush(stdout);
162 * Return the baud rate.
164 * PUBLIC: int cl_baud __P((SCR *, u_long *));
175 * There's no portable way to get a "baud rate" -- cfgetospeed(3)
176 * returns the value associated with some #define, which we may
177 * never have heard of, or which may be a purely local speed. Vi
178 * only cares if it's SLOW (w300), slow (w1200) or fast (w9600).
179 * Try and detect the slow ones, and default to fast.
182 switch (cfgetospeed(&clp->orig)) {
205 * Ring the bell/flash the screen.
207 * PUBLIC: int cl_bell __P((SCR *));
213 if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE))
214 (void)write(STDOUT_FILENO, "\07", 1); /* \a */
217 * Vi has an edit option which determines if the terminal
218 * should be beeped or the screen flashed.
220 if (O_ISSET(sp, O_FLASH))
230 * Clear from the current cursor to the end of the line.
232 * PUBLIC: int cl_clrtoeol __P((SCR *));
238 return (clrtoeol() == ERR);
243 * Return the current cursor position.
245 * PUBLIC: int cl_cursor __P((SCR *, size_t *, size_t *));
248 cl_cursor(sp, yp, xp)
253 * The curses screen support splits a single underlying curses screen
254 * into multiple screens to support split screen semantics. For this
255 * reason the returned value must be adjusted to be relative to the
256 * current screen, and not absolute. Screens that implement the split
257 * using physically distinct screens won't need this hack.
259 getyx(stdscr, *yp, *xp);
266 * Delete the current line, scrolling all lines below it.
268 * PUBLIC: int cl_deleteln __P((SCR *));
276 size_t col, lno, spcnt, oldy, oldx;
281 * This clause is required because the curses screen uses reverse
282 * video to delimit split screens. If the screen does not do this,
283 * this code won't be necessary.
285 * If the bottom line was in reverse video, rewrite it in normal
286 * video before it's scrolled.
288 * Check for the existence of a chgat function; XSI requires it, but
289 * historic implementations of System V curses don't. If it's not
290 * a #define, we'll fall back to doing it by hand, which is slow but
293 * By hand means walking through the line, retrieving and rewriting
294 * each character. Curses has no EOL marker, so track strings of
295 * spaces, and copy the trailing spaces only if there's a non-space
296 * character following.
298 if (!F_ISSET(sp, SC_SCR_EXWROTE) && IS_SPLIT(sp)) {
299 getyx(stdscr, oldy, oldx);
301 mvchgat(RLNO(sp, LASTLINE(sp)), 0, -1, A_NORMAL, 0, NULL);
303 for (lno = RLNO(sp, LASTLINE(sp)), col = spcnt = 0;;) {
304 (void)move(lno, col);
309 (void)move(lno, col - spcnt);
310 for (; spcnt > 0; --spcnt)
314 if (++col >= sp->cols)
318 (void)move(oldy, oldx);
322 * The bottom line is expected to be blank after this operation,
323 * and other screens must support that semantic.
325 return (deleteln() == ERR);
330 * Adjust the screen for ex. This routine is purely for standalone
331 * ex programs. All special purpose, all special case.
333 * PUBLIC: int cl_ex_adjust __P((SCR *, exadj_t));
336 cl_ex_adjust(sp, action)
346 /* Move the cursor up one line if that's possible. */
347 if (clp->cuu1 != NULL)
348 (void)tputs(clp->cuu1, 1, cl_putchar);
349 else if (clp->cup != NULL)
350 (void)tputs(tgoto(clp->cup,
351 0, LINES - 2), 1, cl_putchar);
356 /* Clear the line. */
357 if (clp->el != NULL) {
359 (void)tputs(clp->el, 1, cl_putchar);
362 * Historically, ex didn't erase the line, so, if the
363 * displayed line was only a single glyph, and <eof>
364 * was more than one glyph, the output would not fully
365 * overwrite the user's input. To fix this, output
366 * the maxiumum character number of spaces. Note,
367 * this won't help if the user entered extra prompt
368 * or <blank> characters before the command character.
369 * We'd have to do a lot of work to make that work, and
370 * it's almost certainly not worth the effort.
372 for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt)
374 for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt)
377 (void)fflush(stdout);
388 * Push down the current line, discarding the bottom line.
390 * PUBLIC: int cl_insertln __P((SCR *));
397 * The current line is expected to be blank after this operation,
398 * and the screen must support that semantic.
400 return (insertln() == ERR);
405 * Return the value for a special key.
407 * PUBLIC: int cl_keyval __P((SCR *, scr_keyval_t, CHAR_T *, int *));
410 cl_keyval(sp, val, chp, dnep)
419 * VEOF, VERASE and VKILL are required by POSIX 1003.1-1990,
420 * VWERASE is a 4BSD extension.
425 *dnep = (*chp = clp->orig.c_cc[VEOF]) == _POSIX_VDISABLE;
428 *dnep = (*chp = clp->orig.c_cc[VERASE]) == _POSIX_VDISABLE;
431 *dnep = (*chp = clp->orig.c_cc[VKILL]) == _POSIX_VDISABLE;
435 *dnep = (*chp = clp->orig.c_cc[VWERASE]) == _POSIX_VDISABLE;
449 * PUBLIC: int cl_move __P((SCR *, size_t, size_t));
452 cl_move(sp, lno, cno)
456 /* See the comment in cl_cursor. */
457 if (move(RLNO(sp, lno), cno) == ERR) {
459 "Error: move: l(%u) c(%u) o(%u)", lno, cno, sp->woff);
467 * Refresh the screen.
469 * PUBLIC: int cl_refresh __P((SCR *, int));
472 cl_refresh(sp, repaint)
481 * If we received a killer signal, we're done, there's no point
482 * in refreshing the screen.
488 * If repaint is set, the editor is telling us that we don't know
489 * what's on the screen, so we have to repaint from scratch.
491 * In the curses library, doing wrefresh(curscr) is okay, but the
492 * screen flashes when we then apply the refresh() to bring it up
493 * to date. So, use clearok().
497 return (refresh() == ERR);
504 * PUBLIC: int cl_rename __P((SCR *, char *, int));
507 cl_rename(sp, name, on)
519 ttype = OG_STR(gp, GO_TERM);
523 * We can only rename windows for xterm.
526 if (F_ISSET(clp, CL_RENAME_OK) &&
527 !strncmp(ttype, "xterm", sizeof("xterm") - 1)) {
528 F_SET(clp, CL_RENAME);
529 (void)printf(XTERM_RENAME, name);
530 (void)fflush(stdout);
533 if (F_ISSET(clp, CL_RENAME)) {
534 F_CLR(clp, CL_RENAME);
535 (void)printf(XTERM_RENAME, ttype);
536 (void)fflush(stdout);
545 * PUBLIC: int cl_suspend __P((SCR *, int *));
548 cl_suspend(sp, allowedp)
563 * The ex implementation of this function isn't needed by screens not
564 * supporting ex commands that require full terminal canonical mode
567 * The vi implementation of this function isn't needed by screens not
568 * supporting vi process suspension, i.e. any screen that isn't backed
571 * Setting allowedp to 0 will cause the editor to reject the command.
573 if (F_ISSET(sp, SC_EX)) {
574 /* Save the terminal settings, and restore the original ones. */
575 if (F_ISSET(clp, CL_STDIN_TTY)) {
576 (void)tcgetattr(STDIN_FILENO, &t);
577 (void)tcsetattr(STDIN_FILENO,
578 TCSASOFT | TCSADRAIN, &clp->orig);
581 /* Stop the process group. */
582 (void)kill(0, SIGTSTP);
584 /* Time passes ... */
586 /* Restore terminal settings. */
587 if (F_ISSET(clp, CL_STDIN_TTY))
588 (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t);
593 * Move to the lower left-hand corner of the screen.
596 * Not sure this is necessary in System V implementations, but it
599 getyx(stdscr, oldy, oldx);
600 (void)move(LINES - 1, 0);
604 * Temporarily end the screen. System V introduced a semantic where
605 * endwin() could be restarted. We use it because restarting curses
606 * from scratch often fails in System V. 4BSD curses didn't support
607 * restarting after endwin(), so we have to do what clean up we can
608 * without calling it.
610 #ifdef HAVE_BSD_CURSES
611 /* Save the terminal settings. */
612 (void)tcgetattr(STDIN_FILENO, &t);
615 /* Restore the cursor keys to normal mode. */
616 (void)keypad(stdscr, FALSE);
618 /* Restore the window name. */
619 (void)cl_rename(sp, NULL, 0);
621 #ifdef HAVE_BSD_CURSES
622 (void)cl_attr(sp, SA_ALTERNATE, 0);
628 * Restore the original terminal settings. This is bad -- the
629 * reset can cause character loss from the tty queue. However,
630 * we can't call endwin() in BSD curses implementations, and too
631 * many System V curses implementations don't get it right.
633 (void)tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &clp->orig);
635 /* Stop the process group. */
636 (void)kill(0, SIGTSTP);
638 /* Time passes ... */
641 * If we received a killer signal, we're done. Leave everything
642 * unchanged. In addition, the terminal has already been reset
643 * correctly, so leave it alone.
645 if (clp->killersig) {
646 F_CLR(clp, CL_SCR_EX_INIT | CL_SCR_VI_INIT);
650 #ifdef HAVE_BSD_CURSES
651 /* Restore terminal settings. */
652 if (F_ISSET(clp, CL_STDIN_TTY))
653 (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t);
655 (void)cl_attr(sp, SA_ALTERNATE, 1);
658 /* Set the window name. */
659 (void)cl_rename(sp, sp->frp->name, 1);
661 /* Put the cursor keys into application mode. */
662 (void)keypad(stdscr, TRUE);
664 /* Refresh and repaint the screen. */
665 (void)move(oldy, oldx);
666 (void)cl_refresh(sp, 1);
668 /* If the screen changed size, set the SIGWINCH bit. */
669 if (cl_ssize(sp, 1, NULL, NULL, &changed))
672 F_SET(CLP(sp), CL_SIGWINCH);
679 * Print out the curses usage messages.
681 * PUBLIC: void cl_usage __P((void));
687 usage: ex [-eFRrSsv] [-c command] [-t tag] [-w size] [file ...]\n\
688 usage: vi [-eFlRrSv] [-c command] [-t tag] [-w size] [file ...]\n"
689 (void)fprintf(stderr, "%s", USAGE);
696 * Stub routine so can flush out curses screen changes using gdb.
702 return (0); /* XXX Convince gdb to run it. */