aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/clint.py191
-rw-r--r--src/coverity-model.c69
-rw-r--r--src/nvim/api/autocmd.c12
-rw-r--r--src/nvim/api/extmark.c24
-rw-r--r--src/nvim/api/keysets.lua2
-rw-r--r--src/nvim/api/private/helpers.c9
-rw-r--r--src/nvim/api/ui.c6
-rw-r--r--src/nvim/api/ui_events.in.h2
-rw-r--r--src/nvim/api/vim.c39
-rw-r--r--src/nvim/api/vimscript.c39
-rw-r--r--src/nvim/assert.h4
-rw-r--r--src/nvim/auevents.lua4
-rw-r--r--src/nvim/autocmd.c85
-rw-r--r--src/nvim/autocmd.h1
-rw-r--r--src/nvim/buffer_defs.h13
-rw-r--r--src/nvim/change.c16
-rw-r--r--src/nvim/edit.c9
-rw-r--r--src/nvim/eval.c6
-rw-r--r--src/nvim/eval/funcs.c30
-rw-r--r--src/nvim/eval/userfunc.c1
-rw-r--r--src/nvim/event/loop.c2
-rw-r--r--src/nvim/ex_cmds.c6
-rw-r--r--src/nvim/ex_docmd.c37
-rw-r--r--src/nvim/ex_getln.c11
-rw-r--r--src/nvim/ex_session.c13
-rw-r--r--src/nvim/fold.c25
-rw-r--r--src/nvim/fold.h1
-rw-r--r--src/nvim/getchar.c3
-rw-r--r--src/nvim/globals.h9
-rw-r--r--src/nvim/grid.c137
-rw-r--r--src/nvim/grid_defs.h4
-rw-r--r--src/nvim/highlight_defs.h6
-rw-r--r--src/nvim/highlight_group.c2
-rw-r--r--src/nvim/math.c2
-rw-r--r--src/nvim/mbyte.c22
-rw-r--r--src/nvim/message.c31
-rw-r--r--src/nvim/mouse.c31
-rw-r--r--src/nvim/move.c4
-rw-r--r--src/nvim/normal.c8
-rw-r--r--src/nvim/ops.c10
-rw-r--r--src/nvim/option.c50
-rw-r--r--src/nvim/option_defs.h4
-rw-r--r--src/nvim/options.lua18
-rw-r--r--src/nvim/os/fs.h10
-rw-r--r--src/nvim/os/input.c9
-rw-r--r--src/nvim/os/users.c2
-rw-r--r--src/nvim/popupmnu.c4
-rw-r--r--src/nvim/screen.c437
-rw-r--r--src/nvim/screen.h12
-rw-r--r--src/nvim/search.c38
-rw-r--r--src/nvim/spell.c2
-rw-r--r--src/nvim/strings.c30
-rw-r--r--src/nvim/strings.h2
-rw-r--r--src/nvim/terminal.c17
-rw-r--r--src/nvim/testdir/test_cmdline.vim12
-rw-r--r--src/nvim/testdir/test_cursor_func.vim5
-rw-r--r--src/nvim/testdir/test_edit.vim16
-rw-r--r--src/nvim/testdir/test_fold.vim69
-rw-r--r--src/nvim/testdir/test_mksession.vim24
-rw-r--r--src/nvim/testdir/test_tagjump.vim9
-rw-r--r--src/nvim/ui.c4
-rw-r--r--src/nvim/ui_compositor.c62
-rw-r--r--src/nvim/viml/parser/expressions.c4
-rw-r--r--src/nvim/window.c187
64 files changed, 1109 insertions, 844 deletions
diff --git a/src/clint.py b/src/clint.py
index b0992fcd63..4c9a4f4237 100755
--- a/src/clint.py
+++ b/src/clint.py
@@ -173,12 +173,9 @@ _ERROR_CATEGORIES = [
'build/deprecated',
'build/endif_comment',
'build/header_guard',
- 'build/include',
'build/include_alpha',
'build/printf_format',
'build/storage_class',
- 'build/useless_fattr',
- 'readability/alt_tokens',
'readability/bool',
'readability/braces',
'readability/multiline_comment',
@@ -202,13 +199,10 @@ _ERROR_CATEGORIES = [
'whitespace/comments',
'whitespace/empty_conditional_body',
'whitespace/empty_loop_body',
- 'whitespace/end_of_line',
- 'whitespace/ending_newline',
'whitespace/indent',
'whitespace/newline',
'whitespace/operators',
'whitespace/parens',
- 'whitespace/tab',
'whitespace/todo',
'whitespace/line_continuation',
'whitespace/cast',
@@ -220,11 +214,6 @@ _ERROR_CATEGORIES = [
# All entries here should start with a '-' or '+', as in the --filter= flag.
_DEFAULT_FILTERS = ['-build/include_alpha']
-# These constants define types of headers for use with
-# _IncludeState.CheckNextIncludeOrder().
-_C_SYS_HEADER = 1
-_OTHER_HEADER = 5
-
# These constants define the current inline assembly state
_NO_ASM = 0 # Outside of inline assembly block
_INSIDE_ASM = 1 # Inside inline assembly block
@@ -356,96 +345,6 @@ def Search(pattern, s):
return _regexp_compile_cache[pattern].search(s)
-class _IncludeState(dict): # lgtm [py/missing-equals]
-
- """Tracks line numbers for includes, and the order in which includes appear.
-
- As a dict, an _IncludeState object serves as a mapping between include
- filename and line number on which that file was included.
-
- Call CheckNextIncludeOrder() once for each header in the file, passing
- in the type constants defined above.
-
- """
- # self._section will move monotonically through this set. If it ever
- # needs to move backwards, CheckNextIncludeOrder will raise an error.
- _INITIAL_SECTION = 0
- _C_SECTION = 2
- _OTHER_H_SECTION = 4
-
- _TYPE_NAMES = {
- _C_SYS_HEADER: 'C system header',
- _OTHER_HEADER: 'other header',
- }
- _SECTION_NAMES = {
- _INITIAL_SECTION: "... nothing. (This can't be an error.)",
- _C_SECTION: 'C system header',
- _OTHER_H_SECTION: 'other header',
- }
-
- def __init__(self):
- dict.__init__(self)
- self.ResetSection()
-
- def ResetSection(self):
- # The name of the current section.
- self._section = self._INITIAL_SECTION
- # The path of last found header.
- self._last_header = ''
-
- def SetLastHeader(self, header_path):
- self._last_header = header_path
-
- def CanonicalizeAlphabeticalOrder(self, header_path):
- """Returns a path canonicalized for alphabetical comparison.
-
- - replaces "-" with "_" so they both cmp the same.
- - lowercase everything, just in case.
-
- Args:
- header_path: Path to be canonicalized.
-
- Returns:
- Canonicalized path.
- """
- return header_path.replace('-', '_').lower()
-
- def CheckNextIncludeOrder(self, header_type):
- """Returns a non-empty error message if the next header is out of order.
-
- This function also updates the internal state to be ready to check
- the next include.
-
- Args:
- header_type: One of the _XXX_HEADER constants defined above.
-
- Returns:
- The empty string if the header is in the right order, or an
- error message describing what's wrong.
-
- """
- error_message = ('Found %s after %s' %
- (self._TYPE_NAMES[header_type],
- self._SECTION_NAMES[self._section]))
-
- last_section = self._section
-
- if header_type == _C_SYS_HEADER:
- if self._section <= self._C_SECTION:
- self._section = self._C_SECTION
- else:
- self._last_header = ''
- return error_message
- else:
- assert header_type == _OTHER_HEADER
- self._section = self._OTHER_H_SECTION
-
- if last_section != self._section:
- self._last_header = ''
-
- return ''
-
-
class _CppLintState:
"""Maintains module-wide state.."""
@@ -1253,24 +1152,6 @@ def CheckForBadCharacters(filename, lines, error):
5, 'Line contains NUL byte.')
-def CheckForNewlineAtEOF(filename, lines, error):
- """Logs an error if there is no newline char at the end of the file.
-
- Args:
- filename: The name of the current file.
- lines: An array of strings, each representing a line of the file.
- error: The function to call with any errors found.
- """
-
- # The array lines() was created by adding two newlines to the
- # original file (go figure), then splitting on \n.
- # To verify that the file ends in \n, we just have to make sure the
- # last-but-two element of lines() exists and is empty.
- if len(lines) < 3 or lines[-2]:
- error(filename, len(lines) - 2, 'whitespace/ending_newline', 5,
- 'Could not find a newline character at the end of the file.')
-
-
def CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error):
"""Logs an error if we see /* ... */ or "..." that extend past one line.
@@ -2796,10 +2677,6 @@ def CheckStyle(filename, clean_lines, linenum, error):
raw_lines = clean_lines.lines_without_raw_strings
line = raw_lines[linenum]
- if line.find('\t') != -1:
- error(filename, linenum, 'whitespace/tab', 1,
- 'Tab found; better to use spaces')
-
# One or three blank spaces at the beginning of the line is weird; it's
# hard to reconcile that with 2-space indents.
# NOTE: here are the conditions rob pike used for his tests. Mine aren't
@@ -2815,18 +2692,9 @@ def CheckStyle(filename, clean_lines, linenum, error):
# if(prevodd && match(prevprev, " +for \\(")) complain = 0;
initial_spaces = 0
cleansed_line = clean_lines.elided[linenum]
+
while initial_spaces < len(line) and line[initial_spaces] == ' ':
initial_spaces += 1
- if line and line[-1].isspace():
- error(filename, linenum, 'whitespace/end_of_line', 4,
- 'Line ends in whitespace. Consider deleting these extra spaces.')
- # There are certain situations we allow one space, notably for section
- # labels
- elif ((initial_spaces == 1 or initial_spaces == 3) and
- not Match(r'\s*\w+\s*:\s*$', cleansed_line)):
- error(filename, linenum, 'whitespace/indent', 3,
- 'Weird number of spaces at line-start. '
- 'Are you using a 2-space indent?')
if (cleansed_line.count(';') > 1 and
# for loops are allowed two ;'s (and may run over two lines).
@@ -2849,38 +2717,6 @@ def CheckStyle(filename, clean_lines, linenum, error):
_RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$')
-def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
- """Check rules that are applicable to #include lines.
-
- Strings on #include lines are NOT removed from elided line, to make
- certain tasks easier. However, to prevent false positives, checks
- applicable to #include lines in CheckLanguage must be put here.
-
- Args:
- filename : The name of the current file.
- clean_lines : A CleansedLines instance containing the file.
- linenum : The number of the line to check.
- include_state : An _IncludeState instance in which the headers are
- inserted.
- error : The function to call with any errors found.
- """
-
- line = clean_lines.lines[linenum]
-
- # we shouldn't include a file more than once. actually, there are a
- # handful of instances where doing so is okay, but in general it's
- # not.
- match = _RE_PATTERN_INCLUDE.search(line)
- if match:
- include = match.group(2)
- is_system = (match.group(1) == '<')
- if include in include_state:
- if is_system or not include.endswith('.c.h'):
- error(filename, linenum, 'build/include', 4,
- '"%s" already included at %s:%s' %
- (include, filename, include_state[include]))
-
-
def _GetTextInside(text, start_pattern):
r"""Retrieves all the text between matching open and close parentheses.
@@ -2938,7 +2774,7 @@ def _GetTextInside(text, start_pattern):
return text[start_position:position - 1]
-def CheckLanguage(filename, clean_lines, linenum, include_state, error):
+def CheckLanguage(filename, clean_lines, linenum, error):
"""Checks rules from the 'C++ language rules' section of cppguide.html.
Some of these rules are hard to test (function overloading, using
@@ -2948,8 +2784,6 @@ def CheckLanguage(filename, clean_lines, linenum, include_state, error):
filename : The name of the current file.
clean_lines : A CleansedLines instance containing the file.
linenum : The number of the line to check.
- include_state : An _IncludeState instance in which the headers are
- inserted.
error : The function to call with any errors found.
"""
# If the line is empty or consists of entirely a comment, no need to
@@ -2958,16 +2792,6 @@ def CheckLanguage(filename, clean_lines, linenum, include_state, error):
if not line:
return
- match = _RE_PATTERN_INCLUDE.search(line)
- if match:
- CheckIncludeLine(filename, clean_lines, linenum, include_state, error)
- return
-
- # Reset include state across preprocessor directives. This is meant
- # to silence warnings for conditional includes.
- if Match(r'^\s*#\s*(?:ifdef|elif|else|endif)\b', line):
- include_state.ResetSection()
-
# TODO(unknown): figure out if they're using default arguments in fn proto.
# Check if people are using the verboten C basic types.
@@ -3125,7 +2949,7 @@ def CheckLanguage(filename, clean_lines, linenum, include_state, error):
def ProcessLine(filename, clean_lines, line,
- include_state, function_state, nesting_state, error,
+ function_state, nesting_state, error,
extra_check_functions=[]):
"""Processes a single line in the file.
@@ -3134,8 +2958,6 @@ def ProcessLine(filename, clean_lines, line,
clean_lines : An array of strings, each representing a line of
the file, with comments stripped.
line : Number of line being processed.
- include_state : An _IncludeState instance in which the headers are
- inserted.
function_state : A _FunctionState instance which counts function
lines, etc.
nesting_state : A _NestingState instance which maintains
@@ -3158,7 +2980,7 @@ def ProcessLine(filename, clean_lines, line,
CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)
CheckForOldStyleComments(filename, init_lines[line], line, error)
CheckStyle(filename, clean_lines, line, error)
- CheckLanguage(filename, clean_lines, line, include_state, error)
+ CheckLanguage(filename, clean_lines, line, error)
CheckForNonStandardConstructs(filename, clean_lines, line, error)
CheckPosixThreading(filename, clean_lines, line, error)
CheckMemoryFunctions(filename, clean_lines, line, error)
@@ -3185,7 +3007,6 @@ def ProcessFileData(filename, file_extension, lines, error,
lines = (['// marker so line numbers and indices both start at 1'] + lines +
['// marker so line numbers end in a known way'])
- include_state = _IncludeState()
function_state = _FunctionState()
nesting_state = _NestingState()
@@ -3216,15 +3037,13 @@ def ProcessFileData(filename, file_extension, lines, error,
clean_lines = CleansedLines(lines, init_lines)
for line in range(clean_lines.NumLines()):
ProcessLine(filename, clean_lines, line,
- include_state, function_state, nesting_state, error,
+ function_state, nesting_state, error,
extra_check_functions)
# We check here rather than inside ProcessLine so that we see raw
# lines rather than "cleaned" lines.
CheckForBadCharacters(filename, lines, error)
- CheckForNewlineAtEOF(filename, lines, error)
-
def ProcessFile(filename, vlevel, extra_check_functions=[]):
"""Does neovim-lint on a single file.
diff --git a/src/coverity-model.c b/src/coverity-model.c
index 2fd55c332c..4338b75ea2 100644
--- a/src/coverity-model.c
+++ b/src/coverity-model.c
@@ -42,3 +42,72 @@ int tv_dict_add(dict_T *const d, dictitem_T *const item)
{
__coverity_escape__(item);
}
+
+void *malloc(size_t size)
+{
+ int has_mem;
+ if (has_mem)
+ return __coverity_alloc__(size);
+ else
+ return 0;
+}
+
+void *try_malloc(size_t size)
+{
+ size_t allocated_size = size ? size : 1;
+ return malloc(allocated_size);
+}
+
+void *xmalloc(size_t size)
+{
+ void *p = malloc(size);
+ if (!p)
+ __coverity_panic__();
+ return p;
+}
+
+void xfree(void * ptr)
+{
+ __coverity_free__(ptr);
+}
+
+void *xcalloc(size_t count, size_t size)
+{
+ size_t allocated_count = count && size ? count : 1;
+ size_t allocated_size = count && size ? size : 1;
+ void *p = try_malloc(allocated_count * allocated_size);
+ if (!p)
+ __coverity_panic__();
+ __coverity_writeall0__(p);
+ return p;
+}
+
+void *xrealloc(void *ptr, size_t size)
+{
+ __coverity_escape__(ptr);
+ void * p = xmalloc(size);
+ __coverity_writeall__(p);
+ return p;
+}
+
+void *xmallocz(size_t size)
+{
+ void * p = malloc(size + 1);
+ ((char*)p)[size] = 0;
+ return p;
+}
+
+void * xmemdupz(const void * data, size_t len)
+{
+ void * p = xmallocz(len);
+ __coverity_writeall__(p);
+ ((char*)p)[len] = 0;
+ return p;
+}
+
+void * xmemdup(const void *data, size_t len)
+{
+ void * p = xmalloc(len);
+ __coverity_writeall__(p);
+ return p;
+}
diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c
index 76e531e7aa..4ee834d75a 100644
--- a/src/nvim/api/autocmd.c
+++ b/src/nvim/api/autocmd.c
@@ -283,7 +283,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
PUT(autocmd_info,
"command",
- STRING_OBJ(cstr_to_string(aucmd_exec_to_string(ac, ac->exec))));
+ STRING_OBJ(cstr_as_string(aucmd_exec_to_string(ac, ac->exec))));
PUT(autocmd_info,
"pattern",
@@ -405,6 +405,7 @@ cleanup:
/// - match: (string) the expanded value of |<amatch>|
/// - buf: (number) the expanded value of |<abuf>|
/// - file: (string) the expanded value of |<afile>|
+/// - data: (any) arbitrary data passed to |nvim_exec_autocmds()|
/// - command (string) optional: Vim command to execute on event. Cannot be used with
/// {callback}
/// - once (boolean) optional: defaults to false. Run the autocommand
@@ -749,6 +750,8 @@ void nvim_del_augroup_by_name(String name, Error *err)
/// {pattern}.
/// - modeline (bool) optional: defaults to true. Process the
/// modeline after the autocommands |<nomodeline>|.
+/// - data (any): arbitrary data to send to the autocommand callback. See
+/// |nvim_create_autocmd()| for details.
/// @see |:doautocmd|
void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
FUNC_API_SINCE(9)
@@ -760,6 +763,7 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
bool set_buf = false;
char *pattern = NULL;
+ Object *data = NULL;
bool set_pattern = false;
Array event_array = ARRAY_DICT_INIT;
@@ -818,6 +822,10 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
set_pattern = true;
}
+ if (opts->data.type != kObjectTypeNil) {
+ data = &opts->data;
+ }
+
modeline = api_object_to_bool(opts->modeline, "modeline", true, err);
if (set_pattern && set_buf) {
@@ -829,7 +837,7 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
FOREACH_ITEM(event_array, event_str, {
GET_ONE_EVENT(event_nr, event_str, cleanup)
- did_aucmd |= apply_autocmds_group(event_nr, pattern, NULL, true, au_group, buf, NULL);
+ did_aucmd |= apply_autocmds_group(event_nr, pattern, NULL, true, au_group, buf, NULL, data);
})
if (did_aucmd && modeline) {
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c
index 9143f593b1..94b2af9a6f 100644
--- a/src/nvim/api/extmark.c
+++ b/src/nvim/api/extmark.c
@@ -95,27 +95,27 @@ static bool ns_initialized(uint32_t ns)
}
-static Array extmark_to_array(ExtmarkInfo extmark, bool id, bool add_dict)
+static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict)
{
Array rv = ARRAY_DICT_INIT;
if (id) {
- ADD(rv, INTEGER_OBJ((Integer)extmark.mark_id));
+ ADD(rv, INTEGER_OBJ((Integer)extmark->mark_id));
}
- ADD(rv, INTEGER_OBJ(extmark.row));
- ADD(rv, INTEGER_OBJ(extmark.col));
+ ADD(rv, INTEGER_OBJ(extmark->row));
+ ADD(rv, INTEGER_OBJ(extmark->col));
if (add_dict) {
Dictionary dict = ARRAY_DICT_INIT;
- PUT(dict, "right_gravity", BOOLEAN_OBJ(extmark.right_gravity));
+ PUT(dict, "right_gravity", BOOLEAN_OBJ(extmark->right_gravity));
- if (extmark.end_row >= 0) {
- PUT(dict, "end_row", INTEGER_OBJ(extmark.end_row));
- PUT(dict, "end_col", INTEGER_OBJ(extmark.end_col));
- PUT(dict, "end_right_gravity", BOOLEAN_OBJ(extmark.end_right_gravity));
+ if (extmark->end_row >= 0) {
+ PUT(dict, "end_row", INTEGER_OBJ(extmark->end_row));
+ PUT(dict, "end_col", INTEGER_OBJ(extmark->end_col));
+ PUT(dict, "end_right_gravity", BOOLEAN_OBJ(extmark->end_right_gravity));
}
- Decoration *decor = &extmark.decor;
+ const Decoration *decor = &extmark->decor;
if (decor->hl_id) {
String name = cstr_to_string((const char *)syn_id2name(decor->hl_id));
PUT(dict, "hl_group", STRING_OBJ(name));
@@ -238,7 +238,7 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
if (extmark.row < 0) {
return rv;
}
- return extmark_to_array(extmark, false, details);
+ return extmark_to_array(&extmark, false, details);
}
/// Gets extmarks in "traversal order" from a |charwise| region defined by
@@ -357,7 +357,7 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
u_row, u_col, (int64_t)limit, reverse);
for (size_t i = 0; i < kv_size(marks); i++) {
- ADD(rv, ARRAY_OBJ(extmark_to_array(kv_A(marks, i), true, (bool)details)));
+ ADD(rv, ARRAY_OBJ(extmark_to_array(&kv_A(marks, i), true, (bool)details)));
}
kv_destroy(marks);
diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua
index 78f8ed3cca..6924e2ef8f 100644
--- a/src/nvim/api/keysets.lua
+++ b/src/nvim/api/keysets.lua
@@ -80,6 +80,7 @@ return {
"maxwidth";
"fillchar";
"highlights";
+ "use_winbar";
"use_tabline";
};
option = {
@@ -145,6 +146,7 @@ return {
"group";
"modeline";
"pattern";
+ "data";
};
get_autocmds = {
"event";
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index dcede27bcb..5d4b84482b 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -1418,14 +1418,14 @@ bool set_mark(buf_T *buf, String name, Integer line, Integer col, Error *err)
}
/// Get default statusline highlight for window
-const char *get_default_stl_hl(win_T *wp)
+const char *get_default_stl_hl(win_T *wp, bool use_winbar)
{
if (wp == NULL) {
return "TabLineFill";
- } else if (wp == curwin) {
- return "StatusLine";
+ } else if (use_winbar) {
+ return (wp == curwin) ? "WinBar" : "WinBarNC";
} else {
- return "StatusLineNC";
+ return (wp == curwin) ? "StatusLine" : "StatusLineNC";
}
}
@@ -1624,6 +1624,7 @@ void create_user_command(String name, Object command, Dict(user_command) *opts,
err:
NLUA_CLEAR_REF(luaref);
NLUA_CLEAR_REF(compl_luaref);
+ xfree(compl_arg);
}
int find_sid(uint64_t channel_id)
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index b4d20ed975..52f76f4650 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -349,7 +349,11 @@ void nvim_ui_try_resize_grid(uint64_t channel_id, Integer grid, Integer width, I
return;
}
- ui_grid_resize((handle_T)grid, (int)width, (int)height, err);
+ if (grid == DEFAULT_GRID_HANDLE) {
+ nvim_ui_try_resize(channel_id, width, height, err);
+ } else {
+ ui_grid_resize((handle_T)grid, (int)width, (int)height, err);
+ }
}
/// Tells Nvim the number of elements displaying in the popumenu, to decide
diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h
index 63aaaae38a..0030f9edf7 100644
--- a/src/nvim/api/ui_events.in.h
+++ b/src/nvim/api/ui_events.in.h
@@ -174,4 +174,6 @@ void msg_ruler(Array content)
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
void msg_history_show(Array entries)
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
+void msg_history_clear(void)
+ FUNC_API_SINCE(10) FUNC_API_REMOTE_ONLY;
#endif // NVIM_API_UI_EVENTS_IN_H
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index a257dd6478..15992a98be 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -2140,8 +2140,8 @@ Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Error *err)
}
}
- if (row < 0 || row >= g->Rows
- || col < 0 || col >= g->Columns) {
+ if (row < 0 || row >= g->rows
+ || col < 0 || col >= g->cols) {
return ret;
}
size_t off = g->line_offset[(size_t)row] + (size_t)col;
@@ -2274,8 +2274,9 @@ Array nvim_get_mark(String name, Dictionary opts, Error *err)
/// - fillchar: (string) Character to fill blank spaces in the statusline (see
/// 'fillchars'). Treated as single-width even if it isn't.
/// - highlights: (boolean) Return highlight information.
+/// - use_winbar: (boolean) Evaluate winbar instead of statusline.
/// - use_tabline: (boolean) Evaluate tabline instead of statusline. When |TRUE|, {winid}
-/// is ignored.
+/// is ignored. Mutually exclusive with {use_winbar}.
///
/// @param[out] err Error details, if any.
/// @return Dictionary containing statusline information, with these keys:
@@ -2294,6 +2295,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
int maxwidth;
int fillchar = 0;
Window window = 0;
+ bool use_winbar = false;
bool use_tabline = false;
bool highlights = false;
@@ -2313,7 +2315,6 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
window = (Window)opts->winid.data.integer;
}
-
if (HAS_KEY(opts->fillchar)) {
if (opts->fillchar.type != kObjectTypeString || opts->fillchar.data.string.size == 0
|| ((size_t)utf_ptr2len(opts->fillchar.data.string.data)
@@ -2323,7 +2324,6 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
}
fillchar = utf_ptr2char(opts->fillchar.data.string.data);
}
-
if (HAS_KEY(opts->highlights)) {
highlights = api_object_to_bool(opts->highlights, "highlights", false, err);
@@ -2331,7 +2331,13 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
return result;
}
}
+ if (HAS_KEY(opts->use_winbar)) {
+ use_winbar = api_object_to_bool(opts->use_winbar, "use_winbar", false, err);
+ if (ERROR_SET(err)) {
+ return result;
+ }
+ }
if (HAS_KEY(opts->use_tabline)) {
use_tabline = api_object_to_bool(opts->use_tabline, "use_tabline", false, err);
@@ -2339,6 +2345,10 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
return result;
}
}
+ if (use_winbar && use_tabline) {
+ api_set_error(err, kErrorTypeValidation, "use_winbar and use_tabline are mutually exclusive");
+ return result;
+ }
win_T *wp, *ewp;
@@ -2348,7 +2358,6 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
fillchar = ' ';
} else {
wp = find_window_by_handle(window, err);
-
if (wp == NULL) {
api_set_error(err, kErrorTypeException, "unknown winid %d", window);
return result;
@@ -2356,8 +2365,12 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
ewp = wp;
if (fillchar == 0) {
- int attr;
- fillchar = fillchar_status(&attr, wp);
+ if (use_winbar) {
+ fillchar = wp->w_p_fcs_chars.wbr;
+ } else {
+ int attr;
+ fillchar = fillchar_status(&attr, wp);
+ }
}
}
@@ -2369,7 +2382,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
maxwidth = (int)opts->maxwidth.data.integer;
} else {
- maxwidth = (use_tabline || global_stl_height() > 0) ? Columns : wp->w_width;
+ maxwidth = (use_tabline || (!use_winbar && global_stl_height() > 0)) ? Columns : wp->w_width;
}
char buf[MAXPATHL];
@@ -2404,7 +2417,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
// add the default highlight at the beginning of the highlight list
if (hltab->start == NULL || ((char *)hltab->start - buf) != 0) {
Dictionary hl_info = ARRAY_DICT_INIT;
- grpname = get_default_stl_hl(wp);
+ grpname = get_default_stl_hl(wp, use_winbar);
PUT(hl_info, "start", INTEGER_OBJ(0));
PUT(hl_info, "group", CSTR_TO_OBJ(grpname));
@@ -2418,22 +2431,18 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
PUT(hl_info, "start", INTEGER_OBJ((char *)sp->start - buf));
if (sp->userhl == 0) {
- grpname = get_default_stl_hl(wp);
+ grpname = get_default_stl_hl(wp, use_winbar);
} else if (sp->userhl < 0) {
grpname = (char *)syn_id2name(-sp->userhl);
} else {
snprintf(user_group, sizeof(user_group), "User%d", sp->userhl);
grpname = user_group;
}
-
PUT(hl_info, "group", CSTR_TO_OBJ(grpname));
-
ADD(hl_values, DICTIONARY_OBJ(hl_info));
}
-
PUT(result, "highlights", ARRAY_OBJ(hl_values));
}
-
PUT(result, "str", CSTR_TO_OBJ((char *)buf));
return result;
diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c
index 42101af7f0..e71f1a11ec 100644
--- a/src/nvim/api/vimscript.c
+++ b/src/nvim/api/vimscript.c
@@ -34,7 +34,7 @@
/// Unlike |nvim_command()| this function supports heredocs, script-scope (s:),
/// etc.
///
-/// On execution error: fails with VimL error, does not update v:errmsg.
+/// On execution error: fails with VimL error, updates v:errmsg.
///
/// @see |execute()|
/// @see |nvim_command()|
@@ -98,7 +98,7 @@ theend:
/// Executes an Ex command.
///
-/// On execution error: fails with VimL error, does not update v:errmsg.
+/// On execution error: fails with VimL error, updates v:errmsg.
///
/// Prefer using |nvim_cmd()| or |nvim_exec()| over this. To evaluate multiple lines of Vim script
/// or an Ex command directly, use |nvim_exec()|. To construct an Ex command using a structured
@@ -118,7 +118,7 @@ void nvim_command(String command, Error *err)
/// Evaluates a VimL |expression|.
/// Dictionaries and Lists are recursively expanded.
///
-/// On execution error: fails with VimL error, does not update v:errmsg.
+/// On execution error: fails with VimL error, updates v:errmsg.
///
/// @param expr VimL expression string
/// @param[out] err Error details, if any
@@ -226,7 +226,7 @@ free_vim_args:
/// Calls a VimL function with the given arguments.
///
-/// On execution error: fails with VimL error, does not update v:errmsg.
+/// On execution error: fails with VimL error, updates v:errmsg.
///
/// @param fn Function to call
/// @param args Function arguments packed in an Array
@@ -240,7 +240,7 @@ Object nvim_call_function(String fn, Array args, Error *err)
/// Calls a VimL |Dictionary-function| with the given arguments.
///
-/// On execution error: fails with VimL error, does not update v:errmsg.
+/// On execution error: fails with VimL error, updates v:errmsg.
///
/// @param dict Dictionary, or String evaluating to a VimL |self| dict
/// @param fn Name of the function defined on the VimL dict
@@ -996,6 +996,8 @@ end:
/// such as having spaces inside a command argument, expanding filenames in a command that otherwise
/// doesn't expand filenames, etc.
///
+/// On execution error: fails with VimL error, updates v:errmsg.
+///
/// @see |nvim_exec()|
/// @see |nvim_command()|
///
@@ -1302,20 +1304,23 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
capture_ga = &capture_local;
}
- try_start();
- if (output) {
- msg_silent++;
- }
+ TRY_WRAP({
+ try_start();
+ if (output) {
+ msg_silent++;
+ }
- WITH_SCRIPT_CONTEXT(channel_id, {
- execute_cmd(&ea, &cmdinfo);
- });
+ WITH_SCRIPT_CONTEXT(channel_id, {
+ execute_cmd(&ea, &cmdinfo);
+ });
- if (output) {
- capture_ga = save_capture_ga;
- msg_silent = save_msg_silent;
- }
- try_end(err);
+ if (output) {
+ capture_ga = save_capture_ga;
+ msg_silent = save_msg_silent;
+ }
+
+ try_end(err);
+ });
if (ERROR_SET(err)) {
goto clear_ga;
diff --git a/src/nvim/assert.h b/src/nvim/assert.h
index bc5260b914..ad92d9a2af 100644
--- a/src/nvim/assert.h
+++ b/src/nvim/assert.h
@@ -108,8 +108,6 @@
# define STATIC_ASSERT_STATEMENT STATIC_ASSERT_EXPR
#endif
-// uncrustify:off
-
#define ASSERT_CONCAT_(a, b) a##b
#define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
// These can't be used after statements in c89.
@@ -125,8 +123,6 @@
((enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(e)), }) 0)
#endif
-// uncrustify:on
-
/// @def STRICT_ADD
/// @brief Adds (a + b) and stores result in `c`. Aborts on overflow.
///
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index 9e3eb06752..93a870fe04 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -70,6 +70,8 @@ return {
'InsertEnter', -- when entering Insert mode
'InsertLeave', -- just after leaving Insert mode
'InsertLeavePre', -- just before leaving Insert mode
+ 'LspAttach', -- after an LSP client attaches to a buffer
+ 'LspDetach', -- after an LSP client detaches from a buffer
'MenuPopup', -- just before popup menu is displayed
'ModeChanged', -- after changing the mode
'OptionSet', -- after setting any option
@@ -133,6 +135,8 @@ return {
nvim_specific = {
BufModifiedSet=true,
DiagnosticChanged=true,
+ LspAttach=true,
+ LspDetach=true,
RecordingEnter=true,
RecordingLeave=true,
Signal=true,
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index 6c7950fdd1..bc9e548b77 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -190,7 +190,18 @@ static void aupat_show(AutoPat *ap, event_T event, int previous_group)
if (got_int) {
return;
}
- msg_outtrans((char_u *)aucmd_exec_to_string(ac, ac->exec));
+
+ char *exec_to_string = aucmd_exec_to_string(ac, ac->exec);
+ if (ac->desc != NULL) {
+ size_t msglen = 100;
+ char *msg = (char *)xmallocz(msglen);
+ snprintf(msg, msglen, "%s [%s]", exec_to_string, ac->desc);
+ msg_outtrans((char_u *)msg);
+ XFREE_CLEAR(msg);
+ } else {
+ msg_outtrans((char_u *)exec_to_string);
+ }
+ XFREE_CLEAR(exec_to_string);
if (p_verbose > 0) {
last_set_msg(ac->script_ctx);
}
@@ -1136,8 +1147,6 @@ int autocmd_register(int64_t id, event_T event, char *pat, int patlen, int group
// perhaps: <lua>DESCRIPTION or similar
if (desc != NULL) {
ac->desc = xstrdup(desc);
- } else {
- ac->desc = aucmd_exec_default_desc(aucmd);
}
return OK;
@@ -1220,7 +1229,7 @@ int do_doautocmd(char *arg_start, bool do_msg, bool *did_something)
// Loop over the events.
while (*arg && !ends_excmd(*arg) && !ascii_iswhite(*arg)) {
if (apply_autocmds_group(event_name2nr(arg, &arg), fname, NULL, true, group,
- curbuf, NULL)) {
+ curbuf, NULL, NULL)) {
nothing_done = false;
}
}
@@ -1505,7 +1514,7 @@ win_found:
/// @return true if some commands were executed.
bool apply_autocmds(event_T event, char *fname, char *fname_io, bool force, buf_T *buf)
{
- return apply_autocmds_group(event, fname, fname_io, force, AUGROUP_ALL, buf, NULL);
+ return apply_autocmds_group(event, fname, fname_io, force, AUGROUP_ALL, buf, NULL, NULL);
}
/// Like apply_autocmds(), but with extra "eap" argument. This takes care of
@@ -1522,7 +1531,7 @@ bool apply_autocmds(event_T event, char *fname, char *fname_io, bool force, buf_
bool apply_autocmds_exarg(event_T event, char *fname, char *fname_io, bool force, buf_T *buf,
exarg_T *eap)
{
- return apply_autocmds_group(event, fname, fname_io, force, AUGROUP_ALL, buf, eap);
+ return apply_autocmds_group(event, fname, fname_io, force, AUGROUP_ALL, buf, eap, NULL);
}
/// Like apply_autocmds(), but handles the caller's retval. If the script
@@ -1546,7 +1555,7 @@ bool apply_autocmds_retval(event_T event, char *fname, char *fname_io, bool forc
}
bool did_cmd = apply_autocmds_group(event, fname, fname_io, force,
- AUGROUP_ALL, buf, NULL);
+ AUGROUP_ALL, buf, NULL, NULL);
if (did_cmd && aborting()) {
*retval = FAIL;
}
@@ -1595,7 +1604,7 @@ bool trigger_cursorhold(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
///
/// @return true if some commands were executed.
bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force, int group,
- buf_T *buf, exarg_T *eap)
+ buf_T *buf, exarg_T *eap, Object *data)
{
char *sfname = NULL; // short file name
bool retval = false;
@@ -1811,6 +1820,9 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force
patcmd.next = active_apc_list;
active_apc_list = &patcmd;
+ // Attach data to command
+ patcmd.data = data;
+
// set v:cmdarg (only when there is a matching pattern)
save_cmdbang = (long)get_vim_var_nr(VV_CMDBANG);
if (eap != NULL) {
@@ -2026,6 +2038,10 @@ static bool call_autocmd_callback(const AutoCmd *ac, const AutoPatCmd *apc)
PUT(data, "file", CSTR_TO_OBJ((char *)autocmd_fname));
PUT(data, "buf", INTEGER_OBJ(autocmd_bufnr));
+ if (apc->data) {
+ PUT(data, "data", copy_object(*apc->data));
+ }
+
int group = apc->curpat->group;
switch (group) {
case AUGROUP_ERROR:
@@ -2111,8 +2127,10 @@ char *getnextac(int c, void *cookie, int indent, bool do_concat)
if (p_verbose >= 9) {
verbose_enter_scroll();
- smsg(_("autocommand %s"), aucmd_exec_to_string(ac, ac->exec));
+ char *exec_to_string = aucmd_exec_to_string(ac, ac->exec);
+ smsg(_("autocommand %s"), exec_to_string);
msg_puts("\n"); // don't overwrite this either
+ XFREE_CLEAR(exec_to_string);
verbose_leave_scroll();
}
@@ -2463,45 +2481,42 @@ bool autocmd_delete_id(int64_t id)
// ===========================================================================
// AucmdExecutable Functions
// ===========================================================================
-char *aucmd_exec_default_desc(AucmdExecutable acc)
+
+/// Generate a string description of a callback
+static char *aucmd_callback_to_string(Callback cb)
{
+ // NOTE: this function probably belongs in a helper
+
size_t msglen = 100;
+ char *msg = (char *)xmallocz(msglen);
- switch (acc.type) {
- case CALLABLE_CB:
- switch (acc.callable.cb.type) {
- case kCallbackLua: {
- char *msg = (char *)xmallocz(msglen);
- snprintf(msg, msglen, "<Lua function %d>", acc.callable.cb.data.luaref);
- return msg;
- }
- case kCallbackFuncref: {
- // TODO(tjdevries): Is this enough space for this?
- char *msg = (char *)xmallocz(msglen);
- snprintf(msg, msglen, "<vim function: %s>", acc.callable.cb.data.funcref);
- return msg;
- }
- case kCallbackPartial: {
- char *msg = (char *)xmallocz(msglen);
- snprintf(msg, msglen, "<vim partial: %s>", acc.callable.cb.data.partial->pt_name);
- return msg;
- }
- default:
- return NULL;
- }
+ switch (cb.type) {
+ case kCallbackLua:
+ snprintf(msg, msglen, "<lua: %d>", cb.data.luaref);
+ break;
+ case kCallbackFuncref:
+ // TODO(tjdevries): Is this enough space for this?
+ snprintf(msg, msglen, "<vim function: %s>", cb.data.funcref);
+ break;
+ case kCallbackPartial:
+ snprintf(msg, msglen, "<vim partial: %s>", cb.data.partial->pt_name);
+ break;
default:
- return NULL;
+ snprintf(msg, msglen, "%s", "");
+ break;
}
+ return msg;
}
+/// Generate a string description for the command/callback of an autocmd
char *aucmd_exec_to_string(AutoCmd *ac, AucmdExecutable acc)
FUNC_ATTR_PURE
{
switch (acc.type) {
case CALLABLE_EX:
- return acc.callable.cmd;
+ return xstrdup(acc.callable.cmd);
case CALLABLE_CB:
- return ac->desc;
+ return aucmd_callback_to_string(acc.callable.cb);
case CALLABLE_NONE:
return "This is not possible";
}
diff --git a/src/nvim/autocmd.h b/src/nvim/autocmd.h
index d3503672fd..47f583ae13 100644
--- a/src/nvim/autocmd.h
+++ b/src/nvim/autocmd.h
@@ -57,6 +57,7 @@ typedef struct AutoPatCmd {
char *tail; // tail of fname
event_T event; // current event
int arg_bufnr; // initially equal to <abuf>, set to zero when buf is deleted
+ Object *data; // arbitrary data
struct AutoPatCmd *next; // chain of active apc-s for auto-invalidation
} AutoPatCmd;
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 2adeeadbca..9efa540210 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -233,6 +233,8 @@ typedef struct {
#define w_p_sbr w_onebuf_opt.wo_sbr // 'showbreak'
char_u *wo_stl;
#define w_p_stl w_onebuf_opt.wo_stl // 'statusline'
+ char *wo_wbr;
+#define w_p_wbr w_onebuf_opt.wo_wbr // 'winbar'
int wo_scb;
#define w_p_scb w_onebuf_opt.wo_scb // 'scrollbind'
int wo_diff_saved; // options were saved for starting diff mode
@@ -1235,6 +1237,7 @@ struct window_S {
struct {
int stl;
int stlnc;
+ int wbr;
int horiz;
int horizup;
int horizdown;
@@ -1282,14 +1285,20 @@ struct window_S {
//
int w_winrow; // first row of window in screen
int w_height; // number of rows in window, excluding
- // status/command/winbar line(s)
+ // status/command line(s)
int w_status_height; // number of status lines (0 or 1)
+ int w_winbar_height; // number of window bars (0 or 1)
int w_wincol; // Leftmost column of window in screen.
int w_width; // Width of window, excluding separation.
int w_hsep_height; // Number of horizontal separator rows (0 or 1)
int w_vsep_width; // Number of vertical separator columns (0 or 1).
pos_save_T w_save_cursor; // backup of cursor pos and topline
+ int w_winrow_off; ///< offset from winrow to the inner window area
+ int w_wincol_off; ///< offset from wincol to the inner window area
+ ///< this includes float border but excludes special columns
+ ///< implemented in win_line() (i.e. signs, folds, numbers)
+
// inner size of window, which can be overridden by external UI
int w_height_inner;
int w_width_inner;
@@ -1379,6 +1388,7 @@ struct window_S {
linenr_T w_redraw_top; // when != 0: first line needing redraw
linenr_T w_redraw_bot; // when != 0: last line needing redraw
bool w_redr_status; // if true status line must be redrawn
+ bool w_redr_winbar; // if true window bar must be redrawn
bool w_redr_border; // if true border must be redrawn
// remember what is shown in the ruler for this window (if 'ruler' set)
@@ -1408,6 +1418,7 @@ struct window_S {
// A few options have local flags for P_INSECURE.
uint32_t w_p_stl_flags; // flags for 'statusline'
+ uint32_t w_p_wbr_flags; // flags for 'winbar'
uint32_t w_p_fde_flags; // flags for 'foldexpr'
uint32_t w_p_fdt_flags; // flags for 'foldtext'
int *w_p_cc_cols; // array of columns to highlight or NULL
diff --git a/src/nvim/change.c b/src/nvim/change.c
index 94e5a19edc..349f74e280 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -1033,8 +1033,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
// If 'autoindent' and/or 'smartindent' is set, try to figure out what
// indent to use for the new line.
- if (curbuf->b_p_ai
- || do_si) {
+ if (curbuf->b_p_ai || do_si) {
// count white space on current line
newindent = get_indent_str_vtab(saved_line,
curbuf->b_p_ts,
@@ -1482,8 +1481,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
}
// Recompute the indent, it may have changed.
- if (curbuf->b_p_ai
- || do_si) {
+ if (curbuf->b_p_ai || do_si) {
newindent = get_indent_str_vtab(leader,
curbuf->b_p_ts,
curbuf->b_p_vts_array, false);
@@ -1526,15 +1524,13 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
// if a new indent will be set below, remove the indent that
// is in the comment leader
- if (newindent
- || did_si) {
+ if (newindent || did_si) {
while (lead_len && ascii_iswhite(*leader)) {
lead_len--;
newcol--;
leader++;
}
}
-
did_si = can_si = false;
} else if (comment_end != NULL) {
// We have finished a comment, so we don't use the leader.
@@ -1646,8 +1642,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
}
inhibit_delete_count++;
- if (newindent
- || did_si) {
+ if (newindent || did_si) {
curwin->w_cursor.lnum++;
if (did_si) {
int sw = get_sw_value(curbuf);
@@ -1764,6 +1759,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
} else {
vreplace_mode = 0;
}
+
// May do lisp indenting.
if (!p_paste
&& leader == NULL
@@ -1772,11 +1768,13 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
fixthisline(get_lisp_indent);
ai_col = (colnr_T)getwhitecols_curline();
}
+
// May do indenting after opening a new line.
if (do_cindent) {
do_c_expr_indent();
ai_col = (colnr_T)getwhitecols_curline();
}
+
if (vreplace_mode != 0) {
State = vreplace_mode;
}
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index aa77c03b48..593a358b62 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -1632,7 +1632,7 @@ void edit_putchar(int c, bool highlight)
pc_col = 0;
pc_status = PC_STATUS_UNSET;
if (curwin->w_p_rl) {
- pc_col += curwin->w_grid.Columns - 1 - curwin->w_wcol;
+ pc_col += curwin->w_grid.cols - 1 - curwin->w_wcol;
const int fix_col = grid_fix_col(&curwin->w_grid, pc_col, pc_row);
if (fix_col != pc_col) {
@@ -1759,7 +1759,7 @@ void display_dollar(colnr_T col)
char_u *p = get_cursor_line_ptr();
curwin->w_cursor.col -= utf_head_off(p, p + col);
curs_columns(curwin, false); // Recompute w_wrow and w_wcol
- if (curwin->w_wcol < curwin->w_grid.Columns) {
+ if (curwin->w_wcol < curwin->w_grid.cols) {
edit_putchar('$', false);
dollar_vcol = curwin->w_virtcol;
}
@@ -3799,6 +3799,7 @@ static bool ins_compl_prep(int c)
}
bool want_cindent = (can_cindent && cindent_on());
+
// When completing whole lines: fix indent for 'cindent'.
// Otherwise, break line if it's too long.
if (compl_cont_mode == CTRL_X_WHOLE_LINE) {
@@ -8412,9 +8413,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
mincol = 0;
// keep indent
if (mode == BACKSPACE_LINE
- && (curbuf->b_p_ai
- || cindent_on()
- )
+ && (curbuf->b_p_ai || cindent_on())
&& !revins_on) {
save_col = curwin->w_cursor.col;
beginline(BL_WHITE);
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 9c2069663d..641dcae55e 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -6405,7 +6405,7 @@ dict_T *get_win_info(win_T *wp, int16_t tpnr, int16_t winnr)
tv_dict_add_nr(dict, S_LEN("winrow"), wp->w_winrow + 1);
tv_dict_add_nr(dict, S_LEN("topline"), wp->w_topline);
tv_dict_add_nr(dict, S_LEN("botline"), wp->w_botline - 1);
- tv_dict_add_nr(dict, S_LEN("winbar"), 0);
+ tv_dict_add_nr(dict, S_LEN("winbar"), wp->w_winbar_height);
tv_dict_add_nr(dict, S_LEN("width"), wp->w_width);
tv_dict_add_nr(dict, S_LEN("bufnr"), wp->w_buffer->b_fnum);
tv_dict_add_nr(dict, S_LEN("wincol"), wp->w_wincol + 1);
@@ -6865,8 +6865,8 @@ void screenchar_adjust_grid(ScreenGrid **grid, int *row, int *col)
// have its own buffer, this should just read from it instead.
msg_scroll_flush();
if (msg_grid.chars && msg_grid.comp_index > 0 && *row >= msg_grid.comp_row
- && *row < (msg_grid.Rows + msg_grid.comp_row)
- && *col < msg_grid.Columns) {
+ && *row < (msg_grid.rows + msg_grid.comp_row)
+ && *col < msg_grid.cols) {
*grid = &msg_grid;
*row -= msg_grid.comp_row;
}
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 68c2e37f22..6fa5aac2d6 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -90,11 +90,13 @@ typedef enum {
# pragma function(floor)
# endif
+// uncrustify:off
PRAGMA_DIAG_PUSH_IGNORE_MISSING_PROTOTYPES
PRAGMA_DIAG_PUSH_IGNORE_IMPLICIT_FALLTHROUGH
# include "funcs.generated.h"
PRAGMA_DIAG_POP
PRAGMA_DIAG_POP
+// uncrustify:on
#endif
@@ -3611,8 +3613,8 @@ static void f_getmousepos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// necessary for a top border since `row` starts at -1 in that case.
if (row < height + wp->w_border_adj[2]) {
winid = wp->handle;
- winrow = row + 1 + wp->w_border_adj[0]; // Adjust by 1 for top border
- wincol = col + 1 + wp->w_border_adj[3]; // Adjust by 1 for left border
+ winrow = row + 1 + wp->w_winrow_off; // Adjust by 1 for top border
+ wincol = col + 1 + wp->w_wincol_off; // Adjust by 1 for left border
if (row >= 0 && row < wp->w_height && col >= 0 && col < wp->w_width) {
(void)mouse_comp_pos(wp, &row, &col, &lnum);
col = vcol2col(wp, lnum, col);
@@ -8047,8 +8049,8 @@ static void f_screenattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
int col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
- if (row < 0 || row >= default_grid.Rows
- || col < 0 || col >= default_grid.Columns) {
+ if (row < 0 || row >= default_grid.rows
+ || col < 0 || col >= default_grid.cols) {
c = -1;
} else {
ScreenGrid *grid = &default_grid;
@@ -8065,8 +8067,8 @@ static void f_screenchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int row = tv_get_number_chk(&argvars[0], NULL) - 1;
int col = tv_get_number_chk(&argvars[1], NULL) - 1;
- if (row < 0 || row >= default_grid.Rows
- || col < 0 || col >= default_grid.Columns) {
+ if (row < 0 || row >= default_grid.rows
+ || col < 0 || col >= default_grid.cols) {
c = -1;
} else {
ScreenGrid *grid = &default_grid;
@@ -8081,8 +8083,8 @@ static void f_screenchars(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int row = tv_get_number_chk(&argvars[0], NULL) - 1;
int col = tv_get_number_chk(&argvars[1], NULL) - 1;
- if (row < 0 || row >= default_grid.Rows
- || col < 0 || col >= default_grid.Columns) {
+ if (row < 0 || row >= default_grid.rows
+ || col < 0 || col >= default_grid.cols) {
tv_list_alloc_ret(rettv, 0);
return;
}
@@ -8148,8 +8150,8 @@ static void f_screenstring(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->v_type = VAR_STRING;
int row = tv_get_number_chk(&argvars[0], NULL) - 1;
int col = tv_get_number_chk(&argvars[1], NULL) - 1;
- if (row < 0 || row >= default_grid.Rows
- || col < 0 || col >= default_grid.Columns) {
+ if (row < 0 || row >= default_grid.rows
+ || col < 0 || col >= default_grid.cols) {
return;
}
ScreenGrid *grid = &default_grid;
@@ -10790,10 +10792,16 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// "/home/foo/…" => "~/…"
size_t len = home_replace(NULL, NameBuff, IObuff, sizeof(IObuff), true);
// Trim slash.
- if (IObuff[len - 1] == '\\' || IObuff[len - 1] == '/') {
+ if (len != 1 && (IObuff[len - 1] == '\\' || IObuff[len - 1] == '/')) {
IObuff[len - 1] = '\0';
}
+ if (len == 1 && IObuff[0] == '/') {
+ // Avoid ambiguity in the URI when CWD is root directory.
+ IObuff[1] = '.';
+ IObuff[2] = '\0';
+ }
+
// Terminal URI: "term://$CWD//$PID:$CMD"
snprintf((char *)NameBuff, sizeof(NameBuff), "term://%s//%d:%s",
(char *)IObuff, pid, cmd);
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index e5f48501f7..2059d423d5 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -3598,5 +3598,6 @@ char_u *register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state)
STRCPY(fp->uf_name, name);
hash_add(&func_hashtab, UF2HIKEY(fp));
+ // coverity[leaked_storage]
return fp->uf_name;
}
diff --git a/src/nvim/event/loop.c b/src/nvim/event/loop.c
index 89fced59c5..d4e20e2f66 100644
--- a/src/nvim/event/loop.c
+++ b/src/nvim/event/loop.c
@@ -143,7 +143,7 @@ bool loop_close(Loop *loop, bool wait)
while (true) {
// Run the loop to tickle close-callbacks (which should then free memory).
// Use UV_RUN_NOWAIT to avoid a hang. #11820
- uv_run(&loop->uv, didstop ? UV_RUN_DEFAULT : UV_RUN_NOWAIT);
+ uv_run(&loop->uv, didstop ? UV_RUN_DEFAULT : UV_RUN_NOWAIT); // -V547
if ((uv_loop_close(&loop->uv) != UV_EBUSY) || !wait) {
break;
}
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 8369db7de1..ce3afba19b 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -971,7 +971,11 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
*/
last_line = curbuf->b_ml.ml_line_count;
mark_adjust_nofold(line1, line2, last_line - line2, 0L, kExtmarkNOOP);
+
+ disable_fold_update++;
changed_lines(last_line - num_lines + 1, 0, last_line + 1, num_lines, false);
+ disable_fold_update--;
+
int line_off = 0;
bcount_t byte_off = 0;
if (dest >= line2) {
@@ -1005,7 +1009,9 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
mark_adjust_nofold(last_line - num_lines + 1, last_line,
-(last_line - dest - extra), 0L, kExtmarkNOOP);
+ disable_fold_update++;
changed_lines(last_line - num_lines + 1, 0, last_line + 1, -extra, false);
+ disable_fold_update--;
// send update regarding the new lines that were added
buf_updates_send_changes(curbuf, dest + 1, num_lines, 0, true);
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index e845073c12..5f9d73a25a 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -345,7 +345,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags)
// here. The value of 200 allows nested function calls, ":source", etc.
// Allow 200 or 'maxfuncdepth', whatever is larger.
if (call_depth >= 200 && call_depth >= p_mfd) {
- emsg(_("E169: Command too recursive"));
+ emsg(_(e_command_too_recursive));
// When converting to an exception, we do not include the command name
// since this is not an error of the specific command.
do_errthrow((cstack_T *)NULL, NULL);
@@ -1583,13 +1583,14 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er
/// @param cmdinfo Command parse information
void execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo)
{
+ char *errormsg = NULL;
+
#define ERROR(msg) \
do { \
- emsg(msg); \
+ errormsg = msg; \
goto end; \
} while (0)
- char *errormsg = NULL;
cmdmod_T save_cmdmod = cmdmod;
cmdmod = cmdinfo->cmdmod;
@@ -1648,7 +1649,7 @@ void execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo)
// If filename expansion is enabled, expand filenames
if (cmdinfo->magic.file) {
if (expand_filename(eap, (char_u **)eap->cmdlinep, &errormsg) == FAIL) {
- ERROR(errormsg);
+ goto end;
}
}
@@ -1683,14 +1684,13 @@ void execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo)
(eap->argt & EX_BUFUNL) != 0, false, false);
eap->addr_count = 1;
// Shift each argument by 1
- if (eap->args != NULL) {
- for (size_t i = 0; i < eap->argc - 1; i++) {
- eap->args[i] = eap->args[i + 1];
- }
- // Make the last argument point to the NUL terminator at the end of string
- eap->args[eap->argc - 1] = eap->args[eap->argc - 1] + eap->arglens[eap->argc - 1];
- eap->argc -= 1;
+ for (size_t i = 0; i < eap->argc - 1; i++) {
+ eap->args[i] = eap->args[i + 1];
}
+ // Make the last argument point to the NUL terminator at the end of string
+ eap->args[eap->argc - 1] = eap->args[eap->argc - 1] + eap->arglens[eap->argc - 1];
+ eap->argc -= 1;
+
eap->arg = eap->args[0];
}
if (eap->line2 < 0) { // failed
@@ -1707,14 +1707,20 @@ void execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo)
eap->errmsg = NULL;
(cmdnames[eap->cmdidx].cmd_func)(eap);
if (eap->errmsg != NULL) {
- ERROR(_(eap->errmsg));
+ errormsg = _(eap->errmsg);
}
}
+
end:
+ if (errormsg != NULL && *errormsg != NUL) {
+ emsg(errormsg);
+ }
// Undo command modifiers
undo_cmdmod(eap, msg_scroll);
cmdmod = save_cmdmod;
-
+ if (eap->did_sandbox) {
+ sandbox--;
+ }
#undef ERROR
}
@@ -8831,7 +8837,7 @@ static void ex_redraw(exarg_T *eap)
ui_flush();
}
-/// ":redrawstatus": force redraw of status line(s)
+/// ":redrawstatus": force redraw of status line(s) and window bar(s)
static void ex_redrawstatus(exarg_T *eap)
{
if (State & MODE_CMDPREVIEW) {
@@ -8847,8 +8853,7 @@ static void ex_redrawstatus(exarg_T *eap)
} else {
status_redraw_curbuf();
}
- update_screen(VIsual_active ? INVERTED :
- 0);
+ update_screen(VIsual_active ? INVERTED : 0);
RedrawingDisabled = r;
p_lz = p;
ui_flush();
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 114f1e2ae5..1d496cbf25 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -804,6 +804,12 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init
ccline.cmdlen = s->indent;
}
+ if (cmdline_level == 50) {
+ // Somehow got into a loop recursively calling getcmdline(), bail out.
+ emsg(_(e_command_too_recursive));
+ goto theend;
+ }
+
ExpandInit(&s->xpc);
ccline.xpc = &s->xpc;
@@ -995,12 +1001,13 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init
State = s->save_State;
setmouse();
ui_cursor_shape(); // may show different cursor shape
+ sb_text_end_cmdline();
+
+theend:
xfree(s->save_p_icm);
xfree(ccline.last_colors.cmdbuff);
kv_destroy(ccline.last_colors.colors);
- sb_text_end_cmdline();
-
char_u *p = ccline.cmdbuff;
if (ui_has(kUICmdline)) {
diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c
index 7eef6707dd..3b6f7b90bf 100644
--- a/src/nvim/ex_session.c
+++ b/src/nvim/ex_session.c
@@ -181,6 +181,10 @@ static bool ses_do_frame(const frame_T *fr)
/// @return non-zero if window "wp" is to be stored in the Session.
static int ses_do_win(win_T *wp)
{
+ // Skip floating windows to avoid issues when restoring the Session. #18432
+ if (wp->w_floating) {
+ return false;
+ }
if (wp->w_buffer->b_fname == NULL
// When 'buftype' is "nofile" can't restore the window contents.
|| (!wp->w_buffer->terminal && bt_nofile(wp->w_buffer))) {
@@ -598,9 +602,14 @@ static int makeopens(FILE *fd, char_u *dirnow)
PUTLINE_FAIL("let s:shortmess_save = &shortmess");
}
- // Now save the current files, current buffer first.
- PUTLINE_FAIL("set shortmess=aoO");
+ // set 'shortmess' for the following. Add the 'A' flag if it was there
+ PUTLINE_FAIL("if &shortmess =~ 'A'");
+ PUTLINE_FAIL(" set shortmess=aoOA");
+ PUTLINE_FAIL("else");
+ PUTLINE_FAIL(" set shortmess=aoO");
+ PUTLINE_FAIL("endif");
+ // Now save the current files, current buffer first.
// Put all buffers into the buffer list.
// Do it very early to preserve buffer order after loading session (which
// can be disrupted by prior `edit` or `tabedit` calls).
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 090f754e93..9c8e92cd00 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -775,7 +775,7 @@ void clearFolding(win_T *win)
/// The changes in lines from top to bot (inclusive).
void foldUpdate(win_T *wp, linenr_T top, linenr_T bot)
{
- if (compl_busy || State & MODE_INSERT) {
+ if (disable_fold_update || compl_busy || State & MODE_INSERT) {
return;
}
@@ -785,11 +785,18 @@ void foldUpdate(win_T *wp, linenr_T top, linenr_T bot)
}
if (wp->w_folds.ga_len > 0) {
- // Mark all folds from top to bot as maybe-small.
+ linenr_T maybe_small_start = top;
+ linenr_T maybe_small_end = bot;
+
+ // Mark all folds from top to bot (or bot to top) as maybe-small.
+ if (top > bot) {
+ maybe_small_start = bot;
+ maybe_small_end = top;
+ }
fold_T *fp;
- (void)foldFind(&wp->w_folds, top, &fp);
+ (void)foldFind(&wp->w_folds, maybe_small_start, &fp);
while (fp < (fold_T *)wp->w_folds.ga_data + wp->w_folds.ga_len
- && fp->fd_top < bot) {
+ && fp->fd_top <= maybe_small_end) {
fp->fd_small = kNone;
fp++;
}
@@ -1929,7 +1936,7 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot)
bot = wp->w_buffer->b_ml.ml_line_count;
wp->w_foldinvalid = false;
- // Mark all folds a maybe-small.
+ // Mark all folds as maybe-small.
setSmallMaybe(&wp->w_folds);
}
@@ -1996,7 +2003,7 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot)
// start one line back, because a "<1" may indicate the end of a
// fold in the topline
if (top > 1) {
- --fline.lnum;
+ fline.lnum--;
}
} else if (foldmethodIsSyntax(wp)) {
getlevel = foldlevelSyntax;
@@ -2004,6 +2011,12 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot)
getlevel = foldlevelDiff;
} else {
getlevel = foldlevelIndent;
+ // Start one line back, because if the line above "top" has an
+ // undefined fold level, folding it relies on the line under it,
+ // which is "top".
+ if (top > 1) {
+ fline.lnum--;
+ }
}
// Backup to a line for which the fold level is defined. Since it's
diff --git a/src/nvim/fold.h b/src/nvim/fold.h
index 6b29214760..60ea4b322e 100644
--- a/src/nvim/fold.h
+++ b/src/nvim/fold.h
@@ -23,6 +23,7 @@ typedef struct foldinfo {
#define FOLDINFO_INIT { 0, 0, 0, 0 }
+EXTERN int disable_fold_update INIT(= 0);
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "fold.h.generated.h"
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 2cc068b30d..8881263d1c 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -1881,8 +1881,7 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth)
if (no_mapping == 0 && maphash_valid
&& (no_zero_mapping == 0 || tb_c1 != '0')
&& (typebuf.tb_maplen == 0 || is_plug_map
- || (p_remap
- && !(typebuf.tb_noremap[typebuf.tb_off] & (RM_NONE|RM_ABBR))))
+ || (!(typebuf.tb_noremap[typebuf.tb_off] & (RM_NONE|RM_ABBR))))
&& !(p_paste && (State & (MODE_INSERT | MODE_CMDLINE)))
&& !(State == MODE_HITRETURN && (tb_c1 == CAR || tb_c1 == ' '))
&& State != MODE_ASKMORE
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index e34e3983db..1819af7ee4 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -84,7 +84,7 @@ EXTERN struct nvim_stats_s {
// 0 not starting anymore
// Number of Rows and Columns in the screen.
-// Note: Use default_grid.Rows and default_grid.Columns to access items in
+// Note: Use default_grid.rows and default_grid.cols to access items in
// default_grid.chars[]. They may have different values when the screen
// wasn't (re)allocated yet after setting Rows or Columns (e.g., when starting
// up).
@@ -421,10 +421,6 @@ EXTERN vimmenu_T *root_menu INIT(= NULL);
// overruling of menus that the user already defined.
EXTERN int sys_menu INIT(= false);
-// While redrawing the screen this flag is set. It means the screen size
-// ('lines' and 'rows') must not be changed.
-EXTERN int updating_screen INIT(= 0);
-
// All windows are linked in a list. firstwin points to the first entry,
// lastwin to the last entry (can be the same as firstwin) and curwin to the
// currently active window.
@@ -877,7 +873,8 @@ EXTERN char e_api_spawn_failed[] INIT(= N_("E903: Could not spawn API job"));
EXTERN char e_argreq[] INIT(= N_("E471: Argument required"));
EXTERN char e_backslash[] INIT(= N_("E10: \\ should be followed by /, ? or &"));
EXTERN char e_cmdwin[] INIT(= N_("E11: Invalid in command-line window; <CR> executes, CTRL-C quits"));
-EXTERN char e_curdir[] INIT(= N_( "E12: Command not allowed from exrc/vimrc in current dir or tag search"));
+EXTERN char e_curdir[] INIT(= N_("E12: Command not allowed from exrc/vimrc in current dir or tag search"));
+EXTERN char e_command_too_recursive[] INIT(= N_("E169: Command too recursive"));
EXTERN char e_endif[] INIT(= N_("E171: Missing :endif"));
EXTERN char e_endtry[] INIT(= N_("E600: Missing :endtry"));
EXTERN char e_endwhile[] INIT(= N_("E170: Missing :endwhile"));
diff --git a/src/nvim/grid.c b/src/nvim/grid.c
index 8a5d8081c0..d241f86d1c 100644
--- a/src/nvim/grid.c
+++ b/src/nvim/grid.c
@@ -4,6 +4,7 @@
#include "nvim/arabic.h"
#include "nvim/grid.h"
#include "nvim/highlight.h"
+#include "nvim/screen.h"
#include "nvim/ui.h"
#include "nvim/vim.h"
@@ -63,7 +64,7 @@ void grid_clear_line(ScreenGrid *grid, size_t off, int width, bool valid)
void grid_invalidate(ScreenGrid *grid)
{
- (void)memset(grid->attrs, -1, sizeof(sattr_T) * (size_t)(grid->Rows * grid->Columns));
+ (void)memset(grid->attrs, -1, sizeof(sattr_T) * (size_t)grid->rows * (size_t)grid->cols);
}
bool grid_invalid_row(ScreenGrid *grid, int row)
@@ -92,7 +93,7 @@ bool grid_lefthalve(ScreenGrid *grid, int row, int col)
grid_adjust(&grid, &row, &col);
return grid_off2cells(grid, grid->line_offset[row] + (size_t)col,
- grid->line_offset[row] + (size_t)grid->Columns) > 1;
+ grid->line_offset[row] + (size_t)grid->cols) > 1;
}
/// Correct a position on the screen, if it's the right half of a double-wide
@@ -128,7 +129,7 @@ void grid_getbytes(ScreenGrid *grid, int row, int col, char_u *bytes, int *attrp
grid_adjust(&grid, &row, &col);
// safety check
- if (grid->chars != NULL && row < grid->Rows && col < grid->Columns) {
+ if (grid->chars != NULL && row < grid->rows && col < grid->cols) {
off = grid->line_offset[row] + (size_t)col;
*attrp = grid->attrs[off];
schar_copy(bytes, grid->chars[off]);
@@ -202,8 +203,8 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, int col
// Safety check. The check for negative row and column is to fix issue
// vim/vim#4102. TODO(neovim): find out why row/col could be negative.
if (grid->chars == NULL
- || row >= grid->Rows || row < 0
- || col >= grid->Columns || col < 0) {
+ || row >= grid->rows || row < 0
+ || col >= grid->cols || col < 0) {
return;
}
@@ -225,8 +226,8 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, int col
put_dirty_last = MAX(put_dirty_last, 1);
}
- max_off = grid->line_offset[row] + (size_t)grid->Columns;
- while (col < grid->Columns
+ max_off = grid->line_offset[row] + (size_t)grid->cols;
+ while (col < grid->cols
&& (len < 0 || (int)(ptr - text) < len)
&& *ptr != NUL) {
c = *ptr;
@@ -259,7 +260,7 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, int col
} else {
prev_c = u8c;
}
- if (col + mbyte_cells > grid->Columns) {
+ if (col + mbyte_cells > grid->cols) {
// Only 1 cell left, but character requires 2 cells:
// display a '>' in the last column to avoid wrapping. */
c = '>';
@@ -338,7 +339,7 @@ void grid_puts_line_flush(bool set_cursor)
if (put_dirty_first < put_dirty_last) {
if (set_cursor) {
ui_grid_cursor_goto(put_dirty_grid->handle, put_dirty_row,
- MIN(put_dirty_last, put_dirty_grid->Columns - 1));
+ MIN(put_dirty_last, put_dirty_grid->cols - 1));
}
if (!put_dirty_grid->throttled) {
ui_line(put_dirty_grid, put_dirty_row, put_dirty_first, put_dirty_last,
@@ -371,11 +372,11 @@ void grid_fill(ScreenGrid *grid, int start_row, int end_row, int start_col, int
end_col += col_off;
// safety check
- if (end_row > grid->Rows) {
- end_row = grid->Rows;
+ if (end_row > grid->rows) {
+ end_row = grid->rows;
}
- if (end_col > grid->Columns) {
- end_col = grid->Columns;
+ if (end_col > grid->cols) {
+ end_col = grid->cols;
}
// nothing to do
@@ -391,7 +392,7 @@ void grid_fill(ScreenGrid *grid, int start_row, int end_row, int start_col, int
if (start_col > 0 && grid_fix_col(grid, start_col, row) != start_col) {
grid_puts_len(grid, (char_u *)" ", 1, row, start_col - 1, 0);
}
- if (end_col < grid->Columns
+ if (end_col < grid->cols
&& grid_fix_col(grid, end_col, row) != end_col) {
grid_puts_len(grid, (char_u *)" ", 1, row, end_col, 0);
}
@@ -443,7 +444,7 @@ void grid_fill(ScreenGrid *grid, int start_row, int end_row, int start_col, int
}
}
- if (end_col == grid->Columns) {
+ if (end_col == grid->cols) {
grid->line_wraps[row] = false;
}
}
@@ -491,17 +492,17 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int cle
// TODO(bfredl): check all callsites and eliminate
// Check for illegal row and col, just in case
- if (row >= grid->Rows) {
- row = grid->Rows - 1;
+ if (row >= grid->rows) {
+ row = grid->rows - 1;
}
- if (endcol > grid->Columns) {
- endcol = grid->Columns;
+ if (endcol > grid->cols) {
+ endcol = grid->cols;
}
grid_adjust(&grid, &row, &coloff);
// Safety check. Avoids clang warnings down the call stack.
- if (grid->chars == NULL || row >= grid->Rows || coloff >= grid->Columns) {
+ if (grid->chars == NULL || row >= grid->rows || coloff >= grid->cols) {
DLOG("invalid state, skipped");
return;
}
@@ -509,7 +510,7 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int cle
size_t off_from = 0;
size_t off_to = grid->line_offset[row] + (size_t)coloff;
max_off_from = linebuf_size;
- max_off_to = grid->line_offset[row] + (size_t)grid->Columns;
+ max_off_to = grid->line_offset[row] + (size_t)grid->cols;
if (rlflag) {
// Clear rest first, because it's left of the text.
@@ -617,7 +618,7 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int cle
}
}
- if (clear_width > 0 || wp->w_width != grid->Columns) {
+ if (clear_width > 0 || wp->w_width != grid->cols) {
// If we cleared after the end of the line, it did not wrap.
// For vsplit, line wrapping is not possible.
grid->line_wraps[row] = false;
@@ -646,11 +647,11 @@ void grid_alloc(ScreenGrid *grid, int rows, int columns, bool copy, bool valid)
new.line_offset = xmalloc((size_t)rows * sizeof(*new.line_offset));
new.line_wraps = xmalloc((size_t)rows * sizeof(*new.line_wraps));
- new.Rows = rows;
- new.Columns = columns;
+ new.rows = rows;
+ new.cols = columns;
- for (new_row = 0; new_row < new.Rows; new_row++) {
- new.line_offset[new_row] = (size_t)new_row * (size_t)new.Columns;
+ for (new_row = 0; new_row < new.rows; new_row++) {
+ new.line_offset[new_row] = (size_t)new_row * (size_t)new.cols;
new.line_wraps[new_row] = false;
grid_clear_line(&new, new.line_offset[new_row], columns, valid);
@@ -660,8 +661,8 @@ void grid_alloc(ScreenGrid *grid, int rows, int columns, bool copy, bool valid)
// possible from the old screen to the new one and clear the rest
// (used when resizing the window at the "--more--" prompt or when
// executing an external command, for the GUI).
- if (new_row < grid->Rows && grid->chars != NULL) {
- int len = MIN(grid->Columns, new.Columns);
+ if (new_row < grid->rows && grid->chars != NULL) {
+ int len = MIN(grid->cols, new.cols);
memmove(new.chars + new.line_offset[new_row],
grid->chars + grid->line_offset[new_row],
(size_t)len * sizeof(schar_T));
@@ -705,3 +706,83 @@ void grid_free_all_mem(void)
xfree(linebuf_char);
xfree(linebuf_attr);
}
+
+/// (Re)allocates a window grid if size changed while in ext_multigrid mode.
+/// Updates size, offsets and handle for the grid regardless.
+///
+/// If "doclear" is true, don't try to copy from the old grid rather clear the
+/// resized grid.
+void win_grid_alloc(win_T *wp)
+{
+ ScreenGrid *grid = &wp->w_grid;
+ ScreenGrid *grid_allocated = &wp->w_grid_alloc;
+
+ int rows = wp->w_height_inner;
+ int cols = wp->w_width_inner;
+ int total_rows = wp->w_height_outer;
+ int total_cols = wp->w_width_outer;
+
+ bool want_allocation = ui_has(kUIMultigrid) || wp->w_floating;
+ bool has_allocation = (grid_allocated->chars != NULL);
+
+ if (grid->rows != rows) {
+ wp->w_lines_valid = 0;
+ xfree(wp->w_lines);
+ wp->w_lines = xcalloc((size_t)rows + 1, sizeof(wline_T));
+ }
+
+ int was_resized = false;
+ if (want_allocation && (!has_allocation
+ || grid_allocated->rows != total_rows
+ || grid_allocated->cols != total_cols)) {
+ grid_alloc(grid_allocated, total_rows, total_cols,
+ wp->w_grid_alloc.valid, false);
+ grid_allocated->valid = true;
+ if (wp->w_floating && wp->w_float_config.border) {
+ wp->w_redr_border = true;
+ }
+ was_resized = true;
+ } else if (!want_allocation && has_allocation) {
+ // Single grid mode, all rendering will be redirected to default_grid.
+ // Only keep track of the size and offset of the window.
+ grid_free(grid_allocated);
+ grid_allocated->valid = false;
+ was_resized = true;
+ } else if (want_allocation && has_allocation && !wp->w_grid_alloc.valid) {
+ grid_invalidate(grid_allocated);
+ grid_allocated->valid = true;
+ }
+
+ grid->rows = rows;
+ grid->cols = cols;
+
+ if (want_allocation) {
+ grid->target = grid_allocated;
+ grid->row_offset = wp->w_winrow_off;
+ grid->col_offset = wp->w_wincol_off;
+ } else {
+ grid->target = &default_grid;
+ grid->row_offset = wp->w_winrow + wp->w_winrow_off;
+ grid->col_offset = wp->w_wincol + wp->w_wincol_off;
+ }
+
+ // send grid resize event if:
+ // - a grid was just resized
+ // - screen_resize was called and all grid sizes must be sent
+ // - the UI wants multigrid event (necessary)
+ if ((resizing_screen || was_resized) && want_allocation) {
+ ui_call_grid_resize(grid_allocated->handle,
+ grid_allocated->cols, grid_allocated->rows);
+ }
+}
+
+/// assign a handle to the grid. The grid need not be allocated.
+void grid_assign_handle(ScreenGrid *grid)
+{
+ static int last_grid_handle = DEFAULT_GRID_HANDLE;
+
+ // only assign a grid handle if not already
+ if (grid->handle == 0) {
+ grid->handle = ++last_grid_handle;
+ }
+}
diff --git a/src/nvim/grid_defs.h b/src/nvim/grid_defs.h
index 2516ea52a7..a97a1c2c39 100644
--- a/src/nvim/grid_defs.h
+++ b/src/nvim/grid_defs.h
@@ -58,8 +58,8 @@ struct ScreenGrid {
int *dirty_col;
// the size of the allocated grid.
- int Rows;
- int Columns;
+ int rows;
+ int cols;
// The state of the grid is valid. Otherwise it needs to be redrawn.
bool valid;
diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h
index 0515842b61..d293865efd 100644
--- a/src/nvim/highlight_defs.h
+++ b/src/nvim/highlight_defs.h
@@ -111,7 +111,9 @@ typedef enum {
HLF_NFLOAT, // Floating window
HLF_MSG, // Message area
HLF_BORDER, // Floating window border
- HLF_COUNT, // MUST be the last one
+ HLF_WBR, // Window bars
+ HLF_WBRNC, // Window bars of not-current windows
+ HLF_COUNT, // MUST be the last one
} hlf_T;
EXTERN const char *hlf_names[] INIT(= {
@@ -172,6 +174,8 @@ EXTERN const char *hlf_names[] INIT(= {
[HLF_NFLOAT] = "NormalFloat",
[HLF_MSG] = "MsgArea",
[HLF_BORDER] = "FloatBorder",
+ [HLF_WBR] = "WinBar",
+ [HLF_WBRNC] = "WinBarNC",
});
diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c
index 240a96cb4b..0047cb02d6 100644
--- a/src/nvim/highlight_group.c
+++ b/src/nvim/highlight_group.c
@@ -103,9 +103,11 @@ static const char *highlight_init_both[] = {
"TabLineFill cterm=reverse gui=reverse",
"TabLineSel cterm=bold gui=bold",
"TermCursor cterm=reverse gui=reverse",
+ "WinBar cterm=bold gui=bold",
"WildMenu ctermbg=Yellow ctermfg=Black guibg=Yellow guifg=Black",
"default link VertSplit Normal",
"default link WinSeparator VertSplit",
+ "default link WinBarNC WinBar",
"default link EndOfBuffer NonText",
"default link LineNrAbove LineNr",
"default link LineNrBelow LineNr",
diff --git a/src/nvim/math.c b/src/nvim/math.c
index 63a29509bd..04ded0fd39 100644
--- a/src/nvim/math.c
+++ b/src/nvim/math.c
@@ -1,7 +1,9 @@
// 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
+// uncrustify:off
#include <math.h>
+// uncrustify:on
#include <stdint.h>
#include <string.h>
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index 3868d65ab9..adf071fa77 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -473,27 +473,12 @@ static bool intable(const struct interval *table, size_t n_items, int c)
int utf_char2cells(int c)
{
if (c >= 0x100) {
-#ifdef USE_WCHAR_FUNCTIONS
- //
- // Assume the library function wcwidth() works better than our own
- // stuff. It should return 1 for ambiguous width chars!
- //
- int n = wcwidth(c);
-
- if (n < 0) {
- return 6; // unprintable, displays <xxxx>
- }
- if (n > 1) {
- return n;
- }
-#else
if (!utf_printable(c)) {
return 6; // unprintable, displays <xxxx>
}
if (intable(doublewidth, ARRAY_SIZE(doublewidth), c)) {
return 2;
}
-#endif
if (p_emoji && intable(emoji_width, ARRAY_SIZE(emoji_width), c)) {
return 2;
}
@@ -1061,12 +1046,6 @@ bool utf_iscomposing(int c)
*/
bool utf_printable(int c)
{
-#ifdef USE_WCHAR_FUNCTIONS
- /*
- * Assume the iswprint() library function works better than our own stuff.
- */
- return iswprint(c);
-#else
// Sorted list of non-overlapping intervals.
// 0xd800-0xdfff is reserved for UTF-16, actually illegal.
static struct interval nonprint[] =
@@ -1077,7 +1056,6 @@ bool utf_printable(int c)
};
return !intable(nonprint, ARRAY_SIZE(nonprint), c);
-#endif
}
/*
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 9ab086f1ea..35a57b708d 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -125,6 +125,8 @@ static size_t msg_ext_cur_len = 0;
static bool msg_ext_overwrite = false; ///< will overwrite last message
static int msg_ext_visible = 0; ///< number of messages currently visible
+static bool msg_ext_history_visible = false;
+
/// Shouldn't clear message after leaving cmdline
static bool msg_ext_keep_after_cmdline = false;
@@ -162,7 +164,7 @@ void msg_grid_validate(void)
{
grid_assign_handle(&msg_grid);
bool should_alloc = msg_use_grid();
- if (should_alloc && (msg_grid.Rows != Rows || msg_grid.Columns != Columns
+ if (should_alloc && (msg_grid.rows != Rows || msg_grid.cols != Columns
|| !msg_grid.chars)) {
// TODO(bfredl): eventually should be set to "invalid". I e all callers
// will use the grid including clear to EOS if necessary.
@@ -174,9 +176,9 @@ void msg_grid_validate(void)
// Tricky: allow resize while pager is active
int pos = msg_scrolled ? msg_grid_pos : Rows - p_ch;
- ui_comp_put_grid(&msg_grid, pos, 0, msg_grid.Rows, msg_grid.Columns,
+ ui_comp_put_grid(&msg_grid, pos, 0, msg_grid.rows, msg_grid.cols,
false, true);
- ui_call_grid_resize(msg_grid.handle, msg_grid.Columns, msg_grid.Rows);
+ ui_call_grid_resize(msg_grid.handle, msg_grid.cols, msg_grid.rows);
msg_grid.throttled = false; // don't throttle in 'cmdheight' area
msg_scrolled_at_flush = msg_scrolled;
@@ -1025,6 +1027,9 @@ void ex_messages(void *const eap_p)
// Display what was not skipped.
if (ui_has(kUIMessages)) {
+ if (msg_silent) {
+ return;
+ }
Array entries = ARRAY_DICT_INIT;
for (; p != NULL; p = p->next) {
if (p->msg != NULL && p->msg[0] != NUL) {
@@ -1040,6 +1045,8 @@ void ex_messages(void *const eap_p)
}
}
ui_call_msg_history_show(entries);
+ msg_ext_history_visible = true;
+ wait_return(false);
} else {
msg_hist_off = true;
for (; p != NULL && !got_int; p = p->next) {
@@ -2320,10 +2327,10 @@ void msg_scroll_up(bool may_throttle)
if (msg_grid_pos > 0) {
msg_grid_set_pos(msg_grid_pos - 1, true);
} else {
- grid_del_lines(&msg_grid, 0, 1, msg_grid.Rows, 0, msg_grid.Columns);
+ grid_del_lines(&msg_grid, 0, 1, msg_grid.rows, 0, msg_grid.cols);
memmove(msg_grid.dirty_col, msg_grid.dirty_col + 1,
- (msg_grid.Rows - 1) * sizeof(*msg_grid.dirty_col));
- msg_grid.dirty_col[msg_grid.Rows - 1] = 0;
+ (msg_grid.rows - 1) * sizeof(*msg_grid.dirty_col));
+ msg_grid.dirty_col[msg_grid.rows - 1] = 0;
}
} else {
grid_del_lines(&msg_grid_adj, 0, 1, Rows, 0, Columns);
@@ -2356,7 +2363,7 @@ void msg_scroll_flush(void)
msg_grid.throttled = false;
int pos_delta = msg_grid_pos_at_flush - msg_grid_pos;
assert(pos_delta >= 0);
- int delta = MIN(msg_scrolled - msg_scrolled_at_flush, msg_grid.Rows);
+ int delta = MIN(msg_scrolled - msg_scrolled_at_flush, msg_grid.rows);
if (pos_delta > 0) {
ui_ext_msg_set_pos(msg_grid_pos, true);
@@ -2374,7 +2381,7 @@ void msg_scroll_flush(void)
for (int i = MAX(Rows - MAX(delta, 1), 0); i < Rows; i++) {
int row = i - msg_grid_pos;
assert(row >= 0);
- ui_line(&msg_grid, row, 0, msg_grid.dirty_col[row], msg_grid.Columns,
+ ui_line(&msg_grid, row, 0, msg_grid.dirty_col[row], msg_grid.cols,
HL_ATTR(HLF_MSG), false);
msg_grid.dirty_col[row] = 0;
}
@@ -2400,9 +2407,9 @@ void msg_reset_scroll(void)
clear_cmdline = true;
if (msg_grid.chars) {
// non-displayed part of msg_grid is considered invalid.
- for (int i = 0; i < MIN(msg_scrollsize(), msg_grid.Rows); i++) {
+ for (int i = 0; i < MIN(msg_scrollsize(), msg_grid.rows); i++) {
grid_clear_line(&msg_grid, msg_grid.line_offset[i],
- msg_grid.Columns, false);
+ msg_grid.cols, false);
}
}
} else {
@@ -3126,6 +3133,10 @@ void msg_ext_clear(bool force)
msg_ext_visible = 0;
msg_ext_overwrite = false; // nothing to overwrite
}
+ if (msg_ext_history_visible) {
+ ui_call_msg_history_clear();
+ msg_ext_history_visible = false;
+ }
// Only keep once.
msg_ext_keep_after_cmdline = false;
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index 8038ba2cad..8736c73080 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -68,12 +68,12 @@ bool is_mouse_key(int c)
/// mouse was previously on a status line, then the status line may be dragged.
///
/// If flags has MOUSE_MAY_VIS, then VIsual mode will be started before the
-/// cursor is moved unless the cursor was on a status line.
+/// cursor is moved unless the cursor was on a status line or window bar.
/// This function returns one of IN_UNKNOWN, IN_BUFFER, IN_STATUS_LINE or
/// IN_SEP_LINE depending on where the cursor was clicked.
///
/// If flags has MOUSE_MAY_STOP_VIS, then Visual mode will be stopped, unless
-/// the mouse is on the status line of the same window.
+/// the mouse is on the status line or window bar of the same window.
///
/// If flags has MOUSE_DID_MOVE, nothing is done if the mouse didn't move since
/// the last call.
@@ -87,6 +87,7 @@ int jump_to_mouse(int flags, bool *inclusive, int which_button)
{
static int on_status_line = 0; // #lines below bottom of window
static int on_sep_line = 0; // on separator right of window
+ static bool on_winbar = false;
static int prev_row = -1;
static int prev_col = -1;
static win_T *dragwin = NULL; // window being dragged
@@ -126,6 +127,9 @@ retnomove:
if (on_sep_line) {
return IN_SEP_LINE;
}
+ if (on_winbar) {
+ return IN_OTHER_WIN | MOUSE_WINBAR;
+ }
if (flags & MOUSE_MAY_STOP_VIS) {
end_visual_mode();
redraw_curbuf_later(INVERTED); // delete the inversion
@@ -156,13 +160,15 @@ retnomove:
dragwin = NULL;
if (row == -1) {
- return IN_OTHER_WIN;
+ on_winbar = wp->w_winbar_height != 0;
+ return IN_OTHER_WIN | (on_winbar ? MOUSE_WINBAR : 0);
}
+ on_winbar = false;
// winpos and height may change in win_enter()!
- if (grid == DEFAULT_GRID_HANDLE && row >= wp->w_height) {
+ if (grid == DEFAULT_GRID_HANDLE && row + wp->w_winbar_height >= wp->w_height) {
// In (or below) status line
- on_status_line = row - wp->w_height + 1;
+ on_status_line = row + wp->w_winbar_height - wp->w_height + 1;
dragwin = wp;
} else {
on_status_line = 0;
@@ -253,6 +259,9 @@ retnomove:
did_drag |= count;
}
return IN_SEP_LINE; // Cursor didn't move
+ } else if (on_winbar) {
+ // After a click on the window bar don't start Visual mode.
+ return IN_OTHER_WIN | MOUSE_WINBAR;
} else {
// keep_window_focus must be true
// before moving the cursor for a left click, stop Visual mode
@@ -264,6 +273,9 @@ retnomove:
if (grid == 0) {
row -= curwin->w_grid_alloc.comp_row + curwin->w_grid.row_offset;
col -= curwin->w_grid_alloc.comp_col + curwin->w_grid.col_offset;
+ } else if (grid != DEFAULT_GRID_HANDLE) {
+ row -= curwin->w_grid.row_offset;
+ col -= curwin->w_grid.col_offset;
}
// When clicking beyond the end of the window, scroll the screen.
@@ -497,6 +509,7 @@ win_T *mouse_find_win(int *gridp, int *rowp, int *colp)
// exist.
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp == fp->fr_win) {
+ *rowp -= wp->w_winbar_height;
return wp;
}
}
@@ -512,8 +525,8 @@ static win_T *mouse_find_grid_win(int *gridp, int *rowp, int *colp)
win_T *wp = get_win_by_grid_handle(*gridp);
if (wp && wp->w_grid_alloc.chars
&& !(wp->w_floating && !wp->w_float_config.focusable)) {
- *rowp = MIN(*rowp - wp->w_grid.row_offset, wp->w_grid.Rows - 1);
- *colp = MIN(*colp - wp->w_grid.col_offset, wp->w_grid.Columns - 1);
+ *rowp = MIN(*rowp - wp->w_grid.row_offset, wp->w_grid.rows - 1);
+ *colp = MIN(*colp - wp->w_grid.col_offset, wp->w_grid.cols - 1);
return wp;
}
} else if (*gridp == 0) {
@@ -784,8 +797,8 @@ int mouse_check_fold(void)
wp = mouse_find_win(&click_grid, &click_row, &click_col);
if (wp && multigrid) {
- max_row = wp->w_grid_alloc.Rows;
- max_col = wp->w_grid_alloc.Columns;
+ max_row = wp->w_grid_alloc.rows;
+ max_col = wp->w_grid_alloc.cols;
}
if (wp && mouse_row >= 0 && mouse_row < max_row
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 11feb497ea..97ce92f6a9 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -1016,7 +1016,7 @@ void textpos2screenpos(win_T *wp, pos_T *pos, int *rowp, int *scolp, int *ccolp,
col -= wp->w_leftcol;
if (col >= 0 && col < wp->w_width) {
- coloff = col - scol + (local ? 0 : wp->w_wincol + wp->w_border_adj[3]) + 1;
+ coloff = col - scol + (local ? 0 : wp->w_wincol + wp->w_wincol_off) + 1;
} else {
scol = ccol = ecol = 0;
// character is left or right of the window
@@ -1027,7 +1027,7 @@ void textpos2screenpos(win_T *wp, pos_T *pos, int *rowp, int *scolp, int *ccolp,
}
}
}
- *rowp = (local ? 0 : wp->w_winrow + wp->w_border_adj[0]) + row + rowoff;
+ *rowp = (local ? 0 : wp->w_winrow + wp->w_winrow_off) + row + rowoff;
*scolp = scol + coloff;
*ccolp = ccol + coloff;
*ecolp = ecol + coloff;
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 2826b7dad1..1692970a97 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -1280,7 +1280,8 @@ static void normal_redraw(NormalState *s)
validate_cursor();
if (VIsual_active) {
- update_curbuf(INVERTED); // update inverted part
+ redraw_curbuf_later(INVERTED); // update inverted part
+ update_screen(INVERTED);
} else if (must_redraw) {
update_screen(0);
} else if (redraw_cmdline || clear_cmdline) {
@@ -1850,6 +1851,11 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent)
oap == NULL ? NULL : &(oap->inclusive),
which_button);
+ // A click in the window bar has no side effects.
+ if (jump_flags & MOUSE_WINBAR) {
+ return false;
+ }
+
moved = (jump_flags & CURSOR_MOVED);
in_status_line = (jump_flags & IN_STATUS_LINE);
in_sep_line = (jump_flags & IN_SEP_LINE);
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index c3d7742307..0be49aaad4 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -4911,12 +4911,19 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd)
ssize_t change_cnt = 0;
linenr_T amount = Prenum1;
+ // do_addsub() might trigger re-evaluation of 'foldexpr' halfway, when the
+ // buffer is not completly updated yet. Postpone updating folds until before
+ // the call to changed_lines().
+ disable_fold_update++;
+
if (!VIsual_active) {
pos = curwin->w_cursor;
if (u_save_cursor() == FAIL) {
+ disable_fold_update--;
return;
}
change_cnt = do_addsub(oap->op_type, &pos, 0, amount);
+ disable_fold_update--;
if (change_cnt) {
changed_lines(pos.lnum, 0, pos.lnum + 1, 0L, true);
}
@@ -4927,6 +4934,7 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd)
if (u_save((linenr_T)(oap->start.lnum - 1),
(linenr_T)(oap->end.lnum + 1)) == FAIL) {
+ disable_fold_update--;
return;
}
@@ -4973,6 +4981,8 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd)
amount += Prenum1;
}
}
+
+ disable_fold_update--;
if (change_cnt) {
changed_lines(oap->start.lnum, 0, oap->end.lnum + 1, 0L, true);
}
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 8267bcf9da..7dd7b41328 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -2149,6 +2149,8 @@ static uint32_t *insecure_flag(win_T *const wp, int opt_idx, int opt_flags)
switch ((int)options[opt_idx].indir) {
case PV_STL:
return &wp->w_p_stl_flags;
+ case PV_WBR:
+ return &wp->w_p_wbr_flags;
case PV_FDE:
return &wp->w_p_fde_flags;
case PV_FDT:
@@ -2930,8 +2932,8 @@ ambw_end:
curbuf->b_help = (curbuf->b_p_bt[0] == 'h');
redraw_titles();
}
- } else if (gvarp == &p_stl || varp == &p_tal || varp == &p_ruf) {
- // 'statusline', 'tabline' or 'rulerformat'
+ } else if (gvarp == &p_stl || gvarp == (char_u **)&p_wbr || varp == &p_tal || varp == &p_ruf) {
+ // 'statusline', 'winbar', 'tabline' or 'rulerformat'
int wid;
if (varp == &p_ruf) { // reset ru_wid first
@@ -2950,12 +2952,16 @@ ambw_end:
errmsg = check_stl_option(p_ruf);
}
} else if (varp == &p_ruf || s[0] != '%' || s[1] != '!') {
- // check 'statusline' or 'tabline' only if it doesn't start with "%!"
+ // check 'statusline', 'winbar' or 'tabline' only if it doesn't start with "%!"
errmsg = check_stl_option(s);
}
if (varp == &p_ruf && errmsg == NULL) {
comp_col();
}
+ // add / remove window bars for 'winbar'
+ if (gvarp == (char_u **)&p_wbr) {
+ set_winbar();
+ }
} else if (gvarp == &p_cpt) {
// check if it is a valid value for 'complete' -- Acevedo
for (s = *varp; *s;) {
@@ -3570,6 +3576,7 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
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", 9472 }, // ─
{ &wp->w_p_fcs_chars.horizup, "horizup", 9524 }, // â”´
{ &wp->w_p_fcs_chars.horizdown, "horizdown", 9516 }, // ┬
@@ -3612,15 +3619,15 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
if (*p_ambw == 'd') {
// XXX: If ambiwidth=double then some characters take 2 columns,
// which is forbidden (TUI limitation?). Set old defaults.
- fcs_tab[2].def = '-';
fcs_tab[3].def = '-';
fcs_tab[4].def = '-';
- fcs_tab[5].def = '|';
+ fcs_tab[5].def = '-';
fcs_tab[6].def = '|';
fcs_tab[7].def = '|';
- fcs_tab[8].def = '+';
- fcs_tab[9].def = '-';
- fcs_tab[12].def = '|';
+ fcs_tab[8].def = '|';
+ fcs_tab[9].def = '+';
+ fcs_tab[10].def = '-';
+ fcs_tab[13].def = '|';
}
}
@@ -4042,18 +4049,6 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va
// buf->b_p_swf
mf_close_file(curbuf, true); // remove the swap file
}
- } else if ((int *)varp == &p_terse) {
- // when 'terse' is set change 'shortmess'
- char *p = vim_strchr((char *)p_shm, SHM_SEARCH);
-
- // insert 's' in p_shm
- if (p_terse && p == NULL) {
- STRCPY(IObuff, p_shm);
- STRCAT(IObuff, "s");
- set_string_option_direct("shm", -1, IObuff, OPT_FREE, 0);
- } else if (!p_terse && p != NULL) { // remove 's' from p_shm
- STRMOVE(p, p + 1);
- }
} else if ((int *)varp == &p_paste) {
// when 'paste' is set or reset also change other options
paste_option_changed();
@@ -4766,7 +4761,7 @@ static void check_redraw(uint32_t flags)
bool doclear = (flags & P_RCLR) == P_RCLR;
bool all = ((flags & P_RALL) == P_RALL || doclear);
- if ((flags & P_RSTAT) || all) { // mark all status lines dirty
+ if ((flags & P_RSTAT) || all) { // mark all status lines and window bars dirty
status_redraw_all();
}
@@ -5814,6 +5809,9 @@ void unset_global_local_option(char *name, void *from)
case PV_STL:
clear_string_option(&((win_T *)from)->w_p_stl);
break;
+ case PV_WBR:
+ clear_string_option((char_u **)&((win_T *)from)->w_p_wbr);
+ break;
case PV_UL:
buf->b_p_ul = NO_LOCAL_UNDOLEVEL;
break;
@@ -5891,6 +5889,8 @@ static char_u *get_varp_scope(vimoption_T *p, int opt_flags)
return (char_u *)&(curwin->w_p_sbr);
case PV_STL:
return (char_u *)&(curwin->w_p_stl);
+ case PV_WBR:
+ return (char_u *)&(curwin->w_p_wbr);
case PV_UL:
return (char_u *)&(curbuf->b_p_ul);
case PV_LW:
@@ -5984,6 +5984,9 @@ static char_u *get_varp(vimoption_T *p)
case PV_STL:
return *curwin->w_p_stl != NUL
? (char_u *)&(curwin->w_p_stl) : p->var;
+ case PV_WBR:
+ return *curwin->w_p_wbr != NUL
+ ? (char_u *)&(curwin->w_p_wbr) : p->var;
case PV_UL:
return curbuf->b_p_ul != NO_LOCAL_UNDOLEVEL
? (char_u *)&(curbuf->b_p_ul) : p->var;
@@ -6252,6 +6255,7 @@ void copy_winopt(winopt_T *from, winopt_T *to)
to->wo_rlc = vim_strsave(from->wo_rlc);
to->wo_sbr = vim_strsave(from->wo_sbr);
to->wo_stl = vim_strsave(from->wo_stl);
+ to->wo_wbr = xstrdup(from->wo_wbr);
to->wo_wrap = from->wo_wrap;
to->wo_wrap_save = from->wo_wrap_save;
to->wo_lbr = from->wo_lbr;
@@ -6327,6 +6331,7 @@ static void check_winopt(winopt_T *wop)
check_string_option(&wop->wo_fcs);
check_string_option(&wop->wo_lcs);
check_string_option(&wop->wo_ve);
+ check_string_option((char_u **)&wop->wo_wbr);
}
/// Free the allocated memory inside a winopt_T.
@@ -6352,6 +6357,7 @@ void clear_winopt(winopt_T *wop)
clear_string_option(&wop->wo_fcs);
clear_string_option(&wop->wo_lcs);
clear_string_option(&wop->wo_ve);
+ clear_string_option((char_u **)&wop->wo_wbr);
}
void didset_window_options(win_T *wp)
@@ -6538,6 +6544,7 @@ void buf_copy_options(buf_T *buf, int flags)
COPY_OPT_SCTX(buf, BV_SI);
buf->b_p_channel = 0;
buf->b_p_ci = p_ci;
+
COPY_OPT_SCTX(buf, BV_CI);
buf->b_p_cin = p_cin;
COPY_OPT_SCTX(buf, BV_CIN);
@@ -6547,6 +6554,7 @@ void buf_copy_options(buf_T *buf, int flags)
COPY_OPT_SCTX(buf, BV_CINO);
buf->b_p_cinsd = vim_strsave(p_cinsd);
COPY_OPT_SCTX(buf, BV_CINSD);
+
// Don't copy 'filetype', it must be detected
buf->b_p_ft = empty_option;
buf->b_p_pi = p_pi;
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index e358a29622..876acf2f87 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -557,7 +557,6 @@ static char *(p_rdb_values[]) = {
#define RDB_NODELTA 0x008
EXTERN long p_rdt; // 'redrawtime'
-EXTERN int p_remap; // 'remap'
EXTERN long p_re; // 'regexpengine'
EXTERN long p_report; // 'report'
EXTERN long p_pvh; // 'previewheight'
@@ -618,6 +617,7 @@ EXTERN int p_stmp; // 'shelltemp'
EXTERN int p_ssl; // 'shellslash'
#endif
EXTERN char_u *p_stl; // 'statusline'
+EXTERN char *p_wbr; // 'winbar'
EXTERN int p_sr; // 'shiftround'
EXTERN char_u *p_shm; // 'shortmess'
EXTERN char_u *p_sbr; // 'showbreak'
@@ -678,7 +678,6 @@ EXTERN int p_tr; ///< 'tagrelative'
EXTERN char_u *p_tags; ///< 'tags'
EXTERN int p_tgst; ///< 'tagstack'
EXTERN int p_tbidi; ///< 'termbidi'
-EXTERN int p_terse; ///< 'terse'
EXTERN int p_to; ///< 'tildeop'
EXTERN int p_timeout; ///< 'timeout'
EXTERN long p_tm; ///< 'timeoutlen'
@@ -897,6 +896,7 @@ enum {
WV_FCS,
WV_LCS,
WV_WINBL,
+ WV_WBR,
WV_COUNT, // must be the last one
};
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 313cace4b2..809d4ab48b 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -1911,9 +1911,9 @@ return {
},
{
full_name='remap',
- short_desc=N_("mappings to work recursively"),
+ short_desc=N_("No description"),
type='bool', scope={'global'},
- varname='p_remap',
+ varname='p_force_on',
defaults={if_true=true}
},
{
@@ -2529,9 +2529,9 @@ return {
},
{
full_name='terse',
- short_desc=N_("hides notification of search wrap"),
+ short_desc=N_("No description"),
type='bool', scope={'global'},
- varname='p_terse',
+ varname='p_force_off',
defaults={if_true=false}
},
{
@@ -2832,6 +2832,16 @@ return {
defaults={if_true="menu"}
},
{
+ full_name='winbar', abbreviation='wbr',
+ short_desc=N_("custom format for the window bar"),
+ type='string', scope={'global', 'window'},
+ alloced=true,
+ modelineexpr=true,
+ redraw={'statuslines'},
+ varname='p_wbr',
+ defaults={if_true=""}
+ },
+ {
full_name='winblend', abbreviation='winbl',
short_desc=N_("Controls transparency level for floating windows"),
type='number', scope={'window'},
diff --git a/src/nvim/os/fs.h b/src/nvim/os/fs.h
new file mode 100644
index 0000000000..c68081da02
--- /dev/null
+++ b/src/nvim/os/fs.h
@@ -0,0 +1,10 @@
+#ifndef NVIM_OS_FS_H
+#define NVIM_OS_FS_H
+
+#include "nvim/os/fs_defs.h" // for uv_*
+#include "nvim/types.h" // for char_u
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "os/fs.h.generated.h"
+#endif
+#endif // NVIM_OS_FS_H
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index c99d2869da..ac21b32a3e 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -19,6 +19,7 @@
#include "nvim/memory.h"
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/os/input.h"
+#include "nvim/screen.h"
#include "nvim/state.h"
#include "nvim/ui.h"
#include "nvim/vim.h"
@@ -178,15 +179,7 @@ void os_breakcheck(void)
return;
}
- int save_us = updating_screen;
- // We do not want screen_resize() to redraw here.
- // TODO(bfredl): we are already special casing redraw events, is this
- // hack still needed?
- updating_screen++;
-
loop_poll_events(&main_loop, 0);
-
- updating_screen = save_us;
}
#define BREAKCHECK_SKIP 1000
diff --git a/src/nvim/os/users.c b/src/nvim/os/users.c
index 4803be20c3..3d67ae4ce0 100644
--- a/src/nvim/os/users.c
+++ b/src/nvim/os/users.c
@@ -30,7 +30,7 @@ static void add_user(garray_T *users, char *user, bool need_copy)
if (user_copy == NULL || *user_copy == NUL) {
if (need_copy) {
- xfree(user);
+ xfree(user_copy);
}
return;
}
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index c5c1d87919..9525a84e62 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -429,9 +429,9 @@ void pum_redraw(void)
must_redraw_pum = false;
if (!pum_grid.chars
- || pum_grid.Rows != pum_height || pum_grid.Columns != grid_width) {
+ || pum_grid.rows != pum_height || pum_grid.cols != grid_width) {
grid_alloc(&pum_grid, pum_height, grid_width, !invalid_grid, false);
- ui_call_grid_resize(pum_grid.handle, pum_grid.Columns, pum_grid.Rows);
+ ui_call_grid_resize(pum_grid.handle, pum_grid.cols, pum_grid.rows);
} else if (invalid_grid) {
grid_invalidate(&pum_grid);
}
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 686516f17b..df87955c46 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -132,10 +132,6 @@
static match_T search_hl; // used for 'hlsearch' highlight matching
-StlClickDefinition *tab_page_click_defs = NULL;
-
-long tab_page_click_defs_size = 0;
-
// for line_putchar. Contains the state that needs to be remembered from
// putting one character to the next.
typedef struct {
@@ -276,25 +272,25 @@ void redrawWinline(win_T *wp, linenr_T lnum)
}
}
-/*
- * update all windows that are editing the current buffer
- */
-void update_curbuf(int type)
-{
- redraw_curbuf_later(type);
- update_screen(type);
-}
-
/// called when the status bars for the buffer 'buf' need to be updated
void redraw_buf_status_later(buf_T *buf)
{
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (wp->w_buffer == buf
- && (wp->w_status_height || (wp == curwin && global_stl_height()))) {
+ if (wp->w_buffer != buf) {
+ continue;
+ }
+ bool redraw = false;
+
+ if (wp->w_status_height || (wp == curwin && global_stl_height())) {
wp->w_redr_status = true;
- if (must_redraw < VALID) {
- must_redraw = VALID;
- }
+ redraw = true;
+ }
+ if (wp->w_winbar_height) {
+ wp->w_redr_winbar = true;
+ redraw = true;
+ }
+ if (redraw && must_redraw < VALID) {
+ must_redraw = VALID;
}
}
}
@@ -382,9 +378,9 @@ int update_screen(int type)
int valid = MAX(Rows - msg_scrollsize(), 0);
if (msg_grid.chars) {
// non-displayed part of msg_grid is considered invalid.
- for (int i = 0; i < MIN(msg_scrollsize(), msg_grid.Rows); i++) {
+ for (int i = 0; i < MIN(msg_scrollsize(), msg_grid.rows); i++) {
grid_clear_line(&msg_grid, msg_grid.line_offset[i],
- msg_grid.Columns, false);
+ msg_grid.cols, false);
}
}
if (msg_use_msgsep()) {
@@ -400,6 +396,9 @@ int update_screen(int type)
if (wp->w_floating) {
continue;
}
+ if (wp->w_winrow + wp->w_winbar_height > valid) {
+ wp->w_redr_winbar = true;
+ }
if (W_ENDROW(wp) > valid) {
wp->w_redr_type = MAX(wp->w_redr_type, NOT_VALID);
}
@@ -431,6 +430,9 @@ int update_screen(int type)
wp->w_redr_type = REDRAW_TOP;
} else {
wp->w_redr_type = NOT_VALID;
+ if (wp->w_winrow + wp->w_winbar_height <= msg_scrolled) {
+ wp->w_redr_winbar = true;
+ }
if (!is_stl_global && W_ENDROW(wp) + wp->w_status_height <= msg_scrolled) {
wp->w_redr_status = true;
}
@@ -585,10 +587,13 @@ int update_screen(int type)
win_update(wp, &providers);
}
- // redraw status line after the window to minimize cursor movement
+ // redraw status line and window bar after the window to minimize cursor movement
if (wp->w_redr_status) {
win_redr_status(wp);
}
+ if (wp->w_redr_winbar) {
+ win_redr_winbar(wp);
+ }
}
end_search_hl();
@@ -598,8 +603,6 @@ int update_screen(int type)
pum_redraw();
}
- send_grid_resize = false;
-
/* Reset b_mod_set flags. Going through all windows is probably faster
* than going through all buffers (there could be many buffers). */
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
@@ -743,11 +746,12 @@ static void win_update(win_T *wp, DecorProviders *providers)
if (type >= NOT_VALID) {
wp->w_redr_status = true;
+ wp->w_redr_winbar = true;
wp->w_lines_valid = 0;
}
// Window is zero-height: Only need to draw the separator
- if (wp->w_grid.Rows == 0) {
+ if (wp->w_grid.rows == 0) {
// draw the horizontal separator below this window
draw_hsep_win(wp);
draw_sep_connectors_win(wp);
@@ -756,7 +760,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
}
// Window is zero-width: Only need to draw the separator.
- if (wp->w_grid.Columns == 0) {
+ if (wp->w_grid.cols == 0) {
// draw the vertical separator right of this window
draw_vsep_win(wp);
draw_sep_connectors_win(wp);
@@ -955,7 +959,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
j = 0;
for (ln = wp->w_topline; ln < wp->w_lines[0].wl_lnum; ln++) {
j++;
- if (j >= wp->w_grid.Rows - 2) {
+ if (j >= wp->w_grid.rows - 2) {
break;
}
(void)hasFoldingWin(wp, ln, NULL, &ln, true, NULL);
@@ -963,13 +967,13 @@ static void win_update(win_T *wp, DecorProviders *providers)
} else {
j = wp->w_lines[0].wl_lnum - wp->w_topline;
}
- if (j < wp->w_grid.Rows - 2) { // not too far off
+ if (j < wp->w_grid.rows - 2) { // not too far off
i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1);
// insert extra lines for previously invisible filler lines
if (wp->w_lines[0].wl_lnum != wp->w_topline) {
i += win_get_fill(wp, wp->w_lines[0].wl_lnum) - wp->w_old_topfill;
}
- if (i != 0 && i < wp->w_grid.Rows - 2) { // less than a screen off
+ if (i != 0 && i < wp->w_grid.rows - 2) { // less than a screen off
// Try to insert the correct number of lines.
// If not the last window, delete the lines at the bottom.
// win_ins_lines may fail when the terminal can't do it.
@@ -982,8 +986,8 @@ static void win_update(win_T *wp, DecorProviders *providers)
// Move the entries that were scrolled, disable
// the entries for the lines to be redrawn.
- if ((wp->w_lines_valid += j) > wp->w_grid.Rows) {
- wp->w_lines_valid = wp->w_grid.Rows;
+ if ((wp->w_lines_valid += j) > wp->w_grid.rows) {
+ wp->w_lines_valid = wp->w_grid.rows;
}
for (idx = wp->w_lines_valid; idx - j >= 0; idx--) {
wp->w_lines[idx] = wp->w_lines[idx - j];
@@ -1036,7 +1040,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
row -= wp->w_topfill;
if (row > 0) {
win_scroll_lines(wp, 0, -row);
- bot_start = wp->w_grid.Rows - row;
+ bot_start = wp->w_grid.rows - row;
}
if ((row == 0 || bot_start < 999) && wp->w_lines_valid != 0) {
/*
@@ -1052,7 +1056,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
/* stop at line that didn't fit, unless it is still
* valid (no lines deleted) */
if (row > 0 && bot_start + row
- + (int)wp->w_lines[j].wl_size > wp->w_grid.Rows) {
+ + (int)wp->w_lines[j].wl_size > wp->w_grid.rows) {
wp->w_lines_valid = idx + 1;
break;
}
@@ -1077,18 +1081,18 @@ static void win_update(win_T *wp, DecorProviders *providers)
// When starting redraw in the first line, redraw all lines.
if (mid_start == 0) {
- mid_end = wp->w_grid.Rows;
+ mid_end = wp->w_grid.rows;
}
} else {
// Not VALID or INVERTED: redraw all lines.
mid_start = 0;
- mid_end = wp->w_grid.Rows;
+ mid_end = wp->w_grid.rows;
}
if (type == SOME_VALID) {
// SOME_VALID: redraw all lines.
mid_start = 0;
- mid_end = wp->w_grid.Rows;
+ mid_end = wp->w_grid.rows;
type = NOT_VALID;
}
@@ -1275,7 +1279,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
}
}
srow += mid_start;
- mid_end = wp->w_grid.Rows;
+ mid_end = wp->w_grid.rows;
for (; idx < wp->w_lines_valid; idx++) { // find end
if (wp->w_lines[idx].wl_valid
&& wp->w_lines[idx].wl_lnum >= to + 1) {
@@ -1328,7 +1332,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
for (;;) {
/* stop updating when reached the end of the window (check for _past_
* the end of the window is at the end of the loop) */
- if (row == wp->w_grid.Rows) {
+ if (row == wp->w_grid.rows) {
didline = true;
break;
}
@@ -1433,7 +1437,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
new_rows += plines_win(wp, l, true);
}
j++;
- if (new_rows > wp->w_grid.Rows - row - 2) {
+ if (new_rows > wp->w_grid.rows - row - 2) {
// it's getting too much, must redraw the rest
new_rows = 9999;
break;
@@ -1445,17 +1449,17 @@ static void win_update(win_T *wp, DecorProviders *providers)
* remaining text or scrolling fails, must redraw the
* rest. If scrolling works, must redraw the text
* below the scrolled text. */
- if (row - xtra_rows >= wp->w_grid.Rows - 2) {
+ if (row - xtra_rows >= wp->w_grid.rows - 2) {
mod_bot = MAXLNUM;
} else {
win_scroll_lines(wp, row, xtra_rows);
- bot_start = wp->w_grid.Rows + xtra_rows;
+ bot_start = wp->w_grid.rows + xtra_rows;
}
} else if (xtra_rows > 0) {
/* May scroll text down. If there is not enough
* remaining text of scrolling fails, must redraw the
* rest. */
- if (row + xtra_rows >= wp->w_grid.Rows - 2) {
+ if (row + xtra_rows >= wp->w_grid.rows - 2) {
mod_bot = MAXLNUM;
} else {
win_scroll_lines(wp, row + old_rows, xtra_rows);
@@ -1483,7 +1487,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
wp->w_lines[j] = wp->w_lines[i];
// stop at a line that won't fit
if (x + (int)wp->w_lines[j].wl_size
- > wp->w_grid.Rows) {
+ > wp->w_grid.rows) {
wp->w_lines_valid = j + 1;
break;
}
@@ -1497,8 +1501,8 @@ static void win_update(win_T *wp, DecorProviders *providers)
// move entries in w_lines[] downwards
j -= i;
wp->w_lines_valid += j;
- if (wp->w_lines_valid > wp->w_grid.Rows) {
- wp->w_lines_valid = wp->w_grid.Rows;
+ if (wp->w_lines_valid > wp->w_grid.rows) {
+ wp->w_lines_valid = wp->w_grid.rows;
}
for (i = wp->w_lines_valid; i - j >= idx; i--) {
wp->w_lines[i] = wp->w_lines[i - j];
@@ -1529,11 +1533,11 @@ static void win_update(win_T *wp, DecorProviders *providers)
&& wp->w_lines[idx].wl_lnum == lnum
&& lnum > wp->w_topline
&& !(dy_flags & (DY_LASTLINE | DY_TRUNCATE))
- && srow + wp->w_lines[idx].wl_size > wp->w_grid.Rows
+ && srow + wp->w_lines[idx].wl_size > wp->w_grid.rows
&& win_get_fill(wp, lnum) == 0) {
// This line is not going to fit. Don't draw anything here,
// will draw "@ " lines below.
- row = wp->w_grid.Rows + 1;
+ row = wp->w_grid.rows + 1;
} else {
prepare_search_hl(wp, &search_hl, lnum);
// Let the syntax stuff know we skipped a few lines.
@@ -1544,7 +1548,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
// Display one line
row = win_line(wp, lnum, srow,
- foldinfo.fi_lines ? srow : wp->w_grid.Rows,
+ foldinfo.fi_lines ? srow : wp->w_grid.rows,
mod_top == 0, false, foldinfo, &line_providers);
if (foldinfo.fi_lines == 0) {
@@ -1563,7 +1567,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
wp->w_lines[idx].wl_lnum = lnum;
wp->w_lines[idx].wl_valid = true;
- if (row > wp->w_grid.Rows) { // past end of grid
+ if (row > wp->w_grid.rows) { // past end of grid
// we may need the size of that too long line later on
if (dollar_vcol == -1) {
wp->w_lines[idx].wl_size = plines_win(wp, lnum, true);
@@ -1581,13 +1585,13 @@ static void win_update(win_T *wp, DecorProviders *providers)
// 'relativenumber' set and cursor moved vertically: The
// text doesn't need to be drawn, but the number column does.
foldinfo_T info = fold_info(wp, lnum);
- (void)win_line(wp, lnum, srow, wp->w_grid.Rows, true, true,
+ (void)win_line(wp, lnum, srow, wp->w_grid.rows, true, true,
info, &line_providers);
}
// This line does not need to be drawn, advance to the next one.
row += wp->w_lines[idx++].wl_size;
- if (row > wp->w_grid.Rows) { // past end of screen
+ if (row > wp->w_grid.rows) { // past end of screen
break;
}
lnum = wp->w_lines[idx - 1].wl_lastlnum + 1;
@@ -1635,41 +1639,41 @@ static void win_update(win_T *wp, DecorProviders *providers)
* Don't overwrite it, it can be edited.
*/
wp->w_botline = lnum + 1;
- } else if (win_get_fill(wp, lnum) >= wp->w_grid.Rows - srow) {
+ } else if (win_get_fill(wp, lnum) >= wp->w_grid.rows - srow) {
// Window ends in filler lines.
wp->w_botline = lnum;
- wp->w_filler_rows = wp->w_grid.Rows - srow;
+ wp->w_filler_rows = wp->w_grid.rows - srow;
} else if (dy_flags & DY_TRUNCATE) { // 'display' has "truncate"
- int scr_row = wp->w_grid.Rows - 1;
+ int scr_row = wp->w_grid.rows - 1;
// Last line isn't finished: Display "@@@" in the last screen line.
- grid_puts_len(&wp->w_grid, (char_u *)"@@", MIN(wp->w_grid.Columns, 2), scr_row, 0, at_attr);
+ grid_puts_len(&wp->w_grid, (char_u *)"@@", MIN(wp->w_grid.cols, 2), scr_row, 0, at_attr);
- grid_fill(&wp->w_grid, scr_row, scr_row + 1, 2, wp->w_grid.Columns,
+ grid_fill(&wp->w_grid, scr_row, scr_row + 1, 2, wp->w_grid.cols,
'@', ' ', at_attr);
set_empty_rows(wp, srow);
wp->w_botline = lnum;
} else if (dy_flags & DY_LASTLINE) { // 'display' has "lastline"
- int start_col = wp->w_grid.Columns - 3;
+ int start_col = wp->w_grid.cols - 3;
// Last line isn't finished: Display "@@@" at the end.
- grid_fill(&wp->w_grid, wp->w_grid.Rows - 1, wp->w_grid.Rows,
- MAX(start_col, 0), wp->w_grid.Columns, '@', '@', at_attr);
+ grid_fill(&wp->w_grid, wp->w_grid.rows - 1, wp->w_grid.rows,
+ MAX(start_col, 0), wp->w_grid.cols, '@', '@', at_attr);
set_empty_rows(wp, srow);
wp->w_botline = lnum;
} else {
- win_draw_end(wp, '@', ' ', true, srow, wp->w_grid.Rows, HLF_AT);
+ win_draw_end(wp, '@', ' ', true, srow, wp->w_grid.rows, HLF_AT);
wp->w_botline = lnum;
}
} else {
if (eof) { // we hit the end of the file
wp->w_botline = buf->b_ml.ml_line_count + 1;
j = win_get_fill(wp, wp->w_botline);
- if (j > 0 && !wp->w_botfill && row < wp->w_grid.Rows) {
+ if (j > 0 && !wp->w_botfill && row < wp->w_grid.rows) {
// Display filler text below last line. win_line() will check
// for ml_line_count+1 and only draw filler lines
foldinfo_T info = FOLDINFO_INIT;
- row = win_line(wp, wp->w_botline, row, wp->w_grid.Rows,
+ row = win_line(wp, wp->w_botline, row, wp->w_grid.rows,
false, false, info, &line_providers);
}
} else if (dollar_vcol == -1) {
@@ -1678,7 +1682,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
// make sure the rest of the screen is blank
// write the 'eob' character to rows that aren't part of the file.
- win_draw_end(wp, wp->w_p_fcs_chars.eob, ' ', false, row, wp->w_grid.Rows,
+ win_draw_end(wp, wp->w_p_fcs_chars.eob, ' ', false, row, wp->w_grid.rows,
HLF_EOB);
}
@@ -1763,8 +1767,8 @@ static int win_fill_end(win_T *wp, int c1, int c2, int off, int width, int row,
{
int nn = off + width;
- if (nn > wp->w_grid.Columns) {
- nn = wp->w_grid.Columns;
+ if (nn > wp->w_grid.cols) {
+ nn = wp->w_grid.cols;
}
if (wp->w_p_rl) {
@@ -1813,7 +1817,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, bool draw_margin, int row, i
grid_fill(&wp->w_grid, row, endrow, W_ENDCOL(wp) - 1 - n, W_ENDCOL(wp) - n,
c1, c2, attr);
} else {
- grid_fill(&wp->w_grid, row, endrow, n, wp->w_grid.Columns, c1, c2, attr);
+ grid_fill(&wp->w_grid, row, endrow, n, wp->w_grid.cols, c1, c2, attr);
}
set_empty_rows(wp, row);
@@ -1837,7 +1841,7 @@ static int compute_foldcolumn(win_T *wp, int col)
{
int fdc = win_fdccol_count(wp);
int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw;
- int wwidth = wp->w_grid.Columns;
+ int wwidth = wp->w_grid.cols;
if (fdc > wwidth - (col + wmw)) {
fdc = wwidth - (col + wmw);
@@ -2621,7 +2625,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// Rightleft window: process the text in the normal direction, but put
// it in linebuf_char[off] from right to left. Start at the
// rightmost column of the window.
- col = grid->Columns - 1;
+ col = grid->cols - 1;
off += col;
}
@@ -2803,7 +2807,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (wp->w_p_rl) {
n_extra = col + 1;
} else {
- n_extra = grid->Columns - col;
+ n_extra = grid->cols - col;
}
char_attr = 0;
} else if (filler_todo > 0) {
@@ -2818,7 +2822,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (wp->w_p_rl) {
n_extra = col + 1;
} else {
- n_extra = grid->Columns - col;
+ n_extra = grid->cols - col;
}
char_attr = win_hl_attr(wp, HLF_DED);
}
@@ -2892,15 +2896,15 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
&& vcol >= (long)wp->w_virtcol)
|| (number_only && draw_state > WL_NR))
&& filler_todo <= 0) {
- draw_virt_text(wp, buf, win_col_offset, &col, grid->Columns, row);
- grid_put_linebuf(grid, row, 0, col, -grid->Columns, wp->w_p_rl, wp,
+ draw_virt_text(wp, buf, win_col_offset, &col, grid->cols, row);
+ grid_put_linebuf(grid, row, 0, col, -grid->cols, wp->w_p_rl, wp,
wp->w_hl_attr_normal, false);
// Pretend we have finished updating the window. Except when
// 'cursorcolumn' is set.
if (wp->w_p_cuc) {
row = wp->w_cline_row + wp->w_cline_height;
} else {
- row = grid->Rows;
+ row = grid->rows;
}
break;
}
@@ -2928,19 +2932,19 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (draw_state == WL_LINE
&& has_fold
- && col < grid->Columns
+ && col < grid->cols
&& n_extra == 0
&& row == startrow) {
// fill rest of line with 'fold'
c_extra = wp->w_p_fcs_chars.fold;
c_final = NUL;
- n_extra = wp->w_p_rl ? (col + 1) : (grid->Columns - col);
+ n_extra = wp->w_p_rl ? (col + 1) : (grid->cols - col);
}
if (draw_state == WL_LINE
&& has_fold
- && col >= grid->Columns
+ && col >= grid->cols
&& n_extra != 0
&& row == startrow) {
// Truncate the folding.
@@ -3069,7 +3073,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
}
// If a double-width char doesn't fit display a '>' in the last column.
- if ((wp->w_p_rl ? (col <= 0) : (col >= grid->Columns - 1))
+ if ((wp->w_p_rl ? (col <= 0) : (col >= grid->cols - 1))
&& utf_char2cells(mb_c) == 2) {
c = '>';
mb_c = c;
@@ -3183,7 +3187,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// last column; the character is displayed at the start of the
// next line.
if ((wp->w_p_rl ? (col <= 0) :
- (col >= grid->Columns - 1))
+ (col >= grid->cols - 1))
&& utf_char2cells(mb_c) == 2) {
c = '>';
mb_c = c;
@@ -3388,7 +3392,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
}
}
- if (c == TAB && n_extra + col > grid->Columns) {
+ if (c == TAB && n_extra + col > grid->cols) {
n_extra = tabstop_padding(vcol, wp->w_buffer->b_p_ts,
wp->w_buffer->b_p_vts_array) - 1;
}
@@ -3591,7 +3595,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
|| ((fromcol >= 0 || fromcol_prev >= 0)
&& tocol > vcol
&& VIsual_mode != Ctrl_V
- && (wp->w_p_rl ? (col >= 0) : (col < grid->Columns))
+ && (wp->w_p_rl ? (col >= 0) : (col < grid->cols))
&& !(noinvcur
&& lnum == wp->w_cursor.lnum
&& (colnr_T)vcol == wp->w_virtcol)))
@@ -3663,7 +3667,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
&& virtual_active()
&& tocol != MAXCOL
&& vcol < tocol
- && (wp->w_p_rl ? (col >= 0) : (col < grid->Columns))) {
+ && (wp->w_p_rl ? (col >= 0) : (col < grid->cols))) {
c = ' ';
ptr--; // put it back at the NUL
}
@@ -3745,7 +3749,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
&& conceal_cursor_line(wp)
&& (int)wp->w_virtcol <= vcol + n_skip) {
if (wp->w_p_rl) {
- wp->w_wcol = grid->Columns - col + boguscols - 1;
+ wp->w_wcol = grid->cols - col + boguscols - 1;
} else {
wp->w_wcol = col - boguscols;
}
@@ -3817,7 +3821,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
n = 1;
}
} else {
- if (col >= grid->Columns) {
+ if (col >= grid->cols) {
n = -1;
}
}
@@ -3885,7 +3889,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (((wp->w_p_cuc
&& (int)wp->w_virtcol >= VCOL_HLC - eol_hl_off
&& (int)wp->w_virtcol <
- (long)grid->Columns * (row - startrow + 1) + v
+ (long)grid->cols * (row - startrow + 1) + v
&& lnum != wp->w_cursor.lnum)
|| draw_color_col || line_attr_lowprio || line_attr
|| diff_hlf != (hlf_T)0 || has_virttext)) {
@@ -3923,7 +3927,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
int col_stride = wp->w_p_rl ? -1 : 1;
- while (wp->w_p_rl ? col >= 0 : col < grid->Columns) {
+ while (wp->w_p_rl ? col >= 0 : col < grid->cols) {
schar_from_ascii(linebuf_char[off], ' ');
col += col_stride;
if (draw_color_col) {
@@ -3956,7 +3960,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// terminal buffers may need to highlight beyond the end of the
// logical line
int n = wp->w_p_rl ? -1 : 1;
- while (col >= 0 && col < grid->Columns) {
+ while (col >= 0 && col < grid->cols) {
schar_from_ascii(linebuf_char[off], ' ');
linebuf_attr[off] = vcol >= TERM_ATTRS_MAX ? 0 : term_attrs[vcol];
off += n;
@@ -3965,8 +3969,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
}
}
- draw_virt_text(wp, buf, win_col_offset, &col, grid->Columns, row);
- grid_put_linebuf(grid, row, 0, col, grid->Columns, wp->w_p_rl, wp,
+ draw_virt_text(wp, buf, win_col_offset, &col, grid->cols, row);
+ grid_put_linebuf(grid, row, 0, col, grid->cols, wp->w_p_rl, wp,
wp->w_hl_attr_normal, false);
row++;
@@ -3991,7 +3995,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
&& wp->w_p_list
&& !wp->w_p_wrap
&& filler_todo <= 0
- && (wp->w_p_rl ? col == 0 : col == grid->Columns - 1)
+ && (wp->w_p_rl ? col == 0 : col == grid->cols - 1)
&& !has_fold
&& (*ptr != NUL
|| lcs_eol_one > 0
@@ -4181,7 +4185,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
* At end of screen line and there is more to come: Display the line
* so far. If there is no more to display it is caught above.
*/
- if ((wp->w_p_rl ? (col < 0) : (col >= grid->Columns))
+ if ((wp->w_p_rl ? (col < 0) : (col >= grid->cols))
&& foldinfo.fi_lines == 0
&& (draw_state != WL_LINE
|| *ptr != NUL
@@ -4194,7 +4198,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
&& filler_todo <= 0 // Not drawing diff filler lines.
&& lcs_eol_one != -1 // Haven't printed the lcs_eol character.
&& row != endrow - 1 // Not the last line being displayed.
- && (grid->Columns == Columns // Window spans the width of the screen,
+ && (grid->cols == Columns // Window spans the width of the screen,
|| ui_has(kUIMultigrid)) // or has dedicated grid.
&& !wp->w_p_rl; // Not right-to-left.
@@ -4206,13 +4210,13 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
assert(i >= 0);
int offset = kv_A(virt_lines, i).left_col ? 0 : win_col_offset;
draw_virt_text_item(buf, offset, kv_A(virt_lines, i).line,
- kHlModeReplace, grid->Columns, offset);
+ kHlModeReplace, grid->cols, offset);
}
} else {
- draw_virt_text(wp, buf, win_col_offset, &draw_col, grid->Columns, row);
+ draw_virt_text(wp, buf, win_col_offset, &draw_col, grid->cols, row);
}
- grid_put_linebuf(grid, row, 0, draw_col, grid->Columns, wp->w_p_rl,
+ grid_put_linebuf(grid, row, 0, draw_col, grid->cols, wp->w_p_rl,
wp, wp->w_hl_attr_normal, wrap);
if (wrap) {
ScreenGrid *current_grid = grid;
@@ -4239,7 +4243,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// When the window is too narrow draw all "@" lines.
if (draw_state != WL_LINE && filler_todo <= 0) {
- win_draw_end(wp, '@', ' ', true, row, wp->w_grid.Rows, HLF_AT);
+ win_draw_end(wp, '@', ' ', true, row, wp->w_grid.rows, HLF_AT);
row = endrow;
}
@@ -4252,7 +4256,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
col = 0;
off = 0;
if (wp->w_p_rl) {
- col = grid->Columns - 1; // col is not used if breaking!
+ col = grid->cols - 1; // col is not used if breaking!
off += col;
}
@@ -4528,42 +4532,55 @@ void rl_mirror(char_u *str)
}
}
-/*
- * mark all status lines for redraw; used after first :cd
- */
+/// Mark all status lines and window bars for redraw; used after first :cd
void status_redraw_all(void)
{
- if (global_stl_height()) {
- curwin->w_redr_status = true;
- redraw_later(curwin, VALID);
- } else {
- FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (wp->w_status_height) {
- wp->w_redr_status = true;
- redraw_later(wp, VALID);
- }
+ bool is_stl_global = global_stl_height() != 0;
+
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ bool redraw = false;
+
+ if ((!is_stl_global && wp->w_status_height) || (is_stl_global && wp == curwin)) {
+ wp->w_redr_status = true;
+ redraw = true;
+ }
+ if (wp->w_winbar_height) {
+ wp->w_redr_winbar = true;
+ redraw = true;
+ }
+ if (redraw) {
+ redraw_later(wp, VALID);
}
}
}
-/// Marks all status lines of the current buffer for redraw.
+/// Marks all status lines and window bars of the current buffer for redraw.
void status_redraw_curbuf(void)
{
status_redraw_buf(curbuf);
}
-/// Marks all status lines of the specified buffer for redraw.
+/// Marks all status lines and window bars of the given buffer for redraw.
void status_redraw_buf(buf_T *buf)
{
- if (global_stl_height() != 0 && curwin->w_buffer == buf) {
- curwin->w_redr_status = true;
- redraw_later(curwin, VALID);
- } else {
- FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (wp->w_status_height != 0 && wp->w_buffer == buf) {
- wp->w_redr_status = true;
- redraw_later(wp, VALID);
- }
+ bool is_stl_global = global_stl_height() != 0;
+
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ if (wp->w_buffer != buf) {
+ continue;
+ }
+ bool redraw = false;
+
+ if ((!is_stl_global && wp->w_status_height) || (is_stl_global && wp == curwin)) {
+ wp->w_redr_status = true;
+ redraw = true;
+ }
+ if (wp->w_winbar_height) {
+ wp->w_redr_winbar = true;
+ redraw = true;
+ }
+ if (redraw) {
+ redraw_later(wp, VALID);
}
}
}
@@ -4577,6 +4594,9 @@ void redraw_statuslines(void)
if (wp->w_redr_status) {
win_redr_status(wp);
}
+ if (wp->w_redr_winbar) {
+ win_redr_winbar(wp);
+ }
}
if (redraw_tabline) {
draw_tabline();
@@ -5075,7 +5095,7 @@ static void redraw_custom_statusline(win_T *wp)
entered = true;
did_emsg = false;
- win_redr_custom(wp, false);
+ win_redr_custom(wp, false, false);
if (did_emsg) {
// When there is an error disable the statusline, otherwise the
// display is messed up with errors and a redraw triggers the problem
@@ -5088,6 +5108,41 @@ static void redraw_custom_statusline(win_T *wp)
entered = false;
}
+static void win_redr_winbar(win_T *wp)
+{
+ static bool entered = false;
+
+ // Return when called recursively. This can happen when the winbar contains an expression
+ // that triggers a redraw.
+ if (entered) {
+ return;
+ }
+ entered = true;
+
+ wp->w_redr_winbar = false;
+ if (wp->w_winbar_height == 0) {
+ // No window bar, do nothing.
+ } else if (!redrawing()) {
+ // Don't redraw right now, do it later.
+ wp->w_redr_winbar = true;
+ } else if (*p_wbr != NUL || *wp->w_p_wbr != NUL) {
+ int saved_did_emsg = did_emsg;
+
+ did_emsg = false;
+ win_redr_custom(wp, true, false);
+ if (did_emsg) {
+ // When there is an error disable the winbar, otherwise the
+ // display is messed up with errors and a redraw triggers the problem
+ // again and again.
+ set_string_option_direct("winbar", -1, (char_u *)"",
+ OPT_FREE | (*wp->w_p_stl != NUL
+ ? OPT_LOCAL : OPT_GLOBAL), SID_ERROR);
+ }
+ did_emsg |= saved_did_emsg;
+ }
+ entered = false;
+}
+
/// Only call if (wp->w_vsep_width != 0).
///
/// @return true if the status line of window "wp" is connected to the status
@@ -5224,11 +5279,9 @@ bool get_keymap_str(win_T *wp, char_u *fmt, char_u *buf, int len)
return buf[0] != NUL;
}
-/*
- * Redraw the status line or ruler of window "wp".
- * When "wp" is NULL redraw the tab pages line from 'tabline'.
- */
-static void win_redr_custom(win_T *wp, bool draw_ruler)
+/// Redraw the status line, window bar or ruler of window "wp".
+/// When "wp" is NULL redraw the tab pages line from 'tabline'.
+static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
{
static bool entered = false;
int attr;
@@ -5269,6 +5322,21 @@ static void win_redr_custom(win_T *wp, bool draw_ruler)
attr = HL_ATTR(HLF_TPF);
maxwidth = Columns;
use_sandbox = was_set_insecurely(wp, "tabline", 0);
+ } else if (draw_winbar) {
+ stl = (char_u *)((*wp->w_p_wbr != NUL) ? wp->w_p_wbr : p_wbr);
+ row = -1; // row zero is first row of text
+ col = 0;
+ grid = &wp->w_grid;
+ grid_adjust(&grid, &row, &col);
+
+ if (row < 0) {
+ return;
+ }
+
+ fillchar = wp->w_p_fcs_chars.wbr;
+ attr = (wp == curwin) ? HL_ATTR(HLF_WBR) : HL_ATTR(HLF_WBRNC);
+ maxwidth = wp->w_width_inner;
+ use_sandbox = was_set_insecurely(wp, "winbar", 0);
} else {
row = is_stl_global ? (Rows - p_ch - 1) : W_ENDROW(wp);
fillchar = fillchar_status(&attr, wp);
@@ -5504,85 +5572,6 @@ void check_for_delay(bool check_msg_scroll)
}
}
-/// (Re)allocates a window grid if size changed while in ext_multigrid mode.
-/// Updates size, offsets and handle for the grid regardless.
-///
-/// If "doclear" is true, don't try to copy from the old grid rather clear the
-/// resized grid.
-void win_grid_alloc(win_T *wp)
-{
- ScreenGrid *grid = &wp->w_grid;
- ScreenGrid *grid_allocated = &wp->w_grid_alloc;
-
- int rows = wp->w_height_inner;
- int cols = wp->w_width_inner;
- int total_rows = wp->w_height_outer;
- int total_cols = wp->w_width_outer;
-
- bool want_allocation = ui_has(kUIMultigrid) || wp->w_floating;
- bool has_allocation = (grid_allocated->chars != NULL);
-
- if (grid->Rows != rows) {
- wp->w_lines_valid = 0;
- xfree(wp->w_lines);
- wp->w_lines = xcalloc(rows + 1, sizeof(wline_T));
- }
-
- int was_resized = false;
- if (want_allocation && (!has_allocation
- || grid_allocated->Rows != total_rows
- || grid_allocated->Columns != total_cols)) {
- grid_alloc(grid_allocated, total_rows, total_cols,
- wp->w_grid_alloc.valid, false);
- grid_allocated->valid = true;
- if (wp->w_floating && wp->w_float_config.border) {
- wp->w_redr_border = true;
- }
- was_resized = true;
- } else if (!want_allocation && has_allocation) {
- // Single grid mode, all rendering will be redirected to default_grid.
- // Only keep track of the size and offset of the window.
- grid_free(grid_allocated);
- grid_allocated->valid = false;
- was_resized = true;
- } else if (want_allocation && has_allocation && !wp->w_grid_alloc.valid) {
- grid_invalidate(grid_allocated);
- grid_allocated->valid = true;
- }
-
- grid->Rows = rows;
- grid->Columns = cols;
-
- if (want_allocation) {
- grid->target = grid_allocated;
- grid->row_offset = wp->w_border_adj[0];
- grid->col_offset = wp->w_border_adj[3];
- } else {
- grid->target = &default_grid;
- grid->row_offset = wp->w_winrow;
- grid->col_offset = wp->w_wincol;
- }
-
- // send grid resize event if:
- // - a grid was just resized
- // - screen_resize was called and all grid sizes must be sent
- // - the UI wants multigrid event (necessary)
- if ((send_grid_resize || was_resized) && want_allocation) {
- ui_call_grid_resize(grid_allocated->handle,
- grid_allocated->Columns, grid_allocated->Rows);
- }
-}
-
-/// assign a handle to the grid. The grid need not be allocated.
-void grid_assign_handle(ScreenGrid *grid)
-{
- static int last_grid_handle = DEFAULT_GRID_HANDLE;
-
- // only assign a grid handle if not already
- if (grid->handle == 0) {
- grid->handle = ++last_grid_handle;
- }
-}
/// Resize the screen to Rows and Columns.
///
@@ -5590,7 +5579,7 @@ void grid_assign_handle(ScreenGrid *grid)
///
/// There may be some time between setting Rows and Columns and (re)allocating
/// default_grid arrays. This happens when starting up and when
-/// (manually) changing the shell size. Always use default_grid.Rows and
+/// (manually) changing the shell size. Always use default_grid.rows and
/// default_grid.Columns to access items in default_grid.chars[]. Use Rows
/// and Columns for positioning text etc. where the final size of the shell is
/// needed.
@@ -5611,8 +5600,8 @@ retry:
// when Rows and Columns have been set and we have started doing full
// screen stuff.
if ((default_grid.chars != NULL
- && Rows == default_grid.Rows
- && Columns == default_grid.Columns
+ && Rows == default_grid.rows
+ && Columns == default_grid.cols
)
|| Rows == 0
|| Columns == 0
@@ -5711,9 +5700,9 @@ void screenclear(void)
}
// blank out the default grid
- for (i = 0; i < default_grid.Rows; i++) {
+ for (i = 0; i < default_grid.rows; i++) {
grid_clear_line(&default_grid, default_grid.line_offset[i],
- default_grid.Columns, true);
+ default_grid.cols, true);
default_grid.line_wraps[i] = false;
}
@@ -5797,16 +5786,16 @@ void win_scroll_lines(win_T *wp, int row, int line_count)
}
// No lines are being moved, just draw over the entire area
- if (row + abs(line_count) >= wp->w_grid.Rows) {
+ 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.Columns);
+ 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.Columns);
+ wp->w_grid.rows, 0, wp->w_grid.cols);
}
}
@@ -5845,7 +5834,7 @@ void grid_ins_lines(ScreenGrid *grid, int row, int line_count, int end, int col,
// Shift line_offset[] line_count down to reflect the inserted lines.
// Clear the inserted lines.
for (i = 0; i < line_count; i++) {
- if (width != grid->Columns) {
+ if (width != grid->cols) {
// need to copy part of a line
j = end - 1 - i;
while ((j -= line_count) >= row) {
@@ -5863,7 +5852,7 @@ void grid_ins_lines(ScreenGrid *grid, int row, int line_count, int end, int col,
}
grid->line_offset[j + line_count] = temp;
grid->line_wraps[j + line_count] = false;
- grid_clear_line(grid, temp, grid->Columns, false);
+ grid_clear_line(grid, temp, grid->cols, false);
}
}
@@ -5894,7 +5883,7 @@ void grid_del_lines(ScreenGrid *grid, int row, int line_count, int end, int col,
// Now shift line_offset[] line_count up to reflect the deleted lines.
// Clear the inserted lines.
for (i = 0; i < line_count; i++) {
- if (width != grid->Columns) {
+ if (width != grid->cols) {
// need to copy part of a line
j = row + i;
while ((j += line_count) <= end - 1) {
@@ -5913,7 +5902,7 @@ void grid_del_lines(ScreenGrid *grid, int row, int line_count, int end, int col,
}
grid->line_offset[j - line_count] = temp;
grid->line_wraps[j - line_count] = false;
- grid_clear_line(grid, temp, grid->Columns, false);
+ grid_clear_line(grid, temp, grid->cols, false);
}
}
@@ -6220,7 +6209,7 @@ void draw_tabline(void)
// Check for an error. If there is one we would loop in redrawing the
// screen. Avoid that by making 'tabline' empty.
did_emsg = false;
- win_redr_custom(NULL, false);
+ win_redr_custom(NULL, false, false);
if (did_emsg) {
set_string_option_direct("tabline", -1,
(char_u *)"", OPT_FREE, SID_ERROR);
@@ -6516,7 +6505,7 @@ static void win_redr_ruler(win_T *wp, bool always)
int save_called_emsg = called_emsg;
called_emsg = false;
- win_redr_custom(wp, true);
+ win_redr_custom(wp, false, true);
if (called_emsg) {
set_string_option_direct("rulerformat", -1, (char_u *)"",
OPT_FREE, SID_ERROR);
@@ -6754,11 +6743,9 @@ static void margin_columns_win(win_T *wp, int *left_col, int *right_col)
/// Set dimensions of the Nvim application "shell".
void screen_resize(int width, int height)
{
- static bool recursive = false;
-
// Avoid recursiveness, can happen when setting the window size causes
// another window-changed signal.
- if (updating_screen || recursive) {
+ if (updating_screen || resizing_screen) {
return;
}
@@ -6780,7 +6767,7 @@ void screen_resize(int width, int height)
return;
}
- recursive = true;
+ resizing_screen = true;
Rows = height;
Columns = width;
@@ -6797,9 +6784,9 @@ void screen_resize(int width, int height)
send_grid_resize = true;
- /* The window layout used to be adjusted here, but it now happens in
- * screenalloc() (also invoked from screenclear()). That is because the
- * "recursive" check above may skip this, but not screenalloc(). */
+ /// The window layout used to be adjusted here, but it now happens in
+ /// screenalloc() (also invoked from screenclear()). That is because the
+ /// recursize "resizing_screen" check above may skip this, but not screenalloc().
if (State != MODE_ASKMORE && State != MODE_EXTERNCMD && State != MODE_CONFIRM) {
screenclear();
@@ -6858,7 +6845,7 @@ void screen_resize(int width, int height)
}
ui_flush();
}
- recursive = false;
+ resizing_screen = false;
}
/// Check if the new Nvim application "shell" dimensions are valid.
diff --git a/src/nvim/screen.h b/src/nvim/screen.h
index 3afbaa5eb6..f3beeff8a9 100644
--- a/src/nvim/screen.h
+++ b/src/nvim/screen.h
@@ -49,14 +49,22 @@ typedef struct {
} StlClickRecord;
/// Array defining what should be done when tabline is clicked
-extern StlClickDefinition *tab_page_click_defs;
+EXTERN StlClickDefinition *tab_page_click_defs INIT(= NULL);
/// Size of the tab_page_click_defs array
-extern long tab_page_click_defs_size;
+EXTERN long tab_page_click_defs_size INIT(= 0);
#define W_ENDCOL(wp) ((wp)->w_wincol + (wp)->w_width)
#define W_ENDROW(wp) ((wp)->w_winrow + (wp)->w_height)
+// While redrawing the screen this flag is set. It means the screen size
+// ('lines' and 'rows') must not be changed.
+EXTERN bool updating_screen INIT(= 0);
+
+// While resizing the screen this flag is set.
+EXTERN bool resizing_screen INIT(= 0);
+
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "screen.h.generated.h"
#endif
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 11d40c058c..40c64ce41d 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -204,31 +204,6 @@ char_u *get_search_pat(void)
return mr_pattern;
}
-/*
- * Reverse text into allocated memory.
- * Returns the allocated string.
- *
- * TODO(philix): move reverse_text() to strings.c
- */
-char_u *reverse_text(char_u *s) FUNC_ATTR_NONNULL_RET
-{
- /*
- * Reverse the pattern.
- */
- size_t len = STRLEN(s);
- char_u *rev = xmalloc(len + 1);
- size_t rev_i = len;
- for (size_t s_i = 0; s_i < len; s_i++) {
- const int mb_len = utfc_ptr2len((char *)s + s_i);
- rev_i -= mb_len;
- memmove(rev + rev_i, s + s_i, mb_len);
- s_i += mb_len - 1;
- }
- rev[len] = NUL;
-
- return rev;
-}
-
void save_re_pat(int idx, char_u *pat, int magic)
{
if (spats[idx].pat != pat) {
@@ -1990,13 +1965,13 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
clearpos(&match_pos);
// backward search: Check if this line contains a single-line comment
- if ((backwards && comment_dir)
- || lisp) {
+ if ((backwards && comment_dir) || lisp) {
comment_col = check_linecomment(linep);
}
if (lisp && comment_col != MAXCOL && pos.col > (colnr_T)comment_col) {
lispcomm = true; // find match inside this comment
}
+
while (!got_int) {
/*
* Go to the next position, forward or backward. We could use
@@ -2023,8 +1998,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
line_breakcheck();
// Check if this line contains a single-line comment
- if (comment_dir
- || lisp) {
+ if (comment_dir || lisp) {
comment_col = check_linecomment(linep);
}
// skip comment
@@ -2038,7 +2012,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
} else { // forward search
if (linep[pos.col] == NUL
// at end of line, go to next one
- // don't search for match in comment
+ // For lisp don't search for match in comment
|| (lisp && comment_col != MAXCOL
&& pos.col == (colnr_T)comment_col)) {
if (pos.lnum == curbuf->b_ml.ml_line_count // end of file
@@ -2348,8 +2322,8 @@ int check_linecomment(const char_u *line)
} else {
while ((p = (char_u *)vim_strchr((char *)p, '/')) != NULL) {
// Accept a double /, unless it's preceded with * and followed by *,
- // because * / / * is an end and start of a C comment.
- // Only accept the position if it is not inside a string.
+ // because * / / * is an end and start of a C comment. Only
+ // accept the position if it is not inside a string.
if (p[1] == '/' && (p == line || p[-1] != '*' || p[2] != '*')
&& !is_pos_in_string(line, (colnr_T)(p - line))) {
break;
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 1ba29e3fc1..df3ee73a28 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -443,7 +443,7 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou
MAXWLEN + 1);
mi.mi_fwordlen = (int)STRLEN(mi.mi_fword);
- if (camel_case) {
+ if (camel_case && mi.mi_fwordlen > 0) {
// introduce a fake word end space into the folded word.
mi.mi_fword[mi.mi_fwordlen - 1] = ' ';
}
diff --git a/src/nvim/strings.c b/src/nvim/strings.c
index c0c942ffd2..999e6801fb 100644
--- a/src/nvim/strings.c
+++ b/src/nvim/strings.c
@@ -634,12 +634,12 @@ static const void *tv_ptr(const typval_T *const tvs, int *const idxp)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
#define OFF(attr) offsetof(union typval_vval_union, attr)
- STATIC_ASSERT(OFF(v_string) == OFF(v_list)
+ STATIC_ASSERT(OFF(v_string) == OFF(v_list) // -V568
&& OFF(v_string) == OFF(v_dict)
&& OFF(v_string) == OFF(v_partial)
- && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_list) // -V568
- && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_dict) // -V568
- && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_partial), // -V568
+ && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_list)
+ && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_dict)
+ && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_partial),
"Strings, dictionaries, lists and partials are expected to be pointers, "
"so that all three of them can be accessed via v_string");
#undef OFF
@@ -1496,6 +1496,7 @@ int kv_do_printf(StringBuilder *str, const char *fmt, ...)
// printed string didn't fit, resize and try again
if ((size_t)printed >= remaining) {
kv_ensure_space(*str, (size_t)printed + 1); // include space for NUL terminator at the end
+ assert(str->items != NULL);
va_start(ap, fmt);
printed = vsnprintf(str->items + str->size, str->capacity - str->size, fmt, ap);
va_end(ap);
@@ -1507,3 +1508,24 @@ int kv_do_printf(StringBuilder *str, const char *fmt, ...)
str->size += (size_t)printed;
return printed;
}
+
+/// Reverse text into allocated memory.
+///
+/// @return the allocated string.
+char_u *reverse_text(char_u *s)
+ FUNC_ATTR_NONNULL_RET
+{
+ // Reverse the pattern.
+ size_t len = STRLEN(s);
+ char_u *rev = xmalloc(len + 1);
+ size_t rev_i = len;
+ for (size_t s_i = 0; s_i < len; s_i++) {
+ const int mb_len = utfc_ptr2len((char *)s + s_i);
+ rev_i -= (size_t)mb_len;
+ memmove(rev + rev_i, s + s_i, (size_t)mb_len);
+ s_i += (size_t)mb_len - 1;
+ }
+ rev[len] = NUL;
+
+ return rev;
+}
diff --git a/src/nvim/strings.h b/src/nvim/strings.h
index 0503cecc8a..9ef1eb5816 100644
--- a/src/nvim/strings.h
+++ b/src/nvim/strings.h
@@ -6,8 +6,8 @@
#include <string.h>
#include "nvim/eval/typval.h"
-#include "nvim/types.h"
#include "nvim/lib/kvec.h"
+#include "nvim/types.h"
/// Append string to string and return pointer to the next byte
///
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 2d3102707c..c8f70d4afd 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -1374,26 +1374,21 @@ static void fetch_row(Terminal *term, int row, int end_col)
while (col < end_col) {
VTermScreenCell cell;
fetch_cell(term, row, col, &cell);
- int cell_len = 0;
if (cell.chars[0]) {
+ int cell_len = 0;
for (int i = 0; cell.chars[i]; i++) {
cell_len += utf_char2bytes((int)cell.chars[i], ptr + cell_len);
}
- } else {
- *ptr = ' ';
- cell_len = 1;
- }
- char c = *ptr;
- ptr += cell_len;
- if (c != ' ') {
- // only increase the line length if the last character is not whitespace
+ ptr += cell_len;
line_len = (size_t)(ptr - term->textbuf);
+ } else {
+ *ptr++ = ' ';
}
col += cell.width;
}
- // trim trailing whitespace
- term->textbuf[line_len] = 0;
+ // end of line
+ term->textbuf[line_len] = NUL;
}
static bool fetch_cell(Terminal *term, int row, int col, VTermScreenCell *cell)
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index 759caac878..b2c752376f 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -1224,4 +1224,16 @@ func Test_screenpos_and_completion()
call feedkeys(":let a\<C-R>=Check_completion()\<CR>\<Esc>", "xt")
endfunc
+func Test_recursive_register()
+ let @= = ''
+ silent! ?e/
+ let caught = 'no'
+ try
+ normal //
+ catch /E169:/
+ let caught = 'yes'
+ endtry
+ call assert_equal('yes', caught)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_cursor_func.vim b/src/nvim/testdir/test_cursor_func.vim
index 9ba82e3b70..6c6a6290cb 100644
--- a/src/nvim/testdir/test_cursor_func.vim
+++ b/src/nvim/testdir/test_cursor_func.vim
@@ -102,10 +102,11 @@ func Test_screenpos()
bwipe!
call assert_equal({'col': 1, 'row': 1, 'endcol': 1, 'curscol': 1}, screenpos(win_getid(), 1, 1))
- " Needs WinBar
" nmenu WinBar.TEST :
- " call assert_equal({'col': 1, 'row': 2, 'endcol': 1, 'curscol': 1}, screenpos(win_getid(), 1, 1))
+ setlocal winbar=TEST
+ call assert_equal({'col': 1, 'row': 2, 'endcol': 1, 'curscol': 1}, screenpos(win_getid(), 1, 1))
" nunmenu WinBar.TEST
+ setlocal winbar&
endfunc
func Test_screenpos_number()
diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim
index 848666727f..bd080147fb 100644
--- a/src/nvim/testdir/test_edit.vim
+++ b/src/nvim/testdir/test_edit.vim
@@ -395,15 +395,13 @@ endfunc
func Test_edit_13()
" Test smartindenting
- if exists("+smartindent")
- new
- set smartindent autoindent
- call setline(1, ["\tabc"])
- call feedkeys("A {\<cr>more\<cr>}\<esc>", 'tnix')
- call assert_equal(["\tabc {", "\t\tmore", "\t}"], getline(1, '$'))
- set smartindent& autoindent&
- bwipe!
- endif
+ new
+ set smartindent autoindent
+ call setline(1, ["\tabc"])
+ call feedkeys("A {\<cr>more\<cr>}\<esc>", 'tnix')
+ call assert_equal(["\tabc {", "\t\tmore", "\t}"], getline(1, '$'))
+ set smartindent& autoindent&
+ bwipe!
" Test autoindent removing indent of blank line.
new
diff --git a/src/nvim/testdir/test_fold.vim b/src/nvim/testdir/test_fold.vim
index 9f5ad53adb..538b6b622e 100644
--- a/src/nvim/testdir/test_fold.vim
+++ b/src/nvim/testdir/test_fold.vim
@@ -217,6 +217,26 @@ func Test_update_folds_expr_read()
set foldmethod& foldexpr&
endfunc
+" Test for what patch 8.1.0535 fixes.
+func Test_foldexpr_no_interrupt_addsub()
+ new
+ func! FoldFunc()
+ call setpos('.', getcurpos())
+ return '='
+ endfunc
+
+ set foldmethod=expr
+ set foldexpr=FoldFunc()
+ call setline(1, '1.2')
+
+ exe "norm! $\<C-A>"
+ call assert_equal('1.3', getline(1))
+
+ bwipe!
+ delfunc FoldFunc
+ set foldmethod& foldexpr&
+endfunc
+
func Check_foldlevels(expected)
call assert_equal(a:expected, map(range(1, line('$')), 'foldlevel(v:val)'))
endfunc
@@ -901,4 +921,53 @@ func Test_fold_split()
bw!
endfunc
+" Make sure that when you append under a blank line that is under a fold with
+" the same indent level as your appended line, the fold expands across the
+" blank line
+func Test_indent_append_under_blank_line()
+ new
+ let lines =<< trim END
+ line 1
+ line 2
+ line 3
+ END
+ call setline(1, lines)
+ setlocal sw=2
+ setlocal foldmethod=indent foldenable
+ call assert_equal([0, 1, 1], range(1, 3)->map('foldlevel(v:val)'))
+ call append(3, '')
+ call append(4, ' line 5')
+ call assert_equal([0, 1, 1, 1, 1], range(1, 5)->map('foldlevel(v:val)'))
+ bw!
+endfunc
+
+" Make sure that when you delete 1 line of a fold whose length is 2 lines, the
+" fold can't be closed since its length (1) is now less than foldminlines.
+func Test_indent_one_line_fold_close()
+ let lines =<< trim END
+ line 1
+ line 2
+ line 3
+ END
+
+ new
+ setlocal sw=2 foldmethod=indent
+ call setline(1, lines)
+ " open all folds, delete line, then close all folds
+ normal zR
+ 3delete
+ normal zM
+ call assert_equal(-1, foldclosed(2)) " the fold should not be closed
+
+ " Now do the same, but delete line 2 this time; this covers different code.
+ " (Combining this code with the above code doesn't expose both bugs.)
+ 1,$delete
+ call setline(1, lines)
+ normal zR
+ 2delete
+ normal zM
+ call assert_equal(-1, foldclosed(2))
+ bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_mksession.vim b/src/nvim/testdir/test_mksession.vim
index 5dbe2cd366..c55ba391a5 100644
--- a/src/nvim/testdir/test_mksession.vim
+++ b/src/nvim/testdir/test_mksession.vim
@@ -838,6 +838,30 @@ func Test_mksession_shortmess()
set sessionoptions&
endfunc
+" Test that when Vim loading session has 'A' in 'shortmess' it does not
+" complain about an existing swapfile.
+func Test_mksession_shortmess_with_A()
+ edit Xtestfile
+ write
+ let fname = swapname('%')
+ " readblob() needs patch 8.2.2343
+ " let cont = readblob(fname)
+ let cont = readfile(fname, 'B')
+ set sessionoptions-=options
+ mksession Xtestsession
+ bwipe!
+
+ " Recreate the swap file to pretend the file is being edited
+ call writefile(cont, fname)
+ set shortmess+=A
+ source Xtestsession
+
+ set shortmess&
+ set sessionoptions&
+ call delete('Xtestsession')
+ call delete(fname)
+endfunc
+
" Test for mksession with 'compatible' option
func Test_mksession_compatible()
throw 'skipped: Nvim does not support "compatible" option'
diff --git a/src/nvim/testdir/test_tagjump.vim b/src/nvim/testdir/test_tagjump.vim
index e0b05edf15..2fe3c448d6 100644
--- a/src/nvim/testdir/test_tagjump.vim
+++ b/src/nvim/testdir/test_tagjump.vim
@@ -1077,6 +1077,15 @@ Type number and <Enter> (q or empty cancels):
%bwipe
endfunc
+func Test_define_search()
+ " this was accessing freed memory
+ new
+ call setline(1, ['first line', '', '#define something 0'])
+ sil norm o0
+ sil! norm 
+ bwipe!
+endfunc
+
" Test for the 'taglength' option
func Test_tag_length()
set tags=Xtags
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index 9e2d1f8e68..01583c032f 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -436,7 +436,7 @@ void ui_set_ext_option(UI *ui, UIExtension ext, bool active)
void ui_line(ScreenGrid *grid, int row, int startcol, int endcol, int clearcol, int clearattr,
bool wrap)
{
- assert(0 <= row && row < grid->Rows);
+ assert(0 <= row && row < grid->rows);
LineFlags flags = wrap ? kLineFlagWrap : 0;
if (startcol == -1) {
startcol = 0;
@@ -453,7 +453,7 @@ void ui_line(ScreenGrid *grid, int row, int startcol, int endcol, int clearcol,
if (p_wd && !(rdb_flags & RDB_COMPOSITOR)) {
// If 'writedelay' is active, set the cursor to indicate what was drawn.
ui_call_grid_cursor_goto(grid->handle, row,
- MIN(clearcol, (int)grid->Columns - 1));
+ MIN(clearcol, (int)grid->cols - 1));
ui_call_flush();
uint64_t wd = (uint64_t)labs(p_wd);
os_microdelay(wd * 1000u, true);
diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c
index f76158ff12..1dce84a1de 100644
--- a/src/nvim/ui_compositor.c
+++ b/src/nvim/ui_compositor.c
@@ -138,19 +138,19 @@ bool ui_comp_put_grid(ScreenGrid *grid, int row, int col, int height, int width,
// use it.
grid->comp_disabled = true;
compose_area(grid->comp_row, row,
- grid->comp_col, grid->comp_col + grid->Columns);
+ grid->comp_col, grid->comp_col + grid->cols);
if (grid->comp_col < col) {
compose_area(MAX(row, grid->comp_row),
- MIN(row + height, grid->comp_row + grid->Rows),
+ MIN(row + height, grid->comp_row + grid->rows),
grid->comp_col, col);
}
- if (col + width < grid->comp_col + grid->Columns) {
+ if (col + width < grid->comp_col + grid->cols) {
compose_area(MAX(row, grid->comp_row),
- MIN(row + height, grid->comp_row + grid->Rows),
- col + width, grid->comp_col + grid->Columns);
+ MIN(row + height, grid->comp_row + grid->rows),
+ col + width, grid->comp_col + grid->cols);
}
- compose_area(row + height, grid->comp_row + grid->Rows,
- grid->comp_col, grid->comp_col + grid->Columns);
+ compose_area(row + height, grid->comp_row + grid->rows,
+ grid->comp_col, grid->comp_col + grid->cols);
grid->comp_disabled = false;
}
grid->comp_row = row;
@@ -188,8 +188,8 @@ bool ui_comp_put_grid(ScreenGrid *grid, int row, int col, int height, int width,
grid->comp_index = insert_at;
}
if (moved && valid && ui_comp_should_draw()) {
- compose_area(grid->comp_row, grid->comp_row + grid->Rows,
- grid->comp_col, grid->comp_col + grid->Columns);
+ compose_area(grid->comp_row, grid->comp_row + grid->rows,
+ grid->comp_col, grid->comp_col + grid->cols);
}
return moved;
}
@@ -249,10 +249,10 @@ static void ui_comp_raise_grid(ScreenGrid *grid, size_t new_index)
for (size_t i = old_index; i < new_index; i++) {
ScreenGrid *grid2 = kv_A(layers, i);
int startcol = MAX(grid->comp_col, grid2->comp_col);
- int endcol = MIN(grid->comp_col + grid->Columns,
- grid2->comp_col + grid2->Columns);
+ int endcol = MIN(grid->comp_col + grid->cols,
+ grid2->comp_col + grid2->cols);
compose_area(MAX(grid->comp_row, grid2->comp_row),
- MIN(grid->comp_row + grid->Rows, grid2->comp_row + grid2->Rows),
+ MIN(grid->comp_row + grid->rows, grid2->comp_row + grid2->rows),
startcol, endcol);
}
}
@@ -279,7 +279,7 @@ static void ui_comp_grid_cursor_goto(UI *ui, Integer grid_handle, Integer r, Int
}
}
- if (cursor_col >= default_grid.Columns || cursor_row >= default_grid.Rows) {
+ if (cursor_col >= default_grid.cols || cursor_row >= default_grid.rows) {
// TODO(bfredl): this happens with 'writedelay', refactor?
// abort();
return;
@@ -292,8 +292,8 @@ ScreenGrid *ui_comp_mouse_focus(int row, int col)
for (ssize_t i = (ssize_t)kv_size(layers) - 1; i > 0; i--) {
ScreenGrid *grid = kv_A(layers, i);
if (grid->focusable
- && row >= grid->comp_row && row < grid->comp_row + grid->Rows
- && col >= grid->comp_col && col < grid->comp_col + grid->Columns) {
+ && row >= grid->comp_row && row < grid->comp_row + grid->rows
+ && col >= grid->comp_col && col < grid->comp_col + grid->cols) {
return grid;
}
}
@@ -315,7 +315,7 @@ static void compose_line(Integer row, Integer startcol, Integer endcol, LineFlag
startcol--;
skipstart = 1;
}
- if (endcol < default_grid.Columns && (flags & kLineFlagInvalid)) {
+ if (endcol < default_grid.cols && (flags & kLineFlagInvalid)) {
endcol++;
skipend = 1;
}
@@ -337,8 +337,8 @@ static void compose_line(Integer row, Integer startcol, Integer endcol, LineFlag
// first check to see if any grids have pending updates to width/height,
// to ensure that we don't accidentally put any characters into `linebuf`
// that have been invalidated.
- grid_width = MIN(g->Columns, g->comp_width);
- grid_height = MIN(g->Rows, g->comp_height);
+ grid_width = MIN(g->cols, g->comp_width);
+ grid_height = MIN(g->rows, g->comp_height);
if (g->comp_row > row || row >= g->comp_row + grid_height
|| g->comp_disabled) {
continue;
@@ -354,7 +354,7 @@ static void compose_line(Integer row, Integer startcol, Integer endcol, LineFlag
assert(grid != NULL);
assert(until > col);
- assert(until <= default_grid.Columns);
+ assert(until <= default_grid.cols);
size_t n = (size_t)(until - col);
if (row == msg_sep_row && grid->comp_index <= msg_grid.comp_index) {
@@ -371,7 +371,7 @@ static void compose_line(Integer row, Integer startcol, Integer endcol, LineFlag
+ (size_t)(col - grid->comp_col);
memcpy(linebuf + (col - startcol), grid->chars + off, n * sizeof(*linebuf));
memcpy(attrbuf + (col - startcol), grid->attrs + off, n * sizeof(*attrbuf));
- if (grid->comp_col + grid->Columns > until
+ if (grid->comp_col + grid->cols > until
&& grid->chars[off + n][0] == NUL) {
linebuf[until - 1 - startcol][0] = ' ';
linebuf[until - 1 - startcol][1] = '\0';
@@ -452,8 +452,8 @@ static void compose_debug(Integer startrow, Integer endrow, Integer startcol, In
return;
}
- endrow = MIN(endrow, default_grid.Rows);
- endcol = MIN(endcol, default_grid.Columns);
+ endrow = MIN(endrow, default_grid.rows);
+ endcol = MIN(endcol, default_grid.cols);
int attr = syn_id2attr(syn_id);
for (int row = (int)startrow; row < endrow; row++) {
@@ -480,8 +480,8 @@ static void debug_delay(Integer lines)
static void compose_area(Integer startrow, Integer endrow, Integer startcol, Integer endcol)
{
compose_debug(startrow, endrow, startcol, endcol, dbghl_recompose, true);
- endrow = MIN(endrow, default_grid.Rows);
- endcol = MIN(endcol, default_grid.Columns);
+ endrow = MIN(endrow, default_grid.rows);
+ endcol = MIN(endcol, default_grid.cols);
if (endcol <= startcol) {
return;
}
@@ -497,8 +497,8 @@ static void compose_area(Integer startrow, Integer endrow, Integer startcol, Int
void ui_comp_compose_grid(ScreenGrid *grid)
{
if (ui_comp_should_draw()) {
- compose_area(grid->comp_row, grid->comp_row + grid->Rows,
- grid->comp_col, grid->comp_col + grid->Columns);
+ compose_area(grid->comp_row, grid->comp_row + grid->rows,
+ grid->comp_col, grid->comp_col + grid->cols);
}
}
@@ -523,17 +523,17 @@ static void ui_comp_raw_line(UI *ui, Integer grid, Integer row, Integer startcol
// TODO(bfredl): this should not really be necessary. But on some condition
// when resizing nvim, a window will be attempted to be drawn on the older
// and possibly larger global screen size.
- if (row >= default_grid.Rows) {
+ if (row >= default_grid.rows) {
DLOG("compositor: invalid row %" PRId64 " on grid %" PRId64, row, grid);
return;
}
- if (clearcol > default_grid.Columns) {
+ if (clearcol > default_grid.cols) {
DLOG("compositor: invalid last column %" PRId64 " on grid %" PRId64,
clearcol, grid);
- if (startcol >= default_grid.Columns) {
+ if (startcol >= default_grid.cols) {
return;
}
- clearcol = default_grid.Columns;
+ clearcol = default_grid.cols;
endcol = MIN(endcol, clearcol);
}
@@ -581,7 +581,7 @@ static void ui_comp_msg_set_pos(UI *ui, Integer grid, Integer row, Boolean scrol
}
if (row > msg_current_row && ui_comp_should_draw()) {
- compose_area(MAX(msg_current_row - 1, 0), row, 0, default_grid.Columns);
+ compose_area(MAX(msg_current_row - 1, 0), row, 0, default_grid.cols);
} else if (row < msg_current_row && ui_comp_should_draw()
&& msg_current_row < Rows) {
int delta = msg_current_row - (int)row;
diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c
index 41b4a7edd6..fd7dc17ee3 100644
--- a/src/nvim/viml/parser/expressions.c
+++ b/src/nvim/viml/parser/expressions.c
@@ -2646,6 +2646,7 @@ viml_pexpr_parse_figure_brace_closing_error:
kvi_push(pt_stack, kEPTLambdaArguments);
lambda_node = cur_node;
} else {
+ // uncrustify:off
ADD_IDENT(do {
NEW_NODE_WITH_CUR_POS(cur_node,
kExprNodeCurlyBracesIdentifier);
@@ -2660,6 +2661,7 @@ viml_pexpr_parse_figure_brace_closing_error:
want_node = kENodeValue;
} while (0),
Curly);
+ // uncrustify:on
}
if (pt_is_assignment(cur_pt)
&& !pt_is_assignment(kv_last(pt_stack))) {
@@ -2737,6 +2739,7 @@ viml_pexpr_parse_figure_brace_closing_error:
: HL(IdentifierName)));
} else {
if (scope == kExprVarScopeMissing) {
+ // uncrustify:off
ADD_IDENT(do {
NEW_NODE_WITH_CUR_POS(cur_node, kExprNodePlainIdentifier);
cur_node->data.var.scope = scope;
@@ -2745,6 +2748,7 @@ viml_pexpr_parse_figure_brace_closing_error:
want_node = kENodeOperator;
} while (0),
IdentifierName);
+ // uncrustify:on
} else {
OP_MISSING;
}
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 2c27a5d6a5..4076bb2531 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -515,9 +515,14 @@ wingotofile:
if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0) {
break;
}
+
+ // Make a copy, if the line was changed it will be freed.
+ ptr = vim_strnsave(ptr, len);
+
find_pattern_in_path(ptr, 0, len, true, Prenum == 0,
type, Prenum1, ACTION_SPLIT, 1, MAXLNUM);
- curwin->w_set_curswant = TRUE;
+ xfree(ptr);
+ curwin->w_set_curswant = true;
break;
// Quickfix window only: view the result under the cursor in a new split.
@@ -695,6 +700,7 @@ win_T *win_new_float(win_T *wp, bool last, FloatConfig fconfig, Error *err)
}
wp->w_floating = 1;
wp->w_status_height = 0;
+ wp->w_winbar_height = 0;
wp->w_hsep_height = 0;
wp->w_vsep_width = 0;
@@ -780,10 +786,8 @@ void win_config_float(win_T *wp, FloatConfig fconfig)
}
if (!ui_has(kUIMultigrid)) {
- wp->w_height = MIN(wp->w_height,
- Rows - 1 - (wp->w_border_adj[0] + wp->w_border_adj[2]));
- wp->w_width = MIN(wp->w_width,
- Columns - (wp->w_border_adj[1] + wp->w_border_adj[3]));
+ wp->w_height = MIN(wp->w_height, Rows - 1 - win_extra_height(wp));
+ wp->w_width = MIN(wp->w_width, Columns - win_extra_width(wp));
}
win_set_inner_size(wp);
@@ -1138,15 +1142,12 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
} else {
layout = FR_COL;
- /*
- * Check if we are able to split the current window and compute its
- * height.
- */
- // Current window requires at least 1 space.
- wmh1 = p_wmh == 0 ? 1 : p_wmh;
+ // Check if we are able to split the current window and compute its height.
+ // Current window requires at least 1 space plus space for the window bar.
+ wmh1 = MAX(p_wmh, 1) + oldwin->w_winbar_height;
needed = wmh1 + STATUS_HEIGHT;
if (flags & WSP_ROOM) {
- needed += p_wh - wmh1;
+ needed += p_wh - wmh1 + oldwin->w_winbar_height;
}
if (flags & (WSP_BOT | WSP_TOP)) {
minheight = frame_minheight(topframe, NOWIN) + need_status;
@@ -1155,8 +1156,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
} else if (p_ea) {
minheight = frame_minheight(oldwin->w_frame, NOWIN) + need_status;
prevfrp = oldwin->w_frame;
- for (frp = oldwin->w_frame->fr_parent; frp != NULL;
- frp = frp->fr_parent) {
+ for (frp = oldwin->w_frame->fr_parent; frp != NULL; frp = frp->fr_parent) {
if (frp->fr_layout == FR_COL) {
FOR_ALL_FRAMES(frp2, frp->fr_child) {
if (frp2 != prevfrp) {
@@ -1339,6 +1339,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
set_fraction(oldwin);
}
wp->w_fraction = oldwin->w_fraction;
+ wp->w_winbar_height = oldwin->w_winbar_height;
if (flags & WSP_VERT) {
wp->w_p_scr = curwin->w_p_scr;
@@ -1416,9 +1417,9 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
if (flags & (WSP_TOP | WSP_BOT)) {
int new_fr_height = curfrp->fr_height - new_size;
- if (!((flags & WSP_BOT) && p_ls == 0) && global_stl_height() == 0) {
+ if (!((flags & WSP_BOT) && p_ls == 0) && !is_stl_global) {
new_fr_height -= STATUS_HEIGHT;
- } else if (global_stl_height() > 0) {
+ } else if (is_stl_global) {
if (flags & WSP_BOT) {
frame_add_hsep(curfrp);
} else {
@@ -1452,7 +1453,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
}
}
}
- if ((flags & WSP_BOT) && global_stl_height() == 0) {
+ if ((flags & WSP_BOT) && !is_stl_global) {
frame_add_statusline(curfrp);
}
frame_fix_height(wp);
@@ -1482,10 +1483,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
* equalize the window sizes.
*/
if (do_equal || dir != 0) {
- win_equal(wp, true,
- (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h')
- : dir == 'h' ? 'b' :
- 'v');
+ win_equal(wp, true, (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h') : (dir == 'h' ? 'b' : 'v'));
}
// Don't change the window height/width to 'winheight' / 'winwidth' if a
@@ -1675,10 +1673,10 @@ int win_count(void)
}
/// Make "count" windows on the screen.
-/// Must be called when there is just one window, filling the whole screen
+/// Must be called when there is just one window, filling the whole screen.
/// (excluding the command line).
///
-/// @param vertical split windows vertically if true
+/// @param vertical split windows vertically if true.
///
/// @return actual number of windows on the screen.
int make_windows(int count, bool vertical)
@@ -1687,15 +1685,15 @@ int make_windows(int count, bool vertical)
int todo;
if (vertical) {
- // Each window needs at least 'winminwidth' lines and a separator
- // column.
+ // Each window needs at least 'winminwidth' lines and a separator column.
maxcount = (curwin->w_width + curwin->w_vsep_width
- (p_wiw - p_wmw)) / (p_wmw + 1);
} else {
- // Each window needs at least 'winminheight' lines
- // If statusline isn't global, each window also needs a statusline
+ // Each window needs at least 'winminheight' lines.
+ // If statusline isn't global, each window also needs a statusline.
+ // If 'winbar' is set, each window also needs a winbar.
maxcount = (curwin->w_height + curwin->w_hsep_height + curwin->w_status_height
- - (p_wh - p_wmh)) / (p_wmh + STATUS_HEIGHT);
+ - (p_wh - p_wmh)) / (p_wmh + STATUS_HEIGHT + global_winbar_height());
}
if (maxcount < 2) {
@@ -1705,17 +1703,13 @@ int make_windows(int count, bool vertical)
count = maxcount;
}
- /*
- * add status line now, otherwise first window will be too big
- */
+ // add status line now, otherwise first window will be too big
if (count > 1) {
last_status(true);
}
- /*
- * Don't execute autocommands while creating the windows. Must do that
- * when putting the buffers in the windows.
- */
+ // Don't execute autocommands while creating the windows. Must do that
+ // when putting the buffers in the windows.
block_autocmds();
// todo is number of windows left to create
@@ -1790,7 +1784,7 @@ static void win_exchange(long Prenum)
* if wp != wp2
* 3. remove wp from the list
* 4. insert wp after wp2
- * 5. exchange the status line height, hsep height and vsep width.
+ * 5. exchange the status line height, winbar height, hsep height and vsep width.
*/
wp2 = curwin->w_prev;
frp2 = curwin->w_frame->fr_prev;
@@ -1897,7 +1891,7 @@ static void win_rotate(bool upwards, int count)
frame_insert(frp->fr_parent->fr_child, frp);
}
- // exchange status height, hsep height and vsep width of old and new last window
+ // exchange status height, winbar height, hsep height and vsep width of old and new last window
n = wp2->w_status_height;
wp2->w_status_height = wp1->w_status_height;
wp1->w_status_height = n;
@@ -1988,7 +1982,8 @@ void win_move_after(win_T *win1, win_T *win2)
return;
}
- // may need move the status line, horizontal or vertical separator of the last window
+ // may need move the status line, window bar, horizontal or vertical separator of the last
+ // window
if (win1 == lastwin) {
height = win1->w_prev->w_status_height;
win1->w_prev->w_status_height = win1->w_status_height;
@@ -2038,6 +2033,37 @@ void win_move_after(win_T *win1, win_T *win2)
win2->w_pos_changed = true;
}
+/// Compute maximum number of windows that can fit within "height" in frame "fr".
+static int get_maximum_wincount(frame_T *fr, int height)
+{
+ if (fr->fr_layout != FR_COL) {
+ return (height / (p_wmh + STATUS_HEIGHT + frame2win(fr)->w_winbar_height));
+ } else if (global_winbar_height()) {
+ // If winbar is globally enabled, no need to check each window for it.
+ return (height / (p_wmh + STATUS_HEIGHT + 1));
+ }
+
+ frame_T *frp;
+ int total_wincount = 0;
+
+ // First, try to fit all child frames of "fr" into "height"
+ FOR_ALL_FRAMES(frp, fr->fr_child) {
+ win_T *wp = frame2win(frp);
+
+ if (height < (p_wmh + STATUS_HEIGHT + wp->w_winbar_height)) {
+ break;
+ }
+ height -= p_wmh + STATUS_HEIGHT + wp->w_winbar_height;
+ total_wincount += 1;
+ }
+
+ // If we still have enough room for more windows, just use the default winbar height (which is 0)
+ // in order to get the amount of windows that'd fit in the remaining space
+ total_wincount += height / (p_wmh + STATUS_HEIGHT);
+
+ return total_wincount;
+}
+
/// Make all windows the same height.
///'next_curwin' will soon be the current window, make sure it has enough rows.
///
@@ -2237,7 +2263,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
} else {
extra_sep = 0;
}
- totwincount = (n + extra_sep) / (p_wmh + STATUS_HEIGHT);
+ totwincount = get_maximum_wincount(topfr, n + extra_sep);
has_next_curwin = frame_has_win(topfr, next_curwin);
/*
@@ -2271,8 +2297,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
}
} else {
// These windows don't use up room.
- totwincount -= (n + (fr->fr_next == NULL
- ? extra_sep : 0)) / (p_wmh + STATUS_HEIGHT);
+ totwincount -= get_maximum_wincount(fr, (n + (fr->fr_next == NULL ? extra_sep : 0)));
}
room -= new_size - n;
if (room < 0) {
@@ -2317,8 +2342,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
} else {
// Compute the maximum number of windows vert. in "fr".
n = frame_minheight(fr, NOWIN);
- wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
- / (p_wmh + STATUS_HEIGHT);
+ wincount = get_maximum_wincount(fr, (n + (fr->fr_next == NULL ? extra_sep : 0)));
m = frame_minheight(fr, next_curwin);
if (has_next_curwin) {
hnc = frame_has_win(fr, next_curwin);
@@ -3732,13 +3756,9 @@ static void frame_fix_height(win_T *wp)
wp->w_frame->fr_height = wp->w_height + wp->w_hsep_height + wp->w_status_height;
}
-/*
- * Compute the minimal height for frame "topfrp".
- * Uses the 'winminheight' option.
- * When "next_curwin" isn't NULL, use p_wh for this window.
- * When "next_curwin" is NOWIN, don't use at least one line for the current
- * window.
- */
+/// Compute the minimal height for frame "topfrp". Uses the 'winminheight' option.
+/// When "next_curwin" isn't NULL, use p_wh for this window.
+/// When "next_curwin" is NOWIN, don't use at least one line for the current window.
static int frame_minheight(frame_T *topfrp, win_T *next_curwin)
{
frame_T *frp;
@@ -3746,12 +3766,14 @@ static int frame_minheight(frame_T *topfrp, win_T *next_curwin)
int n;
if (topfrp->fr_win != NULL) {
+ // Combined height of window bar and separator column or status line.
+ int extra_height = topfrp->fr_win->w_winbar_height + topfrp->fr_win->w_hsep_height
+ + topfrp->fr_win->w_status_height;
+
if (topfrp->fr_win == next_curwin) {
- m = p_wh + topfrp->fr_win->w_hsep_height + topfrp->fr_win->w_status_height;
+ m = p_wh + extra_height;
} else {
- // window: minimal height of the window plus separator column or status line
- // depending on whether global statusline is enabled
- m = p_wmh + topfrp->fr_win->w_hsep_height + topfrp->fr_win->w_status_height;
+ m = p_wmh + extra_height;
if (topfrp->fr_win == curwin && next_curwin == NULL) {
// Current window is minimal one line high.
if (p_wmh == 0) {
@@ -3976,7 +3998,7 @@ static void new_frame(win_T *wp)
void win_init_size(void)
{
firstwin->w_height = ROWS_AVAIL;
- firstwin->w_height_inner = firstwin->w_height;
+ firstwin->w_height_inner = firstwin->w_height - firstwin->w_winbar_height;
firstwin->w_height_outer = firstwin->w_height;
topframe->fr_height = ROWS_AVAIL;
firstwin->w_width = Columns;
@@ -4087,6 +4109,7 @@ int win_new_tabpage(int after, char_u *filename)
newtp->tp_topframe = topframe;
last_status(false);
+ set_winbar();
redraw_all_later(NOT_VALID);
@@ -5460,16 +5483,9 @@ void win_setheight(int height)
*/
void win_setheight_win(int height, win_T *win)
{
- if (win == curwin) {
- // Always keep current window at least one line high, even when
- // 'winminheight' is zero.
- if (height < p_wmh) {
- height = p_wmh;
- }
- if (height == 0) {
- height = 1;
- }
- }
+ // Always keep current window at least one line high, even when 'winminheight' is zero.
+ // Keep window at least two lines high if 'winbar' is enabled.
+ height = MAX(height, (win == curwin ? MAX(p_wmh, 1) : p_wmh) + win->w_winbar_height);
if (win->w_floating) {
win->w_float_config.height = height;
@@ -6262,7 +6278,7 @@ void win_set_inner_size(win_T *wp)
int prev_height = wp->w_height_inner;
int height = wp->w_height_request;
if (height == 0) {
- height = wp->w_height;
+ height = wp->w_height - wp->w_winbar_height;
}
if (height != prev_height) {
@@ -6279,8 +6295,8 @@ void win_set_inner_size(win_T *wp)
set_fraction(wp);
}
}
- wp->w_height_inner = height;
wp->w_skipcol = 0;
+ wp->w_height_inner = height;
// There is no point in adjusting the scroll position when exiting. Some
// values might be invalid.
@@ -6306,10 +6322,20 @@ void win_set_inner_size(win_T *wp)
terminal_check_size(wp->w_buffer->terminal);
}
- wp->w_height_outer = (wp->w_height_inner
- + wp->w_border_adj[0] + wp->w_border_adj[2]);
- wp->w_width_outer = (wp->w_width_inner
- + wp->w_border_adj[1] + wp->w_border_adj[3]);
+ wp->w_height_outer = (wp->w_height_inner + win_extra_height(wp));
+ wp->w_width_outer = (wp->w_width_inner + win_extra_width(wp));
+ wp->w_winrow_off = wp->w_border_adj[0] + wp->w_winbar_height;
+ wp->w_wincol_off = wp->w_border_adj[3];
+}
+
+static int win_extra_height(win_T *wp)
+{
+ return wp->w_border_adj[0] + wp->w_border_adj[2] + wp->w_winbar_height;
+}
+
+static int win_extra_width(win_T *wp)
+{
+ return wp->w_border_adj[1] + wp->w_border_adj[3];
}
/// Set the width of a window.
@@ -6662,6 +6688,19 @@ static void last_status_rec(frame_T *fr, bool statusline, bool is_stl_global)
}
}
+// Add or remove window bars from windows depending on the value of 'winbar'.
+void set_winbar(void)
+{
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ int winbar_height = (*p_wbr != NUL || *wp->w_p_wbr != NUL) ? 1 : 0;
+ if (wp->w_winbar_height != winbar_height) {
+ wp->w_winbar_height = winbar_height;
+ win_set_inner_size(wp);
+ wp->w_redr_winbar = winbar_height;
+ }
+ }
+}
+
/// Return the number of lines used by the tab page line.
int tabline_height(void)
{
@@ -6678,6 +6717,12 @@ int tabline_height(void)
return 1;
}
+/// Return the number of lines used by default by the window bar.
+int global_winbar_height(void)
+{
+ return *p_wbr != NUL ? 1 : 0;
+}
+
/// Return the number of lines used by the global statusline
int global_stl_height(void)
{