From 144279ef30a432ac8416746e3491f3120ae9b4e8 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Fri, 3 Feb 2023 09:18:18 +0100 Subject: vim-patch:be4e01637e71 (#22103) Update runtime files. https://github.com/vim/vim/commit/be4e01637e71c8d5095c33b9861fd70b41476732 Co-authored-by: Bram Moolenaar --- runtime/autoload/tohtml.vim | 424 +++++++++++++++++++++++--------------------- 1 file changed, 222 insertions(+), 202 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/tohtml.vim b/runtime/autoload/tohtml.vim index 4ae17815ba..8a1ba14364 100644 --- a/runtime/autoload/tohtml.vim +++ b/runtime/autoload/tohtml.vim @@ -1,6 +1,6 @@ " Vim autoload file for the tohtml plugin. " Maintainer: Ben Fritz -" Last Change: 2019 Aug 16 +" Last Change: 2023 Jan 01 " " Additional contributors: " @@ -351,63 +351,65 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{ let s:old_magic = &magic set magic - if s:settings.use_xhtml - if s:settings.encoding != "" - let xml_line = "" - else - let xml_line = "" + let html = [] + if !s:settings.no_doc + if s:settings.use_xhtml + if s:settings.encoding != "" + let xml_line = "" + else + let xml_line = "" + endif + let tag_close = ' />' endif - let tag_close = ' />' - endif - let style = [s:settings.use_xhtml ? "" : '-->'] - let body_line = '' + let style = [s:settings.use_xhtml ? "" : '-->'] + let body_line = '' - let html = [] - let s:html5 = 0 - if s:settings.use_xhtml - call add(html, xml_line) - endif - if s:settings.use_xhtml - call add(html, "") - call add(html, '') - elseif s:settings.use_css && !s:settings.no_pre - call add(html, "") - call add(html, '') - let s:html5 = 1 - else - call add(html, '') - call add(html, '') - endif - call add(html, '') - - " include encoding as close to the top as possible, but only if not already - " contained in XML information - if s:settings.encoding != "" && !s:settings.use_xhtml - if s:html5 - call add(html, '") + call add(html, '') + elseif s:settings.use_css && !s:settings.no_pre + call add(html, "") + call add(html, '') + let s:html5 = 1 else - call add(html, "') + call add(html, '') endif - endif + call add(html, '') - call add(html, 'diff') - call add(html, '') - let body_line_num = len(html) - call add(html, '') + " include encoding as close to the top as possible, but only if not already + " contained in XML information + if s:settings.encoding != "" && !s:settings.use_xhtml + if s:html5 + call add(html, 'diff') + call add(html, '') + let body_line_num = len(html) + call add(html, '') + endif call add(html, "") call add(html, '') @@ -430,47 +432,53 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{ " When not using CSS or when using xhtml, the line can be important. " Assume it will be the same for all buffers and grab it from the first " buffer. Similarly, need to grab the body end line as well. - if body_line == '' - 1 - call search('', 'b') - let s:body_end_line = getline('.') - endif + if !s:settings.no_doc + if body_line == '' + 1 + call search('', 'b') + let s:body_end_line = getline('.') + endif - " Grab the style information. Some of this will be duplicated so only insert - " it if it's not already there. {{{ - 1 - let style_start = search('^') - 1 - let style_end = search('^') - if style_start > 0 && style_end > 0 - let buf_styles = getline(style_start + 1, style_end - 1) - for a_style in buf_styles - if index(style, a_style) == -1 - if diff_style_start == 0 - if a_style =~ '\') + 1 + let style_end = search('^') + if style_start > 0 && style_end > 0 + let buf_styles = getline(style_start + 1, style_end - 1) + for a_style in buf_styles + if index(style, a_style) == -1 + if diff_style_start == 0 + if a_style =~ '\\_s\+.*id='oneCharWidth'.*\_s\+.*id='oneInputWidth'.*\_s\+.*id='oneEmWidth'\)\?\zs/d_ - $ - ??,$d_ + " Delete those parts that are not needed so we can include the rest into the + " resulting table. + 1,/^\_s\+.*id='oneCharWidth'.*\_s\+.*id='oneInputWidth'.*\_s\+.*id='oneEmWidth'\)\?\zs/d_ + $ + ??,$d_ + elseif !s:settings.no_modeline + " remove modeline from source files if it is included and we haven't deleted + " due to removing html footer already + $d + endif let temp = getline(1,'$') " clean out id on the main content container because we already set it on " the table @@ -478,7 +486,11 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{ " undo deletion of start and end part " so we can later save the file as valid html " TODO: restore using grabbed lines if undolevel is 1? - normal! 2u + if !s:settings.no_doc + normal! 2u + elseif !s:settings.no_modeline + normal! u + endif if s:settings.use_css call add(html, '') call add(html, '
') elseif s:settings.use_xhtml @@ -495,17 +507,23 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{ quit! endfor - let html[body_line_num] = body_line + if !s:settings.no_doc + let html[body_line_num] = body_line + endif call add(html, '
') - call add(html, s:body_end_line) - call add(html, '') + if !s:settings.no_doc + call add(html, s:body_end_line) + call add(html, '') + endif " The generated HTML is admittedly ugly and takes a LONG time to fold. " Make sure the user doesn't do syntax folding when loading a generated file, " using a modeline. - call add(html, '') + if !s:settings.no_modeline + call add(html, '') + endif let i = 1 let name = "Diff" . (s:settings.use_xhtml ? ".xhtml" : ".html") @@ -542,129 +560,131 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{ call append(0, html) - if len(style) > 0 - 1 - let style_start = search('^')-1 + if !s:settings.no_doc + if len(style) > 0 + 1 + let style_start = search('^')-1 - " add required javascript in reverse order so we can just call append again - " and again without adjusting {{{ + " add required javascript in reverse order so we can just call append again + " and again without adjusting {{{ - let s:uses_script = s:settings.dynamic_folds || s:settings.line_ids + let s:uses_script = s:settings.dynamic_folds || s:settings.line_ids - " insert script closing tag if needed - if s:uses_script - call append(style_start, [ - \ '', - \ s:settings.use_xhtml ? '//]]>' : '-->', - \ "" - \ ]) - endif + " insert script closing tag if needed + if s:uses_script + call append(style_start, [ + \ '', + \ s:settings.use_xhtml ? '//]]>' : '-->', + \ "" + \ ]) + endif - " insert javascript to get IDs from line numbers, and to open a fold before - " jumping to any lines contained therein - if s:settings.line_ids - call append(style_start, [ - \ " /* Always jump to new location even if the line was hidden inside a fold, or", - \ " * we corrected the raw number to a line ID.", - \ " */", - \ " if (lineElem) {", - \ " lineElem.scrollIntoView(true);", - \ " }", - \ " return true;", - \ "}", - \ "if ('onhashchange' in window) {", - \ " window.onhashchange = JumpToLine;", - \ "}" - \ ]) + " insert javascript to get IDs from line numbers, and to open a fold before + " jumping to any lines contained therein + if s:settings.line_ids + call append(style_start, [ + \ " /* Always jump to new location even if the line was hidden inside a fold, or", + \ " * we corrected the raw number to a line ID.", + \ " */", + \ " if (lineElem) {", + \ " lineElem.scrollIntoView(true);", + \ " }", + \ " return true;", + \ "}", + \ "if ('onhashchange' in window) {", + \ " window.onhashchange = JumpToLine;", + \ "}" + \ ]) - if s:settings.dynamic_folds + if s:settings.dynamic_folds + call append(style_start, [ + \ "", + \ " /* navigate upwards in the DOM tree to open all folds containing the line */", + \ " var node = lineElem;", + \ " while (node && node.id != 'vimCodeElement".s:settings.id_suffix."')", + \ " {", + \ " if (node.className == 'closed-fold')", + \ " {", + \ " /* toggle open the fold ID (remove window ID) */", + \ " toggleFold(node.id.substr(4));", + \ " }", + \ " node = node.parentNode;", + \ " }", + \ ]) + endif + endif + + if s:settings.line_ids call append(style_start, [ \ "", - \ " /* navigate upwards in the DOM tree to open all folds containing the line */", - \ " var node = lineElem;", - \ " while (node && node.id != 'vimCodeElement".s:settings.id_suffix."')", - \ " {", - \ " if (node.className == 'closed-fold')", - \ " {", - \ " /* toggle open the fold ID (remove window ID) */", - \ " toggleFold(node.id.substr(4));", - \ " }", - \ " node = node.parentNode;", + \ "/* function to open any folds containing a jumped-to line before jumping to it */", + \ "function JumpToLine()", + \ "{", + \ " var lineNum;", + \ " lineNum = window.location.hash;", + \ " lineNum = lineNum.substr(1); /* strip off '#' */", + \ "", + \ " if (lineNum.indexOf('L') == -1) {", + \ " lineNum = 'L'+lineNum;", + \ " }", + \ " if (lineNum.indexOf('W') == -1) {", + \ " lineNum = 'W1'+lineNum;", \ " }", + \ " var lineElem = document.getElementById(lineNum);" \ ]) endif - endif - if s:settings.line_ids - call append(style_start, [ - \ "", - \ "/* function to open any folds containing a jumped-to line before jumping to it */", - \ "function JumpToLine()", - \ "{", - \ " var lineNum;", - \ " lineNum = window.location.hash;", - \ " lineNum = lineNum.substr(1); /* strip off '#' */", - \ "", - \ " if (lineNum.indexOf('L') == -1) {", - \ " lineNum = 'L'+lineNum;", - \ " }", - \ " if (lineNum.indexOf('W') == -1) {", - \ " lineNum = 'W1'+lineNum;", - \ " }", - \ " var lineElem = document.getElementById(lineNum);" - \ ]) - endif + " Insert javascript to toggle matching folds open and closed in all windows, + " if dynamic folding is active. + if s:settings.dynamic_folds + call append(style_start, [ + \ " function toggleFold(objID)", + \ " {", + \ " for (win_num = 1; win_num <= ".len(a:buf_list)."; win_num++)", + \ " {", + \ " var fold;", + \ ' fold = document.getElementById("win"+win_num+objID);', + \ " if(fold.className == 'closed-fold')", + \ " {", + \ " fold.className = 'open-fold';", + \ " }", + \ " else if (fold.className == 'open-fold')", + \ " {", + \ " fold.className = 'closed-fold';", + \ " }", + \ " }", + \ " }", + \ ]) + endif - " Insert javascript to toggle matching folds open and closed in all windows, - " if dynamic folding is active. - if s:settings.dynamic_folds - call append(style_start, [ - \ " function toggleFold(objID)", - \ " {", - \ " for (win_num = 1; win_num <= ".len(a:buf_list)."; win_num++)", - \ " {", - \ " var fold;", - \ ' fold = document.getElementById("win"+win_num+objID);', - \ " if(fold.className == 'closed-fold')", - \ " {", - \ " fold.className = 'open-fold';", - \ " }", - \ " else if (fold.className == 'open-fold')", - \ " {", - \ " fold.className = 'closed-fold';", - \ " }", - \ " }", - \ " }", - \ ]) - endif + if s:uses_script + " insert script tag if needed + call append(style_start, [ + \ "", + \ s:settings.use_xhtml ? '//", - \ s:settings.use_xhtml ? '//']+ + \ style+ + \ [ s:settings.use_xhtml ? '' : '', + \ '' + \]) + endif "}}} endif - - " Insert styles from all the generated html documents and additional styles - " for the table-based layout of the side-by-side diff. The diff should take - " up the full browser window (but not more), and be static in size, - " horizontally scrollable when the lines are too long. Otherwise, the diff - " is pretty useless for really long lines. {{{ - if s:settings.use_css - call append(style_start, - \ ['']+ - \ style+ - \ [ s:settings.use_xhtml ? '' : '', - \ '' - \]) - endif "}}} endif let &paste = s:old_paste -- cgit From 66c384d4e806a5e8de53bc57a05f0ddd8c8a9d1c Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Tue, 28 Feb 2023 09:34:27 +0100 Subject: vim-patch:partial:dd60c365cd26 (#22437) vim-patch:partial:dd60c365cd26 Update runtime files https://github.com/vim/vim/commit/dd60c365cd2630794be84d63c4fe287124a30b97 Co-authored-by: Bram Moolenaar Skip: eval.txt, repeat.txt (needs `getscriptinfo()`) --- runtime/autoload/python.vim | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/python.vim b/runtime/autoload/python.vim index 1eaad09ef5..d5f4862363 100644 --- a/runtime/autoload/python.vim +++ b/runtime/autoload/python.vim @@ -22,8 +22,7 @@ let s:maxoff = 50 " maximum number of lines to look backwards for () function s:SearchBracket(fromlnum, flags) return searchpairpos('[[({]', '', '[])}]', a:flags, \ {-> synstack('.', col('.')) - \ ->map({_, id -> id->synIDattr('name')}) - \ ->match('\%(Comment\|Todo\|String\)$') >= 0}, + \ ->indexof({_, id -> synIDattr(id, 'name') =~ '\%(Comment\|Todo\|String\)$'}) >= 0}, \ [0, a:fromlnum - s:maxoff]->max(), g:python_indent.searchpair_timeout) endfunction @@ -157,15 +156,13 @@ function python#GetIndent(lnum, ...) " the start of the comment. synID() is slow, a linear search would take " too long on a long line. if synstack(plnum, pline_len) - \ ->map({_, id -> id->synIDattr('name')}) - \ ->match('\%(Comment\|Todo\)$') >= 0 + \ ->indexof({_, id -> synIDattr(id, 'name') =~ '\%(Comment\|Todo\)$'}) >= 0 let min = 1 let max = pline_len while min < max let col = (min + max) / 2 if synstack(plnum, col) - \ ->map({_, id -> id->synIDattr('name')}) - \ ->match('\%(Comment\|Todo\)$') >= 0 + \ ->indexof({_, id -> synIDattr(id, 'name') =~ '\%(Comment\|Todo\)$'}) >= 0 let max = col else let min = col + 1 -- cgit From 04e8e1f9eaa9ca64fa6418639d595f142585a934 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 7 Mar 2023 09:28:53 -0500 Subject: refactor(runtime): use vim.version to compare versions #22550 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TODO: Unfortunately, cannot (yet) use vim.version for tmux version comparison, because `vim.version.parse(…,{strict=false})` does not coerce tmux's funny "tmux 3.3a" version string. https://github.com/neovim/neovim/blob/6969d3d7491fc2f10d80309b26dd0c26d211b1b3/runtime/autoload/provider/clipboard.vim#L148 --- runtime/autoload/health/provider.vim | 28 ++++++---------------------- runtime/autoload/provider/node.vim | 18 +++++++----------- 2 files changed, 13 insertions(+), 33 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/health/provider.vim b/runtime/autoload/health/provider.vim index d104bcfd67..59361eb735 100644 --- a/runtime/autoload/health/provider.vim +++ b/runtime/autoload/health/provider.vim @@ -19,22 +19,6 @@ function! s:cmd_ok(cmd) abort return v:shell_error == 0 endfunction -" Simple version comparison. -function! s:version_cmp(a, b) abort - let a = split(a:a, '\.', 0) - let b = split(a:b, '\.', 0) - - for i in range(len(a)) - if str2nr(a[i]) > str2nr(b[i]) - return 1 - elseif str2nr(a[i]) < str2nr(b[i]) - return -1 - endif - endfor - - return 0 -endfunction - " Handler for s:system() function. function! s:system_handler(jobid, data, event) dict abort if a:event ==# 'stderr' @@ -244,7 +228,7 @@ function! s:version_info(python) abort let nvim_path_base = fnamemodify(nvim_path, ':~:h') let version_status = 'unknown; '.nvim_path_base if !s:is_bad_response(nvim_version) && !s:is_bad_response(pypi_version) - if s:version_cmp(nvim_version, pypi_version) == -1 + if v:lua.vim.version.lt(nvim_version, pypi_version) let version_status = 'outdated; from '.nvim_path_base else let version_status = 'up to date' @@ -598,7 +582,7 @@ function! s:check_ruby() abort return endif - if s:version_cmp(current_gem, latest_gem) == -1 + if v:lua.vim.version.lt(current_gem, latest_gem) call health#report_warn( \ printf('Gem "neovim" is out-of-date. Installed: %s, latest: %s', \ current_gem, latest_gem), @@ -623,8 +607,8 @@ function! s:check_node() abort endif let node_v = get(split(s:system(['node', '-v']), "\n"), 0, '') call health#report_info('Node.js: '. node_v) - if s:shell_error || s:version_cmp(node_v[1:], '6.0.0') < 0 - call health#report_warn('Nvim node.js host does not support '.node_v) + if s:shell_error || v:lua.vim.version.lt(node_v[1:], '6.0.0') + call health#report_warn('Nvim node.js host does not support Node '.node_v) " Skip further checks, they are nonsense if nodejs is too old. return endif @@ -675,7 +659,7 @@ function! s:check_node() abort return endif - if s:version_cmp(current_npm, latest_npm) == -1 + if latest_npm !=# 'unable to parse' && v:lua.vim.version.lt(current_npm, latest_npm) call health#report_warn( \ printf('Package "neovim" is out-of-date. Installed: %s, latest: %s', \ current_npm, latest_npm), @@ -751,7 +735,7 @@ function! s:check_perl() abort return endif - if s:version_cmp(current_cpan, latest_cpan) == -1 + if v:lua.vim.version.lt(current_cpan, latest_cpan) call health#report_warn( \ printf('Module "Neovim::Ext" is out-of-date. Installed: %s, latest: %s', \ current_cpan, latest_cpan), diff --git a/runtime/autoload/provider/node.vim b/runtime/autoload/provider/node.vim index 87af0094fe..3e7b8b4ef9 100644 --- a/runtime/autoload/provider/node.vim +++ b/runtime/autoload/provider/node.vim @@ -3,7 +3,7 @@ if exists('g:loaded_node_provider') endif let g:loaded_node_provider = 1 -function! s:is_minimum_version(version, min_major, min_minor) abort +function! s:is_minimum_version(version, min_version) abort if empty(a:version) let nodejs_version = get(split(system(['node', '-v']), "\n"), 0, '') if v:shell_error || nodejs_version[0] !=# 'v' @@ -15,11 +15,7 @@ function! s:is_minimum_version(version, min_major, min_minor) abort " Remove surrounding junk. Example: 'v4.12.0' => '4.12.0' let nodejs_version = matchstr(nodejs_version, '\(\d\.\?\)\+') " [major, minor, patch] - let v_list = split(nodejs_version, '\.') - return len(v_list) == 3 - \ && ((str2nr(v_list[0]) > str2nr(a:min_major)) - \ || (str2nr(v_list[0]) == str2nr(a:min_major) - \ && str2nr(v_list[1]) >= str2nr(a:min_minor))) + return !v:lua.vim.version.lt(nodejs_version, a:min_version) endfunction let s:NodeHandler = { @@ -43,20 +39,20 @@ function! provider#node#can_inspect() abort if v:shell_error || ver[0] !=# 'v' return 0 endif - return (ver[1] ==# '6' && s:is_minimum_version(ver, 6, 12)) - \ || s:is_minimum_version(ver, 7, 6) + return (ver[1] ==# '6' && s:is_minimum_version(ver, '6.12.0')) + \ || s:is_minimum_version(ver, '7.6.0') endfunction function! provider#node#Detect() abort - let minver = [6, 0] + let minver = '6.0.0' if exists('g:node_host_prog') return [expand(g:node_host_prog, v:true), ''] endif if !executable('node') return ['', 'node not found (or not executable)'] endif - if !s:is_minimum_version(v:null, minver[0], minver[1]) - return ['', printf('node version %s.%s not found', minver[0], minver[1])] + if !s:is_minimum_version(v:null, minver) + return ['', printf('node version %s not found', minver)] endif let npm_opts = {} -- cgit From a40eb7cc991eb4f8b89f467e8e42563868efa76b Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 17 Mar 2023 01:12:33 +0100 Subject: feat(vim.version): more coercion with strict=false Problem: "tmux 3.2a" (output from "tmux -V") is not parsed easily. Solution: With `strict=false`, discard everything before the first digit. - rename Semver => Version - rename vim.version.version() => vim.version._version() - rename matches() => has() - remove `opts` from cmp() --- runtime/autoload/provider/clipboard.vim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim index 98c80f1843..6d238ddb55 100644 --- a/runtime/autoload/provider/clipboard.vim +++ b/runtime/autoload/provider/clipboard.vim @@ -145,8 +145,8 @@ function! provider#clipboard#Executable() abort let s:paste['*'] = s:paste['+'] return 'termux-clipboard' elseif !empty($TMUX) && executable('tmux') - let ver = matchlist(systemlist(['tmux', '-V'])[0], '\vtmux %(next-)?(\d+)\.(\d+)') - if len(ver) >= 3 && (ver[1] > 3 || (ver[1] == 3 && ver[2] >= 2)) + let tmux_v = v:lua.vim.version.parse(system(['tmux', '-V'])) + if !empty(tmux_v) && !v:lua.vim.version.lt(tmux_v, [3,2,0]) let s:copy['+'] = ['tmux', 'load-buffer', '-w', '-'] else let s:copy['+'] = ['tmux', 'load-buffer', '-'] -- cgit From a5c572bd446a89be2dccb2f7479ff1b017074640 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Tue, 4 Apr 2023 19:07:33 +0200 Subject: docs: fix typos Co-authored-by: Gregory Anders Co-authored-by: Raphael Co-authored-by: C.D. MacEachern Co-authored-by: himanoa --- runtime/autoload/health/provider.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/health/provider.vim b/runtime/autoload/health/provider.vim index 59361eb735..70f525156c 100644 --- a/runtime/autoload/health/provider.vim +++ b/runtime/autoload/health/provider.vim @@ -435,7 +435,7 @@ endfunction " Check if pyenv is available and a valid pyenv root can be found, then return " their respective paths. If either of those is invalid, return two empty -" strings, effectivly ignoring pyenv. +" strings, effectively ignoring pyenv. function! s:check_for_pyenv() abort let pyenv_path = resolve(exepath('pyenv')) -- cgit From 41b7586cbb947b3215489fd7445b9bfb6e7008d2 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sun, 9 Apr 2023 20:46:53 +0200 Subject: refactor: rewrite clipboard provider healthchecks in Lua This is required to remove the vimscript checkhealth functions. --- runtime/autoload/health/provider.vim | 755 ---------------------------------- runtime/autoload/health/provider2.vim | 729 ++++++++++++++++++++++++++++++++ 2 files changed, 729 insertions(+), 755 deletions(-) delete mode 100644 runtime/autoload/health/provider.vim create mode 100644 runtime/autoload/health/provider2.vim (limited to 'runtime/autoload') diff --git a/runtime/autoload/health/provider.vim b/runtime/autoload/health/provider.vim deleted file mode 100644 index 70f525156c..0000000000 --- a/runtime/autoload/health/provider.vim +++ /dev/null @@ -1,755 +0,0 @@ -let s:shell_error = 0 - -function! s:is_bad_response(s) abort - return a:s =~? '\v(^unable)|(^error)|(^outdated)' -endfunction - -function! s:trim(s) abort - return substitute(a:s, '^\_s*\|\_s*$', '', 'g') -endfunction - -" Convert '\' to '/'. Collapse '//' and '/./'. -function! s:normalize_path(s) abort - return substitute(substitute(a:s, '\', '/', 'g'), '/\./\|/\+', '/', 'g') -endfunction - -" Returns TRUE if `cmd` exits with success, else FALSE. -function! s:cmd_ok(cmd) abort - call system(a:cmd) - return v:shell_error == 0 -endfunction - -" Handler for s:system() function. -function! s:system_handler(jobid, data, event) dict abort - if a:event ==# 'stderr' - if self.add_stderr_to_output - let self.output .= join(a:data, '') - else - let self.stderr .= join(a:data, '') - endif - elseif a:event ==# 'stdout' - let self.output .= join(a:data, '') - elseif a:event ==# 'exit' - let s:shell_error = a:data - endif -endfunction - -" Attempts to construct a shell command from an args list. -" Only for display, to help users debug a failed command. -function! s:shellify(cmd) abort - if type(a:cmd) != type([]) - return a:cmd - endif - return join(map(copy(a:cmd), - \'v:val =~# ''\m[^\-.a-zA-Z_/]'' ? shellescape(v:val) : v:val'), ' ') -endfunction - -" Run a system command and timeout after 30 seconds. -function! s:system(cmd, ...) abort - let stdin = a:0 ? a:1 : '' - let ignore_error = a:0 > 2 ? a:3 : 0 - let opts = { - \ 'add_stderr_to_output': a:0 > 1 ? a:2 : 0, - \ 'output': '', - \ 'stderr': '', - \ 'on_stdout': function('s:system_handler'), - \ 'on_stderr': function('s:system_handler'), - \ 'on_exit': function('s:system_handler'), - \ } - let jobid = jobstart(a:cmd, opts) - - if jobid < 1 - call health#report_error(printf('Command error (job=%d): `%s` (in %s)', - \ jobid, s:shellify(a:cmd), string(getcwd()))) - let s:shell_error = 1 - return opts.output - endif - - if !empty(stdin) - call jobsend(jobid, stdin) - endif - - let res = jobwait([jobid], 30000) - if res[0] == -1 - call health#report_error(printf('Command timed out: %s', s:shellify(a:cmd))) - call jobstop(jobid) - elseif s:shell_error != 0 && !ignore_error - let emsg = printf("Command error (job=%d, exit code %d): `%s` (in %s)", - \ jobid, s:shell_error, s:shellify(a:cmd), string(getcwd())) - if !empty(opts.output) - let emsg .= "\noutput: " . opts.output - end - if !empty(opts.stderr) - let emsg .= "\nstderr: " . opts.stderr - end - call health#report_error(emsg) - endif - - return opts.output -endfunction - -function! s:systemlist(cmd, ...) abort - let stdout = split(s:system(a:cmd, a:0 ? a:1 : ''), "\n") - if a:0 > 1 && !empty(a:2) - return filter(stdout, '!empty(v:val)') - endif - return stdout -endfunction - -" Fetch the contents of a URL. -function! s:download(url) abort - let has_curl = executable('curl') - if has_curl && system(['curl', '-V']) =~# 'Protocols:.*https' - let rv = s:system(['curl', '-sL', a:url], '', 1, 1) - return s:shell_error ? 'curl error with '.a:url.': '.s:shell_error : rv - elseif executable('python') - let script = " - \try:\n - \ from urllib.request import urlopen\n - \except ImportError:\n - \ from urllib2 import urlopen\n - \\n - \response = urlopen('".a:url."')\n - \print(response.read().decode('utf8'))\n - \" - let rv = s:system(['python', '-c', script]) - return empty(rv) && s:shell_error - \ ? 'python urllib.request error: '.s:shell_error - \ : rv - endif - return 'missing `curl` ' - \ .(has_curl ? '(with HTTPS support) ' : '') - \ .'and `python`, cannot make web request' -endfunction - -" Check for clipboard tools. -function! s:check_clipboard() abort - call health#report_start('Clipboard (optional)') - - if !empty($TMUX) && executable('tmux') && executable('pbpaste') && !s:cmd_ok('pbpaste') - let tmux_version = matchstr(system('tmux -V'), '\d\+\.\d\+') - call health#report_error('pbcopy does not work with tmux version: '.tmux_version, - \ ['Install tmux 2.6+. https://superuser.com/q/231130', - \ 'or use tmux with reattach-to-user-namespace. https://superuser.com/a/413233']) - endif - - let clipboard_tool = provider#clipboard#Executable() - if exists('g:clipboard') && empty(clipboard_tool) - call health#report_error( - \ provider#clipboard#Error(), - \ ["Use the example in :help g:clipboard as a template, or don't set g:clipboard at all."]) - elseif empty(clipboard_tool) - call health#report_warn( - \ 'No clipboard tool found. Clipboard registers (`"+` and `"*`) will not work.', - \ [':help clipboard']) - else - call health#report_ok('Clipboard tool found: '. clipboard_tool) - endif -endfunction - -" Get the latest Nvim Python client (pynvim) version from PyPI. -function! s:latest_pypi_version() abort - let pypi_version = 'unable to get pypi response' - let pypi_response = s:download('https://pypi.python.org/pypi/pynvim/json') - if !empty(pypi_response) - try - let pypi_data = json_decode(pypi_response) - catch /E474/ - return 'error: '.pypi_response - endtry - let pypi_version = get(get(pypi_data, 'info', {}), 'version', 'unable to parse') - endif - return pypi_version -endfunction - -" Get version information using the specified interpreter. The interpreter is -" used directly in case breaking changes were introduced since the last time -" Nvim's Python client was updated. -" -" Returns: [ -" {python executable version}, -" {current nvim version}, -" {current pypi nvim status}, -" {installed version status} -" ] -function! s:version_info(python) abort - let pypi_version = s:latest_pypi_version() - let python_version = s:trim(s:system([ - \ a:python, - \ '-c', - \ 'import sys; print(".".join(str(x) for x in sys.version_info[:3]))', - \ ])) - - if empty(python_version) - let python_version = 'unable to parse '.a:python.' response' - endif - - let nvim_path = s:trim(s:system([ - \ a:python, '-c', - \ 'import sys; ' . - \ 'sys.path = [p for p in sys.path if p != ""]; ' . - \ 'import neovim; print(neovim.__file__)'])) - if s:shell_error || empty(nvim_path) - return [python_version, 'unable to load neovim Python module', pypi_version, - \ nvim_path] - endif - - " Assuming that multiple versions of a package are installed, sort them - " numerically in descending order. - function! s:compare(metapath1, metapath2) abort - let a = matchstr(fnamemodify(a:metapath1, ':p:h:t'), '[0-9.]\+') - let b = matchstr(fnamemodify(a:metapath2, ':p:h:t'), '[0-9.]\+') - return a == b ? 0 : a > b ? 1 : -1 - endfunction - - " Try to get neovim.VERSION (added in 0.1.11dev). - let nvim_version = s:system([a:python, '-c', - \ 'from neovim import VERSION as v; '. - \ 'print("{}.{}.{}{}".format(v.major, v.minor, v.patch, v.prerelease))'], - \ '', 1, 1) - if empty(nvim_version) - let nvim_version = 'unable to find pynvim module version' - let base = fnamemodify(nvim_path, ':h') - let metas = glob(base.'-*/METADATA', 1, 1) - \ + glob(base.'-*/PKG-INFO', 1, 1) - \ + glob(base.'.egg-info/PKG-INFO', 1, 1) - let metas = sort(metas, 's:compare') - - if !empty(metas) - for meta_line in readfile(metas[0]) - if meta_line =~# '^Version:' - let nvim_version = matchstr(meta_line, '^Version: \zs\S\+') - break - endif - endfor - endif - endif - - let nvim_path_base = fnamemodify(nvim_path, ':~:h') - let version_status = 'unknown; '.nvim_path_base - if !s:is_bad_response(nvim_version) && !s:is_bad_response(pypi_version) - if v:lua.vim.version.lt(nvim_version, pypi_version) - let version_status = 'outdated; from '.nvim_path_base - else - let version_status = 'up to date' - endif - endif - - return [python_version, nvim_version, pypi_version, version_status] -endfunction - -" Check the Python interpreter's usability. -function! s:check_bin(bin) abort - if !filereadable(a:bin) && (!has('win32') || !filereadable(a:bin.'.exe')) - call health#report_error(printf('"%s" was not found.', a:bin)) - return 0 - elseif executable(a:bin) != 1 - call health#report_error(printf('"%s" is not executable.', a:bin)) - return 0 - endif - return 1 -endfunction - -" Check "loaded" var for given a:provider. -" Returns 1 if the caller should return (skip checks). -function! s:disabled_via_loaded_var(provider) abort - let loaded_var = 'g:loaded_'.a:provider.'_provider' - if exists(loaded_var) && !exists('*provider#'.a:provider.'#Call') - let v = eval(loaded_var) - if 0 is v - call health#report_info('Disabled ('.loaded_var.'='.v.').') - return 1 - else - call health#report_info('Disabled ('.loaded_var.'='.v.'). This might be due to some previous error.') - endif - endif - return 0 -endfunction - -function! s:check_python() abort - call health#report_start('Python 3 provider (optional)') - - let pyname = 'python3' - let python_exe = '' - let venv = exists('$VIRTUAL_ENV') ? resolve($VIRTUAL_ENV) : '' - let host_prog_var = pyname.'_host_prog' - let python_multiple = [] - - if s:disabled_via_loaded_var(pyname) - return - endif - - let [pyenv, pyenv_root] = s:check_for_pyenv() - - if exists('g:'.host_prog_var) - call health#report_info(printf('Using: g:%s = "%s"', host_prog_var, get(g:, host_prog_var))) - endif - - let [pyname, pythonx_warnings] = provider#pythonx#Detect(3) - - if empty(pyname) - call health#report_warn('No Python executable found that can `import neovim`. ' - \ . 'Using the first available executable for diagnostics.') - elseif exists('g:'.host_prog_var) - let python_exe = pyname - endif - - " No Python executable could `import neovim`, or host_prog_var was used. - if !empty(pythonx_warnings) - call health#report_warn(pythonx_warnings, ['See :help provider-python for more information.', - \ 'You may disable this provider (and warning) by adding `let g:loaded_python3_provider = 0` to your init.vim']) - - elseif !empty(pyname) && empty(python_exe) - if !exists('g:'.host_prog_var) - call health#report_info(printf('`g:%s` is not set. Searching for ' - \ . '%s in the environment.', host_prog_var, pyname)) - endif - - if !empty(pyenv) - let python_exe = s:trim(s:system([pyenv, 'which', pyname], '', 1)) - - if empty(python_exe) - call health#report_warn(printf('pyenv could not find %s.', pyname)) - endif - endif - - if empty(python_exe) - let python_exe = exepath(pyname) - - if exists('$PATH') - for path in split($PATH, has('win32') ? ';' : ':') - let path_bin = s:normalize_path(path.'/'.pyname) - if path_bin != s:normalize_path(python_exe) - \ && index(python_multiple, path_bin) == -1 - \ && executable(path_bin) - call add(python_multiple, path_bin) - endif - endfor - - if len(python_multiple) - " This is worth noting since the user may install something - " that changes $PATH, like homebrew. - call health#report_info(printf('Multiple %s executables found. ' - \ . 'Set `g:%s` to avoid surprises.', pyname, host_prog_var)) - endif - - if python_exe =~# '\' - call health#report_warn(printf('`%s` appears to be a pyenv shim.', python_exe), [ - \ '`pyenv` is not in $PATH, your pyenv installation is broken. ' - \ .'Set `g:'.host_prog_var.'` to avoid surprises.', - \ ]) - endif - endif - endif - endif - - if !empty(python_exe) && !exists('g:'.host_prog_var) - if empty(venv) && !empty(pyenv) - \ && !empty(pyenv_root) && resolve(python_exe) !~# '^'.pyenv_root.'/' - call health#report_warn('pyenv is not set up optimally.', [ - \ printf('Create a virtualenv specifically ' - \ . 'for Nvim using pyenv, and set `g:%s`. This will avoid ' - \ . 'the need to install the pynvim module in each ' - \ . 'version/virtualenv.', host_prog_var) - \ ]) - elseif !empty(venv) - if !empty(pyenv_root) - let venv_root = pyenv_root - else - let venv_root = fnamemodify(venv, ':h') - endif - - if resolve(python_exe) !~# '^'.venv_root.'/' - call health#report_warn('Your virtualenv is not set up optimally.', [ - \ printf('Create a virtualenv specifically ' - \ . 'for Nvim and use `g:%s`. This will avoid ' - \ . 'the need to install the pynvim module in each ' - \ . 'virtualenv.', host_prog_var) - \ ]) - endif - endif - endif - - if empty(python_exe) && !empty(pyname) - " An error message should have already printed. - call health#report_error(printf('`%s` was not found.', pyname)) - elseif !empty(python_exe) && !s:check_bin(python_exe) - let python_exe = '' - endif - - " Diagnostic output - call health#report_info('Executable: ' . (empty(python_exe) ? 'Not found' : python_exe)) - if len(python_multiple) - for path_bin in python_multiple - call health#report_info('Other python executable: ' . path_bin) - endfor - endif - - if empty(python_exe) - " No Python executable can import 'neovim'. Check if any Python executable - " can import 'pynvim'. If so, that Python failed to import 'neovim' as - " well, which is most probably due to a failed pip upgrade: - " https://github.com/neovim/neovim/wiki/Following-HEAD#20181118 - let [pynvim_exe, errors] = provider#pythonx#DetectByModule('pynvim', 3) - if !empty(pynvim_exe) - call health#report_error( - \ 'Detected pip upgrade failure: Python executable can import "pynvim" but ' - \ . 'not "neovim": '. pynvim_exe, - \ "Use that Python version to reinstall \"pynvim\" and optionally \"neovim\".\n" - \ . pynvim_exe ." -m pip uninstall pynvim neovim\n" - \ . pynvim_exe ." -m pip install pynvim\n" - \ . pynvim_exe ." -m pip install neovim # only if needed by third-party software") - endif - else - let [majorpyversion, current, latest, status] = s:version_info(python_exe) - - if 3 != str2nr(majorpyversion) - call health#report_warn('Unexpected Python version.' . - \ ' This could lead to confusing error messages.') - endif - - call health#report_info('Python version: ' . majorpyversion) - - if s:is_bad_response(status) - call health#report_info(printf('pynvim version: %s (%s)', current, status)) - else - call health#report_info(printf('pynvim version: %s', current)) - endif - - if s:is_bad_response(current) - call health#report_error( - \ "pynvim is not installed.\nError: ".current, - \ ['Run in shell: '. python_exe .' -m pip install pynvim']) - endif - - if s:is_bad_response(latest) - call health#report_warn('Could not contact PyPI to get latest version.') - call health#report_error('HTTP request failed: '.latest) - elseif s:is_bad_response(status) - call health#report_warn(printf('Latest pynvim is NOT installed: %s', latest)) - elseif !s:is_bad_response(current) - call health#report_ok(printf('Latest pynvim is installed.')) - endif - endif -endfunction - -" Check if pyenv is available and a valid pyenv root can be found, then return -" their respective paths. If either of those is invalid, return two empty -" strings, effectively ignoring pyenv. -function! s:check_for_pyenv() abort - let pyenv_path = resolve(exepath('pyenv')) - - if empty(pyenv_path) - return ['', ''] - endif - - call health#report_info('pyenv: Path: '. pyenv_path) - - let pyenv_root = exists('$PYENV_ROOT') ? resolve($PYENV_ROOT) : '' - - if empty(pyenv_root) - let pyenv_root = s:trim(s:system([pyenv_path, 'root'])) - call health#report_info('pyenv: $PYENV_ROOT is not set. Infer from `pyenv root`.') - endif - - if !isdirectory(pyenv_root) - call health#report_warn( - \ printf('pyenv: Root does not exist: %s. ' - \ . 'Ignoring pyenv for all following checks.', pyenv_root)) - return ['', ''] - endif - - call health#report_info('pyenv: Root: '.pyenv_root) - - return [pyenv_path, pyenv_root] -endfunction - -" Resolves Python executable path by invoking and checking `sys.executable`. -function! s:python_exepath(invocation) abort - return s:normalize_path(system(fnameescape(a:invocation) - \ . ' -c "import sys; sys.stdout.write(sys.executable)"')) -endfunction - -" Checks that $VIRTUAL_ENV Python executables are found at front of $PATH in -" Nvim and subshells. -function! s:check_virtualenv() abort - call health#report_start('Python virtualenv') - if !exists('$VIRTUAL_ENV') - call health#report_ok('no $VIRTUAL_ENV') - return - endif - let errors = [] - " Keep hints as dict keys in order to discard duplicates. - let hints = {} - " The virtualenv should contain some Python executables, and those - " executables should be first both on Nvim's $PATH and the $PATH of - " subshells launched from Nvim. - let bin_dir = has('win32') ? '/Scripts' : '/bin' - let venv_bins = glob($VIRTUAL_ENV . bin_dir . '/python*', v:true, v:true) - " XXX: Remove irrelevant executables found in bin/. - let venv_bins = filter(venv_bins, 'v:val !~# "python-config"') - if len(venv_bins) - for venv_bin in venv_bins - let venv_bin = s:normalize_path(venv_bin) - let py_bin_basename = fnamemodify(venv_bin, ':t') - let nvim_py_bin = s:python_exepath(exepath(py_bin_basename)) - let subshell_py_bin = s:python_exepath(py_bin_basename) - if venv_bin !=# nvim_py_bin - call add(errors, '$PATH yields this '.py_bin_basename.' executable: '.nvim_py_bin) - let hint = '$PATH ambiguities arise if the virtualenv is not ' - \.'properly activated prior to launching Nvim. Close Nvim, activate the virtualenv, ' - \.'check that invoking Python from the command line launches the correct one, ' - \.'then relaunch Nvim.' - let hints[hint] = v:true - endif - if venv_bin !=# subshell_py_bin - call add(errors, '$PATH in subshells yields this ' - \.py_bin_basename . ' executable: '.subshell_py_bin) - let hint = '$PATH ambiguities in subshells typically are ' - \.'caused by your shell config overriding the $PATH previously set by the ' - \.'virtualenv. Either prevent them from doing so, or use this workaround: ' - \.'https://vi.stackexchange.com/a/34996' - let hints[hint] = v:true - endif - endfor - else - call add(errors, 'no Python executables found in the virtualenv '.bin_dir.' directory.') - endif - - let msg = '$VIRTUAL_ENV is set to: '.$VIRTUAL_ENV - if len(errors) - if len(venv_bins) - let msg .= "\nAnd its ".bin_dir.' directory contains: ' - \.join(map(venv_bins, "fnamemodify(v:val, ':t')"), ', ') - endif - let conj = "\nBut " - for error in errors - let msg .= conj.error - let conj = "\nAnd " - endfor - let msg .= "\nSo invoking Python may lead to unexpected results." - call health#report_warn(msg, keys(hints)) - else - call health#report_info(msg) - call health#report_info('Python version: ' - \.system('python -c "import platform, sys; sys.stdout.write(platform.python_version())"')) - call health#report_ok('$VIRTUAL_ENV provides :!python.') - endif -endfunction - -function! s:check_ruby() abort - call health#report_start('Ruby provider (optional)') - - if s:disabled_via_loaded_var('ruby') - return - endif - - if !executable('ruby') || !executable('gem') - call health#report_warn( - \ '`ruby` and `gem` must be in $PATH.', - \ ['Install Ruby and verify that `ruby` and `gem` commands work.']) - return - endif - call health#report_info('Ruby: '. s:system(['ruby', '-v'])) - - let [host, err] = provider#ruby#Detect() - if empty(host) - call health#report_warn('`neovim-ruby-host` not found.', - \ ['Run `gem install neovim` to ensure the neovim RubyGem is installed.', - \ 'Run `gem environment` to ensure the gem bin directory is in $PATH.', - \ 'If you are using rvm/rbenv/chruby, try "rehashing".', - \ 'See :help g:ruby_host_prog for non-standard gem installations.', - \ 'You may disable this provider (and warning) by adding `let g:loaded_ruby_provider = 0` to your init.vim']) - return - endif - call health#report_info('Host: '. host) - - let latest_gem_cmd = has('win32') ? 'cmd /c gem list -ra "^^neovim$"' : 'gem list -ra ^neovim$' - let latest_gem = s:system(split(latest_gem_cmd)) - if s:shell_error || empty(latest_gem) - call health#report_error('Failed to run: '. latest_gem_cmd, - \ ["Make sure you're connected to the internet.", - \ 'Are you behind a firewall or proxy?']) - return - endif - let latest_gem = get(split(latest_gem, 'neovim (\|, \|)$' ), 0, 'not found') - - let current_gem_cmd = [host, '--version'] - let current_gem = s:system(current_gem_cmd) - if s:shell_error - call health#report_error('Failed to run: '. join(current_gem_cmd), - \ ['Report this issue with the output of: ', join(current_gem_cmd)]) - return - endif - - if v:lua.vim.version.lt(current_gem, latest_gem) - call health#report_warn( - \ printf('Gem "neovim" is out-of-date. Installed: %s, latest: %s', - \ current_gem, latest_gem), - \ ['Run in shell: gem update neovim']) - else - call health#report_ok('Latest "neovim" gem is installed: '. current_gem) - endif -endfunction - -function! s:check_node() abort - call health#report_start('Node.js provider (optional)') - - if s:disabled_via_loaded_var('node') - return - endif - - if !executable('node') || (!executable('npm') && !executable('yarn') && !executable('pnpm')) - call health#report_warn( - \ '`node` and `npm` (or `yarn`, `pnpm`) must be in $PATH.', - \ ['Install Node.js and verify that `node` and `npm` (or `yarn`, `pnpm`) commands work.']) - return - endif - let node_v = get(split(s:system(['node', '-v']), "\n"), 0, '') - call health#report_info('Node.js: '. node_v) - if s:shell_error || v:lua.vim.version.lt(node_v[1:], '6.0.0') - call health#report_warn('Nvim node.js host does not support Node '.node_v) - " Skip further checks, they are nonsense if nodejs is too old. - return - endif - if !provider#node#can_inspect() - call health#report_warn('node.js on this system does not support --inspect-brk so $NVIM_NODE_HOST_DEBUG is ignored.') - endif - - let [host, err] = provider#node#Detect() - if empty(host) - call health#report_warn('Missing "neovim" npm (or yarn, pnpm) package.', - \ ['Run in shell: npm install -g neovim', - \ 'Run in shell (if you use yarn): yarn global add neovim', - \ 'Run in shell (if you use pnpm): pnpm install -g neovim', - \ 'You may disable this provider (and warning) by adding `let g:loaded_node_provider = 0` to your init.vim']) - return - endif - call health#report_info('Nvim node.js host: '. host) - - let manager = 'npm' - if executable('yarn') - let manager = 'yarn' - elseif executable('pnpm') - let manager = 'pnpm' - endif - - let latest_npm_cmd = has('win32') ? - \ 'cmd /c '. manager .' info neovim --json' : - \ manager .' info neovim --json' - let latest_npm = s:system(split(latest_npm_cmd)) - if s:shell_error || empty(latest_npm) - call health#report_error('Failed to run: '. latest_npm_cmd, - \ ["Make sure you're connected to the internet.", - \ 'Are you behind a firewall or proxy?']) - return - endif - try - let pkg_data = json_decode(latest_npm) - catch /E474/ - return 'error: '.latest_npm - endtry - let latest_npm = get(get(pkg_data, 'dist-tags', {}), 'latest', 'unable to parse') - - let current_npm_cmd = ['node', host, '--version'] - let current_npm = s:system(current_npm_cmd) - if s:shell_error - call health#report_error('Failed to run: '. join(current_npm_cmd), - \ ['Report this issue with the output of: ', join(current_npm_cmd)]) - return - endif - - if latest_npm !=# 'unable to parse' && v:lua.vim.version.lt(current_npm, latest_npm) - call health#report_warn( - \ printf('Package "neovim" is out-of-date. Installed: %s, latest: %s', - \ current_npm, latest_npm), - \ ['Run in shell: npm install -g neovim', - \ 'Run in shell (if you use yarn): yarn global add neovim', - \ 'Run in shell (if you use pnpm): pnpm install -g neovim']) - else - call health#report_ok('Latest "neovim" npm/yarn/pnpm package is installed: '. current_npm) - endif -endfunction - -function! s:check_perl() abort - call health#report_start('Perl provider (optional)') - - if s:disabled_via_loaded_var('perl') - return - endif - - let [perl_exec, perl_warnings] = provider#perl#Detect() - if empty(perl_exec) - if !empty(perl_warnings) - call health#report_warn(perl_warnings, ['See :help provider-perl for more information.', - \ 'You may disable this provider (and warning) by adding `let g:loaded_perl_provider = 0` to your init.vim']) - else - call health#report_warn('No usable perl executable found') - endif - return - endif - - call health#report_info('perl executable: '. perl_exec) - - " we cannot use cpanm that is on the path, as it may not be for the perl - " set with g:perl_host_prog - call s:system([perl_exec, '-W', '-MApp::cpanminus', '-e', '']) - if s:shell_error - return [perl_exec, '"App::cpanminus" module is not installed'] - endif - - let latest_cpan_cmd = [perl_exec, - \ '-MApp::cpanminus::fatscript', '-e', - \ 'my $app = App::cpanminus::script->new; - \ $app->parse_options ("--info", "-q", "Neovim::Ext"); - \ exit $app->doit'] - - let latest_cpan = s:system(latest_cpan_cmd) - if s:shell_error || empty(latest_cpan) - call health#report_error('Failed to run: '. join(latest_cpan_cmd, " "), - \ ["Make sure you're connected to the internet.", - \ 'Are you behind a firewall or proxy?']) - return - elseif latest_cpan[0] ==# '!' - let cpanm_errs = split(latest_cpan, '!') - if cpanm_errs[0] =~# "Can't write to " - call health#report_warn(cpanm_errs[0], cpanm_errs[1:-2]) - " Last line is the package info - let latest_cpan = cpanm_errs[-1] - else - call health#report_error('Unknown warning from command: ' . latest_cpan_cmd, cpanm_errs) - return - endif - endif - let latest_cpan = matchstr(latest_cpan, '\(\.\?\d\)\+') - if empty(latest_cpan) - call health#report_error('Cannot parse version number from cpanm output: ' . latest_cpan) - return - endif - - let current_cpan_cmd = [perl_exec, '-W', '-MNeovim::Ext', '-e', 'print $Neovim::Ext::VERSION'] - let current_cpan = s:system(current_cpan_cmd) - if s:shell_error - call health#report_error('Failed to run: '. join(current_cpan_cmd), - \ ['Report this issue with the output of: ', join(current_cpan_cmd)]) - return - endif - - if v:lua.vim.version.lt(current_cpan, latest_cpan) - call health#report_warn( - \ printf('Module "Neovim::Ext" is out-of-date. Installed: %s, latest: %s', - \ current_cpan, latest_cpan), - \ ['Run in shell: cpanm -n Neovim::Ext']) - else - call health#report_ok('Latest "Neovim::Ext" cpan module is installed: '. current_cpan) - endif -endfunction - -function! health#provider#check() abort - call s:check_clipboard() - call s:check_python() - call s:check_virtualenv() - call s:check_ruby() - call s:check_node() - call s:check_perl() -endfunction diff --git a/runtime/autoload/health/provider2.vim b/runtime/autoload/health/provider2.vim new file mode 100644 index 0000000000..196a3ce9de --- /dev/null +++ b/runtime/autoload/health/provider2.vim @@ -0,0 +1,729 @@ +let s:shell_error = 0 + +function! s:is_bad_response(s) abort + return a:s =~? '\v(^unable)|(^error)|(^outdated)' +endfunction + +function! s:trim(s) abort + return substitute(a:s, '^\_s*\|\_s*$', '', 'g') +endfunction + +" Convert '\' to '/'. Collapse '//' and '/./'. +function! s:normalize_path(s) abort + return substitute(substitute(a:s, '\', '/', 'g'), '/\./\|/\+', '/', 'g') +endfunction + +" Returns TRUE if `cmd` exits with success, else FALSE. +function! s:cmd_ok(cmd) abort + call system(a:cmd) + return v:shell_error == 0 +endfunction + +" Handler for s:system() function. +function! s:system_handler(jobid, data, event) dict abort + if a:event ==# 'stderr' + if self.add_stderr_to_output + let self.output .= join(a:data, '') + else + let self.stderr .= join(a:data, '') + endif + elseif a:event ==# 'stdout' + let self.output .= join(a:data, '') + elseif a:event ==# 'exit' + let s:shell_error = a:data + endif +endfunction + +" Attempts to construct a shell command from an args list. +" Only for display, to help users debug a failed command. +function! s:shellify(cmd) abort + if type(a:cmd) != type([]) + return a:cmd + endif + return join(map(copy(a:cmd), + \'v:val =~# ''\m[^\-.a-zA-Z_/]'' ? shellescape(v:val) : v:val'), ' ') +endfunction + +" Run a system command and timeout after 30 seconds. +function! s:system(cmd, ...) abort + let stdin = a:0 ? a:1 : '' + let ignore_error = a:0 > 2 ? a:3 : 0 + let opts = { + \ 'add_stderr_to_output': a:0 > 1 ? a:2 : 0, + \ 'output': '', + \ 'stderr': '', + \ 'on_stdout': function('s:system_handler'), + \ 'on_stderr': function('s:system_handler'), + \ 'on_exit': function('s:system_handler'), + \ } + let jobid = jobstart(a:cmd, opts) + + if jobid < 1 + call health#report_error(printf('Command error (job=%d): `%s` (in %s)', + \ jobid, s:shellify(a:cmd), string(getcwd()))) + let s:shell_error = 1 + return opts.output + endif + + if !empty(stdin) + call jobsend(jobid, stdin) + endif + + let res = jobwait([jobid], 30000) + if res[0] == -1 + call health#report_error(printf('Command timed out: %s', s:shellify(a:cmd))) + call jobstop(jobid) + elseif s:shell_error != 0 && !ignore_error + let emsg = printf("Command error (job=%d, exit code %d): `%s` (in %s)", + \ jobid, s:shell_error, s:shellify(a:cmd), string(getcwd())) + if !empty(opts.output) + let emsg .= "\noutput: " . opts.output + end + if !empty(opts.stderr) + let emsg .= "\nstderr: " . opts.stderr + end + call health#report_error(emsg) + endif + + return opts.output +endfunction + +function! s:systemlist(cmd, ...) abort + let stdout = split(s:system(a:cmd, a:0 ? a:1 : ''), "\n") + if a:0 > 1 && !empty(a:2) + return filter(stdout, '!empty(v:val)') + endif + return stdout +endfunction + +" Fetch the contents of a URL. +function! s:download(url) abort + let has_curl = executable('curl') + if has_curl && system(['curl', '-V']) =~# 'Protocols:.*https' + let rv = s:system(['curl', '-sL', a:url], '', 1, 1) + return s:shell_error ? 'curl error with '.a:url.': '.s:shell_error : rv + elseif executable('python') + let script = " + \try:\n + \ from urllib.request import urlopen\n + \except ImportError:\n + \ from urllib2 import urlopen\n + \\n + \response = urlopen('".a:url."')\n + \print(response.read().decode('utf8'))\n + \" + let rv = s:system(['python', '-c', script]) + return empty(rv) && s:shell_error + \ ? 'python urllib.request error: '.s:shell_error + \ : rv + endif + return 'missing `curl` ' + \ .(has_curl ? '(with HTTPS support) ' : '') + \ .'and `python`, cannot make web request' +endfunction + +" Get the latest Nvim Python client (pynvim) version from PyPI. +function! s:latest_pypi_version() abort + let pypi_version = 'unable to get pypi response' + let pypi_response = s:download('https://pypi.python.org/pypi/pynvim/json') + if !empty(pypi_response) + try + let pypi_data = json_decode(pypi_response) + catch /E474/ + return 'error: '.pypi_response + endtry + let pypi_version = get(get(pypi_data, 'info', {}), 'version', 'unable to parse') + endif + return pypi_version +endfunction + +" Get version information using the specified interpreter. The interpreter is +" used directly in case breaking changes were introduced since the last time +" Nvim's Python client was updated. +" +" Returns: [ +" {python executable version}, +" {current nvim version}, +" {current pypi nvim status}, +" {installed version status} +" ] +function! s:version_info(python) abort + let pypi_version = s:latest_pypi_version() + let python_version = s:trim(s:system([ + \ a:python, + \ '-c', + \ 'import sys; print(".".join(str(x) for x in sys.version_info[:3]))', + \ ])) + + if empty(python_version) + let python_version = 'unable to parse '.a:python.' response' + endif + + let nvim_path = s:trim(s:system([ + \ a:python, '-c', + \ 'import sys; ' . + \ 'sys.path = [p for p in sys.path if p != ""]; ' . + \ 'import neovim; print(neovim.__file__)'])) + if s:shell_error || empty(nvim_path) + return [python_version, 'unable to load neovim Python module', pypi_version, + \ nvim_path] + endif + + " Assuming that multiple versions of a package are installed, sort them + " numerically in descending order. + function! s:compare(metapath1, metapath2) abort + let a = matchstr(fnamemodify(a:metapath1, ':p:h:t'), '[0-9.]\+') + let b = matchstr(fnamemodify(a:metapath2, ':p:h:t'), '[0-9.]\+') + return a == b ? 0 : a > b ? 1 : -1 + endfunction + + " Try to get neovim.VERSION (added in 0.1.11dev). + let nvim_version = s:system([a:python, '-c', + \ 'from neovim import VERSION as v; '. + \ 'print("{}.{}.{}{}".format(v.major, v.minor, v.patch, v.prerelease))'], + \ '', 1, 1) + if empty(nvim_version) + let nvim_version = 'unable to find pynvim module version' + let base = fnamemodify(nvim_path, ':h') + let metas = glob(base.'-*/METADATA', 1, 1) + \ + glob(base.'-*/PKG-INFO', 1, 1) + \ + glob(base.'.egg-info/PKG-INFO', 1, 1) + let metas = sort(metas, 's:compare') + + if !empty(metas) + for meta_line in readfile(metas[0]) + if meta_line =~# '^Version:' + let nvim_version = matchstr(meta_line, '^Version: \zs\S\+') + break + endif + endfor + endif + endif + + let nvim_path_base = fnamemodify(nvim_path, ':~:h') + let version_status = 'unknown; '.nvim_path_base + if !s:is_bad_response(nvim_version) && !s:is_bad_response(pypi_version) + if v:lua.vim.version.lt(nvim_version, pypi_version) + let version_status = 'outdated; from '.nvim_path_base + else + let version_status = 'up to date' + endif + endif + + return [python_version, nvim_version, pypi_version, version_status] +endfunction + +" Check the Python interpreter's usability. +function! s:check_bin(bin) abort + if !filereadable(a:bin) && (!has('win32') || !filereadable(a:bin.'.exe')) + call health#report_error(printf('"%s" was not found.', a:bin)) + return 0 + elseif executable(a:bin) != 1 + call health#report_error(printf('"%s" is not executable.', a:bin)) + return 0 + endif + return 1 +endfunction + +" Check "loaded" var for given a:provider. +" Returns 1 if the caller should return (skip checks). +function! s:disabled_via_loaded_var(provider) abort + let loaded_var = 'g:loaded_'.a:provider.'_provider' + if exists(loaded_var) && !exists('*provider#'.a:provider.'#Call') + let v = eval(loaded_var) + if 0 is v + call health#report_info('Disabled ('.loaded_var.'='.v.').') + return 1 + else + call health#report_info('Disabled ('.loaded_var.'='.v.'). This might be due to some previous error.') + endif + endif + return 0 +endfunction + +function! s:check_python() abort + call health#report_start('Python 3 provider (optional)') + + let pyname = 'python3' + let python_exe = '' + let venv = exists('$VIRTUAL_ENV') ? resolve($VIRTUAL_ENV) : '' + let host_prog_var = pyname.'_host_prog' + let python_multiple = [] + + if s:disabled_via_loaded_var(pyname) + return + endif + + let [pyenv, pyenv_root] = s:check_for_pyenv() + + if exists('g:'.host_prog_var) + call health#report_info(printf('Using: g:%s = "%s"', host_prog_var, get(g:, host_prog_var))) + endif + + let [pyname, pythonx_warnings] = provider#pythonx#Detect(3) + + if empty(pyname) + call health#report_warn('No Python executable found that can `import neovim`. ' + \ . 'Using the first available executable for diagnostics.') + elseif exists('g:'.host_prog_var) + let python_exe = pyname + endif + + " No Python executable could `import neovim`, or host_prog_var was used. + if !empty(pythonx_warnings) + call health#report_warn(pythonx_warnings, ['See :help provider-python for more information.', + \ 'You may disable this provider (and warning) by adding `let g:loaded_python3_provider = 0` to your init.vim']) + + elseif !empty(pyname) && empty(python_exe) + if !exists('g:'.host_prog_var) + call health#report_info(printf('`g:%s` is not set. Searching for ' + \ . '%s in the environment.', host_prog_var, pyname)) + endif + + if !empty(pyenv) + let python_exe = s:trim(s:system([pyenv, 'which', pyname], '', 1)) + + if empty(python_exe) + call health#report_warn(printf('pyenv could not find %s.', pyname)) + endif + endif + + if empty(python_exe) + let python_exe = exepath(pyname) + + if exists('$PATH') + for path in split($PATH, has('win32') ? ';' : ':') + let path_bin = s:normalize_path(path.'/'.pyname) + if path_bin != s:normalize_path(python_exe) + \ && index(python_multiple, path_bin) == -1 + \ && executable(path_bin) + call add(python_multiple, path_bin) + endif + endfor + + if len(python_multiple) + " This is worth noting since the user may install something + " that changes $PATH, like homebrew. + call health#report_info(printf('Multiple %s executables found. ' + \ . 'Set `g:%s` to avoid surprises.', pyname, host_prog_var)) + endif + + if python_exe =~# '\' + call health#report_warn(printf('`%s` appears to be a pyenv shim.', python_exe), [ + \ '`pyenv` is not in $PATH, your pyenv installation is broken. ' + \ .'Set `g:'.host_prog_var.'` to avoid surprises.', + \ ]) + endif + endif + endif + endif + + if !empty(python_exe) && !exists('g:'.host_prog_var) + if empty(venv) && !empty(pyenv) + \ && !empty(pyenv_root) && resolve(python_exe) !~# '^'.pyenv_root.'/' + call health#report_warn('pyenv is not set up optimally.', [ + \ printf('Create a virtualenv specifically ' + \ . 'for Nvim using pyenv, and set `g:%s`. This will avoid ' + \ . 'the need to install the pynvim module in each ' + \ . 'version/virtualenv.', host_prog_var) + \ ]) + elseif !empty(venv) + if !empty(pyenv_root) + let venv_root = pyenv_root + else + let venv_root = fnamemodify(venv, ':h') + endif + + if resolve(python_exe) !~# '^'.venv_root.'/' + call health#report_warn('Your virtualenv is not set up optimally.', [ + \ printf('Create a virtualenv specifically ' + \ . 'for Nvim and use `g:%s`. This will avoid ' + \ . 'the need to install the pynvim module in each ' + \ . 'virtualenv.', host_prog_var) + \ ]) + endif + endif + endif + + if empty(python_exe) && !empty(pyname) + " An error message should have already printed. + call health#report_error(printf('`%s` was not found.', pyname)) + elseif !empty(python_exe) && !s:check_bin(python_exe) + let python_exe = '' + endif + + " Diagnostic output + call health#report_info('Executable: ' . (empty(python_exe) ? 'Not found' : python_exe)) + if len(python_multiple) + for path_bin in python_multiple + call health#report_info('Other python executable: ' . path_bin) + endfor + endif + + if empty(python_exe) + " No Python executable can import 'neovim'. Check if any Python executable + " can import 'pynvim'. If so, that Python failed to import 'neovim' as + " well, which is most probably due to a failed pip upgrade: + " https://github.com/neovim/neovim/wiki/Following-HEAD#20181118 + let [pynvim_exe, errors] = provider#pythonx#DetectByModule('pynvim', 3) + if !empty(pynvim_exe) + call health#report_error( + \ 'Detected pip upgrade failure: Python executable can import "pynvim" but ' + \ . 'not "neovim": '. pynvim_exe, + \ "Use that Python version to reinstall \"pynvim\" and optionally \"neovim\".\n" + \ . pynvim_exe ." -m pip uninstall pynvim neovim\n" + \ . pynvim_exe ." -m pip install pynvim\n" + \ . pynvim_exe ." -m pip install neovim # only if needed by third-party software") + endif + else + let [majorpyversion, current, latest, status] = s:version_info(python_exe) + + if 3 != str2nr(majorpyversion) + call health#report_warn('Unexpected Python version.' . + \ ' This could lead to confusing error messages.') + endif + + call health#report_info('Python version: ' . majorpyversion) + + if s:is_bad_response(status) + call health#report_info(printf('pynvim version: %s (%s)', current, status)) + else + call health#report_info(printf('pynvim version: %s', current)) + endif + + if s:is_bad_response(current) + call health#report_error( + \ "pynvim is not installed.\nError: ".current, + \ ['Run in shell: '. python_exe .' -m pip install pynvim']) + endif + + if s:is_bad_response(latest) + call health#report_warn('Could not contact PyPI to get latest version.') + call health#report_error('HTTP request failed: '.latest) + elseif s:is_bad_response(status) + call health#report_warn(printf('Latest pynvim is NOT installed: %s', latest)) + elseif !s:is_bad_response(current) + call health#report_ok(printf('Latest pynvim is installed.')) + endif + endif +endfunction + +" Check if pyenv is available and a valid pyenv root can be found, then return +" their respective paths. If either of those is invalid, return two empty +" strings, effectively ignoring pyenv. +function! s:check_for_pyenv() abort + let pyenv_path = resolve(exepath('pyenv')) + + if empty(pyenv_path) + return ['', ''] + endif + + call health#report_info('pyenv: Path: '. pyenv_path) + + let pyenv_root = exists('$PYENV_ROOT') ? resolve($PYENV_ROOT) : '' + + if empty(pyenv_root) + let pyenv_root = s:trim(s:system([pyenv_path, 'root'])) + call health#report_info('pyenv: $PYENV_ROOT is not set. Infer from `pyenv root`.') + endif + + if !isdirectory(pyenv_root) + call health#report_warn( + \ printf('pyenv: Root does not exist: %s. ' + \ . 'Ignoring pyenv for all following checks.', pyenv_root)) + return ['', ''] + endif + + call health#report_info('pyenv: Root: '.pyenv_root) + + return [pyenv_path, pyenv_root] +endfunction + +" Resolves Python executable path by invoking and checking `sys.executable`. +function! s:python_exepath(invocation) abort + return s:normalize_path(system(fnameescape(a:invocation) + \ . ' -c "import sys; sys.stdout.write(sys.executable)"')) +endfunction + +" Checks that $VIRTUAL_ENV Python executables are found at front of $PATH in +" Nvim and subshells. +function! s:check_virtualenv() abort + call health#report_start('Python virtualenv') + if !exists('$VIRTUAL_ENV') + call health#report_ok('no $VIRTUAL_ENV') + return + endif + let errors = [] + " Keep hints as dict keys in order to discard duplicates. + let hints = {} + " The virtualenv should contain some Python executables, and those + " executables should be first both on Nvim's $PATH and the $PATH of + " subshells launched from Nvim. + let bin_dir = has('win32') ? '/Scripts' : '/bin' + let venv_bins = glob($VIRTUAL_ENV . bin_dir . '/python*', v:true, v:true) + " XXX: Remove irrelevant executables found in bin/. + let venv_bins = filter(venv_bins, 'v:val !~# "python-config"') + if len(venv_bins) + for venv_bin in venv_bins + let venv_bin = s:normalize_path(venv_bin) + let py_bin_basename = fnamemodify(venv_bin, ':t') + let nvim_py_bin = s:python_exepath(exepath(py_bin_basename)) + let subshell_py_bin = s:python_exepath(py_bin_basename) + if venv_bin !=# nvim_py_bin + call add(errors, '$PATH yields this '.py_bin_basename.' executable: '.nvim_py_bin) + let hint = '$PATH ambiguities arise if the virtualenv is not ' + \.'properly activated prior to launching Nvim. Close Nvim, activate the virtualenv, ' + \.'check that invoking Python from the command line launches the correct one, ' + \.'then relaunch Nvim.' + let hints[hint] = v:true + endif + if venv_bin !=# subshell_py_bin + call add(errors, '$PATH in subshells yields this ' + \.py_bin_basename . ' executable: '.subshell_py_bin) + let hint = '$PATH ambiguities in subshells typically are ' + \.'caused by your shell config overriding the $PATH previously set by the ' + \.'virtualenv. Either prevent them from doing so, or use this workaround: ' + \.'https://vi.stackexchange.com/a/34996' + let hints[hint] = v:true + endif + endfor + else + call add(errors, 'no Python executables found in the virtualenv '.bin_dir.' directory.') + endif + + let msg = '$VIRTUAL_ENV is set to: '.$VIRTUAL_ENV + if len(errors) + if len(venv_bins) + let msg .= "\nAnd its ".bin_dir.' directory contains: ' + \.join(map(venv_bins, "fnamemodify(v:val, ':t')"), ', ') + endif + let conj = "\nBut " + for error in errors + let msg .= conj.error + let conj = "\nAnd " + endfor + let msg .= "\nSo invoking Python may lead to unexpected results." + call health#report_warn(msg, keys(hints)) + else + call health#report_info(msg) + call health#report_info('Python version: ' + \.system('python -c "import platform, sys; sys.stdout.write(platform.python_version())"')) + call health#report_ok('$VIRTUAL_ENV provides :!python.') + endif +endfunction + +function! s:check_ruby() abort + call health#report_start('Ruby provider (optional)') + + if s:disabled_via_loaded_var('ruby') + return + endif + + if !executable('ruby') || !executable('gem') + call health#report_warn( + \ '`ruby` and `gem` must be in $PATH.', + \ ['Install Ruby and verify that `ruby` and `gem` commands work.']) + return + endif + call health#report_info('Ruby: '. s:system(['ruby', '-v'])) + + let [host, err] = provider#ruby#Detect() + if empty(host) + call health#report_warn('`neovim-ruby-host` not found.', + \ ['Run `gem install neovim` to ensure the neovim RubyGem is installed.', + \ 'Run `gem environment` to ensure the gem bin directory is in $PATH.', + \ 'If you are using rvm/rbenv/chruby, try "rehashing".', + \ 'See :help g:ruby_host_prog for non-standard gem installations.', + \ 'You may disable this provider (and warning) by adding `let g:loaded_ruby_provider = 0` to your init.vim']) + return + endif + call health#report_info('Host: '. host) + + let latest_gem_cmd = has('win32') ? 'cmd /c gem list -ra "^^neovim$"' : 'gem list -ra ^neovim$' + let latest_gem = s:system(split(latest_gem_cmd)) + if s:shell_error || empty(latest_gem) + call health#report_error('Failed to run: '. latest_gem_cmd, + \ ["Make sure you're connected to the internet.", + \ 'Are you behind a firewall or proxy?']) + return + endif + let latest_gem = get(split(latest_gem, 'neovim (\|, \|)$' ), 0, 'not found') + + let current_gem_cmd = [host, '--version'] + let current_gem = s:system(current_gem_cmd) + if s:shell_error + call health#report_error('Failed to run: '. join(current_gem_cmd), + \ ['Report this issue with the output of: ', join(current_gem_cmd)]) + return + endif + + if v:lua.vim.version.lt(current_gem, latest_gem) + call health#report_warn( + \ printf('Gem "neovim" is out-of-date. Installed: %s, latest: %s', + \ current_gem, latest_gem), + \ ['Run in shell: gem update neovim']) + else + call health#report_ok('Latest "neovim" gem is installed: '. current_gem) + endif +endfunction + +function! s:check_node() abort + call health#report_start('Node.js provider (optional)') + + if s:disabled_via_loaded_var('node') + return + endif + + if !executable('node') || (!executable('npm') && !executable('yarn') && !executable('pnpm')) + call health#report_warn( + \ '`node` and `npm` (or `yarn`, `pnpm`) must be in $PATH.', + \ ['Install Node.js and verify that `node` and `npm` (or `yarn`, `pnpm`) commands work.']) + return + endif + let node_v = get(split(s:system(['node', '-v']), "\n"), 0, '') + call health#report_info('Node.js: '. node_v) + if s:shell_error || v:lua.vim.version.lt(node_v[1:], '6.0.0') + call health#report_warn('Nvim node.js host does not support Node '.node_v) + " Skip further checks, they are nonsense if nodejs is too old. + return + endif + if !provider#node#can_inspect() + call health#report_warn('node.js on this system does not support --inspect-brk so $NVIM_NODE_HOST_DEBUG is ignored.') + endif + + let [host, err] = provider#node#Detect() + if empty(host) + call health#report_warn('Missing "neovim" npm (or yarn, pnpm) package.', + \ ['Run in shell: npm install -g neovim', + \ 'Run in shell (if you use yarn): yarn global add neovim', + \ 'Run in shell (if you use pnpm): pnpm install -g neovim', + \ 'You may disable this provider (and warning) by adding `let g:loaded_node_provider = 0` to your init.vim']) + return + endif + call health#report_info('Nvim node.js host: '. host) + + let manager = 'npm' + if executable('yarn') + let manager = 'yarn' + elseif executable('pnpm') + let manager = 'pnpm' + endif + + let latest_npm_cmd = has('win32') ? + \ 'cmd /c '. manager .' info neovim --json' : + \ manager .' info neovim --json' + let latest_npm = s:system(split(latest_npm_cmd)) + if s:shell_error || empty(latest_npm) + call health#report_error('Failed to run: '. latest_npm_cmd, + \ ["Make sure you're connected to the internet.", + \ 'Are you behind a firewall or proxy?']) + return + endif + try + let pkg_data = json_decode(latest_npm) + catch /E474/ + return 'error: '.latest_npm + endtry + let latest_npm = get(get(pkg_data, 'dist-tags', {}), 'latest', 'unable to parse') + + let current_npm_cmd = ['node', host, '--version'] + let current_npm = s:system(current_npm_cmd) + if s:shell_error + call health#report_error('Failed to run: '. join(current_npm_cmd), + \ ['Report this issue with the output of: ', join(current_npm_cmd)]) + return + endif + + if latest_npm !=# 'unable to parse' && v:lua.vim.version.lt(current_npm, latest_npm) + call health#report_warn( + \ printf('Package "neovim" is out-of-date. Installed: %s, latest: %s', + \ current_npm, latest_npm), + \ ['Run in shell: npm install -g neovim', + \ 'Run in shell (if you use yarn): yarn global add neovim', + \ 'Run in shell (if you use pnpm): pnpm install -g neovim']) + else + call health#report_ok('Latest "neovim" npm/yarn/pnpm package is installed: '. current_npm) + endif +endfunction + +function! s:check_perl() abort + call health#report_start('Perl provider (optional)') + + if s:disabled_via_loaded_var('perl') + return + endif + + let [perl_exec, perl_warnings] = provider#perl#Detect() + if empty(perl_exec) + if !empty(perl_warnings) + call health#report_warn(perl_warnings, ['See :help provider-perl for more information.', + \ 'You may disable this provider (and warning) by adding `let g:loaded_perl_provider = 0` to your init.vim']) + else + call health#report_warn('No usable perl executable found') + endif + return + endif + + call health#report_info('perl executable: '. perl_exec) + + " we cannot use cpanm that is on the path, as it may not be for the perl + " set with g:perl_host_prog + call s:system([perl_exec, '-W', '-MApp::cpanminus', '-e', '']) + if s:shell_error + return [perl_exec, '"App::cpanminus" module is not installed'] + endif + + let latest_cpan_cmd = [perl_exec, + \ '-MApp::cpanminus::fatscript', '-e', + \ 'my $app = App::cpanminus::script->new; + \ $app->parse_options ("--info", "-q", "Neovim::Ext"); + \ exit $app->doit'] + + let latest_cpan = s:system(latest_cpan_cmd) + if s:shell_error || empty(latest_cpan) + call health#report_error('Failed to run: '. join(latest_cpan_cmd, " "), + \ ["Make sure you're connected to the internet.", + \ 'Are you behind a firewall or proxy?']) + return + elseif latest_cpan[0] ==# '!' + let cpanm_errs = split(latest_cpan, '!') + if cpanm_errs[0] =~# "Can't write to " + call health#report_warn(cpanm_errs[0], cpanm_errs[1:-2]) + " Last line is the package info + let latest_cpan = cpanm_errs[-1] + else + call health#report_error('Unknown warning from command: ' . latest_cpan_cmd, cpanm_errs) + return + endif + endif + let latest_cpan = matchstr(latest_cpan, '\(\.\?\d\)\+') + if empty(latest_cpan) + call health#report_error('Cannot parse version number from cpanm output: ' . latest_cpan) + return + endif + + let current_cpan_cmd = [perl_exec, '-W', '-MNeovim::Ext', '-e', 'print $Neovim::Ext::VERSION'] + let current_cpan = s:system(current_cpan_cmd) + if s:shell_error + call health#report_error('Failed to run: '. join(current_cpan_cmd), + \ ['Report this issue with the output of: ', join(current_cpan_cmd)]) + return + endif + + if v:lua.vim.version.lt(current_cpan, latest_cpan) + call health#report_warn( + \ printf('Module "Neovim::Ext" is out-of-date. Installed: %s, latest: %s', + \ current_cpan, latest_cpan), + \ ['Run in shell: cpanm -n Neovim::Ext']) + else + call health#report_ok('Latest "Neovim::Ext" cpan module is installed: '. current_cpan) + endif +endfunction + +function! health#provider2#check() abort + call s:check_python() + call s:check_virtualenv() + call s:check_ruby() + call s:check_node() + call s:check_perl() +endfunction -- cgit From 71225228fc2700a18c56c57f9dc14494cef83149 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sun, 9 Apr 2023 22:28:00 +0200 Subject: refactor: rewrite python provider healthcheck in Lua This is required to remove the vimscript checkhealth functions. --- runtime/autoload/health/provider2.vim | 350 ---------------------------------- 1 file changed, 350 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/health/provider2.vim b/runtime/autoload/health/provider2.vim index 196a3ce9de..0ebf203788 100644 --- a/runtime/autoload/health/provider2.vim +++ b/runtime/autoload/health/provider2.vim @@ -1,24 +1,10 @@ let s:shell_error = 0 -function! s:is_bad_response(s) abort - return a:s =~? '\v(^unable)|(^error)|(^outdated)' -endfunction - -function! s:trim(s) abort - return substitute(a:s, '^\_s*\|\_s*$', '', 'g') -endfunction - " Convert '\' to '/'. Collapse '//' and '/./'. function! s:normalize_path(s) abort return substitute(substitute(a:s, '\', '/', 'g'), '/\./\|/\+', '/', 'g') endfunction -" Returns TRUE if `cmd` exits with success, else FALSE. -function! s:cmd_ok(cmd) abort - call system(a:cmd) - return v:shell_error == 0 -endfunction - " Handler for s:system() function. function! s:system_handler(jobid, data, event) dict abort if a:event ==# 'stderr' @@ -88,143 +74,6 @@ function! s:system(cmd, ...) abort return opts.output endfunction -function! s:systemlist(cmd, ...) abort - let stdout = split(s:system(a:cmd, a:0 ? a:1 : ''), "\n") - if a:0 > 1 && !empty(a:2) - return filter(stdout, '!empty(v:val)') - endif - return stdout -endfunction - -" Fetch the contents of a URL. -function! s:download(url) abort - let has_curl = executable('curl') - if has_curl && system(['curl', '-V']) =~# 'Protocols:.*https' - let rv = s:system(['curl', '-sL', a:url], '', 1, 1) - return s:shell_error ? 'curl error with '.a:url.': '.s:shell_error : rv - elseif executable('python') - let script = " - \try:\n - \ from urllib.request import urlopen\n - \except ImportError:\n - \ from urllib2 import urlopen\n - \\n - \response = urlopen('".a:url."')\n - \print(response.read().decode('utf8'))\n - \" - let rv = s:system(['python', '-c', script]) - return empty(rv) && s:shell_error - \ ? 'python urllib.request error: '.s:shell_error - \ : rv - endif - return 'missing `curl` ' - \ .(has_curl ? '(with HTTPS support) ' : '') - \ .'and `python`, cannot make web request' -endfunction - -" Get the latest Nvim Python client (pynvim) version from PyPI. -function! s:latest_pypi_version() abort - let pypi_version = 'unable to get pypi response' - let pypi_response = s:download('https://pypi.python.org/pypi/pynvim/json') - if !empty(pypi_response) - try - let pypi_data = json_decode(pypi_response) - catch /E474/ - return 'error: '.pypi_response - endtry - let pypi_version = get(get(pypi_data, 'info', {}), 'version', 'unable to parse') - endif - return pypi_version -endfunction - -" Get version information using the specified interpreter. The interpreter is -" used directly in case breaking changes were introduced since the last time -" Nvim's Python client was updated. -" -" Returns: [ -" {python executable version}, -" {current nvim version}, -" {current pypi nvim status}, -" {installed version status} -" ] -function! s:version_info(python) abort - let pypi_version = s:latest_pypi_version() - let python_version = s:trim(s:system([ - \ a:python, - \ '-c', - \ 'import sys; print(".".join(str(x) for x in sys.version_info[:3]))', - \ ])) - - if empty(python_version) - let python_version = 'unable to parse '.a:python.' response' - endif - - let nvim_path = s:trim(s:system([ - \ a:python, '-c', - \ 'import sys; ' . - \ 'sys.path = [p for p in sys.path if p != ""]; ' . - \ 'import neovim; print(neovim.__file__)'])) - if s:shell_error || empty(nvim_path) - return [python_version, 'unable to load neovim Python module', pypi_version, - \ nvim_path] - endif - - " Assuming that multiple versions of a package are installed, sort them - " numerically in descending order. - function! s:compare(metapath1, metapath2) abort - let a = matchstr(fnamemodify(a:metapath1, ':p:h:t'), '[0-9.]\+') - let b = matchstr(fnamemodify(a:metapath2, ':p:h:t'), '[0-9.]\+') - return a == b ? 0 : a > b ? 1 : -1 - endfunction - - " Try to get neovim.VERSION (added in 0.1.11dev). - let nvim_version = s:system([a:python, '-c', - \ 'from neovim import VERSION as v; '. - \ 'print("{}.{}.{}{}".format(v.major, v.minor, v.patch, v.prerelease))'], - \ '', 1, 1) - if empty(nvim_version) - let nvim_version = 'unable to find pynvim module version' - let base = fnamemodify(nvim_path, ':h') - let metas = glob(base.'-*/METADATA', 1, 1) - \ + glob(base.'-*/PKG-INFO', 1, 1) - \ + glob(base.'.egg-info/PKG-INFO', 1, 1) - let metas = sort(metas, 's:compare') - - if !empty(metas) - for meta_line in readfile(metas[0]) - if meta_line =~# '^Version:' - let nvim_version = matchstr(meta_line, '^Version: \zs\S\+') - break - endif - endfor - endif - endif - - let nvim_path_base = fnamemodify(nvim_path, ':~:h') - let version_status = 'unknown; '.nvim_path_base - if !s:is_bad_response(nvim_version) && !s:is_bad_response(pypi_version) - if v:lua.vim.version.lt(nvim_version, pypi_version) - let version_status = 'outdated; from '.nvim_path_base - else - let version_status = 'up to date' - endif - endif - - return [python_version, nvim_version, pypi_version, version_status] -endfunction - -" Check the Python interpreter's usability. -function! s:check_bin(bin) abort - if !filereadable(a:bin) && (!has('win32') || !filereadable(a:bin.'.exe')) - call health#report_error(printf('"%s" was not found.', a:bin)) - return 0 - elseif executable(a:bin) != 1 - call health#report_error(printf('"%s" is not executable.', a:bin)) - return 0 - endif - return 1 -endfunction - " Check "loaded" var for given a:provider. " Returns 1 if the caller should return (skip checks). function! s:disabled_via_loaded_var(provider) abort @@ -241,204 +90,6 @@ function! s:disabled_via_loaded_var(provider) abort return 0 endfunction -function! s:check_python() abort - call health#report_start('Python 3 provider (optional)') - - let pyname = 'python3' - let python_exe = '' - let venv = exists('$VIRTUAL_ENV') ? resolve($VIRTUAL_ENV) : '' - let host_prog_var = pyname.'_host_prog' - let python_multiple = [] - - if s:disabled_via_loaded_var(pyname) - return - endif - - let [pyenv, pyenv_root] = s:check_for_pyenv() - - if exists('g:'.host_prog_var) - call health#report_info(printf('Using: g:%s = "%s"', host_prog_var, get(g:, host_prog_var))) - endif - - let [pyname, pythonx_warnings] = provider#pythonx#Detect(3) - - if empty(pyname) - call health#report_warn('No Python executable found that can `import neovim`. ' - \ . 'Using the first available executable for diagnostics.') - elseif exists('g:'.host_prog_var) - let python_exe = pyname - endif - - " No Python executable could `import neovim`, or host_prog_var was used. - if !empty(pythonx_warnings) - call health#report_warn(pythonx_warnings, ['See :help provider-python for more information.', - \ 'You may disable this provider (and warning) by adding `let g:loaded_python3_provider = 0` to your init.vim']) - - elseif !empty(pyname) && empty(python_exe) - if !exists('g:'.host_prog_var) - call health#report_info(printf('`g:%s` is not set. Searching for ' - \ . '%s in the environment.', host_prog_var, pyname)) - endif - - if !empty(pyenv) - let python_exe = s:trim(s:system([pyenv, 'which', pyname], '', 1)) - - if empty(python_exe) - call health#report_warn(printf('pyenv could not find %s.', pyname)) - endif - endif - - if empty(python_exe) - let python_exe = exepath(pyname) - - if exists('$PATH') - for path in split($PATH, has('win32') ? ';' : ':') - let path_bin = s:normalize_path(path.'/'.pyname) - if path_bin != s:normalize_path(python_exe) - \ && index(python_multiple, path_bin) == -1 - \ && executable(path_bin) - call add(python_multiple, path_bin) - endif - endfor - - if len(python_multiple) - " This is worth noting since the user may install something - " that changes $PATH, like homebrew. - call health#report_info(printf('Multiple %s executables found. ' - \ . 'Set `g:%s` to avoid surprises.', pyname, host_prog_var)) - endif - - if python_exe =~# '\' - call health#report_warn(printf('`%s` appears to be a pyenv shim.', python_exe), [ - \ '`pyenv` is not in $PATH, your pyenv installation is broken. ' - \ .'Set `g:'.host_prog_var.'` to avoid surprises.', - \ ]) - endif - endif - endif - endif - - if !empty(python_exe) && !exists('g:'.host_prog_var) - if empty(venv) && !empty(pyenv) - \ && !empty(pyenv_root) && resolve(python_exe) !~# '^'.pyenv_root.'/' - call health#report_warn('pyenv is not set up optimally.', [ - \ printf('Create a virtualenv specifically ' - \ . 'for Nvim using pyenv, and set `g:%s`. This will avoid ' - \ . 'the need to install the pynvim module in each ' - \ . 'version/virtualenv.', host_prog_var) - \ ]) - elseif !empty(venv) - if !empty(pyenv_root) - let venv_root = pyenv_root - else - let venv_root = fnamemodify(venv, ':h') - endif - - if resolve(python_exe) !~# '^'.venv_root.'/' - call health#report_warn('Your virtualenv is not set up optimally.', [ - \ printf('Create a virtualenv specifically ' - \ . 'for Nvim and use `g:%s`. This will avoid ' - \ . 'the need to install the pynvim module in each ' - \ . 'virtualenv.', host_prog_var) - \ ]) - endif - endif - endif - - if empty(python_exe) && !empty(pyname) - " An error message should have already printed. - call health#report_error(printf('`%s` was not found.', pyname)) - elseif !empty(python_exe) && !s:check_bin(python_exe) - let python_exe = '' - endif - - " Diagnostic output - call health#report_info('Executable: ' . (empty(python_exe) ? 'Not found' : python_exe)) - if len(python_multiple) - for path_bin in python_multiple - call health#report_info('Other python executable: ' . path_bin) - endfor - endif - - if empty(python_exe) - " No Python executable can import 'neovim'. Check if any Python executable - " can import 'pynvim'. If so, that Python failed to import 'neovim' as - " well, which is most probably due to a failed pip upgrade: - " https://github.com/neovim/neovim/wiki/Following-HEAD#20181118 - let [pynvim_exe, errors] = provider#pythonx#DetectByModule('pynvim', 3) - if !empty(pynvim_exe) - call health#report_error( - \ 'Detected pip upgrade failure: Python executable can import "pynvim" but ' - \ . 'not "neovim": '. pynvim_exe, - \ "Use that Python version to reinstall \"pynvim\" and optionally \"neovim\".\n" - \ . pynvim_exe ." -m pip uninstall pynvim neovim\n" - \ . pynvim_exe ." -m pip install pynvim\n" - \ . pynvim_exe ." -m pip install neovim # only if needed by third-party software") - endif - else - let [majorpyversion, current, latest, status] = s:version_info(python_exe) - - if 3 != str2nr(majorpyversion) - call health#report_warn('Unexpected Python version.' . - \ ' This could lead to confusing error messages.') - endif - - call health#report_info('Python version: ' . majorpyversion) - - if s:is_bad_response(status) - call health#report_info(printf('pynvim version: %s (%s)', current, status)) - else - call health#report_info(printf('pynvim version: %s', current)) - endif - - if s:is_bad_response(current) - call health#report_error( - \ "pynvim is not installed.\nError: ".current, - \ ['Run in shell: '. python_exe .' -m pip install pynvim']) - endif - - if s:is_bad_response(latest) - call health#report_warn('Could not contact PyPI to get latest version.') - call health#report_error('HTTP request failed: '.latest) - elseif s:is_bad_response(status) - call health#report_warn(printf('Latest pynvim is NOT installed: %s', latest)) - elseif !s:is_bad_response(current) - call health#report_ok(printf('Latest pynvim is installed.')) - endif - endif -endfunction - -" Check if pyenv is available and a valid pyenv root can be found, then return -" their respective paths. If either of those is invalid, return two empty -" strings, effectively ignoring pyenv. -function! s:check_for_pyenv() abort - let pyenv_path = resolve(exepath('pyenv')) - - if empty(pyenv_path) - return ['', ''] - endif - - call health#report_info('pyenv: Path: '. pyenv_path) - - let pyenv_root = exists('$PYENV_ROOT') ? resolve($PYENV_ROOT) : '' - - if empty(pyenv_root) - let pyenv_root = s:trim(s:system([pyenv_path, 'root'])) - call health#report_info('pyenv: $PYENV_ROOT is not set. Infer from `pyenv root`.') - endif - - if !isdirectory(pyenv_root) - call health#report_warn( - \ printf('pyenv: Root does not exist: %s. ' - \ . 'Ignoring pyenv for all following checks.', pyenv_root)) - return ['', ''] - endif - - call health#report_info('pyenv: Root: '.pyenv_root) - - return [pyenv_path, pyenv_root] -endfunction - " Resolves Python executable path by invoking and checking `sys.executable`. function! s:python_exepath(invocation) abort return s:normalize_path(system(fnameescape(a:invocation) @@ -721,7 +372,6 @@ function! s:check_perl() abort endfunction function! health#provider2#check() abort - call s:check_python() call s:check_virtualenv() call s:check_ruby() call s:check_node() -- cgit From 5ed7ede1f58200e79bc1ac8a15356ef2fa7319b0 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Mon, 10 Apr 2023 11:28:42 +0200 Subject: refactor: rewrite virtualenv healthcheck in lua This is required to remove the vimscript checkhealth functions. --- runtime/autoload/health/provider2.vim | 74 ----------------------------------- 1 file changed, 74 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/health/provider2.vim b/runtime/autoload/health/provider2.vim index 0ebf203788..3387b7eb14 100644 --- a/runtime/autoload/health/provider2.vim +++ b/runtime/autoload/health/provider2.vim @@ -90,79 +90,6 @@ function! s:disabled_via_loaded_var(provider) abort return 0 endfunction -" Resolves Python executable path by invoking and checking `sys.executable`. -function! s:python_exepath(invocation) abort - return s:normalize_path(system(fnameescape(a:invocation) - \ . ' -c "import sys; sys.stdout.write(sys.executable)"')) -endfunction - -" Checks that $VIRTUAL_ENV Python executables are found at front of $PATH in -" Nvim and subshells. -function! s:check_virtualenv() abort - call health#report_start('Python virtualenv') - if !exists('$VIRTUAL_ENV') - call health#report_ok('no $VIRTUAL_ENV') - return - endif - let errors = [] - " Keep hints as dict keys in order to discard duplicates. - let hints = {} - " The virtualenv should contain some Python executables, and those - " executables should be first both on Nvim's $PATH and the $PATH of - " subshells launched from Nvim. - let bin_dir = has('win32') ? '/Scripts' : '/bin' - let venv_bins = glob($VIRTUAL_ENV . bin_dir . '/python*', v:true, v:true) - " XXX: Remove irrelevant executables found in bin/. - let venv_bins = filter(venv_bins, 'v:val !~# "python-config"') - if len(venv_bins) - for venv_bin in venv_bins - let venv_bin = s:normalize_path(venv_bin) - let py_bin_basename = fnamemodify(venv_bin, ':t') - let nvim_py_bin = s:python_exepath(exepath(py_bin_basename)) - let subshell_py_bin = s:python_exepath(py_bin_basename) - if venv_bin !=# nvim_py_bin - call add(errors, '$PATH yields this '.py_bin_basename.' executable: '.nvim_py_bin) - let hint = '$PATH ambiguities arise if the virtualenv is not ' - \.'properly activated prior to launching Nvim. Close Nvim, activate the virtualenv, ' - \.'check that invoking Python from the command line launches the correct one, ' - \.'then relaunch Nvim.' - let hints[hint] = v:true - endif - if venv_bin !=# subshell_py_bin - call add(errors, '$PATH in subshells yields this ' - \.py_bin_basename . ' executable: '.subshell_py_bin) - let hint = '$PATH ambiguities in subshells typically are ' - \.'caused by your shell config overriding the $PATH previously set by the ' - \.'virtualenv. Either prevent them from doing so, or use this workaround: ' - \.'https://vi.stackexchange.com/a/34996' - let hints[hint] = v:true - endif - endfor - else - call add(errors, 'no Python executables found in the virtualenv '.bin_dir.' directory.') - endif - - let msg = '$VIRTUAL_ENV is set to: '.$VIRTUAL_ENV - if len(errors) - if len(venv_bins) - let msg .= "\nAnd its ".bin_dir.' directory contains: ' - \.join(map(venv_bins, "fnamemodify(v:val, ':t')"), ', ') - endif - let conj = "\nBut " - for error in errors - let msg .= conj.error - let conj = "\nAnd " - endfor - let msg .= "\nSo invoking Python may lead to unexpected results." - call health#report_warn(msg, keys(hints)) - else - call health#report_info(msg) - call health#report_info('Python version: ' - \.system('python -c "import platform, sys; sys.stdout.write(platform.python_version())"')) - call health#report_ok('$VIRTUAL_ENV provides :!python.') - endif -endfunction - function! s:check_ruby() abort call health#report_start('Ruby provider (optional)') @@ -372,7 +299,6 @@ function! s:check_perl() abort endfunction function! health#provider2#check() abort - call s:check_virtualenv() call s:check_ruby() call s:check_node() call s:check_perl() -- cgit From 7801ffc38aedbbd527e614b6ba5ad60ecf380470 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Mon, 10 Apr 2023 14:06:10 +0200 Subject: refactor: rewrite ruby healthcheck in lua This is required to remove the vimscript checkhealth functions. --- runtime/autoload/health/provider2.vim | 61 ----------------------------------- 1 file changed, 61 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/health/provider2.vim b/runtime/autoload/health/provider2.vim index 3387b7eb14..edd3baae12 100644 --- a/runtime/autoload/health/provider2.vim +++ b/runtime/autoload/health/provider2.vim @@ -1,10 +1,5 @@ let s:shell_error = 0 -" Convert '\' to '/'. Collapse '//' and '/./'. -function! s:normalize_path(s) abort - return substitute(substitute(a:s, '\', '/', 'g'), '/\./\|/\+', '/', 'g') -endfunction - " Handler for s:system() function. function! s:system_handler(jobid, data, event) dict abort if a:event ==# 'stderr' @@ -90,61 +85,6 @@ function! s:disabled_via_loaded_var(provider) abort return 0 endfunction -function! s:check_ruby() abort - call health#report_start('Ruby provider (optional)') - - if s:disabled_via_loaded_var('ruby') - return - endif - - if !executable('ruby') || !executable('gem') - call health#report_warn( - \ '`ruby` and `gem` must be in $PATH.', - \ ['Install Ruby and verify that `ruby` and `gem` commands work.']) - return - endif - call health#report_info('Ruby: '. s:system(['ruby', '-v'])) - - let [host, err] = provider#ruby#Detect() - if empty(host) - call health#report_warn('`neovim-ruby-host` not found.', - \ ['Run `gem install neovim` to ensure the neovim RubyGem is installed.', - \ 'Run `gem environment` to ensure the gem bin directory is in $PATH.', - \ 'If you are using rvm/rbenv/chruby, try "rehashing".', - \ 'See :help g:ruby_host_prog for non-standard gem installations.', - \ 'You may disable this provider (and warning) by adding `let g:loaded_ruby_provider = 0` to your init.vim']) - return - endif - call health#report_info('Host: '. host) - - let latest_gem_cmd = has('win32') ? 'cmd /c gem list -ra "^^neovim$"' : 'gem list -ra ^neovim$' - let latest_gem = s:system(split(latest_gem_cmd)) - if s:shell_error || empty(latest_gem) - call health#report_error('Failed to run: '. latest_gem_cmd, - \ ["Make sure you're connected to the internet.", - \ 'Are you behind a firewall or proxy?']) - return - endif - let latest_gem = get(split(latest_gem, 'neovim (\|, \|)$' ), 0, 'not found') - - let current_gem_cmd = [host, '--version'] - let current_gem = s:system(current_gem_cmd) - if s:shell_error - call health#report_error('Failed to run: '. join(current_gem_cmd), - \ ['Report this issue with the output of: ', join(current_gem_cmd)]) - return - endif - - if v:lua.vim.version.lt(current_gem, latest_gem) - call health#report_warn( - \ printf('Gem "neovim" is out-of-date. Installed: %s, latest: %s', - \ current_gem, latest_gem), - \ ['Run in shell: gem update neovim']) - else - call health#report_ok('Latest "neovim" gem is installed: '. current_gem) - endif -endfunction - function! s:check_node() abort call health#report_start('Node.js provider (optional)') @@ -299,7 +239,6 @@ function! s:check_perl() abort endfunction function! health#provider2#check() abort - call s:check_ruby() call s:check_node() call s:check_perl() endfunction -- cgit From b5c0e7137cee76a16ee114711616e8a6d340c96f Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Mon, 10 Apr 2023 15:26:22 +0200 Subject: refactor: rewrite node healthcheck in lua This is required to remove the vimscript checkhealth functions. --- runtime/autoload/health/provider2.vim | 80 ----------------------------------- 1 file changed, 80 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/health/provider2.vim b/runtime/autoload/health/provider2.vim index edd3baae12..ce3a360375 100644 --- a/runtime/autoload/health/provider2.vim +++ b/runtime/autoload/health/provider2.vim @@ -85,85 +85,6 @@ function! s:disabled_via_loaded_var(provider) abort return 0 endfunction -function! s:check_node() abort - call health#report_start('Node.js provider (optional)') - - if s:disabled_via_loaded_var('node') - return - endif - - if !executable('node') || (!executable('npm') && !executable('yarn') && !executable('pnpm')) - call health#report_warn( - \ '`node` and `npm` (or `yarn`, `pnpm`) must be in $PATH.', - \ ['Install Node.js and verify that `node` and `npm` (or `yarn`, `pnpm`) commands work.']) - return - endif - let node_v = get(split(s:system(['node', '-v']), "\n"), 0, '') - call health#report_info('Node.js: '. node_v) - if s:shell_error || v:lua.vim.version.lt(node_v[1:], '6.0.0') - call health#report_warn('Nvim node.js host does not support Node '.node_v) - " Skip further checks, they are nonsense if nodejs is too old. - return - endif - if !provider#node#can_inspect() - call health#report_warn('node.js on this system does not support --inspect-brk so $NVIM_NODE_HOST_DEBUG is ignored.') - endif - - let [host, err] = provider#node#Detect() - if empty(host) - call health#report_warn('Missing "neovim" npm (or yarn, pnpm) package.', - \ ['Run in shell: npm install -g neovim', - \ 'Run in shell (if you use yarn): yarn global add neovim', - \ 'Run in shell (if you use pnpm): pnpm install -g neovim', - \ 'You may disable this provider (and warning) by adding `let g:loaded_node_provider = 0` to your init.vim']) - return - endif - call health#report_info('Nvim node.js host: '. host) - - let manager = 'npm' - if executable('yarn') - let manager = 'yarn' - elseif executable('pnpm') - let manager = 'pnpm' - endif - - let latest_npm_cmd = has('win32') ? - \ 'cmd /c '. manager .' info neovim --json' : - \ manager .' info neovim --json' - let latest_npm = s:system(split(latest_npm_cmd)) - if s:shell_error || empty(latest_npm) - call health#report_error('Failed to run: '. latest_npm_cmd, - \ ["Make sure you're connected to the internet.", - \ 'Are you behind a firewall or proxy?']) - return - endif - try - let pkg_data = json_decode(latest_npm) - catch /E474/ - return 'error: '.latest_npm - endtry - let latest_npm = get(get(pkg_data, 'dist-tags', {}), 'latest', 'unable to parse') - - let current_npm_cmd = ['node', host, '--version'] - let current_npm = s:system(current_npm_cmd) - if s:shell_error - call health#report_error('Failed to run: '. join(current_npm_cmd), - \ ['Report this issue with the output of: ', join(current_npm_cmd)]) - return - endif - - if latest_npm !=# 'unable to parse' && v:lua.vim.version.lt(current_npm, latest_npm) - call health#report_warn( - \ printf('Package "neovim" is out-of-date. Installed: %s, latest: %s', - \ current_npm, latest_npm), - \ ['Run in shell: npm install -g neovim', - \ 'Run in shell (if you use yarn): yarn global add neovim', - \ 'Run in shell (if you use pnpm): pnpm install -g neovim']) - else - call health#report_ok('Latest "neovim" npm/yarn/pnpm package is installed: '. current_npm) - endif -endfunction - function! s:check_perl() abort call health#report_start('Perl provider (optional)') @@ -239,6 +160,5 @@ function! s:check_perl() abort endfunction function! health#provider2#check() abort - call s:check_node() call s:check_perl() endfunction -- cgit From bd98ef6ac6e9f059b943ddfaa6676dc48d9ea832 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Mon, 10 Apr 2023 15:59:50 +0200 Subject: refactor: rewrite perl healthcheck in lua This is required to remove the vimscript checkhealth functions. --- runtime/autoload/health/provider2.vim | 164 ---------------------------------- 1 file changed, 164 deletions(-) delete mode 100644 runtime/autoload/health/provider2.vim (limited to 'runtime/autoload') diff --git a/runtime/autoload/health/provider2.vim b/runtime/autoload/health/provider2.vim deleted file mode 100644 index ce3a360375..0000000000 --- a/runtime/autoload/health/provider2.vim +++ /dev/null @@ -1,164 +0,0 @@ -let s:shell_error = 0 - -" Handler for s:system() function. -function! s:system_handler(jobid, data, event) dict abort - if a:event ==# 'stderr' - if self.add_stderr_to_output - let self.output .= join(a:data, '') - else - let self.stderr .= join(a:data, '') - endif - elseif a:event ==# 'stdout' - let self.output .= join(a:data, '') - elseif a:event ==# 'exit' - let s:shell_error = a:data - endif -endfunction - -" Attempts to construct a shell command from an args list. -" Only for display, to help users debug a failed command. -function! s:shellify(cmd) abort - if type(a:cmd) != type([]) - return a:cmd - endif - return join(map(copy(a:cmd), - \'v:val =~# ''\m[^\-.a-zA-Z_/]'' ? shellescape(v:val) : v:val'), ' ') -endfunction - -" Run a system command and timeout after 30 seconds. -function! s:system(cmd, ...) abort - let stdin = a:0 ? a:1 : '' - let ignore_error = a:0 > 2 ? a:3 : 0 - let opts = { - \ 'add_stderr_to_output': a:0 > 1 ? a:2 : 0, - \ 'output': '', - \ 'stderr': '', - \ 'on_stdout': function('s:system_handler'), - \ 'on_stderr': function('s:system_handler'), - \ 'on_exit': function('s:system_handler'), - \ } - let jobid = jobstart(a:cmd, opts) - - if jobid < 1 - call health#report_error(printf('Command error (job=%d): `%s` (in %s)', - \ jobid, s:shellify(a:cmd), string(getcwd()))) - let s:shell_error = 1 - return opts.output - endif - - if !empty(stdin) - call jobsend(jobid, stdin) - endif - - let res = jobwait([jobid], 30000) - if res[0] == -1 - call health#report_error(printf('Command timed out: %s', s:shellify(a:cmd))) - call jobstop(jobid) - elseif s:shell_error != 0 && !ignore_error - let emsg = printf("Command error (job=%d, exit code %d): `%s` (in %s)", - \ jobid, s:shell_error, s:shellify(a:cmd), string(getcwd())) - if !empty(opts.output) - let emsg .= "\noutput: " . opts.output - end - if !empty(opts.stderr) - let emsg .= "\nstderr: " . opts.stderr - end - call health#report_error(emsg) - endif - - return opts.output -endfunction - -" Check "loaded" var for given a:provider. -" Returns 1 if the caller should return (skip checks). -function! s:disabled_via_loaded_var(provider) abort - let loaded_var = 'g:loaded_'.a:provider.'_provider' - if exists(loaded_var) && !exists('*provider#'.a:provider.'#Call') - let v = eval(loaded_var) - if 0 is v - call health#report_info('Disabled ('.loaded_var.'='.v.').') - return 1 - else - call health#report_info('Disabled ('.loaded_var.'='.v.'). This might be due to some previous error.') - endif - endif - return 0 -endfunction - -function! s:check_perl() abort - call health#report_start('Perl provider (optional)') - - if s:disabled_via_loaded_var('perl') - return - endif - - let [perl_exec, perl_warnings] = provider#perl#Detect() - if empty(perl_exec) - if !empty(perl_warnings) - call health#report_warn(perl_warnings, ['See :help provider-perl for more information.', - \ 'You may disable this provider (and warning) by adding `let g:loaded_perl_provider = 0` to your init.vim']) - else - call health#report_warn('No usable perl executable found') - endif - return - endif - - call health#report_info('perl executable: '. perl_exec) - - " we cannot use cpanm that is on the path, as it may not be for the perl - " set with g:perl_host_prog - call s:system([perl_exec, '-W', '-MApp::cpanminus', '-e', '']) - if s:shell_error - return [perl_exec, '"App::cpanminus" module is not installed'] - endif - - let latest_cpan_cmd = [perl_exec, - \ '-MApp::cpanminus::fatscript', '-e', - \ 'my $app = App::cpanminus::script->new; - \ $app->parse_options ("--info", "-q", "Neovim::Ext"); - \ exit $app->doit'] - - let latest_cpan = s:system(latest_cpan_cmd) - if s:shell_error || empty(latest_cpan) - call health#report_error('Failed to run: '. join(latest_cpan_cmd, " "), - \ ["Make sure you're connected to the internet.", - \ 'Are you behind a firewall or proxy?']) - return - elseif latest_cpan[0] ==# '!' - let cpanm_errs = split(latest_cpan, '!') - if cpanm_errs[0] =~# "Can't write to " - call health#report_warn(cpanm_errs[0], cpanm_errs[1:-2]) - " Last line is the package info - let latest_cpan = cpanm_errs[-1] - else - call health#report_error('Unknown warning from command: ' . latest_cpan_cmd, cpanm_errs) - return - endif - endif - let latest_cpan = matchstr(latest_cpan, '\(\.\?\d\)\+') - if empty(latest_cpan) - call health#report_error('Cannot parse version number from cpanm output: ' . latest_cpan) - return - endif - - let current_cpan_cmd = [perl_exec, '-W', '-MNeovim::Ext', '-e', 'print $Neovim::Ext::VERSION'] - let current_cpan = s:system(current_cpan_cmd) - if s:shell_error - call health#report_error('Failed to run: '. join(current_cpan_cmd), - \ ['Report this issue with the output of: ', join(current_cpan_cmd)]) - return - endif - - if v:lua.vim.version.lt(current_cpan, latest_cpan) - call health#report_warn( - \ printf('Module "Neovim::Ext" is out-of-date. Installed: %s, latest: %s', - \ current_cpan, latest_cpan), - \ ['Run in shell: cpanm -n Neovim::Ext']) - else - call health#report_ok('Latest "Neovim::Ext" cpan module is installed: '. current_cpan) - endif -endfunction - -function! health#provider2#check() abort - call s:check_perl() -endfunction -- cgit From 880f7d12fea31ea85d14b419ef8dcbb16dee2cf4 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Tue, 11 Apr 2023 19:10:36 +0200 Subject: feat!: remove vimballs (#22402) Vimball is an outdated feature that is rarely used these days. It is not a maintenance burden on its own, but it is nonetheless dead weight and something we'd need to tell users to ignore when they inevitably ask what it is. See: https://github.com/neovim/neovim/pull/21369#issuecomment-1347615173 --- runtime/autoload/tar.vim | 76 ------------------------------------------------ 1 file changed, 76 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/tar.vim b/runtime/autoload/tar.vim index e495e8262a..d7d1d8399e 100644 --- a/runtime/autoload/tar.vim +++ b/runtime/autoload/tar.vim @@ -735,82 +735,6 @@ fun! s:Rmdir(fname) " call Dret("Rmdir") endfun -" --------------------------------------------------------------------- -" tar#Vimuntar: installs a tarball in the user's .vim / vimfiles directory {{{2 -fun! tar#Vimuntar(...) -" call Dfunc("tar#Vimuntar() a:0=".a:0." a:1<".(exists("a:1")? a:1 : "-n/a-").">") - let tarball = expand("%") -" call Decho("tarball<".tarball.">") - let tarbase = substitute(tarball,'\..*$','','') -" call Decho("tarbase<".tarbase.">") - let tarhome = expand("%:p") - if has("win32") || has("win95") || has("win64") || has("win16") - let tarhome= substitute(tarhome,'\\','/','g') - endif - let tarhome= substitute(tarhome,'/[^/]*$','','') -" call Decho("tarhome<".tarhome.">") - let tartail = expand("%:t") -" call Decho("tartail<".tartail.">") - let curdir = getcwd() -" call Decho("curdir <".curdir.">") - " set up vimhome - if a:0 > 0 && a:1 != "" - let vimhome= a:1 - else - let vimhome= vimball#VimballHome() - endif -" call Decho("vimhome<".vimhome.">") - -" call Decho("curdir<".curdir."> vimhome<".vimhome.">") - if simplify(curdir) != simplify(vimhome) - " copy (possibly compressed) tarball to .vim/vimfiles -" call Decho(netrw#WinPath(g:tar_copycmd)." ".shellescape(tartail)." ".shellescape(vimhome)) - call system(netrw#WinPath(g:tar_copycmd)." ".shellescape(tartail)." ".shellescape(vimhome)) -" call Decho("exe cd ".fnameescape(vimhome)) - exe "cd ".fnameescape(vimhome) - endif -" call Decho("getcwd<".getcwd().">") - - " if necessary, decompress the tarball; then, extract it - if tartail =~ '\.tgz' - if executable("gunzip") - silent exe "!gunzip ".shellescape(tartail) - elseif executable("gzip") - silent exe "!gzip -d ".shellescape(tartail) - else - echoerr "unable to decompress<".tartail."> on this system" - if simplify(curdir) != simplify(tarhome) - " remove decompressed tarball, restore directory -" call Decho("delete(".tartail.".tar)") - call delete(tartail.".tar") -" call Decho("exe cd ".fnameescape(curdir)) - exe "cd ".fnameescape(curdir) - endif -" call Dret("tar#Vimuntar") - return - endif - else - call vimball#Decompress(tartail,0) - endif - let extractcmd= netrw#WinPath(g:tar_extractcmd) -" call Decho("system(".extractcmd." ".shellescape(tarbase.".tar").")") - call system(extractcmd." ".shellescape(tarbase.".tar")) - - " set up help - if filereadable("doc/".tarbase.".txt") -" call Decho("exe helptags ".getcwd()."/doc") - exe "helptags ".getcwd()."/doc" - endif - - if simplify(tarhome) != simplify(vimhome) - " remove decompressed tarball, restore directory - call delete(vimhome."/".tarbase.".tar") - exe "cd ".fnameescape(curdir) - endif - -" call Dret("tar#Vimuntar") -endfun - " ===================================================================== " Modelines And Restoration: {{{1 let &cpo= s:keepcpo -- cgit From c08b03076167837cff9eb66c19440d727e6dad31 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 15 Apr 2023 23:40:48 +0200 Subject: refactor: deprecate checkhealth functions The following functions are deprecated and will be removed in Nvim v0.11: - health#report_start() - health#report_info() - health#report_ok() - health#report_warn() - health#report_error() - vim.health.report_start() - vim.health.report_info() - vim.health.report_ok() - vim.health.report_warn() - vim.health.report_error() Users should instead use these: - vim.health.start() - vim.health.info() - vim.health.ok() - vim.health.warn() - vim.health.error() --- runtime/autoload/health.vim | 211 +++++--------------------------------------- 1 file changed, 21 insertions(+), 190 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/health.vim b/runtime/autoload/health.vim index 5fd4627b11..1c414377f6 100644 --- a/runtime/autoload/health.vim +++ b/runtime/autoload/health.vim @@ -1,207 +1,38 @@ -" Runs the specified healthchecks. -" Runs all discovered healthchecks if a:plugin_names is empty. -function! health#check(plugin_names) abort - let healthchecks = empty(a:plugin_names) - \ ? s:discover_healthchecks() - \ : s:get_healthcheck(a:plugin_names) - - " Create buffer and open in a tab, unless this is the default buffer when Nvim starts. - let emptybuf = (bufnr('$') == 1 && empty(getline(1)) && 1 == line('$')) - execute (emptybuf ? 'buffer' : 'tab sbuffer') nvim_create_buf(v:true, v:true) - if bufexists('health://') - bwipe health:// - endif - file health:// - setfiletype checkhealth - - if empty(healthchecks) - call setline(1, 'ERROR: No healthchecks found.') - else - redraw|echo 'Running healthchecks...' - for name in sort(keys(healthchecks)) - let [func, type] = healthchecks[name] - let s:output = [] - try - if func == '' - throw 'healthcheck_not_found' - endif - eval type == 'v' ? call(func, []) : luaeval(func) - " in the event the healthcheck doesn't return anything - " (the plugin author should avoid this possibility) - if len(s:output) == 0 - throw 'healthcheck_no_return_value' - endif - catch - let s:output = [] " Clear the output - if v:exception =~# 'healthcheck_not_found' - call health#report_error('No healthcheck found for "'.name.'" plugin.') - elseif v:exception =~# 'healthcheck_no_return_value' - call health#report_error('The healthcheck report for "'.name.'" plugin is empty.') - else - call health#report_error(printf( - \ "Failed to run healthcheck for \"%s\" plugin. Exception:\n%s\n%s", - \ name, v:throwpoint, v:exception)) - endif - endtry - let header = [repeat('=', 78), name .. ': ' .. func, ''] - " remove empty line after header from report_start - let s:output = s:output[0] == '' ? s:output[1:] : s:output - let s:output = header + s:output + [''] - call append('$', s:output) - redraw - endfor - endif - - " Clear the 'Running healthchecks...' message. - redraw|echo '' +function! s:deprecate(type) abort + let deprecate = v:lua.vim.deprecate('health#report_' . a:type, 'vim.health.' . a:type, '0.11') + redraw | echo 'Running healthchecks...' + call v:lua.vim.health.warn(deprecate) endfunction -function! s:collect_output(output) - let s:output += split(a:output, "\n", 1) -endfunction - -" Starts a new report. function! health#report_start(name) abort - call s:collect_output(printf("\n%s ~", a:name)) + call v:lua.vim.health.start(a:name) + call s:deprecate('start') endfunction -" Indents lines *except* line 1 of a string if it contains newlines. -function! s:indent_after_line1(s, columns) abort - let lines = split(a:s, "\n", 0) - if len(lines) < 2 " We do not indent line 1, so nothing to do. - return a:s - endif - for i in range(1, len(lines)-1) " Indent lines after the first. - let lines[i] = substitute(lines[i], '^\s*', repeat(' ', a:columns), 'g') - endfor - return join(lines, "\n") +function! health#report_info(msg) abort + call v:lua.vim.health.info(a:msg) + call s:deprecate('info') endfunction -" Changes ':h clipboard' to ':help |clipboard|'. -function! s:help_to_link(s) abort - return substitute(a:s, '\v:h%[elp] ([^|][^"\r\n ]+)', ':help |\1|', 'g') +function! health#report_ok(msg) abort + call v:lua.vim.health.ok(a:msg) + call s:deprecate('ok') endfunction -" Format a message for a specific report item. -" a:1: Optional advice (string or list) -function! s:format_report_message(status, msg, ...) abort " {{{ - let output = '- ' .. a:status .. (empty(a:status) ? '' : ' ') .. s:indent_after_line1(a:msg, 2) - - " Optional parameters - if a:0 > 0 - let advice = type(a:1) == type('') ? [a:1] : a:1 - if type(advice) != type([]) - throw 'a:1: expected String or List' - endif - - " Report each suggestion - if !empty(advice) - let output .= "\n - ADVICE:" - for suggestion in advice - let output .= "\n - " . s:indent_after_line1(suggestion, 6) - endfor - endif - endif - - return s:help_to_link(output) -endfunction " }}} - -" Reports a message as a listitem in the current section. -function! health#report_info(msg) abort " {{{ - call s:collect_output(s:format_report_message('', a:msg)) -endfunction " }}} - -" Reports a successful healthcheck. -function! health#report_ok(msg) abort " {{{ - call s:collect_output(s:format_report_message('OK', a:msg)) -endfunction " }}} - -" Reports a health warning. -" a:1: Optional advice (string or list) -function! health#report_warn(msg, ...) abort " {{{ +function! health#report_warn(msg, ...) abort if a:0 > 0 - call s:collect_output(s:format_report_message('WARNING', a:msg, a:1)) + call v:lua.vim.health.warn(a:msg, a:1) else - call s:collect_output(s:format_report_message('WARNING', a:msg)) + call v:lua.vim.health.warn(a:msg) endif -endfunction " }}} + call s:deprecate('warn') +endfunction -" Reports a failed healthcheck. -" a:1: Optional advice (string or list) -function! health#report_error(msg, ...) abort " {{{ +function! health#report_error(msg, ...) abort if a:0 > 0 - call s:collect_output(s:format_report_message('ERROR', a:msg, a:1)) + call v:lua.vim.health.error(a:msg, a:1) else - call s:collect_output(s:format_report_message('ERROR', a:msg)) + call v:lua.vim.health.error(a:msg) endif -endfunction " }}} - -" From a path return a list [{name}, {func}, {type}] representing a healthcheck -function! s:filepath_to_healthcheck(path) abort - if a:path =~# 'vim$' - let name = matchstr(a:path, '\zs[^\/]*\ze\.vim$') - let func = 'health#'.name.'#check' - let type = 'v' - else - let base_path = substitute(a:path, - \ '.*lua[\/]\(.\{-}\)[\/]health\([\/]init\)\?\.lua$', - \ '\1', '') - let name = substitute(base_path, '[\/]', '.', 'g') - let func = 'require("'.name.'.health").check()' - let type = 'l' - endif - return [name, func, type] -endfunction - -function! s:discover_healthchecks() abort - return s:get_healthcheck('*') -endfunction - -" Returns Dictionary {name: [func, type], ..} representing healthchecks -function! s:get_healthcheck(plugin_names) abort - let health_list = s:get_healthcheck_list(a:plugin_names) - let healthchecks = {} - for c in health_list - let normalized_name = substitute(c[0], '-', '_', 'g') - let existent = get(healthchecks, normalized_name, []) - " Prefer Lua over vim entries - if existent != [] && existent[2] == 'l' - continue - else - let healthchecks[normalized_name] = c - endif - endfor - let output = {} - for v in values(healthchecks) - let output[v[0]] = v[1:] - endfor - try - " vim.health is not a healthcheck, skip it - call remove(output, 'vim') - catch - endtry - return output -endfunction - -" Returns list of lists [ [{name}, {func}, {type}] ] representing healthchecks -function! s:get_healthcheck_list(plugin_names) abort - let healthchecks = [] - let plugin_names = type('') == type(a:plugin_names) - \ ? split(a:plugin_names, ' ', v:false) - \ : a:plugin_names - for p in plugin_names - " support vim/lsp/health{/init/}.lua as :checkhealth vim.lsp - let p = substitute(p, '\.', '/', 'g') - let p = substitute(p, '*$', '**', 'g') " find all submodule e.g vim* - let paths = nvim_get_runtime_file('autoload/health/'.p.'.vim', v:true) - \ + nvim_get_runtime_file('lua/**/'.p.'/health/init.lua', v:true) - \ + nvim_get_runtime_file('lua/**/'.p.'/health.lua', v:true) - if len(paths) == 0 - let healthchecks += [[p, '', '']] " healthcheck not found - else - let healthchecks += map(uniq(sort(paths)), - \'filepath_to_healthcheck(v:val)') - end - endfor - return healthchecks + call s:deprecate('error') endfunction -- cgit From b0978fca6b82a061b345df43745c3ab860e02b58 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sun, 16 Apr 2023 12:26:13 +0200 Subject: fix(checkhealth): fix crash due to incorrect argument type --- runtime/autoload/health.vim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/health.vim b/runtime/autoload/health.vim index 1c414377f6..a7dbedab08 100644 --- a/runtime/autoload/health.vim +++ b/runtime/autoload/health.vim @@ -1,7 +1,9 @@ function! s:deprecate(type) abort let deprecate = v:lua.vim.deprecate('health#report_' . a:type, 'vim.health.' . a:type, '0.11') redraw | echo 'Running healthchecks...' - call v:lua.vim.health.warn(deprecate) + if deprecate isnot v:null + call v:lua.vim.health.warn(deprecate) + endif endfunction function! health#report_start(name) abort -- cgit From e3f36377c156749bbdafc46d8a8cd017f378b4b5 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 23 Apr 2023 15:22:55 +0200 Subject: vim-patch:71badf9547e8 (#23285) Update runtime files https://github.com/vim/vim/commit/71badf9547e8f89571b9a095183671cbb333d528 Co-authored-by: Bram Moolenaar --- runtime/autoload/netrw.vim | 271 ++++++++++++++++++++++++++----------- runtime/autoload/netrwSettings.vim | 8 +- runtime/autoload/zip.vim | 12 +- 3 files changed, 206 insertions(+), 85 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim index 2fcf0b32c7..6c9938d8bb 100644 --- a/runtime/autoload/netrw.vim +++ b/runtime/autoload/netrw.vim @@ -1,7 +1,7 @@ " netrw.vim: Handles file transfer and remote directory listing across " AUTOLOAD SECTION -" Date: Aug 16, 2021 -" Version: 171 +" Date: Mar 15, 2023 +" Version: 172 " Maintainer: Charles E Campbell " GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim " Copyright: Copyright (C) 2016 Charles E. Campbell {{{1 @@ -43,7 +43,7 @@ if exists("s:needspatches") endfor endif -let g:loaded_netrw = "v171" +let g:loaded_netrw = "v172" if !exists("s:NOTE") let s:NOTE = 0 let s:WARNING = 1 @@ -208,7 +208,6 @@ let g:netrw_localcopycmdopt = "" let g:netrw_localcopydircmdopt = "" let g:netrw_localmkdiropt = "" let g:netrw_localmovecmdopt = "" -let g:netrw_localrmdiropt = "" " --------------------------------------------------------------------- " Default values for netrw's global protocol variables {{{2 @@ -1151,6 +1150,11 @@ endfun " --------------------------------------------------------------------- " netrw#Lexplore: toggle Explorer window, keeping it on the left of the current tab {{{2 +" Uses g:netrw_chgwin : specifies the window where Lexplore files are to be opened +" t:netrw_lexposn : winsaveview() output (used on Lexplore window) +" t:netrw_lexbufnr: the buffer number of the Lexplore buffer (internal to this function) +" s:lexplore_win : window number of Lexplore window (serves to indicate which window is a Lexplore window) +" w:lexplore_buf : buffer number of Lexplore window (serves to indicate which window is a Lexplore window) fun! netrw#Lexplore(count,rightside,...) " call Dfunc("netrw#Lexplore(count=".a:count." rightside=".a:rightside.",...) a:0=".a:0." ft=".&ft) let curwin= winnr() @@ -1167,6 +1171,8 @@ fun! netrw#Lexplore(count,rightside,...) " call Decho("exe Explore ".fnameescape(a:1),'~'.expand("")) exe "Explore ".fnameescape(a1) exe curwin."wincmd w" + let s:lexplore_win= curwin + let w:lexplore_buf= bufnr("%") if exists("t:netrw_lexposn") " call Decho("forgetting t:netrw_lexposn",'~'.expand("")) unlet t:netrw_lexposn @@ -1241,7 +1247,7 @@ fun! netrw#Lexplore(count,rightside,...) let t:netrw_lexbufnr = bufnr("%") " done to prevent build-up of hidden buffers due to quitting and re-invocation of :Lexplore. " Since the intended use of :Lexplore is to have an always-present explorer window, the extra - " effort to mis-use :Lex is warranted. + " effort to prevent mis-use of :Lex is warranted. set bh=wipe " call Decho("let t:netrw_lexbufnr=".t:netrw_lexbufnr) " call Decho("t:netrw_lexposn".(exists("t:netrw_lexposn")? string(t:netrw_lexposn) : " n/a")) @@ -1645,7 +1651,7 @@ fun! s:NetrwOptionsSave(vt) endif let {a:vt}netrw_fokeep = &l:fo " formatoptions let {a:vt}netrw_gdkeep = &l:gd " gdefault - let {a:vt}netrw_gokeep = &l:go " guioptions + let {a:vt}netrw_gokeep = &go " guioptions let {a:vt}netrw_hidkeep = &l:hidden let {a:vt}netrw_imkeep = &l:im let {a:vt}netrw_iskkeep = &l:isk @@ -1711,8 +1717,9 @@ fun! s:NetrwOptionsSafe(islocal) if &cpo =~ 'a' | call s:NetrwSetSafeSetting("&cpo",substitute(&cpo,'a','','g')) | endif if &cpo =~ 'A' | call s:NetrwSetSafeSetting("&cpo",substitute(&cpo,'A','','g')) | endif setl fo=nroql2 - " call s:NetrwSetSafeSetting("&go","begmr") - if &go =~ '\ca' | call s:NetrwSetSafeSetting("&go",substitute(&go,'\ca','','g')) | endif + if &go =~ 'a' | set go-=a | endif + if &go =~ 'A' | set go-=A | endif + if &go =~ 'P' | set go-=P | endif call s:NetrwSetSafeSetting("&l:hid",0) call s:NetrwSetSafeSetting("&l:im",0) setl isk+=@ isk+=* isk+=/ @@ -1751,11 +1758,13 @@ fun! s:NetrwOptionsRestore(vt) " call Decho("settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo." a:vt=".a:vt,'~'.expand("")) if !exists("{a:vt}netrw_optionsave") " call Decho("case ".a:vt."netrw_optionsave : doesn't exist",'~'.expand("")) - if !isdirectory(expand('%')) + if filereadable(expand("%")) " call Decho("..doing filetype detect anyway") - filetype detect + filetype detect +" call Decho("..settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo." a:vt=".a:vt,'~'.expand("")) + else + setl ft=netrw endif -" call Decho("..settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo." a:vt=".a:vt,'~'.expand("")) " call Decho("..ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("")) " call Dret("s:NetrwOptionsRestore : ".a:vt."netrw_optionsave doesn't exist") return @@ -1795,7 +1804,7 @@ fun! s:NetrwOptionsRestore(vt) " call Decho("(s:NetrwOptionsRestore) #4 lines=".&lines) call s:NetrwRestoreSetting(a:vt."netrw_fokeep" ,"&l:fo") call s:NetrwRestoreSetting(a:vt."netrw_gdkeep" ,"&l:gd") - call s:NetrwRestoreSetting(a:vt."netrw_gokeep" ,"&l:go") + call s:NetrwRestoreSetting(a:vt."netrw_gokeep" ,"&go") call s:NetrwRestoreSetting(a:vt."netrw_hidkeep" ,"&l:hidden") " call Decho("(s:NetrwOptionsRestore) #5 lines=".&lines) call s:NetrwRestoreSetting(a:vt."netrw_imkeep" ,"&l:im") @@ -1861,11 +1870,9 @@ fun! s:NetrwOptionsRestore(vt) " were having their filetype detect-generated settings overwritten by " NetrwOptionRestore. if &ft != "netrw" - if !isdirectory(expand('%')) -" call Decho("before: filetype detect (ft=".&ft.")",'~'.expand("")) - filetype detect -" call Decho("after : filetype detect (ft=".&ft.")",'~'.expand("")) - endif +" call Decho("before: filetype detect (ft=".&ft.")",'~'.expand("")) + filetype detect +" call Decho("after : filetype detect (ft=".&ft.")",'~'.expand("")) endif " call Decho("(s:NetrwOptionsRestore) lines=".&lines) " call Decho("settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo." a:vt=".a:vt,'~'.expand("")) @@ -2940,13 +2947,19 @@ fun! s:NetrwGetFile(readcmd, tfile, method) " rename buffer back to remote filename call s:NetrwBufRename(rfile) + " Jan 19, 2022: COMBAK -- bram problem with https://github.com/vim/vim/pull/9554.diff filetype " Detect filetype of local version of remote file. " Note that isk must not include a "/" for scripts.vim " to process this detection correctly. -" call Decho("detect filetype of local version of remote file",'~'.expand("")) - let iskkeep= &l:isk +" call Decho("detect filetype of local version of remote file<".rfile.">",'~'.expand("")) +" call Decho("..did_filetype()=".did_filetype()) + setl ft= +" call Decho("..initial filetype<".&ft."> for buf#".bufnr()."<".bufname().">") + let iskkeep= &isk setl isk-=/ - let &l:isk= iskkeep + filetype detect +" call Decho("..local filetype<".&ft."> for buf#".bufnr()."<".bufname().">") + let &isk= iskkeep " call Dredir("ls!","NetrwGetFile (renamed buffer back to remote filename<".rfile."> : expand(%)<".expand("%").">)") let line1 = 1 let line2 = line("$") @@ -4227,7 +4240,7 @@ fun! s:NetrwGetBuffer(islocal,dirname) endif " call Decho(" bufnum#".bufnum,'~'.expand("")) - " hijack the current buffer + " highjack the current buffer " IF the buffer already has the desired name " AND it is empty let curbuf = bufname("%") @@ -4235,7 +4248,7 @@ fun! s:NetrwGetBuffer(islocal,dirname) let curbuf = getcwd() endif " call Dredir("ls!","NetrwGetFile (renamed buffer back to remote filename<".rfile."> : expand(%)<".expand("%").">)") -" call Decho("deciding if netrw may hijack the current buffer#".bufnr("%")."<".curbuf.">",'~'.expand("")) +" call Decho("deciding if netrw may highjack the current buffer#".bufnr("%")."<".curbuf.">",'~'.expand("")) " call Decho("..dirname<".dirname."> IF dirname == bufname",'~'.expand("")) " call Decho("..curbuf<".curbuf.">",'~'.expand("")) " call Decho("..line($)=".line("$")." AND this is 1",'~'.expand("")) @@ -4244,7 +4257,7 @@ fun! s:NetrwGetBuffer(islocal,dirname) " call Dret("s:NetrwGetBuffer 0 : highjacking buffer#".bufnr("%")) return 0 else " DEBUG -" call Decho("..did NOT hijack buffer",'~'.expand("")) +" call Decho("..did NOT highjack buffer",'~'.expand("")) endif " Aug 14, 2021: was thinking about looking for a [No Name] buffer here and using it, but that might cause problems @@ -4280,19 +4293,25 @@ fun! s:NetrwGetBuffer(islocal,dirname) else " Re-use the buffer " call Decho("--re-use buffer#".bufnum." (bufnum#".bufnum.">=0 AND bufexists(".bufnum.")=".bufexists(bufnum)."!=0)",'~'.expand("")) + " ignore all events let eikeep= &ei setl ei=all - if getline(2) =~# '^" Netrw Directory Listing' -" call Decho(" getline(2)<".getline(2).'> matches "Netrw Directory Listing" : using keepalt b '.bufnum,'~'.expand("")) - exe "sil! NetrwKeepj noswapfile keepalt b ".bufnum + + if &ft == "netrw" +" call Decho("buffer type is netrw; not using keepalt with b ".bufnum) + exe "sil! NetrwKeepj noswapfile b ".bufnum +" call Dredir("ls!","one") else -" call Decho(" getline(2)<".getline(2).'> does not match "Netrw Directory Listing" : using b '.bufnum,'~'.expand("")) - exe "sil! NetrwKeepj noswapfile keepalt b ".bufnum +" call Decho("buffer type is not netrw; using keepalt with b ".bufnum) + call s:NetrwEditBuf(bufnum) +" call Dredir("ls!","two") endif " call Decho(" line($)=".line("$"),'~'.expand("")) if bufname("%") == '.' call s:NetrwBufRename(getcwd()) endif + + " restore ei let &ei= eikeep if line("$") <= 1 && getline(1) == "" @@ -4943,7 +4962,7 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...) " the point where netrw actually edits the (local) file " if its local only: LocalBrowseCheck() doesn't edit a file, but NetrwBrowse() will - " no keepalt to support :e # to return to a directory listing + " use keepalt to support :e # to return to a directory listing if !&mod " if e the new file would fail due to &mod, then don't change any of the flags let dolockout= 1 @@ -4954,12 +4973,8 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...) " others like c-^ to return to the netrw buffer " Apr 30, 2020: used to have e! here. That can cause loss of a modified file, " so emit error E37 instead. - if exists("g:netrw_altfile") && g:netrw_altfile - exe "NetrwKeepj keepalt e ".fnameescape(dirname) - else - exe "NetrwKeepj e ".fnameescape(dirname) - endif -" call Decho("edit-a-file: after e! ".dirname.": hidden=".&hidden." bufhidden<".&bufhidden."> mod=".&mod,'~'.expand("")) + call s:NetrwEditFile("e","",dirname) +" call Decho("edit-a-file: after e ".dirname.": hidden=".&hidden." bufhidden<".&bufhidden."> mod=".&mod,'~'.expand("")) " COMBAK -- cuc cul related call s:NetrwCursor(1) if &hidden || &bufhidden == "hide" @@ -5300,8 +5315,8 @@ fun! netrw#BrowseX(fname,remote) " g:Netrw_corehandler is a List of function references (see :help Funcref) " call Decho("g:Netrw_corehandler is a List",'~'.expand("")) for Fncref in g:Netrw_corehandler - if type(FncRef) == 2 - call FncRef(a:fname) + if type(Fncref) == 2 + call Fncref(a:fname) endif endfor endif @@ -5374,6 +5389,8 @@ fun! netrw#BrowseX(fname,remote) else let redir= &srr . "/dev/null" endif + else + let redir= "" endif " call Decho("set up redirection: redir{".redir."} srr{".&srr."}",'~'.expand("")) @@ -5668,6 +5685,35 @@ fun! s:NetrwClearExplore() " call Dret("s:NetrwClearExplore") endfun +" --------------------------------------------------------------------- +" s:NetrwEditBuf: decides whether or not to use keepalt to edit a buffer {{{2 +fun! s:NetrwEditBuf(bufnum) +" call Dfunc("s:NetrwEditBuf(fname<".a:bufnum.">)") + if exists("g:netrw_altfile") && g:netrw_altfile && &ft == "netrw" +" call Decho("exe sil! NetrwKeepj keepalt noswapfile b ".fnameescape(a:bufnum)) + exe "sil! NetrwKeepj keepalt noswapfile b ".fnameescape(a:bufnum) + else +" call Decho("exe sil! NetrwKeepj noswapfile b ".fnameescape(a:bufnum)) + exe "sil! NetrwKeepj noswapfile b ".fnameescape(a:bufnume) + endif +" call Dret("s:NetrwEditBuf") +endfun + +" --------------------------------------------------------------------- +" s:NetrwEditFile: decides whether or not to use keepalt to edit a file {{{2 +" NetrwKeepj [keepalt] +fun! s:NetrwEditFile(cmd,opt,fname) +" call Dfunc("s:NetrwEditFile(cmd<".a:cmd.">,opt<".a:opt.">,fname<".a:fname.">) ft<".&ft.">") + if exists("g:netrw_altfile") && g:netrw_altfile && &ft == "netrw" +" call Decho("exe NetrwKeepj keepalt ".a:opt." ".a:cmd." ".fnameescape(a:fname)) + exe "NetrwKeepj keepalt ".a:opt." ".a:cmd." ".fnameescape(a:fname) + else +" call Decho("exe NetrwKeepj ".a:opt." ".a:cmd." ".fnameescape(a:fname)) + exe "NetrwKeepj ".a:opt." ".a:cmd." ".fnameescape(a:fname) + endif +" call Dret("s:NetrwEditFile") +endfun + " --------------------------------------------------------------------- " s:NetrwExploreListUniq: {{{2 fun! s:NetrwExploreListUniq(explist) @@ -7756,8 +7802,16 @@ fun! s:NetrwMarkFileMove(islocal) " call Decho("movecmd<".movecmd."> (#3 linux or cygwin)",'~'.expand("")) endif for fname in s:netrwmarkfilelist_{bufnr("%")} + if g:netrw_keepdir + " Jul 19, 2022: fixing file move when g:netrw_keepdir is 1 + let fname= b:netrw_curdir."/".fname + endif if !g:netrw_cygwin && (has("win32") || has("win95") || has("win64") || has("win16")) let fname= substitute(fname,'/','\\','g') + if g:netrw_keepdir + " Jul 19, 2022: fixing file move when g:netrw_keepdir is 1 + let fname= b:netrw_curdir."\\".fname + endif endif " call Decho("system(".movecmd." ".s:ShellEscape(fname)." ".tgt.")",'~'.expand("")) let ret= system(movecmd.g:netrw_localmovecmdopt." ".s:ShellEscape(fname)." ".tgt) @@ -8475,21 +8529,28 @@ endfun " choice = 2 : didn't save modified file, opened window " choice = 3 : cancel open fun! s:NetrwPrevWinOpen(islocal) -" call Dfunc("s:NetrwPrevWinOpen(islocal=".a:islocal.")") +" call Dfunc("s:NetrwPrevWinOpen(islocal=".a:islocal.") win#".winnr()) let ykeep= @@ " grab a copy of the b:netrw_curdir to pass it along to newly split windows let curdir = b:netrw_curdir +" call Decho("COMBAK#1: mod=".&mod." win#".winnr()) " get last window number and the word currently under the cursor let origwin = winnr() let lastwinnr = winnr("$") - let curword = s:NetrwGetWord() - let choice = 0 - let s:prevwinopen= 1 " lets s:NetrwTreeDir() know that NetrwPrevWinOpen called it +" call Decho("origwin#".origwin." lastwinnr#".lastwinnr) +" call Decho("COMBAK#2: mod=".&mod." win#".winnr()) + let curword = s:NetrwGetWord() + let choice = 0 + let s:prevwinopen= 1 " lets s:NetrwTreeDir() know that NetrwPrevWinOpen called it (s:NetrwTreeDir() will unlet s:prevwinopen) +" call Decho("COMBAK#3: mod=".&mod." win#".winnr()) let s:treedir = s:NetrwTreeDir(a:islocal) +" call Decho("COMBAK#4: mod=".&mod." win#".winnr()) let curdir = s:treedir +" call Decho("COMBAK#5: mod=".&mod." win#".winnr()) " call Decho("winnr($)#".lastwinnr." curword<".curword.">",'~'.expand("")) +" call Decho("COMBAK#6: mod=".&mod." win#".winnr()) let didsplit = 0 if lastwinnr == 1 @@ -8512,11 +8573,26 @@ fun! s:NetrwPrevWinOpen(islocal) " call Decho("did split",'~'.expand("")) else +" call Decho("COMBAK#7: mod=".&mod." win#".winnr()) NetrwKeepj call s:SaveBufVars() +" call Decho("COMBAK#8: mod=".&mod." win#".winnr()) let eikeep= &ei +" call Decho("COMBAK#9: mod=".&mod." win#".winnr()) setl ei=all +" call Decho("COMBAK#10: mod=".&mod." win#".winnr()) wincmd p +" call Decho("COMBAK#11: mod=".&mod) " call Decho("wincmd p (now in win#".winnr().") curdir<".curdir.">",'~'.expand("")) +" call Decho("COMBAK#12: mod=".&mod) + + if exists("s:lexplore_win") && s:lexplore_win == winnr() + " whoops -- user trying to open file in the Lexplore window. + " Use Lexplore's opening-file window instead. +" call Decho("whoops -- user trying to open file in Lexplore Window. Use win#".g:netrw_chgwin." instead") +" exe g:netrw_chgwin."wincmd w" + wincmd p + call s:NetrwBrowse(0,s:NetrwBrowseChgDir(0,s:NetrwGetWord())) + endif " prevwinnr: the window number of the "prev" window " prevbufnr: the buffer number of the buffer in the "prev" window @@ -8526,8 +8602,10 @@ fun! s:NetrwPrevWinOpen(islocal) let prevbufname = bufname("%") let prevmod = &mod let bnrcnt = 0 +" call Decho("COMBAK#13: mod=".&mod." win#".winnr()) NetrwKeepj call s:RestoreBufVars() " call Decho("after wincmd p: win#".winnr()." win($)#".winnr("$")." origwin#".origwin." &mod=".&mod." bufname(%)<".bufname("%")."> prevbufnr=".prevbufnr,'~'.expand("")) +" call Decho("COMBAK#14: mod=".&mod." win#".winnr()) " if the previous window's buffer has been changed (ie. its modified flag is set), " and it doesn't appear in any other extant window, then ask the @@ -8537,6 +8615,7 @@ fun! s:NetrwPrevWinOpen(islocal) windo if winbufnr(0) == prevbufnr | let bnrcnt=bnrcnt+1 | endif " call Decho("prevbufnr=".prevbufnr." bnrcnt=".bnrcnt." buftype=".&bt." winnr()=".winnr()." prevwinnr#".prevwinnr,'~'.expand("")) exe prevwinnr."wincmd w" +" call Decho("COMBAK#15: mod=".&mod." win#".winnr()) if bnrcnt == 1 && &hidden == 0 " only one copy of the modified buffer in a window, and @@ -8544,6 +8623,7 @@ fun! s:NetrwPrevWinOpen(islocal) let choice = confirm("Save modified buffer<".prevbufname."> first?","&Yes\n&No\n&Cancel") " call Decho("prevbufname<".prevbufname."> choice=".choice." current-winnr#".winnr(),'~'.expand("")) let &ei= eikeep +" call Decho("COMBAK#16: mod=".&mod." win#".winnr()) if choice == 1 " Yes -- write file & then browse @@ -8576,6 +8656,7 @@ fun! s:NetrwPrevWinOpen(islocal) endif let &ei= eikeep endif +" call Decho("COMBAK#17: mod=".&mod." win#".winnr()) " restore b:netrw_curdir (window split/enew may have lost it) let b:netrw_curdir= curdir @@ -9263,19 +9344,23 @@ fun! s:NetrwTreeDir(islocal) if exists("s:prevwinopen") unlet s:prevwinopen endif +" call Decho("COMBAK#18 : mod=".&mod." win#".winnr()) if !exists("b:netrw_curdir") || b:netrw_curdir == "" let b:netrw_curdir= getcwd() endif let treedir = b:netrw_curdir " call Decho("set initial treedir<".treedir.">",'~'.expand("")) +" call Decho("COMBAK#19 : mod=".&mod." win#".winnr()) let s:treecurpos= winsaveview() " call Decho("saving posn to s:treecurpos<".string(s:treecurpos).">",'~'.expand("")) +" call Decho("COMBAK#20 : mod=".&mod." win#".winnr()) if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST " call Decho("w:netrw_liststyle is TREELIST:",'~'.expand("")) " call Decho("line#".line(".")." getline(.)<".getline('.')."> treecurpos<".string(s:treecurpos).">",'~'.expand("")) +" call Decho("COMBAK#21 : mod=".&mod." win#".winnr()) " extract tree directory if on a line specifying a subdirectory (ie. ends with "/") let curline= substitute(getline('.'),"\t -->.*$",'','') @@ -9291,6 +9376,7 @@ fun! s:NetrwTreeDir(islocal) " call Decho("do not extract tree subdirectory from current line and set treedir to empty",'~'.expand("")) let treedir= "" endif +" call Decho("COMBAK#22 : mod=".&mod." win#".winnr()) " detect user attempting to close treeroot " call Decho("check if user is attempting to close treeroot",'~'.expand("")) @@ -9306,10 +9392,12 @@ fun! s:NetrwTreeDir(islocal) " else " Decho " call Decho(".user not attempting to close treeroot",'~'.expand("")) endif +" call Decho("COMBAK#23 : mod=".&mod." win#".winnr()) " call Decho("islocal=".a:islocal." curline<".curline.">",'~'.expand("")) let potentialdir= s:NetrwFile(substitute(curline,'^'.s:treedepthstring.'\+ \(.*\)@$','\1','')) " call Decho("potentialdir<".potentialdir."> isdir=".isdirectory(potentialdir),'~'.expand("")) +" call Decho("COMBAK#24 : mod=".&mod." win#".winnr()) " COMBAK: a symbolic link may point anywhere -- so it will be used to start a new treetop " if a:islocal && curline =~ '@$' && isdirectory(s:NetrwFile(potentialdir)) @@ -9323,10 +9411,12 @@ fun! s:NetrwTreeDir(islocal) let treedir = s:NetrwTreePath(w:netrw_treetop) " endif endif +" call Decho("COMBAK#25 : mod=".&mod." win#".winnr()) " sanity maintenance: keep those //s away... let treedir= substitute(treedir,'//$','/','') " call Decho("treedir<".treedir.">",'~'.expand("")) +" call Decho("COMBAK#26 : mod=".&mod." win#".winnr()) " call Dret("s:NetrwTreeDir <".treedir."> : (side effect) s:treecurpos<".(exists("s:treecurpos")? string(s:treecurpos) : 'n/a').">") return treedir @@ -10687,7 +10777,8 @@ fun! netrw#LocalBrowseCheck(dirname) " call Dfunc("netrw#LocalBrowseCheck(dirname<".a:dirname.">)") " call Decho("isdir<".a:dirname."> =".isdirectory(s:NetrwFile(a:dirname)).((exists("s:treeforceredraw")? " treeforceredraw" : "")).'~'.expand("")) " call Decho("settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo,'~'.expand("")) -" call Dredir("ls!","netrw#LocalBrowseCheck") + " getting E930: Cannot use :redir inside execute +"" call Dredir("ls!","netrw#LocalBrowseCheck") " call Decho("tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> line#".line(".")." col#".col(".")." winline#".winline()." wincol#".wincol(),'~'.expand("")) " call Decho("current buffer#".bufnr("%")."<".bufname("%")."> ft=".&ft,'~'.expand("")) @@ -10981,12 +11072,15 @@ fun! s:LocalListing() if w:netrw_liststyle == s:LONGLIST let sz = getfsize(filename) - let fsz = strpart(" ",1,15-strlen(sz)).sz + let szlen = 15 - (strdisplaywidth(longfile) - g:netrw_maxfilenamelen) + let szlen = (szlen > 0) ? szlen : 0 + let fsz = printf("%".szlen."S",sz) + if g:netrw_sizestyle =~# "[hH]" let sz= s:NetrwHumanReadable(sz) endif - let longfile= printf("%-".(g:netrw_maxfilenamelen+1)."s",pfile) - let pfile = longfile.sz." ".strftime(g:netrw_timefmt,getftime(filename)) + let longfile= printf("%-".g:netrw_maxfilenamelen."S",pfile) + let pfile = longfile." ".sz." ".strftime(g:netrw_timefmt,getftime(filename)) " call Decho("longlist support: sz=".sz." fsz=".fsz,'~'.expand("")) endif @@ -11285,34 +11379,8 @@ fun! s:NetrwLocalRmFile(path,fname,all) let rmfile= substitute(rmfile,'[\/]$','','e') if all || ok =~# 'y\%[es]' || ok == "" - if v:version < 704 || (v:version == 704 && !has("patch1107")) -" " call Decho("1st attempt: system(netrw#WinPath(".g:netrw_localrmdir.') '.s:ShellEscape(rmfile).')','~'.expand("")) - call system(netrw#WinPath(g:netrw_localrmdir).' '.s:ShellEscape(rmfile)) -" " call Decho("v:shell_error=".v:shell_error,'~'.expand("")) - - if v:shell_error != 0 -" " call Decho("2nd attempt to remove directory<".rmfile.">",'~'.expand("")) - let errcode= s:NetrwDelete(rmfile) -" " call Decho("errcode=".errcode,'~'.expand("")) - - if errcode != 0 - if has("unix") -" " call Decho("3rd attempt to remove directory<".rmfile.">",'~'.expand("")) - call system("rm ".s:ShellEscape(rmfile)) - if v:shell_error != 0 && !exists("g:netrw_quiet") - call netrw#ErrorMsg(s:ERROR,"unable to remove directory<".rmfile."> -- is it empty?",34) - let ok="no" - endif - elseif !exists("g:netrw_quiet") - call netrw#ErrorMsg(s:ERROR,"unable to remove directory<".rmfile."> -- is it empty?",35) - let ok="no" - endif - endif - endif - else - if delete(rmfile,"d") - call netrw#ErrorMsg(s:ERROR,"unable to delete directory <".rmfile.">!",103) - endif + if delete(rmfile,"d") + call netrw#ErrorMsg(s:ERROR,"unable to delete directory <".rmfile.">!",103) endif endif endif @@ -11907,13 +11975,13 @@ fun! s:NetrwEnew(...) if exists("b:netrw_prvdir") |let netrw_prvdir = b:netrw_prvdir |endif NetrwKeepj call s:NetrwOptionsRestore("w:") -" call Decho("generate a buffer with NetrwKeepj keepalt enew!",'~'.expand("")) +" call Decho("generate a buffer with NetrwKeepj enew!",'~'.expand("")) " when tree listing uses file TreeListing... a new buffer is made. " Want the old buffer to be unlisted. " COMBAK: this causes a problem, see P43 " setl nobl let netrw_keepdiff= &l:diff - noswapfile NetrwKeepj keepalt enew! + call s:NetrwEditFile("enew!","","") let &l:diff= netrw_keepdiff " call Decho("bufnr($)=".bufnr("$")."<".bufname(bufnr("$"))."> winnr($)=".winnr("$"),'~'.expand("")) NetrwKeepj call s:NetrwOptionsSave("w:") @@ -11962,7 +12030,7 @@ endfun " s:NetrwExe: executes a string using "!" {{{2 fun! s:NetrwExe(cmd) " call Dfunc("s:NetrwExe(a:cmd<".a:cmd.">)") - if has("win32") && &shell !~? 'cmd' && !g:netrw_cygwin + if has("win32") && &shell !~? 'cmd\|pwsh\|powershell' && !g:netrw_cygwin " call Decho("using win32:",expand("")) let savedShell=[&shell,&shellcmdflag,&shellxquote,&shellxescape,&shellquote,&shellpipe,&shellredir,&shellslash] set shell& shellcmdflag& shellxquote& shellxescape& @@ -12631,3 +12699,54 @@ unlet s:keepcpo " Modelines: {{{1 " =============== " vim:ts=8 fdm=marker +" doing autoload/netrw.vim version v172g ~57 +" varname value=0 ~1 +" varname value=0 ~1 +" varname value=1 ~1 +" varname value=2 ~1 +" varname value=3 ~1 +" varname value=4 ~1 +" varname value=2 ~1 +" varname value=-q -O ~1 +" varname value=curl -T ~1 +" varname value=keepj ~1 +" varname value=rcp ~1 +" varname value=rsync ~1 +" varname value=/ ~1 +" varname value=scp -q ~1 +" varname value=sftp ~1 +" varname value=ssh ~1 +" varname value=0 ~1 +" varname value=1 ~1 +" varname value=1 ~1 +" varname value=0 ~1 +" varname value=noma nomod nonu nobl nowrap ro nornu ~1 +" varname value=-1 ~1 +" varname value=1 ~1 +" varname value=gzip ~1 +" varname value=ctags ~1 +" varname value=2 ~1 +" (netrw) COMBAK: cuc=0 cul=0 initialization of s:netrw_cu[cl] +" varname value=/cygdrive ~1 +" varname value=0 ~1 +" varname value=0 ~1 +" varname value={ ".gz" : "gunzip", ".bz2" : "bunzip2", ".zip" : "unzip", ".tar" : "tar -xf", ".xz" : "unxz" } ~1 +" varname value=10 ~1 +" varname value=0 ~1 +" varname value=1 ~1 +" varname value=^total\s\+\d\+$\|^Trying\s\+\d\+.*$\|^KERBEROS_V\d rejected\|^Security extensions not\|No such file\|: connect to address [0-9a-fA-F:]*: No route to host$ ~1 +" varname value=binary ~1 +" varname value=1 ~1 +" varname value=1 ~1 +" varname value= ~1 +" varname value=mkdir ~1 +" varname value=mkdir ~1 +" varname value=0 ~1 +" varname value=*./[\~ ~1 +" varname value=32 ~1 +" varname value=1 ~1 +" varname value=ssh USEPORT HOSTNAME mkdir ~1 +" varname value=1 ~1 +" varname value=0 ~1 +" varname value=chmod PERM FILENAME ~1 +" varname value=0 ~1 diff --git a/runtime/autoload/netrwSettings.vim b/runtime/autoload/netrwSettings.vim index 61c0ef739e..a910d18be8 100644 --- a/runtime/autoload/netrwSettings.vim +++ b/runtime/autoload/netrwSettings.vim @@ -1,7 +1,7 @@ " netrwSettings.vim: makes netrw settings simpler -" Date: Aug 12, 2021 +" Date: Nov 15, 2021 " Maintainer: Charles E Campbell -" Version: 17 ASTRO-ONLY +" Version: 18 " Copyright: Copyright (C) 1999-2007 Charles E. Campbell {{{1 " Permission is hereby granted to use and distribute this code, " with or without modifications, provided that this copyright @@ -19,7 +19,7 @@ if exists("g:loaded_netrwSettings") || &cp finish endif -let g:loaded_netrwSettings = "v17" +let g:loaded_netrwSettings = "v18a" if v:version < 700 echohl WarningMsg echo "***warning*** this version of netrwSettings needs vim 7.0" @@ -159,8 +159,6 @@ fun! netrwSettings#NetrwSettings() put = 'let g:netrw_localmkdiropt = '.g:netrw_localmkdiropt put = 'let g:netrw_localmovecmd = '.g:netrw_localmovecmd put = 'let g:netrw_localmovecmdopt = '.g:netrw_localmovecmdopt - put = 'let g:netrw_localrmdir = '.g:netrw_localrmdir - put = 'let g:netrw_localrmdiropt = '.g:netrw_localrmdiropt put = 'let g:netrw_maxfilenamelen = '.g:netrw_maxfilenamelen put = 'let g:netrw_menu = '.g:netrw_menu put = 'let g:netrw_mousemaps = '.g:netrw_mousemaps diff --git a/runtime/autoload/zip.vim b/runtime/autoload/zip.vim index bc9b62ddb0..8dda30c418 100644 --- a/runtime/autoload/zip.vim +++ b/runtime/autoload/zip.vim @@ -1,7 +1,7 @@ " zip.vim: Handles browsing zipfiles " AUTOLOAD PORTION -" Date: Nov 08, 2021 -" Version: 32 +" Date: Mar 12, 2023 +" Version: 33 " Maintainer: Charles E Campbell " License: Vim License (see vim's :help license) " Copyright: Copyright (C) 2005-2019 Charles E. Campbell {{{1 @@ -20,7 +20,7 @@ if &cp || exists("g:loaded_zip") finish endif -let g:loaded_zip= "v32" +let g:loaded_zip= "v33" if v:version < 702 echohl WarningMsg echo "***warning*** this version of zip needs vim 7.2 or later" @@ -160,10 +160,14 @@ endfun " --------------------------------------------------------------------- " ZipBrowseSelect: {{{2 fun! s:ZipBrowseSelect() -" call Dfunc("ZipBrowseSelect() zipfile<".b:zipfile."> curfile<".expand("%").">") + " call Dfunc("ZipBrowseSelect() zipfile<".((exists("b:zipfile"))? b:zipfile : "n/a")."> curfile<".expand("%").">") let repkeep= &report set report=10 let fname= getline(".") + if !exists("b:zipfile") +" call Dret("ZipBrowseSelect : b:zipfile doesn't exist!") + return + endif " sanity check if fname =~ '^"' -- cgit From c11986ed1a816d7ebcb5a5f707e3ef884f278293 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Mon, 15 May 2023 09:38:32 +0200 Subject: vim-patch:b7398fe41c9e (#23627) Update runtime files https://github.com/vim/vim/commit/b7398fe41c9e1e731d058105a34158871ee83e3f Co-authored-by: Bram Moolenaar --- runtime/autoload/netrw.vim | 8 ++++---- runtime/autoload/netrwSettings.vim | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim index 6c9938d8bb..c9f66f7927 100644 --- a/runtime/autoload/netrw.vim +++ b/runtime/autoload/netrw.vim @@ -1,7 +1,7 @@ " netrw.vim: Handles file transfer and remote directory listing across " AUTOLOAD SECTION -" Date: Mar 15, 2023 -" Version: 172 +" Date: May 03, 2023 +" Version: 173 " Maintainer: Charles E Campbell " GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim " Copyright: Copyright (C) 2016 Charles E. Campbell {{{1 @@ -43,7 +43,7 @@ if exists("s:needspatches") endfor endif -let g:loaded_netrw = "v172" +let g:loaded_netrw = "v173" if !exists("s:NOTE") let s:NOTE = 0 let s:WARNING = 1 @@ -5694,7 +5694,7 @@ fun! s:NetrwEditBuf(bufnum) exe "sil! NetrwKeepj keepalt noswapfile b ".fnameescape(a:bufnum) else " call Decho("exe sil! NetrwKeepj noswapfile b ".fnameescape(a:bufnum)) - exe "sil! NetrwKeepj noswapfile b ".fnameescape(a:bufnume) + exe "sil! NetrwKeepj noswapfile b ".fnameescape(a:bufnum) endif " call Dret("s:NetrwEditBuf") endfun diff --git a/runtime/autoload/netrwSettings.vim b/runtime/autoload/netrwSettings.vim index a910d18be8..d65f83144e 100644 --- a/runtime/autoload/netrwSettings.vim +++ b/runtime/autoload/netrwSettings.vim @@ -19,7 +19,7 @@ if exists("g:loaded_netrwSettings") || &cp finish endif -let g:loaded_netrwSettings = "v18a" +let g:loaded_netrwSettings = "v18" if v:version < 700 echohl WarningMsg echo "***warning*** this version of netrwSettings needs vim 7.0" -- cgit From 2f17ef1fc4b96cf1106fd95ba090d34a2e4b977b Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 22 Jun 2023 04:09:14 -0700 Subject: fix(messages): use "Vimscript" instead of "VimL" #24111 followup to #24109 fix #16150 --- runtime/autoload/msgpack.vim | 8 ++++---- runtime/autoload/shada.vim | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/msgpack.vim b/runtime/autoload/msgpack.vim index 7f98a5b230..18dcd1e6a6 100644 --- a/runtime/autoload/msgpack.vim +++ b/runtime/autoload/msgpack.vim @@ -101,8 +101,8 @@ function s:msgpack_init_python() abort " @return Formatted timestamp. " " @warning Without +python or +python3 this function does not work correctly. - " The VimL code contains “reference” implementation which does not - " really work because of precision loss. + " The Vimscript code contains “reference” implementation which does + " not really work because of precision loss. function s:msgpack_dict_strftime(format, timestamp) return msgpack#strftime(a:format, +msgpack#int_dict_to_str(a:timestamp)) endfunction @@ -541,8 +541,8 @@ let s:MSGPACK_SPECIAL_OBJECTS = { \} "" -" Convert msgpack object dumped by msgpack#string() to a VimL object suitable -" for msgpackdump(). +" Convert msgpack object dumped by msgpack#string() to a Vimscript object +" suitable for msgpackdump(). " " @param[in] s String to evaluate. " @param[in] special_objs Additional special objects, in the same format as diff --git a/runtime/autoload/shada.vim b/runtime/autoload/shada.vim index 87acc515ee..ae718ad2e7 100644 --- a/runtime/autoload/shada.vim +++ b/runtime/autoload/shada.vim @@ -487,7 +487,7 @@ let s:SHADA_ENTRY_OBJECT_SEQUENCE = ['type', 'timestamp', 'length', 'data'] "" " Convert list returned by msgpackparse() to a list of ShaDa objects " -" @param[in] mpack List of VimL objects returned by msgpackparse(). +" @param[in] mpack List of Vimscript objects returned by msgpackparse(). " " @return List of dictionaries with keys type, timestamp, length and data. Each " dictionary describes one ShaDa entry. -- cgit From 8758c6fb875ff5446c0dff2166e9c3392c2c31d6 Mon Sep 17 00:00:00 2001 From: Frede Date: Thu, 29 Jun 2023 23:14:14 +0200 Subject: feat(defaults): set g:netrw_use_errorwindow = 0 #24179 Problem: netrw uses a bespoke window to show messages. Solution: change the default so that netrw uses normal vim :echoerr --- runtime/autoload/netrw.vim | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim index c9f66f7927..be170d8aec 100644 --- a/runtime/autoload/netrw.vim +++ b/runtime/autoload/netrw.vim @@ -211,10 +211,8 @@ let g:netrw_localmovecmdopt = "" " --------------------------------------------------------------------- " Default values for netrw's global protocol variables {{{2 -if (v:version > 802 || (v:version == 802 && has("patch486"))) && has("balloon_eval") && !exists("s:initbeval") && !exists("g:netrw_nobeval") && has("syntax") && exists("g:syntax_on") && has("mouse") - call s:NetrwInit("g:netrw_use_errorwindow",2) -else - call s:NetrwInit("g:netrw_use_errorwindow",1) +if !exists("g:netrw_use_errorwindow") + let g:netrw_use_errorwindow = 0 endif if !exists("g:netrw_dav_cmd") -- cgit From c3de6524a53dc355b1c8074eb6940e9e73714057 Mon Sep 17 00:00:00 2001 From: Kai Ting Date: Sun, 16 Jul 2023 04:15:30 -0700 Subject: fix(clipboard): ignore exit caused by signal #23378 Problem: If clipboard job exits by signal, the exit code is >=128: https://github.com/neovim/neovim/commit/939d9053bdf2f56286640c581eb4e2ff5a856540 xclip 0.13 often exits with code 143, which spams unhelpful messages: clipboard: error invoking xclip: Waiting for selection requests, Control-C to quit Waiting for selection request number 1 Solution: Don't show a warning if the clipboard tool exit code is >=128. Fixes: #7054 --- runtime/autoload/provider/clipboard.vim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim index 6d238ddb55..6ba28dcbfc 100644 --- a/runtime/autoload/provider/clipboard.vim +++ b/runtime/autoload/provider/clipboard.vim @@ -25,7 +25,8 @@ function! s:selection.on_exit(jobid, data, event) abort if self.owner == a:jobid let self.owner = 0 endif - if a:data != 0 + " Don't print if exit code is >= 128 ( exit is 128+SIGNUM if by signal (e.g. 143 on SIGTERM)) + if a:data > 0 && a:data < 128 echohl WarningMsg echomsg 'clipboard: error invoking '.get(self.argv, 0, '?').': '.join(self.stderr) echohl None -- cgit From 278805dfacc865c594c383f6f1fb7eeaf307aa15 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Fri, 11 Aug 2023 19:55:10 +0200 Subject: vim-patch:21aaff3faa82 Update my name and email in runtime files (vim/vim#12763) https://github.com/vim/vim/commit/21aaff3faa828c5c2677a0a9f1b90a0b780d57f6 Co-authored-by: Lily Ballard --- runtime/autoload/rust.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/rust.vim b/runtime/autoload/rust.vim index 34a3b41773..4230332fa7 100644 --- a/runtime/autoload/rust.vim +++ b/runtime/autoload/rust.vim @@ -1,4 +1,4 @@ -" Author: Kevin Ballard +" Author: Lily Ballard " Description: Helper functions for Rust commands/mappings " Last Modified: May 27, 2014 " For bugs, patches and license go to https://github.com/rust-lang/rust.vim -- cgit From cbf54ec2a5aaa1a00ff89e26bab44a30d09d4631 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 13 Aug 2023 13:25:10 +0100 Subject: vim-patch:e978b4534a5e (#24697) Farewell to Bram and dedicate upcoming Vim 9.1 to him (vim/vim#12749) https://github.com/vim/vim/commit/e978b4534a5e10471108259118c0ef791106fd92 Also update the header for the following files that were converted to Vim9 script upstream: - autoload/ccomplete.lua (vim9jitted) - ftplugin.vim - ftplugof.vim - indent.vim - indent/vim.vim - makemenu.vim This also updates the "Last Change" dates, even if some changes (due to rewrites to Vim9 script) were not ported. There's still a few other places where Bram is still mentioned as a maintainer in the files we and Vim have: - ftplugin/bash.vim - indent/bash.vim - indent/html.vim - indent/mail.vim - macros/accents.vim - macros/editexisting.vim - syntax/bash.vim - syntax/shared/typescriptcommon.vim - syntax/tar.vim - syntax/typescript.vim - syntax/typescriptreact.vim - syntax/zimbu.vim Maybe future patches will address that. Also exclude changes to .po files that didn't apply automatically (the `:messages` maintainer string isn't used in Nvim anyway). Co-authored-by: Christian Brabandt --- runtime/autoload/ccomplete.lua | 7 ++++--- runtime/autoload/gzip.vim | 5 +++-- runtime/autoload/paste.vim | 5 +++-- 3 files changed, 10 insertions(+), 7 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/ccomplete.lua b/runtime/autoload/ccomplete.lua index f4a3eabd9a..ce85e84f7a 100644 --- a/runtime/autoload/ccomplete.lua +++ b/runtime/autoload/ccomplete.lua @@ -24,10 +24,11 @@ local SearchMembers = nil -- vim9script -- # Vim completion script --- # Language: C --- # Maintainer: Bram Moolenaar +-- # Language: C +-- # Maintainer: The Vim Project +-- # Last Change: 2023 Aug 10 -- # Rewritten in Vim9 script by github user lacygoill --- # Last Change: 2022 Jan 31 +-- # Former Maintainer: Bram Moolenaar prepended = '' grepCache = vim.empty_dict() diff --git a/runtime/autoload/gzip.vim b/runtime/autoload/gzip.vim index e4adec0947..95dd906794 100644 --- a/runtime/autoload/gzip.vim +++ b/runtime/autoload/gzip.vim @@ -1,6 +1,7 @@ " Vim autoload file for editing compressed files. -" Maintainer: Bram Moolenaar -" Last Change: 2016 Sep 28 +" Maintainer: The Vim Project +" Last Change: 2023 Aug 10 +" Former Maintainer: Bram Moolenaar " These functions are used by the gzip plugin. diff --git a/runtime/autoload/paste.vim b/runtime/autoload/paste.vim index 2d787e7a1d..1ba336c2b3 100644 --- a/runtime/autoload/paste.vim +++ b/runtime/autoload/paste.vim @@ -1,6 +1,7 @@ " Vim support file to help with paste mappings and menus -" Maintainer: Bram Moolenaar -" Last Change: 2019 Jan 27 +" Maintainer: The Vim Project +" Last Change: 2023 Aug 10 +" Former Maintainer: Bram Moolenaar " Define the string to use for items that are present both in Edit, Popup and " Toolbar menu. Also used in mswin.vim and macmap.vim. -- cgit From e2d3c1260ee0a6bc47e457f77638db695d00e972 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Mon, 21 Aug 2023 09:55:21 +0900 Subject: vim-patch:a0fddaa2f4b7 Runtime(javascript): add new document properties to completion file closes: vim/vim#6536 https://github.com/vim/vim/commit/a0fddaa2f4b7358484eb54ccdd1b7433d18a9039 Co-authored-by: Jay Sitter --- runtime/autoload/javascriptcomplete.vim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/javascriptcomplete.vim b/runtime/autoload/javascriptcomplete.vim index 29b6b16254..3ec3b50490 100644 --- a/runtime/autoload/javascriptcomplete.vim +++ b/runtime/autoload/javascriptcomplete.vim @@ -156,8 +156,8 @@ function! javascriptcomplete#CompleteJS(findstart, base) \ 'text', 'vLink'] let bodys = bodyprop " Document - document. - let docuprop = ['anchors', 'body', 'characterSet', 'doctype', - \ 'documentElement', 'documentURI', 'embeds', 'fonts', 'forms', + let docuprop = ['anchors', 'applets', 'body', 'characterSet', 'childNodes', + \ 'doctype', 'documentElement', 'documentURI', 'embeds', 'fonts', 'forms', \ 'head', 'hidden', 'images', 'implementation', 'lastStyleSheetSet', \ 'links', 'plugins', 'preferredStyleSheetSet', 'scripts', \ 'scrollingElement', 'selectedStyleSheetSet', 'styleSheetSets', @@ -171,7 +171,7 @@ function! javascriptcomplete#CompleteJS(findstart, base) \ 'createEvent', 'createExpression', 'createNSResolver', \ 'createNodeIterator', 'createProcessingInstruction', 'createRange', \ 'createTextNode', 'createTouchList', 'createTreeWalker', - \ 'enableStyleSheetsForSet', 'evaluate', 'focus', 'getElementById', + \ 'enableStyleSheetsForSet', 'evaluate', 'focus', \ 'getElementById', 'getElementsByClassName', 'getElementsByName', \ 'getElementsByTagName', 'getElementsByTagNameNS', \ 'hasStorageAccess', 'importNode', 'onClick', 'onDblClick', -- cgit From 67fba9affa14f2f3cd30371568c01d39f3e5f4d4 Mon Sep 17 00:00:00 2001 From: David Moberg Date: Thu, 31 Aug 2023 03:18:39 +0200 Subject: fix(runtime/tutor): don't try to close fold when there is none (#24953) Problem: When double clicking a line starting with a #, the code assumes there is a fold there and tries to close it, resulting in an error if there isn't a fold. Solution: Check foldlevel before performing "zc". --- runtime/autoload/tutor.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/tutor.vim b/runtime/autoload/tutor.vim index 4da4213826..80c09488d5 100644 --- a/runtime/autoload/tutor.vim +++ b/runtime/autoload/tutor.vim @@ -29,7 +29,7 @@ function! tutor#MouseDoubleClick() if foldclosed(line('.')) > -1 normal! zo else - if match(getline('.'), '^#\{1,} ') > -1 + if match(getline('.'), '^#\{1,} ') > -1 && foldlevel(line('.')) > 0 silent normal! zc else call tutor#FollowLink(0) -- cgit From 7bf0963d48ec76b1cdeee55edc8f2053eca87367 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 1 Sep 2023 11:38:31 +0800 Subject: vim-patch:9.0.1833: [security] runtime file fixes (#24969) Problem: runtime files may execute code in current dir Solution: only execute, if not run from current directory The perl, zig and ruby filetype plugins and the zip and gzip autoload plugins may try to load malicious executable files from the current working directory. This is especially a problem on windows, where the current directory is implicitly in your $PATH and windows may even run a file with the extension `.bat` because of $PATHEXT. So make sure that we are not trying to execute a file from the current directory. If this would be the case, error out (for the zip and gzip) plugins or silently do not run those commands (for the ftplugins). This assumes, that only the current working directory is bad. For all other directories, it is assumed that those directories were intentionally set to the $PATH by the user. https://github.com/vim/vim/commit/816fbcc262687b81fc46f82f7bbeb1453addfe0c Co-authored-by: Christian Brabandt --- runtime/autoload/gzip.vim | 7 ++++++- runtime/autoload/zip.vim | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/gzip.vim b/runtime/autoload/gzip.vim index 95dd906794..ac9e37bf85 100644 --- a/runtime/autoload/gzip.vim +++ b/runtime/autoload/gzip.vim @@ -10,12 +10,17 @@ fun s:check(cmd) let name = substitute(a:cmd, '\(\S*\).*', '\1', '') if !exists("s:have_" . name) + " safety check, don't execute anything from the current directory + let f = fnamemodify(exepath(name), ":p:h") !=# getcwd() + if !f + echoerr "Warning: NOT executing " .. name .. " from current directory!" + endif let e = executable(name) if e < 0 let r = system(name . " --version") let e = (r !~ "not found" && r != "") endif - exe "let s:have_" . name . "=" . e + exe "let s:have_" . name . "=" . (e && f) endif exe "return s:have_" . name endfun diff --git a/runtime/autoload/zip.vim b/runtime/autoload/zip.vim index 8dda30c418..0331a542ac 100644 --- a/runtime/autoload/zip.vim +++ b/runtime/autoload/zip.vim @@ -57,6 +57,10 @@ if !exists("g:zip_extractcmd") let g:zip_extractcmd= g:zip_unzipcmd endif +if fnamemodify(exepath(g:zip_unzipcmd), ":p:h") ==# getcwd() + echoerr "Warning: NOT executing " .. g:zip_unzipcmd .. " from current directory!" + finish +endif " ---------------- " Functions: {{{1 " ---------------- -- cgit From 5d1c1da3c90adece96f491e7f12fd76c03a881c9 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Wed, 6 Sep 2023 23:49:58 +0200 Subject: vim-patch:67c951df4c95 runtime(ftplugin): allow to exec if curdir is in PATH In case the current directory is present as valid $PATH entry, it is OK to call the program from it, even if vim curdir is in that same directory. (Without that patch, for instance, you will not be able to open .zip files while your current directory is /bin) closes: vim/vim#13027 https://github.com/vim/vim/commit/67c951df4c95981c716eeedb1b102d9668549e65 Co-authored-by: Anton Sharonov --- runtime/autoload/gzip.vim | 5 ++++- runtime/autoload/zip.vim | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/gzip.vim b/runtime/autoload/gzip.vim index ac9e37bf85..6d0bb13401 100644 --- a/runtime/autoload/gzip.vim +++ b/runtime/autoload/gzip.vim @@ -11,7 +11,10 @@ fun s:check(cmd) let name = substitute(a:cmd, '\(\S*\).*', '\1', '') if !exists("s:have_" . name) " safety check, don't execute anything from the current directory - let f = fnamemodify(exepath(name), ":p:h") !=# getcwd() + let s:tmp_cwd = getcwd() + let f = (fnamemodify(exepath(name), ":p:h") !=# s:tmp_cwd + \ || (index(split($PATH,has("win32")? ';' : ':'), s:tmp_cwd) != -1 && s:tmp_cwd != '.')) + unlet s:tmp_cwd if !f echoerr "Warning: NOT executing " .. name .. " from current directory!" endif diff --git a/runtime/autoload/zip.vim b/runtime/autoload/zip.vim index 0331a542ac..8b39c91c3a 100644 --- a/runtime/autoload/zip.vim +++ b/runtime/autoload/zip.vim @@ -57,10 +57,15 @@ if !exists("g:zip_extractcmd") let g:zip_extractcmd= g:zip_unzipcmd endif -if fnamemodify(exepath(g:zip_unzipcmd), ":p:h") ==# getcwd() +let s:tmp_cwd = getcwd() +if (fnamemodify(exepath(g:zip_unzipcmd), ":p:h") ==# getcwd() + \ && (index(split($PATH,has("win32")? ';' : ':'), s:tmp_cwd) == -1 || s:tmp_cwd == '.')) + unlet s:tmp_cwd echoerr "Warning: NOT executing " .. g:zip_unzipcmd .. " from current directory!" finish endif +unlet s:tmp_cwd + " ---------------- " Functions: {{{1 " ---------------- -- cgit From 294ded9cf26a1a1cab9071588e41bb3ce9474f18 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Fri, 8 Sep 2023 23:35:18 +0200 Subject: vim-patch:86cfb39030eb runtime(tohtml): Update TOhtml to version 9.0v2 (vim/vim#13050) Modified behavior: - Change default value of g:html_use_input_for_pc from "fallback" to "none". This means with default settings, only the standards-based method to make special text unselectable is used. The old method relying on unspecified browser behavior for tags is now only used if a user specifically enables it. - Officially deprecate g:use_xhtml option (in favor of g:html_use_xhtml) by issuing a warning message when used. Bugfixes: - Fix issue vim/vim#8547: LineNr and other special highlight groups did not get proper style rules defined when using "hi link". - Fix that diff filler was not properly added for deleted lines at the end of a buffer. Other: - Refactored function definitions from long lists of strings to use :let-heredoc variable assignment instead. - Corrected deprecated "." string concatenation operator to ".." operator in more places. https://github.com/vim/vim/commit/86cfb39030eb557e1a1c7804f9c147556ca5dbf1 Co-authored-by: fritzophrenic --- runtime/autoload/tohtml.vim | 71 +++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 35 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/tohtml.vim b/runtime/autoload/tohtml.vim index 8a1ba14364..b1693efc5d 100644 --- a/runtime/autoload/tohtml.vim +++ b/runtime/autoload/tohtml.vim @@ -1,6 +1,6 @@ " Vim autoload file for the tohtml plugin. " Maintainer: Ben Fritz -" Last Change: 2023 Jan 01 +" Last Change: 2023 Sep 03 " " Additional contributors: " @@ -307,7 +307,7 @@ func! tohtml#Convert2HTML(line1, line2) "{{{ let g:html_diff_win_num = 0 for window in win_list " switch to the next buffer to convert - exe ":" . bufwinnr(window) . "wincmd w" + exe ":" .. bufwinnr(window) .. "wincmd w" " figure out whether current charset and encoding will work, if not " default to UTF-8 @@ -355,7 +355,7 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{ if !s:settings.no_doc if s:settings.use_xhtml if s:settings.encoding != "" - let xml_line = "" + let xml_line = "" else let xml_line = "" endif @@ -387,34 +387,34 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{ " contained in XML information if s:settings.encoding != "" && !s:settings.use_xhtml if s:html5 - call add(html, 'diff') - call add(html, '') let body_line_num = len(html) - call add(html, '') + call add(html, '') endif - call add(html, "") + call add(html, "
") call add(html, '') for buf in a:win_list - call add(html, '') + call add(html, '') endfor call add(html, '') @@ -423,7 +423,7 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{ for buf in a:buf_list let temp = [] - exe bufwinnr(buf) . 'wincmd w' + exe bufwinnr(buf) .. 'wincmd w' " If text is folded because of user foldmethod settings, etc. we don't want " to act on everything in a fold by mistake. @@ -526,16 +526,16 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{ endif let i = 1 - let name = "Diff" . (s:settings.use_xhtml ? ".xhtml" : ".html") + let name = "Diff" .. (s:settings.use_xhtml ? ".xhtml" : ".html") " Find an unused file name if current file name is already in use while filereadable(name) - let name = substitute(name, '\d*\.x\?html$', '', '') . i . '.' . fnamemodify(copy(name), ":t:e") + let name = substitute(name, '\d*\.x\?html$', '', '') .. i .. '.' .. fnamemodify(copy(name), ":t:e") let i += 1 endwhile let s:ei_sav = &eventignore set eventignore+=FileType - exe "topleft new " . name + exe "topleft new " .. name let &eventignore=s:ei_sav unlet s:ei_sav @@ -601,7 +601,7 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{ \ "", \ " /* navigate upwards in the DOM tree to open all folds containing the line */", \ " var node = lineElem;", - \ " while (node && node.id != 'vimCodeElement".s:settings.id_suffix."')", + \ " while (node && node.id != 'vimCodeElement"..s:settings.id_suffix.."')", \ " {", \ " if (node.className == 'closed-fold')", \ " {", @@ -640,7 +640,7 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{ call append(style_start, [ \ " function toggleFold(objID)", \ " {", - \ " for (win_num = 1; win_num <= ".len(a:buf_list)."; win_num++)", + \ " for (win_num = 1; win_num <= "..len(a:buf_list).."; win_num++)", \ " {", \ " var fold;", \ ' fold = document.getElementById("win"+win_num+objID);', @@ -660,7 +660,7 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{ if s:uses_script " insert script tag if needed call append(style_start, [ - \ "", + \ "", \ s:settings.use_xhtml ? '//']+ + \ ['']+ \ style+ \ [ s:settings.use_xhtml ? '' : '', \ '' @@ -694,7 +694,7 @@ endfunc "}}} " Gets a single user option and sets it in the passed-in Dict, or gives it the " default value if the option doesn't actually exist. func! tohtml#GetOption(settings, option, default) "{{{ - if exists('g:html_'.a:option) + if exists('g:html_'..a:option) let a:settings[a:option] = g:html_{a:option} else let a:settings[a:option] = a:default @@ -713,10 +713,11 @@ func! tohtml#GetUserSettings() "{{{ let user_settings = {} " Define the correct option if the old option name exists and we haven't - " already defined the correct one. Maybe I'll put out a warning message about - " this sometime and remove the old option entirely at some even later time, - " but for now just silently accept the old option. + " already defined the correct one. if exists('g:use_xhtml') && !exists("g:html_use_xhtml") + echohl WarningMsg + echomsg "Warning: g:use_xhtml is deprecated, use g:html_use_xhtml" + echohl None let g:html_use_xhtml = g:use_xhtml endif @@ -739,7 +740,7 @@ func! tohtml#GetUserSettings() "{{{ call tohtml#GetOption(user_settings, 'whole_filler', 0 ) call tohtml#GetOption(user_settings, 'use_xhtml', 0 ) call tohtml#GetOption(user_settings, 'line_ids', user_settings.number_lines ) - call tohtml#GetOption(user_settings, 'use_input_for_pc', 'fallback') + call tohtml#GetOption(user_settings, 'use_input_for_pc', 'none') " }}} " override those settings that need it {{{ @@ -854,16 +855,16 @@ func! tohtml#GetUserSettings() "{{{ if user_settings.use_css if exists("g:html_prevent_copy") if user_settings.dynamic_folds && !user_settings.no_foldcolumn && g:html_prevent_copy =~# 'f' - let user_settings.prevent_copy .= 'f' + let user_settings.prevent_copy ..= 'f' endif if user_settings.number_lines && g:html_prevent_copy =~# 'n' - let user_settings.prevent_copy .= 'n' + let user_settings.prevent_copy ..= 'n' endif if &diff && g:html_prevent_copy =~# 'd' - let user_settings.prevent_copy .= 'd' + let user_settings.prevent_copy ..= 'd' endif if !user_settings.ignore_folding && g:html_prevent_copy =~# 't' - let user_settings.prevent_copy .= 't' + let user_settings.prevent_copy ..= 't' endif else let user_settings.prevent_copy = "" @@ -875,10 +876,10 @@ func! tohtml#GetUserSettings() "{{{ " enforce valid values for use_input_for_pc if user_settings.use_input_for_pc !~# 'fallback\|none\|all' - let user_settings.use_input_for_pc = 'fallback' + let user_settings.use_input_for_pc = 'none' echohl WarningMsg - echomsg '2html: "' . g:html_use_input_for_pc . '" is not valid for g:html_use_input_for_pc' - echomsg '2html: defaulting to "' . user_settings.use_input_for_pc . '"' + echomsg '2html: "' .. g:html_use_input_for_pc .. '" is not valid for g:html_use_input_for_pc' + echomsg '2html: defaulting to "' .. user_settings.use_input_for_pc .. '"' echohl None sleep 3 endif -- cgit From 2dd5e472df8ed448375910d61c050390f7f17f5f Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Tue, 12 Sep 2023 22:30:02 +0200 Subject: vim-patch:fc93594d562d runtime(rust): sync rust runtime files with upstream (vim/vim#13075) https://github.com/vim/vim/commit/fc93594d562dbbd9da03c89754538f91efd0c7ca Co-authored-by: Gregory Anders <8965202+gpanders@users.noreply.github.com> --- runtime/autoload/cargo.vim | 149 +++++++ runtime/autoload/cargo/quickfix.vim | 29 ++ runtime/autoload/rust.vim | 773 ++++++++++++++++++++++-------------- runtime/autoload/rust/debugging.vim | 105 +++++ runtime/autoload/rustfmt.vim | 300 ++++++++++---- 5 files changed, 974 insertions(+), 382 deletions(-) create mode 100644 runtime/autoload/cargo.vim create mode 100644 runtime/autoload/cargo/quickfix.vim create mode 100644 runtime/autoload/rust/debugging.vim (limited to 'runtime/autoload') diff --git a/runtime/autoload/cargo.vim b/runtime/autoload/cargo.vim new file mode 100644 index 0000000000..6696b3105f --- /dev/null +++ b/runtime/autoload/cargo.vim @@ -0,0 +1,149 @@ +" Last Modified: 2023-09-11 + +function! cargo#Load() + " Utility call to get this script loaded, for debugging +endfunction + +function! cargo#cmd(args) abort + " Trim trailing spaces. This is necessary since :terminal command parses + " trailing spaces as an empty argument. + let args = substitute(a:args, '\s\+$', '', '') + if exists('g:cargo_shell_command_runner') + let cmd = g:cargo_shell_command_runner + elseif has('terminal') + let cmd = 'terminal' + elseif has('nvim') + let cmd = 'noautocmd new | terminal' + else + let cmd = '!' + endif + execute cmd 'cargo' args +endfunction + +function! s:nearest_cargo(...) abort + " If the second argument is not specified, the first argument determines + " whether we will start from the current directory or the directory of the + " current buffer, otherwise, we start with the provided path on the + " second argument. + + let l:is_getcwd = get(a:, 1, 0) + if l:is_getcwd + let l:starting_path = get(a:, 2, getcwd()) + else + let l:starting_path = get(a:, 2, expand('%:p:h')) + endif + + return findfile('Cargo.toml', l:starting_path . ';') +endfunction + +function! cargo#nearestCargo(is_getcwd) abort + return s:nearest_cargo(a:is_getcwd) +endfunction + +function! cargo#nearestWorkspaceCargo(is_getcwd) abort + let l:nearest = s:nearest_cargo(a:is_getcwd) + while l:nearest !=# '' + for l:line in readfile(l:nearest, '', 0x100) + if l:line =~# '\V[workspace]' + return l:nearest + endif + endfor + let l:next = fnamemodify(l:nearest, ':p:h:h') + let l:nearest = s:nearest_cargo(0, l:next) + endwhile + return '' +endfunction + +function! cargo#nearestRootCargo(is_getcwd) abort + " Try to find a workspace Cargo.toml, and if not found, take the nearest + " regular Cargo.toml + let l:workspace_cargo = cargo#nearestWorkspaceCargo(a:is_getcwd) + if l:workspace_cargo !=# '' + return l:workspace_cargo + endif + return s:nearest_cargo(a:is_getcwd) +endfunction + + +function! cargo#build(args) + call cargo#cmd("build " . a:args) +endfunction + +function! cargo#check(args) + call cargo#cmd("check " . a:args) +endfunction + +function! cargo#clean(args) + call cargo#cmd("clean " . a:args) +endfunction + +function! cargo#doc(args) + call cargo#cmd("doc " . a:args) +endfunction + +function! cargo#new(args) + call cargo#cmd("new " . a:args) + cd `=a:args` +endfunction + +function! cargo#init(args) + call cargo#cmd("init " . a:args) +endfunction + +function! cargo#run(args) + call cargo#cmd("run " . a:args) +endfunction + +function! cargo#test(args) + call cargo#cmd("test " . a:args) +endfunction + +function! cargo#bench(args) + call cargo#cmd("bench " . a:args) +endfunction + +function! cargo#update(args) + call cargo#cmd("update " . a:args) +endfunction + +function! cargo#search(args) + call cargo#cmd("search " . a:args) +endfunction + +function! cargo#publish(args) + call cargo#cmd("publish " . a:args) +endfunction + +function! cargo#install(args) + call cargo#cmd("install " . a:args) +endfunction + +function! cargo#runtarget(args) + let l:filename = expand('%:p') + let l:read_manifest = system('cargo read-manifest') + let l:metadata = json_decode(l:read_manifest) + let l:targets = get(l:metadata, 'targets', []) + let l:did_run = 0 + for l:target in l:targets + let l:src_path = get(l:target, 'src_path', '') + let l:kinds = get(l:target, 'kind', []) + let l:name = get(l:target, 'name', '') + if l:src_path == l:filename + if index(l:kinds, 'example') != -1 + let l:did_run = 1 + call cargo#run("--example " . shellescape(l:name) . " " . a:args) + return + elseif index(l:kinds, 'bin') != -1 + let l:did_run = 1 + call cargo#run("--bin " . shellescape(l:name) . " " . a:args) + return + endif + endif + endfor + if l:did_run != 1 + call cargo#run(a:args) + return + endif +endfunction + +" vim: set et sw=4 sts=4 ts=8: diff --git a/runtime/autoload/cargo/quickfix.vim b/runtime/autoload/cargo/quickfix.vim new file mode 100644 index 0000000000..f2a006f6c5 --- /dev/null +++ b/runtime/autoload/cargo/quickfix.vim @@ -0,0 +1,29 @@ +" Last Modified: 2023-09-11 + +function! cargo#quickfix#CmdPre() abort + if &filetype ==# 'rust' && get(b:, 'current_compiler', '') ==# 'cargo' && + \ &makeprg =~ '\V\^cargo\ \.\*' + " Preserve the current directory, and 'lcd' to the nearest Cargo file. + let b:rust_compiler_cargo_qf_has_lcd = haslocaldir() + let b:rust_compiler_cargo_qf_prev_cd = getcwd() + let b:rust_compiler_cargo_qf_prev_cd_saved = 1 + let l:nearest = fnamemodify(cargo#nearestRootCargo(0), ':h') + execute 'lchdir! '.l:nearest + else + let b:rust_compiler_cargo_qf_prev_cd_saved = 0 + endif +endfunction + +function! cargo#quickfix#CmdPost() abort + if exists("b:rust_compiler_cargo_qf_prev_cd_saved") && b:rust_compiler_cargo_qf_prev_cd_saved + " Restore the current directory. + if b:rust_compiler_cargo_qf_has_lcd + execute 'lchdir! '.b:rust_compiler_cargo_qf_prev_cd + else + execute 'chdir! '.b:rust_compiler_cargo_qf_prev_cd + endif + let b:rust_compiler_cargo_qf_prev_cd_saved = 0 + endif +endfunction + +" vim: set et sw=4 sts=4 ts=8: diff --git a/runtime/autoload/rust.vim b/runtime/autoload/rust.vim index 4230332fa7..5ccbf4b382 100644 --- a/runtime/autoload/rust.vim +++ b/runtime/autoload/rust.vim @@ -1,207 +1,258 @@ -" Author: Lily Ballard " Description: Helper functions for Rust commands/mappings -" Last Modified: May 27, 2014 +" Last Modified: 2023-09-11 " For bugs, patches and license go to https://github.com/rust-lang/rust.vim +function! rust#Load() + " Utility call to get this script loaded, for debugging +endfunction + +function! rust#GetConfigVar(name, default) + " Local buffer variable with same name takes predeence over global + if has_key(b:, a:name) + return get(b:, a:name) + endif + if has_key(g:, a:name) + return get(g:, a:name) + endif + return a:default +endfunction + +" Include expression {{{1 + +function! rust#IncludeExpr(fname) abort + " Remove leading 'crate::' to deal with 2018 edition style 'use' + " statements + let l:fname = substitute(a:fname, '^crate::', '', '') + + " Remove trailing colons arising from lines like + " + " use foo::{Bar, Baz}; + let l:fname = substitute(l:fname, ':\+$', '', '') + + " Replace '::' with '/' + let l:fname = substitute(l:fname, '::', '/', 'g') + + " When we have + " + " use foo::bar::baz; + " + " we can't tell whether baz is a module or a function; and we can't tell + " which modules correspond to files. + " + " So we work our way up, trying + " + " foo/bar/baz.rs + " foo/bar.rs + " foo.rs + while l:fname !=# '.' + let l:path = findfile(l:fname) + if !empty(l:path) + return l:fname + endif + let l:fname = fnamemodify(l:fname, ':h') + endwhile + return l:fname +endfunction + " Jump {{{1 function! rust#Jump(mode, function) range - let cnt = v:count1 - normal! m' - if a:mode ==# 'v' - norm! gv - endif - let foldenable = &foldenable - set nofoldenable - while cnt > 0 - execute "call Jump_" . a:function . "()" - let cnt = cnt - 1 - endwhile - let &foldenable = foldenable + let cnt = v:count1 + normal! m' + if a:mode ==# 'v' + norm! gv + endif + let foldenable = &foldenable + set nofoldenable + while cnt > 0 + execute "call Jump_" . a:function . "()" + let cnt = cnt - 1 + endwhile + let &foldenable = foldenable endfunction function! s:Jump_Back() - call search('{', 'b') - keepjumps normal! w99[{ + call search('{', 'b') + keepjumps normal! w99[{ endfunction function! s:Jump_Forward() - normal! j0 - call search('{', 'b') - keepjumps normal! w99[{% - call search('{') + normal! j0 + call search('{', 'b') + keepjumps normal! w99[{% + call search('{') endfunction " Run {{{1 function! rust#Run(bang, args) - let args = s:ShellTokenize(a:args) - if a:bang - let idx = index(l:args, '--') - if idx != -1 - let rustc_args = idx == 0 ? [] : l:args[:idx-1] - let args = l:args[idx+1:] - else - let rustc_args = l:args - let args = [] - endif - else - let rustc_args = [] - endif - - let b:rust_last_rustc_args = l:rustc_args - let b:rust_last_args = l:args - - call s:WithPath(function("s:Run"), rustc_args, args) + let args = s:ShellTokenize(a:args) + if a:bang + let idx = index(l:args, '--') + if idx != -1 + let rustc_args = idx == 0 ? [] : l:args[:idx-1] + let args = l:args[idx+1:] + else + let rustc_args = l:args + let args = [] + endif + else + let rustc_args = [] + endif + + let b:rust_last_rustc_args = l:rustc_args + let b:rust_last_args = l:args + + call s:WithPath(function("s:Run"), rustc_args, args) endfunction function! s:Run(dict, rustc_args, args) - let exepath = a:dict.tmpdir.'/'.fnamemodify(a:dict.path, ':t:r') - if has('win32') - let exepath .= '.exe' - endif - - let relpath = get(a:dict, 'tmpdir_relpath', a:dict.path) - let rustc_args = [relpath, '-o', exepath] + a:rustc_args - - let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc" - - let pwd = a:dict.istemp ? a:dict.tmpdir : '' - let output = s:system(pwd, shellescape(rustc) . " " . join(map(rustc_args, 'shellescape(v:val)'))) - if output != '' - echohl WarningMsg - echo output - echohl None - endif - if !v:shell_error - exe '!' . shellescape(exepath) . " " . join(map(a:args, 'shellescape(v:val)')) - endif + let exepath = a:dict.tmpdir.'/'.fnamemodify(a:dict.path, ':t:r') + if has('win32') + let exepath .= '.exe' + endif + + let relpath = get(a:dict, 'tmpdir_relpath', a:dict.path) + let rustc_args = [relpath, '-o', exepath] + a:rustc_args + + let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc" + + let pwd = a:dict.istemp ? a:dict.tmpdir : '' + let output = s:system(pwd, shellescape(rustc) . " " . join(map(rustc_args, 'shellescape(v:val)'))) + if output !=# '' + echohl WarningMsg + echo output + echohl None + endif + if !v:shell_error + exe '!' . shellescape(exepath) . " " . join(map(a:args, 'shellescape(v:val)')) + endif endfunction " Expand {{{1 function! rust#Expand(bang, args) - let args = s:ShellTokenize(a:args) - if a:bang && !empty(l:args) - let pretty = remove(l:args, 0) - else - let pretty = "expanded" - endif - call s:WithPath(function("s:Expand"), pretty, args) + let args = s:ShellTokenize(a:args) + if a:bang && !empty(l:args) + let pretty = remove(l:args, 0) + else + let pretty = "expanded" + endif + call s:WithPath(function("s:Expand"), pretty, args) endfunction function! s:Expand(dict, pretty, args) - try - let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc" - - if a:pretty =~? '^\%(everybody_loops$\|flowgraph=\)' - let flag = '--xpretty' - else - let flag = '--pretty' - endif - let relpath = get(a:dict, 'tmpdir_relpath', a:dict.path) - let args = [relpath, '-Z', 'unstable-options', l:flag, a:pretty] + a:args - let pwd = a:dict.istemp ? a:dict.tmpdir : '' - let output = s:system(pwd, shellescape(rustc) . " " . join(map(args, 'shellescape(v:val)'))) - if v:shell_error - echohl WarningMsg - echo output - echohl None - else - new - silent put =output - 1 - d - setl filetype=rust - setl buftype=nofile - setl bufhidden=hide - setl noswapfile - " give the buffer a nice name - let suffix = 1 - let basename = fnamemodify(a:dict.path, ':t:r') - while 1 - let bufname = basename - if suffix > 1 | let bufname .= ' ('.suffix.')' | endif - let bufname .= '.pretty.rs' - if bufexists(bufname) - let suffix += 1 - continue - endif - exe 'silent noautocmd keepalt file' fnameescape(bufname) - break - endwhile - endif - endtry + try + let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc" + + if a:pretty =~? '^\%(everybody_loops$\|flowgraph=\)' + let flag = '--xpretty' + else + let flag = '--pretty' + endif + let relpath = get(a:dict, 'tmpdir_relpath', a:dict.path) + let args = [relpath, '-Z', 'unstable-options', l:flag, a:pretty] + a:args + let pwd = a:dict.istemp ? a:dict.tmpdir : '' + let output = s:system(pwd, shellescape(rustc) . " " . join(map(args, 'shellescape(v:val)'))) + if v:shell_error + echohl WarningMsg + echo output + echohl None + else + new + silent put =output + 1 + d + setl filetype=rust + setl buftype=nofile + setl bufhidden=hide + setl noswapfile + " give the buffer a nice name + let suffix = 1 + let basename = fnamemodify(a:dict.path, ':t:r') + while 1 + let bufname = basename + if suffix > 1 | let bufname .= ' ('.suffix.')' | endif + let bufname .= '.pretty.rs' + if bufexists(bufname) + let suffix += 1 + continue + endif + exe 'silent noautocmd keepalt file' fnameescape(bufname) + break + endwhile + endif + endtry endfunction function! rust#CompleteExpand(lead, line, pos) - if a:line[: a:pos-1] =~ '^RustExpand!\s*\S*$' - " first argument and it has a ! - let list = ["normal", "expanded", "typed", "expanded,identified", "flowgraph=", "everybody_loops"] - if !empty(a:lead) - call filter(list, "v:val[:len(a:lead)-1] == a:lead") - endif - return list - endif - - return glob(escape(a:lead, "*?[") . '*', 0, 1) + if a:line[: a:pos-1] =~# '^RustExpand!\s*\S*$' + " first argument and it has a ! + let list = ["normal", "expanded", "typed", "expanded,identified", "flowgraph=", "everybody_loops"] + if !empty(a:lead) + call filter(list, "v:val[:len(a:lead)-1] == a:lead") + endif + return list + endif + + return glob(escape(a:lead, "*?[") . '*', 0, 1) endfunction " Emit {{{1 function! rust#Emit(type, args) - let args = s:ShellTokenize(a:args) - call s:WithPath(function("s:Emit"), a:type, args) + let args = s:ShellTokenize(a:args) + call s:WithPath(function("s:Emit"), a:type, args) endfunction function! s:Emit(dict, type, args) - try - let output_path = a:dict.tmpdir.'/output' - - let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc" - - let relpath = get(a:dict, 'tmpdir_relpath', a:dict.path) - let args = [relpath, '--emit', a:type, '-o', output_path] + a:args - let pwd = a:dict.istemp ? a:dict.tmpdir : '' - let output = s:system(pwd, shellescape(rustc) . " " . join(map(args, 'shellescape(v:val)'))) - if output != '' - echohl WarningMsg - echo output - echohl None - endif - if !v:shell_error - new - exe 'silent keepalt read' fnameescape(output_path) - 1 - d - if a:type == "llvm-ir" - setl filetype=llvm - let extension = 'll' - elseif a:type == "asm" - setl filetype=asm - let extension = 's' - endif - setl buftype=nofile - setl bufhidden=hide - setl noswapfile - if exists('l:extension') - " give the buffer a nice name - let suffix = 1 - let basename = fnamemodify(a:dict.path, ':t:r') - while 1 - let bufname = basename - if suffix > 1 | let bufname .= ' ('.suffix.')' | endif - let bufname .= '.'.extension - if bufexists(bufname) - let suffix += 1 - continue - endif - exe 'silent noautocmd keepalt file' fnameescape(bufname) - break - endwhile - endif - endif - endtry + try + let output_path = a:dict.tmpdir.'/output' + + let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc" + + let relpath = get(a:dict, 'tmpdir_relpath', a:dict.path) + let args = [relpath, '--emit', a:type, '-o', output_path] + a:args + let pwd = a:dict.istemp ? a:dict.tmpdir : '' + let output = s:system(pwd, shellescape(rustc) . " " . join(map(args, 'shellescape(v:val)'))) + if output !=# '' + echohl WarningMsg + echo output + echohl None + endif + if !v:shell_error + new + exe 'silent keepalt read' fnameescape(output_path) + 1 + d + if a:type ==# "llvm-ir" + setl filetype=llvm + let extension = 'll' + elseif a:type ==# "asm" + setl filetype=asm + let extension = 's' + endif + setl buftype=nofile + setl bufhidden=hide + setl noswapfile + if exists('l:extension') + " give the buffer a nice name + let suffix = 1 + let basename = fnamemodify(a:dict.path, ':t:r') + while 1 + let bufname = basename + if suffix > 1 | let bufname .= ' ('.suffix.')' | endif + let bufname .= '.'.extension + if bufexists(bufname) + let suffix += 1 + continue + endif + exe 'silent noautocmd keepalt file' fnameescape(bufname) + break + endwhile + endif + endif + endtry endfunction " Utility functions {{{1 @@ -219,145 +270,154 @@ endfunction " existing path of the current buffer. If the path is inside of {dict.tmpdir} " then it is guaranteed to have a '.rs' extension. function! s:WithPath(func, ...) - let buf = bufnr('') - let saved = {} - let dict = {} - try - let saved.write = &write - set write - let dict.path = expand('%') - let pathisempty = empty(dict.path) - - " Always create a tmpdir in case the wrapped command wants it - let dict.tmpdir = tempname() - call mkdir(dict.tmpdir) - - if pathisempty || !saved.write - let dict.istemp = 1 - " if we're doing this because of nowrite, preserve the filename - if !pathisempty - let filename = expand('%:t:r').".rs" - else - let filename = 'unnamed.rs' - endif - let dict.tmpdir_relpath = filename - let dict.path = dict.tmpdir.'/'.filename - - let saved.mod = &mod - set nomod - - silent exe 'keepalt write! ' . fnameescape(dict.path) - if pathisempty - silent keepalt 0file - endif - else - let dict.istemp = 0 - update - endif - - call call(a:func, [dict] + a:000) - finally - if bufexists(buf) - for [opt, value] in items(saved) - silent call setbufvar(buf, '&'.opt, value) - unlet value " avoid variable type mismatches - endfor - endif - if has_key(dict, 'tmpdir') | silent call s:RmDir(dict.tmpdir) | endif - endtry + let buf = bufnr('') + let saved = {} + let dict = {} + try + let saved.write = &write + set write + let dict.path = expand('%') + let pathisempty = empty(dict.path) + + " Always create a tmpdir in case the wrapped command wants it + let dict.tmpdir = tempname() + call mkdir(dict.tmpdir) + + if pathisempty || !saved.write + let dict.istemp = 1 + " if we're doing this because of nowrite, preserve the filename + if !pathisempty + let filename = expand('%:t:r').".rs" + else + let filename = 'unnamed.rs' + endif + let dict.tmpdir_relpath = filename + let dict.path = dict.tmpdir.'/'.filename + + let saved.mod = &modified + set nomodified + + silent exe 'keepalt write! ' . fnameescape(dict.path) + if pathisempty + silent keepalt 0file + endif + else + let dict.istemp = 0 + update + endif + + call call(a:func, [dict] + a:000) + finally + if bufexists(buf) + for [opt, value] in items(saved) + silent call setbufvar(buf, '&'.opt, value) + unlet value " avoid variable type mismatches + endfor + endif + if has_key(dict, 'tmpdir') | silent call s:RmDir(dict.tmpdir) | endif + endtry endfunction function! rust#AppendCmdLine(text) - call setcmdpos(getcmdpos()) - let cmd = getcmdline() . a:text - return cmd + call setcmdpos(getcmdpos()) + let cmd = getcmdline() . a:text + return cmd endfunction " Tokenize the string according to sh parsing rules function! s:ShellTokenize(text) - " states: - " 0: start of word - " 1: unquoted - " 2: unquoted backslash - " 3: double-quote - " 4: double-quoted backslash - " 5: single-quote - let l:state = 0 - let l:current = '' - let l:args = [] - for c in split(a:text, '\zs') - if l:state == 0 || l:state == 1 " unquoted - if l:c ==# ' ' - if l:state == 0 | continue | endif - call add(l:args, l:current) - let l:current = '' - let l:state = 0 - elseif l:c ==# '\' - let l:state = 2 - elseif l:c ==# '"' - let l:state = 3 - elseif l:c ==# "'" - let l:state = 5 - else - let l:current .= l:c - let l:state = 1 - endif - elseif l:state == 2 " unquoted backslash - if l:c !=# "\n" " can it even be \n? - let l:current .= l:c - endif - let l:state = 1 - elseif l:state == 3 " double-quote - if l:c ==# '\' - let l:state = 4 - elseif l:c ==# '"' - let l:state = 1 - else - let l:current .= l:c - endif - elseif l:state == 4 " double-quoted backslash - if stridx('$`"\', l:c) >= 0 - let l:current .= l:c - elseif l:c ==# "\n" " is this even possible? - " skip it - else - let l:current .= '\'.l:c - endif - let l:state = 3 - elseif l:state == 5 " single-quoted - if l:c == "'" - let l:state = 1 - else - let l:current .= l:c - endif - endif - endfor - if l:state != 0 - call add(l:args, l:current) - endif - return l:args + " states: + " 0: start of word + " 1: unquoted + " 2: unquoted backslash + " 3: double-quote + " 4: double-quoted backslash + " 5: single-quote + let l:state = 0 + let l:current = '' + let l:args = [] + for c in split(a:text, '\zs') + if l:state == 0 || l:state == 1 " unquoted + if l:c ==# ' ' + if l:state == 0 | continue | endif + call add(l:args, l:current) + let l:current = '' + let l:state = 0 + elseif l:c ==# '\' + let l:state = 2 + elseif l:c ==# '"' + let l:state = 3 + elseif l:c ==# "'" + let l:state = 5 + else + let l:current .= l:c + let l:state = 1 + endif + elseif l:state == 2 " unquoted backslash + if l:c !=# "\n" " can it even be \n? + let l:current .= l:c + endif + let l:state = 1 + elseif l:state == 3 " double-quote + if l:c ==# '\' + let l:state = 4 + elseif l:c ==# '"' + let l:state = 1 + else + let l:current .= l:c + endif + elseif l:state == 4 " double-quoted backslash + if stridx('$`"\', l:c) >= 0 + let l:current .= l:c + elseif l:c ==# "\n" " is this even possible? + " skip it + else + let l:current .= '\'.l:c + endif + let l:state = 3 + elseif l:state == 5 " single-quoted + if l:c ==# "'" + let l:state = 1 + else + let l:current .= l:c + endif + endif + endfor + if l:state != 0 + call add(l:args, l:current) + endif + return l:args endfunction function! s:RmDir(path) - " sanity check; make sure it's not empty, /, or $HOME - if empty(a:path) - echoerr 'Attempted to delete empty path' - return 0 - elseif a:path == '/' || a:path == $HOME - echoerr 'Attempted to delete protected path: ' . a:path - return 0 - endif - return system("rm -rf " . shellescape(a:path)) + " sanity check; make sure it's not empty, /, or $HOME + if empty(a:path) + echoerr 'Attempted to delete empty path' + return 0 + elseif a:path ==# '/' || a:path ==# $HOME + let l:path = expand(a:path) + if l:path ==# '/' || l:path ==# $HOME + echoerr 'Attempted to delete protected path: ' . a:path + return 0 + endif + endif + + if !isdirectory(a:path) + return 0 + endif + + " delete() returns 0 when removing file successfully + return delete(a:path, 'rf') == 0 endfunction " Executes {cmd} with the cwd set to {pwd}, without changing Vim's cwd. " If {pwd} is the empty string then it doesn't change the cwd. function! s:system(pwd, cmd) - let cmd = a:cmd - if !empty(a:pwd) - let cmd = 'cd ' . shellescape(a:pwd) . ' && ' . cmd - endif - return system(cmd) + let cmd = a:cmd + if !empty(a:pwd) + let cmd = 'cd ' . shellescape(a:pwd) . ' && ' . cmd + endif + return system(cmd) endfunction " Playpen Support {{{1 @@ -366,10 +426,10 @@ endfunction " http://github.com/mattn/gist-vim function! s:has_webapi() if !exists("*webapi#http#post") - try - call webapi#http#post() - catch - endtry + try + call webapi#http#post() + catch + endtry endif return exists("*webapi#http#post") endfunction @@ -381,35 +441,130 @@ function! rust#Play(count, line1, line2, ...) abort let l:rust_shortener_url = get(g:, 'rust_shortener_url', 'https://is.gd/') if !s:has_webapi() - echohl ErrorMsg | echomsg ':RustPlay depends on webapi.vim (https://github.com/mattn/webapi-vim)' | echohl None - return + echohl ErrorMsg | echomsg ':RustPlay depends on webapi.vim (https://github.com/mattn/webapi-vim)' | echohl None + return endif let bufname = bufname('%') if a:count < 1 - let content = join(getline(a:line1, a:line2), "\n") + let content = join(getline(a:line1, a:line2), "\n") else - let save_regcont = @" - let save_regtype = getregtype('"') - silent! normal! gvy - let content = @" - call setreg('"', save_regcont, save_regtype) + let save_regcont = @" + let save_regtype = getregtype('"') + silent! normal! gvy + let content = @" + call setreg('"', save_regcont, save_regtype) endif - let body = l:rust_playpen_url."?code=".webapi#http#encodeURI(content) + let url = l:rust_playpen_url."?code=".webapi#http#encodeURI(content) - if strlen(body) > 5000 - echohl ErrorMsg | echomsg 'Buffer too large, max 5000 encoded characters ('.strlen(body).')' | echohl None - return + if strlen(url) > 5000 + echohl ErrorMsg | echomsg 'Buffer too large, max 5000 encoded characters ('.strlen(url).')' | echohl None + return endif - let payload = "format=simple&url=".webapi#http#encodeURI(body) + let payload = "format=simple&url=".webapi#http#encodeURI(url) let res = webapi#http#post(l:rust_shortener_url.'create.php', payload, {}) - let url = res.content + if res.status[0] ==# '2' + let url = res.content + endif + + let footer = '' + if exists('g:rust_clip_command') + call system(g:rust_clip_command, url) + if !v:shell_error + let footer = ' (copied to clipboard)' + endif + endif + redraw | echomsg 'Done: '.url.footer +endfunction + +" Run a test under the cursor or all tests {{{1 + +" Finds a test function name under the cursor. Returns empty string when a +" test function is not found. +function! s:SearchTestFunctionNameUnderCursor() abort + let cursor_line = line('.') - redraw | echomsg 'Done: '.url + " Find #[test] attribute + if search('\m\C#\[test\]', 'bcW') is 0 + return '' + endif + + " Move to an opening brace of the test function + let test_func_line = search('\m\C^\s*fn\s\+\h\w*\s*(.\+{$', 'eW') + if test_func_line is 0 + return '' + endif + + " Search the end of test function (closing brace) to ensure that the + " cursor position is within function definition + if maparg('(MatchitNormalForward)') ==# '' + keepjumps normal! % + else + " Prefer matchit.vim official plugin to native % since the plugin + " provides better behavior than original % (#391) + " To load the plugin, run: + " :packadd matchit + execute 'keepjumps' 'normal' "\(MatchitNormalForward)" + endif + if line('.') < cursor_line + return '' + endif + + return matchstr(getline(test_func_line), '\m\C^\s*fn\s\+\zs\h\w*') +endfunction + +function! rust#Test(mods, winsize, all, options) abort + let manifest = findfile('Cargo.toml', expand('%:p:h') . ';') + if manifest ==# '' + return rust#Run(1, '--test ' . a:options) + endif + + " defaults to 0, but we prefer an empty string + let winsize = a:winsize ? a:winsize : '' + + if has('terminal') + if has('patch-8.0.910') + let cmd = printf('%s noautocmd %snew | terminal ++curwin ', a:mods, winsize) + else + let cmd = printf('%s terminal ', a:mods) + endif + elseif has('nvim') + let cmd = printf('%s noautocmd %snew | terminal ', a:mods, winsize) + else + let cmd = '!' + let manifest = shellescape(manifest) + endif + + if a:all + if a:options ==# '' + execute cmd . 'cargo test --manifest-path' manifest + else + execute cmd . 'cargo test --manifest-path' manifest a:options + endif + return + endif + + let saved = getpos('.') + try + let func_name = s:SearchTestFunctionNameUnderCursor() + finally + call setpos('.', saved) + endtry + if func_name ==# '' + echohl ErrorMsg + echomsg 'No test function was found under the cursor. Please add ! to command if you want to run all tests' + echohl None + return + endif + if a:options ==# '' + execute cmd . 'cargo test --manifest-path' manifest func_name + else + execute cmd . 'cargo test --manifest-path' manifest func_name a:options + endif endfunction " }}}1 -" vim: set noet sw=8 ts=8: +" vim: set et sw=4 sts=4 ts=8: diff --git a/runtime/autoload/rust/debugging.vim b/runtime/autoload/rust/debugging.vim new file mode 100644 index 0000000000..0e84183172 --- /dev/null +++ b/runtime/autoload/rust/debugging.vim @@ -0,0 +1,105 @@ +" Last Modified: 2023-09-11 + +" For debugging, inspired by https://github.com/w0rp/rust/blob/master/autoload/rust/debugging.vim + +let s:global_variable_list = [ + \ '_rustfmt_autosave_because_of_config', + \ 'ftplugin_rust_source_path', + \ 'loaded_syntastic_rust_cargo_checker', + \ 'loaded_syntastic_rust_filetype', + \ 'loaded_syntastic_rust_rustc_checker', + \ 'rust_bang_comment_leader', + \ 'rust_cargo_avoid_whole_workspace', + \ 'rust_clip_command', + \ 'rust_conceal', + \ 'rust_conceal_mod_path', + \ 'rust_conceal_pub', + \ 'rust_fold', + \ 'rust_last_args', + \ 'rust_last_rustc_args', + \ 'rust_original_delimitMate_excluded_regions', + \ 'rust_playpen_url', + \ 'rust_prev_delimitMate_quotes', + \ 'rust_recent_nearest_cargo_tol', + \ 'rust_recent_root_cargo_toml', + \ 'rust_recommended_style', + \ 'rust_set_conceallevel', + \ 'rust_set_conceallevel=1', + \ 'rust_set_foldmethod', + \ 'rust_set_foldmethod=1', + \ 'rust_shortener_url', + \ 'rustc_makeprg_no_percent', + \ 'rustc_path', + \ 'rustfmt_autosave', + \ 'rustfmt_autosave_if_config_present', + \ 'rustfmt_command', + \ 'rustfmt_emit_files', + \ 'rustfmt_fail_silently', + \ 'rustfmt_options', + \ 'syntastic_extra_filetypes', + \ 'syntastic_rust_cargo_fname', + \] + +function! s:Echo(message) abort + execute 'echo a:message' +endfunction + +function! s:EchoGlobalVariables() abort + for l:key in s:global_variable_list + if l:key !~# '^_' + call s:Echo('let g:' . l:key . ' = ' . string(get(g:, l:key, v:null))) + endif + + if has_key(b:, l:key) + call s:Echo('let b:' . l:key . ' = ' . string(b:[l:key])) + endif + endfor +endfunction + +function! rust#debugging#Info() abort + call cargo#Load() + call rust#Load() + call rustfmt#Load() + call s:Echo('rust.vim Global Variables:') + call s:Echo('') + call s:EchoGlobalVariables() + + silent let l:output = system(g:rustfmt_command . ' --version') + echo l:output + + let l:rustc = exists("g:rustc_path") ? g:rustc_path : "rustc" + silent let l:output = system(l:rustc . ' --version') + echo l:output + + silent let l:output = system('cargo --version') + echo l:output + + version + + if exists(":SyntasticInfo") + echo "----" + echo "Info from Syntastic:" + execute "SyntasticInfo" + endif +endfunction + +function! rust#debugging#InfoToClipboard() abort + redir @" + silent call rust#debugging#Info() + redir END + + call s:Echo('RustInfo copied to your clipboard') +endfunction + +function! rust#debugging#InfoToFile(filename) abort + let l:expanded_filename = expand(a:filename) + + redir => l:output + silent call rust#debugging#Info() + redir END + + call writefile(split(l:output, "\n"), l:expanded_filename) + call s:Echo('RustInfo written to ' . l:expanded_filename) +endfunction + +" vim: set et sw=4 sts=4 ts=8: diff --git a/runtime/autoload/rustfmt.vim b/runtime/autoload/rustfmt.vim index a689b5e00d..652e6af33a 100644 --- a/runtime/autoload/rustfmt.vim +++ b/runtime/autoload/rustfmt.vim @@ -1,107 +1,261 @@ " Author: Stephen Sugden +" Last Modified: 2023-09-11 " " Adapted from https://github.com/fatih/vim-go " For bugs, patches and license go to https://github.com/rust-lang/rust.vim if !exists("g:rustfmt_autosave") - let g:rustfmt_autosave = 0 + let g:rustfmt_autosave = 0 endif if !exists("g:rustfmt_command") - let g:rustfmt_command = "rustfmt" + let g:rustfmt_command = "rustfmt" endif if !exists("g:rustfmt_options") - let g:rustfmt_options = "" + let g:rustfmt_options = "" endif if !exists("g:rustfmt_fail_silently") - let g:rustfmt_fail_silently = 0 + let g:rustfmt_fail_silently = 0 +endif + +function! rustfmt#DetectVersion() + " Save rustfmt '--help' for feature inspection + silent let s:rustfmt_help = system(g:rustfmt_command . " --help") + let s:rustfmt_unstable_features = s:rustfmt_help =~# "--unstable-features" + + " Build a comparable rustfmt version varible out of its `--version` output: + silent let l:rustfmt_version_full = system(g:rustfmt_command . " --version") + let l:rustfmt_version_list = matchlist(l:rustfmt_version_full, + \ '\vrustfmt ([0-9]+[.][0-9]+[.][0-9]+)') + if len(l:rustfmt_version_list) < 3 + let s:rustfmt_version = "0" + else + let s:rustfmt_version = l:rustfmt_version_list[1] + endif + return s:rustfmt_version +endfunction + +call rustfmt#DetectVersion() + +if !exists("g:rustfmt_emit_files") + let g:rustfmt_emit_files = s:rustfmt_version >= "0.8.2" +endif + +if !exists("g:rustfmt_file_lines") + let g:rustfmt_file_lines = s:rustfmt_help =~# "--file-lines JSON" endif let s:got_fmt_error = 0 +function! rustfmt#Load() + " Utility call to get this script loaded, for debugging +endfunction + +function! s:RustfmtWriteMode() + if g:rustfmt_emit_files + return "--emit=files" + else + return "--write-mode=overwrite" + endif +endfunction + +function! s:RustfmtConfigOptions() + let l:rustfmt_toml = findfile('rustfmt.toml', expand('%:p:h') . ';') + if l:rustfmt_toml !=# '' + return '--config-path '.shellescape(fnamemodify(l:rustfmt_toml, ":p")) + endif + + let l:_rustfmt_toml = findfile('.rustfmt.toml', expand('%:p:h') . ';') + if l:_rustfmt_toml !=# '' + return '--config-path '.shellescape(fnamemodify(l:_rustfmt_toml, ":p")) + endif + + " Default to edition 2018 in case no rustfmt.toml was found. + return '--edition 2018' +endfunction + function! s:RustfmtCommandRange(filename, line1, line2) - let l:arg = {"file": shellescape(a:filename), "range": [a:line1, a:line2]} - return printf("%s %s --write-mode=overwrite --file-lines '[%s]'", g:rustfmt_command, g:rustfmt_options, json_encode(l:arg)) + if g:rustfmt_file_lines == 0 + echo "--file-lines is not supported in the installed `rustfmt` executable" + return + endif + + let l:arg = {"file": shellescape(a:filename), "range": [a:line1, a:line2]} + let l:write_mode = s:RustfmtWriteMode() + let l:rustfmt_config = s:RustfmtConfigOptions() + + " FIXME: When --file-lines gets to be stable, add version range checking + " accordingly. + let l:unstable_features = s:rustfmt_unstable_features ? '--unstable-features' : '' + + let l:cmd = printf("%s %s %s %s %s --file-lines '[%s]' %s", g:rustfmt_command, + \ l:write_mode, g:rustfmt_options, + \ l:unstable_features, l:rustfmt_config, + \ json_encode(l:arg), shellescape(a:filename)) + return l:cmd endfunction -function! s:RustfmtCommand(filename) - return g:rustfmt_command . " --write-mode=overwrite " . g:rustfmt_options . " " . shellescape(a:filename) +function! s:RustfmtCommand() + let write_mode = g:rustfmt_emit_files ? '--emit=stdout' : '--write-mode=display' + let config = s:RustfmtConfigOptions() + return join([g:rustfmt_command, write_mode, config, g:rustfmt_options]) endfunction -function! s:RunRustfmt(command, curw, tmpname) - if exists("*systemlist") - let out = systemlist(a:command) - else - let out = split(system(a:command), '\r\?\n') - endif - - if v:shell_error == 0 || v:shell_error == 3 - " remove undo point caused via BufWritePre - try | silent undojoin | catch | endtry - - " Replace current file with temp file, then reload buffer - call rename(a:tmpname, expand('%')) - silent edit! - let &syntax = &syntax - - " only clear location list if it was previously filled to prevent - " clobbering other additions - if s:got_fmt_error - let s:got_fmt_error = 0 - call setloclist(0, []) - lwindow - endif - elseif g:rustfmt_fail_silently == 0 - " otherwise get the errors and put them in the location list - let errors = [] - - for line in out - " src/lib.rs:13:5: 13:10 error: expected `,`, or `}`, found `value` - let tokens = matchlist(line, '^\(.\{-}\):\(\d\+\):\(\d\+\):\s*\(\d\+:\d\+\s*\)\?\s*error: \(.*\)') - if !empty(tokens) - call add(errors, {"filename": @%, - \"lnum": tokens[2], - \"col": tokens[3], - \"text": tokens[5]}) - endif - endfor - - if empty(errors) - % | " Couldn't detect rustfmt error format, output errors - endif - - if !empty(errors) - call setloclist(0, errors, 'r') - echohl Error | echomsg "rustfmt returned error" | echohl None - endif - - let s:got_fmt_error = 1 - lwindow - " We didn't use the temp file, so clean up - call delete(a:tmpname) - endif - - call winrestview(a:curw) +function! s:DeleteLines(start, end) abort + silent! execute a:start . ',' . a:end . 'delete _' endfunction -function! rustfmt#FormatRange(line1, line2) - let l:curw = winsaveview() - let l:tmpname = expand("%:p:h") . "/." . expand("%:p:t") . ".rustfmt" - call writefile(getline(1, '$'), l:tmpname) +function! s:RunRustfmt(command, tmpname, from_writepre) + let l:view = winsaveview() + + let l:stderr_tmpname = tempname() + call writefile([], l:stderr_tmpname) + + let l:command = a:command . ' 2> ' . l:stderr_tmpname - let command = s:RustfmtCommandRange(l:tmpname, a:line1, a:line2) + if a:tmpname ==# '' + " Rustfmt in stdin/stdout mode - call s:RunRustfmt(command, l:curw, l:tmpname) + " chdir to the directory of the file + let l:has_lcd = haslocaldir() + let l:prev_cd = getcwd() + execute 'lchdir! '.expand('%:h') + + let l:buffer = getline(1, '$') + if exists("*systemlist") + silent let out = systemlist(l:command, l:buffer) + else + silent let out = split(system(l:command, + \ join(l:buffer, "\n")), '\r\?\n') + endif + else + if exists("*systemlist") + silent let out = systemlist(l:command) + else + silent let out = split(system(l:command), '\r\?\n') + endif + endif + + let l:stderr = readfile(l:stderr_tmpname) + + call delete(l:stderr_tmpname) + + let l:open_lwindow = 0 + if v:shell_error == 0 + if a:from_writepre + " remove undo point caused via BufWritePre + try | silent undojoin | catch | endtry + endif + + if a:tmpname ==# '' + let l:content = l:out + else + " take the tmpfile's content, this is better than rename + " because it preserves file modes. + let l:content = readfile(a:tmpname) + endif + + call s:DeleteLines(len(l:content), line('$')) + call setline(1, l:content) + + " only clear location list if it was previously filled to prevent + " clobbering other additions + if s:got_fmt_error + let s:got_fmt_error = 0 + call setloclist(0, []) + let l:open_lwindow = 1 + endif + elseif g:rustfmt_fail_silently == 0 && !a:from_writepre + " otherwise get the errors and put them in the location list + let l:errors = [] + + let l:prev_line = "" + for l:line in l:stderr + " error: expected one of `;` or `as`, found `extern` + " --> src/main.rs:2:1 + let tokens = matchlist(l:line, '^\s\+-->\s\(.\{-}\):\(\d\+\):\(\d\+\)$') + if !empty(tokens) + call add(l:errors, {"filename": @%, + \"lnum": tokens[2], + \"col": tokens[3], + \"text": l:prev_line}) + endif + let l:prev_line = l:line + endfor + + if !empty(l:errors) + call setloclist(0, l:errors, 'r') + echohl Error | echomsg "rustfmt returned error" | echohl None + else + echo "rust.vim: was not able to parse rustfmt messages. Here is the raw output:" + echo "\n" + for l:line in l:stderr + echo l:line + endfor + endif + + let s:got_fmt_error = 1 + let l:open_lwindow = 1 + endif + + " Restore the current directory if needed + if a:tmpname ==# '' + if l:has_lcd + execute 'lchdir! '.l:prev_cd + else + execute 'chdir! '.l:prev_cd + endif + endif + + " Open lwindow after we have changed back to the previous directory + if l:open_lwindow == 1 + lwindow + endif + + call winrestview(l:view) +endfunction + +function! rustfmt#FormatRange(line1, line2) + let l:tmpname = tempname() + call writefile(getline(1, '$'), l:tmpname) + let command = s:RustfmtCommandRange(l:tmpname, a:line1, a:line2) + call s:RunRustfmt(command, l:tmpname, v:false) + call delete(l:tmpname) endfunction function! rustfmt#Format() - let l:curw = winsaveview() - let l:tmpname = expand("%:p:h") . "/." . expand("%:p:t") . ".rustfmt" - call writefile(getline(1, '$'), l:tmpname) + call s:RunRustfmt(s:RustfmtCommand(), '', v:false) +endfunction - let command = s:RustfmtCommand(l:tmpname) +function! rustfmt#Cmd() + " Mainly for debugging + return s:RustfmtCommand() +endfunction + +function! rustfmt#PreWrite() + if !filereadable(expand("%@")) + return + endif + if rust#GetConfigVar('rustfmt_autosave_if_config_present', 0) + if findfile('rustfmt.toml', '.;') !=# '' || findfile('.rustfmt.toml', '.;') !=# '' + let b:rustfmt_autosave = 1 + let b:_rustfmt_autosave_because_of_config = 1 + endif + else + if has_key(b:, '_rustfmt_autosave_because_of_config') + unlet b:_rustfmt_autosave_because_of_config + unlet b:rustfmt_autosave + endif + endif + + if !rust#GetConfigVar("rustfmt_autosave", 0) + return + endif - call s:RunRustfmt(command, l:curw, l:tmpname) + call s:RunRustfmt(s:RustfmtCommand(), '', v:true) endfunction + + +" vim: set et sw=4 sts=4 ts=8: -- cgit From 9de5cb0b32f60bb0060335b1e0f4e4dd1c6cbf73 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 17 Sep 2023 19:20:16 +0200 Subject: vim-patch:d8b86c937a41 runtime(netrw): fix filetype detection for remote editing files closes: vim/vim#12990 closes: vim/vim#12992 this partially reverses commit 71badf9 by commenting out the line that intentionally sets the filetype to an empty string. https://github.com/vim/vim/commit/d8b86c937a419db69239a8bb879f0050be0f8e1d Co-authored-by: Christian Brabandt --- runtime/autoload/netrw.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim index be170d8aec..2dd5cf45bf 100644 --- a/runtime/autoload/netrw.vim +++ b/runtime/autoload/netrw.vim @@ -2951,7 +2951,7 @@ fun! s:NetrwGetFile(readcmd, tfile, method) " to process this detection correctly. " call Decho("detect filetype of local version of remote file<".rfile.">",'~'.expand("")) " call Decho("..did_filetype()=".did_filetype()) - setl ft= +" setl ft= " call Decho("..initial filetype<".&ft."> for buf#".bufnr()."<".bufname().">") let iskkeep= &isk setl isk-=/ -- cgit From 7bd6bd1ef7214942e94c9238e08619adf41f5995 Mon Sep 17 00:00:00 2001 From: Jongwook Choi Date: Sat, 23 Sep 2023 05:49:34 -0400 Subject: fix(provider): cannot detect python3.12 #25316 PROBLEM: The builtin python3 provider cannot auto-detect python3.12 when g:python3_host_prog is not set. As a result, when python3 on $PATH is currently python 3.12, neovim will fail to load python3 provider and result in `has("python3") == 0`, e.g., "Failed to load python3 host. You can try to see what happened by ..." ROOT CAUSE: the `system()` call from `provider#pythonx#DetectByModule` does not ignore python warnings, and `pkgutil.get_loader` will print a warning message in the very first line: ``` :1: DeprecationWarning: 'pkgutil.get_loader' is deprecated and slated for removal in Python 3.14; use importlib.util.find_spec() instead ``` SOLUTION: - Use `importlib.util.find_spec` instead (python >= 3.4) - Use `-W ignore` option to prevent any potential warning messages --- runtime/autoload/provider/pythonx.vim | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/provider/pythonx.vim b/runtime/autoload/provider/pythonx.vim index 6211b457d6..db6acf4526 100644 --- a/runtime/autoload/provider/pythonx.vim +++ b/runtime/autoload/provider/pythonx.vim @@ -26,7 +26,7 @@ endfunction function! s:get_python_candidates(major_version) abort return { - \ 3: ['python3', 'python3.10', 'python3.9', 'python3.8', 'python3.7', 'python'] + \ 3: ['python3', 'python3.12', 'python3.11', 'python3.10', 'python3.9', 'python3.8', 'python3.7', 'python'] \ }[a:major_version] endfunction @@ -61,12 +61,11 @@ endfunction " Returns array: [prog_exitcode, prog_version] function! s:import_module(prog, module) abort - let prog_version = system([a:prog, '-c' , printf( - \ 'import sys; ' . + let prog_version = system([a:prog, '-W', 'ignore', '-c', printf( + \ 'import sys, importlib; ' . \ 'sys.path = [p for p in sys.path if p != ""]; ' . \ 'sys.stdout.write(str(sys.version_info[0]) + "." + str(sys.version_info[1])); ' . - \ 'import pkgutil; ' . - \ 'exit(2*int(pkgutil.get_loader("%s") is None))', + \ 'sys.exit(2 * int(importlib.util.find_spec("%s") is None))', \ a:module)]) return [v:shell_error, prog_version] endfunction -- cgit From 61ecb3e16c22eec9cb8eb77f76d9e8ddfc3601bc Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 24 Sep 2023 22:04:29 +0800 Subject: fix(provider/pythonx): import the correct module (#25342) --- runtime/autoload/provider/pythonx.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/provider/pythonx.vim b/runtime/autoload/provider/pythonx.vim index db6acf4526..48b96c699a 100644 --- a/runtime/autoload/provider/pythonx.vim +++ b/runtime/autoload/provider/pythonx.vim @@ -62,7 +62,7 @@ endfunction " Returns array: [prog_exitcode, prog_version] function! s:import_module(prog, module) abort let prog_version = system([a:prog, '-W', 'ignore', '-c', printf( - \ 'import sys, importlib; ' . + \ 'import sys, importlib.util; ' . \ 'sys.path = [p for p in sys.path if p != ""]; ' . \ 'sys.stdout.write(str(sys.version_info[0]) + "." + str(sys.version_info[1])); ' . \ 'sys.exit(2 * int(importlib.util.find_spec("%s") is None))', -- cgit From bc6fc0123d2f02b1f209cbec740665033fbb5892 Mon Sep 17 00:00:00 2001 From: Leonardo Mello Date: Tue, 26 Sep 2023 10:31:35 -0300 Subject: fix(tutor): Tutor steps don't work on Windows #25251 Problem: Some steps in :Tutor don't work on Windows. Solution: Add support for `{unix:...,win:...}` format and transform the Tutor contents depending on the platform. Fix https://github.com/neovim/neovim/issues/24166 --- runtime/autoload/tutor.vim | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'runtime/autoload') diff --git a/runtime/autoload/tutor.vim b/runtime/autoload/tutor.vim index 80c09488d5..701be28ccc 100644 --- a/runtime/autoload/tutor.vim +++ b/runtime/autoload/tutor.vim @@ -220,6 +220,7 @@ function! tutor#TutorCmd(tutor_name) call tutor#SetupVim() exe "edit ".l:to_open + call tutor#ApplyTransform() endfunction function! tutor#TutorCmdComplete(lead,line,pos) @@ -227,3 +228,12 @@ function! tutor#TutorCmdComplete(lead,line,pos) let l:names = uniq(sort(map(l:tutors, 'fnamemodify(v:val, ":t:r")'), 's:Sort')) return join(l:names, "\n") endfunction + +function! tutor#ApplyTransform() + if has('win32') + sil! %s/{unix:(\(.\{-}\)),win:(\(.\{-}\))}/\2/g + else + sil! %s/{unix:(\(.\{-}\)),win:(\(.\{-}\))}/\1/g + endif + normal! gg0 +endfunction -- cgit From de9348978999aa78f8351b5f55930bb109e742f7 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 26 Sep 2023 06:41:53 -0700 Subject: refactor(tutor): cleanup --- runtime/autoload/tutor.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/tutor.vim b/runtime/autoload/tutor.vim index 701be28ccc..a546f7007e 100644 --- a/runtime/autoload/tutor.vim +++ b/runtime/autoload/tutor.vim @@ -230,7 +230,7 @@ function! tutor#TutorCmdComplete(lead,line,pos) endfunction function! tutor#ApplyTransform() - if has('win32') + if has('win32') sil! %s/{unix:(\(.\{-}\)),win:(\(.\{-}\))}/\2/g else sil! %s/{unix:(\(.\{-}\)),win:(\(.\{-}\))}/\1/g -- cgit From 6851b265ba1d232cc47927ef982d10d5df7a5cf4 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 3 Oct 2023 11:24:33 +0800 Subject: fix(clipboard): don't pass --foreground to wl-copy (#25481) Fix #25466 --- runtime/autoload/provider/clipboard.vim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim index 6ba28dcbfc..05f6bdb871 100644 --- a/runtime/autoload/provider/clipboard.vim +++ b/runtime/autoload/provider/clipboard.vim @@ -93,9 +93,9 @@ function! provider#clipboard#Executable() abort let s:cache_enabled = 0 return 'pbcopy' elseif !empty($WAYLAND_DISPLAY) && executable('wl-copy') && executable('wl-paste') - let s:copy['+'] = ['wl-copy', '--foreground', '--type', 'text/plain'] + let s:copy['+'] = ['wl-copy', '--type', 'text/plain'] let s:paste['+'] = ['wl-paste', '--no-newline'] - let s:copy['*'] = ['wl-copy', '--foreground', '--primary', '--type', 'text/plain'] + let s:copy['*'] = ['wl-copy', '--primary', '--type', 'text/plain'] let s:paste['*'] = ['wl-paste', '--no-newline', '--primary'] return 'wl-copy' elseif !empty($WAYLAND_DISPLAY) && executable('waycopy') && executable('waypaste') -- cgit From 0ff13a6a5a0a4d534f4ce9619fa4ccb02f126d53 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Thu, 5 Oct 2023 08:39:23 +0200 Subject: vim-patch:4dbb2669e9ed runtime(netrw): error when trying to :bd unloaded buffer closes: vim/vim#13215 closes: vim/vim#13082 https://github.com/vim/vim/commit/4dbb2669e9ed9ec6864705dcb569715e417e1303 Co-authored-by: yasuda --- runtime/autoload/netrw.vim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim index 2dd5cf45bf..2ed3e9ca39 100644 --- a/runtime/autoload/netrw.vim +++ b/runtime/autoload/netrw.vim @@ -11934,9 +11934,9 @@ fun! s:NetrwBufRemover(bufid) " call Decho("buf#".a:bufid." has name <".bufname(a:bufid).">","~".expand("")) " call Decho("buf#".a:bufid." has winid#".bufwinid(a:bufid),"~".expand("")) - if a:bufid > 1 && !buflisted(a:bufid) && bufname(a:bufid) == "" && bufwinid(a:bufid) == -1 + if a:bufid > 1 && !buflisted(a:bufid) && bufloaded(a:bufid) && bufname(a:bufid) == "" && bufwinid(a:bufid) == -1 " call Decho("(s:NetrwBufRemover) removing buffer#".a:bufid,"~".expand("")) - exe "bd! ".a:bufid + exe "sil! bd! ".a:bufid endif " call Dret("s:NetrwBufRemover") -- cgit From ac6d8d008720f80bdbc5f44c6a75aa78c816dc52 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Fri, 6 Oct 2023 09:50:53 +0200 Subject: vim-patch:f449825ae238 runtime(netrw): Update `.netrwbook` immediately on bookmark change (vim/vim#13276) closes: vim/vim#9738 https://github.com/vim/vim/commit/f449825ae23865437a74ea4140fd32780c02ce43 Co-authored-by: KSR-Yasuda <31273423+KSR-Yasuda@users.noreply.github.com> --- runtime/autoload/netrw.vim | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'runtime/autoload') diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim index 2ed3e9ca39..22431d89e1 100644 --- a/runtime/autoload/netrw.vim +++ b/runtime/autoload/netrw.vim @@ -3469,6 +3469,11 @@ fun! s:NetrwBookHistHandler(chg,curdir) echo "bookmarked the current directory" endif + try + call s:NetrwBookHistSave() + catch + endtry + elseif a:chg == 1 " change to the bookmarked directory " call Decho("(user: <".v:count."gb>) change to the bookmarked directory",'~'.expand("")) @@ -3613,6 +3618,11 @@ fun! s:NetrwBookHistHandler(chg,curdir) " call Decho("g:netrw_bookmarklist=".string(g:netrw_bookmarklist),'~'.expand("")) endif " call Decho("resulting g:netrw_bookmarklist=".string(g:netrw_bookmarklist),'~'.expand("")) + + try + call s:NetrwBookHistSave() + catch + endtry endif call s:NetrwBookmarkMenu() call s:NetrwTgtMenu() -- cgit From a6cccd728a5b9363661c3daf79046afe4b37a5ee Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Fri, 6 Oct 2023 09:51:19 +0200 Subject: vim-patch:0e958410046a runtime(netrw): diff (`df`) may open the wrong window (vim/vim#13275) closes: vim/vim#11359 https://github.com/vim/vim/commit/0e958410046aa764ec73b14b1d2839053b31d242 Co-authored-by: KSR-Yasuda <31273423+KSR-Yasuda@users.noreply.github.com> --- runtime/autoload/netrw.vim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim index 22431d89e1..dcaa075608 100644 --- a/runtime/autoload/netrw.vim +++ b/runtime/autoload/netrw.vim @@ -7332,8 +7332,7 @@ fun! s:NetrwMarkFileDiff(islocal) exe "NetrwKeepj e ".fnameescape(fname) diffthis elseif cnt == 2 || cnt == 3 - vsplit - wincmd l + below vsplit " call Decho("diffthis: ".fname,'~'.expand("")) exe "NetrwKeepj e ".fnameescape(fname) diffthis -- cgit From 3222f0ad0079ce4bd4e45886a00e4fe4685fb5dd Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 16 Oct 2023 16:36:25 +0800 Subject: vim-patch:dbf749bd5aae (#25665) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit runtime: Fix more typos (vim/vim#13354) * Fix more typos * Fix typos in ignored runtime/ directory https://github.com/vim/vim/commit/dbf749bd5aaef6ea2d28bce081349785d174d96a Co-authored-by: Viktor Szépe --- runtime/autoload/netrw.vim | 4 ++-- runtime/autoload/phpcomplete.vim | 2 +- runtime/autoload/rustfmt.vim | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim index dcaa075608..8b29ea9dfa 100644 --- a/runtime/autoload/netrw.vim +++ b/runtime/autoload/netrw.vim @@ -1914,7 +1914,7 @@ endfun " Doing this means that netrw will not come up as having changed a " setting last when it really didn't actually change it. " -" Used by s:NetrwOptionsRestore() to restore each netrw-senstive setting +" Used by s:NetrwOptionsRestore() to restore each netrw-sensitive setting " keepvars are set up by s:NetrwOptionsSave fun! s:NetrwRestoreSetting(keepvar,setting) """ call Dfunc("s:NetrwRestoreSetting(a:keepvar<".a:keepvar."> a:setting<".a:setting.">)") @@ -5515,7 +5515,7 @@ fun! netrw#BrowseX(fname,remote) " cleanup: remove temporary file, " delete current buffer if success with handler, " return to prior buffer (directory listing) - " Feb 12, 2008: had to de-activiate removal of + " Feb 12, 2008: had to de-activate removal of " temporary file because it wasn't getting seen. " if remote == 1 && fname != a:fname "" call Decho("deleting temporary file<".fname.">",'~'.expand("")) diff --git a/runtime/autoload/phpcomplete.vim b/runtime/autoload/phpcomplete.vim index f9aa15c827..2556ac857e 100644 --- a/runtime/autoload/phpcomplete.vim +++ b/runtime/autoload/phpcomplete.vim @@ -2924,7 +2924,7 @@ endfor " builtin class information let g:php_builtin_object_functions = {} -" When completing for 'everyting imaginable' (no class context, not a +" When completing for 'everything imaginable' (no class context, not a " variable) we need a list of built-in classes in a format of {'classname':''} " for performance reasons we precompile this too let g:php_builtin_classnames = {} diff --git a/runtime/autoload/rustfmt.vim b/runtime/autoload/rustfmt.vim index 652e6af33a..8fd3858178 100644 --- a/runtime/autoload/rustfmt.vim +++ b/runtime/autoload/rustfmt.vim @@ -25,7 +25,7 @@ function! rustfmt#DetectVersion() silent let s:rustfmt_help = system(g:rustfmt_command . " --help") let s:rustfmt_unstable_features = s:rustfmt_help =~# "--unstable-features" - " Build a comparable rustfmt version varible out of its `--version` output: + " Build a comparable rustfmt version variable out of its `--version` output: silent let l:rustfmt_version_full = system(g:rustfmt_command . " --version") let l:rustfmt_version_list = matchlist(l:rustfmt_version_full, \ '\vrustfmt ([0-9]+[.][0-9]+[.][0-9]+)') -- cgit From 9455f6b17c6d1009af5d37d62884fe3042abdfa0 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Fri, 27 Oct 2023 19:20:07 +0200 Subject: vim-patch:650dcfc8d12e runtime(netrw): don't echo empty lines (vim/vim#13431) https://github.com/vim/vim/commit/650dcfc8d12e68aa05a358301ec15f9e6dbd03ba Co-authored-by: nwounkn --- runtime/autoload/netrw.vim | 3 --- 1 file changed, 3 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim index 8b29ea9dfa..e3e28b6de2 100644 --- a/runtime/autoload/netrw.vim +++ b/runtime/autoload/netrw.vim @@ -1134,7 +1134,6 @@ fun! netrw#Explore(indx,dosplit,style,...) 2match none if exists("s:explore_match") | unlet s:explore_match | endif if exists("s:explore_prvdir") | unlet s:explore_prvdir | endif - echo " " " call Decho("cleared explore match list",'~'.expand("")) endif @@ -5688,8 +5687,6 @@ fun! s:NetrwClearExplore() if exists("w:netrw_explore_list") |unlet w:netrw_explore_list |endif if exists("w:netrw_explore_bufnr") |unlet w:netrw_explore_bufnr |endif " redraw! - echo " " - echo " " " call Dret("s:NetrwClearExplore") endfun -- cgit From 26cdff0e92bf93a2afcb4a78e056780ea3f582e7 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 4 Nov 2023 11:37:42 +0100 Subject: vim-patch:cd8a3eaf5348 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit runtime(dist): centralize safe executable check and add vim library (vim/vim#13413) Follow up to 816fbcc26 (patch 9.0.1833: [security] runtime file fixes, 2023-08-31) and f7ac0ef50 (runtime: don't execute external commands when loading ftplugins, 2023-09-06). This puts the logic for safe executable checks in a single place, by introducing a central vim library, so all filetypes benefit from consistency. Notable changes: - dist#vim because the (autoload) namespace for a new runtime support library. Supporting functions should get documentation. It might make life easier for NeoVim devs to make the documentation a new file rather than cram it into existing files, though we may want cross-references to it somewhere… - The gzip and zip plugins need to be opted into by enabling execution of those programs (or the global plugin_exec). This needs documentation or discussion. - This fixes a bug in the zig plugin: code setting s:tmp_cwd was removed in f7ac0ef50 (runtime: don't execute external commands when loading ftplugins, 2023-09-06), but the variable was still referenced. Since the new function takes care of that automatically, the variable is no longer needed. https://github.com/vim/vim/commit/cd8a3eaf5348feacfecab4b374b7ea4ce6a97422 Co-authored-by: D. Ben Knoble --- runtime/autoload/dist/vim.vim | 17 +++++++++++++++++ runtime/autoload/gzip.vim | 5 +---- runtime/autoload/zip.vim | 6 +----- 3 files changed, 19 insertions(+), 9 deletions(-) create mode 100644 runtime/autoload/dist/vim.vim (limited to 'runtime/autoload') diff --git a/runtime/autoload/dist/vim.vim b/runtime/autoload/dist/vim.vim new file mode 100644 index 0000000000..57b757f021 --- /dev/null +++ b/runtime/autoload/dist/vim.vim @@ -0,0 +1,17 @@ +vim9script + +# Vim runtime support library +# +# Maintainer: The Vim Project +# Last Change: 2023 Oct 25 + +export def IsSafeExecutable(filetype: string, executable: string): bool + var cwd = getcwd() + return get(g:, filetype .. '_exec', get(g:, 'plugin_exec', 0)) + && (fnamemodify(exepath(executable), ':p:h') !=# cwd + || (split($PATH, has('win32') ? ';' : ':')->index(cwd) != -1 + && cwd != '.')) +enddef + +# Uncomment this line to check for compilation errors early +# defcompile diff --git a/runtime/autoload/gzip.vim b/runtime/autoload/gzip.vim index 6d0bb13401..26b1cda034 100644 --- a/runtime/autoload/gzip.vim +++ b/runtime/autoload/gzip.vim @@ -11,10 +11,7 @@ fun s:check(cmd) let name = substitute(a:cmd, '\(\S*\).*', '\1', '') if !exists("s:have_" . name) " safety check, don't execute anything from the current directory - let s:tmp_cwd = getcwd() - let f = (fnamemodify(exepath(name), ":p:h") !=# s:tmp_cwd - \ || (index(split($PATH,has("win32")? ';' : ':'), s:tmp_cwd) != -1 && s:tmp_cwd != '.')) - unlet s:tmp_cwd + let f = dist#vim#IsSafeExecutable('gzip', name) if !f echoerr "Warning: NOT executing " .. name .. " from current directory!" endif diff --git a/runtime/autoload/zip.vim b/runtime/autoload/zip.vim index 8b39c91c3a..e61293c357 100644 --- a/runtime/autoload/zip.vim +++ b/runtime/autoload/zip.vim @@ -57,14 +57,10 @@ if !exists("g:zip_extractcmd") let g:zip_extractcmd= g:zip_unzipcmd endif -let s:tmp_cwd = getcwd() -if (fnamemodify(exepath(g:zip_unzipcmd), ":p:h") ==# getcwd() - \ && (index(split($PATH,has("win32")? ';' : ':'), s:tmp_cwd) == -1 || s:tmp_cwd == '.')) - unlet s:tmp_cwd +if !dist#vim#IsSafeExecutable('zip', g:zip_unzipcmd) echoerr "Warning: NOT executing " .. g:zip_unzipcmd .. " from current directory!" finish endif -unlet s:tmp_cwd " ---------------- " Functions: {{{1 -- cgit From 2a47dbe2282c656c63a29005f35399db740ab958 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 4 Nov 2023 11:38:08 +0100 Subject: vim-patch:4f174f0de90b runtime(dist): add legacy version for central vim library Also, enable the zip and gzip plugins by default, unless those variables were not explicitly set by the user. related: vim/vim#13413 https://github.com/vim/vim/commit/4f174f0de90b52937ddaf1e6db98e9731930ff7c Co-authored-by: Christian Brabandt --- runtime/autoload/dist/vim.vim | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/dist/vim.vim b/runtime/autoload/dist/vim.vim index 57b757f021..d5a8984dc6 100644 --- a/runtime/autoload/dist/vim.vim +++ b/runtime/autoload/dist/vim.vim @@ -1,17 +1,30 @@ -vim9script +" Vim runtime support library, +" runs the vim9 script version or legacy script version +" on demand (mostly for Neovim compatability) +" +" Maintainer: The Vim Project +" Last Change: 2023 Nov 04 -# Vim runtime support library -# -# Maintainer: The Vim Project -# Last Change: 2023 Oct 25 -export def IsSafeExecutable(filetype: string, executable: string): bool - var cwd = getcwd() - return get(g:, filetype .. '_exec', get(g:, 'plugin_exec', 0)) - && (fnamemodify(exepath(executable), ':p:h') !=# cwd - || (split($PATH, has('win32') ? ';' : ':')->index(cwd) != -1 - && cwd != '.')) -enddef +" enable the zip and gzip plugin by default, if not set +if !exists('g:zip_exec') + let g:zip_exec = 1 +endif -# Uncomment this line to check for compilation errors early -# defcompile +if !exists('g:gzip_exec') + let g:gzip_exec = 1 +endif + +if !exists(":def") + function dist#vim#IsSafeExecutable(filetype, executable) + let cwd = getcwd() + return get(g:, a:filetype .. '_exec', get(g:, 'plugin_exec', 0)) && + \ (fnamemodify(exepath(a:executable), ':p:h') !=# cwd + \ || (split($PATH, has('win32') ? ';' : ':')->index(cwd) != -1 && + \ cwd != '.')) + endfunction +else + def dist#vim#IsSafeExecutable(filetype: string, executable: string): bool + return dist#vim9#IsSafeExecutable(filetype, executable) + enddef +endif -- cgit From dcf5999fcd706c4319fb9c12bf9b46f2dd2b51b2 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 5 Nov 2023 11:32:43 +0100 Subject: vim-patch:b2a4c110a5d1 runtime(dist): Make dist/vim.vim work properly when lacking vim9script support (vim/vim#13487) `:return` cannot be used outside of `:function` (or `:def`) in older Vims lacking Vim9script support or in Neovim, even when evaluation is being skipped in the dead `:else` branch. Instead, use the pattern described in `:h vim9-mix`, which uses `:finish` to end script processing before it reaches the vim9script stuff. https://github.com/vim/vim/commit/b2a4c110a5d13bc794f4eddb2e88a4e8fe9dfbea Co-authored-by: Sean Dewar --- runtime/autoload/dist/vim.vim | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/dist/vim.vim b/runtime/autoload/dist/vim.vim index d5a8984dc6..021244c93b 100644 --- a/runtime/autoload/dist/vim.vim +++ b/runtime/autoload/dist/vim.vim @@ -15,16 +15,18 @@ if !exists('g:gzip_exec') let g:gzip_exec = 1 endif -if !exists(":def") - function dist#vim#IsSafeExecutable(filetype, executable) +if !has('vim9script') + function dist#vim#IsSafeExecutable(filetype, executable) let cwd = getcwd() return get(g:, a:filetype .. '_exec', get(g:, 'plugin_exec', 0)) && \ (fnamemodify(exepath(a:executable), ':p:h') !=# cwd \ || (split($PATH, has('win32') ? ';' : ':')->index(cwd) != -1 && \ cwd != '.')) - endfunction -else - def dist#vim#IsSafeExecutable(filetype: string, executable: string): bool - return dist#vim9#IsSafeExecutable(filetype, executable) - enddef + endfunction + + finish endif + +def dist#vim#IsSafeExecutable(filetype: string, executable: string): bool + return dist#vim9#IsSafeExecutable(filetype, executable) +enddef -- cgit From b329a21bd38ff4eda635c063a0c2580ad99fe0aa Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 5 Nov 2023 18:07:25 +0100 Subject: vim-patch:3d37231437fc runtime(tar): improve the error detection Do not rely on the fact, that the last line matches warning, error, inappropriate or unrecognized to determine if an error occurred. It could also be a file, contains such a keyword. So make the error detection slightly more strict and only assume an error occured, if in addition to those 4 keywords, also a space matches (this assumes the error message contains a space), which luckily on Unix not many files match by default. The whole if condition seems however slightly dubious. In case an error happened, this would probably already be caught in the previous if statement, since this checks for the return code of the tar program. There may however be tar implementations, that do not set the exit code for some kind of error (but print an error message)? But let's keep this check for now, not many people have noticed this behaviour until now, so it seems to work reasonably well anyhow. related: vim/vim#6425 fixes: vim/vim#13489 https://github.com/vim/vim/commit/3d37231437fc0f761664a7cabc8f7b927b468767 Co-authored-by: Christian Brabandt --- runtime/autoload/tar.vim | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/tar.vim b/runtime/autoload/tar.vim index d7d1d8399e..b31549a891 100644 --- a/runtime/autoload/tar.vim +++ b/runtime/autoload/tar.vim @@ -1,7 +1,7 @@ " tar.vim: Handles browsing tarfiles " AUTOLOAD PORTION -" Date: Jan 07, 2020 -" Version: 32 +" Date: Nov 05, 2023 +" Version: 32a (with modifications from the Vim Project) " Maintainer: Charles E Campbell " License: Vim License (see vim's :help license) " @@ -22,7 +22,7 @@ if &cp || exists("g:loaded_tar") finish endif -let g:loaded_tar= "v32" +let g:loaded_tar= "v32a" if v:version < 702 echohl WarningMsg echo "***warning*** this version of tar needs vim 7.2" @@ -208,7 +208,16 @@ fun! tar#Browse(tarfile) " call Dret("tar#Browse : a:tarfile<".a:tarfile.">") return endif - if line("$") == curlast || ( line("$") == (curlast + 1) && getline("$") =~# '\c\%(warning\|error\|inappropriate\|unrecognized\)') + " If there was an error message, the last line probably matches some keywords but + " should also contain whitespace for readability. Make sure not to match a + " filename that contains the keyword (error/warning/unrecognized/inappropriate, etc) + " + " FIXME:is this actually necessary? In case of an error, we should probably + " have noticed in the if statement above since tar should have exited + " with a non-zero exit code. + if line("$") == curlast || ( line("$") == (curlast + 1) && + \ getline("$") =~# '\c\<\%(warning\|error\|inappropriate\|unrecognized\)\>' && + \ getline("$") =~ '\s' ) redraw! echohl WarningMsg | echo "***warning*** (tar#Browse) ".a:tarfile." doesn't appear to be a tar file" | echohl None keepj sil! %d -- cgit From c37f7bdba5069eb989c3374c660b540e7539f874 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Tue, 14 Nov 2023 17:31:59 +0100 Subject: vim-patch:67abf1592c83 runtime(tar): comment out strange error condition check https://github.com/vim/vim/commit/67abf1592c83c910c7815478f67e0a8989d51417 Co-authored-by: Christian Brabandt --- runtime/autoload/tar.vim | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/tar.vim b/runtime/autoload/tar.vim index b31549a891..e242fe98e3 100644 --- a/runtime/autoload/tar.vim +++ b/runtime/autoload/tar.vim @@ -1,7 +1,7 @@ " tar.vim: Handles browsing tarfiles " AUTOLOAD PORTION -" Date: Nov 05, 2023 -" Version: 32a (with modifications from the Vim Project) +" Date: Nov 14, 2023 +" Version: 32b (with modifications from the Vim Project) " Maintainer: Charles E Campbell " License: Vim License (see vim's :help license) " @@ -208,27 +208,24 @@ fun! tar#Browse(tarfile) " call Dret("tar#Browse : a:tarfile<".a:tarfile.">") return endif - " If there was an error message, the last line probably matches some keywords but - " should also contain whitespace for readability. Make sure not to match a - " filename that contains the keyword (error/warning/unrecognized/inappropriate, etc) " - " FIXME:is this actually necessary? In case of an error, we should probably - " have noticed in the if statement above since tar should have exited - " with a non-zero exit code. - if line("$") == curlast || ( line("$") == (curlast + 1) && - \ getline("$") =~# '\c\<\%(warning\|error\|inappropriate\|unrecognized\)\>' && - \ getline("$") =~ '\s' ) - redraw! - echohl WarningMsg | echo "***warning*** (tar#Browse) ".a:tarfile." doesn't appear to be a tar file" | echohl None - keepj sil! %d - let eikeep= &ei - set ei=BufReadCmd,FileReadCmd - exe "r ".fnameescape(a:tarfile) - let &ei= eikeep - keepj sil! 1d -" call Dret("tar#Browse : a:tarfile<".a:tarfile.">") - return - endif + " The following should not be neccessary, since in case of errors the + " previous if statement should have caught the problem (because tar exited + " with a non-zero exit code). + " if line("$") == curlast || ( line("$") == (curlast + 1) && + " \ getline("$") =~# '\c\<\%(warning\|error\|inappropriate\|unrecognized\)\>' && + " \ getline("$") =~ '\s' ) + " redraw! + " echohl WarningMsg | echo "***warning*** (tar#Browse) ".a:tarfile." doesn't appear to be a tar file" | echohl None + " keepj sil! %d + " let eikeep= &ei + " set ei=BufReadCmd,FileReadCmd + " exe "r ".fnameescape(a:tarfile) + " let &ei= eikeep + " keepj sil! 1d + " call Dret("tar#Browse : a:tarfile<".a:tarfile.">") + " return + " endif " set up maps supported for tar setlocal noma nomod ro -- cgit From 059dc3f4a6b94cd028c5041d682982e6eed9bc87 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 22 Nov 2023 11:06:46 +0800 Subject: vim-patch:cb0c113ddc01 (#26147) runtime(netrw): expand $COMSPEC without applying 'wildignore' (vim/vim#13542) When expanding $COMSPEC and a user has set :set wildignore=*.exe netrw won't be able to properly cmd.exe, because it does not ignore the wildignore setting. So let's explicitly use expand() without applying the 'wildignore' and 'suffixes' settings to the result closes: vim/vim#13426 https://github.com/vim/vim/commit/cb0c113ddc0101b05a27c040774cb7106fc74cd4 Co-authored-by: Christian Brabandt --- runtime/autoload/netrw.vim | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim index e3e28b6de2..9dc9d28b1a 100644 --- a/runtime/autoload/netrw.vim +++ b/runtime/autoload/netrw.vim @@ -1,7 +1,9 @@ " netrw.vim: Handles file transfer and remote directory listing across " AUTOLOAD SECTION " Date: May 03, 2023 -" Version: 173 +" Version: 173a +" Last Change: +" 2023 Nov 21 by Vim Project: ignore wildignore when expanding $COMSPEC (v173a) " Maintainer: Charles E Campbell " GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim " Copyright: Copyright (C) 2016 Charles E. Campbell {{{1 @@ -398,7 +400,7 @@ if !exists("g:netrw_localcopycmd") if g:netrw_cygwin let g:netrw_localcopycmd= "cp" else - let g:netrw_localcopycmd = expand("$COMSPEC") + let g:netrw_localcopycmd = expand("$COMSPEC", v:true) let g:netrw_localcopycmdopt= " /c copy" endif elseif has("unix") || has("macunix") @@ -413,7 +415,7 @@ if !exists("g:netrw_localcopydircmd") let g:netrw_localcopydircmd = "cp" let g:netrw_localcopydircmdopt= " -R" else - let g:netrw_localcopydircmd = expand("$COMSPEC") + let g:netrw_localcopydircmd = expand("$COMSPEC", v:true) let g:netrw_localcopydircmdopt= " /c xcopy /e /c /h /i /k" endif elseif has("unix") @@ -434,7 +436,7 @@ if has("win32") || has("win95") || has("win64") || has("win16") if g:netrw_cygwin call s:NetrwInit("g:netrw_localmkdir","mkdir") else - let g:netrw_localmkdir = expand("$COMSPEC") + let g:netrw_localmkdir = expand("$COMSPEC", v:true) let g:netrw_localmkdiropt= " /c mkdir" endif else @@ -450,7 +452,7 @@ if !exists("g:netrw_localmovecmd") if g:netrw_cygwin let g:netrw_localmovecmd= "mv" else - let g:netrw_localmovecmd = expand("$COMSPEC") + let g:netrw_localmovecmd = expand("$COMSPEC", v:true) let g:netrw_localmovecmdopt= " /c move" endif elseif has("unix") || has("macunix") -- cgit From 62dc1f26632fd0c915e7521a4e13a823142ec44d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 23 Nov 2023 17:02:53 +0800 Subject: vim-patch:8750e3cf81f1 (#26163) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit runtime(netrw): Fix handling of very long filename on longlist style (vim/vim#12150) If there is a file with a very long filename (longer than g:netrw_maxfilenamelen), and if g:netrw_liststyle is set to 1, no space is inserted between the filename and the filesize and the file cannot be opened because of this. E.g.: ``` $ echo hello > 12345678901234567890123456789012 # 32 bytes: OK $ echo hello > 123456789012345678901234567890123 # 33 bytes: not OK $ echo hello > 1234567890123456789012345678901234 # 34 bytes: not OK $ echo hello > こんにちは # multibyte filename $ LC_ALL=C.UTF-8 vim . --clean --cmd "set loadplugins" --cmd "let g:netrw_liststyle=1" ``` Then, it will be shown like this: ``` " ============================================================================ " Netrw Directory Listing (netrw v171) " /cygdrive/c/work/netrw-test " Sorted by name " Sort sequence: [\/]$,\,\.h$,\.c$,\.cpp$,\~\=\*$,*,\.o$,\ " Quick Help: :help -:go up dir D:delete R:rename s:sort-by x:special " ============================================================================== ../ 0 Mon Mar 13 19:25:16 2023 ./ 0 Mon Mar 13 19:44:58 2023 12345678901234567890123456789012 6 Mon Mar 13 19:29:43 2023 12345678901234567890123456789012346 Mon Mar 13 19:32:40 2023 1234567890123456789012345678901236 Mon Mar 13 19:29:49 2023 こんにちは 6 Mon Mar 13 19:30:41 2023 ``` If the length of the filename is 32 bytes, there is a space between the filename and the filesize. However, when it is longer than 32 bytes, no space is shown. Also, you may find that the filesize of the multibyte named file is not aligned. After this patch is applied, the filelist will be shown like this: ``` " ============================================================================ " Netrw Directory Listing (netrw v171) " /cygdrive/c/work/netrw-test " Sorted by name " Sort sequence: [\/]$,\,\.h$,\.c$,\.cpp$,\~\=\*$,*,\.o$,\ " Quick Help: :help -:go up dir D:delete R:rename s:sort-by x:special " ============================================================================== ../ 0 Mon Mar 13 20:49:22 2023 ./ 0 Mon Mar 13 21:12:14 2023 1234567890123456789012345678901 10000 Mon Mar 13 20:57:55 2023 12345678901234567890123456789012 6 Mon Mar 13 19:29:43 2023 123456789012345678901234567890123 6 Mon Mar 13 19:29:49 2023 1234567890123456789012345678901234 6 Mon Mar 13 19:32:40 2023 1234567890123456789012345678901234567 10000 Mon Mar 13 21:03:23 2023 1234567890123456789012345678901234567890 10000 Mon Mar 13 21:03:36 2023 123456789012345678901234567890123456789012 10000 Mon Mar 13 21:03:59 2023 1234567890123456789012345678901234567890123 10000 Mon Mar 13 21:03:45 2023 1234567890123456789012345678901234567890123456 5 Mon Mar 13 21:08:15 2023 12345678901234567890123456789012345678901234567 10 Mon Mar 13 21:05:21 2023 こんにちは 6 Mon Mar 13 19:30:41 2023 ``` Now we have 32 + 2 + 15 = 49 characters for filename and filesize. It tries to align the filesize as much as possible. The last line that has multibyte filename is also aligned. Also fixed the issue that the file list is not shown correctly when g:netrw_sort_by is set to 'size' and g:netrw_sizestyle is set to 'h' or 'H'. https://github.com/vim/vim/commit/8750e3cf81f12132e7b4141501feba586b1ae11d Co-authored-by: K.Takata --- runtime/autoload/netrw.vim | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'runtime/autoload') diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim index 9dc9d28b1a..b8092ebeeb 100644 --- a/runtime/autoload/netrw.vim +++ b/runtime/autoload/netrw.vim @@ -4,6 +4,7 @@ " Version: 173a " Last Change: " 2023 Nov 21 by Vim Project: ignore wildignore when expanding $COMSPEC (v173a) +" 2023 Nov 22 by Vim Project: fix handling of very long filename on longlist style (v173a) " Maintainer: Charles E Campbell " GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim " Copyright: Copyright (C) 2016 Charles E. Campbell {{{1 @@ -11077,16 +11078,16 @@ fun! s:LocalListing() " call Decho("pfile <".pfile.">",'~'.expand("")) if w:netrw_liststyle == s:LONGLIST + let longfile= printf("%-".g:netrw_maxfilenamelen."S",pfile) let sz = getfsize(filename) let szlen = 15 - (strdisplaywidth(longfile) - g:netrw_maxfilenamelen) let szlen = (szlen > 0) ? szlen : 0 - let fsz = printf("%".szlen."S",sz) if g:netrw_sizestyle =~# "[hH]" let sz= s:NetrwHumanReadable(sz) endif - let longfile= printf("%-".g:netrw_maxfilenamelen."S",pfile) - let pfile = longfile." ".sz." ".strftime(g:netrw_timefmt,getftime(filename)) + let fsz = printf("%".szlen."S",sz) + let pfile = longfile." ".fsz." ".strftime(g:netrw_timefmt,getftime(filename)) " call Decho("longlist support: sz=".sz." fsz=".fsz,'~'.expand("")) endif @@ -11096,7 +11097,7 @@ fun! s:LocalListing() " call Decho("implementing g:netrw_sort_by=".g:netrw_sort_by." (time)") " call Decho("getftime(".filename.")=".getftime(filename),'~'.expand("")) let t = getftime(filename) - let ft = strpart("000000000000000000",1,18-strlen(t)).t + let ft = printf("%018d",t) " call Decho("exe NetrwKeepj put ='".ft.'/'.pfile."'",'~'.expand("")) let ftpfile= ft.'/'.pfile sil! NetrwKeepj put=ftpfile @@ -11106,10 +11107,7 @@ fun! s:LocalListing() " call Decho("implementing g:netrw_sort_by=".g:netrw_sort_by." (size)") " call Decho("getfsize(".filename.")=".getfsize(filename),'~'.expand("")) let sz = getfsize(filename) - if g:netrw_sizestyle =~# "[hH]" - let sz= s:NetrwHumanReadable(sz) - endif - let fsz = strpart("000000000000000000",1,18-strlen(sz)).sz + let fsz = printf("%018d",sz) " call Decho("exe NetrwKeepj put ='".fsz.'/'.filename."'",'~'.expand("")) let fszpfile= fsz.'/'.pfile sil! NetrwKeepj put =fszpfile -- cgit
'.bufname(buf).''..bufname(buf)..'