📄 screen.c
字号:
)
{
#ifdef USE_GUI
if (gui.in_use)
{
char buf[20];
sprintf(buf, "\033|%dH", screen_attr); /* internal GUI code */
OUT_STR(buf);
}
else
#endif
{
if (screen_attr > HL_ALL) /* special HL attr. */
{
struct attr_entry *aep;
if (*T_CCO != NUL)
{
/*
* Assume that t_me restores the original colors!
*/
aep = syn_cterm_attr2entry(screen_attr);
if (aep != NULL && (aep->ae_u.cterm.fg_color ||
aep->ae_u.cterm.bg_color))
do_ME = TRUE;
}
else
{
aep = syn_term_attr2entry(screen_attr);
if (aep != NULL && aep->ae_u.term.stop != NULL)
{
if (STRCMP(aep->ae_u.term.stop, T_ME) == 0)
do_ME = TRUE;
else
out_str(aep->ae_u.term.stop);
}
}
if (aep == NULL) /* did ":syntax clear" */
screen_attr = 0;
else
screen_attr = aep->ae_attr;
}
/*
* Often all ending-codes are equal to T_ME. Avoid outputting the
* same sequence several times.
*/
if (screen_attr & HL_STANDOUT)
{
if (STRCMP(T_SE, T_ME) == 0)
do_ME = TRUE;
else
out_str(T_SE);
}
if (screen_attr & HL_UNDERLINE)
{
if (STRCMP(T_UE, T_ME) == 0)
do_ME = TRUE;
else
out_str(T_UE);
}
if (screen_attr & HL_ITALIC)
{
if (STRCMP(T_CZR, T_ME) == 0)
do_ME = TRUE;
else
out_str(T_CZR);
}
if (do_ME || (screen_attr & HL_BOLD) || (screen_attr & HL_INVERSE))
out_str(T_ME);
if (*T_CCO != NUL)
{
/* set Normal cterm colors */
if (cterm_normal_fg_color)
term_fg_color(cterm_normal_fg_color - 1);
if (cterm_normal_bg_color)
term_bg_color(cterm_normal_bg_color - 1);
if (cterm_normal_fg_bold)
out_str(T_MD);
}
}
}
screen_attr = 0;
}
/*
* Reset the colors for a cterm. Used when leaving Vim.
*/
void
reset_cterm_colors()
{
if (*T_CCO != NUL)
{
/* set Normal cterm colors */
if (cterm_normal_fg_color || cterm_normal_bg_color)
out_str(T_OP);
if (cterm_normal_fg_bold)
out_str(T_ME);
}
}
/*
* put character '*p' on the screen at position 'row' and 'col'
*/
static void
screen_char(p, row, col)
char_u *p;
int row;
int col;
{
/*
* Outputting the last character on the screen may scrollup the screen.
* Don't to it!
*/
if (col == Columns - 1 && row == Rows - 1)
return;
/*
* Stop highlighting first, so it's easier to move the cursor.
*/
if (screen_attr != *(p + Columns))
screen_stop_highlight();
windgoto(row, col);
if (screen_attr != *(p + Columns))
screen_start_highlight(*(p + Columns));
out_char(*p);
screen_cur_col++;
}
/*
* Fill the screen from 'start_row' to 'end_row', from 'start_col' to 'end_col'
* with character 'c1' in first column followed by 'c2' in the other columns.
* Use attributes 'attr'.
*/
void
screen_fill(start_row, end_row, start_col, end_col, c1, c2, attr)
int start_row, end_row;
int start_col, end_col;
int c1, c2;
int attr;
{
int row;
int col;
char_u *screenp;
char_u *attrp;
int did_delete;
int c;
int norm_term;
if (end_row > Rows) /* safety check */
end_row = Rows;
if (end_col > Columns) /* safety check */
end_col = Columns;
if (NextScreen == NULL ||
start_row >= end_row || start_col >= end_col) /* nothing to do */
return;
/* it's a "normal" terminal when not in a GUI or cterm */
norm_term = (
#ifdef USE_GUI
!gui.in_use &&
#endif
*T_CCO == NUL);
for (row = start_row; row < end_row; ++row)
{
/*
* Try to use delete-line termcap code, when no attributes or in a
* "normal" terminal, where a bold/italic space is just a
* space.
*/
did_delete = FALSE;
if (c2 == ' ' && end_col == Columns && *T_CE != NUL
&& (attr == 0 || (norm_term && attr <= HL_ALL
&& ((attr & ~(HL_BOLD | HL_ITALIC)) == 0))))
{
/*
* check if we really need to clear something
*/
col = start_col;
screenp = LinePointers[row] + start_col;
if (c1 != ' ') /* don't clear first char */
{
++col;
++screenp;
}
/* skip blanks (used often, keep it fast!) */
attrp = screenp + Columns;
while (col < end_col && *screenp == ' ' && *attrp == 0)
{
++col;
++screenp;
++attrp;
}
if (col < end_col) /* something to be cleared */
{
screen_stop_highlight();
term_windgoto(row, col);/* clear rest of this screen line */
out_str(T_CE);
screen_start(); /* don't know where cursor is now */
col = end_col - col;
while (col--) /* clear chars in NextScreen */
{
*attrp++ = 0;
*screenp++ = ' ';
}
}
did_delete = TRUE; /* the chars are cleared now */
}
screenp = LinePointers[row] + start_col;
c = c1;
for (col = start_col; col < end_col; ++col)
{
if (*screenp != c || *(screenp + Columns) != attr)
{
*screenp = c;
*(screenp + Columns) = attr;
if (!did_delete || c != ' ')
screen_char(screenp, row, col);
}
++screenp;
if (col == start_col)
{
if (did_delete)
break;
c = c2;
}
}
if (row == Rows - 1) /* overwritten the command line */
{
redraw_cmdline = TRUE;
if (c1 == ' ' && c2 == ' ')
clear_cmdline = FALSE; /* command line has been cleared */
}
}
}
/*
* compute wp->w_botline. Can be called after wp->w_topline changed.
*/
static void
comp_botline()
{
int n;
linenr_t lnum;
int done;
/*
* If w_cline_row is valid, start there.
* Otherwise have to start at w_topline.
*/
check_cursor_moved(curwin);
if (curwin->w_valid & VALID_CROW)
{
lnum = curwin->w_cursor.lnum;
done = curwin->w_cline_row;
}
else
{
lnum = curwin->w_topline;
done = 0;
}
for ( ; lnum <= curwin->w_buffer->b_ml.ml_line_count; ++lnum)
{
n = plines(lnum);
if (lnum == curwin->w_cursor.lnum)
{
curwin->w_cline_row = done;
curwin->w_cline_height = n;
curwin->w_valid |= (VALID_CROW|VALID_CHEIGHT);
}
if (done + n > curwin->w_height)
break;
done += n;
}
/* curwin->w_botline is the line that is just below the window */
curwin->w_botline = lnum;
curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
/*
* Also set curwin->w_empty_rows, otherwise scroll_cursor_bot() won't work
*/
if (done == 0)
curwin->w_empty_rows = 0; /* single line that doesn't fit */
else
curwin->w_empty_rows = curwin->w_height - done;
}
void
screenalloc(clear)
int clear;
{
int new_row, old_row;
WIN *wp;
int outofmem = FALSE;
int len;
char_u *new_NextScreen;
char_u **new_LinePointers;
static int entered = FALSE; /* avoid recursiveness */
/*
* Allocation of the screen buffers is done only when the size changes
* and when Rows and Columns have been set and we have started doing full
* screen stuff.
*/
if ((NextScreen != NULL &&
Rows == screen_Rows && Columns == screen_Columns) ||
Rows == 0 || Columns == 0 || (!full_screen && NextScreen == NULL))
return;
/*
* It's possible that we produce an out-of-memory message below, which
* will cause this function to be called again. To break the loop, just
* return here.
*/
if (entered)
return;
entered = TRUE;
#ifdef USE_GUI_BEOS
vim_lock_screen(); /* be safe, put it here */
#endif
comp_col(); /* recompute columns for shown command and ruler */
/*
* We're changing the size of the screen.
* - Allocate new arrays for NextScreen.
* - Move lines from the old arrays into the new arrays, clear extra
* lines (unless the screen is going to be cleared).
* - Free the old arrays.
*
* If anything fails, make NextScreen NULL, so we don't do anything!
* Continuing with the old NextScreen may result in a crash, because the
* size is wrong.
*/
for (wp = firstwin; wp; wp = wp->w_next)
win_free_lsize(wp);
new_NextScreen =
(char_u *)lalloc((long_u)((Rows + 1) * Columns * 2), FALSE);
new_LinePointers =
(char_u **)lalloc((long_u)(sizeof(char_u *) * Rows), FALSE);
for (wp = firstwin; wp; wp = wp->w_next)
{
if (win_alloc_lsize(wp) == FAIL)
{
outofmem = TRUE;
break;
}
}
if (new_NextScreen == NULL || new_LinePointers == NULL || outofmem)
{
do_outofmem_msg();
vim_free(new_NextScreen);
new_NextScreen = NULL;
vim_free(new_LinePointers);
new_LinePointers = NULL;
}
else
{
for (new_row = 0; new_row < Rows; ++new_row)
{
new_LinePointers[new_row] = new_NextScreen + new_row * Columns * 2;
/*
* If the screen is not going to be cleared, copy as much as
* possible from the old screen to the new one and clear the rest
* (used when resizing the window at the "--more--" prompt or when
* executing an external command, for the GUI).
*/
if (!clear)
{
lineclear(new_LinePointers[new_row]);
old_row = new_row + (screen_Rows - Rows);
if (old_row >= 0)
{
if (screen_Columns < Columns)
len = screen_Columns;
else
len = Columns;
mch_memmove(new_LinePointers[new_row],
LinePointers[old_row], (size_t)len);
mch_memmove(new_LinePointers[new_row] + Columns,
LinePointers[old_row] + screen_Columns,
(size_t)len);
}
}
}
current_LinePointer = new_NextScreen + Rows * Columns * 2;
}
vim_free(NextScreen);
vim_free(LinePointers);
NextScreen = new_NextScreen;
LinePointers = new_LinePointers;
must_redraw = CLEAR; /* need to clear the screen later */
if (clear)
screenclear2();
#ifdef USE_GUI
else if (gui.in_use && NextScreen != NULL && Rows != screen_Rows)
{
(void)gui_redraw_block(0, 0, (int)Rows - 1, (int)Columns - 1, 0);
/*
* Adjust the position of the cursor, for when executing an external
* command.
*/
if (msg_row >= Rows) /* Rows got smaller */
msg_row = Rows - 1; /* put cursor at last row */
else if (Rows > screen_Rows) /* Rows got bigger */
msg_row += Rows - screen_Rows; /* put cursor in same place */
if (msg_col >= Columns) /* Columns got smaller */
msg_col = Columns - 1; /* put cursor at last column */
}
#endif
screen_Rows = Rows;
screen_Columns = Columns;
#ifdef USE_GUI_BEOS
vim_unlock_screen();
#endif
entered = FALSE;
}
void
screenclear()
{
check_for_delay(FALSE);
screenalloc(FALSE); /* allocate screen buffers if size changed */
screenclear2(); /* clear the screen */
}
static void
screenclear2()
{
int i;
if (starting || NextScreen == NULL)
return;
screen_stop_highlight(); /* don't want highlighting here */
out_str(T_CL); /* clear the display */
/* blank out NextScreen */
for (i = 0; i < Rows; ++i)
lineclear(LinePointers[i]);
screen_cleared = TRUE; /* can use contents of NextScreen now */
win_rest_invalid(firstwin);
clear_cmdline = FALSE;
redraw_cmdline = TRUE;
if (must_redraw == CLEAR) /* no need to clear again */
must_redraw = NOT_VALID;
compute_cmdrow();
msg_row = cmdline_row; /* put cursor on last line for messages */
msg_col = 0;
screen_start(); /* don't know where cursor is now */
msg_scrolled = 0; /* can't scroll back */
msg_didany = FALSE;
msg_didout = FALSE;
}
/*
* Clear one line in NextScreen.
*/
static void
lineclear(p)
char_u *p;
{
(void)vim_memset(p, ' ', (size_t)Columns);
(void)vim_memset(p + Columns, 0, (size_t)Columns);
}
/*
* Update curwin->w_topline and redraw if necessary.
*/
void
update_topline_redraw()
{
update_topline();
if (must_redraw)
update_screen(must_redraw);
}
/*
* Update curwin->w_topline to move the cursor onto the screen.
*/
void
update_topline()
{
long line_count;
int temp;
linenr_t old_topline;
if (!screen_valid(TRUE))
return;
old_topline = curwin->w_topline;
/*
* If the buffer is empty, always set topline to 1.
*/
if (bufempty()) /* special case - file is empty */
{
if (curwin->w_topline != 1)
redraw_later(NOT_VALID);
curwin->w_topline = 1;
curwin->w_botline = 2;
curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
}
/*
* If the cursor is above the top of the window, scroll the window to put
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -