aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2023-03-14 11:49:46 +0100
committerbfredl <bjorn.linse@gmail.com>2023-03-14 13:37:43 +0100
commitd6ecead36406233cc56353dd05f3380f0497630f (patch)
tree6adad28d9a446e422f114d285107595c563760a8
parentef31444cccdd93f515a8b7a968268cb04e680370 (diff)
downloadrneovim-d6ecead36406233cc56353dd05f3380f0497630f.tar.gz
rneovim-d6ecead36406233cc56353dd05f3380f0497630f.tar.bz2
rneovim-d6ecead36406233cc56353dd05f3380f0497630f.zip
refactor(screen): screen.c delenda est
drawscreen.c vs screen.c makes absolutely no sense. The screen exists only to draw upon it, therefore helper functions are distributed randomly between screen.c and the file that does the redrawing. In addition screen.c does a lot of drawing on the screen. It made more sense for vim/vim as our grid.c is their screen.c Not sure if we want to dump all the code for option chars into optionstr.c, so keep these in a optionchar.c for now.
-rw-r--r--src/nvim/autocmd.c1
-rw-r--r--src/nvim/buffer.c1
-rw-r--r--src/nvim/change.c1
-rw-r--r--src/nvim/charset.c11
-rw-r--r--src/nvim/digraph.c40
-rw-r--r--src/nvim/drawline.c87
-rw-r--r--src/nvim/drawline.h1
-rw-r--r--src/nvim/drawscreen.c587
-rw-r--r--src/nvim/drawscreen.h5
-rw-r--r--src/nvim/edit.c3
-rw-r--r--src/nvim/ex_cmds.c3
-rw-r--r--src/nvim/ex_docmd.c1
-rw-r--r--src/nvim/ex_getln.c1
-rw-r--r--src/nvim/fileio.c3
-rw-r--r--src/nvim/getchar.c1
-rw-r--r--src/nvim/indent.c1
-rw-r--r--src/nvim/insexpand.c1
-rw-r--r--src/nvim/mbyte.c2
-rw-r--r--src/nvim/memline.c2
-rw-r--r--src/nvim/message.c27
-rw-r--r--src/nvim/mouse.c1
-rw-r--r--src/nvim/move.c13
-rw-r--r--src/nvim/normal.c1
-rw-r--r--src/nvim/ops.c1
-rw-r--r--src/nvim/option.c1
-rw-r--r--src/nvim/optionstr.c283
-rw-r--r--src/nvim/popupmenu.c1
-rw-r--r--src/nvim/screen.c1098
-rw-r--r--src/nvim/screen.h19
-rw-r--r--src/nvim/search.c1
-rw-r--r--src/nvim/spellsuggest.c5
-rw-r--r--src/nvim/state.c1
-rw-r--r--src/nvim/statusline.c37
-rw-r--r--src/nvim/terminal.c1
-rw-r--r--src/nvim/textobject.c1
-rw-r--r--src/nvim/undo.c1
-rw-r--r--src/nvim/window.c1
37 files changed, 1069 insertions, 1176 deletions
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index 2f1317b05d..c66ee4286e 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -48,7 +48,6 @@
#include "nvim/profile.h"
#include "nvim/regexp.h"
#include "nvim/runtime.h"
-#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/state.h"
#include "nvim/strings.h"
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 7a4e5d3eeb..cedbadbaf3 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -87,7 +87,6 @@
#include "nvim/quickfix.h"
#include "nvim/regexp.h"
#include "nvim/runtime.h"
-#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/sign.h"
#include "nvim/spell.h"
diff --git a/src/nvim/change.c b/src/nvim/change.c
index 7c8f62015d..04eadfa269 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -42,7 +42,6 @@
#include "nvim/os/time.h"
#include "nvim/plines.h"
#include "nvim/pos.h"
-#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/state.h"
#include "nvim/strings.h"
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index b792ae5ece..a3aa6783ee 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -660,6 +660,17 @@ size_t transchar_hex(char *const buf, const int c)
return i;
}
+/// Mirror text "str" for right-left displaying.
+/// Only works for single-byte characters (e.g., numbers).
+void rl_mirror_ascii(char *str)
+{
+ for (char *p1 = str, *p2 = str + strlen(str) - 1; p1 < p2; p1++, p2--) {
+ char t = *p1;
+ *p1 = *p2;
+ *p2 = t;
+ }
+}
+
/// Convert the lower 4 bits of byte "c" to its hex character
///
/// Lower case letters are used to avoid the confusion of <F1> being 0xf1 or
diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c
index ae13164191..2066151564 100644
--- a/src/nvim/digraph.c
+++ b/src/nvim/digraph.c
@@ -15,6 +15,7 @@
#include "nvim/charset.h"
#include "nvim/digraph.h"
#include "nvim/drawscreen.h"
+#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds_defs.h"
@@ -2180,3 +2181,42 @@ static void keymap_unload(void)
curbuf->b_kmap_state &= ~KEYMAP_LOADED;
status_redraw_curbuf();
}
+
+/// Get the value to show for the language mappings, active 'keymap'.
+///
+/// @param fmt format string containing one %s item
+/// @param buf buffer for the result
+/// @param len length of buffer
+bool get_keymap_str(win_T *wp, char *fmt, char *buf, int len)
+{
+ char *p;
+
+ if (wp->w_buffer->b_p_iminsert != B_IMODE_LMAP) {
+ return false;
+ }
+
+ buf_T *old_curbuf = curbuf;
+ win_T *old_curwin = curwin;
+ char *s;
+
+ curbuf = wp->w_buffer;
+ curwin = wp;
+ STRCPY(buf, "b:keymap_name"); // must be writable
+ emsg_skip++;
+ s = p = eval_to_string(buf, NULL, false);
+ emsg_skip--;
+ curbuf = old_curbuf;
+ curwin = old_curwin;
+ if (p == NULL || *p == NUL) {
+ if (wp->w_buffer->b_kmap_state & KEYMAP_LOADED) {
+ p = wp->w_buffer->b_p_keymap;
+ } else {
+ p = "lang";
+ }
+ }
+ if (vim_snprintf(buf, (size_t)len, fmt, p) > len - 1) {
+ buf[0] = NUL;
+ }
+ xfree(s);
+ return buf[0] != NUL;
+}
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index a46f383f64..d9a8c6a6d9 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -21,6 +21,7 @@
#include "nvim/decoration_provider.h"
#include "nvim/diff.h"
#include "nvim/drawline.h"
+#include "nvim/drawscreen.h"
#include "nvim/eval.h"
#include "nvim/extmark_defs.h"
#include "nvim/fold.h"
@@ -40,7 +41,6 @@
#include "nvim/plines.h"
#include "nvim/pos.h"
#include "nvim/quickfix.h"
-#include "nvim/screen.h"
#include "nvim/sign.h"
#include "nvim/spell.h"
#include "nvim/state.h"
@@ -384,6 +384,70 @@ static void handle_foldcolumn(win_T *wp, winlinevars_T *wlv)
}
}
+/// Fills the foldcolumn at "p" for window "wp".
+/// Only to be called when 'foldcolumn' > 0.
+///
+/// @param[out] p Char array to write into
+/// @param lnum Absolute current line number
+/// @param closed Whether it is in 'foldcolumn' mode
+///
+/// Assume monocell characters
+/// @return number of chars added to \param p
+size_t fill_foldcolumn(char *p, win_T *wp, foldinfo_T foldinfo, linenr_T lnum)
+{
+ int i = 0;
+ int level;
+ int first_level;
+ int fdc = compute_foldcolumn(wp, 0); // available cell width
+ size_t char_counter = 0;
+ int symbol = 0;
+ int len = 0;
+ bool closed = foldinfo.fi_lines > 0;
+ // Init to all spaces.
+ memset(p, ' ', MAX_MCO * (size_t)fdc + 1);
+
+ level = foldinfo.fi_level;
+
+ // If the column is too narrow, we start at the lowest level that
+ // fits and use numbers to indicate the depth.
+ first_level = level - fdc - closed + 1;
+ if (first_level < 1) {
+ first_level = 1;
+ }
+
+ for (i = 0; i < MIN(fdc, level); i++) {
+ if (foldinfo.fi_lnum == lnum
+ && first_level + i >= foldinfo.fi_low_level) {
+ symbol = wp->w_p_fcs_chars.foldopen;
+ } else if (first_level == 1) {
+ symbol = wp->w_p_fcs_chars.foldsep;
+ } else if (first_level + i <= 9) {
+ symbol = '0' + first_level + i;
+ } else {
+ symbol = '>';
+ }
+
+ len = utf_char2bytes(symbol, &p[char_counter]);
+ char_counter += (size_t)len;
+ if (first_level + i >= level) {
+ i++;
+ break;
+ }
+ }
+
+ if (closed) {
+ if (symbol != 0) {
+ // rollback previous write
+ char_counter -= (size_t)len;
+ memset(&p[char_counter], ' ', (size_t)len);
+ }
+ len = utf_char2bytes(wp->w_p_fcs_chars.foldclosed, &p[char_counter]);
+ char_counter += (size_t)len;
+ }
+
+ return MAX(char_counter + (size_t)(fdc - i), (size_t)fdc);
+}
+
/// Get information needed to display the sign in line "wlv->lnum" in window "wp".
/// If "nrcol" is true, the sign is going to be displayed in the number column.
/// Otherwise the sign is going to be displayed in the sign column.
@@ -469,6 +533,21 @@ static int get_sign_attrs(buf_T *buf, winlinevars_T *wlv, int *sign_num_attrp, i
return num_signs;
}
+/// Returns width of the signcolumn that should be used for the whole window
+///
+/// @param wp window we want signcolumn width from
+/// @return max width of signcolumn (cell unit)
+///
+/// @note Returns a constant for now but hopefully we can improve neovim so that
+/// the returned value width adapts to the maximum number of marks to draw
+/// for the window
+/// TODO(teto)
+int win_signcol_width(win_T *wp)
+{
+ // 2 is vim default value
+ return 2;
+}
+
static inline void get_line_number_str(win_T *wp, linenr_T lnum, char *buf, size_t buf_len)
{
long num;
@@ -553,7 +632,7 @@ static void handle_lnum_col(win_T *wp, winlinevars_T *wlv, int num_signs, int si
}
}
if (wp->w_p_rl) { // reverse line numbers
- // like rl_mirror(), but keep the space at the end
+ // like rl_mirror_ascii(), but keep the space at the end
char *p2 = skipwhite(wlv->extra);
p2 = skiptowhite(p2) - 1;
for (char *p1 = skipwhite(wlv->extra); p1 < p2; p1++, p2--) {
@@ -1799,7 +1878,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
// Non-BMP character : display as ? or fullwidth ?.
transchar_hex(wlv.extra, mb_c);
if (wp->w_p_rl) { // reverse
- rl_mirror(wlv.extra);
+ rl_mirror_ascii(wlv.extra);
}
wlv.p_extra = wlv.extra;
@@ -2297,7 +2376,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.n_extra = byte2cells(c) - 1;
}
if ((dy_flags & DY_UHEX) && wp->w_p_rl) {
- rl_mirror(wlv.p_extra); // reverse "<12>"
+ rl_mirror_ascii(wlv.p_extra); // reverse "<12>"
}
wlv.c_extra = NUL;
wlv.c_final = NUL;
diff --git a/src/nvim/drawline.h b/src/nvim/drawline.h
index 9f60b46e1b..91261aba78 100644
--- a/src/nvim/drawline.h
+++ b/src/nvim/drawline.h
@@ -8,7 +8,6 @@
#include "nvim/decoration_provider.h"
#include "nvim/fold.h"
#include "nvim/macros.h"
-#include "nvim/screen.h"
#include "nvim/types.h"
// Maximum columns for terminal highlight attributes
diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c
index e1894f27a7..f456947f5a 100644
--- a/src/nvim/drawscreen.c
+++ b/src/nvim/drawscreen.c
@@ -66,11 +66,14 @@
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/cmdexpand.h"
+#include "nvim/cursor.h"
#include "nvim/decoration.h"
#include "nvim/decoration_provider.h"
#include "nvim/diff.h"
+#include "nvim/digraph.h"
#include "nvim/drawline.h"
#include "nvim/drawscreen.h"
+#include "nvim/eval.h"
#include "nvim/ex_getln.h"
#include "nvim/extmark_defs.h"
#include "nvim/fold.h"
@@ -91,7 +94,7 @@
#include "nvim/pos.h"
#include "nvim/profile.h"
#include "nvim/regexp.h"
-#include "nvim/screen.h"
+#include "nvim/search.h"
#include "nvim/state.h"
#include "nvim/statusline.h"
#include "nvim/syntax.h"
@@ -203,7 +206,7 @@ bool default_grid_alloc(void)
void screenclear(void)
{
- check_for_delay(false);
+ msg_check_for_delay(false);
if (starting == NO_SCREEN || default_grid.chars == NULL) {
return;
@@ -375,6 +378,32 @@ void screen_resize(int width, int height)
resizing_screen = false;
}
+/// Check if the new Nvim application "screen" dimensions are valid.
+/// Correct it if it's too small or way too big.
+void check_screensize(void)
+{
+ // Limit Rows and Columns to avoid an overflow in Rows * Columns.
+ if (Rows < min_rows()) {
+ // need room for one window and command line
+ Rows = min_rows();
+ } else if (Rows > 1000) {
+ Rows = 1000;
+ }
+
+ if (Columns < MIN_COLUMNS) {
+ Columns = MIN_COLUMNS;
+ } else if (Columns > 10000) {
+ Columns = 10000;
+ }
+}
+
+/// Return true if redrawing should currently be done.
+bool redrawing(void)
+{
+ return !RedrawingDisabled
+ && !(p_lz && char_avail() && !KeyTyped && !do_redraw);
+}
+
/// Redraw the parts of the screen that is marked for redraw.
///
/// Most code shouldn't call this directly, rather use redraw_later() and
@@ -521,7 +550,7 @@ int update_screen(void)
}
if (clear_cmdline) { // going to clear cmdline (done below)
- check_for_delay(false);
+ msg_check_for_delay(false);
}
// Force redraw when width of 'number' or 'relativenumber' column
@@ -637,6 +666,30 @@ int update_screen(void)
return OK;
}
+/// Prepare for 'hlsearch' highlighting.
+void start_search_hl(void)
+{
+ if (!p_hls || no_hlsearch) {
+ return;
+ }
+
+ end_search_hl(); // just in case it wasn't called before
+ last_pat_prog(&screen_search_hl.rm);
+ // Set the time limit to 'redrawtime'.
+ screen_search_hl.tm = profile_setlimit(p_rdt);
+}
+
+/// Clean up for 'hlsearch' highlighting.
+void end_search_hl(void)
+{
+ if (screen_search_hl.rm.regprog == NULL) {
+ return;
+ }
+
+ vim_regfree(screen_search_hl.rm.regprog);
+ screen_search_hl.rm.regprog = NULL;
+}
+
static void win_border_redr_title(win_T *wp, ScreenGrid *grid, int col)
{
VirtText title_chunks = wp->w_float_config.title_chunks;
@@ -725,6 +778,35 @@ static void win_redr_border(win_T *wp)
}
}
+/// Set cursor to its position in the current window.
+void setcursor(void)
+{
+ setcursor_mayforce(false);
+}
+
+/// Set cursor to its position in the current window.
+/// @param force when true, also when not redrawing.
+void setcursor_mayforce(bool force)
+{
+ if (force || redrawing()) {
+ validate_cursor();
+
+ ScreenGrid *grid = &curwin->w_grid;
+ int row = curwin->w_wrow;
+ int col = curwin->w_wcol;
+ if (curwin->w_p_rl) {
+ // With 'rightleft' set and the cursor on a double-wide character,
+ // position it on the leftmost column.
+ col = curwin->w_width_inner - curwin->w_wcol
+ - ((utf_ptr2cells(get_cursor_pos_ptr()) == 2
+ && vim_isprintc(gchar_cursor())) ? 2 : 1);
+ }
+
+ grid_adjust(&grid, &row, &col);
+ ui_grid_cursor_goto(grid->handle, row, col);
+ }
+}
+
/// Show current cursor info in ruler and various other places
///
/// @param always if false, only show ruler if position has changed.
@@ -771,6 +853,306 @@ void show_cursor_info_later(bool force)
curwin->w_stl_state = state;
}
+/// @return true when postponing displaying the mode message: when not redrawing
+/// or inside a mapping.
+bool skip_showmode(void)
+{
+ // Call char_avail() only when we are going to show something, because it
+ // takes a bit of time. redrawing() may also call char_avail().
+ if (global_busy || msg_silent != 0 || !redrawing() || (char_avail() && !KeyTyped)) {
+ redraw_mode = true; // show mode later
+ return true;
+ }
+ return false;
+}
+
+/// Show the current mode and ruler.
+///
+/// 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.
+/// If redraw_mode is true show or clear the mode.
+/// @return the length of the message (0 if no message).
+int showmode(void)
+{
+ int length = 0;
+
+ if (ui_has(kUIMessages) && clear_cmdline) {
+ msg_ext_clear(true);
+ }
+
+ // don't make non-flushed message part of the showmode
+ msg_ext_ui_flush();
+
+ msg_grid_validate();
+
+ int do_mode = ((p_smd && msg_silent == 0)
+ && ((State & MODE_TERMINAL)
+ || (State & MODE_INSERT)
+ || restart_edit != NUL
+ || VIsual_active));
+ if (do_mode || reg_recording != 0) {
+ int sub_attr;
+ if (skip_showmode()) {
+ return 0; // show mode later
+ }
+
+ bool nwr_save = need_wait_return;
+
+ // wait a bit before overwriting an important message
+ msg_check_for_delay(false);
+
+ // if the cmdline is more than one line high, erase top lines
+ bool need_clear = clear_cmdline;
+ if (clear_cmdline && cmdline_row < Rows - 1) {
+ msg_clr_cmdline(); // will reset clear_cmdline
+ }
+
+ // Position on the last line in the window, column 0
+ msg_pos_mode();
+ int attr = HL_ATTR(HLF_CM); // Highlight mode
+
+ // When the screen is too narrow to show the entire mode message,
+ // avoid scrolling and truncate instead.
+ msg_no_more = true;
+ int save_lines_left = lines_left;
+ lines_left = 0;
+
+ if (do_mode) {
+ msg_puts_attr("--", attr);
+ // CTRL-X in Insert mode
+ if (edit_submode != NULL && !shortmess(SHM_COMPLETIONMENU)) {
+ // These messages can get long, avoid a wrap in a narrow window.
+ // Prefer showing edit_submode_extra. With external messages there
+ // is no imposed limit.
+ if (ui_has(kUIMessages)) {
+ length = INT_MAX;
+ } else {
+ 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) {
+ msg_puts_attr((const char *)edit_submode_pre, attr);
+ }
+ msg_puts_attr((const char *)edit_submode, attr);
+ }
+ if (edit_submode_extra != NULL) {
+ msg_puts_attr(" ", attr); // Add a space in between.
+ if ((int)edit_submode_highl < HLF_COUNT) {
+ sub_attr = win_hl_attr(curwin, (int)edit_submode_highl);
+ } else {
+ sub_attr = attr;
+ }
+ msg_puts_attr((const char *)edit_submode_extra, sub_attr);
+ }
+ }
+ } else {
+ if (State & MODE_TERMINAL) {
+ msg_puts_attr(_(" TERMINAL"), attr);
+ } else if (State & VREPLACE_FLAG) {
+ msg_puts_attr(_(" VREPLACE"), attr);
+ } else if (State & REPLACE_FLAG) {
+ msg_puts_attr(_(" REPLACE"), attr);
+ } else if (State & MODE_INSERT) {
+ if (p_ri) {
+ msg_puts_attr(_(" REVERSE"), attr);
+ }
+ msg_puts_attr(_(" INSERT"), attr);
+ } else if (restart_edit == 'I' || restart_edit == 'i'
+ || restart_edit == 'a' || restart_edit == 'A') {
+ if (curbuf->terminal) {
+ msg_puts_attr(_(" (terminal)"), attr);
+ } else {
+ msg_puts_attr(_(" (insert)"), attr);
+ }
+ } else if (restart_edit == 'R') {
+ msg_puts_attr(_(" (replace)"), attr);
+ } else if (restart_edit == 'V') {
+ msg_puts_attr(_(" (vreplace)"), attr);
+ }
+ if (State & MODE_LANGMAP) {
+ if (curwin->w_p_arab) {
+ msg_puts_attr(_(" Arabic"), attr);
+ } else if (get_keymap_str(curwin, " (%s)",
+ NameBuff, MAXPATHL)) {
+ msg_puts_attr(NameBuff, attr);
+ }
+ }
+ if ((State & MODE_INSERT) && p_paste) {
+ msg_puts_attr(_(" (paste)"), attr);
+ }
+
+ if (VIsual_active) {
+ char *p;
+
+ // Don't concatenate separate words to avoid translation
+ // problems.
+ 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;
+ }
+ msg_puts_attr(_(p), attr);
+ }
+ msg_puts_attr(" --", attr);
+ }
+
+ need_clear = true;
+ }
+ if (reg_recording != 0
+ && edit_submode == NULL // otherwise it gets too long
+ ) {
+ recording_mode(attr);
+ need_clear = true;
+ }
+
+ mode_displayed = true;
+ if (need_clear || clear_cmdline || redraw_mode) {
+ msg_clr_eos();
+ }
+ msg_didout = false; // overwrite this message
+ length = msg_col;
+ msg_col = 0;
+ msg_no_more = false;
+ lines_left = save_lines_left;
+ need_wait_return = nwr_save; // never ask for hit-return for this
+ } else if (clear_cmdline && msg_silent == 0) {
+ // Clear the whole command line. Will reset "clear_cmdline".
+ msg_clr_cmdline();
+ } else if (redraw_mode) {
+ msg_pos_mode();
+ msg_clr_eos();
+ }
+
+ // NB: also handles clearing the showmode if it was empty or disabled
+ msg_ext_flush_showmode();
+
+ // In Visual mode the size of the selected area must be redrawn.
+ if (VIsual_active) {
+ clear_showcmd();
+ }
+
+ // If the last window has no status line and global statusline is disabled,
+ // the ruler is after the mode message and must be redrawn
+ win_T *last = curwin->w_floating ? curwin : lastwin_nofloating();
+ if (redrawing() && last->w_status_height == 0 && global_stl_height() == 0) {
+ win_redr_ruler(last);
+ }
+
+ redraw_cmdline = false;
+ redraw_mode = false;
+ clear_cmdline = false;
+
+ return length;
+}
+
+/// Position for a mode message.
+static void msg_pos_mode(void)
+{
+ 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!).
+/// Caller should check "mode_displayed".
+void unshowmode(bool force)
+{
+ // Don't delete it right now, when not redrawing or inside a mapping.
+ if (!redrawing() || (!force && char_avail() && !KeyTyped)) {
+ redraw_cmdline = true; // delete mode later
+ } else {
+ clearmode();
+ }
+}
+
+// Clear the mode message.
+void clearmode(void)
+{
+ const int save_msg_row = msg_row;
+ const int save_msg_col = msg_col;
+
+ msg_ext_ui_flush();
+ msg_pos_mode();
+ if (reg_recording != 0) {
+ recording_mode(HL_ATTR(HLF_CM));
+ }
+ msg_clr_eos();
+ msg_ext_flush_showmode();
+
+ msg_col = save_msg_col;
+ msg_row = save_msg_row;
+}
+
+static void recording_mode(int attr)
+{
+ msg_puts_attr(_("recording"), attr);
+ if (shortmess(SHM_RECORDING)) {
+ return;
+ }
+
+ char s[4];
+ snprintf(s, ARRAY_SIZE(s), " @%c", reg_recording);
+ msg_puts_attr(s, attr);
+}
+
+#define COL_RULER 17 // columns needed by standard ruler
+
+/// 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'.
+void comp_col(void)
+{
+ int last_has_status = (p_ls > 1 || (p_ls == 1 && !ONE_WINDOW));
+
+ sc_col = 0;
+ ru_col = 0;
+ if (p_ru) {
+ ru_col = (ru_wid ? ru_wid : COL_RULER) + 1;
+ // no last status line, adjust sc_col
+ if (!last_has_status) {
+ sc_col = ru_col;
+ }
+ }
+ if (p_sc) {
+ sc_col += SHOWCMD_COLS;
+ if (!p_ru || last_has_status) { // no need for separating space
+ sc_col++;
+ }
+ }
+ assert(sc_col >= 0
+ && INT_MIN + sc_col <= Columns);
+ sc_col = Columns - sc_col;
+ assert(ru_col >= 0
+ && INT_MIN + ru_col <= Columns);
+ 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;
+ }
+ set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
+}
static void redraw_win_signcol(win_T *wp)
{
// If we can compute a change in the automatic sizing of the sign column
@@ -862,8 +1244,8 @@ static void draw_vsep_win(win_T *wp)
}
// draw the vertical separator right of this window
- int hl;
- int c = fillchar_vsep(wp, &hl);
+ int hl = win_hl_attr(wp, HLF_C);
+ int c = wp->w_p_fcs_chars.vert;
grid_fill(&default_grid, wp->w_winrow, W_ENDROW(wp),
W_ENDCOL(wp), W_ENDCOL(wp) + 1, c, ' ', hl);
}
@@ -876,8 +1258,8 @@ static void draw_hsep_win(win_T *wp)
}
// draw the horizontal separator below this window
- int hl;
- int c = fillchar_hsep(wp, &hl);
+ int hl = win_hl_attr(wp, HLF_C);
+ int c = wp->w_p_fcs_chars.horiz;
grid_fill(&default_grid, W_ENDROW(wp), W_ENDROW(wp) + 1,
wp->w_wincol, W_ENDCOL(wp), c, c, hl);
}
@@ -2021,6 +2403,152 @@ static void win_update(win_T *wp, DecorProviders *providers)
}
}
+/// Scroll `line_count` lines at 'row' in window 'wp'.
+///
+/// Positive `line_count` means scrolling down, so that more space is available
+/// at 'row'. Negative `line_count` implies deleting lines at `row`.
+void win_scroll_lines(win_T *wp, int row, int line_count)
+{
+ if (!redrawing() || line_count == 0) {
+ return;
+ }
+
+ // No lines are being moved, just draw over the entire area
+ if (row + abs(line_count) >= wp->w_grid.rows) {
+ return;
+ }
+
+ if (line_count < 0) {
+ grid_del_lines(&wp->w_grid, row, -line_count,
+ wp->w_grid.rows, 0, wp->w_grid.cols);
+ } else {
+ grid_ins_lines(&wp->w_grid, row, line_count,
+ wp->w_grid.rows, 0, wp->w_grid.cols);
+ }
+}
+
+/// Call grid_fill() with columns adjusted for 'rightleft' if needed.
+/// Return the new offset.
+static int win_fill_end(win_T *wp, int c1, int c2, int off, int width, int row, int endrow,
+ int attr)
+{
+ int nn = off + width;
+ const int endcol = wp->w_grid.cols;
+
+ if (nn > endcol) {
+ nn = endcol;
+ }
+
+ if (wp->w_p_rl) {
+ grid_fill(&wp->w_grid, row, endrow, endcol - nn, endcol - off, c1, c2, attr);
+ } else {
+ grid_fill(&wp->w_grid, row, endrow, off, nn, c1, c2, attr);
+ }
+
+ return nn;
+}
+
+/// Clear lines near the end of the window and mark the unused lines with "c1".
+/// Use "c2" as filler character.
+/// When "draw_margin" is true, then draw the sign/fold/number columns.
+void win_draw_end(win_T *wp, int c1, int c2, bool draw_margin, int row, int endrow, hlf_T hl)
+{
+ assert(hl >= 0 && hl < HLF_COUNT);
+ int n = 0;
+
+ if (draw_margin) {
+ // draw the fold column
+ int fdc = compute_foldcolumn(wp, 0);
+ if (fdc > 0) {
+ n = win_fill_end(wp, ' ', ' ', n, fdc, row, endrow,
+ win_hl_attr(wp, HLF_FC));
+ }
+ // draw the sign column
+ int count = wp->w_scwidth;
+ if (count > 0) {
+ n = win_fill_end(wp, ' ', ' ', n, win_signcol_width(wp) * count, row,
+ endrow, win_hl_attr(wp, HLF_SC));
+ }
+ // draw the number column
+ if ((wp->w_p_nu || wp->w_p_rnu) && vim_strchr(p_cpo, CPO_NUMCOL) == NULL) {
+ n = win_fill_end(wp, ' ', ' ', n, number_width(wp) + 1, row, endrow,
+ win_hl_attr(wp, HLF_N));
+ }
+ }
+
+ int attr = hl_combine_attr(win_bg_attr(wp), win_hl_attr(wp, (int)hl));
+
+ const int endcol = wp->w_grid.cols;
+ if (wp->w_p_rl) {
+ grid_fill(&wp->w_grid, row, endrow, 0, endcol - 1 - n, c2, c2, attr);
+ grid_fill(&wp->w_grid, row, endrow, endcol - 1 - n, endcol - n, c1, c2, attr);
+ } else {
+ grid_fill(&wp->w_grid, row, endrow, n, endcol, c1, c2, attr);
+ }
+}
+
+/// 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 = win_fdccol_count(wp);
+ int wmw = wp == curwin && p_wmw == 0 ? 1 : (int)p_wmw;
+ int wwidth = wp->w_grid.cols;
+
+ if (fdc > wwidth - (col + wmw)) {
+ fdc = wwidth - (col + wmw);
+ }
+ return fdc;
+}
+
+/// Return the width of the 'number' and 'relativenumber' column.
+/// Caller may need to check if 'number' or 'relativenumber' is set.
+/// Otherwise it depends on 'numberwidth' and the line count.
+int number_width(win_T *wp)
+{
+ linenr_T lnum;
+
+ if (wp->w_p_rnu && !wp->w_p_nu) {
+ // cursor line shows "0"
+ lnum = wp->w_height_inner;
+ } else {
+ // cursor line shows absolute line number
+ lnum = wp->w_buffer->b_ml.ml_line_count;
+ }
+
+ if (lnum == wp->w_nrwidth_line_count) {
+ return wp->w_nrwidth_width;
+ }
+ wp->w_nrwidth_line_count = lnum;
+
+ // reset for 'statuscolumn'
+ if (*wp->w_p_stc != NUL) {
+ wp->w_nrwidth_width = (wp->w_p_nu || wp->w_p_rnu) * (int)wp->w_p_nuw;
+ return wp->w_nrwidth_width;
+ }
+
+ int n = 0;
+ do {
+ lnum /= 10;
+ n++;
+ } while (lnum > 0);
+
+ // 'numberwidth' gives the minimal width plus one
+ if (n < wp->w_p_nuw - 1) {
+ n = (int)wp->w_p_nuw - 1;
+ }
+
+ // If 'signcolumn' is set to 'number' and there is a sign to display, then
+ // the minimal width for the number column is 2.
+ if (n < 2 && (wp->w_buffer->b_signlist != NULL)
+ && (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u')) {
+ n = 2;
+ }
+
+ wp->w_nrwidth_width = n;
+ return n;
+}
+
/// Redraw a window later, with wp->w_redr_type >= type.
///
/// Set must_redraw only if not already set to a higher value.
@@ -2209,3 +2737,48 @@ void redrawWinline(win_T *wp, linenr_T lnum)
redraw_later(wp, UPD_VALID);
}
}
+
+/// Return true if the cursor line in window "wp" may be concealed, according
+/// to the 'concealcursor' option.
+bool conceal_cursor_line(const win_T *wp)
+ FUNC_ATTR_NONNULL_ALL
+{
+ int c;
+
+ if (*wp->w_p_cocu == NUL) {
+ return false;
+ }
+ if (get_real_state() & MODE_VISUAL) {
+ c = 'v';
+ } else if (State & MODE_INSERT) {
+ c = 'i';
+ } else if (State & MODE_NORMAL) {
+ c = 'n';
+ } else if (State & MODE_CMDLINE) {
+ c = 'c';
+ } else {
+ return false;
+ }
+ return vim_strchr(wp->w_p_cocu, c) != NULL;
+}
+
+/// Whether cursorline is drawn in a special way
+///
+/// If true, both old and new cursorline will need to be redrawn when moving cursor within windows.
+bool win_cursorline_standout(const win_T *wp)
+ FUNC_ATTR_NONNULL_ALL
+{
+ return wp->w_p_cul || (wp->w_p_cole > 0 && !conceal_cursor_line(wp));
+}
+
+/// Redraw when w_cline_row changes and 'relativenumber' or 'cursorline' is set.
+/// Also when concealing is on and 'concealcursor' is not active.
+void redraw_for_cursorline(win_T *wp)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if ((wp->w_valid & VALID_CROW) == 0 && !pum_visible()
+ && (wp->w_p_rnu || win_cursorline_standout(wp))) {
+ // win_line() will redraw the number column and cursorline only.
+ redraw_later(wp, UPD_VALID);
+ }
+}
diff --git a/src/nvim/drawscreen.h b/src/nvim/drawscreen.h
index c14703dfa9..398825f1bc 100644
--- a/src/nvim/drawscreen.h
+++ b/src/nvim/drawscreen.h
@@ -22,6 +22,11 @@ enum {
/// ('lines' and 'rows') must not be changed.
EXTERN bool updating_screen INIT(= 0);
+EXTERN match_T screen_search_hl INIT(= { 0 }); // used for 'hlsearch' highlight matching
+
+#define W_ENDCOL(wp) ((wp)->w_wincol + (wp)->w_width)
+#define W_ENDROW(wp) ((wp)->w_winrow + (wp)->w_height)
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "drawscreen.h.generated.h"
#endif
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 48ba93e666..66f6f06062 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -52,7 +52,6 @@
#include "nvim/plines.h"
#include "nvim/popupmenu.h"
#include "nvim/pos.h"
-#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/state.h"
#include "nvim/strings.h"
@@ -138,7 +137,7 @@ static void insert_enter(InsertState *s)
did_restart_edit = restart_edit;
// sleep before redrawing, needed for "CTRL-O :" that results in an
// error message
- check_for_delay(true);
+ msg_check_for_delay(true);
// set Insstart_orig to Insstart
update_Insstart_orig = true;
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index d398d3e06e..ac3c8c4f8e 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -77,7 +77,6 @@
#include "nvim/profile.h"
#include "nvim/quickfix.h"
#include "nvim/regexp.h"
-#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/spell.h"
#include "nvim/strings.h"
@@ -2658,7 +2657,7 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum
msg_scroll = false;
}
if (!msg_scroll) { // wait a bit when overwriting an error msg
- check_for_delay(false);
+ msg_check_for_delay(false);
}
msg_start();
msg_scroll = msg_scroll_save;
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 49f6d24c89..061a8e699e 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -72,7 +72,6 @@
#include "nvim/quickfix.h"
#include "nvim/regexp.h"
#include "nvim/runtime.h"
-#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/shada.h"
#include "nvim/state.h"
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 54131986d0..0f823383a4 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -63,7 +63,6 @@
#include "nvim/pos.h"
#include "nvim/profile.h"
#include "nvim/regexp.h"
-#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/state.h"
#include "nvim/strings.h"
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 115d34c3ea..684658b4e3 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -55,7 +55,6 @@
#include "nvim/path.h"
#include "nvim/pos.h"
#include "nvim/regexp.h"
-#include "nvim/screen.h"
#include "nvim/sha256.h"
#include "nvim/shada.h"
#include "nvim/strings.h"
@@ -157,7 +156,7 @@ void filemess(buf_T *buf, char *name, char *s, int attr)
msg_scroll = false;
}
if (!msg_scroll) { // wait a bit when overwriting an error msg
- check_for_delay(false);
+ msg_check_for_delay(false);
}
msg_start();
msg_scroll = msg_scroll_save;
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 605705e0e3..745e9d27e2 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -54,7 +54,6 @@
#include "nvim/os/os.h"
#include "nvim/plines.h"
#include "nvim/pos.h"
-#include "nvim/screen.h"
#include "nvim/state.h"
#include "nvim/strings.h"
#include "nvim/types.h"
diff --git a/src/nvim/indent.c b/src/nvim/indent.c
index c57d26dbe0..6ad19c6f96 100644
--- a/src/nvim/indent.c
+++ b/src/nvim/indent.c
@@ -36,7 +36,6 @@
#include "nvim/plines.h"
#include "nvim/pos.h"
#include "nvim/regexp.h"
-#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/strings.h"
#include "nvim/textformat.h"
diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c
index 8928979455..c61c74c607 100644
--- a/src/nvim/insexpand.c
+++ b/src/nvim/insexpand.c
@@ -54,7 +54,6 @@
#include "nvim/popupmenu.h"
#include "nvim/pos.h"
#include "nvim/regexp.h"
-#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/spell.h"
#include "nvim/state.h"
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index 35af7479b0..fb52a11025 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -60,10 +60,10 @@
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/option_defs.h"
+#include "nvim/optionstr.h"
#include "nvim/os/os.h"
#include "nvim/os/os_defs.h"
#include "nvim/pos.h"
-#include "nvim/screen.h"
#include "nvim/strings.h"
#include "nvim/types.h"
#include "nvim/vim.h"
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 0d8da68a02..0f2790b06c 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -79,8 +79,8 @@
#include "nvim/os/time.h"
#include "nvim/path.h"
#include "nvim/pos.h"
-#include "nvim/screen.h"
#include "nvim/spell.h"
+#include "nvim/statusline.h"
#include "nvim/strings.h"
#include "nvim/types.h"
#include "nvim/ui.h"
diff --git a/src/nvim/message.c b/src/nvim/message.c
index dc88c53392..aecb46c6bd 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -49,7 +49,6 @@
#include "nvim/pos.h"
#include "nvim/regexp.h"
#include "nvim/runtime.h"
-#include "nvim/screen.h"
#include "nvim/strings.h"
#include "nvim/ui.h"
#include "nvim/ui_compositor.h"
@@ -1340,6 +1339,14 @@ void set_keep_msg(char *s, int attr)
keep_msg_attr = attr;
}
+/// Return true if printing messages should currently be done.
+bool messaging(void)
+{
+ // TODO(bfredl): with general support for "async" messages with p_ch,
+ // this should be re-enabled.
+ return !(p_lz && char_avail() && !KeyTyped) && (p_ch > 0 || ui_has(kUIMessages));
+}
+
void msgmore(long n)
{
long pn;
@@ -3807,3 +3814,21 @@ int vim_dialog_yesnoallcancel(int type, char *title, char *message, int dflt)
}
return VIM_CANCEL;
}
+
+/// Check if there should be a delay to allow the user to see a message.
+///
+/// Used before clearing or redrawing the screen or the command line.
+void msg_check_for_delay(bool check_msg_scroll)
+{
+ if ((emsg_on_display || (check_msg_scroll && msg_scroll))
+ && !did_wait_return
+ && emsg_silent == 0
+ && !in_assert_fails) {
+ ui_flush();
+ os_delay(1006L, true);
+ emsg_on_display = false;
+ if (check_msg_scroll) {
+ msg_scroll = false;
+ }
+ }
+}
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index 60efd6a72a..95fe4d70d3 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -35,7 +35,6 @@
#include "nvim/option.h"
#include "nvim/plines.h"
#include "nvim/pos.h"
-#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/state.h"
#include "nvim/statusline.h"
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 6d55955927..1f55362354 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -41,7 +41,6 @@
#include "nvim/plines.h"
#include "nvim/popupmenu.h"
#include "nvim/pos.h"
-#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/strings.h"
#include "nvim/types.h"
@@ -104,18 +103,6 @@ static void comp_botline(win_T *wp)
win_check_anchored_floats(wp);
}
-/// Redraw when w_cline_row changes and 'relativenumber' or 'cursorline' is set.
-/// Also when concealing is on and 'concealcursor' is not active.
-void redraw_for_cursorline(win_T *wp)
- FUNC_ATTR_NONNULL_ALL
-{
- if ((wp->w_valid & VALID_CROW) == 0 && !pum_visible()
- && (wp->w_p_rnu || win_cursorline_standout(wp))) {
- // win_line() will redraw the number column and cursorline only.
- redraw_later(wp, UPD_VALID);
- }
-}
-
/// Redraw when w_virtcol changes and 'cursorcolumn' is set or 'cursorlineopt'
/// contains "screenline" or when the "CurSearch" highlight is in use.
/// Also when concealing is on and 'concealcursor' is active.
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 2a8fbbb962..605b0aee68 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -62,7 +62,6 @@
#include "nvim/plines.h"
#include "nvim/profile.h"
#include "nvim/quickfix.h"
-#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/spell.h"
#include "nvim/spellfile.h"
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 1a33ae8bbf..2edd1772ca 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -52,7 +52,6 @@
#include "nvim/os/input.h"
#include "nvim/os/time.h"
#include "nvim/plines.h"
-#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/state.h"
#include "nvim/strings.h"
diff --git a/src/nvim/option.c b/src/nvim/option.c
index f9b7aa9f99..5fe6e18155 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -86,7 +86,6 @@
#include "nvim/pos.h"
#include "nvim/regexp.h"
#include "nvim/runtime.h"
-#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/sign_defs.h"
#include "nvim/spell.h"
diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c
index cba95377a2..40cddebc2e 100644
--- a/src/nvim/optionstr.c
+++ b/src/nvim/optionstr.c
@@ -45,7 +45,6 @@
#include "nvim/pos.h"
#include "nvim/quickfix.h"
#include "nvim/runtime.h"
-#include "nvim/screen.h"
#include "nvim/spell.h"
#include "nvim/spellfile.h"
#include "nvim/spellsuggest.h"
@@ -1960,3 +1959,285 @@ int check_ff_value(char *p)
{
return check_opt_strings(p, p_ff_values, false);
}
+
+static char e_conflicts_with_value_of_listchars[] = N_("E834: Conflicts with value of 'listchars'");
+static char e_conflicts_with_value_of_fillchars[] = N_("E835: Conflicts with value of 'fillchars'");
+
+/// Calls mb_cptr2char_adv(p) and returns the character.
+/// If "p" starts with "\x", "\u" or "\U" the hex or unicode value is used.
+/// Returns 0 for invalid hex or invalid UTF-8 byte.
+static int get_encoded_char_adv(const char **p)
+{
+ const char *s = *p;
+
+ if (s[0] == '\\' && (s[1] == 'x' || s[1] == 'u' || s[1] == 'U')) {
+ int64_t num = 0;
+ for (int bytes = s[1] == 'x' ? 1 : s[1] == 'u' ? 2 : 4; bytes > 0; bytes--) {
+ *p += 2;
+ int n = hexhex2nr(*p);
+ if (n < 0) {
+ return 0;
+ }
+ num = num * 256 + n;
+ }
+ *p += 2;
+ return (int)num;
+ }
+
+ // TODO(bfredl): use schar_T representation and utfc_ptr2len
+ int clen = utf_ptr2len(s);
+ int c = mb_cptr2char_adv(p);
+ if (clen == 1 && c > 127) { // Invalid UTF-8 byte
+ return 0;
+ }
+ return c;
+}
+
+/// Handle setting 'listchars' or 'fillchars'.
+/// Assume monocell characters
+///
+/// @param varp either the global or the window-local value.
+/// @param apply if false, do not store the flags, only check for errors.
+/// @return error message, NULL if it's OK.
+char *set_chars_option(win_T *wp, char **varp, bool apply)
+{
+ const char *last_multispace = NULL; // Last occurrence of "multispace:"
+ const char *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
+ const bool is_listchars = (varp == &p_lcs || varp == &wp->w_p_lcs);
+
+ struct chars_tab {
+ int *cp; ///< char value
+ char *name; ///< char id
+ int def; ///< default value
+ };
+
+ // XXX: Characters taking 2 columns is forbidden (TUI limitation?). Set old defaults in this case.
+ struct chars_tab fcs_tab[] = {
+ { &wp->w_p_fcs_chars.stl, "stl", ' ' },
+ { &wp->w_p_fcs_chars.stlnc, "stlnc", ' ' },
+ { &wp->w_p_fcs_chars.wbr, "wbr", ' ' },
+ { &wp->w_p_fcs_chars.horiz, "horiz", char2cells(0x2500) == 1 ? 0x2500 : '-' }, // ─
+ { &wp->w_p_fcs_chars.horizup, "horizup", char2cells(0x2534) == 1 ? 0x2534 : '-' }, // ┴
+ { &wp->w_p_fcs_chars.horizdown, "horizdown", char2cells(0x252c) == 1 ? 0x252c : '-' }, // ┬
+ { &wp->w_p_fcs_chars.vert, "vert", char2cells(0x2502) == 1 ? 0x2502 : '|' }, // │
+ { &wp->w_p_fcs_chars.vertleft, "vertleft", char2cells(0x2524) == 1 ? 0x2524 : '|' }, // ┤
+ { &wp->w_p_fcs_chars.vertright, "vertright", char2cells(0x251c) == 1 ? 0x251c : '|' }, // ├
+ { &wp->w_p_fcs_chars.verthoriz, "verthoriz", char2cells(0x253c) == 1 ? 0x253c : '+' }, // ┼
+ { &wp->w_p_fcs_chars.fold, "fold", char2cells(0x00b7) == 1 ? 0x00b7 : '-' }, // ·
+ { &wp->w_p_fcs_chars.foldopen, "foldopen", '-' },
+ { &wp->w_p_fcs_chars.foldclosed, "foldclose", '+' },
+ { &wp->w_p_fcs_chars.foldsep, "foldsep", char2cells(0x2502) == 1 ? 0x2502 : '|' }, // │
+ { &wp->w_p_fcs_chars.diff, "diff", '-' },
+ { &wp->w_p_fcs_chars.msgsep, "msgsep", ' ' },
+ { &wp->w_p_fcs_chars.eob, "eob", '~' },
+ { &wp->w_p_fcs_chars.lastline, "lastline", '@' },
+ };
+
+ struct chars_tab lcs_tab[] = {
+ { &wp->w_p_lcs_chars.eol, "eol", NUL },
+ { &wp->w_p_lcs_chars.ext, "extends", NUL },
+ { &wp->w_p_lcs_chars.nbsp, "nbsp", NUL },
+ { &wp->w_p_lcs_chars.prec, "precedes", NUL },
+ { &wp->w_p_lcs_chars.space, "space", NUL },
+ { &wp->w_p_lcs_chars.tab2, "tab", NUL },
+ { &wp->w_p_lcs_chars.lead, "lead", NUL },
+ { &wp->w_p_lcs_chars.trail, "trail", NUL },
+ { &wp->w_p_lcs_chars.conceal, "conceal", NUL },
+ };
+
+ struct chars_tab *tab;
+ int entries;
+ const char *value = *varp;
+ if (is_listchars) {
+ tab = lcs_tab;
+ entries = ARRAY_SIZE(lcs_tab);
+ if (varp == &wp->w_p_lcs && wp->w_p_lcs[0] == NUL) {
+ value = p_lcs; // local value is empty, use the global value
+ }
+ } else {
+ tab = fcs_tab;
+ entries = ARRAY_SIZE(fcs_tab);
+ if (varp == &wp->w_p_fcs && wp->w_p_fcs[0] == NUL) {
+ value = p_fcs; // local value is empty, use the global value
+ }
+ }
+
+ // first round: check for valid value, second round: assign values
+ for (int round = 0; round <= (apply ? 1 : 0); round++) {
+ if (round > 0) {
+ // After checking that the value is valid: set defaults
+ for (int i = 0; i < entries; i++) {
+ if (tab[i].cp != NULL) {
+ *(tab[i].cp) = tab[i].def;
+ }
+ }
+ if (is_listchars) {
+ wp->w_p_lcs_chars.tab1 = NUL;
+ wp->w_p_lcs_chars.tab3 = NUL;
+
+ xfree(wp->w_p_lcs_chars.multispace);
+ if (multispace_len > 0) {
+ wp->w_p_lcs_chars.multispace = xmalloc(((size_t)multispace_len + 1) * sizeof(int));
+ wp->w_p_lcs_chars.multispace[multispace_len] = NUL;
+ } else {
+ wp->w_p_lcs_chars.multispace = NULL;
+ }
+
+ xfree(wp->w_p_lcs_chars.leadmultispace);
+ if (lead_multispace_len > 0) {
+ wp->w_p_lcs_chars.leadmultispace
+ = xmalloc(((size_t)lead_multispace_len + 1) * sizeof(int));
+ wp->w_p_lcs_chars.leadmultispace[lead_multispace_len] = NUL;
+ } else {
+ wp->w_p_lcs_chars.leadmultispace = NULL;
+ }
+ }
+ }
+ const char *p = value;
+ while (*p) {
+ int i;
+ for (i = 0; i < entries; i++) {
+ const size_t len = strlen(tab[i].name);
+ if (strncmp(p, tab[i].name, len) == 0
+ && p[len] == ':'
+ && p[len + 1] != NUL) {
+ const char *s = p + len + 1;
+ int c1 = get_encoded_char_adv(&s);
+ if (c1 == 0 || char2cells(c1) > 1) {
+ return e_invarg;
+ }
+ int c2 = 0, c3 = 0;
+ if (tab[i].cp == &wp->w_p_lcs_chars.tab2) {
+ if (*s == NUL) {
+ return e_invarg;
+ }
+ c2 = get_encoded_char_adv(&s);
+ if (c2 == 0 || char2cells(c2) > 1) {
+ return e_invarg;
+ }
+ if (!(*s == ',' || *s == NUL)) {
+ c3 = get_encoded_char_adv(&s);
+ if (c3 == 0 || char2cells(c3) > 1) {
+ return e_invarg;
+ }
+ }
+ }
+ if (*s == ',' || *s == NUL) {
+ if (round > 0) {
+ if (tab[i].cp == &wp->w_p_lcs_chars.tab2) {
+ wp->w_p_lcs_chars.tab1 = c1;
+ wp->w_p_lcs_chars.tab2 = c2;
+ wp->w_p_lcs_chars.tab3 = c3;
+ } else if (tab[i].cp != NULL) {
+ *(tab[i].cp) = c1;
+ }
+ }
+ p = s;
+ break;
+ }
+ }
+ }
+
+ if (i == entries) {
+ const size_t len = strlen("multispace");
+ const size_t len2 = strlen("leadmultispace");
+ if (is_listchars
+ && strncmp(p, "multispace", len) == 0
+ && p[len] == ':'
+ && p[len + 1] != NUL) {
+ const char *s = p + len + 1;
+ if (round == 0) {
+ // Get length of lcs-multispace string in the first round
+ last_multispace = p;
+ multispace_len = 0;
+ while (*s != NUL && *s != ',') {
+ int c1 = get_encoded_char_adv(&s);
+ if (c1 == 0 || char2cells(c1) > 1) {
+ return e_invarg;
+ }
+ multispace_len++;
+ }
+ if (multispace_len == 0) {
+ // lcs-multispace cannot be an empty string
+ return e_invarg;
+ }
+ p = s;
+ } else {
+ int multispace_pos = 0;
+ while (*s != NUL && *s != ',') {
+ int c1 = get_encoded_char_adv(&s);
+ if (p == last_multispace) {
+ wp->w_p_lcs_chars.multispace[multispace_pos++] = c1;
+ }
+ }
+ p = s;
+ }
+ } else if (is_listchars
+ && strncmp(p, "leadmultispace", len2) == 0
+ && p[len2] == ':'
+ && p[len2 + 1] != NUL) {
+ const char *s = p + len2 + 1;
+ if (round == 0) {
+ // get length of lcs-leadmultispace string in first round
+ last_lmultispace = p;
+ lead_multispace_len = 0;
+ while (*s != NUL && *s != ',') {
+ int c1 = get_encoded_char_adv(&s);
+ if (c1 == 0 || char2cells(c1) > 1) {
+ return e_invarg;
+ }
+ lead_multispace_len++;
+ }
+ if (lead_multispace_len == 0) {
+ // lcs-leadmultispace cannot be an empty string
+ return e_invarg;
+ }
+ p = s;
+ } else {
+ int multispace_pos = 0;
+ while (*s != NUL && *s != ',') {
+ int c1 = get_encoded_char_adv(&s);
+ if (p == last_lmultispace) {
+ wp->w_p_lcs_chars.leadmultispace[multispace_pos++] = c1;
+ }
+ }
+ p = s;
+ }
+ } else {
+ return e_invarg;
+ }
+ }
+
+ if (*p == ',') {
+ p++;
+ }
+ }
+ }
+
+ return NULL; // no error
+}
+
+/// Check all global and local values of 'listchars' and 'fillchars'.
+/// May set different defaults in case character widths change.
+///
+/// @return an untranslated error message if any of them is invalid, NULL otherwise.
+char *check_chars_options(void)
+{
+ if (set_chars_option(curwin, &p_lcs, false) != NULL) {
+ return e_conflicts_with_value_of_listchars;
+ }
+ if (set_chars_option(curwin, &p_fcs, false) != NULL) {
+ return e_conflicts_with_value_of_fillchars;
+ }
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (set_chars_option(wp, &wp->w_p_lcs, true) != NULL) {
+ return e_conflicts_with_value_of_listchars;
+ }
+ if (set_chars_option(wp, &wp->w_p_fcs, true) != NULL) {
+ return e_conflicts_with_value_of_fillchars;
+ }
+ }
+ return NULL;
+}
diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c
index 8db36e594c..334a9bc904 100644
--- a/src/nvim/popupmenu.c
+++ b/src/nvim/popupmenu.c
@@ -34,7 +34,6 @@
#include "nvim/option.h"
#include "nvim/popupmenu.h"
#include "nvim/pos.h"
-#include "nvim/screen.h"
#include "nvim/strings.h"
#include "nvim/ui.h"
#include "nvim/ui_compositor.h"
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
deleted file mode 100644
index 718c4f3d95..0000000000
--- a/src/nvim/screen.c
+++ /dev/null
@@ -1,1098 +0,0 @@
-// This is an open source non-commercial project. Dear PVS-Studio, please check
-// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-
-// screen.c: Lower level code for displaying on the screen.
-// grid.c contains some other lower-level code.
-
-// 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.
-
-#include <assert.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "nvim/ascii.h"
-#include "nvim/buffer.h"
-#include "nvim/charset.h"
-#include "nvim/cursor.h"
-#include "nvim/eval.h"
-#include "nvim/fold.h"
-#include "nvim/getchar.h"
-#include "nvim/gettext.h"
-#include "nvim/globals.h"
-#include "nvim/grid.h"
-#include "nvim/grid_defs.h"
-#include "nvim/highlight.h"
-#include "nvim/mbyte.h"
-#include "nvim/memline_defs.h"
-#include "nvim/memory.h"
-#include "nvim/message.h"
-#include "nvim/move.h"
-#include "nvim/normal.h"
-#include "nvim/option.h"
-#include "nvim/os/os.h"
-#include "nvim/os/time.h"
-#include "nvim/pos.h"
-#include "nvim/profile.h"
-#include "nvim/regexp.h"
-#include "nvim/screen.h"
-#include "nvim/search.h"
-#include "nvim/state.h"
-#include "nvim/statusline.h"
-#include "nvim/strings.h"
-#include "nvim/types.h"
-#include "nvim/ui.h"
-#include "nvim/vim.h"
-#include "nvim/window.h"
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "screen.c.generated.h"
-#endif
-
-static char e_conflicts_with_value_of_listchars[] = N_("E834: Conflicts with value of 'listchars'");
-static char e_conflicts_with_value_of_fillchars[] = N_("E835: Conflicts with value of 'fillchars'");
-
-/// Return true if the cursor line in window "wp" may be concealed, according
-/// to the 'concealcursor' option.
-bool conceal_cursor_line(const win_T *wp)
- FUNC_ATTR_NONNULL_ALL
-{
- int c;
-
- if (*wp->w_p_cocu == NUL) {
- return false;
- }
- if (get_real_state() & MODE_VISUAL) {
- c = 'v';
- } else if (State & MODE_INSERT) {
- c = 'i';
- } else if (State & MODE_NORMAL) {
- c = 'n';
- } else if (State & MODE_CMDLINE) {
- c = 'c';
- } else {
- return false;
- }
- return vim_strchr(wp->w_p_cocu, c) != NULL;
-}
-
-/// Whether cursorline is drawn in a special way
-///
-/// If true, both old and new cursorline will need to be redrawn when moving cursor within windows.
-bool win_cursorline_standout(const win_T *wp)
- FUNC_ATTR_NONNULL_ALL
-{
- return wp->w_p_cul || (wp->w_p_cole > 0 && !conceal_cursor_line(wp));
-}
-
-/// Returns width of the signcolumn that should be used for the whole window
-///
-/// @param wp window we want signcolumn width from
-/// @return max width of signcolumn (cell unit)
-///
-/// @note Returns a constant for now but hopefully we can improve neovim so that
-/// the returned value width adapts to the maximum number of marks to draw
-/// for the window
-/// TODO(teto)
-int win_signcol_width(win_T *wp)
-{
- // 2 is vim default value
- return 2;
-}
-
-/// Call grid_fill() with columns adjusted for 'rightleft' if needed.
-/// Return the new offset.
-static int win_fill_end(win_T *wp, int c1, int c2, int off, int width, int row, int endrow,
- int attr)
-{
- int nn = off + width;
- const int endcol = wp->w_grid.cols;
-
- if (nn > endcol) {
- nn = endcol;
- }
-
- if (wp->w_p_rl) {
- grid_fill(&wp->w_grid, row, endrow, endcol - nn, endcol - off, c1, c2, attr);
- } else {
- grid_fill(&wp->w_grid, row, endrow, off, nn, c1, c2, attr);
- }
-
- return nn;
-}
-
-/// Clear lines near the end of the window and mark the unused lines with "c1".
-/// Use "c2" as filler character.
-/// When "draw_margin" is true, then draw the sign/fold/number columns.
-void win_draw_end(win_T *wp, int c1, int c2, bool draw_margin, int row, int endrow, hlf_T hl)
-{
- assert(hl >= 0 && hl < HLF_COUNT);
- int n = 0;
-
- if (draw_margin) {
- // draw the fold column
- int fdc = compute_foldcolumn(wp, 0);
- if (fdc > 0) {
- n = win_fill_end(wp, ' ', ' ', n, fdc, row, endrow,
- win_hl_attr(wp, HLF_FC));
- }
- // draw the sign column
- int count = wp->w_scwidth;
- if (count > 0) {
- n = win_fill_end(wp, ' ', ' ', n, win_signcol_width(wp) * count, row,
- endrow, win_hl_attr(wp, HLF_SC));
- }
- // draw the number column
- if ((wp->w_p_nu || wp->w_p_rnu) && vim_strchr(p_cpo, CPO_NUMCOL) == NULL) {
- n = win_fill_end(wp, ' ', ' ', n, number_width(wp) + 1, row, endrow,
- win_hl_attr(wp, HLF_N));
- }
- }
-
- int attr = hl_combine_attr(win_bg_attr(wp), win_hl_attr(wp, (int)hl));
-
- const int endcol = wp->w_grid.cols;
- if (wp->w_p_rl) {
- grid_fill(&wp->w_grid, row, endrow, 0, endcol - 1 - n, c2, c2, attr);
- grid_fill(&wp->w_grid, row, endrow, endcol - 1 - n, endcol - n, c1, c2, attr);
- } else {
- grid_fill(&wp->w_grid, row, endrow, n, endcol, c1, c2, attr);
- }
-}
-
-/// 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 = win_fdccol_count(wp);
- int wmw = wp == curwin && p_wmw == 0 ? 1 : (int)p_wmw;
- int wwidth = wp->w_grid.cols;
-
- if (fdc > wwidth - (col + wmw)) {
- fdc = wwidth - (col + wmw);
- }
- return fdc;
-}
-
-/// Fills the foldcolumn at "p" for window "wp".
-/// Only to be called when 'foldcolumn' > 0.
-///
-/// @param[out] p Char array to write into
-/// @param lnum Absolute current line number
-/// @param closed Whether it is in 'foldcolumn' mode
-///
-/// Assume monocell characters
-/// @return number of chars added to \param p
-size_t fill_foldcolumn(char *p, win_T *wp, foldinfo_T foldinfo, linenr_T lnum)
-{
- int i = 0;
- int level;
- int first_level;
- int fdc = compute_foldcolumn(wp, 0); // available cell width
- size_t char_counter = 0;
- int symbol = 0;
- int len = 0;
- bool closed = foldinfo.fi_lines > 0;
- // Init to all spaces.
- memset(p, ' ', MAX_MCO * (size_t)fdc + 1);
-
- level = foldinfo.fi_level;
-
- // If the column is too narrow, we start at the lowest level that
- // fits and use numbers to indicate the depth.
- first_level = level - fdc - closed + 1;
- if (first_level < 1) {
- first_level = 1;
- }
-
- for (i = 0; i < MIN(fdc, level); i++) {
- if (foldinfo.fi_lnum == lnum
- && first_level + i >= foldinfo.fi_low_level) {
- symbol = wp->w_p_fcs_chars.foldopen;
- } else if (first_level == 1) {
- symbol = wp->w_p_fcs_chars.foldsep;
- } else if (first_level + i <= 9) {
- symbol = '0' + first_level + i;
- } else {
- symbol = '>';
- }
-
- len = utf_char2bytes(symbol, &p[char_counter]);
- char_counter += (size_t)len;
- if (first_level + i >= level) {
- i++;
- break;
- }
- }
-
- if (closed) {
- if (symbol != 0) {
- // rollback previous write
- char_counter -= (size_t)len;
- memset(&p[char_counter], ' ', (size_t)len);
- }
- len = utf_char2bytes(wp->w_p_fcs_chars.foldclosed, &p[char_counter]);
- char_counter += (size_t)len;
- }
-
- return MAX(char_counter + (size_t)(fdc - i), (size_t)fdc);
-}
-
-/// Mirror text "str" for right-left displaying.
-/// Only works for single-byte characters (e.g., numbers).
-void rl_mirror(char *str)
-{
- for (char *p1 = str, *p2 = str + strlen(str) - 1; p1 < p2; p1++, p2--) {
- char t = *p1;
- *p1 = *p2;
- *p2 = t;
- }
-}
-
-/// Only call if (wp->w_vsep_width != 0).
-///
-/// @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.
-bool stl_connected(win_T *wp)
-{
- frame_T *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'.
-///
-/// @param fmt format string containing one %s item
-/// @param buf buffer for the result
-/// @param len length of buffer
-bool get_keymap_str(win_T *wp, char *fmt, char *buf, int len)
-{
- char *p;
-
- if (wp->w_buffer->b_p_iminsert != B_IMODE_LMAP) {
- return false;
- }
-
- buf_T *old_curbuf = curbuf;
- win_T *old_curwin = curwin;
- char *s;
-
- curbuf = wp->w_buffer;
- curwin = wp;
- STRCPY(buf, "b:keymap_name"); // must be writable
- emsg_skip++;
- s = p = eval_to_string(buf, NULL, false);
- emsg_skip--;
- curbuf = old_curbuf;
- curwin = old_curwin;
- if (p == NULL || *p == NUL) {
- if (wp->w_buffer->b_kmap_state & KEYMAP_LOADED) {
- p = wp->w_buffer->b_p_keymap;
- } else {
- p = "lang";
- }
- }
- if (vim_snprintf(buf, (size_t)len, fmt, p) > len - 1) {
- buf[0] = NUL;
- }
- xfree(s);
- return buf[0] != NUL;
-}
-
-/// Prepare for 'hlsearch' highlighting.
-void start_search_hl(void)
-{
- if (!p_hls || no_hlsearch) {
- return;
- }
-
- end_search_hl(); // just in case it wasn't called before
- last_pat_prog(&screen_search_hl.rm);
- // Set the time limit to 'redrawtime'.
- screen_search_hl.tm = profile_setlimit(p_rdt);
-}
-
-/// Clean up for 'hlsearch' highlighting.
-void end_search_hl(void)
-{
- if (screen_search_hl.rm.regprog == NULL) {
- return;
- }
-
- vim_regfree(screen_search_hl.rm.regprog);
- screen_search_hl.rm.regprog = NULL;
-}
-
-/// Check if there should be a delay. Used before clearing or redrawing the
-/// screen or the command line.
-void check_for_delay(bool check_msg_scroll)
-{
- if ((emsg_on_display || (check_msg_scroll && msg_scroll))
- && !did_wait_return
- && emsg_silent == 0
- && !in_assert_fails) {
- ui_flush();
- os_delay(1006L, true);
- emsg_on_display = false;
- if (check_msg_scroll) {
- msg_scroll = false;
- }
- }
-}
-
-/// Set cursor to its position in the current window.
-void setcursor(void)
-{
- setcursor_mayforce(false);
-}
-
-/// Set cursor to its position in the current window.
-/// @param force when true, also when not redrawing.
-void setcursor_mayforce(bool force)
-{
- if (force || redrawing()) {
- validate_cursor();
-
- ScreenGrid *grid = &curwin->w_grid;
- int row = curwin->w_wrow;
- int col = curwin->w_wcol;
- if (curwin->w_p_rl) {
- // With 'rightleft' set and the cursor on a double-wide character,
- // position it on the leftmost column.
- col = curwin->w_width_inner - curwin->w_wcol
- - ((utf_ptr2cells(get_cursor_pos_ptr()) == 2
- && vim_isprintc(gchar_cursor())) ? 2 : 1);
- }
-
- grid_adjust(&grid, &row, &col);
- ui_grid_cursor_goto(grid->handle, row, col);
- }
-}
-
-/// Scroll `line_count` lines at 'row' in window 'wp'.
-///
-/// Positive `line_count` means scrolling down, so that more space is available
-/// at 'row'. Negative `line_count` implies deleting lines at `row`.
-void win_scroll_lines(win_T *wp, int row, int line_count)
-{
- if (!redrawing() || line_count == 0) {
- return;
- }
-
- // No lines are being moved, just draw over the entire area
- if (row + abs(line_count) >= wp->w_grid.rows) {
- return;
- }
-
- if (line_count < 0) {
- grid_del_lines(&wp->w_grid, row, -line_count,
- wp->w_grid.rows, 0, wp->w_grid.cols);
- } else {
- grid_ins_lines(&wp->w_grid, row, line_count,
- wp->w_grid.rows, 0, wp->w_grid.cols);
- }
-}
-
-/// @return true when postponing displaying the mode message: when not redrawing
-/// or inside a mapping.
-bool skip_showmode(void)
-{
- // Call char_avail() only when we are going to show something, because it
- // takes a bit of time. redrawing() may also call char_avail().
- if (global_busy || msg_silent != 0 || !redrawing() || (char_avail() && !KeyTyped)) {
- redraw_mode = true; // show mode later
- return true;
- }
- return false;
-}
-
-/// Show the current mode and ruler.
-///
-/// 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.
-/// If redraw_mode is true show or clear the mode.
-/// @return the length of the message (0 if no message).
-int showmode(void)
-{
- int length = 0;
-
- if (ui_has(kUIMessages) && clear_cmdline) {
- msg_ext_clear(true);
- }
-
- // don't make non-flushed message part of the showmode
- msg_ext_ui_flush();
-
- msg_grid_validate();
-
- int do_mode = ((p_smd && msg_silent == 0)
- && ((State & MODE_TERMINAL)
- || (State & MODE_INSERT)
- || restart_edit != NUL
- || VIsual_active));
- if (do_mode || reg_recording != 0) {
- int sub_attr;
- if (skip_showmode()) {
- return 0; // show mode later
- }
-
- bool nwr_save = need_wait_return;
-
- // wait a bit before overwriting an important message
- check_for_delay(false);
-
- // if the cmdline is more than one line high, erase top lines
- bool need_clear = clear_cmdline;
- if (clear_cmdline && cmdline_row < Rows - 1) {
- msg_clr_cmdline(); // will reset clear_cmdline
- }
-
- // Position on the last line in the window, column 0
- msg_pos_mode();
- int attr = HL_ATTR(HLF_CM); // Highlight mode
-
- // When the screen is too narrow to show the entire mode message,
- // avoid scrolling and truncate instead.
- msg_no_more = true;
- int save_lines_left = lines_left;
- lines_left = 0;
-
- if (do_mode) {
- msg_puts_attr("--", attr);
- // CTRL-X in Insert mode
- if (edit_submode != NULL && !shortmess(SHM_COMPLETIONMENU)) {
- // These messages can get long, avoid a wrap in a narrow window.
- // Prefer showing edit_submode_extra. With external messages there
- // is no imposed limit.
- if (ui_has(kUIMessages)) {
- length = INT_MAX;
- } else {
- 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) {
- msg_puts_attr((const char *)edit_submode_pre, attr);
- }
- msg_puts_attr((const char *)edit_submode, attr);
- }
- if (edit_submode_extra != NULL) {
- msg_puts_attr(" ", attr); // Add a space in between.
- if ((int)edit_submode_highl < HLF_COUNT) {
- sub_attr = win_hl_attr(curwin, (int)edit_submode_highl);
- } else {
- sub_attr = attr;
- }
- msg_puts_attr((const char *)edit_submode_extra, sub_attr);
- }
- }
- } else {
- if (State & MODE_TERMINAL) {
- msg_puts_attr(_(" TERMINAL"), attr);
- } else if (State & VREPLACE_FLAG) {
- msg_puts_attr(_(" VREPLACE"), attr);
- } else if (State & REPLACE_FLAG) {
- msg_puts_attr(_(" REPLACE"), attr);
- } else if (State & MODE_INSERT) {
- if (p_ri) {
- msg_puts_attr(_(" REVERSE"), attr);
- }
- msg_puts_attr(_(" INSERT"), attr);
- } else if (restart_edit == 'I' || restart_edit == 'i'
- || restart_edit == 'a' || restart_edit == 'A') {
- if (curbuf->terminal) {
- msg_puts_attr(_(" (terminal)"), attr);
- } else {
- msg_puts_attr(_(" (insert)"), attr);
- }
- } else if (restart_edit == 'R') {
- msg_puts_attr(_(" (replace)"), attr);
- } else if (restart_edit == 'V') {
- msg_puts_attr(_(" (vreplace)"), attr);
- }
- if (State & MODE_LANGMAP) {
- if (curwin->w_p_arab) {
- msg_puts_attr(_(" Arabic"), attr);
- } else if (get_keymap_str(curwin, " (%s)",
- NameBuff, MAXPATHL)) {
- msg_puts_attr(NameBuff, attr);
- }
- }
- if ((State & MODE_INSERT) && p_paste) {
- msg_puts_attr(_(" (paste)"), attr);
- }
-
- if (VIsual_active) {
- char *p;
-
- // Don't concatenate separate words to avoid translation
- // problems.
- 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;
- }
- msg_puts_attr(_(p), attr);
- }
- msg_puts_attr(" --", attr);
- }
-
- need_clear = true;
- }
- if (reg_recording != 0
- && edit_submode == NULL // otherwise it gets too long
- ) {
- recording_mode(attr);
- need_clear = true;
- }
-
- mode_displayed = true;
- if (need_clear || clear_cmdline || redraw_mode) {
- msg_clr_eos();
- }
- msg_didout = false; // overwrite this message
- length = msg_col;
- msg_col = 0;
- msg_no_more = false;
- lines_left = save_lines_left;
- need_wait_return = nwr_save; // never ask for hit-return for this
- } else if (clear_cmdline && msg_silent == 0) {
- // Clear the whole command line. Will reset "clear_cmdline".
- msg_clr_cmdline();
- } else if (redraw_mode) {
- msg_pos_mode();
- msg_clr_eos();
- }
-
- // NB: also handles clearing the showmode if it was empty or disabled
- msg_ext_flush_showmode();
-
- // In Visual mode the size of the selected area must be redrawn.
- if (VIsual_active) {
- clear_showcmd();
- }
-
- // If the last window has no status line and global statusline is disabled,
- // the ruler is after the mode message and must be redrawn
- win_T *last = curwin->w_floating ? curwin : lastwin_nofloating();
- if (redrawing() && last->w_status_height == 0 && global_stl_height() == 0) {
- win_redr_ruler(last);
- }
-
- redraw_cmdline = false;
- redraw_mode = false;
- clear_cmdline = false;
-
- return length;
-}
-
-/// Position for a mode message.
-static void msg_pos_mode(void)
-{
- 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!).
-/// Caller should check "mode_displayed".
-void unshowmode(bool force)
-{
- // Don't delete it right now, when not redrawing or inside a mapping.
- if (!redrawing() || (!force && char_avail() && !KeyTyped)) {
- redraw_cmdline = true; // delete mode later
- } else {
- clearmode();
- }
-}
-
-// Clear the mode message.
-void clearmode(void)
-{
- const int save_msg_row = msg_row;
- const int save_msg_col = msg_col;
-
- msg_ext_ui_flush();
- msg_pos_mode();
- if (reg_recording != 0) {
- recording_mode(HL_ATTR(HLF_CM));
- }
- msg_clr_eos();
- msg_ext_flush_showmode();
-
- msg_col = save_msg_col;
- msg_row = save_msg_row;
-}
-
-static void recording_mode(int attr)
-{
- msg_puts_attr(_("recording"), attr);
- if (shortmess(SHM_RECORDING)) {
- return;
- }
-
- char s[4];
- snprintf(s, ARRAY_SIZE(s), " @%c", reg_recording);
- msg_puts_attr(s, attr);
-}
-
-void get_trans_bufname(buf_T *buf)
-{
- if (buf_spname(buf) != NULL) {
- xstrlcpy(NameBuff, buf_spname(buf), MAXPATHL);
- } else {
- home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, true);
- }
- trans_characters(NameBuff, MAXPATHL);
-}
-
-/// Get the character to use in a separator between vertically split windows.
-/// Get its attributes in "*attr".
-int fillchar_vsep(win_T *wp, int *attr)
-{
- *attr = win_hl_attr(wp, HLF_C);
- return wp->w_p_fcs_chars.vert;
-}
-
-/// Get the character to use in a separator between horizontally split windows.
-/// Get its attributes in "*attr".
-int fillchar_hsep(win_T *wp, int *attr)
-{
- *attr = win_hl_attr(wp, HLF_C);
- return wp->w_p_fcs_chars.horiz;
-}
-
-/// Return true if redrawing should currently be done.
-bool redrawing(void)
-{
- return !RedrawingDisabled
- && !(p_lz && char_avail() && !KeyTyped && !do_redraw);
-}
-
-/// Return true if printing messages should currently be done.
-bool messaging(void)
-{
- // TODO(bfredl): with general support for "async" messages with p_ch,
- // this should be re-enabled.
- return !(p_lz && char_avail() && !KeyTyped) && (p_ch > 0 || ui_has(kUIMessages));
-}
-
-#define COL_RULER 17 // columns needed by standard ruler
-
-/// 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'.
-void comp_col(void)
-{
- int last_has_status = (p_ls > 1 || (p_ls == 1 && !ONE_WINDOW));
-
- sc_col = 0;
- ru_col = 0;
- if (p_ru) {
- ru_col = (ru_wid ? ru_wid : COL_RULER) + 1;
- // no last status line, adjust sc_col
- if (!last_has_status) {
- sc_col = ru_col;
- }
- }
- if (p_sc) {
- sc_col += SHOWCMD_COLS;
- if (!p_ru || last_has_status) { // no need for separating space
- sc_col++;
- }
- }
- assert(sc_col >= 0
- && INT_MIN + sc_col <= Columns);
- sc_col = Columns - sc_col;
- assert(ru_col >= 0
- && INT_MIN + ru_col <= Columns);
- 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;
- }
- set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
-}
-
-/// Return the width of the 'number' and 'relativenumber' column.
-/// Caller may need to check if 'number' or 'relativenumber' is set.
-/// Otherwise it depends on 'numberwidth' and the line count.
-int number_width(win_T *wp)
-{
- linenr_T lnum;
-
- if (wp->w_p_rnu && !wp->w_p_nu) {
- // cursor line shows "0"
- lnum = wp->w_height_inner;
- } else {
- // cursor line shows absolute line number
- lnum = wp->w_buffer->b_ml.ml_line_count;
- }
-
- if (lnum == wp->w_nrwidth_line_count) {
- return wp->w_nrwidth_width;
- }
- wp->w_nrwidth_line_count = lnum;
-
- // reset for 'statuscolumn'
- if (*wp->w_p_stc != NUL) {
- wp->w_nrwidth_width = (wp->w_p_nu || wp->w_p_rnu) * (int)wp->w_p_nuw;
- return wp->w_nrwidth_width;
- }
-
- int n = 0;
- do {
- lnum /= 10;
- n++;
- } while (lnum > 0);
-
- // 'numberwidth' gives the minimal width plus one
- if (n < wp->w_p_nuw - 1) {
- n = (int)wp->w_p_nuw - 1;
- }
-
- // If 'signcolumn' is set to 'number' and there is a sign to display, then
- // the minimal width for the number column is 2.
- if (n < 2 && (wp->w_buffer->b_signlist != NULL)
- && (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u')) {
- n = 2;
- }
-
- wp->w_nrwidth_width = n;
- return n;
-}
-
-/// Calls mb_cptr2char_adv(p) and returns the character.
-/// If "p" starts with "\x", "\u" or "\U" the hex or unicode value is used.
-/// Returns 0 for invalid hex or invalid UTF-8 byte.
-static int get_encoded_char_adv(const char **p)
-{
- const char *s = *p;
-
- if (s[0] == '\\' && (s[1] == 'x' || s[1] == 'u' || s[1] == 'U')) {
- int64_t num = 0;
- for (int bytes = s[1] == 'x' ? 1 : s[1] == 'u' ? 2 : 4; bytes > 0; bytes--) {
- *p += 2;
- int n = hexhex2nr(*p);
- if (n < 0) {
- return 0;
- }
- num = num * 256 + n;
- }
- *p += 2;
- return (int)num;
- }
-
- // TODO(bfredl): use schar_T representation and utfc_ptr2len
- int clen = utf_ptr2len(s);
- int c = mb_cptr2char_adv(p);
- if (clen == 1 && c > 127) { // Invalid UTF-8 byte
- return 0;
- }
- return c;
-}
-
-/// Handle setting 'listchars' or 'fillchars'.
-/// Assume monocell characters
-///
-/// @param varp either the global or the window-local value.
-/// @param apply if false, do not store the flags, only check for errors.
-/// @return error message, NULL if it's OK.
-char *set_chars_option(win_T *wp, char **varp, bool apply)
-{
- const char *last_multispace = NULL; // Last occurrence of "multispace:"
- const char *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
- const bool is_listchars = (varp == &p_lcs || varp == &wp->w_p_lcs);
-
- struct chars_tab {
- int *cp; ///< char value
- char *name; ///< char id
- int def; ///< default value
- };
-
- // XXX: Characters taking 2 columns is forbidden (TUI limitation?). Set old defaults in this case.
- struct chars_tab fcs_tab[] = {
- { &wp->w_p_fcs_chars.stl, "stl", ' ' },
- { &wp->w_p_fcs_chars.stlnc, "stlnc", ' ' },
- { &wp->w_p_fcs_chars.wbr, "wbr", ' ' },
- { &wp->w_p_fcs_chars.horiz, "horiz", char2cells(0x2500) == 1 ? 0x2500 : '-' }, // ─
- { &wp->w_p_fcs_chars.horizup, "horizup", char2cells(0x2534) == 1 ? 0x2534 : '-' }, // ┴
- { &wp->w_p_fcs_chars.horizdown, "horizdown", char2cells(0x252c) == 1 ? 0x252c : '-' }, // ┬
- { &wp->w_p_fcs_chars.vert, "vert", char2cells(0x2502) == 1 ? 0x2502 : '|' }, // │
- { &wp->w_p_fcs_chars.vertleft, "vertleft", char2cells(0x2524) == 1 ? 0x2524 : '|' }, // ┤
- { &wp->w_p_fcs_chars.vertright, "vertright", char2cells(0x251c) == 1 ? 0x251c : '|' }, // ├
- { &wp->w_p_fcs_chars.verthoriz, "verthoriz", char2cells(0x253c) == 1 ? 0x253c : '+' }, // ┼
- { &wp->w_p_fcs_chars.fold, "fold", char2cells(0x00b7) == 1 ? 0x00b7 : '-' }, // ·
- { &wp->w_p_fcs_chars.foldopen, "foldopen", '-' },
- { &wp->w_p_fcs_chars.foldclosed, "foldclose", '+' },
- { &wp->w_p_fcs_chars.foldsep, "foldsep", char2cells(0x2502) == 1 ? 0x2502 : '|' }, // │
- { &wp->w_p_fcs_chars.diff, "diff", '-' },
- { &wp->w_p_fcs_chars.msgsep, "msgsep", ' ' },
- { &wp->w_p_fcs_chars.eob, "eob", '~' },
- { &wp->w_p_fcs_chars.lastline, "lastline", '@' },
- };
-
- struct chars_tab lcs_tab[] = {
- { &wp->w_p_lcs_chars.eol, "eol", NUL },
- { &wp->w_p_lcs_chars.ext, "extends", NUL },
- { &wp->w_p_lcs_chars.nbsp, "nbsp", NUL },
- { &wp->w_p_lcs_chars.prec, "precedes", NUL },
- { &wp->w_p_lcs_chars.space, "space", NUL },
- { &wp->w_p_lcs_chars.tab2, "tab", NUL },
- { &wp->w_p_lcs_chars.lead, "lead", NUL },
- { &wp->w_p_lcs_chars.trail, "trail", NUL },
- { &wp->w_p_lcs_chars.conceal, "conceal", NUL },
- };
-
- struct chars_tab *tab;
- int entries;
- const char *value = *varp;
- if (is_listchars) {
- tab = lcs_tab;
- entries = ARRAY_SIZE(lcs_tab);
- if (varp == &wp->w_p_lcs && wp->w_p_lcs[0] == NUL) {
- value = p_lcs; // local value is empty, use the global value
- }
- } else {
- tab = fcs_tab;
- entries = ARRAY_SIZE(fcs_tab);
- if (varp == &wp->w_p_fcs && wp->w_p_fcs[0] == NUL) {
- value = p_fcs; // local value is empty, use the global value
- }
- }
-
- // first round: check for valid value, second round: assign values
- for (int round = 0; round <= (apply ? 1 : 0); round++) {
- if (round > 0) {
- // After checking that the value is valid: set defaults
- for (int i = 0; i < entries; i++) {
- if (tab[i].cp != NULL) {
- *(tab[i].cp) = tab[i].def;
- }
- }
- if (is_listchars) {
- wp->w_p_lcs_chars.tab1 = NUL;
- wp->w_p_lcs_chars.tab3 = NUL;
-
- xfree(wp->w_p_lcs_chars.multispace);
- if (multispace_len > 0) {
- wp->w_p_lcs_chars.multispace = xmalloc(((size_t)multispace_len + 1) * sizeof(int));
- wp->w_p_lcs_chars.multispace[multispace_len] = NUL;
- } else {
- wp->w_p_lcs_chars.multispace = NULL;
- }
-
- xfree(wp->w_p_lcs_chars.leadmultispace);
- if (lead_multispace_len > 0) {
- wp->w_p_lcs_chars.leadmultispace
- = xmalloc(((size_t)lead_multispace_len + 1) * sizeof(int));
- wp->w_p_lcs_chars.leadmultispace[lead_multispace_len] = NUL;
- } else {
- wp->w_p_lcs_chars.leadmultispace = NULL;
- }
- }
- }
- const char *p = value;
- while (*p) {
- int i;
- for (i = 0; i < entries; i++) {
- const size_t len = strlen(tab[i].name);
- if (strncmp(p, tab[i].name, len) == 0
- && p[len] == ':'
- && p[len + 1] != NUL) {
- const char *s = p + len + 1;
- int c1 = get_encoded_char_adv(&s);
- if (c1 == 0 || char2cells(c1) > 1) {
- return e_invarg;
- }
- int c2 = 0, c3 = 0;
- if (tab[i].cp == &wp->w_p_lcs_chars.tab2) {
- if (*s == NUL) {
- return e_invarg;
- }
- c2 = get_encoded_char_adv(&s);
- if (c2 == 0 || char2cells(c2) > 1) {
- return e_invarg;
- }
- if (!(*s == ',' || *s == NUL)) {
- c3 = get_encoded_char_adv(&s);
- if (c3 == 0 || char2cells(c3) > 1) {
- return e_invarg;
- }
- }
- }
- if (*s == ',' || *s == NUL) {
- if (round > 0) {
- if (tab[i].cp == &wp->w_p_lcs_chars.tab2) {
- wp->w_p_lcs_chars.tab1 = c1;
- wp->w_p_lcs_chars.tab2 = c2;
- wp->w_p_lcs_chars.tab3 = c3;
- } else if (tab[i].cp != NULL) {
- *(tab[i].cp) = c1;
- }
- }
- p = s;
- break;
- }
- }
- }
-
- if (i == entries) {
- const size_t len = strlen("multispace");
- const size_t len2 = strlen("leadmultispace");
- if (is_listchars
- && strncmp(p, "multispace", len) == 0
- && p[len] == ':'
- && p[len + 1] != NUL) {
- const char *s = p + len + 1;
- if (round == 0) {
- // Get length of lcs-multispace string in the first round
- last_multispace = p;
- multispace_len = 0;
- while (*s != NUL && *s != ',') {
- int c1 = get_encoded_char_adv(&s);
- if (c1 == 0 || char2cells(c1) > 1) {
- return e_invarg;
- }
- multispace_len++;
- }
- if (multispace_len == 0) {
- // lcs-multispace cannot be an empty string
- return e_invarg;
- }
- p = s;
- } else {
- int multispace_pos = 0;
- while (*s != NUL && *s != ',') {
- int c1 = get_encoded_char_adv(&s);
- if (p == last_multispace) {
- wp->w_p_lcs_chars.multispace[multispace_pos++] = c1;
- }
- }
- p = s;
- }
- } else if (is_listchars
- && strncmp(p, "leadmultispace", len2) == 0
- && p[len2] == ':'
- && p[len2 + 1] != NUL) {
- const char *s = p + len2 + 1;
- if (round == 0) {
- // get length of lcs-leadmultispace string in first round
- last_lmultispace = p;
- lead_multispace_len = 0;
- while (*s != NUL && *s != ',') {
- int c1 = get_encoded_char_adv(&s);
- if (c1 == 0 || char2cells(c1) > 1) {
- return e_invarg;
- }
- lead_multispace_len++;
- }
- if (lead_multispace_len == 0) {
- // lcs-leadmultispace cannot be an empty string
- return e_invarg;
- }
- p = s;
- } else {
- int multispace_pos = 0;
- while (*s != NUL && *s != ',') {
- int c1 = get_encoded_char_adv(&s);
- if (p == last_lmultispace) {
- wp->w_p_lcs_chars.leadmultispace[multispace_pos++] = c1;
- }
- }
- p = s;
- }
- } else {
- return e_invarg;
- }
- }
-
- if (*p == ',') {
- p++;
- }
- }
- }
-
- return NULL; // no error
-}
-
-/// Check all global and local values of 'listchars' and 'fillchars'.
-/// May set different defaults in case character widths change.
-///
-/// @return an untranslated error message if any of them is invalid, NULL otherwise.
-char *check_chars_options(void)
-{
- if (set_chars_option(curwin, &p_lcs, false) != NULL) {
- return e_conflicts_with_value_of_listchars;
- }
- if (set_chars_option(curwin, &p_fcs, false) != NULL) {
- return e_conflicts_with_value_of_fillchars;
- }
- FOR_ALL_TAB_WINDOWS(tp, wp) {
- if (set_chars_option(wp, &wp->w_p_lcs, true) != NULL) {
- return e_conflicts_with_value_of_listchars;
- }
- if (set_chars_option(wp, &wp->w_p_fcs, true) != NULL) {
- return e_conflicts_with_value_of_fillchars;
- }
- }
- return NULL;
-}
-
-/// Check if the new Nvim application "screen" dimensions are valid.
-/// Correct it if it's too small or way too big.
-void check_screensize(void)
-{
- // Limit Rows and Columns to avoid an overflow in Rows * Columns.
- if (Rows < min_rows()) {
- // need room for one window and command line
- Rows = min_rows();
- } else if (Rows > 1000) {
- Rows = 1000;
- }
-
- if (Columns < MIN_COLUMNS) {
- Columns = MIN_COLUMNS;
- } else if (Columns > 10000) {
- Columns = 10000;
- }
-}
diff --git a/src/nvim/screen.h b/src/nvim/screen.h
deleted file mode 100644
index 1d8de8ca21..0000000000
--- a/src/nvim/screen.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef NVIM_SCREEN_H
-#define NVIM_SCREEN_H
-
-#include <stdbool.h>
-
-#include "nvim/buffer_defs.h"
-#include "nvim/fold.h"
-#include "nvim/grid_defs.h"
-#include "nvim/macros.h"
-
-EXTERN match_T screen_search_hl; // used for 'hlsearch' highlight matching
-
-#define W_ENDCOL(wp) ((wp)->w_wincol + (wp)->w_width)
-#define W_ENDROW(wp) ((wp)->w_winrow + (wp)->w_height)
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "screen.h.generated.h"
-#endif
-#endif // NVIM_SCREEN_H
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 782f60f11f..67b6f5e6a6 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -49,7 +49,6 @@
#include "nvim/path.h"
#include "nvim/profile.h"
#include "nvim/regexp.h"
-#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/strings.h"
#include "nvim/ui.h"
diff --git a/src/nvim/spellsuggest.c b/src/nvim/spellsuggest.c
index 2a9b5e1f4e..705e215dfa 100644
--- a/src/nvim/spellsuggest.c
+++ b/src/nvim/spellsuggest.c
@@ -39,7 +39,6 @@
#include "nvim/os/os_defs.h"
#include "nvim/pos.h"
#include "nvim/profile.h"
-#include "nvim/screen.h"
#include "nvim/spell.h"
#include "nvim/spellfile.h"
#include "nvim/spellsuggest.h"
@@ -569,7 +568,7 @@ void spell_suggest(int count)
}
vim_snprintf(IObuff, IOSIZE, "%2d", i + 1);
if (cmdmsg_rl) {
- rl_mirror(IObuff);
+ rl_mirror_ascii(IObuff);
}
msg_puts((const char *)IObuff);
@@ -595,7 +594,7 @@ void spell_suggest(int count)
}
if (cmdmsg_rl) {
// Mirror the numbers, but keep the leading space.
- rl_mirror(IObuff + 1);
+ rl_mirror_ascii(IObuff + 1);
}
msg_advance(30);
msg_puts((const char *)IObuff);
diff --git a/src/nvim/state.c b/src/nvim/state.c
index 40ee9af5ac..d02ea46d31 100644
--- a/src/nvim/state.c
+++ b/src/nvim/state.c
@@ -24,7 +24,6 @@
#include "nvim/main.h"
#include "nvim/option.h"
#include "nvim/os/input.h"
-#include "nvim/screen.h"
#include "nvim/state.h"
#include "nvim/strings.h"
#include "nvim/types.h"
diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c
index ff03017e6c..ca92953b05 100644
--- a/src/nvim/statusline.c
+++ b/src/nvim/statusline.c
@@ -15,6 +15,7 @@
#include "nvim/buffer.h"
#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
+#include "nvim/digraph.h"
#include "nvim/drawscreen.h"
#include "nvim/eval.h"
#include "nvim/eval/typval_defs.h"
@@ -36,7 +37,6 @@
#include "nvim/os/os.h"
#include "nvim/path.h"
#include "nvim/pos.h"
-#include "nvim/screen.h"
#include "nvim/sign.h"
#include "nvim/statusline.h"
#include "nvim/strings.h"
@@ -180,13 +180,46 @@ void win_redr_status(win_T *wp)
if (stl_connected(wp)) {
fillchar = fillchar_status(&attr, wp);
} else {
- fillchar = fillchar_vsep(wp, &attr);
+ attr = win_hl_attr(wp, HLF_C);
+ fillchar = wp->w_p_fcs_chars.vert;
}
grid_putchar(&default_grid, fillchar, W_ENDROW(wp), W_ENDCOL(wp), attr);
}
busy = false;
}
+void get_trans_bufname(buf_T *buf)
+{
+ if (buf_spname(buf) != NULL) {
+ xstrlcpy(NameBuff, buf_spname(buf), MAXPATHL);
+ } else {
+ home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, true);
+ }
+ trans_characters(NameBuff, MAXPATHL);
+}
+
+/// Only call if (wp->w_vsep_width != 0).
+///
+/// @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.
+bool stl_connected(win_T *wp)
+{
+ frame_T *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;
+}
+
/// Clear status line, window bar or tab page line click definition table
///
/// @param[out] tpcd Table to clear.
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index a52a34cd66..fca8515fab 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -82,7 +82,6 @@
#include "nvim/option.h"
#include "nvim/optionstr.h"
#include "nvim/pos.h"
-#include "nvim/screen.h"
#include "nvim/state.h"
#include "nvim/terminal.h"
#include "nvim/types.h"
diff --git a/src/nvim/textobject.c b/src/nvim/textobject.c
index 37f893ecec..6683fbe8f4 100644
--- a/src/nvim/textobject.c
+++ b/src/nvim/textobject.c
@@ -25,7 +25,6 @@
#include "nvim/normal.h"
#include "nvim/option_defs.h"
#include "nvim/pos.h"
-#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/strings.h"
#include "nvim/textobject.h"
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index 2b5dd297b5..3902d9c2aa 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -118,7 +118,6 @@
#include "nvim/os/time.h"
#include "nvim/path.h"
#include "nvim/pos.h"
-#include "nvim/screen.h"
#include "nvim/sha256.h"
#include "nvim/state.h"
#include "nvim/strings.h"
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 39e9efbabb..6bb9411048 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -66,7 +66,6 @@
#include "nvim/plines.h"
#include "nvim/pos.h"
#include "nvim/quickfix.h"
-#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/state.h"
#include "nvim/statusline.h"