aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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"