diff options
96 files changed, 1804 insertions, 1803 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 166fef028d..482d8c198d 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -1851,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 @@ -2175,7 +2175,7 @@ nvim_buf_set_text({buffer}, {start_row}, {start_col}, {end_row}, {end_col}, Parameters: ~ {buffer} Buffer handle, or 0 for current buffer {start_row} First line index - {start_column} Last column + {start_column} First column {end_row} Last line index {end_column} Last column {replacement} Array of lines to use as replacement @@ -2500,7 +2500,7 @@ nvim_set_decoration_provider({ns_id}, {opts}) specific window. ["win", winid, bufnr, topline, botline_guess] • on_line: called for each buffer line being - redrawn. (The interation with fold lines is + 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 2737ac9b9f..5d9f9590e2 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 @@ -793,7 +793,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 2fab111498..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: @@ -573,9 +575,6 @@ buf_request_sync({bufnr}, {method}, {params}, {timeout_ms}) error, returns `(nil, err)` where `err` is a string describing the failure reason. -check_clients_closed() *vim.lsp.check_clients_closed()* - TODO: Documentation - client() *vim.lsp.client* LSP client object. You can get an active client object via |vim.lsp.get_client_by_id()| or @@ -648,12 +647,21 @@ 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 @@ -676,6 +684,8 @@ 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} number client id @@ -717,16 +727,6 @@ omnifunc({findstart}, {base}) *vim.lsp.omnifunc()* |complete-items| |CompleteDone| - *vim.lsp.prepare()* -prepare({bufnr}, {firstline}, {lastline}, {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. @@ -745,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. @@ -768,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()|, @@ -792,19 +796,16 @@ start_client({config}) *vim.lsp.start_client()* 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 (code action, code - lenses, ...) triggers the command. + 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. @@ -873,6 +874,15 @@ start_client({config}) *vim.lsp.start_client()* 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 @@ -981,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 @@ -1051,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: ~ @@ -1083,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. @@ -1340,25 +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}, {offset_encoding}) Shows a list of document highlights for a certain buffer. Parameters: ~ - {bufnr} buffer id - {references} List of `DocumentHighlight` objects to - highlight - {offset_encoding} string utf-8|utf-16|utf-32|nil defaults - to utf-16 + {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 @@ -1425,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. @@ -1458,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. @@ -1615,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 + • max_height: (number) maximal height of floating window - • focusable (boolean, default true): Make + • 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 @@ -1774,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 @@ -1853,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 @@ -1912,10 +1898,6 @@ compute_diff({prev_lines}, {curr_lines}, {firstline}, {lastline}, Return: ~ table TextDocumentContentChangeEvent see https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#textDocumentContentChangeEvent - *vim.lsp.sync.compute_line_length()* -compute_line_length({line}, {offset_encoding}) - TODO: Documentation - ============================================================================== Lua module: vim.lsp.protocol *lsp-protocol* diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index cc70c7b2fd..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}, {handle}) *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: ~ 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 0bc7a305f0..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. @@ -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 88dcb38dd1..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 @@ -1655,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 @@ -1714,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..ebf504fd42 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -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 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 f185e3973f..5df2a4d144 100644 --- a/runtime/lua/vim/lsp/sync.lua +++ b/runtime/lua/vim/lsp/sync.lua @@ -74,6 +74,7 @@ local function byte_to_utf(line, byte, offset_encoding) return utf_idx + 1 end +---@private local function compute_line_length(line, offset_encoding) local length local _ @@ -133,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 } @@ -187,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 } 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/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/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/auevents.lua b/src/nvim/auevents.lua index 6be51c504c..7e7114b291 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 @@ -126,6 +127,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 1512d6bcd5..f2f4950e58 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -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); } } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index b97282dd1a..d3d0121632 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -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"), diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 714c60c27e..dfadd28ebe 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -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) { @@ -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) { diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 34c3b3889e..62919c98f7 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -7753,6 +7753,7 @@ void post_chdir(CdScope scope, bool trigger_dirchanged) abort(); } + last_chdir_reason = NULL; shorten_fnames(true); if (trigger_dirchanged) { @@ -7870,7 +7871,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"; diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index b803acdddc..c90115d796 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -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; diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 9c065c09f4..b5e1fda9f1 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -789,6 +789,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); diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c index 32b471efb0..93fcdc55a6 100644 --- a/src/nvim/hardcopy.c +++ b/src/nvim/hardcopy.c @@ -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[] = { diff --git a/src/nvim/lib/khash.h b/src/nvim/lib/khash.h index 8cfeb03cc4..e81db43038 100644 --- a/src/nvim/lib/khash.h +++ b/src/nvim/lib/khash.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/memory.c b/src/nvim/memory.c index 9683499eae..559a3cc435 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(); diff --git a/src/nvim/ops.c b/src/nvim/ops.c index b4b9545daf..09979c4ef5 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -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; @@ -3340,6 +3357,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; @@ -3386,6 +3404,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 @@ -3405,10 +3427,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 @@ -3520,12 +3547,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; } diff --git a/src/nvim/option.c b/src/nvim/option.c index 44b7d98e88..45e2032b35 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -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' diff --git a/src/nvim/path.c b/src/nvim/path.c index 19c820e4dd..7b9081eafa 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -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/search.c b/src/nvim/search.c index f45ae102d2..2e45a8f509 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -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; } @@ -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; diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 1f0ebcd963..49f8bbab37 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -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(' '); } 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_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_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_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/window.c b/src/nvim/window.c index 9c13264684..e328ff5467 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -4592,6 +4592,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 +4604,7 @@ void fix_current_dir(void) } } XFREE_CLEAR(globaldir); + last_chdir_reason = NULL; shorten_fnames(true); } } @@ -4754,6 +4756,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); 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/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_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 1bdfa7a6dd..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() @@ -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) |