aboutsummaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/CMakeLists.txt4
-rw-r--r--runtime/autoload/health.vim545
-rw-r--r--runtime/autoload/health/nvim.vim62
-rw-r--r--runtime/autoload/health/provider.vim382
-rw-r--r--runtime/autoload/man.vim322
-rw-r--r--runtime/autoload/provider/pythonx.vim21
-rw-r--r--runtime/autoload/provider/ruby.vim18
-rw-r--r--runtime/autoload/remote/host.vim58
-rw-r--r--runtime/doc/api.txt33
-rw-r--r--runtime/doc/develop.txt50
-rw-r--r--runtime/doc/eval.txt124
-rw-r--r--runtime/doc/filetype.txt55
-rw-r--r--runtime/doc/help.txt1
-rw-r--r--runtime/doc/if_cscop.txt9
-rw-r--r--runtime/doc/map.txt21
-rw-r--r--runtime/doc/msgpack_rpc.txt251
-rw-r--r--runtime/doc/options.txt5
-rw-r--r--runtime/doc/pi_health.txt127
-rw-r--r--runtime/doc/provider.txt8
-rw-r--r--runtime/doc/quickfix.txt18
-rw-r--r--runtime/doc/remote_plugin.txt26
-rw-r--r--runtime/doc/starting.txt3
-rw-r--r--runtime/doc/syntax.txt4
-rw-r--r--runtime/doc/usr_12.txt20
-rw-r--r--runtime/doc/vim_diff.txt8
-rw-r--r--runtime/ftplugin/c.vim2
-rw-r--r--runtime/ftplugin/man.vim78
-rw-r--r--runtime/plugin/health.vim2
-rw-r--r--runtime/plugin/man.vim11
-rw-r--r--runtime/syntax/man.vim90
-rw-r--r--runtime/syntax/vim.vim2
31 files changed, 1566 insertions, 794 deletions
diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt
index 0dd8b07b7a..cced1a8d04 100644
--- a/runtime/CMakeLists.txt
+++ b/runtime/CMakeLists.txt
@@ -3,6 +3,7 @@ set(GENERATED_RUNTIME_DIR ${PROJECT_BINARY_DIR}/runtime)
set(GENERATED_SYN_VIM ${GENERATED_RUNTIME_DIR}/syntax/vim/generated.vim)
set(GENERATED_HELP_TAGS ${GENERATED_RUNTIME_DIR}/doc/tags)
set(GENERATED_PACKAGE_DIR ${GENERATED_RUNTIME_DIR}/pack/dist/opt)
+set(FUNCS_DATA ${PROJECT_BINARY_DIR}/funcs_data.mpack)
file(MAKE_DIRECTORY ${GENERATED_RUNTIME_DIR})
file(MAKE_DIRECTORY ${GENERATED_RUNTIME_DIR}/syntax)
@@ -10,13 +11,14 @@ file(MAKE_DIRECTORY ${GENERATED_RUNTIME_DIR}/syntax/vim)
add_custom_command(OUTPUT ${GENERATED_SYN_VIM}
COMMAND ${LUA_PRG} ${SYN_VIM_GENERATOR}
- ${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_SYN_VIM}
+ ${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_SYN_VIM} ${FUNCS_DATA}
DEPENDS
${SYN_VIM_GENERATOR}
${PROJECT_SOURCE_DIR}/src/nvim/ex_cmds.lua
${PROJECT_SOURCE_DIR}/src/nvim/auevents.lua
${PROJECT_SOURCE_DIR}/src/nvim/options.lua
${PROJECT_SOURCE_DIR}/src/nvim/eval.c
+ ${FUNCS_DATA}
)
if(POLICY CMP0054)
diff --git a/runtime/autoload/health.vim b/runtime/autoload/health.vim
index 0a698e6492..783c30cbf6 100644
--- a/runtime/autoload/health.vim
+++ b/runtime/autoload/health.vim
@@ -1,468 +1,153 @@
-function! s:trim(s) abort
- return substitute(a:s, '^\_s*\|\_s*$', '', 'g')
-endfunction
+function! s:enhance_syntax() abort
+ syntax keyword healthError ERROR
+ highlight link healthError Error
+ syntax keyword healthWarning WARNING
+ highlight link healthWarning WarningMsg
-" Simple version comparison.
-function! s:version_cmp(a, b) abort
- let a = split(a:a, '\.')
- let b = split(a:b, '\.')
+ syntax keyword healthInfo INFO
+ highlight link healthInfo ModeMsg
- for i in range(len(a))
- if a[i] > b[i]
- return 1
- elseif a[i] < b[i]
- return -1
- endif
- endfor
+ syntax keyword healthSuccess SUCCESS
+ highlight link healthSuccess Function
- return 0
+ syntax keyword healthSuggestion SUGGESTIONS
+ highlight link healthSuggestion String
endfunction
+" 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_health_checks()
+ \ : s:to_fn_names(a:plugin_names)
-" Fetch the contents of a URL.
-function! s:download(url) abort
- let content = ''
- if executable('curl')
- let content = system('curl -sL "'.a:url.'"')
- endif
-
- if empty(content) && executable('python')
- let script = "
- \try:\n
- \ from urllib.request import urlopen\n
- \except ImportError:\n
- \ from urllib2 import urlopen\n
- \\n
- \try:\n
- \ response = urlopen('".a:url."')\n
- \ print(response.read().decode('utf8'))\n
- \except Exception:\n
- \ pass\n
- \"
- let content = system('python -c "'.script.'" 2>/dev/null')
- endif
-
- return content
-endfunction
-
-
-" Get the latest Neovim Python client version from PyPI. The result is
-" cached.
-function! s:latest_pypi_version()
- if exists('s:pypi_version')
- return s:pypi_version
- endif
-
- let s:pypi_version = 'unknown'
- let pypi_info = s:download('https://pypi.python.org/pypi/neovim/json')
- if !empty(pypi_info)
- let pypi_data = json_decode(pypi_info)
- let s:pypi_version = get(get(pypi_data, 'info', {}), 'version', 'unknown')
- return s:pypi_version
- endif
-endfunction
-
+ tabnew
+ setlocal filetype=markdown bufhidden=wipe
+ call s:enhance_syntax()
-" Get version information using the specified interpreter. The interpreter is
-" used directly in case breaking changes were introduced since the last time
-" Neovim's Python client was updated.
-function! s:version_info(python) abort
- let pypi_version = s:latest_pypi_version()
- let python_version = s:trim(system(
- \ printf('"%s" -c "import sys; print(''.''.join(str(x) '
- \ . 'for x in sys.version_info[:3]))"', a:python)))
- if empty(python_version)
- let python_version = 'unknown'
- endif
-
- let nvim_path = s:trim(system(printf('"%s" -c "import sys, neovim;'
- \ . 'print(neovim.__file__)" 2>/dev/null', a:python)))
- if empty(nvim_path)
- return [python_version, 'not found', pypi_version, 'unknown']
- endif
-
- let nvim_version = 'unknown'
- let base = fnamemodify(nvim_path, ':h')
- for meta in glob(base.'-*/METADATA', 1, 1) + glob(base.'-*/PKG-INFO', 1, 1)
- for meta_line in readfile(meta)
- if meta_line =~# '^Version:'
- let nvim_version = matchstr(meta_line, '^Version: \zs\S\+')
- endif
+ if empty(healthchecks)
+ call setline(1, 'ERROR: No healthchecks found.')
+ else
+ redraw|echo 'Running healthchecks...'
+ for c in healthchecks
+ let output = ''
+ call append('$', split(printf("\n%s\n%s", c, repeat('=',80)), "\n"))
+ try
+ let output = "\n\n".execute('call '.c.'()')
+ catch
+ if v:exception =~# '^Vim\%((\a\+)\)\=:E117.*\V'.c
+ let output = execute(
+ \ 'call health#report_error(''No healthcheck found for "'
+ \ .s:to_plugin_name(c)
+ \ .'" plugin.'')')
+ else
+ let output = execute(
+ \ 'call health#report_error(''Failed to run healthcheck for "'
+ \ .s:to_plugin_name(c)
+ \ .'" plugin. Exception:''."\n".v:exception)')
+ endif
+ endtry
+ call append('$', split(output, "\n") + [''])
+ redraw
endfor
- endfor
-
- let version_status = 'unknown'
- if nvim_version != 'unknown' && pypi_version != 'unknown'
- if s:version_cmp(nvim_version, pypi_version) == -1
- let version_status = 'outdated'
- else
- let version_status = 'up to date'
- endif
endif
- return [python_version, nvim_version, pypi_version, version_status]
+ setlocal nomodified
+ redraw|echo ''
endfunction
-
-" Check the Python interpreter's usability.
-function! s:check_bin(bin, notes) abort
- if !filereadable(a:bin)
- call add(a:notes, printf('Error: "%s" was not found.', a:bin))
- return 0
- elseif executable(a:bin) != 1
- call add(a:notes, printf('Error: "%s" is not executable.', a:bin))
- return 0
- endif
- return 1
+" Starts a new report.
+function! health#report_start(name) abort
+ echo "\n## " . a:name
endfunction
-
-" Text wrapping that returns a list of lines
-function! s:textwrap(text, width) abort
- let pattern = '.*\%(\s\+\|\_$\)\zs\%<'.a:width.'c'
- return map(split(a:text, pattern), 's:trim(v:val)')
-endfunction
-
-
-" Echo wrapped notes
-function! s:echo_notes(notes) abort
- if empty(a:notes)
- return
+" 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
-
- echo ' Messages:'
- for msg in a:notes
- if msg =~# "\n"
- let msg_lines = []
- for msgl in filter(split(msg, "\n"), 'v:val !~# ''^\s*$''')
- call extend(msg_lines, s:textwrap(msgl, 74))
- endfor
- else
- let msg_lines = s:textwrap(msg, 74)
- endif
-
- if !len(msg_lines)
- continue
- endif
- echo ' *' msg_lines[0]
- if len(msg_lines) > 1
- echo join(map(msg_lines[1:], '" ".v:val'), "\n")
- endif
- endfor
-endfunction
-
-
-" Load the remote plugin manifest file and check for unregistered plugins
-function! s:diagnose_manifest() abort
- echo 'Checking: Remote Plugins'
- let existing_rplugins = {}
-
- for item in remote#host#PluginsForHost('python')
- let existing_rplugins[item.path] = 'python'
- endfor
-
- for item in remote#host#PluginsForHost('python3')
- let existing_rplugins[item.path] = 'python3'
- endfor
-
- let require_update = 0
- let notes = []
-
- for path in map(split(&rtp, ','), 'resolve(v:val)')
- let python_glob = glob(path.'/rplugin/python*', 1, 1)
- if empty(python_glob)
- continue
- endif
-
- let python_dir = python_glob[0]
- let python_version = fnamemodify(python_dir, ':t')
-
- for script in glob(python_dir.'/*.py', 1, 1)
- \ + glob(python_dir.'/*/__init__.py', 1, 1)
- let contents = join(readfile(script))
- if contents =~# '\<\%(from\|import\)\s\+neovim\>'
- if script =~# '/__init__\.py$'
- let script = fnamemodify(script, ':h')
- endif
-
- if !has_key(existing_rplugins, script)
- let msg = printf('"%s" is not registered.', fnamemodify(path, ':t'))
- if python_version == 'pythonx'
- if !has('python2') && !has('python3')
- let msg .= ' (python2 and python3 not available)'
- endif
- elseif !has(python_version)
- let msg .= printf(' (%s not available)', python_version)
- else
- let require_update = 1
- endif
-
- call add(notes, msg)
- endif
-
- break
- endif
- endfor
+ 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
-
- echo ' Status: '
- if require_update
- echon 'Out of date'
- call add(notes, 'Run :UpdateRemotePlugins')
- else
- echon 'Up to date'
- endif
-
- call s:echo_notes(notes)
+ return join(lines, "\n")
endfunction
+" Format a message for a specific report item
+function! s:format_report_message(status, msg, ...) abort " {{{
+ let output = ' - ' . a:status . ': ' . s:indent_after_line1(a:msg, 4)
+ let suggestions = []
-function! s:diagnose_python(version) abort
- let python_bin_name = 'python'.(a:version == 2 ? '' : '3')
- let pyenv = resolve(exepath('pyenv'))
- let pyenv_root = exists('$PYENV_ROOT') ? resolve($PYENV_ROOT) : ''
- let venv = exists('$VIRTUAL_ENV') ? resolve($VIRTUAL_ENV) : ''
- let host_prog_var = python_bin_name.'_host_prog'
- let host_skip_var = python_bin_name.'_host_skip_check'
- let python_bin = ''
- let python_multiple = []
- let notes = []
-
- if exists('g:'.host_prog_var)
- call add(notes, printf('Using: g:%s = "%s"', host_prog_var, get(g:, host_prog_var)))
- endif
-
- let [python_bin_name, pythonx_errs] = provider#pythonx#Detect(a:version)
- if empty(python_bin_name)
- call add(notes, 'Warning: No Python interpreter was found with the neovim '
- \ . 'module. Using the first available for diagnostics.')
- if !empty(pythonx_errs)
- call add(notes, pythonx_errs)
- endif
- let old_skip = get(g:, host_skip_var, 0)
- let g:[host_skip_var] = 1
- let [python_bin_name, pythonx_errs] = provider#pythonx#Detect(a:version)
- let g:[host_skip_var] = old_skip
- endif
-
- if !empty(python_bin_name)
- if exists('g:'.host_prog_var)
- let python_bin = exepath(python_bin_name)
+ " Optional parameters
+ if a:0 > 0
+ let suggestions = type(a:1) == type("") ? [a:1] : a:1
+ if type(suggestions) != type([])
+ echoerr "Expected String or List"
endif
- let python_bin_name = fnamemodify(python_bin_name, ':t')
endif
- if !empty(pythonx_errs)
- call add(notes, pythonx_errs)
+ " Report each suggestion
+ if len(suggestions) > 0
+ let output .= "\n - SUGGESTIONS:"
endif
+ for suggestion in suggestions
+ let output .= "\n - " . s:indent_after_line1(suggestion, 10)
+ endfor
- if !empty(python_bin_name) && empty(python_bin) && empty(pythonx_errs)
- if !exists('g:'.host_prog_var)
- call add(notes, printf('Warning: "g:%s" is not set. Searching for '
- \ . '%s in the environment.', host_prog_var, python_bin_name))
- endif
-
- if !empty(pyenv)
- if empty(pyenv_root)
- call add(notes, 'Warning: pyenv was found, but $PYENV_ROOT '
- \ . 'is not set. Did you follow the final install '
- \ . 'instructions?')
- else
- call add(notes, printf('Notice: pyenv found: "%s"', pyenv))
- endif
-
- let python_bin = s:trim(system(
- \ printf('"%s" which %s 2>/dev/null', pyenv, python_bin_name)))
-
- if empty(python_bin)
- call add(notes, printf('Warning: pyenv couldn''t find %s.', python_bin_name))
- endif
- endif
-
- if empty(python_bin)
- let python_bin = exepath(python_bin_name)
-
- if exists('$PATH')
- for path in split($PATH, ':')
- let path_bin = path.'/'.python_bin_name
- if path_bin != python_bin && 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 add(notes, printf('Suggestion: There are multiple %s executables found. '
- \ . 'Set "g:%s" to avoid surprises.', python_bin_name, host_prog_var))
- endif
-
- if python_bin =~# '\<shims\>'
- call add(notes, printf('Warning: "%s" appears to be a pyenv shim. '
- \ . 'This could mean that a) the "pyenv" executable is not in '
- \ . '$PATH, b) your pyenv installation is broken. '
- \ . 'You should set "g:%s" to avoid surprises.',
- \ python_bin, host_prog_var))
- endif
- endif
- endif
- endif
-
- if !empty(python_bin)
- if !empty(pyenv) && !exists('g:'.host_prog_var) && !empty(pyenv_root)
- \ && resolve(python_bin) !~# '^'.pyenv_root.'/'
- call add(notes, printf('Suggestion: Create a virtualenv specifically '
- \ . 'for Neovim using pyenv and use "g:%s". This will avoid '
- \ . 'the need to install Neovim''s Python client in each '
- \ . 'version/virtualenv.', host_prog_var))
- endif
-
- if !empty(venv) && exists('g:'.host_prog_var)
- if !empty(pyenv_root)
- let venv_root = pyenv_root
- else
- let venv_root = fnamemodify(venv, ':h')
- endif
-
- if resolve(python_bin) !~# '^'.venv_root.'/'
- call add(notes, printf('Suggestion: Create a virtualenv specifically '
- \ . 'for Neovim and use "g:%s". This will avoid '
- \ . 'the need to install Neovim''s Python client in each '
- \ . 'virtualenv.', host_prog_var))
- endif
- endif
- endif
-
- if empty(python_bin) && !empty(python_bin_name)
- " An error message should have already printed.
- call add(notes, printf('Error: "%s" was not found.', python_bin_name))
- elseif !empty(python_bin) && !s:check_bin(python_bin, notes)
- let python_bin = ''
- endif
-
- " Check if $VIRTUAL_ENV is active
- let virtualenv_inactive = 0
-
- if exists('$VIRTUAL_ENV')
- if !empty(pyenv)
- let pyenv_prefix = resolve(s:trim(system(printf('"%s" prefix', pyenv))))
- if $VIRTUAL_ENV != pyenv_prefix
- let virtualenv_inactive = 1
- endif
- elseif !empty(python_bin_name) && exepath(python_bin_name) !~# '^'.$VIRTUAL_ENV.'/'
- let virtualenv_inactive = 1
- endif
- endif
-
- if virtualenv_inactive
- call add(notes, 'Warning: $VIRTUAL_ENV exists but appears to be '
- \ . 'inactive. This could lead to unexpected results. If you are '
- \ . 'using Zsh, see: http://vi.stackexchange.com/a/7654/5229')
- endif
-
- " Diagnostic output
- echo 'Checking: Python' a:version
- echo ' Executable:' (empty(python_bin) ? 'Not found' : python_bin)
- if len(python_multiple)
- for path_bin in python_multiple
- echo ' (other):' path_bin
- endfor
- endif
-
- if !empty(python_bin)
- let [pyversion, current, latest, status] = s:version_info(python_bin)
- if a:version != str2nr(pyversion)
- call add(notes, 'Warning: Got an unexpected version of Python. '
- \ . 'This could lead to confusing error messages. Please '
- \ . 'consider this before reporting bugs to plugin developers.')
- endif
- if a:version == 3 && str2float(pyversion) < 3.3
- call add(notes, 'Warning: Python 3.3+ is recommended.')
- endif
-
- echo ' Python Version:' pyversion
- echo printf(' %s-neovim Version: %s', python_bin_name, current)
+ return output
+endfunction " }}}
- if current == 'not found'
- call add(notes, 'Error: Neovim Python client is not installed.')
- endif
+" Use {msg} to report information in the current section
+function! health#report_info(msg) abort " {{{
+ echo s:format_report_message('INFO', a:msg)
+endfunction " }}}
- if latest == 'unknown'
- call add(notes, 'Warning: Unable to fetch latest Neovim Python client version.')
- endif
+" Reports a successful healthcheck.
+function! health#report_ok(msg) abort " {{{
+ echo s:format_report_message('SUCCESS', a:msg)
+endfunction " }}}
- if status == 'outdated'
- echon ' (latest: '.latest.')'
- else
- echon ' ('.status.')'
- endif
+" Reports a health warning.
+function! health#report_warn(msg, ...) abort " {{{
+ if a:0 > 0
+ echo s:format_report_message('WARNING', a:msg, a:1)
+ else
+ echo s:format_report_message('WARNING', a:msg)
endif
+endfunction " }}}
- call s:echo_notes(notes)
-endfunction
-
-
-function! s:diagnose_ruby() abort
- echo 'Checking: Ruby'
- let ruby_vers = systemlist('ruby -v')[0]
- let ruby_prog = provider#ruby#Detect()
- let notes = []
-
- if empty(ruby_prog)
- let ruby_prog = 'not found'
- let prog_vers = 'not found'
- call add(notes, 'Suggestion: Install the neovim RubyGem using ' .
- \ '`gem install neovim`.')
+" Reports a failed healthcheck.
+function! health#report_error(msg, ...) abort " {{{
+ if a:0 > 0
+ echo s:format_report_message('ERROR', a:msg, a:1)
else
- silent let prog_vers = systemlist(ruby_prog . ' --version')[0]
-
- if v:shell_error
- let prog_vers = 'outdated'
- call add(notes, 'Suggestion: Install the latest neovim RubyGem using ' .
- \ '`gem install neovim`.')
- elseif s:version_cmp(prog_vers, "0.2.0") == -1
- let prog_vers .= ' (outdated)'
- call add(notes, 'Suggestion: Install the latest neovim RubyGem using ' .
- \ '`gem install neovim`.')
- endif
+ echo s:format_report_message('ERROR', a:msg)
endif
+endfunction " }}}
- echo ' Ruby Version: ' . ruby_vers
- echo ' Host Executable: ' . ruby_prog
- echo ' Host Version: ' . prog_vers
-
- call s:echo_notes(notes)
+function! s:filepath_to_function(name) abort
+ return substitute(substitute(substitute(a:name, ".*autoload/", "", ""),
+ \ "\\.vim", "#check", ""), "/", "#", "g")
endfunction
+function! s:discover_health_checks() abort
+ let healthchecks = globpath(&runtimepath, 'autoload/health/*.vim', 1, 1)
+ let healthchecks = map(healthchecks, '<SID>filepath_to_function(v:val)')
+ return healthchecks
+endfunction
-function! health#check(bang) abort
- redir => report
- try
- silent call s:diagnose_python(2)
- silent echo ''
- silent call s:diagnose_python(3)
- silent echo ''
- silent call s:diagnose_ruby()
- silent echo ''
- silent call s:diagnose_manifest()
- silent echo ''
- finally
- redir END
- endtry
+" Translates a list of plugin names to healthcheck function names.
+function! s:to_fn_names(plugin_names) abort
+ let healthchecks = []
+ for p in a:plugin_names
+ call add(healthchecks, 'health#'.p.'#check')
+ endfor
+ return healthchecks
+endfunction
- if a:bang
- new
- setlocal bufhidden=wipe
- call setline(1, split(report, "\n"))
- setlocal nomodified
- else
- echo report
- echo "\nTip: Use "
- echohl Identifier
- echon ":CheckHealth!"
- echohl None
- echon " to open this in a new buffer."
- endif
+" Extracts 'foo' from 'health#foo#check'.
+function! s:to_plugin_name(fn_name) abort
+ return substitute(a:fn_name,
+ \ '\v.*health\#(.+)\#check.*', '\1', '')
endfunction
diff --git a/runtime/autoload/health/nvim.vim b/runtime/autoload/health/nvim.vim
new file mode 100644
index 0000000000..d769525373
--- /dev/null
+++ b/runtime/autoload/health/nvim.vim
@@ -0,0 +1,62 @@
+" Load the remote plugin manifest file and check for unregistered plugins
+function! s:check_manifest() abort
+ call health#report_start('Remote Plugins')
+ let existing_rplugins = {}
+
+ for item in remote#host#PluginsForHost('python')
+ let existing_rplugins[item.path] = 'python'
+ endfor
+
+ for item in remote#host#PluginsForHost('python3')
+ let existing_rplugins[item.path] = 'python3'
+ endfor
+
+ let require_update = 0
+
+ for path in map(split(&runtimepath, ','), 'resolve(v:val)')
+ let python_glob = glob(path.'/rplugin/python*', 1, 1)
+ if empty(python_glob)
+ continue
+ endif
+
+ let python_dir = python_glob[0]
+ let python_version = fnamemodify(python_dir, ':t')
+
+ for script in glob(python_dir.'/*.py', 1, 1)
+ \ + glob(python_dir.'/*/__init__.py', 1, 1)
+ let contents = join(readfile(script))
+ if contents =~# '\<\%(from\|import\)\s\+neovim\>'
+ if script =~# '/__init__\.py$'
+ let script = fnamemodify(script, ':h')
+ endif
+
+ if !has_key(existing_rplugins, script)
+ let msg = printf('"%s" is not registered.', fnamemodify(path, ':t'))
+ if python_version ==# 'pythonx'
+ if !has('python2') && !has('python3')
+ let msg .= ' (python2 and python3 not available)'
+ endif
+ elseif !has(python_version)
+ let msg .= printf(' (%s not available)', python_version)
+ else
+ let require_update = 1
+ endif
+
+ call health#report_warn(msg)
+ endif
+
+ break
+ endif
+ endfor
+ endfor
+
+ if require_update
+ call health#report_warn('Out of date', ['Run `:UpdateRemotePlugins`'])
+ else
+ call health#report_ok('Up to date')
+ endif
+endfunction
+
+function! health#nvim#check() abort
+ call s:check_manifest()
+endfunction
diff --git a/runtime/autoload/health/provider.vim b/runtime/autoload/health/provider.vim
new file mode 100644
index 0000000000..8fa281e7e3
--- /dev/null
+++ b/runtime/autoload/health/provider.vim
@@ -0,0 +1,382 @@
+let s:bad_responses = [
+ \ 'unable to parse python response',
+ \ 'unable to parse',
+ \ 'unable to get pypi response',
+ \ 'unable to get neovim executable',
+ \ 'unable to find neovim version'
+ \ ]
+
+function! s:is_bad_response(s) abort
+ return index(s:bad_responses, a:s) >= 0
+endfunction
+
+function! s:trim(s) abort
+ return substitute(a:s, '^\_s*\|\_s*$', '', 'g')
+endfunction
+
+" Simple version comparison.
+function! s:version_cmp(a, b) abort
+ let a = split(a:a, '\.')
+ let b = split(a:b, '\.')
+
+ for i in range(len(a))
+ if a[i] > b[i]
+ return 1
+ elseif a[i] < b[i]
+ return -1
+ endif
+ endfor
+
+ return 0
+endfunction
+
+" Fetch the contents of a URL.
+function! s:download(url) abort
+ let content = ''
+ if executable('curl')
+ let content = system(['curl', '-sL', "'", a:url, "'"])
+ endif
+
+ if empty(content) && executable('python')
+ let script = "
+ \try:\n
+ \ from urllib.request import urlopen\n
+ \except ImportError:\n
+ \ from urllib2 import urlopen\n
+ \\n
+ \try:\n
+ \ response = urlopen('".a:url."')\n
+ \ print(response.read().decode('utf8'))\n
+ \except Exception:\n
+ \ pass\n
+ \"
+ let content = system(['python', '-c', "'", script, "'", '2>/dev/null'])
+ endif
+
+ return content
+endfunction
+
+
+" Get the latest Neovim Python client version from PyPI. Result is cached.
+function! s:latest_pypi_version() abort
+ if exists('s:pypi_version')
+ return s:pypi_version
+ endif
+
+ let s:pypi_version = 'unable to get pypi response'
+ let pypi_info = s:download('https://pypi.python.org/pypi/neovim/json')
+ if !empty(pypi_info)
+ let pypi_data = json_decode(pypi_info)
+ let s:pypi_version = get(get(pypi_data, 'info', {}), 'version', 'unable to parse')
+ return s:pypi_version
+ endif
+endfunction
+
+" Get version information using the specified interpreter. The interpreter is
+" used directly in case breaking changes were introduced since the last time
+" Neovim'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(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 python response'
+ endif
+
+ let nvim_path = s:trim(system([
+ \ a:python,
+ \ '-c',
+ \ 'import neovim; print(neovim.__file__)',
+ \ '2>/dev/null']))
+
+ let nvim_path = s:trim(system([
+ \ 'python3',
+ \ '-c',
+ \ 'import neovim; print(neovim.__file__)'
+ \ ]))
+ " \ '2>/dev/null']))
+
+ if empty(nvim_path)
+ return [python_version, 'unable to find neovim executable', pypi_version, 'unable to get neovim executable']
+ endif
+
+ let nvim_version = 'unable to find neovim version'
+ let base = fnamemodify(nvim_path, ':h')
+ for meta in glob(base.'-*/METADATA', 1, 1) + glob(base.'-*/PKG-INFO', 1, 1)
+ for meta_line in readfile(meta)
+ if meta_line =~# '^Version:'
+ let nvim_version = matchstr(meta_line, '^Version: \zs\S\+')
+ endif
+ endfor
+ endfor
+
+ let version_status = 'unknown'
+ if !s:is_bad_response(nvim_version) && !s:is_bad_response(pypi_version)
+ if s:version_cmp(nvim_version, pypi_version) == -1
+ let version_status = 'outdated'
+ 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)
+ 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
+
+function! s:check_python(version) abort
+ call health#report_start('Python ' . a:version . ' provider')
+
+ let python_bin_name = 'python'.(a:version == 2 ? '2' : '3')
+ let pyenv = resolve(exepath('pyenv'))
+ let pyenv_root = exists('$PYENV_ROOT') ? resolve($PYENV_ROOT) : 'n'
+ let venv = exists('$VIRTUAL_ENV') ? resolve($VIRTUAL_ENV) : ''
+ let host_prog_var = python_bin_name.'_host_prog'
+ let host_skip_var = python_bin_name.'_host_skip_check'
+ let python_bin = ''
+ let python_multiple = []
+
+ 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 [python_bin_name, pythonx_errs] = provider#pythonx#Detect(a:version)
+ if empty(python_bin_name)
+ call health#report_warn('No Python interpreter was found with the neovim '
+ \ . 'module. Using the first available for diagnostics.')
+ if !empty(pythonx_errs)
+ call health#report_warn(pythonx_errs)
+ endif
+ let old_skip = get(g:, host_skip_var, 0)
+ let g:[host_skip_var] = 1
+ let [python_bin_name, pythonx_errs] = provider#pythonx#Detect(a:version)
+ let g:[host_skip_var] = old_skip
+ endif
+
+ if !empty(python_bin_name)
+ if exists('g:'.host_prog_var)
+ let python_bin = exepath(python_bin_name)
+ endif
+ let python_bin_name = fnamemodify(python_bin_name, ':t')
+ endif
+
+ if !empty(pythonx_errs)
+ call health#report_error('Python provider error', pythonx_errs)
+ endif
+
+ if !empty(python_bin_name) && empty(python_bin) && empty(pythonx_errs)
+ 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, python_bin_name))
+ endif
+
+ if !empty(pyenv)
+ if empty(pyenv_root)
+ call health#report_warn(
+ \ 'pyenv was found, but $PYENV_ROOT is not set.',
+ \ ['Did you follow the final install instructions?']
+ \ )
+ else
+ call health#report_ok(printf('pyenv found: "%s"', pyenv))
+ endif
+
+ let python_bin = s:trim(system(
+ \ printf('"%s" which %s 2>/dev/null', pyenv, python_bin_name)))
+
+ if empty(python_bin)
+ call health#report_warn(printf('pyenv couldn''t find %s.', python_bin_name))
+ endif
+ endif
+
+ if empty(python_bin)
+ let python_bin = exepath(python_bin_name)
+
+ if exists('$PATH')
+ for path in split($PATH, ':')
+ let path_bin = path.'/'.python_bin_name
+ if path_bin != python_bin && 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('There are multiple %s executables found. '
+ \ . 'Set "g:%s" to avoid surprises.', python_bin_name, host_prog_var))
+ endif
+
+ if python_bin =~# '\<shims\>'
+ call health#report_warn(printf('"%s" appears to be a pyenv shim.', python_bin), [
+ \ 'The "pyenv" executable is not in $PATH,',
+ \ 'Your pyenv installation is broken. You should set '
+ \ . '"g:'.host_prog_var.'" to avoid surprises.',
+ \ ])
+ endif
+ endif
+ endif
+ endif
+
+ if !empty(python_bin)
+ if empty(venv) && !empty(pyenv) && !exists('g:'.host_prog_var)
+ \ && !empty(pyenv_root) && resolve(python_bin) !~# '^'.pyenv_root.'/'
+ call health#report_warn('pyenv is not set up optimally.', [
+ \ printf('Suggestion: Create a virtualenv specifically '
+ \ . 'for Neovim using pyenv and use "g:%s". This will avoid '
+ \ . 'the need to install Neovim''s Python client in each '
+ \ . 'version/virtualenv.', host_prog_var)
+ \ ])
+ elseif !empty(venv) && exists('g:'.host_prog_var)
+ if !empty(pyenv_root)
+ let venv_root = pyenv_root
+ else
+ let venv_root = fnamemodify(venv, ':h')
+ endif
+
+ if resolve(python_bin) !~# '^'.venv_root.'/'
+ call health#report_warn('Your virtualenv is not set up optimally.', [
+ \ printf('Suggestion: Create a virtualenv specifically '
+ \ . 'for Neovim and use "g:%s". This will avoid '
+ \ . 'the need to install Neovim''s Python client in each '
+ \ . 'virtualenv.', host_prog_var)
+ \ ])
+ endif
+ endif
+ endif
+
+ if empty(python_bin) && !empty(python_bin_name)
+ " An error message should have already printed.
+ call health#report_error(printf('"%s" was not found.', python_bin_name))
+ elseif !empty(python_bin) && !s:check_bin(python_bin)
+ let python_bin = ''
+ endif
+
+ " Check if $VIRTUAL_ENV is active
+ let virtualenv_inactive = 0
+
+ if exists('$VIRTUAL_ENV')
+ if !empty(pyenv)
+ let pyenv_prefix = resolve(s:trim(system([pyenv, 'prefix'])))
+ if $VIRTUAL_ENV != pyenv_prefix
+ let virtualenv_inactive = 1
+ endif
+ elseif !empty(python_bin_name) && exepath(python_bin_name) !~# '^'.$VIRTUAL_ENV.'/'
+ let virtualenv_inactive = 1
+ endif
+ endif
+
+ if virtualenv_inactive
+ let suggestions = [
+ \ 'If you are using Zsh, see: http://vi.stackexchange.com/a/7654/5229',
+ \ ]
+ call health#report_warn(
+ \ '$VIRTUAL_ENV exists but appears to be inactive. '
+ \ . 'This could lead to unexpected results.',
+ \ suggestions)
+ endif
+
+ " Diagnostic output
+ call health#report_info('Executable: ' . (empty(python_bin) ? 'Not found' : python_bin))
+ if len(python_multiple)
+ for path_bin in python_multiple
+ call health#report_info('Other python executable: ' . path_bin)
+ endfor
+ endif
+
+ if !empty(python_bin)
+ let [pyversion, current, latest, status] = s:version_info(python_bin)
+ if a:version != str2nr(pyversion)
+ call health#report_warn('Got an unexpected version of Python.' .
+ \ ' This could lead to confusing error messages.')
+ endif
+ if a:version == 3 && str2float(pyversion) < 3.3
+ call health#report_warn('Python 3.3+ is recommended.')
+ endif
+
+ call health#report_info('Python'.a:version.' version: ' . pyversion)
+ call health#report_info(printf('%s-neovim Version: %s', python_bin_name, current))
+
+ if s:is_bad_response(current)
+ let suggestions = [
+ \ 'Error found was: ' . current,
+ \ 'Use the command `$ pip' . a:version . ' install neovim`',
+ \ ]
+ call health#report_error(
+ \ 'Neovim Python client is not installed.',
+ \ suggestions)
+ endif
+
+ if s:is_bad_response(latest)
+ call health#report_warn('Unable to fetch latest Neovim Python client version.')
+ endif
+
+ if s:is_bad_response(status)
+ call health#report_warn('Latest Neovim Python client versions: ('.latest.')')
+ else
+ call health#report_ok('Latest Neovim Python client is installed: ('.status.')')
+ endif
+ endif
+
+endfunction
+
+function! s:check_ruby() abort
+ call health#report_start('Ruby provider')
+ let ruby_version = systemlist('ruby -v')[0]
+ let ruby_prog = provider#ruby#Detect()
+ let suggestions =
+ \ ['Install or upgrade the neovim RubyGem using `gem install neovim`.']
+
+ if empty(ruby_prog)
+ let ruby_prog = 'not found'
+ let prog_vers = 'not found'
+ call health#report_error('Missing Neovim RubyGem', suggestions)
+ else
+ silent let latest_gem = get(systemlist("gem list -ra '^neovim$' 2>/dev/null | " .
+ \ "awk -F'[()]' '{print $2}' | " .
+ \ 'cut -d, -f1'), 0, 'not found')
+ let latest_desc = ' (latest: ' . latest_gem . ')'
+
+ silent let prog_vers = systemlist(ruby_prog . ' --version')[0]
+ if v:shell_error
+ let prog_vers = 'not found' . latest_desc
+ call health#report_warn('Neovim RubyGem is not up-to-date.', suggestions)
+ elseif s:version_cmp(prog_vers, latest_gem) == -1
+ let prog_vers .= latest_desc
+ call health#report_warn('Neovim RubyGem is not up-to-date.', suggestions)
+ else
+ call health#report_ok('Found up-to-date neovim RubyGem')
+ endif
+ endif
+
+ call health#report_info('Ruby Version: ' . ruby_version)
+ call health#report_info('Host Executable: ' . ruby_prog)
+ call health#report_info('Host Version: ' . prog_vers)
+endfunction
+
+function! health#provider#check() abort
+ call s:check_python(2)
+ call s:check_python(3)
+ call s:check_ruby()
+endfunction
diff --git a/runtime/autoload/man.vim b/runtime/autoload/man.vim
index 0dfcc424e2..bac88fc99e 100644
--- a/runtime/autoload/man.vim
+++ b/runtime/autoload/man.vim
@@ -1,137 +1,261 @@
-let s:man_tag_depth = 0
-let s:man_sect_arg = ''
-let s:man_find_arg = '-w'
+" Maintainer: Anmol Sethi <anmol@aubble.com>
+if &shell =~# 'fish$'
+ let s:man_cmd = 'man ^/dev/null'
+else
+ let s:man_cmd = 'man 2>/dev/null'
+endif
+
+let s:man_find_arg = "-w"
+
+" TODO(nhooyr) Completion may work on SunOS; I'm not sure if `man -l` displays
+" the list of searched directories.
try
- if !has('win32') && $OSTYPE !~? 'cygwin\|linux' && system('uname -s') =~? 'SunOS' && system('uname -r') =~? '^5'
- let s:man_sect_arg = '-s'
+ if !has('win32') && $OSTYPE !~? 'cygwin\|linux' && system('uname -s') =~? 'SunOS' && system('uname -r') =~# '^5'
let s:man_find_arg = '-l'
endif
catch /E145:/
" Ignore the error in restricted mode
endtry
-" Load man page {page} from {section}
-" call man#get_page([{section}, ]{page})
-function man#get_page(...) abort
- let invoked_from_man = (&filetype ==# 'man')
-
- if a:0 == 0
- echoerr 'argument required'
+function! man#open_page(count, count1, mods, ...) abort
+ if a:0 > 2
+ call s:error('too many arguments')
return
- elseif a:0 > 2
- echoerr 'too many arguments'
+ elseif a:0 == 0
+ let ref = &filetype ==# 'man' ? expand('<cWORD>') : expand('<cword>')
+ if empty(ref)
+ call s:error('no identifier under cursor')
+ return
+ endif
+ elseif a:0 ==# 1
+ let ref = a:1
+ else
+ " Combine the name and sect into a manpage reference so that all
+ " verification/extraction can be kept in a single function.
+ " If a:2 is a reference as well, that is fine because it is the only
+ " reference that will match.
+ let ref = a:2.'('.a:1.')'
+ endif
+ try
+ let [sect, name] = man#extract_sect_and_name_ref(ref)
+ if a:count ==# a:count1
+ " v:count defaults to 0 which is a valid section, and v:count1 defaults to
+ " 1, also a valid section. If they are equal, count explicitly set.
+ let sect = string(a:count)
+ endif
+ let [sect, name, path] = s:verify_exists(sect, name)
+ catch
+ call s:error(v:exception)
return
+ endtry
+ call s:push_tag()
+ let bufname = 'man://'.name.(empty(sect)?'':'('.sect.')')
+ if a:mods !~# 'tab' && s:find_man()
+ noautocmd execute 'silent edit' bufname
+ else
+ noautocmd execute 'silent' a:mods 'split' bufname
endif
+ let b:man_sect = sect
+ call s:read_page(path)
+endfunction
- let sect = get(a:000, 0)
- let page = get(a:000, 1, sect)
+function! man#read_page(ref) abort
+ try
+ let [sect, name] = man#extract_sect_and_name_ref(a:ref)
+ let [b:man_sect, name, path] = s:verify_exists(sect, name)
+ catch
+ " call to s:error() is unnecessary
+ return
+ endtry
+ call s:read_page(path)
+endfunction
- let [page, sect] = s:parse_page_and_section(sect, page)
+function! s:read_page(path) abort
+ setlocal modifiable
+ setlocal noreadonly
+ silent keepjumps %delete _
+ " Force MANPAGER=cat to ensure Vim is not recursively invoked (by man-db).
+ " http://comments.gmane.org/gmane.editors.vim.devel/29085
+ " Respect $MANWIDTH, or default to window width.
+ let cmd = 'env MANPAGER=cat'.(empty($MANWIDTH) ? ' MANWIDTH='.winwidth(0) : '')
+ let cmd .= ' '.s:man_cmd.' '.shellescape(a:path)
+ silent put =system(cmd)
+ " remove all the backspaced text
+ execute 'silent keeppatterns keepjumps %substitute,.\b,,e'.(&gdefault?'':'g')
+ while getline(1) =~# '^\s*$'
+ silent keepjumps 1delete _
+ endwhile
+ setlocal filetype=man
+endfunction
- if !empty(sect) && s:find_page(sect, page) == 0
- let sect = ''
+" attempt to extract the name and sect out of 'name(sect)'
+" otherwise just return the largest string of valid characters in ref
+function! man#extract_sect_and_name_ref(ref) abort
+ if a:ref[0] ==# '-' " try ':Man -pandoc' with this disabled.
+ throw 'manpage name cannot start with ''-'''
endif
-
- if s:find_page(sect, page) == 0
- echo 'No manual entry for '.page
- return
+ let ref = matchstr(a:ref, '[^()]\+([^()]\+)')
+ if empty(ref)
+ let name = matchstr(a:ref, '[^()]\+')
+ if empty(name)
+ throw 'manpage reference cannot contain only parentheses'
+ endif
+ return [get(b:, 'man_default_sects', ''), name]
endif
+ let left = split(ref, '(')
+ " see ':Man 3X curses' on why tolower.
+ " TODO(nhooyr) Not sure if this is portable across OSs
+ " but I have not seen a single uppercase section.
+ return [tolower(split(left[1], ')')[0]), left[0]]
+endfunction
- exec 'let s:man_tag_buf_'.s:man_tag_depth.' = '.bufnr('%')
- exec 'let s:man_tag_lin_'.s:man_tag_depth.' = '.line('.')
- exec 'let s:man_tag_col_'.s:man_tag_depth.' = '.col('.')
- let s:man_tag_depth = s:man_tag_depth + 1
-
- let editcmd = 'edit'
- " Use an existing 'man' window, else open a new one.
- if &filetype !=# 'man'
- let thiswin = winnr()
- wincmd b
- if winnr() > 1
- exec thiswin . 'wincmd w'
- while 1
- if &filetype ==# 'man'
- break
- endif
- wincmd w
- if thiswin == winnr()
- break
- endif
- endwhile
+function! s:get_path(sect, name) abort
+ if empty(a:sect)
+ let path = system(s:man_cmd.' '.s:man_find_arg.' '.shellescape(a:name))
+ if path !~# '^\/'
+ throw 'no manual entry for '.a:name
endif
+ return path
+ endif
+ " '-s' flag handles:
+ " - tokens like 'printf(echo)'
+ " - sections starting with '-'
+ " - 3pcap section (found on macOS)
+ " - commas between sections (for section priority)
+ return system(s:man_cmd.' '.s:man_find_arg.' -s '.shellescape(a:sect).' '.shellescape(a:name))
+endfunction
- if &filetype !=# 'man'
- let editcmd = 'tabnew'
+function! s:verify_exists(sect, name) abort
+ let path = s:get_path(a:sect, a:name)
+ if path !~# '^\/'
+ let path = s:get_path(get(b:, 'man_default_sects', ''), a:name)
+ if path !~# '^\/'
+ let path = s:get_path('', a:name)
endif
endif
+ " We need to extract the section from the path because sometimes
+ " the actual section of the manpage is more specific than the section
+ " we provided to `man`. Try ':Man 3 App::CLI'.
+ " Also on linux, it seems that the name is case insensitive. So if one does
+ " ':Man PRIntf', we still want the name of the buffer to be 'printf' or
+ " whatever the correct capitilization is.
+ let path = path[:len(path)-2]
+ return s:extract_sect_and_name_path(path) + [path]
+endfunction
- silent exec editcmd.' man://'.page.(empty(sect)?'':'('.sect.')')
-
- setlocal modifiable
- silent keepjumps norm! 1G"_dG
- if empty($MANWIDTH)
- let $MANWIDTH = winwidth(0)
- endif
- silent exec 'r!/usr/bin/man '.s:cmd(sect, page).' | col -b'
- " Remove blank lines from top and bottom.
- while getline(1) =~# '^\s*$'
- silent keepjumps 1delete _
- endwhile
- while getline('$') =~# '^\s*$'
- silent keepjumps $delete _
- endwhile
- setlocal nomodified
- setlocal filetype=man
+let s:tag_stack = []
- if invoked_from_man || editcmd ==# 'tabnew'
- call s:set_window_local_options()
- endif
+function! s:push_tag() abort
+ let s:tag_stack += [{
+ \ 'buf': bufnr('%'),
+ \ 'lnum': line('.'),
+ \ 'col': col('.'),
+ \ }]
endfunction
-function s:set_window_local_options() abort
- setlocal colorcolumn=0 foldcolumn=0 nonumber
- setlocal nolist norelativenumber nofoldenable
+function! man#pop_tag() abort
+ if !empty(s:tag_stack)
+ let tag = remove(s:tag_stack, -1)
+ silent execute tag['buf'].'buffer'
+ call cursor(tag['lnum'], tag['col'])
+ endif
endfunction
-function man#pop_page() abort
- if s:man_tag_depth > 0
- let s:man_tag_depth = s:man_tag_depth - 1
- exec "let s:man_tag_buf=s:man_tag_buf_".s:man_tag_depth
- exec "let s:man_tag_lin=s:man_tag_lin_".s:man_tag_depth
- exec "let s:man_tag_col=s:man_tag_col_".s:man_tag_depth
- exec s:man_tag_buf."b"
- exec s:man_tag_lin
- exec "norm! ".s:man_tag_col."|"
- exec "unlet s:man_tag_buf_".s:man_tag_depth
- exec "unlet s:man_tag_lin_".s:man_tag_depth
- exec "unlet s:man_tag_col_".s:man_tag_depth
- unlet s:man_tag_buf s:man_tag_lin s:man_tag_col
+" extracts the name and sect out of 'path/name.sect'
+function! s:extract_sect_and_name_path(path) abort
+ let tail = fnamemodify(a:path, ':t')
+ if a:path =~# '\.\%([glx]z\|bz2\|lzma\|Z\)$' " valid extensions
+ let tail = fnamemodify(tail, ':r')
endif
+ let sect = matchstr(tail, '\.\zs[^.]\+$')
+ let name = matchstr(tail, '^.\+\ze\.')
+ return [sect, name]
endfunction
-" Expects a string like 'access' or 'access(2)'.
-function s:parse_page_and_section(sect, str) abort
- try
- let [page, sect] = matchlist(a:str, '\v\C([-.[:alnum:]_]+)%(\(([-.[:alnum:]_]+)\))?')[1:2]
- if empty(sect)
- let sect = a:sect
+function! s:find_man() abort
+ if &filetype ==# 'man'
+ return 1
+ elseif winnr('$') ==# 1
+ return 0
+ endif
+ let thiswin = winnr()
+ while 1
+ wincmd w
+ if &filetype ==# 'man'
+ return 1
+ elseif thiswin ==# winnr()
+ return 0
endif
- catch
- echoerr 'man.vim: failed to parse: "'.a:str.'"'
- endtry
+ endwhile
+endfunction
- return [page, sect]
+function! s:error(msg) abort
+ redraw
+ echohl ErrorMsg
+ echon 'man.vim: ' a:msg
+ echohl None
endfunction
-function s:cmd(sect, page) abort
- if !empty(a:sect)
- return s:man_sect_arg.' '.a:sect.' '.a:page
+let s:mandirs = join(split(system(s:man_cmd.' '.s:man_find_arg), ':\|\n'), ',')
+
+" see man#extract_sect_and_name_ref on why tolower(sect)
+function! man#complete(arg_lead, cmd_line, cursor_pos) abort
+ let args = split(a:cmd_line)
+ let l = len(args)
+ if l > 3
+ return
+ elseif l ==# 1
+ let name = ''
+ let sect = ''
+ elseif a:arg_lead =~# '^[^()]\+([^()]*$'
+ " cursor (|) is at ':Man printf(|' or ':Man 1 printf(|'
+ " The later is is allowed because of ':Man pri<TAB>'.
+ " It will offer 'priclass.d(1m)' even though section is specified as 1.
+ let tmp = split(a:arg_lead, '(')
+ let name = tmp[0]
+ let sect = tolower(get(tmp, 1, ''))
+ elseif args[1] !~# '^[^()]\+$'
+ " cursor (|) is at ':Man 3() |' or ':Man (3|' or ':Man 3() pri|'
+ " or ':Man 3() pri |'
+ return
+ elseif l ==# 2
+ if empty(a:arg_lead)
+ " cursor (|) is at ':Man 1 |'
+ let name = ''
+ let sect = tolower(args[1])
+ else
+ " cursor (|) is at ':Man pri|'
+ if a:arg_lead =~# '\/'
+ " if the name is a path, complete files
+ " TODO(nhooyr) why does this complete the last one automatically
+ return glob(a:arg_lead.'*', 0, 1)
+ endif
+ let name = a:arg_lead
+ let sect = ''
+ endif
+ elseif a:arg_lead !~# '^[^()]\+$'
+ " cursor (|) is at ':Man 3 printf |' or ':Man 3 (pr)i|'
+ return
+ else
+ " cursor (|) is at ':Man 3 pri|'
+ let name = a:arg_lead
+ let sect = tolower(args[1])
endif
- return a:page
+ " We remove duplicates incase the same manpage in different languages was found.
+ return uniq(sort(map(globpath(s:mandirs,'man?/'.name.'*.'.sect.'*', 0, 1), 's:format_candidate(v:val, sect)'), 'i'))
endfunction
-function s:find_page(sect, page) abort
- let where = system('/usr/bin/man '.s:man_find_arg.' '.s:cmd(a:sect, a:page))
- return (where =~# '^ */')
+function! s:format_candidate(path, sect) abort
+ if a:path =~# '\.\%(pdf\|in\)$' " invalid extensions
+ return
+ endif
+ let [sect, name] = s:extract_sect_and_name_path(a:path)
+ if sect ==# a:sect
+ return name
+ elseif sect =~# a:sect.'.\+$'
+ " We include the section if the user provided section is a prefix
+ " of the actual section.
+ return name.'('.sect.')'
+ endif
endfunction
diff --git a/runtime/autoload/provider/pythonx.vim b/runtime/autoload/provider/pythonx.vim
index 0ebf00112f..6d6b38978c 100644
--- a/runtime/autoload/provider/pythonx.vim
+++ b/runtime/autoload/provider/pythonx.vim
@@ -5,11 +5,24 @@ endif
let s:loaded_pythonx_provider = 1
+let s:stderr = {}
+let s:job_opts = {'rpc': v:true}
+
+" TODO(bfredl): this logic is common and should be builtin
+function! s:job_opts.on_stderr(chan_id, data, event)
+ let stderr = get(s:stderr, a:chan_id, [''])
+ let last = remove(stderr, -1)
+ let a:data[0] = last.a:data[0]
+ call extend(stderr, a:data)
+ let s:stderr[a:chan_id] = stderr
+endfunction
+
function! provider#pythonx#Require(host) abort
let ver = (a:host.orig_name ==# 'python') ? 2 : 3
" Python host arguments
- let args = ['-c', 'import sys; sys.path.remove(""); import neovim; neovim.start_host()']
+ let prog = (ver == '2' ? provider#python#Prog() : provider#python3#Prog())
+ let args = [prog, '-c', 'import sys; sys.path.remove(""); import neovim; neovim.start_host()']
" Collect registered Python plugins into args
let python_plugins = remote#host#PluginsForHost(a:host.name)
@@ -18,14 +31,16 @@ function! provider#pythonx#Require(host) abort
endfor
try
- let channel_id = rpcstart((ver ==# '2' ?
- \ provider#python#Prog() : provider#python3#Prog()), args)
+ let channel_id = jobstart(args, s:job_opts)
if rpcrequest(channel_id, 'poll') ==# 'ok'
return channel_id
endif
catch
echomsg v:throwpoint
echomsg v:exception
+ for row in get(s:stderr, channel_id, [])
+ echomsg row
+ endfor
endtry
throw remote#host#LoadErrorForHost(a:host.orig_name,
\ '$NVIM_PYTHON_LOG_FILE')
diff --git a/runtime/autoload/provider/ruby.vim b/runtime/autoload/provider/ruby.vim
index e9130b98c1..c8ede20a75 100644
--- a/runtime/autoload/provider/ruby.vim
+++ b/runtime/autoload/provider/ruby.vim
@@ -4,6 +4,17 @@ if exists('g:loaded_ruby_provider')
endif
let g:loaded_ruby_provider = 1
+let s:stderr = {}
+let s:job_opts = {'rpc': v:true}
+
+function! s:job_opts.on_stderr(chan_id, data, event)
+ let stderr = get(s:stderr, a:chan_id, [''])
+ let last = remove(stderr, -1)
+ let a:data[0] = last.a:data[0]
+ call extend(stderr, a:data)
+ let s:stderr[a:chan_id] = stderr
+endfunction
+
function! provider#ruby#Detect() abort
return exepath('neovim-ruby-host')
endfunction
@@ -13,7 +24,7 @@ function! provider#ruby#Prog()
endfunction
function! provider#ruby#Require(host) abort
- let args = []
+ let args = [provider#ruby#Prog()]
let ruby_plugins = remote#host#PluginsForHost(a:host.name)
for plugin in ruby_plugins
@@ -21,13 +32,16 @@ function! provider#ruby#Require(host) abort
endfor
try
- let channel_id = rpcstart(provider#ruby#Prog(), args)
+ let channel_id = jobstart(args, s:job_opts)
if rpcrequest(channel_id, 'poll') ==# 'ok'
return channel_id
endif
catch
echomsg v:throwpoint
echomsg v:exception
+ for row in get(s:stderr, channel_id, [])
+ echomsg row
+ endfor
endtry
throw remote#host#LoadErrorForHost(a:host.orig_name, '$NVIM_RUBY_LOG_FILE')
endfunction
diff --git a/runtime/autoload/remote/host.vim b/runtime/autoload/remote/host.vim
index eb5e87d7e1..110f80297a 100644
--- a/runtime/autoload/remote/host.vim
+++ b/runtime/autoload/remote/host.vim
@@ -118,7 +118,32 @@ function! remote#host#RegisterPlugin(host, path, specs) abort
endfunction
-function! s:GetManifest() abort
+" Get the path to the rplugin manifest file.
+function! s:GetManifestPath() abort
+ let manifest_base = ''
+
+ if exists('$NVIM_RPLUGIN_MANIFEST')
+ return fnamemodify($NVIM_RPLUGIN_MANIFEST, ':p')
+ endif
+
+ let dest = has('win32') ? '$LOCALAPPDATA' : '$XDG_DATA_HOME'
+ if !exists(dest)
+ let dest = has('win32') ? '~/AppData/Local' : '~/.local/share'
+ endif
+
+ let dest = fnamemodify(expand(dest), ':p')
+ if !empty(dest) && !filereadable(dest)
+ let dest .= ('/' ==# dest[-1:] ? '' : '/') . 'nvim'
+ call mkdir(dest, 'p', 0700)
+ let manifest_base = dest
+ endif
+
+ return manifest_base.'/rplugin.vim'
+endfunction
+
+
+" Old manifest file based on known script locations.
+function! s:GetOldManifestPath() abort
let prefix = exists('$MYVIMRC')
\ ? $MYVIMRC
\ : matchstr(get(split(execute('scriptnames'), '\n'), 0, ''), '\f\+$')
@@ -127,9 +152,25 @@ function! s:GetManifest() abort
endfunction
+function! s:GetManifest() abort
+ let manifest = s:GetManifestPath()
+
+ if !filereadable(manifest)
+ " Check if an old manifest file exists and move it to the new location.
+ let old_manifest = s:GetOldManifestPath()
+ if filereadable(old_manifest)
+ call rename(old_manifest, manifest)
+ endif
+ endif
+
+ return manifest
+endfunction
+
+
function! remote#host#LoadRemotePlugins() abort
- if filereadable(s:GetManifest())
- exe 'source '.s:GetManifest()
+ let manifest = s:GetManifest()
+ if filereadable(manifest)
+ execute 'source' fnameescape(manifest)
endif
endfunction
@@ -137,7 +178,9 @@ endfunction
function! remote#host#LoadRemotePluginsEvent(event, pattern) abort
autocmd! nvim-rplugin
call remote#host#LoadRemotePlugins()
- execute 'silent doautocmd <nomodeline>' a:event a:pattern
+ if exists('#'.a:event.'#'.a:pattern) " Avoid 'No matching autocommands'.
+ execute 'silent doautocmd <nomodeline>' a:event a:pattern
+ endif
endfunction
@@ -202,7 +245,7 @@ function! remote#host#UpdateRemotePlugins() abort
endif
endfor
call writefile(commands, s:GetManifest())
- echomsg printf('remote/host: generated the manifest file in "%s"',
+ echomsg printf('remote/host: generated rplugin manifest: %s',
\ s:GetManifest())
endfunction
@@ -220,9 +263,8 @@ function! remote#host#LoadErrorForHost(host, log) abort
\ 'You can try to see what happened '.
\ 'by starting Neovim with the environment variable '.
\ a:log . ' set to a file and opening the generated '.
- \ 'log file. Also, the host stderr will be available '.
- \ 'in Neovim log, so it may contain useful information. '.
- \ 'See also ~/.nvimlog.'
+ \ 'log file. Also, the host stderr is available '.
+ \ 'in messages.'
endfunction
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index bdeca367b1..c3d7fdb35b 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -14,13 +14,13 @@ C API for Nvim *API* *api*
==============================================================================
1. Introduction *api-intro*
-Nvim exposes a public API for external code to interact with the Nvim core. In
-the present version of Nvim the API is primarily used by external processes to
-interact with Nvim using the msgpack-rpc protocol, see |msgpack-rpc|. The API
-will also be used from vimscript to access new Nvim core features, but this is
-not implemented yet. Later on, Nvim might be embeddable in C applications as
-libnvim, and the application will then control the embedded instance by
-calling the C API directly.
+Nvim exposes a public API for external code to interact with the Nvim core.
+The API is used by external processes to interact with Nvim using the
+msgpack-rpc protocol, see |msgpack-rpc|. The API is used from vimscript to
+access some new Nvim core features. See |eval-api| for how api functions are
+called from vimscript. Later on, Nvim might be embeddable in C applications as
+libnvim, and the application will then control the embedded instance by calling
+the C API directly.
==============================================================================
2. API Types *api-types*
@@ -73,10 +73,10 @@ Another use case are plugins that show output in an append-only buffer, and
want to add highlights to the outputs. Highlight data cannot be preserved
on writing and loading a buffer to file, nor in undo/redo cycles.
-Highlights are registered using the |buffer_add_highlight| function, see the
+Highlights are registered using the |nvim_buf_add_highlight| function, see the
generated API documentation for details. If an external highlighter plugin is
adding a large number of highlights in a batch, performance can be improved by
-calling |buffer_add_highlight| as an asynchronous notification, after first
+calling |nvim_buf_add_highlight| as an asynchronous notification, after first
(synchronously) reqesting a source id. Here is an example using wrapper
functions in the python client:
>
@@ -91,10 +91,19 @@ functions in the python client:
buf.clear_highlight(src)
<
If the highlights don't need to be deleted or updated, just pass -1 as
-src_id (this is the default in python). |buffer_clear_highlight| can be used
-to clear highligts from a specific source, in a specific line range or the
-entire buffer by passing in the line range 0, -1 (the later is the default
+src_id (this is the default in python). |nvim_buf_clear_highlight| can be used
+to clear highlights from a specific source, in a specific line range or the
+entire buffer by passing in the line range 0, -1 (the latter is the default
in python as used above).
+An example of calling the api from vimscript: >
+
+ call nvim_buf_set_lines(0, 0, 0, v:true, ["test text"])
+ let src = nvim_buf_add_highlight(0, 0, "String", 1, 0, 4)
+ call nvim_buf_add_highlight(0, src, "Identifier", 0, 5, -1)
+
+ " later
+ call nvim_buf_clear_highlight(0, src, 0, -1)
+>
==============================================================================
vim:tw=78:ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt
index 6ecbf9fb0d..ddec137079 100644
--- a/runtime/doc/develop.txt
+++ b/runtime/doc/develop.txt
@@ -124,13 +124,26 @@ include the kitchen sink... but you can use it for plumbing."
==============================================================================
2. Design decisions *design-decisions*
-Jargon *dev-jargon*
+JARGON *dev-jargon*
+
+API client ~
+All external UIs and remote plugins (as opposed to regular Vim plugins) are
+"clients" in general; but we call something an "API client" if its purpose is
+to abstract or wrap the RPC API for the convenience of other applications
+(just like a REST client or SDK such as boto3 for AWS: you can speak AWS REST
+using an HTTP client like curl, but boto3 wraps that in a convenient python
+interface). For example, the Nvim lua-client is an API client:
+ https://github.com/neovim/lua-client
Host ~
A plugin "host" is both a client (of the Nvim API) and a server (of an
external platform, e.g. python). It is a remote plugin that hosts other
plugins.
+Remote plugin ~
+Arbitrary code registered via |:UpdateRemotePlugins|, that runs in a separate
+process and communicates with Nvim via the |api|.
+
Window ~
The word "window" is commonly used for several things: A window on the screen,
the xterm window, a window inside Vim to view a buffer.
@@ -145,7 +158,7 @@ window View on a buffer. There can be several windows in Vim,
together with the command line, menubar, toolbar, etc. they
fit in the shell.
-Providers *dev-provider*
+PROVIDERS *dev-provider*
A goal of Nvim is to allow extension of the editor without special knowledge
in the core. But some Vim components are too tightly coupled; in those cases
@@ -189,8 +202,35 @@ Python host isn't installed then the plugin will "think" it is running in
a Vim compiled without the |+python| feature.
-RPC API
-API client
-remote plugin
+API *dev-api*
+
+Use this pattern to name new API functions:
+ nvim_{thing}_{action}_{arbitrary-qualifiers}
+
+If the function acts on an object then {thing} is the name of that object
+(e.g. "buf" or "win"). If the function operates in a "global" context then
+{thing} is usually omitted (but consider "namespacing" your global operations
+with a {thing} that groups functions under a common concept).
+
+Use existing common {action} names if possible:
+ add append to, or insert into, a collection
+ get get a thing (or subset of things by some query)
+ set set a thing
+ del delete a thing (or group of things)
+ list get all things
+
+Use consistent names for {thing} in all API function. E.g. a buffer is called
+"buf" everywhere, not "buffer" in some places and "buf" in others.
+
+Example: `nvim_get_current_line` acts on the global editor state; the common
+{action} "get" is used but {thing} is omitted.
+
+Example: `nvim_buf_add_highlight` acts on a `Buffer` object (the first
+parameter) and uses the common {action} "add".
+
+Example: `nvim_list_bufs` operates in a global context (first parameter is
+_not_ a Buffer). The common {action} "list" indicates that it lists all
+bufs (plural) in the global context.
+
vim:tw=78:ts=8:ft=help:norl:
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index de1ced160c..d97a1400ce 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -754,13 +754,23 @@ expressions are referring to the same |List| or |Dictionary| instance. A copy
of a |List| is different from the original |List|. When using "is" without
a |List| or a |Dictionary| it is equivalent to using "equal", using "isnot"
equivalent to using "not equal". Except that a different type means the
-values are different: "4 == '4'" is true, "4 is '4'" is false and "0 is []" is
-false and not an error. "is#"/"isnot#" and "is?"/"isnot?" can be used to match
-and ignore case.
+values are different: >
+ echo 4 == '4'
+ 1
+ echo 4 is '4'
+ 0
+ echo 0 is []
+ 0
+"is#"/"isnot#" and "is?"/"isnot?" can be used to match and ignore case.
When comparing a String with a Number, the String is converted to a Number,
-and the comparison is done on Numbers. This means that "0 == 'x'" is TRUE,
-because 'x' converted to a Number is zero.
+and the comparison is done on Numbers. This means that: >
+ echo 0 == 'x'
+ 1
+because 'x' converted to a Number is zero. However: >
+ echo 0 == 'x'
+ 0
+Inside a List or Dictionary this conversion is not used.
When comparing two Strings, this is done with strcmp() or stricmp(). This
results in the mathematical difference (comparing byte values), not
@@ -1999,6 +2009,7 @@ msgpackdump({list}) List dump a list of objects to msgpack
msgpackparse({list}) List parse msgpack to a list of objects
nextnonblank({lnum}) Number line nr of non-blank line >= {lnum}
nr2char({expr}[, {utf8}]) String single char with ASCII/UTF8 value {expr}
+nvim_...({args}...) any call nvim |api| functions
or({expr}, {expr}) Number bitwise OR
pathshorten({expr}) String shorten directory names in a path
pow({x}, {y}) Float {x} to the power of {y}
@@ -2033,7 +2044,6 @@ rpcnotify({channel}, {event}[, {args}...])
Sends an |RPC| notification to {channel}
rpcrequest({channel}, {method}[, {args}...])
Sends an |RPC| request to {channel}
-rpcstart({prog}[, {argv}]) Spawns {prog} and opens an |RPC| channel
rpcstop({channel}) Closes an |RPC| {channel}
screenattr({row}, {col}) Number attribute at screen position
screenchar({row}, {col}) Number character at screen position
@@ -2138,6 +2148,11 @@ values({dict}) List values in {dict}
virtcol({expr}) Number screen column of cursor or mark
visualmode([expr]) String last visual mode used
wildmenumode() Number whether 'wildmenu' mode is active
+win_findbuf( {bufnr}) List find windows containing {bufnr}
+win_getid( [{win} [, {tab}]]) Number get window ID for {win} in {tab}
+win_gotoid( {expr}) Number go to window with ID {expr}
+win_id2tabwin( {expr}) List get tab window nr from window ID
+win_id2win( {expr}) Number get window nr from window ID
winbufnr({nr}) Number buffer number of window {nr}
wincol() Number window column of the cursor
winheight({nr}) Number height of window {nr}
@@ -2195,11 +2210,9 @@ and({expr}, {expr}) *and()*
Example: >
:let flag = and(bits, 0x80)
-
api_info() *api_info()*
Returns Dictionary of |api-metadata|.
-
append({lnum}, {expr}) *append()*
When {expr} is a |List|: Append each item of the |List| as a
text line below line {lnum} in the current buffer.
@@ -4381,8 +4394,10 @@ items({dict}) *items()*
order.
jobclose({job}[, {stream}]) {Nvim} *jobclose()*
- Close {job}'s {stream}, which can be one "stdin", "stdout" or
- "stderr". If {stream} is omitted, all streams are closed.
+ Close {job}'s {stream}, which can be one of "stdin", "stdout",
+ "stderr" or "rpc" (closes the rpc channel for a job started
+ with the "rpc" option.) If {stream} is omitted, all streams
+ are closed.
jobpid({job}) {Nvim} *jobpid()*
Return the pid (process id) of {job}.
@@ -4404,6 +4419,10 @@ jobsend({job}, {data}) {Nvim} *jobsend()*
:call jobsend(j, ["abc", "123\n456", ""])
< will send "abc<NL>123<NUL>456<NL>".
+ If the job was started with the rpc option this function
+ cannot be used, instead use |rpcnotify()| and |rpcrequest()|
+ to communicate with the job.
+
jobstart({cmd}[, {opts}]) {Nvim} *jobstart()*
Spawns {cmd} as a job. If {cmd} is a |List| it is run
directly. If {cmd} is a |String| it is processed like this: >
@@ -4419,9 +4438,14 @@ jobstart({cmd}[, {opts}]) {Nvim} *jobstart()*
on_exit : exit event handler (function name or |Funcref|)
cwd : Working directory of the job; defaults to
|current-directory|.
+ rpc : If set, |msgpack-rpc| will be used to communicate
+ with the job over stdin and stdout. "on_stdout" is
+ then ignored, but "on_stderr" can still be used.
pty : If set, the job will be connected to a new pseudo
- terminal, and the job streams are connected to
- the master file descriptor.
+ terminal, and the job streams are connected to
+ the master file descriptor. "on_stderr" is ignored
+ as all output will be received on stdout.
+
width : (pty only) Width of the terminal screen
height : (pty only) Height of the terminal screen
TERM : (pty only) $TERM environment variable
@@ -4433,10 +4457,12 @@ jobstart({cmd}[, {opts}]) {Nvim} *jobstart()*
{opts} is passed as |self| to the callback; the caller may
pass arbitrary data by setting other keys.
Returns:
- - job ID on success, used by |jobsend()| and |jobstop()|
+ - The job ID on success, which is used by |jobsend()| (or
+ |rpcnotify()| and |rpcrequest()| if "rpc" option was used)
+ and |jobstop()|
- 0 on invalid arguments or if the job table is full
- -1 if {cmd}[0] is not executable.
- See |job-control| for more information.
+ See |job-control| and |msgpack-rpc| for more information.
jobstop({job}) {Nvim} *jobstop()*
Stop a job created with |jobstart()| by sending a `SIGTERM`
@@ -5146,6 +5172,17 @@ nr2char({expr}[, {utf8}]) *nr2char()*
characters. nr2char(0) is a real NUL and terminates the
string, thus results in an empty string.
+nvim_...({...}) *nvim_...()* *eval-api*
+ Call nvim |api| functions. The type checking of arguments will
+ be stricter than for most other builtins. For instance,
+ if Integer is expected, a |Number| must be passed in, a
+ |String| will not be autoconverted.
+ Buffer numbers, as returned by |bufnr()| could be used as
+ first argument to nvim_buf_... functions. All functions
+ expecting an object (buffer, window or tabpage) can
+ also take the numerical value 0 to indicate the current
+ (focused) object.
+
or({expr}, {expr}) *or()*
Bitwise OR on the two arguments. The arguments are converted
to a number. A List, Dict or Float argument causes an error.
@@ -5444,14 +5481,20 @@ reltime([{start} [, {end}]]) *reltime()*
the item depends on the system. It can be passed to
|reltimestr()| to convert it to a string or |reltimefloat()|
to convert to a float.
- Without an argument it returns the current time.
- With one argument is returns the time passed since the time
+
+ Without an argument it returns the current "relative time", an
+ implementation-defined value meaningful only when used as an
+ argument to |reltime()|, |reltimestr()| and |reltimefloat()|.
+
+ With one argument it returns the time passed since the time
specified in the argument.
With two arguments it returns the time passed between {start}
and {end}.
The {start} and {end} arguments must be values returned by
reltime().
+ Note: |localtime()| returns the current (non-relative) time.
+
reltimefloat({time}) *reltimefloat()*
Return a Float that represents the time value of {time}.
Unit of time is seconds.
@@ -5635,19 +5678,19 @@ rpcrequest({channel}, {method}[, {args}...]) {Nvim} *rpcrequest()*
:let result = rpcrequest(rpc_chan, "func", 1, 2, 3)
rpcstart({prog}[, {argv}]) {Nvim} *rpcstart()*
- Spawns {prog} as a job (optionally passing the list {argv}),
- and opens an |RPC| channel with the spawned process's
- stdin/stdout. Returns:
- - channel id on success, which is used by |rpcrequest()|,
- |rpcnotify()| and |rpcstop()|
- - 0 on failure
- Example: >
- :let rpc_chan = rpcstart('prog', ['arg1', 'arg2'])
+ Deprecated. Replace >
+ :let id = rpcstart('prog', ['arg1', 'arg2'])
+< with >
+ :let id = jobstart(['prog', 'arg1', 'arg2'], {'rpc': v:true})
rpcstop({channel}) {Nvim} *rpcstop()*
- Closes an |RPC| {channel}, possibly created via
- |rpcstart()|. Also closes channels created by connections to
- |v:servername|.
+ Closes an |RPC| {channel}. If the channel is a job
+ started with |jobstart()| the job is killed.
+ It is better to use |jobstop()| in this case, or use
+ |jobclose|(id, "rpc") to only close the channel without
+ killing the job.
+ Closes the socket connection if the channel was opened by
+ connecting to |v:servername|.
screenattr(row, col) *screenattr()*
Like screenchar(), but return the attribute. This is a rather
@@ -7192,6 +7235,33 @@ wildmenumode() *wildmenumode()*
(Note, this needs the 'wildcharm' option set appropriately).
+win_findbuf({bufnr}) *win_findbuf()*
+ Returns a list with window IDs for windows that contain buffer
+ {bufnr}. When there is none the list is empty.
+
+win_getid([{win} [, {tab}]]) *win_getid()*
+ Get the window ID for the specified window.
+ When {win} is missing use the current window.
+ With {win} this is the window number. The top window has
+ number 1.
+ Without {tab} use the current tab, otherwise the tab with
+ number {tab}. The first tab has number one.
+ Return zero if the window cannot be found.
+
+win_gotoid({expr}) *win_gotoid()*
+ Go to window with ID {expr}. This may also change the current
+ tabpage.
+ Return 1 if successful, 0 if the window cannot be found.
+
+win_id2tabwin({expr} *win_id2tabwin()*
+ Return a list with the tab number and window number of window
+ with ID {expr}: [tabnr, winnr].
+ Return [0, 0] if the window cannot be found.
+
+win_id2win({expr}) *win_id2win()*
+ Return the window number of window with ID {expr}.
+ Return 0 if the window cannot be found in the current tabpage.
+
*winbufnr()*
winbufnr({nr}) The result is a Number, which is the number of the buffer
associated with window {nr}. When {nr} is zero, the number of
diff --git a/runtime/doc/filetype.txt b/runtime/doc/filetype.txt
index 76aa3a50ce..df6b55cfe7 100644
--- a/runtime/doc/filetype.txt
+++ b/runtime/doc/filetype.txt
@@ -500,7 +500,7 @@ Options:
avoid that a Subject line with "Vim:" in it will cause an
error message.
'textwidth' is set to 72. This is often recommended for e-mail.
-'formatoptions' is set to break text lines and to repeat the comment leader
+'formatoptions' is set to break text lines and to repeat the comment leader
in new lines, so that a leading ">" for quotes is repeated.
You can also format quoted text with |gq|.
@@ -512,37 +512,42 @@ Local mappings:
MAN *ft-man-plugin* *:Man* *man.vim*
-Displays a manual page in a nice way. Also see the user manual
-|find-manpage|.
+View manpages in Nvim. Supports highlighting, completion, locales, and
+navigation. Also see |find-manpage|.
-To start using the ":Man" command before any manual page was loaded, source
-this script from your startup vimrc file: >
+To use Nvim as a manpager: >
+ export MANPAGER="nvim -c 'set ft=man' -"
- runtime ftplugin/man.vim
-
-Options:
-'iskeyword' the '.' character is added to be able to use CTRL-] on the
- manual page name.
+man.vim will always attempt to reuse the closest man window (above/left) but
+otherwise create a split.
Commands:
-Man {name} Display the manual page for {name} in a window.
-Man {number} {name}
- Display the manual page for {name} in a section {number}.
-
-Global mapping:
-<Leader>K Displays the manual page for the word under the cursor.
+Man {name} Display the manpage for {name}.
+Man {sect} {name} Display the manpage for {name} and section {sect}.
+Man {name}({sect}) Alternate syntax which completes the section.
+Man {sect} {name}({sect}) Used during completion to show the real section of
+ when the provided section is a prefix, e.g. 1m vs 1.
+Man {path} Open the manpage specified by path. Prepend "./" if
+ page is in the current directory.
+Man Open the manpage for the <cWORD> (man buffers)
+ or <cword> (non-man buffers) under the cursor.
+
+|:Man| accepts command modifiers. For example, to use a vertical split: >
+ :vertical Man printf
Local mappings:
-CTRL-] Jump to the manual page for the word under the cursor.
-CTRL-T Jump back to the previous manual page.
-q Same as ":quit"
-
-To enable folding use this: >
- let g:ft_man_folding_enable = 1
-If you do not like the default folding, use an autocommand to add your desired
-folding style instead. For example: >
- autocmd FileType man setlocal foldmethod=indent foldenable
+K or CTRL-] Jump to the manpage for the <cWORD> under the
+ cursor. Takes a count for the section.
+CTRL-T Jump back to the location that the manpage was
+ opened from.
+q :quit if invoked as $MANPAGER, otherwise :close.
+Variables:
+*g:no_man_maps* Do not create mappings in manpage buffers.
+*g:ft_man_folding_enable* Fold manpages with foldmethod=indent foldnestmax=1.
+*b:man_default_sects* Comma-separated, ordered list of preferred sections.
+ For example in C one usually wants section 3 or 2: >
+ :let b:man_default_sections = '3,2'
PDF *ft-pdf-plugin*
diff --git a/runtime/doc/help.txt b/runtime/doc/help.txt
index fc4816a6c8..a81d32831b 100644
--- a/runtime/doc/help.txt
+++ b/runtime/doc/help.txt
@@ -154,6 +154,7 @@ GUI ~
Interfaces ~
|if_cscop.txt| using Cscope with Vim
|if_pyth.txt| Python interface
+|if_ruby.txt| Ruby interface
|debugger.txt| Interface with a debugger
|sign.txt| debugging signs
diff --git a/runtime/doc/if_cscop.txt b/runtime/doc/if_cscop.txt
index 70f8d1c6f3..99d1fe42e1 100644
--- a/runtime/doc/if_cscop.txt
+++ b/runtime/doc/if_cscop.txt
@@ -128,6 +128,7 @@ The available subcommands are:
6 or e: Find this egrep pattern
7 or f: Find this file
8 or i: Find files #including this file
+ 9 or a: Find places where this symbol is assigned a value
For all types, except 4 and 6, leading white space for {name} is
removed. For 4 and 6 there is exactly one space between {querytype}
@@ -254,13 +255,13 @@ started will have no effect!
{not available when compiled without the |+quickfix| feature}
'cscopequickfix' specifies whether to use quickfix window to show cscope
results. This is a list of comma-separated values. Each item consists of
-|cscope-find| command (s, g, d, c, t, e, f or i) and flag (+, - or 0).
+|cscope-find| command (s, g, d, c, t, e, f, i or a) and flag (+, - or 0).
'+' indicates that results must be appended to quickfix window,
'-' implies previous results clearance, '0' or command absence - don't use
quickfix. Search is performed from start until first command occurrence.
The default value is "" (don't use quickfix anyway). The following value
seems to be useful: >
- :set cscopequickfix=s-,c-,d-,i-,t-,e-
+ :set cscopequickfix=s-,c-,d-,i-,t-,e-,a-
<
*cscopetag* *cst*
If 'cscopetag' is set, the commands ":tag" and CTRL-] as well as "vim -t"
@@ -418,6 +419,7 @@ Cscope Home Page (http://cscope.sourceforge.net/): >
nmap <C-_>f :cs find f <C-R>=expand("<cfile>")<CR><CR>
nmap <C-_>i :cs find i ^<C-R>=expand("<cfile>")<CR>$<CR>
nmap <C-_>d :cs find d <C-R>=expand("<cword>")<CR><CR>
+ nmap <C-_>a :cs find a <C-R>=expand("<cword>")<CR><CR>
" Using 'CTRL-spacebar' then a search type makes the vim window
" split horizontally, with search result displayed in
@@ -431,6 +433,7 @@ Cscope Home Page (http://cscope.sourceforge.net/): >
nmap <C-Space>f :scs find f <C-R>=expand("<cfile>")<CR><CR>
nmap <C-Space>i :scs find i ^<C-R>=expand("<cfile>")<CR>$<CR>
nmap <C-Space>d :scs find d <C-R>=expand("<cword>")<CR><CR>
+ nmap <C-Space>a :scs find a <C-R>=expand("<cword>")<CR><CR>
" Hitting CTRL-space *twice* before the search type does a vertical
" split instead of a horizontal one
@@ -449,6 +452,8 @@ Cscope Home Page (http://cscope.sourceforge.net/): >
\:vert scs find i ^<C-R>=expand("<cfile>")<CR>$<CR>
nmap <C-Space><C-Space>d
\:vert scs find d <C-R>=expand("<cword>")<CR><CR>
+ nmap <C-Space><C-Space>a
+ \:vert scs find a <C-R>=expand("<cword>")<CR><CR>
==============================================================================
7. Cscope availability and information *cscope-info*
diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt
index c1eef398e2..4561020d22 100644
--- a/runtime/doc/map.txt
+++ b/runtime/doc/map.txt
@@ -1406,6 +1406,27 @@ The valid escape sequences are
<bang> (See the '-bang' attribute) Expands to a ! if the
command was executed with a ! modifier, otherwise
expands to nothing.
+ *<mods>*
+ <mods> The command modifiers, if specified. Otherwise, expands to
+ nothing. Supported modifiers are |aboveleft|, |belowright|,
+ |botright|, |browse|, |confirm|, |hide|, |keepalt|,
+ |keepjumps|, |keepmarks|, |keeppatterns|, |lockmarks|,
+ |noswapfile|, |silent|, |tab|, |topleft|, |verbose|, and
+ |vertical|.
+ Examples: >
+ command! -nargs=+ -complete=file MyEdit
+ \ for f in expand(<q-args>, 0, 1) |
+ \ exe '<mods> split ' . f |
+ \ endfor
+
+ function! SpecialEdit(files, mods)
+ for f in expand(a:files, 0, 1)
+ exe a:mods . ' split ' . f
+ endfor
+ endfunction
+ command! -nargs=+ -complete=file Sedit
+ \ call SpecialEdit(<q-args>, <q-mods>)
+<
*<reg>* *<register>*
<reg> (See the '-register' attribute) The optional register,
if specified. Otherwise, expands to nothing. <register>
diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt
index cfd9084cfc..b3fed9e756 100644
--- a/runtime/doc/msgpack_rpc.txt
+++ b/runtime/doc/msgpack_rpc.txt
@@ -11,7 +11,7 @@ RPC API for Nvim *RPC* *rpc* *msgpack-rpc*
3. Connecting |rpc-connecting|
4. Clients |rpc-api-client|
5. Types |rpc-types|
-6. Vimscript functions |rpc-vim-functions|
+6. Remote UIs |rpc-remote-ui|
==============================================================================
1. Introduction *rpc-intro*
@@ -47,7 +47,7 @@ instance.
There are three ways to obtain API metadata:
- 1. Connect to a running Nvim instance and call `vim_get_api_info` via
+ 1. Connect to a running Nvim instance and call `nvim_get_api_info` via
msgpack-rpc. This is best for clients written in dynamic languages which
can define functions at runtime.
@@ -66,12 +66,16 @@ To get a formatted dump of the API using python (requires the `pyyaml` and
==============================================================================
3. Connecting *rpc-connecting*
-There are several ways to open a msgpack-rpc stream to an Nvim server:
+There are several ways to open a msgpack-rpc channel to an Nvim instance:
1. Through stdin/stdout when `nvim` is started with `--embed`. This is how
applications can embed Nvim.
- 2. Through stdin/stdout of some other process spawned by |rpcstart()|.
+ 2. Through stdin/stdout of some other process spawned by |jobstart()|.
+ Set the "rpc" key to |v:true| in the options dict to use the job's stdin
+ and stdout as a single msgpack channel that is processed directly by
+ Nvim. Then it is not possible to process raw data to or from the
+ process's stdin and stdout. stderr can still be used, though.
3. Through the socket automatically created with each instance. The socket
location is stored in |v:servername|.
@@ -101,7 +105,7 @@ Nvim instance:
require 'msgpack/rpc/transport/unix'
nvim = MessagePack::RPC::Client.new(MessagePack::RPC::UNIXTransport.new, ENV['NVIM_LISTEN_ADDRESS'])
- result = nvim.call(:vim_command, 'echo "hello world!"')
+ result = nvim.call(:nvim_command, 'echo "hello world!"')
<
A better way is to use the Python REPL with the `neovim` package, where API
functions can be called interactively:
@@ -110,26 +114,26 @@ functions can be called interactively:
>>> nvim = attach('socket', path='[address]')
>>> nvim.command('echo "hello world!"')
<
-You can also embed an Nvim instance via |rpcstart()|
+You can also embed an Nvim instance via |jobstart()|, and communicate using
+|rpcrequest()| and |rpcnotify()|:
>
- let vim = rpcstart('nvim', ['--embed'])
- echo rpcrequest(vim, 'vim_eval', '"Hello " . "world!"')
- call rpcstop(vim)
+ let nvim = jobstart(['nvim', '--embed'], {'rpc': v:true})
+ echo rpcrequest(nvim, 'nvim_eval', '"Hello " . "world!"')
+ call jobstop(nvim)
<
==============================================================================
4. Implementing API clients *rpc-api-client* *api-client*
-All external UIs and remote plugins (as opposed to regular Vim plugins) are
-"clients" in general; but we call something an "API client" if its purpose is
-to abstract or wrap the RPC API for the convenience of other applications
-(just like a REST client or SDK such as boto3 for AWS: you can speak AWS REST
-using an HTTP client like curl, but boto3 wraps that in a convenient python
-interface). For example, the lua-client is an API client:
- https://github.com/neovim/lua-client
-
-The Python client (pip package "neovim") is the reference implementation of an
-API client. It is always up-to-date with the Nvim API, so its source code and
-test suite are an authoritative reference.
+"API clients" wrap the Nvim API to provide idiomatic "SDKs" for their
+respective platforms (see |dev-jargon|). You can build a new API client for
+your favorite platform or programming language.
+
+Existing API clients are listed here:
+ https://github.com/neovim/neovim/wiki/Related-projects#api-clients
+
+The Python client is the reference implementation for API clients. It is
+always up-to-date with the Nvim API, so its source code and test suite are
+authoritative references.
https://github.com/neovim/python-client
API client implementation guidelines ~
@@ -172,15 +176,20 @@ contains information that makes this task easier (see also |rpc-types|):
- Container types may be decorated with type/size constraints, e.g.
ArrayOf(Buffer) or ArrayOf(Integer, 2). This can be useful to generate
even more strongly-typed APIs.
- - Methods that operate on instances of Nvim special types (msgpack EXT) are
- prefixed with the type name in lower case, e.g. `buffer_get_line`
- represents the `get_line` method of a Buffer instance.
- - Global methods are prefixed with `vim`, e.g. `vim_get_buffers`.
+ - Functions that are considered to be methods that operate on instances of
+ Nvim special types (msgpack EXT) will have the `"method"` attribute set to
+ `true`. The reciever type is the type of the first argument. The method
+ names are prefixed with `nvim_` plus a shortened type name, e.g.
+ `nvim_buf_get_lines` represents the `get_lines` method of a Buffer instance.
+ - Global functions have `"method"` set to `false` and are prefixed with just
+ `nvim_`, e.g. `nvim_get_buffers`.
So for an object-oriented language, an API client contains the classes
representing Nvim special types, and the methods of each class could be
-defined by inspecting the method name prefix. There could also be a singleton
-Vim class with methods mapped to functions prefixed with `vim_`.
+defined by stripping the prefix for the type as defined in the `types` metadata
+(this will always be the first two "_"-separated parts of the function name).
+There could also be a singleton Vim class with methods where the `nvim_`
+prefix is stripped off.
==============================================================================
5. Types *rpc-types*
@@ -214,18 +223,21 @@ an integer, but not a Window or Tabpage.
The most reliable way of determining the type codes for the special Nvim types
is to inspect the `types` key of metadata dictionary returned by the
-`vim_get_api_info` method at runtime. Here's a sample JSON representation of
+`nvim_get_api_info` method at runtime. Here's a sample JSON representation of
the `types` object:
>
"types": {
"Buffer": {
- "id": 0
+ "id": 0,
+ "prefix": "nvim_buf_"
},
"Window": {
- "id": 1
+ "id": 1,
+ "prefix": "nvim_win_"
},
"Tabpage": {
- "id": 2
+ "id": 2,
+ "prefix": "nvim_tabpage_"
}
}
<
@@ -234,22 +246,169 @@ the type codes, because a client may be built against one Nvim version but
connect to another with different type codes.
==============================================================================
-6. Vimscript functions *rpc-vim-functions*
-
-RPC functions are available in Vimscript:
-
- 1. |rpcstart()|: Similarly to |jobstart()|, this will spawn a co-process
- with its standard handles connected to Nvim. The difference is that it's
- not possible to process raw data to or from the process's stdin, stdout,
- or stderr. This is because the job's stdin and stdout are used as
- a single msgpack channel that is processed directly by Nvim.
- 2. |rpcstop()|: Same as |jobstop()|, but operates on handles returned by
- |rpcstart()|.
- 3. |rpcrequest()|: Sends a msgpack-rpc request to the process.
- 4. |rpcnotify()|: Sends a msgpack-rpc notification to the process.
-
-|rpcrequest()| and |rpcnotify()| can also be used with channels connected to
-a nvim server. |v:servername|
+6. Remote UIs *rpc-remote-ui*
+
+Nvim allows Graphical user interfaces to be implemented by separate processes
+communicating with Nvim over the RPC API. Currently the ui model conists of a
+terminal-like grid with one single, monospace font size, with a few elements
+that could be drawn separately from the grid (for the momemnt only the popup
+menu)
+
+After connecting to a nvim instance (typically a spawned, embedded instance)
+use the |nvim_ui_attach|(width, height, options) API method to tell nvim that your
+program wants to draw the nvim screen on a grid with "width" times
+"height" cells. "options" should be a dictionary with the following (all
+optional) keys:
+ `rgb`: Controls what color format to use.
+ Set to true (default) to use 24-bit rgb
+ colors.
+ Set to false to use terminal color codes (at
+ most 256 different colors).
+ `popupmenu_external`: Instead of drawing the completion popupmenu on
+ the grid, Nvim will send higher-level events to
+ the ui and let it draw the popupmenu.
+ Defaults to false.
+
+Nvim will then send msgpack-rpc notifications, with the method name "redraw"
+and a single argument, an array of screen updates (described below).
+These should be processed in order. Preferably the user should only be able to
+see the screen state after all updates are processed (not any intermediate
+state after processing only a part of the array).
+
+Screen updates are arrays. The first element a string describing the kind
+of update.
+
+["resize", width, height]
+ The grid is resized to `width` and `height` cells.
+
+["clear"]
+ Clear the screen.
+
+["eol_clear"]
+ Clear from the cursor position to the end of the current line.
+
+["cursor_goto", row, col]
+ Move the cursor to position (row, col). Currently, the same cursor is
+ used to define the position for text insertion and the visible cursor.
+ However, only the last cursor position, after processing the entire
+ array in the "redraw" event, is intended to be a visible cursor
+ position.
+
+["update_fg", color]
+["update_bg", color]
+["update_sp", color]
+ Set the default foreground, background and special colors
+ respectively.
+
+["highlight_set", attrs]
+ Set the attributes that the next text put on the screen will have.
+ `attrs` is a dict with the keys below. Any absent key is reset
+ to its default value. Color defaults are set by the `update_fg` etc
+ updates. All boolean keys default to false.
+
+ `foreground`: foreground color.
+ `background`: backround color.
+ `special`: color to use for underline and undercurl, when present.
+ `reverse`: reverse video. Foreground and background colors are
+ switched.
+ `italic`: italic text.
+ `bold`: bold text.
+ `underline`: underlined text. The line has `special` color.
+ `undercurl`: undercurled text. The curl has `special` color.
+
+["put", text]
+ The (utf-8 encoded) string `text` is put at the cursor position
+ (and the cursor is advanced), with the highlights as set by the
+ last `highlight_set` update.
+
+["set_scroll_region", top, bot, left, right]
+ Define the scroll region used by `scroll` below.
+
+["scroll", count]
+ Scroll the text in the scroll region. The diagrams below illustrate
+ what will happen, depending on the scroll direction. "=" is used to
+ represent the SR(scroll region) boundaries and "-" the moved rectangles.
+ Note that dst and src share a common region.
+
+ If count is bigger than 0, move a rectangle in the SR up, this can
+ happen while scrolling down.
+>
+ +-------------------------+
+ | (clipped above SR) | ^
+ |=========================| dst_top |
+ | dst (still in SR) | |
+ +-------------------------+ src_top |
+ | src (moved up) and dst | |
+ |-------------------------| dst_bot |
+ | src (cleared) | |
+ +=========================+ src_bot
+<
+ If count is less than zero, move a rectangle in the SR down, this can
+ happen while scrolling up.
+>
+ +=========================+ src_top
+ | src (cleared) | |
+ |------------------------ | dst_top |
+ | src (moved down) and dst| |
+ +-------------------------+ src_bot |
+ | dst (still in SR) | |
+ |=========================| dst_bot |
+ | (clipped below SR) | v
+ +-------------------------+
+<
+["set_title", title]
+["set_icon", icon]
+ Set the window title, and icon (minimized) window title, respectively.
+ In windowing systems not distinguishing between the two, "set_icon"
+ can be ignored.
+
+["mouse_on"]
+["mouse_off"]
+ Tells the client whether mouse support, as determined by |'mouse'|
+ option, is considered to be active in the current mode. This is mostly
+ useful for a terminal frontend, or other situations where nvim mouse
+ would conflict with other usages of the mouse. It is safe for a client
+ to ignore this and always send mouse events.
+
+["busy_on"]
+["busy_off"]
+ Nvim started or stopped being busy, and possibly not responsible to user
+ input. This could be indicated to the user by hiding the cursor.
+
+["suspend"]
+ |:suspend| command or |Ctrl-Z| mapping is used. A terminal client (or other
+ client where it makes sense) could suspend itself. Other clients can
+ safely ignore it.
+
+["bell"]
+["visual_bell"]
+ Notify the user with an audible or visual bell, respectively.
+
+["update_menu"]
+ The menu mappings changed.
+
+["mode_change", mode]
+ The mode changed. Currently sent when "insert", "replace" and "normal"
+ modes are entered. A client could for instance change the cursor shape.
+
+["popupmenu_show", items, selected, row, col]
+ When `popupmenu_external` is set to true, nvim will not draw the
+ popupmenu on the grid, instead when the popupmenu is to be displayed
+ this update is sent. `items` is an array of the items to show, the
+ items are themselves arrays of the form [word, kind, menu, info]
+ as defined at |complete-items|, except that `word` is replaced by
+ `abbr` if present. `selected` is the initially selected item, either a
+ zero-based index into the array of items, or -1 if no item is
+ selected. `row` and `col` is the anchor position, where the first
+ character of the completed word will be.
+
+["popupmenu_select", selected]
+ An item in the currently displayed popupmenu is selected. `selected`
+ is either a zero-based index into the array of items from the last
+ `popupmenu_show` event, or -1 if no item is selected.
+
+["popupmenu_hide"]
+ The popupmenu is hidden.
==============================================================================
vim:tw=78:ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index e00f27f9f0..60acfbf700 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -4399,9 +4399,8 @@ A jump table for the options with a short description can be found at |Q_op|.
*'mousetime'* *'mouset'*
'mousetime' 'mouset' number (default 500)
global
- Only for GUI, Windows and Unix with xterm. Defines the maximum
- time in msec between two mouse clicks for the second click to be
- recognized as a multi click.
+ Defines the maximum time in msec between two mouse clicks for the
+ second click to be recognized as a multi click.
*'nrformats'* *'nf'*
'nrformats' 'nf' string (default "bin,hex")
diff --git a/runtime/doc/pi_health.txt b/runtime/doc/pi_health.txt
new file mode 100644
index 0000000000..69833103d1
--- /dev/null
+++ b/runtime/doc/pi_health.txt
@@ -0,0 +1,127 @@
+*pi_health.txt* Healthcheck framework
+
+Author: TJ DeVries <devries.timothyj@gmail.com>
+
+==============================================================================
+1. Introduction |health.vim-intro|
+2. Commands and functions |health.vim-manual|
+3. Create a healthcheck |health.vim-dev|
+
+==============================================================================
+Introduction *healthcheck* *health.vim-intro*
+
+Troubleshooting user configuration problems is a time-consuming task that
+developers want to minimize. health.vim provides a simple framework for plugin
+authors to hook into, and for users to invoke, to check and report the user's
+configuration and environment. Type this command to try it: >
+
+ :CheckHealth
+<
+For example, some users have broken or unusual Python setups, which breaks the
+|:python| command. |:CheckHealth| detects several common Python configuration
+problems and reports them. If the Neovim Python module is not installed, it
+shows a warning: >
+
+ You have not installed the Neovim Python module
+ You might want to try `pip install Neovim`
+<
+Plugin authors are encouraged to add healthchecks, see |health.vim-dev|.
+
+==============================================================================
+Commands and functions *health.vim-manual*
+
+Commands
+------------------------------------------------------------------------------
+ *:CheckHealth*
+:CheckHealth Run all healthchecks and show the output in a new
+ tabpage. These healthchecks are included by default:
+ - python2
+ - python3
+ - ruby
+ - remote plugin
+
+:CheckHealth {plugins}
+ Run healthchecks for one or more plugins. E.g. to run
+ only the standard Nvim healthcheck: >
+ :CheckHealth nvim
+< To run the healthchecks for the "foo" and "bar" plugins
+ (assuming these plugins are on your 'runtimepath' and
+ they have implemented health#foo#check() and
+ health#bar#check(), respectively): >
+ :CheckHealth foo bar
+<
+Functions
+------------------------------------------------------------------------------
+
+health.vim functions are for creating new healthchecks. They mostly just do
+some layout and formatting, to give users a consistent presentation.
+
+health#report_start({name}) *health#report_start*
+ Starts a new report. Most plugins should call this only once, but if
+ you want different sections to appear in your report, call this once
+ per section.
+
+health#report_info({msg}) *health#report_info*
+ Displays an informational message.
+
+health#report_ok({msg}) *health#report_ok*
+ Displays a "success" message.
+
+health#report_warn({msg}, [{suggestions}]) *health#report_warn*
+ Displays a warning. {suggestions} is an optional List of suggestions.
+
+health#report_error({msg}, [{suggestions}]) *health#report_error*
+ Displays an error. {suggestions} is an optional List of suggestions.
+
+health#{plugin}#check() *health.user_checker*
+ This is the form of a healthcheck definition. Call the above functions
+ from this function, then |:CheckHealth| does the rest. Example: >
+
+ function! health#my_plug#check() abort
+ silent call s:check_environment_vars()
+ silent call s:check_python_configuration()
+ endfunction
+<
+ The function will be found and called automatically when the user
+ invokes |:CheckHealth|.
+
+ All output will be captured from the healthcheck. Use the
+ health#report_* functions so that your healthcheck has a format
+ consistent with the standard healthchecks.
+
+==============================================================================
+Create a healthcheck *health.vim-dev*
+
+Healthchecks are functions that check the health of the system. Neovim has
+built-in checkers, found in $VIMRUNTIME/autoload/health/.
+
+To add a new checker for your own plugin, simply define a
+health#{plugin}#check() function in autoload/health/{plugin}.vim.
+|:CheckHealth| automatically finds and invokes such functions.
+
+If your plugin is named "jslint", then its healthcheck function must be >
+
+ health#jslint#check()
+<
+defined in this file on 'runtimepath': >
+
+ autoload/health/jslint.vim
+<
+Here's a sample to get started: >
+
+ function! health#jslint#check() abort
+ call health#report_start('sanity checks')
+ " perform arbitrary checks
+ " ...
+
+ if looks_good
+ call health#report_ok('found required dependencies')
+ else
+ call health#report_error('cannot find jslint',
+ \ ['npm install --save jslint'])
+ endif
+ endfunction
+<
+==============================================================================
+
+vim:tw=78:ts=8:ft=help:fdm=marker
diff --git a/runtime/doc/provider.txt b/runtime/doc/provider.txt
index 7380fb9346..63dbb00896 100644
--- a/runtime/doc/provider.txt
+++ b/runtime/doc/provider.txt
@@ -79,14 +79,6 @@ TROUBLESHOOTING *python-trouble*
If you have trouble with a plugin that uses the `neovim` Python client, use
the |:CheckHealth| command to diagnose your setup.
- *:CheckHealth*
-:CheckHealth[!] Check your setup for common problems that may be keeping a
- plugin from functioning correctly. Include the output of
- this command in bug reports to help reduce the amount of
- time it takes to address your issue. With "!" the output
- will be placed in a new buffer which can make it easier to
- save to a file or copy to the clipboard.
-
==============================================================================
Ruby integration *provider-ruby*
diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt
index 3b54faf18e..e2a44541ae 100644
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -1,4 +1,4 @@
-*quickfix.txt* For Vim version 7.4. Last change: 2016 Mar 19
+*quickfix.txt* For Vim version 7.4. Last change: 2016 Jul 01
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -259,9 +259,23 @@ location list command, it will be aborted.
The 'switchbuf' settings are respected when jumping
to a buffer.
+:cl[ist] +{count} List the current and next {count} valid errors. This
+ is similar to ":clist from from+count", where "from"
+ is the current error position.
+
:cl[ist]! [from] [, [to]]
List all errors.
+:cl[ist]! +{count} List the current and next {count} error lines. This
+ is useful to see unrecognized lines after the current
+ one. For example, if ":clist" shows:
+ 8384 testje.java:252: error: cannot find symbol ~
+ Then using ":cl! +3" shows the reason:
+ 8384 testje.java:252: error: cannot find symbol ~
+ 8385: ZexitCode = Fmainx(); ~
+ 8386: ^ ~
+ 8387: symbol: method Fmainx() ~
+
*:lli* *:llist*
:lli[st] [from] [, [to]]
Same as ":clist", except the location list for the
@@ -306,7 +320,7 @@ EXECUTE A COMMAND IN ALL THE BUFFERS IN QUICKFIX OR LOCATION LIST:
etc.
< When the current file can't be |abandon|ed and the [!]
is not present, the command fails.
- When an error is detected excecution stops.
+ When an error is detected execution stops.
The last buffer (or where an error occurred) becomes
the current buffer.
{cmd} can contain '|' to concatenate several commands.
diff --git a/runtime/doc/remote_plugin.txt b/runtime/doc/remote_plugin.txt
index d906096a86..dddc021d68 100644
--- a/runtime/doc/remote_plugin.txt
+++ b/runtime/doc/remote_plugin.txt
@@ -93,22 +93,22 @@ approach with |rpcnotify()|, meaning return values or exceptions raised in the
handler function are ignored.
To test the above plugin, it must be saved in "rplugin/python" in a
-'runtimepath' directory (~/.config/nvim/rplugin/python/limit.py for example).
-Then, the remote plugin manifest must be generated with
-`:UpdateRemotePlugins`.
+'runtimepath' directory (~/.config/nvim/rplugin/python/limit.py for example).
+Then, the remote plugin manifest must be generated with
+|:UpdateRemotePlugins|.
==============================================================================
4. Remote plugin manifest *remote-plugin-manifest*
+ *:UpdateRemotePlugins*
Just installing remote plugins to "rplugin/{host}" isn't enough for them to be
-automatically loaded when required. You must execute `:UpdateRemotePlugins`
+automatically loaded when required. You must execute |:UpdateRemotePlugins|
every time a remote plugin is installed, updated, or deleted.
-`:UpdateRemotePlugins` generates the remote plugin manifest, a special
+|:UpdateRemotePlugins| generates the remote plugin manifest, a special
Vimscript file containing declarations for all Vimscript entities
(commands/autocommands/functions) defined by all remote plugins, with each
-entity associated with the host and plugin path. The manifest is a generated
-extension to the user's vimrc (it even has the vimrc filename prepended).
+entity associated with the host and plugin path.
Manifest declarations are just calls to the `remote#host#RegisterPlugin`
function, which takes care of bootstrapping the host as soon as the declared
@@ -125,10 +125,20 @@ the example, say the Java plugin is a semantic completion engine for Java code.
If it defines the autocommand "BufEnter *.java", then the Java host is spawned
only when Nvim loads a buffer matching "*.java".
-If the explicit call to `:UpdateRemotePlugins` seems incovenient, try to see it
+If the explicit call to |:UpdateRemotePlugins| seems incovenient, try to see it
like this: It's a way to provide IDE capabilities in Nvim while still keeping
it fast and lightweight for general use. It's also analogous to the |:helptags|
command.
+ *$NVIM_RPLUGIN_MANIFEST*
+Unless $NVIM_RPLUGIN_MANIFEST is set the manifest will be written to a file
+named `rplugin.vim` at:
+
+ Unix ~
+ $XDG_DATA_HOME/nvim/ or ~/.local/share/nvim/
+
+ Windows ~
+ $LOCALAPPDATA/nvim/ or ~/AppData/Local/nvim/
+
==============================================================================
vim:tw=78:ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt
index 8249f8e71f..c6f51d47b9 100644
--- a/runtime/doc/starting.txt
+++ b/runtime/doc/starting.txt
@@ -1200,11 +1200,10 @@ running) you have additional options:
:wv[iminfo][!] [file] Deprecated alias to |:wshada| command.
*:o* *:ol* *:oldfiles*
-:o[ldfiles][!] List the files that have marks stored in the ShaDa
+:o[ldfiles] List the files that have marks stored in the ShaDa
file. This list is read on startup and only changes
afterwards with ":rshada!". Also see |v:oldfiles|.
The number can be used with |c_#<|.
- Use ! to get a file selection prompt.
:bro[wse] o[ldfiles][!]
List file names as with |:oldfiles|, and then prompt
diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt
index 491e5801c8..d9440b6df8 100644
--- a/runtime/doc/syntax.txt
+++ b/runtime/doc/syntax.txt
@@ -4883,6 +4883,10 @@ PmenuSbar Popup menu: scrollbar.
PmenuThumb Popup menu: Thumb of the scrollbar.
*hl-Question*
Question |hit-enter| prompt and yes/no questions
+ *hl-QuickFixLine*
+QuickFixLine The selected |quickfix| item in the quickfix window.
+ |hl-CursorLine| is combined with this when the cursor is on
+ the currently selected quickfix item.
*hl-Search*
Search Last search pattern highlighting (see 'hlsearch').
Also used for highlighting the current line in the quickfix
diff --git a/runtime/doc/usr_12.txt b/runtime/doc/usr_12.txt
index 237abae55f..f64a230576 100644
--- a/runtime/doc/usr_12.txt
+++ b/runtime/doc/usr_12.txt
@@ -237,19 +237,8 @@ simple way: Move the cursor to the word you want to find help on and press >
K
-Vim will run the external "man" program on the word. If the man page is
-found, it is displayed. This uses the normal pager to scroll through the text
-(mostly the "more" program). When you get to the end pressing <Enter> will
-get you back into Vim.
-
-A disadvantage is that you can't see the man page and the text you are working
-on at the same time. There is a trick to make the man page appear in a Vim
-window. First, load the man filetype plugin: >
-
- :runtime! ftplugin/man.vim
-
-Put this command in your vimrc file if you intend to do this often. Now you
-can use the ":Man" command to open a window on a man page: >
+Nvim will run |:Man| on the word. If the man page is found, it is displayed.
+You can also use the |:Man| command to open a window on a man page: >
:Man csh
@@ -267,15 +256,14 @@ window.
To display a man page for the word under the cursor, use this: >
- \K
+ K
-(If you redefined the <Leader>, use it instead of the backslash).
For example, you want to know the return value of "strstr()" while editing
this line:
if ( strstr (input, "aap") == ) ~
-Move the cursor to somewhere on "strstr" and type "\K". A window will open
+Move the cursor to somewhere on "strstr" and type "K". A window will open
to display the man page for strstr().
==============================================================================
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index 937ed9e8ba..dd4dbc1272 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -64,13 +64,13 @@ these differences.
MAJOR FEATURES ~
Embedded terminal emulator |terminal-emulator|
-Shared data |shada|
RPC API |RPC|
+Shared data |shada|
+XDG base directories |xdg|
Job control |job-control|
Remote plugins |remote-plugin|
Python plugins |provider-python|
Clipboard integration |provider-clipboard|
-XDG support
OTHER FEATURES ~
@@ -96,6 +96,7 @@ Options:
Commands:
|:CheckHealth|
+ |:Man| is available by default, with many improvements such as completion
Functions:
|execute()| works with |:redir|
@@ -106,9 +107,11 @@ Events:
|TabClosed|
|TermOpen|
|TermClose|
+ |TextYankPost|
Highlight groups:
|hl-EndOfBuffer|
+ |hl-QuickFixLine|
|hl-TermCursor|
|hl-TermCursorNC|
@@ -187,7 +190,6 @@ Additional differences:
compatibility reasons.
- |:wviminfo| was renamed to |:wshada|, |:rviminfo| to |:rshada|. Old
commands are still kept.
-- |:oldfiles| supports !.
- When writing (|:wshada| without bang or at exit) it merges much more data,
and does this according to the timestamp. Vim merges only marks.
|shada-merging|
diff --git a/runtime/ftplugin/c.vim b/runtime/ftplugin/c.vim
index 487ce7a165..d1b2a4941e 100644
--- a/runtime/ftplugin/c.vim
+++ b/runtime/ftplugin/c.vim
@@ -55,5 +55,7 @@ if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
endif
endif
+let b:man_default_sects = '3,2'
+
let &cpo = s:cpo_save
unlet s:cpo_save
diff --git a/runtime/ftplugin/man.vim b/runtime/ftplugin/man.vim
index 04ab539fb1..02d2b4e557 100644
--- a/runtime/ftplugin/man.vim
+++ b/runtime/ftplugin/man.vim
@@ -1,41 +1,63 @@
-" Vim filetype plugin file
-" Language: man
-" Maintainer: SungHyun Nam <goweol@gmail.com>
+" Maintainer: Anmol Sethi <anmol@aubble.com>
+" Previous Maintainer: SungHyun Nam <goweol@gmail.com>
-if has('vim_starting') && &filetype !=# 'man'
- finish
-endif
-
-" Only do this when not done yet for this buffer
-if exists('b:did_ftplugin')
+if exists('b:did_ftplugin') || &filetype !=# 'man'
finish
endif
let b:did_ftplugin = 1
-" Ensure Vim is not recursively invoked (man-db does this)
-" when doing ctrl-[ on a man page reference.
-if exists('$MANPAGER')
- let $MANPAGER = ''
-endif
-
-setlocal iskeyword+=\.,-,(,)
-
-setlocal buftype=nofile noswapfile
-setlocal nomodifiable readonly bufhidden=hide nobuflisted tabstop=8
+let s:pager = 0
-if !exists("g:no_plugin_maps") && !exists("g:no_man_maps")
- nnoremap <silent> <buffer> <C-]> :call man#get_page(v:count, expand('<cword>'))<CR>
- nnoremap <silent> <buffer> <C-T> :call man#pop_page()<CR>
- nnoremap <silent> <nowait><buffer> q <C-W>c
- if &keywordprg !=# ':Man'
- nnoremap <silent> <buffer> K :call man#get_page(v:count, expand('<cword>'))<CR>
+if has('vim_starting')
+ let s:pager = 1
+ " remove all those backspaces
+ silent execute 'keeppatterns keepjumps %substitute,.\b,,e'.(&gdefault?'':'g')
+ if getline(1) =~# '^\s*$'
+ silent keepjumps 1delete _
+ else
+ keepjumps 1
endif
+ " This is not perfect. See `man glDrawArraysInstanced`. Since the title is
+ " all caps it is impossible to tell what the original capitilization was.
+ let ref = tolower(matchstr(getline(1), '^\S\+'))
+ let b:man_sect = man#extract_sect_and_name_ref(ref)[0]
+ execute 'file man://'.ref
endif
-if exists('g:ft_man_folding_enable') && (g:ft_man_folding_enable == 1)
- setlocal foldmethod=indent foldnestmax=1 foldenable
+setlocal buftype=nofile
+setlocal noswapfile
+setlocal bufhidden=hide
+setlocal nomodified
+setlocal readonly
+setlocal nomodifiable
+setlocal noexpandtab
+setlocal tabstop=8
+setlocal softtabstop=8
+setlocal shiftwidth=8
+
+setlocal nonumber
+setlocal norelativenumber
+setlocal foldcolumn=0
+setlocal colorcolumn=0
+setlocal nolist
+setlocal nofoldenable
+
+if !exists('g:no_plugin_maps') && !exists('g:no_man_maps')
+ nmap <silent> <buffer> <C-]> :Man<CR>
+ nmap <silent> <buffer> K :Man<CR>
+ nnoremap <silent> <buffer> <C-T> :call man#pop_tag()<CR>
+ if s:pager
+ nnoremap <silent> <buffer> <nowait> q :q<CR>
+ else
+ nnoremap <silent> <buffer> <nowait> q <C-W>c
+ endif
endif
-let b:undo_ftplugin = 'setlocal iskeyword<'
+if get(g:, 'ft_man_folding_enable', 0)
+ setlocal foldenable
+ setlocal foldmethod=indent
+ setlocal foldnestmax=1
+endif
+let b:undo_ftplugin = ''
" vim: set sw=2:
diff --git a/runtime/plugin/health.vim b/runtime/plugin/health.vim
index db094a03a4..3c8e509acd 100644
--- a/runtime/plugin/health.vim
+++ b/runtime/plugin/health.vim
@@ -1 +1 @@
-command! -bang CheckHealth call health#check(<bang>0)
+command! -nargs=* CheckHealth call health#check([<f-args>])
diff --git a/runtime/plugin/man.vim b/runtime/plugin/man.vim
index 8e5062a209..63faa15213 100644
--- a/runtime/plugin/man.vim
+++ b/runtime/plugin/man.vim
@@ -1,6 +1,13 @@
-if get(g:, 'loaded_man', 0)
+" Maintainer: Anmol Sethi <anmol@aubble.com>
+
+if exists('g:loaded_man')
finish
endif
let g:loaded_man = 1
-command! -count=0 -nargs=+ Man call man#get_page(<count>, <f-args>)
+command! -range=0 -complete=customlist,man#complete -nargs=* Man call man#open_page(v:count, v:count1, <q-mods>, <f-args>)
+
+augroup man
+ autocmd!
+ autocmd BufReadCmd man://* call man#read_page(matchstr(expand('<amatch>'), 'man://\zs.*'))
+augroup END
diff --git a/runtime/syntax/man.vim b/runtime/syntax/man.vim
index fbc1847e6e..4a527dd350 100644
--- a/runtime/syntax/man.vim
+++ b/runtime/syntax/man.vim
@@ -1,67 +1,37 @@
-" Vim syntax file
-" Language: Man page
-" Maintainer: SungHyun Nam <goweol@gmail.com>
-" Previous Maintainer: Gautam H. Mudunuri <gmudunur@informatica.com>
-" Version Info:
-" Last Change: 2015 Nov 24
+" Maintainer: Anmol Sethi <anmol@aubble.com>
+" Previous Maintainer: SungHyun Nam <goweol@gmail.com>
-" Additional highlighting by Johannes Tanzler <johannes.tanzler@aon.at>:
-" * manSubHeading
-" * manSynopsis (only for sections 2 and 3)
-
-" For version 5.x: Clear all syntax items
-" For version 6.x: Quit when a syntax file was already loaded
-if version < 600
- syntax clear
-elseif exists("b:current_syntax")
+if exists('b:current_syntax')
finish
endif
-" Get the CTRL-H syntax to handle backspaced text
-if version >= 600
- runtime! syntax/ctrlh.vim
-else
- source <sfile>:p:h/ctrlh.vim
-endif
-
-syn case ignore
-syn match manReference "\f\+([1-9][a-z]\=)"
-syn match manTitle "^\f\+([0-9]\+[a-z]\=).*"
-syn match manSectionHeading "^[a-z][a-z -]*[a-z]$"
-syn match manSubHeading "^\s\{3\}[a-z][a-z -]*[a-z]$"
-syn match manOptionDesc "^\s*[+-][a-z0-9]\S*"
-syn match manLongOptionDesc "^\s*--[a-z0-9-]\S*"
-" syn match manHistory "^[a-z].*last change.*$"
-
-if getline(1) =~ '^[a-zA-Z_]\+([23])'
- syntax include @cCode <sfile>:p:h/c.vim
- syn match manCFuncDefinition display "\<\h\w*\>\s*("me=e-1 contained
- syn region manSynopsis start="^SYNOPSIS"hs=s+8 end="^\u\+\s*$"me=e-12 keepend contains=manSectionHeading,@cCode,manCFuncDefinition
-endif
-
-
-" Define the default highlighting.
-" For version 5.7 and earlier: only when not done already
-" For version 5.8 and later: only when an item doesn't have highlighting yet
-if version >= 508 || !exists("did_man_syn_inits")
- if version < 508
- let did_man_syn_inits = 1
- command -nargs=+ HiLink hi link <args>
- else
- command -nargs=+ HiLink hi def link <args>
- endif
-
- HiLink manTitle Title
- HiLink manSectionHeading Statement
- HiLink manOptionDesc Constant
- HiLink manLongOptionDesc Constant
- HiLink manReference PreProc
- HiLink manSubHeading Function
- HiLink manCFuncDefinition Function
-
- delcommand HiLink
+syntax case ignore
+syntax match manReference display '[^()[:space:]]\+([0-9nx][a-z]*)'
+syntax match manSectionHeading display '^\S.*$'
+syntax match manTitle display '^\%1l.*$'
+syntax match manSubHeading display '^ \{3\}\S.*$'
+syntax match manOptionDesc display '^\s\+\%(+\|-\)\S\+'
+
+highlight default link manTitle Title
+highlight default link manSectionHeading Statement
+highlight default link manOptionDesc Constant
+highlight default link manReference PreProc
+highlight default link manSubHeading Function
+
+if b:man_sect =~# '^[23]'
+ syntax include @c $VIMRUNTIME/syntax/c.vim
+ syntax match manCFuncDefinition display '\<\h\w*\>\ze\(\s\|\n\)*(' contained
+ syntax region manSynopsis start='^\%(
+ \SYNOPSIS\|
+ \SYNTAX\|
+ \SINTASSI\|
+ \SKŁADNIA\|
+ \СИНТАКСИС\|
+ \書式\)$' end='^\%(\S.*\)\=\S$' keepend contains=manSectionHeading,@c,manCFuncDefinition
+ highlight default link manCFuncDefinition Function
endif
-let b:current_syntax = "man"
+" Prevent everything else from matching the last line
+execute 'syntax match manFooter display "^\%'.line('$').'l.*$"'
-" vim:ts=8 sts=2 sw=2:
+let b:current_syntax = 'man'
diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim
index cf51830b68..c855267137 100644
--- a/runtime/syntax/vim.vim
+++ b/runtime/syntax/vim.vim
@@ -53,7 +53,7 @@ syn keyword vimGroup contained Comment Constant String Character Number Boolean
syn keyword vimHLGroup contained ColorColumn Cursor CursorColumn CursorIM CursorLine CursorLineNr DiffAdd DiffChange DiffDelete DiffText Directory ErrorMsg FoldColumn Folded IncSearch LineNr MatchParen Menu ModeMsg MoreMsg NonText Normal Pmenu PmenuSbar PmenuSel PmenuThumb Question Scrollbar Search SignColumn SpecialKey SpellBad SpellCap SpellLocal SpellRare StatusLine StatusLineNC TabLine TabLineFill TabLineSel Title Tooltip VertSplit Visual WarningMsg WildMenu
syn match vimHLGroup contained "Conceal"
syn keyword vimOnlyHLGroup contained VisualNOS
-syn keyword nvimHLGroup contained EndOfBuffer TermCursor TermCursorNC
+syn keyword nvimHLGroup contained EndOfBuffer TermCursor TermCursorNC QuickFixLine
"}}}2
syn case match
" Special Vim Highlighting (not automatic) {{{1