/* * cl_deleteln -- * Delete the current line, scrolling all lines below it. * * PUBLIC: int cl_deleteln __P((SCR *)); */ int cl_deleteln(SCR *sp) { CHAR_T ch; CL_PRIVATE *clp; WINDOW *win; size_t col, lno, spcnt, y, x; clp = CLP(sp); win = CLSP(sp) ? CLSP(sp) : stdscr; /* * This clause is required because the curses screen uses reverse * video to delimit split screens. If the screen does not do this, * this code won't be necessary. * * If the bottom line was in reverse video, rewrite it in normal * video before it's scrolled. * * Check for the existence of a chgat function; XSI requires it, but * historic implementations of System V curses don't. If it's not * a #define, we'll fall back to doing it by hand, which is slow but * acceptable. * * By hand means walking through the line, retrieving and rewriting * each character. Curses has no EOL marker, so track strings of * spaces, and copy the trailing spaces only if there's a non-space * character following. */ if (!F_ISSET(sp, SC_SCR_EXWROTE) && IS_SPLIT(sp)) { getyx(win, y, x); #ifdef mvchgat mvwchgat(win, RLNO(sp, LASTLINE(sp)), 0, -1, A_NORMAL, 0, NULL); #else for (lno = RLNO(sp, LASTLINE(sp)), col = spcnt = 0;;) { (void)wmove(win, lno, col); ch = winch(win); if (isblank(ch)) ++spcnt; else { (void)wmove(win, lno, col - spcnt); for (; spcnt > 0; --spcnt) (void)waddch(win, ' '); (void)waddch(win, ch); } if (++col >= sp->cols) break; } #endif (void)wmove(win, y, x); } /* * The bottom line is expected to be blank after this operation, * and other screens must support that semantic. */ return (wdeleteln(win) == ERR); }
/* * ip_deleteln -- * Delete the current line, scrolling all lines below it. * * PUBLIC: int ip_deleteln __P((SCR *)); */ int ip_deleteln(SCR *sp) { IP_BUF ipb; IP_PRIVATE *ipp = IPP(sp); /* * This clause is required because the curses screen uses reverse * video to delimit split screens. If the screen does not do this, * this code won't be necessary. * * If the bottom line was in reverse video, rewrite it in normal * video before it's scrolled. */ if (!F_ISSET(sp, SC_SCR_EXWROTE) && IS_SPLIT(sp)) { ipb.code = SI_REWRITE; ipb.val1 = RLNO(sp, LASTLINE(sp)); if (vi_send(ipp->o_fd, "1", &ipb)) return (1); } /* * The bottom line is expected to be blank after this operation, * and other screens must support that semantic. */ ipb.code = SI_DELETELN; return (vi_send(ipp->o_fd, NULL, &ipb)); }
static int addstr4(SCR *sp, const void *str, size_t len, int wide) { WINDOW *win; size_t y, x; int iv; win = CLSP(sp) ? CLSP(sp) : stdscr; /* * If ex isn't in control, it's the last line of the screen and * it's a split screen, use inverse video. */ iv = 0; getyx(win, y, x); __USE(x); if (!F_ISSET(sp, SC_SCR_EXWROTE) && y == RLNO(sp, LASTLINE(sp)) && IS_SPLIT(sp)) { iv = 1; (void)wstandout(win); } #ifdef USE_WIDECHAR if (wide) { if (waddnwstr(win, str, len) == ERR) return (1); } else #endif if (waddnstr(win, str, len) == ERR) return (1); if (iv) (void)wstandend(win); return (0); }
/* * cl_move -- * Move the cursor. * * PUBLIC: int cl_move __P((SCR *, size_t, size_t)); */ int cl_move(SCR *sp, size_t lno, size_t cno) { WINDOW *win; win = CLSP(sp) ? CLSP(sp) : stdscr; /* See the comment in cl_cursor. */ if (wmove(win, RLNO(sp, lno), RCNO(sp, cno)) == ERR) { msgq(sp, M_ERR, "Error: move: l(%zu + %zu) c(%zu + %zu)", lno, sp->roff, cno, sp->coff); return (1); } return (0); }
/* * ip_move -- * Move the cursor. * * PUBLIC: int ip_move __P((SCR *, size_t, size_t)); */ int ip_move(SCR *sp, size_t lno, size_t cno) { IP_PRIVATE *ipp; IP_BUF ipb; ipp = IPP(sp); ipp->row = lno; ipp->col = cno; ipb.code = SI_MOVE; ipb.val1 = RLNO(sp, lno); ipb.val2 = RCNO(sp, cno); return (vi_send(ipp->o_fd, "12", &ipb)); }
/* * cl_screen -- * Switch screen types. * * PUBLIC: int cl_screen __P((SCR *, u_int32_t)); */ int cl_screen(SCR *sp, u_int32_t flags) { CL_PRIVATE *clp; WINDOW *win; GS *gp; int ret, error; sigset_t oset; gp = sp->gp; clp = CLP(sp); win = CLSP(sp) ? CLSP(sp) : stdscr; ret = 0; /* * During initialization of the screen, block signals to make sure that * curses/terminfo routines are not interrupted. */ error = sigprocmask(SIG_BLOCK, &__sigblockset, &oset); /* See if the current information is incorrect. */ if (F_ISSET(gp, G_SRESTART)) { if (CLSP(sp)) { delwin(CLSP(sp)); sp->cl_private = NULL; } if (cl_quit(gp)) { ret = 1; goto end; } F_CLR(gp, G_SRESTART); } /* See if we're already in the right mode. */ if ((LF_ISSET(SC_EX) && F_ISSET(sp, SC_SCR_EX)) || (LF_ISSET(SC_VI) && F_ISSET(sp, SC_SCR_VI))) goto end; /* * Fake leaving ex mode. * * We don't actually exit ex or vi mode unless forced (e.g. by a window * size change). This is because many curses implementations can't be * called twice in a single program. Plus, it's faster. If the editor * "leaves" vi to enter ex, when it exits ex we'll just fall back into * vi. */ if (F_ISSET(sp, SC_SCR_EX)) F_CLR(sp, SC_SCR_EX); /* * Fake leaving vi mode. * * Clear out the rest of the screen if we're in the middle of a split * screen. Move to the last line in the current screen -- this makes * terminal scrolling happen naturally. Note: *don't* move past the * end of the screen, as there are ex commands (e.g., :read ! cat file) * that don't want to. Don't clear the info line, its contents may be * valid, e.g. :file|append. */ if (F_ISSET(sp, SC_SCR_VI)) { F_CLR(sp, SC_SCR_VI); if (TAILQ_NEXT(sp, q) != NULL) { (void)wmove(win, RLNO(sp, sp->rows), 0); wclrtobot(win); } (void)wmove(win, RLNO(sp, sp->rows) - 1, 0); wrefresh(win); } /* Enter the requested mode. */ if (LF_ISSET(SC_EX)) { if (cl_ex_init(sp)) { ret = 1; goto end; } F_SET(clp, CL_IN_EX | CL_SCR_EX_INIT); /* * If doing an ex screen for ex mode, move to the last line * on the screen. */ if (F_ISSET(sp, SC_EX) && clp->cup != NULL) tputs(tgoto(clp->cup, 0, O_VAL(sp, O_LINES) - 1), 1, cl_putchar); } else { if (cl_vi_init(sp)) { ret = 1; goto end; } F_CLR(clp, CL_IN_EX); F_SET(clp, CL_SCR_VI_INIT); } end: /* Unblock signals. */ if (error == 0) (void)sigprocmask(SIG_SETMASK, &oset, NULL); return ret; }