2016-08-29 22:49:24 +02:00
|
|
|
/* vi:set ts=8 sts=4 sw=4 noet:
|
2004-06-13 20:20:40 +00:00
|
|
|
*
|
|
|
|
|
* VIM - Vi IMproved by Bram Moolenaar
|
|
|
|
|
*
|
|
|
|
|
* Do ":help uganda" in Vim to read copying and usage conditions.
|
|
|
|
|
* Do ":help credits" in Vim to see a list of people who contributed.
|
|
|
|
|
* See README.txt for an overview of the Vim source code.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
2019-09-19 23:06:20 +02:00
|
|
|
* screen.c: Lower level code for displaying on the screen.
|
2004-06-13 20:20:40 +00:00
|
|
|
*
|
|
|
|
|
* Output to the screen (console, terminal emulator or GUI window) is minimized
|
|
|
|
|
* by remembering what is already on the screen, and only updating the parts
|
|
|
|
|
* that changed.
|
|
|
|
|
*
|
|
|
|
|
* ScreenLines[off] Contains a copy of the whole screen, as it is currently
|
|
|
|
|
* displayed (excluding text written by external commands).
|
|
|
|
|
* ScreenAttrs[off] Contains the associated attributes.
|
2023-08-19 13:08:50 +02:00
|
|
|
* ScreenCols[off] Contains the virtual columns in the line. -1 means not
|
2024-03-17 19:44:30 +01:00
|
|
|
* available or before buffer text.
|
2022-07-09 04:56:24 +01:00
|
|
|
*
|
|
|
|
|
* LineOffset[row] Contains the offset into ScreenLines*[], ScreenAttrs[]
|
|
|
|
|
* and ScreenCols[] for each line.
|
2004-06-13 20:20:40 +00:00
|
|
|
* LineWraps[row] Flag for each line whether it wraps to the next line.
|
|
|
|
|
*
|
|
|
|
|
* For double-byte characters, two consecutive bytes in ScreenLines[] can form
|
|
|
|
|
* one character which occupies two display cells.
|
|
|
|
|
* For UTF-8 a multi-byte character is converted to Unicode and stored in
|
|
|
|
|
* ScreenLinesUC[]. ScreenLines[] contains the first byte only. For an ASCII
|
2010-03-23 15:36:35 +01:00
|
|
|
* character without composing chars ScreenLinesUC[] will be 0 and
|
|
|
|
|
* ScreenLinesC[][] is not used. When the character occupies two display
|
|
|
|
|
* cells the next byte in ScreenLines[] is 0.
|
2006-03-06 23:29:24 +00:00
|
|
|
* ScreenLinesC[][] contain up to 'maxcombine' composing characters
|
2010-03-23 15:36:35 +01:00
|
|
|
* (drawn on top of the first character). There is 0 after the last one used.
|
2004-06-13 20:20:40 +00:00
|
|
|
* ScreenLines2[] is only used for euc-jp to store the second byte if the
|
|
|
|
|
* first byte is 0x8e (single-width character).
|
|
|
|
|
*
|
|
|
|
|
* The screen_*() functions write to the screen and handle updating
|
|
|
|
|
* ScreenLines[].
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "vim.h"
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The attributes that are actually active for writing to the screen.
|
|
|
|
|
*/
|
|
|
|
|
static int screen_attr = 0;
|
|
|
|
|
|
2016-01-29 22:47:03 +01:00
|
|
|
static void screen_char_2(unsigned off, int row, int col);
|
2022-09-26 15:19:56 +01:00
|
|
|
static int screenclear2(int doclear);
|
2017-08-17 20:31:48 +02:00
|
|
|
static void lineclear(unsigned off, int width, int attr);
|
2016-01-29 22:47:03 +01:00
|
|
|
static void lineinvalid(unsigned off, int width);
|
2017-08-17 20:31:48 +02:00
|
|
|
static int win_do_lines(win_T *wp, int row, int line_count, int mayclear, int del, int clear_attr);
|
2016-01-29 22:47:03 +01:00
|
|
|
static void win_rest_invalid(win_T *wp);
|
|
|
|
|
static void msg_pos_mode(void);
|
|
|
|
|
static void recording_mode(int attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// Ugly global: overrule attribute used by screen_char()
|
2004-06-13 20:20:40 +00:00
|
|
|
static int screen_char_attr = 0;
|
|
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
#if defined(FEAT_CONCEAL) || defined(PROTO)
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
2019-09-19 23:06:20 +02:00
|
|
|
* Return TRUE if the cursor line in window "wp" may be concealed, according
|
|
|
|
|
* to the 'concealcursor' option.
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
2019-09-19 23:06:20 +02:00
|
|
|
int
|
|
|
|
|
conceal_cursor_line(win_T *wp)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-09-19 23:06:20 +02:00
|
|
|
int c;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
if (*wp->w_p_cocu == NUL)
|
|
|
|
|
return FALSE;
|
2022-05-07 20:01:16 +01:00
|
|
|
if (get_real_state() & MODE_VISUAL)
|
2019-09-19 23:06:20 +02:00
|
|
|
c = 'v';
|
2022-05-07 20:01:16 +01:00
|
|
|
else if (State & MODE_INSERT)
|
2019-09-19 23:06:20 +02:00
|
|
|
c = 'i';
|
2022-05-07 20:01:16 +01:00
|
|
|
else if (State & MODE_NORMAL)
|
2019-09-19 23:06:20 +02:00
|
|
|
c = 'n';
|
2022-05-07 20:01:16 +01:00
|
|
|
else if (State & MODE_CMDLINE)
|
2019-09-19 23:06:20 +02:00
|
|
|
c = 'c';
|
2006-04-11 21:38:50 +00:00
|
|
|
else
|
2019-09-19 23:06:20 +02:00
|
|
|
return FALSE;
|
|
|
|
|
return vim_strchr(wp->w_p_cocu, c) != NULL;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2019-09-19 23:06:20 +02:00
|
|
|
* Check if the cursor line needs to be redrawn because of 'concealcursor'.
|
2021-06-29 20:22:32 +02:00
|
|
|
* To be called after changing the state, "was_concealed" is the value of
|
|
|
|
|
* "conceal_cursor_line()" before the change.
|
|
|
|
|
* "
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
|
|
|
|
void
|
2021-06-29 20:22:32 +02:00
|
|
|
conceal_check_cursor_line(int was_concealed)
|
2017-04-30 19:39:39 +02:00
|
|
|
{
|
2023-01-23 20:46:21 +00:00
|
|
|
if (curwin->w_p_cole <= 0 || conceal_cursor_line(curwin) == was_concealed)
|
|
|
|
|
return;
|
2021-06-29 20:22:32 +02:00
|
|
|
|
2023-01-23 20:46:21 +00:00
|
|
|
int wcol = curwin->w_wcol;
|
2021-06-29 20:22:32 +02:00
|
|
|
|
2023-01-23 20:46:21 +00:00
|
|
|
need_cursor_line_redraw = TRUE;
|
|
|
|
|
// Need to recompute cursor column, e.g., when starting Visual mode
|
|
|
|
|
// without concealing.
|
|
|
|
|
curs_columns(TRUE);
|
|
|
|
|
|
|
|
|
|
// When concealing now w_wcol will be computed wrong, keep the previous
|
|
|
|
|
// value, it will be updated in win_line().
|
|
|
|
|
if (!was_concealed)
|
|
|
|
|
curwin->w_wcol = wcol;
|
2017-04-30 19:39:39 +02:00
|
|
|
}
|
2019-01-20 15:30:40 +01:00
|
|
|
#endif
|
2017-04-30 19:39:39 +02:00
|
|
|
|
2013-07-03 12:45:31 +02:00
|
|
|
/*
|
2019-09-19 23:06:20 +02:00
|
|
|
* Get 'wincolor' attribute for window "wp". If not set and "wp" is a popup
|
|
|
|
|
* window then get the "Pmenu" highlight attribute.
|
2013-07-03 12:45:31 +02:00
|
|
|
*/
|
|
|
|
|
int
|
2019-09-19 23:06:20 +02:00
|
|
|
get_wcr_attr(win_T *wp)
|
2016-03-15 23:10:59 +01:00
|
|
|
{
|
2019-09-19 23:06:20 +02:00
|
|
|
int wcr_attr = 0;
|
2018-08-26 21:23:07 +02:00
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
if (*wp->w_p_wcr != NUL)
|
|
|
|
|
wcr_attr = syn_name2attr(wp->w_p_wcr);
|
2019-11-30 22:48:27 +01:00
|
|
|
#ifdef FEAT_PROP_POPUP
|
2019-09-19 23:06:20 +02:00
|
|
|
else if (WIN_IS_POPUP(wp))
|
2016-03-19 17:05:20 +01:00
|
|
|
{
|
2019-09-19 23:06:20 +02:00
|
|
|
if (wp->w_popup_flags & POPF_INFO)
|
|
|
|
|
wcr_attr = HL_ATTR(HLF_PSI); // PmenuSel
|
|
|
|
|
else
|
|
|
|
|
wcr_attr = HL_ATTR(HLF_PNI); // Pmenu
|
2016-03-19 17:05:20 +01:00
|
|
|
}
|
2018-05-11 22:01:51 +02:00
|
|
|
#endif
|
2019-09-19 23:06:20 +02:00
|
|
|
return wcr_attr;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2019-09-19 23:06:20 +02:00
|
|
|
* Call screen_fill() with the columns adjusted for 'rightleft' if needed.
|
|
|
|
|
* Return the new offset.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
screen_fill_end(
|
|
|
|
|
win_T *wp,
|
|
|
|
|
int c1,
|
|
|
|
|
int c2,
|
|
|
|
|
int off,
|
|
|
|
|
int width,
|
|
|
|
|
int row,
|
|
|
|
|
int endrow,
|
|
|
|
|
int attr)
|
|
|
|
|
{
|
|
|
|
|
int nn = off + width;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
if (nn > wp->w_width)
|
|
|
|
|
nn = wp->w_width;
|
|
|
|
|
#ifdef FEAT_RIGHTLEFT
|
|
|
|
|
if (wp->w_p_rl)
|
|
|
|
|
{
|
|
|
|
|
screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
|
|
|
|
|
W_ENDCOL(wp) - nn, (int)W_ENDCOL(wp) - off,
|
|
|
|
|
c1, c2, attr);
|
|
|
|
|
}
|
|
|
|
|
else
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
2019-09-19 23:06:20 +02:00
|
|
|
screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
|
|
|
|
|
wp->w_wincol + off, (int)wp->w_wincol + nn,
|
|
|
|
|
c1, c2, attr);
|
|
|
|
|
return nn;
|
|
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
/*
|
|
|
|
|
* Clear lines near the end the window and mark the unused lines with "c1".
|
|
|
|
|
* use "c2" as the filler character.
|
|
|
|
|
* When "draw_margin" is TRUE then draw the sign, fold and number columns.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
win_draw_end(
|
|
|
|
|
win_T *wp,
|
|
|
|
|
int c1,
|
|
|
|
|
int c2,
|
|
|
|
|
int draw_margin,
|
|
|
|
|
int row,
|
|
|
|
|
int endrow,
|
|
|
|
|
hlf_T hl)
|
|
|
|
|
{
|
|
|
|
|
int n = 0;
|
|
|
|
|
int attr = HL_ATTR(hl);
|
|
|
|
|
int wcr_attr = get_wcr_attr(wp);
|
2006-03-12 22:05:10 +00:00
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
attr = hl_combine_attr(wcr_attr, attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
if (draw_margin)
|
|
|
|
|
{
|
|
|
|
|
#ifdef FEAT_FOLDING
|
|
|
|
|
int fdc = compute_foldcolumn(wp, 0);
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
if (fdc > 0)
|
|
|
|
|
// draw the fold column
|
|
|
|
|
n = screen_fill_end(wp, ' ', ' ', n, fdc,
|
|
|
|
|
row, endrow, hl_combine_attr(wcr_attr, HL_ATTR(HLF_FC)));
|
2010-06-05 23:22:07 +02:00
|
|
|
#endif
|
2019-09-19 23:06:20 +02:00
|
|
|
#ifdef FEAT_SIGNS
|
|
|
|
|
if (signcolumn_on(wp))
|
|
|
|
|
// draw the sign column
|
|
|
|
|
n = screen_fill_end(wp, ' ', ' ', n, 2,
|
|
|
|
|
row, endrow, hl_combine_attr(wcr_attr, HL_ATTR(HLF_SC)));
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
2019-09-19 23:06:20 +02:00
|
|
|
if ((wp->w_p_nu || wp->w_p_rnu)
|
|
|
|
|
&& vim_strchr(p_cpo, CPO_NUMCOL) == NULL)
|
|
|
|
|
// draw the number column
|
|
|
|
|
n = screen_fill_end(wp, ' ', ' ', n, number_width(wp) + 1,
|
|
|
|
|
row, endrow, hl_combine_attr(wcr_attr, HL_ATTR(HLF_N)));
|
|
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
#ifdef FEAT_RIGHTLEFT
|
|
|
|
|
if (wp->w_p_rl)
|
|
|
|
|
{
|
|
|
|
|
screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
|
|
|
|
|
wp->w_wincol, W_ENDCOL(wp) - 1 - n,
|
|
|
|
|
c2, c2, attr);
|
|
|
|
|
screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
|
|
|
|
|
W_ENDCOL(wp) - 1 - n, W_ENDCOL(wp) - n,
|
|
|
|
|
c1, c2, attr);
|
|
|
|
|
}
|
|
|
|
|
else
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
2019-09-19 23:06:20 +02:00
|
|
|
{
|
|
|
|
|
screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
|
|
|
|
|
wp->w_wincol + n, (int)W_ENDCOL(wp),
|
|
|
|
|
c1, c2, attr);
|
|
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
set_empty_rows(wp, row);
|
|
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
#if defined(FEAT_FOLDING) || defined(PROTO)
|
|
|
|
|
/*
|
|
|
|
|
* Compute the width of the foldcolumn. Based on 'foldcolumn' and how much
|
|
|
|
|
* space is available for window "wp", minus "col".
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
compute_foldcolumn(win_T *wp, int col)
|
|
|
|
|
{
|
|
|
|
|
int fdc = wp->w_p_fdc;
|
|
|
|
|
int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw;
|
|
|
|
|
int wwidth = wp->w_width;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
if (fdc > wwidth - (col + wmw))
|
|
|
|
|
fdc = wwidth - (col + wmw);
|
|
|
|
|
return fdc;
|
|
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
/*
|
|
|
|
|
* Fill the foldcolumn at "p" for window "wp".
|
|
|
|
|
* Only to be called when 'foldcolumn' > 0.
|
2021-03-03 13:26:02 +01:00
|
|
|
* Returns the number of bytes stored in 'p'. When non-multibyte characters are
|
|
|
|
|
* used for the fold column markers, this is equal to 'fdc' setting. Otherwise,
|
|
|
|
|
* this will be greater than 'fdc'.
|
2019-09-19 23:06:20 +02:00
|
|
|
*/
|
2021-03-03 13:26:02 +01:00
|
|
|
size_t
|
2019-09-19 23:06:20 +02:00
|
|
|
fill_foldcolumn(
|
|
|
|
|
char_u *p,
|
|
|
|
|
win_T *wp,
|
2019-12-05 21:10:38 +01:00
|
|
|
int closed, // TRUE of FALSE
|
|
|
|
|
linenr_T lnum) // current line number
|
2019-09-19 23:06:20 +02:00
|
|
|
{
|
|
|
|
|
int i = 0;
|
|
|
|
|
int level;
|
|
|
|
|
int first_level;
|
|
|
|
|
int empty;
|
|
|
|
|
int fdc = compute_foldcolumn(wp, 0);
|
2021-03-03 13:26:02 +01:00
|
|
|
size_t byte_counter = 0;
|
|
|
|
|
int symbol = 0;
|
|
|
|
|
int len = 0;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// Init to all spaces.
|
2021-03-03 13:26:02 +01:00
|
|
|
vim_memset(p, ' ', MAX_MCO * fdc + 1);
|
2019-09-19 23:06:20 +02:00
|
|
|
|
|
|
|
|
level = win_foldinfo.fi_level;
|
2021-03-03 13:26:02 +01:00
|
|
|
empty = (fdc == 1) ? 0 : 1;
|
|
|
|
|
|
|
|
|
|
// If the column is too narrow, we start at the lowest level that
|
2021-03-04 21:55:58 +01:00
|
|
|
// fits and use numbers to indicate the depth.
|
2021-03-03 13:26:02 +01:00
|
|
|
first_level = level - fdc - closed + 1 + empty;
|
|
|
|
|
if (first_level < 1)
|
|
|
|
|
first_level = 1;
|
2019-09-19 23:06:20 +02:00
|
|
|
|
2021-03-03 13:26:02 +01:00
|
|
|
for (i = 0; i < MIN(fdc, level); i++)
|
|
|
|
|
{
|
|
|
|
|
if (win_foldinfo.fi_lnum == lnum
|
|
|
|
|
&& first_level + i >= win_foldinfo.fi_low_level)
|
2022-07-04 17:34:33 +01:00
|
|
|
symbol = wp->w_fill_chars.foldopen;
|
2021-03-03 13:26:02 +01:00
|
|
|
else if (first_level == 1)
|
2022-07-04 17:34:33 +01:00
|
|
|
symbol = wp->w_fill_chars.foldsep;
|
2021-03-03 13:26:02 +01:00
|
|
|
else if (first_level + i <= 9)
|
|
|
|
|
symbol = '0' + first_level + i;
|
|
|
|
|
else
|
|
|
|
|
symbol = '>';
|
2019-09-19 23:06:20 +02:00
|
|
|
|
2021-03-03 13:26:02 +01:00
|
|
|
len = utf_char2bytes(symbol, &p[byte_counter]);
|
|
|
|
|
byte_counter += len;
|
|
|
|
|
if (first_level + i >= level)
|
2019-09-19 23:06:20 +02:00
|
|
|
{
|
2021-03-03 13:26:02 +01:00
|
|
|
i++;
|
|
|
|
|
break;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2005-07-02 23:19:16 +00:00
|
|
|
}
|
2021-03-03 13:26:02 +01:00
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
if (closed)
|
2021-03-03 13:26:02 +01:00
|
|
|
{
|
|
|
|
|
if (symbol != 0)
|
2021-03-21 14:39:19 +01:00
|
|
|
{
|
|
|
|
|
// rollback length and the character
|
2021-03-03 13:26:02 +01:00
|
|
|
byte_counter -= len;
|
2021-03-21 14:39:19 +01:00
|
|
|
if (len > 1)
|
|
|
|
|
// for a multibyte character, erase all the bytes
|
|
|
|
|
vim_memset(p + byte_counter, ' ', len);
|
|
|
|
|
}
|
2022-07-04 17:34:33 +01:00
|
|
|
symbol = wp->w_fill_chars.foldclosed;
|
2021-03-03 13:26:02 +01:00
|
|
|
len = utf_char2bytes(symbol, &p[byte_counter]);
|
|
|
|
|
byte_counter += len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return MAX(byte_counter + (fdc - i), (size_t)fdc);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2019-12-05 21:10:38 +01:00
|
|
|
#endif // FEAT_FOLDING
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2006-03-06 23:29:24 +00:00
|
|
|
/*
|
|
|
|
|
* Return if the composing characters at "off_from" and "off_to" differ.
|
2010-03-23 15:36:35 +01:00
|
|
|
* Only to be used when ScreenLinesUC[off_from] != 0.
|
2006-03-06 23:29:24 +00:00
|
|
|
*/
|
|
|
|
|
static int
|
2016-01-30 20:31:25 +01:00
|
|
|
comp_char_differs(int off_from, int off_to)
|
2006-03-06 23:29:24 +00:00
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < Screen_mco; ++i)
|
|
|
|
|
{
|
|
|
|
|
if (ScreenLinesC[i][off_from] != ScreenLinesC[i][off_to])
|
|
|
|
|
return TRUE;
|
|
|
|
|
if (ScreenLinesC[i][off_from] == 0)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
|
|
|
|
* Check whether the given character needs redrawing:
|
|
|
|
|
* - the (first byte of the) character is different
|
|
|
|
|
* - the attributes are different
|
|
|
|
|
* - the character is multi-byte and the next byte is different
|
2008-06-21 12:14:30 +00:00
|
|
|
* - the character is two cells wide and the second cell differs.
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
|
|
|
|
static int
|
2016-01-30 20:31:25 +01:00
|
|
|
char_needs_redraw(int off_from, int off_to, int cols)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
if (cols > 0
|
|
|
|
|
&& ((ScreenLines[off_from] != ScreenLines[off_to]
|
|
|
|
|
|| ScreenAttrs[off_from] != ScreenAttrs[off_to])
|
|
|
|
|
|| (enc_dbcs != 0
|
|
|
|
|
&& MB_BYTE2LEN(ScreenLines[off_from]) > 1
|
|
|
|
|
&& (enc_dbcs == DBCS_JPNU && ScreenLines[off_from] == 0x8e
|
|
|
|
|
? ScreenLines2[off_from] != ScreenLines2[off_to]
|
|
|
|
|
: (cols > 1 && ScreenLines[off_from + 1]
|
|
|
|
|
!= ScreenLines[off_to + 1])))
|
|
|
|
|
|| (enc_utf8
|
|
|
|
|
&& (ScreenLinesUC[off_from] != ScreenLinesUC[off_to]
|
|
|
|
|
|| (ScreenLinesUC[off_from] != 0
|
2008-06-21 12:14:30 +00:00
|
|
|
&& comp_char_differs(off_from, off_to))
|
2012-08-23 18:58:14 +02:00
|
|
|
|| ((*mb_off2cells)(off_from, off_from + cols) > 1
|
|
|
|
|
&& ScreenLines[off_from + 1]
|
2019-01-24 16:39:02 +01:00
|
|
|
!= ScreenLines[off_to + 1])))))
|
2004-06-13 20:20:40 +00:00
|
|
|
return TRUE;
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-16 13:48:22 +02:00
|
|
|
#if defined(FEAT_TERMINAL) || defined(PROTO)
|
|
|
|
|
/*
|
|
|
|
|
* Return the index in ScreenLines[] for the current screen line.
|
|
|
|
|
*/
|
|
|
|
|
int
|
2023-02-21 14:27:41 +00:00
|
|
|
screen_get_current_line_off(void)
|
2017-07-16 13:48:22 +02:00
|
|
|
{
|
|
|
|
|
return (int)(current_ScreenLine - ScreenLines);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2019-11-30 22:48:27 +01:00
|
|
|
#ifdef FEAT_PROP_POPUP
|
2019-06-23 00:15:57 +02:00
|
|
|
/*
|
|
|
|
|
* Return TRUE if this position has a higher level popup or this cell is
|
|
|
|
|
* transparent in the current popup.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
blocked_by_popup(int row, int col)
|
|
|
|
|
{
|
|
|
|
|
int off;
|
|
|
|
|
|
|
|
|
|
if (!popup_visible)
|
|
|
|
|
return FALSE;
|
|
|
|
|
off = row * screen_Columns + col;
|
|
|
|
|
return popup_mask[off] > screen_zindex || popup_transparent[off];
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
/*
|
|
|
|
|
* Reset the highlighting. Used before clearing the screen.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
reset_screen_attr(void)
|
|
|
|
|
{
|
|
|
|
|
#ifdef FEAT_GUI
|
|
|
|
|
if (gui.in_use)
|
|
|
|
|
// Use a code that will reset gui.highlight_mask in
|
|
|
|
|
// gui_stop_highlight().
|
|
|
|
|
screen_attr = HL_ALL + 1;
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
// Use attributes that is very unlikely to appear in text.
|
|
|
|
|
screen_attr = HL_BOLD | HL_UNDERLINE | HL_INVERSE | HL_STRIKETHROUGH;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-02 14:28:30 +01:00
|
|
|
/*
|
|
|
|
|
* Return TRUE if the character at "row" / "col" is under the popup menu and it
|
|
|
|
|
* will be redrawn soon or it is under another popup.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
skip_for_popup(int row, int col)
|
|
|
|
|
{
|
|
|
|
|
// Popup windows with zindex higher than POPUPMENU_ZINDEX go on top.
|
|
|
|
|
if (pum_under_menu(row, col, TRUE)
|
|
|
|
|
#ifdef FEAT_PROP_POPUP
|
|
|
|
|
&& screen_zindex <= POPUPMENU_ZINDEX
|
|
|
|
|
#endif
|
|
|
|
|
)
|
|
|
|
|
return TRUE;
|
|
|
|
|
#ifdef FEAT_PROP_POPUP
|
|
|
|
|
if (blocked_by_popup(row, col))
|
|
|
|
|
return TRUE;
|
|
|
|
|
#endif
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
|
|
|
|
* Move one "cooked" screen line to the screen, but only the characters that
|
|
|
|
|
* have actually changed. Handle insert/delete character.
|
|
|
|
|
* "coloff" gives the first column on the screen for this line.
|
|
|
|
|
* "endcol" gives the columns where valid characters are.
|
|
|
|
|
* "clear_width" is the width of the window. It's > 0 if the rest of the line
|
|
|
|
|
* needs to be cleared, negative otherwise.
|
2019-05-25 19:51:39 +02:00
|
|
|
* "flags" can have bits:
|
|
|
|
|
* SLF_POPUP popup window
|
|
|
|
|
* SLF_RIGHTLEFT rightleft window:
|
2004-06-13 20:20:40 +00:00
|
|
|
* When TRUE and "clear_width" > 0, clear columns 0 to "endcol"
|
|
|
|
|
* When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width"
|
2024-03-16 15:03:33 +01:00
|
|
|
* SLF_INC_VCOL:
|
|
|
|
|
* When FALSE, use "last_vcol" for ScreenCols[] of the columns to clear.
|
|
|
|
|
* When TRUE, use an increasing sequence starting from "last_vcol + 1" for
|
|
|
|
|
* ScreenCols[] of the columns to clear.
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
2017-07-16 13:48:22 +02:00
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
screen_line(
|
2022-07-04 17:34:33 +01:00
|
|
|
win_T *wp,
|
|
|
|
|
int row,
|
|
|
|
|
int coloff,
|
|
|
|
|
int endcol,
|
|
|
|
|
int clear_width,
|
2024-03-16 15:03:33 +01:00
|
|
|
colnr_T last_vcol,
|
2022-07-04 17:34:33 +01:00
|
|
|
int flags UNUSED)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
unsigned off_from;
|
|
|
|
|
unsigned off_to;
|
2007-08-30 11:53:22 +00:00
|
|
|
unsigned max_off_from;
|
|
|
|
|
unsigned max_off_to;
|
2004-06-13 20:20:40 +00:00
|
|
|
int col = 0;
|
|
|
|
|
int hl;
|
2019-12-05 21:10:38 +01:00
|
|
|
int force = FALSE; // force update rest of the line
|
|
|
|
|
int redraw_this // bool: does character need redraw?
|
2004-06-13 20:20:40 +00:00
|
|
|
#ifdef FEAT_GUI
|
2019-12-05 21:10:38 +01:00
|
|
|
= TRUE // For GUI when while-loop empty
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
|
|
|
|
;
|
2019-12-05 21:10:38 +01:00
|
|
|
int redraw_next; // redraw_this for next character
|
2022-10-11 12:48:44 +01:00
|
|
|
#ifdef FEAT_GUI_MSWIN
|
|
|
|
|
int changed_this; // TRUE if character changed
|
|
|
|
|
int changed_next; // TRUE if next character changed
|
|
|
|
|
#endif
|
2004-06-13 20:20:40 +00:00
|
|
|
int clear_next = FALSE;
|
2019-12-05 21:10:38 +01:00
|
|
|
int char_cells; // 1: normal char
|
|
|
|
|
// 2: occupies two display cells
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// Check for illegal row and col, just in case.
|
2012-03-16 19:07:58 +01:00
|
|
|
if (row >= Rows)
|
|
|
|
|
row = Rows - 1;
|
|
|
|
|
if (endcol > Columns)
|
|
|
|
|
endcol = Columns;
|
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
# ifdef FEAT_CLIPBOARD
|
|
|
|
|
clip_may_clear_selection(row, row);
|
|
|
|
|
# endif
|
|
|
|
|
|
|
|
|
|
off_from = (unsigned)(current_ScreenLine - ScreenLines);
|
|
|
|
|
off_to = LineOffset[row] + coloff;
|
2007-08-30 11:53:22 +00:00
|
|
|
max_off_from = off_from + screen_Columns;
|
|
|
|
|
max_off_to = LineOffset[row] + screen_Columns;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
|
#ifdef FEAT_RIGHTLEFT
|
2019-05-25 19:51:39 +02:00
|
|
|
if (flags & SLF_RIGHTLEFT)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
// Clear rest first, because it's left of the text.
|
2004-06-13 20:20:40 +00:00
|
|
|
if (clear_width > 0)
|
|
|
|
|
{
|
2024-03-17 19:44:30 +01:00
|
|
|
int clear_start = col;
|
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
while (col <= endcol && ScreenLines[off_to] == ' '
|
|
|
|
|
&& ScreenAttrs[off_to] == 0
|
2019-01-24 16:39:02 +01:00
|
|
|
&& (!enc_utf8 || ScreenLinesUC[off_to] == 0))
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
++off_to;
|
|
|
|
|
++col;
|
|
|
|
|
}
|
|
|
|
|
if (col <= endcol)
|
|
|
|
|
screen_fill(row, row + 1, col + coloff,
|
|
|
|
|
endcol + coloff + 1, ' ', ' ', 0);
|
2024-03-17 19:44:30 +01:00
|
|
|
|
|
|
|
|
for (int i = endcol; i >= clear_start; i--)
|
|
|
|
|
ScreenCols[off_to + (i - col)] =
|
|
|
|
|
(flags & SLF_INC_VCOL) ? ++last_vcol : last_vcol;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
col = endcol + 1;
|
|
|
|
|
off_to = LineOffset[row] + col + coloff;
|
|
|
|
|
off_from += col;
|
|
|
|
|
endcol = (clear_width > 0 ? clear_width : -clear_width);
|
|
|
|
|
}
|
2019-12-05 21:10:38 +01:00
|
|
|
#endif // FEAT_RIGHTLEFT
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-11-30 22:48:27 +01:00
|
|
|
#ifdef FEAT_PROP_POPUP
|
2019-11-26 22:39:10 +01:00
|
|
|
// First char of a popup window may go on top of the right half of a
|
|
|
|
|
// double-wide character. Clear the left half to avoid it getting the popup
|
|
|
|
|
// window background color.
|
2020-11-06 17:58:35 +01:00
|
|
|
if (coloff > 0 && enc_utf8
|
|
|
|
|
&& ScreenLines[off_to] == 0
|
2020-08-23 15:09:36 +02:00
|
|
|
&& ScreenLinesUC[off_to - 1] != 0
|
|
|
|
|
&& (*mb_char2cells)(ScreenLinesUC[off_to - 1]) > 1)
|
2019-11-26 22:39:10 +01:00
|
|
|
{
|
|
|
|
|
ScreenLines[off_to - 1] = ' ';
|
|
|
|
|
ScreenLinesUC[off_to - 1] = 0;
|
|
|
|
|
screen_char(off_to - 1, row, col + coloff - 1);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
redraw_next = char_needs_redraw(off_from, off_to, endcol - col);
|
2022-10-11 12:48:44 +01:00
|
|
|
#ifdef FEAT_GUI_MSWIN
|
|
|
|
|
changed_next = redraw_next;
|
|
|
|
|
#endif
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
|
while (col < endcol)
|
|
|
|
|
{
|
|
|
|
|
if (has_mbyte && (col + 1 < endcol))
|
2007-08-30 11:53:22 +00:00
|
|
|
char_cells = (*mb_off2cells)(off_from, max_off_from);
|
2004-06-13 20:20:40 +00:00
|
|
|
else
|
|
|
|
|
char_cells = 1;
|
|
|
|
|
|
|
|
|
|
redraw_this = redraw_next;
|
2022-07-09 04:56:24 +01:00
|
|
|
redraw_next = force || char_needs_redraw(off_from + char_cells,
|
|
|
|
|
off_to + char_cells, endcol - col - char_cells);
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
|
#ifdef FEAT_GUI
|
2022-10-11 12:48:44 +01:00
|
|
|
# ifdef FEAT_GUI_MSWIN
|
|
|
|
|
changed_this = changed_next;
|
|
|
|
|
changed_next = redraw_next;
|
|
|
|
|
# endif
|
2019-12-05 21:10:38 +01:00
|
|
|
// If the next character was bold, then redraw the current character to
|
|
|
|
|
// remove any pixels that might have spilt over into us. This only
|
|
|
|
|
// happens in the GUI.
|
2022-10-11 12:48:44 +01:00
|
|
|
// With MS-Windows antialiasing may also cause pixels to spill over
|
|
|
|
|
// from a previous character, no matter attributes, always redraw if a
|
|
|
|
|
// character changed.
|
2004-06-13 20:20:40 +00:00
|
|
|
if (redraw_next && gui.in_use)
|
|
|
|
|
{
|
2022-10-11 12:48:44 +01:00
|
|
|
# ifndef FEAT_GUI_MSWIN
|
2022-07-09 04:56:24 +01:00
|
|
|
hl = ScreenAttrs[off_to + char_cells];
|
2006-03-12 22:05:10 +00:00
|
|
|
if (hl > HL_ALL)
|
|
|
|
|
hl = syn_attr2attr(hl);
|
|
|
|
|
if (hl & HL_BOLD)
|
2022-10-11 12:48:44 +01:00
|
|
|
# endif
|
2004-06-13 20:20:40 +00:00
|
|
|
redraw_this = TRUE;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2022-10-02 14:28:30 +01:00
|
|
|
// Do not redraw if under the popup menu.
|
|
|
|
|
if (redraw_this && skip_for_popup(row, col + coloff))
|
2019-06-08 16:01:13 +02:00
|
|
|
redraw_this = FALSE;
|
2022-10-02 14:28:30 +01:00
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
if (redraw_this)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Special handling when 'xs' termcap flag set (hpterm):
|
|
|
|
|
* Attributes for characters are stored at the position where the
|
|
|
|
|
* cursor is when writing the highlighting code. The
|
|
|
|
|
* start-highlighting code must be written with the cursor on the
|
|
|
|
|
* first highlighted character. The stop-highlighting code must
|
|
|
|
|
* be written with the cursor just after the last highlighted
|
|
|
|
|
* character.
|
2018-11-16 16:21:05 +01:00
|
|
|
* Overwriting a character doesn't remove its highlighting. Need
|
2004-06-13 20:20:40 +00:00
|
|
|
* to clear the rest of the line, and force redrawing it
|
|
|
|
|
* completely.
|
|
|
|
|
*/
|
|
|
|
|
if ( p_wiv
|
|
|
|
|
&& !force
|
|
|
|
|
#ifdef FEAT_GUI
|
|
|
|
|
&& !gui.in_use
|
|
|
|
|
#endif
|
|
|
|
|
&& ScreenAttrs[off_to] != 0
|
|
|
|
|
&& ScreenAttrs[off_from] != ScreenAttrs[off_to])
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Need to remove highlighting attributes here.
|
|
|
|
|
*/
|
|
|
|
|
windgoto(row, col + coloff);
|
2019-12-05 21:10:38 +01:00
|
|
|
out_str(T_CE); // clear rest of this screen line
|
|
|
|
|
screen_start(); // don't know where cursor is now
|
|
|
|
|
force = TRUE; // force redraw of rest of the line
|
|
|
|
|
redraw_next = TRUE; // or else next char would miss out
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the previous character was highlighted, need to stop
|
|
|
|
|
* highlighting at this character.
|
|
|
|
|
*/
|
|
|
|
|
if (col + coloff > 0 && ScreenAttrs[off_to - 1] != 0)
|
|
|
|
|
{
|
|
|
|
|
screen_attr = ScreenAttrs[off_to - 1];
|
|
|
|
|
term_windgoto(row, col + coloff);
|
|
|
|
|
screen_stop_highlight();
|
|
|
|
|
}
|
|
|
|
|
else
|
2019-12-05 21:10:38 +01:00
|
|
|
screen_attr = 0; // highlighting has stopped
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
if (enc_dbcs != 0)
|
|
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
// Check if overwriting a double-byte with a single-byte or
|
|
|
|
|
// the other way around requires another character to be
|
|
|
|
|
// redrawn. For UTF-8 this isn't needed, because comparing
|
|
|
|
|
// ScreenLinesUC[] is sufficient.
|
2004-06-13 20:20:40 +00:00
|
|
|
if (char_cells == 1
|
|
|
|
|
&& col + 1 < endcol
|
2007-08-30 11:53:22 +00:00
|
|
|
&& (*mb_off2cells)(off_to, max_off_to) > 1)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
// Writing a single-cell character over a double-cell
|
|
|
|
|
// character: need to redraw the next cell.
|
2004-06-13 20:20:40 +00:00
|
|
|
ScreenLines[off_to + 1] = 0;
|
|
|
|
|
redraw_next = TRUE;
|
|
|
|
|
}
|
|
|
|
|
else if (char_cells == 2
|
|
|
|
|
&& col + 2 < endcol
|
2007-08-30 11:53:22 +00:00
|
|
|
&& (*mb_off2cells)(off_to, max_off_to) == 1
|
|
|
|
|
&& (*mb_off2cells)(off_to + 1, max_off_to) > 1)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
// Writing the second half of a double-cell character over
|
|
|
|
|
// a double-cell character: need to redraw the second
|
|
|
|
|
// cell.
|
2004-06-13 20:20:40 +00:00
|
|
|
ScreenLines[off_to + 2] = 0;
|
|
|
|
|
redraw_next = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (enc_dbcs == DBCS_JPNU)
|
|
|
|
|
ScreenLines2[off_to] = ScreenLines2[off_from];
|
|
|
|
|
}
|
2019-12-05 21:10:38 +01:00
|
|
|
// When writing a single-width character over a double-width
|
|
|
|
|
// character and at the end of the redrawn text, need to clear out
|
2021-12-27 17:21:41 +00:00
|
|
|
// the right half of the old character.
|
|
|
|
|
// Also required when writing the right half of a double-width
|
|
|
|
|
// char over the left half of an existing one.
|
2004-06-13 20:20:40 +00:00
|
|
|
if (has_mbyte && col + char_cells == endcol
|
|
|
|
|
&& ((char_cells == 1
|
2007-08-30 11:53:22 +00:00
|
|
|
&& (*mb_off2cells)(off_to, max_off_to) > 1)
|
2004-06-13 20:20:40 +00:00
|
|
|
|| (char_cells == 2
|
2007-08-30 11:53:22 +00:00
|
|
|
&& (*mb_off2cells)(off_to, max_off_to) == 1
|
|
|
|
|
&& (*mb_off2cells)(off_to + 1, max_off_to) > 1)))
|
2004-06-13 20:20:40 +00:00
|
|
|
clear_next = TRUE;
|
|
|
|
|
|
|
|
|
|
ScreenLines[off_to] = ScreenLines[off_from];
|
|
|
|
|
if (enc_utf8)
|
|
|
|
|
{
|
|
|
|
|
ScreenLinesUC[off_to] = ScreenLinesUC[off_from];
|
|
|
|
|
if (ScreenLinesUC[off_from] != 0)
|
|
|
|
|
{
|
2006-03-06 23:29:24 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < Screen_mco; ++i)
|
|
|
|
|
ScreenLinesC[i][off_to] = ScreenLinesC[i][off_from];
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (char_cells == 2)
|
|
|
|
|
ScreenLines[off_to + 1] = ScreenLines[off_from + 1];
|
|
|
|
|
|
|
|
|
|
#if defined(FEAT_GUI) || defined(UNIX)
|
2019-12-05 21:10:38 +01:00
|
|
|
// The bold trick makes a single column of pixels appear in the
|
|
|
|
|
// next character. When a bold character is removed, the next
|
|
|
|
|
// character should be redrawn too. This happens for our own GUI
|
|
|
|
|
// and for some xterms.
|
2004-06-13 20:20:40 +00:00
|
|
|
if (
|
|
|
|
|
# ifdef FEAT_GUI
|
|
|
|
|
gui.in_use
|
|
|
|
|
# endif
|
|
|
|
|
# if defined(FEAT_GUI) && defined(UNIX)
|
|
|
|
|
||
|
|
|
|
|
# endif
|
|
|
|
|
# ifdef UNIX
|
|
|
|
|
term_is_xterm
|
|
|
|
|
# endif
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
hl = ScreenAttrs[off_to];
|
2006-03-12 22:05:10 +00:00
|
|
|
if (hl > HL_ALL)
|
|
|
|
|
hl = syn_attr2attr(hl);
|
|
|
|
|
if (hl & HL_BOLD)
|
2004-06-13 20:20:40 +00:00
|
|
|
redraw_next = TRUE;
|
|
|
|
|
}
|
2022-10-11 12:48:44 +01:00
|
|
|
#endif
|
|
|
|
|
#ifdef FEAT_GUI_MSWIN
|
|
|
|
|
// MS-Windows antialiasing may spill over to the next character,
|
|
|
|
|
// redraw that one if this one changed, no matter attributes.
|
|
|
|
|
if (gui.in_use && changed_this)
|
|
|
|
|
redraw_next = TRUE;
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
|
|
|
|
ScreenAttrs[off_to] = ScreenAttrs[off_from];
|
2019-01-24 16:39:02 +01:00
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// For simplicity set the attributes of second half of a
|
|
|
|
|
// double-wide character equal to the first half.
|
2006-04-05 20:41:53 +00:00
|
|
|
if (char_cells == 2)
|
2004-06-13 20:20:40 +00:00
|
|
|
ScreenAttrs[off_to + 1] = ScreenAttrs[off_from];
|
2006-04-05 20:41:53 +00:00
|
|
|
|
|
|
|
|
if (enc_dbcs != 0 && char_cells == 2)
|
2004-06-13 20:20:40 +00:00
|
|
|
screen_char_2(off_to, row, col + coloff);
|
|
|
|
|
else
|
|
|
|
|
screen_char(off_to, row, col + coloff);
|
|
|
|
|
}
|
|
|
|
|
else if ( p_wiv
|
|
|
|
|
#ifdef FEAT_GUI
|
|
|
|
|
&& !gui.in_use
|
|
|
|
|
#endif
|
|
|
|
|
&& col + coloff > 0)
|
|
|
|
|
{
|
|
|
|
|
if (ScreenAttrs[off_to] == ScreenAttrs[off_to - 1])
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Don't output stop-highlight when moving the cursor, it will
|
|
|
|
|
* stop the highlighting when it should continue.
|
|
|
|
|
*/
|
|
|
|
|
screen_attr = 0;
|
|
|
|
|
}
|
|
|
|
|
else if (screen_attr != 0)
|
|
|
|
|
screen_stop_highlight();
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-09 04:56:24 +01:00
|
|
|
ScreenCols[off_to] = ScreenCols[off_from];
|
|
|
|
|
if (char_cells == 2)
|
2023-08-19 13:08:50 +02:00
|
|
|
ScreenCols[off_to + 1] = ScreenCols[off_from + 1];
|
2022-07-09 04:56:24 +01:00
|
|
|
|
|
|
|
|
off_to += char_cells;
|
|
|
|
|
off_from += char_cells;
|
|
|
|
|
col += char_cells;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
2022-10-02 15:21:04 +01:00
|
|
|
if (clear_next && !skip_for_popup(row, col + coloff))
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
// Clear the second half of a double-wide character of which the left
|
|
|
|
|
// half was overwritten with a single-wide character.
|
2004-06-13 20:20:40 +00:00
|
|
|
ScreenLines[off_to] = ' ';
|
|
|
|
|
if (enc_utf8)
|
|
|
|
|
ScreenLinesUC[off_to] = 0;
|
|
|
|
|
screen_char(off_to, row, col + coloff);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (clear_width > 0
|
|
|
|
|
#ifdef FEAT_RIGHTLEFT
|
2019-05-25 19:51:39 +02:00
|
|
|
&& !(flags & SLF_RIGHTLEFT)
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
#ifdef FEAT_GUI
|
|
|
|
|
int startCol = col;
|
|
|
|
|
#endif
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// blank out the rest of the line
|
2004-06-13 20:20:40 +00:00
|
|
|
while (col < clear_width && ScreenLines[off_to] == ' '
|
|
|
|
|
&& ScreenAttrs[off_to] == 0
|
2019-01-24 16:39:02 +01:00
|
|
|
&& (!enc_utf8 || ScreenLinesUC[off_to] == 0))
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2024-03-16 15:03:33 +01:00
|
|
|
ScreenCols[off_to] =
|
|
|
|
|
(flags & SLF_INC_VCOL) ? ++last_vcol : last_vcol;
|
2004-06-13 20:20:40 +00:00
|
|
|
++off_to;
|
|
|
|
|
++col;
|
|
|
|
|
}
|
|
|
|
|
if (col < clear_width)
|
|
|
|
|
{
|
|
|
|
|
#ifdef FEAT_GUI
|
|
|
|
|
/*
|
|
|
|
|
* In the GUI, clearing the rest of the line may leave pixels
|
|
|
|
|
* behind if the first character cleared was bold. Some bold
|
|
|
|
|
* fonts spill over the left. In this case we redraw the previous
|
|
|
|
|
* character too. If we didn't skip any blanks above, then we
|
|
|
|
|
* only redraw if the character wasn't already redrawn anyway.
|
|
|
|
|
*/
|
2006-10-09 20:11:17 +00:00
|
|
|
if (gui.in_use && (col > startCol || !redraw_this))
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
hl = ScreenAttrs[off_to];
|
|
|
|
|
if (hl > HL_ALL || (hl & HL_BOLD))
|
2006-10-09 20:11:17 +00:00
|
|
|
{
|
|
|
|
|
int prev_cells = 1;
|
2019-01-24 16:39:02 +01:00
|
|
|
|
2006-10-09 20:11:17 +00:00
|
|
|
if (enc_utf8)
|
2019-12-05 21:10:38 +01:00
|
|
|
// for utf-8, ScreenLines[char_offset + 1] == 0 means
|
|
|
|
|
// that its width is 2.
|
2006-10-09 20:11:17 +00:00
|
|
|
prev_cells = ScreenLines[off_to - 1] == 0 ? 2 : 1;
|
|
|
|
|
else if (enc_dbcs != 0)
|
|
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
// find previous character by counting from first
|
|
|
|
|
// column and get its width.
|
2006-10-09 20:11:17 +00:00
|
|
|
unsigned off = LineOffset[row];
|
2007-08-30 11:53:22 +00:00
|
|
|
unsigned max_off = LineOffset[row] + screen_Columns;
|
2006-10-09 20:11:17 +00:00
|
|
|
|
|
|
|
|
while (off < off_to)
|
|
|
|
|
{
|
2007-08-30 11:53:22 +00:00
|
|
|
prev_cells = (*mb_off2cells)(off, max_off);
|
2006-10-09 20:11:17 +00:00
|
|
|
off += prev_cells;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-02 15:21:04 +01:00
|
|
|
if (!skip_for_popup(row, col + coloff - prev_cells))
|
|
|
|
|
{
|
|
|
|
|
if (enc_dbcs != 0 && prev_cells > 1)
|
|
|
|
|
screen_char_2(off_to - prev_cells, row,
|
2006-10-09 20:11:17 +00:00
|
|
|
col + coloff - prev_cells);
|
2022-10-02 15:21:04 +01:00
|
|
|
else
|
|
|
|
|
screen_char(off_to - prev_cells, row,
|
2006-10-09 20:11:17 +00:00
|
|
|
col + coloff - prev_cells);
|
2022-10-02 15:21:04 +01:00
|
|
|
}
|
2006-10-09 20:11:17 +00:00
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
screen_fill(row, row + 1, col + coloff, clear_width + coloff,
|
|
|
|
|
' ', ' ', 0);
|
2022-07-09 04:56:24 +01:00
|
|
|
while (col < clear_width)
|
|
|
|
|
{
|
2024-03-16 15:03:33 +01:00
|
|
|
ScreenCols[off_to++]
|
|
|
|
|
= (flags & SLF_INC_VCOL) ? ++last_vcol : last_vcol;
|
2022-07-09 04:56:24 +01:00
|
|
|
++col;
|
|
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-25 19:51:39 +02:00
|
|
|
if (clear_width > 0
|
2019-11-30 22:48:27 +01:00
|
|
|
#ifdef FEAT_PROP_POPUP
|
2019-05-25 19:51:39 +02:00
|
|
|
&& !(flags & SLF_POPUP) // no separator for popup window
|
|
|
|
|
#endif
|
|
|
|
|
)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-05-25 19:51:39 +02:00
|
|
|
// For a window that has a right neighbor, draw the separator char
|
2019-06-08 17:25:33 +02:00
|
|
|
// right of the window contents. But not on top of a popup window.
|
2019-05-25 19:51:39 +02:00
|
|
|
if (coloff + col < Columns)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2022-10-02 15:21:04 +01:00
|
|
|
if (!skip_for_popup(row, col + coloff))
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-06-08 17:25:33 +02:00
|
|
|
int c;
|
|
|
|
|
|
2022-07-04 17:34:33 +01:00
|
|
|
c = fillchar_vsep(&hl, wp);
|
2019-06-08 17:25:33 +02:00
|
|
|
if (ScreenLines[off_to] != (schar_T)c
|
|
|
|
|
|| (enc_utf8 && (int)ScreenLinesUC[off_to]
|
|
|
|
|
!= (c >= 0x80 ? c : 0))
|
|
|
|
|
|| ScreenAttrs[off_to] != hl)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-06-08 17:25:33 +02:00
|
|
|
ScreenLines[off_to] = c;
|
|
|
|
|
ScreenAttrs[off_to] = hl;
|
|
|
|
|
if (enc_utf8)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-09-19 23:06:20 +02:00
|
|
|
if (c >= 0x80)
|
|
|
|
|
{
|
|
|
|
|
ScreenLinesUC[off_to] = c;
|
|
|
|
|
ScreenLinesC[0][off_to] = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
ScreenLinesUC[off_to] = 0;
|
|
|
|
|
}
|
|
|
|
|
screen_char(off_to, row, col + coloff);
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2019-09-19 23:06:20 +02:00
|
|
|
else
|
|
|
|
|
LineWraps[row] = FALSE;
|
|
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
#if defined(FEAT_RIGHTLEFT) || defined(PROTO)
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
2019-09-19 23:06:20 +02:00
|
|
|
* Mirror text "str" for right-left displaying.
|
|
|
|
|
* Only works for single-byte characters (e.g., numbers).
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
|
|
|
|
void
|
2019-09-19 23:06:20 +02:00
|
|
|
rl_mirror(char_u *str)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-09-19 23:06:20 +02:00
|
|
|
char_u *p1, *p2;
|
|
|
|
|
int t;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
for (p1 = str, p2 = str + STRLEN(str) - 1; p1 < p2; ++p1, --p2)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-09-19 23:06:20 +02:00
|
|
|
t = *p1;
|
|
|
|
|
*p1 = *p2;
|
|
|
|
|
*p2 = t;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Draw the verticap separator right of window "wp" starting with line "row".
|
|
|
|
|
*/
|
2019-09-19 23:06:20 +02:00
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
draw_vsep_win(win_T *wp, int row)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
int hl;
|
|
|
|
|
int c;
|
|
|
|
|
|
2023-01-23 20:46:21 +00:00
|
|
|
if (!wp->w_vsep_width)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// draw the vertical separator right of this window
|
|
|
|
|
c = fillchar_vsep(&hl, wp);
|
|
|
|
|
screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
|
|
|
|
|
W_ENDCOL(wp), W_ENDCOL(wp) + 1,
|
|
|
|
|
c, ' ', hl);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Return TRUE if the status line of window "wp" is connected to the status
|
|
|
|
|
* line of the window right of it. If not, then it's a vertical separator.
|
|
|
|
|
* Only call if (wp->w_vsep_width != 0).
|
|
|
|
|
*/
|
|
|
|
|
int
|
2016-01-30 20:31:25 +01:00
|
|
|
stl_connected(win_T *wp)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
frame_T *fr;
|
|
|
|
|
|
|
|
|
|
fr = wp->w_frame;
|
|
|
|
|
while (fr->fr_parent != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (fr->fr_parent->fr_layout == FR_COL)
|
|
|
|
|
{
|
|
|
|
|
if (fr->fr_next != NULL)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (fr->fr_next != NULL)
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
fr = fr->fr_parent;
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Get the value to show for the language mappings, active 'keymap'.
|
|
|
|
|
*/
|
|
|
|
|
int
|
2016-01-30 20:31:25 +01:00
|
|
|
get_keymap_str(
|
|
|
|
|
win_T *wp,
|
2019-12-05 21:10:38 +01:00
|
|
|
char_u *fmt, // format string containing one %s item
|
|
|
|
|
char_u *buf, // buffer for the result
|
|
|
|
|
int len) // length of buffer
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
char_u *p;
|
|
|
|
|
|
|
|
|
|
if (wp->w_buffer->b_p_iminsert != B_IMODE_LMAP)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
#ifdef FEAT_EVAL
|
2023-01-23 20:46:21 +00:00
|
|
|
buf_T *old_curbuf = curbuf;
|
|
|
|
|
win_T *old_curwin = curwin;
|
|
|
|
|
char_u *s;
|
|
|
|
|
|
|
|
|
|
curbuf = wp->w_buffer;
|
|
|
|
|
curwin = wp;
|
|
|
|
|
STRCPY(buf, "b:keymap_name"); // must be writable
|
|
|
|
|
++emsg_skip;
|
|
|
|
|
s = p = eval_to_string(buf, FALSE, FALSE);
|
|
|
|
|
--emsg_skip;
|
|
|
|
|
curbuf = old_curbuf;
|
|
|
|
|
curwin = old_curwin;
|
|
|
|
|
if (p == NULL || *p == NUL)
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
2023-01-23 20:46:21 +00:00
|
|
|
{
|
2004-06-13 20:20:40 +00:00
|
|
|
#ifdef FEAT_KEYMAP
|
2023-01-23 20:46:21 +00:00
|
|
|
if (wp->w_buffer->b_kmap_state & KEYMAP_LOADED)
|
|
|
|
|
p = wp->w_buffer->b_p_keymap;
|
|
|
|
|
else
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
2023-01-23 20:46:21 +00:00
|
|
|
p = (char_u *)"lang";
|
|
|
|
|
}
|
|
|
|
|
if (vim_snprintf((char *)buf, len, (char *)fmt, p) > len - 1)
|
|
|
|
|
buf[0] = NUL;
|
2004-06-13 20:20:40 +00:00
|
|
|
#ifdef FEAT_EVAL
|
2023-01-23 20:46:21 +00:00
|
|
|
vim_free(s);
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
|
|
|
|
return buf[0] != NUL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if defined(FEAT_STL_OPT) || defined(PROTO)
|
|
|
|
|
/*
|
2006-02-20 21:37:40 +00:00
|
|
|
* Redraw the status line or ruler of window "wp".
|
|
|
|
|
* When "wp" is NULL redraw the tab pages line from 'tabline'.
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
2019-09-19 23:06:20 +02:00
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
win_redr_custom(
|
|
|
|
|
win_T *wp,
|
2019-09-19 23:06:20 +02:00
|
|
|
int draw_ruler) // TRUE or FALSE
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2013-12-11 15:52:01 +01:00
|
|
|
static int entered = FALSE;
|
2004-06-13 20:20:40 +00:00
|
|
|
int attr;
|
|
|
|
|
int curattr;
|
|
|
|
|
int row;
|
|
|
|
|
int col = 0;
|
|
|
|
|
int maxwidth;
|
|
|
|
|
int width;
|
|
|
|
|
int n;
|
|
|
|
|
int len;
|
|
|
|
|
int fillchar;
|
|
|
|
|
char_u buf[MAXPATHL];
|
2009-11-03 16:20:34 +00:00
|
|
|
char_u *stl;
|
2004-06-13 20:20:40 +00:00
|
|
|
char_u *p;
|
2022-11-07 12:16:51 +00:00
|
|
|
char_u *opt_name;
|
2022-11-24 00:09:02 +00:00
|
|
|
int opt_scope = 0;
|
2020-10-26 21:05:27 +01:00
|
|
|
stl_hlrec_T *hltab;
|
|
|
|
|
stl_hlrec_T *tabtab;
|
2011-02-01 18:01:11 +01:00
|
|
|
win_T *ewp;
|
|
|
|
|
int p_crb_save;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
// There is a tiny chance that this gets called recursively: When
|
|
|
|
|
// redrawing a status line triggers redrawing the ruler or tabline.
|
|
|
|
|
// Avoid trouble by not allowing recursion.
|
2013-12-11 15:52:01 +01:00
|
|
|
if (entered)
|
|
|
|
|
return;
|
|
|
|
|
entered = TRUE;
|
|
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
// setup environment for the task at hand
|
2006-02-20 21:37:40 +00:00
|
|
|
if (wp == NULL)
|
|
|
|
|
{
|
2019-09-19 23:06:20 +02:00
|
|
|
// Use 'tabline'. Always at the first line of the screen.
|
2009-11-03 16:20:34 +00:00
|
|
|
stl = p_tal;
|
2006-02-20 21:37:40 +00:00
|
|
|
row = 0;
|
2006-03-03 22:56:30 +00:00
|
|
|
fillchar = ' ';
|
2017-03-16 17:23:31 +01:00
|
|
|
attr = HL_ATTR(HLF_TPF);
|
2006-02-20 21:37:40 +00:00
|
|
|
maxwidth = Columns;
|
2022-11-07 12:16:51 +00:00
|
|
|
opt_name = (char_u *)"tabline";
|
2006-02-20 21:37:40 +00:00
|
|
|
}
|
2004-12-24 14:35:23 +00:00
|
|
|
else
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2021-04-01 16:16:18 +02:00
|
|
|
row = statusline_row(wp);
|
2017-07-31 22:29:35 +02:00
|
|
|
fillchar = fillchar_status(&attr, wp);
|
2023-04-17 16:41:20 +01:00
|
|
|
int in_status_line = wp->w_status_height != 0;
|
|
|
|
|
maxwidth = in_status_line ? wp->w_width : Columns;
|
2006-02-20 21:37:40 +00:00
|
|
|
|
|
|
|
|
if (draw_ruler)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2009-11-03 16:20:34 +00:00
|
|
|
stl = p_ruf;
|
2022-11-07 12:16:51 +00:00
|
|
|
opt_name = (char_u *)"rulerformat";
|
2019-09-19 23:06:20 +02:00
|
|
|
// advance past any leading group spec - implicit in ru_col
|
2009-11-03 16:20:34 +00:00
|
|
|
if (*stl == '%')
|
2006-02-20 21:37:40 +00:00
|
|
|
{
|
2009-11-03 16:20:34 +00:00
|
|
|
if (*++stl == '-')
|
|
|
|
|
stl++;
|
|
|
|
|
if (atoi((char *)stl))
|
|
|
|
|
while (VIM_ISDIGIT(*stl))
|
|
|
|
|
stl++;
|
|
|
|
|
if (*stl++ != '(')
|
|
|
|
|
stl = p_ruf;
|
2006-02-20 21:37:40 +00:00
|
|
|
}
|
2023-04-17 16:41:20 +01:00
|
|
|
col = ru_col - (Columns - maxwidth);
|
|
|
|
|
if (col < (maxwidth + 1) / 2)
|
|
|
|
|
col = (maxwidth + 1) / 2;
|
|
|
|
|
maxwidth -= col;
|
|
|
|
|
if (!in_status_line)
|
2006-02-20 21:37:40 +00:00
|
|
|
{
|
|
|
|
|
row = Rows - 1;
|
2019-09-19 23:06:20 +02:00
|
|
|
--maxwidth; // writing in last column may cause scrolling
|
2006-02-20 21:37:40 +00:00
|
|
|
fillchar = ' ';
|
|
|
|
|
attr = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2022-11-07 12:16:51 +00:00
|
|
|
opt_name = (char_u *)"statusline";
|
2006-02-20 21:37:40 +00:00
|
|
|
if (*wp->w_p_stl != NUL)
|
2022-11-07 12:16:51 +00:00
|
|
|
{
|
2009-11-03 16:20:34 +00:00
|
|
|
stl = wp->w_p_stl;
|
2022-11-07 12:16:51 +00:00
|
|
|
opt_scope = OPT_LOCAL;
|
|
|
|
|
}
|
2006-02-20 21:37:40 +00:00
|
|
|
else
|
2009-11-03 16:20:34 +00:00
|
|
|
stl = p_stl;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2006-02-20 21:37:40 +00:00
|
|
|
|
2023-04-17 16:41:20 +01:00
|
|
|
if (in_status_line)
|
|
|
|
|
col += wp->w_wincol;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2006-02-20 21:37:40 +00:00
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
if (maxwidth <= 0)
|
2013-12-11 15:52:01 +01:00
|
|
|
goto theend;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
// Temporarily reset 'cursorbind', we don't want a side effect from moving
|
|
|
|
|
// the cursor away and back.
|
2011-02-01 18:01:11 +01:00
|
|
|
ewp = wp == NULL ? curwin : wp;
|
|
|
|
|
p_crb_save = ewp->w_p_crb;
|
|
|
|
|
ewp->w_p_crb = FALSE;
|
|
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
// Make a copy, because the statusline may include a function call that
|
|
|
|
|
// might change the option value and free the memory.
|
2009-11-03 16:20:34 +00:00
|
|
|
stl = vim_strsave(stl);
|
2011-02-01 18:01:11 +01:00
|
|
|
width = build_stl_str_hl(ewp, buf, sizeof(buf),
|
2022-11-07 12:16:51 +00:00
|
|
|
stl, opt_name, opt_scope,
|
2020-10-26 21:05:27 +01:00
|
|
|
fillchar, maxwidth, &hltab, &tabtab);
|
2009-11-03 16:20:34 +00:00
|
|
|
vim_free(stl);
|
2011-02-01 18:01:11 +01:00
|
|
|
ewp->w_p_crb = p_crb_save;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
// Make all characters printable.
|
2010-12-08 19:56:58 +01:00
|
|
|
p = transstr(buf);
|
|
|
|
|
if (p != NULL)
|
|
|
|
|
{
|
|
|
|
|
vim_strncpy(buf, p, sizeof(buf) - 1);
|
|
|
|
|
vim_free(p);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
// fill up with "fillchar"
|
2010-12-08 19:56:58 +01:00
|
|
|
len = (int)STRLEN(buf);
|
2009-05-17 11:33:22 +00:00
|
|
|
while (width < maxwidth && len < (int)sizeof(buf) - 1)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
len += (*mb_char2bytes)(fillchar, buf + len);
|
|
|
|
|
++width;
|
|
|
|
|
}
|
|
|
|
|
buf[len] = NUL;
|
|
|
|
|
|
2006-02-22 21:25:37 +00:00
|
|
|
/*
|
|
|
|
|
* Draw each snippet with the specified highlighting.
|
|
|
|
|
*/
|
2004-06-13 20:20:40 +00:00
|
|
|
curattr = attr;
|
|
|
|
|
p = buf;
|
2006-02-22 21:25:37 +00:00
|
|
|
for (n = 0; hltab[n].start != NULL; n++)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2006-02-22 21:25:37 +00:00
|
|
|
len = (int)(hltab[n].start - p);
|
2004-06-13 20:20:40 +00:00
|
|
|
screen_puts_len(p, len, row, col, curattr);
|
|
|
|
|
col += vim_strnsize(p, len);
|
2006-02-22 21:25:37 +00:00
|
|
|
p = hltab[n].start;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2006-02-22 21:25:37 +00:00
|
|
|
if (hltab[n].userhl == 0)
|
2004-06-13 20:20:40 +00:00
|
|
|
curattr = attr;
|
2006-02-22 21:25:37 +00:00
|
|
|
else if (hltab[n].userhl < 0)
|
|
|
|
|
curattr = syn_id2attr(-hltab[n].userhl);
|
2017-09-16 20:54:51 +02:00
|
|
|
#ifdef FEAT_TERMINAL
|
2017-08-14 22:35:08 +02:00
|
|
|
else if (wp != NULL && wp != curwin && bt_terminal(wp->w_buffer)
|
|
|
|
|
&& wp->w_status_height != 0)
|
|
|
|
|
curattr = highlight_stltermnc[hltab[n].userhl - 1];
|
2017-08-13 21:37:43 +02:00
|
|
|
else if (wp != NULL && bt_terminal(wp->w_buffer)
|
|
|
|
|
&& wp->w_status_height != 0)
|
|
|
|
|
curattr = highlight_stlterm[hltab[n].userhl - 1];
|
2017-09-16 20:54:51 +02:00
|
|
|
#endif
|
2006-02-21 22:12:05 +00:00
|
|
|
else if (wp != NULL && wp != curwin && wp->w_status_height != 0)
|
2006-02-22 21:25:37 +00:00
|
|
|
curattr = highlight_stlnc[hltab[n].userhl - 1];
|
2004-06-13 20:20:40 +00:00
|
|
|
else
|
2006-02-22 21:25:37 +00:00
|
|
|
curattr = highlight_user[hltab[n].userhl - 1];
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
screen_puts(p, row, col, curattr);
|
2006-02-22 21:25:37 +00:00
|
|
|
|
|
|
|
|
if (wp == NULL)
|
|
|
|
|
{
|
2019-09-19 23:06:20 +02:00
|
|
|
// Fill the TabPageIdxs[] array for clicking in the tab pagesline.
|
2006-02-22 21:25:37 +00:00
|
|
|
col = 0;
|
|
|
|
|
len = 0;
|
|
|
|
|
p = buf;
|
|
|
|
|
fillchar = 0;
|
|
|
|
|
for (n = 0; tabtab[n].start != NULL; n++)
|
|
|
|
|
{
|
|
|
|
|
len += vim_strnsize(p, (int)(tabtab[n].start - p));
|
|
|
|
|
while (col < len)
|
|
|
|
|
TabPageIdxs[col++] = fillchar;
|
|
|
|
|
p = tabtab[n].start;
|
|
|
|
|
fillchar = tabtab[n].userhl;
|
|
|
|
|
}
|
|
|
|
|
while (col < Columns)
|
|
|
|
|
TabPageIdxs[col++] = fillchar;
|
|
|
|
|
}
|
2013-12-11 15:52:01 +01:00
|
|
|
|
|
|
|
|
theend:
|
|
|
|
|
entered = FALSE;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
#endif // FEAT_STL_OPT
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Output a single character directly to the screen and update ScreenLines.
|
|
|
|
|
*/
|
|
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
screen_putchar(int c, int row, int col, int attr)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
char_u buf[MB_MAXBYTES + 1];
|
|
|
|
|
|
2012-06-01 15:21:02 +02:00
|
|
|
if (has_mbyte)
|
|
|
|
|
buf[(*mb_char2bytes)(c, buf)] = NUL;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
buf[0] = c;
|
|
|
|
|
buf[1] = NUL;
|
|
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
screen_puts(buf, row, col, attr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2023-06-01 20:26:55 +01:00
|
|
|
* Get a single character directly from ScreenLines into "bytes", which must
|
|
|
|
|
* have a size of "MB_MAXBYTES + 1".
|
|
|
|
|
* If "attrp" is not NULL, return the character's attribute in "*attrp".
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
|
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
screen_getbytes(int row, int col, char_u *bytes, int *attrp)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
unsigned off;
|
|
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
// safety check
|
2023-01-23 20:46:21 +00:00
|
|
|
if (ScreenLines == NULL || row >= screen_Rows || col >= screen_Columns)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
off = LineOffset[row] + col;
|
2023-06-01 20:26:55 +01:00
|
|
|
if (attrp != NULL)
|
|
|
|
|
*attrp = ScreenAttrs[off];
|
2023-01-23 20:46:21 +00:00
|
|
|
bytes[0] = ScreenLines[off];
|
|
|
|
|
bytes[1] = NUL;
|
|
|
|
|
|
|
|
|
|
if (enc_utf8 && ScreenLinesUC[off] != 0)
|
|
|
|
|
bytes[utfc_char2bytes(off, bytes)] = NUL;
|
|
|
|
|
else if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
bytes[0] = ScreenLines[off];
|
2023-01-23 20:46:21 +00:00
|
|
|
bytes[1] = ScreenLines2[off];
|
|
|
|
|
bytes[2] = NUL;
|
|
|
|
|
}
|
|
|
|
|
else if (enc_dbcs && MB_BYTE2LEN(bytes[0]) > 1)
|
|
|
|
|
{
|
|
|
|
|
bytes[1] = ScreenLines[off + 1];
|
|
|
|
|
bytes[2] = NUL;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-03-06 23:29:24 +00:00
|
|
|
/*
|
|
|
|
|
* Return TRUE if composing characters for screen posn "off" differs from
|
|
|
|
|
* composing characters in "u8cc".
|
2010-03-23 15:36:35 +01:00
|
|
|
* Only to be used when ScreenLinesUC[off] != 0.
|
2006-03-06 23:29:24 +00:00
|
|
|
*/
|
|
|
|
|
static int
|
2016-01-30 20:31:25 +01:00
|
|
|
screen_comp_differs(int off, int *u8cc)
|
2006-03-06 23:29:24 +00:00
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < Screen_mco; ++i)
|
|
|
|
|
{
|
|
|
|
|
if (ScreenLinesC[i][off] != (u8char_T)u8cc[i])
|
|
|
|
|
return TRUE;
|
|
|
|
|
if (u8cc[i] == 0)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
|
|
|
|
* Put string '*text' on the screen at position 'row' and 'col', with
|
|
|
|
|
* attributes 'attr', and update ScreenLines[] and ScreenAttrs[].
|
|
|
|
|
* Note: only outputs within one row, message is truncated at screen boundary!
|
|
|
|
|
* Note: if ScreenLines[], row and/or col is invalid, nothing is done.
|
|
|
|
|
*/
|
|
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
screen_puts(
|
|
|
|
|
char_u *text,
|
|
|
|
|
int row,
|
|
|
|
|
int col,
|
|
|
|
|
int attr)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
screen_puts_len(text, -1, row, col, attr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Like screen_puts(), but output "text[len]". When "len" is -1 output up to
|
|
|
|
|
* a NUL.
|
|
|
|
|
*/
|
|
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
screen_puts_len(
|
|
|
|
|
char_u *text,
|
|
|
|
|
int textlen,
|
|
|
|
|
int row,
|
|
|
|
|
int col,
|
2022-03-03 11:46:00 +00:00
|
|
|
int attr_arg)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2022-03-03 11:46:00 +00:00
|
|
|
int attr = attr_arg;
|
2004-06-13 20:20:40 +00:00
|
|
|
unsigned off;
|
|
|
|
|
char_u *ptr = text;
|
2014-05-22 16:05:19 +02:00
|
|
|
int len = textlen;
|
2004-06-13 20:20:40 +00:00
|
|
|
int c;
|
2007-08-30 11:53:22 +00:00
|
|
|
unsigned max_off;
|
2004-06-13 20:20:40 +00:00
|
|
|
int mbyte_blen = 1;
|
|
|
|
|
int mbyte_cells = 1;
|
|
|
|
|
int u8c = 0;
|
2006-03-06 23:29:24 +00:00
|
|
|
int u8cc[MAX_MCO];
|
2004-06-13 20:20:40 +00:00
|
|
|
int clear_next_cell = FALSE;
|
2019-01-24 16:39:02 +01:00
|
|
|
#ifdef FEAT_ARABIC
|
2019-09-19 23:06:20 +02:00
|
|
|
int prev_c = 0; // previous Arabic character
|
2006-03-06 23:29:24 +00:00
|
|
|
int pc, nc, nc1;
|
|
|
|
|
int pcc[MAX_MCO];
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
2009-03-11 16:58:40 +00:00
|
|
|
int force_redraw_this;
|
|
|
|
|
int force_redraw_next = FALSE;
|
|
|
|
|
int need_redraw;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-06-03 22:04:23 +02:00
|
|
|
// Safety check. The check for negative row and column is to fix issue
|
|
|
|
|
// #4102. TODO: find out why row/col could be negative.
|
|
|
|
|
if (ScreenLines == NULL
|
|
|
|
|
|| row >= screen_Rows || row < 0
|
|
|
|
|
|| col >= screen_Columns || col < 0)
|
2004-06-13 20:20:40 +00:00
|
|
|
return;
|
2009-03-11 16:58:40 +00:00
|
|
|
off = LineOffset[row] + col;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2021-12-27 17:21:41 +00:00
|
|
|
// When drawing over the right half of a double-wide char clear out the
|
|
|
|
|
// left half. Only needed in a terminal.
|
2008-07-24 18:29:37 +00:00
|
|
|
if (has_mbyte && col > 0 && col < screen_Columns
|
2019-01-24 16:39:02 +01:00
|
|
|
#ifdef FEAT_GUI
|
2008-07-13 17:41:49 +00:00
|
|
|
&& !gui.in_use
|
2019-01-24 16:39:02 +01:00
|
|
|
#endif
|
2008-07-13 17:41:49 +00:00
|
|
|
&& mb_fix_col(col, row) != col)
|
2009-03-11 16:58:40 +00:00
|
|
|
{
|
2022-10-02 15:21:04 +01:00
|
|
|
if (!skip_for_popup(row, col - 1))
|
2009-03-11 16:58:40 +00:00
|
|
|
{
|
2022-10-02 15:21:04 +01:00
|
|
|
ScreenLines[off - 1] = ' ';
|
|
|
|
|
ScreenAttrs[off - 1] = 0;
|
|
|
|
|
if (enc_utf8)
|
|
|
|
|
{
|
|
|
|
|
ScreenLinesUC[off - 1] = 0;
|
|
|
|
|
ScreenLinesC[0][off - 1] = 0;
|
|
|
|
|
}
|
|
|
|
|
// redraw the previous cell, make it empty
|
|
|
|
|
screen_char(off - 1, row, col - 1);
|
2009-03-11 16:58:40 +00:00
|
|
|
}
|
2019-09-19 23:06:20 +02:00
|
|
|
// force the cell at "col" to be redrawn
|
2009-03-11 16:58:40 +00:00
|
|
|
force_redraw_next = TRUE;
|
|
|
|
|
}
|
2008-07-13 17:41:49 +00:00
|
|
|
|
2007-08-30 11:53:22 +00:00
|
|
|
max_off = LineOffset[row] + screen_Columns;
|
2007-08-05 18:10:54 +00:00
|
|
|
while (col < screen_Columns
|
|
|
|
|
&& (len < 0 || (int)(ptr - text) < len)
|
|
|
|
|
&& *ptr != NUL)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
c = *ptr;
|
2019-12-05 21:10:38 +01:00
|
|
|
// check if this is the first byte of a multibyte
|
2004-06-13 20:20:40 +00:00
|
|
|
if (has_mbyte)
|
|
|
|
|
{
|
2022-07-25 19:42:02 +01:00
|
|
|
mbyte_blen = enc_utf8 && len > 0
|
|
|
|
|
? utfc_ptr2len_len(ptr, (int)((text + len) - ptr))
|
|
|
|
|
: (*mb_ptr2len)(ptr);
|
2004-06-13 20:20:40 +00:00
|
|
|
if (enc_dbcs == DBCS_JPNU && c == 0x8e)
|
|
|
|
|
mbyte_cells = 1;
|
|
|
|
|
else if (enc_dbcs != 0)
|
|
|
|
|
mbyte_cells = mbyte_blen;
|
2019-12-05 21:10:38 +01:00
|
|
|
else // enc_utf8
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2022-07-25 19:42:02 +01:00
|
|
|
u8c = len >= 0
|
|
|
|
|
? utfc_ptr2char_len(ptr, u8cc, (int)((text + len) - ptr))
|
|
|
|
|
: utfc_ptr2char(ptr, u8cc);
|
2004-06-13 20:20:40 +00:00
|
|
|
mbyte_cells = utf_char2cells(u8c);
|
2019-01-24 16:39:02 +01:00
|
|
|
#ifdef FEAT_ARABIC
|
2004-06-13 20:20:40 +00:00
|
|
|
if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
|
|
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
// Do Arabic shaping.
|
2004-06-13 20:20:40 +00:00
|
|
|
if (len >= 0 && (int)(ptr - text) + mbyte_blen >= len)
|
|
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
// Past end of string to be displayed.
|
2004-06-13 20:20:40 +00:00
|
|
|
nc = NUL;
|
|
|
|
|
nc1 = NUL;
|
|
|
|
|
}
|
|
|
|
|
else
|
2006-03-06 23:29:24 +00:00
|
|
|
{
|
2022-07-25 19:42:02 +01:00
|
|
|
nc = len >= 0
|
|
|
|
|
? utfc_ptr2char_len(ptr + mbyte_blen, pcc,
|
|
|
|
|
(int)((text + len) - ptr - mbyte_blen))
|
|
|
|
|
: utfc_ptr2char(ptr + mbyte_blen, pcc);
|
2006-03-06 23:29:24 +00:00
|
|
|
nc1 = pcc[0];
|
|
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
pc = prev_c;
|
|
|
|
|
prev_c = u8c;
|
2006-03-06 23:29:24 +00:00
|
|
|
u8c = arabic_shape(u8c, &c, &u8cc[0], nc, nc1, pc);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
prev_c = u8c;
|
2019-01-24 16:39:02 +01:00
|
|
|
#endif
|
2010-01-19 17:40:46 +01:00
|
|
|
if (col + mbyte_cells > screen_Columns)
|
|
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
// Only 1 cell left, but character requires 2 cells:
|
|
|
|
|
// display a '>' in the last column to avoid wrapping.
|
2010-01-19 17:40:46 +01:00
|
|
|
c = '>';
|
|
|
|
|
mbyte_cells = 1;
|
|
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-11 16:58:40 +00:00
|
|
|
force_redraw_this = force_redraw_next;
|
|
|
|
|
force_redraw_next = FALSE;
|
|
|
|
|
|
|
|
|
|
need_redraw = ScreenLines[off] != c
|
2004-06-13 20:20:40 +00:00
|
|
|
|| (mbyte_cells == 2
|
|
|
|
|
&& ScreenLines[off + 1] != (enc_dbcs ? ptr[1] : 0))
|
|
|
|
|
|| (enc_dbcs == DBCS_JPNU
|
|
|
|
|
&& c == 0x8e
|
|
|
|
|
&& ScreenLines2[off] != ptr[1])
|
|
|
|
|
|| (enc_utf8
|
2010-03-23 15:36:35 +01:00
|
|
|
&& (ScreenLinesUC[off] !=
|
|
|
|
|
(u8char_T)(c < 0x80 && u8cc[0] == 0 ? 0 : u8c)
|
|
|
|
|
|| (ScreenLinesUC[off] != 0
|
|
|
|
|
&& screen_comp_differs(off, u8cc))))
|
2004-06-13 20:20:40 +00:00
|
|
|
|| ScreenAttrs[off] != attr
|
2009-03-11 16:58:40 +00:00
|
|
|
|| exmode_active;
|
|
|
|
|
|
2022-10-02 15:21:04 +01:00
|
|
|
if ((need_redraw || force_redraw_this) && !skip_for_popup(row, col))
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
#if defined(FEAT_GUI) || defined(UNIX)
|
2019-12-05 21:10:38 +01:00
|
|
|
// The bold trick makes a single row of pixels appear in the next
|
|
|
|
|
// character. When a bold character is removed, the next
|
|
|
|
|
// character should be redrawn too. This happens for our own GUI
|
|
|
|
|
// and for some xterms.
|
2009-03-11 16:58:40 +00:00
|
|
|
if (need_redraw && ScreenLines[off] != ' ' && (
|
2004-06-13 20:20:40 +00:00
|
|
|
# ifdef FEAT_GUI
|
|
|
|
|
gui.in_use
|
|
|
|
|
# endif
|
|
|
|
|
# if defined(FEAT_GUI) && defined(UNIX)
|
|
|
|
|
||
|
|
|
|
|
# endif
|
|
|
|
|
# ifdef UNIX
|
|
|
|
|
term_is_xterm
|
|
|
|
|
# endif
|
2009-03-11 16:58:40 +00:00
|
|
|
))
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2009-03-11 16:58:40 +00:00
|
|
|
int n = ScreenAttrs[off];
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2009-03-11 16:58:40 +00:00
|
|
|
if (n > HL_ALL)
|
|
|
|
|
n = syn_attr2attr(n);
|
|
|
|
|
if (n & HL_BOLD)
|
|
|
|
|
force_redraw_next = TRUE;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
#endif
|
2019-12-05 21:10:38 +01:00
|
|
|
// When at the end of the text and overwriting a two-cell
|
|
|
|
|
// character with a one-cell character, need to clear the next
|
2021-12-27 17:21:41 +00:00
|
|
|
// cell. Also when overwriting the left half of a two-cell char
|
|
|
|
|
// with the right half of a two-cell char. Do this only once
|
|
|
|
|
// (mb_off2cells() may return 2 on the right half).
|
2004-06-13 20:20:40 +00:00
|
|
|
if (clear_next_cell)
|
|
|
|
|
clear_next_cell = FALSE;
|
|
|
|
|
else if (has_mbyte
|
|
|
|
|
&& (len < 0 ? ptr[mbyte_blen] == NUL
|
|
|
|
|
: ptr + mbyte_blen >= text + len)
|
2007-08-30 11:53:22 +00:00
|
|
|
&& ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
|
2004-06-13 20:20:40 +00:00
|
|
|
|| (mbyte_cells == 2
|
2007-08-30 11:53:22 +00:00
|
|
|
&& (*mb_off2cells)(off, max_off) == 1
|
|
|
|
|
&& (*mb_off2cells)(off + 1, max_off) > 1)))
|
2004-06-13 20:20:40 +00:00
|
|
|
clear_next_cell = TRUE;
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// Make sure we never leave a second byte of a double-byte behind,
|
|
|
|
|
// it confuses mb_off2cells().
|
2004-06-13 20:20:40 +00:00
|
|
|
if (enc_dbcs
|
2007-08-30 11:53:22 +00:00
|
|
|
&& ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
|
2004-06-13 20:20:40 +00:00
|
|
|
|| (mbyte_cells == 2
|
2007-08-30 11:53:22 +00:00
|
|
|
&& (*mb_off2cells)(off, max_off) == 1
|
|
|
|
|
&& (*mb_off2cells)(off + 1, max_off) > 1)))
|
2004-06-13 20:20:40 +00:00
|
|
|
ScreenLines[off + mbyte_blen] = 0;
|
|
|
|
|
ScreenLines[off] = c;
|
|
|
|
|
ScreenAttrs[off] = attr;
|
2022-07-09 04:56:24 +01:00
|
|
|
ScreenCols[off] = -1;
|
2004-06-13 20:20:40 +00:00
|
|
|
if (enc_utf8)
|
|
|
|
|
{
|
2006-03-06 23:29:24 +00:00
|
|
|
if (c < 0x80 && u8cc[0] == 0)
|
2004-06-13 20:20:40 +00:00
|
|
|
ScreenLinesUC[off] = 0;
|
|
|
|
|
else
|
|
|
|
|
{
|
2006-03-06 23:29:24 +00:00
|
|
|
int i;
|
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
ScreenLinesUC[off] = u8c;
|
2006-03-06 23:29:24 +00:00
|
|
|
for (i = 0; i < Screen_mco; ++i)
|
|
|
|
|
{
|
|
|
|
|
ScreenLinesC[i][off] = u8cc[i];
|
|
|
|
|
if (u8cc[i] == 0)
|
|
|
|
|
break;
|
|
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
if (mbyte_cells == 2)
|
|
|
|
|
{
|
|
|
|
|
ScreenLines[off + 1] = 0;
|
|
|
|
|
ScreenAttrs[off + 1] = attr;
|
2022-07-09 04:56:24 +01:00
|
|
|
ScreenCols[off + 1] = -1;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
screen_char(off, row, col);
|
|
|
|
|
}
|
|
|
|
|
else if (mbyte_cells == 2)
|
|
|
|
|
{
|
|
|
|
|
ScreenLines[off + 1] = ptr[1];
|
|
|
|
|
ScreenAttrs[off + 1] = attr;
|
2022-07-09 04:56:24 +01:00
|
|
|
ScreenCols[off + 1] = -1;
|
2004-06-13 20:20:40 +00:00
|
|
|
screen_char_2(off, row, col);
|
|
|
|
|
}
|
|
|
|
|
else if (enc_dbcs == DBCS_JPNU && c == 0x8e)
|
|
|
|
|
{
|
|
|
|
|
ScreenLines2[off] = ptr[1];
|
|
|
|
|
screen_char(off, row, col);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
screen_char(off, row, col);
|
|
|
|
|
}
|
|
|
|
|
if (has_mbyte)
|
|
|
|
|
{
|
|
|
|
|
off += mbyte_cells;
|
|
|
|
|
col += mbyte_cells;
|
|
|
|
|
ptr += mbyte_blen;
|
|
|
|
|
if (clear_next_cell)
|
2014-05-22 16:05:19 +02:00
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
// This only happens at the end, display one space next.
|
2022-03-03 11:46:00 +00:00
|
|
|
// Keep the attribute from before.
|
2004-06-13 20:20:40 +00:00
|
|
|
ptr = (char_u *)" ";
|
2014-05-22 16:05:19 +02:00
|
|
|
len = -1;
|
2022-03-03 11:46:00 +00:00
|
|
|
attr = ScreenAttrs[off];
|
2014-05-22 16:05:19 +02:00
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
++off;
|
|
|
|
|
++col;
|
|
|
|
|
++ptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-03-11 16:58:40 +00:00
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// If we detected the next character needs to be redrawn, but the text
|
|
|
|
|
// doesn't extend up to there, update the character here.
|
2022-10-02 15:21:04 +01:00
|
|
|
if (force_redraw_next && col < screen_Columns && !skip_for_popup(row, col))
|
2009-03-11 16:58:40 +00:00
|
|
|
{
|
|
|
|
|
if (enc_dbcs != 0 && dbcs_off2cells(off, max_off) > 1)
|
|
|
|
|
screen_char_2(off, row, col);
|
|
|
|
|
else
|
|
|
|
|
screen_char(off, row, col);
|
|
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
#if defined(FEAT_SEARCH_EXTRA) || defined(PROTO)
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
2007-07-26 20:58:42 +00:00
|
|
|
* Prepare for 'hlsearch' highlighting.
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
2019-09-19 23:06:20 +02:00
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
start_search_hl(void)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2023-01-23 20:46:21 +00:00
|
|
|
if (!p_hls || no_hlsearch)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
end_search_hl(); // just in case it wasn't called before
|
|
|
|
|
last_pat_prog(&screen_search_hl.rm);
|
|
|
|
|
screen_search_hl.attr = HL_ATTR(HLF_L);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2007-07-26 20:58:42 +00:00
|
|
|
* Clean up for 'hlsearch' highlighting.
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
2019-09-19 23:06:20 +02:00
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
end_search_hl(void)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2023-01-23 20:46:21 +00:00
|
|
|
if (screen_search_hl.rm.regprog == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
vim_regfree(screen_search_hl.rm.regprog);
|
|
|
|
|
screen_search_hl.rm.regprog = NULL;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2014-06-17 23:18:01 +02:00
|
|
|
#endif
|
2014-06-17 17:48:32 +02:00
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
static void
|
2016-01-30 20:31:25 +01:00
|
|
|
screen_start_highlight(int attr)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
attrentry_T *aep = NULL;
|
|
|
|
|
|
|
|
|
|
screen_attr = attr;
|
2023-01-23 20:46:21 +00:00
|
|
|
if (!full_screen
|
2019-02-17 17:44:42 +01:00
|
|
|
#ifdef MSWIN
|
2023-01-23 20:46:21 +00:00
|
|
|
|| !termcap_active
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
2023-01-23 20:46:21 +00:00
|
|
|
)
|
|
|
|
|
return;
|
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
#ifdef FEAT_GUI
|
2023-01-23 20:46:21 +00:00
|
|
|
if (gui.in_use)
|
|
|
|
|
{
|
|
|
|
|
char buf[20];
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2023-01-23 20:46:21 +00:00
|
|
|
// The GUI handles this internally.
|
|
|
|
|
sprintf(buf, "\033|%dh", attr);
|
|
|
|
|
OUT_STR(buf);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
2023-01-23 20:46:21 +00:00
|
|
|
|
|
|
|
|
if (attr > HL_ALL) // special HL attr.
|
|
|
|
|
{
|
|
|
|
|
if (IS_CTERM)
|
|
|
|
|
aep = syn_cterm_attr2entry(attr);
|
|
|
|
|
else
|
|
|
|
|
aep = syn_term_attr2entry(attr);
|
|
|
|
|
if (aep == NULL) // did ":syntax clear"
|
|
|
|
|
attr = 0;
|
|
|
|
|
else
|
|
|
|
|
attr = aep->ae_attr;
|
|
|
|
|
}
|
2019-12-02 21:35:31 +01:00
|
|
|
#if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
|
2023-01-23 20:46:21 +00:00
|
|
|
if (use_vtp())
|
|
|
|
|
{
|
|
|
|
|
guicolor_T defguifg, defguibg;
|
|
|
|
|
int defctermfg, defctermbg;
|
2019-12-02 21:35:31 +01:00
|
|
|
|
2023-01-23 20:46:21 +00:00
|
|
|
// If FG and BG are unset, the color is undefined when
|
|
|
|
|
// BOLD+INVERSE. Use Normal as the default value.
|
|
|
|
|
get_default_console_color(&defctermfg, &defctermbg, &defguifg,
|
|
|
|
|
&defguibg);
|
2019-12-02 21:35:31 +01:00
|
|
|
|
2023-01-23 20:46:21 +00:00
|
|
|
if (p_tgc)
|
|
|
|
|
{
|
|
|
|
|
if (aep == NULL || COLOR_INVALID(aep->ae_u.cterm.fg_rgb))
|
|
|
|
|
term_fg_rgb_color(defguifg);
|
|
|
|
|
if (aep == NULL || COLOR_INVALID(aep->ae_u.cterm.bg_rgb))
|
|
|
|
|
term_bg_rgb_color(defguibg);
|
|
|
|
|
}
|
|
|
|
|
else if (t_colors >= 256)
|
|
|
|
|
{
|
|
|
|
|
if (aep == NULL || aep->ae_u.cterm.fg_color == 0)
|
|
|
|
|
term_fg_color(defctermfg);
|
|
|
|
|
if (aep == NULL || aep->ae_u.cterm.bg_color == 0)
|
|
|
|
|
term_bg_color(defctermbg);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-12-02 21:35:31 +01:00
|
|
|
#endif
|
2023-01-23 20:46:21 +00:00
|
|
|
if ((attr & HL_BOLD) && *T_MD != NUL) // bold
|
|
|
|
|
out_str(T_MD);
|
|
|
|
|
else if (aep != NULL && cterm_normal_fg_bold && (
|
2016-04-29 22:59:22 +02:00
|
|
|
#ifdef FEAT_TERMGUICOLORS
|
2023-01-23 20:46:21 +00:00
|
|
|
p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR
|
|
|
|
|
? aep->ae_u.cterm.fg_rgb != INVALCOLOR
|
|
|
|
|
:
|
2016-04-21 21:10:14 +02:00
|
|
|
#endif
|
2023-01-23 20:46:21 +00:00
|
|
|
t_colors > 1 && aep->ae_u.cterm.fg_color))
|
|
|
|
|
// If the Normal FG color has BOLD attribute and the new HL
|
|
|
|
|
// has a FG color defined, clear BOLD.
|
|
|
|
|
out_str(T_ME);
|
|
|
|
|
if ((attr & HL_STANDOUT) && *T_SO != NUL) // standout
|
|
|
|
|
out_str(T_SO);
|
|
|
|
|
if ((attr & HL_UNDERCURL) && *T_UCS != NUL) // undercurl
|
|
|
|
|
out_str(T_UCS);
|
|
|
|
|
if ((attr & HL_UNDERDOUBLE) && *T_USS != NUL) // double underline
|
|
|
|
|
out_str(T_USS);
|
|
|
|
|
if ((attr & HL_UNDERDOTTED) && *T_DS != NUL) // dotted underline
|
|
|
|
|
out_str(T_DS);
|
|
|
|
|
if ((attr & HL_UNDERDASHED) && *T_CDS != NUL) // dashed underline
|
|
|
|
|
out_str(T_CDS);
|
|
|
|
|
if (((attr & HL_UNDERLINE) // underline or undercurl, etc.
|
|
|
|
|
|| ((attr & HL_UNDERCURL) && *T_UCS == NUL)
|
|
|
|
|
|| ((attr & HL_UNDERDOUBLE) && *T_USS == NUL)
|
|
|
|
|
|| ((attr & HL_UNDERDOTTED) && *T_DS == NUL)
|
|
|
|
|
|| ((attr & HL_UNDERDASHED) && *T_CDS == NUL))
|
|
|
|
|
&& *T_US != NUL)
|
|
|
|
|
out_str(T_US);
|
|
|
|
|
if ((attr & HL_ITALIC) && *T_CZH != NUL) // italic
|
|
|
|
|
out_str(T_CZH);
|
|
|
|
|
if ((attr & HL_INVERSE) && *T_MR != NUL) // inverse (reverse)
|
|
|
|
|
out_str(T_MR);
|
|
|
|
|
if ((attr & HL_STRIKETHROUGH) && *T_STS != NUL) // strike
|
|
|
|
|
out_str(T_STS);
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2023-01-23 20:46:21 +00:00
|
|
|
/*
|
|
|
|
|
* Output the color or start string after bold etc., in case the
|
|
|
|
|
* bold etc. override the color setting.
|
|
|
|
|
*/
|
|
|
|
|
if (aep != NULL)
|
|
|
|
|
{
|
2023-11-15 15:35:49 +01:00
|
|
|
if (aep->ae_u.cterm.font > 0 && aep->ae_u.cterm.font < 12)
|
|
|
|
|
term_font(aep->ae_u.cterm.font);
|
2016-04-29 22:59:22 +02:00
|
|
|
#ifdef FEAT_TERMGUICOLORS
|
2023-01-23 20:46:21 +00:00
|
|
|
// When 'termguicolors' is set but fg or bg is unset,
|
|
|
|
|
// fall back to the cterm colors. This helps for SpellBad,
|
|
|
|
|
// where the GUI uses a red undercurl.
|
|
|
|
|
if (p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR)
|
|
|
|
|
{
|
|
|
|
|
if (aep->ae_u.cterm.fg_rgb != INVALCOLOR)
|
|
|
|
|
term_fg_rgb_color(aep->ae_u.cterm.fg_rgb);
|
|
|
|
|
}
|
|
|
|
|
else
|
2018-02-27 14:39:03 +01:00
|
|
|
#endif
|
2023-01-23 20:46:21 +00:00
|
|
|
if (t_colors > 1)
|
|
|
|
|
{
|
|
|
|
|
if (aep->ae_u.cterm.fg_color)
|
|
|
|
|
term_fg_color(aep->ae_u.cterm.fg_color - 1);
|
|
|
|
|
}
|
2018-02-27 14:39:03 +01:00
|
|
|
#ifdef FEAT_TERMGUICOLORS
|
2023-01-23 20:46:21 +00:00
|
|
|
if (p_tgc && aep->ae_u.cterm.bg_rgb != CTERMCOLOR)
|
|
|
|
|
{
|
|
|
|
|
if (aep->ae_u.cterm.bg_rgb != INVALCOLOR)
|
|
|
|
|
term_bg_rgb_color(aep->ae_u.cterm.bg_rgb);
|
|
|
|
|
}
|
|
|
|
|
else
|
2016-04-21 21:10:14 +02:00
|
|
|
#endif
|
2023-01-23 20:46:21 +00:00
|
|
|
if (t_colors > 1)
|
|
|
|
|
{
|
|
|
|
|
if (aep->ae_u.cterm.bg_color)
|
|
|
|
|
term_bg_color(aep->ae_u.cterm.bg_color - 1);
|
|
|
|
|
}
|
2020-05-31 16:42:30 +02:00
|
|
|
#ifdef FEAT_TERMGUICOLORS
|
2023-01-23 20:46:21 +00:00
|
|
|
if (p_tgc && aep->ae_u.cterm.ul_rgb != CTERMCOLOR)
|
|
|
|
|
{
|
|
|
|
|
if (aep->ae_u.cterm.ul_rgb != INVALCOLOR)
|
|
|
|
|
term_ul_rgb_color(aep->ae_u.cterm.ul_rgb);
|
|
|
|
|
}
|
|
|
|
|
else
|
2020-05-31 16:42:30 +02:00
|
|
|
#endif
|
2023-01-23 20:46:21 +00:00
|
|
|
if (t_colors > 1)
|
|
|
|
|
{
|
|
|
|
|
if (aep->ae_u.cterm.ul_color)
|
|
|
|
|
term_ul_color(aep->ae_u.cterm.ul_color - 1);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2023-01-23 20:46:21 +00:00
|
|
|
|
|
|
|
|
if (!IS_CTERM)
|
|
|
|
|
{
|
|
|
|
|
if (aep->ae_u.term.start != NULL)
|
|
|
|
|
out_str(aep->ae_u.term.start);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
screen_stop_highlight(void)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
int do_ME = FALSE; // output T_ME code
|
2020-04-30 20:59:57 +02:00
|
|
|
#if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
|
2020-05-29 21:42:55 +02:00
|
|
|
int do_ME_fg = FALSE, do_ME_bg = FALSE;
|
2020-04-30 20:59:57 +02:00
|
|
|
#endif
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
|
if (screen_attr != 0
|
2019-02-17 17:44:42 +01:00
|
|
|
#ifdef MSWIN
|
2004-06-13 20:20:40 +00:00
|
|
|
&& termcap_active
|
|
|
|
|
#endif
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
#ifdef FEAT_GUI
|
|
|
|
|
if (gui.in_use)
|
|
|
|
|
{
|
|
|
|
|
char buf[20];
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// use internal GUI code
|
2022-01-31 14:59:41 +00:00
|
|
|
sprintf(buf, "\033|%dH", screen_attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
OUT_STR(buf);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
{
|
2022-06-29 18:39:11 +01:00
|
|
|
int is_under;
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
if (screen_attr > HL_ALL) // special HL attr.
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
attrentry_T *aep;
|
|
|
|
|
|
2016-04-21 21:10:14 +02:00
|
|
|
if (IS_CTERM)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Assume that t_me restores the original colors!
|
|
|
|
|
*/
|
|
|
|
|
aep = syn_cterm_attr2entry(screen_attr);
|
2018-02-27 14:39:03 +01:00
|
|
|
if (aep != NULL && ((
|
2016-04-29 22:59:22 +02:00
|
|
|
#ifdef FEAT_TERMGUICOLORS
|
2018-02-27 14:39:03 +01:00
|
|
|
p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR
|
|
|
|
|
? aep->ae_u.cterm.fg_rgb != INVALCOLOR
|
2020-04-30 20:59:57 +02:00
|
|
|
# ifdef FEAT_VTP
|
|
|
|
|
? !(do_ME_fg = TRUE) : (do_ME_fg = FALSE)
|
|
|
|
|
# endif
|
2018-02-27 14:39:03 +01:00
|
|
|
:
|
2016-04-21 21:10:14 +02:00
|
|
|
#endif
|
2018-02-27 14:39:03 +01:00
|
|
|
aep->ae_u.cterm.fg_color) || (
|
2016-04-29 22:59:22 +02:00
|
|
|
#ifdef FEAT_TERMGUICOLORS
|
2018-02-27 14:39:03 +01:00
|
|
|
p_tgc && aep->ae_u.cterm.bg_rgb != CTERMCOLOR
|
|
|
|
|
? aep->ae_u.cterm.bg_rgb != INVALCOLOR
|
2020-04-30 20:59:57 +02:00
|
|
|
# ifdef FEAT_VTP
|
|
|
|
|
? !(do_ME_bg = TRUE) : (do_ME_bg = FALSE)
|
|
|
|
|
# endif
|
2018-02-27 14:39:03 +01:00
|
|
|
:
|
2016-04-21 21:10:14 +02:00
|
|
|
#endif
|
2018-02-27 14:39:03 +01:00
|
|
|
aep->ae_u.cterm.bg_color)))
|
2004-06-13 20:20:40 +00:00
|
|
|
do_ME = TRUE;
|
2020-04-30 20:59:57 +02:00
|
|
|
#if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
|
|
|
|
|
if (use_vtp())
|
|
|
|
|
{
|
|
|
|
|
if (do_ME_fg && do_ME_bg)
|
|
|
|
|
do_ME = TRUE;
|
|
|
|
|
|
|
|
|
|
// FG and BG cannot be separated in T_ME, which is not
|
|
|
|
|
// efficient.
|
|
|
|
|
if (!do_ME && do_ME_fg)
|
|
|
|
|
out_str((char_u *)"\033|39m"); // restore FG
|
|
|
|
|
if (!do_ME && do_ME_bg)
|
|
|
|
|
out_str((char_u *)"\033|49m"); // restore BG
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Process FG and BG at once.
|
|
|
|
|
if (!do_ME)
|
|
|
|
|
do_ME = do_ME_fg | do_ME_bg;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-12-05 21:10:38 +01:00
|
|
|
if (aep == NULL) // did ":syntax clear"
|
2004-06-13 20:20:40 +00:00
|
|
|
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);
|
|
|
|
|
}
|
2022-06-29 18:39:11 +01:00
|
|
|
is_under = (screen_attr & (HL_UNDERCURL
|
|
|
|
|
| HL_UNDERDOUBLE | HL_UNDERDOTTED | HL_UNDERDASHED));
|
|
|
|
|
if (is_under && *T_UCE != NUL)
|
2017-11-28 21:25:21 +01:00
|
|
|
{
|
|
|
|
|
if (STRCMP(T_UCE, T_ME) == 0)
|
|
|
|
|
do_ME = TRUE;
|
|
|
|
|
else
|
|
|
|
|
out_str(T_UCE);
|
|
|
|
|
}
|
2022-06-29 18:39:11 +01:00
|
|
|
if ((screen_attr & HL_UNDERLINE) || (is_under && *T_UCE == NUL))
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
}
|
2017-09-02 18:33:56 +02:00
|
|
|
if (screen_attr & HL_STRIKETHROUGH)
|
|
|
|
|
{
|
|
|
|
|
if (STRCMP(T_STE, T_ME) == 0)
|
|
|
|
|
do_ME = TRUE;
|
|
|
|
|
else
|
|
|
|
|
out_str(T_STE);
|
|
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
if (do_ME || (screen_attr & (HL_BOLD | HL_INVERSE)))
|
|
|
|
|
out_str(T_ME);
|
|
|
|
|
|
2016-04-29 22:59:22 +02:00
|
|
|
#ifdef FEAT_TERMGUICOLORS
|
|
|
|
|
if (p_tgc)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2016-08-22 23:04:33 +02:00
|
|
|
if (cterm_normal_fg_gui_color != INVALCOLOR)
|
2016-04-21 21:10:14 +02:00
|
|
|
term_fg_rgb_color(cterm_normal_fg_gui_color);
|
2016-08-22 23:04:33 +02:00
|
|
|
if (cterm_normal_bg_gui_color != INVALCOLOR)
|
2016-04-21 21:10:14 +02:00
|
|
|
term_bg_rgb_color(cterm_normal_bg_gui_color);
|
2020-05-31 16:42:30 +02:00
|
|
|
if (cterm_normal_ul_gui_color != INVALCOLOR)
|
|
|
|
|
term_ul_rgb_color(cterm_normal_ul_gui_color);
|
2016-04-21 21:10:14 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
if (t_colors > 1)
|
|
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
// set Normal cterm colors
|
2016-04-21 21:10:14 +02:00
|
|
|
if (cterm_normal_fg_color != 0)
|
|
|
|
|
term_fg_color(cterm_normal_fg_color - 1);
|
|
|
|
|
if (cterm_normal_bg_color != 0)
|
|
|
|
|
term_bg_color(cterm_normal_bg_color - 1);
|
2020-05-31 16:42:30 +02:00
|
|
|
if (cterm_normal_ul_color != 0)
|
|
|
|
|
term_ul_color(cterm_normal_ul_color - 1);
|
2016-04-21 21:10:14 +02:00
|
|
|
if (cterm_normal_fg_bold)
|
|
|
|
|
out_str(T_MD);
|
|
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
screen_attr = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Reset the colors for a cterm. Used when leaving Vim.
|
|
|
|
|
* The machine specific code may override this again.
|
|
|
|
|
*/
|
|
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
reset_cterm_colors(void)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2023-01-23 20:46:21 +00:00
|
|
|
if (!IS_CTERM)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// set Normal cterm colors
|
2016-04-29 22:59:22 +02:00
|
|
|
#ifdef FEAT_TERMGUICOLORS
|
2023-01-23 20:46:21 +00:00
|
|
|
if (p_tgc ? (cterm_normal_fg_gui_color != INVALCOLOR
|
|
|
|
|
|| cterm_normal_bg_gui_color != INVALCOLOR)
|
|
|
|
|
: (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0))
|
2016-04-21 21:10:14 +02:00
|
|
|
#else
|
2004-06-13 20:20:40 +00:00
|
|
|
if (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0)
|
2016-04-21 21:10:14 +02:00
|
|
|
#endif
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
out_str(T_OP);
|
|
|
|
|
screen_attr = -1;
|
|
|
|
|
}
|
2023-01-23 20:46:21 +00:00
|
|
|
if (cterm_normal_fg_bold)
|
|
|
|
|
{
|
|
|
|
|
out_str(T_ME);
|
|
|
|
|
screen_attr = -1;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Put character ScreenLines["off"] on the screen at position "row" and "col",
|
|
|
|
|
* using the attributes from ScreenAttrs["off"].
|
|
|
|
|
*/
|
2019-09-19 23:06:20 +02:00
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
screen_char(unsigned off, int row, int col)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
int attr;
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// Check for illegal values, just in case (could happen just after
|
|
|
|
|
// resizing).
|
2004-06-13 20:20:40 +00:00
|
|
|
if (row >= screen_Rows || col >= screen_Columns)
|
|
|
|
|
return;
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// Outputting a character in the last cell on the screen may scroll the
|
|
|
|
|
// screen up. Only do it when the "xn" termcap property is set, otherwise
|
|
|
|
|
// mark the character invalid (update it when scrolled up).
|
2015-02-10 19:20:37 +01:00
|
|
|
if (*T_XN == NUL
|
|
|
|
|
&& row == screen_Rows - 1 && col == screen_Columns - 1
|
2004-06-13 20:20:40 +00:00
|
|
|
#ifdef FEAT_RIGHTLEFT
|
2019-12-05 21:10:38 +01:00
|
|
|
// account for first command-line character in rightleft mode
|
2004-06-13 20:20:40 +00:00
|
|
|
&& !cmdmsg_rl
|
|
|
|
|
#endif
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
ScreenAttrs[off] = (sattr_T)-1;
|
2022-07-09 04:56:24 +01:00
|
|
|
ScreenCols[off] = -1;
|
2004-06-13 20:20:40 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Stop highlighting first, so it's easier to move the cursor.
|
|
|
|
|
*/
|
|
|
|
|
if (screen_char_attr != 0)
|
|
|
|
|
attr = screen_char_attr;
|
|
|
|
|
else
|
|
|
|
|
attr = ScreenAttrs[off];
|
|
|
|
|
if (screen_attr != attr)
|
|
|
|
|
screen_stop_highlight();
|
|
|
|
|
|
|
|
|
|
windgoto(row, col);
|
|
|
|
|
|
|
|
|
|
if (screen_attr != attr)
|
|
|
|
|
screen_start_highlight(attr);
|
|
|
|
|
|
|
|
|
|
if (enc_utf8 && ScreenLinesUC[off] != 0)
|
|
|
|
|
{
|
|
|
|
|
char_u buf[MB_MAXBYTES + 1];
|
|
|
|
|
|
2024-04-20 17:57:19 +02:00
|
|
|
if (
|
2024-04-17 22:06:54 +02:00
|
|
|
#ifdef FEAT_GUI
|
2024-04-20 17:57:19 +02:00
|
|
|
!gui.in_use &&
|
2024-04-17 22:06:54 +02:00
|
|
|
#endif
|
2024-04-20 17:57:19 +02:00
|
|
|
get_cellwidth(ScreenLinesUC[off]) > 1
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
// If the width is set to 2 with setcellwidths()
|
|
|
|
|
// clear the two screen cells. If the character is actually
|
|
|
|
|
// single width it won't change the second cell.
|
|
|
|
|
out_str((char_u *)" ");
|
|
|
|
|
term_windgoto(row, col);
|
|
|
|
|
screen_cur_col = 9999;
|
2024-04-17 22:06:54 +02:00
|
|
|
}
|
|
|
|
|
else if (utf_ambiguous_width(ScreenLinesUC[off]))
|
2017-12-12 22:29:30 +01:00
|
|
|
{
|
|
|
|
|
if (*p_ambw == 'd'
|
2019-01-24 16:39:02 +01:00
|
|
|
#ifdef FEAT_GUI
|
2017-12-12 22:29:30 +01:00
|
|
|
&& !gui.in_use
|
2019-01-24 16:39:02 +01:00
|
|
|
#endif
|
2017-12-12 22:29:30 +01:00
|
|
|
)
|
|
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
// Clear the two screen cells. If the character is actually
|
|
|
|
|
// single width it won't change the second cell.
|
2017-12-12 22:29:30 +01:00
|
|
|
out_str((char_u *)" ");
|
|
|
|
|
term_windgoto(row, col);
|
|
|
|
|
}
|
2019-12-05 21:10:38 +01:00
|
|
|
// not sure where the cursor is after drawing the ambiguous width
|
|
|
|
|
// character
|
2016-04-02 22:14:51 +02:00
|
|
|
screen_cur_col = 9999;
|
2017-12-12 22:29:30 +01:00
|
|
|
}
|
2016-04-02 22:14:51 +02:00
|
|
|
else if (utf_char2cells(ScreenLinesUC[off]) > 1)
|
2004-06-13 20:20:40 +00:00
|
|
|
++screen_cur_col;
|
2017-12-12 22:29:30 +01:00
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// Convert the UTF-8 character to bytes and write it.
|
2017-12-12 22:29:30 +01:00
|
|
|
buf[utfc_char2bytes(off, buf)] = NUL;
|
|
|
|
|
out_str(buf);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
out_flush_check();
|
|
|
|
|
out_char(ScreenLines[off]);
|
2019-12-05 21:10:38 +01:00
|
|
|
// double-byte character in single-width cell
|
2004-06-13 20:20:40 +00:00
|
|
|
if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
|
|
|
|
|
out_char(ScreenLines2[off]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
screen_cur_col++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Used for enc_dbcs only: Put one double-wide character at ScreenLines["off"]
|
|
|
|
|
* on the screen at position 'row' and 'col'.
|
|
|
|
|
* The attributes of the first byte is used for all. This is required to
|
|
|
|
|
* output the two bytes of a double-byte character with nothing in between.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2016-01-30 20:31:25 +01:00
|
|
|
screen_char_2(unsigned off, int row, int col)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
// Check for illegal values (could be wrong when screen was resized).
|
2004-06-13 20:20:40 +00:00
|
|
|
if (off + 1 >= (unsigned)(screen_Rows * screen_Columns))
|
|
|
|
|
return;
|
|
|
|
|
|
2022-11-02 13:30:51 +00:00
|
|
|
// Outputting the last character on the screen may scroll the screen up.
|
2019-12-05 21:10:38 +01:00
|
|
|
// Don't to it! Mark the character invalid (update it when scrolled up)
|
2004-06-13 20:20:40 +00:00
|
|
|
if (row == screen_Rows - 1 && col >= screen_Columns - 2)
|
|
|
|
|
{
|
|
|
|
|
ScreenAttrs[off] = (sattr_T)-1;
|
2022-07-09 04:56:24 +01:00
|
|
|
ScreenCols[off] = -1;
|
2004-06-13 20:20:40 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// Output the first byte normally (positions the cursor), then write the
|
|
|
|
|
// second byte directly.
|
2004-06-13 20:20:40 +00:00
|
|
|
screen_char(off, row, col);
|
|
|
|
|
out_char(ScreenLines[off + 1]);
|
|
|
|
|
++screen_cur_col;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Draw a rectangle of the screen, inverted when "invert" is TRUE.
|
|
|
|
|
* This uses the contents of ScreenLines[] and doesn't change it.
|
|
|
|
|
*/
|
|
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
screen_draw_rectangle(
|
|
|
|
|
int row,
|
|
|
|
|
int col,
|
|
|
|
|
int height,
|
|
|
|
|
int width,
|
|
|
|
|
int invert)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
int r, c;
|
|
|
|
|
int off;
|
2007-08-30 11:53:22 +00:00
|
|
|
int max_off;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// Can't use ScreenLines unless initialized
|
2005-09-29 18:26:07 +00:00
|
|
|
if (ScreenLines == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
if (invert)
|
|
|
|
|
screen_char_attr = HL_INVERSE;
|
|
|
|
|
for (r = row; r < row + height; ++r)
|
|
|
|
|
{
|
|
|
|
|
off = LineOffset[r];
|
2007-08-30 11:53:22 +00:00
|
|
|
max_off = off + screen_Columns;
|
2004-06-13 20:20:40 +00:00
|
|
|
for (c = col; c < col + width; ++c)
|
|
|
|
|
{
|
2007-08-30 11:53:22 +00:00
|
|
|
if (enc_dbcs != 0 && dbcs_off2cells(off + c, max_off) > 1)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2022-10-02 15:21:04 +01:00
|
|
|
if (!skip_for_popup(r, c))
|
|
|
|
|
screen_char_2(off + c, r, c);
|
2004-06-13 20:20:40 +00:00
|
|
|
++c;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-10-02 15:21:04 +01:00
|
|
|
if (!skip_for_popup(r, c))
|
|
|
|
|
screen_char(off + c, r, c);
|
2007-08-30 11:53:22 +00:00
|
|
|
if (utf_off2cells(off + c, max_off) > 1)
|
2004-06-13 20:20:40 +00:00
|
|
|
++c;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
screen_char_attr = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Redraw the characters for a vertically split window.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2016-01-30 20:31:25 +01:00
|
|
|
redraw_block(int row, int end, win_T *wp)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
int col;
|
|
|
|
|
int width;
|
|
|
|
|
|
|
|
|
|
# ifdef FEAT_CLIPBOARD
|
|
|
|
|
clip_may_clear_selection(row, end - 1);
|
|
|
|
|
# endif
|
|
|
|
|
|
|
|
|
|
if (wp == NULL)
|
|
|
|
|
{
|
|
|
|
|
col = 0;
|
|
|
|
|
width = Columns;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
col = wp->w_wincol;
|
|
|
|
|
width = wp->w_width;
|
|
|
|
|
}
|
|
|
|
|
screen_draw_rectangle(row, col, end - row, width, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-19 23:06:20 +02:00
|
|
|
void
|
2017-09-17 23:03:31 +02:00
|
|
|
space_to_screenline(int off, int attr)
|
|
|
|
|
{
|
|
|
|
|
ScreenLines[off] = ' ';
|
|
|
|
|
ScreenAttrs[off] = attr;
|
2022-07-09 04:56:24 +01:00
|
|
|
ScreenCols[off] = -1;
|
2017-09-17 23:03:31 +02:00
|
|
|
if (enc_utf8)
|
|
|
|
|
ScreenLinesUC[off] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
2022-04-09 12:40:13 +01:00
|
|
|
* Fill the screen from "start_row" to "end_row" (exclusive), from "start_col"
|
|
|
|
|
* to "end_col" (exclusive) with character "c1" in first column followed by
|
|
|
|
|
* "c2" in the other columns. Use attributes "attr".
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
|
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
screen_fill(
|
2019-06-23 00:15:57 +02:00
|
|
|
int start_row,
|
|
|
|
|
int end_row,
|
|
|
|
|
int start_col,
|
|
|
|
|
int end_col,
|
|
|
|
|
int c1,
|
|
|
|
|
int c2,
|
|
|
|
|
int attr)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-06-23 00:15:57 +02:00
|
|
|
int row;
|
|
|
|
|
int col;
|
|
|
|
|
int off;
|
|
|
|
|
int end_off;
|
|
|
|
|
int did_delete;
|
|
|
|
|
int c;
|
|
|
|
|
int norm_term;
|
2004-06-13 20:20:40 +00:00
|
|
|
#if defined(FEAT_GUI) || defined(UNIX)
|
2019-06-23 00:15:57 +02:00
|
|
|
int force_next = FALSE;
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
if (end_row > screen_Rows) // safety check
|
2004-06-13 20:20:40 +00:00
|
|
|
end_row = screen_Rows;
|
2019-12-05 21:10:38 +01:00
|
|
|
if (end_col > screen_Columns) // safety check
|
2004-06-13 20:20:40 +00:00
|
|
|
end_col = screen_Columns;
|
|
|
|
|
if (ScreenLines == NULL
|
|
|
|
|
|| start_row >= end_row
|
2019-12-05 21:10:38 +01:00
|
|
|
|| start_col >= end_col) // nothing to do
|
2004-06-13 20:20:40 +00:00
|
|
|
return;
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// it's a "normal" terminal when not in a GUI or cterm
|
2004-06-13 20:20:40 +00:00
|
|
|
norm_term = (
|
|
|
|
|
#ifdef FEAT_GUI
|
|
|
|
|
!gui.in_use &&
|
|
|
|
|
#endif
|
2016-04-21 21:10:14 +02:00
|
|
|
!IS_CTERM);
|
2004-06-13 20:20:40 +00:00
|
|
|
for (row = start_row; row < end_row; ++row)
|
|
|
|
|
{
|
2008-07-13 17:41:49 +00:00
|
|
|
if (has_mbyte
|
2019-01-24 16:39:02 +01:00
|
|
|
#ifdef FEAT_GUI
|
2008-07-13 17:41:49 +00:00
|
|
|
&& !gui.in_use
|
2019-01-24 16:39:02 +01:00
|
|
|
#endif
|
2008-07-13 17:41:49 +00:00
|
|
|
)
|
|
|
|
|
{
|
2021-12-27 17:21:41 +00:00
|
|
|
// When drawing over the right half of a double-wide char clear
|
|
|
|
|
// out the left half. When drawing over the left half of a
|
|
|
|
|
// double wide-char clear out the right half. Only needed in a
|
2019-12-05 21:10:38 +01:00
|
|
|
// terminal.
|
2008-07-24 18:29:37 +00:00
|
|
|
if (start_col > 0 && mb_fix_col(start_col, row) != start_col)
|
2008-07-14 17:51:11 +00:00
|
|
|
screen_puts_len((char_u *)" ", 1, row, start_col - 1, 0);
|
2008-07-18 15:14:43 +00:00
|
|
|
if (end_col < screen_Columns && mb_fix_col(end_col, row) != end_col)
|
2008-07-14 17:51:11 +00:00
|
|
|
screen_puts_len((char_u *)" ", 1, row, end_col, 0);
|
2008-07-13 17:41:49 +00:00
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
|
|
|
|
* 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
|
|
|
|
|
&& can_clear(T_CE)
|
|
|
|
|
&& (attr == 0
|
|
|
|
|
|| (norm_term
|
|
|
|
|
&& attr <= HL_ALL
|
|
|
|
|
&& ((attr & ~(HL_BOLD | HL_ITALIC)) == 0))))
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* check if we really need to clear something
|
|
|
|
|
*/
|
|
|
|
|
col = start_col;
|
2019-12-05 21:10:38 +01:00
|
|
|
if (c1 != ' ') // don't clear first char
|
2004-06-13 20:20:40 +00:00
|
|
|
++col;
|
|
|
|
|
|
|
|
|
|
off = LineOffset[row] + col;
|
|
|
|
|
end_off = LineOffset[row] + end_col;
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// skip blanks (used often, keep it fast!)
|
2004-06-13 20:20:40 +00:00
|
|
|
if (enc_utf8)
|
|
|
|
|
while (off < end_off && ScreenLines[off] == ' '
|
|
|
|
|
&& ScreenAttrs[off] == 0 && ScreenLinesUC[off] == 0)
|
|
|
|
|
++off;
|
|
|
|
|
else
|
|
|
|
|
while (off < end_off && ScreenLines[off] == ' '
|
|
|
|
|
&& ScreenAttrs[off] == 0)
|
|
|
|
|
++off;
|
2019-12-05 21:10:38 +01:00
|
|
|
if (off < end_off) // something to be cleared
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
col = off - LineOffset[row];
|
|
|
|
|
screen_stop_highlight();
|
2019-12-05 21:10:38 +01:00
|
|
|
term_windgoto(row, col);// clear rest of this screen line
|
2004-06-13 20:20:40 +00:00
|
|
|
out_str(T_CE);
|
2019-12-05 21:10:38 +01:00
|
|
|
screen_start(); // don't know where cursor is now
|
2004-06-13 20:20:40 +00:00
|
|
|
col = end_col - col;
|
2019-12-05 21:10:38 +01:00
|
|
|
while (col--) // clear chars in ScreenLines
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2017-09-17 23:03:31 +02:00
|
|
|
space_to_screenline(off, 0);
|
2004-06-13 20:20:40 +00:00
|
|
|
++off;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-12-05 21:10:38 +01:00
|
|
|
did_delete = TRUE; // the chars are cleared now
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
off = LineOffset[row] + start_col;
|
|
|
|
|
c = c1;
|
|
|
|
|
for (col = start_col; col < end_col; ++col)
|
|
|
|
|
{
|
2019-06-08 16:01:13 +02:00
|
|
|
if ((ScreenLines[off] != c
|
2006-03-06 23:29:24 +00:00
|
|
|
|| (enc_utf8 && (int)ScreenLinesUC[off]
|
|
|
|
|
!= (c >= 0x80 ? c : 0))
|
2004-06-13 20:20:40 +00:00
|
|
|
|| ScreenAttrs[off] != attr
|
2022-09-26 15:19:56 +01:00
|
|
|
|| must_redraw == UPD_CLEAR // screen clear pending
|
2004-06-13 20:20:40 +00:00
|
|
|
#if defined(FEAT_GUI) || defined(UNIX)
|
|
|
|
|
|| force_next
|
|
|
|
|
#endif
|
|
|
|
|
)
|
2019-06-08 16:01:13 +02:00
|
|
|
// Skip if under a(nother) popup.
|
2022-10-02 15:21:04 +01:00
|
|
|
&& !skip_for_popup(row, col))
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
#if defined(FEAT_GUI) || defined(UNIX)
|
2019-12-05 21:10:38 +01:00
|
|
|
// The bold trick may make a single row of pixels appear in
|
|
|
|
|
// the next character. When a bold character is removed, the
|
|
|
|
|
// next character should be redrawn too. This happens for our
|
|
|
|
|
// own GUI and for some xterms.
|
2004-06-13 20:20:40 +00:00
|
|
|
if (
|
|
|
|
|
# ifdef FEAT_GUI
|
|
|
|
|
gui.in_use
|
|
|
|
|
# endif
|
|
|
|
|
# if defined(FEAT_GUI) && defined(UNIX)
|
|
|
|
|
||
|
|
|
|
|
# endif
|
|
|
|
|
# ifdef UNIX
|
|
|
|
|
term_is_xterm
|
|
|
|
|
# endif
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
if (ScreenLines[off] != ' '
|
|
|
|
|
&& (ScreenAttrs[off] > HL_ALL
|
|
|
|
|
|| ScreenAttrs[off] & HL_BOLD))
|
|
|
|
|
force_next = TRUE;
|
|
|
|
|
else
|
|
|
|
|
force_next = FALSE;
|
|
|
|
|
}
|
2022-10-04 14:36:29 +01:00
|
|
|
#endif // FEAT_GUI || defined(UNIX)
|
2004-06-13 20:20:40 +00:00
|
|
|
ScreenLines[off] = c;
|
|
|
|
|
if (enc_utf8)
|
|
|
|
|
{
|
|
|
|
|
if (c >= 0x80)
|
|
|
|
|
{
|
|
|
|
|
ScreenLinesUC[off] = c;
|
2006-03-06 23:29:24 +00:00
|
|
|
ScreenLinesC[0][off] = 0;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
ScreenLinesUC[off] = 0;
|
|
|
|
|
}
|
|
|
|
|
ScreenAttrs[off] = attr;
|
|
|
|
|
if (!did_delete || c != ' ')
|
|
|
|
|
screen_char(off, row, col);
|
|
|
|
|
}
|
2022-07-09 04:56:24 +01:00
|
|
|
ScreenCols[off] = -1;
|
2004-06-13 20:20:40 +00:00
|
|
|
++off;
|
|
|
|
|
if (col == start_col)
|
|
|
|
|
{
|
|
|
|
|
if (did_delete)
|
|
|
|
|
break;
|
|
|
|
|
c = c2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (end_col == Columns)
|
|
|
|
|
LineWraps[row] = FALSE;
|
2019-12-05 21:10:38 +01:00
|
|
|
if (row == Rows - 1) // overwritten the command line
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
redraw_cmdline = TRUE;
|
2018-04-13 20:41:29 +02:00
|
|
|
if (start_col == 0 && end_col == Columns
|
|
|
|
|
&& c1 == ' ' && c2 == ' ' && attr == 0)
|
2019-12-05 21:10:38 +01:00
|
|
|
clear_cmdline = FALSE; // command line has been cleared
|
2006-01-25 22:10:52 +00:00
|
|
|
if (start_col == 0)
|
2019-12-05 21:10:38 +01:00
|
|
|
mode_displayed = FALSE; // mode cleared or overwritten
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Check if there should be a delay. Used before clearing or redrawing the
|
|
|
|
|
* screen or the command line.
|
|
|
|
|
*/
|
|
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
check_for_delay(int check_msg_scroll)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
if ((emsg_on_display || (check_msg_scroll && msg_scroll))
|
|
|
|
|
&& !did_wait_return
|
2020-10-28 20:20:00 +01:00
|
|
|
&& emsg_silent == 0
|
|
|
|
|
&& !in_assert_fails)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
out_flush();
|
2019-11-17 17:06:33 +01:00
|
|
|
ui_delay(1006L, TRUE);
|
2004-06-13 20:20:40 +00:00
|
|
|
emsg_on_display = FALSE;
|
|
|
|
|
if (check_msg_scroll)
|
|
|
|
|
msg_scroll = FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-13 14:53:16 +02:00
|
|
|
/*
|
|
|
|
|
* Init TabPageIdxs[] to zero: Clicking outside of tabs has no effect.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
clear_TabPageIdxs(void)
|
|
|
|
|
{
|
|
|
|
|
int scol;
|
|
|
|
|
|
|
|
|
|
for (scol = 0; scol < Columns; ++scol)
|
|
|
|
|
TabPageIdxs[scol] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
|
|
|
|
* screen_valid - allocate screen buffers if size changed
|
2012-01-10 22:26:17 +01:00
|
|
|
* If "doclear" is TRUE: clear screen if it has been resized.
|
2004-06-13 20:20:40 +00:00
|
|
|
* Returns TRUE if there is a valid screen to write to.
|
|
|
|
|
* Returns FALSE when starting up and screen not initialized yet.
|
|
|
|
|
*/
|
|
|
|
|
int
|
2016-01-30 20:31:25 +01:00
|
|
|
screen_valid(int doclear)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
screenalloc(doclear); // allocate screen buffers if size changed
|
2004-06-13 20:20:40 +00:00
|
|
|
return (ScreenLines != NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Resize the shell to Rows and Columns.
|
|
|
|
|
* Allocate ScreenLines[] and associated items.
|
|
|
|
|
*
|
|
|
|
|
* There may be some time between setting Rows and Columns and (re)allocating
|
|
|
|
|
* ScreenLines[]. This happens when starting up and when (manually) changing
|
|
|
|
|
* the shell size. Always use screen_Rows and screen_Columns to access items
|
|
|
|
|
* in ScreenLines[]. Use Rows and Columns for positioning text etc. where the
|
|
|
|
|
* final size of the shell is needed.
|
|
|
|
|
*/
|
|
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
screenalloc(int doclear)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
int new_row, old_row;
|
|
|
|
|
#ifdef FEAT_GUI
|
|
|
|
|
int old_Rows;
|
|
|
|
|
#endif
|
|
|
|
|
win_T *wp;
|
|
|
|
|
int outofmem = FALSE;
|
|
|
|
|
int len;
|
|
|
|
|
schar_T *new_ScreenLines;
|
|
|
|
|
u8char_T *new_ScreenLinesUC = NULL;
|
2006-03-06 23:29:24 +00:00
|
|
|
u8char_T *new_ScreenLinesC[MAX_MCO];
|
2004-06-13 20:20:40 +00:00
|
|
|
schar_T *new_ScreenLines2 = NULL;
|
|
|
|
|
sattr_T *new_ScreenAttrs;
|
2022-07-09 04:56:24 +01:00
|
|
|
colnr_T *new_ScreenCols;
|
2004-06-13 20:20:40 +00:00
|
|
|
unsigned *new_LineOffset;
|
|
|
|
|
char_u *new_LineWraps;
|
2006-02-22 21:25:37 +00:00
|
|
|
short *new_TabPageIdxs;
|
2019-11-30 22:48:27 +01:00
|
|
|
#ifdef FEAT_PROP_POPUP
|
2019-06-08 16:01:13 +02:00
|
|
|
short *new_popup_mask;
|
2019-06-10 21:24:12 +02:00
|
|
|
short *new_popup_mask_next;
|
2019-06-23 00:15:57 +02:00
|
|
|
char *new_popup_transparent;
|
2019-06-08 16:01:13 +02:00
|
|
|
#endif
|
2006-02-16 22:11:02 +00:00
|
|
|
tabpage_T *tp;
|
2019-12-05 21:10:38 +01:00
|
|
|
static int entered = FALSE; // avoid recursiveness
|
|
|
|
|
static int done_outofmem_msg = FALSE; // did outofmem message
|
2009-02-22 20:13:39 +00:00
|
|
|
int retry_count = 0;
|
2022-11-28 19:11:02 +00:00
|
|
|
int found_null;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2009-02-22 20:13:39 +00:00
|
|
|
retry:
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
|
|
|
|
* 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 ((ScreenLines != NULL
|
|
|
|
|
&& Rows == screen_Rows
|
|
|
|
|
&& Columns == screen_Columns
|
|
|
|
|
&& enc_utf8 == (ScreenLinesUC != NULL)
|
|
|
|
|
&& (enc_dbcs == DBCS_JPNU) == (ScreenLines2 != NULL)
|
2019-01-24 16:39:02 +01:00
|
|
|
&& p_mco == Screen_mco)
|
2004-06-13 20:20:40 +00:00
|
|
|
|| Rows == 0
|
|
|
|
|
|| Columns == 0
|
|
|
|
|
|| (!full_screen && ScreenLines == 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;
|
|
|
|
|
|
2006-07-11 21:01:01 +00:00
|
|
|
/*
|
|
|
|
|
* Note that the window sizes are updated before reallocating the arrays,
|
|
|
|
|
* thus we must not redraw here!
|
|
|
|
|
*/
|
|
|
|
|
++RedrawingDisabled;
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
win_new_shellsize(); // fit the windows in the new sized shell
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2020-02-26 16:16:53 +01:00
|
|
|
#ifdef FEAT_GUI_HAIKU
|
|
|
|
|
vim_lock_screen(); // be safe, put it here
|
|
|
|
|
#endif
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
comp_col(); // recompute columns for shown command and ruler
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We're changing the size of the screen.
|
|
|
|
|
* - Allocate new arrays for ScreenLines and ScreenAttrs.
|
|
|
|
|
* - 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 ScreenLines NULL, so we don't do anything!
|
|
|
|
|
* Continuing with the old ScreenLines may result in a crash, because the
|
|
|
|
|
* size is wrong.
|
|
|
|
|
*/
|
2006-02-16 22:11:02 +00:00
|
|
|
FOR_ALL_TAB_WINDOWS(tp, wp)
|
2004-06-13 20:20:40 +00:00
|
|
|
win_free_lsize(wp);
|
2022-11-28 18:51:43 +00:00
|
|
|
for (int i = 0; i < AUCMD_WIN_COUNT; ++i)
|
2022-11-28 20:34:52 +00:00
|
|
|
if (aucmd_win[i].auc_win != NULL)
|
2022-11-28 18:51:43 +00:00
|
|
|
win_free_lsize(aucmd_win[i].auc_win);
|
2019-11-30 22:48:27 +01:00
|
|
|
#ifdef FEAT_PROP_POPUP
|
2019-06-01 18:11:22 +02:00
|
|
|
// global popup windows
|
2020-04-02 18:50:46 +02:00
|
|
|
FOR_ALL_POPUPWINS(wp)
|
2019-06-01 18:11:22 +02:00
|
|
|
win_free_lsize(wp);
|
|
|
|
|
// tab-local popup windows
|
|
|
|
|
FOR_ALL_TABPAGES(tp)
|
2020-04-02 18:50:46 +02:00
|
|
|
FOR_ALL_POPUPWINS_IN_TAB(tp, wp)
|
2019-06-01 18:11:22 +02:00
|
|
|
win_free_lsize(wp);
|
|
|
|
|
#endif
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-05-28 23:08:19 +02:00
|
|
|
new_ScreenLines = LALLOC_MULT(schar_T, (Rows + 1) * Columns);
|
2010-03-23 13:56:59 +01:00
|
|
|
vim_memset(new_ScreenLinesC, 0, sizeof(u8char_T *) * MAX_MCO);
|
2004-06-13 20:20:40 +00:00
|
|
|
if (enc_utf8)
|
|
|
|
|
{
|
2019-05-28 23:08:19 +02:00
|
|
|
new_ScreenLinesUC = LALLOC_MULT(u8char_T, (Rows + 1) * Columns);
|
2022-11-28 18:51:43 +00:00
|
|
|
for (int i = 0; i < p_mco; ++i)
|
2019-05-28 23:08:19 +02:00
|
|
|
new_ScreenLinesC[i] = LALLOC_CLEAR_MULT(u8char_T,
|
|
|
|
|
(Rows + 1) * Columns);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
if (enc_dbcs == DBCS_JPNU)
|
2019-05-28 23:08:19 +02:00
|
|
|
new_ScreenLines2 = LALLOC_MULT(schar_T, (Rows + 1) * Columns);
|
|
|
|
|
new_ScreenAttrs = LALLOC_MULT(sattr_T, (Rows + 1) * Columns);
|
2022-11-02 13:30:51 +00:00
|
|
|
// Clear ScreenCols to avoid a warning for uninitialized memory in
|
2022-09-19 11:44:11 +01:00
|
|
|
// jump_to_mouse().
|
|
|
|
|
new_ScreenCols = LALLOC_CLEAR_MULT(colnr_T, (Rows + 1) * Columns);
|
2019-05-28 23:08:19 +02:00
|
|
|
new_LineOffset = LALLOC_MULT(unsigned, Rows);
|
|
|
|
|
new_LineWraps = LALLOC_MULT(char_u, Rows);
|
|
|
|
|
new_TabPageIdxs = LALLOC_MULT(short, Columns);
|
2019-11-30 22:48:27 +01:00
|
|
|
#ifdef FEAT_PROP_POPUP
|
2019-06-08 16:01:13 +02:00
|
|
|
new_popup_mask = LALLOC_MULT(short, Rows * Columns);
|
2019-06-10 21:24:12 +02:00
|
|
|
new_popup_mask_next = LALLOC_MULT(short, Rows * Columns);
|
2019-06-23 00:15:57 +02:00
|
|
|
new_popup_transparent = LALLOC_MULT(char, Rows * Columns);
|
2019-06-08 16:01:13 +02:00
|
|
|
#endif
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2006-02-20 21:37:40 +00:00
|
|
|
FOR_ALL_TAB_WINDOWS(tp, wp)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
if (win_alloc_lines(wp) == FAIL)
|
|
|
|
|
{
|
|
|
|
|
outofmem = TRUE;
|
2009-02-21 23:03:09 +00:00
|
|
|
goto give_up;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
2022-11-28 18:51:43 +00:00
|
|
|
for (int i = 0; i < AUCMD_WIN_COUNT; ++i)
|
2022-11-28 20:34:52 +00:00
|
|
|
if (aucmd_win[i].auc_win != NULL
|
2022-11-28 18:51:43 +00:00
|
|
|
&& aucmd_win[i].auc_win->w_lines == NULL
|
|
|
|
|
&& win_alloc_lines(aucmd_win[i].auc_win) == FAIL)
|
|
|
|
|
{
|
|
|
|
|
outofmem = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-11-30 22:48:27 +01:00
|
|
|
#ifdef FEAT_PROP_POPUP
|
2019-06-01 18:11:22 +02:00
|
|
|
// global popup windows
|
2020-04-02 18:50:46 +02:00
|
|
|
FOR_ALL_POPUPWINS(wp)
|
2019-06-01 18:11:22 +02:00
|
|
|
if (win_alloc_lines(wp) == FAIL)
|
|
|
|
|
{
|
|
|
|
|
outofmem = TRUE;
|
|
|
|
|
goto give_up;
|
|
|
|
|
}
|
|
|
|
|
// tab-local popup windows
|
|
|
|
|
FOR_ALL_TABPAGES(tp)
|
2020-04-02 18:50:46 +02:00
|
|
|
FOR_ALL_POPUPWINS_IN_TAB(tp, wp)
|
2019-06-01 18:11:22 +02:00
|
|
|
if (win_alloc_lines(wp) == FAIL)
|
|
|
|
|
{
|
|
|
|
|
outofmem = TRUE;
|
|
|
|
|
goto give_up;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2009-02-21 23:03:09 +00:00
|
|
|
give_up:
|
2022-11-28 19:11:02 +00:00
|
|
|
found_null = FALSE;
|
2022-11-28 18:51:43 +00:00
|
|
|
for (int i = 0; i < p_mco; ++i)
|
2006-03-06 23:29:24 +00:00
|
|
|
if (new_ScreenLinesC[i] == NULL)
|
2022-11-28 18:51:43 +00:00
|
|
|
{
|
|
|
|
|
found_null = TRUE;
|
2006-03-06 23:29:24 +00:00
|
|
|
break;
|
2022-11-28 18:51:43 +00:00
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
if (new_ScreenLines == NULL
|
2022-11-28 18:51:43 +00:00
|
|
|
|| (enc_utf8 && (new_ScreenLinesUC == NULL || found_null))
|
2004-06-13 20:20:40 +00:00
|
|
|
|| (enc_dbcs == DBCS_JPNU && new_ScreenLines2 == NULL)
|
|
|
|
|
|| new_ScreenAttrs == NULL
|
2022-07-09 04:56:24 +01:00
|
|
|
|| new_ScreenCols == NULL
|
2004-06-13 20:20:40 +00:00
|
|
|
|| new_LineOffset == NULL
|
|
|
|
|
|| new_LineWraps == NULL
|
2006-02-16 22:11:02 +00:00
|
|
|
|| new_TabPageIdxs == NULL
|
2019-11-30 22:48:27 +01:00
|
|
|
#ifdef FEAT_PROP_POPUP
|
2019-06-08 16:01:13 +02:00
|
|
|
|| new_popup_mask == NULL
|
2019-06-10 21:24:12 +02:00
|
|
|
|| new_popup_mask_next == NULL
|
2019-06-23 00:15:57 +02:00
|
|
|
|| new_popup_transparent == NULL
|
2019-06-08 16:01:13 +02:00
|
|
|
#endif
|
2004-06-13 20:20:40 +00:00
|
|
|
|| outofmem)
|
|
|
|
|
{
|
2006-08-29 15:30:07 +00:00
|
|
|
if (ScreenLines != NULL || !done_outofmem_msg)
|
2005-09-29 18:26:07 +00:00
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
// guess the size
|
2005-09-29 18:26:07 +00:00
|
|
|
do_outofmem_msg((long_u)((Rows + 1) * Columns));
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// Remember we did this to avoid getting outofmem messages over
|
|
|
|
|
// and over again.
|
2006-08-29 15:30:07 +00:00
|
|
|
done_outofmem_msg = TRUE;
|
2005-09-29 18:26:07 +00:00
|
|
|
}
|
2018-02-10 18:45:26 +01:00
|
|
|
VIM_CLEAR(new_ScreenLines);
|
|
|
|
|
VIM_CLEAR(new_ScreenLinesUC);
|
2022-11-28 18:51:43 +00:00
|
|
|
for (int i = 0; i < p_mco; ++i)
|
2018-02-10 18:45:26 +01:00
|
|
|
VIM_CLEAR(new_ScreenLinesC[i]);
|
|
|
|
|
VIM_CLEAR(new_ScreenLines2);
|
|
|
|
|
VIM_CLEAR(new_ScreenAttrs);
|
2022-07-09 04:56:24 +01:00
|
|
|
VIM_CLEAR(new_ScreenCols);
|
2018-02-10 18:45:26 +01:00
|
|
|
VIM_CLEAR(new_LineOffset);
|
|
|
|
|
VIM_CLEAR(new_LineWraps);
|
|
|
|
|
VIM_CLEAR(new_TabPageIdxs);
|
2019-11-30 22:48:27 +01:00
|
|
|
#ifdef FEAT_PROP_POPUP
|
2019-06-08 16:01:13 +02:00
|
|
|
VIM_CLEAR(new_popup_mask);
|
2019-06-10 21:24:12 +02:00
|
|
|
VIM_CLEAR(new_popup_mask_next);
|
2019-06-23 00:15:57 +02:00
|
|
|
VIM_CLEAR(new_popup_transparent);
|
2019-06-08 16:01:13 +02:00
|
|
|
#endif
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2006-08-29 15:30:07 +00:00
|
|
|
done_outofmem_msg = FALSE;
|
2005-09-29 18:26:07 +00:00
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
for (new_row = 0; new_row < Rows; ++new_row)
|
|
|
|
|
{
|
|
|
|
|
new_LineOffset[new_row] = new_row * Columns;
|
|
|
|
|
new_LineWraps[new_row] = FALSE;
|
|
|
|
|
|
2024-02-01 21:11:16 +01:00
|
|
|
(void)vim_memset(new_ScreenLines + new_row * Columns,
|
|
|
|
|
' ', (size_t)Columns * sizeof(schar_T));
|
|
|
|
|
if (enc_utf8)
|
|
|
|
|
{
|
|
|
|
|
(void)vim_memset(new_ScreenLinesUC + new_row * Columns,
|
|
|
|
|
0, (size_t)Columns * sizeof(u8char_T));
|
|
|
|
|
for (int i = 0; i < p_mco; ++i)
|
|
|
|
|
(void)vim_memset(new_ScreenLinesC[i]
|
|
|
|
|
+ new_row * Columns,
|
|
|
|
|
0, (size_t)Columns * sizeof(u8char_T));
|
|
|
|
|
}
|
|
|
|
|
if (enc_dbcs == DBCS_JPNU)
|
|
|
|
|
(void)vim_memset(new_ScreenLines2 + new_row * Columns,
|
|
|
|
|
0, (size_t)Columns * sizeof(schar_T));
|
|
|
|
|
(void)vim_memset(new_ScreenAttrs + new_row * Columns,
|
|
|
|
|
0, (size_t)Columns * sizeof(sattr_T));
|
|
|
|
|
(void)vim_memset(new_ScreenCols + new_row * Columns,
|
|
|
|
|
0, (size_t)Columns * sizeof(colnr_T));
|
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
|
|
|
|
* 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).
|
|
|
|
|
*/
|
2012-01-10 22:26:17 +01:00
|
|
|
if (!doclear)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
old_row = new_row + (screen_Rows - Rows);
|
2005-09-29 18:26:07 +00:00
|
|
|
if (old_row >= 0 && ScreenLines != NULL)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
if (screen_Columns < Columns)
|
|
|
|
|
len = screen_Columns;
|
|
|
|
|
else
|
|
|
|
|
len = Columns;
|
2019-12-05 21:10:38 +01:00
|
|
|
// When switching to utf-8 don't copy characters, they
|
|
|
|
|
// may be invalid now. Also when p_mco changes.
|
2006-03-06 23:29:24 +00:00
|
|
|
if (!(enc_utf8 && ScreenLinesUC == NULL)
|
|
|
|
|
&& p_mco == Screen_mco)
|
2004-10-07 21:02:47 +00:00
|
|
|
mch_memmove(new_ScreenLines + new_LineOffset[new_row],
|
|
|
|
|
ScreenLines + LineOffset[old_row],
|
|
|
|
|
(size_t)len * sizeof(schar_T));
|
2006-03-06 23:29:24 +00:00
|
|
|
if (enc_utf8 && ScreenLinesUC != NULL
|
|
|
|
|
&& p_mco == Screen_mco)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
mch_memmove(new_ScreenLinesUC + new_LineOffset[new_row],
|
|
|
|
|
ScreenLinesUC + LineOffset[old_row],
|
|
|
|
|
(size_t)len * sizeof(u8char_T));
|
2022-11-28 18:51:43 +00:00
|
|
|
for (int i = 0; i < p_mco; ++i)
|
2006-03-06 23:29:24 +00:00
|
|
|
mch_memmove(new_ScreenLinesC[i]
|
|
|
|
|
+ new_LineOffset[new_row],
|
|
|
|
|
ScreenLinesC[i] + LineOffset[old_row],
|
2004-06-13 20:20:40 +00:00
|
|
|
(size_t)len * sizeof(u8char_T));
|
|
|
|
|
}
|
|
|
|
|
if (enc_dbcs == DBCS_JPNU && ScreenLines2 != NULL)
|
|
|
|
|
mch_memmove(new_ScreenLines2 + new_LineOffset[new_row],
|
|
|
|
|
ScreenLines2 + LineOffset[old_row],
|
|
|
|
|
(size_t)len * sizeof(schar_T));
|
|
|
|
|
mch_memmove(new_ScreenAttrs + new_LineOffset[new_row],
|
|
|
|
|
ScreenAttrs + LineOffset[old_row],
|
|
|
|
|
(size_t)len * sizeof(sattr_T));
|
2022-07-09 04:56:24 +01:00
|
|
|
mch_memmove(new_ScreenCols + new_LineOffset[new_row],
|
|
|
|
|
ScreenAttrs + LineOffset[old_row],
|
|
|
|
|
(size_t)len * sizeof(colnr_T));
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-12-05 21:10:38 +01:00
|
|
|
// Use the last line of the screen for the current line.
|
2004-06-13 20:20:40 +00:00
|
|
|
current_ScreenLine = new_ScreenLines + Rows * Columns;
|
2019-08-13 23:09:49 +02:00
|
|
|
|
2019-11-30 22:48:27 +01:00
|
|
|
#ifdef FEAT_PROP_POPUP
|
2019-08-13 23:09:49 +02:00
|
|
|
vim_memset(new_popup_mask, 0, Rows * Columns * sizeof(short));
|
|
|
|
|
vim_memset(new_popup_transparent, 0, Rows * Columns * sizeof(char));
|
|
|
|
|
#endif
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
2005-06-24 23:07:47 +00:00
|
|
|
free_screenlines();
|
|
|
|
|
|
2019-08-13 23:09:49 +02:00
|
|
|
// NOTE: this may result in all pointers to become NULL.
|
2004-06-13 20:20:40 +00:00
|
|
|
ScreenLines = new_ScreenLines;
|
|
|
|
|
ScreenLinesUC = new_ScreenLinesUC;
|
2022-11-28 18:51:43 +00:00
|
|
|
for (int i = 0; i < p_mco; ++i)
|
2006-03-06 23:29:24 +00:00
|
|
|
ScreenLinesC[i] = new_ScreenLinesC[i];
|
|
|
|
|
Screen_mco = p_mco;
|
2004-06-13 20:20:40 +00:00
|
|
|
ScreenLines2 = new_ScreenLines2;
|
|
|
|
|
ScreenAttrs = new_ScreenAttrs;
|
2022-07-09 04:56:24 +01:00
|
|
|
ScreenCols = new_ScreenCols;
|
2004-06-13 20:20:40 +00:00
|
|
|
LineOffset = new_LineOffset;
|
|
|
|
|
LineWraps = new_LineWraps;
|
2006-02-16 22:11:02 +00:00
|
|
|
TabPageIdxs = new_TabPageIdxs;
|
2019-11-30 22:48:27 +01:00
|
|
|
#ifdef FEAT_PROP_POPUP
|
2019-06-08 16:01:13 +02:00
|
|
|
popup_mask = new_popup_mask;
|
2019-06-23 00:15:57 +02:00
|
|
|
popup_mask_next = new_popup_mask_next;
|
|
|
|
|
popup_transparent = new_popup_transparent;
|
2019-06-08 16:01:13 +02:00
|
|
|
popup_mask_refresh = TRUE;
|
|
|
|
|
#endif
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// It's important that screen_Rows and screen_Columns reflect the actual
|
|
|
|
|
// size of ScreenLines[]. Set them before calling anything.
|
2004-06-13 20:20:40 +00:00
|
|
|
#ifdef FEAT_GUI
|
|
|
|
|
old_Rows = screen_Rows;
|
|
|
|
|
#endif
|
|
|
|
|
screen_Rows = Rows;
|
|
|
|
|
screen_Columns = Columns;
|
|
|
|
|
|
2022-08-22 15:19:16 +01:00
|
|
|
set_must_redraw(UPD_CLEAR); // need to clear the screen later
|
2012-01-10 22:26:17 +01:00
|
|
|
if (doclear)
|
2022-08-29 13:44:28 +01:00
|
|
|
screenclear2(TRUE);
|
2004-06-13 20:20:40 +00:00
|
|
|
#ifdef FEAT_GUI
|
|
|
|
|
else if (gui.in_use
|
|
|
|
|
&& !gui.starting
|
|
|
|
|
&& ScreenLines != NULL
|
|
|
|
|
&& old_Rows != Rows)
|
|
|
|
|
{
|
2020-03-28 20:44:41 +01:00
|
|
|
gui_redraw_block(0, 0, (int)Rows - 1, (int)Columns - 1, 0);
|
|
|
|
|
|
|
|
|
|
// Adjust the position of the cursor, for when executing an external
|
|
|
|
|
// command.
|
2019-12-05 21:10:38 +01:00
|
|
|
if (msg_row >= Rows) // Rows got smaller
|
|
|
|
|
msg_row = Rows - 1; // put cursor at last row
|
|
|
|
|
else if (Rows > old_Rows) // Rows got bigger
|
|
|
|
|
msg_row += Rows - old_Rows; // put cursor in same place
|
|
|
|
|
if (msg_col >= Columns) // Columns got smaller
|
|
|
|
|
msg_col = Columns - 1; // put cursor at last column
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
#endif
|
2019-04-13 14:53:16 +02:00
|
|
|
clear_TabPageIdxs();
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2020-02-26 16:16:53 +01:00
|
|
|
#ifdef FEAT_GUI_HAIKU
|
|
|
|
|
vim_unlock_screen();
|
|
|
|
|
#endif
|
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
entered = FALSE;
|
2023-05-20 14:07:00 +01:00
|
|
|
if (RedrawingDisabled > 0)
|
|
|
|
|
--RedrawingDisabled;
|
2006-03-15 22:59:18 +00:00
|
|
|
|
2009-02-22 20:13:39 +00:00
|
|
|
/*
|
|
|
|
|
* Do not apply autocommands more than 3 times to avoid an endless loop
|
|
|
|
|
* in case applying autocommands always changes Rows or Columns.
|
|
|
|
|
*/
|
|
|
|
|
if (starting == 0 && ++retry_count <= 3)
|
|
|
|
|
{
|
2006-03-15 22:59:18 +00:00
|
|
|
apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, FALSE, curbuf);
|
2019-12-05 21:10:38 +01:00
|
|
|
// In rare cases, autocommands may have altered Rows or Columns,
|
|
|
|
|
// jump back to check if we need to allocate the screen again.
|
2009-02-22 20:13:39 +00:00
|
|
|
goto retry;
|
|
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
2005-06-24 23:07:47 +00:00
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
free_screenlines(void)
|
2005-06-24 23:07:47 +00:00
|
|
|
{
|
2006-03-06 23:29:24 +00:00
|
|
|
int i;
|
|
|
|
|
|
2019-06-08 16:01:13 +02:00
|
|
|
VIM_CLEAR(ScreenLinesUC);
|
2006-03-06 23:29:24 +00:00
|
|
|
for (i = 0; i < Screen_mco; ++i)
|
2019-06-08 16:01:13 +02:00
|
|
|
VIM_CLEAR(ScreenLinesC[i]);
|
|
|
|
|
VIM_CLEAR(ScreenLines2);
|
|
|
|
|
VIM_CLEAR(ScreenLines);
|
|
|
|
|
VIM_CLEAR(ScreenAttrs);
|
2022-07-09 04:56:24 +01:00
|
|
|
VIM_CLEAR(ScreenCols);
|
2019-06-08 16:01:13 +02:00
|
|
|
VIM_CLEAR(LineOffset);
|
|
|
|
|
VIM_CLEAR(LineWraps);
|
|
|
|
|
VIM_CLEAR(TabPageIdxs);
|
2019-11-30 22:48:27 +01:00
|
|
|
#ifdef FEAT_PROP_POPUP
|
2019-06-08 16:01:13 +02:00
|
|
|
VIM_CLEAR(popup_mask);
|
2019-06-10 21:24:12 +02:00
|
|
|
VIM_CLEAR(popup_mask_next);
|
2019-06-23 00:15:57 +02:00
|
|
|
VIM_CLEAR(popup_transparent);
|
2019-06-08 16:01:13 +02:00
|
|
|
#endif
|
2005-06-24 23:07:47 +00:00
|
|
|
}
|
|
|
|
|
|
2022-08-29 13:44:28 +01:00
|
|
|
/*
|
|
|
|
|
* Clear the screen.
|
|
|
|
|
* May delay if there is something the user should read.
|
|
|
|
|
* Allocated the screen for resizing if needed.
|
2022-10-01 19:43:52 +01:00
|
|
|
* Returns TRUE when the screen was actually cleared, FALSE if all display
|
2022-09-26 15:19:56 +01:00
|
|
|
* cells were marked for updating.
|
2022-08-29 13:44:28 +01:00
|
|
|
*/
|
2022-09-26 15:19:56 +01:00
|
|
|
int
|
2016-01-30 20:31:25 +01:00
|
|
|
screenclear(void)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
check_for_delay(FALSE);
|
2022-09-26 15:19:56 +01:00
|
|
|
screenalloc(FALSE); // allocate screen buffers if size changed
|
|
|
|
|
return screenclear2(TRUE); // clear the screen
|
2022-08-29 13:44:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Do not clear the screen but mark everything for redraw.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
redraw_as_cleared(void)
|
|
|
|
|
{
|
|
|
|
|
screenclear2(FALSE);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
2022-09-26 15:19:56 +01:00
|
|
|
static int
|
2022-08-29 13:44:28 +01:00
|
|
|
screenclear2(int doclear)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
int i;
|
2022-09-26 15:19:56 +01:00
|
|
|
int did_clear = FALSE;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
|
if (starting == NO_SCREEN || ScreenLines == NULL
|
|
|
|
|
#ifdef FEAT_GUI
|
|
|
|
|
|| (gui.in_use && gui.starting)
|
|
|
|
|
#endif
|
|
|
|
|
)
|
2022-09-26 15:19:56 +01:00
|
|
|
return FALSE;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
|
#ifdef FEAT_GUI
|
|
|
|
|
if (!gui.in_use)
|
|
|
|
|
#endif
|
2019-12-05 21:10:38 +01:00
|
|
|
screen_attr = -1; // force setting the Normal colors
|
|
|
|
|
screen_stop_highlight(); // don't want highlighting here
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
|
#ifdef FEAT_CLIPBOARD
|
2019-12-05 21:10:38 +01:00
|
|
|
// disable selection without redrawing it
|
2004-06-13 20:20:40 +00:00
|
|
|
clip_scroll_selection(9999);
|
|
|
|
|
#endif
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// blank out ScreenLines
|
2004-06-13 20:20:40 +00:00
|
|
|
for (i = 0; i < Rows; ++i)
|
|
|
|
|
{
|
2017-08-17 20:31:48 +02:00
|
|
|
lineclear(LineOffset[i], (int)Columns, 0);
|
2004-06-13 20:20:40 +00:00
|
|
|
LineWraps[i] = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-29 13:44:28 +01:00
|
|
|
if (doclear && can_clear(T_CL))
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
out_str(T_CL); // clear the display
|
2022-09-26 15:19:56 +01:00
|
|
|
did_clear = TRUE;
|
2004-06-13 20:20:40 +00:00
|
|
|
clear_cmdline = FALSE;
|
2006-01-25 22:10:52 +00:00
|
|
|
mode_displayed = FALSE;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
// can't clear the screen, mark all chars with invalid attributes
|
2004-06-13 20:20:40 +00:00
|
|
|
for (i = 0; i < Rows; ++i)
|
|
|
|
|
lineinvalid(LineOffset[i], (int)Columns);
|
|
|
|
|
clear_cmdline = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
screen_cleared = TRUE; // can use contents of ScreenLines now
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2022-08-29 13:44:28 +01:00
|
|
|
win_rest_invalid(firstwin); // redraw all regular windows
|
2004-06-13 20:20:40 +00:00
|
|
|
redraw_cmdline = TRUE;
|
2006-02-17 21:53:23 +00:00
|
|
|
redraw_tabline = TRUE;
|
2022-08-14 14:17:45 +01:00
|
|
|
if (must_redraw == UPD_CLEAR) // no need to clear again
|
|
|
|
|
must_redraw = UPD_NOT_VALID;
|
2022-09-11 21:36:17 +01:00
|
|
|
msg_scrolled = 0; // compute_cmdrow() uses this
|
2004-06-13 20:20:40 +00:00
|
|
|
compute_cmdrow();
|
2022-09-11 21:36:17 +01:00
|
|
|
#ifdef FEAT_PROP_POPUP
|
|
|
|
|
popup_redraw_all(); // redraw all popup windows
|
|
|
|
|
#endif
|
2019-12-05 21:10:38 +01:00
|
|
|
msg_row = cmdline_row; // put cursor on last line for messages
|
2004-06-13 20:20:40 +00:00
|
|
|
msg_col = 0;
|
2019-12-05 21:10:38 +01:00
|
|
|
screen_start(); // don't know where cursor is now
|
2004-06-13 20:20:40 +00:00
|
|
|
msg_didany = FALSE;
|
|
|
|
|
msg_didout = FALSE;
|
2022-09-26 15:19:56 +01:00
|
|
|
|
|
|
|
|
return did_clear;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Clear one line in ScreenLines.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2017-08-17 20:31:48 +02:00
|
|
|
lineclear(unsigned off, int width, int attr)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
(void)vim_memset(ScreenLines + off, ' ', (size_t)width * sizeof(schar_T));
|
|
|
|
|
if (enc_utf8)
|
|
|
|
|
(void)vim_memset(ScreenLinesUC + off, 0,
|
|
|
|
|
(size_t)width * sizeof(u8char_T));
|
2017-08-17 20:31:48 +02:00
|
|
|
(void)vim_memset(ScreenAttrs + off, attr, (size_t)width * sizeof(sattr_T));
|
2022-07-09 04:56:24 +01:00
|
|
|
(void)vim_memset(ScreenCols + off, -1, (size_t)width * sizeof(colnr_T));
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Mark one line in ScreenLines invalid by setting the attributes to an
|
|
|
|
|
* invalid value.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2016-01-30 20:31:25 +01:00
|
|
|
lineinvalid(unsigned off, int width)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
(void)vim_memset(ScreenAttrs + off, -1, (size_t)width * sizeof(sattr_T));
|
2022-07-09 04:56:24 +01:00
|
|
|
(void)vim_memset(ScreenCols + off, -1, (size_t)width * sizeof(colnr_T));
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
2020-07-08 23:09:28 +02:00
|
|
|
/*
|
|
|
|
|
* To be called when characters were sent to the terminal directly, outputting
|
|
|
|
|
* test on "screen_lnum".
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
line_was_clobbered(int screen_lnum)
|
|
|
|
|
{
|
|
|
|
|
lineinvalid(LineOffset[screen_lnum], (int)Columns);
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
|
|
|
|
* Copy part of a Screenline for vertically split window "wp".
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2016-01-30 20:31:25 +01:00
|
|
|
linecopy(int to, int from, win_T *wp)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
unsigned off_to = LineOffset[to] + wp->w_wincol;
|
|
|
|
|
unsigned off_from = LineOffset[from] + wp->w_wincol;
|
|
|
|
|
|
|
|
|
|
mch_memmove(ScreenLines + off_to, ScreenLines + off_from,
|
|
|
|
|
wp->w_width * sizeof(schar_T));
|
|
|
|
|
if (enc_utf8)
|
|
|
|
|
{
|
2006-03-06 23:29:24 +00:00
|
|
|
int i;
|
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
mch_memmove(ScreenLinesUC + off_to, ScreenLinesUC + off_from,
|
|
|
|
|
wp->w_width * sizeof(u8char_T));
|
2006-03-06 23:29:24 +00:00
|
|
|
for (i = 0; i < p_mco; ++i)
|
|
|
|
|
mch_memmove(ScreenLinesC[i] + off_to, ScreenLinesC[i] + off_from,
|
|
|
|
|
wp->w_width * sizeof(u8char_T));
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
if (enc_dbcs == DBCS_JPNU)
|
|
|
|
|
mch_memmove(ScreenLines2 + off_to, ScreenLines2 + off_from,
|
|
|
|
|
wp->w_width * sizeof(schar_T));
|
|
|
|
|
mch_memmove(ScreenAttrs + off_to, ScreenAttrs + off_from,
|
|
|
|
|
wp->w_width * sizeof(sattr_T));
|
2022-07-09 04:56:24 +01:00
|
|
|
mch_memmove(ScreenCols + off_to, ScreenCols + off_from,
|
|
|
|
|
wp->w_width * sizeof(colnr_T));
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Return TRUE if clearing with term string "p" would work.
|
|
|
|
|
* It can't work when the string is empty or it won't set the right background.
|
2019-06-08 16:01:13 +02:00
|
|
|
* Don't clear to end-of-line when there are popups, it may cause flicker.
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
|
|
|
|
int
|
2016-01-30 20:31:25 +01:00
|
|
|
can_clear(char_u *p)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
return (*p != NUL && (t_colors <= 1
|
|
|
|
|
#ifdef FEAT_GUI
|
|
|
|
|
|| gui.in_use
|
2016-04-21 21:10:14 +02:00
|
|
|
#endif
|
2016-04-29 22:59:22 +02:00
|
|
|
#ifdef FEAT_TERMGUICOLORS
|
2016-08-22 23:04:33 +02:00
|
|
|
|| (p_tgc && cterm_normal_bg_gui_color == INVALCOLOR)
|
2016-06-17 13:18:49 +02:00
|
|
|
|| (!p_tgc && cterm_normal_bg_color == 0)
|
|
|
|
|
#else
|
|
|
|
|
|| cterm_normal_bg_color == 0
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
2019-06-08 16:01:13 +02:00
|
|
|
|| *T_UT != NUL)
|
2019-11-30 22:48:27 +01:00
|
|
|
#ifdef FEAT_PROP_POPUP
|
2019-06-08 16:01:13 +02:00
|
|
|
&& !(p == T_CE && popup_visible)
|
|
|
|
|
#endif
|
|
|
|
|
);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Reset cursor position. Use whenever cursor was moved because of outputting
|
|
|
|
|
* something directly to the screen (shell commands) or a terminal control
|
|
|
|
|
* code.
|
|
|
|
|
*/
|
|
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
screen_start(void)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
screen_cur_row = screen_cur_col = 9999;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Move the cursor to position "row","col" in the screen.
|
|
|
|
|
* This tries to find the most efficient way to move, minimizing the number of
|
|
|
|
|
* characters sent to the terminal.
|
|
|
|
|
*/
|
|
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
windgoto(int row, int col)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2005-03-15 22:43:58 +00:00
|
|
|
sattr_T *p;
|
2004-06-13 20:20:40 +00:00
|
|
|
int i;
|
|
|
|
|
int plan;
|
|
|
|
|
int cost;
|
|
|
|
|
int wouldbe_col;
|
|
|
|
|
int noinvcurs;
|
|
|
|
|
char_u *bs;
|
|
|
|
|
int goto_cost;
|
|
|
|
|
int attr;
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
#define GOTO_COST 7 // assume a term_windgoto() takes about 7 chars
|
|
|
|
|
#define HIGHL_COST 5 // assume unhighlight takes 5 chars
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
|
#define PLAN_LE 1
|
|
|
|
|
#define PLAN_CR 2
|
|
|
|
|
#define PLAN_NL 3
|
|
|
|
|
#define PLAN_WRITE 4
|
2019-12-05 21:10:38 +01:00
|
|
|
// Can't use ScreenLines unless initialized
|
2004-06-13 20:20:40 +00:00
|
|
|
if (ScreenLines == NULL)
|
|
|
|
|
return;
|
2023-01-23 20:46:21 +00:00
|
|
|
if (col == screen_cur_col && row == screen_cur_row)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// Check for valid position.
|
|
|
|
|
if (row < 0) // window without text lines?
|
|
|
|
|
row = 0;
|
|
|
|
|
if (row >= screen_Rows)
|
|
|
|
|
row = screen_Rows - 1;
|
|
|
|
|
if (col >= screen_Columns)
|
|
|
|
|
col = screen_Columns - 1;
|
|
|
|
|
|
|
|
|
|
// check if no cursor movement is allowed in highlight mode
|
|
|
|
|
if (screen_attr && *T_MS == NUL)
|
|
|
|
|
noinvcurs = HIGHL_COST;
|
|
|
|
|
else
|
|
|
|
|
noinvcurs = 0;
|
|
|
|
|
goto_cost = GOTO_COST + noinvcurs;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2023-01-23 20:46:21 +00:00
|
|
|
/*
|
|
|
|
|
* Plan how to do the positioning:
|
|
|
|
|
* 1. Use CR to move it to column 0, same row.
|
|
|
|
|
* 2. Use T_LE to move it a few columns to the left.
|
|
|
|
|
* 3. Use NL to move a few lines down, column 0.
|
|
|
|
|
* 4. Move a few columns to the right with T_ND or by writing chars.
|
|
|
|
|
*
|
|
|
|
|
* Don't do this if the cursor went beyond the last column, the cursor
|
|
|
|
|
* position is unknown then (some terminals wrap, some don't )
|
|
|
|
|
*
|
|
|
|
|
* First check if the highlighting attributes allow us to write
|
|
|
|
|
* characters to move the cursor to the right.
|
|
|
|
|
*/
|
|
|
|
|
if (row >= screen_cur_row && screen_cur_col < Columns)
|
|
|
|
|
{
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
2023-01-23 20:46:21 +00:00
|
|
|
* If the cursor is in the same row, bigger col, we can use CR
|
|
|
|
|
* or T_LE.
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
2023-01-23 20:46:21 +00:00
|
|
|
bs = NULL; // init for GCC
|
|
|
|
|
attr = screen_attr;
|
|
|
|
|
if (row == screen_cur_row && col < screen_cur_col)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2023-01-23 20:46:21 +00:00
|
|
|
// "le" is preferred over "bc", because "bc" is obsolete
|
|
|
|
|
if (*T_LE)
|
|
|
|
|
bs = T_LE; // "cursor left"
|
|
|
|
|
else
|
|
|
|
|
bs = T_BC; // "backspace character (old)
|
|
|
|
|
if (*bs)
|
|
|
|
|
cost = (screen_cur_col - col) * (int)STRLEN(bs);
|
|
|
|
|
else
|
|
|
|
|
cost = 999;
|
|
|
|
|
if (col + 1 < cost) // using CR is less characters
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2023-01-23 20:46:21 +00:00
|
|
|
plan = PLAN_CR;
|
|
|
|
|
wouldbe_col = 0;
|
|
|
|
|
cost = 1; // CR is just one character
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2023-01-23 20:46:21 +00:00
|
|
|
else
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2023-01-23 20:46:21 +00:00
|
|
|
plan = PLAN_LE;
|
|
|
|
|
wouldbe_col = col;
|
|
|
|
|
}
|
|
|
|
|
if (noinvcurs) // will stop highlighting
|
|
|
|
|
{
|
|
|
|
|
cost += noinvcurs;
|
|
|
|
|
attr = 0;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2023-01-23 20:46:21 +00:00
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2023-01-23 20:46:21 +00:00
|
|
|
/*
|
|
|
|
|
* If the cursor is above where we want to be, we can use CR LF.
|
|
|
|
|
*/
|
|
|
|
|
else if (row > screen_cur_row)
|
|
|
|
|
{
|
|
|
|
|
plan = PLAN_NL;
|
|
|
|
|
wouldbe_col = 0;
|
|
|
|
|
cost = (row - screen_cur_row) * 2; // CR LF
|
|
|
|
|
if (noinvcurs) // will stop highlighting
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2023-01-23 20:46:21 +00:00
|
|
|
cost += noinvcurs;
|
|
|
|
|
attr = 0;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2023-01-23 20:46:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the cursor is in the same row, smaller col, just use write.
|
|
|
|
|
*/
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
plan = PLAN_WRITE;
|
|
|
|
|
wouldbe_col = screen_cur_col;
|
|
|
|
|
cost = 0;
|
|
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2023-01-23 20:46:21 +00:00
|
|
|
/*
|
|
|
|
|
* Check if any characters that need to be written have the
|
|
|
|
|
* correct attributes. Also avoid UTF-8 characters.
|
|
|
|
|
*/
|
|
|
|
|
i = col - wouldbe_col;
|
|
|
|
|
if (i > 0)
|
|
|
|
|
cost += i;
|
|
|
|
|
if (cost < goto_cost && i > 0)
|
|
|
|
|
{
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
2023-01-23 20:46:21 +00:00
|
|
|
* Check if the attributes are correct without additionally
|
|
|
|
|
* stopping highlighting.
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
2023-01-23 20:46:21 +00:00
|
|
|
p = ScreenAttrs + LineOffset[row] + wouldbe_col;
|
|
|
|
|
while (i && *p++ == attr)
|
|
|
|
|
--i;
|
|
|
|
|
if (i != 0)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
/*
|
2023-01-23 20:46:21 +00:00
|
|
|
* Try if it works when highlighting is stopped here.
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
2023-01-23 20:46:21 +00:00
|
|
|
if (*--p == 0)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2023-01-23 20:46:21 +00:00
|
|
|
cost += noinvcurs;
|
|
|
|
|
while (i && *p++ == 0)
|
|
|
|
|
--i;
|
|
|
|
|
}
|
|
|
|
|
if (i != 0)
|
|
|
|
|
cost = 999; // different attributes, don't do it
|
|
|
|
|
}
|
|
|
|
|
if (enc_utf8)
|
|
|
|
|
{
|
|
|
|
|
// Don't use an UTF-8 char for positioning, it's slow.
|
|
|
|
|
for (i = wouldbe_col; i < col; ++i)
|
|
|
|
|
if (ScreenLinesUC[LineOffset[row] + i] != 0)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2023-01-23 20:46:21 +00:00
|
|
|
cost = 999;
|
|
|
|
|
break;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
2023-01-23 20:46:21 +00:00
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2023-01-23 20:46:21 +00:00
|
|
|
/*
|
|
|
|
|
* We can do it without term_windgoto()!
|
|
|
|
|
*/
|
|
|
|
|
if (cost < goto_cost)
|
|
|
|
|
{
|
|
|
|
|
if (plan == PLAN_LE)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2023-01-23 20:46:21 +00:00
|
|
|
if (noinvcurs)
|
|
|
|
|
screen_stop_highlight();
|
|
|
|
|
while (screen_cur_col > col)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2023-01-23 20:46:21 +00:00
|
|
|
out_str(bs);
|
|
|
|
|
--screen_cur_col;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2023-01-23 20:46:21 +00:00
|
|
|
}
|
|
|
|
|
else if (plan == PLAN_CR)
|
|
|
|
|
{
|
|
|
|
|
if (noinvcurs)
|
|
|
|
|
screen_stop_highlight();
|
|
|
|
|
out_char('\r');
|
|
|
|
|
screen_cur_col = 0;
|
|
|
|
|
}
|
|
|
|
|
else if (plan == PLAN_NL)
|
|
|
|
|
{
|
|
|
|
|
if (noinvcurs)
|
|
|
|
|
screen_stop_highlight();
|
|
|
|
|
while (screen_cur_row < row)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2023-01-23 20:46:21 +00:00
|
|
|
out_char('\n');
|
|
|
|
|
++screen_cur_row;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2023-01-23 20:46:21 +00:00
|
|
|
screen_cur_col = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i = col - screen_cur_col;
|
|
|
|
|
if (i > 0)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Use cursor-right if it's one character only. Avoids
|
|
|
|
|
* removing a line of pixels from the last bold char, when
|
|
|
|
|
* using the bold trick in the GUI.
|
|
|
|
|
*/
|
|
|
|
|
if (T_ND[0] != NUL && T_ND[1] == NUL)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2023-01-23 20:46:21 +00:00
|
|
|
while (i-- > 0)
|
|
|
|
|
out_char(*T_ND);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2023-01-23 20:46:21 +00:00
|
|
|
else
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2023-01-23 20:46:21 +00:00
|
|
|
int off;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2023-01-23 20:46:21 +00:00
|
|
|
off = LineOffset[row] + screen_cur_col;
|
|
|
|
|
while (i-- > 0)
|
|
|
|
|
{
|
|
|
|
|
if (ScreenAttrs[off] != screen_attr)
|
|
|
|
|
screen_stop_highlight();
|
|
|
|
|
out_flush_check();
|
|
|
|
|
out_char(ScreenLines[off]);
|
|
|
|
|
if (enc_dbcs == DBCS_JPNU
|
|
|
|
|
&& ScreenLines[off] == 0x8e)
|
|
|
|
|
out_char(ScreenLines2[off]);
|
|
|
|
|
++off;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-01-23 20:46:21 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
cost = 999;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2023-01-23 20:46:21 +00:00
|
|
|
if (cost >= goto_cost)
|
|
|
|
|
{
|
|
|
|
|
if (noinvcurs)
|
|
|
|
|
screen_stop_highlight();
|
|
|
|
|
if (row == screen_cur_row && (col > screen_cur_col)
|
|
|
|
|
&& *T_CRI != NUL)
|
|
|
|
|
term_cursor_right(col - screen_cur_col);
|
|
|
|
|
else
|
|
|
|
|
term_windgoto(row, col);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2023-01-23 20:46:21 +00:00
|
|
|
screen_cur_row = row;
|
|
|
|
|
screen_cur_col = col;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set cursor to its position in the current window.
|
|
|
|
|
*/
|
|
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
setcursor(void)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2018-03-06 11:43:04 +01:00
|
|
|
setcursor_mayforce(FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set cursor to its position in the current window.
|
|
|
|
|
* When "force" is TRUE also when not redrawing.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
setcursor_mayforce(int force)
|
|
|
|
|
{
|
|
|
|
|
if (force || redrawing())
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
validate_cursor();
|
|
|
|
|
windgoto(W_WINROW(curwin) + curwin->w_wrow,
|
2017-09-22 14:35:51 +02:00
|
|
|
curwin->w_wincol + (
|
2004-06-13 20:20:40 +00:00
|
|
|
#ifdef FEAT_RIGHTLEFT
|
2019-12-05 21:10:38 +01:00
|
|
|
// With 'rightleft' set and the cursor on a double-wide
|
|
|
|
|
// character, position it on the leftmost column.
|
2019-01-24 16:39:02 +01:00
|
|
|
curwin->w_p_rl ? ((int)curwin->w_width - curwin->w_wcol
|
|
|
|
|
- ((has_mbyte
|
2008-02-20 13:16:29 +00:00
|
|
|
&& (*mb_ptr2cells)(ml_get_cursor()) == 2
|
2019-01-24 16:39:02 +01:00
|
|
|
&& vim_isprintc(gchar_cursor())) ? 2 : 1)) :
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
|
|
|
|
curwin->w_wcol));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2017-07-12 20:24:41 +02:00
|
|
|
* Insert 'line_count' lines at 'row' in window 'wp'.
|
|
|
|
|
* If 'invalid' is TRUE the wp->w_lines[].wl_lnum is invalidated.
|
|
|
|
|
* If 'mayclear' is TRUE the screen will be cleared if it is faster than
|
2004-06-13 20:20:40 +00:00
|
|
|
* scrolling.
|
|
|
|
|
* Returns FAIL if the lines are not inserted, OK for success.
|
|
|
|
|
*/
|
|
|
|
|
int
|
2016-01-30 20:31:25 +01:00
|
|
|
win_ins_lines(
|
|
|
|
|
win_T *wp,
|
|
|
|
|
int row,
|
|
|
|
|
int line_count,
|
|
|
|
|
int invalid,
|
|
|
|
|
int mayclear)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
int did_delete;
|
|
|
|
|
int nextrow;
|
|
|
|
|
int lastrow;
|
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
|
|
if (invalid)
|
|
|
|
|
wp->w_lines_valid = 0;
|
|
|
|
|
|
2022-06-21 18:10:39 +01:00
|
|
|
// with only a few lines it's not worth the effort
|
2004-06-13 20:20:40 +00:00
|
|
|
if (wp->w_height < 5)
|
|
|
|
|
return FAIL;
|
|
|
|
|
|
2022-06-21 18:10:39 +01:00
|
|
|
// with the popup menu visible this might not work correctly
|
|
|
|
|
if (pum_visible())
|
|
|
|
|
return FAIL;
|
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
if (line_count > wp->w_height - row)
|
|
|
|
|
line_count = wp->w_height - row;
|
|
|
|
|
|
2017-08-17 20:31:48 +02:00
|
|
|
retval = win_do_lines(wp, row, line_count, mayclear, FALSE, 0);
|
2004-06-13 20:20:40 +00:00
|
|
|
if (retval != MAYBE)
|
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If there is a next window or a status line, we first try to delete the
|
|
|
|
|
* lines at the bottom to avoid messing what is after the window.
|
2019-08-04 18:13:46 +02:00
|
|
|
* If this fails and there are following windows, don't do anything to
|
|
|
|
|
* avoid messing up those windows, better just redraw.
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
|
|
|
|
did_delete = FALSE;
|
|
|
|
|
if (wp->w_next != NULL || wp->w_status_height)
|
|
|
|
|
{
|
|
|
|
|
if (screen_del_lines(0, W_WINROW(wp) + wp->w_height - line_count,
|
2017-08-17 20:31:48 +02:00
|
|
|
line_count, (int)Rows, FALSE, 0, NULL) == OK)
|
2004-06-13 20:20:40 +00:00
|
|
|
did_delete = TRUE;
|
|
|
|
|
else if (wp->w_next)
|
|
|
|
|
return FAIL;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* if no lines deleted, blank the lines that will end up below the window
|
|
|
|
|
*/
|
|
|
|
|
if (!did_delete)
|
|
|
|
|
{
|
|
|
|
|
wp->w_redr_status = TRUE;
|
|
|
|
|
redraw_cmdline = TRUE;
|
2017-09-24 16:24:34 +02:00
|
|
|
nextrow = W_WINROW(wp) + wp->w_height + wp->w_status_height;
|
2004-06-13 20:20:40 +00:00
|
|
|
lastrow = nextrow + line_count;
|
|
|
|
|
if (lastrow > Rows)
|
|
|
|
|
lastrow = Rows;
|
|
|
|
|
screen_fill(nextrow - line_count, lastrow - line_count,
|
2017-09-22 14:35:51 +02:00
|
|
|
wp->w_wincol, (int)W_ENDCOL(wp),
|
2004-06-13 20:20:40 +00:00
|
|
|
' ', ' ', 0);
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-17 20:31:48 +02:00
|
|
|
if (screen_ins_lines(0, W_WINROW(wp) + row, line_count, (int)Rows, 0, NULL)
|
2004-06-13 20:20:40 +00:00
|
|
|
== FAIL)
|
|
|
|
|
{
|
2019-08-04 18:13:46 +02:00
|
|
|
// deletion will have messed up other windows
|
2004-06-13 20:20:40 +00:00
|
|
|
if (did_delete)
|
|
|
|
|
{
|
|
|
|
|
wp->w_redr_status = TRUE;
|
|
|
|
|
win_rest_invalid(W_NEXT(wp));
|
|
|
|
|
}
|
|
|
|
|
return FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2017-07-12 20:24:41 +02:00
|
|
|
* Delete "line_count" window lines at "row" in window "wp".
|
2004-06-13 20:20:40 +00:00
|
|
|
* If "invalid" is TRUE curwin->w_lines[] is invalidated.
|
|
|
|
|
* If "mayclear" is TRUE the screen will be cleared if it is faster than
|
|
|
|
|
* scrolling
|
|
|
|
|
* Return OK for success, FAIL if the lines are not deleted.
|
|
|
|
|
*/
|
|
|
|
|
int
|
2016-01-30 20:31:25 +01:00
|
|
|
win_del_lines(
|
|
|
|
|
win_T *wp,
|
|
|
|
|
int row,
|
|
|
|
|
int line_count,
|
|
|
|
|
int invalid,
|
2017-08-17 20:31:48 +02:00
|
|
|
int mayclear,
|
2019-12-05 21:10:38 +01:00
|
|
|
int clear_attr) // for clearing lines
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
|
|
if (invalid)
|
|
|
|
|
wp->w_lines_valid = 0;
|
|
|
|
|
|
|
|
|
|
if (line_count > wp->w_height - row)
|
|
|
|
|
line_count = wp->w_height - row;
|
|
|
|
|
|
2017-08-17 20:31:48 +02:00
|
|
|
retval = win_do_lines(wp, row, line_count, mayclear, TRUE, clear_attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
if (retval != MAYBE)
|
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
|
|
if (screen_del_lines(0, W_WINROW(wp) + row, line_count,
|
2017-08-17 20:31:48 +02:00
|
|
|
(int)Rows, FALSE, clear_attr, NULL) == FAIL)
|
2004-06-13 20:20:40 +00:00
|
|
|
return FAIL;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If there are windows or status lines below, try to put them at the
|
|
|
|
|
* correct place. If we can't do that, they have to be redrawn.
|
|
|
|
|
*/
|
|
|
|
|
if (wp->w_next || wp->w_status_height || cmdline_row < Rows - 1)
|
|
|
|
|
{
|
|
|
|
|
if (screen_ins_lines(0, W_WINROW(wp) + wp->w_height - line_count,
|
2017-08-17 20:31:48 +02:00
|
|
|
line_count, (int)Rows, clear_attr, NULL) == FAIL)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
wp->w_redr_status = TRUE;
|
|
|
|
|
win_rest_invalid(wp->w_next);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* If this is the last window and there is no status line, redraw the
|
|
|
|
|
* command line later.
|
|
|
|
|
*/
|
|
|
|
|
else
|
|
|
|
|
redraw_cmdline = TRUE;
|
|
|
|
|
return OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Common code for win_ins_lines() and win_del_lines().
|
|
|
|
|
* Returns OK or FAIL when the work has been done.
|
|
|
|
|
* Returns MAYBE when not finished yet.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
2016-01-30 20:31:25 +01:00
|
|
|
win_do_lines(
|
|
|
|
|
win_T *wp,
|
|
|
|
|
int row,
|
|
|
|
|
int line_count,
|
|
|
|
|
int mayclear,
|
2017-08-17 20:31:48 +02:00
|
|
|
int del,
|
|
|
|
|
int clear_attr)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
|
|
if (!redrawing() || line_count <= 0)
|
|
|
|
|
return FAIL;
|
|
|
|
|
|
2019-06-08 16:01:13 +02:00
|
|
|
// When inserting lines would result in loss of command output, just redraw
|
|
|
|
|
// the lines.
|
2017-04-30 19:39:39 +02:00
|
|
|
if (no_win_do_lines_ins && !del)
|
|
|
|
|
return FAIL;
|
|
|
|
|
|
2019-06-08 16:01:13 +02:00
|
|
|
// only a few lines left: redraw is faster
|
2017-09-16 20:54:51 +02:00
|
|
|
if (mayclear && Rows - line_count < 5 && wp->w_width == Columns)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2017-04-30 19:39:39 +02:00
|
|
|
if (!no_win_do_lines_ins)
|
2019-06-08 16:01:13 +02:00
|
|
|
screenclear(); // will set wp->w_lines_valid to 0
|
2004-06-13 20:20:40 +00:00
|
|
|
return FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-30 22:48:27 +01:00
|
|
|
#ifdef FEAT_PROP_POPUP
|
2019-06-10 21:24:12 +02:00
|
|
|
// this doesn't work when there are popups visible
|
2019-06-08 16:01:13 +02:00
|
|
|
if (popup_visible)
|
|
|
|
|
return FAIL;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Delete all remaining lines
|
2004-06-13 20:20:40 +00:00
|
|
|
if (row + line_count >= wp->w_height)
|
|
|
|
|
{
|
|
|
|
|
screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
|
2017-09-22 14:35:51 +02:00
|
|
|
wp->w_wincol, (int)W_ENDCOL(wp),
|
2004-06-13 20:20:40 +00:00
|
|
|
' ', ' ', 0);
|
|
|
|
|
return OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2017-04-30 19:39:39 +02:00
|
|
|
* When scrolling, the message on the command line should be cleared,
|
2004-06-13 20:20:40 +00:00
|
|
|
* otherwise it will stay there forever.
|
2017-04-30 19:39:39 +02:00
|
|
|
* Don't do this when avoiding to insert lines.
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
2017-04-30 19:39:39 +02:00
|
|
|
if (!no_win_do_lines_ins)
|
|
|
|
|
clear_cmdline = TRUE;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the terminal can set a scroll region, use that.
|
|
|
|
|
* Always do this in a vertically split window. This will redraw from
|
|
|
|
|
* ScreenLines[] when t_CV isn't defined. That's faster than using
|
|
|
|
|
* win_line().
|
|
|
|
|
* Don't use a scroll region when we are going to redraw the text, writing
|
2016-02-23 14:53:34 +01:00
|
|
|
* a character in the lower right corner of the scroll region may cause a
|
|
|
|
|
* scroll-up .
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
2017-09-22 15:20:32 +02:00
|
|
|
if (scroll_region || wp->w_width != Columns)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
|
|
|
|
|
scroll_region_set(wp, row);
|
|
|
|
|
if (del)
|
|
|
|
|
retval = screen_del_lines(W_WINROW(wp) + row, 0, line_count,
|
2017-08-17 20:31:48 +02:00
|
|
|
wp->w_height - row, FALSE, clear_attr, wp);
|
2004-06-13 20:20:40 +00:00
|
|
|
else
|
|
|
|
|
retval = screen_ins_lines(W_WINROW(wp) + row, 0, line_count,
|
2017-08-17 20:31:48 +02:00
|
|
|
wp->w_height - row, clear_attr, wp);
|
2004-06-13 20:20:40 +00:00
|
|
|
if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
|
|
|
|
|
scroll_region_reset();
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
if (wp->w_next != NULL && p_tf) // don't delete/insert on fast terminal
|
2004-06-13 20:20:40 +00:00
|
|
|
return FAIL;
|
|
|
|
|
|
|
|
|
|
return MAYBE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* window 'wp' and everything after it is messed up, mark it for redraw
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2016-01-30 20:31:25 +01:00
|
|
|
win_rest_invalid(win_T *wp)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
while (wp != NULL)
|
|
|
|
|
{
|
2022-08-14 14:17:45 +01:00
|
|
|
redraw_win_later(wp, UPD_NOT_VALID);
|
2004-06-13 20:20:40 +00:00
|
|
|
wp->w_redr_status = TRUE;
|
|
|
|
|
wp = wp->w_next;
|
|
|
|
|
}
|
|
|
|
|
redraw_cmdline = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The rest of the routines in this file perform screen manipulations. The
|
|
|
|
|
* given operation is performed physically on the screen. The corresponding
|
|
|
|
|
* change is also made to the internal screen image. In this way, the editor
|
|
|
|
|
* anticipates the effect of editing changes on the appearance of the screen.
|
|
|
|
|
* That way, when we call screenupdate a complete redraw isn't usually
|
|
|
|
|
* necessary. Another advantage is that we can keep adding code to anticipate
|
|
|
|
|
* screen changes, and in the meantime, everything still works.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* types for inserting or deleting lines
|
|
|
|
|
*/
|
|
|
|
|
#define USE_T_CAL 1
|
|
|
|
|
#define USE_T_CDL 2
|
|
|
|
|
#define USE_T_AL 3
|
|
|
|
|
#define USE_T_CE 4
|
|
|
|
|
#define USE_T_DL 5
|
|
|
|
|
#define USE_T_SR 6
|
|
|
|
|
#define USE_NL 7
|
|
|
|
|
#define USE_T_CD 8
|
|
|
|
|
#define USE_REDRAW 9
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* insert lines on the screen and update ScreenLines[]
|
2022-04-01 19:44:47 +01:00
|
|
|
* "end" is the line after the scrolled part. Normally it is Rows.
|
|
|
|
|
* When scrolling region used "off" is the offset from the top for the region.
|
|
|
|
|
* "row" and "end" are relative to the start of the region.
|
2004-06-13 20:20:40 +00:00
|
|
|
*
|
|
|
|
|
* return FAIL for failure, OK for success.
|
|
|
|
|
*/
|
2005-07-27 21:13:01 +00:00
|
|
|
int
|
2016-01-30 20:31:25 +01:00
|
|
|
screen_ins_lines(
|
|
|
|
|
int off,
|
|
|
|
|
int row,
|
|
|
|
|
int line_count,
|
|
|
|
|
int end,
|
2017-08-17 20:31:48 +02:00
|
|
|
int clear_attr,
|
2019-12-05 21:10:38 +01:00
|
|
|
win_T *wp) // NULL or window to use width from
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
int j;
|
|
|
|
|
unsigned temp;
|
|
|
|
|
int cursor_row;
|
2018-06-16 16:20:52 +02:00
|
|
|
int cursor_col = 0;
|
2004-06-13 20:20:40 +00:00
|
|
|
int type;
|
|
|
|
|
int result_empty;
|
|
|
|
|
int can_ce = can_clear(T_CE);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* FAIL if
|
|
|
|
|
* - there is no valid screen
|
|
|
|
|
* - the line count is less than one
|
|
|
|
|
* - the line count is more than 'ttyscroll'
|
2022-04-01 19:44:47 +01:00
|
|
|
* - "end" is more than "Rows" (safety check, should not happen)
|
2017-07-19 12:51:52 +02:00
|
|
|
* - redrawing for a callback and there is a modeless selection
|
2019-06-08 16:01:13 +02:00
|
|
|
* - there is a popup window
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
2019-06-08 16:01:13 +02:00
|
|
|
if (!screen_valid(TRUE)
|
|
|
|
|
|| line_count <= 0 || line_count > p_ttyscroll
|
2022-04-01 19:44:47 +01:00
|
|
|
|| end > Rows
|
2017-07-19 12:51:52 +02:00
|
|
|
#ifdef FEAT_CLIPBOARD
|
|
|
|
|
|| (clip_star.state != SELECT_CLEARED
|
|
|
|
|
&& redrawing_for_callback > 0)
|
2019-06-08 16:01:13 +02:00
|
|
|
#endif
|
2019-11-30 22:48:27 +01:00
|
|
|
#ifdef FEAT_PROP_POPUP
|
2019-06-08 16:01:13 +02:00
|
|
|
|| popup_visible
|
2017-07-19 12:51:52 +02:00
|
|
|
#endif
|
|
|
|
|
)
|
2004-06-13 20:20:40 +00:00
|
|
|
return FAIL;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* There are seven ways to insert lines:
|
|
|
|
|
* 0. When in a vertically split window and t_CV isn't set, redraw the
|
|
|
|
|
* characters from ScreenLines[].
|
|
|
|
|
* 1. Use T_CD (clear to end of display) if it exists and the result of
|
|
|
|
|
* the insert is just empty lines
|
|
|
|
|
* 2. Use T_CAL (insert multiple lines) if it exists and T_AL is not
|
|
|
|
|
* present or line_count > 1. It looks better if we do all the inserts
|
|
|
|
|
* at once.
|
|
|
|
|
* 3. Use T_CDL (delete multiple lines) if it exists and the result of the
|
|
|
|
|
* insert is just empty lines and T_CE is not present or line_count >
|
|
|
|
|
* 1.
|
|
|
|
|
* 4. Use T_AL (insert line) if it exists.
|
|
|
|
|
* 5. Use T_CE (erase line) if it exists and the result of the insert is
|
|
|
|
|
* just empty lines.
|
|
|
|
|
* 6. Use T_DL (delete line) if it exists and the result of the insert is
|
|
|
|
|
* just empty lines.
|
|
|
|
|
* 7. Use T_SR (scroll reverse) if it exists and inserting at row 0 and
|
|
|
|
|
* the 'da' flag is not set or we have clear line capability.
|
|
|
|
|
* 8. redraw the characters from ScreenLines[].
|
|
|
|
|
*
|
|
|
|
|
* Careful: In a hpterm scroll reverse doesn't work as expected, it moves
|
|
|
|
|
* the scrollbar for the window. It does have insert line, use that if it
|
|
|
|
|
* exists.
|
|
|
|
|
*/
|
|
|
|
|
result_empty = (row + line_count >= end);
|
|
|
|
|
if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
|
2022-04-03 13:23:22 +01:00
|
|
|
{
|
|
|
|
|
// Avoid that lines are first cleared here and then redrawn, which
|
|
|
|
|
// results in many characters updated twice. This happens with CTRL-F
|
|
|
|
|
// in a vertically split window. With line-by-line scrolling
|
|
|
|
|
// USE_REDRAW should be faster.
|
|
|
|
|
if (line_count > 3)
|
|
|
|
|
return FAIL;
|
2004-06-13 20:20:40 +00:00
|
|
|
type = USE_REDRAW;
|
2022-04-03 13:23:22 +01:00
|
|
|
}
|
2017-09-16 20:54:51 +02:00
|
|
|
else if (can_clear(T_CD) && result_empty)
|
2004-06-13 20:20:40 +00:00
|
|
|
type = USE_T_CD;
|
|
|
|
|
else if (*T_CAL != NUL && (line_count > 1 || *T_AL == NUL))
|
|
|
|
|
type = USE_T_CAL;
|
|
|
|
|
else if (*T_CDL != NUL && result_empty && (line_count > 1 || !can_ce))
|
|
|
|
|
type = USE_T_CDL;
|
|
|
|
|
else if (*T_AL != NUL)
|
|
|
|
|
type = USE_T_AL;
|
|
|
|
|
else if (can_ce && result_empty)
|
|
|
|
|
type = USE_T_CE;
|
|
|
|
|
else if (*T_DL != NUL && result_empty)
|
|
|
|
|
type = USE_T_DL;
|
|
|
|
|
else if (*T_SR != NUL && row == 0 && (*T_DA == NUL || can_ce))
|
|
|
|
|
type = USE_T_SR;
|
|
|
|
|
else
|
|
|
|
|
return FAIL;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* For clearing the lines screen_del_lines() is used. This will also take
|
|
|
|
|
* care of t_db if necessary.
|
|
|
|
|
*/
|
|
|
|
|
if (type == USE_T_CD || type == USE_T_CDL ||
|
|
|
|
|
type == USE_T_CE || type == USE_T_DL)
|
2017-08-17 20:31:48 +02:00
|
|
|
return screen_del_lines(off, row, line_count, end, FALSE, 0, wp);
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If text is retained below the screen, first clear or delete as many
|
|
|
|
|
* lines at the bottom of the window as are about to be inserted so that
|
|
|
|
|
* the deleted lines won't later surface during a screen_del_lines.
|
|
|
|
|
*/
|
|
|
|
|
if (*T_DB)
|
2017-08-17 20:31:48 +02:00
|
|
|
screen_del_lines(off, end - line_count, line_count, end, FALSE, 0, wp);
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
|
#ifdef FEAT_CLIPBOARD
|
2019-12-05 21:10:38 +01:00
|
|
|
// Remove a modeless selection when inserting lines halfway the screen
|
|
|
|
|
// or not the full width of the screen.
|
2017-09-16 20:54:51 +02:00
|
|
|
if (off + row > 0 || (wp != NULL && wp->w_width != Columns))
|
2012-07-10 16:49:23 +02:00
|
|
|
clip_clear_selection(&clip_star);
|
2004-06-13 20:20:40 +00:00
|
|
|
else
|
|
|
|
|
clip_scroll_selection(-line_count);
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-02-26 16:16:53 +01:00
|
|
|
#ifdef FEAT_GUI_HAIKU
|
|
|
|
|
vim_lock_screen();
|
|
|
|
|
#endif
|
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
#ifdef FEAT_GUI
|
2019-12-05 21:10:38 +01:00
|
|
|
// Don't update the GUI cursor here, ScreenLines[] is invalid until the
|
|
|
|
|
// scrolling is actually carried out.
|
2016-08-12 14:08:25 +02:00
|
|
|
gui_dont_update_cursor(row + off <= gui.cursor_row);
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
|
|
|
|
|
2018-06-16 16:20:52 +02:00
|
|
|
if (wp != NULL && wp->w_wincol != 0 && *T_CSV != NUL && *T_CCS == NUL)
|
|
|
|
|
cursor_col = wp->w_wincol;
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
if (*T_CCS != NUL) // cursor relative to region
|
2004-06-13 20:20:40 +00:00
|
|
|
cursor_row = row;
|
|
|
|
|
else
|
|
|
|
|
cursor_row = row + off;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Shift LineOffset[] line_count down to reflect the inserted lines.
|
|
|
|
|
* Clear the inserted lines in ScreenLines[].
|
|
|
|
|
*/
|
|
|
|
|
row += off;
|
|
|
|
|
end += off;
|
|
|
|
|
for (i = 0; i < line_count; ++i)
|
|
|
|
|
{
|
|
|
|
|
if (wp != NULL && wp->w_width != Columns)
|
|
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
// need to copy part of a line
|
2004-06-13 20:20:40 +00:00
|
|
|
j = end - 1 - i;
|
|
|
|
|
while ((j -= line_count) >= row)
|
|
|
|
|
linecopy(j + line_count, j, wp);
|
|
|
|
|
j += line_count;
|
|
|
|
|
if (can_clear((char_u *)" "))
|
2017-08-17 20:31:48 +02:00
|
|
|
lineclear(LineOffset[j] + wp->w_wincol, wp->w_width,
|
|
|
|
|
clear_attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
else
|
|
|
|
|
lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
|
|
|
|
|
LineWraps[j] = FALSE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
j = end - 1 - i;
|
|
|
|
|
temp = LineOffset[j];
|
|
|
|
|
while ((j -= line_count) >= row)
|
|
|
|
|
{
|
|
|
|
|
LineOffset[j + line_count] = LineOffset[j];
|
|
|
|
|
LineWraps[j + line_count] = LineWraps[j];
|
|
|
|
|
}
|
|
|
|
|
LineOffset[j + line_count] = temp;
|
|
|
|
|
LineWraps[j + line_count] = FALSE;
|
|
|
|
|
if (can_clear((char_u *)" "))
|
2017-08-17 20:31:48 +02:00
|
|
|
lineclear(temp, (int)Columns, clear_attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
else
|
|
|
|
|
lineinvalid(temp, (int)Columns);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-26 16:16:53 +01:00
|
|
|
#ifdef FEAT_GUI_HAIKU
|
|
|
|
|
vim_unlock_screen();
|
|
|
|
|
#endif
|
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
screen_stop_highlight();
|
2018-06-16 16:20:52 +02:00
|
|
|
windgoto(cursor_row, cursor_col);
|
2017-08-17 20:31:48 +02:00
|
|
|
if (clear_attr != 0)
|
|
|
|
|
screen_start_highlight(clear_attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// redraw the characters
|
2004-06-13 20:20:40 +00:00
|
|
|
if (type == USE_REDRAW)
|
|
|
|
|
redraw_block(row, end, wp);
|
2017-09-16 20:54:51 +02:00
|
|
|
else if (type == USE_T_CAL)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
term_append_lines(line_count);
|
2019-12-05 21:10:38 +01:00
|
|
|
screen_start(); // don't know where cursor is now
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; i < line_count; i++)
|
|
|
|
|
{
|
|
|
|
|
if (type == USE_T_AL)
|
|
|
|
|
{
|
|
|
|
|
if (i && cursor_row != 0)
|
2018-06-16 16:20:52 +02:00
|
|
|
windgoto(cursor_row, cursor_col);
|
2004-06-13 20:20:40 +00:00
|
|
|
out_str(T_AL);
|
|
|
|
|
}
|
2019-12-05 21:10:38 +01:00
|
|
|
else // type == USE_T_SR
|
2004-06-13 20:20:40 +00:00
|
|
|
out_str(T_SR);
|
2019-12-05 21:10:38 +01:00
|
|
|
screen_start(); // don't know where cursor is now
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* With scroll-reverse and 'da' flag set we need to clear the lines that
|
|
|
|
|
* have been scrolled down into the region.
|
|
|
|
|
*/
|
|
|
|
|
if (type == USE_T_SR && *T_DA)
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; i < line_count; ++i)
|
|
|
|
|
{
|
2018-06-16 16:20:52 +02:00
|
|
|
windgoto(off + i, cursor_col);
|
2004-06-13 20:20:40 +00:00
|
|
|
out_str(T_CE);
|
2019-12-05 21:10:38 +01:00
|
|
|
screen_start(); // don't know where cursor is now
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef FEAT_GUI
|
|
|
|
|
gui_can_update_cursor();
|
|
|
|
|
if (gui.in_use)
|
2019-12-05 21:10:38 +01:00
|
|
|
out_flush(); // always flush after a scroll
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
|
|
|
|
return OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2016-08-12 14:08:25 +02:00
|
|
|
* Delete lines on the screen and update ScreenLines[].
|
|
|
|
|
* "end" is the line after the scrolled part. Normally it is Rows.
|
|
|
|
|
* When scrolling region used "off" is the offset from the top for the region.
|
|
|
|
|
* "row" and "end" are relative to the start of the region.
|
2004-06-13 20:20:40 +00:00
|
|
|
*
|
|
|
|
|
* Return OK for success, FAIL if the lines are not deleted.
|
|
|
|
|
*/
|
|
|
|
|
int
|
2016-01-30 20:31:25 +01:00
|
|
|
screen_del_lines(
|
|
|
|
|
int off,
|
|
|
|
|
int row,
|
|
|
|
|
int line_count,
|
|
|
|
|
int end,
|
2019-12-05 21:10:38 +01:00
|
|
|
int force, // even when line_count > p_ttyscroll
|
|
|
|
|
int clear_attr, // used for clearing lines
|
2022-04-03 13:23:22 +01:00
|
|
|
win_T *wp) // NULL or window to use width from
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
int j;
|
|
|
|
|
int i;
|
|
|
|
|
unsigned temp;
|
|
|
|
|
int cursor_row;
|
2018-06-16 16:20:52 +02:00
|
|
|
int cursor_col = 0;
|
2004-06-13 20:20:40 +00:00
|
|
|
int cursor_end;
|
2019-12-05 21:10:38 +01:00
|
|
|
int result_empty; // result is empty until end of region
|
|
|
|
|
int can_delete; // deleting line codes can be used
|
2004-06-13 20:20:40 +00:00
|
|
|
int type;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* FAIL if
|
|
|
|
|
* - there is no valid screen
|
|
|
|
|
* - the screen has to be redrawn completely
|
|
|
|
|
* - the line count is less than one
|
|
|
|
|
* - the line count is more than 'ttyscroll'
|
2022-04-01 19:44:47 +01:00
|
|
|
* - "end" is more than "Rows" (safety check, should not happen)
|
2017-07-19 12:51:52 +02:00
|
|
|
* - redrawing for a callback and there is a modeless selection
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
2022-04-01 19:44:47 +01:00
|
|
|
if (!screen_valid(TRUE)
|
|
|
|
|
|| line_count <= 0
|
|
|
|
|
|| (!force && line_count > p_ttyscroll)
|
|
|
|
|
|| end > Rows
|
2017-07-19 12:51:52 +02:00
|
|
|
#ifdef FEAT_CLIPBOARD
|
2022-04-01 19:44:47 +01:00
|
|
|
|| (clip_star.state != SELECT_CLEARED && redrawing_for_callback > 0)
|
2017-07-19 12:51:52 +02:00
|
|
|
#endif
|
|
|
|
|
)
|
2004-06-13 20:20:40 +00:00
|
|
|
return FAIL;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Check if the rest of the current region will become empty.
|
|
|
|
|
*/
|
|
|
|
|
result_empty = row + line_count >= end;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We can delete lines only when 'db' flag not set or when 'ce' option
|
|
|
|
|
* available.
|
|
|
|
|
*/
|
|
|
|
|
can_delete = (*T_DB == NUL || can_clear(T_CE));
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* There are six ways to delete lines:
|
|
|
|
|
* 0. When in a vertically split window and t_CV isn't set, redraw the
|
|
|
|
|
* characters from ScreenLines[].
|
|
|
|
|
* 1. Use T_CD if it exists and the result is empty.
|
|
|
|
|
* 2. Use newlines if row == 0 and count == 1 or T_CDL does not exist.
|
|
|
|
|
* 3. Use T_CDL (delete multiple lines) if it exists and line_count > 1 or
|
|
|
|
|
* none of the other ways work.
|
|
|
|
|
* 4. Use T_CE (erase line) if the result is empty.
|
|
|
|
|
* 5. Use T_DL (delete line) if it exists.
|
|
|
|
|
* 6. redraw the characters from ScreenLines[].
|
|
|
|
|
*/
|
|
|
|
|
if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
|
2022-04-03 13:23:22 +01:00
|
|
|
{
|
|
|
|
|
// Avoid that lines are first cleared here and then redrawn, which
|
|
|
|
|
// results in many characters updated twice. This happens with CTRL-F
|
|
|
|
|
// in a vertically split window. With line-by-line scrolling
|
|
|
|
|
// USE_REDRAW should be faster.
|
|
|
|
|
if (line_count > 3)
|
|
|
|
|
return FAIL;
|
2004-06-13 20:20:40 +00:00
|
|
|
type = USE_REDRAW;
|
2022-04-03 13:23:22 +01:00
|
|
|
}
|
2017-09-16 20:54:51 +02:00
|
|
|
else if (can_clear(T_CD) && result_empty)
|
2004-06-13 20:20:40 +00:00
|
|
|
type = USE_T_CD;
|
|
|
|
|
else if (row == 0 && (
|
|
|
|
|
#ifndef AMIGA
|
2019-12-05 21:10:38 +01:00
|
|
|
// On the Amiga, somehow '\n' on the last line doesn't always scroll
|
|
|
|
|
// up, so use delete-line command
|
2004-06-13 20:20:40 +00:00
|
|
|
line_count == 1 ||
|
|
|
|
|
#endif
|
|
|
|
|
*T_CDL == NUL))
|
|
|
|
|
type = USE_NL;
|
|
|
|
|
else if (*T_CDL != NUL && line_count > 1 && can_delete)
|
|
|
|
|
type = USE_T_CDL;
|
|
|
|
|
else if (can_clear(T_CE) && result_empty
|
2017-09-16 20:54:51 +02:00
|
|
|
&& (wp == NULL || wp->w_width == Columns))
|
2004-06-13 20:20:40 +00:00
|
|
|
type = USE_T_CE;
|
|
|
|
|
else if (*T_DL != NUL && can_delete)
|
|
|
|
|
type = USE_T_DL;
|
|
|
|
|
else if (*T_CDL != NUL && can_delete)
|
|
|
|
|
type = USE_T_CDL;
|
|
|
|
|
else
|
|
|
|
|
return FAIL;
|
|
|
|
|
|
|
|
|
|
#ifdef FEAT_CLIPBOARD
|
2019-12-05 21:10:38 +01:00
|
|
|
// Remove a modeless selection when deleting lines halfway the screen or
|
|
|
|
|
// not the full width of the screen.
|
2017-09-16 20:54:51 +02:00
|
|
|
if (off + row > 0 || (wp != NULL && wp->w_width != Columns))
|
2012-07-10 16:49:23 +02:00
|
|
|
clip_clear_selection(&clip_star);
|
2004-06-13 20:20:40 +00:00
|
|
|
else
|
|
|
|
|
clip_scroll_selection(line_count);
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-04-24 22:19:00 +02:00
|
|
|
#ifdef FEAT_GUI_HAIKU
|
|
|
|
|
vim_lock_screen();
|
|
|
|
|
#endif
|
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
#ifdef FEAT_GUI
|
2019-12-05 21:10:38 +01:00
|
|
|
// Don't update the GUI cursor here, ScreenLines[] is invalid until the
|
|
|
|
|
// scrolling is actually carried out.
|
2016-08-12 14:08:25 +02:00
|
|
|
gui_dont_update_cursor(gui.cursor_row >= row + off
|
|
|
|
|
&& gui.cursor_row < end + off);
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
|
|
|
|
|
2018-06-16 16:20:52 +02:00
|
|
|
if (wp != NULL && wp->w_wincol != 0 && *T_CSV != NUL && *T_CCS == NUL)
|
|
|
|
|
cursor_col = wp->w_wincol;
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
if (*T_CCS != NUL) // cursor relative to region
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
cursor_row = row;
|
|
|
|
|
cursor_end = end;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cursor_row = row + off;
|
|
|
|
|
cursor_end = end + off;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now shift LineOffset[] line_count up to reflect the deleted lines.
|
|
|
|
|
* Clear the inserted lines in ScreenLines[].
|
|
|
|
|
*/
|
|
|
|
|
row += off;
|
|
|
|
|
end += off;
|
|
|
|
|
for (i = 0; i < line_count; ++i)
|
|
|
|
|
{
|
|
|
|
|
if (wp != NULL && wp->w_width != Columns)
|
|
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
// need to copy part of a line
|
2004-06-13 20:20:40 +00:00
|
|
|
j = row + i;
|
|
|
|
|
while ((j += line_count) <= end - 1)
|
|
|
|
|
linecopy(j - line_count, j, wp);
|
|
|
|
|
j -= line_count;
|
|
|
|
|
if (can_clear((char_u *)" "))
|
2017-08-17 20:31:48 +02:00
|
|
|
lineclear(LineOffset[j] + wp->w_wincol, wp->w_width,
|
|
|
|
|
clear_attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
else
|
|
|
|
|
lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
|
|
|
|
|
LineWraps[j] = FALSE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
// whole width, moving the line pointers is faster
|
2004-06-13 20:20:40 +00:00
|
|
|
j = row + i;
|
|
|
|
|
temp = LineOffset[j];
|
|
|
|
|
while ((j += line_count) <= end - 1)
|
|
|
|
|
{
|
|
|
|
|
LineOffset[j - line_count] = LineOffset[j];
|
|
|
|
|
LineWraps[j - line_count] = LineWraps[j];
|
|
|
|
|
}
|
|
|
|
|
LineOffset[j - line_count] = temp;
|
|
|
|
|
LineWraps[j - line_count] = FALSE;
|
|
|
|
|
if (can_clear((char_u *)" "))
|
2017-08-17 20:31:48 +02:00
|
|
|
lineclear(temp, (int)Columns, clear_attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
else
|
|
|
|
|
lineinvalid(temp, (int)Columns);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-26 16:16:53 +01:00
|
|
|
#ifdef FEAT_GUI_HAIKU
|
|
|
|
|
vim_unlock_screen();
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-08-17 20:31:48 +02:00
|
|
|
if (screen_attr != clear_attr)
|
|
|
|
|
screen_stop_highlight();
|
|
|
|
|
if (clear_attr != 0)
|
|
|
|
|
screen_start_highlight(clear_attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// redraw the characters
|
2004-06-13 20:20:40 +00:00
|
|
|
if (type == USE_REDRAW)
|
|
|
|
|
redraw_block(row, end, wp);
|
2019-12-05 21:10:38 +01:00
|
|
|
else if (type == USE_T_CD) // delete the lines
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2018-06-16 16:20:52 +02:00
|
|
|
windgoto(cursor_row, cursor_col);
|
2004-06-13 20:20:40 +00:00
|
|
|
out_str(T_CD);
|
2019-12-05 21:10:38 +01:00
|
|
|
screen_start(); // don't know where cursor is now
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
else if (type == USE_T_CDL)
|
|
|
|
|
{
|
2018-06-16 16:20:52 +02:00
|
|
|
windgoto(cursor_row, cursor_col);
|
2004-06-13 20:20:40 +00:00
|
|
|
term_delete_lines(line_count);
|
2019-12-05 21:10:38 +01:00
|
|
|
screen_start(); // don't know where cursor is now
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Deleting lines at top of the screen or scroll region: Just scroll
|
|
|
|
|
* the whole screen (scroll region) up by outputting newlines on the
|
|
|
|
|
* last line.
|
|
|
|
|
*/
|
|
|
|
|
else if (type == USE_NL)
|
|
|
|
|
{
|
2018-06-16 16:20:52 +02:00
|
|
|
windgoto(cursor_end - 1, cursor_col);
|
2004-06-13 20:20:40 +00:00
|
|
|
for (i = line_count; --i >= 0; )
|
2019-12-05 21:10:38 +01:00
|
|
|
out_char('\n'); // cursor will remain on same line
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (i = line_count; --i >= 0; )
|
|
|
|
|
{
|
|
|
|
|
if (type == USE_T_DL)
|
|
|
|
|
{
|
2018-06-16 16:20:52 +02:00
|
|
|
windgoto(cursor_row, cursor_col);
|
2019-12-05 21:10:38 +01:00
|
|
|
out_str(T_DL); // delete a line
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2019-12-05 21:10:38 +01:00
|
|
|
else // type == USE_T_CE
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2018-06-16 16:20:52 +02:00
|
|
|
windgoto(cursor_row + i, cursor_col);
|
2019-12-05 21:10:38 +01:00
|
|
|
out_str(T_CE); // erase a line
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2019-12-05 21:10:38 +01:00
|
|
|
screen_start(); // don't know where cursor is now
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the 'db' flag is set, we need to clear the lines that have been
|
|
|
|
|
* scrolled up at the bottom of the region.
|
|
|
|
|
*/
|
|
|
|
|
if (*T_DB && (type == USE_T_DL || type == USE_T_CDL))
|
|
|
|
|
{
|
|
|
|
|
for (i = line_count; i > 0; --i)
|
|
|
|
|
{
|
2018-06-16 16:20:52 +02:00
|
|
|
windgoto(cursor_end - i, cursor_col);
|
2019-12-05 21:10:38 +01:00
|
|
|
out_str(T_CE); // erase a line
|
|
|
|
|
screen_start(); // don't know where cursor is now
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef FEAT_GUI
|
|
|
|
|
gui_can_update_cursor();
|
|
|
|
|
if (gui.in_use)
|
2019-12-05 21:10:38 +01:00
|
|
|
out_flush(); // always flush after a scroll
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-25 22:29:57 +01:00
|
|
|
/*
|
|
|
|
|
* Return TRUE when postponing displaying the mode message: when not redrawing
|
|
|
|
|
* or inside a mapping.
|
|
|
|
|
*/
|
|
|
|
|
int
|
2023-02-21 14:27:41 +00:00
|
|
|
skip_showmode(void)
|
2019-01-25 22:29:57 +01:00
|
|
|
{
|
|
|
|
|
// Call char_avail() only when we are going to show something, because it
|
2022-06-27 22:17:37 +01:00
|
|
|
// takes a bit of time. redrawing() may also call char_avail().
|
2019-01-25 22:29:57 +01:00
|
|
|
if (global_busy
|
|
|
|
|
|| msg_silent != 0
|
|
|
|
|
|| !redrawing()
|
|
|
|
|
|| (char_avail() && !KeyTyped))
|
|
|
|
|
{
|
2019-04-20 23:38:07 +02:00
|
|
|
redraw_mode = TRUE; // show mode later
|
2019-01-25 22:29:57 +01:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
2018-02-20 21:44:45 +01:00
|
|
|
* Show the current mode and ruler.
|
2004-06-13 20:20:40 +00:00
|
|
|
*
|
|
|
|
|
* If clear_cmdline is TRUE, clear the rest of the cmdline.
|
|
|
|
|
* If clear_cmdline is FALSE there may be a message there that needs to be
|
|
|
|
|
* cleared only if a mode is shown.
|
2019-04-20 23:38:07 +02:00
|
|
|
* If redraw_mode is TRUE show or clear the mode.
|
2004-06-13 20:20:40 +00:00
|
|
|
* Return the length of the message (0 if no message).
|
|
|
|
|
*/
|
|
|
|
|
int
|
2016-01-30 20:31:25 +01:00
|
|
|
showmode(void)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
int need_clear;
|
|
|
|
|
int length = 0;
|
|
|
|
|
int do_mode;
|
|
|
|
|
int attr;
|
|
|
|
|
int nwr_save;
|
|
|
|
|
int sub_attr;
|
|
|
|
|
|
2022-08-31 14:46:18 +01:00
|
|
|
do_mode = p_smd && msg_silent == 0
|
2022-05-07 20:01:16 +01:00
|
|
|
&& ((State & MODE_INSERT)
|
2018-06-17 16:23:34 +02:00
|
|
|
|| restart_edit != NUL
|
2022-08-27 21:30:03 +01:00
|
|
|
|| VIsual_active);
|
2018-05-22 20:35:17 +02:00
|
|
|
if (do_mode || reg_recording != 0)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-01-25 22:29:57 +01:00
|
|
|
if (skip_showmode())
|
|
|
|
|
return 0; // show mode later
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
|
nwr_save = need_wait_return;
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// wait a bit before overwriting an important message
|
2004-06-13 20:20:40 +00:00
|
|
|
check_for_delay(FALSE);
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// if the cmdline is more than one line high, erase top lines
|
2004-06-13 20:20:40 +00:00
|
|
|
need_clear = clear_cmdline;
|
|
|
|
|
if (clear_cmdline && cmdline_row < Rows - 1)
|
2019-12-05 21:10:38 +01:00
|
|
|
msg_clr_cmdline(); // will reset clear_cmdline
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// Position on the last line in the window, column 0
|
2004-06-13 20:20:40 +00:00
|
|
|
msg_pos_mode();
|
|
|
|
|
cursor_off();
|
2019-12-05 21:10:38 +01:00
|
|
|
attr = HL_ATTR(HLF_CM); // Highlight mode
|
2004-06-13 20:20:40 +00:00
|
|
|
if (do_mode)
|
|
|
|
|
{
|
2019-01-19 17:43:09 +01:00
|
|
|
msg_puts_attr("--", attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
#if defined(FEAT_XIM)
|
2008-07-13 17:41:49 +00:00
|
|
|
if (
|
2010-08-08 16:38:42 +02:00
|
|
|
# ifdef FEAT_GUI_GTK
|
2008-07-13 17:41:49 +00:00
|
|
|
preedit_get_status()
|
2010-08-08 16:38:42 +02:00
|
|
|
# else
|
2008-07-13 17:41:49 +00:00
|
|
|
im_get_status()
|
|
|
|
|
# endif
|
2010-08-08 16:38:42 +02:00
|
|
|
)
|
2019-12-05 21:10:38 +01:00
|
|
|
# ifdef FEAT_GUI_GTK // most of the time, it's not XIM being used
|
2019-01-19 17:43:09 +01:00
|
|
|
msg_puts_attr(" IM", attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
# else
|
2019-01-19 17:43:09 +01:00
|
|
|
msg_puts_attr(" XIM", attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
# endif
|
|
|
|
|
#endif
|
2019-12-05 21:10:38 +01:00
|
|
|
// CTRL-X in Insert mode
|
2014-05-28 21:40:52 +02:00
|
|
|
if (edit_submode != NULL && !shortmess(SHM_COMPLETIONMENU))
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
// These messages can get long, avoid a wrap in a narrow
|
|
|
|
|
// window. Prefer showing edit_submode_extra.
|
2004-06-13 20:20:40 +00:00
|
|
|
length = (Rows - msg_row) * Columns - 3;
|
|
|
|
|
if (edit_submode_extra != NULL)
|
|
|
|
|
length -= vim_strsize(edit_submode_extra);
|
|
|
|
|
if (length > 0)
|
|
|
|
|
{
|
|
|
|
|
if (edit_submode_pre != NULL)
|
|
|
|
|
length -= vim_strsize(edit_submode_pre);
|
|
|
|
|
if (length - vim_strsize(edit_submode) > 0)
|
|
|
|
|
{
|
|
|
|
|
if (edit_submode_pre != NULL)
|
2019-01-19 17:43:09 +01:00
|
|
|
msg_puts_attr((char *)edit_submode_pre, attr);
|
|
|
|
|
msg_puts_attr((char *)edit_submode, attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
if (edit_submode_extra != NULL)
|
|
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
msg_puts_attr(" ", attr); // add a space in between
|
2004-06-13 20:20:40 +00:00
|
|
|
if ((int)edit_submode_highl < (int)HLF_COUNT)
|
2017-03-16 17:23:31 +01:00
|
|
|
sub_attr = HL_ATTR(edit_submode_highl);
|
2004-06-13 20:20:40 +00:00
|
|
|
else
|
|
|
|
|
sub_attr = attr;
|
2019-01-19 17:43:09 +01:00
|
|
|
msg_puts_attr((char *)edit_submode_extra, sub_attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (State & VREPLACE_FLAG)
|
2019-01-19 17:43:09 +01:00
|
|
|
msg_puts_attr(_(" VREPLACE"), attr);
|
2018-07-29 16:09:22 +02:00
|
|
|
else if (State & REPLACE_FLAG)
|
2019-01-19 17:43:09 +01:00
|
|
|
msg_puts_attr(_(" REPLACE"), attr);
|
2022-05-07 20:01:16 +01:00
|
|
|
else if (State & MODE_INSERT)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
#ifdef FEAT_RIGHTLEFT
|
|
|
|
|
if (p_ri)
|
2019-01-19 17:43:09 +01:00
|
|
|
msg_puts_attr(_(" REVERSE"), attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
2019-01-19 17:43:09 +01:00
|
|
|
msg_puts_attr(_(" INSERT"), attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2020-11-12 14:21:06 +01:00
|
|
|
else if (restart_edit == 'I' || restart_edit == 'i' ||
|
|
|
|
|
restart_edit == 'a' || restart_edit == 'A')
|
2019-01-19 17:43:09 +01:00
|
|
|
msg_puts_attr(_(" (insert)"), attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
else if (restart_edit == 'R')
|
2019-01-19 17:43:09 +01:00
|
|
|
msg_puts_attr(_(" (replace)"), attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
else if (restart_edit == 'V')
|
2019-01-19 17:43:09 +01:00
|
|
|
msg_puts_attr(_(" (vreplace)"), attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
#ifdef FEAT_RIGHTLEFT
|
|
|
|
|
if (p_hkmap)
|
2019-01-19 17:43:09 +01:00
|
|
|
msg_puts_attr(_(" Hebrew"), attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
|
|
|
|
#ifdef FEAT_KEYMAP
|
2022-05-07 20:01:16 +01:00
|
|
|
if (State & MODE_LANGMAP)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
# ifdef FEAT_ARABIC
|
|
|
|
|
if (curwin->w_p_arab)
|
2019-01-19 17:43:09 +01:00
|
|
|
msg_puts_attr(_(" Arabic"), attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
else
|
|
|
|
|
# endif
|
2016-07-24 16:17:59 +02:00
|
|
|
if (get_keymap_str(curwin, (char_u *)" (%s)",
|
|
|
|
|
NameBuff, MAXPATHL))
|
2019-01-19 17:43:09 +01:00
|
|
|
msg_puts_attr((char *)NameBuff, attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
#endif
|
2022-05-07 20:01:16 +01:00
|
|
|
if ((State & MODE_INSERT) && p_paste)
|
2019-01-19 17:43:09 +01:00
|
|
|
msg_puts_attr(_(" (paste)"), attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
|
if (VIsual_active)
|
|
|
|
|
{
|
|
|
|
|
char *p;
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// Don't concatenate separate words to avoid translation
|
|
|
|
|
// problems.
|
2004-06-13 20:20:40 +00:00
|
|
|
switch ((VIsual_select ? 4 : 0)
|
|
|
|
|
+ (VIsual_mode == Ctrl_V) * 2
|
|
|
|
|
+ (VIsual_mode == 'V'))
|
|
|
|
|
{
|
|
|
|
|
case 0: p = N_(" VISUAL"); break;
|
|
|
|
|
case 1: p = N_(" VISUAL LINE"); break;
|
|
|
|
|
case 2: p = N_(" VISUAL BLOCK"); break;
|
|
|
|
|
case 4: p = N_(" SELECT"); break;
|
|
|
|
|
case 5: p = N_(" SELECT LINE"); break;
|
|
|
|
|
default: p = N_(" SELECT BLOCK"); break;
|
|
|
|
|
}
|
2019-01-19 17:43:09 +01:00
|
|
|
msg_puts_attr(_(p), attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2019-01-19 17:43:09 +01:00
|
|
|
msg_puts_attr(" --", attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2006-01-25 22:10:52 +00:00
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
need_clear = TRUE;
|
|
|
|
|
}
|
2018-05-22 20:35:17 +02:00
|
|
|
if (reg_recording != 0
|
2019-08-21 14:37:09 +02:00
|
|
|
&& edit_submode == NULL) // otherwise it gets too long
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2015-11-19 17:56:13 +01:00
|
|
|
recording_mode(attr);
|
2004-06-13 20:20:40 +00:00
|
|
|
need_clear = TRUE;
|
|
|
|
|
}
|
2006-01-25 22:10:52 +00:00
|
|
|
|
|
|
|
|
mode_displayed = TRUE;
|
2019-04-20 23:38:07 +02:00
|
|
|
if (need_clear || clear_cmdline || redraw_mode)
|
2004-06-13 20:20:40 +00:00
|
|
|
msg_clr_eos();
|
2019-12-05 21:10:38 +01:00
|
|
|
msg_didout = FALSE; // overwrite this message
|
2004-06-13 20:20:40 +00:00
|
|
|
length = msg_col;
|
|
|
|
|
msg_col = 0;
|
2019-12-05 21:10:38 +01:00
|
|
|
need_wait_return = nwr_save; // never ask for hit-return for this
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
else if (clear_cmdline && msg_silent == 0)
|
2019-12-05 21:10:38 +01:00
|
|
|
// Clear the whole command line. Will reset "clear_cmdline".
|
2004-06-13 20:20:40 +00:00
|
|
|
msg_clr_cmdline();
|
2019-04-20 23:38:07 +02:00
|
|
|
else if (redraw_mode)
|
|
|
|
|
{
|
|
|
|
|
msg_pos_mode();
|
|
|
|
|
msg_clr_eos();
|
|
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// In Visual mode the size of the selected area must be redrawn.
|
2004-06-13 20:20:40 +00:00
|
|
|
if (VIsual_active)
|
|
|
|
|
clear_showcmd();
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// If the last window has no status line, the ruler is after the mode
|
|
|
|
|
// message and must be redrawn
|
2017-09-16 20:54:51 +02:00
|
|
|
if (redrawing() && lastwin->w_status_height == 0)
|
2018-06-17 14:47:55 +02:00
|
|
|
win_redr_ruler(lastwin, TRUE, FALSE);
|
2022-10-13 22:12:15 +01:00
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
redraw_cmdline = FALSE;
|
2019-04-20 23:38:07 +02:00
|
|
|
redraw_mode = FALSE;
|
2004-06-13 20:20:40 +00:00
|
|
|
clear_cmdline = FALSE;
|
|
|
|
|
|
|
|
|
|
return length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Position for a mode message.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2016-01-30 20:31:25 +01:00
|
|
|
msg_pos_mode(void)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
msg_col = 0;
|
|
|
|
|
msg_row = Rows - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Delete mode message. Used when ESC is typed which is expected to end
|
|
|
|
|
* Insert mode (but Insert mode didn't end yet!).
|
2006-01-25 22:10:52 +00:00
|
|
|
* Caller should check "mode_displayed".
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
|
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
unshowmode(int force)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
/*
|
2010-01-19 17:40:46 +01:00
|
|
|
* Don't delete it right now, when not redrawing or inside a mapping.
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
|
|
|
|
if (!redrawing() || (!force && char_avail() && !KeyTyped))
|
2019-12-05 21:10:38 +01:00
|
|
|
redraw_cmdline = TRUE; // delete mode later
|
2004-06-13 20:20:40 +00:00
|
|
|
else
|
2016-04-02 19:39:16 +02:00
|
|
|
clearmode();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Clear the mode message.
|
|
|
|
|
*/
|
|
|
|
|
void
|
2016-06-12 21:18:43 +02:00
|
|
|
clearmode(void)
|
2016-04-02 19:39:16 +02:00
|
|
|
{
|
2018-05-19 14:43:45 +02:00
|
|
|
int save_msg_row = msg_row;
|
|
|
|
|
int save_msg_col = msg_col;
|
|
|
|
|
|
2016-04-02 19:39:16 +02:00
|
|
|
msg_pos_mode();
|
2018-05-22 20:35:17 +02:00
|
|
|
if (reg_recording != 0)
|
2017-03-16 17:23:31 +01:00
|
|
|
recording_mode(HL_ATTR(HLF_CM));
|
2016-04-02 19:39:16 +02:00
|
|
|
msg_clr_eos();
|
2018-05-19 14:43:45 +02:00
|
|
|
|
|
|
|
|
msg_col = save_msg_col;
|
|
|
|
|
msg_row = save_msg_row;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
2015-11-19 17:56:13 +01:00
|
|
|
static void
|
2016-01-30 20:31:25 +01:00
|
|
|
recording_mode(int attr)
|
2015-11-19 17:56:13 +01:00
|
|
|
{
|
2019-01-19 17:43:09 +01:00
|
|
|
msg_puts_attr(_("recording"), attr);
|
2023-01-23 20:46:21 +00:00
|
|
|
if (shortmess(SHM_RECORDING))
|
|
|
|
|
return;
|
2019-01-19 17:43:09 +01:00
|
|
|
|
2023-01-23 20:46:21 +00:00
|
|
|
char s[4];
|
|
|
|
|
|
|
|
|
|
sprintf(s, " @%c", reg_recording);
|
|
|
|
|
msg_puts_attr(s, attr);
|
2015-11-19 17:56:13 +01:00
|
|
|
}
|
|
|
|
|
|
2006-02-14 22:29:30 +00:00
|
|
|
/*
|
|
|
|
|
* Draw the tab pages line at the top of the Vim window.
|
|
|
|
|
*/
|
2019-01-08 22:02:56 +01:00
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
draw_tabline(void)
|
2006-02-14 22:29:30 +00:00
|
|
|
{
|
|
|
|
|
int tabcount = 0;
|
|
|
|
|
tabpage_T *tp;
|
|
|
|
|
int tabwidth;
|
|
|
|
|
int col = 0;
|
2006-02-17 21:53:23 +00:00
|
|
|
int scol = 0;
|
2006-02-14 22:29:30 +00:00
|
|
|
int attr;
|
|
|
|
|
win_T *wp;
|
2006-02-16 22:11:02 +00:00
|
|
|
win_T *cwp;
|
|
|
|
|
int wincount;
|
|
|
|
|
int modified;
|
2006-02-14 22:29:30 +00:00
|
|
|
int c;
|
|
|
|
|
int len;
|
2017-03-16 17:23:31 +01:00
|
|
|
int attr_sel = HL_ATTR(HLF_TPS);
|
|
|
|
|
int attr_nosel = HL_ATTR(HLF_TP);
|
|
|
|
|
int attr_fill = HL_ATTR(HLF_TPF);
|
2006-02-17 21:53:23 +00:00
|
|
|
char_u *p;
|
2006-02-20 21:37:40 +00:00
|
|
|
int room;
|
|
|
|
|
int use_sep_chars = (t_colors < 8
|
|
|
|
|
#ifdef FEAT_GUI
|
|
|
|
|
&& !gui.in_use
|
2016-04-21 21:10:14 +02:00
|
|
|
#endif
|
2016-04-29 22:59:22 +02:00
|
|
|
#ifdef FEAT_TERMGUICOLORS
|
|
|
|
|
&& !p_tgc
|
2006-02-20 21:37:40 +00:00
|
|
|
#endif
|
|
|
|
|
);
|
2006-02-14 22:29:30 +00:00
|
|
|
|
2017-01-08 20:00:04 +01:00
|
|
|
if (ScreenLines == NULL)
|
|
|
|
|
return;
|
2006-02-17 21:53:23 +00:00
|
|
|
redraw_tabline = FALSE;
|
2006-02-14 22:29:30 +00:00
|
|
|
|
2006-02-24 23:53:04 +00:00
|
|
|
#ifdef FEAT_GUI_TABLINE
|
2019-12-05 21:10:38 +01:00
|
|
|
// Take care of a GUI tabline.
|
2006-02-24 23:53:04 +00:00
|
|
|
if (gui_use_tabline())
|
|
|
|
|
{
|
|
|
|
|
gui_update_tabline();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (tabline_height() < 1)
|
2006-02-14 22:29:30 +00:00
|
|
|
return;
|
|
|
|
|
|
2006-02-20 21:37:40 +00:00
|
|
|
#if defined(FEAT_STL_OPT)
|
2019-04-13 14:53:16 +02:00
|
|
|
clear_TabPageIdxs();
|
2006-02-22 21:25:37 +00:00
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// Use the 'tabline' option if it's set.
|
2006-02-20 21:37:40 +00:00
|
|
|
if (*p_tal != NUL)
|
|
|
|
|
win_redr_custom(NULL, FALSE);
|
2006-02-21 22:12:05 +00:00
|
|
|
else
|
2006-02-20 21:37:40 +00:00
|
|
|
#endif
|
2006-02-21 22:12:05 +00:00
|
|
|
{
|
2016-07-24 22:04:11 +02:00
|
|
|
FOR_ALL_TABPAGES(tp)
|
2006-02-21 22:12:05 +00:00
|
|
|
++tabcount;
|
2006-02-20 21:37:40 +00:00
|
|
|
|
2006-02-21 22:12:05 +00:00
|
|
|
tabwidth = (Columns - 1 + tabcount / 2) / tabcount;
|
|
|
|
|
if (tabwidth < 6)
|
|
|
|
|
tabwidth = 6;
|
2006-02-14 22:29:30 +00:00
|
|
|
|
2006-02-21 22:12:05 +00:00
|
|
|
attr = attr_nosel;
|
|
|
|
|
tabcount = 0;
|
2006-03-01 22:09:21 +00:00
|
|
|
for (tp = first_tabpage; tp != NULL && col < Columns - 4;
|
|
|
|
|
tp = tp->tp_next)
|
2006-02-21 22:12:05 +00:00
|
|
|
{
|
|
|
|
|
scol = col;
|
2006-02-16 22:11:02 +00:00
|
|
|
|
2006-02-21 22:12:05 +00:00
|
|
|
if (tp->tp_topframe == topframe)
|
|
|
|
|
attr = attr_sel;
|
|
|
|
|
if (use_sep_chars && col > 0)
|
|
|
|
|
screen_putchar('|', 0, col++, attr);
|
2006-02-14 22:29:30 +00:00
|
|
|
|
2006-02-21 22:12:05 +00:00
|
|
|
if (tp->tp_topframe != topframe)
|
|
|
|
|
attr = attr_nosel;
|
2006-02-14 22:29:30 +00:00
|
|
|
|
2006-02-21 22:12:05 +00:00
|
|
|
screen_putchar(' ', 0, col++, attr);
|
2006-02-15 22:18:42 +00:00
|
|
|
|
2006-02-21 22:12:05 +00:00
|
|
|
if (tp == curtab)
|
|
|
|
|
{
|
|
|
|
|
cwp = curwin;
|
|
|
|
|
wp = firstwin;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cwp = tp->tp_curwin;
|
|
|
|
|
wp = tp->tp_firstwin;
|
|
|
|
|
}
|
2006-02-16 22:11:02 +00:00
|
|
|
|
2006-02-21 22:12:05 +00:00
|
|
|
modified = FALSE;
|
|
|
|
|
for (wincount = 0; wp != NULL; wp = wp->w_next, ++wincount)
|
|
|
|
|
if (bufIsChanged(wp->w_buffer))
|
|
|
|
|
modified = TRUE;
|
|
|
|
|
if (modified || wincount > 1)
|
2006-02-16 22:11:02 +00:00
|
|
|
{
|
2006-02-21 22:12:05 +00:00
|
|
|
if (wincount > 1)
|
|
|
|
|
{
|
|
|
|
|
vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount);
|
2006-04-17 22:14:47 +00:00
|
|
|
len = (int)STRLEN(NameBuff);
|
2006-03-01 22:09:21 +00:00
|
|
|
if (col + len >= Columns - 3)
|
|
|
|
|
break;
|
2006-02-21 22:12:05 +00:00
|
|
|
screen_puts_len(NameBuff, len, 0, col,
|
2006-02-20 21:37:40 +00:00
|
|
|
#if defined(FEAT_SYN_HL)
|
2017-03-16 17:23:31 +01:00
|
|
|
hl_combine_attr(attr, HL_ATTR(HLF_T))
|
2006-02-20 21:37:40 +00:00
|
|
|
#else
|
2014-08-06 13:20:56 +02:00
|
|
|
attr
|
2006-02-20 21:37:40 +00:00
|
|
|
#endif
|
2006-02-21 22:12:05 +00:00
|
|
|
);
|
|
|
|
|
col += len;
|
|
|
|
|
}
|
|
|
|
|
if (modified)
|
|
|
|
|
screen_puts_len((char_u *)"+", 1, 0, col++, attr);
|
|
|
|
|
screen_putchar(' ', 0, col++, attr);
|
2006-02-16 22:11:02 +00:00
|
|
|
}
|
|
|
|
|
|
2006-02-21 22:12:05 +00:00
|
|
|
room = scol - col + tabwidth - 1;
|
|
|
|
|
if (room > 0)
|
|
|
|
|
{
|
2019-12-05 21:10:38 +01:00
|
|
|
// Get buffer name in NameBuff[]
|
2006-02-24 23:53:04 +00:00
|
|
|
get_trans_bufname(cwp->w_buffer);
|
2006-04-05 20:41:53 +00:00
|
|
|
shorten_dir(NameBuff);
|
2006-02-21 22:12:05 +00:00
|
|
|
len = vim_strsize(NameBuff);
|
|
|
|
|
p = NameBuff;
|
|
|
|
|
if (has_mbyte)
|
|
|
|
|
while (len > room)
|
|
|
|
|
{
|
|
|
|
|
len -= ptr2cells(p);
|
2017-03-12 19:22:36 +01:00
|
|
|
MB_PTR_ADV(p);
|
2006-02-21 22:12:05 +00:00
|
|
|
}
|
2019-01-24 16:39:02 +01:00
|
|
|
else if (len > room)
|
2006-02-20 21:37:40 +00:00
|
|
|
{
|
2006-02-21 22:12:05 +00:00
|
|
|
p += len - room;
|
|
|
|
|
len = room;
|
2006-02-20 21:37:40 +00:00
|
|
|
}
|
2006-03-01 22:09:21 +00:00
|
|
|
if (len > Columns - col - 1)
|
|
|
|
|
len = Columns - col - 1;
|
2006-02-21 22:12:05 +00:00
|
|
|
|
2006-04-17 22:14:47 +00:00
|
|
|
screen_puts_len(p, (int)STRLEN(p), 0, col, attr);
|
2006-02-21 22:12:05 +00:00
|
|
|
col += len;
|
2006-02-20 21:37:40 +00:00
|
|
|
}
|
2006-02-21 22:12:05 +00:00
|
|
|
screen_putchar(' ', 0, col++, attr);
|
2006-02-20 21:37:40 +00:00
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// Store the tab page number in TabPageIdxs[], so that
|
|
|
|
|
// jump_to_mouse() knows where each one is.
|
2006-02-21 22:12:05 +00:00
|
|
|
++tabcount;
|
|
|
|
|
while (scol < col)
|
|
|
|
|
TabPageIdxs[scol++] = tabcount;
|
2006-02-16 22:11:02 +00:00
|
|
|
}
|
|
|
|
|
|
2006-02-21 22:12:05 +00:00
|
|
|
if (use_sep_chars)
|
|
|
|
|
c = '_';
|
|
|
|
|
else
|
|
|
|
|
c = ' ';
|
|
|
|
|
screen_fill(0, 1, col, (int)Columns, c, c, attr_fill);
|
2006-02-14 22:29:30 +00:00
|
|
|
|
2022-12-15 13:15:39 +00:00
|
|
|
// Draw the 'showcmd' information if 'showcmdloc' == "tabline".
|
|
|
|
|
if (p_sc && *p_sloc == 't')
|
|
|
|
|
{
|
|
|
|
|
int width = MIN(10, (int)Columns - col - (tabcount > 1) * 3);
|
|
|
|
|
|
|
|
|
|
if (width > 0)
|
|
|
|
|
screen_puts_len(showcmd_buf, width, 0, (int)Columns
|
|
|
|
|
- width - (tabcount > 1) * 2, attr_nosel);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// Put an "X" for closing the current tab if there are several.
|
2022-12-15 13:15:39 +00:00
|
|
|
if (tabcount > 1)
|
2006-02-22 21:25:37 +00:00
|
|
|
{
|
|
|
|
|
screen_putchar('X', 0, (int)Columns - 1, attr_nosel);
|
|
|
|
|
TabPageIdxs[Columns - 1] = -999;
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-04-16 18:30:08 +00:00
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// Reset the flag here again, in case evaluating 'tabline' causes it to be
|
|
|
|
|
// set.
|
2006-04-16 18:30:08 +00:00
|
|
|
redraw_tabline = FALSE;
|
2006-02-14 22:29:30 +00:00
|
|
|
}
|
2006-02-24 23:53:04 +00:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Get buffer name for "buf" into NameBuff[].
|
|
|
|
|
* Takes care of special buffer names and translates special characters.
|
|
|
|
|
*/
|
|
|
|
|
void
|
2016-01-30 20:31:25 +01:00
|
|
|
get_trans_bufname(buf_T *buf)
|
2006-02-24 23:53:04 +00:00
|
|
|
{
|
|
|
|
|
if (buf_spname(buf) != NULL)
|
2012-10-03 18:25:00 +02:00
|
|
|
vim_strncpy(NameBuff, buf_spname(buf), MAXPATHL - 1);
|
2006-02-24 23:53:04 +00:00
|
|
|
else
|
|
|
|
|
home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE);
|
|
|
|
|
trans_characters(NameBuff, MAXPATHL);
|
|
|
|
|
}
|
2006-02-14 22:29:30 +00:00
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
|
|
|
|
* Get the character to use in a status line. Get its attributes in "*attr".
|
|
|
|
|
*/
|
2019-09-19 23:06:20 +02:00
|
|
|
int
|
2017-07-31 22:29:35 +02:00
|
|
|
fillchar_status(int *attr, win_T *wp)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
|
int fill;
|
2017-07-31 22:29:35 +02:00
|
|
|
|
|
|
|
|
#ifdef FEAT_TERMINAL
|
|
|
|
|
if (bt_terminal(wp->w_buffer))
|
|
|
|
|
{
|
|
|
|
|
if (wp == curwin)
|
2017-08-14 22:35:08 +02:00
|
|
|
{
|
|
|
|
|
*attr = HL_ATTR(HLF_ST);
|
2022-07-04 17:34:33 +01:00
|
|
|
fill = wp->w_fill_chars.stl;
|
2017-08-14 22:35:08 +02:00
|
|
|
}
|
2017-07-31 22:29:35 +02:00
|
|
|
else
|
2017-08-14 22:35:08 +02:00
|
|
|
{
|
|
|
|
|
*attr = HL_ATTR(HLF_STNC);
|
2022-07-04 17:34:33 +01:00
|
|
|
fill = wp->w_fill_chars.stlnc;
|
2017-08-14 22:35:08 +02:00
|
|
|
}
|
2017-07-31 22:29:35 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
if (wp == curwin)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2017-03-16 17:23:31 +01:00
|
|
|
*attr = HL_ATTR(HLF_S);
|
2022-07-04 17:34:33 +01:00
|
|
|
fill = wp->w_fill_chars.stl;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-03-16 17:23:31 +01:00
|
|
|
*attr = HL_ATTR(HLF_SNC);
|
2022-07-04 17:34:33 +01:00
|
|
|
fill = wp->w_fill_chars.stlnc;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2023-11-08 21:23:29 +01:00
|
|
|
return fill;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Get the character to use in a separator between vertically split windows.
|
|
|
|
|
* Get its attributes in "*attr".
|
|
|
|
|
*/
|
2019-09-19 23:06:20 +02:00
|
|
|
int
|
2022-07-04 17:34:33 +01:00
|
|
|
fillchar_vsep(int *attr, win_T *wp)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2017-03-16 17:23:31 +01:00
|
|
|
*attr = HL_ATTR(HLF_C);
|
2022-07-04 17:34:33 +01:00
|
|
|
if (*attr == 0 && wp->w_fill_chars.vert == ' ')
|
2004-06-13 20:20:40 +00:00
|
|
|
return '|';
|
|
|
|
|
else
|
2022-07-04 17:34:33 +01:00
|
|
|
return wp->w_fill_chars.vert;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Return TRUE if redrawing should currently be done.
|
|
|
|
|
*/
|
|
|
|
|
int
|
2016-01-30 20:31:25 +01:00
|
|
|
redrawing(void)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2017-03-09 18:20:16 +01:00
|
|
|
#ifdef FEAT_EVAL
|
|
|
|
|
if (disable_redraw_for_testing)
|
|
|
|
|
return 0;
|
|
|
|
|
else
|
|
|
|
|
#endif
|
2023-05-20 14:07:00 +01:00
|
|
|
return ((RedrawingDisabled == 0
|
2018-09-06 13:14:43 +02:00
|
|
|
#ifdef FEAT_EVAL
|
|
|
|
|
|| ignore_redraw_flag_for_testing
|
|
|
|
|
#endif
|
|
|
|
|
) && !(p_lz && char_avail() && !KeyTyped && !do_redraw));
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Return TRUE if printing messages should currently be done.
|
|
|
|
|
*/
|
|
|
|
|
int
|
2016-01-30 20:31:25 +01:00
|
|
|
messaging(void)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2022-08-31 14:46:18 +01:00
|
|
|
return (!(p_lz && char_avail() && !KeyTyped));
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
2019-09-02 22:31:11 +02:00
|
|
|
/*
|
|
|
|
|
* Compute columns for ruler and shown command. 'sc_col' is also used to
|
|
|
|
|
* decide what the maximum length of a message on the status line can be.
|
|
|
|
|
* If there is a status line for the last window, 'sc_col' is independent
|
|
|
|
|
* of 'ru_col'.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define COL_RULER 17 // columns needed by standard ruler
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
comp_col(void)
|
|
|
|
|
{
|
2023-08-17 22:40:05 +02:00
|
|
|
int last_has_status = last_stl_height(FALSE) > 0;
|
2019-09-02 22:31:11 +02:00
|
|
|
|
|
|
|
|
sc_col = 0;
|
|
|
|
|
ru_col = 0;
|
|
|
|
|
if (p_ru)
|
|
|
|
|
{
|
2022-10-13 22:12:15 +01:00
|
|
|
#ifdef FEAT_STL_OPT
|
2019-09-02 22:31:11 +02:00
|
|
|
ru_col = (ru_wid ? ru_wid : COL_RULER) + 1;
|
2022-10-13 22:12:15 +01:00
|
|
|
#else
|
2019-09-02 22:31:11 +02:00
|
|
|
ru_col = COL_RULER + 1;
|
2022-10-13 22:12:15 +01:00
|
|
|
#endif
|
2019-09-02 22:31:11 +02:00
|
|
|
// no last status line, adjust sc_col
|
|
|
|
|
if (!last_has_status)
|
|
|
|
|
sc_col = ru_col;
|
|
|
|
|
}
|
2024-02-29 17:40:29 +01:00
|
|
|
if (p_sc && *p_sloc == 'l')
|
2019-09-02 22:31:11 +02:00
|
|
|
{
|
|
|
|
|
sc_col += SHOWCMD_COLS;
|
|
|
|
|
if (!p_ru || last_has_status) // no need for separating space
|
|
|
|
|
++sc_col;
|
|
|
|
|
}
|
|
|
|
|
sc_col = Columns - sc_col;
|
|
|
|
|
ru_col = Columns - ru_col;
|
|
|
|
|
if (sc_col <= 0) // screen too narrow, will become a mess
|
|
|
|
|
sc_col = 1;
|
|
|
|
|
if (ru_col <= 0)
|
|
|
|
|
ru_col = 1;
|
|
|
|
|
#ifdef FEAT_EVAL
|
|
|
|
|
set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2004-07-03 16:05:59 +00:00
|
|
|
#if defined(FEAT_LINEBREAK) || defined(PROTO)
|
|
|
|
|
/*
|
2010-05-16 15:46:46 +02:00
|
|
|
* Return the width of the 'number' and 'relativenumber' column.
|
|
|
|
|
* Caller may need to check if 'number' or 'relativenumber' is set.
|
2004-07-03 16:05:59 +00:00
|
|
|
* Otherwise it depends on 'numberwidth' and the line count.
|
|
|
|
|
*/
|
|
|
|
|
int
|
2016-01-30 20:31:25 +01:00
|
|
|
number_width(win_T *wp)
|
2004-07-03 16:05:59 +00:00
|
|
|
{
|
|
|
|
|
int n;
|
|
|
|
|
linenr_T lnum;
|
|
|
|
|
|
2013-06-04 22:13:50 +02:00
|
|
|
if (wp->w_p_rnu && !wp->w_p_nu)
|
2019-12-05 21:10:38 +01:00
|
|
|
// cursor line shows "0"
|
2013-06-04 22:13:50 +02:00
|
|
|
lnum = wp->w_height;
|
|
|
|
|
else
|
2019-12-05 21:10:38 +01:00
|
|
|
// cursor line shows absolute line number
|
2013-06-04 22:13:50 +02:00
|
|
|
lnum = wp->w_buffer->b_ml.ml_line_count;
|
2010-05-16 15:46:46 +02:00
|
|
|
|
2015-03-20 15:42:10 +01:00
|
|
|
if (lnum == wp->w_nrwidth_line_count && wp->w_nuw_cached == wp->w_p_nuw)
|
2004-07-03 16:05:59 +00:00
|
|
|
return wp->w_nrwidth_width;
|
|
|
|
|
wp->w_nrwidth_line_count = lnum;
|
|
|
|
|
|
|
|
|
|
n = 0;
|
|
|
|
|
do
|
|
|
|
|
{
|
2006-04-30 18:54:39 +00:00
|
|
|
lnum /= 10;
|
|
|
|
|
++n;
|
2004-07-03 16:05:59 +00:00
|
|
|
} while (lnum > 0);
|
|
|
|
|
|
2019-12-05 21:10:38 +01:00
|
|
|
// 'numberwidth' gives the minimal width plus one
|
2004-07-03 16:05:59 +00:00
|
|
|
if (n < wp->w_p_nuw - 1)
|
|
|
|
|
n = wp->w_p_nuw - 1;
|
|
|
|
|
|
2019-07-04 11:59:28 +02:00
|
|
|
# ifdef FEAT_SIGNS
|
|
|
|
|
// If 'signcolumn' is set to 'number' and there is a sign to display, then
|
|
|
|
|
// the minimal width for the number column is 2.
|
2019-11-12 22:33:45 +01:00
|
|
|
if (n < 2 && get_first_valid_sign(wp) != NULL
|
2019-07-04 11:59:28 +02:00
|
|
|
&& (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u'))
|
|
|
|
|
n = 2;
|
|
|
|
|
# endif
|
|
|
|
|
|
2004-07-03 16:05:59 +00:00
|
|
|
wp->w_nrwidth_width = n;
|
2015-03-20 15:42:10 +01:00
|
|
|
wp->w_nuw_cached = wp->w_p_nuw;
|
2004-07-03 16:05:59 +00:00
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2012-12-05 16:10:42 +01:00
|
|
|
|
2019-01-20 15:30:40 +01:00
|
|
|
#if defined(FEAT_EVAL) || defined(PROTO)
|
2012-12-05 16:10:42 +01:00
|
|
|
/*
|
|
|
|
|
* Return the current cursor column. This is the actual position on the
|
|
|
|
|
* screen. First column is 0.
|
|
|
|
|
*/
|
|
|
|
|
int
|
2016-01-30 20:31:25 +01:00
|
|
|
screen_screencol(void)
|
2012-12-05 16:10:42 +01:00
|
|
|
{
|
|
|
|
|
return screen_cur_col;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Return the current cursor row. This is the actual position on the screen.
|
|
|
|
|
* First row is 0.
|
|
|
|
|
*/
|
|
|
|
|
int
|
2016-01-30 20:31:25 +01:00
|
|
|
screen_screenrow(void)
|
2012-12-05 16:10:42 +01:00
|
|
|
{
|
|
|
|
|
return screen_cur_row;
|
|
|
|
|
}
|
2019-01-20 15:30:40 +01:00
|
|
|
#endif
|
2019-09-02 22:31:11 +02:00
|
|
|
|
2021-10-16 17:51:40 +01:00
|
|
|
/*
|
|
|
|
|
* Calls mb_ptr2char_adv(p) and returns the character.
|
|
|
|
|
* If "p" starts with "\x", "\u" or "\U" the hex or unicode value is used.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
get_encoded_char_adv(char_u **p)
|
|
|
|
|
{
|
|
|
|
|
char_u *s = *p;
|
|
|
|
|
|
|
|
|
|
if (s[0] == '\\' && (s[1] == 'x' || s[1] == 'u' || s[1] == 'U'))
|
|
|
|
|
{
|
|
|
|
|
varnumber_T num = 0;
|
|
|
|
|
int bytes;
|
|
|
|
|
int n;
|
|
|
|
|
|
|
|
|
|
for (bytes = s[1] == 'x' ? 1 : s[1] == 'u' ? 2 : 4; bytes > 0; --bytes)
|
|
|
|
|
{
|
|
|
|
|
*p += 2;
|
|
|
|
|
n = hexhex2nr(*p);
|
|
|
|
|
if (n < 0)
|
|
|
|
|
return 0;
|
|
|
|
|
num = num * 256 + n;
|
|
|
|
|
}
|
|
|
|
|
*p += 2;
|
|
|
|
|
return num;
|
|
|
|
|
}
|
|
|
|
|
return mb_ptr2char_adv(p);
|
|
|
|
|
}
|
|
|
|
|
|
patch 9.0.1958: cannot complete option values
Problem: cannot complete option values
Solution: Add completion functions for several options
Add cmdline tab-completion for setting string options
Add tab-completion for setting string options on the cmdline using
`:set=` (along with `:set+=` and `:set-=`).
The existing tab completion for setting options currently only works
when nothing is typed yet, and it only fills in with the existing value,
e.g. when the user does `:set diffopt=<Tab>` it will be completed to
`set diffopt=internal,filler,closeoff` and nothing else. This isn't too
useful as a user usually wants auto-complete to suggest all the possible
values, such as 'iblank', or 'algorithm:patience'.
For set= and set+=, this adds a new optional callback function for each
option that can be invoked when doing completion. This allows for each
option to have control over how completion works. For example, in
'diffopt', it will suggest the default enumeration, but if `algorithm:`
is selected, it will further suggest different algorithm types like
'meyers' and 'patience'. When using set=, the existing option value will
be filled in as the first choice to preserve the existing behavior. When
using set+= this won't happen as it doesn't make sense.
For flag list options (e.g. 'mouse' and 'guioptions'), completion will
take into account existing typed values (and in the case of set+=, the
existing option value) to make sure it doesn't suggest duplicates.
For set-=, there is a new `ExpandSettingSubtract` function which will
handle flag list and comma-separated options smartly, by only suggesting
values that currently exist in the option.
Note that Vim has some existing code that adds special handling for
'filetype', 'syntax', and misc dir options like 'backupdir'. This change
preserves them as they already work, instead of converting to the new
callback API for each option.
closes: #13182
Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
2023-09-29 20:42:32 +02:00
|
|
|
struct charstab
|
|
|
|
|
{
|
|
|
|
|
int *cp;
|
|
|
|
|
char *name;
|
|
|
|
|
};
|
|
|
|
|
static fill_chars_T fill_chars;
|
|
|
|
|
static struct charstab filltab[] =
|
|
|
|
|
{
|
|
|
|
|
{&fill_chars.stl, "stl"},
|
|
|
|
|
{&fill_chars.stlnc, "stlnc"},
|
|
|
|
|
{&fill_chars.vert, "vert"},
|
|
|
|
|
{&fill_chars.fold, "fold"},
|
|
|
|
|
{&fill_chars.foldopen, "foldopen"},
|
|
|
|
|
{&fill_chars.foldclosed, "foldclose"},
|
|
|
|
|
{&fill_chars.foldsep, "foldsep"},
|
|
|
|
|
{&fill_chars.diff, "diff"},
|
|
|
|
|
{&fill_chars.eob, "eob"},
|
|
|
|
|
{&fill_chars.lastline, "lastline"},
|
|
|
|
|
};
|
|
|
|
|
static lcs_chars_T lcs_chars;
|
|
|
|
|
static struct charstab lcstab[] =
|
|
|
|
|
{
|
|
|
|
|
{&lcs_chars.eol, "eol"},
|
|
|
|
|
{&lcs_chars.ext, "extends"},
|
|
|
|
|
{&lcs_chars.nbsp, "nbsp"},
|
|
|
|
|
{&lcs_chars.prec, "precedes"},
|
|
|
|
|
{&lcs_chars.space, "space"},
|
|
|
|
|
{&lcs_chars.tab2, "tab"},
|
|
|
|
|
{&lcs_chars.trail, "trail"},
|
|
|
|
|
{&lcs_chars.lead, "lead"},
|
|
|
|
|
#ifdef FEAT_CONCEAL
|
|
|
|
|
{&lcs_chars.conceal, "conceal"},
|
|
|
|
|
#else
|
|
|
|
|
{NULL, "conceal"},
|
|
|
|
|
#endif
|
2023-09-30 12:43:07 +02:00
|
|
|
{NULL, "multispace"},
|
|
|
|
|
{NULL, "leadmultispace"},
|
patch 9.0.1958: cannot complete option values
Problem: cannot complete option values
Solution: Add completion functions for several options
Add cmdline tab-completion for setting string options
Add tab-completion for setting string options on the cmdline using
`:set=` (along with `:set+=` and `:set-=`).
The existing tab completion for setting options currently only works
when nothing is typed yet, and it only fills in with the existing value,
e.g. when the user does `:set diffopt=<Tab>` it will be completed to
`set diffopt=internal,filler,closeoff` and nothing else. This isn't too
useful as a user usually wants auto-complete to suggest all the possible
values, such as 'iblank', or 'algorithm:patience'.
For set= and set+=, this adds a new optional callback function for each
option that can be invoked when doing completion. This allows for each
option to have control over how completion works. For example, in
'diffopt', it will suggest the default enumeration, but if `algorithm:`
is selected, it will further suggest different algorithm types like
'meyers' and 'patience'. When using set=, the existing option value will
be filled in as the first choice to preserve the existing behavior. When
using set+= this won't happen as it doesn't make sense.
For flag list options (e.g. 'mouse' and 'guioptions'), completion will
take into account existing typed values (and in the case of set+=, the
existing option value) to make sure it doesn't suggest duplicates.
For set-=, there is a new `ExpandSettingSubtract` function which will
handle flag list and comma-separated options smartly, by only suggesting
values that currently exist in the option.
Note that Vim has some existing code that adds special handling for
'filetype', 'syntax', and misc dir options like 'backupdir'. This change
preserves them as they already work, instead of converting to the new
callback API for each option.
closes: #13182
Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
2023-09-29 20:42:32 +02:00
|
|
|
};
|
|
|
|
|
|
2024-01-17 20:54:49 +01:00
|
|
|
static char *
|
|
|
|
|
field_value_err(char *errbuf, size_t errbuflen, char *fmt, char *field)
|
|
|
|
|
{
|
|
|
|
|
if (errbuf == NULL)
|
|
|
|
|
return "";
|
|
|
|
|
vim_snprintf(errbuf, errbuflen, _(fmt), field);
|
|
|
|
|
return errbuf;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-02 22:31:11 +02:00
|
|
|
/*
|
|
|
|
|
* Handle setting 'listchars' or 'fillchars'.
|
2023-03-03 12:26:15 +00:00
|
|
|
* "value" points to either the global or the window-local value.
|
2023-05-08 15:56:21 +01:00
|
|
|
* "is_listchars" is TRUE for "listchars" and FALSE for "fillchars".
|
2022-07-04 21:03:36 +01:00
|
|
|
* When "apply" is FALSE do not store the flags, only check for errors.
|
2021-02-15 20:38:25 +01:00
|
|
|
* Assume monocell characters.
|
2019-09-02 22:31:11 +02:00
|
|
|
* Returns error message, NULL if it's OK.
|
|
|
|
|
*/
|
2023-03-02 14:46:48 +00:00
|
|
|
static char *
|
2024-01-17 20:54:49 +01:00
|
|
|
set_chars_option(win_T *wp, char_u *value, int is_listchars, int apply,
|
|
|
|
|
char *errbuf, size_t errbuflen)
|
2019-09-02 22:31:11 +02:00
|
|
|
{
|
2023-09-30 12:43:07 +02:00
|
|
|
int round, i, len, entries;
|
2022-07-04 17:34:33 +01:00
|
|
|
char_u *p, *s;
|
|
|
|
|
int c1 = 0, c2 = 0, c3 = 0;
|
|
|
|
|
char_u *last_multispace = NULL; // Last occurrence of "multispace:"
|
|
|
|
|
char_u *last_lmultispace = NULL; // Last occurrence of "leadmultispace:"
|
|
|
|
|
int multispace_len = 0; // Length of lcs-multispace string
|
|
|
|
|
int lead_multispace_len = 0; // Length of lcs-leadmultispace string
|
2022-07-04 21:03:36 +01:00
|
|
|
|
|
|
|
|
struct charstab *tab;
|
|
|
|
|
|
|
|
|
|
if (is_listchars)
|
2019-09-02 22:31:11 +02:00
|
|
|
{
|
|
|
|
|
tab = lcstab;
|
2021-02-16 22:22:13 +01:00
|
|
|
CLEAR_FIELD(lcs_chars);
|
2021-06-02 13:28:16 +02:00
|
|
|
entries = ARRAY_LENGTH(lcstab);
|
2023-05-08 15:56:21 +01:00
|
|
|
if (wp->w_p_lcs[0] == NUL)
|
2023-03-02 14:46:48 +00:00
|
|
|
value = p_lcs; // local value is empty, use the global value
|
2019-09-02 22:31:11 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tab = filltab;
|
2021-06-02 13:28:16 +02:00
|
|
|
entries = ARRAY_LENGTH(filltab);
|
2023-05-08 15:56:21 +01:00
|
|
|
if (wp->w_p_fcs[0] == NUL)
|
2022-07-04 21:03:36 +01:00
|
|
|
value = p_fcs; // local value is empty, us the global value
|
2019-09-02 22:31:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// first round: check for valid value, second round: assign values
|
2023-11-23 20:47:16 +01:00
|
|
|
for (round = 0; round <= (apply ? 1 : 0); ++round)
|
2019-09-02 22:31:11 +02:00
|
|
|
{
|
|
|
|
|
if (round > 0)
|
|
|
|
|
{
|
2022-07-04 17:34:33 +01:00
|
|
|
// After checking that the value is valid: set defaults.
|
2022-07-04 21:03:36 +01:00
|
|
|
if (is_listchars)
|
2019-09-02 22:31:11 +02:00
|
|
|
{
|
2022-07-04 17:34:33 +01:00
|
|
|
for (i = 0; i < entries; ++i)
|
|
|
|
|
if (tab[i].cp != NULL)
|
|
|
|
|
*(tab[i].cp) = NUL;
|
2021-02-16 22:22:13 +01:00
|
|
|
lcs_chars.tab1 = NUL;
|
|
|
|
|
lcs_chars.tab3 = NUL;
|
2022-06-09 13:55:28 +01:00
|
|
|
|
2021-09-13 22:17:38 +02:00
|
|
|
if (multispace_len > 0)
|
2021-09-10 16:58:30 +02:00
|
|
|
{
|
|
|
|
|
lcs_chars.multispace = ALLOC_MULT(int, multispace_len + 1);
|
2022-07-04 21:03:36 +01:00
|
|
|
if (lcs_chars.multispace != NULL)
|
|
|
|
|
lcs_chars.multispace[multispace_len] = NUL;
|
2021-09-10 16:58:30 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
lcs_chars.multispace = NULL;
|
2022-06-07 10:16:15 +01:00
|
|
|
|
|
|
|
|
if (lead_multispace_len > 0)
|
|
|
|
|
{
|
2022-07-04 17:34:33 +01:00
|
|
|
lcs_chars.leadmultispace =
|
|
|
|
|
ALLOC_MULT(int, lead_multispace_len + 1);
|
2022-06-07 10:16:15 +01:00
|
|
|
lcs_chars.leadmultispace[lead_multispace_len] = NUL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
lcs_chars.leadmultispace = NULL;
|
2019-09-02 22:31:11 +02:00
|
|
|
}
|
|
|
|
|
else
|
2021-02-13 18:24:23 +01:00
|
|
|
{
|
2022-07-04 17:34:33 +01:00
|
|
|
fill_chars.stl = ' ';
|
|
|
|
|
fill_chars.stlnc = ' ';
|
|
|
|
|
fill_chars.vert = ' ';
|
|
|
|
|
fill_chars.fold = '-';
|
|
|
|
|
fill_chars.foldopen = '-';
|
|
|
|
|
fill_chars.foldclosed = '+';
|
|
|
|
|
fill_chars.foldsep = '|';
|
|
|
|
|
fill_chars.diff = '-';
|
|
|
|
|
fill_chars.eob = '~';
|
2022-10-04 14:36:29 +01:00
|
|
|
fill_chars.lastline = '@';
|
2021-02-13 18:24:23 +01:00
|
|
|
}
|
2019-09-02 22:31:11 +02:00
|
|
|
}
|
2022-07-04 21:03:36 +01:00
|
|
|
p = value;
|
2019-09-02 22:31:11 +02:00
|
|
|
while (*p)
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; i < entries; ++i)
|
|
|
|
|
{
|
|
|
|
|
len = (int)STRLEN(tab[i].name);
|
2024-01-17 20:54:49 +01:00
|
|
|
if (!(STRNCMP(p, tab[i].name, len) == 0 && p[len] == ':'))
|
2023-09-30 12:43:07 +02:00
|
|
|
continue;
|
2019-09-02 22:31:11 +02:00
|
|
|
|
2023-09-30 12:43:07 +02:00
|
|
|
if (is_listchars && strcmp(tab[i].name, "multispace") == 0)
|
2021-09-10 16:58:30 +02:00
|
|
|
{
|
|
|
|
|
s = p + len + 1;
|
|
|
|
|
if (round == 0)
|
|
|
|
|
{
|
|
|
|
|
// Get length of lcs-multispace string in first round
|
|
|
|
|
last_multispace = p;
|
|
|
|
|
multispace_len = 0;
|
|
|
|
|
while (*s != NUL && *s != ',')
|
|
|
|
|
{
|
2021-10-16 17:51:40 +01:00
|
|
|
c1 = get_encoded_char_adv(&s);
|
2021-12-18 15:32:46 +00:00
|
|
|
if (char2cells(c1) > 1)
|
2024-01-17 20:54:49 +01:00
|
|
|
return field_value_err(errbuf, errbuflen,
|
|
|
|
|
e_wrong_character_width_for_field_str,
|
|
|
|
|
tab[i].name);
|
2021-09-10 16:58:30 +02:00
|
|
|
++multispace_len;
|
|
|
|
|
}
|
|
|
|
|
if (multispace_len == 0)
|
|
|
|
|
// lcs-multispace cannot be an empty string
|
2024-01-17 20:54:49 +01:00
|
|
|
return field_value_err(errbuf, errbuflen,
|
|
|
|
|
e_wrong_number_of_characters_for_field_str,
|
|
|
|
|
tab[i].name);
|
2021-09-10 16:58:30 +02:00
|
|
|
p = s;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int multispace_pos = 0;
|
2021-09-13 22:17:38 +02:00
|
|
|
|
2021-09-10 16:58:30 +02:00
|
|
|
while (*s != NUL && *s != ',')
|
|
|
|
|
{
|
2021-10-16 17:51:40 +01:00
|
|
|
c1 = get_encoded_char_adv(&s);
|
2021-09-10 16:58:30 +02:00
|
|
|
if (p == last_multispace)
|
|
|
|
|
lcs_chars.multispace[multispace_pos++] = c1;
|
|
|
|
|
}
|
|
|
|
|
p = s;
|
|
|
|
|
}
|
2023-09-30 12:43:07 +02:00
|
|
|
break;
|
2021-09-10 16:58:30 +02:00
|
|
|
}
|
2022-06-07 10:16:15 +01:00
|
|
|
|
2023-09-30 12:43:07 +02:00
|
|
|
if (is_listchars && strcmp(tab[i].name, "leadmultispace") == 0)
|
2022-06-07 10:16:15 +01:00
|
|
|
{
|
2023-09-30 12:43:07 +02:00
|
|
|
s = p + len + 1;
|
2022-06-07 10:16:15 +01:00
|
|
|
if (round == 0)
|
|
|
|
|
{
|
2022-06-09 13:55:28 +01:00
|
|
|
// get length of lcs-leadmultispace string in first
|
|
|
|
|
// round
|
2022-06-07 10:16:15 +01:00
|
|
|
last_lmultispace = p;
|
|
|
|
|
lead_multispace_len = 0;
|
|
|
|
|
while (*s != NUL && *s != ',')
|
|
|
|
|
{
|
|
|
|
|
c1 = get_encoded_char_adv(&s);
|
|
|
|
|
if (char2cells(c1) > 1)
|
2024-01-17 20:54:49 +01:00
|
|
|
return field_value_err(errbuf, errbuflen,
|
|
|
|
|
e_wrong_character_width_for_field_str,
|
|
|
|
|
tab[i].name);
|
2022-06-07 10:16:15 +01:00
|
|
|
++lead_multispace_len;
|
|
|
|
|
}
|
|
|
|
|
if (lead_multispace_len == 0)
|
2022-06-09 13:55:28 +01:00
|
|
|
// lcs-leadmultispace cannot be an empty string
|
2024-01-17 20:54:49 +01:00
|
|
|
return field_value_err(errbuf, errbuflen,
|
|
|
|
|
e_wrong_number_of_characters_for_field_str,
|
|
|
|
|
tab[i].name);
|
2022-06-07 10:16:15 +01:00
|
|
|
p = s;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int multispace_pos = 0;
|
|
|
|
|
|
|
|
|
|
while (*s != NUL && *s != ',')
|
|
|
|
|
{
|
|
|
|
|
c1 = get_encoded_char_adv(&s);
|
|
|
|
|
if (p == last_lmultispace)
|
|
|
|
|
lcs_chars.leadmultispace[multispace_pos++] = c1;
|
|
|
|
|
}
|
|
|
|
|
p = s;
|
|
|
|
|
}
|
2023-09-30 12:43:07 +02:00
|
|
|
break;
|
2022-06-07 10:16:15 +01:00
|
|
|
}
|
2023-09-30 12:43:07 +02:00
|
|
|
|
|
|
|
|
c2 = c3 = 0;
|
|
|
|
|
s = p + len + 1;
|
2024-01-17 20:54:49 +01:00
|
|
|
if (*s == NUL)
|
|
|
|
|
return field_value_err(errbuf, errbuflen,
|
|
|
|
|
e_wrong_number_of_characters_for_field_str,
|
|
|
|
|
tab[i].name);
|
2023-09-30 12:43:07 +02:00
|
|
|
c1 = get_encoded_char_adv(&s);
|
|
|
|
|
if (char2cells(c1) > 1)
|
2024-01-17 20:54:49 +01:00
|
|
|
return field_value_err(errbuf, errbuflen,
|
|
|
|
|
e_wrong_character_width_for_field_str,
|
|
|
|
|
tab[i].name);
|
2023-09-30 12:43:07 +02:00
|
|
|
if (tab[i].cp == &lcs_chars.tab2)
|
|
|
|
|
{
|
|
|
|
|
if (*s == NUL)
|
2024-01-17 20:54:49 +01:00
|
|
|
return field_value_err(errbuf, errbuflen,
|
|
|
|
|
e_wrong_number_of_characters_for_field_str,
|
|
|
|
|
tab[i].name);
|
2023-09-30 12:43:07 +02:00
|
|
|
c2 = get_encoded_char_adv(&s);
|
|
|
|
|
if (char2cells(c2) > 1)
|
2024-01-17 20:54:49 +01:00
|
|
|
return field_value_err(errbuf, errbuflen,
|
|
|
|
|
e_wrong_character_width_for_field_str,
|
|
|
|
|
tab[i].name);
|
2023-09-30 12:43:07 +02:00
|
|
|
if (!(*s == ',' || *s == NUL))
|
|
|
|
|
{
|
|
|
|
|
c3 = get_encoded_char_adv(&s);
|
|
|
|
|
if (char2cells(c3) > 1)
|
2024-01-17 20:54:49 +01:00
|
|
|
return field_value_err(errbuf, errbuflen,
|
|
|
|
|
e_wrong_character_width_for_field_str,
|
|
|
|
|
tab[i].name);
|
2023-09-30 12:43:07 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (*s == ',' || *s == NUL)
|
|
|
|
|
{
|
|
|
|
|
if (round > 0)
|
|
|
|
|
{
|
|
|
|
|
if (tab[i].cp == &lcs_chars.tab2)
|
|
|
|
|
{
|
|
|
|
|
lcs_chars.tab1 = c1;
|
|
|
|
|
lcs_chars.tab2 = c2;
|
|
|
|
|
lcs_chars.tab3 = c3;
|
|
|
|
|
}
|
|
|
|
|
else if (tab[i].cp != NULL)
|
|
|
|
|
*(tab[i].cp) = c1;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
p = s;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2024-01-17 20:54:49 +01:00
|
|
|
else
|
|
|
|
|
return field_value_err(errbuf, errbuflen,
|
|
|
|
|
e_wrong_number_of_characters_for_field_str,
|
|
|
|
|
tab[i].name);
|
2021-09-10 16:58:30 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-30 12:43:07 +02:00
|
|
|
if (i == entries)
|
|
|
|
|
return e_invalid_argument;
|
|
|
|
|
|
2019-09-02 22:31:11 +02:00
|
|
|
if (*p == ',')
|
|
|
|
|
++p;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-04 17:34:33 +01:00
|
|
|
|
2022-07-04 21:03:36 +01:00
|
|
|
if (apply)
|
2021-09-10 16:58:30 +02:00
|
|
|
{
|
2022-07-04 21:03:36 +01:00
|
|
|
if (is_listchars)
|
|
|
|
|
{
|
|
|
|
|
vim_free(wp->w_lcs_chars.multispace);
|
|
|
|
|
vim_free(wp->w_lcs_chars.leadmultispace);
|
|
|
|
|
wp->w_lcs_chars = lcs_chars;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
wp->w_fill_chars = fill_chars;
|
|
|
|
|
}
|
2021-09-10 16:58:30 +02:00
|
|
|
}
|
2019-09-02 22:31:11 +02:00
|
|
|
|
|
|
|
|
return NULL; // no error
|
|
|
|
|
}
|
2022-08-09 12:53:14 +01:00
|
|
|
|
2023-03-02 14:46:48 +00:00
|
|
|
/*
|
|
|
|
|
* Handle the new value of 'fillchars'.
|
|
|
|
|
*/
|
|
|
|
|
char *
|
2024-01-17 20:54:49 +01:00
|
|
|
set_fillchars_option(win_T *wp, char_u *val, int apply, char *errbuf,
|
|
|
|
|
size_t errbuflen)
|
2023-03-02 14:46:48 +00:00
|
|
|
{
|
2024-01-17 20:54:49 +01:00
|
|
|
return set_chars_option(wp, val, FALSE, apply, errbuf, errbuflen);
|
2023-03-02 14:46:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Handle the new value of 'listchars'.
|
|
|
|
|
*/
|
|
|
|
|
char *
|
2024-01-17 20:54:49 +01:00
|
|
|
set_listchars_option(win_T *wp, char_u *val, int apply, char *errbuf,
|
|
|
|
|
size_t errbuflen)
|
2023-03-02 14:46:48 +00:00
|
|
|
{
|
2024-01-17 20:54:49 +01:00
|
|
|
return set_chars_option(wp, val, TRUE, apply, errbuf, errbuflen);
|
2023-03-02 14:46:48 +00:00
|
|
|
}
|
|
|
|
|
|
patch 9.0.1958: cannot complete option values
Problem: cannot complete option values
Solution: Add completion functions for several options
Add cmdline tab-completion for setting string options
Add tab-completion for setting string options on the cmdline using
`:set=` (along with `:set+=` and `:set-=`).
The existing tab completion for setting options currently only works
when nothing is typed yet, and it only fills in with the existing value,
e.g. when the user does `:set diffopt=<Tab>` it will be completed to
`set diffopt=internal,filler,closeoff` and nothing else. This isn't too
useful as a user usually wants auto-complete to suggest all the possible
values, such as 'iblank', or 'algorithm:patience'.
For set= and set+=, this adds a new optional callback function for each
option that can be invoked when doing completion. This allows for each
option to have control over how completion works. For example, in
'diffopt', it will suggest the default enumeration, but if `algorithm:`
is selected, it will further suggest different algorithm types like
'meyers' and 'patience'. When using set=, the existing option value will
be filled in as the first choice to preserve the existing behavior. When
using set+= this won't happen as it doesn't make sense.
For flag list options (e.g. 'mouse' and 'guioptions'), completion will
take into account existing typed values (and in the case of set+=, the
existing option value) to make sure it doesn't suggest duplicates.
For set-=, there is a new `ExpandSettingSubtract` function which will
handle flag list and comma-separated options smartly, by only suggesting
values that currently exist in the option.
Note that Vim has some existing code that adds special handling for
'filetype', 'syntax', and misc dir options like 'backupdir'. This change
preserves them as they already work, instead of converting to the new
callback API for each option.
closes: #13182
Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
2023-09-29 20:42:32 +02:00
|
|
|
/*
|
|
|
|
|
* Function given to ExpandGeneric() to obtain possible arguments of the
|
|
|
|
|
* 'fillchars' option.
|
|
|
|
|
*/
|
|
|
|
|
char_u *
|
|
|
|
|
get_fillchars_name(expand_T *xp UNUSED, int idx)
|
|
|
|
|
{
|
|
|
|
|
if (idx >= (int)(sizeof(filltab) / sizeof(filltab[0])))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return (char_u*)filltab[idx].name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Function given to ExpandGeneric() to obtain possible arguments of the
|
|
|
|
|
* 'listchars' option.
|
|
|
|
|
*/
|
|
|
|
|
char_u *
|
|
|
|
|
get_listchars_name(expand_T *xp UNUSED, int idx)
|
|
|
|
|
{
|
|
|
|
|
if (idx >= (int)(sizeof(lcstab) / sizeof(lcstab[0])))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return (char_u*)lcstab[idx].name;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-09 12:53:14 +01:00
|
|
|
/*
|
|
|
|
|
* Check all global and local values of 'listchars' and 'fillchars'.
|
|
|
|
|
* Return an untranslated error messages if any of them is invalid, NULL
|
|
|
|
|
* otherwise.
|
|
|
|
|
*/
|
|
|
|
|
char *
|
|
|
|
|
check_chars_options(void)
|
|
|
|
|
{
|
|
|
|
|
tabpage_T *tp;
|
|
|
|
|
win_T *wp;
|
|
|
|
|
|
2024-01-17 20:54:49 +01:00
|
|
|
if (set_listchars_option(curwin, p_lcs, FALSE, NULL, 0) != NULL)
|
2022-08-09 12:53:14 +01:00
|
|
|
return e_conflicts_with_value_of_listchars;
|
2024-01-17 20:54:49 +01:00
|
|
|
if (set_fillchars_option(curwin, p_fcs, FALSE, NULL, 0) != NULL)
|
2022-08-09 12:53:14 +01:00
|
|
|
return e_conflicts_with_value_of_fillchars;
|
|
|
|
|
FOR_ALL_TAB_WINDOWS(tp, wp)
|
|
|
|
|
{
|
2024-01-17 20:54:49 +01:00
|
|
|
if (set_listchars_option(wp, wp->w_p_lcs, FALSE, NULL, 0) != NULL)
|
2022-08-09 12:53:14 +01:00
|
|
|
return e_conflicts_with_value_of_listchars;
|
2024-01-17 20:54:49 +01:00
|
|
|
if (set_fillchars_option(wp, wp->w_p_fcs, FALSE, NULL, 0) != NULL)
|
2022-08-09 12:53:14 +01:00
|
|
|
return e_conflicts_with_value_of_fillchars;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|