aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/clint.py313
-rw-r--r--src/coverity-model.c69
-rw-r--r--src/nvim/api/autocmd.c12
-rw-r--r--src/nvim/api/extmark.c35
-rw-r--r--src/nvim/api/keysets.lua2
-rw-r--r--src/nvim/api/private/helpers.c11
-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.c27
-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.h26
-rw-r--r--src/nvim/change.c18
-rw-r--r--src/nvim/change.h11
-rw-r--r--src/nvim/edit.c70
-rw-r--r--src/nvim/eval.c9
-rw-r--r--src/nvim/eval/funcs.c33
-rw-r--r--src/nvim/eval/userfunc.c1
-rw-r--r--src/nvim/event/loop.c2
-rw-r--r--src/nvim/ex_cmds.c15
-rw-r--r--src/nvim/ex_docmd.c45
-rw-r--r--src/nvim/ex_docmd.h1
-rw-r--r--src/nvim/ex_getln.c17
-rw-r--r--src/nvim/ex_session.c13
-rw-r--r--src/nvim/fold.c26
-rw-r--r--src/nvim/fold.h1
-rw-r--r--src/nvim/getchar.c12
-rw-r--r--src/nvim/globals.h9
-rw-r--r--src/nvim/grid.c137
-rw-r--r--src/nvim/grid_defs.h22
-rw-r--r--src/nvim/highlight_defs.h6
-rw-r--r--src/nvim/highlight_group.c2
-rw-r--r--src/nvim/main.c5
-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.c35
-rw-r--r--src/nvim/move.c4
-rw-r--r--src/nvim/normal.c196
-rw-r--r--src/nvim/ops.c12
-rw-r--r--src/nvim/option.c65
-rw-r--r--src/nvim/option_defs.h11
-rw-r--r--src/nvim/options.lua22
-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/po/check.vim6
-rw-r--r--src/nvim/popupmnu.c4
-rw-r--r--src/nvim/quickfix.c4
-rw-r--r--src/nvim/screen.c475
-rw-r--r--src/nvim/screen.h30
-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/testdir/test_bufline.vim35
-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.vim39
-rw-r--r--src/nvim/testdir/test_filetype.vim63
-rw-r--r--src/nvim/testdir/test_fold.vim88
-rw-r--r--src/nvim/testdir/test_mksession.vim24
-rw-r--r--src/nvim/testdir/test_normal.vim9
-rw-r--r--src/nvim/testdir/test_tagjump.vim9
-rw-r--r--src/nvim/testdir/test_textformat.vim19
-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.c234
72 files changed, 1436 insertions, 1274 deletions
diff --git a/src/clint.py b/src/clint.py
index b0992fcd63..944946bd16 100755
--- a/src/clint.py
+++ b/src/clint.py
@@ -49,7 +49,6 @@ import re
import sre_compile
import string
import sys
-import unicodedata
import json
import collections # for defaultdict
@@ -173,12 +172,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',
@@ -189,7 +185,6 @@ _ERROR_CATEGORIES = [
'readability/increment',
'runtime/arrays',
'runtime/int',
- 'runtime/invalid_increment',
'runtime/memset',
'runtime/printf',
'runtime/printf_format',
@@ -197,20 +192,13 @@ _ERROR_CATEGORIES = [
'runtime/deprecated',
'syntax/parenthesis',
'whitespace/alignment',
- 'whitespace/blank_line',
'whitespace/braces',
'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 +208,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 +339,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.."""
@@ -932,7 +825,6 @@ BRACES = {
'(': ')',
'{': '}',
'[': ']',
- # '<': '>', C++-specific pair removed
}
@@ -1253,24 +1145,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.
@@ -2156,7 +2030,6 @@ def CheckSpacing(filename, clean_lines, linenum, error):
# for the case where the previous line is indented 6 spaces, which
# may happen when the initializers of a constructor do not fit into
# a 80 column line.
- exception = False
if Match(r' {6}\w', prev_line): # Initializer list?
# We are looking for the opening column of initializer list,
# which should be indented 4 spaces to cause 6 space indentation
@@ -2165,39 +2038,6 @@ def CheckSpacing(filename, clean_lines, linenum, error):
while (search_position >= 0
and Match(r' {6}\w', elided[search_position])):
search_position -= 1
- exception = (search_position >= 0
- and elided[search_position][:5] == ' :')
- else:
- # Search for the function arguments or an initializer list. We
- # use a simple heuristic here: If the line is indented 4 spaces;
- # and we have a closing paren, without the opening paren,
- # followed by an opening brace or colon (for initializer lists)
- # we assume that it is the last line of a function header. If
- # we have a colon indented 4 spaces, it is an initializer list.
- exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)',
- prev_line)
- or Match(r' {4}:', prev_line))
-
- if not exception:
- error(filename, linenum, 'whitespace/blank_line', 2,
- 'Redundant blank line at the start of a code block '
- 'should be deleted.')
- # Ignore blank lines at the end of a block in a long if-else
- # chain, like this:
- # if (condition1) {
- # // Something followed by a blank line
- #
- # } else if (condition2) {
- # // Something else
- # }
- if linenum + 1 < clean_lines.NumLines():
- next_line = raw[linenum + 1]
- if (next_line
- and Match(r'\s*}', next_line)
- and next_line.find('} else ') == -1):
- error(filename, linenum, 'whitespace/blank_line', 3,
- 'Redundant blank line at the end of a code block '
- 'should be deleted.')
# Next, we complain if there's a comment too near the text
commentpos = line.find('//')
@@ -2334,12 +2174,6 @@ def CheckSpacing(filename, clean_lines, linenum, error):
error(filename, linenum, 'whitespace/operators', 4,
'Extra space for operator %s' % match.group(1))
- # A pet peeve of mine: no spaces after an if, while, switch, or for
- match = Search(r' (if\(|for\(|while\(|switch\()', line)
- if match:
- error(filename, linenum, 'whitespace/parens', 5,
- 'Missing space before ( in %s' % match.group(1))
-
# For if/for/while/switch, the left and right parens should be
# consistent about how many spaces are inside the parens, and
# there should either be zero or one spaces inside the parens.
@@ -2407,9 +2241,6 @@ def CheckSpacing(filename, clean_lines, linenum, error):
for offset in range(endlinenum + 1,
min(endlinenum + 3, clean_lines.NumLines() - 1)):
trailing_text += clean_lines.elided[offset]
- if not Match(r'^[\s}]*[{.;,)<\]]', trailing_text):
- error(filename, linenum, 'whitespace/braces', 5,
- 'Missing space before {')
# Make sure '} else {' has spaces.
if Search(r'}else', line):
@@ -2429,18 +2260,6 @@ def CheckSpacing(filename, clean_lines, linenum, error):
error(filename, linenum, 'whitespace/braces', 5,
'Missing space before }')
- if Search(r'\S {2,}\\$', line):
- error(filename, linenum, 'whitespace/line_continuation', 5,
- 'Too many spaces before \\, line continuation character must be '
- 'preceded by exactly one space. For “blank lines” '
- 'it is preferred to use the same amount of spaces as preceding '
- 'indent')
-
- if Match(r'^ +#', line):
- error(filename, linenum, 'whitespace/indent', 5,
- 'Must not indent preprocessor directives, use 1-space indent '
- 'after the hash')
-
cast_line = re.sub(r'^# *define +\w+\([^)]*\)', '', line)
match = Search(r'(?<!\bkvec_t)'
r'(?<!\bkvec_withinit_t)'
@@ -2717,65 +2536,6 @@ def CheckBraces(filename, clean_lines, linenum, error):
"You don't need a ; after a }")
-def CheckEmptyBlockBody(filename, clean_lines, linenum, error):
- """Look for empty loop/conditional body with only a single semicolon.
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- linenum: The number of the line to check.
- error: The function to call with any errors found.
- """
-
- # Search for loop keywords at the beginning of the line. Because only
- # whitespaces are allowed before the keywords, this will also ignore most
- # do-while-loops, since those lines should start with closing brace.
- #
- # We also check "if" blocks here, since an empty conditional block
- # is likely an error.
- line = clean_lines.elided[linenum]
- matched = Match(r'\s*(for|while|if)\s*\(', line)
- if matched:
- # Find the end of the conditional expression
- (end_line, end_linenum, end_pos) = CloseExpression(
- clean_lines, linenum, line.find('('))
-
- # Output warning if what follows the condition expression is a
- # semicolon. No warning for all other cases, including whitespace or
- # newline, since we have a separate check for semicolons preceded by
- # whitespace.
- if end_pos >= 0 and Match(r';', end_line[end_pos:]):
- if matched.group(1) == 'if':
- error(filename, end_linenum,
- 'whitespace/empty_conditional_body', 5,
- 'Empty conditional bodies should use {}')
- else:
- error(filename, end_linenum, 'whitespace/empty_loop_body', 5,
- 'Empty loop bodies should use {} or continue')
-
-
-def GetLineWidth(line):
- """Determines the width of the line in column positions.
-
- Args:
- line: A string, which may be a Unicode string.
-
- Returns:
- The width of the line in column positions, accounting for Unicode
- combining characters and wide characters.
- """
- if isinstance(line, str):
- width = 0
- for uc in unicodedata.normalize('NFC', line):
- if unicodedata.east_asian_width(uc) in ('W', 'F'):
- width += 2
- elif not unicodedata.combining(uc):
- width += 1
- return width
- else:
- return len(line)
-
-
def CheckStyle(filename, clean_lines, linenum, error):
"""Checks rules from the 'C++ style rules' section of cppguide.html.
@@ -2796,10 +2556,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 +2571,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).
@@ -2842,45 +2589,12 @@ def CheckStyle(filename, clean_lines, linenum, error):
# Some more style checks
CheckBraces(filename, clean_lines, linenum, error)
- CheckEmptyBlockBody(filename, clean_lines, linenum, error)
CheckSpacing(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 +2652,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 +2662,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 +2670,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 +2827,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 +2836,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 +2858,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 +2885,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 +2915,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 e05d80812d..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);
@@ -366,12 +366,11 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
/// Creates or updates an extmark.
///
-/// To create a new extmark, pass id=0. The extmark id will be returned.
-/// To move an existing mark, pass its id.
-///
-/// It is also allowed to create a new mark by passing in a previously unused
-/// id, but the caller must then keep track of existing and unused ids itself.
-/// (Useful over RPC, to avoid waiting for the return value.)
+/// By default a new extmark is created when no id is passed in, but it is also
+/// possible to create a new mark by passing in a previously unused id or move
+/// an existing mark by passing in its id. The caller must then keep track of
+/// existing and unused ids itself. (Useful over RPC, to avoid waiting for the
+/// return value.)
///
/// Using the optional arguments, it is possible to use this to highlight
/// a range of text, and also to associate virtual text to the mark.
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..adabb1471e 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";
}
}
@@ -1616,7 +1616,7 @@ void create_user_command(String name, Object command, Dict(user_command) *opts,
if (uc_add_command(name.data, name.size, rep, argt, def, flags, compl, compl_arg, compl_luaref,
addr_type_arg, luaref, force) != OK) {
api_set_error(err, kErrorTypeException, "Failed to create user command");
- goto err;
+ // Do not goto err, since uc_add_command now owns luaref, compl_luaref, and compl_arg
}
return;
@@ -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 b8f7b33cd5..e71f1a11ec 100644
--- a/src/nvim/api/vimscript.c
+++ b/src/nvim/api/vimscript.c
@@ -1304,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..b5980612f8 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -6,6 +6,8 @@
// for FILE
#include <stdio.h>
+#include "grid_defs.h"
+
typedef struct file_buffer buf_T; // Forward declaration
// Reference to a buffer that stores the value of buf_free_count.
@@ -233,6 +235,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 +1239,7 @@ struct window_S {
struct {
int stl;
int stlnc;
+ int wbr;
int horiz;
int horizup;
int horizdown;
@@ -1282,14 +1287,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;
@@ -1378,7 +1389,7 @@ struct window_S {
// w_redr_type is REDRAW_TOP
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_status; // if true statusline/winbar 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 +1419,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
@@ -1481,6 +1493,16 @@ struct window_S {
// Location list reference used in the location list window.
// In a non-location list window, w_llist_ref is NULL.
qf_info_T *w_llist_ref;
+
+ // Status line click definitions
+ StlClickDefinition *w_status_click_defs;
+ // Size of the w_status_click_defs array
+ size_t w_status_click_defs_size;
+
+ // Window bar click definitions
+ StlClickDefinition *w_winbar_click_defs;
+ // Size of the w_winbar_click_defs array
+ size_t w_winbar_click_defs_size;
};
static inline int win_hl_attr(win_T *wp, int hlf)
diff --git a/src/nvim/change.c b/src/nvim/change.c
index 94e5a19edc..c1fe5bc405 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,
@@ -1189,7 +1188,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
if (flags & OPENLINE_DO_COM) {
lead_len = get_leader_len(saved_line, &lead_flags, dir == BACKWARD, true);
if (lead_len == 0 && curbuf->b_p_cin && do_cindent && dir == FORWARD
- && !has_format_option(FO_NO_OPEN_COMS)) {
+ && (!has_format_option(FO_NO_OPEN_COMS) || (flags & OPENLINE_FORMAT))) {
// Check for a line comment after code.
comment_start = check_linecomment(saved_line);
if (comment_start != MAXCOL) {
@@ -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/change.h b/src/nvim/change.h
index e7c8a2b031..fdfa8a29ec 100644
--- a/src/nvim/change.h
+++ b/src/nvim/change.h
@@ -5,11 +5,12 @@
#include "nvim/pos.h" // for linenr_T
// flags for open_line()
-#define OPENLINE_DELSPACES 1 // delete spaces after cursor
-#define OPENLINE_DO_COM 2 // format comments
-#define OPENLINE_KEEPTRAIL 4 // keep trailing spaces
-#define OPENLINE_MARKFIX 8 // fix mark positions
-#define OPENLINE_COM_LIST 16 // format comments with list/2nd line indent
+#define OPENLINE_DELSPACES 0x01 // delete spaces after cursor
+#define OPENLINE_DO_COM 0x02 // format comments
+#define OPENLINE_KEEPTRAIL 0x04 // keep trailing spaces
+#define OPENLINE_MARKFIX 0x08 // fix mark positions
+#define OPENLINE_COM_LIST 0x10 // format comments with list/2nd line indent
+#define OPENLINE_FORMAT 0x20 // formatting long comment
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "change.h.generated.h"
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index aa77c03b48..568a8573db 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -459,9 +459,8 @@ static void insert_enter(InsertState *s)
where_paste_started.lnum = 0;
can_cindent = true;
- // The cursor line is not in a closed fold, unless 'insertmode' is set or
- // restarting.
- if (!p_im && did_restart_edit == 0) {
+ // The cursor line is not in a closed fold, unless restarting.
+ if (did_restart_edit == 0) {
foldOpenCursor();
}
@@ -473,7 +472,7 @@ static void insert_enter(InsertState *s)
s->i = showmode();
}
- if (!p_im && did_restart_edit == 0) {
+ if (did_restart_edit == 0) {
change_warning(curbuf, s->i == 0 ? 0 : s->i + 1);
}
@@ -554,7 +553,7 @@ static int insert_check(VimState *state)
}
if (stop_insert_mode && !compl_started) {
- // ":stopinsert" used or 'insertmode' reset
+ // ":stopinsert" used
s->count = 0;
return 0; // exit insert mode
}
@@ -756,7 +755,6 @@ static int insert_execute(VimState *state, int key)
}
// CTRL-\ CTRL-N goes to Normal mode,
- // CTRL-\ CTRL-G goes to mode selected with 'insertmode',
// CTRL-\ CTRL-O is like CTRL-O but without moving the cursor
if (s->c == Ctrl_BSL) {
// may need to redraw when no more chars available now
@@ -770,8 +768,6 @@ static int insert_execute(VimState *state, int key)
// it's something else
vungetc(s->c);
s->c = Ctrl_BSL;
- } else if (s->c == Ctrl_G && p_im) {
- return 1; // continue
} else {
if (s->c == Ctrl_O) {
ins_ctrl_o();
@@ -843,16 +839,6 @@ static int insert_execute(VimState *state, int key)
}
-/// Return true when need to go to Insert mode because of 'insertmode'.
-///
-/// Don't do this when still processing a command or a mapping.
-/// Don't do this when inside a ":normal" command.
-bool goto_im(void)
- FUNC_ATTR_PURE
-{
- return p_im && stuff_empty() && typebuf_typed();
-}
-
static int insert_handle_key(InsertState *s)
{
// The big switch to handle a character in insert mode.
@@ -884,26 +870,10 @@ static int insert_handle_key(InsertState *s)
}
}
- // when 'insertmode' set, and not halfway through a mapping, don't leave
- // Insert mode
- if (goto_im()) {
- if (got_int) {
- (void)vgetc(); // flush all buffers
- got_int = false;
- } else {
- vim_beep(BO_IM);
- }
- break;
- }
return 0; // exit insert mode
- case Ctrl_Z: // suspend when 'insertmode' set
- if (!p_im) {
- goto normalchar; // insert CTRL-Z as normal char
- }
- do_cmdline_cmd("stop");
- ui_cursor_shape(); // may need to update cursor shape
- break;
+ case Ctrl_Z:
+ goto normalchar; // insert CTRL-Z as normal char
case Ctrl_O: // execute one command
if (ctrl_x_mode == CTRL_X_OMNI) {
@@ -939,9 +909,6 @@ static int insert_handle_key(InsertState *s)
case K_F1:
case K_XF1:
stuffcharReadbuff(K_HELP);
- if (p_im) {
- need_start_insertmode = true;
- }
return 0; // exit insert mode
@@ -956,7 +923,7 @@ static int insert_handle_key(InsertState *s)
// For ^@ the trailing ESC will end the insert, unless there is an
// error.
if (stuff_inserted(NUL, 1L, (s->c == Ctrl_A)) == FAIL
- && s->c != Ctrl_A && !p_im) {
+ && s->c != Ctrl_A) {
return 0; // exit insert mode
}
s->inserted_space = false;
@@ -1236,7 +1203,7 @@ check_pum:
}
break;
}
- if (!ins_eol(s->c) && !p_im) {
+ if (!ins_eol(s->c)) {
return 0; // out of memory
}
auto_format(false, false);
@@ -1288,13 +1255,6 @@ check_pum:
case Ctrl_L: // Whole line completion after ^X
if (ctrl_x_mode != CTRL_X_WHOLE_LINE) {
- // CTRL-L with 'insertmode' set: Leave Insert mode
- if (p_im) {
- if (echeck_abbr(Ctrl_L + ABBR_OFF)) {
- break;
- }
- return 0; // exit insert mode
- }
goto normalchar;
}
FALLTHROUGH;
@@ -1632,7 +1592,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 +1719,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 +3759,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) {
@@ -6285,6 +6246,7 @@ static void internal_format(int textwidth, int second_indent, int flags, int for
open_line(FORWARD, OPENLINE_DELSPACES + OPENLINE_MARKFIX
+ (fo_white_par ? OPENLINE_KEEPTRAIL : 0)
+ (do_comments ? OPENLINE_DO_COM : 0)
+ + OPENLINE_FORMAT
+ ((flags & INSCHAR_COM_LIST) ? OPENLINE_COM_LIST : 0),
((flags & INSCHAR_COM_LIST) ? second_indent : old_indent),
&did_do_comment);
@@ -7963,10 +7925,8 @@ static bool ins_esc(long *count, int cmdchar, bool nomove)
}
if (!arrow_used) {
// Don't append the ESC for "r<CR>" and "grx".
- // When 'insertmode' is set only CTRL-L stops Insert mode. Needed for
- // when "count" is non-zero.
if (cmdchar != 'r' && cmdchar != 'v') {
- AppendToRedobuff(p_im ? "\014" : ESC_STR);
+ AppendToRedobuff(ESC_STR);
}
/*
@@ -8412,9 +8372,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..33080c145d 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;
}
@@ -6886,6 +6886,7 @@ void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, const typval_T
buf_T *curbuf_save = NULL;
win_T *curwin_save = NULL;
const bool is_curbuf = buf == curbuf;
+ const bool save_VIsual_active = VIsual_active;
// When using the current buffer ml_mfp will be set if needed. Useful when
// setline() is used on startup. For other buffers the buffer must be
@@ -6896,6 +6897,7 @@ void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, const typval_T
}
if (!is_curbuf) {
+ VIsual_active = false;
curbuf_save = curbuf;
curwin_save = curwin;
curbuf = buf;
@@ -6986,6 +6988,7 @@ void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, const typval_T
if (!is_curbuf) {
curbuf = curbuf_save;
curwin = curwin_save;
+ VIsual_active = save_VIsual_active;
}
}
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 68c2e37f22..59c290a5b1 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
@@ -1634,6 +1636,7 @@ static void f_deletebufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
const bool is_curbuf = buf == curbuf;
+ const bool save_VIsual_active = VIsual_active;
const linenr_T first = tv_get_lnum_buf(&argvars[1], buf);
if (argvars[2].v_type != VAR_UNKNOWN) {
@@ -1649,6 +1652,7 @@ static void f_deletebufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (!is_curbuf) {
+ VIsual_active = false;
curbuf_save = curbuf;
curwin_save = curwin;
curbuf = buf;
@@ -1692,6 +1696,7 @@ static void f_deletebufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (!is_curbuf) {
curbuf = curbuf_save;
curwin = curwin_save;
+ VIsual_active = save_VIsual_active;
}
}
@@ -3611,8 +3616,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 +8052,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 +8070,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 +8086,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 +8153,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 +10795,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..f5fa424514 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);
@@ -2874,10 +2880,6 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum
redraw_curbuf_later(NOT_VALID); // redraw this buffer later
}
- if (p_im && (State & MODE_INSERT) == 0) {
- need_start_insertmode = true;
- }
-
// Change directories when the 'acd' option is set.
do_autochdir();
@@ -4903,9 +4905,8 @@ void ex_help(exarg_T *eap)
}
}
- if (!p_im) {
- restart_edit = 0; // don't want insert mode in help file
- }
+ restart_edit = 0; // don't want insert mode in help file
+
// Restore KeyTyped, setting 'filetype=help' may reset it.
// It is needed for do_tag top open folds under the cursor.
KeyTyped = old_KeyTyped;
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index e845073c12..ae6d26227b 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
}
@@ -5522,6 +5528,11 @@ char *uc_validate_name(char *name)
return name;
}
+/// Create a new user command {name}, if one doesn't already exist.
+///
+/// This function takes ownership of compl_arg, compl_luaref, and luaref.
+///
+/// @return OK if the command is created, FAIL otherwise.
int uc_add_command(char *name, size_t name_len, char *rep, uint32_t argt, long def, int flags,
int compl, char *compl_arg, LuaRef compl_luaref, cmd_addr_T addr_type,
LuaRef luaref, bool force)
@@ -8831,7 +8842,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 +8858,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();
@@ -8969,7 +8979,6 @@ bool save_current_state(save_state_T *sst)
sst->save_restart_edit = restart_edit;
sst->save_msg_didout = msg_didout;
sst->save_State = State;
- sst->save_insertmode = p_im;
sst->save_finish_op = finish_op;
sst->save_opcount = opcount;
sst->save_reg_executing = reg_executing;
@@ -8977,7 +8986,6 @@ bool save_current_state(save_state_T *sst)
msg_scroll = false; // no msg scrolling in Normal mode
restart_edit = 0; // don't go to Insert mode
- p_im = false; // don't use 'insertmode
// Save the current typeahead. This is required to allow using ":normal"
// from an event handler and makes sure we don't hang when the argument
@@ -9000,7 +9008,6 @@ void restore_current_state(save_state_T *sst)
// override the value of restart_edit anyway.
restart_edit = sst->save_restart_edit;
}
- p_im = sst->save_insertmode;
finish_op = sst->save_finish_op;
opcount = sst->save_opcount;
reg_executing = sst->save_reg_executing;
diff --git a/src/nvim/ex_docmd.h b/src/nvim/ex_docmd.h
index 874e0e599e..24656f3851 100644
--- a/src/nvim/ex_docmd.h
+++ b/src/nvim/ex_docmd.h
@@ -25,7 +25,6 @@ typedef struct {
int save_restart_edit;
bool save_msg_didout;
int save_State;
- int save_insertmode;
bool save_finish_op;
long save_opcount;
int save_reg_executing;
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 114f1e2ae5..3b1ff9ffed 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)) {
@@ -1329,8 +1336,7 @@ static int command_line_execute(VimState *state, int key)
}
}
- // CTRL-\ CTRL-N goes to Normal mode, CTRL-\ CTRL-G goes to Insert
- // mode when 'insertmode' is set, CTRL-\ e prompts for an expression.
+ // CTRL-\ CTRL-N goes to Normal mode, CTRL-\ e prompts for an expression.
if (s->c == Ctrl_BSL) {
no_mapping++;
allow_keys++;
@@ -1392,9 +1398,6 @@ static int command_line_execute(VimState *state, int key)
redrawcmd();
return command_line_not_changed(s);
} else {
- if (s->c == Ctrl_G && p_im && restart_edit == 0) {
- restart_edit = 'a';
- }
s->gotesc = true; // will free ccline.cmdbuff after putting it
// in history
return 0; // back to Normal mode
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..1bd6cfb0a4 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
@@ -2310,6 +2323,7 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *const gap, const int level,
}
fp->fd_len += fp->fd_top - firstlnum;
fp->fd_top = firstlnum;
+ fp->fd_small = kNone;
fold_changed = true;
} else if ((flp->start != 0 && lvl == level)
|| (firstlnum != startlnum)) {
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..005415514c 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -1352,14 +1352,12 @@ void openscript(char_u *name, bool directly)
int oldcurscript;
int save_State = State;
int save_restart_edit = restart_edit;
- int save_insertmode = p_im;
int save_finish_op = finish_op;
int save_msg_scroll = msg_scroll;
State = MODE_NORMAL;
msg_scroll = false; // no msg scrolling in Normal mode
restart_edit = 0; // don't go to Insert mode
- p_im = false; // don't use 'insertmode'
clear_oparg(&oa);
finish_op = false;
@@ -1373,7 +1371,6 @@ void openscript(char_u *name, bool directly)
State = save_State;
msg_scroll = save_msg_scroll;
restart_edit = save_restart_edit;
- p_im = save_insertmode;
finish_op = save_finish_op;
}
}
@@ -1881,8 +1878,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
@@ -2514,16 +2510,12 @@ static int vgetorpeek(bool advance)
timedout = true;
continue;
}
- // When 'insertmode' is set, ESC just beeps in Insert
- // mode. Use CTRL-L to make edit() return.
// In Ex-mode \n is compatible with original Vim behaviour.
// For the command line only CTRL-C always breaks it.
// For the cmdline window: Alternate between ESC and
// CTRL-C: ESC for most situations and CTRL-C to close the
// cmdline window.
- if (p_im && (State & MODE_INSERT)) {
- c = Ctrl_L;
- } else if ((State & MODE_CMDLINE) || (cmdwin_type > 0 && tc == ESC)) {
+ if ((State & MODE_CMDLINE) || (cmdwin_type > 0 && tc == ESC)) {
c = Ctrl_C;
} else {
c = ESC;
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..f2427f8aef 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;
@@ -111,4 +111,22 @@ struct ScreenGrid {
false, 0, 0, NULL, false, true, 0, \
0, 0, 0, 0, 0, false }
+/// Status line click definition
+typedef struct {
+ enum {
+ kStlClickDisabled = 0, ///< Clicks to this area are ignored.
+ kStlClickTabSwitch, ///< Switch to the given tab.
+ kStlClickTabClose, ///< Close given tab.
+ kStlClickFuncRun, ///< Run user function.
+ } type; ///< Type of the click.
+ int tabnr; ///< Tab page number.
+ char *func; ///< Function to run.
+} StlClickDefinition;
+
+/// Used for tabline clicks
+typedef struct {
+ StlClickDefinition def; ///< Click definition.
+ const char *start; ///< Location where region starts.
+} StlClickRecord;
+
#endif // NVIM_GRID_DEFS_H
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/main.c b/src/nvim/main.c
index 80a856e91a..0ffd6cddff 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -530,11 +530,6 @@ int main(int argc, char **argv)
// 'autochdir' has been postponed.
do_autochdir();
- // start in insert mode
- if (p_im) {
- need_start_insertmode = true;
- }
-
set_vim_var_nr(VV_VIM_DID_ENTER, 1L);
apply_autocmds(EVENT_VIMENTER, NULL, NULL, false, curbuf);
TIME_MSG("VimEnter autocommands");
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..347adc589f 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;
@@ -235,8 +241,8 @@ retnomove:
}
curwin->w_cursor.lnum = curwin->w_topline;
- } else if (on_status_line && which_button == MOUSE_LEFT) {
- if (dragwin != NULL) {
+ } else if (on_status_line) {
+ if (which_button == MOUSE_LEFT && dragwin != NULL) {
// Drag the status line
count = row - dragwin->w_winrow - dragwin->w_height + 1
- on_status_line;
@@ -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..7c7a042eac 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -32,6 +32,7 @@
#include "nvim/fold.h"
#include "nvim/getchar.h"
#include "nvim/globals.h"
+#include "nvim/grid_defs.h"
#include "nvim/indent.h"
#include "nvim/keycodes.h"
#include "nvim/log.h"
@@ -1126,9 +1127,6 @@ static int normal_execute(VimState *state, int key)
if (s->ca.nchar == ESC) {
clearop(&s->oa);
- if (restart_edit == 0 && goto_im()) {
- restart_edit = 'a';
- }
s->command_finished = true;
goto finish;
}
@@ -1178,14 +1176,6 @@ static void normal_check_stuff_buffer(NormalState *s)
// if wait_return still needed call it now
wait_return(false);
}
-
- if (need_start_insertmode && goto_im() && !VIsual_active) {
- need_start_insertmode = false;
- stuffReadbuff("i"); // start insert mode next
- // skip the fileinfo message now, because it would be shown
- // after insert mode finishes!
- need_fileinfo = false;
- }
}
}
@@ -1280,7 +1270,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) {
@@ -1442,6 +1433,63 @@ static void move_tab_to_mouse(void)
}
}
+/// Call click definition function for column "col" in the "click_defs" array for button
+/// "which_button".
+static void call_click_def_func(StlClickDefinition *click_defs, int col, int which_button)
+{
+ typval_T argv[] = {
+ {
+ .v_lock = VAR_FIXED,
+ .v_type = VAR_NUMBER,
+ .vval = {
+ .v_number = (varnumber_T)click_defs[col].tabnr
+ },
+ },
+ {
+ .v_lock = VAR_FIXED,
+ .v_type = VAR_NUMBER,
+ .vval = {
+ .v_number = ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_4CLICK
+ ? 4
+ : ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_3CLICK
+ ? 3
+ : ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK
+ ? 2
+ : 1)))
+ },
+ },
+ {
+ .v_lock = VAR_FIXED,
+ .v_type = VAR_STRING,
+ .vval = {
+ .v_string = (which_button == MOUSE_LEFT
+ ? "l"
+ : (which_button == MOUSE_RIGHT
+ ? "r"
+ : (which_button == MOUSE_MIDDLE
+ ? "m"
+ : "?")))
+ },
+ },
+ {
+ .v_lock = VAR_FIXED,
+ .v_type = VAR_STRING,
+ .vval = {
+ .v_string = (char[]) {
+ (char)(mod_mask & MOD_MASK_SHIFT ? 's' : ' '),
+ (char)(mod_mask & MOD_MASK_CTRL ? 'c' : ' '),
+ (char)(mod_mask & MOD_MASK_ALT ? 'a' : ' '),
+ (char)(mod_mask & MOD_MASK_META ? 'm' : ' '),
+ NUL
+ }
+ },
+ }
+ };
+ typval_T rettv;
+ (void)call_vim_function(click_defs[col].func, ARRAY_SIZE(argv), argv, &rettv);
+ tv_clear(&rettv);
+}
+
/// Do the appropriate action for the current mouse click in the current mode.
/// Not used for Command-line mode.
///
@@ -1491,6 +1539,7 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent)
int jump_flags = 0; // flags for jump_to_mouse()
pos_T start_visual;
bool moved; // Has cursor moved?
+ bool in_winbar; // mouse in window bar
bool in_status_line; // mouse in status line
static bool in_tab_line = false; // mouse clicked in tab line
bool in_sep_line; // mouse in vertical separator line
@@ -1721,66 +1770,10 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent)
}
}
break;
- case kStlClickFuncRun: {
- typval_T argv[] = {
- {
- .v_lock = VAR_FIXED,
- .v_type = VAR_NUMBER,
- .vval = {
- .v_number = (varnumber_T)tab_page_click_defs[mouse_col].tabnr
- },
- },
- {
- .v_lock = VAR_FIXED,
- .v_type = VAR_NUMBER,
- .vval = {
- .v_number = ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_4CLICK
- ? 4
- : ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_3CLICK
- ? 3
- : ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK
- ? 2
- : 1)))
- },
- },
- {
- .v_lock = VAR_FIXED,
- .v_type = VAR_STRING,
- .vval = {
- .v_string = (which_button == MOUSE_LEFT
- ? "l"
- : (which_button == MOUSE_RIGHT
- ? "r"
- : (which_button == MOUSE_MIDDLE
- ? "m"
- : "?")))
- },
- },
- {
- .v_lock = VAR_FIXED,
- .v_type = VAR_STRING,
- .vval = {
- .v_string = (char[]) {
- (char)(mod_mask & MOD_MASK_SHIFT ? 's' : ' '),
- (char)(mod_mask & MOD_MASK_CTRL ? 'c' : ' '),
- (char)(mod_mask & MOD_MASK_ALT ? 'a' : ' '),
- (char)(mod_mask & MOD_MASK_META ? 'm' : ' '),
- NUL
- }
- },
- }
- };
- typval_T rettv;
- funcexe_T funcexe = FUNCEXE_INIT;
- funcexe.firstline = curwin->w_cursor.lnum;
- funcexe.lastline = curwin->w_cursor.lnum;
- funcexe.evaluate = true;
- (void)call_func(tab_page_click_defs[mouse_col].func, -1,
- &rettv, ARRAY_SIZE(argv), argv, &funcexe);
- tv_clear(&rettv);
+ case kStlClickFuncRun:
+ call_click_def_func(tab_page_click_defs, mouse_col, which_button);
break;
}
- }
}
return true;
} else if (is_drag && in_tab_line) {
@@ -1851,9 +1844,38 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent)
which_button);
moved = (jump_flags & CURSOR_MOVED);
+ in_winbar = (jump_flags & MOUSE_WINBAR);
in_status_line = (jump_flags & IN_STATUS_LINE);
in_sep_line = (jump_flags & IN_SEP_LINE);
+ if ((in_winbar || in_status_line) && is_click) {
+ // Handle click event on window bar or status lin
+ int click_grid = mouse_grid;
+ int click_row = mouse_row;
+ int click_col = mouse_col;
+ win_T *wp = mouse_find_win(&click_grid, &click_row, &click_col);
+
+ StlClickDefinition *click_defs = in_status_line ? wp->w_status_click_defs
+ : wp->w_winbar_click_defs;
+
+ if (click_defs != NULL) {
+ switch (click_defs[click_col].type) {
+ case kStlClickDisabled:
+ break;
+ case kStlClickFuncRun:
+ call_click_def_func(click_defs, click_col, which_button);
+ break;
+ default:
+ assert(false && "winbar and statusline only support %@ for clicks");
+ break;
+ }
+ }
+
+ return false;
+ } else if (in_winbar) {
+ // A drag or release event in the window bar has no side effects.
+ return false;
+ }
// When jumping to another window, clear a pending operator. That's a bit
// friendlier than beeping and not jumping to that window.
@@ -3898,7 +3920,6 @@ static void nv_regreplay(cmdarg_T *cap)
/// Handle a ":" command and <Cmd> or Lua keymaps.
static void nv_colon(cmdarg_T *cap)
{
- int old_p_im;
bool cmd_result;
bool is_cmdkey = cap->cmdchar == K_COMMAND;
bool is_lua = cap->cmdchar == K_LUA;
@@ -3924,8 +3945,6 @@ static void nv_colon(cmdarg_T *cap)
compute_cmdrow();
}
- old_p_im = p_im;
-
if (is_lua) {
cmd_result = map_execute_lua();
} else {
@@ -3934,15 +3953,6 @@ static void nv_colon(cmdarg_T *cap)
cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0);
}
- // If 'insertmode' changed, enter or exit Insert mode
- if (p_im != old_p_im) {
- if (p_im) {
- restart_edit = 'i';
- } else {
- restart_edit = 0;
- }
- }
-
if (cmd_result == false) {
// The Ex command failed, do not execute the operator.
clearop(cap->oap);
@@ -6729,10 +6739,6 @@ static void nv_normal(cmdarg_T *cap)
end_visual_mode(); // stop Visual
redraw_curbuf_later(INVERTED);
}
- // CTRL-\ CTRL-G restarts Insert mode when 'insertmode' is set.
- if (cap->nchar == Ctrl_G && p_im) {
- restart_edit = 'a';
- }
} else {
clearopbeep(cap->oap);
}
@@ -6747,8 +6753,7 @@ static void nv_esc(cmdarg_T *cap)
no_reason = (cap->oap->op_type == OP_NOP
&& cap->opcount == 0
&& cap->count0 == 0
- && cap->oap->regname == 0
- && !p_im);
+ && cap->oap->regname == 0);
if (cap->arg) { // true for CTRL-C
if (restart_edit == 0
@@ -6765,9 +6770,8 @@ static void nv_esc(cmdarg_T *cap)
// Don't reset "restart_edit" when 'insertmode' is set, it won't be
// set again below when halfway through a mapping.
- if (!p_im) {
- restart_edit = 0;
- }
+ restart_edit = 0;
+
if (cmdwin_type != 0) {
cmdwin_result = K_IGNORE;
got_int = false; // don't stop executing autocommands et al.
@@ -6790,13 +6794,6 @@ static void nv_esc(cmdarg_T *cap)
vim_beep(BO_ESC);
}
clearop(cap->oap);
-
- // A CTRL-C is often used at the start of a menu. When 'insertmode' is
- // set return to Insert mode afterwards.
- if (restart_edit == 0 && goto_im()
- && ex_normal_busy == 0) {
- restart_edit = 'a';
- }
}
// Move the cursor for the "A" command.
@@ -6831,8 +6828,7 @@ static void nv_edit(cmdarg_T *cap)
} else if ((cap->cmdchar == 'a' || cap->cmdchar == 'i')
&& (cap->oap->op_type != OP_NOP || VIsual_active)) {
nv_object(cap);
- } else if (!curbuf->b_p_ma && !p_im && !curbuf->terminal) {
- // Only give this error when 'insertmode' is off.
+ } else if (!curbuf->b_p_ma && !curbuf->terminal) {
emsg(_(e_modifiable));
clearop(cap->oap);
} else if (!checkclearopq(cap->oap)) {
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index c3d7742307..8ea55579bb 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);
}
@@ -6709,7 +6719,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
// remember it to make 'insertmode' work with mappings for
// Visual mode. But do this only once and not when typed and
// 'insertmode' isn't set.
- if (p_im || !KeyTyped) {
+ if (!KeyTyped) {
restart_edit_save = restart_edit;
} else {
restart_edit_save = 0;
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 8267bcf9da..0d02bae5f7 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,36 +4049,9 @@ 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();
- } else if ((int *)varp == &p_im) {
- // when 'insertmode' is set from an autocommand need to do work here
- if (p_im) {
- if ((State & MODE_INSERT) == 0) {
- need_start_insertmode = true;
- }
- stop_insert_mode = false;
- } else if (old_value) { // only reset if it was set previously
- need_start_insertmode = false;
- stop_insert_mode = true;
- if (restart_edit != 0 && mode_displayed) {
- clear_cmdline = true; // remove "(insert)"
- }
- restart_edit = 0;
- }
} else if ((int *)varp == &p_ic && p_hls) {
// when 'ignorecase' is set or reset and 'hlsearch' is set, redraw
redraw_all_later(SOME_VALID);
@@ -4766,7 +4746,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 +5794,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 +5874,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 +5969,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 +6240,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 +6316,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 +6342,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 +6529,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 +6539,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..0dc4bd1b90 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -334,9 +334,9 @@ EXTERN unsigned bo_flags;
#ifdef IN_OPTION_C
static char *(p_bo_values[]) = { "all", "backspace", "cursor", "complete",
"copy", "ctrlg", "error", "esc", "ex",
- "hangul", "insertmode", "lang", "mess",
- "showmatch", "operator", "register", "shell",
- "spell", "wildmode", NULL };
+ "hangul", "lang", "mess", "showmatch",
+ "operator", "register", "shell", "spell",
+ "wildmode", NULL };
#endif
// values for the 'belloff' option
@@ -485,7 +485,6 @@ EXTERN char_u *p_iconstring; // 'iconstring'
EXTERN int p_ic; // 'ignorecase'
EXTERN int p_is; // 'incsearch'
EXTERN char_u *p_icm; // 'inccommand'
-EXTERN int p_im; // 'insertmode'
EXTERN char_u *p_isf; // 'isfname'
EXTERN char_u *p_isi; // 'isident'
EXTERN char_u *p_isp; // 'isprint'
@@ -557,7 +556,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 +616,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 +677,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 +895,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..a0fbf8d9f0 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -1250,9 +1250,9 @@ return {
},
{
full_name='insertmode', abbreviation='im',
- short_desc=N_("start the edit of a file in Insert mode"),
+ short_desc=N_("No description"),
type='bool', scope={'global'},
- varname='p_im',
+ varname='p_force_off',
defaults={if_true=false}
},
{
@@ -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/po/check.vim b/src/nvim/po/check.vim
index aca878f9d5..7705ba8577 100644
--- a/src/nvim/po/check.vim
+++ b/src/nvim/po/check.vim
@@ -41,7 +41,7 @@ set nowrapscan
" Start at the first "msgid" line.
let wsv = winsaveview()
1
-/^msgid\>
+keeppatterns /^msgid\>
" When an error is detected this is set to the line number.
" Note: this is used in the Makefile.
@@ -104,7 +104,7 @@ while 1
" Find next msgid. Quit when there is no more.
let lnum = line('.')
- silent! /^msgid\>
+ silent! keeppatterns /^msgid\>
if line('.') == lnum
break
endif
@@ -137,7 +137,7 @@ endfunc
" Check that the \n at the end of the msgid line is also present in the msgstr
" line. Skip over the header.
1
-/^"MIME-Version:
+keeppatterns /^"MIME-Version:
while 1
let lnum = search('^msgid\>')
if lnum <= 0
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/quickfix.c b/src/nvim/quickfix.c
index 883de85aee..9c7b36396b 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -2540,9 +2540,7 @@ static int jump_to_help_window(qf_info_T *qi, bool newwin, int *opened_window)
}
}
- if (!p_im) {
- restart_edit = 0; // don't want insert mode in help file
- }
+ restart_edit = 0; // don't want insert mode in help file
return OK;
}
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 686516f17b..d88975fa78 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -88,6 +88,7 @@
#include "nvim/fold.h"
#include "nvim/garray.h"
#include "nvim/getchar.h"
+#include "nvim/grid_defs.h"
#include "nvim/highlight.h"
#include "nvim/highlight_group.h"
#include "nvim/indent.h"
@@ -132,10 +133,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,21 +273,12 @@ 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 && (wp->w_status_height || (wp == curwin && global_stl_height())
+ || wp->w_winbar_height)) {
wp->w_redr_status = true;
if (must_redraw < VALID) {
must_redraw = VALID;
@@ -382,9 +370,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()) {
@@ -431,7 +419,7 @@ int update_screen(int type)
wp->w_redr_type = REDRAW_TOP;
} else {
wp->w_redr_type = NOT_VALID;
- if (!is_stl_global && W_ENDROW(wp) + wp->w_status_height <= msg_scrolled) {
+ if (wp->w_winrow + wp->w_winbar_height <= msg_scrolled) {
wp->w_redr_status = true;
}
}
@@ -585,8 +573,9 @@ 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_winbar(wp);
win_redr_status(wp);
}
}
@@ -598,8 +587,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) {
@@ -747,7 +734,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
}
// 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 +743,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 +942,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 +950,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 +969,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 +1023,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 +1039,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 +1064,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 +1262,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 +1315,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 +1420,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 +1432,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 +1470,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 +1484,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 +1516,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 +1531,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 +1550,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 +1568,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 +1622,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 +1665,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 +1750,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 +1800,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 +1824,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 +2608,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 +2790,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 +2805,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 +2879,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 +2915,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 +3056,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 +3170,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 +3375,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 +3578,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 +3650,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 +3732,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 +3804,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 +3872,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 +3910,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 +3943,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 +3952,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 +3978,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 +4168,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 +4181,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 +4193,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 +4226,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 +4239,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 +4515,36 @@ 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) {
+ if ((!is_stl_global && wp->w_status_height) || (is_stl_global && wp == curwin)
+ || wp->w_winbar_height) {
+ wp->w_redr_status = true;
+ 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 && ((!is_stl_global && wp->w_status_height)
+ || (is_stl_global && wp == curwin) || wp->w_winbar_height)) {
+ wp->w_redr_status = true;
+ redraw_later(wp, VALID);
}
}
}
@@ -4575,6 +4556,7 @@ void redraw_statuslines(void)
{
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_redr_status) {
+ win_redr_winbar(wp);
win_redr_status(wp);
}
}
@@ -5075,7 +5057,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 +5070,37 @@ 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;
+
+ if (wp->w_winbar_height == 0 || !redrawing()) {
+ // Do nothing.
+ } 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 +5237,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,11 +5280,42 @@ 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);
+
+ stl_clear_click_defs(wp->w_winbar_click_defs, wp->w_winbar_click_defs_size);
+ // Allocate / resize the click definitions array for winbar if needed.
+ if (wp->w_winbar_height && wp->w_winbar_click_defs_size < (size_t)maxwidth) {
+ xfree(wp->w_winbar_click_defs);
+ wp->w_winbar_click_defs_size = (size_t)maxwidth;
+ wp->w_winbar_click_defs = xcalloc(wp->w_winbar_click_defs_size, sizeof(StlClickRecord));
+ }
} else {
row = is_stl_global ? (Rows - p_ch - 1) : W_ENDROW(wp);
fillchar = fillchar_status(&attr, wp);
maxwidth = is_stl_global ? Columns : wp->w_width;
+ stl_clear_click_defs(wp->w_status_click_defs, wp->w_status_click_defs_size);
+ // Allocate / resize the click definitions array for statusline if needed.
+ if (wp->w_status_click_defs_size < (size_t)maxwidth) {
+ xfree(wp->w_status_click_defs);
+ wp->w_status_click_defs_size = maxwidth;
+ wp->w_status_click_defs = xcalloc(wp->w_status_click_defs_size, sizeof(StlClickRecord));
+ }
+
if (draw_ruler) {
stl = p_ruf;
// advance past any leading group spec - implicit in ru_col
@@ -5377,26 +5419,38 @@ static void win_redr_custom(win_T *wp, bool draw_ruler)
grid_puts_line_flush(false);
- if (wp == NULL) {
- // Fill the tab_page_click_defs array for clicking in the tab pages line.
- col = 0;
- len = 0;
- p = buf;
- StlClickDefinition cur_click_def = {
- .type = kStlClickDisabled,
- };
- for (n = 0; tabtab[n].start != NULL; n++) {
- len += vim_strnsize(p, (int)(tabtab[n].start - (char *)p));
- while (col < len) {
- tab_page_click_defs[col++] = cur_click_def;
- }
- p = (char_u *)tabtab[n].start;
- cur_click_def = tabtab[n].def;
+ // Fill the tab_page_click_defs, w_status_click_defs or w_winbar_click_defs array for clicking
+ // in the tab page line, status line or window bar
+ StlClickDefinition *click_defs = (wp == NULL) ? tab_page_click_defs
+ : draw_winbar ? wp->w_winbar_click_defs
+ : wp->w_status_click_defs;
+
+ if (click_defs == NULL) {
+ goto theend;
+ }
+
+ col = 0;
+ len = 0;
+ p = buf;
+ StlClickDefinition cur_click_def = {
+ .type = kStlClickDisabled,
+ };
+ for (n = 0; tabtab[n].start != NULL; n++) {
+ len += vim_strnsize(p, (int)(tabtab[n].start - (char *)p));
+ while (col < len) {
+ click_defs[col++] = cur_click_def;
}
- while (col < Columns) {
- tab_page_click_defs[col++] = cur_click_def;
+ p = (char_u *)tabtab[n].start;
+ cur_click_def = tabtab[n].def;
+ if ((wp != NULL) && !(cur_click_def.type == kStlClickDisabled
+ || cur_click_def.type == kStlClickFuncRun)) {
+ // window bar and status line only support click functions
+ cur_click_def.type = kStlClickDisabled;
}
}
+ while (col < maxwidth) {
+ click_defs[col++] = cur_click_def;
+ }
theend:
entered = false;
@@ -5504,93 +5558,13 @@ 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.
///
/// Allocate default_grid.chars[] and other grid arrays.
///
/// 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 +5585,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
@@ -5652,7 +5626,7 @@ retry:
StlClickDefinition *new_tab_page_click_defs =
xcalloc((size_t)Columns, sizeof(*new_tab_page_click_defs));
- clear_tab_page_click_defs(tab_page_click_defs, tab_page_click_defs_size);
+ stl_clear_click_defs(tab_page_click_defs, tab_page_click_defs_size);
xfree(tab_page_click_defs);
tab_page_click_defs = new_tab_page_click_defs;
@@ -5683,19 +5657,19 @@ retry:
resizing = false;
}
-/// Clear tab_page_click_defs table
+/// Clear status line, window bar or tab page line click definition table
///
/// @param[out] tpcd Table to clear.
/// @param[in] tpcd_size Size of the table.
-void clear_tab_page_click_defs(StlClickDefinition *const tpcd, const long tpcd_size)
+void stl_clear_click_defs(StlClickDefinition *const click_defs, const long click_defs_size)
{
- if (tpcd != NULL) {
- for (long i = 0; i < tpcd_size; i++) {
- if (i == 0 || tpcd[i].func != tpcd[i - 1].func) {
- xfree(tpcd[i].func);
+ if (click_defs != NULL) {
+ for (long i = 0; i < click_defs_size; i++) {
+ if (i == 0 || click_defs[i].func != click_defs[i - 1].func) {
+ xfree(click_defs[i].func);
}
}
- memset(tpcd, 0, (size_t)tpcd_size * sizeof(tpcd[0]));
+ memset(click_defs, 0, (size_t)click_defs_size * sizeof(click_defs[0]));
}
}
@@ -5711,9 +5685,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 +5771,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 +5819,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 +5837,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 +5868,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 +5887,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);
}
}
@@ -6211,7 +6185,7 @@ void draw_tabline(void)
// Init TabPageIdxs[] to zero: Clicking outside of tabs has no effect.
assert(Columns == tab_page_click_defs_size);
- clear_tab_page_click_defs(tab_page_click_defs, tab_page_click_defs_size);
+ stl_clear_click_defs(tab_page_click_defs, tab_page_click_defs_size);
// Use the 'tabline' option if it's set.
if (*p_tal != NUL) {
@@ -6220,7 +6194,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);
@@ -6474,6 +6448,9 @@ void showruler(bool always)
} else {
win_redr_ruler(curwin, always);
}
+ if (*p_wbr != NUL || *curwin->w_p_wbr != NUL) {
+ win_redr_winbar(curwin);
+ }
if (need_maketitle
|| (p_icon && (stl_syntax & STL_IN_ICON))
@@ -6516,7 +6493,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 +6731,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 +6755,7 @@ void screen_resize(int width, int height)
return;
}
- recursive = true;
+ resizing_screen = true;
Rows = height;
Columns = width;
@@ -6797,9 +6772,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 +6833,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..0afbc24538 100644
--- a/src/nvim/screen.h
+++ b/src/nvim/screen.h
@@ -30,33 +30,23 @@ typedef enum {
// Maximum columns for terminal highlight attributes
#define TERM_ATTRS_MAX 1024
-/// Status line click definition
-typedef struct {
- enum {
- kStlClickDisabled = 0, ///< Clicks to this area are ignored.
- kStlClickTabSwitch, ///< Switch to the given tab.
- kStlClickTabClose, ///< Close given tab.
- kStlClickFuncRun, ///< Run user function.
- } type; ///< Type of the click.
- int tabnr; ///< Tab page number.
- char *func; ///< Function to run.
-} StlClickDefinition;
-
-/// Used for tabline clicks
-typedef struct {
- StlClickDefinition def; ///< Click definition.
- const char *start; ///< Location where region starts.
-} 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/testdir/test_bufline.vim b/src/nvim/testdir/test_bufline.vim
index 765ae17736..ffb8e3facd 100644
--- a/src/nvim/testdir/test_bufline.vim
+++ b/src/nvim/testdir/test_bufline.vim
@@ -153,3 +153,38 @@ func Test_appendbufline_redraw()
call StopVimInTerminal(buf)
call delete('XscriptMatchCommon')
endfunc
+
+func Test_setbufline_select_mode()
+ new
+ call setline(1, ['foo', 'bar'])
+ call feedkeys("j^v2l\<C-G>", 'nx')
+
+ let bufnr = bufadd('Xdummy')
+ call bufload(bufnr)
+ call setbufline(bufnr, 1, ['abc'])
+
+ call feedkeys("x", 'nx')
+ call assert_equal(['foo', 'x'], getline(1, 2))
+
+ exe "bwipe! " .. bufnr
+ bwipe!
+endfunc
+
+func Test_deletebufline_select_mode()
+ new
+ call setline(1, ['foo', 'bar'])
+ call feedkeys("j^v2l\<C-G>", 'nx')
+
+ let bufnr = bufadd('Xdummy')
+ call bufload(bufnr)
+ call setbufline(bufnr, 1, ['abc', 'def'])
+ call deletebufline(bufnr, 1)
+
+ call feedkeys("x", 'nx')
+ call assert_equal(['foo', 'x'], getline(1, 2))
+
+ exe "bwipe! " .. bufnr
+ bwipe!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
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..275c8f7a15 100644
--- a/src/nvim/testdir/test_edit.vim
+++ b/src/nvim/testdir/test_edit.vim
@@ -16,8 +16,9 @@ func Test_edit_00b()
call setline(1, ['abc '])
inoreabbr <buffer> h here some more
call cursor(1, 4)
- " <c-l> expands the abbreviation and ends insertmode
- call feedkeys(":set im\<cr> h\<c-l>:set noim\<cr>", 'tix')
+ " <esc> expands the abbreviation and ends insert mode
+ " call feedkeys(":set im\<cr> h\<c-l>:set noim\<cr>", 'tix')
+ call feedkeys("i h\<esc>", 'tix')
call assert_equal(['abc here some more '], getline(1,'$'))
iunabbr <buffer> h
bw!
@@ -234,15 +235,18 @@ func Test_edit_09()
call setline(1, ['abc', 'def', 'ghi'])
call cursor(1, 1)
" 1) CTRL-\ CTLR-N
- call feedkeys(":set im\<cr>\<c-\>\<c-n>ccABC\<c-l>", 'txin')
+ " call feedkeys(":set im\<cr>\<c-\>\<c-n>ccABC\<c-l>", 'txin')
+ call feedkeys("i\<c-\>\<c-n>ccABC\<esc>", 'txin')
call assert_equal(['ABC', 'def', 'ghi'], getline(1,'$'))
call setline(1, ['ABC', 'def', 'ghi'])
" 2) CTRL-\ CTLR-G
- call feedkeys("j0\<c-\>\<c-g>ZZZ\<cr>\<c-l>", 'txin')
- call assert_equal(['ABC', 'ZZZ', 'def', 'ghi'], getline(1,'$'))
- call feedkeys("I\<c-\>\<c-g>YYY\<c-l>", 'txin')
- call assert_equal(['ABC', 'ZZZ', 'YYYdef', 'ghi'], getline(1,'$'))
- set noinsertmode
+ " CTRL-\ CTRL-G goes to Insert mode when 'insertmode' is set, but
+ " 'insertmode' is now removed so skip this test
+ " call feedkeys("j0\<c-\>\<c-g>ZZZ\<cr>\<esc>", 'txin')
+ " call assert_equal(['ABC', 'ZZZ', 'def', 'ghi'], getline(1,'$'))
+ " call feedkeys("I\<c-\>\<c-g>YYY\<c-l>", 'txin')
+ " call assert_equal(['ABC', 'ZZZ', 'YYYdef', 'ghi'], getline(1,'$'))
+ " set noinsertmode
" 3) CTRL-\ CTRL-O
call setline(1, ['ABC', 'ZZZ', 'def', 'ghi'])
call cursor(1, 1)
@@ -395,15 +399,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
@@ -1045,7 +1047,8 @@ endfunc
func Test_edit_F1()
" Pressing <f1>
new
- call feedkeys(":set im\<cr>\<f1>\<c-l>", 'tnix')
+ " call feedkeys(":set im\<cr>\<f1>\<c-l>", 'tnix')
+ call feedkeys("i\<f1>\<esc>", 'tnix')
set noinsertmode
call assert_equal('help', &buftype)
bw
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index c0c35b89cb..9eccb4babd 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -77,16 +77,16 @@ let s:filename_checks = {
\ 'awk': ['file.awk', 'file.gawk'],
\ 'b': ['file.mch', 'file.ref', 'file.imp'],
\ 'basic': ['file.bas', 'file.bi', 'file.bm'],
- \ 'bzl': ['file.bazel', 'file.bzl', 'WORKSPACE'],
\ 'bc': ['file.bc'],
\ 'bdf': ['file.bdf'],
+ \ 'beancount': ['file.beancount'],
\ 'bib': ['file.bib'],
\ 'bicep': ['file.bicep'],
- \ 'beancount': ['file.beancount'],
\ 'bindzone': ['named.root', '/bind/db.file', '/named/db.file', 'any/bind/db.file', 'any/named/db.file'],
\ 'blank': ['file.bl'],
\ 'bsdl': ['file.bsd', 'file.bsdl', 'bsd', 'some-bsd'],
\ 'bst': ['file.bst'],
+ \ 'bzl': ['file.bazel', 'file.bzl', 'WORKSPACE'],
\ 'bzr': ['bzr_log.any', 'bzr_log.file'],
\ 'c': ['enlightenment/file.cfg', 'file.qc', 'file.c', 'some-enlightenment/file.cfg'],
\ 'cabal': ['file.cabal'],
@@ -109,6 +109,7 @@ let s:filename_checks = {
\ 'clean': ['file.dcl', 'file.icl'],
\ 'clojure': ['file.clj', 'file.cljs', 'file.cljx', 'file.cljc'],
\ 'cmake': ['CMakeLists.txt', 'file.cmake', 'file.cmake.in'],
+ \ 'cmod': ['file.cmod'],
\ 'cmusrc': ['any/.cmus/autosave', 'any/.cmus/rc', 'any/.cmus/command-history', 'any/.cmus/file.theme', 'any/cmus/rc', 'any/cmus/file.theme', '/.cmus/autosave', '/.cmus/command-history', '/.cmus/file.theme', '/.cmus/rc', '/cmus/file.theme', '/cmus/rc'],
\ 'cobol': ['file.cbl', 'file.cob', 'file.lib'],
\ 'coco': ['file.atg'],
@@ -164,9 +165,9 @@ let s:filename_checks = {
\ 'dylanlid': ['file.lid'],
\ 'ecd': ['file.ecd'],
\ 'edif': ['file.edf', 'file.edif', 'file.edo'],
+ \ 'eelixir': ['file.eex', 'file.leex'],
\ 'elinks': ['elinks.conf'],
\ 'elixir': ['file.ex', 'file.exs', 'mix.lock'],
- \ 'eelixir': ['file.eex', 'file.leex'],
\ 'elm': ['file.elm'],
\ 'elmfilt': ['filter-rules'],
\ 'elvish': ['file.elv'],
@@ -199,9 +200,9 @@ let s:filename_checks = {
\ 'fusion': ['file.fusion'],
\ 'fvwm': ['/.fvwm/file', 'any/.fvwm/file'],
\ 'gdb': ['.gdbinit', 'gdbinit', 'file.gdb', '.config/gdbearlyinit', '.gdbearlyinit'],
+ \ 'gdmo': ['file.mo', 'file.gdmo'],
\ 'gdresource': ['file.tscn', 'file.tres'],
\ 'gdscript': ['file.gd'],
- \ 'gdmo': ['file.mo', 'file.gdmo'],
\ 'gedcom': ['file.ged', 'lltxxxxx.txt', '/tmp/lltmp', '/tmp/lltmp-file', 'any/tmp/lltmp', 'any/tmp/lltmp-file'],
\ 'gemtext': ['file.gmi', 'file.gemini'],
\ 'gift': ['file.gift'],
@@ -237,8 +238,8 @@ let s:filename_checks = {
\ 'hastepreproc': ['file.htpp'],
\ 'hb': ['file.hb'],
\ 'hcl': ['file.hcl'],
- \ 'hercules': ['file.vc', 'file.ev', 'file.sum', 'file.errsum'],
\ 'heex': ['file.heex'],
+ \ 'hercules': ['file.vc', 'file.ev', 'file.sum', 'file.errsum'],
\ 'hex': ['file.hex', 'file.h32'],
\ 'hgcommit': ['hg-editor-file.txt'],
\ 'hjson': ['file.hjson'],
@@ -246,22 +247,10 @@ let s:filename_checks = {
\ 'hollywood': ['file.hws'],
\ 'hostconf': ['/etc/host.conf', 'any/etc/host.conf'],
\ 'hostsaccess': ['/etc/hosts.allow', '/etc/hosts.deny', 'any/etc/hosts.allow', 'any/etc/hosts.deny'],
- \ 'i3config': ['/home/user/.i3/config', '/home/user/.config/i3/config', '/etc/i3/config', '/etc/xdg/i3/config'],
- \ 'logcheck': ['/etc/logcheck/file.d-some/file', '/etc/logcheck/file.d/file', 'any/etc/logcheck/file.d-some/file', 'any/etc/logcheck/file.d/file'],
- \ 'modula3': ['file.m3', 'file.mg', 'file.i3', 'file.ig'],
- \ 'natural': ['file.NSA', 'file.NSC', 'file.NSG', 'file.NSL', 'file.NSM', 'file.NSN', 'file.NSP', 'file.NSS'],
- \ 'neomuttrc': ['Neomuttrc', '.neomuttrc', '.neomuttrc-file', '/.neomutt/neomuttrc', '/.neomutt/neomuttrc-file', 'Neomuttrc', 'Neomuttrc-file', 'any/.neomutt/neomuttrc', 'any/.neomutt/neomuttrc-file', 'neomuttrc', 'neomuttrc-file'],
- \ 'opl': ['file.OPL', 'file.OPl', 'file.OpL', 'file.Opl', 'file.oPL', 'file.oPl', 'file.opL', 'file.opl'],
- \ 'pcmk': ['file.pcmk'],
- \ 'r': ['file.r'],
- \ 'rhelp': ['file.rd'],
- \ 'rmd': ['file.rmd', 'file.smd'],
- \ 'rnoweb': ['file.rnw', 'file.snw'],
- \ 'rrst': ['file.rrst', 'file.srst'],
- \ 'template': ['file.tmpl'],
\ 'html': ['file.html', 'file.htm', 'file.cshtml'],
\ 'htmlm4': ['file.html.m4'],
\ 'httest': ['file.htt', 'file.htb'],
+ \ 'i3config': ['/home/user/.i3/config', '/home/user/.config/i3/config', '/etc/i3/config', '/etc/xdg/i3/config'],
\ 'ibasic': ['file.iba', 'file.ibi'],
\ 'icemenu': ['/.icewm/menu', 'any/.icewm/menu'],
\ 'icon': ['file.icn'],
@@ -314,17 +303,18 @@ let s:filename_checks = {
\ 'lisp': ['file.lsp', 'file.lisp', 'file.asd', 'file.el', 'file.cl', '.emacs', '.sawfishrc', 'sbclrc', '.sbclrc'],
\ 'lite': ['file.lite', 'file.lt'],
\ 'litestep': ['/LiteStep/any/file.rc', 'any/LiteStep/any/file.rc'],
+ \ 'logcheck': ['/etc/logcheck/file.d-some/file', '/etc/logcheck/file.d/file', 'any/etc/logcheck/file.d-some/file', 'any/etc/logcheck/file.d/file'],
\ 'loginaccess': ['/etc/login.access', 'any/etc/login.access'],
\ 'logindefs': ['/etc/login.defs', 'any/etc/login.defs'],
\ 'logtalk': ['file.lgt'],
\ 'lotos': ['file.lot', 'file.lotos'],
\ 'lout': ['file.lou', 'file.lout'],
+ \ 'lpc': ['file.lpc', 'file.ulpc'],
\ 'lprolog': ['file.sig'],
\ 'lsl': ['file.lsl'],
\ 'lss': ['file.lss'],
\ 'lua': ['file.lua', 'file.rockspec', 'file.nse'],
\ 'lynx': ['lynx.cfg'],
- \ 'matlab': ['file.m'],
\ 'm3build': ['m3makefile', 'm3overrides'],
\ 'm3quake': ['file.quake', 'cm3.cfg'],
\ 'm4': ['file.at'],
@@ -339,6 +329,7 @@ let s:filename_checks = {
\ 'markdown': ['file.markdown', 'file.mdown', 'file.mkd', 'file.mkdn', 'file.mdwn', 'file.md'],
\ 'mason': ['file.mason', 'file.mhtml', 'file.comp'],
\ 'master': ['file.mas', 'file.master'],
+ \ 'matlab': ['file.m'],
\ 'maxima': ['file.demo', 'file.dmt', 'file.dm1', 'file.dm2', 'file.dm3',
\ 'file.wxm', 'maxima-init.mac'],
\ 'mel': ['file.mel'],
@@ -359,6 +350,7 @@ let s:filename_checks = {
\ 'mmp': ['file.mmp'],
\ 'modconf': ['/etc/modules.conf', '/etc/modules', '/etc/conf.modules', '/etc/modprobe.file', 'any/etc/conf.modules', 'any/etc/modprobe.file', 'any/etc/modules', 'any/etc/modules.conf'],
\ 'modula2': ['file.m2', 'file.mi'],
+ \ 'modula3': ['file.m3', 'file.mg', 'file.i3', 'file.ig'],
\ 'monk': ['file.isc', 'file.monk', 'file.ssc', 'file.tsc'],
\ 'moo': ['file.moo'],
\ 'mp': ['file.mp'],
@@ -373,7 +365,9 @@ let s:filename_checks = {
\ 'n1ql': ['file.n1ql', 'file.nql'],
\ 'named': ['namedfile.conf', 'rndcfile.conf', 'named-file.conf', 'named.conf', 'rndc-file.conf', 'rndc-file.key', 'rndc.conf', 'rndc.key'],
\ 'nanorc': ['/etc/nanorc', 'file.nanorc', 'any/etc/nanorc'],
+ \ 'natural': ['file.NSA', 'file.NSC', 'file.NSG', 'file.NSL', 'file.NSM', 'file.NSN', 'file.NSP', 'file.NSS'],
\ 'ncf': ['file.ncf'],
+ \ 'neomuttrc': ['Neomuttrc', '.neomuttrc', '.neomuttrc-file', '/.neomutt/neomuttrc', '/.neomutt/neomuttrc-file', 'Neomuttrc', 'Neomuttrc-file', 'any/.neomutt/neomuttrc', 'any/.neomutt/neomuttrc-file', 'neomuttrc', 'neomuttrc-file'],
\ 'netrc': ['.netrc'],
\ 'nginx': ['file.nginx', 'nginxfile.conf', 'filenginx.conf', 'any/etc/nginx/file', 'any/usr/local/nginx/conf/file', 'any/nginx/file.conf'],
\ 'ninja': ['file.ninja'],
@@ -389,6 +383,7 @@ let s:filename_checks = {
\ 'opam': ['opam', 'file.opam', 'file.opam.template'],
\ 'openroad': ['file.or'],
\ 'openscad': ['file.scad'],
+ \ 'opl': ['file.OPL', 'file.OPl', 'file.OpL', 'file.Opl', 'file.oPL', 'file.oPl', 'file.opL', 'file.opl'],
\ 'ora': ['file.ora'],
\ 'org': ['file.org', 'file.org_archive'],
\ 'pamconf': ['/etc/pam.conf', '/etc/pam.d/file', 'any/etc/pam.conf', 'any/etc/pam.d/file'],
@@ -398,14 +393,13 @@ let s:filename_checks = {
\ 'passwd': ['any/etc/passwd', 'any/etc/passwd-', 'any/etc/passwd.edit', 'any/etc/shadow', 'any/etc/shadow-', 'any/etc/shadow.edit', 'any/var/backups/passwd.bak', 'any/var/backups/shadow.bak', '/etc/passwd', '/etc/passwd-', '/etc/passwd.edit', '/etc/shadow', '/etc/shadow-', '/etc/shadow.edit', '/var/backups/passwd.bak', '/var/backups/shadow.bak'],
\ 'pbtxt': ['file.pbtxt'],
\ 'pccts': ['file.g'],
+ \ 'pcmk': ['file.pcmk'],
\ 'pdf': ['file.pdf'],
\ 'perl': ['file.plx', 'file.al', 'file.psgi', 'gitolite.rc', '.gitolite.rc', 'example.gitolite.rc'],
\ 'pf': ['pf.conf'],
\ 'pfmain': ['main.cf'],
\ 'php': ['file.php', 'file.php9', 'file.phtml', 'file.ctp', 'file.phpt'],
- \ 'lpc': ['file.lpc', 'file.ulpc'],
\ 'pike': ['file.pike', 'file.pmod'],
- \ 'cmod': ['file.cmod'],
\ 'pilrc': ['file.rcp'],
\ 'pine': ['.pinerc', 'pinerc', '.pinercex', 'pinercex'],
\ 'pinfo': ['/etc/pinforc', '/.pinforc', 'any/.pinforc', 'any/etc/pinforc'],
@@ -421,8 +415,8 @@ let s:filename_checks = {
\ 'povini': ['.povrayrc'],
\ 'ppd': ['file.ppd'],
\ 'ppwiz': ['file.it', 'file.ih'],
- \ 'privoxy': ['file.action'],
\ 'prisma': ['file.prisma'],
+ \ 'privoxy': ['file.action'],
\ 'proc': ['file.pc'],
\ 'procmail': ['.procmail', '.procmailrc'],
\ 'prolog': ['file.pdb'],
@@ -440,27 +434,33 @@ let s:filename_checks = {
\ 'python': ['file.py', 'file.pyw', '.pythonstartup', '.pythonrc', 'file.ptl', 'file.pyi', 'SConstruct'],
\ 'ql': ['file.ql', 'file.qll'],
\ 'quake': ['anybaseq2/file.cfg', 'anyid1/file.cfg', 'quake3/file.cfg', 'baseq2/file.cfg', 'id1/file.cfg', 'quake1/file.cfg', 'some-baseq2/file.cfg', 'some-id1/file.cfg', 'some-quake1/file.cfg'],
+ \ 'r': ['file.r'],
\ 'radiance': ['file.rad', 'file.mat'],
\ 'raku': ['file.pm6', 'file.p6', 'file.t6', 'file.pod6', 'file.raku', 'file.rakumod', 'file.rakudoc', 'file.rakutest'],
+ \ 'raml': ['file.raml'],
\ 'ratpoison': ['.ratpoisonrc', 'ratpoisonrc'],
\ 'rbs': ['file.rbs'],
\ 'rc': ['file.rc', 'file.rch'],
\ 'rcs': ['file,v'],
\ 'readline': ['.inputrc', 'inputrc'],
- \ 'remind': ['.reminders', 'file.remind', 'file.rem', '.reminders-file'],
\ 'rego': ['file.rego'],
+ \ 'remind': ['.reminders', 'file.remind', 'file.rem', '.reminders-file'],
\ 'rescript': ['file.res', 'file.resi'],
\ 'resolv': ['resolv.conf'],
\ 'reva': ['file.frt'],
\ 'rexx': ['file.rex', 'file.orx', 'file.rxo', 'file.rxj', 'file.jrexx', 'file.rexxj', 'file.rexx', 'file.testGroup', 'file.testUnit'],
+ \ 'rhelp': ['file.rd'],
\ 'rib': ['file.rib'],
+ \ 'rmd': ['file.rmd', 'file.smd'],
\ 'rnc': ['file.rnc'],
\ 'rng': ['file.rng'],
+ \ 'rnoweb': ['file.rnw', 'file.snw'],
\ 'robot': ['file.robot', 'file.resource'],
\ 'robots': ['robots.txt'],
\ 'routeros': ['file.rsc'],
\ 'rpcgen': ['file.x'],
\ 'rpl': ['file.rpl'],
+ \ 'rrst': ['file.rrst', 'file.srst'],
\ 'rst': ['file.rst'],
\ 'rtf': ['file.rtf'],
\ 'ruby': ['.irbrc', 'irbrc', 'file.rb', 'file.rbw', 'file.gemspec', 'file.ru', 'Gemfile', 'file.builder', 'file.rxml', 'file.rjs', 'file.rant', 'file.rake', 'rakefile', 'Rakefile', 'rantfile', 'Rantfile', 'rakefile-file', 'Rakefile-file', 'Puppetfile', 'Vagrantfile'],
@@ -474,7 +474,6 @@ let s:filename_checks = {
\ 'scheme': ['file.scm', 'file.ss', 'file.sld', 'file.rkt', 'file.rktd', 'file.rktl'],
\ 'scilab': ['file.sci', 'file.sce'],
\ 'screen': ['.screenrc', 'screenrc'],
- \ 'sexplib': ['file.sexp'],
\ 'scss': ['file.scss'],
\ 'sd': ['file.sd'],
\ 'sdc': ['file.sdc'],
@@ -483,28 +482,29 @@ let s:filename_checks = {
\ 'sensors': ['/etc/sensors.conf', '/etc/sensors3.conf', '/etc/sensors.d/file', 'any/etc/sensors.conf', 'any/etc/sensors3.conf', 'any/etc/sensors.d/file'],
\ 'services': ['/etc/services', 'any/etc/services'],
\ 'setserial': ['/etc/serial.conf', 'any/etc/serial.conf'],
+ \ 'sexplib': ['file.sexp'],
\ 'sh': ['.bashrc', 'file.bash', '/usr/share/doc/bash-completion/filter.sh','/etc/udev/cdsymlinks.conf', 'any/etc/udev/cdsymlinks.conf'],
\ 'sieve': ['file.siv', 'file.sieve'],
+ \ 'sil': ['file.sil'],
\ 'simula': ['file.sim'],
\ 'sinda': ['file.sin', 'file.s85'],
\ 'sisu': ['file.sst', 'file.ssm', 'file.ssi', 'file.-sst', 'file._sst', 'file.sst.meta', 'file.-sst.meta', 'file._sst.meta'],
\ 'skill': ['file.il', 'file.ils', 'file.cdf'],
\ 'slang': ['file.sl'],
\ 'slice': ['file.ice'],
- \ 'solidity': ['file.sol'],
- \ 'solution': ['file.sln'],
\ 'slpconf': ['/etc/slp.conf', 'any/etc/slp.conf'],
\ 'slpreg': ['/etc/slp.reg', 'any/etc/slp.reg'],
\ 'slpspi': ['/etc/slp.spi', 'any/etc/slp.spi'],
\ 'slrnrc': ['.slrnrc'],
\ 'slrnsc': ['file.score'],
\ 'sm': ['sendmail.cf'],
- \ 'svelte': ['file.svelte'],
\ 'smarty': ['file.tpl'],
\ 'smcl': ['file.hlp', 'file.ihlp', 'file.smcl'],
\ 'smith': ['file.smt', 'file.smith'],
\ 'sml': ['file.sml'],
\ 'snobol4': ['file.sno', 'file.spt'],
+ \ 'solidity': ['file.sol'],
+ \ 'solution': ['file.sln'],
\ 'sparql': ['file.rq', 'file.sparql'],
\ 'spec': ['file.spec'],
\ 'spice': ['file.sp', 'file.spice'],
@@ -524,11 +524,11 @@ let s:filename_checks = {
\ 'sudoers': ['any/etc/sudoers', 'sudoers.tmp', '/etc/sudoers', 'any/etc/sudoers.d/file'],
\ 'supercollider': ['file.quark'],
\ 'surface': ['file.sface'],
+ \ 'svelte': ['file.svelte'],
\ 'svg': ['file.svg'],
\ 'svn': ['svn-commitfile.tmp', 'svn-commit-file.tmp', 'svn-commit.tmp'],
\ 'swift': ['file.swift'],
\ 'swiftgyb': ['file.swift.gyb'],
- \ 'sil': ['file.sil'],
\ 'sysctl': ['/etc/sysctl.conf', '/etc/sysctl.d/file.conf', 'any/etc/sysctl.conf', 'any/etc/sysctl.d/file.conf'],
\ 'systemd': ['any/systemd/file.automount', 'any/systemd/file.dnssd', 'any/systemd/file.link', 'any/systemd/file.mount', 'any/systemd/file.netdev', 'any/systemd/file.network', 'any/systemd/file.nspawn', 'any/systemd/file.path', 'any/systemd/file.service', 'any/systemd/file.slice', 'any/systemd/file.socket', 'any/systemd/file.swap', 'any/systemd/file.target', 'any/systemd/file.timer', '/etc/systemd/some.conf.d/file.conf', '/etc/systemd/system/some.d/file.conf', '/etc/systemd/system/some.d/.#file', '/etc/systemd/system/.#otherfile', '/home/user/.config/systemd/user/some.d/mine.conf', '/home/user/.config/systemd/user/some.d/.#file', '/home/user/.config/systemd/user/.#otherfile', '/.config/systemd/user/.#', '/.config/systemd/user/.#-file', '/.config/systemd/user/file.d/.#', '/.config/systemd/user/file.d/.#-file', '/.config/systemd/user/file.d/file.conf', '/etc/systemd/file.conf.d/file.conf', '/etc/systemd/system/.#', '/etc/systemd/system/.#-file', '/etc/systemd/system/file.d/.#', '/etc/systemd/system/file.d/.#-file', '/etc/systemd/system/file.d/file.conf', '/systemd/file.automount', '/systemd/file.dnssd', '/systemd/file.link', '/systemd/file.mount', '/systemd/file.netdev', '/systemd/file.network', '/systemd/file.nspawn', '/systemd/file.path', '/systemd/file.service', '/systemd/file.slice', '/systemd/file.socket', '/systemd/file.swap', '/systemd/file.target', '/systemd/file.timer', 'any/.config/systemd/user/.#', 'any/.config/systemd/user/.#-file', 'any/.config/systemd/user/file.d/.#', 'any/.config/systemd/user/file.d/.#-file', 'any/.config/systemd/user/file.d/file.conf', 'any/etc/systemd/file.conf.d/file.conf', 'any/etc/systemd/system/.#', 'any/etc/systemd/system/.#-file', 'any/etc/systemd/system/file.d/.#', 'any/etc/systemd/system/file.d/.#-file', 'any/etc/systemd/system/file.d/file.conf'],
\ 'systemverilog': ['file.sv', 'file.svh'],
@@ -538,6 +538,7 @@ let s:filename_checks = {
\ 'taskedit': ['file.task'],
\ 'tcl': ['file.tcl', 'file.tm', 'file.tk', 'file.itcl', 'file.itk', 'file.jacl', '.tclshrc', 'tclsh.rc', '.wishrc'],
\ 'teal': ['file.tl'],
+ \ 'template': ['file.tmpl'],
\ 'teraterm': ['file.ttl'],
\ 'terminfo': ['file.ti'],
\ 'terraform': ['file.tfvars'],
@@ -574,8 +575,8 @@ let s:filename_checks = {
\ 'upstreamlog': ['fdrupstream.log', 'upstream.log', 'UPSTREAM.LOG', 'upstream.file.log', 'UPSTREAM.FILE.LOG', 'file.upstream.log', 'FILE.UPSTREAM.LOG', 'UPSTREAM-file.log', 'UPSTREAM-FILE.LOG'],
\ 'usserverlog': ['usserver.log', 'USSERVER.LOG', 'usserver.file.log', 'USSERVER.FILE.LOG', 'file.usserver.log', 'FILE.USSERVER.LOG'],
\ 'usw2kagtlog': ['usw2kagt.log', 'USW2KAGT.LOG', 'usw2kagt.file.log', 'USW2KAGT.FILE.LOG', 'file.usw2kagt.log', 'FILE.USW2KAGT.LOG'],
- \ 'vb': ['file.sba', 'file.vb', 'file.vbs', 'file.dsm', 'file.ctl'],
\ 'vala': ['file.vala'],
+ \ 'vb': ['file.sba', 'file.vb', 'file.vbs', 'file.dsm', 'file.ctl'],
\ 'vera': ['file.vr', 'file.vri', 'file.vrh'],
\ 'verilog': ['file.v'],
\ 'verilogams': ['file.va', 'file.vams'],
@@ -598,12 +599,12 @@ let s:filename_checks = {
\ 'wsml': ['file.wsml'],
\ 'wvdial': ['wvdial.conf', '.wvdialrc'],
\ 'xdefaults': ['.Xdefaults', '.Xpdefaults', '.Xresources', 'xdm-config', 'file.ad', '/Xresources/file', '/app-defaults/file', 'Xresources', 'Xresources-file', 'any/Xresources/file', 'any/app-defaults/file'],
+ \ 'xf86conf': ['xorg.conf', 'xorg.conf-4'],
\ 'xhtml': ['file.xhtml', 'file.xht'],
\ 'xinetd': ['/etc/xinetd.conf', '/etc/xinetd.d/file', 'any/etc/xinetd.conf', 'any/etc/xinetd.d/file'],
\ 'xmath': ['file.msc', 'file.msf'],
\ 'xml': ['/etc/blkid.tab', '/etc/blkid.tab.old', 'file.xmi', 'file.csproj', 'file.csproj.user', 'file.fsproj', 'file.fsproj.user', 'file.vbproj', 'file.vbproj.user', 'file.ui', 'file.tpm', '/etc/xdg/menus/file.menu', 'fglrxrc', 'file.xlf', 'file.xliff', 'file.xul', 'file.wsdl', 'file.wpl', 'any/etc/blkid.tab', 'any/etc/blkid.tab.old', 'any/etc/xdg/menus/file.menu', 'file.atom', 'file.rss', 'file.cdxml', 'file.psc1', 'file.mpd'],
\ 'xmodmap': ['anyXmodmap', 'Xmodmap', 'some-Xmodmap', 'some-xmodmap', 'some-xmodmap-file', 'xmodmap', 'xmodmap-file'],
- \ 'xf86conf': ['xorg.conf', 'xorg.conf-4'],
\ 'xpm': ['file.xpm'],
\ 'xpm2': ['file.xpm2'],
\ 'xquery': ['file.xq', 'file.xql', 'file.xqm', 'file.xquery', 'file.xqy'],
@@ -613,7 +614,6 @@ let s:filename_checks = {
\ 'yacc': ['file.yy', 'file.yxx', 'file.y++'],
\ 'yaml': ['file.yaml', 'file.yml'],
\ 'yang': ['file.yang'],
- \ 'raml': ['file.raml'],
\ 'z8a': ['file.z8a'],
\ 'zig': ['file.zig'],
\ 'zimbu': ['file.zu'],
@@ -843,6 +843,7 @@ func Test_cfg_file()
let ext = substitute(ext, '\(\l\)', '\u\1', '')
endfor
+ " clean up
filetype off
endfunc
diff --git a/src/nvim/testdir/test_fold.vim b/src/nvim/testdir/test_fold.vim
index 9f5ad53adb..327f0f73f2 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,72 @@ 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
+
+" Make sure that when appending [an indented line then a blank line] right
+" before a single indented line, the resulting extended fold can be closed
+func Test_indent_append_blank_small_fold_close()
+ new
+ setlocal sw=2 foldmethod=indent
+ " at first, the fold at the second line can't be closed since it's smaller
+ " than foldminlines
+ let lines =<< trim END
+ line 1
+ line 4
+ END
+ call setline(1, lines)
+ call append(1, [' line 2', ''])
+ " close all folds
+ normal zM
+ call assert_notequal(-1, foldclosed(2)) " the fold should be closed now
+ 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_normal.vim b/src/nvim/testdir/test_normal.vim
index 1feffe1f8c..d1cb89bbd4 100644
--- a/src/nvim/testdir/test_normal.vim
+++ b/src/nvim/testdir/test_normal.vim
@@ -133,7 +133,8 @@ func Test_normal02_selectmode2()
" some basic select mode tests
call Setup_NewWindow()
50
- call feedkeys(":set im\n\<c-o>gHc\<c-o>:set noim\n", 'tx')
+ " call feedkeys(":set im\n\<c-o>gHc\<c-o>:set noim\n", 'tx')
+ call feedkeys("i\<c-o>gHc\<esc>", 'tx')
call assert_equal('c51', getline('.'))
" clean up
bw!
@@ -2113,11 +2114,11 @@ fun! Test_normal40_ctrl_bsl()
call assert_equal('n', mode())
call assert_equal(1, col('.'))
"imap <buffer> , <c-\><c-n>
- set im
+ " set im
exe ":norm! \<c-\>\<c-n>dw"
- set noim
+ " set noim
call assert_equal('are some words', getline(1))
- call assert_false(&insertmode)
+ " call assert_false(&insertmode)
" clean up
bw!
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/testdir/test_textformat.vim b/src/nvim/testdir/test_textformat.vim
index 92705cb69f..748af199b2 100644
--- a/src/nvim/testdir/test_textformat.vim
+++ b/src/nvim/testdir/test_textformat.vim
@@ -289,11 +289,28 @@ func Test_format_c_comment()
x
END
call assert_equal(expected, getline(1, '$'))
+
+ " Comment is formatted when it wraps
+ normal 2GA with some more text added
+ let expected =<< trim END
+ nop;
+ val = val; // This is a comment
+ // with some more text
+ // added
+ x
+ END
+ call assert_equal(expected, getline(1, '$'))
+
set fo-=/
" using 'indentexpr' instead of 'cindent' does not repeat a comment
setl nocindent indentexpr=2
- 3delete
+ %del
+ let text =<< trim END
+ nop;
+ val = val; // This is a comment
+ END
+ call setline(1, text)
normal 2Gox
let expected =<< trim END
nop;
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..0ba5bb1889 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);
@@ -5096,6 +5119,12 @@ static void win_free(win_T *wp, tabpage_T *tp)
xfree(wp->w_localdir);
xfree(wp->w_prevdir);
+ stl_clear_click_defs(wp->w_status_click_defs, wp->w_status_click_defs_size);
+ xfree(wp->w_status_click_defs);
+
+ stl_clear_click_defs(wp->w_winbar_click_defs, wp->w_winbar_click_defs_size);
+ xfree(wp->w_winbar_click_defs);
+
// Remove the window from the b_wininfo lists, it may happen that the
// freed memory is re-used for another window.
FOR_ALL_BUFFERS(buf) {
@@ -5460,16 +5489,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 +6284,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 +6301,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 +6328,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.
@@ -6586,6 +6618,23 @@ void last_status(bool morewin)
global_stl_height() > 0);
}
+// Remove status line from window, replacing it with a horizontal separator if needed.
+static void win_remove_status_line(win_T *wp, bool add_hsep)
+{
+ wp->w_status_height = 0;
+ if (add_hsep) {
+ wp->w_hsep_height = 1;
+ } else {
+ win_new_height(wp, wp->w_height + STATUS_HEIGHT);
+ }
+ comp_col();
+
+ stl_clear_click_defs(wp->w_status_click_defs, wp->w_status_click_defs_size);
+ xfree(wp->w_status_click_defs);
+ wp->w_status_click_defs_size = 0;
+ wp->w_status_click_defs = NULL;
+}
+
// Look for resizable frames and take lines from them to make room for the statusline
static void resize_frame_for_status(frame_T *fr)
{
@@ -6626,10 +6675,7 @@ static void last_status_rec(frame_T *fr, bool statusline, bool is_stl_global)
if (is_last) {
if (wp->w_status_height != 0 && (!statusline || is_stl_global)) {
- // Remove status line
- wp->w_status_height = 0;
- win_new_height(wp, wp->w_height + STATUS_HEIGHT);
- comp_col();
+ win_remove_status_line(wp, false);
} else if (wp->w_status_height == 0 && !is_stl_global && statusline) {
// Add statusline to window if needed
wp->w_status_height = STATUS_HEIGHT;
@@ -6639,9 +6685,7 @@ static void last_status_rec(frame_T *fr, bool statusline, bool is_stl_global)
} else if (wp->w_status_height != 0 && is_stl_global) {
// If statusline is global and the window has a statusline, replace it with a horizontal
// separator
- wp->w_status_height = 0;
- wp->w_hsep_height = 1;
- comp_col();
+ win_remove_status_line(wp, true);
} else if (wp->w_status_height == 0 && !is_stl_global) {
// If statusline isn't global and the window doesn't have a statusline, re-add it
wp->w_status_height = STATUS_HEIGHT;
@@ -6649,19 +6693,35 @@ static void last_status_rec(frame_T *fr, bool statusline, bool is_stl_global)
comp_col();
}
redraw_all_later(SOME_VALID);
- } else if (fr->fr_layout == FR_COL) {
- // For a column frame, recursively call this function for all child frames
- FOR_ALL_FRAMES(fp, fr->fr_child) {
- last_status_rec(fp, statusline, is_stl_global);
- }
} else {
- // For a row frame, recursively call this function for all child frames
+ // For a column or row frame, recursively call this function for all child frames
FOR_ALL_FRAMES(fp, fr->fr_child) {
last_status_rec(fp, statusline, 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_status = wp->w_redr_status || winbar_height;
+
+ if (winbar_height == 0) {
+ // When removing winbar, deallocate the w_winbar_click_defs array
+ stl_clear_click_defs(wp->w_winbar_click_defs, wp->w_winbar_click_defs_size);
+ xfree(wp->w_winbar_click_defs);
+ wp->w_winbar_click_defs_size = 0;
+ wp->w_winbar_click_defs = NULL;
+ }
+ }
+ }
+}
+
/// Return the number of lines used by the tab page line.
int tabline_height(void)
{
@@ -6678,6 +6738,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)
{