diff options
152 files changed, 3029 insertions, 2801 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index f44937b5ae..87223b9d4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -136,14 +136,14 @@ set_property(CACHE CMAKE_BUILD_TYPE PROPERTY # If not in a git repo (e.g., a tarball) these tokens define the complete # version string, else they are combined with the result of `git describe`. set(NVIM_VERSION_MAJOR 0) -set(NVIM_VERSION_MINOR 6) +set(NVIM_VERSION_MINOR 7) set(NVIM_VERSION_PATCH 0) set(NVIM_VERSION_PRERELEASE "-dev") # for package maintainers # API level set(NVIM_API_LEVEL 8) # Bump this after any API change. set(NVIM_API_LEVEL_COMPAT 0) # Adjust this after a _breaking_ API change. -set(NVIM_API_PRERELEASE true) +set(NVIM_API_PRERELEASE false) set(NVIM_VERSION_BUILD_TYPE "${CMAKE_BUILD_TYPE}") # NVIM_VERSION_CFLAGS set further below. diff --git a/ci/snap/deploy.sh b/ci/snap/deploy.sh index 579c48e933..8429059e22 100755 --- a/ci/snap/deploy.sh +++ b/ci/snap/deploy.sh @@ -24,7 +24,7 @@ snap_realease_needed() { trigger_snapcraft_webhook() { [[ -n "${PAYLOAD_SIG}" ]] || exit - echo "Triggering new snap relase via webhook..." + echo "Triggering new snap release via webhook..." curl -X POST \ -H "Content-Type: application/json" \ -H "X-Hub-Signature: sha1=${PAYLOAD_SIG}" \ diff --git a/config/CMakeLists.txt b/config/CMakeLists.txt index 581f25857b..613475b00d 100644 --- a/config/CMakeLists.txt +++ b/config/CMakeLists.txt @@ -92,7 +92,7 @@ if (NOT "${HAVE_BE64TOH}") # any case and ORDER_BIG_ENDIAN will not be examined. # - CMAKE_CROSSCOMPILING *and* HAVE_BE64TOH are both false. In this case # be64toh function which uses cycle and arithmetic operations is used which - # will work regardless of endianess. Function is sub-optimal though. + # will work regardless of endianness. Function is sub-optimal though. check_c_source_runs(" ${SI} ${MS} diff --git a/contrib/local.mk.example b/contrib/local.mk.example index 778e848d60..20396e86ae 100644 --- a/contrib/local.mk.example +++ b/contrib/local.mk.example @@ -27,7 +27,7 @@ # With non-Debug builds interprocedural optimization (IPO) (which includes # link-time optimization (LTO)) is enabled by default, which causes the link -# step to take a significant amout of time, which is relevant when building +# step to take a significant amount of time, which is relevant when building # often. You can disable it explicitly: # CMAKE_EXTRA_FLAGS += -DENABLE_LTO=OFF diff --git a/man/nvim.1 b/man/nvim.1 index b206b62343..43dfc21dc7 100644 --- a/man/nvim.1 +++ b/man/nvim.1 @@ -177,8 +177,7 @@ If .Ar vimrc is .Cm NORC , -do not load any initialization files (except plugins), -and do not attempt to parse environment variables. +do not load any initialization files (except plugins). If .Ar vimrc is diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 37029874f2..f656f1cbc3 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -123,7 +123,7 @@ foreach(PROG ${RUNTIME_PROGRAMS}) endforeach() globrecurse_wrapper(RUNTIME_FILES ${CMAKE_CURRENT_SOURCE_DIR} - rgb.txt *.vim *.lua *.dict *.py *.rb *.ps *.spl *.tutor *.tutor.json) + *.vim *.lua *.dict *.py *.rb *.ps *.spl *.tutor *.tutor.json) foreach(F ${RUNTIME_FILES}) get_filename_component(BASEDIR ${F} PATH) diff --git a/runtime/autoload/dist/ft.vim b/runtime/autoload/dist/ft.vim index 7484149a26..74df871544 100644 --- a/runtime/autoload/dist/ft.vim +++ b/runtime/autoload/dist/ft.vim @@ -219,6 +219,23 @@ func dist#ft#FTe() endif endfunc +" Distinguish between Forth and F#. +" Provided by Doug Kearns. +func dist#ft#FTfs() + if exists("g:filetype_fs") + exe "setf " . g:filetype_fs + else + let line = getline(nextnonblank(1)) + " comments and colon definitions + if line =~ '^\s*\.\=( ' || line =~ '^\s*\\G\= ' || line =~ '^\\$' + \ || line =~ '^\s*: \S' + setf forth + else + setf fsharp + endif + endif +endfunc + " Distinguish between HTML, XHTML and Django func dist#ft#FThtml() let n = 1 @@ -272,6 +289,8 @@ func dist#ft#FTm() " excluding end(for|function|if|switch|while) common to Murphi let octave_block_terminators = '\<end\%(_try_catch\|classdef\|enumeration\|events\|methods\|parfor\|properties\)\>' + let objc_preprocessor = '^\s*#\s*\%(import\|include\|define\|if\|ifn\=def\|undef\|line\|error\|pragma\)\>' + let n = 1 let saw_comment = 0 " Whether we've seen a multiline comment leader. while n < 100 @@ -282,7 +301,7 @@ func dist#ft#FTm() " anything more definitive. let saw_comment = 1 endif - if line =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|//\)' + if line =~ '^\s*//' || line =~ '^\s*@import\>' || line =~ objc_preprocessor setf objc return endif diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index bb8e83f84a..482d8c198d 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -652,35 +652,6 @@ nvim_call_atomic({calls}) *nvim_call_atomic()* occurred, the values from all preceding calls will still be returned. - *nvim_call_dict_function()* -nvim_call_dict_function({dict}, {fn}, {args}) - Calls a VimL |Dictionary-function| with the given arguments. - - On execution error: fails with VimL error, does not update - v:errmsg. - - Parameters: ~ - {dict} Dictionary, or String evaluating to a VimL |self| - dict - {fn} Name of the function defined on the VimL dict - {args} Function arguments packed in an Array - - Return: ~ - Result of the function call - -nvim_call_function({fn}, {args}) *nvim_call_function()* - Calls a VimL function with the given arguments. - - On execution error: fails with VimL error, does not update - v:errmsg. - - Parameters: ~ - {fn} Function to call - {args} Function arguments packed in an Array - - Return: ~ - Result of the function call - nvim_chan_send({chan}, {data}) *nvim_chan_send()* Send data to channel `id` . For a job, it writes it to the stdin of the process. For the stdio channel |channel-stdio|, @@ -697,18 +668,6 @@ nvim_chan_send({chan}, {data}) *nvim_chan_send()* {chan} id of the channel {data} data to write. 8-bit clean: can contain NUL bytes. -nvim_command({command}) *nvim_command()* - Executes an ex-command. - - On execution error: fails with VimL error, does not update - v:errmsg. - - Parameters: ~ - {command} Ex-command string - - See also: ~ - |nvim_exec()| - nvim_create_buf({listed}, {scratch}) *nvim_create_buf()* Creates a new, empty, unnamed buffer. @@ -724,22 +683,6 @@ nvim_create_buf({listed}, {scratch}) *nvim_create_buf()* See also: ~ buf_open_scratch -nvim_create_namespace({name}) *nvim_create_namespace()* - Creates a new *namespace* or gets an existing one. - - Namespaces are used for buffer highlights and virtual text, - see |nvim_buf_add_highlight()| and |nvim_buf_set_extmark()|. - - Namespaces can be named or anonymous. If `name` matches an - existing namespace, the associated id is returned. If `name` - is an empty string a new, anonymous namespace is created. - - Parameters: ~ - {name} Namespace name or empty string - - Return: ~ - Namespace id - nvim_del_current_line() *nvim_del_current_line()* Deletes the current line. @@ -806,19 +749,6 @@ nvim_err_writeln({str}) *nvim_err_writeln()* See also: ~ nvim_err_write() -nvim_eval({expr}) *nvim_eval()* - Evaluates a VimL |expression|. Dictionaries and Lists are - recursively expanded. - - On execution error: fails with VimL error, does not update - v:errmsg. - - Parameters: ~ - {expr} VimL expression string - - Return: ~ - Evaluation result or expanded object - nvim_eval_statusline({str}, {*opts}) *nvim_eval_statusline()* Evaluates statusline string. @@ -852,29 +782,6 @@ nvim_eval_statusline({str}, {*opts}) *nvim_eval_statusline()* character that uses the highlight. • group: (string) Name of highlight group. -nvim_exec({src}, {output}) *nvim_exec()* - Executes Vimscript (multiline block of Ex-commands), like - anonymous |:source|. - - Unlike |nvim_command()| this function supports heredocs, - script-scope (s:), etc. - - On execution error: fails with VimL error, does not update - v:errmsg. - - Parameters: ~ - {src} Vimscript code - {output} Capture and return all (non-error, non-shell - |:!|) output - - Return: ~ - Output (non-error, non-shell |:!|) if `output` is true, - else empty string. - - See also: ~ - |execute()| - |nvim_command()| - nvim_exec_lua({code}, {args}) *nvim_exec_lua()* Execute Lua code. Parameters (if any) are available as `...` inside the chunk. The chunk can return a value. @@ -1110,12 +1017,6 @@ nvim_get_mode() *nvim_get_mode()* Attributes: ~ {fast} -nvim_get_namespaces() *nvim_get_namespaces()* - Gets existing, non-anonymous namespaces. - - Return: ~ - dict that maps from names to namespace ids. - nvim_get_option({name}) *nvim_get_option()* Gets an option value string. @@ -1344,7 +1245,15 @@ nvim_open_term({buffer}, {opts}) *nvim_open_term()* Parameters: ~ {buffer} the buffer to use (expected to be empty) - {opts} Optional parameters. Reserved for future use. + {opts} Optional parameters. + • on_input: lua callback for input sent, i e + keypresses in terminal mode. Note: keypresses + are sent raw as they would be to the pty + master end. For instance, a carriage return is + sent as a "\r", not as a "\n". |textlock| + applies. It is possible to call + |nvim_chan_send| directly in the callback + however. ["input", term, bufnr, data] Return: ~ Channel id, or 0 on error @@ -1357,104 +1266,6 @@ nvim_out_write({str}) *nvim_out_write()* Parameters: ~ {str} Message - *nvim_parse_expression()* -nvim_parse_expression({expr}, {flags}, {highlight}) - Parse a VimL expression. - - Attributes: ~ - {fast} - - Parameters: ~ - {expr} Expression to parse. Always treated as a - single line. - {flags} Flags: - • "m" if multiple expressions in a row are - allowed (only the first one will be - parsed), - • "E" if EOC tokens are not allowed - (determines whether they will stop parsing - process or be recognized as an - operator/space, though also yielding an - error). - • "l" when needing to start parsing with - lvalues for ":let" or ":for". Common flag - sets: - • "m" to parse like for ":echo". - • "E" to parse like for "<C-r>=". - • empty string for ":call". - • "lm" to parse for ":let". - {highlight} If true, return value will also include - "highlight" key containing array of 4-tuples - (arrays) (Integer, Integer, Integer, String), - where first three numbers define the - highlighted region and represent line, - starting column and ending column (latter - exclusive: one should highlight region - [start_col, end_col)). - - Return: ~ - - • AST: top-level dictionary with these keys: - • "error": Dictionary with error, present only if parser - saw some error. Contains the following keys: - • "message": String, error message in printf format, - translated. Must contain exactly one "%.*s". - • "arg": String, error message argument. - - • "len": Amount of bytes successfully parsed. With flags - equal to "" that should be equal to the length of expr - string. (“Successfully parsed” here means - “participated in AST creation”, not “till the first - error”.) - • "ast": AST, either nil or a dictionary with these - keys: - • "type": node type, one of the value names from - ExprASTNodeType stringified without "kExprNode" - prefix. - • "start": a pair [line, column] describing where node - is "started" where "line" is always 0 (will not be 0 - if you will be using nvim_parse_viml() on e.g. - ":let", but that is not present yet). Both elements - are Integers. - • "len": “length” of the node. This and "start" are - there for debugging purposes primary (debugging - parser and providing debug information). - • "children": a list of nodes described in top/"ast". - There always is zero, one or two children, key will - not be present if node has no children. Maximum - number of children may be found in node_maxchildren - array. - - • Local values (present only for certain nodes): - • "scope": a single Integer, specifies scope for - "Option" and "PlainIdentifier" nodes. For "Option" it - is one of ExprOptScope values, for "PlainIdentifier" - it is one of ExprVarScope values. - • "ident": identifier (without scope, if any), present - for "Option", "PlainIdentifier", "PlainKey" and - "Environment" nodes. - • "name": Integer, register name (one character) or -1. - Only present for "Register" nodes. - • "cmp_type": String, comparison type, one of the value - names from ExprComparisonType, stringified without - "kExprCmp" prefix. Only present for "Comparison" - nodes. - • "ccs_strategy": String, case comparison strategy, one - of the value names from ExprCaseCompareStrategy, - stringified without "kCCStrategy" prefix. Only present - for "Comparison" nodes. - • "augmentation": String, augmentation type for - "Assignment" nodes. Is either an empty string, "Add", - "Subtract" or "Concat" for "=", "+=", "-=" or ".=" - respectively. - • "invert": Boolean, true if result of comparison needs - to be inverted. Only present for "Comparison" nodes. - • "ivalue": Integer, integer value for "Integer" nodes. - • "fvalue": Float, floating-point value for "Float" - nodes. - • "svalue": String, value for "SingleQuotedString" and - "DoubleQuotedString" nodes. - nvim_paste({data}, {crlf}, {phase}) *nvim_paste()* Pastes at cursor, in any mode. @@ -1650,53 +1461,6 @@ nvim_set_current_win({window}) *nvim_set_current_win()* Parameters: ~ {window} Window handle - *nvim_set_decoration_provider()* -nvim_set_decoration_provider({ns_id}, {opts}) - Set or change decoration provider for a namespace - - This is a very general purpose interface for having lua - callbacks being triggered during the redraw code. - - The expected usage is to set extmarks for the currently - redrawn buffer. |nvim_buf_set_extmark| can be called to add - marks on a per-window or per-lines basis. Use the `ephemeral` - key to only use the mark for the current screen redraw (the - callback will be called again for the next redraw ). - - Note: this function should not be called often. Rather, the - callbacks themselves can be used to throttle unneeded - callbacks. the `on_start` callback can return `false` to - disable the provider until the next redraw. Similarly, return - `false` in `on_win` will skip the `on_lines` calls for that - window (but any extmarks set in `on_win` will still be used). - A plugin managing multiple sources of decoration should - ideally only set one provider, and merge the sources - internally. You can use multiple `ns_id` for the extmarks - set/modified inside the callback anyway. - - Note: doing anything other than setting extmarks is considered - experimental. Doing things like changing options are not - expliticly forbidden, but is likely to have unexpected - consequences (such as 100% CPU consumption). doing - `vim.rpcnotify` should be OK, but `vim.rpcrequest` is quite - dubious for the moment. - - Parameters: ~ - {ns_id} Namespace id from |nvim_create_namespace()| - {opts} Callbacks invoked during redraw: - • on_start: called first on each screen redraw - ["start", tick] - • on_buf: called for each buffer being redrawn - (before window callbacks) ["buf", bufnr, tick] - • on_win: called when starting to redraw a - specific window. ["win", winid, bufnr, topline, - botline_guess] - • on_line: called for each buffer line being - redrawn. (The interation with fold lines is - subject to change) ["win", winid, bufnr, row] - • on_end: called at the end of a redraw cycle - ["end", tick] - nvim_set_hl({ns_id}, {name}, {val}) *nvim_set_hl()* Set a highlight group. @@ -1790,6 +1554,185 @@ nvim_unsubscribe({event}) *nvim_unsubscribe()* ============================================================================== +Vimscript Functions *api-vimscript* + + *nvim_call_dict_function()* +nvim_call_dict_function({dict}, {fn}, {args}) + Calls a VimL |Dictionary-function| with the given arguments. + + On execution error: fails with VimL error, does not update + v:errmsg. + + Parameters: ~ + {dict} Dictionary, or String evaluating to a VimL |self| + dict + {fn} Name of the function defined on the VimL dict + {args} Function arguments packed in an Array + + Return: ~ + Result of the function call + +nvim_call_function({fn}, {args}) *nvim_call_function()* + Calls a VimL function with the given arguments. + + On execution error: fails with VimL error, does not update + v:errmsg. + + Parameters: ~ + {fn} Function to call + {args} Function arguments packed in an Array + + Return: ~ + Result of the function call + +nvim_command({command}) *nvim_command()* + Executes an ex-command. + + On execution error: fails with VimL error, does not update + v:errmsg. + + Parameters: ~ + {command} Ex-command string + + See also: ~ + |nvim_exec()| + +nvim_eval({expr}) *nvim_eval()* + Evaluates a VimL |expression|. Dictionaries and Lists are + recursively expanded. + + On execution error: fails with VimL error, does not update + v:errmsg. + + Parameters: ~ + {expr} VimL expression string + + Return: ~ + Evaluation result or expanded object + +nvim_exec({src}, {output}) *nvim_exec()* + Executes Vimscript (multiline block of Ex-commands), like + anonymous |:source|. + + Unlike |nvim_command()| this function supports heredocs, + script-scope (s:), etc. + + On execution error: fails with VimL error, does not update + v:errmsg. + + Parameters: ~ + {src} Vimscript code + {output} Capture and return all (non-error, non-shell + |:!|) output + + Return: ~ + Output (non-error, non-shell |:!|) if `output` is true, + else empty string. + + See also: ~ + |execute()| + |nvim_command()| + + *nvim_parse_expression()* +nvim_parse_expression({expr}, {flags}, {highlight}) + Parse a VimL expression. + + Attributes: ~ + {fast} + + Parameters: ~ + {expr} Expression to parse. Always treated as a + single line. + {flags} Flags: + • "m" if multiple expressions in a row are + allowed (only the first one will be + parsed), + • "E" if EOC tokens are not allowed + (determines whether they will stop parsing + process or be recognized as an + operator/space, though also yielding an + error). + • "l" when needing to start parsing with + lvalues for ":let" or ":for". Common flag + sets: + • "m" to parse like for ":echo". + • "E" to parse like for "<C-r>=". + • empty string for ":call". + • "lm" to parse for ":let". + {highlight} If true, return value will also include + "highlight" key containing array of 4-tuples + (arrays) (Integer, Integer, Integer, String), + where first three numbers define the + highlighted region and represent line, + starting column and ending column (latter + exclusive: one should highlight region + [start_col, end_col)). + + Return: ~ + + • AST: top-level dictionary with these keys: + • "error": Dictionary with error, present only if parser + saw some error. Contains the following keys: + • "message": String, error message in printf format, + translated. Must contain exactly one "%.*s". + • "arg": String, error message argument. + + • "len": Amount of bytes successfully parsed. With flags + equal to "" that should be equal to the length of expr + string. (“Successfully parsed” here means + “participated in AST creation”, not “till the first + error”.) + • "ast": AST, either nil or a dictionary with these + keys: + • "type": node type, one of the value names from + ExprASTNodeType stringified without "kExprNode" + prefix. + • "start": a pair [line, column] describing where node + is "started" where "line" is always 0 (will not be 0 + if you will be using nvim_parse_viml() on e.g. + ":let", but that is not present yet). Both elements + are Integers. + • "len": “length” of the node. This and "start" are + there for debugging purposes primary (debugging + parser and providing debug information). + • "children": a list of nodes described in top/"ast". + There always is zero, one or two children, key will + not be present if node has no children. Maximum + number of children may be found in node_maxchildren + array. + + • Local values (present only for certain nodes): + • "scope": a single Integer, specifies scope for + "Option" and "PlainIdentifier" nodes. For "Option" it + is one of ExprOptScope values, for "PlainIdentifier" + it is one of ExprVarScope values. + • "ident": identifier (without scope, if any), present + for "Option", "PlainIdentifier", "PlainKey" and + "Environment" nodes. + • "name": Integer, register name (one character) or -1. + Only present for "Register" nodes. + • "cmp_type": String, comparison type, one of the value + names from ExprComparisonType, stringified without + "kExprCmp" prefix. Only present for "Comparison" + nodes. + • "ccs_strategy": String, case comparison strategy, one + of the value names from ExprCaseCompareStrategy, + stringified without "kCCStrategy" prefix. Only present + for "Comparison" nodes. + • "augmentation": String, augmentation type for + "Assignment" nodes. Is either an empty string, "Add", + "Subtract" or "Concat" for "=", "+=", "-=" or ".=" + respectively. + • "invert": Boolean, true if result of comparison needs + to be inverted. Only present for "Comparison" nodes. + • "ivalue": Integer, integer value for "Integer" nodes. + • "fvalue": Float, floating-point value for "Float" + nodes. + • "svalue": String, value for "SingleQuotedString" and + "DoubleQuotedString" nodes. + + +============================================================================== Buffer Functions *api-buffer* @@ -1815,48 +1758,6 @@ nvim__buf_redraw_range({buffer}, {first}, {last}) nvim__buf_stats({buffer}) *nvim__buf_stats()* TODO: Documentation - *nvim_buf_add_highlight()* -nvim_buf_add_highlight({buffer}, {ns_id}, {hl_group}, {line}, {col_start}, - {col_end}) - Adds a highlight to buffer. - - Useful for plugins that dynamically generate highlights to a - buffer (like a semantic highlighter or linter). The function - adds a single highlight to a buffer. Unlike |matchaddpos()| - highlights follow changes to line numbering (as lines are - inserted/removed above the highlighted line), like signs and - marks do. - - Namespaces are used for batch deletion/updating of a set of - highlights. To create a namespace, use - |nvim_create_namespace()| which returns a namespace id. Pass - it in to this function as `ns_id` to add highlights to the - namespace. All highlights in the same namespace can then be - cleared with single call to |nvim_buf_clear_namespace()|. If - the highlight never will be deleted by an API call, pass - `ns_id = -1` . - - As a shorthand, `ns_id = 0` can be used to create a new - namespace for the highlight, the allocated id is then - returned. If `hl_group` is the empty string no highlight is - added, but a new `ns_id` is still returned. This is supported - for backwards compatibility, new code should use - |nvim_create_namespace()| to create a new empty namespace. - - Parameters: ~ - {buffer} Buffer handle, or 0 for current buffer - {ns_id} namespace to use or -1 for ungrouped - highlight - {hl_group} Name of the highlight group to use - {line} Line to highlight (zero-indexed) - {col_start} Start of (byte-indexed) column range to - highlight - {col_end} End of (byte-indexed) column range to - highlight, or -1 to highlight to end of line - - Return: ~ - The ns_id that was used - nvim_buf_attach({buffer}, {send_buffer}, {opts}) *nvim_buf_attach()* Activates buffer-update events on a channel, or as Lua callbacks. @@ -1950,7 +1851,7 @@ nvim_buf_call({buffer}, {fun}) *nvim_buf_call()* switched If a window inside the current tabpage (including a float) already shows the buffer One of these windows will be set as current window temporarily. Otherwise a temporary - scratch window (calleed the "autocmd window" for historical + scratch window (called the "autocmd window" for historical reasons) will be used. This is useful e.g. to call vimL functions that only work with @@ -1965,33 +1866,6 @@ nvim_buf_call({buffer}, {fun}) *nvim_buf_call()* Return value of function. NB: will deepcopy lua values currently, use upvalues to send lua references in and out. - *nvim_buf_clear_namespace()* -nvim_buf_clear_namespace({buffer}, {ns_id}, {line_start}, {line_end}) - Clears namespaced objects (highlights, extmarks, virtual text) - from a region. - - Lines are 0-indexed. |api-indexing| To clear the namespace in - the entire buffer, specify line_start=0 and line_end=-1. - - Parameters: ~ - {buffer} Buffer handle, or 0 for current buffer - {ns_id} Namespace to clear, or -1 to clear all - namespaces. - {line_start} Start of range of lines to clear - {line_end} End of range of lines to clear (exclusive) - or -1 to clear to end of buffer. - -nvim_buf_del_extmark({buffer}, {ns_id}, {id}) *nvim_buf_del_extmark()* - Removes an extmark. - - Parameters: ~ - {buffer} Buffer handle, or 0 for current buffer - {ns_id} Namespace id from |nvim_create_namespace()| - {id} Extmark id - - Return: ~ - true if the extmark was found, else false - nvim_buf_del_keymap({buffer}, {mode}, {lhs}) *nvim_buf_del_keymap()* Unmaps a buffer-local |mapping| for the given mode. @@ -2073,73 +1947,6 @@ nvim_buf_get_commands({buffer}, {*opts}) *nvim_buf_get_commands()* Return: ~ Map of maps describing commands. - *nvim_buf_get_extmark_by_id()* -nvim_buf_get_extmark_by_id({buffer}, {ns_id}, {id}, {opts}) - Gets the position (0-indexed) of an extmark. - - Parameters: ~ - {buffer} Buffer handle, or 0 for current buffer - {ns_id} Namespace id from |nvim_create_namespace()| - {id} Extmark id - {opts} Optional parameters. Keys: - • details: Whether to include the details dict - - Return: ~ - 0-indexed (row, col) tuple or empty list () if extmark id - was absent - - *nvim_buf_get_extmarks()* -nvim_buf_get_extmarks({buffer}, {ns_id}, {start}, {end}, {opts}) - Gets extmarks in "traversal order" from a |charwise| region - defined by buffer positions (inclusive, 0-indexed - |api-indexing|). - - Region can be given as (row,col) tuples, or valid extmark ids - (whose positions define the bounds). 0 and -1 are understood - as (0,0) and (-1,-1) respectively, thus the following are - equivalent: -> - nvim_buf_get_extmarks(0, my_ns, 0, -1, {}) - nvim_buf_get_extmarks(0, my_ns, [0,0], [-1,-1], {}) -< - - If `end` is less than `start` , traversal works backwards. - (Useful with `limit` , to get the first marks prior to a given - position.) - - Example: -> - local a = vim.api - local pos = a.nvim_win_get_cursor(0) - local ns = a.nvim_create_namespace('my-plugin') - -- Create new extmark at line 1, column 1. - local m1 = a.nvim_buf_set_extmark(0, ns, 0, 0, 0, {}) - -- Create new extmark at line 3, column 1. - local m2 = a.nvim_buf_set_extmark(0, ns, 0, 2, 0, {}) - -- Get extmarks only from line 3. - local ms = a.nvim_buf_get_extmarks(0, ns, {2,0}, {2,0}, {}) - -- Get all marks in this buffer + namespace. - local all = a.nvim_buf_get_extmarks(0, ns, 0, -1, {}) - print(vim.inspect(ms)) -< - - Parameters: ~ - {buffer} Buffer handle, or 0 for current buffer - {ns_id} Namespace id from |nvim_create_namespace()| - {start} Start of range: a 0-indexed (row, col) or valid - extmark id (whose position defines the bound). - |api-indexing| - {end} End of range (inclusive): a 0-indexed (row, col) - or valid extmark id (whose position defines the - bound). |api-indexing| - {opts} Optional parameters. Keys: - • limit: Maximum number of marks to return - • details Whether to include the details dict - - Return: ~ - List of [extmark_id, row, col] tuples in "traversal - order". - nvim_buf_get_keymap({buffer}, {mode}) *nvim_buf_get_keymap()* Gets a list of buffer-local |mapping| definitions. @@ -2270,6 +2077,257 @@ nvim_buf_line_count({buffer}) *nvim_buf_line_count()* Return: ~ Line count, or 0 for unloaded buffer. |api-buffer| + *nvim_buf_set_keymap()* +nvim_buf_set_keymap({buffer}, {mode}, {lhs}, {rhs}, {*opts}) + Sets a buffer-local |mapping| for the given mode. + + Parameters: ~ + {buffer} Buffer handle, or 0 for current buffer + + See also: ~ + |nvim_set_keymap()| + + *nvim_buf_set_lines()* +nvim_buf_set_lines({buffer}, {start}, {end}, {strict_indexing}, {replacement}) + Sets (replaces) a line-range in the buffer. + + Indexing is zero-based, end-exclusive. Negative indices are + interpreted as length+1+index: -1 refers to the index past the + end. So to change or delete the last element use start=-2 and + end=-1. + + To insert lines at a given index, set `start` and `end` to the + same index. To delete a range of lines, set `replacement` to + an empty array. + + Out-of-bounds indices are clamped to the nearest valid value, + unless `strict_indexing` is set. + + Attributes: ~ + not allowed when |textlock| is active + + Parameters: ~ + {buffer} Buffer handle, or 0 for current buffer + {start} First line index + {end} Last line index (exclusive) + {strict_indexing} Whether out-of-bounds should be an + error. + {replacement} Array of lines to use as replacement + + *nvim_buf_set_mark()* +nvim_buf_set_mark({buffer}, {name}, {line}, {col}, {opts}) + Sets a named mark in the given buffer, all marks are allowed + file/uppercase, visual, last change, etc. See |mark-motions|. + + Marks are (1,0)-indexed. |api-indexing| + + Note: + Passing 0 as line deletes the mark + + Parameters: ~ + {buffer} Buffer to set the mark on + {name} Mark name + {line} Line number + {col} Column/row number + {opts} Optional parameters. Reserved for future use. + + Return: ~ + true if the mark was set, else false. + + See also: ~ + |nvim_buf_del_mark()| + |nvim_buf_get_mark()| + +nvim_buf_set_name({buffer}, {name}) *nvim_buf_set_name()* + Sets the full file name for a buffer + + Parameters: ~ + {buffer} Buffer handle, or 0 for current buffer + {name} Buffer name + +nvim_buf_set_option({buffer}, {name}, {value}) *nvim_buf_set_option()* + Sets a buffer option value. Passing 'nil' as value deletes the + option (only works if there's a global fallback) + + Parameters: ~ + {buffer} Buffer handle, or 0 for current buffer + {name} Option name + {value} Option value + + *nvim_buf_set_text()* +nvim_buf_set_text({buffer}, {start_row}, {start_col}, {end_row}, {end_col}, + {replacement}) + Sets (replaces) a range in the buffer + + This is recommended over nvim_buf_set_lines when only + modifying parts of a line, as extmarks will be preserved on + non-modified parts of the touched lines. + + Indexing is zero-based and end-exclusive. + + To insert text at a given index, set `start` and `end` ranges + to the same index. To delete a range, set `replacement` to an + array containing an empty string, or simply an empty array. + + Prefer nvim_buf_set_lines when adding or deleting entire lines + only. + + Parameters: ~ + {buffer} Buffer handle, or 0 for current buffer + {start_row} First line index + {start_column} First column + {end_row} Last line index + {end_column} Last column + {replacement} Array of lines to use as replacement + +nvim_buf_set_var({buffer}, {name}, {value}) *nvim_buf_set_var()* + Sets a buffer-scoped (b:) variable + + Parameters: ~ + {buffer} Buffer handle, or 0 for current buffer + {name} Variable name + {value} Variable value + + +============================================================================== +Extmark Functions *api-extmark* + + *nvim_buf_add_highlight()* +nvim_buf_add_highlight({buffer}, {ns_id}, {hl_group}, {line}, {col_start}, + {col_end}) + Adds a highlight to buffer. + + Useful for plugins that dynamically generate highlights to a + buffer (like a semantic highlighter or linter). The function + adds a single highlight to a buffer. Unlike |matchaddpos()| + highlights follow changes to line numbering (as lines are + inserted/removed above the highlighted line), like signs and + marks do. + + Namespaces are used for batch deletion/updating of a set of + highlights. To create a namespace, use + |nvim_create_namespace()| which returns a namespace id. Pass + it in to this function as `ns_id` to add highlights to the + namespace. All highlights in the same namespace can then be + cleared with single call to |nvim_buf_clear_namespace()|. If + the highlight never will be deleted by an API call, pass + `ns_id = -1` . + + As a shorthand, `ns_id = 0` can be used to create a new + namespace for the highlight, the allocated id is then + returned. If `hl_group` is the empty string no highlight is + added, but a new `ns_id` is still returned. This is supported + for backwards compatibility, new code should use + |nvim_create_namespace()| to create a new empty namespace. + + Parameters: ~ + {buffer} Buffer handle, or 0 for current buffer + {ns_id} namespace to use or -1 for ungrouped + highlight + {hl_group} Name of the highlight group to use + {line} Line to highlight (zero-indexed) + {col_start} Start of (byte-indexed) column range to + highlight + {col_end} End of (byte-indexed) column range to + highlight, or -1 to highlight to end of line + + Return: ~ + The ns_id that was used + + *nvim_buf_clear_namespace()* +nvim_buf_clear_namespace({buffer}, {ns_id}, {line_start}, {line_end}) + Clears namespaced objects (highlights, extmarks, virtual text) + from a region. + + Lines are 0-indexed. |api-indexing| To clear the namespace in + the entire buffer, specify line_start=0 and line_end=-1. + + Parameters: ~ + {buffer} Buffer handle, or 0 for current buffer + {ns_id} Namespace to clear, or -1 to clear all + namespaces. + {line_start} Start of range of lines to clear + {line_end} End of range of lines to clear (exclusive) + or -1 to clear to end of buffer. + +nvim_buf_del_extmark({buffer}, {ns_id}, {id}) *nvim_buf_del_extmark()* + Removes an extmark. + + Parameters: ~ + {buffer} Buffer handle, or 0 for current buffer + {ns_id} Namespace id from |nvim_create_namespace()| + {id} Extmark id + + Return: ~ + true if the extmark was found, else false + + *nvim_buf_get_extmark_by_id()* +nvim_buf_get_extmark_by_id({buffer}, {ns_id}, {id}, {opts}) + Gets the position (0-indexed) of an extmark. + + Parameters: ~ + {buffer} Buffer handle, or 0 for current buffer + {ns_id} Namespace id from |nvim_create_namespace()| + {id} Extmark id + {opts} Optional parameters. Keys: + • details: Whether to include the details dict + + Return: ~ + 0-indexed (row, col) tuple or empty list () if extmark id + was absent + + *nvim_buf_get_extmarks()* +nvim_buf_get_extmarks({buffer}, {ns_id}, {start}, {end}, {opts}) + Gets extmarks in "traversal order" from a |charwise| region + defined by buffer positions (inclusive, 0-indexed + |api-indexing|). + + Region can be given as (row,col) tuples, or valid extmark ids + (whose positions define the bounds). 0 and -1 are understood + as (0,0) and (-1,-1) respectively, thus the following are + equivalent: +> + nvim_buf_get_extmarks(0, my_ns, 0, -1, {}) + nvim_buf_get_extmarks(0, my_ns, [0,0], [-1,-1], {}) +< + + If `end` is less than `start` , traversal works backwards. + (Useful with `limit` , to get the first marks prior to a given + position.) + + Example: +> + local a = vim.api + local pos = a.nvim_win_get_cursor(0) + local ns = a.nvim_create_namespace('my-plugin') + -- Create new extmark at line 1, column 1. + local m1 = a.nvim_buf_set_extmark(0, ns, 0, 0, 0, {}) + -- Create new extmark at line 3, column 1. + local m2 = a.nvim_buf_set_extmark(0, ns, 0, 2, 0, {}) + -- Get extmarks only from line 3. + local ms = a.nvim_buf_get_extmarks(0, ns, {2,0}, {2,0}, {}) + -- Get all marks in this buffer + namespace. + local all = a.nvim_buf_get_extmarks(0, ns, 0, -1, {}) + print(vim.inspect(ms)) +< + + Parameters: ~ + {buffer} Buffer handle, or 0 for current buffer + {ns_id} Namespace id from |nvim_create_namespace()| + {start} Start of range: a 0-indexed (row, col) or valid + extmark id (whose position defines the bound). + |api-indexing| + {end} End of range (inclusive): a 0-indexed (row, col) + or valid extmark id (whose position defines the + bound). |api-indexing| + {opts} Optional parameters. Keys: + • limit: Maximum number of marks to return + • details Whether to include the details dict + + Return: ~ + List of [extmark_id, row, col] tuples in "traversal + order". + *nvim_buf_set_extmark()* nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {*opts}) Creates or updates an extmark. @@ -2351,12 +2409,7 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {*opts}) of the array. However the 'tabstop' buffer option is still used for hard tabs. By default lines are placed below the buffer line - containing the mark. • Note: currently virtual lines are limited to - one block per buffer. Thus setting a new mark - disables any previous `virt_lines` decoration. - However plugins should not rely on this - behaviour, as this limitation is planned to be - removed. + containing the mark. • virt_lines_above: place virtual lines above instead. • virt_lines_leftcol: Place extmarks in the @@ -2383,116 +2436,74 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {*opts}) Return: ~ Id of the created/updated extmark - *nvim_buf_set_keymap()* -nvim_buf_set_keymap({buffer}, {mode}, {lhs}, {rhs}, {*opts}) - Sets a buffer-local |mapping| for the given mode. - - Parameters: ~ - {buffer} Buffer handle, or 0 for current buffer - - See also: ~ - |nvim_set_keymap()| - - *nvim_buf_set_lines()* -nvim_buf_set_lines({buffer}, {start}, {end}, {strict_indexing}, {replacement}) - Sets (replaces) a line-range in the buffer. - - Indexing is zero-based, end-exclusive. Negative indices are - interpreted as length+1+index: -1 refers to the index past the - end. So to change or delete the last element use start=-2 and - end=-1. - - To insert lines at a given index, set `start` and `end` to the - same index. To delete a range of lines, set `replacement` to - an empty array. - - Out-of-bounds indices are clamped to the nearest valid value, - unless `strict_indexing` is set. - - Attributes: ~ - not allowed when |textlock| is active - - Parameters: ~ - {buffer} Buffer handle, or 0 for current buffer - {start} First line index - {end} Last line index (exclusive) - {strict_indexing} Whether out-of-bounds should be an - error. - {replacement} Array of lines to use as replacement - - *nvim_buf_set_mark()* -nvim_buf_set_mark({buffer}, {name}, {line}, {col}, {opts}) - Sets a named mark in the given buffer, all marks are allowed - file/uppercase, visual, last change, etc. See |mark-motions|. +nvim_create_namespace({name}) *nvim_create_namespace()* + Creates a new *namespace* or gets an existing one. - Marks are (1,0)-indexed. |api-indexing| + Namespaces are used for buffer highlights and virtual text, + see |nvim_buf_add_highlight()| and |nvim_buf_set_extmark()|. - Note: - Passing 0 as line deletes the mark + Namespaces can be named or anonymous. If `name` matches an + existing namespace, the associated id is returned. If `name` + is an empty string a new, anonymous namespace is created. Parameters: ~ - {buffer} Buffer to set the mark on - {name} Mark name - {line} Line number - {col} Column/row number - {opts} Optional parameters. Reserved for future use. + {name} Namespace name or empty string Return: ~ - true if the mark was set, else false. - - See also: ~ - |nvim_buf_del_mark()| - |nvim_buf_get_mark()| - -nvim_buf_set_name({buffer}, {name}) *nvim_buf_set_name()* - Sets the full file name for a buffer - - Parameters: ~ - {buffer} Buffer handle, or 0 for current buffer - {name} Buffer name - -nvim_buf_set_option({buffer}, {name}, {value}) *nvim_buf_set_option()* - Sets a buffer option value. Passing 'nil' as value deletes the - option (only works if there's a global fallback) - - Parameters: ~ - {buffer} Buffer handle, or 0 for current buffer - {name} Option name - {value} Option value + Namespace id - *nvim_buf_set_text()* -nvim_buf_set_text({buffer}, {start_row}, {start_col}, {end_row}, {end_col}, - {replacement}) - Sets (replaces) a range in the buffer +nvim_get_namespaces() *nvim_get_namespaces()* + Gets existing, non-anonymous namespaces. - This is recommended over nvim_buf_set_lines when only - modifying parts of a line, as extmarks will be preserved on - non-modified parts of the touched lines. + Return: ~ + dict that maps from names to namespace ids. - Indexing is zero-based and end-exclusive. + *nvim_set_decoration_provider()* +nvim_set_decoration_provider({ns_id}, {opts}) + Set or change decoration provider for a namespace - To insert text at a given index, set `start` and `end` ranges - to the same index. To delete a range, set `replacement` to an - array containing an empty string, or simply an empty array. + This is a very general purpose interface for having lua + callbacks being triggered during the redraw code. - Prefer nvim_buf_set_lines when adding or deleting entire lines - only. + The expected usage is to set extmarks for the currently + redrawn buffer. |nvim_buf_set_extmark| can be called to add + marks on a per-window or per-lines basis. Use the `ephemeral` + key to only use the mark for the current screen redraw (the + callback will be called again for the next redraw ). - Parameters: ~ - {buffer} Buffer handle, or 0 for current buffer - {start_row} First line index - {start_column} Last column - {end_row} Last line index - {end_column} Last column - {replacement} Array of lines to use as replacement + Note: this function should not be called often. Rather, the + callbacks themselves can be used to throttle unneeded + callbacks. the `on_start` callback can return `false` to + disable the provider until the next redraw. Similarly, return + `false` in `on_win` will skip the `on_lines` calls for that + window (but any extmarks set in `on_win` will still be used). + A plugin managing multiple sources of decoration should + ideally only set one provider, and merge the sources + internally. You can use multiple `ns_id` for the extmarks + set/modified inside the callback anyway. -nvim_buf_set_var({buffer}, {name}, {value}) *nvim_buf_set_var()* - Sets a buffer-scoped (b:) variable + Note: doing anything other than setting extmarks is considered + experimental. Doing things like changing options are not + expliticly forbidden, but is likely to have unexpected + consequences (such as 100% CPU consumption). doing + `vim.rpcnotify` should be OK, but `vim.rpcrequest` is quite + dubious for the moment. Parameters: ~ - {buffer} Buffer handle, or 0 for current buffer - {name} Variable name - {value} Variable value + {ns_id} Namespace id from |nvim_create_namespace()| + {opts} Callbacks invoked during redraw: + • on_start: called first on each screen redraw + ["start", tick] + • on_buf: called for each buffer being redrawn + (before window callbacks) ["buf", bufnr, tick] + • on_win: called when starting to redraw a + specific window. ["win", winid, bufnr, topline, + botline_guess] + • on_line: called for each buffer line being + redrawn. (The interaction with fold lines is + subject to change) ["win", winid, bufnr, row] + • on_end: called at the end of a redraw cycle + ["end", tick] ============================================================================== diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt index d196167319..879a34bcaa 100644 --- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -57,7 +57,7 @@ The special pattern <buffer> or <buffer=N> defines a buffer-local autocommand. See |autocmd-buflocal|. Note: The ":autocmd" command can only be followed by another command when the -'|' appears before {cmd}. This works: > +'|' appears where the pattern is expected. This works: > :augroup mine | au! BufRead | augroup END But this sees "augroup" as part of the defined command: > :augroup mine | au! BufRead * | augroup END @@ -813,7 +813,7 @@ QuitPre When using `:quit`, `:wq` or `:qall`, before before QuitPre is triggered. Can be used to close any non-essential window if the current window is the last ordinary window. - See also |ExitPre|, ||WinClosed|. + See also |ExitPre|, |WinClosed|. *RemoteReply* RemoteReply When a reply from a Vim that functions as server was received |server2client()|. The diff --git a/runtime/doc/diagnostic.txt b/runtime/doc/diagnostic.txt index 1dd9c4f301..9a65737dae 100644 --- a/runtime/doc/diagnostic.txt +++ b/runtime/doc/diagnostic.txt @@ -239,7 +239,7 @@ DiagnosticUnderlineHint *hl-DiagnosticFloatingError* DiagnosticFloatingError Used to color "Error" diagnostic messages in diagnostics float. - See |vim.diagnostic.show_line_diagnostics()| + See |vim.diagnostic.open_float()| *hl-DiagnosticFloatingWarn* DiagnosticFloatingWarn @@ -289,11 +289,11 @@ option in the "signs" table of |vim.diagnostic.config()| or 10 if unset). ============================================================================== EVENTS *diagnostic-events* - *DiagnosticsChanged* -DiagnosticsChanged After diagnostics have changed. + *DiagnosticChanged* +DiagnosticChanged After diagnostics have changed. Example: > - autocmd User DiagnosticsChanged lua vim.diagnostic.setqflist({open = false }) + autocmd DiagnosticChanged * lua vim.diagnostic.setqflist({open = false }) < ============================================================================== ============================================================================== @@ -373,39 +373,8 @@ config({opts}, {namespace}) *vim.diagnostic.config()* Otherwise, all signs use the same priority. - • float: Options for floating windows: - • severity: See |diagnostic-severity|. - • header: (string or table) String to use - as the header for the floating window. If - a table, it is interpreted as a [text, - hl_group] tuple. Defaults to - "Diagnostics:". - • source: (string) Include the diagnostic - source in the message. One of "always" or - "if_many". - • format: (function) A function that takes - a diagnostic as input and returns a - string. The return value is the text used - to display the diagnostic. - • prefix: (function, string, or table) - Prefix each diagnostic in the floating - window. If a function, it must have the - signature (diagnostic, i, total) -> - (string, string), where {i} is the index - of the diagnostic being evaluated and - {total} is the total number of - diagnostics displayed in the window. The - function should return a string which is - prepended to each diagnostic in the - window as well as an (optional) highlight - group which will be used to highlight the - prefix. If {prefix} is a table, it is - interpreted as a [text, hl_group] tuple - as in |nvim_echo()|; otherwise, if - {prefix} is a string, it is prepended to - each diagnostic in the window with no - highlight. - + • float: Options for floating windows. See + |vim.diagnostic.open_float()|. • update_in_insert: (default false) Update diagnostics in Insert mode (if false, diagnostics are updated on InsertLeave) @@ -470,7 +439,7 @@ get_namespace({namespace}) *vim.diagnostic.get_namespace()* Get namespace metadata. Parameters: ~ - {ns} number Diagnostic namespace + {namespace} number Diagnostic namespace Return: ~ table Namespace metadata @@ -539,6 +508,9 @@ goto_next({opts}) *vim.diagnostic.goto_next()* "true", call |vim.diagnostic.open_float()| after moving. If a table, pass the table as the {opts} parameter to |vim.diagnostic.open_float()|. + Unless overridden, the float will show + diagnostics at the new cursor position (as if + "cursor" were passed to the "scope" option). • win_id: (number, default 0) Window ID goto_prev({opts}) *vim.diagnostic.goto_prev()* @@ -613,7 +585,7 @@ open_float({bufnr}, {opts}) *vim.diagnostic.open_float()* addition to the following: • namespace: (number) Limit diagnostics to the given namespace - • scope: (string, default "buffer") Show + • scope: (string, default "line") Show diagnostics from the whole buffer ("buffer"), the current cursor line ("line"), or the current cursor position ("cursor"). @@ -641,8 +613,21 @@ open_float({bufnr}, {opts}) *vim.diagnostic.open_float()* diagnostic. Overrides the setting from |vim.diagnostic.config()|. • prefix: (function, string, or table) Prefix - each diagnostic in the floating window. - Overrides the setting from + each diagnostic in the floating window. If a + function, it must have the signature + (diagnostic, i, total) -> (string, string), + where {i} is the index of the diagnostic being + evaluated and {total} is the total number of + diagnostics displayed in the window. The + function should return a string which is + prepended to each diagnostic in the window as + well as an (optional) highlight group which + will be used to highlight the prefix. If + {prefix} is a table, it is interpreted as a + [text, hl_group] tuple as in |nvim_echo()|; + otherwise, if {prefix} is a string, it is + prepended to each diagnostic in the window with + no highlight. Overrides the setting from |vim.diagnostic.config()|. Return: ~ diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index eb3dbd9b70..4d4e011c08 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -3081,7 +3081,7 @@ bufname([{buf}]) *bufname()* bufname(3) name of buffer 3 bufname("%") name of current buffer bufname("file2") name of buffer where "file2" matches. - +< *bufnr()* bufnr([{buf} [, {create}]]) The result is the number of a buffer, as it is displayed by @@ -3584,7 +3584,7 @@ count({comp}, {expr} [, {ic} [, {start}]]) *count()* Can also be used as a |method|: > mylist->count(val) - +< *cscope_connection()* cscope_connection([{num} , {dbpath} [, {prepend}]]) Checks for the existence of a |cscope| connection. If no @@ -3937,7 +3937,7 @@ exepath({expr}) *exepath()* Can also be used as a |method|: > GetCommand()->exepath() - +< *exists()* exists({expr}) The result is a Number, which is |TRUE| if {expr} is defined, zero otherwise. @@ -4483,7 +4483,7 @@ foldlevel({lnum}) *foldlevel()* Can also be used as a |method|: > GetLnum()->foldlevel() - +< *foldtext()* foldtext() Returns a String, to be displayed for a closed fold. This is the default function used for the 'foldtext' option and should @@ -5001,11 +5001,11 @@ getcurpos() Get the position of the cursor. This is like getpos('.'), but getcwd([{winnr}[, {tabnr}]]) *getcwd()* With no arguments, returns the name of the effective |current-directory|. With {winnr} or {tabnr} the working - directory of that scope is returned. + directory of that scope is returned, and 'autochdir' is + ignored. Tabs and windows are identified by their respective numbers, - 0 means current tab or window. Missing argument implies 0. + 0 means current tab or window. Missing tab number implies 0. Thus the following are equivalent: > - getcwd() getcwd(0) getcwd(0, 0) < If {winnr} is -1 it is ignored, only the tab is resolved. @@ -5136,8 +5136,8 @@ getline({lnum} [, {end}]) digit, |line()| is called to translate the String into a Number. To get the line under the cursor: > getline(".") -< When {lnum} is smaller than 1 or bigger than the number of - lines in the buffer, an empty string is returned. +< When {lnum} is a number smaller than 1 or bigger than the + number of lines in the buffer, an empty string is returned. When {end} is given the result is a |List| where each item is a line from the current buffer in the range {lnum} to {end}, @@ -5562,6 +5562,9 @@ getwininfo([{winid}]) *getwininfo()* otherwise wincol leftmost screen column of the window; "col" from |win_screenpos()| + textoff number of columns occupied by any + 'foldcolumn', 'signcolumn' and line + number in front of the text winid |window-ID| winnr window number winrow topmost screen line of the window; @@ -7461,15 +7464,18 @@ printf({fmt}, {expr1} ...) *printf()* field width. If the converted value has fewer bytes than the field width, it will be padded with spaces on the left (or right, if the left-adjustment flag has - been given) to fill out the field width. + been given) to fill out the field width. For the S + conversion the count is in cells. .precision An optional precision, in the form of a period '.' followed by an optional digit string. If the digit string is omitted, the precision is taken as zero. This gives the minimum number of digits to appear for - d, o, x, and X conversions, or the maximum number of - bytes to be printed from a string for s conversions. + d, o, x, and X conversions, the maximum number of + bytes to be printed from a string for s conversions, + or the maximum number of cells to be printed from a + string for S conversions. For floating point it is the number of digits after the decimal point. @@ -8546,6 +8552,7 @@ setbufline({buf}, {lnum}, {text}) *setbufline()* For the use of {buf}, see |bufname()| above. {lnum} is used like with |setline()|. + Use "$" to refer to the last line in buffer {buf}. When {lnum} is just below the last line the {text} will be added below the last line. On success 0 is returned, on failure 1 is returned. @@ -8970,7 +8977,7 @@ shellescape({string} [, {special}]) *shellescape()* Otherwise encloses {string} in single-quotes and replaces all "'" with "'\''". - If {special} is a ||non-zero-arg|: + If {special} is a |non-zero-arg|: - Special items such as "!", "%", "#" and "<cword>" will be preceded by a backslash. The backslash will be removed again by the |:!| command. @@ -8980,7 +8987,7 @@ shellescape({string} [, {special}]) *shellescape()* - The "!" character will be escaped. This is because csh and tcsh use "!" for history replacement even in single-quotes. - The <NL> character is escaped (twice if {special} is - a ||non-zero-arg|). + a |non-zero-arg|). If 'shell' contains "fish" in the tail, the "\" character will be escaped because in fish it is used as an escape character diff --git a/runtime/doc/filetype.txt b/runtime/doc/filetype.txt index 42a9993c8c..bbbe71ec3a 100644 --- a/runtime/doc/filetype.txt +++ b/runtime/doc/filetype.txt @@ -128,18 +128,19 @@ can be used to overrule the filetype used for certain extensions: file name variable ~ *.asa g:filetype_asa |ft-aspvbs-syntax| |ft-aspperl-syntax| - *.asp g:filetype_asp |ft-aspvbs-syntax| |ft-aspperl-syntax| *.asm g:asmsyntax |ft-asm-syntax| - *.prg g:filetype_prg - *.pl g:filetype_pl - *.inc g:filetype_inc - *.w g:filetype_w |ft-cweb-syntax| + *.asp g:filetype_asp |ft-aspvbs-syntax| |ft-aspperl-syntax| + *.fs g:filetype_fs |ft-forth-syntax| *.i g:filetype_i |ft-progress-syntax| + *.inc g:filetype_inc *.m g:filetype_m |ft-mathematica-syntax| *.p g:filetype_p |ft-pascal-syntax| + *.pl g:filetype_pl *.pp g:filetype_pp |ft-pascal-syntax| + *.prg g:filetype_prg *.sh g:bash_is_sh |ft-sh-syntax| *.tex g:tex_flavor |ft-tex-plugin| + *.w g:filetype_w |ft-cweb-syntax| *filetype-ignore* To avoid that certain files are being inspected, the g:ft_ignore_pat variable @@ -494,7 +495,6 @@ Options: For further discussion of fortran_have_tabs and the method used for the detection of source format see |ft-fortran-syntax|. - GIT COMMIT *ft-gitcommit-plugin* One command, :DiffGitCached, is provided to show a diff of the current commit diff --git a/runtime/doc/helphelp.txt b/runtime/doc/helphelp.txt index c884eea54f..e7b489d6e1 100644 --- a/runtime/doc/helphelp.txt +++ b/runtime/doc/helphelp.txt @@ -319,7 +319,7 @@ Hints for translators: 3. Writing help files *help-writing* For ease of use, a Vim help file for a plugin should follow the format of the -standard Vim help files, except fot the fist line. If you are writing a new +standard Vim help files, except for the first line. If you are writing a new help file it's best to copy one of the existing files and use it as a template. @@ -332,7 +332,7 @@ remainder of the line, after a Tab, describes the plugin purpose in a short way. This will show up in the "LOCAL ADDITIONS" section of the main help file. Check there that it shows up properly: |local-additions|. -If you want to add a version number of last modification date, put it in the +If you want to add a version number or last modification date, put it in the second line, right aligned. At the bottom of the help file, place a Vim modeline to set the 'textwidth' diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index 83d201c23a..9bd304cbb4 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -521,7 +521,9 @@ buf_request({bufnr}, {method}, {params}, {handler}) {method} (string) LSP method name {params} (optional, table) Parameters to send to the server - {handler} (optional, function) See |lsp-handler| + {handler} (optional, function) See |lsp-handler| If nil, + follows resolution strategy defined in + |lsp-handler-configuration| Return: ~ 2-tuple: @@ -628,11 +630,6 @@ client() *vim.lsp.client* server. • {handlers} (table): The handlers used by the client as described in |lsp-handler|. - • {requests} (table): The current pending requests in flight - to the server. Entries are key-value pairs with the key - being the request ID while the value is a table with `type`, - `bufnr`, and `method` key-value pairs. `type` is either "pending" - for an active request, or "cancel" for a cancel request. • {config} (table): copy of the table that was passed by the user to |vim.lsp.start_client()|. • {server_capabilities} (table): Response from the server @@ -650,12 +647,34 @@ client_is_stopped({client_id}) *vim.lsp.client_is_stopped()* Return: ~ true if client is stopped, false otherwise. -flush({client}) *vim.lsp.flush()* - TODO: Documentation - *vim.lsp.for_each_buffer_client()* for_each_buffer_client({bufnr}, {fn}) - TODO: Documentation + Invokes a function for each LSP client attached to a buffer. + + Parameters: ~ + {bufnr} number Buffer number + {fn} function Function to run on each client attached + to buffer {bufnr}. The function takes the client, + client ID, and buffer number as arguments. + Example: > + + vim.lsp.for_each_buffer_client(0, function(client, client_id, bufnr) + print(vim.inspect(client)) + end) +< + +formatexpr({opts}) *vim.lsp.formatexpr()* + Provides an interface between the built-in client and a + `formatexpr` function. + + Currently only supports a single client. This can be set via `setlocal formatexpr=v:lua.vim.lsp.formatexpr()` but will typically or in `on_attach` via vim.api.nvim_buf_set_option(bufnr, 'formatexpr , 'v:lua.vim.lsp.formatexpr(#{timeout_ms:250})')`. + + Parameters: ~ + {opts} table options for customizing the formatting + expression which takes the following optional + keys: + • timeout_ms (default 500ms). The timeout period + for the formatting request. get_active_clients() *vim.lsp.get_active_clients()* Gets all active clients. @@ -665,8 +684,10 @@ get_active_clients() *vim.lsp.get_active_clients()* *vim.lsp.get_buffers_by_client_id()* get_buffers_by_client_id({client_id}) + Returns list of buffers attached to client_id. + Parameters: ~ - {client_id} client id + {client_id} number client id Return: ~ list of buffer ids @@ -676,7 +697,7 @@ get_client_by_id({client_id}) *vim.lsp.get_client_by_id()* client may not yet be fully initialized. Parameters: ~ - {client_id} client id number + {client_id} number client id Return: ~ |vim.lsp.client| object, or nil @@ -706,16 +727,6 @@ omnifunc({findstart}, {base}) *vim.lsp.omnifunc()* |complete-items| |CompleteDone| - *vim.lsp.prepare()* -prepare({bufnr}, {firstline}, {new_lastline}, {changedtick}) - TODO: Documentation - -reset({client_id}) *vim.lsp.reset()* - TODO: Documentation - -reset_buf({client}, {bufnr}) *vim.lsp.reset_buf()* - TODO: Documentation - set_log_level({level}) *vim.lsp.set_log_level()* Sets the global log level for LSP logging. @@ -734,15 +745,12 @@ set_log_level({level}) *vim.lsp.set_log_level()* start_client({config}) *vim.lsp.start_client()* Starts and initializes a client with the given configuration. - Parameters `cmd` and `root_dir` are required. + Parameter `cmd` is required. The following parameters describe fields in the {config} table. Parameters: ~ - {root_dir} (string) Directory where the LSP - server will base its rootUri on - initialization. {cmd} (required, string or list treated like |jobstart()|) Base command that initiates the LSP client. @@ -757,6 +765,13 @@ start_client({config}) *vim.lsp.start_client()* { "PRODUCTION=true"; "TEST=123"; PORT = 8080; HOST = "0.0.0.0"; } < + {workspace_folders} (table) List of workspace folders + passed to the language server. For + backwards compatibility rootUri and + rootPath will be derived from the + first workspace folder in this list. + See `workspaceFolders` in the LSP + spec. {capabilities} Map overriding the default capabilities defined by |vim.lsp.protocol.make_client_capabilities()|, @@ -776,15 +791,21 @@ start_client({config}) *vim.lsp.start_client()* language server if requested via `workspace/configuration` . Keys are case-sensitive. + {commands} table Table that maps string of + clientside commands to user-defined + functions. Commands passed to + start_client take precedence over the + global command registry. Each key + must be a unique command name, and + the value is a function which is + called if any LSP action (code + action, code lenses, ...) triggers + the command. {init_options} Values to pass in the initialization request as `initializationOptions` . See `initialize` in the LSP spec. {name} (string, default=client-id) Name in log messages. - {workspace_folders} (table) List of workspace folders - passed to the language server. - Defaults to root_dir if not set. See - `workspaceFolders` in the LSP spec {get_language_id} function(bufnr, filetype) -> language ID as string. Defaults to the filetype. @@ -851,6 +872,17 @@ start_client({config}) *vim.lsp.start_client()* notifications to the server by the given number in milliseconds. No debounce occurs if nil + • exit_timeout (number, default 500): + Milliseconds to wait for server to + exit cleanly after sending the + 'shutdown' request before sending + kill -15. If set to false, nvim + exits immediately after sending the + 'shutdown' request to the server. + {root_dir} string Directory where the LSP server + will base its workspaceFolders, + rootUri, and rootPath on + initialization. Return: ~ Client id. |vim.lsp.get_client_by_id()| Note: client may @@ -876,6 +908,23 @@ stop_client({client_id}, {force}) *vim.lsp.stop_client()* thereof {force} boolean (optional) shutdown forcefully +tagfunc({...}) *vim.lsp.tagfunc()* + Provides an interface between the built-in client and + 'tagfunc'. + + When used with normal mode commands (e.g. |CTRL-]|) this will + invoke the "textDocument/definition" LSP method to find the + tag under the cursor. Otherwise, uses "workspace/symbol". If + no results are returned from any LSP servers, falls back to + using built-in tags. + + Parameters: ~ + {pattern} Pattern used to find a workspace symbol + {flags} See |tag-function| + + Return: ~ + A list of matching tags + with({handler}, {override_config}) *vim.lsp.with()* Function to manage overriding defaults for LSP handlers. @@ -942,9 +991,9 @@ document_highlight() *vim.lsp.buf.document_highlight()* triggered by a key mapping or by events such as `CursorHold` , eg: > - vim.api.nvim_command [[autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight()]] - vim.api.nvim_command [[autocmd CursorHoldI <buffer> lua vim.lsp.buf.document_highlight()]] - vim.api.nvim_command [[autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references()]] + autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight() + autocmd CursorHoldI <buffer> lua vim.lsp.buf.document_highlight() + autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references() < Note: Usage of |vim.lsp.buf.document_highlight()| requires the @@ -1012,7 +1061,7 @@ formatting_sync({options}, {timeout_ms}) |vim.lsp.buf_request_sync()|. Example: > - vim.api.nvim_command[[autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting_sync()]] + autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting_sync() < Parameters: ~ @@ -1044,9 +1093,6 @@ outgoing_calls() *vim.lsp.buf.outgoing_calls()* cursor in the |quickfix| window. If the symbol can resolve to multiple items, the user can pick one in the |inputlist|. -prepare_rename({err}, {result}) *vim.lsp.buf.prepare_rename()* - TODO: Documentation - *vim.lsp.buf.range_code_action()* range_code_action({context}, {start_pos}, {end_pos}) Performs |vim.lsp.buf.code_action()| for a given range. @@ -1301,23 +1347,22 @@ buf_clear_references({bufnr}) *vim.lsp.util.buf_clear_references()* Removes document highlights from a buffer. Parameters: ~ - {bufnr} buffer id + {bufnr} number Buffer id *vim.lsp.util.buf_highlight_references()* -buf_highlight_references({bufnr}, {references}) +buf_highlight_references({bufnr}, {references}, {offset_encoding}) Shows a list of document highlights for a certain buffer. Parameters: ~ - {bufnr} buffer id - {references} List of `DocumentHighlight` objects to - highlight + {bufnr} number Buffer id + {references} table List of `DocumentHighlight` + objects to highlight + {offset_encoding} string One of "utf-8", "utf-16", + "utf-32", or nil. Defaults to utf-16 See also: ~ https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#documentHighlight -buf_lines({bufnr}) *vim.lsp.util.buf_lines()* - TODO: Documentation - *vim.lsp.util.character_offset()* character_offset({bufnr}, {row}, {col}) Returns the UTF-32 and UTF-16 offsets for a position in a @@ -1344,25 +1389,6 @@ close_preview_autocmd({events}, {winnr}) See also: ~ |autocmd-events| - *vim.lsp.util.compute_diff()* -compute_diff({old_lines}, {new_lines}, {start_line_idx}, {end_line_idx}, - {offset_encoding}) - Returns the range table for the difference between old and new - lines - - Parameters: ~ - {old_lines} table list of lines - {new_lines} table list of lines - {start_line_idx} int line to begin search for first - difference - {end_line_idx} int line to begin search for last - difference - {offset_encoding} string encoding requested by language - server - - Return: ~ - table start_line_idx and start_col_idx of range - *vim.lsp.util.convert_input_to_markdown_lines()* convert_input_to_markdown_lines({input}, {contents}) Converts any of `MarkedString` | `MarkedString[]` | @@ -1403,12 +1429,6 @@ convert_signature_help_to_markdown_lines({signature_help}, {ft}, {triggers}) See also: ~ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp -create_file({change}) *vim.lsp.util.create_file()* - TODO: Documentation - -delete_file({change}) *vim.lsp.util.delete_file()* - TODO: Documentation - *vim.lsp.util.extract_completion_items()* extract_completion_items({result}) Can be used to extract the completion items from a `textDocument/completion` request, which may return one of `CompletionItem[]` , `CompletionList` or null. @@ -1436,29 +1456,6 @@ get_effective_tabstop({bufnr}) *vim.lsp.util.get_effective_tabstop()* See also: ~ |softtabstop| -get_line({uri}, {row}) *vim.lsp.util.get_line()* - Gets the zero-indexed line from the given uri. - - Parameters: ~ - {uri} string uri of the resource to get the line from - {row} number zero-indexed line number - - Return: ~ - string the line at row in filename - -get_lines({uri}, {rows}) *vim.lsp.util.get_lines()* - Gets the zero-indexed lines from the given uri. - - Parameters: ~ - {uri} string uri of the resource to get the lines from - {rows} number[] zero-indexed line numbers - - Return: ~ - table<number string> a table mapping rows to lines - -get_progress_messages() *vim.lsp.util.get_progress_messages()* - TODO: Documentation - jump_to_location({location}) *vim.lsp.util.jump_to_location()* Jumps to a location. @@ -1593,25 +1590,32 @@ open_floating_preview({contents}, {syntax}, {opts}) Parameters: ~ {contents} table of lines to show in window {syntax} string of syntax to set for opened buffer - {opts} dictionary with optional fields - • height of floating window - • width of floating window - • wrap boolean enable wrapping of long lines - (defaults to true) - • wrap_at character to wrap at for computing - height when wrap is enabled - • max_width maximal width of floating window - • max_height maximal height of floating window - • pad_top number of lines to pad contents at - top - • pad_bottom number of lines to pad contents - at bottom - • focus_id if a popup with this id is opened, - then focus it - • close_events list of events that closes the + {opts} table with optional fields (additional keys + are passed on to |vim.api.nvim_open_win()|) + • height: (number) height of floating window + • width: (number) width of floating window + • wrap: (boolean, default true) wrap long + lines + • wrap_at: (string) character to wrap at for + computing height when wrap is enabled + • max_width: (number) maximal width of floating window - • focusable (boolean, default true): Make + • max_height: (number) maximal height of + floating window + • pad_top: (number) number of lines to pad + contents at top + • pad_bottom: (number) number of lines to pad + contents at bottom + • focus_id: (string) if a popup with this id + is opened, then focus it + • close_events: (table) list of events that + closes the floating window + • focusable: (boolean, default true) Make float focusable + • focus: (boolean, default true) If `true` , + and if {focusable} is also `true` , focus an + existing floating window with the same + {focus_id} Return: ~ bufnr,winnr buffer and window number of the newly created @@ -1752,7 +1756,10 @@ get_filename() *vim.lsp.log.get_filename()* (string) log filename get_level() *vim.lsp.log.get_level()* - TODO: Documentation + Gets the current log level. + + Return: ~ + string current log level set_format_func({handle}) *vim.lsp.log.set_format_func()* Sets formatting function used to format logs @@ -1800,14 +1807,19 @@ notify({method}, {params}) *vim.lsp.rpc.notify()* (bool) `true` if notification could be sent, `false` if not -request({method}, {params}, {callback}) *vim.lsp.rpc.request()* + *vim.lsp.rpc.request()* +request({method}, {params}, {callback}, {notify_reply_callback}) Sends a request to the LSP server and runs {callback} upon response. Parameters: ~ - {method} (string) The invoked LSP method - {params} (table) Parameters for the invoked LSP method - {callback} (function) Callback to invoke + {method} (string) The invoked LSP method + {params} (table) Parameters for the + invoked LSP method + {callback} (function) Callback to invoke + {notify_reply_callback} (function) Callback to invoke as + soon as a request is no longer + pending Return: ~ (bool, number) `(true, message_id)` if request could be @@ -1826,7 +1838,8 @@ rpc_response_error({code}, {message}, {data}) *vim.lsp.rpc.start()* start({cmd}, {cmd_args}, {dispatchers}, {extra_spawn_params}) Starts an LSP server process and create an LSP RPC client - object to interact with it. + object to interact with it. Communication with the server is + currently limited to stdio. Parameters: ~ {cmd} (string) Command to start the LSP @@ -1862,6 +1875,31 @@ start({cmd}, {cmd_args}, {dispatchers}, {extra_spawn_params}) ============================================================================== +Lua module: vim.lsp.sync *lsp-sync* + + *vim.lsp.sync.compute_diff()* +compute_diff({prev_lines}, {curr_lines}, {firstline}, {lastline}, + {new_lastline}, {offset_encoding}, {line_ending}) + Returns the range table for the difference between prev and + curr lines + + Parameters: ~ + {prev_lines} table list of lines + {curr_lines} table list of lines + {firstline} number line to begin search for first + difference + {lastline} number line to begin search in + old_lines for last difference + {new_lastline} number line to begin search in + new_lines for last difference + {offset_encoding} string encoding requested by language + server + + Return: ~ + table TextDocumentContentChangeEvent see https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#textDocumentContentChangeEvent + + +============================================================================== Lua module: vim.lsp.protocol *lsp-protocol* *vim.lsp.protocol.make_client_capabilities()* diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index ef2d87949d..630df16e79 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -362,8 +362,8 @@ cases there is the following agreement: converted to a dictionary `{'a': 42}`: non-string keys are ignored. Without `vim.type_idx` key tables with keys not fitting in 1., 2. or 3. are errors. - - `{[vim.type_idx]=vim.types.list}` is converted to an empty list. As well - as `{[vim.type_idx]=vim.types.list, [42]=1}`: integral keys that do not + - `{[vim.type_idx]=vim.types.array}` is converted to an empty list. As well + as `{[vim.type_idx]=vim.types.array, [42]=1}`: integral keys that do not form a 1-step sequence from 1 to N are ignored, as well as all non-integral keys. @@ -1190,9 +1190,6 @@ defer_fn({fn}, {timeout}) *vim.defer_fn()* Return: ~ timer luv timer object -insert_keys({obj}) *vim.insert_keys()* - TODO: Documentation - inspect({object}, {options}) *vim.inspect()* Return a human-readable representation of the given object. @@ -1200,20 +1197,16 @@ inspect({object}, {options}) *vim.inspect()* https://github.com/kikito/inspect.lua https://github.com/mpeterv/vinspect -make_dict_accessor({scope}) *vim.make_dict_accessor()* - TODO: Documentation - -notify({msg}, {log_level}, {_opts}) *vim.notify()* +notify({msg}, {log_level}, {opts}) *vim.notify()* Notification provider Without a runtime, writes to :Messages Parameters: ~ - {msg} Content of the notification to show to the - user - {log_level} Optional log level - {opts} Dictionary with optional options (timeout, - etc) + {msg} string Content of the notification to show to + the user + {log_level} number|nil enum from vim.log.levels + {opts} table|nil additional options (timeout, etc) See also: ~ :help nvim_notify @@ -1239,7 +1232,7 @@ on_key({fn}, {ns_id}) *vim.on_key()* it removes the callback for the associated {ns_id} {ns_id} number? Namespace ID. If nil or 0, generates and - returns a new |nvim_create_namesapce()| id. + returns a new |nvim_create_namespace()| id. Return: ~ number Namespace id associated with {fn}. Or count of all @@ -1328,7 +1321,7 @@ deepcopy({orig}) *vim.deepcopy()* and will throw an error. Parameters: ~ - {orig} Table to copy + {orig} table Table to copy Return: ~ New table of copied keys and (nested) values. @@ -1369,9 +1362,6 @@ is_callable({f}) *vim.is_callable()* Return: ~ true if `f` is callable, else false -is_valid({opt}) *vim.is_valid()* - TODO: Documentation - list_extend({dst}, {src}, {start}, {finish}) *vim.list_extend()* Extends a list-like table with the values of another list-like table. @@ -1617,14 +1607,12 @@ validate({opt}) *vim.validate()* vim.validate{arg1={{'foo'}, 'table'}, arg2={'foo', 'string'}} => NOP (success) -< -> - vim.validate{arg1={1, 'table'}} - => error('arg1: expected table, got number') -< -> - vim.validate{arg1={3, function(a) return (a % 2) == 0 end, 'even number'}} - => error('arg1: expected even number, got 3') + + vim.validate{arg1={1, 'table'}} + => error('arg1: expected table, got number') + + vim.validate{arg1={3, function(a) return (a % 2) == 0 end, 'even number'}} + => error('arg1: expected even number, got 3') < Parameters: ~ @@ -1658,40 +1646,38 @@ uri_from_bufnr({bufnr}) *vim.uri_from_bufnr()* Get a URI from a bufnr Parameters: ~ - {bufnr} (number): Buffer number + {bufnr} number Return: ~ - URI + string URI uri_from_fname({path}) *vim.uri_from_fname()* Get a URI from a file path. Parameters: ~ - {path} (string): Path to file + {path} string Path to file Return: ~ - URI + string URI uri_to_bufnr({uri}) *vim.uri_to_bufnr()* - Return or create a buffer for a uri. + Get the buffer for a uri. Creates a new unloaded buffer if no + buffer for the uri already exists. Parameters: ~ - {uri} (string): The URI + {uri} string Return: ~ - bufnr. - - Note: - Creates buffer but does not load it + number bufnr uri_to_fname({uri}) *vim.uri_to_fname()* Get a filename from a URI Parameters: ~ - {uri} (string): The URI + {uri} string Return: ~ - Filename + string filename or unchanged URI for non-file URIs ============================================================================== @@ -1731,6 +1717,12 @@ select({items}, {opts}, {on_choice}) *vim.ui.select()* • format_item (function item -> text) Function to format an individual item from `items` . Defaults to `tostring` . + • kind (string|nil) Arbitrary hint string + indicating the item shape. Plugins + reimplementing `vim.ui.select` may wish to + use this to infer the structure or + semantics of `items` , or the context in + which select() was called. {on_choice} function ((item|nil, idx|nil) -> ()) Called once the user made a choice. `idx` is the 1-based index of `item` within `item` . `nil` diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt index 0b9ac42898..0ea2565694 100644 --- a/runtime/doc/map.txt +++ b/runtime/doc/map.txt @@ -81,6 +81,9 @@ modes. Remove the mapping of {lhs} for the modes where the map command applies. The mapping may remain defined for other modes where it applies. + It also works when {lhs} matches the {rhs} of a + mapping. This is for when when an abbreviation + applied. Note: Trailing spaces are included in the {lhs}. This unmap does NOT work: > :map @@ foo @@ -320,6 +323,8 @@ Note: - For the same reason, |keycodes| like <C-R><C-W> are interpreted as plain, unmapped keys. - The command is not echo'ed, no need for <silent>. +- The {rhs} is not subject to abbreviations nor to other mappings, even if the + mapping is recursive. - In Visual mode you can use `line('v')` and `col('v')` to get one end of the Visual area, the cursor is at the other end. - In select-mode, |:map| and |:vmap| command mappings are executed in diff --git a/runtime/doc/pi_msgpack.txt b/runtime/doc/pi_msgpack.txt index 951b897f55..1dbd268038 100644 --- a/runtime/doc/pi_msgpack.txt +++ b/runtime/doc/pi_msgpack.txt @@ -68,7 +68,7 @@ msgpack#strftime({format}, {msgpack-integer}) *msgpack#strftime()* *msgpack#strptime* msgpack#strptime({format}, {time}) *msgpack#strptime()* - Reverse of |msgpack#strptime()|: for any time and format + Reverse of |msgpack#strftime()|: for any time and format |msgpack#equal|( |msgpack#strptime|(format, |msgpack#strftime|(format, time)), time) be true. Requires |+python| or |+python3|, without it only supports non-|msgpack-special-dict| nonnegative times and format diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index e423c59efe..72f08c37ca 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -1497,6 +1497,14 @@ gvim display. Here, statements are colored LightYellow instead of Yellow, and conditionals are LightBlue for better distinction. +FORTH *forth.vim* *ft-forth-syntax* + +Files matching "*.fs" could be F# or Forth. If the automatic detection +doesn't work for you, or you don't edit F# at all, use this in your +startup vimrc: > + :let filetype_fs = "forth" + + FORTRAN *fortran.vim* *ft-fortran-syntax* Default highlighting and dialect ~ diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt index 441ae13df4..08dc0583ac 100644 --- a/runtime/doc/treesitter.txt +++ b/runtime/doc/treesitter.txt @@ -353,7 +353,7 @@ Lua module: vim.treesitter *lua-treesitter-core* get_parser({bufnr}, {lang}, {opts}) *get_parser()* Gets the parser for this bufnr / ft combination. - If needed this will create the parser. Unconditionnally attach + If needed this will create the parser. Unconditionally attach the provided callback Parameters: ~ @@ -380,7 +380,7 @@ Lua module: vim.treesitter.language *treesitter-language* inspect_language({lang}) *inspect_language()* Inspects the provided language. - Inspecting provides some useful informations on the language + Inspecting provides some useful information on the language like node names, ... Parameters: ~ @@ -479,7 +479,7 @@ Query:iter_captures({self}, {node}, {source}, {start}, {stop}) {source} is needed if the query contains predicates, then the caller must ensure to use a freshly parsed tree consistent - with the current text of the buffer (if relevent). {start_row} + with the current text of the buffer (if relevant). {start_row} and {end_row} can be used to limit matches inside a row range (this is typically used with root node as the node, i e to get syntax highlight matches in the current viewport). When @@ -503,8 +503,7 @@ Query:iter_captures({self}, {node}, {source}, {start}, {stop}) Parameters: ~ {node} The node under which the search will occur - {source} The source buffer or string to exctract text - from + {source} The source buffer or string to extract text from {start} The starting line of the search {stop} The stopping line of the search (end-exclusive) {self} @@ -611,7 +610,7 @@ LanguageTree:children({self}) *LanguageTree:children()* {self} LanguageTree:contains({self}, {range}) *LanguageTree:contains()* - Determines wether This goes down the tree to recursively check childs. + Determines whether This goes down the tree to recursively check children. Parameters: ~ {range} is contained in this language tree diff --git a/runtime/doc/usr_20.txt b/runtime/doc/usr_20.txt index cff5c7d2f2..6a8836c8e8 100644 --- a/runtime/doc/usr_20.txt +++ b/runtime/doc/usr_20.txt @@ -292,7 +292,7 @@ to newer commands. There are actually five histories. The ones we will mention here are for ":" commands and for "/" and "?" search commands. The "/" and "?" commands share the same history, because they are both search commands. The three other -histories are for expressions, debug more commands and input lines for the +histories are for expressions, debug mode commands and input lines for the input() function. |cmdline-history| Suppose you have done a ":set" command, typed ten more colon commands and then diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index d88f4f42e8..956cb3e624 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -428,7 +428,7 @@ Working directory (Vim implemented some of these later than Nvim): - |DirChanged| can be triggered when switching to another window. - |getcwd()| and |haslocaldir()| may throw errors if the tab page or window cannot be found. *E5000* *E5001* *E5002* -- |haslocaldir()| only checks for tab-local directory when -1 is passed as +- |haslocaldir()| checks for tab-local directory if and only if -1 is passed as window number, and its only possible returns values are 0 and 1. - `getcwd(-1)` is equivalent to `getcwd(-1, 0)` instead of returning the global working directory. Use `getcwd(-1, -1)` to get the global working directory. diff --git a/runtime/doc/visual.txt b/runtime/doc/visual.txt index 111588e43a..4a69fc989b 100644 --- a/runtime/doc/visual.txt +++ b/runtime/doc/visual.txt @@ -360,7 +360,8 @@ same amount of text as the last time: last line the same number of characters as in the last line the last time. The start of the text is the Cursor position. If the "$" command was used as one of the last commands to extend the highlighted text, the repeating will -be applied up to the rightmost column of the longest line. +be applied up to the rightmost column of the longest line. Any count passed +to the `.` command is not used. ============================================================================== diff --git a/runtime/filetype.vim b/runtime/filetype.vim index 1b48070128..cc28dba1d0 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -484,7 +484,7 @@ au BufNewFile,BufRead *.desktop,*.directory setf desktop au BufNewFile,BufRead dict.conf,.dictrc setf dictconf " Dictd config -au BufNewFile,BufRead dictd.conf setf dictdconf +au BufNewFile,BufRead dictd*.conf setf dictdconf " Diff files au BufNewFile,BufRead *.diff,*.rej setf diff @@ -628,7 +628,7 @@ au BufNewFile,BufRead auto.master setf conf au BufNewFile,BufRead *.mas,*.master setf master " Forth -au BufNewFile,BufRead *.fs,*.ft,*.fth setf forth +au BufNewFile,BufRead *.ft,*.fth setf forth " Reva Forth au BufNewFile,BufRead *.frt setf reva @@ -645,6 +645,12 @@ au BufNewFile,BufRead *.fsl setf framescript " FStab au BufNewFile,BufRead fstab,mtab setf fstab +" F# or Forth +au BufNewFile,BufRead *.fs call dist#ft#FTfs() + +" F# +au BufNewFile,BufRead *.fsi,*.fsx setf fsharp + " GDB command files au BufNewFile,BufRead .gdbinit,gdbinit setf gdb @@ -1095,6 +1101,9 @@ au BufNewFile,BufRead *.moo setf moo " Modconf au BufNewFile,BufRead */etc/modules.conf,*/etc/modules,*/etc/conf.modules setf modconf +" MPD is based on XML +au BufNewFile,BufRead *.mpd setf xml + " Mplayer config au BufNewFile,BufRead mplayer.conf,*/.mplayer/config setf mplayerconf @@ -2055,9 +2064,15 @@ au BufNewFile,BufRead *.xml call dist#ft#FTxml() " XMI (holding UML models) is also XML au BufNewFile,BufRead *.xmi setf xml -" CSPROJ files are Visual Studio.NET's XML-based project config files +" CSPROJ files are Visual Studio.NET's XML-based C# project config files au BufNewFile,BufRead *.csproj,*.csproj.user setf xml +" FSPROJ files are Visual Studio.NET's XML-based F# project config files +au BufNewFile,BufRead *.fsproj,*.fsproj.user setf xml + +" VBPROJ files are Visual Studio.NET's XML-based Visual Basic project config files +au BufNewFile,BufRead *.vbproj,*.vbproj.user setf xml + " Qt Linguist translation source and Qt User Interface Files are XML " However, for .ts Typescript is more common. au BufNewFile,BufRead *.ui setf xml @@ -2155,7 +2170,7 @@ au BufNewFile,BufRead proftpd.conf* call s:StarSetf('apachestyle') " More Apache config files au BufNewFile,BufRead access.conf*,apache.conf*,apache2.conf*,httpd.conf*,srm.conf* call s:StarSetf('apache') -au BufNewFile,BufRead */etc/apache2/*.conf*,*/etc/apache2/conf.*/*,*/etc/apache2/mods-*/*,*/etc/apache2/sites-*/*,*/etc/httpd/conf.d/*.conf* call s:StarSetf('apache') +au BufNewFile,BufRead */etc/apache2/*.conf*,*/etc/apache2/conf.*/*,*/etc/apache2/mods-*/*,*/etc/apache2/sites-*/*,*/etc/httpd/conf.*/*,*/etc/httpd/mods-*/*,*/etc/httpd/sites-*/*,*/etc/httpd/conf.d/*.conf* call s:StarSetf('apache') " Asterisk config file au BufNewFile,BufRead *asterisk/*.conf* call s:StarSetf('asterisk') diff --git a/runtime/ftplugin/indent.vim b/runtime/ftplugin/indent.vim index e6d928a073..64a650ad7b 100644 --- a/runtime/ftplugin/indent.vim +++ b/runtime/ftplugin/indent.vim @@ -1,7 +1,8 @@ " Vim filetype plugin file -" Language: indent(1) configuration file -" Previous Maintainer: Nikolai Weibull <now@bitwi.se> -" Latest Revision: 2008-07-09 +" Language: indent(1) configuration file +" Maintainer: Doug Kearns <dougkearns@gmail.com> +" Previous Maintainer: Nikolai Weibull <now@bitwi.se> +" Latest Revision: 2008-07-09 if exists("b:did_ftplugin") finish diff --git a/runtime/ftplugin/jsonc.vim b/runtime/ftplugin/jsonc.vim index 90d52cd0d3..e47a75f574 100644 --- a/runtime/ftplugin/jsonc.vim +++ b/runtime/ftplugin/jsonc.vim @@ -4,7 +4,7 @@ " Acknowledgement: Based off of vim-jsonc maintained by Kevin Locke <kevin@kevinlocke.name> " https://github.com/kevinoid/vim-jsonc " License: MIT -" Last Change: 2021-07-01 +" Last Change: 2021 Nov 22 runtime! ftplugin/json.vim @@ -14,14 +14,8 @@ else let b:did_ftplugin_jsonc = 1 endif -" A list of commands that undo buffer local changes made below. -let s:undo_ftplugin = [] - " Set comment (formatting) related options. {{{1 setlocal commentstring=//%s comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// -call add(s:undo_ftplugin, 'commentstring< comments<') " Let Vim know how to disable the plug-in. -call map(s:undo_ftplugin, "'execute ' . string(v:val)") -let b:undo_ftplugin = join(s:undo_ftplugin, ' | ') -unlet s:undo_ftplugin +let b:undo_ftplugin = 'setlocal commentstring< comments<' diff --git a/runtime/ftplugin/vb.vim b/runtime/ftplugin/vb.vim index d70db89273..5a9548115b 100644 --- a/runtime/ftplugin/vb.vim +++ b/runtime/ftplugin/vb.vim @@ -1,44 +1,70 @@ " Vim filetype plugin file -" Language: VisualBasic (ft=vb) -" Maintainer: Johannes Zellner <johannes@zellner.org> -" Last Change: Thu, 22 Nov 2001 12:56:14 W. Europe Standard Time +" Language: Visual Basic (ft=vb) +" Maintainer: Doug Kearns <dougkearns@gmail.com> +" Previous Maintainer: Johannes Zellner <johannes@zellner.org> +" Last Change: 2021 Nov 17 -if exists("b:did_ftplugin") | finish | endif +if exists("b:did_ftplugin") + finish +endif let b:did_ftplugin = 1 -setlocal com=sr:'\ -,mb:'\ \ ,el:'\ \ ,:' +let s:cpo_save = &cpo +set cpo&vim + +setlocal comments=sr:'\ -,mb:'\ \ ,el:'\ \ ,:' +setlocal commentstring='\ %s +setlocal formatoptions-=t formatoptions+=croql + +let b:undo_ftplugin = "setlocal com< cms< fo<" " we need this wrapper, as call doesn't allow a count -fun! <SID>VbSearch(pattern, flags) +function! s:VbSearch(pattern, flags) let cnt = v:count1 while cnt > 0 call search(a:pattern, a:flags) let cnt = cnt - 1 endwhile -endfun +endfunction -let s:cpo_save = &cpo -set cpo&vim +if !exists("no_plugin_maps") && !exists("no_vb_maps") + nnoremap <buffer> <silent> [[ <Cmd>call <SID>VbSearch('^\s*\%(\%(private\<Bar>public\)\s\+\)\=\%(function\<Bar>sub\)', 'sbW')<CR> + vnoremap <buffer> <silent> [[ <Cmd>call <SID>VbSearch('^\s*\%(\%(private\<Bar>public\)\s\+\)\=\%(function\<Bar>sub\)', 'sbW')<CR> + nnoremap <buffer> <silent> ]] <Cmd>call <SID>VbSearch('^\s*\%(\%(private\<Bar>public\)\s\+\)\=\%(function\<Bar>sub\)', 'sW')<CR> + vnoremap <buffer> <silent> ]] <Cmd>call <SID>VbSearch('^\s*\%(\%(private\<Bar>public\)\s\+\)\=\%(function\<Bar>sub\)', 'sW')<CR> + nnoremap <buffer> <silent> [] <Cmd>call <SID>VbSearch('^\s*end\s\+\%(function\<Bar>sub\)', 'sbW')<CR> + vnoremap <buffer> <silent> [] <Cmd>call <SID>VbSearch('^\s*end\s\+\%(function\<Bar>sub\)', 'sbW')<CR> + nnoremap <buffer> <silent> ][ <Cmd>call <SID>VbSearch('^\s*end\s\+\%(function\<Bar>sub\)', 'sW')<CR> + vnoremap <buffer> <silent> ][ <Cmd>call <SID>VbSearch('^\s*end\s\+\%(function\<Bar>sub\)', 'sW')<CR> + let b:undo_ftplugin .= " | sil! exe 'nunmap <buffer> [[' | sil! exe 'vunmap <buffer> [['" . + \ " | sil! exe 'nunmap <buffer> ]]' | sil! exe 'vunmap <buffer> ]]'" . + \ " | sil! exe 'nunmap <buffer> []' | sil! exe 'vunmap <buffer> []'" . + \ " | sil! exe 'nunmap <buffer> ][' | sil! exe 'vunmap <buffer> ]['" +endif + +" TODO: line start anchors are almost certainly overly restrictive - allow +" after statement separators. Even in QuickBasic only block IF statements +" were required to be at the start of a line. +if exists("loaded_matchit") && !exists("b:match_words") + let b:match_ignorecase = 1 + let b:match_words = + \ '\%(^\s*\)\@<=\<if\>.*\<then\>\s*\%($\|''\):\%(^\s*\)\@<=\<else\>:\%(^\s*\)\@<=\<elseif\>:\%(^\s*\)\@<=\<end\>\s\+\<if\>,' . + \ '\%(^\s*\)\@<=\<for\>:\%(^\s*\)\@<=\<next\>,' . + \ '\%(^\s*\)\@<=\<while\>:\%(^\s*\)\@<=\<wend\>,' . + \ '\%(^\s*\)\@<=\<do\>:\%(^\s*\)\@<=\<loop\>\s\+\<while\>,' . + \ '\%(^\s*\)\@<=\<select\>\s\+\<case\>:\%(^\s*\)\@<=\<case\>:\%(^\s*\)\@<=\<end\>\s\+\<select\>,' . + \ '\%(^\s*\)\@<=\<enum\>:\%(^\s*\)\@<=\<end\>\s\<enum\>,' . + \ '\%(^\s*\)\@<=\<with\>:\%(^\s*\)\@<=\<end\>\s\<with\>,' . + \ '\%(^\s*\)\@<=\%(\<\%(private\|public\)\>\s\+\)\=\<function\>\s\+\([^ \t(]\+\):\%(^\s*\)\@<=\<\1\>\s*=:\%(^\s*\)\@<=\<end\>\s\+\<function\>,' . + \ '\%(^\s*\)\@<=\%(\<\%(private\|public\)\>\s\+\)\=\<sub\>\s\+:\%(^\s*\)\@<=\<end\>\s\+\<sub\>' + let b:undo_ftplugin .= " | unlet! b:match_words b:match_ignorecase" +endif -" NOTE the double escaping \\| -nnoremap <buffer> <silent> [[ :call <SID>VbSearch('^\s*\(\(private\|public\)\s\+\)\=\(function\\|sub\)', 'bW')<cr> -nnoremap <buffer> <silent> ]] :call <SID>VbSearch('^\s*\(\(private\|public\)\s\+\)\=\(function\\|sub\)', 'W')<cr> -nnoremap <buffer> <silent> [] :call <SID>VbSearch('^\s*\<end\>\s\+\(function\\|sub\)', 'bW')<cr> -nnoremap <buffer> <silent> ][ :call <SID>VbSearch('^\s*\<end\>\s\+\(function\\|sub\)', 'W')<cr> - -" matchit support -if exists("loaded_matchit") - let b:match_ignorecase=1 - let b:match_words= - \ '\%(^\s*\)\@<=\<if\>.*\<then\>\s*$:\%(^\s*\)\@<=\<else\>:\%(^\s*\)\@<=\<elseif\>:\%(^\s*\)\@<=\<end\>\s\+\<if\>,' . - \ '\%(^\s*\)\@<=\<for\>:\%(^\s*\)\@<=\<next\>,' . - \ '\%(^\s*\)\@<=\<while\>:\%(^\s*\)\@<=\<wend\>,' . - \ '\%(^\s*\)\@<=\<do\>:\%(^\s*\)\@<=\<loop\>\s\+\<while\>,' . - \ '\%(^\s*\)\@<=\<select\>\s\+\<case\>:\%(^\s*\)\@<=\<case\>:\%(^\s*\)\@<=\<end\>\s\+\<select\>,' . - \ '\%(^\s*\)\@<=\<enum\>:\%(^\s*\)\@<=\<end\>\s\<enum\>,' . - \ '\%(^\s*\)\@<=\<with\>:\%(^\s*\)\@<=\<end\>\s\<with\>,' . - \ '\%(^\s*\)\@<=\%(\<\%(private\|public\)\>\s\+\)\=\<function\>\s\+\([^ \t(]\+\):\%(^\s*\)\@<=\<\1\>\s*=:\%(^\s*\)\@<=\<end\>\s\+\<function\>,' . - \ '\%(^\s*\)\@<=\%(\<\%(private\|public\)\>\s\+\)\=\<sub\>\s\+:\%(^\s*\)\@<=\<end\>\s\+\<sub\>' +if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter") + let b:browsefilter = "Visual Basic Source Files (*.bas)\t*.bas\n" . + \ "Visual Basic Form Files (*.frm)\t*.frm\n" . + \ "All Files (*.*)\t*.*\n" + let b:undo_ftplugin .= " | unlet! b:browsefilter" endif let &cpo = s:cpo_save diff --git a/runtime/lua/vim/F.lua b/runtime/lua/vim/F.lua index 1a258546a5..9327c652db 100644 --- a/runtime/lua/vim/F.lua +++ b/runtime/lua/vim/F.lua @@ -27,7 +27,7 @@ function F.nil_wrap(fn) end end ---- like {...} except preserve the lenght explicitly +--- like {...} except preserve the length explicitly function F.pack_len(...) return {n=select('#', ...), ...} end diff --git a/runtime/lua/vim/_meta.lua b/runtime/lua/vim/_meta.lua index f7d47c1030..a3d5f64630 100644 --- a/runtime/lua/vim/_meta.lua +++ b/runtime/lua/vim/_meta.lua @@ -398,7 +398,7 @@ end)() --- Converts a vimoption_T style value to a Lua value local convert_value_to_lua = (function() - -- Map of OptionType to functions that take vimoption_T values and conver to lua values. + -- Map of OptionType to functions that take vimoption_T values and convert to lua values. -- Each function takes (info, vim_value) -> lua_value local to_lua_value = { [OptionTypes.BOOLEAN] = function(_, value) return value end, diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index 191b9b9145..5c5631af98 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -36,7 +36,34 @@ M.handlers = setmetatable({}, { end, }) --- Local functions {{{ +-- Metatable that automatically creates an empty table when assigning to a missing key +local bufnr_and_namespace_cacher_mt = { + __index = function(t, bufnr) + assert(bufnr > 0, "Invalid buffer number") + t[bufnr] = {} + return t[bufnr] + end, +} + +local diagnostic_cache = setmetatable({}, { + __index = function(t, bufnr) + assert(bufnr > 0, "Invalid buffer number") + vim.api.nvim_buf_attach(bufnr, false, { + on_detach = function() + rawset(t, bufnr, nil) -- clear cache + end + }) + t[bufnr] = {} + return t[bufnr] + end, +}) + +local diagnostic_cache_extmarks = setmetatable({}, bufnr_and_namespace_cacher_mt) +local diagnostic_attached_buffers = {} +local diagnostic_disabled = {} +local bufs_waiting_to_update = setmetatable({}, bufnr_and_namespace_cacher_mt) + +local all_namespaces = {} ---@private local function to_severity(severity) @@ -106,8 +133,6 @@ local function reformat_diagnostics(format, diagnostics) return formatted end -local all_namespaces = {} - ---@private local function enabled_value(option, namespace) local ns = namespace and M.get_namespace(namespace) or {} @@ -213,36 +238,6 @@ local function get_bufnr(bufnr) return bufnr end --- Metatable that automatically creates an empty table when assigning to a missing key -local bufnr_and_namespace_cacher_mt = { - __index = function(t, bufnr) - if not bufnr or bufnr == 0 then - bufnr = vim.api.nvim_get_current_buf() - end - - if rawget(t, bufnr) == nil then - rawset(t, bufnr, {}) - end - - return rawget(t, bufnr) - end, - - __newindex = function(t, bufnr, v) - if not bufnr or bufnr == 0 then - bufnr = vim.api.nvim_get_current_buf() - end - - rawset(t, bufnr, v) - end, -} - -local diagnostic_cleanup = setmetatable({}, bufnr_and_namespace_cacher_mt) -local diagnostic_cache = setmetatable({}, bufnr_and_namespace_cacher_mt) -local diagnostic_cache_extmarks = setmetatable({}, bufnr_and_namespace_cacher_mt) -local diagnostic_attached_buffers = {} -local diagnostic_disabled = {} -local bufs_waiting_to_update = setmetatable({}, bufnr_and_namespace_cacher_mt) - ---@private local function is_disabled(namespace, bufnr) local ns = M.get_namespace(namespace) @@ -287,11 +282,6 @@ local function set_diagnostic_cache(namespace, bufnr, diagnostics) end ---@private -local function clear_diagnostic_cache(namespace, bufnr) - diagnostic_cache[bufnr][namespace] = nil -end - ----@private local function restore_extmarks(bufnr, last) for ns, extmarks in pairs(diagnostic_cache_extmarks[bufnr]) do local extmarks_current = vim.api.nvim_buf_get_extmarks(bufnr, ns, 0, -1, {details = true}) @@ -377,6 +367,71 @@ local function clear_scheduled_display(namespace, bufnr) end ---@private +local function get_diagnostics(bufnr, opts, clamp) + opts = opts or {} + + local namespace = opts.namespace + local diagnostics = {} + + -- Memoized results of buf_line_count per bufnr + local buf_line_count = setmetatable({}, { + __index = function(t, k) + t[k] = vim.api.nvim_buf_line_count(k) + return rawget(t, k) + end, + }) + + ---@private + local function add(b, d) + if not opts.lnum or d.lnum == opts.lnum then + if clamp and vim.api.nvim_buf_is_loaded(b) then + local line_count = buf_line_count[b] - 1 + if (d.lnum > line_count or d.end_lnum > line_count) then + d = vim.deepcopy(d) + d.lnum = math.max(math.min(d.lnum, line_count), 0) + d.end_lnum = math.max(math.min(d.end_lnum, line_count), 0) + end + end + table.insert(diagnostics, d) + end + end + + if namespace == nil and bufnr == nil then + for b, t in pairs(diagnostic_cache) do + for _, v in pairs(t) do + for _, diagnostic in pairs(v) do + add(b, diagnostic) + end + end + end + elseif namespace == nil then + bufnr = get_bufnr(bufnr) + for iter_namespace in pairs(diagnostic_cache[bufnr]) do + for _, diagnostic in pairs(diagnostic_cache[bufnr][iter_namespace]) do + add(bufnr, diagnostic) + end + end + elseif bufnr == nil then + for b, t in pairs(diagnostic_cache) do + for _, diagnostic in pairs(t[namespace] or {}) do + add(b, diagnostic) + end + end + else + bufnr = get_bufnr(bufnr) + for _, diagnostic in pairs(diagnostic_cache[bufnr][namespace] or {}) do + add(bufnr, diagnostic) + end + end + + if opts.severity then + diagnostics = filter_by_severity(opts.severity, diagnostics) + end + + return diagnostics +end + +---@private local function set_list(loclist, opts) opts = opts or {} local open = vim.F.if_nil(opts.open, true) @@ -386,7 +441,9 @@ local function set_list(loclist, opts) if loclist then bufnr = vim.api.nvim_win_get_buf(winnr) end - local diagnostics = M.get(bufnr, opts) + -- Don't clamp line numbers since the quickfix list can already handle line + -- numbers beyond the end of the buffer + local diagnostics = get_diagnostics(bufnr, opts, false) local items = M.toqflist(diagnostics) if loclist then vim.fn.setloclist(winnr, {}, ' ', { title = title, items = items }) @@ -399,27 +456,12 @@ local function set_list(loclist, opts) end ---@private ---- To (slightly) improve performance, modifies diagnostics in place. -local function clamp_line_numbers(bufnr, diagnostics) - local buf_line_count = vim.api.nvim_buf_line_count(bufnr) - if buf_line_count == 0 then - return - end - - for _, diagnostic in ipairs(diagnostics) do - diagnostic.lnum = math.max(math.min(diagnostic.lnum, buf_line_count - 1), 0) - diagnostic.end_lnum = math.max(math.min(diagnostic.end_lnum, buf_line_count - 1), 0) - end -end - ----@private local function next_diagnostic(position, search_forward, bufnr, opts, namespace) position[1] = position[1] - 1 bufnr = get_bufnr(bufnr) local wrap = vim.F.if_nil(opts.wrap, true) local line_count = vim.api.nvim_buf_line_count(bufnr) - local diagnostics = M.get(bufnr, vim.tbl_extend("keep", opts, {namespace = namespace})) - clamp_line_numbers(bufnr, diagnostics) + local diagnostics = get_diagnostics(bufnr, vim.tbl_extend("keep", opts, {namespace = namespace}), true) local line_diagnostics = diagnostic_lines(diagnostics) for i = 0, line_count do local offset = i * (search_forward and 1 or -1) @@ -431,13 +473,14 @@ local function next_diagnostic(position, search_forward, bufnr, opts, namespace) lnum = (lnum + line_count) % line_count end if line_diagnostics[lnum] and not vim.tbl_isempty(line_diagnostics[lnum]) then + local line_length = #vim.api.nvim_buf_get_lines(bufnr, lnum, lnum + 1, true)[1] local sort_diagnostics, is_next if search_forward then sort_diagnostics = function(a, b) return a.col < b.col end - is_next = function(diagnostic) return diagnostic.col > position[2] end + is_next = function(d) return math.min(d.col, line_length - 1) > position[2] end else sort_diagnostics = function(a, b) return a.col > b.col end - is_next = function(diagnostic) return diagnostic.col < position[2] end + is_next = function(d) return math.min(d.col, line_length - 1) < position[2] end end table.sort(line_diagnostics[lnum], sort_diagnostics) if i == 0 then @@ -475,16 +518,15 @@ local function diagnostic_move_pos(opts, pos) vim.schedule(function() M.open_float( vim.api.nvim_win_get_buf(win_id), - vim.tbl_extend("keep", float_opts, {scope="cursor"}) + vim.tbl_extend("keep", float_opts, { + scope = "cursor", + focus = false, + }) ) end) end end --- }}} - --- Public API {{{ - --- Configure diagnostic options globally or for a specific diagnostic --- namespace. --- @@ -537,26 +579,7 @@ end --- * priority: (number, default 10) Base priority to use for signs. When --- {severity_sort} is used, the priority of a sign is adjusted based on --- its severity. Otherwise, all signs use the same priority. ---- - float: Options for floating windows: ---- * severity: See |diagnostic-severity|. ---- * header: (string or table) String to use as the header for the floating ---- window. If a table, it is interpreted as a [text, hl_group] tuple. ---- Defaults to "Diagnostics:". ---- * source: (string) Include the diagnostic source in ---- the message. One of "always" or "if_many". ---- * format: (function) A function that takes a diagnostic as input and returns a ---- string. The return value is the text used to display the diagnostic. ---- * prefix: (function, string, or table) Prefix each diagnostic in the floating ---- window. If a function, it must have the signature (diagnostic, i, ---- total) -> (string, string), where {i} is the index of the diagnostic ---- being evaluated and {total} is the total number of diagnostics ---- displayed in the window. The function should return a string which ---- is prepended to each diagnostic in the window as well as an ---- (optional) highlight group which will be used to highlight the ---- prefix. If {prefix} is a table, it is interpreted as a [text, ---- hl_group] tuple as in |nvim_echo()|; otherwise, if {prefix} is a ---- string, it is prepended to each diagnostic in the window with no ---- highlight. +--- - float: Options for floating windows. See |vim.diagnostic.open_float()|. --- - update_in_insert: (default false) Update diagnostics in Insert mode (if false, --- diagnostics are updated on InsertLeave) --- - severity_sort: (default false) Sort diagnostics by severity. This affects the order in @@ -564,6 +587,7 @@ end --- are displayed before lower severities (e.g. ERROR is displayed before WARN). --- Options: --- * reverse: (boolean) Reverse sort order +--- ---@param namespace number|nil Update the options for the given namespace. When omitted, update the --- global diagnostic options. function M.config(opts, namespace) @@ -617,33 +641,26 @@ function M.set(namespace, bufnr, diagnostics, opts) opts = {opts, 't', true}, } + bufnr = get_bufnr(bufnr) + if vim.tbl_isempty(diagnostics) then - clear_diagnostic_cache(namespace, bufnr) + diagnostic_cache[bufnr][namespace] = nil else - if not diagnostic_cleanup[bufnr][namespace] then - diagnostic_cleanup[bufnr][namespace] = true - - -- Clean up our data when the buffer unloads. - vim.api.nvim_buf_attach(bufnr, false, { - on_detach = function(_, b) - clear_diagnostic_cache(namespace, b) - diagnostic_cleanup[b][namespace] = nil - end - }) - end set_diagnostic_cache(namespace, bufnr, diagnostics) end if vim.api.nvim_buf_is_loaded(bufnr) then - M.show(namespace, bufnr, diagnostics, opts) + M.show(namespace, bufnr, nil, opts) end - vim.api.nvim_command("doautocmd <nomodeline> User DiagnosticsChanged") + vim.api.nvim_command( + string.format("doautocmd <nomodeline> DiagnosticChanged %s", vim.api.nvim_buf_get_name(bufnr)) + ) end --- Get namespace metadata. --- ----@param ns number Diagnostic namespace +---@param namespace number Diagnostic namespace ---@return table Namespace metadata function M.get_namespace(namespace) vim.validate { namespace = { namespace, 'n' } } @@ -689,49 +706,7 @@ function M.get(bufnr, opts) opts = { opts, 't', true }, } - opts = opts or {} - - local namespace = opts.namespace - local diagnostics = {} - - ---@private - local function add(d) - if not opts.lnum or d.lnum == opts.lnum then - table.insert(diagnostics, d) - end - end - - if namespace == nil and bufnr == nil then - for _, t in pairs(diagnostic_cache) do - for _, v in pairs(t) do - for _, diagnostic in pairs(v) do - add(diagnostic) - end - end - end - elseif namespace == nil then - for iter_namespace in pairs(diagnostic_cache[bufnr]) do - for _, diagnostic in pairs(diagnostic_cache[bufnr][iter_namespace]) do - add(diagnostic) - end - end - elseif bufnr == nil then - for _, t in pairs(diagnostic_cache) do - for _, diagnostic in pairs(t[namespace] or {}) do - add(diagnostic) - end - end - else - for _, diagnostic in pairs(diagnostic_cache[bufnr][namespace] or {}) do - add(diagnostic) - end - end - - if opts.severity then - diagnostics = filter_by_severity(opts.severity, diagnostics) - end - - return diagnostics + return get_diagnostics(bufnr, opts, false) end --- Get the previous diagnostic closest to the cursor position. @@ -807,7 +782,9 @@ end --- - severity: See |diagnostic-severity|. --- - float: (boolean or table, default true) If "true", call |vim.diagnostic.open_float()| --- after moving. If a table, pass the table as the {opts} parameter to ---- |vim.diagnostic.open_float()|. +--- |vim.diagnostic.open_float()|. Unless overridden, the float will show +--- diagnostics at the new cursor position (as if "cursor" were passed to +--- the "scope" option). --- - win_id: (number, default 0) Window ID function M.goto_next(opts) return diagnostic_move_pos( @@ -1115,7 +1092,7 @@ function M.show(namespace, bufnr, diagnostics, opts) M.hide(namespace, bufnr) - diagnostics = diagnostics or M.get(bufnr, {namespace=namespace}) + diagnostics = diagnostics or get_diagnostics(bufnr, {namespace=namespace}, true) if not diagnostics or vim.tbl_isempty(diagnostics) then return @@ -1141,8 +1118,6 @@ function M.show(namespace, bufnr, diagnostics, opts) end end - clamp_line_numbers(bufnr, diagnostics) - for handler_name, handler in pairs(M.handlers) do if handler.show and opts[handler_name] then handler.show(namespace, bufnr, diagnostics, opts) @@ -1156,7 +1131,7 @@ end ---@param opts table|nil Configuration table with the same keys as --- |vim.lsp.util.open_floating_preview()| in addition to the following: --- - namespace: (number) Limit diagnostics to the given namespace ---- - scope: (string, default "buffer") Show diagnostics from the whole buffer ("buffer"), +--- - scope: (string, default "line") Show diagnostics from the whole buffer ("buffer"), --- the current cursor line ("line"), or the current cursor position ("cursor"). --- - pos: (number or table) If {scope} is "line" or "cursor", use this position rather --- than the cursor position. If a number, interpreted as a line number; @@ -1173,7 +1148,17 @@ end --- - format: (function) A function that takes a diagnostic as input and returns a --- string. The return value is the text used to display the diagnostic. --- Overrides the setting from |vim.diagnostic.config()|. ---- - prefix: (function, string, or table) Prefix each diagnostic in the floating window. +--- - prefix: (function, string, or table) Prefix each diagnostic in the floating +--- window. If a function, it must have the signature (diagnostic, i, +--- total) -> (string, string), where {i} is the index of the diagnostic +--- being evaluated and {total} is the total number of diagnostics +--- displayed in the window. The function should return a string which +--- is prepended to each diagnostic in the window as well as an +--- (optional) highlight group which will be used to highlight the +--- prefix. If {prefix} is a table, it is interpreted as a [text, +--- hl_group] tuple as in |nvim_echo()|; otherwise, if {prefix} is a +--- string, it is prepended to each diagnostic in the window with no +--- highlight. --- Overrides the setting from |vim.diagnostic.config()|. ---@return tuple ({float_bufnr}, {win_id}) function M.open_float(bufnr, opts) @@ -1184,7 +1169,7 @@ function M.open_float(bufnr, opts) opts = opts or {} bufnr = get_bufnr(bufnr) - local scope = opts.scope or "buffer" + local scope = opts.scope or "line" local lnum, col if scope == "line" or scope == "cursor" then if not opts.pos then @@ -1213,8 +1198,7 @@ function M.open_float(bufnr, opts) opts = get_resolved_options({ float = float_opts }, nil, bufnr).float end - local diagnostics = M.get(bufnr, opts) - clamp_line_numbers(bufnr, diagnostics) + local diagnostics = get_diagnostics(bufnr, opts, true) if scope == "line" then diagnostics = vim.tbl_filter(function(d) @@ -1334,16 +1318,18 @@ function M.reset(namespace, bufnr) bufnr = {bufnr, 'n', true}, } - local buffers = bufnr and {bufnr} or vim.tbl_keys(diagnostic_cache) + local buffers = bufnr and {get_bufnr(bufnr)} or vim.tbl_keys(diagnostic_cache) for _, iter_bufnr in ipairs(buffers) do local namespaces = namespace and {namespace} or vim.tbl_keys(diagnostic_cache[iter_bufnr]) for _, iter_namespace in ipairs(namespaces) do - clear_diagnostic_cache(iter_namespace, iter_bufnr) + diagnostic_cache[iter_bufnr][iter_namespace] = nil M.hide(iter_namespace, iter_bufnr) end end - vim.api.nvim_command("doautocmd <nomodeline> User DiagnosticsChanged") + vim.api.nvim_command( + string.format("doautocmd <nomodeline> DiagnosticChanged %s", vim.api.nvim_buf_get_name(bufnr)) + ) end --- Add all diagnostics to the quickfix list. @@ -1545,7 +1531,7 @@ function M.fromqflist(list) for _, item in ipairs(list) do if item.valid == 1 then local lnum = math.max(0, item.lnum - 1) - local col = item.col > 0 and (item.col - 1) or nil + local col = math.max(0, item.col - 1) local end_lnum = item.end_lnum > 0 and (item.end_lnum - 1) or lnum local end_col = item.end_col > 0 and (item.end_col - 1) or col local severity = item.type ~= "" and M.severity[item.type] or M.severity.ERROR @@ -1563,6 +1549,4 @@ function M.fromqflist(list) return diagnostics end --- }}} - return M diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 0fc0a7a7aa..61a700bd15 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -115,6 +115,13 @@ local format_line_ending = { ["mac"] = '\r', } +---@private +---@param bufnr (number) +---@returns (string) +local function buf_get_line_ending(bufnr) + return format_line_ending[nvim_buf_get_option(bufnr, 'fileformat')] or '\n' +end + local client_index = 0 ---@private --- Returns a new, unused client id. @@ -130,12 +137,6 @@ local all_buffer_active_clients = {} local uninitialized_clients = {} ---@private ---- Invokes a function for each LSP client attached to the buffer {bufnr}. ---- ----@param bufnr (Number) of buffer ----@param fn (function({client}, {client_id}, {bufnr}) Function to run on ----each client attached to that buffer. ----@param restrict_client_ids table list of client ids on which to restrict function application. local function for_each_buffer_client(bufnr, fn, restrict_client_ids) validate { fn = { fn, 'f' }; @@ -236,7 +237,6 @@ local function validate_client_config(config) config = { config, 't' }; } validate { - root_dir = { config.root_dir, optional_validator(is_dir), "directory" }; handlers = { config.handlers, "t", true }; capabilities = { config.capabilities, "t", true }; cmd_cwd = { config.cmd_cwd, optional_validator(is_dir), "directory" }; @@ -278,9 +278,10 @@ end ---@param bufnr (number) Buffer handle, or 0 for current. ---@returns Buffer text as string. local function buf_get_full_text(bufnr) - local text = table.concat(nvim_buf_get_lines(bufnr, 0, -1, true), '\n') + local line_ending = buf_get_line_ending(bufnr) + local text = table.concat(nvim_buf_get_lines(bufnr, 0, -1, true), line_ending) if nvim_buf_get_option(bufnr, 'eol') then - text = text .. '\n' + text = text .. line_ending end return text end @@ -313,12 +314,14 @@ do --- --- state --- pending_change?: function that the timer starts to trigger didChange - --- pending_changes: list of tables with the pending changesets; for incremental_sync only + --- pending_changes: table (uri -> list of pending changeset tables)); + -- Only set if incremental_sync is used --- use_incremental_sync: bool --- buffers?: table (bufnr → lines); for incremental sync only --- timer?: uv_timer local state_by_client = {} + ---@private function changetracking.init(client, bufnr) local state = state_by_client[client.id] if not state then @@ -340,16 +343,16 @@ do state.buffers[bufnr] = nvim_buf_get_lines(bufnr, 0, -1, true) end + ---@private function changetracking.reset_buf(client, bufnr) + changetracking.flush(client) local state = state_by_client[client.id] - if state then - changetracking._reset_timer(state) - if state.buffers then - state.buffers[bufnr] = nil - end + if state and state.buffers then + state.buffers[bufnr] = nil end end + ---@private function changetracking.reset(client_id) local state = state_by_client[client_id] if state then @@ -358,13 +361,14 @@ do end end - function changetracking.prepare(bufnr, firstline, lastline, new_lastline, changedtick) + ---@private + function changetracking.prepare(bufnr, firstline, lastline, new_lastline) local incremental_changes = function(client) local cached_buffers = state_by_client[client.id].buffers local curr_lines = nvim_buf_get_lines(bufnr, 0, -1, true) - local line_ending = format_line_ending[vim.api.nvim_buf_get_option(0, 'fileformat')] + local line_ending = buf_get_line_ending(bufnr) local incremental_change = sync.compute_diff( - cached_buffers[bufnr], curr_lines, firstline, lastline, new_lastline, client.offset_encoding or 'utf-16', line_ending or '\n') + cached_buffers[bufnr], curr_lines, firstline, lastline, new_lastline, client.offset_encoding or 'utf-16', line_ending) cached_buffers[bufnr] = curr_lines return incremental_change end @@ -385,7 +389,7 @@ do client.notify("textDocument/didChange", { textDocument = { uri = uri; - version = changedtick; + version = util.buf_versions[bufnr]; }; contentChanges = { changes, } }) @@ -395,27 +399,36 @@ do if state.use_incremental_sync then -- This must be done immediately and cannot be delayed -- The contents would further change and startline/endline may no longer fit - table.insert(state.pending_changes, incremental_changes(client)) + if not state.pending_changes[uri] then + state.pending_changes[uri] = {} + end + table.insert(state.pending_changes[uri], incremental_changes(client)) end state.pending_change = function() state.pending_change = nil if client.is_stopped() or not vim.api.nvim_buf_is_valid(bufnr) then return end - local contentChanges if state.use_incremental_sync then - contentChanges = state.pending_changes + for change_uri, content_changes in pairs(state.pending_changes) do + client.notify("textDocument/didChange", { + textDocument = { + uri = change_uri; + version = util.buf_versions[vim.uri_to_bufnr(change_uri)]; + }; + contentChanges = content_changes, + }) + end state.pending_changes = {} else - contentChanges = { full_changes(), } + client.notify("textDocument/didChange", { + textDocument = { + uri = uri; + version = util.buf_versions[bufnr]; + }; + contentChanges = { full_changes() }, + }) end - client.notify("textDocument/didChange", { - textDocument = { - uri = uri; - version = changedtick; - }; - contentChanges = contentChanges - }) end state.timer = vim.loop.new_timer() -- Must use schedule_wrap because `full_changes()` calls nvim_buf_get_lines @@ -432,6 +445,7 @@ do end --- Flushes any outstanding change notification. + ---@private function changetracking.flush(client) local state = state_by_client[client.id] if state then @@ -566,12 +580,10 @@ end -- --- Starts and initializes a client with the given configuration. --- ---- Parameters `cmd` and `root_dir` are required. +--- Parameter `cmd` is required. --- --- The following parameters describe fields in the {config} table. --- ----@param root_dir: (string) Directory where the LSP server will base ---- its rootUri on initialization. --- ---@param cmd: (required, string or list treated like |jobstart()|) Base command --- that initiates the LSP client. @@ -587,6 +599,11 @@ end --- { "PRODUCTION=true"; "TEST=123"; PORT = 8080; HOST = "0.0.0.0"; } --- </pre> --- +---@param workspace_folders (table) List of workspace folders passed to the +--- language server. For backwards compatibility rootUri and rootPath will be +--- derived from the first workspace folder in this list. See `workspaceFolders` in +--- the LSP spec. +--- ---@param capabilities Map overriding the default capabilities defined by --- |vim.lsp.protocol.make_client_capabilities()|, passed to the language --- server on initialization. Hint: use make_client_capabilities() and modify @@ -603,17 +620,13 @@ end --- ---@param commands table Table that maps string of clientside commands to user-defined functions. --- Commands passed to start_client take precedence over the global command registry. Each key ---- must be a unique comand name, and the value is a function which is called if any LSP action +--- must be a unique command name, and the value is a function which is called if any LSP action --- (code action, code lenses, ...) triggers the command. --- ---@param init_options Values to pass in the initialization request --- as `initializationOptions`. See `initialize` in the LSP spec. --- ---@param name (string, default=client-id) Name in log messages. --- ----@param workspace_folders (table) List of workspace folders passed to the ---- language server. Defaults to root_dir if not set. See `workspaceFolders` in ---- the LSP spec --- ---@param get_language_id function(bufnr, filetype) -> language ID as string. --- Defaults to the filetype. @@ -661,8 +674,13 @@ end --- notifications to the server by the given number in milliseconds. No debounce --- occurs if nil --- - exit_timeout (number, default 500): Milliseconds to wait for server to --- exit cleanly after sending the 'shutdown' request before sending kill -15. --- If set to false, nvim exits immediately after sending the 'shutdown' request to the server. +--- exit cleanly after sending the 'shutdown' request before sending kill -15. +--- If set to false, nvim exits immediately after sending the 'shutdown' request to the server. +--- +---@param root_dir string Directory where the LSP +--- server will base its workspaceFolders, rootUri, and rootPath +--- on initialization. +--- ---@returns Client id. |vim.lsp.get_client_by_id()| Note: client may not be --- fully initialized. Use `on_init` to do any actions once --- the client has been initialized. @@ -779,6 +797,9 @@ function lsp.start_client(config) env = config.cmd_env; }) + -- Return nil if client fails to start + if not rpc then return end + local client = { id = client_id; name = name; @@ -805,11 +826,24 @@ function lsp.start_client(config) } local version = vim.version() - if config.root_dir and not config.workspace_folders then - config.workspace_folders = {{ - uri = vim.uri_from_fname(config.root_dir); - name = string.format("%s", config.root_dir); - }}; + local workspace_folders + local root_uri + local root_path + if config.workspace_folders or config.root_dir then + if config.root_dir and not config.workspace_folders then + workspace_folders = {{ + uri = vim.uri_from_fname(config.root_dir); + name = string.format("%s", config.root_dir); + }}; + else + workspace_folders = config.workspace_folders + end + root_uri = workspace_folders[1].uri + root_path = vim.uri_to_fname(root_uri) + else + workspace_folders = nil + root_uri = nil + root_path = nil end local initialize_params = { @@ -827,10 +861,15 @@ function lsp.start_client(config) -- The rootPath of the workspace. Is null if no folder is open. -- -- @deprecated in favour of rootUri. - rootPath = config.root_dir; + rootPath = root_path or vim.NIL; -- The rootUri of the workspace. Is null if no folder is open. If both -- `rootPath` and `rootUri` are set `rootUri` wins. - rootUri = config.root_dir and vim.uri_from_fname(config.root_dir); + rootUri = root_uri or vim.NIL; + -- The workspace folders configured in the client when the server starts. + -- This property is only available if the client supports workspace folders. + -- It can be `null` if the client supports workspace folders but none are + -- configured. + workspaceFolders = workspace_folders or vim.NIL; -- User provided initialization options. initializationOptions = config.init_options; -- The capabilities provided by the client (editor or tool) @@ -838,21 +877,6 @@ function lsp.start_client(config) -- The initial trace setting. If omitted trace is disabled ("off"). -- trace = "off" | "messages" | "verbose"; trace = valid_traces[config.trace] or 'off'; - -- The workspace folders configured in the client when the server starts. - -- This property is only available if the client supports workspace folders. - -- It can be `null` if the client supports workspace folders but none are - -- configured. - -- - -- Since 3.6.0 - -- workspaceFolders?: WorkspaceFolder[] | null; - -- export interface WorkspaceFolder { - -- -- The associated URI for this workspace folder. - -- uri - -- -- The name of the workspace folder. Used to refer to this - -- -- workspace folder in the user interface. - -- name - -- } - workspaceFolders = config.workspace_folders, } if config.before_init then -- TODO(ashkan) handle errors here. @@ -865,7 +889,9 @@ function lsp.start_client(config) rpc.notify('initialized', vim.empty_dict()) client.initialized = true uninitialized_clients[client_id] = nil - client.workspaceFolders = initialize_params.workspaceFolders + client.workspace_folders = workspace_folders + -- TODO(mjlbach): Backwards compatbility, to be removed in 0.7 + client.workspaceFolders = client.workspace_folders client.server_capabilities = assert(result.capabilities, "initialize result doesn't contain capabilities") -- These are the cleaned up capabilities we use for dynamically deciding -- when to send certain events to clients. @@ -1007,7 +1033,7 @@ function lsp.start_client(config) return rpc.notify("$/cancelRequest", { id = id }) end - -- Track this so that we can escalate automatically if we've alredy tried a + -- Track this so that we can escalate automatically if we've already tried a -- graceful shutdown local graceful_shutdown_failed = false ---@private @@ -1084,7 +1110,7 @@ do return end util.buf_versions[bufnr] = changedtick - local compute_change_and_notify = changetracking.prepare(bufnr, firstline, lastline, new_lastline, changedtick) + local compute_change_and_notify = changetracking.prepare(bufnr, firstline, lastline, new_lastline) for_each_buffer_client(bufnr, compute_change_and_notify) end end @@ -1143,6 +1169,7 @@ function lsp.buf_attach_client(bufnr, client_id) on_reload = function() local params = { textDocument = { uri = uri; } } for_each_buffer_client(bufnr, function(client, _) + changetracking.reset_buf(client, bufnr) if client.resolved_capabilities.text_document_open_close then client.notify('textDocument/didClose', params) end @@ -1152,10 +1179,10 @@ function lsp.buf_attach_client(bufnr, client_id) on_detach = function() local params = { textDocument = { uri = uri; } } for_each_buffer_client(bufnr, function(client, _) + changetracking.reset_buf(client, bufnr) if client.resolved_capabilities.text_document_open_close then client.notify('textDocument/didClose', params) end - changetracking.reset_buf(client, bufnr) end) util.buf_versions[bufnr] = nil all_buffer_active_clients[bufnr] = nil @@ -1190,7 +1217,7 @@ end --- Gets a client by id, or nil if the id is invalid. --- The returned client may not yet be fully initialized. --- +--- ---@param client_id number client id --- ---@returns |vim.lsp.client| object, or nil @@ -1199,7 +1226,7 @@ function lsp.get_client_by_id(client_id) end --- Returns list of buffers attached to client_id. --- +--- ---@param client_id number client id ---@returns list of buffer ids function lsp.get_buffers_by_client_id(client_id) @@ -1269,6 +1296,7 @@ function lsp._vim_exit_handler() local poll_time = 50 + ---@private local function check_clients_closed() for client_id, timeout in pairs(timeouts) do timeouts[client_id] = timeout - poll_time @@ -1303,8 +1331,8 @@ nvim_command("autocmd VimLeavePre * lua vim.lsp._vim_exit_handler()") ---@param method (string) LSP method name ---@param params (optional, table) Parameters to send to the server ---@param handler (optional, function) See |lsp-handler| --- If nil, follows resolution strategy defined in |lsp-handler-configuration| --- +--- If nil, follows resolution strategy defined in |lsp-handler-configuration| +--- ---@returns 2-tuple: --- - Map of client-id:request-id pairs for all successful requests. --- - Function which can be used to cancel all the requests. You could instead @@ -1587,6 +1615,21 @@ function lsp.formatexpr(opts) return 0 end +--- Provides an interface between the built-in client and 'tagfunc'. +--- +--- When used with normal mode commands (e.g. |CTRL-]|) this will invoke +--- the "textDocument/definition" LSP method to find the tag under the cursor. +--- Otherwise, uses "workspace/symbol". If no results are returned from +--- any LSP servers, falls back to using built-in tags. +--- +---@param pattern Pattern used to find a workspace symbol +---@param flags See |tag-function| +--- +---@returns A list of matching tags +function lsp.tagfunc(...) + return require('vim.lsp.tagfunc')(...) +end + ---Checks whether a client is stopped. --- ---@param client_id (Number) @@ -1640,7 +1683,17 @@ function lsp.get_log_path() return log.get_filename() end ---- Call {fn} for every client attached to {bufnr} +--- Invokes a function for each LSP client attached to a buffer. +--- +---@param bufnr number Buffer number +---@param fn function Function to run on each client attached to buffer +--- {bufnr}. The function takes the client, client ID, and +--- buffer number as arguments. Example: +--- <pre> +--- vim.lsp.for_each_buffer_client(0, function(client, client_id, bufnr) +--- print(vim.inspect(client)) +--- end) +--- </pre> function lsp.for_each_buffer_client(bufnr, fn) return for_each_buffer_client(bufnr, fn) end @@ -1699,11 +1752,11 @@ end --- using `workspace/executeCommand`. --- --- The first argument to the function will be the `Command`: --- Command --- title: String --- command: String --- arguments?: any[] --- +--- Command +--- title: String +--- command: String +--- arguments?: any[] +--- --- The second argument is the `ctx` of |lsp-handler| lsp.commands = setmetatable({}, { __newindex = function(tbl, key, value) diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 747d761730..f02ebfb9dc 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -165,7 +165,7 @@ end --- saved. {timeout_ms} is passed on to |vim.lsp.buf_request_sync()|. Example: --- --- <pre> ---- vim.api.nvim_command[[autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting_sync()]] +--- autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting_sync() --- </pre> --- ---@param options Table with valid `FormattingOptions` entries @@ -176,9 +176,10 @@ function M.formatting_sync(options, timeout_ms) if client == nil then return end local params = util.make_formatting_params(options) - local result, err = client.request_sync("textDocument/formatting", params, timeout_ms, vim.api.nvim_get_current_buf()) + local bufnr = vim.api.nvim_get_current_buf() + local result, err = client.request_sync("textDocument/formatting", params, timeout_ms, bufnr) if result and result.result then - util.apply_text_edits(result.result) + util.apply_text_edits(result.result, bufnr) elseif err then vim.notify("vim.lsp.buf.formatting_sync: " .. err, vim.log.levels.WARN) end @@ -202,6 +203,7 @@ end ---the remaining clients in the order as they occur in the `order` list. function M.formatting_seq_sync(options, timeout_ms, order) local clients = vim.tbl_values(vim.lsp.buf_get_clients()); + local bufnr = vim.api.nvim_get_current_buf() -- sort the clients according to `order` for _, client_name in pairs(order or {}) do @@ -220,7 +222,7 @@ function M.formatting_seq_sync(options, timeout_ms, order) local params = util.make_formatting_params(options) local result, err = client.request_sync("textDocument/formatting", params, timeout_ms, vim.api.nvim_get_current_buf()) if result and result.result then - util.apply_text_edits(result.result) + util.apply_text_edits(result.result, bufnr) elseif err then vim.notify(string.format("vim.lsp.buf.formatting_seq_sync: (%s) %s", client.name, err), vim.log.levels.WARN) end @@ -261,6 +263,7 @@ function M.rename(new_name) request('textDocument/rename', params) end + ---@private local function prepare_rename(err, result) if err == nil and result == nil then vim.notify('nothing to rename', vim.log.levels.INFO) @@ -369,7 +372,7 @@ end function M.list_workspace_folders() local workspace_folders = {} for _, client in pairs(vim.lsp.buf_get_clients()) do - for _, folder in pairs(client.workspaceFolders or {}) do + for _, folder in pairs(client.workspace_folders or {}) do table.insert(workspace_folders, folder.name) end end @@ -389,7 +392,7 @@ function M.add_workspace_folder(workspace_folder) local params = util.make_workspace_params({{uri = vim.uri_from_fname(workspace_folder); name = workspace_folder}}, {{}}) for _, client in pairs(vim.lsp.buf_get_clients()) do local found = false - for _, folder in pairs(client.workspaceFolders or {}) do + for _, folder in pairs(client.workspace_folders or {}) do if folder.name == workspace_folder then found = true print(workspace_folder, "is already part of this workspace") @@ -398,10 +401,10 @@ function M.add_workspace_folder(workspace_folder) end if not found then vim.lsp.buf_notify(0, 'workspace/didChangeWorkspaceFolders', params) - if not client.workspaceFolders then - client.workspaceFolders = {} + if not client.workspace_folders then + client.workspace_folders = {} end - table.insert(client.workspaceFolders, params.event.added[1]) + table.insert(client.workspace_folders, params.event.added[1]) end end end @@ -415,10 +418,10 @@ function M.remove_workspace_folder(workspace_folder) if not (workspace_folder and #workspace_folder > 0) then return end local params = util.make_workspace_params({{}}, {{uri = vim.uri_from_fname(workspace_folder); name = workspace_folder}}) for _, client in pairs(vim.lsp.buf_get_clients()) do - for idx, folder in pairs(client.workspaceFolders) do + for idx, folder in pairs(client.workspace_folders) do if folder.name == workspace_folder then vim.lsp.buf_notify(0, 'workspace/didChangeWorkspaceFolders', params) - client.workspaceFolders[idx] = nil + client.workspace_folders[idx] = nil return end end @@ -444,9 +447,9 @@ end --- by events such as `CursorHold`, eg: --- --- <pre> ---- vim.api.nvim_command [[autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight()]] ---- vim.api.nvim_command [[autocmd CursorHoldI <buffer> lua vim.lsp.buf.document_highlight()]] ---- vim.api.nvim_command [[autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references()]] +--- autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight() +--- autocmd CursorHoldI <buffer> lua vim.lsp.buf.document_highlight() +--- autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references() --- </pre> --- --- Note: Usage of |vim.lsp.buf.document_highlight()| requires the following highlight groups diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 1e6f83c1ba..075da41b23 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -220,12 +220,9 @@ function M.on_publish_diagnostics(_, result, ctx, config) end vim.diagnostic.set(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id)) - - -- Keep old autocmd for back compat. This should eventually be removed. - vim.api.nvim_command("doautocmd <nomodeline> User LspDiagnosticsChanged") end ---- Clear diagnotics and diagnostic cache. +--- Clear diagnostics and diagnostic cache. --- --- Diagnostic producers should prefer |vim.diagnostic.reset()|. However, --- this method signature is still used internally in some parts of the LSP @@ -434,24 +431,6 @@ end --- Move to the next diagnostic --- ---@deprecated Prefer |vim.diagnostic.goto_next()| ---- ----@param opts table|nil Configuration table. Keys: ---- - {client_id}: (number) ---- - If nil, will consider all clients attached to buffer. ---- - {cursor_position}: (Position, default current position) ---- - See |nvim_win_get_cursor()| ---- - {wrap}: (boolean, default true) ---- - Whether to loop around file or not. Similar to 'wrapscan' ---- - {severity}: (DiagnosticSeverity) ---- - Exclusive severity to consider. Overrides {severity_limit} ---- - {severity_limit}: (DiagnosticSeverity) ---- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid. ---- - {enable_popup}: (boolean, default true) ---- - Call |vim.lsp.diagnostic.show_line_diagnostics()| on jump ---- - {popup_opts}: (table) ---- - Table to pass as {opts} parameter to |vim.lsp.diagnostic.show_line_diagnostics()| ---- - {win_id}: (number, default 0) ---- - Window ID function M.goto_next(opts) if opts then if opts.severity then @@ -565,7 +544,7 @@ end --- Open a floating window with the diagnostics from {line_nr} --- ----@deprecated Prefer |vim.diagnostic.show_line_diagnostics()| +---@deprecated Prefer |vim.diagnostic.open_float()| --- ---@param opts table Configuration table --- - all opts for |vim.lsp.diagnostic.get_line_diagnostics()| and @@ -717,5 +696,3 @@ end -- }}} return M - --- vim: fdm=marker diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index fa4f2b22a5..22089aaaa6 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -28,7 +28,7 @@ local function progress_handler(_, result, ctx, _) local client_name = client and client.name or string.format("id=%d", client_id) if not client then err_message("LSP[", client_name, "] client has shut down after sending the message") - return + return vim.NIL end local val = result.value -- unspecified yet local token = result.token -- string or number @@ -70,6 +70,7 @@ M['window/workDoneProgress/create'] = function(_, result, ctx) local client_name = client and client.name or string.format("id=%d", client_id) if not client then err_message("LSP[", client_name, "] client has shut down after sending the message") + return vim.NIL end client.messages.progress[token] = {} return vim.NIL diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua index 4597f1919a..dbc473b52c 100644 --- a/runtime/lua/vim/lsp/log.lua +++ b/runtime/lua/vim/lsp/log.lua @@ -101,6 +101,7 @@ function log.set_level(level) end --- Gets the current log level. +---@return string current log level function log.get_level() return current_log_level end diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index bce1e9f35d..1fb75ddeb7 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -230,7 +230,7 @@ function default_dispatchers.on_error(code, err) end --- Starts an LSP server process and create an LSP RPC client object to ---- interact with it. +--- interact with it. Communication with the server is currently limited to stdio. --- ---@param cmd (string) Command to start the LSP server. ---@param cmd_args (table) List of additional string arguments to pass to {cmd}. @@ -264,8 +264,6 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) if extra_spawn_params and extra_spawn_params.cwd then assert(is_dir(extra_spawn_params.cwd), "cwd must be a directory") - elseif not (vim.fn.executable(cmd) == 1) then - error(string.format("The given command %q is not executable.", cmd)) end if dispatchers then local user_dispatchers = dispatchers @@ -325,7 +323,14 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) end handle, pid = uv.spawn(cmd, spawn_params, onexit) if handle == nil then - error(string.format("start `%s` failed: %s", cmd, pid)) + local msg = string.format("Spawning language server with cmd: `%s` failed", cmd) + if string.match(pid, "ENOENT") then + msg = msg .. ". The language server is either not installed, missing from PATH, or not executable." + else + msg = msg .. string.format(" with error message: %s", pid) + end + vim.notify(msg, vim.log.levels.WARN) + return end end diff --git a/runtime/lua/vim/lsp/sync.lua b/runtime/lua/vim/lsp/sync.lua index 585c14a00f..5df2a4d144 100644 --- a/runtime/lua/vim/lsp/sync.lua +++ b/runtime/lua/vim/lsp/sync.lua @@ -75,42 +75,45 @@ local function byte_to_utf(line, byte, offset_encoding) end ---@private +local function compute_line_length(line, offset_encoding) + local length + local _ + if offset_encoding == 'utf-16' then + _, length = str_utfindex(line) + elseif offset_encoding == 'utf-32' then + length, _ = str_utfindex(line) + else + length = #line + end + return length +end + +---@private -- Given a line, byte idx, alignment, and offset_encoding convert to the aligned -- utf-8 index and either the utf-16, or utf-32 index. ---@param line string the line to index into ---@param byte integer the byte idx ----@param align string when dealing with multibyte characters, --- to choose the start of the current character or the beginning of the next. --- Used for incremental sync for start/end range respectively ---@param offset_encoding string utf-8|utf-16|utf-32|nil (default: utf-8) ---@returns table<string, int> byte_idx and char_idx of first change position -local function align_position(line, byte, align, offset_encoding) +local function align_end_position(line, byte, offset_encoding) local char -- If on the first byte, or an empty string: the trivial case if byte == 1 or #line == 0 then char = byte -- Called in the case of extending an empty line "" -> "a" elseif byte == #line + 1 then - byte = byte + str_utf_end(line, #line) - char = byte_to_utf(line, byte, offset_encoding) + char = compute_line_length(line, offset_encoding) + 1 else -- Modifying line, find the nearest utf codepoint - if align == 'start' then - byte = byte + str_utf_start(line, byte) - char = byte_to_utf(line, byte, offset_encoding) - elseif align == 'end' then - local offset = str_utf_end(line, byte) - -- If the byte does not fall on the start of the character, then - -- align to the start of the next character. - if offset > 0 then - char = byte_to_utf(line, byte, offset_encoding) + 1 - byte = byte + offset - else - char = byte_to_utf(line, byte, offset_encoding) - byte = byte + offset - end + local offset = str_utf_end(line, byte) + -- If the byte does not fall on the start of the character, then + -- align to the start of the next character. + if offset > 0 then + char = byte_to_utf(line, byte, offset_encoding) + 1 + byte = byte + offset else - error('`align` must be start or end.') + char = byte_to_utf(line, byte, offset_encoding) + byte = byte + offset end -- Extending line, find the nearest utf codepoint for the last valid character end @@ -131,7 +134,7 @@ local function compute_start_range(prev_lines, curr_lines, firstline, lastline, -- occur on a new line pointed to by lastline. This occurs during insertion of -- new lines(O), the new newline is inserted at the line indicated by -- new_lastline. - -- If firstline == new_lastline, the first change occured on a line that was deleted. + -- If firstline == new_lastline, the first change occurred on a line that was deleted. -- In this case, the first byte change is also at the first byte of firstline if firstline == new_lastline or firstline == lastline then return { line_idx = firstline, byte_idx = 1, char_idx = 1 } @@ -154,7 +157,18 @@ local function compute_start_range(prev_lines, curr_lines, firstline, lastline, end -- Convert byte to codepoint if applicable - local byte_idx, char_idx = align_position(prev_line, start_byte_idx, 'start', offset_encoding) + local char_idx + local byte_idx + if start_byte_idx == 1 or (#prev_line == 0 and start_byte_idx == 1)then + byte_idx = start_byte_idx + char_idx = 1 + elseif start_byte_idx == #prev_line + 1 then + byte_idx = start_byte_idx + char_idx = compute_line_length(prev_line, offset_encoding) + 1 + else + byte_idx = start_byte_idx + str_utf_start(prev_line, start_byte_idx) + char_idx = byte_to_utf(prev_line, start_byte_idx, offset_encoding) + end -- Return the start difference (shared for new and prev lines) return { line_idx = firstline, byte_idx = byte_idx, char_idx = char_idx } @@ -174,7 +188,7 @@ end ---@param offset_encoding string ---@returns (int, int) end_line_idx and end_col_idx of range local function compute_end_range(prev_lines, curr_lines, start_range, firstline, lastline, new_lastline, offset_encoding) - -- If firstline == new_lastline, the first change occured on a line that was deleted. + -- If firstline == new_lastline, the first change occurred on a line that was deleted. -- In this case, the last_byte... if firstline == new_lastline then return { line_idx = (lastline - new_lastline + firstline), byte_idx = 1, char_idx = 1 }, { line_idx = firstline, byte_idx = 1, char_idx = 1 } @@ -219,11 +233,12 @@ local function compute_end_range(prev_lines, curr_lines, start_range, firstline, -- Iterate from end to beginning of shortest line local prev_end_byte_idx = prev_line_length - byte_offset + 1 + -- Handle case where lines match if prev_end_byte_idx == 0 then prev_end_byte_idx = 1 end - local prev_byte_idx, prev_char_idx = align_position(prev_line, prev_end_byte_idx, 'start', offset_encoding) + local prev_byte_idx, prev_char_idx = align_end_position(prev_line, prev_end_byte_idx, offset_encoding) local prev_end_range = { line_idx = prev_line_idx, byte_idx = prev_byte_idx, char_idx = prev_char_idx } local curr_end_range @@ -236,7 +251,7 @@ local function compute_end_range(prev_lines, curr_lines, start_range, firstline, if curr_end_byte_idx == 0 then curr_end_byte_idx = 1 end - local curr_byte_idx, curr_char_idx = align_position(curr_line, curr_end_byte_idx, 'start', offset_encoding) + local curr_byte_idx, curr_char_idx = align_end_position(curr_line, curr_end_byte_idx, offset_encoding) curr_end_range = { line_idx = curr_line_idx, byte_idx = curr_byte_idx, char_idx = curr_char_idx } end @@ -280,18 +295,6 @@ local function extract_text(lines, start_range, end_range, line_ending) end end -local function compute_line_length(line, offset_encoding) - local length - local _ - if offset_encoding == 'utf-16' then - _, length = str_utfindex(line) - elseif offset_encoding == 'utf-32' then - length, _ = str_utfindex(line) - else - length = #line - end - return length -end ---@private -- rangelength depends on the offset encoding -- bytes for utf-8 (clangd with extenion) diff --git a/runtime/lua/vim/lsp/tagfunc.lua b/runtime/lua/vim/lsp/tagfunc.lua new file mode 100644 index 0000000000..5c55e8559f --- /dev/null +++ b/runtime/lua/vim/lsp/tagfunc.lua @@ -0,0 +1,76 @@ +local lsp = vim.lsp +local util = vim.lsp.util + +---@private +local function mk_tag_item(name, range, uri, offset_encoding) + local bufnr = vim.uri_to_bufnr(uri) + -- This is get_line_byte_from_position is 0-indexed, call cursor expects a 1-indexed position + local byte = util._get_line_byte_from_position(bufnr, range.start, offset_encoding) + 1 + return { + name = name, + filename = vim.uri_to_fname(uri), + cmd = string.format('call cursor(%d, %d)|', range.start.line + 1, byte), + } +end + +---@private +local function query_definition(pattern) + local params = lsp.util.make_position_params() + local results_by_client, err = lsp.buf_request_sync(0, 'textDocument/definition', params, 1000) + if err then + return {} + end + local results = {} + local add = function(range, uri, offset_encoding) + table.insert(results, mk_tag_item(pattern, range, uri, offset_encoding)) + end + for client_id, lsp_results in pairs(results_by_client) do + local client = lsp.get_client_by_id(client_id) + local result = lsp_results.result or {} + if result.range then -- Location + add(result.range, result.uri) + else -- Location[] or LocationLink[] + for _, item in pairs(result) do + if item.range then -- Location + add(item.range, item.uri, client.offset_encoding) + else -- LocationLink + add(item.targetSelectionRange, item.targetUri, client.offset_encoding) + end + end + end + end + return results +end + +---@private +local function query_workspace_symbols(pattern) + local results_by_client, err = lsp.buf_request_sync(0, 'workspace/symbol', { query = pattern }, 1000) + if err then + return {} + end + local results = {} + for client_id, symbols in pairs(results_by_client) do + local client = lsp.get_client_by_id(client_id) + for _, symbol in pairs(symbols.result or {}) do + local loc = symbol.location + local item = mk_tag_item(symbol.name, loc.range, loc.uri, client.offset_encoding) + item.kind = lsp.protocol.SymbolKind[symbol.kind] or 'Unknown' + table.insert(results, item) + end + end + return results +end + +---@private +local function tagfunc(pattern, flags) + local matches + if string.match(flags, 'c') then + matches = query_definition(pattern) + else + matches = query_workspace_symbols(pattern) + end + -- fall back to tags if no matches + return #matches > 0 and matches or vim.NIL +end + +return tagfunc diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index ba5c20ef9f..fad2b962b5 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -148,6 +148,93 @@ local function sort_by_key(fn) end ---@private +--- Gets the zero-indexed lines from the given buffer. +--- Works on unloaded buffers by reading the file using libuv to bypass buf reading events. +--- Falls back to loading the buffer and nvim_buf_get_lines for buffers with non-file URI. +--- +---@param bufnr number bufnr to get the lines from +---@param rows number[] zero-indexed line numbers +---@return table<number string> a table mapping rows to lines +local function get_lines(bufnr, rows) + rows = type(rows) == "table" and rows or { rows } + + ---@private + local function buf_lines() + local lines = {} + for _, row in pairs(rows) do + lines[row] = (vim.api.nvim_buf_get_lines(bufnr, row, row + 1, false) or { "" })[1] + end + return lines + end + + local uri = vim.uri_from_bufnr(bufnr) + + -- load the buffer if this is not a file uri + -- Custom language server protocol extensions can result in servers sending URIs with custom schemes. Plugins are able to load these via `BufReadCmd` autocmds. + if uri:sub(1, 4) ~= "file" then + vim.fn.bufload(bufnr) + return buf_lines() + end + + -- use loaded buffers if available + if vim.fn.bufloaded(bufnr) == 1 then + return buf_lines() + end + + local filename = api.nvim_buf_get_name(bufnr) + + -- get the data from the file + local fd = uv.fs_open(filename, "r", 438) + if not fd then return "" end + local stat = uv.fs_fstat(fd) + local data = uv.fs_read(fd, stat.size, 0) + uv.fs_close(fd) + + local lines = {} -- rows we need to retrieve + local need = 0 -- keep track of how many unique rows we need + for _, row in pairs(rows) do + if not lines[row] then + need = need + 1 + end + lines[row] = true + end + + local found = 0 + local lnum = 0 + + for line in string.gmatch(data, "([^\n]*)\n?") do + if lines[lnum] == true then + lines[lnum] = line + found = found + 1 + if found == need then break end + end + lnum = lnum + 1 + end + + -- change any lines we didn't find to the empty string + for i, line in pairs(lines) do + if line == true then + lines[i] = "" + end + end + return lines +end + + +---@private +--- Gets the zero-indexed line from the given buffer. +--- Works on unloaded buffers by reading the file using libuv to bypass buf reading events. +--- Falls back to loading the buffer and nvim_buf_get_lines for buffers with non-file URI. +--- +---@param bufnr number +---@param row number zero-indexed line number +---@return string the line at row in filename +local function get_line(bufnr, row) + return get_lines(bufnr, { row })[row] +end + + +---@private --- Position is a https://microsoft.github.io/language-server-protocol/specifications/specification-current/#position --- Returns a zero-indexed column, since set_lines() does the conversion to --- 1-indexed @@ -158,31 +245,25 @@ local function get_line_byte_from_position(bufnr, position, offset_encoding) -- When on the first character, we can ignore the difference between byte and -- character if col > 0 then - if not api.nvim_buf_is_loaded(bufnr) then - vim.fn.bufload(bufnr) - end + local line = get_line(bufnr, position.line) + local ok, result - local line = position.line - local lines = api.nvim_buf_get_lines(bufnr, line, line + 1, false) - if #lines > 0 then - local ok, result - - if offset_encoding == "utf-16" or not offset_encoding then - ok, result = pcall(vim.str_byteindex, lines[1], col, true) - elseif offset_encoding == "utf-32" then - ok, result = pcall(vim.str_byteindex, lines[1], col, false) - end + if offset_encoding == "utf-16" or not offset_encoding then + ok, result = pcall(vim.str_byteindex, line, col, true) + elseif offset_encoding == "utf-32" then + ok, result = pcall(vim.str_byteindex, line, col, false) + end - if ok then - return result - end - return math.min(#lines[1], col) + if ok then + return result end + return math.min(#line, col) end return col end --- Process and return progress reports from lsp server +---@private function M.get_progress_messages() local new_messages = {} @@ -246,6 +327,10 @@ end ---@param bufnr number Buffer id ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit function M.apply_text_edits(text_edits, bufnr) + validate { + text_edits = { text_edits, 't', false }; + bufnr = { bufnr, 'number', false }; + } if not next(text_edits) then return end if not api.nvim_buf_is_loaded(bufnr) then vim.fn.bufload(bufnr) @@ -474,7 +559,7 @@ local function remove_unmatch_completion_items(items, prefix) end, items) end ---- Acording to LSP spec, if the client set `completionItemKind.valueSet`, +--- According to LSP spec, if the client set `completionItemKind.valueSet`, --- the client must handle it properly even if it receives a value outside the --- specification. --- @@ -574,7 +659,7 @@ function M.rename(old_fname, new_fname, opts) api.nvim_buf_delete(oldbuf, { force = true }) end - +---@private local function create_file(change) local opts = change.options or {} -- from spec: Overwrite wins over `ignoreIfExists` @@ -586,7 +671,7 @@ local function create_file(change) vim.fn.bufadd(fname) end - +---@private local function delete_file(change) local opts = change.options or {} local fname = vim.uri_to_fname(change.uri) @@ -1054,7 +1139,7 @@ function M.stylize_markdown(bufnr, contents, opts) markdown_lines[#stripped] = true end else - -- strip any emty lines or separators prior to this separator in actual markdown + -- strip any empty lines or separators prior to this separator in actual markdown if line:match("^---+$") then while markdown_lines[#stripped] and (stripped[#stripped]:match("^%s*$") or stripped[#stripped]:match("^---+$")) do markdown_lines[#stripped] = false @@ -1087,7 +1172,7 @@ function M.stylize_markdown(bufnr, contents, opts) local idx = 1 ---@private - -- keep track of syntaxes we already inlcuded. + -- keep track of syntaxes we already included. -- no need to include the same syntax more than once local langs = {} local fences = get_markdown_fences() @@ -1223,18 +1308,21 @@ end --- ---@param contents table of lines to show in window ---@param syntax string of syntax to set for opened buffer ----@param opts dictionary with optional fields ---- - height of floating window ---- - width of floating window ---- - wrap boolean enable wrapping of long lines (defaults to true) ---- - wrap_at character to wrap at for computing height when wrap is enabled ---- - max_width maximal width of floating window ---- - max_height maximal height of floating window ---- - pad_top number of lines to pad contents at top ---- - pad_bottom number of lines to pad contents at bottom ---- - focus_id if a popup with this id is opened, then focus it ---- - close_events list of events that closes the floating window ---- - focusable (boolean, default true): Make float focusable +---@param opts table with optional fields (additional keys are passed on to |vim.api.nvim_open_win()|) +--- - height: (number) height of floating window +--- - width: (number) width of floating window +--- - wrap: (boolean, default true) wrap long lines +--- - wrap_at: (string) character to wrap at for computing height when wrap is enabled +--- - max_width: (number) maximal width of floating window +--- - max_height: (number) maximal height of floating window +--- - pad_top: (number) number of lines to pad contents at top +--- - pad_bottom: (number) number of lines to pad contents at bottom +--- - focus_id: (string) if a popup with this id is opened, then focus it +--- - close_events: (table) list of events that closes the floating window +--- - focusable: (boolean, default true) Make float focusable +--- - focus: (boolean, default true) If `true`, and if {focusable} +--- is also `true`, focus an existing floating window with the same +--- {focus_id} ---@returns bufnr,winnr buffer and window number of the newly created floating ---preview window function M.open_floating_preview(contents, syntax, opts) @@ -1246,12 +1334,13 @@ function M.open_floating_preview(contents, syntax, opts) opts = opts or {} opts.wrap = opts.wrap ~= false -- wrapping by default opts.stylize_markdown = opts.stylize_markdown ~= false + opts.focus = opts.focus ~= false opts.close_events = opts.close_events or {"CursorMoved", "CursorMovedI", "BufHidden", "InsertCharPre"} local bufnr = api.nvim_get_current_buf() -- check if this popup is focusable and we need to focus - if opts.focus_id and opts.focusable ~= false then + if opts.focus_id and opts.focusable ~= false and opts.focus then -- Go back to previous window if we are in a focusable one local current_winnr = api.nvim_get_current_win() if npcall(api.nvim_win_get_var, current_winnr, opts.focus_id) then @@ -1314,7 +1403,7 @@ function M.open_floating_preview(contents, syntax, opts) api.nvim_buf_set_option(floating_bufnr, 'modifiable', false) api.nvim_buf_set_option(floating_bufnr, 'bufhidden', 'wipe') - api.nvim_buf_set_keymap(floating_bufnr, "n", "q", "<cmd>bdelete<cr>", {silent = true, noremap = true}) + api.nvim_buf_set_keymap(floating_bufnr, "n", "q", "<cmd>bdelete<cr>", {silent = true, noremap = true, nowait = true}) M.close_preview_autocmd(opts.close_events, floating_winnr) -- save focus_id @@ -1331,7 +1420,7 @@ do --[[ References ]] --- Removes document highlights from a buffer. --- - ---@param bufnr buffer id + ---@param bufnr number Buffer id function M.buf_clear_references(bufnr) validate { bufnr = {bufnr, 'n', true} } api.nvim_buf_clear_namespace(bufnr, reference_ns, 0, -1) @@ -1339,9 +1428,9 @@ do --[[ References ]] --- Shows a list of document highlights for a certain buffer. --- - ---@param bufnr buffer id - ---@param references List of `DocumentHighlight` objects to highlight - ---@param offset_encoding string utf-8|utf-16|utf-32|nil defaults to utf-16 + ---@param bufnr number Buffer id + ---@param references table List of `DocumentHighlight` objects to highlight + ---@param offset_encoding string One of "utf-8", "utf-16", "utf-32", or nil. Defaults to utf-16 ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#documentHighlight function M.buf_highlight_references(bufnr, references, offset_encoding) validate { bufnr = {bufnr, 'n', true} } @@ -1372,88 +1461,6 @@ local position_sort = sort_by_key(function(v) return {v.start.line, v.start.character} end) ---- Gets the zero-indexed line from the given uri. ----@param uri string uri of the resource to get the line from ----@param row number zero-indexed line number ----@return string the line at row in filename --- For non-file uris, we load the buffer and get the line. --- If a loaded buffer exists, then that is used. --- Otherwise we get the line using libuv which is a lot faster than loading the buffer. -function M.get_line(uri, row) - return M.get_lines(uri, { row })[row] -end - ---- Gets the zero-indexed lines from the given uri. ----@param uri string uri of the resource to get the lines from ----@param rows number[] zero-indexed line numbers ----@return table<number string> a table mapping rows to lines --- For non-file uris, we load the buffer and get the lines. --- If a loaded buffer exists, then that is used. --- Otherwise we get the lines using libuv which is a lot faster than loading the buffer. -function M.get_lines(uri, rows) - rows = type(rows) == "table" and rows or { rows } - - local function buf_lines(bufnr) - local lines = {} - for _, row in pairs(rows) do - lines[row] = (vim.api.nvim_buf_get_lines(bufnr, row, row + 1, false) or { "" })[1] - end - return lines - end - - -- load the buffer if this is not a file uri - -- Custom language server protocol extensions can result in servers sending URIs with custom schemes. Plugins are able to load these via `BufReadCmd` autocmds. - if uri:sub(1, 4) ~= "file" then - local bufnr = vim.uri_to_bufnr(uri) - vim.fn.bufload(bufnr) - return buf_lines(bufnr) - end - - local filename = vim.uri_to_fname(uri) - - -- use loaded buffers if available - if vim.fn.bufloaded(filename) == 1 then - local bufnr = vim.fn.bufnr(filename, false) - return buf_lines(bufnr) - end - - -- get the data from the file - local fd = uv.fs_open(filename, "r", 438) - if not fd then return "" end - local stat = uv.fs_fstat(fd) - local data = uv.fs_read(fd, stat.size, 0) - uv.fs_close(fd) - - local lines = {} -- rows we need to retrieve - local need = 0 -- keep track of how many unique rows we need - for _, row in pairs(rows) do - if not lines[row] then - need = need + 1 - end - lines[row] = true - end - - local found = 0 - local lnum = 0 - - for line in string.gmatch(data, "([^\n]*)\n?") do - if lines[lnum] == true then - lines[lnum] = line - found = found + 1 - if found == need then break end - end - lnum = lnum + 1 - end - - -- change any lines we didn't find to the empty string - for i, line in pairs(lines) do - if line == true then - lines[i] = "" - end - end - return lines -end - --- Returns the items with the byte position calculated correctly and in sorted --- order, for display in quickfix and location lists. --- @@ -1496,7 +1503,7 @@ function M.locations_to_items(locations) end -- get all the lines for this uri - local lines = M.get_lines(uri, uri_rows) + local lines = get_lines(vim.uri_to_bufnr(uri), uri_rows) for _, temp in ipairs(rows) do local pos = temp.start @@ -1541,7 +1548,7 @@ function M.set_qflist(items) }) end --- Acording to LSP spec, if the client set "symbolKind.valueSet", +-- According to LSP spec, if the client set "symbolKind.valueSet", -- the client must handle it properly even if it receives a value outside the specification. -- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol function M._get_symbol_kind_name(symbol_kind) @@ -1773,8 +1780,7 @@ end ---@param col 0-indexed byte offset in line ---@returns (number, number) UTF-32 and UTF-16 index of the character in line {row} column {col} in buffer {buf} function M.character_offset(bufnr, row, col) - local uri = vim.uri_from_bufnr(bufnr) - local line = M.get_line(uri, row) + local line = get_line(bufnr, row) -- If the col is past the EOL, use the line length. if col > #line then return str_utfindex(line) diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 6e40b6ca52..1cf618725d 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -12,7 +12,7 @@ local vim = vim or {} --- same functions as those in the input table. Userdata and threads are not --- copied and will throw an error. --- ----@param orig Table to copy +---@param orig table Table to copy ---@returns New table of copied keys and (nested) values. function vim.deepcopy(orig) end -- luacheck: no unused vim.deepcopy = (function() @@ -21,17 +21,16 @@ vim.deepcopy = (function() end local deepcopy_funcs = { - table = function(orig) + table = function(orig, cache) + if cache[orig] then return cache[orig] end local copy = {} - if vim._empty_dict_mt ~= nil and getmetatable(orig) == vim._empty_dict_mt then - copy = vim.empty_dict() - end - + cache[orig] = copy + local mt = getmetatable(orig) for k, v in pairs(orig) do - copy[vim.deepcopy(k)] = vim.deepcopy(v) + copy[vim.deepcopy(k, cache)] = vim.deepcopy(v, cache) end - return copy + return setmetatable(copy, mt) end, number = _id, string = _id, @@ -40,10 +39,10 @@ vim.deepcopy = (function() ['function'] = _id, } - return function(orig) + return function(orig, cache) local f = deepcopy_funcs[type(orig)] if f then - return f(orig) + return f(orig, cache or {}) else error("Cannot deepcopy object of type "..type(orig)) end @@ -560,6 +559,7 @@ do return type(val) == t or (t == 'callable' and vim.is_callable(val)) end + ---@private local function is_valid(opt) if type(opt) ~= 'table' then return false, string.format('opt: expected table, got %s', type(opt)) diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index 66999c5f7f..07f6418c0c 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -72,7 +72,7 @@ end --- Gets the parser for this bufnr / ft combination. --- --- If needed this will create the parser. ---- Unconditionnally attach the provided callback +--- Unconditionally attach the provided callback --- ---@param bufnr The buffer the parser should be tied to ---@param lang The filetype of this parser diff --git a/runtime/lua/vim/treesitter/language.lua b/runtime/lua/vim/treesitter/language.lua index 89ddd6cd5a..6f347ff25f 100644 --- a/runtime/lua/vim/treesitter/language.lua +++ b/runtime/lua/vim/treesitter/language.lua @@ -38,7 +38,7 @@ end --- Inspects the provided language. --- ---- Inspecting provides some useful informations on the language like node names, ... +--- Inspecting provides some useful information on the language like node names, ... --- ---@param lang The language. function M.inspect_language(lang) diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index 7e392f72a4..594765761d 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -493,9 +493,9 @@ local function tree_contains(tree, range) return false end ---- Determines wether @param range is contained in this language tree +--- Determines whether @param range is contained in this language tree --- ---- This goes down the tree to recursively check childs. +--- This goes down the tree to recursively check children. --- ---@param range A range, that is a `{ start_line, start_col, end_line, end_col }` table. function LanguageTree:contains(range) diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 66da179ea3..b8255e61ed 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -48,7 +48,7 @@ function M.get_query_files(lang, query_name, is_included) local base_langs = {} -- Now get the base languages by looking at the first line of every file - -- The syntax is the folowing : + -- The syntax is the following : -- ;+ inherits: ({language},)*{language} -- -- {language} ::= {lang} | ({lang}) @@ -446,7 +446,7 @@ end --- --- {source} is needed if the query contains predicates, then the caller --- must ensure to use a freshly parsed tree consistent with the current ---- text of the buffer (if relevent). {start_row} and {end_row} can be used to limit +--- text of the buffer (if relevant). {start_row} and {end_row} can be used to limit --- matches inside a row range (this is typically used with root node --- as the node, i e to get syntax highlight matches in the current --- viewport). When omitted the start and end row values are used from the given node. @@ -466,7 +466,7 @@ end --- </pre> --- ---@param node The node under which the search will occur ----@param source The source buffer or string to exctract text from +---@param source The source buffer or string to extract text from ---@param start The starting line of the search ---@param stop The stopping line of the search (end-exclusive) --- diff --git a/runtime/lua/vim/uri.lua b/runtime/lua/vim/uri.lua index 5d8d4fa169..d08d2a3ee3 100644 --- a/runtime/lua/vim/uri.lua +++ b/runtime/lua/vim/uri.lua @@ -56,8 +56,8 @@ local function is_windows_file_uri(uri) end --- Get a URI from a file path. ----@param path (string): Path to file ----@return URI +---@param path string Path to file +---@return string URI local function uri_from_fname(path) local volume_path, fname = path:match("^([a-zA-Z]:)(.*)") local is_windows = volume_path ~= nil @@ -78,8 +78,8 @@ local URI_SCHEME_PATTERN = '^([a-zA-Z]+[a-zA-Z0-9+-.]*):.*' local WINDOWS_URI_SCHEME_PATTERN = '^([a-zA-Z]+[a-zA-Z0-9+-.]*):[a-zA-Z]:.*' --- Get a URI from a bufnr ----@param bufnr (number): Buffer number ----@return URI +---@param bufnr number +---@return string URI local function uri_from_bufnr(bufnr) local fname = vim.api.nvim_buf_get_name(bufnr) local volume_path = fname:match("^([a-zA-Z]:).*") @@ -99,8 +99,8 @@ local function uri_from_bufnr(bufnr) end --- Get a filename from a URI ----@param uri (string): The URI ----@return Filename +---@param uri string +---@return string filename or unchanged URI for non-file URIs local function uri_to_fname(uri) local scheme = assert(uri:match(URI_SCHEME_PATTERN), 'URI must contain a scheme: ' .. uri) if scheme ~= 'file' then @@ -117,17 +117,13 @@ local function uri_to_fname(uri) return uri end ---- Return or create a buffer for a uri. ----@param uri (string): The URI ----@return bufnr. ----@note Creates buffer but does not load it +--- Get the buffer for a uri. +--- Creates a new unloaded buffer if no buffer for the uri already exists. +-- +---@param uri string +---@return number bufnr local function uri_to_bufnr(uri) - local scheme = assert(uri:match(URI_SCHEME_PATTERN), 'URI must contain a scheme: ' .. uri) - if scheme == 'file' then - return vim.fn.bufadd(uri_to_fname(uri)) - else - return vim.fn.bufadd(uri) - end + return vim.fn.bufadd(uri_to_fname(uri)) end return { diff --git a/runtime/nvim.appdata.xml b/runtime/nvim.appdata.xml index 099c9a57c0..225dd79878 100644 --- a/runtime/nvim.appdata.xml +++ b/runtime/nvim.appdata.xml @@ -26,6 +26,7 @@ </screenshots> <releases> + <release date="2021-11-30" version="0.6.0"/> <release date="2021-07-02" version="0.5.0"/> <release date="2020-08-04" version="0.4.4"/> <release date="2019-11-06" version="0.4.3"/> diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim index ae0242a312..4a58bee8ce 100644 --- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim +++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim @@ -2,7 +2,7 @@ " " Author: Bram Moolenaar " Copyright: Vim license applies, see ":help license" -" Last Change: 2021 Nov 14 +" Last Change: 2021 Nov 27 " " WORK IN PROGRESS - Only the basics work " Note: On MS-Windows you need a recent version of gdb. The one included with @@ -102,6 +102,7 @@ endfunc call s:Highlight(1, '', &background) hi default debugBreakpoint term=reverse ctermbg=red guibg=red +hi default debugBreakpointDisabled term=reverse ctermbg=gray guibg=gray func s:StartDebug(bang, ...) " First argument is the command to debug, second core file or process ID. @@ -241,15 +242,29 @@ func s:StartDebug_term(dict) let comm_job_info = nvim_get_chan_info(s:comm_job_id) let commpty = comm_job_info['pty'] - " Open a terminal window to run the debugger. - " Add -quiet to avoid the intro message causing a hit-enter prompt. let gdb_args = get(a:dict, 'gdb_args', []) let proc_args = get(a:dict, 'proc_args', []) - let cmd = [g:termdebugger, '-quiet', '-tty', pty, '--eval-command', 'echo startupdone\n'] + gdb_args - "call ch_log('executing "' . join(cmd) . '"') + let gdb_cmd = [g:termdebugger] + " Add -quiet to avoid the intro message causing a hit-enter prompt. + let gdb_cmd += ['-quiet'] + " Disable pagination, it causes everything to stop at the gdb + let gdb_cmd += ['-iex', 'set pagination off'] + " Interpret commands while the target is running. This should usually only + " be exec-interrupt, since many commands don't work properly while the + " target is running (so execute during startup). + let gdb_cmd += ['-iex', 'set mi-async on'] + " Open a terminal window to run the debugger. + let gdb_cmd += ['-tty', pty] + " Command executed _after_ startup is done, provides us with the necessary feedback + let gdb_cmd += ['-ex', 'echo startupdone\n'] + + " Adding arguments requested by the user + let gdb_cmd += gdb_args + execute 'new' - let s:gdb_job_id = termopen(cmd, {'on_exit': function('s:EndTermDebug')}) + " call ch_log('executing "' . join(gdb_cmd) . '"') + let s:gdb_job_id = termopen(gdb_cmd, {'on_exit': function('s:EndTermDebug')}) if s:gdb_job_id == 0 echoerr 'invalid argument (or job table is full) while opening gdb terminal window' exe 'bwipe! ' . s:ptybuf @@ -272,8 +287,8 @@ func s:StartDebug_term(dict) for lnum in range(1, 200) if get(getbufline(s:gdbbuf, lnum), 0, '') =~ 'startupdone' - let try_count = 9999 - break + let try_count = 9999 + break endif endfor let try_count += 1 @@ -286,11 +301,12 @@ func s:StartDebug_term(dict) " Set arguments to be run. if len(proc_args) - call chansend(s:gdb_job_id, 'set args ' . join(proc_args) . "\r") + call chansend(s:gdb_job_id, 'server set args ' . join(proc_args) . "\r") endif - " Connect gdb to the communication pty, using the GDB/MI interface - call chansend(s:gdb_job_id, 'new-ui mi ' . commpty . "\r") + " Connect gdb to the communication pty, using the GDB/MI interface. + " Prefix "server" to avoid adding this to the history. + call chansend(s:gdb_job_id, 'server new-ui mi ' . commpty . "\r") " Wait for the response to show up, users may not notice the error and wonder " why the debugger doesn't work. @@ -309,7 +325,8 @@ func s:StartDebug_term(dict) let response = line1 . line2 if response =~ 'Undefined command' echoerr 'Sorry, your gdb is too old, gdb 7.12 is required' - call s:CloseBuffers() + " CHECKME: possibly send a "server show version" here + call s:CloseBuffers() return endif if response =~ 'New UI allocated' @@ -332,17 +349,6 @@ func s:StartDebug_term(dict) sleep 10m endwhile - " Interpret commands while the target is running. This should usually only be - " exec-interrupt, since many commands don't work properly while the target is - " running. - call s:SendCommand('-gdb-set mi-async on') - " Older gdb uses a different command. - call s:SendCommand('-gdb-set target-async on') - - " Disable pagination, it causes everything to stop at the gdb - " "Type <return> to continue" prompt. - call s:SendCommand('set pagination off') - " Set the filetype, this can be used to add mappings. set filetype=termdebug @@ -370,14 +376,26 @@ func s:StartDebug_prompt(dict) exe (&columns / 2 - 1) . "wincmd |" endif - " Add -quiet to avoid the intro message causing a hit-enter prompt. let gdb_args = get(a:dict, 'gdb_args', []) let proc_args = get(a:dict, 'proc_args', []) - let cmd = [g:termdebugger, '-quiet', '--interpreter=mi2'] + gdb_args - "call ch_log('executing "' . join(cmd) . '"') + let gdb_cmd = [g:termdebugger] + " Add -quiet to avoid the intro message causing a hit-enter prompt. + let gdb_cmd += ['-quiet'] + " Disable pagination, it causes everything to stop at the gdb, needs to be run early + let gdb_cmd += ['-iex', 'set pagination off'] + " Interpret commands while the target is running. This should usually only + " be exec-interrupt, since many commands don't work properly while the + " target is running (so execute during startup). + let gdb_cmd += ['-iex', 'set mi-async on'] + " directly communicate via mi2 + let gdb_cmd += ['--interpreter=mi2'] - let s:gdbjob = jobstart(cmd, { + " Adding arguments requested by the user + let gdb_cmd += gdb_args + + " call ch_log('executing "' . join(gdb_cmd) . '"') + let s:gdbjob = jobstart(gdb_cmd, { \ 'on_exit': function('s:EndPromptDebug'), \ 'on_stdout': function('s:GdbOutCallback'), \ }) @@ -391,13 +409,6 @@ func s:StartDebug_prompt(dict) return endif - " Interpret commands while the target is running. This should usually only - " be exec-interrupt, since many commands don't work properly while the - " target is running. - call s:SendCommand('-gdb-set mi-async on') - " Older gdb uses a different command. - call s:SendCommand('-gdb-set target-async on') - let s:ptybuf = 0 if has('win32') " MS-Windows: run in a new console window for maximum compatibility @@ -432,8 +443,6 @@ func s:StartDebug_prompt(dict) endif call s:SendCommand('set print pretty on') call s:SendCommand('set breakpoint pending on') - " Disable pagination, it causes everything to stop at the gdb - call s:SendCommand('set pagination off') " Set arguments to be run if len(proc_args) @@ -504,7 +513,7 @@ func TermDebugSendCommand(cmd) " needed once. call jobstop(s:gdbjob) else - call s:SendCommand('-exec-interrupt') + Stop endif sleep 10m endif @@ -515,6 +524,15 @@ func TermDebugSendCommand(cmd) endif endfunc +" Send a command only when stopped. Used for :Next and :Step. +func s:SendCommandIfStopped(cmd) + if s:stopped + call s:SendCommand(a:cmd) + " else + " call ch_log('dropping command, program is running: ' . a:cmd) + endif +endfunc + " Function called when entering a line in the prompt buffer. func s:PromptCallback(text) call s:SendCommand(a:text) @@ -583,32 +601,23 @@ func s:GdbOutCallback(job_id, msgs, event) endfunc " Decode a message from gdb. quotedText starts with a ", return the text up -" to the next ", unescaping characters. +" to the next ", unescaping characters: +" - remove line breaks +" - change \\t to \t +" - change \0xhh to \xhh +" - change \ooo to octal +" - change \\ to \ func s:DecodeMessage(quotedText) if a:quotedText[0] != '"' echoerr 'DecodeMessage(): missing quote in ' . a:quotedText return endif - let result = '' - let i = 1 - while a:quotedText[i] != '"' && i < len(a:quotedText) - if a:quotedText[i] == '\' - let i += 1 - if a:quotedText[i] == 'n' - " drop \n - let i += 1 - continue - elseif a:quotedText[i] == 't' - " append \t - let i += 1 - let result .= "\t" - continue - endif - endif - let result .= a:quotedText[i] - let i += 1 - endwhile - return result + return a:quotedText + \->substitute('^"\|".*\|\\n', '', 'g') + \->substitute('\\t', "\t", 'g') + \->substitute('\\0x\(\x\x\)', {-> eval('"\x' .. submatch(1) .. '"')}, 'g') + \->substitute('\\\o\o\o', {-> eval('"' .. submatch(0) .. '"')}, 'g') + \->substitute('\\\\', '\', 'g') endfunc " Extract the "name" value from a gdb message with fullname="name". @@ -657,8 +666,8 @@ func s:EndDebugCommon() if bufexists(bufnr) exe bufnr .. "buf" if exists('b:save_signcolumn') - let &signcolumn = b:save_signcolumn - unlet b:save_signcolumn + let &signcolumn = b:save_signcolumn + unlet b:save_signcolumn endif endif endfor @@ -770,7 +779,9 @@ func s:CommOutput(job_id, msgs, event) if msg =~ '^\(\*stopped\|\*running\|=thread-selected\)' call s:HandleCursor(msg) elseif msg =~ '^\^done,bkpt=' || msg =~ '^=breakpoint-created,' - call s:HandleNewBreakpoint(msg) + call s:HandleNewBreakpoint(msg, 0) + elseif msg =~ '^=breakpoint-modified,' + call s:HandleNewBreakpoint(msg, 1) elseif msg =~ '^=breakpoint-deleted,' call s:HandleBreakpointDelete(msg) elseif msg =~ '^=thread-group-started' @@ -804,17 +815,20 @@ func s:InstallCommands() command -nargs=? Break call s:SetBreakpoint(<q-args>) command Clear call s:ClearBreakpoint() - command Step call s:SendCommand('-exec-step') - command Over call s:SendCommand('-exec-next') - command Finish call s:SendCommand('-exec-finish') + command Step call s:SendCommandIfStopped('-exec-step') + command Over call s:SendCommandIfStopped('-exec-next') + command Finish call s:SendCommandIfStopped('-exec-finish') command -nargs=* Run call s:Run(<q-args>) command -nargs=* Arguments call s:SendCommand('-exec-arguments ' . <q-args>) - command Stop call s:SendCommand('-exec-interrupt') - " using -exec-continue results in CTRL-C in gdb window not working if s:way == 'prompt' + command Stop call s:PromptInterrupt() command Continue call s:SendCommand('continue') else + command Stop call s:SendCommand('-exec-interrupt') + " using -exec-continue results in CTRL-C in the gdb window not working, + " communicating via commbuf (= use of SendCommand) has the same result + "command Continue call s:SendCommand('-exec-continue') command Continue call chansend(s:gdb_job_id, "continue\r") endif @@ -913,20 +927,16 @@ func s:SetBreakpoint(at) let do_continue = 0 if !s:stopped let do_continue = 1 - if s:way == 'prompt' - call s:PromptInterrupt() - else - call s:SendCommand('-exec-interrupt') - endif + Stop sleep 10m endif " Use the fname:lnum format, older gdb can't handle --source. let at = empty(a:at) ? - \ fnameescape(expand('%:p')) . ':' . line('.') : a:at + \ fnameescape(expand('%:p')) . ':' . line('.') : a:at call s:SendCommand('-break-insert ' . at) if do_continue - call s:SendCommand('-exec-continue') + Continue endif endfunc @@ -937,23 +947,32 @@ func s:ClearBreakpoint() let bploc = printf('%s:%d', fname, lnum) if has_key(s:breakpoint_locations, bploc) let idx = 0 + let nr = 0 for id in s:breakpoint_locations[bploc] if has_key(s:breakpoints, id) - " Assume this always works, the reply is simply "^done". - call s:SendCommand('-break-delete ' . id) - for subid in keys(s:breakpoints[id]) - exe 'sign unplace ' . s:Breakpoint2SignNumber(id, subid) - endfor - unlet s:breakpoints[id] - unlet s:breakpoint_locations[bploc][idx] - break + " Assume this always works, the reply is simply "^done". + call s:SendCommand('-break-delete ' . id) + for subid in keys(s:breakpoints[id]) + exe 'sign unplace ' . s:Breakpoint2SignNumber(id, subid) + endfor + unlet s:breakpoints[id] + unlet s:breakpoint_locations[bploc][idx] + let nr = id + break else - let idx += 1 + let idx += 1 endif endfor - if empty(s:breakpoint_locations[bploc]) - unlet s:breakpoint_locations[bploc] + if nr != 0 + if empty(s:breakpoint_locations[bploc]) + unlet s:breakpoint_locations[bploc] + endif + echomsg 'Breakpoint ' . id . ' cleared from line ' . lnum . '.' + else + echoerr 'Internal error trying to remove breakpoint at line ' . lnum . '!' endif + else + echomsg 'No breakpoint to remove at line ' . lnum . '.' endif endfunc @@ -965,44 +984,75 @@ func s:Run(args) endfunc func s:SendEval(expr) - " clean up expression that may got in because of range - " (newlines and surrounding spaces) - let expr = a:expr - if &filetype ==# 'cobol' - " extra cleanup for COBOL: _every: expression ends with a period, - " a trailing comma is ignored as it commonly separates multiple expr. - let expr = substitute(expr, '\..*', '', '') - let expr = substitute(expr, '[;\n]', ' ', 'g') - let expr = substitute(expr, ',*$', '', '') + " check for "likely" boolean expressions, in which case we take it as lhs + if a:expr =~ "[=!<>]=" + let exprLHS = a:expr else - let expr = substitute(expr, '\n', ' ', 'g') + " remove text that is likely an assignment + let exprLHS = substitute(a:expr, ' *=.*', '', '') endif - let expr = substitute(expr, '^ *\(.*\) *', '\1', '') + " encoding expression to prevent bad errors + let expr = a:expr + let expr = substitute(expr, '\\', '\\\\', 'g') + let expr = substitute(expr, '"', '\\"', 'g') call s:SendCommand('-data-evaluate-expression "' . expr . '"') - let s:evalexpr = expr + let s:evalexpr = exprLHS endfunc -" :Evaluate - evaluate what is under the cursor +" :Evaluate - evaluate what is specified / under the cursor func s:Evaluate(range, arg) + let expr = s:GetEvaluationExpression(a:range, a:arg) + let s:ignoreEvalError = 0 + call s:SendEval(expr) +endfunc + +" get what is specified / under the cursor +func s:GetEvaluationExpression(range, arg) if a:arg != '' - let expr = a:arg - let s:evalFromBalloonExpr = 0 + " user supplied evaluation + let expr = s:CleanupExpr(a:arg) + " DSW: replace "likely copy + paste" assignment + let expr = substitute(expr, '"\([^"]*\)": *', '\1=', 'g') elseif a:range == 2 let pos = getcurpos() let reg = getreg('v', 1, 1) let regt = getregtype('v') normal! gv"vy - let expr = @v + let expr = s:CleanupExpr(@v) call setpos('.', pos) call setreg('v', reg, regt) let s:evalFromBalloonExpr = 1 else + " no evaluation provided: get from C-expression under cursor + " TODO: allow filetype specific lookup #9057 let expr = expand('<cexpr>') let s:evalFromBalloonExpr = 1 endif - let s:ignoreEvalError = 0 - call s:SendEval(expr) + return expr +endfunc + +" clean up expression that may got in because of range +" (newlines and surrounding whitespace) +" As it can also be specified via ex-command for assignments this function +" may not change the "content" parts (like replacing contained spaces +func s:CleanupExpr(expr) + " replace all embedded newlines/tabs/... + let expr = substitute(a:expr, '\_s', ' ', 'g') + + if &filetype ==# 'cobol' + " extra cleanup for COBOL: + " - a semicolon nmay be used instead of a space + " - a trailing comma or period is ignored as it commonly separates/ends + " multiple expr + let expr = substitute(expr, ';', ' ', 'g') + let expr = substitute(expr, '[,.]\+ *$', '', '') + endif + + " get rid of leading and trailing spaces + let expr = substitute(expr, '^ *', '', '') + let expr = substitute(expr, ' *$', '', '') + return expr endfunc let s:ignoreEvalError = 0 @@ -1013,6 +1063,8 @@ let s:evalFromBalloonExprResult = '' func s:HandleEvaluate(msg) let value = substitute(a:msg, '.*value="\(.*\)"', '\1', '') let value = substitute(value, '\\"', '"', 'g') + " multi-byte characters arrive in octal form + let value = substitute(value, '\\\o\o\o', {-> eval('"' .. submatch(0) .. '"')}, 'g') let value = substitute(value, '
', '\1', '') if s:evalFromBalloonExpr if s:evalFromBalloonExprResult == '' @@ -1246,15 +1298,15 @@ func s:HandleCursor(msg) let curwinid = win_getid(winnr()) if win_gotoid(s:asmwin) - let lnum = search('^' . s:asm_addr) - if lnum == 0 - call s:SendCommand('disassemble $pc') - else - exe 'sign unplace ' . s:asm_id - exe 'sign place ' . s:asm_id . ' line=' . lnum . ' name=debugPC' - endif + let lnum = search('^' . s:asm_addr) + if lnum == 0 + call s:SendCommand('disassemble $pc') + else + exe 'sign unplace ' . s:asm_id + exe 'sign place ' . s:asm_id . ' line=' . lnum . ' name=debugPC' + endif - call win_gotoid(curwinid) + call win_gotoid(curwinid) endif endif endif @@ -1278,8 +1330,8 @@ func s:HandleCursor(msg) exe 'sign unplace ' . s:pc_id exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC file=' . fname if !exists('b:save_signcolumn') - let b:save_signcolumn = &signcolumn - call add(s:signcolumn_buflist, bufnr()) + let b:save_signcolumn = &signcolumn + call add(s:signcolumn_buflist, bufnr()) endif setlocal signcolumn=yes endif @@ -1292,11 +1344,16 @@ endfunc let s:BreakpointSigns = [] -func s:CreateBreakpoint(id, subid) +func s:CreateBreakpoint(id, subid, enabled) let nr = printf('%d.%d', a:id, a:subid) if index(s:BreakpointSigns, nr) == -1 call add(s:BreakpointSigns, nr) - exe "sign define debugBreakpoint" . nr . " text=" . substitute(nr, '\..*', '', '') . " texthl=debugBreakpoint" + if a:enabled == "n" + let hiName = "debugBreakpointDisabled" + else + let hiName = "debugBreakpoint" + endif + exe "sign define debugBreakpoint" . nr . " text=" . substitute(nr, '\..*', '', '') . " texthl=" . hiName endif endfunc @@ -1306,9 +1363,14 @@ endfunction " Handle setting a breakpoint " Will update the sign that shows the breakpoint -func s:HandleNewBreakpoint(msg) +func s:HandleNewBreakpoint(msg, modifiedFlag) if a:msg !~ 'fullname=' - " a watch does not have a file name + " a watch or a pending breakpoint does not have a file name + if a:msg =~ 'pending=' + let nr = substitute(a:msg, '.*number=\"\([0-9.]*\)\".*', '\1', '') + let target = substitute(a:msg, '.*pending=\"\([^"]*\)\".*', '\1', '') + echomsg 'Breakpoint ' . nr . ' (' . target . ') pending.' + endif return endif for msg in s:SplitMsg(a:msg) @@ -1324,7 +1386,8 @@ func s:HandleNewBreakpoint(msg) " If "nr" is 123 it becomes "123.0" and subid is "0". " If "nr" is 123.4 it becomes "123.4.0" and subid is "4"; "0" is discarded. let [id, subid; _] = map(split(nr . '.0', '\.'), 'v:val + 0') - call s:CreateBreakpoint(id, subid) + let enabled = substitute(msg, '.*enabled="\([yn]\)".*', '\1', '') + call s:CreateBreakpoint(id, subid, enabled) if has_key(s:breakpoints, id) let entries = s:breakpoints[id] @@ -1351,7 +1414,18 @@ func s:HandleNewBreakpoint(msg) if bufloaded(fname) call s:PlaceSign(id, subid, entry) + let posMsg = ' at line ' . lnum . '.' + else + let posMsg = ' in ' . fname . ' at line ' . lnum . '.' + endif + if !a:modifiedFlag + let actionTaken = 'created' + elseif enabled == 'n' + let actionTaken = 'disabled' + else + let actionTaken = 'enabled' endif + echomsg 'Breakpoint ' . nr . ' ' . actionTaken . posMsg endfor endfunc @@ -1371,11 +1445,12 @@ func s:HandleBreakpointDelete(msg) if has_key(s:breakpoints, id) for [subid, entry] in items(s:breakpoints[id]) if has_key(entry, 'placed') - exe 'sign unplace ' . s:Breakpoint2SignNumber(id, subid) - unlet entry['placed'] + exe 'sign unplace ' . s:Breakpoint2SignNumber(id, subid) + unlet entry['placed'] endif endfor unlet s:breakpoints[id] + echomsg 'Breakpoint ' . id . ' cleared.' endif endfunc @@ -1396,7 +1471,7 @@ func s:BufRead() for [id, entries] in items(s:breakpoints) for [subid, entry] in items(entries) if entry['fname'] == fname - call s:PlaceSign(id, subid, entry) + call s:PlaceSign(id, subid, entry) endif endfor endfor @@ -1408,7 +1483,7 @@ func s:BufUnloaded() for [id, entries] in items(s:breakpoints) for [subid, entry] in items(entries) if entry['fname'] == fname - let entry['placed'] = 0 + let entry['placed'] = 0 endif endfor endfor diff --git a/runtime/rgb.txt b/runtime/rgb.txt deleted file mode 100644 index 5bc2baa3d6..0000000000 --- a/runtime/rgb.txt +++ /dev/null @@ -1,753 +0,0 @@ -! $XConsortium: rgb.txt,v 10.41 94/02/20 18:39:36 rws Exp $ -255 250 250 snow -248 248 255 ghost white -248 248 255 GhostWhite -245 245 245 white smoke -245 245 245 WhiteSmoke -220 220 220 gainsboro -255 250 240 floral white -255 250 240 FloralWhite -253 245 230 old lace -253 245 230 OldLace -250 240 230 linen -250 235 215 antique white -250 235 215 AntiqueWhite -255 239 213 papaya whip -255 239 213 PapayaWhip -255 235 205 blanched almond -255 235 205 BlanchedAlmond -255 228 196 bisque -255 218 185 peach puff -255 218 185 PeachPuff -255 222 173 navajo white -255 222 173 NavajoWhite -255 228 181 moccasin -255 248 220 cornsilk -255 255 240 ivory -255 250 205 lemon chiffon -255 250 205 LemonChiffon -255 245 238 seashell -240 255 240 honeydew -245 255 250 mint cream -245 255 250 MintCream -240 255 255 azure -240 248 255 alice blue -240 248 255 AliceBlue -230 230 250 lavender -255 240 245 lavender blush -255 240 245 LavenderBlush -255 228 225 misty rose -255 228 225 MistyRose -255 255 255 white - 0 0 0 black - 47 79 79 dark slate gray - 47 79 79 DarkSlateGray - 47 79 79 dark slate grey - 47 79 79 DarkSlateGrey -105 105 105 dim gray -105 105 105 DimGray -105 105 105 dim grey -105 105 105 DimGrey -112 128 144 slate gray -112 128 144 SlateGray -112 128 144 slate grey -112 128 144 SlateGrey -119 136 153 light slate gray -119 136 153 LightSlateGray -119 136 153 light slate grey -119 136 153 LightSlateGrey -190 190 190 gray -190 190 190 grey -211 211 211 light grey -211 211 211 LightGrey -211 211 211 light gray -211 211 211 LightGray - 25 25 112 midnight blue - 25 25 112 MidnightBlue - 0 0 128 navy - 0 0 128 navy blue - 0 0 128 NavyBlue -100 149 237 cornflower blue -100 149 237 CornflowerBlue - 72 61 139 dark slate blue - 72 61 139 DarkSlateBlue -106 90 205 slate blue -106 90 205 SlateBlue -123 104 238 medium slate blue -123 104 238 MediumSlateBlue -132 112 255 light slate blue -132 112 255 LightSlateBlue - 0 0 205 medium blue - 0 0 205 MediumBlue - 65 105 225 royal blue - 65 105 225 RoyalBlue - 0 0 255 blue - 30 144 255 dodger blue - 30 144 255 DodgerBlue - 0 191 255 deep sky blue - 0 191 255 DeepSkyBlue -135 206 235 sky blue -135 206 235 SkyBlue -135 206 250 light sky blue -135 206 250 LightSkyBlue - 70 130 180 steel blue - 70 130 180 SteelBlue -176 196 222 light steel blue -176 196 222 LightSteelBlue -173 216 230 light blue -173 216 230 LightBlue -176 224 230 powder blue -176 224 230 PowderBlue -175 238 238 pale turquoise -175 238 238 PaleTurquoise - 0 206 209 dark turquoise - 0 206 209 DarkTurquoise - 72 209 204 medium turquoise - 72 209 204 MediumTurquoise - 64 224 208 turquoise - 0 255 255 cyan -224 255 255 light cyan -224 255 255 LightCyan - 95 158 160 cadet blue - 95 158 160 CadetBlue -102 205 170 medium aquamarine -102 205 170 MediumAquamarine -127 255 212 aquamarine - 0 100 0 dark green - 0 100 0 DarkGreen - 85 107 47 dark olive green - 85 107 47 DarkOliveGreen -143 188 143 dark sea green -143 188 143 DarkSeaGreen - 46 139 87 sea green - 46 139 87 SeaGreen - 60 179 113 medium sea green - 60 179 113 MediumSeaGreen - 32 178 170 light sea green - 32 178 170 LightSeaGreen -152 251 152 pale green -152 251 152 PaleGreen - 0 255 127 spring green - 0 255 127 SpringGreen -124 252 0 lawn green -124 252 0 LawnGreen - 0 255 0 green -127 255 0 chartreuse - 0 250 154 medium spring green - 0 250 154 MediumSpringGreen -173 255 47 green yellow -173 255 47 GreenYellow - 50 205 50 lime green - 50 205 50 LimeGreen -154 205 50 yellow green -154 205 50 YellowGreen - 34 139 34 forest green - 34 139 34 ForestGreen -107 142 35 olive drab -107 142 35 OliveDrab -189 183 107 dark khaki -189 183 107 DarkKhaki -240 230 140 khaki -238 232 170 pale goldenrod -238 232 170 PaleGoldenrod -250 250 210 light goldenrod yellow -250 250 210 LightGoldenrodYellow -255 255 224 light yellow -255 255 224 LightYellow -255 255 0 yellow -255 215 0 gold -238 221 130 light goldenrod -238 221 130 LightGoldenrod -218 165 32 goldenrod -184 134 11 dark goldenrod -184 134 11 DarkGoldenrod -188 143 143 rosy brown -188 143 143 RosyBrown -205 92 92 indian red -205 92 92 IndianRed -139 69 19 saddle brown -139 69 19 SaddleBrown -160 82 45 sienna -205 133 63 peru -222 184 135 burlywood -245 245 220 beige -245 222 179 wheat -244 164 96 sandy brown -244 164 96 SandyBrown -210 180 140 tan -210 105 30 chocolate -178 34 34 firebrick -165 42 42 brown -233 150 122 dark salmon -233 150 122 DarkSalmon -250 128 114 salmon -255 160 122 light salmon -255 160 122 LightSalmon -255 165 0 orange -255 140 0 dark orange -255 140 0 DarkOrange -255 127 80 coral -240 128 128 light coral -240 128 128 LightCoral -255 99 71 tomato -255 69 0 orange red -255 69 0 OrangeRed -255 0 0 red -255 105 180 hot pink -255 105 180 HotPink -255 20 147 deep pink -255 20 147 DeepPink -255 192 203 pink -255 182 193 light pink -255 182 193 LightPink -219 112 147 pale violet red -219 112 147 PaleVioletRed -176 48 96 maroon -199 21 133 medium violet red -199 21 133 MediumVioletRed -208 32 144 violet red -208 32 144 VioletRed -255 0 255 magenta -238 130 238 violet -221 160 221 plum -218 112 214 orchid -186 85 211 medium orchid -186 85 211 MediumOrchid -153 50 204 dark orchid -153 50 204 DarkOrchid -148 0 211 dark violet -148 0 211 DarkViolet -138 43 226 blue violet -138 43 226 BlueViolet -160 32 240 purple -147 112 219 medium purple -147 112 219 MediumPurple -216 191 216 thistle -255 250 250 snow1 -238 233 233 snow2 -205 201 201 snow3 -139 137 137 snow4 -255 245 238 seashell1 -238 229 222 seashell2 -205 197 191 seashell3 -139 134 130 seashell4 -255 239 219 AntiqueWhite1 -238 223 204 AntiqueWhite2 -205 192 176 AntiqueWhite3 -139 131 120 AntiqueWhite4 -255 228 196 bisque1 -238 213 183 bisque2 -205 183 158 bisque3 -139 125 107 bisque4 -255 218 185 PeachPuff1 -238 203 173 PeachPuff2 -205 175 149 PeachPuff3 -139 119 101 PeachPuff4 -255 222 173 NavajoWhite1 -238 207 161 NavajoWhite2 -205 179 139 NavajoWhite3 -139 121 94 NavajoWhite4 -255 250 205 LemonChiffon1 -238 233 191 LemonChiffon2 -205 201 165 LemonChiffon3 -139 137 112 LemonChiffon4 -255 248 220 cornsilk1 -238 232 205 cornsilk2 -205 200 177 cornsilk3 -139 136 120 cornsilk4 -255 255 240 ivory1 -238 238 224 ivory2 -205 205 193 ivory3 -139 139 131 ivory4 -240 255 240 honeydew1 -224 238 224 honeydew2 -193 205 193 honeydew3 -131 139 131 honeydew4 -255 240 245 LavenderBlush1 -238 224 229 LavenderBlush2 -205 193 197 LavenderBlush3 -139 131 134 LavenderBlush4 -255 228 225 MistyRose1 -238 213 210 MistyRose2 -205 183 181 MistyRose3 -139 125 123 MistyRose4 -240 255 255 azure1 -224 238 238 azure2 -193 205 205 azure3 -131 139 139 azure4 -131 111 255 SlateBlue1 -122 103 238 SlateBlue2 -105 89 205 SlateBlue3 - 71 60 139 SlateBlue4 - 72 118 255 RoyalBlue1 - 67 110 238 RoyalBlue2 - 58 95 205 RoyalBlue3 - 39 64 139 RoyalBlue4 - 0 0 255 blue1 - 0 0 238 blue2 - 0 0 205 blue3 - 0 0 139 blue4 - 30 144 255 DodgerBlue1 - 28 134 238 DodgerBlue2 - 24 116 205 DodgerBlue3 - 16 78 139 DodgerBlue4 - 99 184 255 SteelBlue1 - 92 172 238 SteelBlue2 - 79 148 205 SteelBlue3 - 54 100 139 SteelBlue4 - 0 191 255 DeepSkyBlue1 - 0 178 238 DeepSkyBlue2 - 0 154 205 DeepSkyBlue3 - 0 104 139 DeepSkyBlue4 -135 206 255 SkyBlue1 -126 192 238 SkyBlue2 -108 166 205 SkyBlue3 - 74 112 139 SkyBlue4 -176 226 255 LightSkyBlue1 -164 211 238 LightSkyBlue2 -141 182 205 LightSkyBlue3 - 96 123 139 LightSkyBlue4 -198 226 255 SlateGray1 -185 211 238 SlateGray2 -159 182 205 SlateGray3 -108 123 139 SlateGray4 -202 225 255 LightSteelBlue1 -188 210 238 LightSteelBlue2 -162 181 205 LightSteelBlue3 -110 123 139 LightSteelBlue4 -191 239 255 LightBlue1 -178 223 238 LightBlue2 -154 192 205 LightBlue3 -104 131 139 LightBlue4 -224 255 255 LightCyan1 -209 238 238 LightCyan2 -180 205 205 LightCyan3 -122 139 139 LightCyan4 -187 255 255 PaleTurquoise1 -174 238 238 PaleTurquoise2 -150 205 205 PaleTurquoise3 -102 139 139 PaleTurquoise4 -152 245 255 CadetBlue1 -142 229 238 CadetBlue2 -122 197 205 CadetBlue3 - 83 134 139 CadetBlue4 - 0 245 255 turquoise1 - 0 229 238 turquoise2 - 0 197 205 turquoise3 - 0 134 139 turquoise4 - 0 255 255 cyan1 - 0 238 238 cyan2 - 0 205 205 cyan3 - 0 139 139 cyan4 -151 255 255 DarkSlateGray1 -141 238 238 DarkSlateGray2 -121 205 205 DarkSlateGray3 - 82 139 139 DarkSlateGray4 -127 255 212 aquamarine1 -118 238 198 aquamarine2 -102 205 170 aquamarine3 - 69 139 116 aquamarine4 -193 255 193 DarkSeaGreen1 -180 238 180 DarkSeaGreen2 -155 205 155 DarkSeaGreen3 -105 139 105 DarkSeaGreen4 - 84 255 159 SeaGreen1 - 78 238 148 SeaGreen2 - 67 205 128 SeaGreen3 - 46 139 87 SeaGreen4 -154 255 154 PaleGreen1 -144 238 144 PaleGreen2 -124 205 124 PaleGreen3 - 84 139 84 PaleGreen4 - 0 255 127 SpringGreen1 - 0 238 118 SpringGreen2 - 0 205 102 SpringGreen3 - 0 139 69 SpringGreen4 - 0 255 0 green1 - 0 238 0 green2 - 0 205 0 green3 - 0 139 0 green4 -127 255 0 chartreuse1 -118 238 0 chartreuse2 -102 205 0 chartreuse3 - 69 139 0 chartreuse4 -192 255 62 OliveDrab1 -179 238 58 OliveDrab2 -154 205 50 OliveDrab3 -105 139 34 OliveDrab4 -202 255 112 DarkOliveGreen1 -188 238 104 DarkOliveGreen2 -162 205 90 DarkOliveGreen3 -110 139 61 DarkOliveGreen4 -255 246 143 khaki1 -238 230 133 khaki2 -205 198 115 khaki3 -139 134 78 khaki4 -255 236 139 LightGoldenrod1 -238 220 130 LightGoldenrod2 -205 190 112 LightGoldenrod3 -139 129 76 LightGoldenrod4 -255 255 224 LightYellow1 -238 238 209 LightYellow2 -205 205 180 LightYellow3 -139 139 122 LightYellow4 -255 255 0 yellow1 -238 238 0 yellow2 -205 205 0 yellow3 -139 139 0 yellow4 -255 215 0 gold1 -238 201 0 gold2 -205 173 0 gold3 -139 117 0 gold4 -255 193 37 goldenrod1 -238 180 34 goldenrod2 -205 155 29 goldenrod3 -139 105 20 goldenrod4 -255 185 15 DarkGoldenrod1 -238 173 14 DarkGoldenrod2 -205 149 12 DarkGoldenrod3 -139 101 8 DarkGoldenrod4 -255 193 193 RosyBrown1 -238 180 180 RosyBrown2 -205 155 155 RosyBrown3 -139 105 105 RosyBrown4 -255 106 106 IndianRed1 -238 99 99 IndianRed2 -205 85 85 IndianRed3 -139 58 58 IndianRed4 -255 130 71 sienna1 -238 121 66 sienna2 -205 104 57 sienna3 -139 71 38 sienna4 -255 211 155 burlywood1 -238 197 145 burlywood2 -205 170 125 burlywood3 -139 115 85 burlywood4 -255 231 186 wheat1 -238 216 174 wheat2 -205 186 150 wheat3 -139 126 102 wheat4 -255 165 79 tan1 -238 154 73 tan2 -205 133 63 tan3 -139 90 43 tan4 -255 127 36 chocolate1 -238 118 33 chocolate2 -205 102 29 chocolate3 -139 69 19 chocolate4 -255 48 48 firebrick1 -238 44 44 firebrick2 -205 38 38 firebrick3 -139 26 26 firebrick4 -255 64 64 brown1 -238 59 59 brown2 -205 51 51 brown3 -139 35 35 brown4 -255 140 105 salmon1 -238 130 98 salmon2 -205 112 84 salmon3 -139 76 57 salmon4 -255 160 122 LightSalmon1 -238 149 114 LightSalmon2 -205 129 98 LightSalmon3 -139 87 66 LightSalmon4 -255 165 0 orange1 -238 154 0 orange2 -205 133 0 orange3 -139 90 0 orange4 -255 127 0 DarkOrange1 -238 118 0 DarkOrange2 -205 102 0 DarkOrange3 -139 69 0 DarkOrange4 -255 114 86 coral1 -238 106 80 coral2 -205 91 69 coral3 -139 62 47 coral4 -255 99 71 tomato1 -238 92 66 tomato2 -205 79 57 tomato3 -139 54 38 tomato4 -255 69 0 OrangeRed1 -238 64 0 OrangeRed2 -205 55 0 OrangeRed3 -139 37 0 OrangeRed4 -255 0 0 red1 -238 0 0 red2 -205 0 0 red3 -139 0 0 red4 -255 20 147 DeepPink1 -238 18 137 DeepPink2 -205 16 118 DeepPink3 -139 10 80 DeepPink4 -255 110 180 HotPink1 -238 106 167 HotPink2 -205 96 144 HotPink3 -139 58 98 HotPink4 -255 181 197 pink1 -238 169 184 pink2 -205 145 158 pink3 -139 99 108 pink4 -255 174 185 LightPink1 -238 162 173 LightPink2 -205 140 149 LightPink3 -139 95 101 LightPink4 -255 130 171 PaleVioletRed1 -238 121 159 PaleVioletRed2 -205 104 137 PaleVioletRed3 -139 71 93 PaleVioletRed4 -255 52 179 maroon1 -238 48 167 maroon2 -205 41 144 maroon3 -139 28 98 maroon4 -255 62 150 VioletRed1 -238 58 140 VioletRed2 -205 50 120 VioletRed3 -139 34 82 VioletRed4 -255 0 255 magenta1 -238 0 238 magenta2 -205 0 205 magenta3 -139 0 139 magenta4 -255 131 250 orchid1 -238 122 233 orchid2 -205 105 201 orchid3 -139 71 137 orchid4 -255 187 255 plum1 -238 174 238 plum2 -205 150 205 plum3 -139 102 139 plum4 -224 102 255 MediumOrchid1 -209 95 238 MediumOrchid2 -180 82 205 MediumOrchid3 -122 55 139 MediumOrchid4 -191 62 255 DarkOrchid1 -178 58 238 DarkOrchid2 -154 50 205 DarkOrchid3 -104 34 139 DarkOrchid4 -155 48 255 purple1 -145 44 238 purple2 -125 38 205 purple3 - 85 26 139 purple4 -171 130 255 MediumPurple1 -159 121 238 MediumPurple2 -137 104 205 MediumPurple3 - 93 71 139 MediumPurple4 -255 225 255 thistle1 -238 210 238 thistle2 -205 181 205 thistle3 -139 123 139 thistle4 - 0 0 0 gray0 - 0 0 0 grey0 - 3 3 3 gray1 - 3 3 3 grey1 - 5 5 5 gray2 - 5 5 5 grey2 - 8 8 8 gray3 - 8 8 8 grey3 - 10 10 10 gray4 - 10 10 10 grey4 - 13 13 13 gray5 - 13 13 13 grey5 - 15 15 15 gray6 - 15 15 15 grey6 - 18 18 18 gray7 - 18 18 18 grey7 - 20 20 20 gray8 - 20 20 20 grey8 - 23 23 23 gray9 - 23 23 23 grey9 - 26 26 26 gray10 - 26 26 26 grey10 - 28 28 28 gray11 - 28 28 28 grey11 - 31 31 31 gray12 - 31 31 31 grey12 - 33 33 33 gray13 - 33 33 33 grey13 - 36 36 36 gray14 - 36 36 36 grey14 - 38 38 38 gray15 - 38 38 38 grey15 - 41 41 41 gray16 - 41 41 41 grey16 - 43 43 43 gray17 - 43 43 43 grey17 - 46 46 46 gray18 - 46 46 46 grey18 - 48 48 48 gray19 - 48 48 48 grey19 - 51 51 51 gray20 - 51 51 51 grey20 - 54 54 54 gray21 - 54 54 54 grey21 - 56 56 56 gray22 - 56 56 56 grey22 - 59 59 59 gray23 - 59 59 59 grey23 - 61 61 61 gray24 - 61 61 61 grey24 - 64 64 64 gray25 - 64 64 64 grey25 - 66 66 66 gray26 - 66 66 66 grey26 - 69 69 69 gray27 - 69 69 69 grey27 - 71 71 71 gray28 - 71 71 71 grey28 - 74 74 74 gray29 - 74 74 74 grey29 - 77 77 77 gray30 - 77 77 77 grey30 - 79 79 79 gray31 - 79 79 79 grey31 - 82 82 82 gray32 - 82 82 82 grey32 - 84 84 84 gray33 - 84 84 84 grey33 - 87 87 87 gray34 - 87 87 87 grey34 - 89 89 89 gray35 - 89 89 89 grey35 - 92 92 92 gray36 - 92 92 92 grey36 - 94 94 94 gray37 - 94 94 94 grey37 - 97 97 97 gray38 - 97 97 97 grey38 - 99 99 99 gray39 - 99 99 99 grey39 -102 102 102 gray40 -102 102 102 grey40 -105 105 105 gray41 -105 105 105 grey41 -107 107 107 gray42 -107 107 107 grey42 -110 110 110 gray43 -110 110 110 grey43 -112 112 112 gray44 -112 112 112 grey44 -115 115 115 gray45 -115 115 115 grey45 -117 117 117 gray46 -117 117 117 grey46 -120 120 120 gray47 -120 120 120 grey47 -122 122 122 gray48 -122 122 122 grey48 -125 125 125 gray49 -125 125 125 grey49 -127 127 127 gray50 -127 127 127 grey50 -130 130 130 gray51 -130 130 130 grey51 -133 133 133 gray52 -133 133 133 grey52 -135 135 135 gray53 -135 135 135 grey53 -138 138 138 gray54 -138 138 138 grey54 -140 140 140 gray55 -140 140 140 grey55 -143 143 143 gray56 -143 143 143 grey56 -145 145 145 gray57 -145 145 145 grey57 -148 148 148 gray58 -148 148 148 grey58 -150 150 150 gray59 -150 150 150 grey59 -153 153 153 gray60 -153 153 153 grey60 -156 156 156 gray61 -156 156 156 grey61 -158 158 158 gray62 -158 158 158 grey62 -161 161 161 gray63 -161 161 161 grey63 -163 163 163 gray64 -163 163 163 grey64 -166 166 166 gray65 -166 166 166 grey65 -168 168 168 gray66 -168 168 168 grey66 -171 171 171 gray67 -171 171 171 grey67 -173 173 173 gray68 -173 173 173 grey68 -176 176 176 gray69 -176 176 176 grey69 -179 179 179 gray70 -179 179 179 grey70 -181 181 181 gray71 -181 181 181 grey71 -184 184 184 gray72 -184 184 184 grey72 -186 186 186 gray73 -186 186 186 grey73 -189 189 189 gray74 -189 189 189 grey74 -191 191 191 gray75 -191 191 191 grey75 -194 194 194 gray76 -194 194 194 grey76 -196 196 196 gray77 -196 196 196 grey77 -199 199 199 gray78 -199 199 199 grey78 -201 201 201 gray79 -201 201 201 grey79 -204 204 204 gray80 -204 204 204 grey80 -207 207 207 gray81 -207 207 207 grey81 -209 209 209 gray82 -209 209 209 grey82 -212 212 212 gray83 -212 212 212 grey83 -214 214 214 gray84 -214 214 214 grey84 -217 217 217 gray85 -217 217 217 grey85 -219 219 219 gray86 -219 219 219 grey86 -222 222 222 gray87 -222 222 222 grey87 -224 224 224 gray88 -224 224 224 grey88 -227 227 227 gray89 -227 227 227 grey89 -229 229 229 gray90 -229 229 229 grey90 -232 232 232 gray91 -232 232 232 grey91 -235 235 235 gray92 -235 235 235 grey92 -237 237 237 gray93 -237 237 237 grey93 -240 240 240 gray94 -240 240 240 grey94 -242 242 242 gray95 -242 242 242 grey95 -245 245 245 gray96 -245 245 245 grey96 -247 247 247 gray97 -247 247 247 grey97 -250 250 250 gray98 -250 250 250 grey98 -252 252 252 gray99 -252 252 252 grey99 -255 255 255 gray100 -255 255 255 grey100 -169 169 169 dark grey -169 169 169 DarkGrey -169 169 169 dark gray -169 169 169 DarkGray -0 0 139 dark blue -0 0 139 DarkBlue -0 139 139 dark cyan -0 139 139 DarkCyan -139 0 139 dark magenta -139 0 139 DarkMagenta -139 0 0 dark red -139 0 0 DarkRed -144 238 144 light green -144 238 144 LightGreen diff --git a/runtime/scripts.vim b/runtime/scripts.vim index 0ff8e49088..3790b1c10f 100644 --- a/runtime/scripts.vim +++ b/runtime/scripts.vim @@ -198,6 +198,10 @@ if s:line1 =~# "^#!" elseif s:name =~# 'fish\>' set ft=fish + " Gforth + elseif s:name =~# 'gforth\>' + set ft=forth + endif unlet s:name diff --git a/runtime/syntax/indent.vim b/runtime/syntax/indent.vim index ddeae67e0d..b2a1a0c85f 100644 --- a/runtime/syntax/indent.vim +++ b/runtime/syntax/indent.vim @@ -1,7 +1,8 @@ " Vim syntax file -" Language: indent(1) configuration file -" Previous Maintainer: Nikolai Weibull <now@bitwi.se> -" Latest Revision: 2010-01-23 +" Language: indent(1) configuration file +" Maintainer: Doug Kearns <dougkearns@gmail.com> +" Previous Maintainer: Nikolai Weibull <now@bitwi.se> +" Last Change: 2021 Nov 17 " indent_is_bsd: If exists, will change somewhat to match BSD implementation " " TODO: is the deny-all (a la lilo.vim nice or no?)... @@ -27,7 +28,7 @@ syn region indentComment start='//' skip='\\$' end='$' \ contains=indentTodo,@Spell if !exists("indent_is_bsd") - syn match indentOptions '-i\|--indentation-level\|-il\|--indent-level' + syn match indentOptions '-i\|--indent-level\|-il\|--indent-label' \ nextgroup=indentNumber skipwhite skipempty endif syn match indentOptions '-\%(bli\|c\%([bl]i\|[dip]\)\=\|di\=\|ip\=\|lc\=\|pp\=i\|sbi\|ts\|-\%(brace-indent\|comment-indentation\|case-brace-indentation\|declaration-comment-column\|continuation-indentation\|case-indentation\|else-endif-column\|line-comments-indentation\|declaration-indentation\|indent-level\|parameter-indentation\|line-length\|comment-line-length\|paren-indentation\|preprocessor-indentation\|struct-brace-indentation\|tab-size\)\)' diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim index f7b5ce0f63..d0272916b9 100644 --- a/runtime/syntax/vim.vim +++ b/runtime/syntax/vim.vim @@ -741,10 +741,10 @@ if g:vimsyn_embed =~# 'P' && filereadable(s:pythonpath) unlet! b:current_syntax syn cluster vimFuncBodyList add=vimPythonRegion exe "syn include @vimPythonScript ".s:pythonpath - VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+py\%[thon][3x]\=\s*<<\s*\z(\S*\)\ze\(\s*#.*\)\=$+ end=+^\z1\ze\(\s*".*\)\=$+ contains=@vimPythonScript - VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+py\%[thon][3x]\=\s*<<\s*$+ end=+\.$+ contains=@vimPythonScript - VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+Py\%[thon]2or3\s*<<\s*\z(\S*\)\ze\(\s*#.*\)\=$+ end=+^\z1\ze\(\s*".*\)\=$+ contains=@vimPythonScript - VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+Py\%[thon]2or3\=\s*<<\s*$+ end=+\.$+ contains=@vimPythonScript + VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+py\%[thon][3x]\=\s*<<\s*\%(trim\s*\)\=\z(\S*\)\ze\(\s*#.*\)\=$+ end=+^\z1\ze\(\s*".*\)\=$+ contains=@vimPythonScript + VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+py\%[thon][3x]\=\s*<<\s*\%(trim\s*\)\=$+ end=+\.$+ contains=@vimPythonScript + VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+Py\%[thon]2or3\s*<<\s*\%(trim\s*\)\=\z(\S*\)\ze\(\s*#.*\)\=$+ end=+^\z1\ze\(\s*".*\)\=$+ contains=@vimPythonScript + VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+Py\%[thon]2or3\=\s*<<\s*\%(trim\s*\)\=$+ end=+\.$+ contains=@vimPythonScript syn cluster vimFuncBodyList add=vimPythonRegion else syn region vimEmbedError start=+py\%[thon]3\=\s*<<\s*\z(.*\)$+ end=+^\z1$+ diff --git a/runtime/tools/check_colors.vim b/runtime/tools/check_colors.vim index 966072c706..85df882d1e 100644 --- a/runtime/tools/check_colors.vim +++ b/runtime/tools/check_colors.vim @@ -226,7 +226,13 @@ fu! Result(err) endif endfu -call Test_check_colors() - -let &cpo = s:save_cpo -unlet s:save_cpo +try + call Test_check_colors() +catch + echohl ErrorMsg + echomsg v:exception + echohl NONE +finally + let &cpo = s:save_cpo + unlet s:save_cpo +endtry diff --git a/scripts/gen_vimdoc.py b/scripts/gen_vimdoc.py index 2d2d46d1bd..89fc14121e 100755 --- a/scripts/gen_vimdoc.py +++ b/scripts/gen_vimdoc.py @@ -162,6 +162,7 @@ CONFIG = { 'buf.lua', 'diagnostic.lua', 'codelens.lua', + 'tagfunc.lua', 'handlers.lua', 'util.lua', 'log.lua', diff --git a/scripts/lintcommit.lua b/scripts/lintcommit.lua index c30a1b10da..0a7da4d4ef 100644 --- a/scripts/lintcommit.lua +++ b/scripts/lintcommit.lua @@ -47,7 +47,7 @@ end local function validate_commit(commit_message) local commit_split = vim.split(commit_message, ":") - -- Return true if the type is vim-patch since most of the normal rules don't + -- Return nil if the type is vim-patch since most of the normal rules don't -- apply. if commit_split[1] == "vim-patch" then return nil diff --git a/src/mpack/object.h b/src/mpack/object.h index 5327e56e18..e69821f9de 100644 --- a/src/mpack/object.h +++ b/src/mpack/object.h @@ -22,7 +22,7 @@ enum { }; /* Storing integer in pointers in undefined behavior according to the C - * standard. Define a union type to accomodate arbitrary user data associated + * standard. Define a union type to accommodate arbitrary user data associated * with nodes(and with requests in rpc.h). */ typedef union { void *p; diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 4076a0d220..718743ed9c 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -535,7 +535,7 @@ end: /// @param channel_id /// @param buffer Buffer handle, or 0 for current buffer /// @param start_row First line index -/// @param start_column Last column +/// @param start_column First column /// @param end_row Last line index /// @param end_column Last column /// @param replacement Array of lines to use as replacement @@ -1246,7 +1246,7 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err) /// If the current window already shows "buffer", the window is not switched /// If a window inside the current tabpage (including a float) already shows the /// buffer One of these windows will be set as current window temporarily. -/// Otherwise a temporary scratch window (calleed the "autocmd window" for +/// Otherwise a temporary scratch window (called the "autocmd window" for /// historical reasons) will be used. /// /// This is useful e.g. to call vimL functions that only work with the current diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 6f1fb15dac..6e25e627b9 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -839,7 +839,7 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start, /// - on_win: called when starting to redraw a specific window. /// ["win", winid, bufnr, topline, botline_guess] /// - on_line: called for each buffer line being redrawn. (The -/// interation with fold lines is subject to change) +/// interaction with fold lines is subject to change) /// ["win", winid, bufnr, row] /// - on_end: called at the end of a redraw cycle /// ["end", tick] diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index c516cedaf4..640144b234 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -390,7 +390,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E FUNC_API_SINCE(4) FUNC_API_FAST { int pflags = 0; - for (size_t i = 0 ; i < flags.size ; i++) { + for (size_t i = 0; i < flags.size; i++) { switch (flags.data[i]) { case 'm': pflags |= kExprFlagsMulti; break; @@ -478,7 +478,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E .capacity = kv_size(colors), .size = kv_size(colors), }; - for (size_t i = 0 ; i < kv_size(colors) ; i++) { + for (size_t i = 0; i < kv_size(colors); i++) { const ParserHighlightChunk chunk = kv_A(colors, i); Array chunk_arr = (Array) { .items = xmalloc(4 * sizeof(chunk_arr.items[0])), diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua index bd30966acf..1daae85c5e 100644 --- a/src/nvim/auevents.lua +++ b/src/nvim/auevents.lua @@ -37,6 +37,7 @@ return { 'CursorHoldI', -- idem, in Insert mode 'CursorMoved', -- cursor was moved 'CursorMovedI', -- cursor was moved in Insert mode + 'DiagnosticChanged', -- diagnostics in a buffer were modified 'DiffUpdated', -- diffs have been updated 'DirChanged', -- directory changed 'EncodingChanged', -- after changing the 'encoding' option @@ -127,6 +128,7 @@ return { -- syntax file nvim_specific = { BufModifiedSet=true, + DiagnosticChanged=true, DirChanged=true, Signal=true, TabClosed=true, diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 88938d5099..f2f4950e58 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1305,7 +1305,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) if (buf == NULL) { // No previous buffer, Try 2'nd approach forward = true; buf = curbuf->b_next; - for (;; ) { + for (;;) { if (buf == NULL) { if (!forward) { // tried both directions break; @@ -1587,7 +1587,7 @@ void do_autochdir(void) if (starting == 0 && curbuf->b_ffname != NULL && vim_chdirfile(curbuf->b_ffname, kCdCauseAuto) == OK) { - post_chdir(kCdScopeGlobal, false); + last_chdir_reason = "autochdir"; shorten_fnames(true); } } @@ -2163,7 +2163,7 @@ int buflist_findpat(const char_u *pattern, const char_u *pattern_end, bool unlis // First try finding a listed buffer. If not found and "unlisted" // is true, try finding an unlisted buffer. find_listed = true; - for (;; ) { + for (;;) { for (attempt = 0; attempt <= 3; attempt++) { // may add '^' and '$' if (toggledollar) { @@ -3511,7 +3511,7 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use // Proceed character by character through the statusline format string // fmt_p is the current position in the input buffer - for (char_u *fmt_p = usefmt; *fmt_p; ) { + for (char_u *fmt_p = usefmt; *fmt_p;) { if (curitem == (int)stl_items_len) { size_t new_len = stl_items_len * 3 / 2; @@ -4407,7 +4407,7 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use // string to find the last character that will fit. trunc_p = out; width = 0; - for (;; ) { + for (;;) { width += ptr2cells(trunc_p); if (width >= maxwidth) { break; @@ -4758,7 +4758,7 @@ void do_arg_all(int count, int forceit, int keep_tabs) if (had_tab > 0) { goto_tabpage_tp(first_tabpage, true, true); } - for (;; ) { + for (;;) { win_T *wpnext = NULL; tpnext = curtab->tp_next; for (win_T *wp = firstwin; wp != NULL; wp = wpnext) { @@ -5009,7 +5009,7 @@ void ex_buffer_all(exarg_T *eap) if (had_tab > 0) { goto_tabpage_tp(first_tabpage, true, true); } - for (;; ) { + for (;;) { tpnext = curtab->tp_next; for (wp = firstwin; wp != NULL; wp = wpnext) { wpnext = wp->w_next; @@ -5020,8 +5020,8 @@ void ex_buffer_all(exarg_T *eap) : wp->w_width != Columns) || (had_tab > 0 && wp != firstwin)) && !ONE_WINDOW - && !(wp->w_closing || - wp->w_buffer->b_locked > 0)) { + && !(wp->w_closing + || wp->w_buffer->b_locked > 0)) { win_close(wp, false); wpnext = firstwin; // just in case an autocommand does // something strange with windows @@ -5138,7 +5138,7 @@ void ex_buffer_all(exarg_T *eap) /* * Close superfluous windows. */ - for (wp = lastwin; open_wins > count; ) { + for (wp = lastwin; open_wins > count;) { r = (buf_hide(wp->w_buffer) || !bufIsChanged(wp->w_buffer) || autowrite(wp->w_buffer, false) == OK); if (!win_valid(wp)) { diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 3d7b03d921..e53b2d1dfa 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -1127,14 +1127,14 @@ typedef struct { /// @{ enum { MENU_INDEX_INVALID = -1, - MENU_INDEX_NORMAL = 0, - MENU_INDEX_VISUAL = 1, - MENU_INDEX_SELECT = 2, - MENU_INDEX_OP_PENDING = 3, - MENU_INDEX_INSERT = 4, - MENU_INDEX_CMDLINE = 5, - MENU_INDEX_TIP = 6, - MENU_MODES = 7, + MENU_INDEX_NORMAL = 0, + MENU_INDEX_VISUAL = 1, + MENU_INDEX_SELECT = 2, + MENU_INDEX_OP_PENDING = 3, + MENU_INDEX_INSERT = 4, + MENU_INDEX_CMDLINE = 5, + MENU_INDEX_TIP = 6, + MENU_MODES = 7, }; typedef struct VimMenu vimmenu_T; diff --git a/src/nvim/change.c b/src/nvim/change.c index 6ec4979dac..ef771125f1 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -625,7 +625,7 @@ void ins_char_bytes(char_u *buf, size_t charlen) } } - char_u *newp = xmalloc((size_t)(linelen + newlen - oldlen)); + char_u *newp = xmalloc(linelen + newlen - oldlen); // Copy bytes before the cursor. if (col > 0) { @@ -1355,7 +1355,7 @@ int open_line(int dir, int flags, int second_line_indent) int c = 0; int off = 0; - for (p = lead_flags; *p != NUL && *p != ':'; ) { + for (p = lead_flags; *p != NUL && *p != ':';) { if (*p == COM_RIGHT || *p == COM_LEFT) { c = *p++; } else if (ascii_isdigit(*p) || *p == '-') { @@ -1841,7 +1841,7 @@ void del_lines(long nlines, bool undo) return; } - for (n = 0; n < nlines; ) { + for (n = 0; n < nlines;) { if (curbuf->b_ml.ml_flags & ML_EMPTY) { // nothing to delete break; } diff --git a/src/nvim/cursor_shape.c b/src/nvim/cursor_shape.c index 644bb2c324..6b0a5dfe12 100644 --- a/src/nvim/cursor_shape.c +++ b/src/nvim/cursor_shape.c @@ -168,7 +168,7 @@ char *parse_shape_opt(int what) } // Parse the part after the colon - for (p = colonp + 1; *p && *p != ','; ) { + for (p = colonp + 1; *p && *p != ',';) { { /* * First handle the ones with a number argument. diff --git a/src/nvim/debugger.c b/src/nvim/debugger.c index 3ac128a20f..b6e35f3047 100644 --- a/src/nvim/debugger.c +++ b/src/nvim/debugger.c @@ -109,7 +109,7 @@ void do_debug(char_u *cmd) smsg(_("cmd: %s"), cmd); } // Repeat getting a command and executing it. - for (;; ) { + for (;;) { msg_scroll = true; need_wait_return = false; // Save the current typeahead buffer and replace it with an empty one. diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 4e03f4761c..1f8acd8c79 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -739,7 +739,7 @@ static int diff_write_buffer(buf_T *buf, diffin_T *din) len = 0; for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) { - for (s = ml_get_buf(buf, lnum, false); *s != NUL; ) { + for (s = ml_get_buf(buf, lnum, false); *s != NUL;) { if (diff_flags & DIFF_ICASE) { char_u cbuf[MB_MAXBYTES + 1]; diff --git a/src/nvim/edit.c b/src/nvim/edit.c index cccb33b792..f171897606 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -4173,7 +4173,7 @@ static int ins_compl_get_exp(pos_T *ini) pos = (compl_direction == FORWARD) ? &last_match_pos : &first_match_pos; // For ^N/^P loop over all the flags/windows/buffers in 'complete' - for (;; ) { + for (;;) { found_new_match = FAIL; set_match_pos = false; @@ -4391,7 +4391,7 @@ static int ins_compl_get_exp(pos_T *ini) p_ws = true; } bool looped_around = false; - for (;; ) { + for (;;) { bool cont_s_ipos = false; msg_silent++; // Don't want messages for wrapscan. @@ -5579,7 +5579,7 @@ int get_literal(void) no_mapping++; // don't map the next key hits cc = 0; i = 0; - for (;; ) { + for (;;) { nc = plain_vgetc(); if (!(State & CMDLINE) && MB_BYTE2LEN_CHECK(nc) == 1) { @@ -6686,7 +6686,7 @@ static void stop_insert(pos_T *end_insert_pos, int esc, int nomove) curwin->w_cursor = *end_insert_pos; check_cursor_col(); // make sure it is not past the line - for (;; ) { + for (;;) { if (gchar_cursor() == NUL && curwin->w_cursor.col > 0) { --curwin->w_cursor.col; } @@ -6877,7 +6877,7 @@ int oneleft(void) // We might get stuck on 'showbreak', skip over it. width = 1; - for (;; ) { + for (;;) { coladvance(v - width); // getviscol() is slow, skip it when 'showbreak' is empty, // 'breakindent' is not set and there are no multi-byte @@ -7211,7 +7211,7 @@ static void replace_join(int off) { int i; - for (i = replace_stack_nr; --i >= 0; ) { + for (i = replace_stack_nr; --i >= 0;) { if (replace_stack[i] == NUL && off-- <= 0) { --replace_stack_nr; memmove(replace_stack + i, replace_stack + i + 1, @@ -7260,7 +7260,7 @@ static void mb_replace_pop_ins(int cc) } // Handle composing chars. - for (;; ) { + for (;;) { c = replace_pop(); if (c == -1) { // stack empty break; @@ -9023,7 +9023,7 @@ static bool ins_tab(void) // correct replace stack. if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) { - for (temp = i; --temp >= 0; ) { + for (temp = i; --temp >= 0;) { replace_join(repl_off); } } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 0123c7265b..d3d0121632 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -1551,7 +1551,7 @@ static const char_u *skip_var_list(const char_u *arg, int *var_count, int *semic if (*arg == '[') { // "[var, var]": find the matching ']'. p = arg; - for (;; ) { + for (;;) { p = skipwhite(p + 1); // skip whites after '[', ';' or ',' s = skip_var_one(p); if (s == p) { @@ -2448,7 +2448,7 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, co // Check whether any of the list items is locked for (ri = tv_list_first(rettv->vval.v_list); - ri != NULL && ll_li != NULL; ) { + ri != NULL && ll_li != NULL;) { if (var_check_lock(TV_LIST_ITEM_TV(ll_li)->v_lock, lp->ll_name, TV_CSTRING)) { return; @@ -2464,7 +2464,7 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, co /* * Assign the List values to the list items. */ - for (ri = tv_list_first(rettv->vval.v_list); ri != NULL; ) { + for (ri = tv_list_first(rettv->vval.v_list); ri != NULL;) { if (op != NULL && *op != '=') { eexe_mod_op(TV_LIST_ITEM_TV(lp->ll_li), TV_LIST_ITEM_TV(ri), op); } else { @@ -2691,7 +2691,7 @@ void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx) xp->xp_context = EXPAND_USER_VARS; if (vim_strpbrk(arg, (char_u *)"\"'+-*/%.=!?~|&$([<>,#") == NULL) { // ":let var1 var2 ...": find last space. - for (p = arg + STRLEN(arg); p >= arg; ) { + for (p = arg + STRLEN(arg); p >= arg;) { xp->xp_pattern = p; MB_PTR_BACK(arg, p); if (ascii_iswhite(*p)) { @@ -3732,7 +3732,7 @@ static int eval5(char_u **arg, typval_T *rettv, int evaluate) /* * Repeat computing, until no '+', '-' or '.' is following. */ - for (;; ) { + for (;;) { op = **arg; if (op != '+' && op != '-' && op != '.') { break; @@ -3907,7 +3907,7 @@ static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string) /* * Repeat computing, until no '*', '/' or '%' is following. */ - for (;; ) { + for (;;) { op = **arg; if (op != '*' && op != '/' && op != '%') { break; @@ -4890,7 +4890,7 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate) rettv->v_type = VAR_STRING; rettv->vval.v_string = name; - for (p = *arg + 1; *p != NUL && *p != '"'; ) { + for (p = *arg + 1; *p != NUL && *p != '"';) { if (*p == '\\') { switch (*++p) { case 'b': @@ -5026,7 +5026,7 @@ static int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate) rettv->v_type = VAR_STRING; rettv->vval.v_string = str; - for (p = *arg + 1; *p != NUL; ) { + for (p = *arg + 1; *p != NUL;) { if (*p == '\'') { if (p[1] != '\'') { break; @@ -6086,7 +6086,7 @@ int assert_equalfile(typval_T *argvars) snprintf((char *)IObuff, IOSIZE, (char *)e_notread, fname2); } else { int64_t linecount = 1; - for (int64_t count = 0; ; count++) { + for (int64_t count = 0;; count++) { const int c1 = fgetc(fd1); const int c2 = fgetc(fd2); if (c1 == EOF) { @@ -6851,7 +6851,7 @@ dict_T *get_win_info(win_T *wp, int16_t tpnr, int16_t winnr) 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); - + tv_dict_add_nr(dict, S_LEN("textoff"), win_col_off(wp)); tv_dict_add_nr(dict, S_LEN("terminal"), bt_terminal(wp->w_buffer)); tv_dict_add_nr(dict, S_LEN("quickfix"), bt_quickfix(wp->w_buffer)); tv_dict_add_nr(dict, S_LEN("loclist"), @@ -7382,7 +7382,7 @@ void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, const typval_T } // Default result is zero == OK. - for (;; ) { + for (;;) { if (lines->v_type == VAR_LIST) { // List argument, get next string. if (li == NULL) { diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 7549ec7ac8..dfadd28ebe 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2663,12 +2663,12 @@ static void f_fnamemodify(typval_T *argvars, typval_T *rettv, FunPtr fptr) char buf[NUMBUFLEN]; const char *fname = tv_get_string_chk(&argvars[0]); const char *const mods = tv_get_string_buf_chk(&argvars[1], buf); - if (fname == NULL) { + if (mods == NULL || fname == NULL) { fname = NULL; - } else if (mods != NULL && *mods != NUL) { + } else { len = strlen(fname); - size_t usedlen = 0; if (*mods != NUL) { + size_t usedlen = 0; (void)modify_fname((char_u *)mods, false, &usedlen, (char_u **)&fname, &fbuf, &len); } @@ -3174,7 +3174,7 @@ static void getchar_common(typval_T *argvars, typval_T *rettv) bool error = false; no_mapping++; - for (;; ) { + for (;;) { // Position the cursor. Needed after a message that ends in a space, // or if event processing caused a redraw. ui_cursor_goto(msg_row, msg_col); @@ -3386,15 +3386,17 @@ static void f_getcompletion(typval_T *argvars, typval_T *rettv, FunPtr fptr) emsg(_(e_invarg)); return; } + const char *pattern = tv_get_string(&argvars[0]); if (strcmp(type, "cmdline") == 0) { - set_one_cmd_context(&xpc, tv_get_string(&argvars[0])); + set_one_cmd_context(&xpc, pattern); xpc.xp_pattern_len = STRLEN(xpc.xp_pattern); + xpc.xp_col = STRLEN(pattern); goto theend; } ExpandInit(&xpc); - xpc.xp_pattern = (char_u *)tv_get_string(&argvars[0]); + xpc.xp_pattern = (char_u *)pattern; xpc.xp_pattern_len = STRLEN(xpc.xp_pattern); xpc.xp_context = cmdcomplete_str_to_type(type); if (xpc.xp_context == EXPAND_NOTHING) { @@ -3447,7 +3449,7 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr) // Numbers of the scope objects (window, tab) we want the working directory // of. A `-1` means to skip this scope, a `0` means the current object. int scope_number[] = { - [kCdScopeWindow ] = 0, // Number of window to look at. + [kCdScopeWindow] = 0, // Number of window to look at. [kCdScopeTabpage] = 0, // Number of tab to look at. }; @@ -3485,11 +3487,6 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } - // If the user didn't specify anything, default to window scope - if (scope == kCdScopeInvalid) { - scope = MIN_CD_SCOPE; - } - // Find the tabpage by number if (scope_number[kCdScopeTabpage] > 0) { tp = find_tabpage(scope_number[kCdScopeTabpage]); @@ -3535,12 +3532,13 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr) case kCdScopeGlobal: if (globaldir) { // `globaldir` is not always set. from = globaldir; - } else if (os_dirname(cwd, MAXPATHL) == FAIL) { // Get the OS CWD. + break; + } + FALLTHROUGH; // In global directory, just need to get OS CWD. + case kCdScopeInvalid: // If called without any arguments, get OS CWD. + if (os_dirname(cwd, MAXPATHL) == FAIL) { from = (char_u *)""; // Return empty string on failure. } - break; - case kCdScopeInvalid: // We should never get here - abort(); } if (from) { @@ -4667,7 +4665,7 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv, FunPtr fptr) // Numbers of the scope objects (window, tab) we want the working directory // of. A `-1` means to skip this scope, a `0` means the current object. int scope_number[] = { - [kCdScopeWindow ] = 0, // Number of window to look at. + [kCdScopeWindow] = 0, // Number of window to look at. [kCdScopeTabpage] = 0, // Number of tab to look at. }; @@ -6182,7 +6180,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, if (regmatch.regprog != NULL) { regmatch.rm_ic = p_ic; - for (;; ) { + for (;;) { if (l != NULL) { if (li == NULL) { match = false; @@ -7727,8 +7725,8 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr) char *const buf = xmallocz(MAXPATHL); char *cpy; - for (;; ) { - for (;; ) { + for (;;) { + for (;;) { len = readlink(p, buf, MAXPATHL); if (len <= 0) { break; @@ -8603,7 +8601,7 @@ long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir clearpos(&firstpos); clearpos(&foundpos); pat = pat3; - for (;; ) { + for (;;) { searchit_arg_T sia; memset(&sia, 0, sizeof(sia)); sia.sa_stop_lnum = lnum_stop; diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index 69732f1a7d..d1275d6512 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -141,7 +141,7 @@ typedef struct { dict_T *v_dict; ///< Dictionary for VAR_DICT, can be NULL. partial_T *v_partial; ///< Closure: function with args. blob_T *v_blob; ///< Blob for VAR_BLOB, can be NULL. - } vval; ///< Actual value. + } vval; ///< Actual value. } typval_T; /// Values for (struct dictvar_S).dv_scope diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 80a22f6f9d..9478a8441b 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -2141,7 +2141,7 @@ void ex_function(exarg_T *eap) } // find extra arguments "range", "dict", "abort" and "closure" - for (;; ) { + for (;;) { p = skipwhite(p); if (STRNCMP(p, "range", 5) == 0) { flags |= FC_RANGE; @@ -2204,7 +2204,7 @@ void ex_function(exarg_T *eap) indent = 2; nesting = 0; - for (;; ) { + for (;;) { if (KeyTyped) { msg_scroll = true; saved_wait_return = false; diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 66e30bdf2b..77944851d2 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -303,7 +303,7 @@ void ex_align(exarg_T *eap) * Now try to move the line as much as possible to * the right. Stop when it moves too far. */ - do{ + do { (void)set_indent(++new_indent, 0); } while (linelen(NULL) <= width); @@ -774,7 +774,7 @@ void ex_retab(exarg_T *eap) col = 0; vcol = 0; did_undo = false; - for (;; ) { + for (;;) { if (ascii_iswhite(ptr[col])) { if (!got_tab && num_spaces == 0) { // First consecutive white-space @@ -2150,7 +2150,7 @@ static int check_readonly(int *forceit, buf_T *buf) if (buf->b_p_ro) { dialog_msg(buff, - _( "'readonly' option is set for \"%s\".\nDo you wish to write anyway?"), + _("'readonly' option is set for \"%s\".\nDo you wish to write anyway?"), buf->b_fname); } else { dialog_msg(buff, @@ -2944,7 +2944,7 @@ void ex_append(exarg_T *eap) State |= LANGMAP; } - for (;; ) { + for (;;) { msg_scroll = TRUE; need_wait_return = false; if (curbuf->b_p_ai) { @@ -3719,7 +3719,7 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout, bool do_buf_event, handle * 4. if subflags.do_all is set, find next match * 5. break if there isn't another match in this line */ - for (;; ) { + for (;;) { SubResult current_match = { .start = { 0, 0 }, .end = { 0, 0 }, @@ -5030,9 +5030,9 @@ int find_help_tags(const char_u *arg, int *num_matches, char_u ***matches, bool // When the string starting with "expr-" and containing '?' and matches // the table, it is taken literally (but ~ is escaped). Otherwise '?' // is recognized as a wildcard. - for (i = (int)ARRAY_SIZE(expr_table); --i >= 0; ) { + for (i = (int)ARRAY_SIZE(expr_table); --i >= 0;) { if (STRCMP(arg + 5, expr_table[i]) == 0) { - for (int si = 0, di = 0; ; si++) { + for (int si = 0, di = 0;; si++) { if (arg[si] == '~') { d[di++] = '\\'; } @@ -5047,7 +5047,7 @@ int find_help_tags(const char_u *arg, int *num_matches, char_u ***matches, bool } else { // Recognize a few exceptions to the rule. Some strings that contain // '*' with "star". Otherwise '*' is recognized as a wildcard. - for (i = (int)ARRAY_SIZE(mtable); --i >= 0; ) { + for (i = (int)ARRAY_SIZE(mtable); --i >= 0;) { if (STRCMP(arg, mtable[i]) == 0) { STRCPY(d, rtable[i]); break; diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 787b3f07b2..449e6f7bf5 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -410,7 +410,7 @@ static void script_dump_profile(FILE *fd) } else { // Keep going till the end of file, so that trailing // continuation lines are listed. - for (int i = 0; ; i++) { + for (int i = 0;; i++) { if (vim_fgets(IObuff, IOSIZE, sfd)) { break; } @@ -2505,7 +2505,7 @@ static char_u *get_one_sourceline(struct source_cookie *sp) // Loop until there is a finished line (or end-of-file). sp->sourcing_lnum++; - for (;; ) { + for (;;) { // make room to read at least 120 (more) characters ga_grow(&ga, 120); buf = (char_u *)ga.ga_data; diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h index 6e5dd144ad..ea899b660b 100644 --- a/src/nvim/ex_cmds_defs.h +++ b/src/nvim/ex_cmds_defs.h @@ -135,10 +135,10 @@ typedef struct { // Flags for the cs_lflags item in cstack_T. enum { - CSL_HAD_LOOP = 1, // just found ":while" or ":for" + CSL_HAD_LOOP = 1, // just found ":while" or ":for" CSL_HAD_ENDLOOP = 2, // just found ":endwhile" or ":endfor" - CSL_HAD_CONT = 4, // just found ":continue" - CSL_HAD_FINA = 8, // just found ":finally" + CSL_HAD_CONT = 4, // just found ":continue" + CSL_HAD_FINA = 8, // just found ":finally" }; /// Arguments used for Ex commands. diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 03d85ea888..024eb0a904 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -433,8 +433,8 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags) if (next_cmdline == NULL && !force_abort && cstack.cs_idx < 0 - && !(getline_is_func && - func_has_abort(real_cookie))) { + && !(getline_is_func + && func_has_abort(real_cookie))) { did_emsg = FALSE; } @@ -819,7 +819,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags) // of interrupts or errors to exceptions, and ensure that no more // commands are executed. if (current_exception) { - void *p = NULL; + char *p = NULL; char_u *saved_sourcing_name; int saved_sourcing_lnum; struct msglist *messages = NULL; @@ -836,7 +836,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags) vim_snprintf((char *)IObuff, IOSIZE, _("E605: Exception not caught: %s"), current_exception->value); - p = vim_strsave(IObuff); + p = (char *)vim_strsave(IObuff); break; case ET_ERROR: messages = current_exception->messages; @@ -2066,7 +2066,7 @@ int parse_command_modifiers(exarg_T *eap, char **errormsg, bool skip_only) eap->save_msg_silent = -1; // Repeat until no more command modifiers are found. - for (;; ) { + for (;;) { while (*eap->cmd == ' ' || *eap->cmd == '\t' || *eap->cmd == ':') { @@ -2716,7 +2716,7 @@ static char_u *find_ucmd(exarg_T *eap, char_u *p, int *full, expand_T *xp, int * * Look for buffer-local user commands first, then global ones. */ gap = &curbuf->b_ucmds; - for (;; ) { + for (;;) { for (j = 0; j < gap->ga_len; ++j) { uc = USER_CMD_GA(gap, j); cp = eap->cmd; @@ -4072,7 +4072,7 @@ static linenr_T get_address(exarg_T *eap, char_u **ptr, cmd_addr_T addr_type, in } } - for (;; ) { + for (;;) { cmd = skipwhite(cmd); if (*cmd != '-' && *cmd != '+' && !ascii_isdigit(*cmd)) { break; @@ -5327,7 +5327,7 @@ static void uc_list(char_u *name, size_t name_len) garray_T *gap = (cmdwin_type != 0 && get_cmdline_type() == NUL) ? &prevwin->w_buffer->b_ucmds : &curbuf->b_ucmds; - for (;; ) { + for (;;) { for (i = 0; i < gap->ga_len; ++i) { cmd = USER_CMD_GA(gap, i); a = cmd->uc_argt; @@ -5714,7 +5714,7 @@ static void ex_delcommand(exarg_T *eap) garray_T *gap; gap = &curbuf->b_ucmds; - for (;; ) { + for (;;) { for (i = 0; i < gap->ga_len; ++i) { cmd = USER_CMD_GA(gap, i); cmp = STRCMP(eap->arg, cmd->uc_name); @@ -6154,12 +6154,12 @@ static void do_ucmd(exarg_T *eap) * Second round: copy result into "buf". */ buf = NULL; - for (;; ) { + for (;;) { p = cmd->uc_rep; // source q = buf; // destination totlen = 0; - for (;; ) { + for (;;) { start = vim_strchr(p, '<'); if (start != NULL) { end = vim_strchr(start + 1, '>'); @@ -6185,7 +6185,7 @@ static void do_ucmd(exarg_T *eap) } } - // break if there no <item> is found + // break if no <item> is found if (start == NULL || end == NULL) { break; } @@ -7754,6 +7754,7 @@ void post_chdir(CdScope scope, bool trigger_dirchanged) abort(); } + last_chdir_reason = NULL; shorten_fnames(true); if (trigger_dirchanged) { @@ -7871,7 +7872,9 @@ static void ex_pwd(exarg_T *eap) #endif if (p_verbose > 0) { char *context = "global"; - if (curwin->w_localdir != NULL) { + if (last_chdir_reason != NULL) { + context = last_chdir_reason; + } else if (curwin->w_localdir != NULL) { context = "window"; } else if (curtab->tp_localdir != NULL) { context = "tabpage"; @@ -8984,8 +8987,8 @@ ssize_t find_cmdline_var(const char_u *src, size_t *usedlen) /// @return an allocated string if a valid match was found. /// Returns NULL if no match was found. "usedlen" then still contains the /// number of characters to skip. -char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnump, - char **errormsg, int *escaped) +char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnump, char **errormsg, + int *escaped) { int i; char_u *s; @@ -9253,7 +9256,7 @@ static char_u *arg_all(void) * first time: compute the total length * second time: concatenate the names */ - for (;; ) { + for (;;) { len = 0; for (idx = 0; idx < ARGCOUNT; ++idx) { p = alist_name(&ARGLIST[idx]); @@ -9316,7 +9319,7 @@ char_u *expand_sfile(char_u *arg) result = vim_strsave(arg); - for (p = result; *p; ) { + for (p = result; *p;) { if (STRNCMP(p, "<sfile>", 7) != 0) { ++p; } else { @@ -9462,7 +9465,7 @@ static void ex_filetype(exarg_T *eap) } // Accept "plugin" and "indent" in any order. - for (;; ) { + for (;;) { if (STRNCMP(arg, "plugin", 6) == 0) { plugin = true; arg = skipwhite(arg + 6); diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index 348a26d723..f60f0ebe98 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -1628,7 +1628,7 @@ void ex_endtry(exarg_T *eap) eap->errmsg = get_end_emsg(cstack); // Find the matching ":try" and report what's missing. idx = cstack->cs_idx; - do{ + do { --idx; } while (idx > 0 && !(cstack->cs_flags[idx] & CSF_TRY)); @@ -2091,7 +2091,7 @@ int has_loop_cmd(char_u *p) int len; // skip modifiers, white space and ':' - for (;; ) { + for (;;) { while (*p == ' ' || *p == '\t' || *p == ':') { ++p; } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 2823cb7567..9cf39802de 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1667,7 +1667,7 @@ static int may_do_command_line_next_incsearch(int firstc, long count, incsearch_ static void command_line_next_histidx(CommandLineState *s, bool next_match) { int j = (int)STRLEN(s->lookfor); - for (;; ) { + for (;;) { // one step backwards if (!next_match) { if (s->hiscnt == hislen) { @@ -2689,7 +2689,7 @@ static void color_expr_cmdline(const CmdlineInfo *const colored_ccline, viml_parser_destroy(&pstate); kv_resize(ret_ccline_colors->colors, kv_size(colors)); size_t prev_end = 0; - for (size_t i = 0 ; i < kv_size(colors) ; i++) { + for (size_t i = 0; i < kv_size(colors); i++) { const ParserHighlightChunk chunk = kv_A(colors, i); assert(chunk.start.col < INT_MAX); assert(chunk.end_col < INT_MAX); @@ -3469,7 +3469,7 @@ static bool cmdline_paste(int regname, bool literally, bool remcr) int len; // Locate start of last word in the cmd buffer. - for (w = ccline.cmdbuff + ccline.cmdpos; w > ccline.cmdbuff; ) { + for (w = ccline.cmdbuff + ccline.cmdpos; w > ccline.cmdbuff;) { len = utf_head_off(ccline.cmdbuff, w - 1) + 1; if (!vim_iswordc(utf_ptr2char(w - len))) { break; @@ -4389,7 +4389,7 @@ static int showmatches(expand_T *xp, int wildmenu) msg_outtrans_long_attr(p + 2, HL_ATTR(HLF_D)); break; } - for (j = maxlen - lastlen; --j >= 0; ) { + for (j = maxlen - lastlen; --j >= 0;) { msg_putchar(' '); } if (xp->xp_context == EXPAND_FILES @@ -4460,7 +4460,7 @@ char_u *sm_gettail(char_u *s, bool eager) char_u *t = s; int had_sep = FALSE; - for (p = s; *p != NUL; ) { + for (p = s; *p != NUL;) { if (vim_ispathsep(*p) #ifdef BACKSLASH_IN_FILENAME && !rem_backslash(p) @@ -5222,7 +5222,7 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file, int ga_init(&ga, (int)sizeof(char *), 10); hashtab_T found_ht; hash_init(&found_ht); - for (s = path; ; s = e) { + for (s = path;; s = e) { e = vim_strchr(s, ENV_SEPCHAR); if (e == NULL) { e = s + STRLEN(s); diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c index 9aa8cc0107..f80a63560c 100644 --- a/src/nvim/ex_session.c +++ b/src/nvim/ex_session.c @@ -345,8 +345,8 @@ static int put_view(FILE *fd, win_T *wp, int add_edit, unsigned *flagp, int curr // Load the file. // if (wp->w_buffer->b_ffname != NULL - && (!bt_nofile(wp->w_buffer) || - wp->w_buffer->terminal)) { + && (!bt_nofile(wp->w_buffer) + || wp->w_buffer->terminal)) { // Editing a file in this buffer: use ":edit file". // This may have side effects! (e.g., compressed or network file). // @@ -431,8 +431,8 @@ static int put_view(FILE *fd, win_T *wp, int add_edit, unsigned *flagp, int curr // if ((*flagp & SSOP_FOLDS) && wp->w_buffer->b_ffname != NULL - && (bt_normal(wp->w_buffer) || - bt_help(wp->w_buffer))) { + && (bt_normal(wp->w_buffer) + || bt_help(wp->w_buffer))) { if (put_folds(fd, wp) == FAIL) { return FAIL; } diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index fe991963a0..5953a574f3 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -605,9 +605,9 @@ char_u *vim_findfile(void *search_ctx_arg) } // upward search loop - for (;; ) { + for (;;) { // downward search loop - for (;; ) { + for (;;) { // check if user user wants to stop the search os_breakcheck(); if (got_int) { @@ -829,7 +829,7 @@ char_u *vim_findfile(void *search_ctx_arg) } else { suf = curbuf->b_p_sua; } - for (;; ) { + for (;;) { // if file exists and we didn't already find it if ((path_with_url((char *)file_path) || (os_path_exists(file_path) @@ -1500,7 +1500,7 @@ char_u *find_file_in_path_option(char_u *ptr, size_t len, int options, int first /* When the file doesn't exist, try adding parts of * 'suffixesadd'. */ buf = suffixes; - for (;; ) { + for (;;) { if ( (os_path_exists(NameBuff) && (find_what == FINDFILE_BOTH @@ -1530,7 +1530,7 @@ char_u *find_file_in_path_option(char_u *ptr, size_t len, int options, int first did_findfile_init = FALSE; } - for (;; ) { + for (;;) { if (did_findfile_init) { file_name = vim_findfile(fdip_search_ctx); if (file_name != NULL) { diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 321d884d9c..c90115d796 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -100,8 +100,8 @@ struct bw_info { char_u bw_rest[CONV_RESTLEN]; // not converted bytes int bw_restlen; // nr of bytes in bw_rest[] int bw_first; // first write call - char_u *bw_conv_buf; // buffer for writing converted chars - int bw_conv_buflen; // size of bw_conv_buf + char_u *bw_conv_buf; // buffer for writing converted chars + size_t bw_conv_buflen; // size of bw_conv_buf int bw_conv_error; // set for conversion error linenr_T bw_conv_error_lnum; // first line with error or zero linenr_T bw_start_lnum; // line number at start of buffer @@ -995,7 +995,7 @@ retry: long tlen; tlen = 0; - for (;; ) { + for (;;) { p = ml_get(read_buf_lnum) + read_buf_col; n = (int)STRLEN(p); if ((int)tlen + n + 1 > size) { @@ -1360,6 +1360,10 @@ retry: u8c += (unsigned)(*--p) << 16; u8c += (unsigned)(*--p) << 24; } + // Replace characters over INT_MAX with Unicode replacement character + if (u8c > INT_MAX) { + u8c = 0xfffd; + } } else { // UTF-8 if (*--p < 0x80) { u8c = *p; @@ -3125,7 +3129,7 @@ nobackup: // If conversion is taking place, we may first pretend to write and check // for conversion errors. Then loop again to write for real. // When not doing conversion this writes for real right away. - for (checking_conversion = true; ; checking_conversion = false) { + for (checking_conversion = true;; checking_conversion = false) { // There is no need to check conversion when: // - there is no conversion // - we make a backup file, that can be restored in case of conversion @@ -4265,8 +4269,8 @@ static char_u *check_for_bom(char_u *p, long size, int *lenp, int flags) len = 4; } else if (flags == (FIO_UCS2 | FIO_ENDIAN_L)) { name = "ucs-2le"; // FF FE - } else if (flags == FIO_ALL || - flags == (FIO_UTF16 | FIO_ENDIAN_L)) { + } else if (flags == FIO_ALL + || flags == (FIO_UTF16 | FIO_ENDIAN_L)) { // utf-16le is preferred, it also works for ucs-2le text name = "utf-16le"; // FF FE } @@ -4811,8 +4815,8 @@ int check_timestamps(int focus) } if (!stuff_empty() || global_busy || !typebuf_typed() - || autocmd_busy || curbuf->b_ro_locked > 0 || - allbuf_lock > 0) { + || autocmd_busy || curbuf->b_ro_locked > 0 + || allbuf_lock > 0) { need_check_timestamps = true; // check later } else { no_wait_return++; @@ -5727,7 +5731,7 @@ long read_eintr(int fd, void *buf, size_t bufsize) { long ret; - for (;; ) { + for (;;) { ret = read(fd, buf, bufsize); if (ret >= 0 || errno != EINTR) { break; diff --git a/src/nvim/fold.c b/src/nvim/fold.c index daf0df9326..4a8be7a31b 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -202,7 +202,7 @@ bool hasFoldingWin(win_T *const win, const linenr_T lnum, linenr_T *const firstp * Recursively search for a fold that contains "lnum". */ garray_T *gap = &win->w_folds; - for (;; ) { + for (;;) { if (!foldFind(gap, lnum_rel, &fp)) { break; } @@ -455,7 +455,7 @@ void foldOpenCursor(void) checkupdate(curwin); if (hasAnyFolding(curwin)) { - for (;; ) { + for (;;) { done = DONE_NOTHING; (void)setManualFold(curwin->w_cursor, true, false, &done); if (!(done & DONE_ACTION)) { @@ -716,7 +716,7 @@ void deleteFold(win_T *const wp, const linenr_T start, const linenr_T end, const garray_T *found_ga = NULL; linenr_T lnum_off = 0; bool use_level = false; - for (;; ) { + for (;;) { if (!foldFind(gap, lnum - lnum_off, &fp)) { break; } @@ -897,7 +897,7 @@ int foldMoveTo(const bool updown, const int dir, const long count) linenr_T lnum_found = curwin->w_cursor.lnum; int level = 0; bool last = false; - for (;; ) { + for (;;) { if (!foldFind(gap, curwin->w_cursor.lnum - lnum_off, &fp)) { if (!updown || gap->ga_len == 0) { break; @@ -1155,7 +1155,7 @@ static int foldLevelWin(win_T *wp, linenr_T lnum) // Recursively search for a fold that contains "lnum". gap = &wp->w_folds; - for (;; ) { + for (;;) { if (!foldFind(gap, lnum_rel, &fp)) { break; } @@ -1265,7 +1265,7 @@ static linenr_T setManualFoldWin(win_T *wp, linenr_T lnum, int opening, int recu * Find the fold, open or close it. */ gap = &wp->w_folds; - for (;; ) { + for (;;) { if (!foldFind(gap, lnum, &fp)) { // If there is a following fold, continue there next time. if (fp != NULL && fp < (fold_T *)gap->ga_data + gap->ga_len) { @@ -1928,7 +1928,7 @@ void foldtext_cleanup(char_u *str) } parseMarker(curwin); - for (s = str; *s != NUL; ) { + for (s = str; *s != NUL;) { size_t len = 0; if (STRNCMP(s, curwin->w_p_fmr, foldstartmarkerlen) == 0) { len = foldstartmarkerlen; @@ -2603,7 +2603,7 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *const gap, const int level, } // delete following folds that end before the current line - for (;; ) { + for (;;) { fp2 = fp + 1; if (fp2 >= (fold_T *)gap->ga_data + gap->ga_len || fp2->fd_top > flp->lnum) { diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 5267b313c7..2f4b59837a 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1453,7 +1453,7 @@ int vgetc(void) } else { mod_mask = 0x0; last_recorded_len = 0; - for (;; ) { // this is done twice if there are modifiers + for (;;) { // this is done twice if there are modifiers bool did_inc = false; if (mod_mask) { // no mapping after modifier has been read no_mapping++; @@ -1793,7 +1793,7 @@ static int vgetorpeek(bool advance) * If a mapped key sequence is found we go back to the start to * try re-mapping. */ - for (;; ) { + for (;;) { /* * os_breakcheck() is slow, don't use it too often when * inside a mapping. But call it each time for typed @@ -1861,8 +1861,8 @@ static int vgetorpeek(bool advance) && State != CONFIRM && !((ctrl_x_mode_not_default() && vim_is_ctrl_x_key(c1)) || ((compl_cont_status & CONT_LOCAL) - && (c1 == Ctrl_N || - c1 == Ctrl_P)))) { + && (c1 == Ctrl_N + || c1 == Ctrl_P)))) { if (c1 == K_SPECIAL) { nolmaplen = 2; } else { @@ -1951,7 +1951,7 @@ static int vgetorpeek(bool advance) * If one of the typed keys cannot be * remapped, skip the entry. */ - for (n = mlen; --n >= 0; ) { + for (n = mlen; --n >= 0;) { if (*s++ & (RM_NONE|RM_ABBR)) { break; } @@ -2550,7 +2550,7 @@ int inchar(char_u *buf, int maxlen, long wait_time) #define DUM_LEN MAXMAPLEN * 3 + 3 char_u dum[DUM_LEN + 1]; - for (;; ) { + for (;;) { len = os_inchar(dum, DUM_LEN, 0L, 0, NULL); if (len == 0 || (len == 1 && dum[0] == 3)) { break; @@ -3599,7 +3599,7 @@ char_u *set_context_in_map_cmd(expand_T *xp, char_u *cmd, char_u *arg, bool forc expand_isabbrev = isabbrev; xp->xp_context = EXPAND_MAPPINGS; expand_buffer = false; - for (;; ) { + for (;;) { if (STRNCMP(arg, "<buffer>", 8) == 0) { expand_buffer = true; arg = skipwhite(arg + 8); @@ -3987,7 +3987,7 @@ char_u *vim_strsave_escape_csi(char_u *p) // 0xc0 -> 0xc3 - 0x80 -> 0xc3 K_SPECIAL KS_SPECIAL KE_FILLER char_u *res = xmalloc(STRLEN(p) * 4 + 1); char_u *d = res; - for (char_u *s = p; *s != NUL; ) { + for (char_u *s = p; *s != NUL;) { if (s[0] == K_SPECIAL && s[1] != NUL && s[2] != NUL) { // Copy special key unmodified. *d++ = *s++; diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 9f0f19024b..7ae7b65702 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -790,6 +790,8 @@ extern char_u *compiled_sys; // directory is not a local directory, globaldir is NULL. EXTERN char_u *globaldir INIT(= NULL); +EXTERN char *last_chdir_reason INIT(= NULL); + // Whether 'keymodel' contains "stopsel" and "startsel". EXTERN bool km_stopsel INIT(= false); EXTERN bool km_startsel INIT(= false); @@ -843,6 +845,7 @@ EXTERN disptick_T display_tick INIT(= 0); // cursor position in Insert mode. EXTERN linenr_T spell_redraw_lnum INIT(= 0); +// uncrustify:off // The error messages that can be shared are included here. // Excluded are errors that are only used once and debugging messages. @@ -851,12 +854,8 @@ EXTERN char e_afterinit[] INIT(= N_("E905: Cannot set this option after startup" 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_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_endif[] INIT(= N_("E171: Missing :endif")); EXTERN char e_endtry[] INIT(= N_("E600: Missing :endtry")); EXTERN char e_endwhile[] INIT(= N_("E170: Missing :endwhile")); @@ -886,10 +885,7 @@ EXTERN char e_channotpty[] INIT(= N_("E904: channel is not a pty")); EXTERN char e_stdiochan2[] INIT(= N_("E905: Couldn't open stdio channel: %s")); EXTERN char e_invstream[] INIT(= N_("E906: invalid stream for channel")); EXTERN char e_invstreamrpc[] INIT(= N_("E906: invalid stream for rpc channel, use 'rpc'")); -EXTERN char e_streamkey[] INIT(= - N_( - "E5210: dict key '%s' already set for buffered stream in channel %" - PRIu64)); +EXTERN char e_streamkey[] INIT(= N_("E5210: dict key '%s' already set for buffered stream in channel %" PRIu64)); EXTERN char e_libcall[] INIT(= N_("E364: Library call failed for \"%s()\"")); EXTERN char e_fsync[] INIT(= N_("E667: Fsync failed: %s")); EXTERN char e_mkdir[] INIT(= N_("E739: Cannot create directory %s: %s")); @@ -940,9 +936,7 @@ EXTERN char e_dictkey[] INIT(= N_("E716: Key not present in Dictionary: \"%s\"") EXTERN char e_listreq[] INIT(= N_("E714: List required")); EXTERN char e_listblobreq[] INIT(= N_("E897: List or Blob required")); EXTERN char e_listdictarg[] INIT(= N_("E712: Argument of %s must be a List or Dictionary")); -EXTERN char e_listdictblobarg[] INIT(= - N_( - "E896: Argument of %s must be a List, Dictionary or Blob")); +EXTERN char e_listdictblobarg[] INIT(= N_("E896: Argument of %s must be a List, Dictionary or Blob")); EXTERN char e_readerrf[] INIT(= N_("E47: Error while reading errorfile")); EXTERN char e_sandbox[] INIT(= N_("E48: Not allowed in sandbox")); EXTERN char e_secure[] INIT(= N_("E523: Not allowed here")); @@ -981,25 +975,21 @@ EXTERN char e_unsupportedoption[] INIT(= N_("E519: Option not supported")); EXTERN char e_fnametoolong[] INIT(= N_("E856: Filename too long")); EXTERN char e_float_as_string[] INIT(= N_("E806: using Float as a String")); -EXTERN char e_autocmd_err[] INIT(=N_("E5500: autocmd has thrown an exception: %s")); -EXTERN char e_cmdmap_err[] INIT(=N_("E5520: <Cmd> mapping must end with <CR>")); -EXTERN char -e_cmdmap_repeated[] INIT(=N_("E5521: <Cmd> mapping must end with <CR> before second <Cmd>")); -EXTERN char e_cmdmap_key[] INIT(=N_("E5522: <Cmd> mapping must not include %s key")); +EXTERN char e_autocmd_err[] INIT(= N_("E5500: autocmd has thrown an exception: %s")); +EXTERN char e_cmdmap_err[] INIT(= N_("E5520: <Cmd> mapping must end with <CR>")); +EXTERN char e_cmdmap_repeated[] INIT(= N_("E5521: <Cmd> mapping must end with <CR> before second <Cmd>")); +EXTERN char e_cmdmap_key[] INIT(= N_("E5522: <Cmd> mapping must not include %s key")); -EXTERN char e_api_error[] INIT(=N_("E5555: API call: %s")); +EXTERN char e_api_error[] INIT(= N_("E5555: API call: %s")); -EXTERN char e_luv_api_disabled[] INIT(=N_("E5560: %s must not be called in a lua loop callback")); +EXTERN char e_luv_api_disabled[] INIT(= N_("E5560: %s must not be called in a lua loop callback")); -EXTERN char e_floatonly[] INIT(=N_( - "E5601: Cannot close window, only floating window would remain")); -EXTERN char e_floatexchange[] INIT(=N_("E5602: Cannot exchange or rotate float")); +EXTERN char e_floatonly[] INIT(= N_("E5601: Cannot close window, only floating window would remain")); +EXTERN char e_floatexchange[] INIT(= N_("E5602: Cannot exchange or rotate float")); EXTERN char e_non_empty_string_required[] INIT(= N_("E1142: Non-empty string required")); -EXTERN char e_cannot_define_autocommands_for_all_events[] INIT(= - N_( - "E1155: Cannot define autocommands for ALL events")); +EXTERN char e_cannot_define_autocommands_for_all_events[] INIT(= N_("E1155: Cannot define autocommands for ALL events")); EXTERN char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM")); EXTERN char bot_top_msg[] INIT(= N_("search hit BOTTOM, continuing at TOP")); @@ -1021,6 +1011,8 @@ EXTERN bool embedded_mode INIT(= false); // Do not start a UI nor read/write to stdio (unless embedding). EXTERN bool headless_mode INIT(= false); +// uncrustify:on + /// Used to track the status of external functions. /// Currently only used for iconv(). typedef enum { diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c index ab3f63c93e..93fcdc55a6 100644 --- a/src/nvim/hardcopy.c +++ b/src/nvim/hardcopy.c @@ -571,7 +571,7 @@ static void prt_header(prt_settings_T *const psettings, const int pagenum, const // Use a negative line number to indicate printing in the top margin. int page_line = 0 - prt_header_height(); mch_print_start_line(true, page_line); - for (char_u *p = tbuf; *p != NUL; ) { + for (char_u *p = tbuf; *p != NUL;) { const int l = utfc_ptr2len(p); assert(l >= 0); if (mch_print_text_out(p, (size_t)l)) { @@ -986,8 +986,7 @@ static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T #define PRT_PS_DEFAULT_DPI (72) // Default user space resolution #define PRT_PS_DEFAULT_FONTSIZE (10) -#define PRT_MEDIASIZE_LEN (sizeof(prt_mediasize) / \ - sizeof(struct prt_mediasize_S)) +#define PRT_MEDIASIZE_LEN ARRAY_SIZE(prt_mediasize) static struct prt_mediasize_S prt_mediasize[] = { @@ -2455,7 +2454,7 @@ static int prt_add_resource(struct prt_ps_resource_S *resource) prt_dsc_textline("BeginDocument", (char *)resource->filename); - for (;; ) { + for (;;) { bytes_read = fread((char *)resource_buffer, sizeof(char_u), sizeof(resource_buffer), fd_resource); if (ferror(fd_resource)) { diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c index 2c44ce380d..6f02ebfb48 100644 --- a/src/nvim/if_cscope.c +++ b/src/nvim/if_cscope.c @@ -557,7 +557,7 @@ static int cs_cnt_matches(size_t idx) int nlines = 0; char *buf = xmalloc(CSREAD_BUFSIZE); - for (;; ) { + for (;;) { errno = 0; if (!fgets(buf, CSREAD_BUFSIZE, csinfo[idx].fr_fp)) { if (errno == EINTR) { @@ -966,7 +966,7 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose, int us qfpos++; // next symbol must be + or - if (strchr(CSQF_FLAGS, *qfpos) == NULL) { - (void)semsg(_("E469: invalid cscopequickfix flag %c for %c"), *qfpos, *(qfpos - 1));; + (void)semsg(_("E469: invalid cscopequickfix flag %c for %c"), *qfpos, *(qfpos - 1)); return FALSE; } diff --git a/src/nvim/lib/kbtree.h b/src/nvim/lib/kbtree.h index 5d9c1095bc..617773a79a 100644 --- a/src/nvim/lib/kbtree.h +++ b/src/nvim/lib/kbtree.h @@ -53,7 +53,7 @@ bool is_internal; \ key_t key[2*T-1]; \ kbnode_##name##_t *ptr[]; \ - } ; \ + }; \ typedef struct { \ kbnode_##name##_t *root; \ int n_keys, n_nodes; \ diff --git a/src/nvim/lib/khash.h b/src/nvim/lib/khash.h index e0faf94db9..e81db43038 100644 --- a/src/nvim/lib/khash.h +++ b/src/nvim/lib/khash.h @@ -459,7 +459,7 @@ static kh_inline khint_t __ac_X31_hash_string(const char *s) { khint_t h = (khint_t)*s; if (h) { - for (++s ; *s; ++s) { h = (h << 5) - h + (uint8_t)*s; } + for (++s; *s; ++s) { h = (h << 5) - h + (uint8_t)*s; } } return h; } @@ -666,7 +666,7 @@ static kh_inline khint_t __ac_Wang_hash(khint_t key) } \ } -// More conenient interfaces +// More convenient interfaces /*! @function @abstract Instantiate a hash set containing integer keys diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index db79e9e7e9..b5553060a1 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -175,13 +175,13 @@ int nlua_str_utfindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL size_t s1_len; const char *s1 = luaL_checklstring(lstate, 1, &s1_len); intptr_t idx; - if (lua_gettop(lstate) >= 2) { + if (lua_isnoneornil(lstate, 2)) { + idx = (intptr_t)s1_len; + } else { idx = luaL_checkinteger(lstate, 2); if (idx < 0 || idx > (intptr_t)s1_len) { return luaL_error(lstate, "index out of range"); } - } else { - idx = (intptr_t)s1_len; } size_t codepoints = 0, codeunits = 0; diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua index 30c7034209..c1a1e7f162 100644 --- a/src/nvim/lua/vim.lua +++ b/src/nvim/lua/vim.lua @@ -323,6 +323,7 @@ end do local validate = vim.validate + --@private local function make_dict_accessor(scope, handle) validate { scope = {scope, 's'}; @@ -422,11 +423,10 @@ end --- --- Without a runtime, writes to :Messages ---@see :help nvim_notify ----@param msg Content of the notification to show to the user ----@param log_level Optional log level ----@param opts Dictionary with optional options (timeout, etc) -function vim.notify(msg, log_level, _opts) - +---@param msg string Content of the notification to show to the user +---@param log_level number|nil enum from vim.log.levels +---@param opts table|nil additional options (timeout, etc) +function vim.notify(msg, log_level, opts) -- luacheck: no unused if log_level == vim.log.levels.ERROR then vim.api.nvim_err_writeln(msg) elseif log_level == vim.log.levels.WARN then @@ -454,7 +454,7 @@ local on_key_cbs = {} --- On each key press, Nvim passes the key char to fn(). |i_CTRL-V| --- If {fn} is nil, it removes the callback for the associated {ns_id} ---@param ns_id number? Namespace ID. If nil or 0, generates and returns a new ---- |nvim_create_namesapce()| id. +--- |nvim_create_namespace()| id. --- ---@return number Namespace id associated with {fn}. Or count of all callbacks ---if on_key() is called without arguments. @@ -580,6 +580,7 @@ function vim._expand_pat(pat, env) end local keys = {} + ---@private local function insert_keys(obj) for k,_ in pairs(obj) do if type(k) == "string" and string.sub(k,1,string.len(match_part)) == match_part then diff --git a/src/nvim/lua/xdiff.c b/src/nvim/lua/xdiff.c index 7eda9b6270..b2e971f9f3 100644 --- a/src/nvim/lua/xdiff.c +++ b/src/nvim/lua/xdiff.c @@ -17,7 +17,7 @@ #include "xdiff/xdiff.h" typedef enum { - kNluaXdiffModeUnified = 0, + kNluaXdiffModeUnified = 0, kNluaXdiffModeOnHunkCB, kNluaXdiffModeLocations, } NluaXdiffMode; diff --git a/src/nvim/mark.c b/src/nvim/mark.c index 51f4ba635f..39f18b333d 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -235,7 +235,7 @@ pos_T *movemark(int count) return (pos_T *)NULL; } - for (;; ) { + for (;;) { if (curwin->w_jumplistidx + count < 0 || curwin->w_jumplistidx + count >= curwin->w_jumplistlen) { return (pos_T *)NULL; diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 12460646ed..42117bc762 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -764,7 +764,7 @@ int utfc_ptr2char(const char_u *p, int *pcc) && p[len] >= 0x80 && utf_composinglike(p, p + len)) { cc = utf_ptr2char(p + len); - for (;; ) { + for (;;) { pcc[i++] = cc; if (i == MAX_MCO) { break; @@ -1322,7 +1322,7 @@ static int utf_strnicmp(const char_u *s1, const char_u *s2, size_t n1, size_t n2 int c1, c2, cdiff; char_u buffer[6]; - for (;; ) { + for (;;) { c1 = utf_safe_read_char_adv(&s1, &n1); c2 = utf_safe_read_char_adv(&s2, &n2); @@ -1933,7 +1933,7 @@ void utf_find_illegal(void) } curwin->w_cursor.coladd = 0; - for (;; ) { + for (;;) { p = get_cursor_pos_ptr(); if (vimconv.vc_type != CONV_NONE) { xfree(tofree); @@ -2363,7 +2363,7 @@ static char_u *iconv_string(const vimconv_T *const vcp, char_u *str, size_t slen from = (char *)str; fromlen = slen; - for (;; ) { + for (;;) { if (len == 0 || ICONV_ERRNO == ICONV_E2BIG) { // Allocate enough room for most conversions. When re-allocating // increase the buffer size. diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c index 2a0ea9a269..3397296b3a 100644 --- a/src/nvim/memfile.c +++ b/src/nvim/memfile.c @@ -505,7 +505,7 @@ bool mf_release_all(void) // Flush as many blocks as possible, only if there is a swapfile. if (mfp->mf_fd >= 0) { - for (bhdr_T *hp = mfp->mf_used_last; hp != NULL; ) { + for (bhdr_T *hp = mfp->mf_used_last; hp != NULL;) { if (!(hp->bh_flags & BH_LOCKED) && (!(hp->bh_flags & BH_DIRTY) || mf_write(mfp, hp) != FAIL)) { diff --git a/src/nvim/memline.c b/src/nvim/memline.c index edab367f02..08202a6d5c 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -407,7 +407,7 @@ void ml_setname(buf_T *buf) */ dirp = p_dir; bool found_existing_dir = false; - for (;; ) { + for (;;) { if (*dirp == NUL) { // tried all directories, fail break; } @@ -504,7 +504,7 @@ void ml_open_file(buf_T *buf) */ dirp = p_dir; bool found_existing_dir = false; - for (;; ) { + for (;;) { if (*dirp == NUL) { break; } @@ -1236,7 +1236,7 @@ void ml_recover(bool checkext) } else if (error) { ++no_wait_return; msg(">>>>>>>>>>>>>"); - emsg(_( "E312: Errors detected while recovering; look for lines starting with ???")); + emsg(_("E312: Errors detected while recovering; look for lines starting with ???")); --no_wait_return; msg(_("See \":help E312\" for more information.")); msg(">>>>>>>>>>>>>"); @@ -2349,7 +2349,7 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b * move some of the pointer into the new block * prepare for updating the parent block */ - for (;; ) { // do this twice when splitting block 1 + for (;;) { // do this twice when splitting block 1 hp_new = ml_new_ptr(mfp); if (hp_new == NULL) { // TODO: try to fix tree return FAIL; @@ -2733,7 +2733,7 @@ linenr_T ml_firstmarked(void) * The search starts with lowest_marked line. This is the last line where * a mark was found, adjusted by inserting/deleting lines. */ - for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; ) { + for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count;) { /* * Find the data block containing the line. * This also fills the stack with the blocks from the root to the data @@ -2775,7 +2775,7 @@ void ml_clearmarked(void) /* * The search starts with line lowest_marked. */ - for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; ) { + for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count;) { /* * Find the data block containing the line. * This also fills the stack with the blocks from the root to the data @@ -3034,7 +3034,7 @@ static bhdr_T *ml_find_line(buf_T *buf, linenr_T lnum, int action) /* * search downwards in the tree until a data block is found */ - for (;; ) { + for (;;) { if ((hp = mf_get(mfp, bnum, page_count)) == NULL) { goto error_noblock; } @@ -3211,7 +3211,7 @@ int resolve_symlink(const char_u *fname, char_u *buf) // Put the result so far in tmp[], starting with the original name. STRLCPY(tmp, fname, MAXPATHL); - for (;; ) { + for (;;) { // Limit symlink depth to 100, catch recursive loops. if (++depth == 100) { semsg(_("E773: Symlink loop for \"%s\""), fname); @@ -3481,7 +3481,7 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_ fname = (char *)makeswapname((char_u *)buf_fname, buf->b_ffname, buf, (char_u *)dir_name); - for (;; ) { + for (;;) { if (fname == NULL) { // must be out of memory break; } diff --git a/src/nvim/memory.c b/src/nvim/memory.c index 85140e4c64..3d621ebbb7 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -573,7 +573,6 @@ void free_all_mem(void) return; } entered_free_all_mem = true; - // Don't want to trigger autocommands from here on. block_autocmds(); @@ -673,7 +672,7 @@ void free_all_mem(void) first_tabpage = NULL; // message history - for (;; ) { + for (;;) { if (delete_first_msg() == FAIL) { break; } @@ -688,7 +687,7 @@ void free_all_mem(void) // Must be after eval_clear to avoid it trying to access b:changedtick after // freeing it. p_acd = false; - for (buf = firstbuf; buf != NULL; ) { + for (buf = firstbuf; buf != NULL;) { bufref_T bufref; set_bufref(&bufref, buf); nextbuf = buf->b_next; diff --git a/src/nvim/menu.c b/src/nvim/menu.c index c2b6a5e402..d596b31062 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -80,7 +80,7 @@ void ex_menu(exarg_T *eap) modes = get_menu_cmd_modes((char *)eap->cmd, eap->forceit, &noremap, &unmenu); arg = eap->arg; - for (;; ) { + for (;;) { if (STRNCMP(arg, "<script>", 8) == 0) { noremap = REMAP_SCRIPT; arg = skipwhite(arg + 8); @@ -449,7 +449,7 @@ static int add_menu_path(const char_u *const menu_path, vimmenu_T *menuarg, } if (c != 0) { - menu->strings[i] = xmalloc(STRLEN(call_data) + 5 ); + menu->strings[i] = xmalloc(STRLEN(call_data) + 5); menu->strings[i][0] = c; if (d == 0) { STRCPY(menu->strings[i] + 1, call_data); @@ -1315,7 +1315,7 @@ static char_u *menu_text(const char_u *str, int *mnemonic, char_u **actext) } // Find mnemonic characters "&a" and reduce "&&" to "&". - for (p = text; p != NULL; ) { + for (p = text; p != NULL;) { p = vim_strchr(p, '&'); if (p != NULL) { if (p[1] == NUL) { // trailing "&" diff --git a/src/nvim/message.c b/src/nvim/message.c index 8223e6c188..6fcd4cef8a 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -401,7 +401,7 @@ void trunc_string(char_u *s, char_u *buf, int room_in, int buflen) } len += n; buf[e] = s[e]; - for (n = utfc_ptr2len(s + e); --n > 0; ) { + for (n = utfc_ptr2len(s + e); --n > 0;) { if (++e == buflen) { break; } @@ -883,7 +883,7 @@ char_u *msg_may_trunc(int force, char_u *s) return s; } int n; - for (n = 0; size >= room; ) { + for (n = 0; size >= room;) { size -= utf_ptr2cells(s + n); n += utfc_ptr2len(s + n); } @@ -2549,7 +2549,7 @@ static msgchunk_T *disp_sb_line(int row, msgchunk_T *smp) msgchunk_T *mp = smp; char_u *p; - for (;; ) { + for (;;) { msg_row = row; msg_col = mp->sb_msg_col; p = mp->sb_text; @@ -2688,7 +2688,7 @@ static int do_more_prompt(int typed_char) if (typed_char == NUL) { msg_moremsg(FALSE); } - for (;; ) { + for (;;) { /* * Get a typed character directly from the user. */ @@ -3436,7 +3436,7 @@ int do_dialog(int type, char_u *title, char_u *message, char_u *buttons, int dfl ++no_wait_return; hotkeys = msg_show_console_dialog(message, buttons, dfltbutton); - for (;; ) { + for (;;) { // Get a typed character directly from the user. c = get_keystroke(NULL); switch (c) { diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index 9900a68fac..872a2c58e3 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -99,7 +99,7 @@ int get_leader_len(char_u *line, char_u **flags, bool backward, bool include_spa * scan through the 'comments' option for a match */ found_one = FALSE; - for (list = curbuf->b_p_com; *list; ) { + for (list = curbuf->b_p_com; *list;) { // Get one option part into part_buf[]. Advance "list" to next // one. Put "string" at start of string. if (!got_com && flags != NULL) { @@ -244,7 +244,7 @@ int get_last_leader_offset(char_u *line, char_u **flags) * scan through the 'comments' option for a match */ found_one = FALSE; - for (list = curbuf->b_p_com; *list; ) { + for (list = curbuf->b_p_com; *list;) { char_u *flags_save = list; /* @@ -340,7 +340,7 @@ int get_last_leader_offset(char_u *line, char_u **flags) } len1 = (int)STRLEN(com_leader); - for (list = curbuf->b_p_com; *list; ) { + for (list = curbuf->b_p_com; *list;) { char_u *flags_save = list; (void)copy_option_part(&list, part_buf2, COM_MAX_LEN, ","); @@ -359,7 +359,7 @@ int get_last_leader_offset(char_u *line, char_u **flags) // Now we have to verify whether string ends with a substring // beginning the com_leader. - for (off = (len2 > i ? i : len2); off > 0 && off + len1 > len2; ) { + for (off = (len2 > i ? i : len2); off > 0 && off + len1 > len2;) { --off; if (!STRNCMP(string + off, com_leader, len2 - off)) { if (i - off < lower_check_bound) { @@ -492,7 +492,7 @@ int get_keystroke(MultiQueue *events) int waited = 0; mapped_ctrl_c = 0; // mappings are not used here - for (;; ) { + for (;;) { // flush output before waiting ui_flush(); // Leave some room for check_termcode() to insert a key code into (max @@ -580,7 +580,7 @@ int get_number(int colon, int *mouse_used) } no_mapping++; - for (;; ) { + for (;;) { ui_cursor_goto(msg_row, msg_col); c = safe_vgetc(); if (ascii_isdigit(c)) { diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index f02c000e82..386094e509 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -245,7 +245,7 @@ retnomove: // Scroll by however many rows outside the window we are. if (row < 0) { count = 0; - for (first = true; curwin->w_topline > 1; ) { + for (first = true; curwin->w_topline > 1;) { if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline)) { count++; } else { @@ -270,7 +270,7 @@ retnomove: row = 0; } else if (row >= curwin->w_height_inner) { count = 0; - for (first = true; curwin->w_topline < curbuf->b_ml.ml_line_count; ) { + for (first = true; curwin->w_topline < curbuf->b_ml.ml_line_count;) { if (curwin->w_topfill > 0) { ++count; } else { @@ -448,7 +448,7 @@ win_T *mouse_find_win(int *gridp, int *rowp, int *colp) fp = topframe; *rowp -= firstwin->w_winrow; - for (;; ) { + for (;;) { if (fp->fr_layout == FR_LEAF) { break; } diff --git a/src/nvim/move.c b/src/nvim/move.c index 5114cd6d8a..d80e63e79d 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -382,8 +382,8 @@ static bool check_top_offset(void) topline_back(curwin, &loff); // Stop when included a line above the window. if (loff.lnum < curwin->w_topline - || (loff.lnum == curwin->w_topline && - loff.fill > 0)) { + || (loff.lnum == curwin->w_topline + && loff.fill > 0)) { break; } n += loff.height; @@ -1661,7 +1661,7 @@ void scroll_cursor_bot(int min_scroll, int set_topbot) boff.fill = curwin->w_topfill; boff.lnum = curwin->w_topline - 1; int i; - for (i = 0; i < scrolled && boff.lnum < curwin->w_botline; ) { + for (i = 0; i < scrolled && boff.lnum < curwin->w_botline;) { botline_forw(curwin, &boff); i += boff.height; ++line_count; diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 2ef15bde9b..f2b272a13f 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -571,8 +571,8 @@ static bool normal_need_additional_char(NormalState *s) // // TODO(tarruda): Visual state needs to be refactored into a // separate state that "inherits" from normal state. - || ((cmdchar == 'a' || cmdchar == 'i') && - (pending_op || VIsual_active))); + || ((cmdchar == 'a' || cmdchar == 'i') + && (pending_op || VIsual_active))); } static bool normal_need_redraw_mode_message(NormalState *s) @@ -2286,7 +2286,7 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent) save_cursor = curwin->w_cursor; - for (;; ) { + for (;;) { which_button = get_mouse_button(KEY2TERMCAP1(c), &is_click, &is_drag); if (is_drag) { /* If the next character is the same mouse event then use that @@ -3932,7 +3932,7 @@ bool find_decl(char_u *ptr, size_t len, bool locally, bool thisblock, int flags_ // Search forward for the identifier, ignore comment lines. clearpos(&found_pos); - for (;; ) { + for (;;) { t = searchit(curwin, curbuf, &curwin->w_cursor, NULL, FORWARD, pat, 1L, searchflags, RE_LAST, NULL); if (curwin->w_cursor.lnum >= old_pos.lnum) { @@ -4311,7 +4311,7 @@ static void nv_zet(cmdarg_T *cap) return; } n = nchar - '0'; - for (;; ) { + for (;;) { no_mapping++; nchar = plain_vgetc(); LANGMAP_ADJUST(nchar, true); @@ -5347,8 +5347,8 @@ static void nv_right(cmdarg_T *cap) for (n = cap->count1; n > 0; --n) { if ((!PAST_LINE && oneright() == false) - || (PAST_LINE && - *get_cursor_pos_ptr() == NUL)) { + || (PAST_LINE + && *get_cursor_pos_ptr() == NUL)) { // <Space> wraps to next line if 'whichwrap' has 's'. // 'l' wraps to next line if 'whichwrap' has 'l'. // CURS_RIGHT wraps to next line if 'whichwrap' has '>'. @@ -5844,7 +5844,7 @@ static void nv_brackets(cmdarg_T *cap) pos = NULL; } while (n > 0) { - for (;; ) { + for (;;) { if ((findc == '{' ? dec_cursor() : inc_cursor()) < 0) { // if not found anything, that's an error if (pos == NULL) { @@ -7696,8 +7696,8 @@ static void adjust_cursor(oparg_T *oap) // - 'virtualedit' is not "all" and not "onemore". if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL && (!VIsual_active || *p_sel == 'o') - && !virtual_active() && - (ve_flags & VE_ONEMORE) == 0) { + && !virtual_active() + && (ve_flags & VE_ONEMORE) == 0) { curwin->w_cursor.col--; // prevent cursor from moving on the trail byte mb_adjust_cursor(); diff --git a/src/nvim/ops.c b/src/nvim/ops.c index c2555add50..38de24b8ad 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -378,7 +378,7 @@ static void shift_block(oparg_T *oap, int amount) bd.startspaces = 0; } } - for (; ascii_iswhite(*bd.textstart); ) { + for (; ascii_iswhite(*bd.textstart);) { // TODO: is passing bd.textstart for start of the line OK? incr = lbr_chartabsize_adv(bd.textstart, &bd.textstart, (bd.start_vcol)); total += incr; @@ -2037,7 +2037,7 @@ void op_tilde(oparg_T *oap) did_change = swapchars(oap->op_type, &pos, oap->end.col - pos.col + 1); } else { - for (;; ) { + for (;;) { did_change |= swapchars(oap->op_type, &pos, pos.lnum == oap->end.lnum ? oap->end.col + 1 : (int)STRLEN(ml_get_pos(&pos))); @@ -2162,7 +2162,8 @@ void op_insert(oparg_T *oap, long count1) { long ins_len, pre_textlen = 0; char_u *firstline, *ins_text; - colnr_T ind_pre = 0; + colnr_T ind_pre_col = 0, ind_post_col; + int ind_pre_vcol = 0, ind_post_vcol = 0; struct block_def bd; int i; pos_T t1; @@ -2196,7 +2197,8 @@ void op_insert(oparg_T *oap, long count1) // Get the info about the block before entering the text block_prep(oap, &bd, oap->start.lnum, true); // Get indent information - ind_pre = (colnr_T)getwhitecols_curline(); + ind_pre_col = (colnr_T)getwhitecols_curline(); + ind_pre_vcol = get_indent(); firstline = ml_get(oap->start.lnum) + bd.textcol; if (oap->op_type == OP_APPEND) { @@ -2261,10 +2263,11 @@ void op_insert(oparg_T *oap, long count1) // if indent kicked in, the firstline might have changed // but only do that, if the indent actually increased - const colnr_T ind_post = (colnr_T)getwhitecols_curline(); - if (curbuf->b_op_start.col > ind_pre && ind_post > ind_pre) { - bd.textcol += ind_post - ind_pre; - bd.start_vcol += ind_post - ind_pre; + ind_post_col = (colnr_T)getwhitecols_curline(); + if (curbuf->b_op_start.col > ind_pre_col && ind_post_col > ind_pre_col) { + bd.textcol += ind_post_col - ind_pre_col; + ind_post_vcol = get_indent(); + bd.start_vcol += ind_post_vcol - ind_pre_vcol; did_indent = true; } @@ -2297,12 +2300,26 @@ void op_insert(oparg_T *oap, long count1) } } - /* - * Spaces and tabs in the indent may have changed to other spaces and - * tabs. Get the starting column again and correct the length. - * Don't do this when "$" used, end-of-line will have changed. - */ + // Spaces and tabs in the indent may have changed to other spaces and + // tabs. Get the starting column again and correct the length. + // Don't do this when "$" used, end-of-line will have changed. + // + // if indent was added and the inserted text was after the indent, + // correct the selection for the new indent. + if (did_indent && bd.textcol - ind_post_col > 0) { + oap->start.col += ind_post_col - ind_pre_col; + oap->start_vcol += ind_post_vcol - ind_pre_vcol; + oap->end.col += ind_post_col - ind_pre_col; + oap->end_vcol += ind_post_vcol - ind_pre_vcol; + } block_prep(oap, &bd2, oap->start.lnum, true); + if (did_indent && bd.textcol - ind_post_col > 0) { + // undo for where "oap" is used below + oap->start.col -= ind_post_col - ind_pre_col; + oap->start_vcol -= ind_post_vcol - ind_pre_vcol; + oap->end.col -= ind_post_col - ind_pre_col; + oap->end_vcol -= ind_post_vcol - ind_pre_vcol; + } if (!bd.is_MAX || bd2.textlen < bd.textlen) { if (oap->op_type == OP_APPEND) { pre_textlen += bd2.textlen - bd.textlen; @@ -2988,7 +3005,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) /* For the = register we need to split the string at NL * characters. * Loop twice: count the number of lines and save them. */ - for (;; ) { + for (;;) { y_size = 0; ptr = insert_string; while (ptr != NULL) { @@ -3205,7 +3222,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) // get the old line and advance to the position to insert at oldp = get_cursor_line_ptr(); oldlen = STRLEN(oldp); - for (ptr = oldp; vcol < col && *ptr; ) { + for (ptr = oldp; vcol < col && *ptr;) { // Count a tab for what it's worth (if list mode not on) incr = lbr_chartabsize_adv(oldp, &ptr, vcol); vcol += incr; @@ -3341,6 +3358,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) if (y_type == kMTCharWise && y_size == 1) { linenr_T end_lnum = 0; // init for gcc linenr_T start_lnum = lnum; + int first_byte_off = 0; if (VIsual_active) { end_lnum = curbuf->b_visual.vi_end.lnum; @@ -3387,6 +3405,10 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) } STRMOVE(ptr, oldp + col); ml_replace(lnum, newp, false); + + // compute the byte offset for the last character + first_byte_off = utf_head_off(newp, ptr - 1); + // Place cursor on last putted char. if (lnum == curwin->w_cursor.lnum) { // make sure curwin->w_virtcol is updated @@ -3406,10 +3428,15 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) lnum--; } + // put '] at the first byte of the last character curbuf->b_op_end = curwin->w_cursor; + curbuf->b_op_end.col -= first_byte_off; + // For "CTRL-O p" in Insert mode, put cursor after last char if (totlen && (restart_edit != 0 || (flags & PUT_CURSEND))) { curwin->w_cursor.col++; + } else { + curwin->w_cursor.col -= first_byte_off; } } else { // Insert at least one line. When y_type is kMTCharWise, break the first @@ -3521,12 +3548,13 @@ error: curbuf->b_op_start.lnum, nr_lines, true); } - // put '] mark at last inserted character + // Put the '] mark on the first byte of the last inserted character. + // Correct the length for change in indent. curbuf->b_op_end.lnum = lnum; - // correct length for change in indent col = (colnr_T)STRLEN(y_array[y_size - 1]) - lendiff; if (col > 1) { - curbuf->b_op_end.col = col - 1; + curbuf->b_op_end.col = col - 1 - utf_head_off(y_array[y_size - 1], + y_array[y_size - 1] + col - 1); } else { curbuf->b_op_end.col = 0; } @@ -3937,8 +3965,8 @@ int do_join(size_t count, int insert_space, int save_undo, int use_formatoptions || (utf_ptr2char(curr) < 0x100 && endcurr1 < 0x100)) && (!has_format_option(FO_MBYTE_JOIN2) || (utf_ptr2char(curr) < 0x100 && !utf_eat_space(endcurr1)) - || (endcurr1 < 0x100 && - !utf_eat_space(utf_ptr2char(curr))))) { + || (endcurr1 < 0x100 + && !utf_eat_space(utf_ptr2char(curr))))) { // don't add a space if the line is ending in a space if (endcurr1 == ' ') { endcurr1 = endcurr2; @@ -5632,7 +5660,7 @@ static varnumber_T line_count_info(char_u *line, varnumber_T *wc, varnumber_T *c varnumber_T chars = 0; int is_word = 0; - for (i = 0; i < limit && line[i] != NUL; ) { + for (i = 0; i < limit && line[i] != NUL;) { if (is_word) { if (ascii_isspace(line[i])) { words++; diff --git a/src/nvim/option.c b/src/nvim/option.c index b85649a5cc..45e2032b35 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1233,7 +1233,7 @@ int do_set(char_u *arg, int opt_flags) } errmsg = set_bool_option(opt_idx, varp, (int)value, - opt_flags); + opt_flags); } else { // Numeric or string. if (vim_strchr((const char_u *)"=:&<", nextchar) == NULL || prefix != 1) { @@ -2315,8 +2315,8 @@ static bool valid_spellfile(const char_u *val) /// @param opt_flags OPT_LOCAL and/or OPT_GLOBAL /// @param value_checked value was checked to be safe, no need to set P_INSECURE static char *did_set_string_option(int opt_idx, char_u **varp, bool new_value_alloced, - char_u *oldval, char *errbuf, size_t errbuflen, - int opt_flags, int *value_checked) + char_u *oldval, char *errbuf, size_t errbuflen, int opt_flags, + int *value_checked) { char *errmsg = NULL; char_u *s, *p; @@ -2625,7 +2625,7 @@ ambw_end: } } } else if (gvarp == &p_com) { // 'comments' - for (s = *varp; *s; ) { + for (s = *varp; *s;) { while (*s && *s != ':') { if (vim_strchr((char_u *)COM_ALL, *s) == NULL && !ascii_isdigit(*s) && *s != '-') { @@ -2650,24 +2650,38 @@ ambw_end: } s = skip_to_option_part(s); } - } else if (varp == &p_lcs) { // 'listchars' + } else if (varp == &p_lcs) { // global 'listchars' errmsg = set_chars_option(curwin, varp, false); - if (!errmsg) { + if (errmsg == NULL) { + // The current window is set to use the global 'listchars' value. + // So clear the window-local value. + if (!(opt_flags & OPT_GLOBAL)) { + clear_string_option(&curwin->w_p_lcs); + } FOR_ALL_TAB_WINDOWS(tp, wp) { - set_chars_option(wp, &wp->w_p_lcs, true); + // If no error was returned above, we don't expect an error + // here, so ignore the return value. + (void)set_chars_option(wp, &wp->w_p_lcs, true); } + redraw_all_later(NOT_VALID); } - redraw_all_later(NOT_VALID); } else if (varp == &curwin->w_p_lcs) { // local 'listchars' errmsg = set_chars_option(curwin, varp, true); - } else if (varp == &p_fcs) { // 'fillchars' + } else if (varp == &p_fcs) { // global 'fillchars' errmsg = set_chars_option(curwin, varp, false); - if (!errmsg) { + if (errmsg == NULL) { + // The current window is set to use the global 'fillchars' value. + // So clear the window-local value. + if (!(opt_flags & OPT_GLOBAL)) { + clear_string_option(&curwin->w_p_fcs); + } FOR_ALL_TAB_WINDOWS(tp, wp) { - set_chars_option(wp, &wp->w_p_fcs, true); + // If no error was returned above, we don't expect an error + // here, so ignore the return value. + (void)set_chars_option(wp, &wp->w_p_fcs, true); } + redraw_all_later(NOT_VALID); } - redraw_all_later(NOT_VALID); } else if (varp == &curwin->w_p_fcs) { // local 'fillchars' errmsg = set_chars_option(curwin, varp, true); } else if (varp == &p_cedit) { // 'cedit' @@ -2690,7 +2704,7 @@ ambw_end: // there would be a disconnect between the check for P_ALLOCED at the start // of the function and the set of P_ALLOCED at the end of the function. free_oldval = (options[opt_idx].flags & P_ALLOCED); - for (s = p_shada; *s; ) { + for (s = p_shada; *s;) { // Check it's a valid character if (vim_strchr((char_u *)"!\"%'/:<@cfhnrs", *s) == NULL) { errmsg = illegal_char(errbuf, errbuflen, *s); @@ -2735,7 +2749,7 @@ ambw_end: errmsg = N_("E528: Must specify a ' value"); } } else if (gvarp == &p_sbr) { // 'showbreak' - for (s = *varp; *s; ) { + for (s = *varp; *s;) { if (ptr2cells(s) != 1) { errmsg = N_("E595: 'showbreak' contains unprintable or wide character"); } @@ -2879,7 +2893,7 @@ ambw_end: } } else if (gvarp == &p_cpt) { // check if it is a valid value for 'complete' -- Acevedo - for (s = *varp; *s; ) { + for (s = *varp; *s;) { while (*s == ',' || *s == ' ') { s++; } @@ -3355,7 +3369,7 @@ char *check_colorcolumn(win_T *wp) return NULL; // buffer was closed } - for (s = wp->w_p_cc; *s != NUL && count < 255; ) { + for (s = wp->w_p_cc; *s != NUL && count < 255;) { if (*s == '-' || *s == '+') { // -N and +N: add to 'textwidth' col = (*s == '-') ? -1 : 1; @@ -6804,7 +6818,7 @@ static void langmap_set(void) ga_clear(&langmap_mapga); // clear the previous map first langmap_init(); // back to one-to-one map - for (p = p_langmap; p[0] != NUL; ) { + for (p = p_langmap; p[0] != NUL;) { for (p2 = p; p2[0] != NUL && p2[0] != ',' && p2[0] != ';'; MB_PTR_ADV(p2)) { if (p2[0] == '\\' && p2[1] != NUL) { diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 3ff13c2b3f..e9963516fc 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -369,7 +369,7 @@ static bool is_executable_in_path(const char *name, char **abspath) // is an executable file. char *p = path; bool rv = false; - for (;; ) { + for (;;) { char *e = xstrchrnul(p, ENV_SEPCHAR); // Combine the $PATH segment with `name`. diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c index 10b0d391bf..5b824d23f4 100644 --- a/src/nvim/os/stdpaths.c +++ b/src/nvim/os/stdpaths.c @@ -146,7 +146,7 @@ char *stdpaths_user_data_subpath(const char *fname, const size_t trailing_pathse const size_t numcommas = (escape_commas ? memcnt(ret, ',', len) : 0); if (numcommas || trailing_pathseps) { ret = xrealloc(ret, len + trailing_pathseps + numcommas + 1); - for (size_t i = 0 ; i < len + numcommas ; i++) { + for (size_t i = 0; i < len + numcommas; i++) { if (ret[i] == ',') { memmove(ret + i + 1, ret + i, len - i + numcommas); ret[i] = '\\'; diff --git a/src/nvim/path.c b/src/nvim/path.c index c28d848683..7b9081eafa 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -1079,7 +1079,7 @@ const char *gettail_dir(const char *const fname) const char *next_dir_end = fname; bool look_for_sep = true; - for (const char *p = fname; *p != NUL; ) { + for (const char *p = fname; *p != NUL;) { if (vim_ispathsep(*p)) { if (look_for_sep) { next_dir_end = p; @@ -1289,8 +1289,8 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***fil && !path_is_absolute(p) && !(p[0] == '.' && (vim_ispathsep(p[1]) - || (p[1] == '.' && - vim_ispathsep(p[2]))))) { + || (p[1] == '.' + && vim_ispathsep(p[2]))))) { /* :find completion where 'path' is used. * Recursiveness is OK here. */ recursive = false; @@ -1505,7 +1505,7 @@ void simplify_filename(char_u *filename) if (vim_ispathsep(*p)) { relative = false; - do{ + do { ++p; } while (vim_ispathsep(*p)); @@ -1517,8 +1517,8 @@ void simplify_filename(char_u *filename) * or "p" is at the "start" of the (absolute or relative) path name. */ if (vim_ispathsep(*p)) { STRMOVE(p, p + 1); // remove duplicate "/" - } else if (p[0] == '.' && - (vim_ispathsep(p[1]) || p[1] == NUL)) { + } else if (p[0] == '.' + && (vim_ispathsep(p[1]) || p[1] == NUL)) { if (p == start && relative) { p += 1 + (p[1] != NUL); // keep single "." or leading "./" } else { @@ -2198,7 +2198,7 @@ int match_suffix(char_u *fname) size_t fnamelen = STRLEN(fname); size_t setsuflen = 0; - for (char_u *setsuf = p_su; *setsuf; ) { + for (char_u *setsuf = p_su; *setsuf;) { setsuflen = copy_option_part(&setsuf, suf_buf, MAXSUFLEN, ".,"); if (setsuflen == 0) { char_u *tail = path_tail(fname); @@ -2245,11 +2245,17 @@ int path_full_dir_name(char *directory, char *buffer, size_t len) } if (os_chdir(directory) != SUCCESS) { - // Do not return immediately since we may be in the wrong directory. - retval = FAIL; - } - - if (retval == FAIL || os_dirname((char_u *)buffer, len) == FAIL) { + // Path does not exist (yet). For a full path fail, + // will use the path as-is. For a relative path use + // the current directory and append the file name. + if (path_is_absolute((const char_u *)directory)) { + // Do not return immediately since we may be in the wrong directory. + retval = FAIL; + } else { + xstrlcpy(buffer, old_dir, len); + append_path(buffer, directory, len); + } + } else if (os_dirname((char_u *)buffer, len) == FAIL) { // Do not return immediately since we are in the wrong directory. retval = FAIL; } diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index bf9052de6f..6a192d148f 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -539,7 +539,7 @@ static size_t efm_regpat_bufsz(char_u *efm) size_t sz; sz = (FMT_PATTERNS * 3) + (STRLEN(efm) << 2); - for (int i = FMT_PATTERNS - 1; i >= 0; ) { + for (int i = FMT_PATTERNS - 1; i >= 0;) { sz += STRLEN(fmt_pat[i--].pattern); } #ifdef BACKSLASH_IN_FILENAME @@ -2028,7 +2028,7 @@ void copy_loclist_stack(win_T *from, win_T *to) /// Get buffer number for file "directory/fname". /// Also sets the b_has_qf_entry flag. -static int qf_get_fnum(qf_list_T *qfl, char_u *directory, char_u *fname ) +static int qf_get_fnum(qf_list_T *qfl, char_u *directory, char_u *fname) { char_u *ptr = NULL; char_u *bufname; @@ -4380,7 +4380,7 @@ static char_u *get_mef_name(void) } // Keep trying until the name doesn't exist yet. - for (;; ) { + for (;;) { if (start == -1) { start = (int)os_get_pid(); } else { diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index 14f49d05d5..be365d4ab8 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -479,7 +479,7 @@ RuntimeSearchPath runtime_search_path_build(void) CharVec after_path = KV_INITIAL_VALUE; static char_u buf[MAXPATHL]; - for (char *entry = (char *)p_pp; *entry != NUL; ) { + for (char *entry = (char *)p_pp; *entry != NUL;) { char *cur_entry = entry; copy_option_part((char_u **)&entry, buf, MAXPATHL, ","); @@ -491,7 +491,7 @@ RuntimeSearchPath runtime_search_path_build(void) char *rtp_entry; - for (rtp_entry = (char *)p_rtp; *rtp_entry != NUL; ) { + for (rtp_entry = (char *)p_rtp; *rtp_entry != NUL;) { char *cur_entry = rtp_entry; copy_option_part((char_u **)&rtp_entry, buf, MAXPATHL, ","); size_t buflen = STRLEN(buf); @@ -663,7 +663,7 @@ static int add_pack_dir_to_rtp(char_u *fname, bool is_pack) } const char *insp = NULL; const char *after_insp = NULL; - for (const char *entry = (const char *)p_rtp; *entry != NUL; ) { + for (const char *entry = (const char *)p_rtp; *entry != NUL;) { const char *cur_entry = entry; copy_option_part((char_u **)&entry, buf, MAXPATHL, ","); diff --git a/src/nvim/screen.c b/src/nvim/screen.c index cc3fab3503..2ce2be0bfd 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -1084,7 +1084,7 @@ static void win_update(win_T *wp, Providers *providers) */ bot_start = 0; idx = 0; - for (;; ) { + for (;;) { wp->w_lines[idx] = wp->w_lines[j]; /* stop at line that didn't fit, unless it is still * valid (no lines deleted) */ @@ -1359,7 +1359,7 @@ static void win_update(win_T *wp, Providers *providers) win_check_ns_hl(wp); - for (;; ) { + 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) { @@ -1508,7 +1508,7 @@ static void win_update(win_T *wp, Providers *providers) int x = row + new_rows; // move entries in w_lines[] upwards - for (;; ) { + for (;;) { // stop at last valid entry in w_lines[] if (i >= wp->w_lines_valid) { wp->w_lines_valid = j; @@ -2707,7 +2707,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc int sign_idx = 0; // Repeat for the whole displayed line. - for (;; ) { + for (;;) { int has_match_conc = 0; ///< match wants to conceal bool did_decrement_ptr = false; @@ -4413,8 +4413,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc || filler_todo > 0 || (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL && p_extra != at_end_str) - || (n_extra != 0 && - (c_extra != NUL || *p_extra != NUL)))) { + || (n_extra != 0 + && (c_extra != NUL || *p_extra != NUL)))) { bool wrap = wp->w_p_wrap // Wrapping enabled. && filler_todo <= 0 // Not drawing diff filler lines. && lcs_eol_one != -1 // Haven't printed the lcs_eol character. @@ -5011,8 +5011,8 @@ static int skip_status_match_char(expand_T *xp, char_u *s) if ((rem_backslash(s) && xp->xp_context != EXPAND_HELP) || ((xp->xp_context == EXPAND_MENUS || xp->xp_context == EXPAND_MENUNAMES) - && (s[0] == '\t' || - (s[0] == '\\' && s[1] != NUL)))) { + && (s[0] == '\t' + || (s[0] == '\\' && s[1] != NUL)))) { #ifndef BACKSLASH_IN_FILENAME if (xp->xp_shell && csh_like_shell() && s[1] == '\\' && s[2] == '!') { return 2; @@ -6144,7 +6144,7 @@ static void next_search_hl(win_T *win, match_T *shl, linenr_T lnum, colnr_T minc * or none is found in this line. */ called_emsg = FALSE; - for (;; ) { + for (;;) { // Stop searching after passing the time limit. if (profile_passed_limit(shl->tm)) { shl->lnum = 0; // no match found in time diff --git a/src/nvim/search.c b/src/nvim/search.c index 0756fbf37d..f47315705c 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -370,8 +370,8 @@ int ignorecase_opt(char_u *pat, int ic_in, int scs) { int ic = ic_in; if (ic && !no_smartcase && scs - && !(ctrl_x_mode_not_default() && - curbuf->b_p_inf)) { + && !(ctrl_x_mode_not_default() + && curbuf->b_p_inf)) { ic = !pat_has_uppercase(pat); } no_smartcase = false; @@ -757,7 +757,7 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, * relative to the end of the match. */ match_ok = false; - for (;; ) { + for (;;) { // Remember a position that is before the start // position, we use it if it's the last match in // the line. Always accept a position after @@ -1105,7 +1105,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count, /* * Repeat the search when pattern followed by ';', e.g. "/foo/;?bar". */ - for (;; ) { + for (;;) { bool show_top_bot_msg = false; searchstr = pat; @@ -1465,7 +1465,7 @@ int search_for_exact_line(buf_T *buf, pos_T *pos, Direction dir, char_u *pat) if (buf->b_ml.ml_line_count == 0) { return FAIL; } - for (;; ) { + for (;;) { pos->lnum += dir; if (pos->lnum < 1) { if (p_ws) { @@ -1585,7 +1585,7 @@ int searchc(cmdarg_T *cap, int t_cmd) len = (int)STRLEN(p); while (count--) { - for (;; ) { + for (;;) { if (dir > 0) { col += utfc_ptr2len(p + col); if (col >= len) { @@ -1808,6 +1808,9 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) initc = NUL; } else if (initc != '#' && initc != NUL) { find_mps_values(&initc, &findc, &backwards, true); + if (dir) { + backwards = (dir == FORWARD) ? false : true; + } if (findc == NUL) { return NULL; } @@ -1870,7 +1873,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) if (linep[pos.col] == NUL && pos.col) { --pos.col; } - for (;; ) { + for (;;) { initc = utf_ptr2char(linep + pos.col); if (initc == NUL) { break; @@ -1894,7 +1897,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) // Set "match_escaped" if there are an odd number of // backslashes. - for (col = pos.col; check_prevcol(linep, col, '\\', &col); ) { + for (col = pos.col; check_prevcol(linep, col, '\\', &col);) { bslcnt++; } match_escaped = (bslcnt & 1); @@ -2278,7 +2281,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) int col, bslcnt = 0; if (!cpo_bsl) { - for (col = pos.col; check_prevcol(linep, col, '\\', &col); ) { + for (col = pos.col; check_prevcol(linep, col, '\\', &col);) { bslcnt++; } } @@ -2520,7 +2523,7 @@ int findsent(Direction dir, long count) const int startlnum = pos.lnum; const bool cpo_J = vim_strchr(p_cpo, CPO_ENDOFSENT) != NULL; - for (;; ) { // find end of sentence + for (;;) { // find end of sentence c = gchar_pos(&pos); if (c == NUL || (pos.col == 0 && startPS(pos.lnum, NUL, FALSE))) { if (dir == BACKWARD && pos.lnum != startlnum) { @@ -2530,7 +2533,7 @@ int findsent(Direction dir, long count) } if (c == '.' || c == '!' || c == '?') { tpos = pos; - do{ + do { if ((c = inc(&tpos)) == -1) { break; } @@ -3004,7 +3007,7 @@ static void back_in_line(void) int sclass; // starting class sclass = cls(); - for (;; ) { + for (;;) { if (curwin->w_cursor.col == 0) { // stop at start of line break; } @@ -3427,12 +3430,22 @@ int current_block(oparg_T *oap, long count, int include, int what, int other) // user wants. save_cpo = p_cpo; p_cpo = (char_u *)(vim_strchr(p_cpo, CPO_MATCHBSL) != NULL ? "%M" : "%"); - while (count-- > 0) { - if ((pos = findmatch(NULL, what)) == NULL) { - break; + if ((pos = findmatch(NULL, what)) != NULL) { + while (count-- > 0) { + if ((pos = findmatch(NULL, what)) == NULL) { + break; + } + curwin->w_cursor = *pos; + start_pos = *pos; // the findmatch for end_pos will overwrite *pos + } + } else { + while (count-- > 0) { + if ((pos = findmatchlimit(NULL, what, FM_FORWARD, 0)) == NULL) { + break; + } + curwin->w_cursor = *pos; + start_pos = *pos; // the findmatch for end_pos will overwrite *pos } - curwin->w_cursor = *pos; - start_pos = *pos; // the findmatch for end_pos will overwrite *pos } p_cpo = save_cpo; @@ -3527,7 +3540,7 @@ static bool in_html_tag(bool end_tag) int lc = NUL; pos_T pos; - for (p = line + curwin->w_cursor.col; p > line; ) { + for (p = line + curwin->w_cursor.col; p > line;) { if (*p == '<') { // find '<' under/before cursor break; } @@ -3555,7 +3568,7 @@ static bool in_html_tag(bool end_tag) } // check that the matching '>' is not preceded by '/' - for (;; ) { + for (;;) { if (inc(&pos) < 0) { return false; } @@ -3791,7 +3804,7 @@ extend: } else { dir = FORWARD; } - for (i = count; --i >= 0; ) { + for (i = count; --i >= 0;) { if (start_lnum == (dir == BACKWARD ? 1 : curbuf->b_ml.ml_line_count)) { retval = FAIL; @@ -3806,7 +3819,7 @@ extend: start_lnum -= dir; break; } - for (;; ) { + for (;;) { if (start_lnum == (dir == BACKWARD ? 1 : curbuf->b_ml.ml_line_count)) { break; @@ -3946,7 +3959,7 @@ static int find_next_quote(char_u *line, int col, int quotechar, char_u *escape) { int c; - for (;; ) { + for (;;) { c = line[col]; if (c == NUL) { return -1; @@ -4118,7 +4131,7 @@ bool current_quote(oparg_T *oap, long count, bool include, int quotechar) // Also do this when there is a Visual area, a' may leave the cursor // in between two strings. col_start = 0; - for (;; ) { + for (;;) { // Find open quote character. col_start = find_next_quote(line, col_start, quotechar, NULL); if (col_start < 0 || col_start > first_col) { @@ -4842,7 +4855,7 @@ void find_pattern_in_path(char_u *ptr, Direction dir, size_t len, bool whole, bo } line = ml_get(lnum); - for (;; ) { + for (;;) { if (incl_regmatch.regprog != NULL && vim_regexec(&incl_regmatch, line, (colnr_T)0)) { char_u *p_fname = (curr_fname == curbuf->b_fname) @@ -5235,6 +5248,9 @@ search_line: if (depth == -1) { // match in current file if (l_g_do_tagpreview != 0) { + if (!win_valid(curwin_save)) { + break; + } if (!GETFILE_SUCCESS(getfile(curwin_save->w_buffer->b_fnum, NULL, NULL, true, lnum, false))) { break; // failed to jump to file @@ -5379,7 +5395,7 @@ static void show_pat_in_path(char_u *line, int type, bool did_show, int action, if (got_int) { // 'q' typed at "--more--" message return; } - for (;; ) { + for (;;) { p = line + STRLEN(line) - 1; if (fp != NULL) { // We used fgets(), so get rid of newline at end diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 89f9d3a719..e75a244031 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -3977,7 +3977,7 @@ static bool shada_removable(const char *name) bool retval = false; char *new_name = (char *)home_replace_save(NULL, (char_u *)name); - for (p = (char *)p_shada; *p; ) { + for (p = (char *)p_shada; *p;) { (void)copy_option_part((char_u **)&p, (char_u *)part, ARRAY_SIZE(part), ", "); if (part[0] == 'r') { home_replace(NULL, (char_u *)(part + 1), (char_u *)NameBuff, MAXPATHL, true); diff --git a/src/nvim/sign.c b/src/nvim/sign.c index dfa863d0ff..fca73dc9f2 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -80,7 +80,7 @@ static signgroup_T *sign_group_ref(const char_u *groupname) hi = hash_lookup(&sg_table, (char *)groupname, STRLEN(groupname), hash); if (HASHITEM_EMPTY(hi)) { // new group - group = xmalloc((unsigned)(sizeof(signgroup_T) + STRLEN(groupname))); + group = xmalloc(sizeof(signgroup_T) + STRLEN(groupname)); STRCPY(group->sg_name, groupname); group->sg_refcount = 1; @@ -774,7 +774,7 @@ static int sign_cmd_idx(char_u *begin_cmd, char_u *end_cmd) char_u save = *end_cmd; *end_cmd = (char_u)NUL; - for (idx = 0; ; idx++) { + for (idx = 0;; idx++) { if (cmds[idx] == NULL || STRCMP(begin_cmd, cmds[idx]) == 0) { break; } @@ -816,7 +816,7 @@ static sign_T *alloc_new_sign(char_u *name) // Check that next_sign_typenr is not already being used. // This only happens after wrapping around. Hopefully // another one got deleted and we can use its number. - for (lp = first_sign; lp != NULL; ) { + for (lp = first_sign; lp != NULL;) { if (lp->sn_typenr == next_sign_typenr) { next_sign_typenr++; if (next_sign_typenr == MAX_TYPENR) { diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 20081bce4f..85d1e139bf 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -622,7 +622,7 @@ static void find_word(matchinf_T *mip, int mode) // - there is a byte that doesn't match, // - we reach the end of the tree, // - or we reach the end of the line. - for (;; ) { + for (;;) { if (flen <= 0 && *mip->mi_fend != NUL) { flen = fold_more(mip); } @@ -689,7 +689,7 @@ static void find_word(matchinf_T *mip, int mode) // One space in the good word may stand for several spaces in the // checked word. if (c == ' ') { - for (;; ) { + for (;;) { if (flen <= 0 && *mip->mi_fend != NUL) { flen = fold_more(mip); } @@ -1269,7 +1269,7 @@ static void find_prefix(matchinf_T *mip, int mode) // - there is a byte that doesn't match, // - we reach the end of the tree, // - or we reach the end of the line. - for (;; ) { + for (;;) { if (flen == 0 && *mip->mi_fend != NUL) { flen = fold_more(mip); } @@ -2083,7 +2083,7 @@ char *did_set_spelllang(win_T *wp) wp->w_s->b_cjk = 0; // Loop over comma separated language names. - for (splp = spl_copy; *splp != NUL; ) { + for (splp = spl_copy; *splp != NUL;) { // Get one language name. copy_option_part(&splp, lang, MAXWLEN, ","); region = NULL; @@ -2354,7 +2354,7 @@ static void use_midword(slang_T *lp, win_T *wp) return; } - for (char_u *p = lp->sl_midword; *p != NUL; ) { + for (char_u *p = lp->sl_midword; *p != NUL;) { const int c = utf_ptr2char(p); const int l = utfc_ptr2len(p); if (c < 256 && l <= 2) { @@ -2759,7 +2759,7 @@ int spell_casefold(const win_T *wp, char_u *str, int len, char_u *buf, int bufle int outi = 0; // Fold one character at a time. - for (char_u *p = str; p < str + len; ) { + for (char_u *p = str; p < str + len;) { if (outi + MB_MAXBYTES > buflen) { buf[outi] = NUL; return FAIL; @@ -2806,7 +2806,7 @@ int spell_check_sps(void) sps_flags = 0; sps_limit = 9999; - for (p = p_sps; *p != NUL; ) { + for (p = p_sps; *p != NUL;) { copy_option_part(&p, buf, MAXPATHL, ","); f = 0; @@ -3118,7 +3118,7 @@ static bool check_need_cap(linenr_T lnum, colnr_T col) regmatch.regprog = curwin->w_s->b_cap_prog; regmatch.rm_ic = FALSE; p = line + endcol; - for (;; ) { + for (;;) { MB_PTR_BACK(line, p); if (p == line || spell_iswordp_nmw(p, curwin)) { break; @@ -3330,7 +3330,7 @@ static void spell_find_suggest(char_u *badptr, int badlen, suginfo_T *su, int ma sps_copy = vim_strsave(p_sps); // Loop over the items in 'spellsuggest'. - for (p = sps_copy; *p != NUL; ) { + for (p = sps_copy; *p != NUL;) { copy_option_part(&p, buf, MAXPATHL, ","); if (STRNCMP(buf, "expr:", 5) == 0) { @@ -3557,7 +3557,7 @@ void onecap_copy(char_u *word, char_u *wcopy, bool upper) static void allcap_copy(char_u *word, char_u *wcopy) { char_u *d = wcopy; - for (char_u *s = word; *s != NUL; ) { + for (char_u *s = word; *s != NUL;) { int c = mb_cptr2char_adv((const char_u **)&s); if (c == 0xdf) { @@ -4352,8 +4352,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so // just deleted this byte, accepting it is always cheaper than // delete + substitute. if (c == fword[sp->ts_fidx] - || (sp->ts_tcharlen > 0 && - sp->ts_isdiff != DIFF_NONE)) { + || (sp->ts_tcharlen > 0 + && sp->ts_isdiff != DIFF_NONE)) { newscore = 0; } else { newscore = SCORE_SUBST; @@ -4513,7 +4513,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so // skip over NUL bytes n = sp->ts_arridx; - for (;; ) { + for (;;) { if (sp->ts_curi > byts[n]) { // Only NUL bytes at this node, go to next state. PROF_STORE(sp->ts_state) @@ -5257,7 +5257,7 @@ static int stp_sal_score(suggest_T *stp, suginfo_T *su, slang_T *slang, char_u * // space. if (ascii_iswhite(su->su_badptr[su->su_badlen]) && *skiptowhite(stp->st_word) == NUL) { - for (p = fword; *(p = skiptowhite(p)) != NUL; ) { + for (p = fword; *(p = skiptowhite(p)) != NUL;) { STRMOVE(p, p + 1); } } @@ -5568,7 +5568,7 @@ static int soundfold_find(slang_T *slang, char_u *word) byts = slang->sl_sbyts; idxs = slang->sl_sidxs; - for (;; ) { + for (;;) { // First byte is the number of possible bytes. len = byts[arridx++]; @@ -5701,7 +5701,7 @@ static void add_suggestion(suginfo_T *su, garray_T *gap, const char_u *goodword, // "thee the" is added next to changing the first "the" the "thee". const char_u *pgood = goodword + STRLEN(goodword); char_u *pbad = su->su_badptr + badlenarg; - for (;; ) { + for (;;) { goodlen = (int)(pgood - goodword); badlen = (int)(pbad - su->su_badptr); if (goodlen <= 0 || badlen <= 0) { @@ -6004,7 +6004,7 @@ static void spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res) // The sl_sal_first[] table contains the translation for chars up to // 255, sl_sal the rest. - for (char_u *s = inword; *s != NUL; ) { + for (char_u *s = inword; *s != NUL;) { int c = mb_cptr2char_adv((const char_u **)&s); if (utf_class(c) == 0) { c = ' '; @@ -6015,7 +6015,7 @@ static void spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res) if (ip == NULL) { // empty list, can't match c = NUL; } else { - for (;; ) { // find "c" in the list + for (;;) { // find "c" in the list if (*ip == 0) { // not found c = NUL; break; @@ -6069,7 +6069,7 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) // Remove accents, if wanted. We actually remove all non-word characters. // But keep white space. wordlen = 0; - for (const char_u *s = inword; *s != NUL; ) { + for (const char_u *s = inword; *s != NUL;) { const char_u *t = s; c = mb_cptr2char_adv(&s); if (slang->sl_rem_accents) { @@ -6591,12 +6591,12 @@ static int spell_edit_score(slang_T *slang, char_u *badword, char_u *goodword) // Get the characters from the multi-byte strings and put them in an // int array for easy access. badlen = 0; - for (const char_u *p = badword; *p != NUL; ) { + for (const char_u *p = badword; *p != NUL;) { wbadword[badlen++] = mb_cptr2char_adv(&p); } wbadword[badlen++] = 0; goodlen = 0; - for (const char_u *p = goodword; *p != NUL; ) { + for (const char_u *p = goodword; *p != NUL;) { wgoodword[goodlen++] = mb_cptr2char_adv(&p); } wgoodword[goodlen++] = 0; @@ -6690,12 +6690,12 @@ static int spell_edit_score_limit_w(slang_T *slang, char_u *badword, char_u *goo // Get the characters from the multi-byte strings and put them in an // int array for easy access. bi = 0; - for (const char_u *p = badword; *p != NUL; ) { + for (const char_u *p = badword; *p != NUL;) { wbadword[bi++] = mb_cptr2char_adv(&p); } wbadword[bi++] = 0; gi = 0; - for (const char_u *p = goodword; *p != NUL; ) { + for (const char_u *p = goodword; *p != NUL;) { wgoodword[gi++] = mb_cptr2char_adv(&p); } wgoodword[gi++] = 0; @@ -6713,9 +6713,9 @@ static int spell_edit_score_limit_w(slang_T *slang, char_u *badword, char_u *goo score = 0; minscore = limit + 1; - for (;; ) { + for (;;) { // Skip over an equal part, score remains the same. - for (;; ) { + for (;;) { bc = wbadword[bi]; gc = wgoodword[gi]; @@ -7289,7 +7289,7 @@ int spell_word_start(int startcol) // Find a word character before "startcol". line = get_cursor_line_ptr(); - for (p = line + startcol; p > line; ) { + for (p = line + startcol; p > line;) { MB_PTR_BACK(line, p); if (spell_iswordp_nmw(p, curwin)) { break; diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index 0fc9012f27..ae4514dd30 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -549,7 +549,7 @@ static inline int spell_check_magic_string(FILE *const fd) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE { char buf[VIMSPELLMAGICL]; - SPELL_READ_BYTES(buf, VIMSPELLMAGICL, fd, ; ); + SPELL_READ_BYTES(buf, VIMSPELLMAGICL, fd,; ); if (memcmp(buf, VIMSPELLMAGIC, VIMSPELLMAGICL) != 0) { return SP_FORMERROR; } @@ -640,7 +640,7 @@ slang_T *spell_load_file(char_u *fname, char_u *lang, slang_T *old_lp, bool sile // <SECTIONS>: <section> ... <sectionend> // <section>: <sectionID> <sectionflags> <sectionlen> (section contents) - for (;; ) { + for (;;) { n = getc(fd); // <sectionID> or <sectionend> if (n == SN_END) { break; @@ -960,7 +960,7 @@ someerror: ga_init(&ga, 1, 100); for (wordnr = 0; wordnr < wcount; ++wordnr) { ga.ga_len = 0; - for (;; ) { + for (;;) { c = getc(fd); // <sugline> if (c < 0) { goto someerror; @@ -1030,7 +1030,7 @@ static int read_region_section(FILE *fd, slang_T *lp, int len) if (len > MAXREGIONS * 2) { return SP_FORMERROR; } - SPELL_READ_NONNUL_BYTES((char *)lp->sl_regions, (size_t)len, fd, ; ); + SPELL_READ_NONNUL_BYTES((char *)lp->sl_regions, (size_t)len, fd,; ); lp->sl_regions[len] = NUL; return 0; } @@ -1097,7 +1097,7 @@ static int read_prefcond_section(FILE *fd, slang_T *lp) if (n > 0) { char buf[MAXWLEN + 1]; buf[0] = '^'; // always match at one position only - SPELL_READ_NONNUL_BYTES(buf + 1, (size_t)n, fd, ; ); + SPELL_READ_NONNUL_BYTES(buf + 1, (size_t)n, fd,; ); buf[n + 1] = NUL; lp->sl_prefprog[i] = vim_regcomp((char_u *)buf, RE_MAGIC | RE_STRING); } @@ -1548,7 +1548,7 @@ static int set_sofo(slang_T *lp, char_u *from, char_u *to) // First count the number of items for each list. Temporarily use // sl_sal_first[] for this. - for (p = from, s = to; *p != NUL && *s != NUL; ) { + for (p = from, s = to; *p != NUL && *s != NUL;) { const int c = mb_cptr2char_adv((const char_u **)&p); MB_CPTR_ADV(s); if (c >= 256) { @@ -1571,7 +1571,7 @@ static int set_sofo(slang_T *lp, char_u *from, char_u *to) // Put the characters up to 255 in sl_sal_first[] the rest in a sl_sal // list. memset(lp->sl_sal_first, 0, sizeof(salfirst_T) * 256); - for (p = from, s = to; *p != NUL && *s != NUL; ) { + for (p = from, s = to; *p != NUL && *s != NUL;) { const int c = mb_cptr2char_adv((const char_u **)&p); const int i = mb_cptr2char_adv((const char_u **)&s); if (c >= 256) { @@ -1647,7 +1647,7 @@ static int *mb_str2wide(char_u *s) int i = 0; int *res = xmalloc((mb_charlen(s) + 1) * sizeof(int)); - for (char_u *p = s; *p != NUL; ) { + for (char_u *p = s; *p != NUL;) { res[i++] = mb_ptr2char_adv((const char_u **)&p); } res[i] = NUL; @@ -2095,7 +2095,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) // Split the line up in white separated items. Put a NUL after each // item. itemcnt = 0; - for (p = line;; ) { + for (p = line;;) { while (*p != NUL && *p <= ' ') { // skip white space and CR/NL ++p; } @@ -2646,7 +2646,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) int c; // Check that every character appears only once. - for (p = items[1]; *p != NUL; ) { + for (p = items[1]; *p != NUL;) { c = mb_ptr2char_adv((const char_u **)&p); if ((!GA_EMPTY(&spin->si_map) && vim_strchr(spin->si_map.ga_data, c) @@ -2804,7 +2804,7 @@ static void aff_process_flags(afffile_T *affile, affentry_T *entry) if (entry->ae_flags != NULL && (affile->af_compforbid != 0 || affile->af_comppermit != 0)) { - for (p = entry->ae_flags; *p != NUL; ) { + for (p = entry->ae_flags; *p != NUL;) { prevp = p; flag = get_affitem(affile->af_flagtype, &p); if (flag == affile->af_comppermit || flag == affile->af_compforbid) { @@ -2922,7 +2922,7 @@ static void process_compflags(spellinfo_T *spin, afffile_T *aff, char_u *compfla spin->si_compflags = p; tp = p + STRLEN(p); - for (p = compflags; *p != NUL; ) { + for (p = compflags; *p != NUL;) { if (vim_strchr((char_u *)"/?*+[]", *p) != NULL) { // Copy non-flag characters directly. *tp++ = *p++; @@ -2985,7 +2985,7 @@ static bool flag_in_afflist(int flagtype, char_u *afflist, unsigned flag) case AFT_CAPLONG: case AFT_LONG: - for (p = afflist; *p != NUL; ) { + for (p = afflist; *p != NUL;) { n = mb_ptr2char_adv((const char_u **)&p); if ((flagtype == AFT_LONG || (n >= 'A' && n <= 'Z')) && *p != NUL) { @@ -2998,7 +2998,7 @@ static bool flag_in_afflist(int flagtype, char_u *afflist, unsigned flag) break; case AFT_NUM: - for (p = afflist; *p != NUL; ) { + for (p = afflist; *p != NUL;) { int digits = getdigits_int(&p, true, 0); assert(digits >= 0); n = (unsigned int)digits; @@ -3248,9 +3248,9 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile) // Extract flags from the affix list. flags |= get_affix_flags(affile, afflist); - if (affile->af_needaffix != 0 && - flag_in_afflist(affile->af_flagtype, afflist, - affile->af_needaffix)) { + if (affile->af_needaffix != 0 + && flag_in_afflist(affile->af_flagtype, afflist, + affile->af_needaffix)) { need_affix = true; } @@ -3311,32 +3311,32 @@ static int get_affix_flags(afffile_T *affile, char_u *afflist) { int flags = 0; - if (affile->af_keepcase != 0 && - flag_in_afflist(affile->af_flagtype, afflist, - affile->af_keepcase)) { + if (affile->af_keepcase != 0 + && flag_in_afflist(affile->af_flagtype, afflist, + affile->af_keepcase)) { flags |= WF_KEEPCAP | WF_FIXCAP; } - if (affile->af_rare != 0 && - flag_in_afflist(affile->af_flagtype, afflist, affile->af_rare)) { + if (affile->af_rare != 0 + && flag_in_afflist(affile->af_flagtype, afflist, affile->af_rare)) { flags |= WF_RARE; } - if (affile->af_bad != 0 && - flag_in_afflist(affile->af_flagtype, afflist, affile->af_bad)) { + if (affile->af_bad != 0 + && flag_in_afflist(affile->af_flagtype, afflist, affile->af_bad)) { flags |= WF_BANNED; } - if (affile->af_needcomp != 0 && - flag_in_afflist(affile->af_flagtype, afflist, - affile->af_needcomp)) { + if (affile->af_needcomp != 0 + && flag_in_afflist(affile->af_flagtype, afflist, + affile->af_needcomp)) { flags |= WF_NEEDCOMP; } - if (affile->af_comproot != 0 && - flag_in_afflist(affile->af_flagtype, afflist, - affile->af_comproot)) { + if (affile->af_comproot != 0 + && flag_in_afflist(affile->af_flagtype, afflist, + affile->af_comproot)) { flags |= WF_COMPROOT; } - if (affile->af_nosuggest != 0 && - flag_in_afflist(affile->af_flagtype, afflist, - affile->af_nosuggest)) { + if (affile->af_nosuggest != 0 + && flag_in_afflist(affile->af_flagtype, afflist, + affile->af_nosuggest)) { flags |= WF_NOSUGGEST; } return flags; @@ -3355,7 +3355,7 @@ static int get_pfxlist(afffile_T *affile, char_u *afflist, char_u *store_afflist char_u key[AH_KEY_LEN]; hashitem_T *hi; - for (p = afflist; *p != NUL; ) { + for (p = afflist; *p != NUL;) { prevp = p; if (get_affitem(affile->af_flagtype, &p) != 0) { // A flag is a postponed prefix flag if it appears in "af_pref" @@ -3389,7 +3389,7 @@ static void get_compflags(afffile_T *affile, char_u *afflist, char_u *store_affl char_u key[AH_KEY_LEN]; hashitem_T *hi; - for (p = afflist; *p != NUL; ) { + for (p = afflist; *p != NUL;) { prevp = p; if (get_affitem(affile->af_flagtype, &p) != 0) { // A flag is a compound flag if it appears in "af_comp". @@ -5845,7 +5845,7 @@ static void set_map_str(slang_T *lp, char_u *map) // The similar characters are stored separated with slashes: // "aaa/bbb/ccc/". Fill sl_map_array[c] with the character before c and // before the same slash. For characters above 255 sl_map_hash is used. - for (p = map; *p != NUL; ) { + for (p = map; *p != NUL;) { c = mb_cptr2char_adv((const char_u **)&p); if (c == '/') { headc = 0; diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 47cbf01996..c58e052ae9 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -242,7 +242,7 @@ char_u *vim_strsave_shellescape(const char_u *string, bool do_special, bool do_n #endif *d++ = '\''; - for (const char_u *p = string; *p != NUL; ) { + for (const char_u *p = string; *p != NUL;) { #ifdef WIN32 if (!p_ssl) { if (*p == '"') { @@ -405,7 +405,7 @@ int vim_stricmp(const char *s1, const char *s2) { int i; - for (;; ) { + for (;;) { i = (int)TOLOWER_LOC(*s1) - (int)TOLOWER_LOC(*s2); if (i != 0) { return i; // this character different diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 8347f1bff1..49f8bbab37 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -691,7 +691,7 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid) * Restrict the search for the end of a comment to b_syn_sync_maxlines. */ if (find_start_comment((int)syn_block->b_syn_sync_maxlines) != NULL) { - for (idx = syn_block->b_syn_patterns.ga_len; --idx >= 0; ) { + for (idx = syn_block->b_syn_patterns.ga_len; --idx >= 0;) { if (SYN_ITEMS(syn_block)[idx].sp_syn.id == syn_block->b_syn_sync_id && SYN_ITEMS(syn_block)[idx].sp_type == SPTYPE_START) { @@ -752,7 +752,7 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid) for (current_lnum = lnum; current_lnum < end_lnum; ++current_lnum) { syn_start_line(); - for (;; ) { + for (;;) { had_sync_point = syn_finish_line(true); // When a sync point has been found, remember where, and // continue to look for another one, further on in the line. @@ -1146,7 +1146,7 @@ static void syn_stack_apply_changes_block(synblock_T *block, buf_T *buf) linenr_T n; prev = NULL; - for (p = block->b_sst_first; p != NULL; ) { + for (p = block->b_sst_first; p != NULL;) { if (p->sst_lnum + block->b_syn_sync_linebreaks > buf->b_mod_top) { n = p->sst_lnum + buf->b_mod_xlines; if (n <= buf->b_mod_bot) { @@ -1449,7 +1449,7 @@ static bool syn_stack_equal(synstate_T *sp) } int i; - for (i = current_state.ga_len; --i >= 0; ) { + for (i = current_state.ga_len; --i >= 0;) { // If the item has another index the state is different. if (bp[i].bs_idx != CUR_STATE(i).si_idx) { break; @@ -1788,9 +1788,9 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con line = syn_getcurline(); const char_u *cur_pos = line + current_col; if (vim_iswordp_buf(cur_pos, syn_buf) - && (current_col == 0 || - !vim_iswordp_buf(cur_pos - 1 - utf_head_off(line, cur_pos - 1), - syn_buf))) { + && (current_col == 0 + || !vim_iswordp_buf(cur_pos - 1 - utf_head_off(line, cur_pos - 1), + syn_buf))) { syn_id = check_keyword_id(line, (int)current_col, &endcol, &flags, &next_list, cur_si, &cchar); if (syn_id != 0) { @@ -1852,7 +1852,7 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con */ next_match_idx = 0; // no match in this line yet next_match_col = MAXCOL; - for (int idx = syn_block->b_syn_patterns.ga_len; --idx >= 0; ) { + for (int idx = syn_block->b_syn_patterns.ga_len; --idx >= 0;) { synpat_T *const spp = &(SYN_ITEMS(syn_block)[idx]); if (spp->sp_syncing == syncing && (displaying || !(spp->sp_flags & HL_DISPLAY)) @@ -2207,7 +2207,7 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con /// @return true if we already matched pattern "idx" at the current column. static bool did_match_already(int idx, garray_T *gap) { - for (int i = current_state.ga_len; --i >= 0; ) { + for (int i = current_state.ga_len; --i >= 0;) { if (CUR_STATE(i).si_m_startcol == (int)current_col && CUR_STATE(i).si_m_lnum == (int)current_lnum && CUR_STATE(i).si_idx == idx) { @@ -2217,7 +2217,7 @@ static bool did_match_already(int idx, garray_T *gap) // Zero-width matches with a nextgroup argument are not put on the syntax // stack, and can only be matched once anyway. - for (int i = gap->ga_len; --i >= 0; ) { + for (int i = gap->ga_len; --i >= 0;) { if (((int *)(gap->ga_data))[i] == idx) { return true; } @@ -2318,7 +2318,7 @@ static void check_state_ends(void) int had_extend; cur_si = &CUR_STATE(current_state.ga_len - 1); - for (;; ) { + for (;;) { if (cur_si->si_ends && (cur_si->si_m_endpos.lnum < current_lnum || (cur_si->si_m_endpos.lnum == current_lnum @@ -2658,7 +2658,7 @@ static void find_endpos(int idx, lpos_T *startpos, lpos_T *m_endpos, lpos_T *hl_ /* * Find the SKIP or first END pattern after the last START pattern. */ - for (;; ) { + for (;;) { spp = &(SYN_ITEMS(syn_block)[idx]); if (spp->sp_type != SPTYPE_START) { break; @@ -2687,7 +2687,7 @@ static void find_endpos(int idx, lpos_T *startpos, lpos_T *m_endpos, lpos_T *hl_ // use syntax iskeyword option save_chartab(buf_chartab); - for (;; ) { + for (;;) { /* * Find end pattern that matches first after "matchcol". */ @@ -3286,13 +3286,13 @@ void syntax_clear(synblock_T *block) clear_keywtab(&block->b_keywtab_ic); // free the syntax patterns - for (int i = block->b_syn_patterns.ga_len; --i >= 0; ) { + for (int i = block->b_syn_patterns.ga_len; --i >= 0;) { syn_clear_pattern(block, i); } ga_clear(&block->b_syn_patterns); // free the syntax clusters - for (int i = block->b_syn_clusters.ga_len; --i >= 0; ) { + for (int i = block->b_syn_clusters.ga_len; --i >= 0;) { syn_clear_cluster(block, i); } ga_clear(&block->b_syn_clusters); @@ -3336,7 +3336,7 @@ void reset_synblock(win_T *wp) static void syntax_sync_clear(void) { // free the syntax patterns - for (int i = curwin->w_s->b_syn_patterns.ga_len; --i >= 0; ) { + for (int i = curwin->w_s->b_syn_patterns.ga_len; --i >= 0;) { if (SYN_ITEMS(curwin->w_s)[i].sp_syncing) { syn_remove_pattern(curwin->w_s, i); } @@ -3484,7 +3484,7 @@ static void syn_clear_one(const int id, const bool syncing) } // clear the patterns for "id" - for (int idx = curwin->w_s->b_syn_patterns.ga_len; --idx >= 0; ) { + for (int idx = curwin->w_s->b_syn_patterns.ga_len; --idx >= 0;) { spp = &(SYN_ITEMS(curwin->w_s)[idx]); if (spp->sp_syn.id != id || spp->sp_syncing != syncing) { continue; @@ -3874,7 +3874,7 @@ static void put_pattern(const char *const s, const int c, const synpat_T *const msg_putchar(c); // output the pattern, in between a char that is not in the pattern - for (i = 0; vim_strchr(spp->sp_pattern, sepchars[i]) != NULL; ) { + for (i = 0; vim_strchr(spp->sp_pattern, sepchars[i]) != NULL;) { if (sepchars[++i] == NUL) { i = 0; // no good char found, just use the first one break; @@ -4015,7 +4015,7 @@ static void syn_clear_keyword(int id, hashtab_T *ht) } --todo; kp_prev = NULL; - for (kp = HI2KE(hi); kp != NULL; ) { + for (kp = HI2KE(hi); kp != NULL;) { if (kp->k_syn.id == id) { kp_next = kp->ke_next; if (kp_prev == NULL) { @@ -4191,7 +4191,7 @@ static char_u *get_syn_options(char_u *arg, syn_opt_arg_T *opt, int *conceal_cha opt->flags |= HL_CONCEAL; } - for (;; ) { + for (;;) { /* * This is used very often when a large number of keywords is defined. * Need to skip quickly when no option name is found. @@ -4201,7 +4201,7 @@ static char_u *get_syn_options(char_u *arg, syn_opt_arg_T *opt, int *conceal_cha break; } - for (fidx = ARRAY_SIZE(flagtab); --fidx >= 0; ) { + for (fidx = ARRAY_SIZE(flagtab); --fidx >= 0;) { p = flagtab[fidx].name; int i; for (i = 0, len = 0; p[i] != NUL; i += 2, ++len) { @@ -4273,7 +4273,7 @@ static char_u *get_syn_options(char_u *arg, syn_opt_arg_T *opt, int *conceal_cha } else { syn_id = syn_name2id((char *)gname); int i; - for (i = curwin->w_s->b_syn_patterns.ga_len; --i >= 0; ) { + for (i = curwin->w_s->b_syn_patterns.ga_len; --i >= 0;) { if (SYN_ITEMS(curwin->w_s)[i].sp_syn.id == syn_id && SYN_ITEMS(curwin->w_s)[i].sp_type == SPTYPE_START) { *opt->sync_idx = i; @@ -4460,7 +4460,7 @@ static void syn_cmd_keyword(exarg_T *eap, int syncing) // 2: Add an entry for each keyword. for (kw = keyword_copy; --cnt >= 0; kw += STRLEN(kw) + 1) { - for (p = vim_strchr(kw, '[');; ) { + for (p = vim_strchr(kw, '[');;) { if (p != NULL) { *p = NUL; } @@ -4972,7 +4972,7 @@ static int syn_scl_name2id(char_u *name) // Avoid using stricmp() too much, it's slow on some systems char_u *name_u = vim_strsave_up(name); int i; - for (i = curwin->w_s->b_syn_clusters.ga_len; --i >= 0; ) { + for (i = curwin->w_s->b_syn_clusters.ga_len; --i >= 0;) { if (SYN_CLSTR(curwin->w_s)[i].scl_name_u != NULL && STRCMP(name_u, SYN_CLSTR(curwin->w_s)[i].scl_name_u) == 0) { break; @@ -5078,7 +5078,7 @@ static void syn_cmd_cluster(exarg_T *eap, int syncing) } scl_id -= SYNID_CLUSTER; - for (;; ) { + for (;;) { if (STRNICMP(rest, "add", 3) == 0 && (ascii_iswhite(rest[3]) || rest[3] == '=')) { opt_len = 3; @@ -5174,7 +5174,7 @@ static char_u *get_syn_pattern(char_u *arg, synpat_T *ci) */ ++end; do { - for (idx = SPO_COUNT; --idx >= 0; ) { + for (idx = SPO_COUNT; --idx >= 0;) { if (STRNCMP(end, spo_name_tab[idx], 3) == 0) { break; } @@ -5401,7 +5401,7 @@ static int get_id_list(char_u **const arg, const int keylen, int16_t **const lis do { for (end = p; *end && !ascii_iswhite(*end) && *end != ','; end++) { } - char_u *const name = xmalloc((int)(end - p + 3)); // leave room for "^$" + char_u *const name = xmalloc(end - p + 3); // leave room for "^$" STRLCPY(name + 1, p, end - p + 1); if (STRCMP(name + 1, "ALLBUT") == 0 || STRCMP(name + 1, "ALL") == 0 @@ -5456,7 +5456,7 @@ static int get_id_list(char_u **const arg, const int keylen, int16_t **const lis regmatch.rm_ic = TRUE; id = 0; - for (int i = highlight_ga.ga_len; --i >= 0; ) { + for (int i = highlight_ga.ga_len; --i >= 0;) { if (vim_regexec(®match, HL_TABLE()[i].sg_name, (colnr_T)0)) { if (round == 2) { // Got more items than expected; can happen @@ -6520,7 +6520,7 @@ const char *const highlight_init_cmdline[] = { /// Create default links for Nvim* highlight groups used for cmdline coloring void syn_init_cmdline_highlight(bool reset, bool init) { - for (size_t i = 0 ; highlight_init_cmdline[i] != NULL ; i++) { + for (size_t i = 0; highlight_init_cmdline[i] != NULL; i++) { do_highlight(highlight_init_cmdline[i], reset, init); } } @@ -6968,7 +6968,7 @@ void do_highlight(const char *line, const bool forceit, const bool init) attr = 0; off = 0; while (arg[off] != NUL) { - for (i = ARRAY_SIZE(hl_attr_table); --i >= 0; ) { + for (i = ARRAY_SIZE(hl_attr_table); --i >= 0;) { len = (int)STRLEN(hl_name_table[i]); if (STRNICMP(arg + off, hl_name_table[i], len) == 0) { attr |= hl_attr_table[i]; @@ -7040,7 +7040,7 @@ void do_highlight(const char *line, const bool forceit, const bool init) } else { // Reduce calls to STRICMP a bit, it can be slow. off = TOUPPER_ASC(*arg); - for (i = ARRAY_SIZE(color_names); --i >= 0; ) { + for (i = ARRAY_SIZE(color_names); --i >= 0;) { if (off == color_names[i][0] && STRICMP(arg + 1, color_names[i] + 1) == 0) { break; @@ -7536,6 +7536,7 @@ static bool syn_list_header(const bool did_header, const int outlen, const int i { int endcol = 19; bool newline = true; + int name_col = 0; bool adjust = true; if (!did_header) { @@ -7544,6 +7545,7 @@ static bool syn_list_header(const bool did_header, const int outlen, const int i return true; } msg_outtrans(HL_TABLE()[id - 1].sg_name); + name_col = msg_col; endcol = 15; } else if ((ui_has(kUIMessages) || msg_silent) && !force_newline) { msg_putchar(' '); @@ -7570,6 +7572,9 @@ static bool syn_list_header(const bool did_header, const int outlen, const int i // Show "xxx" with the attributes. if (!did_header) { + if (endcol == Columns - 1 && endcol <= name_col) { + msg_putchar(' '); + } msg_puts_attr("xxx", syn_id2attr(id)); msg_putchar(' '); } @@ -7784,7 +7789,7 @@ int syn_get_final_id(int hl_id) * Follow links until there is no more. * Look out for loops! Break after 100 links. */ - for (count = 100; --count >= 0; ) { + for (count = 100; --count >= 0;) { struct hl_group *sgp = &HL_TABLE()[hl_id - 1]; // index is ID minus one // ACHTUNG: when using "tmp" attribute (no link) the function might be @@ -7983,10 +7988,10 @@ static void highlight_list(void) { int i; - for (i = 10; --i >= 0; ) { + for (i = 10; --i >= 0;) { highlight_list_two(i, HL_ATTR(HLF_D)); } - for (i = 40; --i >= 0; ) { + for (i = 40; --i >= 0;) { highlight_list_two(99, 0); } } diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 673ebc2668..1f4d3adc92 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -431,7 +431,7 @@ int do_tag(char_u *tag, int type, int count, int forceit, int verbose) /* * Repeat searching for tags, when a file has not been found. */ - for (;; ) { + for (;;) { int other_name; char_u *name; @@ -1638,7 +1638,7 @@ int find_tags(char_u *pat, int *num_matches, char_u ***matchesp, int flags, int /* * Read and parse the lines in the file one by one */ - for (;; ) { + for (;;) { // check for CTRL-C typed, more often when jumping around if (state == TS_BINARY || state == TS_SKIP_BACK) { line_breakcheck(); @@ -2403,7 +2403,7 @@ int get_tagfname(tagname_T *tnp, int first, char_u *buf) * tnp->tn_did_filefind_init == FALSE: setup for next part in 'tags'. * tnp->tn_did_filefind_init == TRUE: find next file in this part. */ - for (;; ) { + for (;;) { if (tnp->tn_did_filefind_init) { fname = vim_findfile(tnp->tn_search_ctx); if (fname != NULL) { @@ -2687,7 +2687,7 @@ static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help) // copy the command to pbuf[], remove trailing CR/NL str = tagp.command; - for (pbuf_end = pbuf; *str && *str != '\n' && *str != '\r'; ) { + for (pbuf_end = pbuf; *str && *str != '\n' && *str != '\r';) { *pbuf_end++ = *str++; if (pbuf_end - pbuf + 1 >= LSIZE) { break; @@ -3056,7 +3056,7 @@ static int find_extra(char_u **pp) char_u first_char = **pp; // Repeat for addresses separated with ';' - for (;; ) { + for (;;) { if (ascii_isdigit(*str)) { str = skipdigits(str + 1); } else if (*str == '/' || *str == '?') { diff --git a/src/nvim/testdir/test_arglist.vim b/src/nvim/testdir/test_arglist.vim index 8fd60d6a5a..164149476f 100644 --- a/src/nvim/testdir/test_arglist.vim +++ b/src/nvim/testdir/test_arglist.vim @@ -1,5 +1,9 @@ " Test argument list commands +func Reset_arglist() + args a | %argd +endfunc + func Test_argidx() args a b c last @@ -26,6 +30,8 @@ func Test_argidx() endfunc func Test_argadd() + call Reset_arglist() + %argdelete argadd a b c call assert_equal(0, argidx()) @@ -115,8 +121,7 @@ endfunc " Test for [count]argument and [count]argdelete commands " Ported from the test_argument_count.in test script func Test_argument() - " Clean the argument list - arga a | %argd + call Reset_arglist() let save_hidden = &hidden set hidden @@ -244,8 +249,7 @@ endfunc " Test for 0argadd and 0argedit " Ported from the test_argument_0count.in test script func Test_zero_argadd() - " Clean the argument list - arga a | %argd + call Reset_arglist() arga a b c d 2argu @@ -272,10 +276,6 @@ func Test_zero_argadd() call assert_equal('file with spaces', expand('%')) endfunc -func Reset_arglist() - args a | %argd -endfunc - " Test for argc() func Test_argc() call Reset_arglist() diff --git a/src/nvim/testdir/test_autochdir.vim b/src/nvim/testdir/test_autochdir.vim index 0b76828dd7..9ad727241e 100644 --- a/src/nvim/testdir/test_autochdir.vim +++ b/src/nvim/testdir/test_autochdir.vim @@ -26,4 +26,42 @@ func Test_set_filename() call delete('samples/Xtest') endfunc +func Test_verbose_pwd() + CheckFunction test_autochdir + let cwd = getcwd() + call test_autochdir() + + edit global.txt + call assert_match('\[global\].*testdir$', execute('verbose pwd')) + + call mkdir('Xautodir') + split Xautodir/local.txt + lcd Xautodir + call assert_match('\[window\].*testdir[/\\]Xautodir', execute('verbose pwd')) + + set acd + wincmd w + call assert_match('\[autochdir\].*testdir$', execute('verbose pwd')) + execute 'lcd' cwd + call assert_match('\[window\].*testdir$', execute('verbose pwd')) + execute 'tcd' cwd + call assert_match('\[tabpage\].*testdir$', execute('verbose pwd')) + execute 'cd' cwd + call assert_match('\[global\].*testdir$', execute('verbose pwd')) + edit + call assert_match('\[autochdir\].*testdir$', execute('verbose pwd')) + wincmd w + call assert_match('\[autochdir\].*testdir[/\\]Xautodir', execute('verbose pwd')) + set noacd + call assert_match('\[autochdir\].*testdir[/\\]Xautodir', execute('verbose pwd')) + wincmd w + call assert_match('\[global\].*testdir', execute('verbose pwd')) + wincmd w + call assert_match('\[window\].*testdir[/\\]Xautodir', execute('verbose pwd')) + + bwipe! + call chdir(cwd) + call delete('Xautodir', 'rf') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 0c8b8a45d9..49d56349a5 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -33,7 +33,7 @@ if has('timers') let g:triggered = 0 au CursorHoldI * let g:triggered += 1 set updatetime=20 - call timer_start(LoadAdjust(100), 'ExitInsertMode') + call timer_start(LoadAdjust(200), 'ExitInsertMode') call feedkeys('a', 'x!') call assert_equal(1, g:triggered) unlet g:triggered @@ -1897,6 +1897,26 @@ func Test_autocmd_CmdWinEnter() call delete(filename) endfunc +func Test_autocmd_was_using_freed_memory() + pedit xx + n x + augroup winenter + au WinEnter * if winnr('$') > 2 | quit | endif + augroup END + " Nvim needs large 'winwidth' and 'nowinfixwidth' to crash + set winwidth=99999 nowinfixwidth + split + + augroup winenter + au! WinEnter + augroup END + + set winwidth& winfixwidth& + bwipe xx + bwipe x + pclose +endfunc + func Test_FileChangedShell_reload() if !has('unix') return @@ -2125,6 +2145,19 @@ func Test_autocmd_closes_window() au! BufWinLeave endfunc +func Test_autocmd_quit_psearch() + sn aa bb + augroup aucmd_win_test + au! + au BufEnter,BufLeave,BufNew,WinEnter,WinLeave,WinNew * if winnr('$') > 1 | q | endif + augroup END + ps / + + augroup aucmd_win_test + au! + augroup END +endfunc + func Test_autocmd_closing_cmdwin() au BufWinLeave * nested q call assert_fails("norm 7q?\n", 'E855:') diff --git a/src/nvim/testdir/test_blockedit.vim b/src/nvim/testdir/test_blockedit.vim index 180524cd73..38978ef689 100644 --- a/src/nvim/testdir/test_blockedit.vim +++ b/src/nvim/testdir/test_blockedit.vim @@ -15,6 +15,58 @@ func Test_blockinsert_indent() bwipe! endfunc +func Test_blockinsert_autoindent() + new + let lines =<< trim END + var d = { + a: () => 0, + b: () => 0, + c: () => 0, + } + END + call setline(1, lines) + filetype plugin indent on + setlocal sw=2 et ft=vim + setlocal indentkeys+=: + exe "norm! 2Gf)\<c-v>2jA: asdf\<esc>" + let expected =<< trim END + var d = { + a: (): asdf => 0, + b: (): asdf => 0, + c: (): asdf => 0, + } + END + call assert_equal(expected, getline(1, 5)) + + " insert on the next column should do exactly the same + :%dele + call setline(1, lines) + exe "norm! 2Gf)l\<c-v>2jI: asdf\<esc>" + call assert_equal(expected, getline(1, 5)) + + :%dele + call setline(1, lines) + setlocal sw=8 noet + exe "norm! 2Gf)\<c-v>2jA: asdf\<esc>" + let expected =<< trim END + var d = { + a: (): asdf => 0, + b: (): asdf => 0, + c: (): asdf => 0, + } + END + call assert_equal(expected, getline(1, 5)) + + " insert on the next column should do exactly the same + :%dele + call setline(1, lines) + exe "norm! 2Gf)l\<c-v>2jI: asdf\<esc>" + call assert_equal(expected, getline(1, 5)) + + filetype off + bwipe! +endfunc + func Test_blockinsert_delete() new let _bs = &bs diff --git a/src/nvim/testdir/test_bufwintabinfo.vim b/src/nvim/testdir/test_bufwintabinfo.vim index bb672cf0ec..c04c8fbf60 100644 --- a/src/nvim/testdir/test_bufwintabinfo.vim +++ b/src/nvim/testdir/test_bufwintabinfo.vim @@ -1,108 +1,110 @@ " Tests for the getbufinfo(), getwininfo() and gettabinfo() functions function Test_getbufwintabinfo() - edit Xtestfile1 - edit Xtestfile2 - let buflist = getbufinfo() - call assert_equal(2, len(buflist)) - call assert_match('Xtestfile1', buflist[0].name) - call assert_match('Xtestfile2', getbufinfo('Xtestfile2')[0].name) - call assert_equal([], getbufinfo(2016)) - edit Xtestfile1 - hide edit Xtestfile2 - hide enew - call assert_equal(3, len(getbufinfo({'bufloaded':1}))) - - set tabstop&vim - let b:editor = 'vim' + edit Xtestfile1 + edit Xtestfile2 + let buflist = getbufinfo() + call assert_equal(2, len(buflist)) + call assert_match('Xtestfile1', buflist[0].name) + call assert_match('Xtestfile2', getbufinfo('Xtestfile2')[0].name) + call assert_equal([], getbufinfo(2016)) + edit Xtestfile1 + hide edit Xtestfile2 + hide enew + call assert_equal(3, len(getbufinfo({'bufloaded':1}))) + + set tabstop&vim + let b:editor = 'vim' + let l = getbufinfo('%') + call assert_equal(bufnr('%'), l[0].bufnr) + call assert_equal('vim', l[0].variables.editor) + call assert_notequal(-1, index(l[0].windows, '%'->bufwinid())) + + " Test for getbufinfo() with 'bufmodified' + call assert_equal(0, len(getbufinfo({'bufmodified' : 1}))) + call setbufline('Xtestfile1', 1, ["Line1"]) + let l = getbufinfo({'bufmodified' : 1}) + call assert_equal(1, len(l)) + call assert_equal(bufnr('Xtestfile1'), l[0].bufnr) + + if has('signs') + call append(0, ['Linux', 'Windows', 'Mac']) + sign define Mark text=>> texthl=Search + exe "sign place 2 line=3 name=Mark buffer=" . bufnr('%') let l = getbufinfo('%') - call assert_equal(bufnr('%'), l[0].bufnr) - call assert_equal('vim', l[0].variables.editor) - call assert_notequal(-1, index(l[0].windows, '%'->bufwinid())) - - " Test for getbufinfo() with 'bufmodified' - call assert_equal(0, len(getbufinfo({'bufmodified' : 1}))) - call setbufline('Xtestfile1', 1, ["Line1"]) - let l = getbufinfo({'bufmodified' : 1}) - call assert_equal(1, len(l)) - call assert_equal(bufnr('Xtestfile1'), l[0].bufnr) - - if has('signs') - call append(0, ['Linux', 'Windows', 'Mac']) - sign define Mark text=>> texthl=Search - exe "sign place 2 line=3 name=Mark buffer=" . bufnr('%') - let l = getbufinfo('%') - call assert_equal(2, l[0].signs[0].id) - call assert_equal(3, l[0].signs[0].lnum) - call assert_equal('Mark', l[0].signs[0].name) - sign unplace * - sign undefine Mark - enew! - endif - - only - let w1_id = win_getid() - new - let w2_id = win_getid() - tabnew | let w3_id = win_getid() - new | let w4_id = win_getid() - vert new | let w5_id = win_getid() - call setwinvar(0, 'signal', 'green') - tabfirst - let winlist = getwininfo() - call assert_equal(5, len(winlist)) - call assert_equal(winwidth(1), winlist[0].width) - call assert_equal(1, winlist[0].wincol) - " tabline adds one row in terminal, not in GUI - let tablineheight = winlist[0].winrow == 2 ? 1 : 0 - call assert_equal(tablineheight + 1, winlist[0].winrow) - - call assert_equal(winbufnr(2), winlist[1].bufnr) - call assert_equal(winheight(2), winlist[1].height) - call assert_equal(1, winlist[1].wincol) - call assert_equal(tablineheight + winheight(1) + 2, winlist[1].winrow) - - call assert_equal(1, winlist[2].winnr) - call assert_equal(tablineheight + 1, winlist[2].winrow) - call assert_equal(1, winlist[2].wincol) - - call assert_equal(winlist[2].width + 2, winlist[3].wincol) - call assert_equal(1, winlist[4].wincol) - - call assert_equal(1, winlist[0].tabnr) - call assert_equal(1, winlist[1].tabnr) - call assert_equal(2, winlist[2].tabnr) - call assert_equal(2, winlist[3].tabnr) - call assert_equal(2, winlist[4].tabnr) - - call assert_equal('green', winlist[2].variables.signal) - call assert_equal(w4_id, winlist[3].winid) - let winfo = w5_id->getwininfo()[0] - call assert_equal(2, winfo.tabnr) - call assert_equal([], getwininfo(3)) - - call settabvar(1, 'space', 'build') - let tablist = gettabinfo() - call assert_equal(2, len(tablist)) - call assert_equal(3, len(tablist[1].windows)) - call assert_equal(2, tablist[1].tabnr) - call assert_equal('build', tablist[0].variables.space) - call assert_equal(w2_id, tablist[0].windows[0]) - call assert_equal([], 3->gettabinfo()) - - tabonly | only - - lexpr '' - lopen - copen - let winlist = getwininfo() - call assert_false(winlist[0].quickfix) - call assert_false(winlist[0].loclist) - call assert_true(winlist[1].quickfix) - call assert_true(winlist[1].loclist) - call assert_true(winlist[2].quickfix) - call assert_false(winlist[2].loclist) - wincmd t | only + call assert_equal(2, l[0].signs[0].id) + call assert_equal(3, l[0].signs[0].lnum) + call assert_equal('Mark', l[0].signs[0].name) + sign unplace * + sign undefine Mark + enew! + endif + + only + let w1_id = win_getid() + setl foldcolumn=3 + new + let w2_id = win_getid() + tabnew | let w3_id = win_getid() + new | let w4_id = win_getid() + vert new | let w5_id = win_getid() + call setwinvar(0, 'signal', 'green') + tabfirst + let winlist = getwininfo() + call assert_equal(5, len(winlist)) + call assert_equal(winwidth(1), winlist[0].width) + call assert_equal(1, winlist[0].wincol) + " tabline adds one row in terminal, not in GUI + let tablineheight = winlist[0].winrow == 2 ? 1 : 0 + call assert_equal(tablineheight + 1, winlist[0].winrow) + + call assert_equal(winbufnr(2), winlist[1].bufnr) + call assert_equal(winheight(2), winlist[1].height) + call assert_equal(1, winlist[1].wincol) + call assert_equal(3, winlist[1].textoff) " foldcolumn + call assert_equal(tablineheight + winheight(1) + 2, winlist[1].winrow) + + call assert_equal(1, winlist[2].winnr) + call assert_equal(tablineheight + 1, winlist[2].winrow) + call assert_equal(1, winlist[2].wincol) + + call assert_equal(winlist[2].width + 2, winlist[3].wincol) + call assert_equal(1, winlist[4].wincol) + + call assert_equal(1, winlist[0].tabnr) + call assert_equal(1, winlist[1].tabnr) + call assert_equal(2, winlist[2].tabnr) + call assert_equal(2, winlist[3].tabnr) + call assert_equal(2, winlist[4].tabnr) + + call assert_equal('green', winlist[2].variables.signal) + call assert_equal(w4_id, winlist[3].winid) + let winfo = w5_id->getwininfo()[0] + call assert_equal(2, winfo.tabnr) + call assert_equal([], getwininfo(3)) + + call settabvar(1, 'space', 'build') + let tablist = gettabinfo() + call assert_equal(2, len(tablist)) + call assert_equal(3, len(tablist[1].windows)) + call assert_equal(2, tablist[1].tabnr) + call assert_equal('build', tablist[0].variables.space) + call assert_equal(w2_id, tablist[0].windows[0]) + call assert_equal([], 3->gettabinfo()) + + tabonly | only + + lexpr '' + lopen + copen + let winlist = getwininfo() + call assert_false(winlist[0].quickfix) + call assert_false(winlist[0].loclist) + call assert_true(winlist[1].quickfix) + call assert_true(winlist[1].loclist) + call assert_true(winlist[2].quickfix) + call assert_false(winlist[2].loclist) + wincmd t | only endfunction function Test_get_buf_options() diff --git a/src/nvim/testdir/test_cd.vim b/src/nvim/testdir/test_cd.vim index 0bba321ee2..57db0a2544 100644 --- a/src/nvim/testdir/test_cd.vim +++ b/src/nvim/testdir/test_cd.vim @@ -215,3 +215,42 @@ func Test_cd_from_non_existing_dir() cd - call assert_equal(saveddir, getcwd()) endfunc + +func Test_cd_unknown_dir() + call mkdir('Xa') + cd Xa + call writefile(['text'], 'Xb.txt') + edit Xa/Xb.txt + let first_buf = bufnr() + cd .. + edit + call assert_equal(first_buf, bufnr()) + edit Xa/Xb.txt + call assert_notequal(first_buf, bufnr()) + + bwipe! + exe "bwipe! " .. first_buf + call delete('Xa', 'rf') +endfunc + +func Test_getcwd_actual_dir() + CheckFunction test_autochdir + let startdir = getcwd() + call mkdir('Xactual') + call test_autochdir() + set autochdir + edit Xactual/file.txt + call assert_match('testdir.Xactual$', getcwd()) + lcd .. + call assert_match('testdir$', getcwd()) + edit + call assert_match('testdir.Xactual$', getcwd()) + call assert_match('testdir$', getcwd(win_getid())) + + set noautochdir + bwipe! + call chdir(startdir) + call delete('Xactual', 'rf') +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim index 98340d0ac6..75e17b47b8 100644 --- a/src/nvim/testdir/test_cmdline.vim +++ b/src/nvim/testdir/test_cmdline.vim @@ -428,14 +428,17 @@ func Test_getcompletion() call assert_equal([], l) func T(a, c, p) + let g:cmdline_compl_params = [a:a, a:c, a:p] return "oneA\noneB\noneC" endfunc command -nargs=1 -complete=custom,T MyCmd let l = getcompletion('MyCmd ', 'cmdline') call assert_equal(['oneA', 'oneB', 'oneC'], l) + call assert_equal(['', 'MyCmd ', 6], g:cmdline_compl_params) delcommand MyCmd delfunc T + unlet g:cmdline_compl_params " For others test if the name is recognized. let names = ['buffer', 'environment', 'file_in_path', 'mapping', 'tag', 'tag_listfiles', 'user'] diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index 9651b8dce0..48b434b9fd 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -59,7 +59,7 @@ let s:filename_checks = { \ 'aml': ['file.aml'], \ 'ampl': ['file.run'], \ 'ant': ['build.xml'], - \ 'apache': ['.htaccess', '/etc/httpd/file.conf', '/etc/apache2/sites-2/file.com', '/etc/apache2/some.config', '/etc/apache2/conf.file/conf', '/etc/apache2/mods-some/file', '/etc/apache2/sites-some/file', '/etc/httpd/conf.d/file.config', '/etc/apache2/conf.file/file', '/etc/apache2/file.conf', '/etc/apache2/file.conf-file', '/etc/apache2/mods-file/file', '/etc/apache2/sites-file/file', '/etc/apache2/sites-file/file.com', '/etc/httpd/conf.d/file.conf', '/etc/httpd/conf.d/file.conf-file', 'access.conf', 'access.conf-file', 'any/etc/apache2/conf.file/file', 'any/etc/apache2/file.conf', 'any/etc/apache2/file.conf-file', 'any/etc/apache2/mods-file/file', 'any/etc/apache2/sites-file/file', 'any/etc/apache2/sites-file/file.com', 'any/etc/httpd/conf.d/file.conf', 'any/etc/httpd/conf.d/file.conf-file', 'any/etc/httpd/file.conf', 'apache.conf', 'apache.conf-file', 'apache2.conf', 'apache2.conf-file', 'httpd.conf', 'httpd.conf-file', 'srm.conf', 'srm.conf-file'], + \ 'apache': ['.htaccess', '/etc/httpd/file.conf', '/etc/apache2/sites-2/file.com', '/etc/apache2/some.config', '/etc/apache2/conf.file/conf', '/etc/apache2/mods-some/file', '/etc/apache2/sites-some/file', '/etc/httpd/conf.d/file.config', '/etc/apache2/conf.file/file', '/etc/apache2/file.conf', '/etc/apache2/file.conf-file', '/etc/apache2/mods-file/file', '/etc/apache2/sites-file/file', '/etc/apache2/sites-file/file.com', '/etc/httpd/conf.d/file.conf', '/etc/httpd/conf.d/file.conf-file', 'access.conf', 'access.conf-file', 'any/etc/apache2/conf.file/file', 'any/etc/apache2/file.conf', 'any/etc/apache2/file.conf-file', 'any/etc/apache2/mods-file/file', 'any/etc/apache2/sites-file/file', 'any/etc/apache2/sites-file/file.com', 'any/etc/httpd/conf.d/file.conf', 'any/etc/httpd/conf.d/file.conf-file', 'any/etc/httpd/file.conf', 'apache.conf', 'apache.conf-file', 'apache2.conf', 'apache2.conf-file', 'httpd.conf', 'httpd.conf-file', 'srm.conf', 'srm.conf-file', '/etc/httpd/mods-some/file', '/etc/httpd/sites-some/file', '/etc/httpd/conf.file/conf'], \ 'apachestyle': ['/etc/proftpd/file.config,/etc/proftpd/conf.file/file', '/etc/proftpd/conf.file/file', '/etc/proftpd/file.conf', '/etc/proftpd/file.conf-file', 'any/etc/proftpd/conf.file/file', 'any/etc/proftpd/file.conf', 'any/etc/proftpd/file.conf-file', 'proftpd.conf', 'proftpd.conf-file'], \ 'applescript': ['file.scpt'], \ 'aptconf': ['apt.conf', '/.aptitude/config', 'any/.aptitude/config'], @@ -142,7 +142,7 @@ let s:filename_checks = { \ 'desc': ['file.desc'], \ 'desktop': ['file.desktop', '.directory', 'file.directory'], \ 'dictconf': ['dict.conf', '.dictrc'], - \ 'dictdconf': ['dictd.conf'], + \ 'dictdconf': ['dictd.conf', 'dictdfile.conf', 'dictd-file.conf'], \ 'diff': ['file.diff', 'file.rej'], \ 'dircolors': ['.dir_colors', '.dircolors', '/etc/DIR_COLORS', 'any/etc/DIR_COLORS'], \ 'dnsmasq': ['/etc/dnsmasq.conf', '/etc/dnsmasq.d/file', 'any/etc/dnsmasq.conf', 'any/etc/dnsmasq.d/file'], @@ -182,11 +182,12 @@ let s:filename_checks = { \ 'fgl': ['file.4gl', 'file.4gh', 'file.m4gl'], \ 'fish': ['file.fish'], \ 'focexec': ['file.fex', 'file.focexec'], - \ 'forth': ['file.fs', 'file.ft', 'file.fth'], + \ 'forth': ['file.ft', 'file.fth'], \ 'fortran': ['file.f', 'file.for', 'file.fortran', 'file.fpp', 'file.ftn', 'file.f77', 'file.f90', 'file.f95', 'file.f03', 'file.f08'], \ 'fpcmake': ['file.fpc'], \ 'framescript': ['file.fsl'], \ 'freebasic': ['file.fb', 'file.bi'], + \ 'fsharp': ['file.fs', 'file.fsi', 'file.fsx'], \ 'fstab': ['fstab', 'mtab'], \ 'fvwm': ['/.fvwm/file', 'any/.fvwm/file'], \ 'gdb': ['.gdbinit', 'gdbinit'], @@ -553,7 +554,7 @@ let s:filename_checks = { \ '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.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'], + \ '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'], @@ -663,6 +664,7 @@ let s:script_checks = { \ 'fennel': [['#!/path/fennel']], \ 'routeros': [['#!/path/rsc']], \ 'fish': [['#!/path/fish']], + \ 'forth': [['#!/path/gforth']], \ } " Various forms of "env" optional arguments. @@ -866,6 +868,16 @@ func Test_m_file() call assert_equal('objc', &filetype) bwipe! + call writefile(['#include <header.h>'], 'Xfile.m') + split Xfile.m + call assert_equal('objc', &filetype) + bwipe! + + call writefile(['#define FORTY_TWO'], 'Xfile.m') + split Xfile.m + call assert_equal('objc', &filetype) + bwipe! + " Octave call writefile(['# Octave line comment'], 'Xfile.m') @@ -935,4 +947,57 @@ func Test_xpm_file() filetype off endfunc +func Test_fs_file() + filetype on + + call writefile(['looks like F#'], 'Xfile.fs') + split Xfile.fs + call assert_equal('fsharp', &filetype) + bwipe! + + let g:filetype_fs = 'forth' + split Xfile.fs + call assert_equal('forth', &filetype) + bwipe! + unlet g:filetype_fs + + " Test dist#ft#FTfs() + + " Forth (Gforth) + + call writefile(['( Forth inline comment )'], 'Xfile.fs') + split Xfile.fs + call assert_equal('forth', &filetype) + bwipe! + + call writefile(['.( Forth displayed inline comment )'], 'Xfile.fs') + split Xfile.fs + call assert_equal('forth', &filetype) + bwipe! + + call writefile(['\ Forth line comment'], 'Xfile.fs') + split Xfile.fs + call assert_equal('forth', &filetype) + bwipe! + + " empty line comment - no space required + call writefile(['\'], 'Xfile.fs') + split Xfile.fs + call assert_equal('forth', &filetype) + bwipe! + + call writefile(['\G Forth documentation comment '], 'Xfile.fs') + split Xfile.fs + call assert_equal('forth', &filetype) + bwipe! + + call writefile([': squared ( n -- n^2 )', 'dup * ;'], 'Xfile.fs') + split Xfile.fs + call assert_equal('forth', &filetype) + bwipe! + + call delete('Xfile.fs') + filetype off +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim index d10fad690c..4a2ade5afa 100644 --- a/src/nvim/testdir/test_functions.vim +++ b/src/nvim/testdir/test_functions.vim @@ -1592,6 +1592,10 @@ func Test_bufadd_bufload() endfunc func Test_readdir() + if isdirectory('Xdir') + call delete('Xdir', 'rf') + endif + call mkdir('Xdir') call writefile([], 'Xdir/foo.txt') call writefile([], 'Xdir/bar.txt') diff --git a/src/nvim/testdir/test_highlight.vim b/src/nvim/testdir/test_highlight.vim index 6fd9477ce9..c38bfa5677 100644 --- a/src/nvim/testdir/test_highlight.vim +++ b/src/nvim/testdir/test_highlight.vim @@ -651,6 +651,16 @@ func Test_1_highlight_Normalgroup_exists() endif endfunc +function Test_no_space_before_xxx() + " Note: we need to create this highlight group in the test because it does not exist in Neovim + execute('hi StatusLineTermNC ctermfg=green') + let l:org_columns = &columns + set columns=17 + let l:hi_StatusLineTermNC = join(split(execute('hi StatusLineTermNC'))) + call assert_match('StatusLineTermNC xxx', l:hi_StatusLineTermNC) + let &columns = l:org_columns +endfunction + " Test for using RGB color values in a highlight group func Test_xxlast_highlight_RGB_color() CheckCanRunGui diff --git a/src/nvim/testdir/test_listchars.vim b/src/nvim/testdir/test_listchars.vim index 751be8eff5..9906b00222 100644 --- a/src/nvim/testdir/test_listchars.vim +++ b/src/nvim/testdir/test_listchars.vim @@ -112,7 +112,7 @@ func Test_listchars() " Test lead and trail normal ggdG - set listchars=eol:$ + set listchars=eol:$ " Accommodate Nvim default set listchars+=lead:>,trail:<,space:x set list @@ -142,7 +142,7 @@ func Test_listchars() " Test multispace normal ggdG - set listchars=eol:$ + set listchars=eol:$ " Accommodate Nvim default set listchars+=multispace:yYzZ set list @@ -305,7 +305,7 @@ func Test_listchars_invalid() enew! set ff=unix - set listchars=eol:$ + set listchars=eol:$ " Accommodate Nvim default set list set ambiwidth=double @@ -369,3 +369,138 @@ func Test_listchars_composing() enew! set listchars& ff& endfunction + +" Check for the value of the 'listchars' option +func s:CheckListCharsValue(expected) + call assert_equal(a:expected, &listchars) + call assert_equal(a:expected, getwinvar(0, '&listchars')) +endfunc + +" Test for using a window local value for 'listchars' +func Test_listchars_window_local() + %bw! + set list listchars& + let l:default_listchars = &listchars " Accommodate Nvim default + new + " set a local value for 'listchars' + setlocal listchars=tab:+-,eol:# + call s:CheckListCharsValue('tab:+-,eol:#') + " When local value is reset, global value should be used + setlocal listchars= + call s:CheckListCharsValue(l:default_listchars) " Accommodate Nvim default + " Use 'setlocal <' to copy global value + setlocal listchars=space:.,extends:> + setlocal listchars< + call s:CheckListCharsValue(l:default_listchars) " Accommodate Nvim default + " Use 'set <' to copy global value + setlocal listchars=space:.,extends:> + set listchars< + call s:CheckListCharsValue(l:default_listchars) " Accommodate Nvim default + " Changing global setting should not change the local setting + setlocal listchars=space:.,extends:> + setglobal listchars=tab:+-,eol:# + call s:CheckListCharsValue('space:.,extends:>') + " when split opening a new window, local value should be copied + split + call s:CheckListCharsValue('space:.,extends:>') + " clearing local value in one window should not change the other window + set listchars& + call s:CheckListCharsValue(l:default_listchars) " Accommodate Nvim default + close + call s:CheckListCharsValue('space:.,extends:>') + + " use different values for 'listchars' items in two different windows + call setline(1, ["\t one two "]) + setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:# + split + setlocal listchars=tab:[.],lead:#,space:_,trail:.,eol:& + split + set listchars=tab:+-+,lead:^,space:>,trail:<,eol:% + call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$'))) + close + call assert_equal(['[......]##one__two..&'], ScreenLines(1, virtcol('$'))) + close + call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) + " changing the global setting should not change the local value + setglobal listchars=tab:[.],lead:#,space:_,trail:.,eol:& + call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) + set listchars< + call assert_equal(['[......]##one__two..&'], ScreenLines(1, virtcol('$'))) + + " Using setglobal in a window with local setting should not affect the + " window. But should impact other windows using the global setting. + enew! | only + call setline(1, ["\t one two "]) + set listchars=tab:[.],lead:#,space:_,trail:.,eol:& + split + setlocal listchars=tab:+-+,lead:^,space:>,trail:<,eol:% + split + setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:# + setglobal listchars=tab:{.},lead:-,space:=,trail:#,eol:$ + call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) + close + call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$'))) + close + call assert_equal(['{......}--one==two##$'], ScreenLines(1, virtcol('$'))) + + " Setting the global setting to the default value should not impact a window + " using a local setting. + split + setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:# + setglobal listchars=eol:$ " Accommodate Nvim default + call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) + close + call assert_equal(['^I one two $'], ScreenLines(1, virtcol('$'))) + + " Setting the local setting to the default value should not impact a window + " using a global setting. + set listchars=tab:{.},lead:-,space:=,trail:#,eol:$ + split + setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:# + call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) + setlocal listchars=eol:$ " Accommodate Nvim default + call assert_equal(['^I one two $'], ScreenLines(1, virtcol('$'))) + close + call assert_equal(['{......}--one==two##$'], ScreenLines(1, virtcol('$'))) + + " Using set in a window with a local setting should change it to use the + " global setting and also impact other windows using the global setting. + split + setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:# + call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) + set listchars=tab:+-+,lead:^,space:>,trail:<,eol:% + call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$'))) + close + call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$'))) + + " Setting invalid value for a local setting should not impact the local and + " global settings. + split + setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:# + let cmd = 'setlocal listchars=tab:{.},lead:-,space:=,trail:#,eol:$,x' + call assert_fails(cmd, 'E474:') + call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) + close + call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$'))) + + " Setting invalid value for a global setting should not impact the local and + " global settings. + split + setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:# + let cmd = 'setglobal listchars=tab:{.},lead:-,space:=,trail:#,eol:$,x' + call assert_fails(cmd, 'E474:') + call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) + close + call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$'))) + + " Closing window with local lcs-multispace should not cause a memory leak. + setlocal listchars=multispace:---+ + split + call s:CheckListCharsValue('multispace:---+') + close + + %bw! + set list& listchars& +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_listlbr.vim b/src/nvim/testdir/test_listlbr.vim index e0518de3c2..2fda12d8b4 100644 --- a/src/nvim/testdir/test_listlbr.vim +++ b/src/nvim/testdir/test_listlbr.vim @@ -43,6 +43,7 @@ endfunc func Test_linebreak_with_list() throw 'skipped: Nvim does not support enc=latin1' + set listchars= call s:test_windows('setl ts=4 sbr=+ list listchars=') call setline(1, "\tabcdef hijklmn\tpqrstuvwxyz_1060ABCDEFGHIJKLMNOP ") let lines = s:screen_lines([1, 4], winwidth(0)) @@ -54,6 +55,7 @@ func Test_linebreak_with_list() \ ] call s:compare_lines(expect, lines) call s:close_windows() + set listchars&vim endfunc func Test_linebreak_with_nolist() diff --git a/src/nvim/testdir/test_put.vim b/src/nvim/testdir/test_put.vim index 15745d5619..8d8cc77025 100644 --- a/src/nvim/testdir/test_put.vim +++ b/src/nvim/testdir/test_put.vim @@ -111,3 +111,16 @@ func Test_put_p_indent_visual() call assert_equal('select that text', getline(2)) bwipe! endfunc + +func Test_multibyte_op_end_mark() + new + call setline(1, 'тест') + normal viwdp + call assert_equal([0, 1, 7, 0], getpos("'>")) + call assert_equal([0, 1, 7, 0], getpos("']")) + + normal Vyp + call assert_equal([0, 1, 2147483647, 0], getpos("'>")) + call assert_equal([0, 2, 7, 0], getpos("']")) + bwipe! + endfunc diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 8c6ce63ade..b38a59e98f 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -3653,6 +3653,9 @@ func Xqftick_tests(cchar) \ {'filename' : 'F7', 'lnum' : 11, 'text' : 'L11'}], 'r') call assert_equal(2, g:Xgetlist({'changedtick' : 0}).changedtick) + if isdirectory("Xone") + call delete("Xone", 'rf') + endif call writefile(["F8:80:L80", "F8:81:L81"], "Xone") Xfile Xone call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick) diff --git a/src/nvim/testdir/test_registers.vim b/src/nvim/testdir/test_registers.vim index fd8653a2eb..84a5aca3d5 100644 --- a/src/nvim/testdir/test_registers.vim +++ b/src/nvim/testdir/test_registers.vim @@ -43,6 +43,10 @@ func Test_yank_shows_register() endfunc func Test_display_registers() + " Disable clipboard + let save_clipboard = get(g:, 'clipboard', {}) + let g:clipboard = {} + e file1 e file2 call setline(1, ['foo', 'bar']) @@ -78,6 +82,7 @@ func Test_display_registers() \ . ' c ": ls', a) bwipe! + let g:clipboard = save_clipboard endfunc func Test_recording_status_in_ex_line() diff --git a/src/nvim/testdir/test_textobjects.vim b/src/nvim/testdir/test_textobjects.vim index c259453b5e..2b6bb8b302 100644 --- a/src/nvim/testdir/test_textobjects.vim +++ b/src/nvim/testdir/test_textobjects.vim @@ -421,4 +421,36 @@ func Test_textobj_quote() close! endfunc +" Test for i(, i<, etc. when cursor is in front of a block +func Test_textobj_find_paren_forward() + new + + " i< and a> when cursor is in front of a block + call setline(1, '#include <foo.h>') + normal 0yi< + call assert_equal('foo.h', @") + normal 0ya> + call assert_equal('<foo.h>', @") + + " 2i(, 3i( in front of a block enters second/third nested '(' + call setline(1, 'foo (bar (baz (quux)))') + normal 0yi) + call assert_equal('bar (baz (quux))', @") + normal 02yi) + call assert_equal('baz (quux)', @") + normal 03yi) + call assert_equal('quux', @") + + " 3i( in front of a block doesn't enter third but un-nested '(' + call setline(1, 'foo (bar (baz) (quux))') + normal 03di) + call assert_equal('foo (bar (baz) (quux))', getline(1)) + normal 02di) + call assert_equal('foo (bar () (quux))', getline(1)) + normal 0di) + call assert_equal('foo ()', getline(1)) + + close! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/undo.c b/src/nvim/undo.c index 7eb76abd2c..8161fce9f4 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -922,7 +922,7 @@ static u_header_T *unserialize_uhp(bufinfo_T *bi, const char *file_name) uhp->uh_time = undo_read_time(bi); // Unserialize optional fields. - for (;; ) { + for (;;) { int len = undo_read_byte(bi); if (len == EOF) { @@ -1504,7 +1504,7 @@ void u_read_undo(char *name, const char_u *hash, const char_u *orig_name FUNC_AT // Optional header fields. long last_save_nr = 0; - for (;; ) { + for (;;) { int len = undo_read_byte(&bi); if (len == 0 || len == EOF) { diff --git a/src/nvim/version.c b/src/nvim/version.c index 1fcbae8be3..5e2a81795a 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -458,11 +458,11 @@ static const int included_patches[] = { 1466, 1465, 1464, - // 1463, + 1463, 1462, - // 1461, - // 1460, - // 1459, + 1461, + 1460, + 1459, 1458, 1457, 1456, diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c index 4f028fa87f..800ecf10db 100644 --- a/src/nvim/viml/parser/expressions.c +++ b/src/nvim/viml/parser/expressions.c @@ -1036,7 +1036,7 @@ void viml_pexpr_free_ast(ExprAST ast) ExprASTNode **const cur_node = kv_last(ast_stack); #ifndef NDEBUG // Explicitly check for AST recursiveness. - for (size_t i = 0 ; i < kv_size(ast_stack) - 1 ; i++) { + for (size_t i = 0; i < kv_size(ast_stack) - 1; i++) { assert(*kv_A(ast_stack, i) != *cur_node); } #endif diff --git a/src/nvim/window.c b/src/nvim/window.c index 9f6481f5de..3e6e42dec2 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -224,7 +224,7 @@ newwindow: beep_flush(); } else { if (Prenum) { // go to specified window - for (wp = firstwin; --Prenum > 0; ) { + for (wp = firstwin; --Prenum > 0;) { if (wp->w_next == NULL) { break; } else { @@ -1958,8 +1958,8 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int // Set the width/height of this frame. // Redraw when size or position changes if (topfr->fr_height != height || topfr->fr_win->w_winrow != row - || topfr->fr_width != width || - topfr->fr_win->w_wincol != col) { + || topfr->fr_width != width + || topfr->fr_win->w_wincol != col) { topfr->fr_win->w_winrow = row; frame_new_height(topfr, height, false, false); topfr->fr_win->w_wincol = col; @@ -2239,7 +2239,7 @@ void close_windows(buf_T *buf, int keep_curwin) ++RedrawingDisabled; - for (win_T *wp = firstwin; wp != NULL && !ONE_WINDOW; ) { + for (win_T *wp = firstwin; wp != NULL && !ONE_WINDOW;) { if (wp->w_buffer == buf && (!keep_curwin || wp != curwin) && !(wp->w_closing || wp->w_buffer->b_locked > 0)) { if (win_close(wp, false) == FAIL) { @@ -2582,7 +2582,7 @@ int win_close(win_T *win, bool free_buf) * If the cursor goes to the preview or the quickfix window, try * finding another window to go to. */ - for (;; ) { + for (;;) { if (wp->w_next == NULL) { wp = firstwin; } else { @@ -3147,12 +3147,12 @@ static void frame_new_height(frame_T *topfrp, int height, bool topfirst, bool wf break; } if (topfirst) { - do{ + do { frp = frp->fr_next; } while (wfh && frp != NULL && frame_fixed_height(frp)); } else { - do{ + do { frp = frp->fr_prev; } while (wfh && frp != NULL && frame_fixed_height(frp)); @@ -3347,12 +3347,12 @@ static void frame_new_width(frame_T *topfrp, int width, bool leftfirst, bool wfw break; } if (leftfirst) { - do{ + do { frp = frp->fr_next; } while (wfw && frp != NULL && frame_fixed_width(frp)); } else { - do{ + do { frp = frp->fr_prev; } while (wfw && frp != NULL && frame_fixed_width(frp)); @@ -4316,7 +4316,7 @@ win_T *win_vert_neighbor(tabpage_T *tp, win_T *wp, bool up, long count) * downwards neighbor. */ fr = foundfr; - for (;; ) { + for (;;) { if (fr == tp->tp_topframe) { goto end; } @@ -4334,7 +4334,7 @@ win_T *win_vert_neighbor(tabpage_T *tp, win_T *wp, bool up, long count) /* * Now go downwards to find the bottom or top frame in it. */ - for (;; ) { + for (;;) { if (nfr->fr_layout == FR_LEAF) { foundfr = nfr; break; @@ -4399,7 +4399,7 @@ win_T *win_horz_neighbor(tabpage_T *tp, win_T *wp, bool left, long count) * right neighbor. */ fr = foundfr; - for (;; ) { + for (;;) { if (fr == tp->tp_topframe) { goto end; } @@ -4417,7 +4417,7 @@ win_T *win_horz_neighbor(tabpage_T *tp, win_T *wp, bool left, long count) /* * Now go downwards to find the leftmost or rightmost frame in it. */ - for (;; ) { + for (;;) { if (nfr->fr_layout == FR_LEAF) { foundfr = nfr; break; @@ -4525,6 +4525,7 @@ static void win_enter_ext(win_T *const wp, const int flags) fix_current_dir(); + // Careful: autocommands may close the window and make "wp" invalid if (flags & WEE_TRIGGER_NEW_AUTOCMDS) { apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf); } @@ -4558,7 +4559,7 @@ static void win_enter_ext(win_T *const wp, const int flags) } // set window width to desired minimal value - if (curwin->w_width < p_wiw && !curwin->w_p_wfw && !wp->w_floating) { + if (curwin->w_width < p_wiw && !curwin->w_p_wfw && !curwin->w_floating) { win_setwidth((int)p_wiw); } @@ -4592,6 +4593,7 @@ void fix_current_dir(void) do_autocmd_dirchanged(new_dir, curwin->w_localdir ? kCdScopeWindow : kCdScopeTabpage, kCdCauseWindow); } + last_chdir_reason = NULL; shorten_fnames(true); } } else if (globaldir != NULL) { @@ -4603,6 +4605,7 @@ void fix_current_dir(void) } } XFREE_CLEAR(globaldir); + last_chdir_reason = NULL; shorten_fnames(true); } } @@ -4754,6 +4757,8 @@ static void win_free(win_T *wp, tabpage_T *tp) clear_winopt(&wp->w_onebuf_opt); clear_winopt(&wp->w_allbuf_opt); + xfree(wp->w_p_lcs_chars.multispace); + vars_clear(&wp->w_vars->dv_hashtab); // free all w: variables hash_init(&wp->w_vars->dv_hashtab); unref_var_dict(wp->w_vars); @@ -5827,8 +5832,8 @@ void scroll_to_fraction(win_T *wp, int prev_height) // is visible. if (height > 0 && (!wp->w_p_scb || wp == curwin) - && (height < wp->w_buffer->b_ml.ml_line_count || - wp->w_topline > 1)) { + && (height < wp->w_buffer->b_ml.ml_line_count + || wp->w_topline > 1)) { /* * Find a value for w_topline that shows the cursor at the same * relative position in the window as before (more or less). @@ -6084,7 +6089,7 @@ void command_height(void) static void frame_add_height(frame_T *frp, int n) { frame_new_height(frp, frp->fr_height + n, false, false); - for (;; ) { + for (;;) { frp = frp->fr_parent; if (frp == NULL) { break; @@ -7010,7 +7015,7 @@ int win_getid(typval_T *argvars) wp = tp->tp_firstwin; } } - for ( ; wp != NULL; wp = wp->w_next) { + for (; wp != NULL; wp = wp->w_next) { if (--winnr == 0) { return wp->handle; } diff --git a/src/uncrustify.cfg b/src/uncrustify.cfg index c06bf41d47..558fa1759f 100644 --- a/src/uncrustify.cfg +++ b/src/uncrustify.cfg @@ -141,7 +141,7 @@ sp_enum_before_assign = ignore # ignore/add/remove/force/not_defined # Add or remove space after assignment '=' in enum. # # Overrides sp_enum_assign. -sp_enum_after_assign = ignore # ignore/add/remove/force/not_defined +sp_enum_after_assign = force # ignore/add/remove/force/not_defined # Add or remove space around assignment ':' in enum. sp_enum_colon = ignore # ignore/add/remove/force/not_defined @@ -149,11 +149,11 @@ sp_enum_colon = ignore # ignore/add/remove/force/not_defined # Add or remove space around preprocessor '##' concatenation operator. # # Default: add -sp_pp_concat = ignore # ignore/add/remove/force/not_defined +sp_pp_concat = remove # ignore/add/remove/force/not_defined # Add or remove space after preprocessor '#' stringify operator. # Also affects the '#@' charizing operator. -sp_pp_stringify = ignore # ignore/add/remove/force/not_defined +sp_pp_stringify = remove # ignore/add/remove/force/not_defined # Add or remove space before preprocessor '#' stringify operator # as in '#define x(y) L#y'. @@ -334,10 +334,10 @@ sp_after_sparen = ignore # ignore/add/remove/force/not_defined sp_sparen_brace = ignore # ignore/add/remove/force/not_defined # Add or remove space between 'do' and '{'. -sp_do_brace_open = ignore # ignore/add/remove/force/not_defined +sp_do_brace_open = force # ignore/add/remove/force/not_defined # Add or remove space between '}' and 'while'. -sp_brace_close_while = ignore # ignore/add/remove/force/not_defined +sp_brace_close_while = force # ignore/add/remove/force/not_defined # Add or remove space between 'while' and '('. Overrides sp_before_sparen. sp_while_paren_open = ignore # ignore/add/remove/force/not_defined @@ -354,18 +354,18 @@ sp_special_semi = ignore # ignore/add/remove/force/not_defined # Add or remove space before ';'. # # Default: remove -sp_before_semi = ignore # ignore/add/remove/force/not_defined +sp_before_semi = remove # ignore/add/remove/force/not_defined # Add or remove space before ';' in non-empty 'for' statements. -sp_before_semi_for = ignore # ignore/add/remove/force/not_defined +sp_before_semi_for = remove # ignore/add/remove/force/not_defined # Add or remove space before a semicolon of an empty left part of a for # statement, as in 'for ( <here> ; ; )'. -sp_before_semi_for_empty = ignore # ignore/add/remove/force/not_defined +sp_before_semi_for_empty = remove # ignore/add/remove/force/not_defined # Add or remove space between the semicolons of an empty middle part of a for # statement, as in 'for ( ; <here> ; )'. -sp_between_semi_for_empty = ignore # ignore/add/remove/force/not_defined +sp_between_semi_for_empty = remove # ignore/add/remove/force/not_defined # Add or remove space after ';', except when followed by a comment. # @@ -379,10 +379,10 @@ sp_after_semi_for = force # ignore/add/remove/force/not_defined # Add or remove space after the final semicolon of an empty part of a for # statement, as in 'for ( ; ; <here> )'. -sp_after_semi_for_empty = ignore # ignore/add/remove/force/not_defined +sp_after_semi_for_empty = remove # ignore/add/remove/force/not_defined # Add or remove space before '[' (except '[]'). -sp_before_square = ignore # ignore/add/remove/force/not_defined +sp_before_square = remove # ignore/add/remove/force/not_defined # Add or remove space before '[' for a variable definition. # @@ -393,13 +393,13 @@ sp_before_vardef_square = remove # ignore/add/remove/force/not_defined sp_before_square_asm_block = ignore # ignore/add/remove/force/not_defined # Add or remove space before '[]'. -sp_before_squares = ignore # ignore/add/remove/force/not_defined +sp_before_squares = remove # ignore/add/remove/force/not_defined # Add or remove space before C++17 structured bindings. sp_cpp_before_struct_binding = ignore # ignore/add/remove/force/not_defined # Add or remove space inside a non-empty '[' and ']'. -sp_inside_square = ignore # ignore/add/remove/force/not_defined +sp_inside_square = remove # ignore/add/remove/force/not_defined # Add or remove space inside '[]'. sp_inside_square_empty = ignore # ignore/add/remove/force/not_defined @@ -592,18 +592,18 @@ sp_func_def_paren_empty = ignore # ignore/add/remove/force/not_defined # Add or remove space inside empty function '()'. # Overrides sp_after_angle unless use_sp_after_angle_always is set to true. -sp_inside_fparens = ignore # ignore/add/remove/force/not_defined +sp_inside_fparens = remove # ignore/add/remove/force/not_defined # Add or remove space inside function '(' and ')'. -sp_inside_fparen = ignore # ignore/add/remove/force/not_defined +sp_inside_fparen = remove # ignore/add/remove/force/not_defined # Add or remove space inside the first parentheses in a function type, as in # 'void (*x)(...)'. -sp_inside_tparen = ignore # ignore/add/remove/force/not_defined +sp_inside_tparen = remove # ignore/add/remove/force/not_defined # Add or remove space between the ')' and '(' in a function type, as in # 'void (*x)(...)'. -sp_after_tparen_close = ignore # ignore/add/remove/force/not_defined +sp_after_tparen_close = remove # ignore/add/remove/force/not_defined # Add or remove space between ']' and '(' when part of a function call. sp_square_fparen = ignore # ignore/add/remove/force/not_defined @@ -649,7 +649,7 @@ sp_func_class_paren = ignore # ignore/add/remove/force/not_defined sp_func_class_paren_empty = ignore # ignore/add/remove/force/not_defined # Add or remove space between 'return' and '('. -sp_return_paren = ignore # ignore/add/remove/force/not_defined +sp_return_paren = force # ignore/add/remove/force/not_defined # Add or remove space between 'return' and '{'. sp_return_brace = ignore # ignore/add/remove/force/not_defined @@ -714,7 +714,7 @@ sp_else_brace = add # ignore/add/remove/force/not_defined sp_brace_else = add # ignore/add/remove/force/not_defined # Add or remove space between '}' and the name of a typedef on the same line. -sp_brace_typedef = ignore # ignore/add/remove/force/not_defined +sp_brace_typedef = force # ignore/add/remove/force/not_defined # Add or remove space before the '{' of a 'catch' statement, if the '{' and # 'catch' are on the same line, as in 'catch (decl) <here> {'. @@ -1632,7 +1632,7 @@ nl_using_brace = ignore # ignore/add/remove/force/not_defined nl_brace_brace = ignore # ignore/add/remove/force/not_defined # Add or remove newline between 'do' and '{'. -nl_do_brace = ignore # ignore/add/remove/force/not_defined +nl_do_brace = remove # ignore/add/remove/force/not_defined # Add or remove newline between '}' and 'while' of 'do' statement. nl_brace_while = ignore # ignore/add/remove/force/not_defined @@ -2333,7 +2333,7 @@ pos_arith = ignore # ignore/break/force/lead/trail/join/ pos_assign = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force # The position of Boolean operators in wrapped expressions. -pos_bool = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force +pos_bool = lead # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force # The position of comparison operators in wrapped expressions. pos_compare = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force @@ -3307,5 +3307,5 @@ set QUESTION REAL_FATTR_CONST set QUESTION REAL_FATTR_NONNULL_ALL set QUESTION REAL_FATTR_PURE set QUESTION REAL_FATTR_WARN_UNUSED_RESULT -# option(s) with 'not default' value: 69 +# option(s) with 'not default' value: 87 # diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua index f4c476560d..c68bc18eed 100644 --- a/test/functional/core/fileio_spec.lua +++ b/test/functional/core/fileio_spec.lua @@ -15,6 +15,7 @@ local read_file = helpers.read_file local trim = helpers.trim local currentdir = helpers.funcs.getcwd local iswin = helpers.iswin +local assert_alive = helpers.assert_alive describe('fileio', function() before_each(function() @@ -26,6 +27,7 @@ describe('fileio', function() os.remove('Xtest_startup_file1~') os.remove('Xtest_startup_file2') os.remove('Xtest_тест.md') + os.remove('Xtest-u8-int-max') rmdir('Xtest_startup_swapdir') rmdir('Xtest_backupdir') end) @@ -128,5 +130,12 @@ describe('fileio', function() table.insert(text, '') eq(text, funcs.readfile(fname, 'b')) end) + it('read invalid u8 over INT_MAX doesn\'t segfault', function() + clear() + command('call writefile(0zFFFFFFFF, "Xtest-u8-int-max")') + -- This should not segfault + command('edit ++enc=utf32 Xtest-u8-int-max') + assert_alive() + end) end) diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua index d1dce0f8da..4220d68ee1 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -560,7 +560,7 @@ describe('user config init', function() it('loads default lua config, but shows an error', function() clear{ args_rm={'-u'}, env=xenv } - feed('<cr>') -- TODO check this, test execution is blocked without it + feed('<cr>') -- confirm "Conflicting config ..." message eq(1, eval('g:lua_rc')) matches('^E5422: Conflicting configs', meths.exec('messages', true)) end) diff --git a/test/functional/ex_cmds/cd_spec.lua b/test/functional/ex_cmds/cd_spec.lua index 283fcf9672..f9cce0deb6 100644 --- a/test/functional/ex_cmds/cd_spec.lua +++ b/test/functional/ex_cmds/cd_spec.lua @@ -294,7 +294,16 @@ describe("getcwd()", function () command('set autochdir') command('edit ' .. directories.global .. '/foo') eq(curdir .. pathsep .. directories.global, cwd()) + eq(curdir, wcwd()) + call('mkdir', 'bar') + command('edit ' .. 'bar/foo') + eq(curdir .. pathsep .. directories.global .. pathsep .. 'bar', cwd()) + eq(curdir, wcwd()) + command('lcd ..') + eq(curdir .. pathsep .. directories.global, cwd()) + eq(curdir .. pathsep .. directories.global, wcwd()) + command('edit') + eq(curdir .. pathsep .. directories.global .. pathsep .. 'bar', cwd()) + eq(curdir .. pathsep .. directories.global, wcwd()) end) end) - - diff --git a/test/functional/fixtures/api_level_8.mpack b/test/functional/fixtures/api_level_8.mpack Binary files differnew file mode 100644 index 0000000000..0447fce3ed --- /dev/null +++ b/test/functional/fixtures/api_level_8.mpack diff --git a/test/functional/legacy/autochdir_spec.lua b/test/functional/legacy/autochdir_spec.lua index 466e3ed830..37a94476a0 100644 --- a/test/functional/legacy/autochdir_spec.lua +++ b/test/functional/legacy/autochdir_spec.lua @@ -1,10 +1,11 @@ local lfs = require('lfs') local helpers = require('test.functional.helpers')(after_each) -local clear, eq = helpers.clear, helpers.eq -local eval, command = helpers.eval, helpers.command +local clear, eq, matches = helpers.clear, helpers.eq, helpers.matches +local eval, command, call = helpers.eval, helpers.command, helpers.call +local exec_capture = helpers.exec_capture describe('autochdir behavior', function() - local dir = 'Xtest-functional-legacy-autochdir' + local dir = 'Xtest_functional_legacy_autochdir' before_each(function() lfs.mkdir(dir) @@ -23,4 +24,35 @@ describe('autochdir behavior', function() eq('Xtest', eval("expand('%')")) eq(dir, eval([[substitute(getcwd(), '.*[/\\]\(\k*\)', '\1', '')]])) end) + + it(':verbose pwd shows whether autochdir is used', function() + local subdir = 'Xautodir' + command('cd '..dir) + local cwd = eval('getcwd()') + command('edit global.txt') + matches('%[global%].*'..dir, exec_capture('verbose pwd')) + call('mkdir', subdir) + command('split '..subdir..'/local.txt') + command('lcd '..subdir) + matches('%[window%].*'..dir..'[/\\]'..subdir, exec_capture('verbose pwd')) + command('set autochdir') + command('wincmd w') + matches('%[autochdir%].*'..dir, exec_capture('verbose pwd')) + command('lcd '..cwd) + matches('%[window%].*'..dir, exec_capture('verbose pwd')) + command('tcd '..cwd) + matches('%[tabpage%].*'..dir, exec_capture('verbose pwd')) + command('cd '..cwd) + matches('%[global%].*'..dir, exec_capture('verbose pwd')) + command('edit') + matches('%[autochdir%].*'..dir, exec_capture('verbose pwd')) + command('wincmd w') + matches('%[autochdir%].*'..dir..'[/\\]'..subdir, exec_capture('verbose pwd')) + command('set noautochdir') + matches('%[autochdir%].*'..dir..'[/\\]'..subdir, exec_capture('verbose pwd')) + command('wincmd w') + matches('%[global%].*'..dir, exec_capture('verbose pwd')) + command('wincmd w') + matches('%[window%].*'..dir..'[/\\]'..subdir, exec_capture('verbose pwd')) + end) end) diff --git a/test/functional/legacy/fnamemodify_spec.lua b/test/functional/legacy/fnamemodify_spec.lua index 6a5538c26f..6262db3a2f 100644 --- a/test/functional/legacy/fnamemodify_spec.lua +++ b/test/functional/legacy/fnamemodify_spec.lua @@ -29,7 +29,7 @@ describe('filename modifiers', function() call assert_equal('test.out', fnamemodify('test.out', ':.')) call assert_equal('../testdir/a', fnamemodify('../testdir/a', ':.')) call assert_equal(fnamemodify(tmpdir, ':~').'/test.out', fnamemodify('test.out', ':~')) - call assert_equal('../testdir/a', fnamemodify('../testdir/a', ':~')) + call assert_equal(fnamemodify(tmpdir, ':~').'/../testdir/a', fnamemodify('../testdir/a', ':~')) call assert_equal('a', fnamemodify('../testdir/a', ':t')) call assert_equal('', fnamemodify('.', ':p:t')) call assert_equal('test.out', fnamemodify('test.out', ':p:t')) diff --git a/test/functional/legacy/packadd_spec.lua b/test/functional/legacy/packadd_spec.lua index 48cd3ef9f8..4f9f5a0237 100644 --- a/test/functional/legacy/packadd_spec.lua +++ b/test/functional/legacy/packadd_spec.lua @@ -20,6 +20,9 @@ describe('packadd', function() func SetUp() let s:topdir = expand(getcwd() . '/Xdir') + if isdirectory(s:topdir) + call delete(s:topdir, 'rf') + endif exe 'set packpath=' . s:topdir let s:plugdir = expand(s:topdir . '/pack/mine/opt/mytest') endfunc diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index 6414483c0d..927ee8060d 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -110,20 +110,35 @@ describe('vim.diagnostic', function() it('retrieves diagnostics from all buffers and namespaces', function() local result = exec_lua [[ - vim.diagnostic.set(diagnostic_ns, 1, { + local other_bufnr = vim.api.nvim_create_buf(true, false) + local lines = vim.api.nvim_buf_get_lines(diagnostic_bufnr, 0, -1, true) + vim.api.nvim_buf_set_lines(other_bufnr, 0, 1, false, lines) + + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic #1', 1, 1, 1, 1), make_error('Diagnostic #2', 2, 1, 2, 1), }) - vim.diagnostic.set(other_ns, 2, { + vim.diagnostic.set(other_ns, other_bufnr, { make_error('Diagnostic #3', 3, 1, 3, 1), }) return vim.diagnostic.get() ]] eq(3, #result) - eq(2, exec_lua([[return #vim.tbl_filter(function(d) return d.bufnr == 1 end, ...)]], result)) + eq(2, exec_lua([[return #vim.tbl_filter(function(d) return d.bufnr == diagnostic_bufnr end, ...)]], result)) eq('Diagnostic #1', result[1].message) end) + it('resolves buffer number 0 to the current buffer', function() + eq(2, exec_lua [[ + vim.api.nvim_set_current_buf(diagnostic_bufnr) + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #1', 1, 1, 1, 1), + make_error('Diagnostic #2', 2, 1, 2, 1), + }) + return #vim.diagnostic.get(0) + ]]) + end) + it('saves and count a single error', function() eq(1, exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { @@ -339,6 +354,16 @@ describe('vim.diagnostic', function() eq(0, result[5]) eq(3, result[6]) end) + + it("doesn't error after bwipeout on buffer", function() + exec_lua [[ + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {{ lnum = 0, end_lnum = 0, col = 0, end_col = 0 }}) + vim.cmd("bwipeout! " .. diagnostic_bufnr) + + vim.diagnostic.show(diagnostic_ns) + vim.diagnostic.hide(diagnostic_ns) + ]] + end) end) describe('enable() and disable()', function() @@ -625,6 +650,15 @@ describe('vim.diagnostic', function() ]]) end) + + it("doesn't error after bwipeout called on buffer", function() + exec_lua [[ + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {{ lnum = 0, end_lnum = 0, col = 0, end_col = 0 }}) + vim.cmd("bwipeout! " .. diagnostic_bufnr) + + vim.diagnostic.reset(diagnostic_ns) + ]] + end) end) describe('get_next_pos()', function() @@ -682,6 +716,19 @@ describe('vim.diagnostic', function() return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns } ]]) end) + + it('works with diagnostics past the end of the line #16349', function() + eq({4, 0}, exec_lua [[ + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #1', 3, 9001, 3, 9001), + make_error('Diagnostic #2', 4, 0, 4, 0), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {1, 1}) + vim.diagnostic.goto_next { float = false } + return vim.diagnostic.get_next_pos { namespace = diagnostic_ns } + ]]) + end) end) describe('get_prev_pos()', function() @@ -878,7 +925,7 @@ describe('vim.diagnostic', function() ]] eq(1, exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]]) - -- eq(1, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) + eq(1, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) end) it('allows filtering by severity', function() @@ -1323,7 +1370,7 @@ describe('vim.diagnostic', function() } vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(0, {header = false}) + local float_bufnr, winnr = vim.diagnostic.open_float(0, {header = false, scope="buffer"}) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines @@ -1340,7 +1387,7 @@ describe('vim.diagnostic', function() vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) vim.api.nvim_win_set_cursor(0, {2, 1}) - local float_bufnr, winnr = vim.diagnostic.open_float(0, {header=false, scope="line"}) + local float_bufnr, winnr = vim.diagnostic.open_float(0, {header=false}) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines @@ -1355,7 +1402,7 @@ describe('vim.diagnostic', function() vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) vim.api.nvim_win_set_cursor(0, {1, 1}) - local float_bufnr, winnr = vim.diagnostic.open_float(0, {header=false, scope="line", pos=1}) + local float_bufnr, winnr = vim.diagnostic.open_float(0, {header=false, pos=1}) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines @@ -1419,7 +1466,7 @@ describe('vim.diagnostic', function() } vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, {scope="line"}) + local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return #lines @@ -1486,7 +1533,7 @@ describe('vim.diagnostic', function() } vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, {header = false, scope = "line", pos = 5}) + local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, {header = false, pos = 5}) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return #lines @@ -1618,7 +1665,7 @@ describe('vim.diagnostic', function() } vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(0, {header = false}) + local float_bufnr, winnr = vim.diagnostic.open_float(0, {header = false, scope = "buffer"}) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines @@ -1631,7 +1678,7 @@ describe('vim.diagnostic', function() } vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(0, {header = false, prefix = ""}) + local float_bufnr, winnr = vim.diagnostic.open_float(0, {header = false, scope = "buffer", prefix = ""}) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines @@ -1640,7 +1687,7 @@ describe('vim.diagnostic', function() eq({'1. Syntax error', '2. Some warning'}, exec_lua [[ local diagnostics = { make_error("Syntax error", 0, 1, 0, 3), - make_warning("Some warning", 1, 1, 1, 3), + make_warning("Some warning", 0, 1, 0, 3), } vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) diff --git a/test/functional/lua/uri_spec.lua b/test/functional/lua/uri_spec.lua index 81f1820986..dbfbe2dbfe 100644 --- a/test/functional/lua/uri_spec.lua +++ b/test/functional/lua/uri_spec.lua @@ -143,8 +143,8 @@ describe('URI methods', function() end) it('uri_to_fname returns non-file scheme URI without authority unchanged', function() - eq('zipfile:/path/to/archive.zip%3A%3Afilename.txt', exec_lua [[ - return vim.uri_to_fname('zipfile:/path/to/archive.zip%3A%3Afilename.txt') + eq('zipfile:///path/to/archive.zip%3A%3Afilename.txt', exec_lua [[ + return vim.uri_to_fname('zipfile:///path/to/archive.zip%3A%3Afilename.txt') ]]) end) end) @@ -186,7 +186,7 @@ describe('URI methods', function() end) it('uri_to_bufnr & uri_from_bufnr returns original uri for non-file uris without authority', function() - local uri = 'zipfile:/path/to/archive.zip%3A%3Afilename.txt' + local uri = 'zipfile:///path/to/archive.zip%3A%3Afilename.txt' local test_case = string.format([[ local uri = '%s' return vim.uri_from_bufnr(vim.uri_to_bufnr(uri)) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 3832d27a22..28471bdd46 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -396,6 +396,20 @@ describe('lua stdlib', function() return t1.f() ~= t2.f() ]])) + ok(exec_lua([[ + local t1 = {a = 5} + t1.self = t1 + local t2 = vim.deepcopy(t1) + return t2.self == t2 and t2.self ~= t1 + ]])) + + ok(exec_lua([[ + local mt = {mt=true} + local t1 = setmetatable({a = 5}, mt) + local t2 = vim.deepcopy(t1) + return getmetatable(t2) == mt + ]])) + eq('Error executing lua: vim/shared.lua:0: Cannot deepcopy object of type thread', pcall_err(exec_lua, [[ local thread = coroutine.create(function () return 0 end) diff --git a/test/functional/options/chars_spec.lua b/test/functional/options/chars_spec.lua index 5439ca3dba..a082204980 100644 --- a/test/functional/options/chars_spec.lua +++ b/test/functional/options/chars_spec.lua @@ -67,36 +67,52 @@ describe("'fillchars'", function() shouldfail('eob:xy') -- two ascii chars shouldfail('eob:\255', 'eob:<ff>') -- invalid UTF-8 end) - it('has global value', function() - screen:try_resize(50, 5) - insert("foo\nbar") - command('set laststatus=0') - command('1,2fold') - command('vsplit') - command('set fillchars=fold:x') - screen:expect([[ - ^+-- 2 lines: fooxxxxxxxx│+-- 2 lines: fooxxxxxxx| - ~ │~ | - ~ │~ | - ~ │~ | - | - ]]) - end) - it('has local window value', function() - screen:try_resize(50, 5) - insert("foo\nbar") - command('set laststatus=0') - command('1,2fold') - command('vsplit') - command('setl fillchars=fold:x') - screen:expect([[ - ^+-- 2 lines: fooxxxxxxxx│+-- 2 lines: foo·······| - ~ │~ | - ~ │~ | - ~ │~ | - | - ]]) - end) + end) + it('has global value', function() + screen:try_resize(50, 5) + insert("foo\nbar") + command('set laststatus=0') + command('1,2fold') + command('vsplit') + command('set fillchars=fold:x') + screen:expect([[ + ^+-- 2 lines: fooxxxxxxxx│+-- 2 lines: fooxxxxxxx| + ~ │~ | + ~ │~ | + ~ │~ | + | + ]]) + end) + it('has window-local value', function() + screen:try_resize(50, 5) + insert("foo\nbar") + command('set laststatus=0') + command('1,2fold') + command('vsplit') + command('setl fillchars=fold:x') + screen:expect([[ + ^+-- 2 lines: fooxxxxxxxx│+-- 2 lines: foo·······| + ~ │~ | + ~ │~ | + ~ │~ | + | + ]]) + end) + it('using :set clears window-local value', function() + screen:try_resize(50, 5) + insert("foo\nbar") + command('set laststatus=0') + command('setl fillchars=fold:x') + command('1,2fold') + command('vsplit') + command('set fillchars&') + screen:expect([[ + ^+-- 2 lines: foo········│+-- 2 lines: fooxxxxxxx| + ~ │~ | + ~ │~ | + ~ │~ | + | + ]]) end) end) @@ -122,7 +138,7 @@ describe("'listchars'", function() | ]]) end) - it('has value local to window', function() + it('has window-local value', function() feed('i<tab><tab><tab><esc>') command('set list laststatus=0') command('setl listchars=tab:<->') @@ -136,4 +152,18 @@ describe("'listchars'", function() | ]]) end) + it('using :set clears window-local value', function() + feed('i<tab><tab><tab><esc>') + command('set list laststatus=0') + command('setl listchars=tab:<->') + command('vsplit') + command('set listchars=tab:>-,eol:$') + screen:expect([[ + >------->-------^>-------$│<------><------><------>| + ~ │~ | + ~ │~ | + ~ │~ | + | + ]]) + end) end) diff --git a/test/functional/plugin/lsp/incremental_sync_spec.lua b/test/functional/plugin/lsp/incremental_sync_spec.lua index 890db4abf5..5dd34e7665 100644 --- a/test/functional/plugin/lsp/incremental_sync_spec.lua +++ b/test/functional/plugin/lsp/incremental_sync_spec.lua @@ -297,7 +297,31 @@ describe('incremental synchronization', function() } test_edit({"🔥"}, {"x"}, expected_text_changes, 'utf-16', '\n') end) - it('deleting a multiple lines containing multibyte characters', function() + it('deleting a multibyte character from a long line', function() + local expected_text_changes = { + { + range = { + ['start'] = { + character = 85, + line = 1 + }, + ['end'] = { + character = 86, + line = 1 + } + }, + rangeLength = 1, + text = '' + } + } + local original_lines = { + "\\begin{document}", + "→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→", + "\\end{document}", + } + test_edit(original_lines, {"jx"}, expected_text_changes, 'utf-16', '\n') + end) + it('deleting multiple lines containing multibyte characters', function() local expected_text_changes = { { range = { diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 228fc06e9b..b12d4227d5 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -66,7 +66,10 @@ local function fake_lsp_server_setup(test_name, timeout_ms, options) end end; }); - root_dir = vim.loop.cwd(); + workspace_folders = {{ + uri = 'file://' .. vim.loop.cwd(), + name = 'test_folder', + }}; on_init = function(client, result) TEST_RPC_CLIENT = client vim.rpcrequest(1, "init", result) @@ -153,7 +156,10 @@ describe('LSP', function() "-c", string.format("lua TEST_NAME = %q", test_name), "-c", "luafile "..fixture_filename; }; - root_dir = vim.loop.cwd(); + workspace_folders = {{ + uri = 'file://' .. vim.loop.cwd(), + name = 'test_folder', + }}; } end TEST_CLIENT1 = test__start_client() diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index ffaa4141c4..1138cfbf4c 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -231,11 +231,11 @@ void ui_refresh(void) insert('char* astring = "\\n"; (1 + 1) * 2 != 2;') local res = exec_lua([[ - cquery = vim.treesitter.parse_query("c", '((_) @plus (vim-match? @plus "^\\\\+$"))'.. - '((_) @times (vim-match? @times "^\\\\*$"))'.. - '((_) @paren (vim-match? @paren "^\\\\($"))'.. - '((_) @escape (vim-match? @escape "^\\\\\\\\n$"))'.. - '((_) @string (vim-match? @string "^\\"\\\\\\\\n\\"$"))') + cquery = vim.treesitter.parse_query("c", '([_] @plus (#vim-match? @plus "^\\\\+$"))'.. + '([_] @times (#vim-match? @times "^\\\\*$"))'.. + '([_] @paren (#vim-match? @paren "^\\\\($"))'.. + '([_] @escape (#vim-match? @escape "^\\\\\\\\n$"))'.. + '([_] @string (#vim-match? @string "^\\"\\\\\\\\n\\"$"))') parser = vim.treesitter.get_parser(0, "c") tree = parser:parse()[1] res = {} @@ -321,7 +321,7 @@ void ui_refresh(void) insert('char* astring = "Hello World!";') local res = exec_lua([[ - cquery = vim.treesitter.parse_query("c", '((_) @quote (vim-match? @quote "^\\"$")) ((_) @quote (lua-match? @quote "^\\"$"))') + cquery = vim.treesitter.parse_query("c", '([_] @quote (#vim-match? @quote "^\\"$")) ([_] @quote (#lua-match? @quote "^\\"$"))') parser = vim.treesitter.get_parser(0, "c") tree = parser:parse()[1] res = {} diff --git a/test/unit/path_spec.lua b/test/unit/path_spec.lua index 41954de9be..15ce59747e 100644 --- a/test/unit/path_spec.lua +++ b/test/unit/path_spec.lua @@ -54,15 +54,21 @@ describe('path.c', function() eq(lfs.currentdir(), (ffi.string(buffer))) end) - itp('fails if the given directory does not exist', function() - eq(FAIL, path_full_dir_name('does_not_exist', buffer, length)) - end) - itp('works with a normal relative dir', function() local result = path_full_dir_name('unit-test-directory', buffer, length) eq(lfs.currentdir() .. '/unit-test-directory', (ffi.string(buffer))) eq(OK, result) end) + + itp('works with a non-existing relative dir', function() + local result = path_full_dir_name('does-not-exist', buffer, length) + eq(lfs.currentdir() .. '/does-not-exist', (ffi.string(buffer))) + eq(OK, result) + end) + + itp('fails with a non-existing absolute dir', function() + eq(FAIL, path_full_dir_name('/does_not_exist', buffer, length)) + end) end) describe('path_full_compare', function() diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt index 8ad71cfd3a..52839d8efa 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -97,7 +97,7 @@ endif() if(MINGW AND CMAKE_GENERATOR MATCHES "Ninja") find_program(MAKE_PRG NAMES mingw32-make) if(NOT MAKE_PRG) - message(FATAL_ERROR "GNU Make for mingw32 is required to build the dependecies.") + message(FATAL_ERROR "GNU Make for mingw32 is required to build the dependencies.") else() message(STATUS "Found GNU Make for mingw32: ${MAKE_PRG}") endif() @@ -157,8 +157,8 @@ set(LUAJIT_SHA256 6c9e46877db2df16ca0fa76db4043ed30a1ae60c89d9ba2c3e4d35eb2360cd set(LUA_URL https://www.lua.org/ftp/lua-5.1.5.tar.gz) set(LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333) -set(LUAROCKS_URL https://github.com/luarocks/luarocks/archive/v3.7.0.tar.gz) -set(LUAROCKS_SHA256 968c98ae894cea2c850f077133e3feb9f8ce94df7a33a5611bd4d25e07c94925) +set(LUAROCKS_URL https://github.com/luarocks/luarocks/archive/v3.8.0.tar.gz) +set(LUAROCKS_SHA256 ab6612ca9ab87c6984871d2712d05525775e8b50172701a0a1cabddf76de2be7) set(UNIBILIUM_URL https://github.com/neovim/unibilium/archive/92d929f.tar.gz) set(UNIBILIUM_SHA256 29815283c654277ef77a3adcc8840db79ddbb20a0f0b0c8f648bd8cd49a02e4b) @@ -200,11 +200,11 @@ set(GETTEXT_SHA256 66415634c6e8c3fa8b71362879ec7575e27da43da562c798a8a2f223e6e47 set(LIBICONV_URL https://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.15.tar.gz) set(LIBICONV_SHA256 ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc8913178) -set(TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/5aa0bbb.tar.gz) -set(TREESITTER_C_SHA256 a5dcb37460d83002dfae7f9a208170ddbc9a047f231b9d6b75da7d36d707db2f) +set(TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.20.1.tar.gz) +set(TREESITTER_C_SHA256 ffcc2ef0eded59ad1acec9aec4f9b0c7dd209fc1a85d85f8b0e81298e3dddcc2) -set(TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/7890a29db0b186b7b21a0a95d99fa6c562b8316b.tar.gz) -set(TREESITTER_SHA256 634006b0336a5eef1b07d2f80a4d4f8ac1522bf15759ec3e5dda0032a734fb19) +set(TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.20.1.tar.gz) +set(TREESITTER_SHA256 12a3f7206af3028dbe8a0de50d8ebd6d7010bf762db918acae76fc7585f1258d) if(USE_BUNDLED_UNIBILIUM) include(BuildUnibilium) |