aboutsummaryrefslogtreecommitdiff
path: root/runtime/autoload
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2023-01-25 18:31:31 +0000
committerJosh Rahm <joshuarahm@gmail.com>2023-01-25 18:31:31 +0000
commit9243becbedbb6a1592208051f8fa2b090dcc5e7d (patch)
tree607c2a862ec3f4399b8766383f6f8e04c4aa43b4 /runtime/autoload
parent9e40b6e9e1bc67f2d856adb837ee64dd0e25b717 (diff)
parent3c48d3c83fc21dbc0841f9210f04bdb073d73cd1 (diff)
downloadrneovim-usermarks.tar.gz
rneovim-usermarks.tar.bz2
rneovim-usermarks.zip
Merge remote-tracking branch 'upstream/master' into usermarksusermarks
Diffstat (limited to 'runtime/autoload')
-rw-r--r--runtime/autoload/ccomplete.lua857
-rw-r--r--runtime/autoload/ccomplete.vim647
-rw-r--r--runtime/autoload/dist/ft.vim1073
-rw-r--r--runtime/autoload/health.vim26
-rw-r--r--runtime/autoload/health/nvim.vim284
-rw-r--r--runtime/autoload/man.vim529
-rw-r--r--runtime/autoload/netrw.vim57
-rw-r--r--runtime/autoload/provider/clipboard.vim25
-rw-r--r--runtime/autoload/provider/node.vim10
-rw-r--r--runtime/autoload/python.vim40
-rw-r--r--runtime/autoload/tohtml.vim5
-rw-r--r--runtime/autoload/tutor.vim2
-rw-r--r--runtime/autoload/zig/fmt.vim100
13 files changed, 1042 insertions, 2613 deletions
diff --git a/runtime/autoload/ccomplete.lua b/runtime/autoload/ccomplete.lua
new file mode 100644
index 0000000000..f4a3eabd9a
--- /dev/null
+++ b/runtime/autoload/ccomplete.lua
@@ -0,0 +1,857 @@
+----------------------------------------
+-- This file is generated via github.com/tjdevries/vim9jit
+-- For any bugs, please first consider reporting there.
+----------------------------------------
+
+-- Ignore "value assigned to a local variable is unused" because
+-- we can't guarantee that local variables will be used by plugins
+-- luacheck: ignore 311
+
+local vim9 = require('_vim9script')
+local M = {}
+local prepended = nil
+local grepCache = nil
+local Complete = nil
+local GetAddition = nil
+local Tag2item = nil
+local Dict2info = nil
+local ParseTagline = nil
+local Tagline2item = nil
+local Tagcmd2extra = nil
+local Nextitem = nil
+local StructMembers = nil
+local SearchMembers = nil
+-- vim9script
+
+-- # Vim completion script
+-- # Language: C
+-- # Maintainer: Bram Moolenaar <Bram@vim.org>
+-- # Rewritten in Vim9 script by github user lacygoill
+-- # Last Change: 2022 Jan 31
+
+prepended = ''
+grepCache = vim.empty_dict()
+
+-- # This function is used for the 'omnifunc' option.
+
+Complete = function(findstart, abase)
+ findstart = vim9.bool(findstart)
+ if vim9.bool(findstart) then
+ -- # Locate the start of the item, including ".", "->" and "[...]".
+ local line = vim9.fn.getline('.')
+ local start = vim9.fn.charcol('.') - 1
+ local lastword = -1
+ while start > 0 do
+ if vim9.ops.RegexpMatches(vim9.index(line, vim9.ops.Minus(start, 1)), '\\w') then
+ start = start - 1
+ elseif
+ vim9.bool(vim9.ops.RegexpMatches(vim9.index(line, vim9.ops.Minus(start, 1)), '\\.'))
+ then
+ if lastword == -1 then
+ lastword = start
+ end
+ start = start - 1
+ elseif
+ vim9.bool(
+ start > 1
+ and vim9.index(line, vim9.ops.Minus(start, 2)) == '-'
+ and vim9.index(line, vim9.ops.Minus(start, 1)) == '>'
+ )
+ then
+ if lastword == -1 then
+ lastword = start
+ end
+ start = vim9.ops.Minus(start, 2)
+ elseif vim9.bool(vim9.index(line, vim9.ops.Minus(start, 1)) == ']') then
+ -- # Skip over [...].
+ local n = 0
+ start = start - 1
+ while start > 0 do
+ start = start - 1
+ if vim9.index(line, start) == '[' then
+ if n == 0 then
+ break
+ end
+ n = n - 1
+ elseif vim9.bool(vim9.index(line, start) == ']') then
+ n = n + 1
+ end
+ end
+ else
+ break
+ end
+ end
+
+ -- # Return the column of the last word, which is going to be changed.
+ -- # Remember the text that comes before it in prepended.
+ if lastword == -1 then
+ prepended = ''
+ return vim9.fn.byteidx(line, start)
+ end
+ prepended = vim9.slice(line, start, vim9.ops.Minus(lastword, 1))
+ return vim9.fn.byteidx(line, lastword)
+ end
+
+ -- # Return list of matches.
+
+ local base = prepended .. abase
+
+ -- # Don't do anything for an empty base, would result in all the tags in the
+ -- # tags file.
+ if base == '' then
+ return {}
+ end
+
+ -- # init cache for vimgrep to empty
+ grepCache = {}
+
+ -- # Split item in words, keep empty word after "." or "->".
+ -- # "aa" -> ['aa'], "aa." -> ['aa', ''], "aa.bb" -> ['aa', 'bb'], etc.
+ -- # We can't use split, because we need to skip nested [...].
+ -- # "aa[...]" -> ['aa', '[...]'], "aa.bb[...]" -> ['aa', 'bb', '[...]'], etc.
+ local items = {}
+ local s = 0
+ local arrays = 0
+ while 1 do
+ local e = vim9.fn.charidx(base, vim9.fn.match(base, '\\.\\|->\\|\\[', s))
+ if e < 0 then
+ if s == 0 or vim9.index(base, vim9.ops.Minus(s, 1)) ~= ']' then
+ vim9.fn.add(items, vim9.slice(base, s, nil))
+ end
+ break
+ end
+ if s == 0 or vim9.index(base, vim9.ops.Minus(s, 1)) ~= ']' then
+ vim9.fn.add(items, vim9.slice(base, s, vim9.ops.Minus(e, 1)))
+ end
+ if vim9.index(base, e) == '.' then
+ -- # skip over '.'
+ s = vim9.ops.Plus(e, 1)
+ elseif vim9.bool(vim9.index(base, e) == '-') then
+ -- # skip over '->'
+ s = vim9.ops.Plus(e, 2)
+ else
+ -- # Skip over [...].
+ local n = 0
+ s = e
+ e = e + 1
+ while e < vim9.fn.strcharlen(base) do
+ if vim9.index(base, e) == ']' then
+ if n == 0 then
+ break
+ end
+ n = n - 1
+ elseif vim9.bool(vim9.index(base, e) == '[') then
+ n = n + 1
+ end
+ e = e + 1
+ end
+ e = e + 1
+ vim9.fn.add(items, vim9.slice(base, s, vim9.ops.Minus(e, 1)))
+ arrays = arrays + 1
+ s = e
+ end
+ end
+
+ -- # Find the variable items[0].
+ -- # 1. in current function (like with "gd")
+ -- # 2. in tags file(s) (like with ":tag")
+ -- # 3. in current file (like with "gD")
+ local res = {}
+ if vim9.fn.searchdecl(vim9.index(items, 0), false, true) == 0 then
+ -- # Found, now figure out the type.
+ -- # TODO: join previous line if it makes sense
+ local line = vim9.fn.getline('.')
+ local col = vim9.fn.charcol('.')
+ if vim9.fn.stridx(vim9.slice(line, nil, vim9.ops.Minus(col, 1)), ';') >= 0 then
+ -- # Handle multiple declarations on the same line.
+ local col2 = vim9.ops.Minus(col, 1)
+ while vim9.index(line, col2) ~= ';' do
+ col2 = col2 - 1
+ end
+ line = vim9.slice(line, vim9.ops.Plus(col2, 1), nil)
+ col = vim9.ops.Minus(col, col2)
+ end
+ if vim9.fn.stridx(vim9.slice(line, nil, vim9.ops.Minus(col, 1)), ',') >= 0 then
+ -- # Handle multiple declarations on the same line in a function
+ -- # declaration.
+ local col2 = vim9.ops.Minus(col, 1)
+ while vim9.index(line, col2) ~= ',' do
+ col2 = col2 - 1
+ end
+ if
+ vim9.ops.RegexpMatches(
+ vim9.slice(line, vim9.ops.Plus(col2, 1), vim9.ops.Minus(col, 1)),
+ ' *[^ ][^ ]* *[^ ]'
+ )
+ then
+ line = vim9.slice(line, vim9.ops.Plus(col2, 1), nil)
+ col = vim9.ops.Minus(col, col2)
+ end
+ end
+ if vim9.fn.len(items) == 1 then
+ -- # Completing one word and it's a local variable: May add '[', '.' or
+ -- # '->'.
+ local match = vim9.index(items, 0)
+ local kind = 'v'
+ if vim9.fn.match(line, '\\<' .. match .. '\\s*\\[') > 0 then
+ match = match .. '['
+ else
+ res = Nextitem(vim9.slice(line, nil, vim9.ops.Minus(col, 1)), { '' }, 0, true)
+ if vim9.fn.len(res) > 0 then
+ -- # There are members, thus add "." or "->".
+ if vim9.fn.match(line, '\\*[ \\t(]*' .. match .. '\\>') > 0 then
+ match = match .. '->'
+ else
+ match = match .. '.'
+ end
+ end
+ end
+ res = { { ['match'] = match, ['tagline'] = '', ['kind'] = kind, ['info'] = line } }
+ elseif vim9.bool(vim9.fn.len(items) == vim9.ops.Plus(arrays, 1)) then
+ -- # Completing one word and it's a local array variable: build tagline
+ -- # from declaration line
+ local match = vim9.index(items, 0)
+ local kind = 'v'
+ local tagline = '\t/^' .. line .. '$/'
+ res = { { ['match'] = match, ['tagline'] = tagline, ['kind'] = kind, ['info'] = line } }
+ else
+ -- # Completing "var.", "var.something", etc.
+ res =
+ Nextitem(vim9.slice(line, nil, vim9.ops.Minus(col, 1)), vim9.slice(items, 1, nil), 0, true)
+ end
+ end
+
+ if vim9.fn.len(items) == 1 or vim9.fn.len(items) == vim9.ops.Plus(arrays, 1) then
+ -- # Only one part, no "." or "->": complete from tags file.
+ local tags = {}
+ if vim9.fn.len(items) == 1 then
+ tags = vim9.fn.taglist('^' .. base)
+ else
+ tags = vim9.fn.taglist('^' .. vim9.index(items, 0) .. '$')
+ end
+
+ vim9.fn_mut('filter', {
+ vim9.fn_mut('filter', {
+ tags,
+ function(_, v)
+ return vim9.ternary(vim9.fn.has_key(v, 'kind'), function()
+ return v.kind ~= 'm'
+ end, true)
+ end,
+ }, { replace = 0 }),
+ function(_, v)
+ return vim9.ops.Or(
+ vim9.ops.Or(
+ vim9.prefix['Bang'](vim9.fn.has_key(v, 'static')),
+ vim9.prefix['Bang'](vim9.index(v, 'static'))
+ ),
+ vim9.fn.bufnr('%') == vim9.fn.bufnr(vim9.index(v, 'filename'))
+ )
+ end,
+ }, { replace = 0 })
+
+ res = vim9.fn.extend(
+ res,
+ vim9.fn.map(tags, function(_, v)
+ return Tag2item(v)
+ end)
+ )
+ end
+
+ if vim9.fn.len(res) == 0 then
+ -- # Find the variable in the tags file(s)
+ local diclist = vim9.fn.filter(
+ vim9.fn.taglist('^' .. vim9.index(items, 0) .. '$'),
+ function(_, v)
+ return vim9.ternary(vim9.fn.has_key(v, 'kind'), function()
+ return v.kind ~= 'm'
+ end, true)
+ end
+ )
+
+ res = {}
+
+ for _, i in vim9.iter(vim9.fn.range(vim9.fn.len(diclist))) do
+ -- # New ctags has the "typeref" field. Patched version has "typename".
+ if vim9.bool(vim9.fn.has_key(vim9.index(diclist, i), 'typename')) then
+ res = vim9.fn.extend(
+ res,
+ StructMembers(
+ vim9.index(vim9.index(diclist, i), 'typename'),
+ vim9.slice(items, 1, nil),
+ true
+ )
+ )
+ elseif vim9.bool(vim9.fn.has_key(vim9.index(diclist, i), 'typeref')) then
+ res = vim9.fn.extend(
+ res,
+ StructMembers(
+ vim9.index(vim9.index(diclist, i), 'typeref'),
+ vim9.slice(items, 1, nil),
+ true
+ )
+ )
+ end
+
+ -- # For a variable use the command, which must be a search pattern that
+ -- # shows the declaration of the variable.
+ if vim9.index(vim9.index(diclist, i), 'kind') == 'v' then
+ local line = vim9.index(vim9.index(diclist, i), 'cmd')
+ if vim9.slice(line, nil, 1) == '/^' then
+ local col =
+ vim9.fn.charidx(line, vim9.fn.match(line, '\\<' .. vim9.index(items, 0) .. '\\>'))
+ res = vim9.fn.extend(
+ res,
+ Nextitem(
+ vim9.slice(line, 2, vim9.ops.Minus(col, 1)),
+ vim9.slice(items, 1, nil),
+ 0,
+ true
+ )
+ )
+ end
+ end
+ end
+ end
+
+ if vim9.fn.len(res) == 0 and vim9.fn.searchdecl(vim9.index(items, 0), true) == 0 then
+ -- # Found, now figure out the type.
+ -- # TODO: join previous line if it makes sense
+ local line = vim9.fn.getline('.')
+ local col = vim9.fn.charcol('.')
+ res =
+ Nextitem(vim9.slice(line, nil, vim9.ops.Minus(col, 1)), vim9.slice(items, 1, nil), 0, true)
+ end
+
+ -- # If the last item(s) are [...] they need to be added to the matches.
+ local last = vim9.fn.len(items) - 1
+ local brackets = ''
+ while last >= 0 do
+ if vim9.index(vim9.index(items, last), 0) ~= '[' then
+ break
+ end
+ brackets = vim9.index(items, last) .. brackets
+ last = last - 1
+ end
+
+ return vim9.fn.map(res, function(_, v)
+ return Tagline2item(v, brackets)
+ end)
+end
+M['Complete'] = Complete
+
+GetAddition = function(line, match, memarg, bracket)
+ bracket = vim9.bool(bracket)
+ -- # Guess if the item is an array.
+ if vim9.bool(vim9.ops.And(bracket, vim9.fn.match(line, match .. '\\s*\\[') > 0)) then
+ return '['
+ end
+
+ -- # Check if the item has members.
+ if vim9.fn.len(SearchMembers(memarg, { '' }, false)) > 0 then
+ -- # If there is a '*' before the name use "->".
+ if vim9.fn.match(line, '\\*[ \\t(]*' .. match .. '\\>') > 0 then
+ return '->'
+ else
+ return '.'
+ end
+ end
+ return ''
+end
+
+Tag2item = function(val)
+ -- # Turn the tag info "val" into an item for completion.
+ -- # "val" is is an item in the list returned by taglist().
+ -- # If it is a variable we may add "." or "->". Don't do it for other types,
+ -- # such as a typedef, by not including the info that GetAddition() uses.
+ local res = vim9.convert.decl_dict({ ['match'] = vim9.index(val, 'name') })
+
+ res[vim9.index_expr('extra')] =
+ Tagcmd2extra(vim9.index(val, 'cmd'), vim9.index(val, 'name'), vim9.index(val, 'filename'))
+
+ local s = Dict2info(val)
+ if s ~= '' then
+ res[vim9.index_expr('info')] = s
+ end
+
+ res[vim9.index_expr('tagline')] = ''
+ if vim9.bool(vim9.fn.has_key(val, 'kind')) then
+ local kind = vim9.index(val, 'kind')
+ res[vim9.index_expr('kind')] = kind
+ if kind == 'v' then
+ res[vim9.index_expr('tagline')] = '\t' .. vim9.index(val, 'cmd')
+ res[vim9.index_expr('dict')] = val
+ elseif vim9.bool(kind == 'f') then
+ res[vim9.index_expr('match')] = vim9.index(val, 'name') .. '('
+ end
+ end
+
+ return res
+end
+
+Dict2info = function(dict)
+ -- # Use all the items in dictionary for the "info" entry.
+ local info = ''
+
+ for _, k in vim9.iter(vim9.fn_mut('sort', { vim9.fn.keys(dict) }, { replace = 0 })) do
+ info = info .. k .. vim9.fn['repeat'](' ', 10 - vim9.fn.strlen(k))
+ if k == 'cmd' then
+ info = info
+ .. vim9.fn.substitute(
+ vim9.fn.matchstr(vim9.index(dict, 'cmd'), '/^\\s*\\zs.*\\ze$/'),
+ '\\\\\\(.\\)',
+ '\\1',
+ 'g'
+ )
+ else
+ local dictk = vim9.index(dict, k)
+ if vim9.fn.typename(dictk) ~= 'string' then
+ info = info .. vim9.fn.string(dictk)
+ else
+ info = info .. dictk
+ end
+ end
+ info = info .. '\n'
+ end
+
+ return info
+end
+
+ParseTagline = function(line)
+ -- # Parse a tag line and return a dictionary with items like taglist()
+ local l = vim9.fn.split(line, '\t')
+ local d = vim.empty_dict()
+ if vim9.fn.len(l) >= 3 then
+ d[vim9.index_expr('name')] = vim9.index(l, 0)
+ d[vim9.index_expr('filename')] = vim9.index(l, 1)
+ d[vim9.index_expr('cmd')] = vim9.index(l, 2)
+ local n = 2
+ if vim9.ops.RegexpMatches(vim9.index(l, 2), '^/') then
+ -- # Find end of cmd, it may contain Tabs.
+ while n < vim9.fn.len(l) and vim9.ops.NotRegexpMatches(vim9.index(l, n), '/;"$') do
+ n = n + 1
+ d[vim9.index_expr('cmd')] = vim9.index(d, 'cmd') .. ' ' .. vim9.index(l, n)
+ end
+ end
+
+ for _, i in vim9.iter(vim9.fn.range(vim9.ops.Plus(n, 1), vim9.fn.len(l) - 1)) do
+ if vim9.index(l, i) == 'file:' then
+ d[vim9.index_expr('static')] = 1
+ elseif vim9.bool(vim9.ops.NotRegexpMatches(vim9.index(l, i), ':')) then
+ d[vim9.index_expr('kind')] = vim9.index(l, i)
+ else
+ d[vim9.index_expr(vim9.fn.matchstr(vim9.index(l, i), '[^:]*'))] =
+ vim9.fn.matchstr(vim9.index(l, i), ':\\zs.*')
+ end
+ end
+ end
+
+ return d
+end
+
+Tagline2item = function(val, brackets)
+ -- # Turn a match item "val" into an item for completion.
+ -- # "val['match']" is the matching item.
+ -- # "val['tagline']" is the tagline in which the last part was found.
+ local line = vim9.index(val, 'tagline')
+ local add = GetAddition(line, vim9.index(val, 'match'), { val }, brackets == '')
+ local res = vim9.convert.decl_dict({ ['word'] = vim9.index(val, 'match') .. brackets .. add })
+
+ if vim9.bool(vim9.fn.has_key(val, 'info')) then
+ -- # Use info from Tag2item().
+ res[vim9.index_expr('info')] = vim9.index(val, 'info')
+ else
+ -- # Parse the tag line and add each part to the "info" entry.
+ local s = Dict2info(ParseTagline(line))
+ if s ~= '' then
+ res[vim9.index_expr('info')] = s
+ end
+ end
+
+ if vim9.bool(vim9.fn.has_key(val, 'kind')) then
+ res[vim9.index_expr('kind')] = vim9.index(val, 'kind')
+ elseif vim9.bool(add == '(') then
+ res[vim9.index_expr('kind')] = 'f'
+ else
+ local s = vim9.fn.matchstr(line, '\\t\\(kind:\\)\\=\\zs\\S\\ze\\(\\t\\|$\\)')
+ if s ~= '' then
+ res[vim9.index_expr('kind')] = s
+ end
+ end
+
+ if vim9.bool(vim9.fn.has_key(val, 'extra')) then
+ res[vim9.index_expr('menu')] = vim9.index(val, 'extra')
+ return res
+ end
+
+ -- # Isolate the command after the tag and filename.
+ local s = vim9.fn.matchstr(
+ line,
+ '[^\\t]*\\t[^\\t]*\\t\\zs\\(/^.*$/\\|[^\\t]*\\)\\ze\\(;"\\t\\|\\t\\|$\\)'
+ )
+ if s ~= '' then
+ res[vim9.index_expr('menu')] = Tagcmd2extra(
+ s,
+ vim9.index(val, 'match'),
+ vim9.fn.matchstr(line, '[^\\t]*\\t\\zs[^\\t]*\\ze\\t')
+ )
+ end
+ return res
+end
+
+Tagcmd2extra = function(cmd, name, fname)
+ -- # Turn a command from a tag line to something that is useful in the menu
+ local x = ''
+ if vim9.ops.RegexpMatches(cmd, '^/^') then
+ -- # The command is a search command, useful to see what it is.
+ x = vim9.fn.substitute(
+ vim9.fn.substitute(
+ vim9.fn.matchstr(cmd, '^/^\\s*\\zs.*\\ze$/'),
+ '\\<' .. name .. '\\>',
+ '@@',
+ ''
+ ),
+ '\\\\\\(.\\)',
+ '\\1',
+ 'g'
+ ) .. ' - ' .. fname
+ elseif vim9.bool(vim9.ops.RegexpMatches(cmd, '^\\d*$')) then
+ -- # The command is a line number, the file name is more useful.
+ x = fname .. ' - ' .. cmd
+ else
+ -- # Not recognized, use command and file name.
+ x = cmd .. ' - ' .. fname
+ end
+ return x
+end
+
+Nextitem = function(lead, items, depth, all)
+ all = vim9.bool(all)
+ -- # Find composing type in "lead" and match items[0] with it.
+ -- # Repeat this recursively for items[1], if it's there.
+ -- # When resolving typedefs "depth" is used to avoid infinite recursion.
+ -- # Return the list of matches.
+
+ -- # Use the text up to the variable name and split it in tokens.
+ local tokens = vim9.fn.split(lead, '\\s\\+\\|\\<')
+
+ -- # Try to recognize the type of the variable. This is rough guessing...
+ local res = {}
+
+ local body = function(_, tidx)
+ -- # Skip tokens starting with a non-ID character.
+ if vim9.ops.NotRegexpMatches(vim9.index(tokens, tidx), '^\\h') then
+ return vim9.ITER_CONTINUE
+ end
+
+ -- # Recognize "struct foobar" and "union foobar".
+ -- # Also do "class foobar" when it's C++ after all (doesn't work very well
+ -- # though).
+ if
+ (
+ vim9.index(tokens, tidx) == 'struct'
+ or vim9.index(tokens, tidx) == 'union'
+ or vim9.index(tokens, tidx) == 'class'
+ ) and vim9.ops.Plus(tidx, 1) < vim9.fn.len(tokens)
+ then
+ res = StructMembers(
+ vim9.index(tokens, tidx) .. ':' .. vim9.index(tokens, vim9.ops.Plus(tidx, 1)),
+ items,
+ all
+ )
+ return vim9.ITER_BREAK
+ end
+
+ -- # TODO: add more reserved words
+ if
+ vim9.fn.index(
+ { 'int', 'short', 'char', 'float', 'double', 'static', 'unsigned', 'extern' },
+ vim9.index(tokens, tidx)
+ ) >= 0
+ then
+ return vim9.ITER_CONTINUE
+ end
+
+ -- # Use the tags file to find out if this is a typedef.
+ local diclist = vim9.fn.taglist('^' .. vim9.index(tokens, tidx) .. '$')
+
+ local body = function(_, tagidx)
+ local item = vim9.convert.decl_dict(vim9.index(diclist, tagidx))
+
+ -- # New ctags has the "typeref" field. Patched version has "typename".
+ if vim9.bool(vim9.fn.has_key(item, 'typeref')) then
+ res = vim9.fn.extend(res, StructMembers(vim9.index(item, 'typeref'), items, all))
+ return vim9.ITER_CONTINUE
+ end
+ if vim9.bool(vim9.fn.has_key(item, 'typename')) then
+ res = vim9.fn.extend(res, StructMembers(vim9.index(item, 'typename'), items, all))
+ return vim9.ITER_CONTINUE
+ end
+
+ -- # Only handle typedefs here.
+ if vim9.index(item, 'kind') ~= 't' then
+ return vim9.ITER_CONTINUE
+ end
+
+ -- # Skip matches local to another file.
+ if
+ vim9.bool(
+ vim9.ops.And(
+ vim9.ops.And(vim9.fn.has_key(item, 'static'), vim9.index(item, 'static')),
+ vim9.fn.bufnr('%') ~= vim9.fn.bufnr(vim9.index(item, 'filename'))
+ )
+ )
+ then
+ return vim9.ITER_CONTINUE
+ end
+
+ -- # For old ctags we recognize "typedef struct aaa" and
+ -- # "typedef union bbb" in the tags file command.
+ local cmd = vim9.index(item, 'cmd')
+ local ei = vim9.fn.charidx(cmd, vim9.fn.matchend(cmd, 'typedef\\s\\+'))
+ if ei > 1 then
+ local cmdtokens = vim9.fn.split(vim9.slice(cmd, ei, nil), '\\s\\+\\|\\<')
+ if vim9.fn.len(cmdtokens) > 1 then
+ if
+ vim9.index(cmdtokens, 0) == 'struct'
+ or vim9.index(cmdtokens, 0) == 'union'
+ or vim9.index(cmdtokens, 0) == 'class'
+ then
+ local name = ''
+ -- # Use the first identifier after the "struct" or "union"
+
+ for _, ti in vim9.iter(vim9.fn.range((vim9.fn.len(cmdtokens) - 1))) do
+ if vim9.ops.RegexpMatches(vim9.index(cmdtokens, ti), '^\\w') then
+ name = vim9.index(cmdtokens, ti)
+ break
+ end
+ end
+
+ if name ~= '' then
+ res = vim9.fn.extend(
+ res,
+ StructMembers(vim9.index(cmdtokens, 0) .. ':' .. name, items, all)
+ )
+ end
+ elseif vim9.bool(depth < 10) then
+ -- # Could be "typedef other_T some_T".
+ res = vim9.fn.extend(
+ res,
+ Nextitem(vim9.index(cmdtokens, 0), items, vim9.ops.Plus(depth, 1), all)
+ )
+ end
+ end
+ end
+
+ return vim9.ITER_DEFAULT
+ end
+
+ for _, tagidx in vim9.iter(vim9.fn.range(vim9.fn.len(diclist))) do
+ local nvim9_status, nvim9_ret = body(_, tagidx)
+ if nvim9_status == vim9.ITER_BREAK then
+ break
+ elseif nvim9_status == vim9.ITER_RETURN then
+ return nvim9_ret
+ end
+ end
+
+ if vim9.fn.len(res) > 0 then
+ return vim9.ITER_BREAK
+ end
+
+ return vim9.ITER_DEFAULT
+ end
+
+ for _, tidx in vim9.iter(vim9.fn.range(vim9.fn.len(tokens))) do
+ local nvim9_status, nvim9_ret = body(_, tidx)
+ if nvim9_status == vim9.ITER_BREAK then
+ break
+ elseif nvim9_status == vim9.ITER_RETURN then
+ return nvim9_ret
+ end
+ end
+
+ return res
+end
+
+StructMembers = function(atypename, items, all)
+ all = vim9.bool(all)
+
+ -- # Search for members of structure "typename" in tags files.
+ -- # Return a list with resulting matches.
+ -- # Each match is a dictionary with "match" and "tagline" entries.
+ -- # When "all" is true find all, otherwise just return 1 if there is any member.
+
+ -- # Todo: What about local structures?
+ local fnames = vim9.fn.join(vim9.fn.map(vim9.fn.tagfiles(), function(_, v)
+ return vim9.fn.escape(v, ' \\#%')
+ end))
+ if fnames == '' then
+ return {}
+ end
+
+ local typename = atypename
+ local qflist = {}
+ local cached = 0
+ local n = ''
+ if vim9.bool(vim9.prefix['Bang'](all)) then
+ n = '1'
+ if vim9.bool(vim9.fn.has_key(grepCache, typename)) then
+ qflist = vim9.index(grepCache, typename)
+ cached = 1
+ end
+ else
+ n = ''
+ end
+ if vim9.bool(vim9.prefix['Bang'](cached)) then
+ while 1 do
+ vim.api.nvim_command(
+ 'silent! keepjumps noautocmd '
+ .. n
+ .. 'vimgrep '
+ .. '/\\t'
+ .. typename
+ .. '\\(\\t\\|$\\)/j '
+ .. fnames
+ )
+
+ qflist = vim9.fn.getqflist()
+ if vim9.fn.len(qflist) > 0 or vim9.fn.match(typename, '::') < 0 then
+ break
+ end
+ -- # No match for "struct:context::name", remove "context::" and try again.
+ typename = vim9.fn.substitute(typename, ':[^:]*::', ':', '')
+ end
+
+ if vim9.bool(vim9.prefix['Bang'](all)) then
+ -- # Store the result to be able to use it again later.
+ grepCache[vim9.index_expr(typename)] = qflist
+ end
+ end
+
+ -- # Skip over [...] items
+ local idx = 0
+ local target = ''
+ while 1 do
+ if idx >= vim9.fn.len(items) then
+ target = ''
+ break
+ end
+ if vim9.index(vim9.index(items, idx), 0) ~= '[' then
+ target = vim9.index(items, idx)
+ break
+ end
+ idx = idx + 1
+ end
+ -- # Put matching members in matches[].
+ local matches = {}
+
+ for _, l in vim9.iter(qflist) do
+ local memb = vim9.fn.matchstr(vim9.index(l, 'text'), '[^\\t]*')
+ if vim9.ops.RegexpMatches(memb, '^' .. target) then
+ -- # Skip matches local to another file.
+ if
+ vim9.fn.match(vim9.index(l, 'text'), '\tfile:') < 0
+ or vim9.fn.bufnr('%')
+ == vim9.fn.bufnr(vim9.fn.matchstr(vim9.index(l, 'text'), '\\t\\zs[^\\t]*'))
+ then
+ local item =
+ vim9.convert.decl_dict({ ['match'] = memb, ['tagline'] = vim9.index(l, 'text') })
+
+ -- # Add the kind of item.
+ local s =
+ vim9.fn.matchstr(vim9.index(l, 'text'), '\\t\\(kind:\\)\\=\\zs\\S\\ze\\(\\t\\|$\\)')
+ if s ~= '' then
+ item[vim9.index_expr('kind')] = s
+ if s == 'f' then
+ item[vim9.index_expr('match')] = memb .. '('
+ end
+ end
+
+ vim9.fn.add(matches, item)
+ end
+ end
+ end
+
+ if vim9.fn.len(matches) > 0 then
+ -- # Skip over next [...] items
+ idx = idx + 1
+ while 1 do
+ if idx >= vim9.fn.len(items) then
+ return matches
+ end
+ if vim9.index(vim9.index(items, idx), 0) ~= '[' then
+ break
+ end
+ idx = idx + 1
+ end
+
+ -- # More items following. For each of the possible members find the
+ -- # matching following members.
+ return SearchMembers(matches, vim9.slice(items, idx, nil), all)
+ end
+
+ -- # Failed to find anything.
+ return {}
+end
+
+SearchMembers = function(matches, items, all)
+ all = vim9.bool(all)
+
+ -- # For matching members, find matches for following items.
+ -- # When "all" is true find all, otherwise just return 1 if there is any member.
+ local res = {}
+
+ for _, i in vim9.iter(vim9.fn.range(vim9.fn.len(matches))) do
+ local typename = ''
+ local line = ''
+ if vim9.bool(vim9.fn.has_key(vim9.index(matches, i), 'dict')) then
+ if vim9.bool(vim9.fn.has_key(vim9.index(vim9.index(matches, i), 'dict'), 'typename')) then
+ typename = vim9.index(vim9.index(vim9.index(matches, i), 'dict'), 'typename')
+ elseif vim9.bool(vim9.fn.has_key(vim9.index(vim9.index(matches, i), 'dict'), 'typeref')) then
+ typename = vim9.index(vim9.index(vim9.index(matches, i), 'dict'), 'typeref')
+ end
+ line = '\t' .. vim9.index(vim9.index(vim9.index(matches, i), 'dict'), 'cmd')
+ else
+ line = vim9.index(vim9.index(matches, i), 'tagline')
+ local eb = vim9.fn.matchend(line, '\\ttypename:')
+ local e = vim9.fn.charidx(line, eb)
+ if e < 0 then
+ eb = vim9.fn.matchend(line, '\\ttyperef:')
+ e = vim9.fn.charidx(line, eb)
+ end
+ if e > 0 then
+ -- # Use typename field
+ typename = vim9.fn.matchstr(line, '[^\\t]*', eb)
+ end
+ end
+
+ if typename ~= '' then
+ res = vim9.fn.extend(res, StructMembers(typename, items, all))
+ else
+ -- # Use the search command (the declaration itself).
+ local sb = vim9.fn.match(line, '\\t\\zs/^')
+ local s = vim9.fn.charidx(line, sb)
+ if s > 0 then
+ local e = vim9.fn.charidx(
+ line,
+ vim9.fn.match(line, '\\<' .. vim9.index(vim9.index(matches, i), 'match') .. '\\>', sb)
+ )
+ if e > 0 then
+ res =
+ vim9.fn.extend(res, Nextitem(vim9.slice(line, s, vim9.ops.Minus(e, 1)), items, 0, all))
+ end
+ end
+ end
+ if vim9.bool(vim9.ops.And(vim9.prefix['Bang'](all), vim9.fn.len(res) > 0)) then
+ break
+ end
+ end
+
+ return res
+end
+
+-- #}}}1
+
+-- # vim: noet sw=2 sts=2
+return M
diff --git a/runtime/autoload/ccomplete.vim b/runtime/autoload/ccomplete.vim
index 95a20e16b0..d7e0ba4ac5 100644
--- a/runtime/autoload/ccomplete.vim
+++ b/runtime/autoload/ccomplete.vim
@@ -1,639 +1,8 @@
-" Vim completion script
-" Language: C
-" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2020 Nov 14
-
-let s:cpo_save = &cpo
-set cpo&vim
-
-" This function is used for the 'omnifunc' option.
-func ccomplete#Complete(findstart, base)
- if a:findstart
- " Locate the start of the item, including ".", "->" and "[...]".
- let line = getline('.')
- let start = col('.') - 1
- let lastword = -1
- while start > 0
- if line[start - 1] =~ '\w'
- let start -= 1
- elseif line[start - 1] =~ '\.'
- if lastword == -1
- let lastword = start
- endif
- let start -= 1
- elseif start > 1 && line[start - 2] == '-' && line[start - 1] == '>'
- if lastword == -1
- let lastword = start
- endif
- let start -= 2
- elseif line[start - 1] == ']'
- " Skip over [...].
- let n = 0
- let start -= 1
- while start > 0
- let start -= 1
- if line[start] == '['
- if n == 0
- break
- endif
- let n -= 1
- elseif line[start] == ']' " nested []
- let n += 1
- endif
- endwhile
- else
- break
- endif
- endwhile
-
- " Return the column of the last word, which is going to be changed.
- " Remember the text that comes before it in s:prepended.
- if lastword == -1
- let s:prepended = ''
- return start
- endif
- let s:prepended = strpart(line, start, lastword - start)
- return lastword
- endif
-
- " Return list of matches.
-
- let base = s:prepended . a:base
-
- " Don't do anything for an empty base, would result in all the tags in the
- " tags file.
- if base == ''
- return []
- endif
-
- " init cache for vimgrep to empty
- let s:grepCache = {}
-
- " Split item in words, keep empty word after "." or "->".
- " "aa" -> ['aa'], "aa." -> ['aa', ''], "aa.bb" -> ['aa', 'bb'], etc.
- " We can't use split, because we need to skip nested [...].
- " "aa[...]" -> ['aa', '[...]'], "aa.bb[...]" -> ['aa', 'bb', '[...]'], etc.
- let items = []
- let s = 0
- let arrays = 0
- while 1
- let e = match(base, '\.\|->\|\[', s)
- if e < 0
- if s == 0 || base[s - 1] != ']'
- call add(items, strpart(base, s))
- endif
- break
- endif
- if s == 0 || base[s - 1] != ']'
- call add(items, strpart(base, s, e - s))
- endif
- if base[e] == '.'
- let s = e + 1 " skip over '.'
- elseif base[e] == '-'
- let s = e + 2 " skip over '->'
- else
- " Skip over [...].
- let n = 0
- let s = e
- let e += 1
- while e < len(base)
- if base[e] == ']'
- if n == 0
- break
- endif
- let n -= 1
- elseif base[e] == '[' " nested [...]
- let n += 1
- endif
- let e += 1
- endwhile
- let e += 1
- call add(items, strpart(base, s, e - s))
- let arrays += 1
- let s = e
- endif
- endwhile
-
- " Find the variable items[0].
- " 1. in current function (like with "gd")
- " 2. in tags file(s) (like with ":tag")
- " 3. in current file (like with "gD")
- let res = []
- if searchdecl(items[0], 0, 1) == 0
- " Found, now figure out the type.
- " TODO: join previous line if it makes sense
- let line = getline('.')
- let col = col('.')
- if stridx(strpart(line, 0, col), ';') != -1
- " Handle multiple declarations on the same line.
- let col2 = col - 1
- while line[col2] != ';'
- let col2 -= 1
- endwhile
- let line = strpart(line, col2 + 1)
- let col -= col2
- endif
- if stridx(strpart(line, 0, col), ',') != -1
- " Handle multiple declarations on the same line in a function
- " declaration.
- let col2 = col - 1
- while line[col2] != ','
- let col2 -= 1
- endwhile
- if strpart(line, col2 + 1, col - col2 - 1) =~ ' *[^ ][^ ]* *[^ ]'
- let line = strpart(line, col2 + 1)
- let col -= col2
- endif
- endif
- if len(items) == 1
- " Completing one word and it's a local variable: May add '[', '.' or
- " '->'.
- let match = items[0]
- let kind = 'v'
- if match(line, '\<' . match . '\s*\[') > 0
- let match .= '['
- else
- let res = s:Nextitem(strpart(line, 0, col), [''], 0, 1)
- if len(res) > 0
- " There are members, thus add "." or "->".
- if match(line, '\*[ \t(]*' . match . '\>') > 0
- let match .= '->'
- else
- let match .= '.'
- endif
- endif
- endif
- let res = [{'match': match, 'tagline' : '', 'kind' : kind, 'info' : line}]
- elseif len(items) == arrays + 1
- " Completing one word and it's a local array variable: build tagline
- " from declaration line
- let match = items[0]
- let kind = 'v'
- let tagline = "\t/^" . line . '$/'
- let res = [{'match': match, 'tagline' : tagline, 'kind' : kind, 'info' : line}]
- else
- " Completing "var.", "var.something", etc.
- let res = s:Nextitem(strpart(line, 0, col), items[1:], 0, 1)
- endif
- endif
-
- if len(items) == 1 || len(items) == arrays + 1
- " Only one part, no "." or "->": complete from tags file.
- if len(items) == 1
- let tags = taglist('^' . base)
- else
- let tags = taglist('^' . items[0] . '$')
- endif
-
- " Remove members, these can't appear without something in front.
- call filter(tags, 'has_key(v:val, "kind") ? v:val["kind"] != "m" : 1')
-
- " Remove static matches in other files.
- call filter(tags, '!has_key(v:val, "static") || !v:val["static"] || bufnr("%") == bufnr(v:val["filename"])')
-
- call extend(res, map(tags, 's:Tag2item(v:val)'))
- endif
-
- if len(res) == 0
- " Find the variable in the tags file(s)
- let diclist = taglist('^' . items[0] . '$')
-
- " Remove members, these can't appear without something in front.
- call filter(diclist, 'has_key(v:val, "kind") ? v:val["kind"] != "m" : 1')
-
- let res = []
- for i in range(len(diclist))
- " New ctags has the "typeref" field. Patched version has "typename".
- if has_key(diclist[i], 'typename')
- call extend(res, s:StructMembers(diclist[i]['typename'], items[1:], 1))
- elseif has_key(diclist[i], 'typeref')
- call extend(res, s:StructMembers(diclist[i]['typeref'], items[1:], 1))
- endif
-
- " For a variable use the command, which must be a search pattern that
- " shows the declaration of the variable.
- if diclist[i]['kind'] == 'v'
- let line = diclist[i]['cmd']
- if line[0] == '/' && line[1] == '^'
- let col = match(line, '\<' . items[0] . '\>')
- call extend(res, s:Nextitem(strpart(line, 2, col - 2), items[1:], 0, 1))
- endif
- endif
- endfor
- endif
-
- if len(res) == 0 && searchdecl(items[0], 1) == 0
- " Found, now figure out the type.
- " TODO: join previous line if it makes sense
- let line = getline('.')
- let col = col('.')
- let res = s:Nextitem(strpart(line, 0, col), items[1:], 0, 1)
- endif
-
- " If the last item(s) are [...] they need to be added to the matches.
- let last = len(items) - 1
- let brackets = ''
- while last >= 0
- if items[last][0] != '['
- break
- endif
- let brackets = items[last] . brackets
- let last -= 1
- endwhile
-
- return map(res, 's:Tagline2item(v:val, brackets)')
-endfunc
-
-func s:GetAddition(line, match, memarg, bracket)
- " Guess if the item is an array.
- if a:bracket && match(a:line, a:match . '\s*\[') > 0
- return '['
- endif
-
- " Check if the item has members.
- if len(s:SearchMembers(a:memarg, [''], 0)) > 0
- " If there is a '*' before the name use "->".
- if match(a:line, '\*[ \t(]*' . a:match . '\>') > 0
- return '->'
- else
- return '.'
- endif
- endif
- return ''
-endfunc
-
-" Turn the tag info "val" into an item for completion.
-" "val" is is an item in the list returned by taglist().
-" If it is a variable we may add "." or "->". Don't do it for other types,
-" such as a typedef, by not including the info that s:GetAddition() uses.
-func s:Tag2item(val)
- let res = {'match': a:val['name']}
-
- let res['extra'] = s:Tagcmd2extra(a:val['cmd'], a:val['name'], a:val['filename'])
-
- let s = s:Dict2info(a:val)
- if s != ''
- let res['info'] = s
- endif
-
- let res['tagline'] = ''
- if has_key(a:val, "kind")
- let kind = a:val['kind']
- let res['kind'] = kind
- if kind == 'v'
- let res['tagline'] = "\t" . a:val['cmd']
- let res['dict'] = a:val
- elseif kind == 'f'
- let res['match'] = a:val['name'] . '('
- endif
- endif
-
- return res
-endfunc
-
-" Use all the items in dictionary for the "info" entry.
-func s:Dict2info(dict)
- let info = ''
- for k in sort(keys(a:dict))
- let info .= k . repeat(' ', 10 - len(k))
- if k == 'cmd'
- let info .= substitute(matchstr(a:dict['cmd'], '/^\s*\zs.*\ze$/'), '\\\(.\)', '\1', 'g')
- else
- let info .= a:dict[k]
- endif
- let info .= "\n"
- endfor
- return info
-endfunc
-
-" Parse a tag line and return a dictionary with items like taglist()
-func s:ParseTagline(line)
- let l = split(a:line, "\t")
- let d = {}
- if len(l) >= 3
- let d['name'] = l[0]
- let d['filename'] = l[1]
- let d['cmd'] = l[2]
- let n = 2
- if l[2] =~ '^/'
- " Find end of cmd, it may contain Tabs.
- while n < len(l) && l[n] !~ '/;"$'
- let n += 1
- let d['cmd'] .= " " . l[n]
- endwhile
- endif
- for i in range(n + 1, len(l) - 1)
- if l[i] == 'file:'
- let d['static'] = 1
- elseif l[i] !~ ':'
- let d['kind'] = l[i]
- else
- let d[matchstr(l[i], '[^:]*')] = matchstr(l[i], ':\zs.*')
- endif
- endfor
- endif
-
- return d
-endfunc
-
-" Turn a match item "val" into an item for completion.
-" "val['match']" is the matching item.
-" "val['tagline']" is the tagline in which the last part was found.
-func s:Tagline2item(val, brackets)
- let line = a:val['tagline']
- let add = s:GetAddition(line, a:val['match'], [a:val], a:brackets == '')
- let res = {'word': a:val['match'] . a:brackets . add }
-
- if has_key(a:val, 'info')
- " Use info from Tag2item().
- let res['info'] = a:val['info']
- else
- " Parse the tag line and add each part to the "info" entry.
- let s = s:Dict2info(s:ParseTagline(line))
- if s != ''
- let res['info'] = s
- endif
- endif
-
- if has_key(a:val, 'kind')
- let res['kind'] = a:val['kind']
- elseif add == '('
- let res['kind'] = 'f'
- else
- let s = matchstr(line, '\t\(kind:\)\=\zs\S\ze\(\t\|$\)')
- if s != ''
- let res['kind'] = s
- endif
- endif
-
- if has_key(a:val, 'extra')
- let res['menu'] = a:val['extra']
- return res
- endif
-
- " Isolate the command after the tag and filename.
- let s = matchstr(line, '[^\t]*\t[^\t]*\t\zs\(/^.*$/\|[^\t]*\)\ze\(;"\t\|\t\|$\)')
- if s != ''
- let res['menu'] = s:Tagcmd2extra(s, a:val['match'], matchstr(line, '[^\t]*\t\zs[^\t]*\ze\t'))
- endif
- return res
-endfunc
-
-" Turn a command from a tag line to something that is useful in the menu
-func s:Tagcmd2extra(cmd, name, fname)
- if a:cmd =~ '^/^'
- " The command is a search command, useful to see what it is.
- let x = matchstr(a:cmd, '^/^\s*\zs.*\ze$/')
- let x = substitute(x, '\<' . a:name . '\>', '@@', '')
- let x = substitute(x, '\\\(.\)', '\1', 'g')
- let x = x . ' - ' . a:fname
- elseif a:cmd =~ '^\d*$'
- " The command is a line number, the file name is more useful.
- let x = a:fname . ' - ' . a:cmd
- else
- " Not recognized, use command and file name.
- let x = a:cmd . ' - ' . a:fname
- endif
- return x
-endfunc
-
-" Find composing type in "lead" and match items[0] with it.
-" Repeat this recursively for items[1], if it's there.
-" When resolving typedefs "depth" is used to avoid infinite recursion.
-" Return the list of matches.
-func s:Nextitem(lead, items, depth, all)
-
- " Use the text up to the variable name and split it in tokens.
- let tokens = split(a:lead, '\s\+\|\<')
-
- " Try to recognize the type of the variable. This is rough guessing...
- let res = []
- for tidx in range(len(tokens))
-
- " Skip tokens starting with a non-ID character.
- if tokens[tidx] !~ '^\h'
- continue
- endif
-
- " Recognize "struct foobar" and "union foobar".
- " Also do "class foobar" when it's C++ after all (doesn't work very well
- " though).
- if (tokens[tidx] == 'struct' || tokens[tidx] == 'union' || tokens[tidx] == 'class') && tidx + 1 < len(tokens)
- let res = s:StructMembers(tokens[tidx] . ':' . tokens[tidx + 1], a:items, a:all)
- break
- endif
-
- " TODO: add more reserved words
- if index(['int', 'short', 'char', 'float', 'double', 'static', 'unsigned', 'extern'], tokens[tidx]) >= 0
- continue
- endif
-
- " Use the tags file to find out if this is a typedef.
- let diclist = taglist('^' . tokens[tidx] . '$')
- for tagidx in range(len(diclist))
- let item = diclist[tagidx]
-
- " New ctags has the "typeref" field. Patched version has "typename".
- if has_key(item, 'typeref')
- call extend(res, s:StructMembers(item['typeref'], a:items, a:all))
- continue
- endif
- if has_key(item, 'typename')
- call extend(res, s:StructMembers(item['typename'], a:items, a:all))
- continue
- endif
-
- " Only handle typedefs here.
- if item['kind'] != 't'
- continue
- endif
-
- " Skip matches local to another file.
- if has_key(item, 'static') && item['static'] && bufnr('%') != bufnr(item['filename'])
- continue
- endif
-
- " For old ctags we recognize "typedef struct aaa" and
- " "typedef union bbb" in the tags file command.
- let cmd = item['cmd']
- let ei = matchend(cmd, 'typedef\s\+')
- if ei > 1
- let cmdtokens = split(strpart(cmd, ei), '\s\+\|\<')
- if len(cmdtokens) > 1
- if cmdtokens[0] == 'struct' || cmdtokens[0] == 'union' || cmdtokens[0] == 'class'
- let name = ''
- " Use the first identifier after the "struct" or "union"
- for ti in range(len(cmdtokens) - 1)
- if cmdtokens[ti] =~ '^\w'
- let name = cmdtokens[ti]
- break
- endif
- endfor
- if name != ''
- call extend(res, s:StructMembers(cmdtokens[0] . ':' . name, a:items, a:all))
- endif
- elseif a:depth < 10
- " Could be "typedef other_T some_T".
- call extend(res, s:Nextitem(cmdtokens[0], a:items, a:depth + 1, a:all))
- endif
- endif
- endif
- endfor
- if len(res) > 0
- break
- endif
- endfor
-
- return res
-endfunc
-
-
-" Search for members of structure "typename" in tags files.
-" Return a list with resulting matches.
-" Each match is a dictionary with "match" and "tagline" entries.
-" When "all" is non-zero find all, otherwise just return 1 if there is any
-" member.
-func s:StructMembers(typename, items, all)
- " Todo: What about local structures?
- let fnames = join(map(tagfiles(), 'escape(v:val, " \\#%")'))
- if fnames == ''
- return []
- endif
-
- let typename = a:typename
- let qflist = []
- let cached = 0
- if a:all == 0
- let n = '1' " stop at first found match
- if has_key(s:grepCache, a:typename)
- let qflist = s:grepCache[a:typename]
- let cached = 1
- endif
- else
- let n = ''
- endif
- if !cached
- while 1
- exe 'silent! keepj noautocmd ' . n . 'vimgrep /\t' . typename . '\(\t\|$\)/j ' . fnames
-
- let qflist = getqflist()
- if len(qflist) > 0 || match(typename, "::") < 0
- break
- endif
- " No match for "struct:context::name", remove "context::" and try again.
- let typename = substitute(typename, ':[^:]*::', ':', '')
- endwhile
-
- if a:all == 0
- " Store the result to be able to use it again later.
- let s:grepCache[a:typename] = qflist
- endif
- endif
-
- " Skip over [...] items
- let idx = 0
- while 1
- if idx >= len(a:items)
- let target = '' " No further items, matching all members
- break
- endif
- if a:items[idx][0] != '['
- let target = a:items[idx]
- break
- endif
- let idx += 1
- endwhile
- " Put matching members in matches[].
- let matches = []
- for l in qflist
- let memb = matchstr(l['text'], '[^\t]*')
- if memb =~ '^' . target
- " Skip matches local to another file.
- if match(l['text'], "\tfile:") < 0 || bufnr('%') == bufnr(matchstr(l['text'], '\t\zs[^\t]*'))
- let item = {'match': memb, 'tagline': l['text']}
-
- " Add the kind of item.
- let s = matchstr(l['text'], '\t\(kind:\)\=\zs\S\ze\(\t\|$\)')
- if s != ''
- let item['kind'] = s
- if s == 'f'
- let item['match'] = memb . '('
- endif
- endif
-
- call add(matches, item)
- endif
- endif
- endfor
-
- if len(matches) > 0
- " Skip over next [...] items
- let idx += 1
- while 1
- if idx >= len(a:items)
- return matches " No further items, return the result.
- endif
- if a:items[idx][0] != '['
- break
- endif
- let idx += 1
- endwhile
-
- " More items following. For each of the possible members find the
- " matching following members.
- return s:SearchMembers(matches, a:items[idx :], a:all)
- endif
-
- " Failed to find anything.
- return []
-endfunc
-
-" For matching members, find matches for following items.
-" When "all" is non-zero find all, otherwise just return 1 if there is any
-" member.
-func s:SearchMembers(matches, items, all)
- let res = []
- for i in range(len(a:matches))
- let typename = ''
- if has_key(a:matches[i], 'dict')
- if has_key(a:matches[i].dict, 'typename')
- let typename = a:matches[i].dict['typename']
- elseif has_key(a:matches[i].dict, 'typeref')
- let typename = a:matches[i].dict['typeref']
- endif
- let line = "\t" . a:matches[i].dict['cmd']
- else
- let line = a:matches[i]['tagline']
- let e = matchend(line, '\ttypename:')
- if e < 0
- let e = matchend(line, '\ttyperef:')
- endif
- if e > 0
- " Use typename field
- let typename = matchstr(line, '[^\t]*', e)
- endif
- endif
-
- if typename != ''
- call extend(res, s:StructMembers(typename, a:items, a:all))
- else
- " Use the search command (the declaration itself).
- let s = match(line, '\t\zs/^')
- if s > 0
- let e = match(line, '\<' . a:matches[i]['match'] . '\>', s)
- if e > 0
- call extend(res, s:Nextitem(strpart(line, s, e - s), a:items, 0, a:all))
- endif
- endif
- endif
- if a:all == 0 && len(res) > 0
- break
- endif
- endfor
- return res
-endfunc
-
-let &cpo = s:cpo_save
-unlet s:cpo_save
-
-" vim: noet sw=2 sts=2
+" Generated vim file by vim9jit. Please do not edit
+let s:path = expand("<script>")
+let s:lua_path = fnamemodify(s:path, ":r") . ".lua"
+let s:nvim_module = luaeval('require("_vim9script").autoload(_A)', s:lua_path)
+
+function! ccomplete#Complete(findstart, abase) abort
+ return s:nvim_module.Complete(a:findstart, a:abase)
+endfunction
diff --git a/runtime/autoload/dist/ft.vim b/runtime/autoload/dist/ft.vim
deleted file mode 100644
index 77140d62b1..0000000000
--- a/runtime/autoload/dist/ft.vim
+++ /dev/null
@@ -1,1073 +0,0 @@
-" Vim functions for file type detection
-"
-" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2022 Apr 13
-
-" These functions are moved here from runtime/filetype.vim to make startup
-" faster.
-
-" Line continuation is used here, remove 'C' from 'cpoptions'
-let s:cpo_save = &cpo
-set cpo&vim
-
-func dist#ft#Check_inp()
- if getline(1) =~ '^\*'
- setf abaqus
- else
- let n = 1
- if line("$") > 500
- let nmax = 500
- else
- let nmax = line("$")
- endif
- while n <= nmax
- if getline(n) =~? "^header surface data"
- setf trasys
- break
- endif
- let n = n + 1
- endwhile
- endif
-endfunc
-
-" This function checks for the kind of assembly that is wanted by the user, or
-" can be detected from the first five lines of the file.
-func dist#ft#FTasm()
- " make sure b:asmsyntax exists
- if !exists("b:asmsyntax")
- let b:asmsyntax = ""
- endif
-
- if b:asmsyntax == ""
- call dist#ft#FTasmsyntax()
- endif
-
- " if b:asmsyntax still isn't set, default to asmsyntax or GNU
- if b:asmsyntax == ""
- if exists("g:asmsyntax")
- let b:asmsyntax = g:asmsyntax
- else
- let b:asmsyntax = "asm"
- endif
- endif
-
- exe "setf " . fnameescape(b:asmsyntax)
-endfunc
-
-func dist#ft#FTasmsyntax()
- " see if file contains any asmsyntax=foo overrides. If so, change
- " b:asmsyntax appropriately
- let head = " ".getline(1)." ".getline(2)." ".getline(3)." ".getline(4).
- \" ".getline(5)." "
- let match = matchstr(head, '\sasmsyntax=\zs[a-zA-Z0-9]\+\ze\s')
- if match != ''
- let b:asmsyntax = match
- elseif ((head =~? '\.title') || (head =~? '\.ident') || (head =~? '\.macro') || (head =~? '\.subtitle') || (head =~? '\.library'))
- let b:asmsyntax = "vmasm"
- endif
-endfunc
-
-let s:ft_visual_basic_content = '\cVB_Name\|Begin VB\.\(Form\|MDIForm\|UserControl\)'
-
-" See FTfrm() for Visual Basic form file detection
-func dist#ft#FTbas()
- if exists("g:filetype_bas")
- exe "setf " . g:filetype_bas
- return
- endif
-
- " most frequent FreeBASIC-specific keywords in distro files
- let fb_keywords = '\c^\s*\%(extern\|var\|enum\|private\|scope\|union\|byref\|operator\|constructor\|delete\|namespace\|public\|property\|with\|destructor\|using\)\>\%(\s*[:=(]\)\@!'
- let fb_preproc = '\c^\s*\%(' ..
- \ '#\s*\a\+\|' ..
- \ 'option\s\+\%(byval\|dynamic\|escape\|\%(no\)\=gosub\|nokeyword\|private\|static\)\>\|' ..
- \ '\%(''\|rem\)\s*\$lang\>\|' ..
- \ 'def\%(byte\|longint\|short\|ubyte\|uint\|ulongint\|ushort\)\>' ..
- \ '\)'
- let fb_comment = "^\\s*/'"
- " OPTION EXPLICIT, without the leading underscore, is common to many dialects
- let qb64_preproc = '\c^\s*\%($\a\+\|option\s\+\%(_explicit\|_\=explicitarray\)\>\)'
-
- for lnum in range(1, min([line("$"), 100]))
- let line = getline(lnum)
- if line =~ s:ft_visual_basic_content
- setf vb
- return
- elseif line =~ fb_preproc || line =~ fb_comment || line =~ fb_keywords
- setf freebasic
- return
- elseif line =~ qb64_preproc
- setf qb64
- return
- endif
- endfor
- setf basic
-endfunc
-
-func dist#ft#FTbtm()
- if exists("g:dosbatch_syntax_for_btm") && g:dosbatch_syntax_for_btm
- setf dosbatch
- else
- setf btm
- endif
-endfunc
-
-func dist#ft#BindzoneCheck(default)
- if getline(1).getline(2).getline(3).getline(4) =~ '^; <<>> DiG [0-9.]\+.* <<>>\|$ORIGIN\|$TTL\|IN\s\+SOA'
- setf bindzone
- elseif a:default != ''
- exe 'setf ' . a:default
- endif
-endfunc
-
-" Returns true if file content looks like RAPID
-func IsRapid(sChkExt = "")
- if a:sChkExt == "cfg"
- return getline(1) =~? '\v^%(EIO|MMC|MOC|PROC|SIO|SYS):CFG'
- endif
- " called from FTmod, FTprg or FTsys
- return getline(nextnonblank(1)) =~? '\v^\s*%(\%{3}|module\s+\k+\s*%(\(|$))'
-endfunc
-
-func dist#ft#FTcfg()
- if exists("g:filetype_cfg")
- exe "setf " .. g:filetype_cfg
- elseif IsRapid("cfg")
- setf rapid
- else
- setf cfg
- endif
-endfunc
-
-func dist#ft#FTcls()
- if exists("g:filetype_cls")
- exe "setf " .. g:filetype_cls
- return
- endif
-
- if getline(1) =~ '^%'
- setf tex
- elseif getline(1)[0] == '#' && getline(1) =~ 'rexx'
- setf rexx
- elseif getline(1) == 'VERSION 1.0 CLASS'
- setf vb
- else
- setf st
- endif
-endfunc
-
-func dist#ft#FTlpc()
- if exists("g:lpc_syntax_for_c")
- let lnum = 1
- while lnum <= 12
- if getline(lnum) =~# '^\(//\|inherit\|private\|protected\|nosave\|string\|object\|mapping\|mixed\)'
- setf lpc
- return
- endif
- let lnum = lnum + 1
- endwhile
- endif
- setf c
-endfunc
-
-func dist#ft#FTheader()
- if match(getline(1, min([line("$"), 200])), '^@\(interface\|end\|class\)') > -1
- if exists("g:c_syntax_for_h")
- setf objc
- else
- setf objcpp
- endif
- elseif exists("g:c_syntax_for_h")
- setf c
- elseif exists("g:ch_syntax_for_h")
- setf ch
- else
- setf cpp
- endif
-endfunc
-
-" This function checks if one of the first ten lines start with a '@'. In
-" that case it is probably a change file.
-" If the first line starts with # or ! it's probably a ch file.
-" If a line has "main", "include", "//" or "/*" it's probably ch.
-" Otherwise CHILL is assumed.
-func dist#ft#FTchange()
- let lnum = 1
- while lnum <= 10
- if getline(lnum)[0] == '@'
- setf change
- return
- endif
- if lnum == 1 && (getline(1)[0] == '#' || getline(1)[0] == '!')
- setf ch
- return
- endif
- if getline(lnum) =~ "MODULE"
- setf chill
- return
- endif
- if getline(lnum) =~ 'main\s*(\|#\s*include\|//'
- setf ch
- return
- endif
- let lnum = lnum + 1
- endwhile
- setf chill
-endfunc
-
-func dist#ft#FTent()
- " This function checks for valid cl syntax in the first five lines.
- " Look for either an opening comment, '#', or a block start, '{'.
- " If not found, assume SGML.
- let lnum = 1
- while lnum < 6
- let line = getline(lnum)
- if line =~ '^\s*[#{]'
- setf cl
- return
- elseif line !~ '^\s*$'
- " Not a blank line, not a comment, and not a block start,
- " so doesn't look like valid cl code.
- break
- endif
- let lnum = lnum + 1
- endw
- setf dtd
-endfunc
-
-func dist#ft#ExCheck()
- let lines = getline(1, min([line("$"), 100]))
- if exists('g:filetype_euphoria')
- exe 'setf ' . g:filetype_euphoria
- elseif match(lines, '^--\|^ifdef\>\|^include\>') > -1
- setf euphoria3
- else
- setf elixir
- endif
-endfunc
-
-func dist#ft#EuphoriaCheck()
- if exists('g:filetype_euphoria')
- exe 'setf ' . g:filetype_euphoria
- else
- setf euphoria3
- endif
-endfunc
-
-func dist#ft#DtraceCheck()
- if did_filetype()
- " Filetype was already detected
- return
- endif
- let lines = getline(1, min([line("$"), 100]))
- if match(lines, '^module\>\|^import\>') > -1
- " D files often start with a module and/or import statement.
- setf d
- elseif match(lines, '^#!\S\+dtrace\|#pragma\s\+D\s\+option\|:\S\{-}:\S\{-}:') > -1
- setf dtrace
- else
- setf d
- endif
-endfunc
-
-func dist#ft#FTe()
- if exists('g:filetype_euphoria')
- exe 'setf ' . g:filetype_euphoria
- else
- let n = 1
- while n < 100 && n <= line("$")
- if getline(n) =~ "^\\s*\\(<'\\|'>\\)\\s*$"
- setf specman
- return
- endif
- let n = n + 1
- endwhile
- setf eiffel
- endif
-endfunc
-
-func dist#ft#FTfrm()
- if exists("g:filetype_frm")
- exe "setf " . g:filetype_frm
- return
- endif
-
- let lines = getline(1, min([line("$"), 5]))
-
- if match(lines, s:ft_visual_basic_content) > -1
- setf vb
- else
- setf form
- endif
-endfunc
-
-" Distinguish between Forth and F#.
-" Provided by Doug Kearns.
-func dist#ft#FTfs()
- if exists("g:filetype_fs")
- exe "setf " . g:filetype_fs
- else
- let line = getline(nextnonblank(1))
- " comments and colon definitions
- if line =~ '^\s*\.\=( ' || line =~ '^\s*\\G\= ' || line =~ '^\\$'
- \ || line =~ '^\s*: \S'
- setf forth
- else
- setf fsharp
- endif
- endif
-endfunc
-
-" Distinguish between HTML, XHTML and Django
-func dist#ft#FThtml()
- let n = 1
- while n < 10 && n <= line("$")
- if getline(n) =~ '\<DTD\s\+XHTML\s'
- setf xhtml
- return
- endif
- if getline(n) =~ '{%\s*\(extends\|block\|load\)\>\|{#\s\+'
- setf htmldjango
- return
- endif
- let n = n + 1
- endwhile
- setf FALLBACK html
-endfunc
-
-" Distinguish between standard IDL and MS-IDL
-func dist#ft#FTidl()
- let n = 1
- while n < 50 && n <= line("$")
- if getline(n) =~ '^\s*import\s\+"\(unknwn\|objidl\)\.idl"'
- setf msidl
- return
- endif
- let n = n + 1
- endwhile
- setf idl
-endfunc
-
-" Distinguish between "default", Prolog and Cproto prototype file. */
-func dist#ft#ProtoCheck(default)
- " Cproto files have a comment in the first line and a function prototype in
- " the second line, it always ends in ";". Indent files may also have
- " comments, thus we can't match comments to see the difference.
- " IDL files can have a single ';' in the second line, require at least one
- " chacter before the ';'.
- if getline(2) =~ '.;$'
- setf cpp
- else
- " recognize Prolog by specific text in the first non-empty line
- " require a blank after the '%' because Perl uses "%list" and "%translate"
- let l = getline(nextnonblank(1))
- if l =~ '\<prolog\>' || l =~ '^\s*\(%\+\(\s\|$\)\|/\*\)' || l =~ ':-'
- setf prolog
- else
- exe 'setf ' .. a:default
- endif
- endif
-endfunc
-
-func dist#ft#FTm()
- if exists("g:filetype_m")
- exe "setf " . g:filetype_m
- return
- endif
-
- " excluding end(for|function|if|switch|while) common to Murphi
- let octave_block_terminators = '\<end\%(_try_catch\|classdef\|enumeration\|events\|methods\|parfor\|properties\)\>'
-
- let objc_preprocessor = '^\s*#\s*\%(import\|include\|define\|if\|ifn\=def\|undef\|line\|error\|pragma\)\>'
-
- let n = 1
- let saw_comment = 0 " Whether we've seen a multiline comment leader.
- while n < 100
- let line = getline(n)
- if line =~ '^\s*/\*'
- " /* ... */ is a comment in Objective C and Murphi, so we can't conclude
- " it's either of them yet, but track this as a hint in case we don't see
- " anything more definitive.
- let saw_comment = 1
- endif
- if line =~ '^\s*//' || line =~ '^\s*@import\>' || line =~ objc_preprocessor
- setf objc
- return
- endif
- if line =~ '^\s*\%(#\|%!\)' || line =~ '^\s*unwind_protect\>' ||
- \ line =~ '\%(^\|;\)\s*' .. octave_block_terminators
- setf octave
- return
- endif
- " TODO: could be Matlab or Octave
- if line =~ '^\s*%'
- setf matlab
- return
- endif
- if line =~ '^\s*(\*'
- setf mma
- return
- endif
- if line =~ '^\c\s*\(\(type\|var\)\>\|--\)'
- setf murphi
- return
- endif
- let n = n + 1
- endwhile
-
- if saw_comment
- " We didn't see anything definitive, but this looks like either Objective C
- " or Murphi based on the comment leader. Assume the former as it is more
- " common.
- setf objc
- else
- " Default is Matlab
- setf matlab
- endif
-endfunc
-
-func dist#ft#FTmms()
- let n = 1
- while n < 20
- let line = getline(n)
- if line =~ '^\s*\(%\|//\)' || line =~ '^\*'
- setf mmix
- return
- endif
- if line =~ '^\s*#'
- setf make
- return
- endif
- let n = n + 1
- endwhile
- setf mmix
-endfunc
-
-" This function checks if one of the first five lines start with a dot. In
-" that case it is probably an nroff file: 'filetype' is set and 1 is returned.
-func dist#ft#FTnroff()
- if getline(1)[0] . getline(2)[0] . getline(3)[0] . getline(4)[0] . getline(5)[0] =~ '\.'
- setf nroff
- return 1
- endif
- return 0
-endfunc
-
-func dist#ft#FTmm()
- let n = 1
- while n < 20
- let line = getline(n)
- if line =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|/\*\)'
- setf objcpp
- return
- endif
- let n = n + 1
- endwhile
- setf nroff
-endfunc
-
-" Returns true if file content looks like LambdaProlog module
-func IsLProlog()
- " skip apparent comments and blank lines, what looks like
- " LambdaProlog comment may be RAPID header
- let l = nextnonblank(1)
- while l > 0 && l < line('$') && getline(l) =~ '^\s*%' " LambdaProlog comment
- let l = nextnonblank(l + 1)
- endwhile
- " this pattern must not catch a go.mod file
- return getline(l) =~ '\<module\s\+\w\+\s*\.\s*\(%\|$\)'
-endfunc
-
-" Determine if *.mod is ABB RAPID, LambdaProlog, Modula-2, Modsim III or go.mod
-func dist#ft#FTmod()
- if exists("g:filetype_mod")
- exe "setf " .. g:filetype_mod
- elseif IsLProlog()
- setf lprolog
- elseif getline(nextnonblank(1)) =~ '\%(\<MODULE\s\+\w\+\s*;\|^\s*(\*\)'
- setf modula2
- elseif IsRapid()
- setf rapid
- elseif expand("<afile>") =~ '\<go.mod$'
- setf gomod
- else
- " Nothing recognized, assume modsim3
- setf modsim3
- endif
-endfunc
-
-func dist#ft#FTpl()
- if exists("g:filetype_pl")
- exe "setf " . g:filetype_pl
- else
- " recognize Prolog by specific text in the first non-empty line
- " require a blank after the '%' because Perl uses "%list" and "%translate"
- let l = getline(nextnonblank(1))
- if l =~ '\<prolog\>' || l =~ '^\s*\(%\+\(\s\|$\)\|/\*\)' || l =~ ':-'
- setf prolog
- else
- setf perl
- endif
- endif
-endfunc
-
-func dist#ft#FTinc()
- if exists("g:filetype_inc")
- exe "setf " . g:filetype_inc
- else
- let lines = getline(1).getline(2).getline(3)
- if lines =~? "perlscript"
- setf aspperl
- elseif lines =~ "<%"
- setf aspvbs
- elseif lines =~ "<?"
- setf php
- " Pascal supports // comments but they're vary rarely used for file
- " headers so assume POV-Ray
- elseif lines =~ '^\s*\%({\|(\*\)' || lines =~? s:ft_pascal_keywords
- setf pascal
- elseif lines =~# '\<\%(require\|inherit\)\>' || lines =~# '[A-Z][A-Za-z0-9_:${}]*\s\+\%(??\|[?:+]\)\?= '
- setf bitbake
- else
- call dist#ft#FTasmsyntax()
- if exists("b:asmsyntax")
- exe "setf " . fnameescape(b:asmsyntax)
- else
- setf pov
- endif
- endif
- endif
-endfunc
-
-func dist#ft#FTprogress_cweb()
- if exists("g:filetype_w")
- exe "setf " . g:filetype_w
- return
- endif
- if getline(1) =~ '&ANALYZE' || getline(3) =~ '&GLOBAL-DEFINE'
- setf progress
- else
- setf cweb
- endif
-endfunc
-
-func dist#ft#FTprogress_asm()
- if exists("g:filetype_i")
- exe "setf " . g:filetype_i
- return
- endif
- " This function checks for an assembly comment the first ten lines.
- " If not found, assume Progress.
- let lnum = 1
- while lnum <= 10 && lnum < line('$')
- let line = getline(lnum)
- if line =~ '^\s*;' || line =~ '^\*'
- call dist#ft#FTasm()
- return
- elseif line !~ '^\s*$' || line =~ '^/\*'
- " Not an empty line: Doesn't look like valid assembly code.
- " Or it looks like a Progress /* comment
- break
- endif
- let lnum = lnum + 1
- endw
- setf progress
-endfunc
-
-let s:ft_pascal_comments = '^\s*\%({\|(\*\|//\)'
-let s:ft_pascal_keywords = '^\s*\%(program\|unit\|library\|uses\|begin\|procedure\|function\|const\|type\|var\)\>'
-
-func dist#ft#FTprogress_pascal()
- if exists("g:filetype_p")
- exe "setf " . g:filetype_p
- return
- endif
- " This function checks for valid Pascal syntax in the first ten lines.
- " Look for either an opening comment or a program start.
- " If not found, assume Progress.
- let lnum = 1
- while lnum <= 10 && lnum < line('$')
- let line = getline(lnum)
- if line =~ s:ft_pascal_comments || line =~? s:ft_pascal_keywords
- setf pascal
- return
- elseif line !~ '^\s*$' || line =~ '^/\*'
- " Not an empty line: Doesn't look like valid Pascal code.
- " Or it looks like a Progress /* comment
- break
- endif
- let lnum = lnum + 1
- endw
- setf progress
-endfunc
-
-func dist#ft#FTpp()
- if exists("g:filetype_pp")
- exe "setf " . g:filetype_pp
- else
- let line = getline(nextnonblank(1))
- if line =~ s:ft_pascal_comments || line =~? s:ft_pascal_keywords
- setf pascal
- else
- setf puppet
- endif
- endif
-endfunc
-
-" Determine if *.prg is ABB RAPID. Can also be Clipper, FoxPro or eviews
-func dist#ft#FTprg()
- if exists("g:filetype_prg")
- exe "setf " .. g:filetype_prg
- elseif IsRapid()
- setf rapid
- else
- " Nothing recognized, assume Clipper
- setf clipper
- endif
-endfunc
-
-func dist#ft#FTr()
- let max = line("$") > 50 ? 50 : line("$")
-
- for n in range(1, max)
- " Rebol is easy to recognize, check for that first
- if getline(n) =~? '\<REBOL\>'
- setf rebol
- return
- endif
- endfor
-
- for n in range(1, max)
- " R has # comments
- if getline(n) =~ '^\s*#'
- setf r
- return
- endif
- " Rexx has /* comments */
- if getline(n) =~ '^\s*/\*'
- setf rexx
- return
- endif
- endfor
-
- " Nothing recognized, use user default or assume Rexx
- if exists("g:filetype_r")
- exe "setf " . g:filetype_r
- else
- " Rexx used to be the default, but R appears to be much more popular.
- setf r
- endif
-endfunc
-
-func dist#ft#McSetf()
- " Rely on the file to start with a comment.
- " MS message text files use ';', Sendmail files use '#' or 'dnl'
- for lnum in range(1, min([line("$"), 20]))
- let line = getline(lnum)
- if line =~ '^\s*\(#\|dnl\)'
- setf m4 " Sendmail .mc file
- return
- elseif line =~ '^\s*;'
- setf msmessages " MS Message text file
- return
- endif
- endfor
- setf m4 " Default: Sendmail .mc file
-endfunc
-
-" Called from filetype.vim and scripts.vim.
-func dist#ft#SetFileTypeSH(name)
- if did_filetype()
- " Filetype was already detected
- return
- endif
- if expand("<amatch>") =~ g:ft_ignore_pat
- return
- endif
- if a:name =~ '\<csh\>'
- " Some .sh scripts contain #!/bin/csh.
- call dist#ft#SetFileTypeShell("csh")
- return
- elseif a:name =~ '\<tcsh\>'
- " Some .sh scripts contain #!/bin/tcsh.
- call dist#ft#SetFileTypeShell("tcsh")
- return
- elseif a:name =~ '\<zsh\>'
- " Some .sh scripts contain #!/bin/zsh.
- call dist#ft#SetFileTypeShell("zsh")
- return
- elseif a:name =~ '\<ksh\>'
- let b:is_kornshell = 1
- if exists("b:is_bash")
- unlet b:is_bash
- endif
- if exists("b:is_sh")
- unlet b:is_sh
- endif
- elseif exists("g:bash_is_sh") || a:name =~ '\<bash\>' || a:name =~ '\<bash2\>'
- let b:is_bash = 1
- if exists("b:is_kornshell")
- unlet b:is_kornshell
- endif
- if exists("b:is_sh")
- unlet b:is_sh
- endif
- elseif a:name =~ '\<sh\>'
- let b:is_sh = 1
- if exists("b:is_kornshell")
- unlet b:is_kornshell
- endif
- if exists("b:is_bash")
- unlet b:is_bash
- endif
- endif
- call dist#ft#SetFileTypeShell("sh")
-endfunc
-
-" For shell-like file types, check for an "exec" command hidden in a comment,
-" as used for Tcl.
-" Also called from scripts.vim, thus can't be local to this script.
-func dist#ft#SetFileTypeShell(name)
- if did_filetype()
- " Filetype was already detected
- return
- endif
- if expand("<amatch>") =~ g:ft_ignore_pat
- return
- endif
- let l = 2
- while l < 20 && l < line("$") && getline(l) =~ '^\s*\(#\|$\)'
- " Skip empty and comment lines.
- let l = l + 1
- endwhile
- if l < line("$") && getline(l) =~ '\s*exec\s' && getline(l - 1) =~ '^\s*#.*\\$'
- " Found an "exec" line after a comment with continuation
- let n = substitute(getline(l),'\s*exec\s\+\([^ ]*/\)\=', '', '')
- if n =~ '\<tclsh\|\<wish'
- setf tcl
- return
- endif
- endif
- exe "setf " . a:name
-endfunc
-
-func dist#ft#CSH()
- if did_filetype()
- " Filetype was already detected
- return
- endif
- if exists("g:filetype_csh")
- call dist#ft#SetFileTypeShell(g:filetype_csh)
- elseif &shell =~ "tcsh"
- call dist#ft#SetFileTypeShell("tcsh")
- else
- call dist#ft#SetFileTypeShell("csh")
- endif
-endfunc
-
-let s:ft_rules_udev_rules_pattern = '^\s*\cudev_rules\s*=\s*"\([^"]\{-1,}\)/*".*'
-func dist#ft#FTRules()
- let path = expand('<amatch>:p')
- if path =~ '/\(etc/udev/\%(rules\.d/\)\=.*\.rules\|\%(usr/\)\=lib/udev/\%(rules\.d/\)\=.*\.rules\)$'
- setf udevrules
- return
- endif
- if path =~ '^/etc/ufw/'
- setf conf " Better than hog
- return
- endif
- if path =~ '^/\(etc\|usr/share\)/polkit-1/rules\.d'
- setf javascript
- return
- endif
- try
- let config_lines = readfile('/etc/udev/udev.conf')
- catch /^Vim\%((\a\+)\)\=:E484/
- setf hog
- return
- endtry
- let dir = expand('<amatch>:p:h')
- for line in config_lines
- if line =~ s:ft_rules_udev_rules_pattern
- let udev_rules = substitute(line, s:ft_rules_udev_rules_pattern, '\1', "")
- if dir == udev_rules
- setf udevrules
- endif
- break
- endif
- endfor
- setf hog
-endfunc
-
-func dist#ft#SQL()
- if exists("g:filetype_sql")
- exe "setf " . g:filetype_sql
- else
- setf sql
- endif
-endfunc
-
-" This function checks the first 25 lines of file extension "sc" to resolve
-" detection between scala and SuperCollider
-func dist#ft#FTsc()
- for lnum in range(1, min([line("$"), 25]))
- if getline(lnum) =~# '[A-Za-z0-9]*\s:\s[A-Za-z0-9]\|var\s<\|classvar\s<\|\^this.*\||\w*|\|+\s\w*\s{\|\*ar\s'
- setf supercollider
- return
- endif
- endfor
- setf scala
-endfunc
-
-" This function checks the first line of file extension "scd" to resolve
-" detection between scdoc and SuperCollider
-func dist#ft#FTscd()
- if getline(1) =~# '\%^\S\+(\d[0-9A-Za-z]*)\%(\s\+\"[^"]*\"\%(\s\+\"[^"]*\"\)\=\)\=$'
- setf scdoc
- else
- setf supercollider
- endif
-endfunc
-
-" If the file has an extension of 't' and is in a directory 't' or 'xt' then
-" it is almost certainly a Perl test file.
-" If the first line starts with '#' and contains 'perl' it's probably a Perl
-" file.
-" (Slow test) If a file contains a 'use' statement then it is almost certainly
-" a Perl file.
-func dist#ft#FTperl()
- let dirname = expand("%:p:h:t")
- if expand("%:e") == 't' && (dirname == 't' || dirname == 'xt')
- setf perl
- return 1
- endif
- if getline(1)[0] == '#' && getline(1) =~ 'perl'
- setf perl
- return 1
- endif
- let save_cursor = getpos('.')
- call cursor(1,1)
- let has_use = search('^use\s\s*\k', 'c', 30) > 0
- call setpos('.', save_cursor)
- if has_use
- setf perl
- return 1
- endif
- return 0
-endfunc
-
-" LambdaProlog and Standard ML signature files
-func dist#ft#FTsig()
- if exists("g:filetype_sig")
- exe "setf " .. g:filetype_sig
- return
- endif
-
- let lprolog_comment = '^\s*\%(/\*\|%\)'
- let lprolog_keyword = '^\s*sig\s\+\a'
- let sml_comment = '^\s*(\*'
- let sml_keyword = '^\s*\%(signature\|structure\)\s\+\a'
-
- let line = getline(nextnonblank(1))
-
- if line =~ lprolog_comment || line =~# lprolog_keyword
- setf lprolog
- elseif line =~ sml_comment || line =~# sml_keyword
- setf sml
- endif
-endfunc
-
-func dist#ft#FTsys()
- if exists("g:filetype_sys")
- exe "setf " .. g:filetype_sys
- elseif IsRapid()
- setf rapid
- else
- setf bat
- endif
-endfunc
-
-" Choose context, plaintex, or tex (LaTeX) based on these rules:
-" 1. Check the first line of the file for "%&<format>".
-" 2. Check the first 1000 non-comment lines for LaTeX or ConTeXt keywords.
-" 3. Default to "plain" or to g:tex_flavor, can be set in user's vimrc.
-func dist#ft#FTtex()
- let firstline = getline(1)
- if firstline =~ '^%&\s*\a\+'
- let format = tolower(matchstr(firstline, '\a\+'))
- let format = substitute(format, 'pdf', '', '')
- if format == 'tex'
- let format = 'latex'
- elseif format == 'plaintex'
- let format = 'plain'
- endif
- elseif expand('%') =~ 'tex/context/.*/.*.tex'
- let format = 'context'
- else
- " Default value, may be changed later:
- let format = exists("g:tex_flavor") ? g:tex_flavor : 'plain'
- " Save position, go to the top of the file, find first non-comment line.
- let save_cursor = getpos('.')
- call cursor(1,1)
- let firstNC = search('^\s*[^[:space:]%]', 'c', 1000)
- if firstNC > 0
- " Check the next thousand lines for a LaTeX or ConTeXt keyword.
- let lpat = 'documentclass\>\|usepackage\>\|begin{\|newcommand\>\|renewcommand\>'
- let cpat = 'start\a\+\|setup\a\+\|usemodule\|enablemode\|enableregime\|setvariables\|useencoding\|usesymbols\|stelle\a\+\|verwende\a\+\|stel\a\+\|gebruik\a\+\|usa\a\+\|imposta\a\+\|regle\a\+\|utilisemodule\>'
- let kwline = search('^\s*\\\%(' . lpat . '\)\|^\s*\\\(' . cpat . '\)',
- \ 'cnp', firstNC + 1000)
- if kwline == 1 " lpat matched
- let format = 'latex'
- elseif kwline == 2 " cpat matched
- let format = 'context'
- endif " If neither matched, keep default set above.
- " let lline = search('^\s*\\\%(' . lpat . '\)', 'cn', firstNC + 1000)
- " let cline = search('^\s*\\\%(' . cpat . '\)', 'cn', firstNC + 1000)
- " if cline > 0
- " let format = 'context'
- " endif
- " if lline > 0 && (cline == 0 || cline > lline)
- " let format = 'tex'
- " endif
- endif " firstNC
- call setpos('.', save_cursor)
- endif " firstline =~ '^%&\s*\a\+'
-
- " Translation from formats to file types. TODO: add AMSTeX, RevTex, others?
- if format == 'plain'
- setf plaintex
- elseif format == 'context'
- setf context
- else " probably LaTeX
- setf tex
- endif
- return
-endfunc
-
-func dist#ft#FTxml()
- let n = 1
- while n < 100 && n <= line("$")
- let line = getline(n)
- " DocBook 4 or DocBook 5.
- let is_docbook4 = line =~ '<!DOCTYPE.*DocBook'
- let is_docbook5 = line =~ ' xmlns="http://docbook.org/ns/docbook"'
- if is_docbook4 || is_docbook5
- let b:docbk_type = "xml"
- if is_docbook5
- let b:docbk_ver = 5
- else
- let b:docbk_ver = 4
- endif
- setf docbk
- return
- endif
- if line =~ 'xmlns:xbl="http://www.mozilla.org/xbl"'
- setf xbl
- return
- endif
- let n += 1
- endwhile
- setf xml
-endfunc
-
-func dist#ft#FTy()
- let n = 1
- while n < 100 && n <= line("$")
- let line = getline(n)
- if line =~ '^\s*%'
- setf yacc
- return
- endif
- if getline(n) =~ '^\s*\(#\|class\>\)' && getline(n) !~ '^\s*#\s*include'
- setf racc
- return
- endif
- let n = n + 1
- endwhile
- setf yacc
-endfunc
-
-func dist#ft#Redif()
- let lnum = 1
- while lnum <= 5 && lnum < line('$')
- if getline(lnum) =~ "^\ctemplate-type:"
- setf redif
- return
- endif
- let lnum = lnum + 1
- endwhile
-endfunc
-
-" This function is called for all files under */debian/patches/*, make sure not
-" to non-dep3patch files, such as README and other text files.
-func dist#ft#Dep3patch()
- if expand('%:t') ==# 'series'
- return
- endif
-
- for ln in getline(1, 100)
- if ln =~# '^\%(Description\|Subject\|Origin\|Bug\|Forwarded\|Author\|From\|Reviewed-by\|Acked-by\|Last-Updated\|Applied-Upstream\):'
- setf dep3patch
- return
- elseif ln =~# '^---'
- " end of headers found. stop processing
- return
- endif
- endfor
-endfunc
-
-" This function checks the first 15 lines for appearance of 'FoamFile'
-" and then 'object' in a following line.
-" In that case, it's probably an OpenFOAM file
-func dist#ft#FTfoam()
- let ffile = 0
- let lnum = 1
- while lnum <= 15
- if getline(lnum) =~# '^FoamFile'
- let ffile = 1
- elseif ffile == 1 && getline(lnum) =~# '^\s*object'
- setf foam
- return
- endif
- let lnum = lnum + 1
- endwhile
-endfunc
-
-" Determine if a *.tf file is TF mud client or terraform
-func dist#ft#FTtf()
- let numberOfLines = line('$')
- for i in range(1, numberOfLines)
- let currentLine = trim(getline(i))
- let firstCharacter = currentLine[0]
- if firstCharacter !=? ";" && firstCharacter !=? "/" && firstCharacter !=? ""
- setf terraform
- return
- endif
- endfor
- setf tf
-endfunc
-
-let s:ft_krl_header = '\&\w+'
-" Determine if a *.src file is Kuka Robot Language
-func dist#ft#FTsrc()
- let ft_krl_def_or_deffct = '%(global\s+)?def%(fct)?>'
- if exists("g:filetype_src")
- exe "setf " .. g:filetype_src
- elseif getline(nextnonblank(1)) =~? '\v^\s*%(' .. s:ft_krl_header .. '|' .. ft_krl_def_or_deffct .. ')'
- setf krl
- endif
-endfunc
-
-" Determine if a *.dat file is Kuka Robot Language
-func dist#ft#FTdat()
- let ft_krl_defdat = 'defdat>'
- if exists("g:filetype_dat")
- exe "setf " .. g:filetype_dat
- elseif getline(nextnonblank(1)) =~? '\v^\s*%(' .. s:ft_krl_header .. '|' .. ft_krl_defdat .. ')'
- setf krl
- endif
-endfunc
-
-" Restore 'cpoptions'
-let &cpo = s:cpo_save
-unlet s:cpo_save
diff --git a/runtime/autoload/health.vim b/runtime/autoload/health.vim
index a693868381..5fd4627b11 100644
--- a/runtime/autoload/health.vim
+++ b/runtime/autoload/health.vim
@@ -5,8 +5,13 @@ function! health#check(plugin_names) abort
\ ? s:discover_healthchecks()
\ : s:get_healthcheck(a:plugin_names)
- " create scratch-buffer
- execute 'tab sbuffer' nvim_create_buf(v:true, v:true)
+ " Create buffer and open in a tab, unless this is the default buffer when Nvim starts.
+ let emptybuf = (bufnr('$') == 1 && empty(getline(1)) && 1 == line('$'))
+ execute (emptybuf ? 'buffer' : 'tab sbuffer') nvim_create_buf(v:true, v:true)
+ if bufexists('health://')
+ bwipe health://
+ endif
+ file health://
setfiletype checkhealth
if empty(healthchecks)
@@ -38,7 +43,7 @@ function! health#check(plugin_names) abort
\ name, v:throwpoint, v:exception))
endif
endtry
- let header = [name. ': ' . func, repeat('=', 72)]
+ let header = [repeat('=', 78), name .. ': ' .. func, '']
" remove empty line after header from report_start
let s:output = s:output[0] == '' ? s:output[1:] : s:output
let s:output = header + s:output + ['']
@@ -47,8 +52,7 @@ function! health#check(plugin_names) abort
endfor
endif
- " needed for plasticboy/vim-markdown, because it uses fdm=expr
- normal! zR
+ " Clear the 'Running healthchecks...' message.
redraw|echo ''
endfunction
@@ -58,7 +62,7 @@ endfunction
" Starts a new report.
function! health#report_start(name) abort
- call s:collect_output("\n## " . a:name)
+ call s:collect_output(printf("\n%s ~", a:name))
endfunction
" Indents lines *except* line 1 of a string if it contains newlines.
@@ -81,7 +85,7 @@ endfunction
" Format a message for a specific report item.
" a:1: Optional advice (string or list)
function! s:format_report_message(status, msg, ...) abort " {{{
- let output = ' - ' . a:status . ': ' . s:indent_after_line1(a:msg, 4)
+ let output = '- ' .. a:status .. (empty(a:status) ? '' : ' ') .. s:indent_after_line1(a:msg, 2)
" Optional parameters
if a:0 > 0
@@ -92,9 +96,9 @@ function! s:format_report_message(status, msg, ...) abort " {{{
" Report each suggestion
if !empty(advice)
- let output .= "\n - ADVICE:"
+ let output .= "\n - ADVICE:"
for suggestion in advice
- let output .= "\n - " . s:indent_after_line1(suggestion, 10)
+ let output .= "\n - " . s:indent_after_line1(suggestion, 6)
endfor
endif
endif
@@ -102,9 +106,9 @@ function! s:format_report_message(status, msg, ...) abort " {{{
return s:help_to_link(output)
endfunction " }}}
-" Use {msg} to report information in the current section
+" Reports a message as a listitem in the current section.
function! health#report_info(msg) abort " {{{
- call s:collect_output(s:format_report_message('INFO', a:msg))
+ call s:collect_output(s:format_report_message('', a:msg))
endfunction " }}}
" Reports a successful healthcheck.
diff --git a/runtime/autoload/health/nvim.vim b/runtime/autoload/health/nvim.vim
deleted file mode 100644
index 9b387095ee..0000000000
--- a/runtime/autoload/health/nvim.vim
+++ /dev/null
@@ -1,284 +0,0 @@
-let s:suggest_faq = 'https://github.com/neovim/neovim/wiki/FAQ'
-
-function! s:check_config() abort
- let ok = v:true
- call health#report_start('Configuration')
-
- let vimrc = empty($MYVIMRC) ? stdpath('config').'/init.vim' : $MYVIMRC
- if !filereadable(vimrc)
- let ok = v:false
- let has_vim = filereadable(expand('~/.vimrc'))
- call health#report_warn((-1 == getfsize(vimrc) ? 'Missing' : 'Unreadable').' user config file: '.vimrc,
- \[ has_vim ? ':help nvim-from-vim' : ':help init.vim' ])
- endif
-
- " If $VIM is empty we don't care. Else make sure it is valid.
- if !empty($VIM) && !filereadable($VIM.'/runtime/doc/nvim.txt')
- let ok = v:false
- call health#report_error('$VIM is invalid: '.$VIM)
- endif
-
- if exists('$NVIM_TUI_ENABLE_CURSOR_SHAPE')
- let ok = v:false
- call health#report_warn('$NVIM_TUI_ENABLE_CURSOR_SHAPE is ignored in Nvim 0.2+',
- \ [ "Use the 'guicursor' option to configure cursor shape. :help 'guicursor'",
- \ 'https://github.com/neovim/neovim/wiki/Following-HEAD#20170402' ])
- endif
-
- if v:ctype ==# 'C'
- let ok = v:false
- call health#report_error('Locale does not support UTF-8. Unicode characters may not display correctly.'
- \ .printf("\n$LANG=%s $LC_ALL=%s $LC_CTYPE=%s", $LANG, $LC_ALL, $LC_CTYPE),
- \ [ 'If using tmux, try the -u option.',
- \ 'Ensure that your terminal/shell/tmux/etc inherits the environment, or set $LANG explicitly.' ,
- \ 'Configure your system locale.' ])
- endif
-
- if &paste
- let ok = v:false
- call health#report_error("'paste' is enabled. This option is only for pasting text.\nIt should not be set in your config.",
- \ [ 'Remove `set paste` from your init.vim, if applicable.',
- \ 'Check `:verbose set paste?` to see if a plugin or script set the option.', ])
- endif
-
- let writeable = v:true
- let shadafile = empty(&shada) ? &shada : substitute(matchstr(
- \ split(&shada, ',')[-1], '^n.\+'), '^n', '', '')
- let shadafile = empty(&shadafile) ? empty(shadafile) ?
- \ stdpath('state').'/shada/main.shada' : expand(shadafile)
- \ : &shadafile ==# 'NONE' ? '' : &shadafile
- if !empty(shadafile) && empty(glob(shadafile))
- " Since this may be the first time neovim has been run, we will try to
- " create a shada file
- try
- wshada
- catch /.*/
- let writeable = v:false
- endtry
- endif
- if !writeable || (!empty(shadafile) &&
- \ (!filereadable(shadafile) || !filewritable(shadafile)))
- let ok = v:false
- call health#report_error('shada file is not '.
- \ ((!writeable || filereadable(shadafile)) ?
- \ 'writeable' : 'readable').":\n".shadafile)
- endif
-
- if ok
- call health#report_ok('no issues found')
- endif
-endfunction
-
-" Load the remote plugin manifest file and check for unregistered plugins
-function! s:check_rplugin_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 = tr(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('python3')
- let msg .= ' (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! s:check_performance() abort
- call health#report_start('Performance')
-
- " check buildtype
- let buildtype = matchstr(execute('version'), '\v\cbuild type:?\s*[^\n\r\t ]+')
- if empty(buildtype)
- call health#report_error('failed to get build type from :version')
- elseif buildtype =~# '\v(MinSizeRel|Release|RelWithDebInfo)'
- call health#report_ok(buildtype)
- else
- call health#report_info(buildtype)
- call health#report_warn(
- \ 'Non-optimized '.(has('debug')?'(DEBUG) ':'').'build. Nvim will be slower.',
- \ ['Install a different Nvim package, or rebuild with `CMAKE_BUILD_TYPE=RelWithDebInfo`.',
- \ s:suggest_faq])
- endif
-
- " check for slow shell invocation
- let slow_cmd_time = 1.5
- let start_time = reltime()
- call system('echo')
- let elapsed_time = reltimefloat(reltime(start_time))
- if elapsed_time > slow_cmd_time
- call health#report_warn(
- \ 'Slow shell invocation (took '.printf('%.2f', elapsed_time).' seconds).')
- endif
-endfunction
-
-function! s:get_tmux_option(option) abort
- let cmd = 'tmux show-option -qvg '.a:option " try global scope
- let out = system(split(cmd))
- let val = substitute(out, '\v(\s|\r|\n)', '', 'g')
- if v:shell_error
- call health#report_error('command failed: '.cmd."\n".out)
- return 'error'
- elseif empty(val)
- let cmd = 'tmux show-option -qvgs '.a:option " try session scope
- let out = system(split(cmd))
- let val = substitute(out, '\v(\s|\r|\n)', '', 'g')
- if v:shell_error
- call health#report_error('command failed: '.cmd."\n".out)
- return 'error'
- endif
- endif
- return val
-endfunction
-
-function! s:check_tmux() abort
- if empty($TMUX) || !executable('tmux')
- return
- endif
- call health#report_start('tmux')
-
- " check escape-time
- let suggestions = ["set escape-time in ~/.tmux.conf:\nset-option -sg escape-time 10",
- \ s:suggest_faq]
- let tmux_esc_time = s:get_tmux_option('escape-time')
- if tmux_esc_time !=# 'error'
- if empty(tmux_esc_time)
- call health#report_error('`escape-time` is not set', suggestions)
- elseif tmux_esc_time > 300
- call health#report_error(
- \ '`escape-time` ('.tmux_esc_time.') is higher than 300ms', suggestions)
- else
- call health#report_ok('escape-time: '.tmux_esc_time)
- endif
- endif
-
- " check focus-events
- let suggestions = ["(tmux 1.9+ only) Set `focus-events` in ~/.tmux.conf:\nset-option -g focus-events on"]
- let tmux_focus_events = s:get_tmux_option('focus-events')
- call health#report_info('Checking stuff')
- if tmux_focus_events !=# 'error'
- if empty(tmux_focus_events) || tmux_focus_events !=# 'on'
- call health#report_warn(
- \ "`focus-events` is not enabled. |'autoread'| may not work.", suggestions)
- else
- call health#report_ok('focus-events: '.tmux_focus_events)
- endif
- endif
-
- " check default-terminal and $TERM
- call health#report_info('$TERM: '.$TERM)
- let cmd = 'tmux show-option -qvg default-terminal'
- let out = system(split(cmd))
- let tmux_default_term = substitute(out, '\v(\s|\r|\n)', '', 'g')
- if empty(tmux_default_term)
- let cmd = 'tmux show-option -qvgs default-terminal'
- let out = system(split(cmd))
- let tmux_default_term = substitute(out, '\v(\s|\r|\n)', '', 'g')
- endif
-
- if v:shell_error
- call health#report_error('command failed: '.cmd."\n".out)
- elseif tmux_default_term !=# $TERM
- call health#report_info('default-terminal: '.tmux_default_term)
- call health#report_error(
- \ '$TERM differs from the tmux `default-terminal` setting. Colors might look wrong.',
- \ ['$TERM may have been set by some rc (.bashrc, .zshrc, ...).'])
- elseif $TERM !~# '\v(tmux-256color|screen-256color)'
- call health#report_error(
- \ '$TERM should be "screen-256color" or "tmux-256color" in tmux. Colors might look wrong.',
- \ ["Set default-terminal in ~/.tmux.conf:\nset-option -g default-terminal \"screen-256color\"",
- \ s:suggest_faq])
- endif
-
- " check for RGB capabilities
- let info = system(['tmux', 'server-info'])
- let has_tc = stridx(info, " Tc: (flag) true") != -1
- let has_rgb = stridx(info, " RGB: (flag) true") != -1
- if !has_tc && !has_rgb
- call health#report_warn(
- \ "Neither Tc nor RGB capability set. True colors are disabled. |'termguicolors'| won't work properly.",
- \ ["Put this in your ~/.tmux.conf and replace XXX by your $TERM outside of tmux:\nset-option -sa terminal-overrides ',XXX:RGB'",
- \ "For older tmux versions use this instead:\nset-option -ga terminal-overrides ',XXX:Tc'"])
- endif
-endfunction
-
-function! s:check_terminal() abort
- if !executable('infocmp')
- return
- endif
- call health#report_start('terminal')
- let cmd = 'infocmp -L'
- let out = system(split(cmd))
- let kbs_entry = matchstr(out, 'key_backspace=[^,[:space:]]*')
- let kdch1_entry = matchstr(out, 'key_dc=[^,[:space:]]*')
-
- if v:shell_error
- \ && (!has('win32')
- \ || empty(matchstr(out,
- \ 'infocmp: couldn''t open terminfo file .\+'
- \ ..'\%(conemu\|vtpcon\|win32con\)')))
- call health#report_error('command failed: '.cmd."\n".out)
- else
- call health#report_info('key_backspace (kbs) terminfo entry: '
- \ .(empty(kbs_entry) ? '? (not found)' : kbs_entry))
- call health#report_info('key_dc (kdch1) terminfo entry: '
- \ .(empty(kbs_entry) ? '? (not found)' : kdch1_entry))
- endif
- for env_var in ['XTERM_VERSION', 'VTE_VERSION', 'TERM_PROGRAM', 'COLORTERM', 'SSH_TTY']
- if exists('$'.env_var)
- call health#report_info(printf("$%s='%s'", env_var, eval('$'.env_var)))
- endif
- endfor
-endfunction
-
-function! health#nvim#check() abort
- call s:check_config()
- call s:check_performance()
- call s:check_rplugin_manifest()
- call s:check_terminal()
- call s:check_tmux()
-endfunction
diff --git a/runtime/autoload/man.vim b/runtime/autoload/man.vim
deleted file mode 100644
index b8a73a64c9..0000000000
--- a/runtime/autoload/man.vim
+++ /dev/null
@@ -1,529 +0,0 @@
-" Maintainer: Anmol Sethi <hi@nhooyr.io>
-
-if exists('s:loaded_man')
- finish
-endif
-let s:loaded_man = 1
-
-let s:find_arg = '-w'
-let s:localfile_arg = v:true " Always use -l if possible. #6683
-
-function! man#init() abort
- try
- " Check for -l support.
- call s:get_page(s:get_path('', 'man'))
- catch /command error .*/
- let s:localfile_arg = v:false
- endtry
-endfunction
-
-function! man#open_page(count, mods, ...) abort
- if a:0 > 2
- call s:error('too many arguments')
- return
- 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] = s:extract_sect_and_name_ref(ref)
- if a:count >= 0
- let sect = string(a:count)
- endif
- let path = s:verify_exists(sect, name)
- let [sect, name] = s:extract_sect_and_name_path(path)
- catch
- call s:error(v:exception)
- return
- endtry
-
- let [l:buf, l:save_tfu] = [bufnr(), &tagfunc]
- try
- setlocal tagfunc=man#goto_tag
- let l:target = l:name . '(' . l:sect . ')'
- if a:mods !~# 'tab' && s:find_man()
- execute 'silent keepalt tag' l:target
- else
- execute 'silent keepalt' a:mods 'stag' l:target
- endif
- call s:set_options(v:false)
- finally
- call setbufvar(l:buf, '&tagfunc', l:save_tfu)
- endtry
-
- let b:man_sect = sect
-endfunction
-
-" Called when a man:// buffer is opened.
-function! man#read_page(ref) abort
- try
- let [sect, name] = s:extract_sect_and_name_ref(a:ref)
- let path = s:verify_exists(sect, name)
- let [sect, name] = s:extract_sect_and_name_path(path)
- let page = s:get_page(path)
- catch
- call s:error(v:exception)
- return
- endtry
- let b:man_sect = sect
- call s:put_page(page)
-endfunction
-
-" Handler for s:system() function.
-function! s:system_handler(jobid, data, event) dict abort
- if a:event is# 'stdout' || a:event is# 'stderr'
- let self[a:event] .= join(a:data, "\n")
- else
- let self.exit_code = a:data
- endif
-endfunction
-
-" Run a system command and timeout after 30 seconds.
-function! s:system(cmd, ...) abort
- let opts = {
- \ 'stdout': '',
- \ 'stderr': '',
- \ 'exit_code': 0,
- \ 'on_stdout': function('s:system_handler'),
- \ 'on_stderr': function('s:system_handler'),
- \ 'on_exit': function('s:system_handler'),
- \ }
- let jobid = jobstart(a:cmd, opts)
-
- if jobid < 1
- throw printf('command error %d: %s', jobid, join(a:cmd))
- endif
-
- let res = jobwait([jobid], 30000)
- if res[0] == -1
- try
- call jobstop(jobid)
- throw printf('command timed out: %s', join(a:cmd))
- catch /^Vim(call):E900:/
- endtry
- elseif res[0] == -2
- throw printf('command interrupted: %s', join(a:cmd))
- endif
- if opts.exit_code != 0
- throw printf("command error (%d) %s: %s", jobid, join(a:cmd), substitute(opts.stderr, '\_s\+$', '', &gdefault ? '' : 'g'))
- endif
-
- return opts.stdout
-endfunction
-
-function! s:set_options(pager) abort
- setlocal noswapfile buftype=nofile bufhidden=hide
- setlocal nomodified readonly nomodifiable
- let b:pager = a:pager
- setlocal filetype=man
-endfunction
-
-function! s:get_page(path) abort
- " Disable hard-wrap by using a big $MANWIDTH (max 1000 on some systems #9065).
- " Soft-wrap: ftplugin/man.vim sets wrap/breakindent/….
- " Hard-wrap: driven by `man`.
- let manwidth = !get(g:, 'man_hardwrap', 1) ? 999 : (empty($MANWIDTH) ? winwidth(0) : $MANWIDTH)
- " Force MANPAGER=cat to ensure Vim is not recursively invoked (by man-db).
- " http://comments.gmane.org/gmane.editors.vim.devel/29085
- " Set MAN_KEEP_FORMATTING so Debian man doesn't discard backspaces.
- let cmd = ['env', 'MANPAGER=cat', 'MANWIDTH='.manwidth, 'MAN_KEEP_FORMATTING=1', 'man']
- return s:system(cmd + (s:localfile_arg ? ['-l', a:path] : [a:path]))
-endfunction
-
-function! s:put_page(page) abort
- setlocal modifiable noreadonly noswapfile
- silent keepjumps %delete _
- silent put =a:page
- while getline(1) =~# '^\s*$'
- silent keepjumps 1delete _
- endwhile
- " XXX: nroff justifies text by filling it with whitespace. That interacts
- " badly with our use of $MANWIDTH=999. Hack around this by using a fixed
- " size for those whitespace regions.
- silent! keeppatterns keepjumps %s/\s\{199,}/\=repeat(' ', 10)/g
- 1
- lua require("man").highlight_man_page()
- call s:set_options(v:false)
-endfunction
-
-function! man#show_toc() abort
- let bufname = bufname('%')
- let info = getloclist(0, {'winid': 1})
- if !empty(info) && getwinvar(info.winid, 'qf_toc') ==# bufname
- lopen
- return
- endif
-
- let toc = []
- let lnum = 2
- let last_line = line('$') - 1
- while lnum && lnum < last_line
- let text = getline(lnum)
- if text =~# '^\%( \{3\}\)\=\S.*$'
- " if text is a section title
- call add(toc, {'bufnr': bufnr('%'), 'lnum': lnum, 'text': text})
- elseif text =~# '^\s\+\%(+\|-\)\S\+'
- " if text is a flag title. we strip whitespaces and prepend two
- " spaces to have a consistent format in the loclist.
- let text = ' ' .. substitute(text, '^\s*\(.\{-}\)\s*$', '\1', '')
- call add(toc, {'bufnr': bufnr('%'), 'lnum': lnum, 'text': text})
- endif
- let lnum = nextnonblank(lnum + 1)
- endwhile
-
- call setloclist(0, toc, ' ')
- call setloclist(0, [], 'a', {'title': 'Man TOC'})
- lopen
- let w:qf_toc = bufname
-endfunction
-
-" attempt to extract the name and sect out of 'name(sect)'
-" otherwise just return the largest string of valid characters in ref
-function! s:extract_sect_and_name_ref(ref) abort
- if a:ref[0] ==# '-' " try ':Man -pandoc' with this disabled.
- throw 'manpage name cannot start with ''-'''
- endif
- 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 ['', s:spaces_to_underscores(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]), s:spaces_to_underscores(left[0])]
-endfunction
-
-" replace spaces in a man page name with underscores
-" intended for PostgreSQL, which has man pages like 'CREATE_TABLE(7)';
-" while editing SQL source code, it's nice to visually select 'CREATE TABLE'
-" and hit 'K', which requires this transformation
-function! s:spaces_to_underscores(str)
- return substitute(a:str, ' ', '_', 'g')
-endfunction
-
-function! s:get_path(sect, name) abort
- " Some man implementations (OpenBSD) return all available paths from the
- " search command. Previously, this function would simply select the first one.
- "
- " However, some searches will report matches that are incorrect:
- " man -w strlen may return string.3 followed by strlen.3, and therefore
- " selecting the first would get us the wrong page. Thus, we must find the
- " first matching one.
- "
- " There's yet another special case here. Consider the following:
- " If you run man -w strlen and string.3 comes up first, this is a problem. We
- " should search for a matching named one in the results list.
- " However, if you search for man -w clock_gettime, you will *only* get
- " clock_getres.2, which is the right page. Searching the resuls for
- " clock_gettime will no longer work. In this case, we should just use the
- " first one that was found in the correct section.
- "
- " Finally, we can avoid relying on -S or -s here since they are very
- " inconsistently supported. Instead, call -w with a section and a name.
- if empty(a:sect)
- let results = split(s:system(['man', s:find_arg, a:name]))
- else
- let results = split(s:system(['man', s:find_arg, a:sect, a:name]))
- endif
-
- if empty(results)
- return ''
- endif
-
- " find any that match the specified name
- let namematches = filter(copy(results), 'fnamemodify(v:val, ":t") =~ a:name')
- let sectmatches = []
-
- if !empty(namematches) && !empty(a:sect)
- let sectmatches = filter(copy(namematches), 'fnamemodify(v:val, ":e") == a:sect')
- endif
-
- return substitute(get(sectmatches, 0, get(namematches, 0, results[0])), '\n\+$', '', '')
-endfunction
-
-" s:verify_exists attempts to find the path to a manpage
-" based on the passed section and name.
-"
-" 1. If the passed section is empty, b:man_default_sects is used.
-" 2. If manpage could not be found with the given sect and name,
-" then another attempt is made with b:man_default_sects.
-" 3. If it still could not be found, then we try again without a section.
-" 4. If still not found but $MANSECT is set, then we try again with $MANSECT
-" unset.
-"
-" This function is careful to avoid duplicating a search if a previous
-" step has already done it. i.e if we use b:man_default_sects in step 1,
-" then we don't do it again in step 2.
-function! s:verify_exists(sect, name) abort
- let sect = a:sect
-
- if empty(sect)
- " no section specified, so search with b:man_default_sects
- if exists('b:man_default_sects')
- let sects = split(b:man_default_sects, ',')
- for sec in sects
- try
- let res = s:get_path(sec, a:name)
- if !empty(res)
- return res
- endif
- catch /^command error (/
- endtry
- endfor
- endif
- else
- " try with specified section
- try
- let res = s:get_path(sect, a:name)
- if !empty(res)
- return res
- endif
- catch /^command error (/
- endtry
-
- " try again with b:man_default_sects
- if exists('b:man_default_sects')
- let sects = split(b:man_default_sects, ',')
- for sec in sects
- try
- let res = s:get_path(sec, a:name)
- if !empty(res)
- return res
- endif
- catch /^command error (/
- endtry
- endfor
- endif
- endif
-
- " if none of the above worked, we will try with no section
- try
- let res = s:get_path('', a:name)
- if !empty(res)
- return res
- endif
- catch /^command error (/
- endtry
-
- " if that still didn't work, we will check for $MANSECT and try again with it
- " unset
- if !empty($MANSECT)
- try
- let MANSECT = $MANSECT
- call setenv('MANSECT', v:null)
- let res = s:get_path('', a:name)
- if !empty(res)
- return res
- endif
- catch /^command error (/
- finally
- call setenv('MANSECT', MANSECT)
- endtry
- endif
-
- " finally, if that didn't work, there is no hope
- throw 'no manual entry for ' . a:name
-endfunction
-
-" Extracts the name/section from the 'path/name.sect', because sometimes the actual section is
-" more specific than what we provided to `man` (try `:Man 3 App::CLI`).
-" Also on linux, name seems to be case-insensitive. So for `:Man PRIntf`, we
-" still want the name of the buffer to be 'printf'.
-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
-
-function! s:find_man() abort
- let l:win = 1
- while l:win <= winnr('$')
- let l:buf = winbufnr(l:win)
- if getbufvar(l:buf, '&filetype', '') ==# 'man'
- execute l:win.'wincmd w'
- return 1
- endif
- let l:win += 1
- endwhile
- return 0
-endfunction
-
-function! s:error(msg) abort
- redraw
- echohl ErrorMsg
- echon 'man.vim: ' a:msg
- echohl None
-endfunction
-
-" see s: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 cmd_offset = index(args, 'Man')
- if cmd_offset > 0
- " Prune all arguments up to :Man itself. Otherwise modifier commands like
- " :tab, :vertical, etc. would lead to a wrong length.
- let args = args[cmd_offset:]
- endif
- 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, ''))
- return s:complete(sect, '', name)
- 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 s:complete(sect, sect, name)
-endfunction
-
-function! s:get_paths(sect, name, do_fallback) abort
- " callers must try-catch this, as some `man` implementations don't support `s:find_arg`
- try
- let mandirs = join(split(s:system(['man', s:find_arg]), ':\|\n'), ',')
- let paths = globpath(mandirs, 'man?/'.a:name.'*.'.a:sect.'*', 0, 1)
- try
- " Prioritize the result from verify_exists as it obeys b:man_default_sects.
- let first = s:verify_exists(a:sect, a:name)
- let paths = filter(paths, 'v:val !=# first')
- let paths = [first] + paths
- catch
- endtry
- return paths
- catch
- if !a:do_fallback
- throw v:exception
- endif
-
- " Fallback to a single path, with the page we're trying to find.
- try
- return [s:verify_exists(a:sect, a:name)]
- catch
- return []
- endtry
- endtry
-endfunction
-
-function! s:complete(sect, psect, name) abort
- let pages = s:get_paths(a:sect, a:name, v:false)
- " We remove duplicates in case the same manpage in different languages was found.
- return uniq(sort(map(pages, 's:format_candidate(v:val, a:psect)'), 'i'))
-endfunction
-
-function! s:format_candidate(path, psect) abort
- if a:path =~# '\.\%(pdf\|in\)$' " invalid extensions
- return
- endif
- let [sect, name] = s:extract_sect_and_name_path(a:path)
- if sect ==# a:psect
- return name
- elseif sect =~# a:psect.'.\+$'
- " We include the section if the user provided section is a prefix
- " of the actual section.
- return name.'('.sect.')'
- endif
-endfunction
-
-" Called when Nvim is invoked as $MANPAGER.
-function! man#init_pager() abort
- if getline(1) =~# '^\s*$'
- silent keepjumps 1delete _
- else
- keepjumps 1
- endif
- lua require("man").highlight_man_page()
- " Guess the ref from the heading (which is usually uppercase, so we cannot
- " know the correct casing, cf. `man glDrawArraysInstanced`).
- let ref = substitute(matchstr(getline(1), '^[^)]\+)'), ' ', '_', 'g')
- try
- let b:man_sect = s:extract_sect_and_name_ref(ref)[0]
- catch
- let b:man_sect = ''
- endtry
- if -1 == match(bufname('%'), 'man:\/\/') " Avoid duplicate buffers, E95.
- execute 'silent file man://'.tolower(fnameescape(ref))
- endif
-
- call s:set_options(v:true)
-endfunction
-
-function! man#goto_tag(pattern, flags, info) abort
- let [l:sect, l:name] = s:extract_sect_and_name_ref(a:pattern)
-
- let l:paths = s:get_paths(l:sect, l:name, v:true)
- let l:structured = []
-
- for l:path in l:paths
- let [l:sect, l:name] = s:extract_sect_and_name_path(l:path)
- let l:structured += [{
- \ 'name': l:name,
- \ 'title': l:name . '(' . l:sect . ')'
- \ }]
- endfor
-
- if &cscopetag
- " return only a single entry so we work well with :cstag (#11675)
- let l:structured = l:structured[:0]
- endif
-
- return map(l:structured, {
- \ _, entry -> {
- \ 'name': entry.name,
- \ 'filename': 'man://' . entry.title,
- \ 'cmd': '1'
- \ }
- \ })
-endfunction
-
-call man#init()
diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim
index ef0282848f..2fcf0b32c7 100644
--- a/runtime/autoload/netrw.vim
+++ b/runtime/autoload/netrw.vim
@@ -1751,8 +1751,10 @@ fun! s:NetrwOptionsRestore(vt)
" call Decho("settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo." a:vt=".a:vt,'~'.expand("<slnum>"))
if !exists("{a:vt}netrw_optionsave")
" call Decho("case ".a:vt."netrw_optionsave : doesn't exist",'~'.expand("<slnum>"))
-" call Decho("..doing filetype detect anyway")
- filetype detect
+ if !isdirectory(expand('%'))
+" call Decho("..doing filetype detect anyway")
+ filetype detect
+ endif
" call Decho("..settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo." a:vt=".a:vt,'~'.expand("<slnum>"))
" call Decho("..ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
" call Dret("s:NetrwOptionsRestore : ".a:vt."netrw_optionsave doesn't exist")
@@ -1859,9 +1861,11 @@ fun! s:NetrwOptionsRestore(vt)
" were having their filetype detect-generated settings overwritten by
" NetrwOptionRestore.
if &ft != "netrw"
-" call Decho("before: filetype detect (ft=".&ft.")",'~'.expand("<slnum>"))
- filetype detect
-" call Decho("after : filetype detect (ft=".&ft.")",'~'.expand("<slnum>"))
+ if !isdirectory(expand('%'))
+" call Decho("before: filetype detect (ft=".&ft.")",'~'.expand("<slnum>"))
+ filetype detect
+" call Decho("after : filetype detect (ft=".&ft.")",'~'.expand("<slnum>"))
+ endif
endif
" call Decho("(s:NetrwOptionsRestore) lines=".&lines)
" call Decho("settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo." a:vt=".a:vt,'~'.expand("<slnum>"))
@@ -6442,7 +6446,6 @@ fun! s:NetrwMaps(islocal)
" if !hasmapto('<Plug>NetrwMarkFileGrep') |nmap <buffer> <silent> <nowait> mg <Plug>NetrwMarkFileGrep|endif
" if !hasmapto('<Plug>NetrwMarkHideSfx') |nmap <buffer> <silent> <nowait> mh <Plug>NetrwMarkHideSfx|endif
" if !hasmapto('<Plug>NetrwMarkFileMove') |nmap <buffer> <silent> <nowait> mm <Plug>NetrwMarkFileMove|endif
-" if !hasmapto('<Plug>NetrwMarkFilePrint') |nmap <buffer> <silent> <nowait> mp <Plug>NetrwMarkFilePrint|endif
" if !hasmapto('<Plug>NetrwMarkFileRegexp') |nmap <buffer> <silent> <nowait> mr <Plug>NetrwMarkFileRegexp|endif
" if !hasmapto('<Plug>NetrwMarkFileSource') |nmap <buffer> <silent> <nowait> ms <Plug>NetrwMarkFileSource|endif
" if !hasmapto('<Plug>NetrwMarkFileTag') |nmap <buffer> <silent> <nowait> mT <Plug>NetrwMarkFileTag|endif
@@ -6505,7 +6508,6 @@ fun! s:NetrwMaps(islocal)
nnoremap <buffer> <silent> <nowait> mg :<c-u>call <SID>NetrwMarkFileGrep(1)<cr>
nnoremap <buffer> <silent> <nowait> mh :<c-u>call <SID>NetrwMarkHideSfx(1)<cr>
nnoremap <buffer> <silent> <nowait> mm :<c-u>call <SID>NetrwMarkFileMove(1)<cr>
- nnoremap <buffer> <silent> <nowait> mp :<c-u>call <SID>NetrwMarkFilePrint(1)<cr>
nnoremap <buffer> <silent> <nowait> mr :<c-u>call <SID>NetrwMarkFileRegexp(1)<cr>
nnoremap <buffer> <silent> <nowait> ms :<c-u>call <SID>NetrwMarkFileSource(1)<cr>
nnoremap <buffer> <silent> <nowait> mT :<c-u>call <SID>NetrwMarkFileTag(1)<cr>
@@ -6618,7 +6620,6 @@ fun! s:NetrwMaps(islocal)
nnoremap <buffer> <silent> <nowait> mg :<c-u>call <SID>NetrwMarkFileGrep(0)<cr>
nnoremap <buffer> <silent> <nowait> mh :<c-u>call <SID>NetrwMarkHideSfx(0)<cr>
nnoremap <buffer> <silent> <nowait> mm :<c-u>call <SID>NetrwMarkFileMove(0)<cr>
- nnoremap <buffer> <silent> <nowait> mp :<c-u>call <SID>NetrwMarkFilePrint(0)<cr>
nnoremap <buffer> <silent> <nowait> mr :<c-u>call <SID>NetrwMarkFileRegexp(0)<cr>
nnoremap <buffer> <silent> <nowait> ms :<c-u>call <SID>NetrwMarkFileSource(0)<cr>
nnoremap <buffer> <silent> <nowait> mT :<c-u>call <SID>NetrwMarkFileTag(0)<cr>
@@ -7836,46 +7837,6 @@ fun! s:NetrwMarkFileMove(islocal)
endfun
" ---------------------------------------------------------------------
-" s:NetrwMarkFilePrint: (invoked by mp) This function prints marked files {{{2
-" using the hardcopy command. Local marked-file list only.
-fun! s:NetrwMarkFilePrint(islocal)
-" call Dfunc("s:NetrwMarkFilePrint(islocal=".a:islocal.")")
- let curbufnr= bufnr("%")
-
- " sanity check
- if !exists("s:netrwmarkfilelist_{curbufnr}") || empty(s:netrwmarkfilelist_{curbufnr})
- NetrwKeepj call netrw#ErrorMsg(2,"there are no marked files in this window (:help netrw-mf)",66)
-" call Dret("s:NetrwMarkFilePrint")
- return
- endif
-" call Decho("sanity chk passed: s:netrwmarkfilelist_".curbufnr."<".string(s:netrwmarkfilelist_{curbufnr}),'~'.expand("<slnum>"))
- let curdir= s:NetrwGetCurdir(a:islocal)
-
- if exists("s:netrwmarkfilelist_{curbufnr}")
- let netrwmarkfilelist = s:netrwmarkfilelist_{curbufnr}
- call s:NetrwUnmarkList(curbufnr,curdir)
- for fname in netrwmarkfilelist
- if a:islocal
- if g:netrw_keepdir
- let fname= s:ComposePath(curdir,fname)
- endif
- else
- let fname= curdir.fname
- endif
- 1split
- " the autocmds will handle both local and remote files
-" call Decho("exe sil e ".escape(fname,' '),'~'.expand("<slnum>"))
- exe "sil NetrwKeepj e ".fnameescape(fname)
-" call Decho("hardcopy",'~'.expand("<slnum>"))
- hardcopy
- q
- endfor
- 2match none
- endif
-" call Dret("s:NetrwMarkFilePrint")
-endfun
-
-" ---------------------------------------------------------------------
" s:NetrwMarkFileRegexp: (invoked by mr) This function is used to mark {{{2
" files when given a regexp (for which a prompt is
" issued) (matches to name of files).
diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim
index 991bed6bbd..98c80f1843 100644
--- a/runtime/autoload/provider/clipboard.vim
+++ b/runtime/autoload/provider/clipboard.vim
@@ -97,18 +97,24 @@ function! provider#clipboard#Executable() abort
let s:copy['*'] = ['wl-copy', '--foreground', '--primary', '--type', 'text/plain']
let s:paste['*'] = ['wl-paste', '--no-newline', '--primary']
return 'wl-copy'
- elseif !empty($DISPLAY) && executable('xclip')
- let s:copy['+'] = ['xclip', '-quiet', '-i', '-selection', 'clipboard']
- let s:paste['+'] = ['xclip', '-o', '-selection', 'clipboard']
- let s:copy['*'] = ['xclip', '-quiet', '-i', '-selection', 'primary']
- let s:paste['*'] = ['xclip', '-o', '-selection', 'primary']
- return 'xclip'
+ elseif !empty($WAYLAND_DISPLAY) && executable('waycopy') && executable('waypaste')
+ let s:copy['+'] = ['waycopy', '-t', 'text/plain']
+ let s:paste['+'] = ['waypaste', '-t', 'text/plain']
+ let s:copy['*'] = s:copy['+']
+ let s:paste['*'] = s:paste['+']
+ return 'wayclip'
elseif !empty($DISPLAY) && executable('xsel') && s:cmd_ok('xsel -o -b')
let s:copy['+'] = ['xsel', '--nodetach', '-i', '-b']
let s:paste['+'] = ['xsel', '-o', '-b']
let s:copy['*'] = ['xsel', '--nodetach', '-i', '-p']
let s:paste['*'] = ['xsel', '-o', '-p']
return 'xsel'
+ elseif !empty($DISPLAY) && executable('xclip')
+ let s:copy['+'] = ['xclip', '-quiet', '-i', '-selection', 'clipboard']
+ let s:paste['+'] = ['xclip', '-o', '-selection', 'clipboard']
+ let s:copy['*'] = ['xclip', '-quiet', '-i', '-selection', 'primary']
+ let s:paste['*'] = ['xclip', '-o', '-selection', 'primary']
+ return 'xclip'
elseif executable('lemonade')
let s:copy['+'] = ['lemonade', 'copy']
let s:paste['+'] = ['lemonade', 'paste']
@@ -139,7 +145,12 @@ function! provider#clipboard#Executable() abort
let s:paste['*'] = s:paste['+']
return 'termux-clipboard'
elseif !empty($TMUX) && executable('tmux')
- let s:copy['+'] = ['tmux', 'load-buffer', '-']
+ let ver = matchlist(systemlist(['tmux', '-V'])[0], '\vtmux %(next-)?(\d+)\.(\d+)')
+ if len(ver) >= 3 && (ver[1] > 3 || (ver[1] == 3 && ver[2] >= 2))
+ let s:copy['+'] = ['tmux', 'load-buffer', '-w', '-']
+ else
+ let s:copy['+'] = ['tmux', 'load-buffer', '-']
+ endif
let s:paste['+'] = ['tmux', 'save-buffer', '-']
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
diff --git a/runtime/autoload/provider/node.vim b/runtime/autoload/provider/node.vim
index 45b1dd4fd7..87af0094fe 100644
--- a/runtime/autoload/provider/node.vim
+++ b/runtime/autoload/provider/node.vim
@@ -71,13 +71,11 @@ function! provider#node#Detect() abort
let yarn_opts = deepcopy(s:NodeHandler)
let yarn_opts.entry_point = '/node_modules/neovim/bin/cli.js'
" `yarn global dir` is slow (> 250ms), try the default path first
- " XXX: The following code is not portable
" https://github.com/yarnpkg/yarn/issues/2049#issuecomment-263183768
- if has('unix')
- let yarn_default_path = $HOME . '/.config/yarn/global/' . yarn_opts.entry_point
- if filereadable(yarn_default_path)
- return [yarn_default_path, '']
- endif
+ let yarn_config_dir = has('win32') ? '/AppData/Local/Yarn/Data' : '/.config/yarn'
+ let yarn_default_path = $HOME . yarn_config_dir . '/global/' . yarn_opts.entry_point
+ if filereadable(yarn_default_path)
+ return [yarn_default_path, '']
endif
let yarn_opts.job_id = jobstart('yarn global dir', yarn_opts)
endif
diff --git a/runtime/autoload/python.vim b/runtime/autoload/python.vim
index e45dbd9db8..1eaad09ef5 100644
--- a/runtime/autoload/python.vim
+++ b/runtime/autoload/python.vim
@@ -3,13 +3,19 @@
let s:keepcpo= &cpo
set cpo&vim
-" searchpair() can be slow, limit the time to 150 msec or what is put in
-" g:pyindent_searchpair_timeout
-let s:searchpair_timeout = get(g:, 'pyindent_searchpair_timeout', 150)
-
-" Identing inside parentheses can be very slow, regardless of the searchpair()
-" timeout, so let the user disable this feature if he doesn't need it
-let s:disable_parentheses_indenting = get(g:, 'pyindent_disable_parentheses_indenting', v:false)
+" need to inspect some old g:pyindent_* variables to be backward compatible
+let g:python_indent = extend(get(g:, 'python_indent', {}), #{
+ \ closed_paren_align_last_line: v:true,
+ \ open_paren: get(g:, 'pyindent_open_paren', 'shiftwidth() * 2'),
+ \ nested_paren: get(g:, 'pyindent_nested_paren', 'shiftwidth()'),
+ \ continue: get(g:, 'pyindent_continue', 'shiftwidth() * 2'),
+ "\ searchpair() can be slow, limit the time to 150 msec or what is put in
+ "\ g:python_indent.searchpair_timeout
+ \ searchpair_timeout: get(g:, 'pyindent_searchpair_timeout', 150),
+ "\ Identing inside parentheses can be very slow, regardless of the searchpair()
+ "\ timeout, so let the user disable this feature if he doesn't need it
+ \ disable_parentheses_indenting: get(g:, 'pyindent_disable_parentheses_indenting', v:false),
+ \ }, 'keep')
let s:maxoff = 50 " maximum number of lines to look backwards for ()
@@ -18,7 +24,7 @@ function s:SearchBracket(fromlnum, flags)
\ {-> synstack('.', col('.'))
\ ->map({_, id -> id->synIDattr('name')})
\ ->match('\%(Comment\|Todo\|String\)$') >= 0},
- \ [0, a:fromlnum - s:maxoff]->max(), s:searchpair_timeout)
+ \ [0, a:fromlnum - s:maxoff]->max(), g:python_indent.searchpair_timeout)
endfunction
" See if the specified line is already user-dedented from the expected value.
@@ -38,7 +44,7 @@ function python#GetIndent(lnum, ...)
if a:lnum > 1 && getline(a:lnum - 2) =~ '\\$'
return indent(a:lnum - 1)
endif
- return indent(a:lnum - 1) + (exists("g:pyindent_continue") ? eval(g:pyindent_continue) : (shiftwidth() * 2))
+ return indent(a:lnum - 1) + get(g:, 'pyindent_continue', g:python_indent.continue)->eval()
endif
" If the start of the line is in a string don't change the indent.
@@ -55,7 +61,7 @@ function python#GetIndent(lnum, ...)
return 0
endif
- if s:disable_parentheses_indenting == 1
+ if g:python_indent.disable_parentheses_indenting == 1
let plindent = indent(plnum)
let plnumstart = plnum
else
@@ -70,8 +76,12 @@ function python#GetIndent(lnum, ...)
" 100, 200, 300, 400)
call cursor(a:lnum, 1)
let [parlnum, parcol] = s:SearchBracket(a:lnum, 'nbW')
- if parlnum > 0 && parcol != col([parlnum, '$']) - 1
- return parcol
+ if parlnum > 0
+ if parcol != col([parlnum, '$']) - 1
+ return parcol
+ elseif getline(a:lnum) =~ '^\s*[])}]' && !g:python_indent.closed_paren_align_last_line
+ return indent(parlnum)
+ endif
endif
call cursor(plnum, 1)
@@ -123,9 +133,11 @@ function python#GetIndent(lnum, ...)
" When the start is inside parenthesis, only indent one 'shiftwidth'.
let [pp, _] = s:SearchBracket(a:lnum, 'bW')
if pp > 0
- return indent(plnum) + (exists("g:pyindent_nested_paren") ? eval(g:pyindent_nested_paren) : shiftwidth())
+ return indent(plnum)
+ \ + get(g:, 'pyindent_nested_paren', g:python_indent.nested_paren)->eval()
endif
- return indent(plnum) + (exists("g:pyindent_open_paren") ? eval(g:pyindent_open_paren) : (shiftwidth() * 2))
+ return indent(plnum)
+ \ + get(g:, 'pyindent_open_paren', g:python_indent.open_paren)->eval()
endif
if plnumstart == p
return indent(plnum)
diff --git a/runtime/autoload/tohtml.vim b/runtime/autoload/tohtml.vim
index 66f1cb46cb..4ae17815ba 100644
--- a/runtime/autoload/tohtml.vim
+++ b/runtime/autoload/tohtml.vim
@@ -712,6 +712,9 @@ func! tohtml#GetUserSettings() "{{{
call tohtml#GetOption(user_settings, 'no_foldcolumn', user_settings.ignore_folding)
call tohtml#GetOption(user_settings, 'hover_unfold', 0 )
call tohtml#GetOption(user_settings, 'no_pre', 0 )
+ call tohtml#GetOption(user_settings, 'no_doc', 0 )
+ call tohtml#GetOption(user_settings, 'no_links', 0 )
+ call tohtml#GetOption(user_settings, 'no_modeline', 0 )
call tohtml#GetOption(user_settings, 'no_invalid', 0 )
call tohtml#GetOption(user_settings, 'whole_filler', 0 )
call tohtml#GetOption(user_settings, 'use_xhtml', 0 )
@@ -752,7 +755,7 @@ func! tohtml#GetUserSettings() "{{{
" pre_wrap doesn't do anything if not using pre or not using CSS
if user_settings.no_pre || !user_settings.use_css
- let user_settings.pre_wrap=0
+ let user_settings.pre_wrap = 0
endif
"}}}
diff --git a/runtime/autoload/tutor.vim b/runtime/autoload/tutor.vim
index abf5c5e2c8..4da4213826 100644
--- a/runtime/autoload/tutor.vim
+++ b/runtime/autoload/tutor.vim
@@ -104,7 +104,7 @@ function! tutor#CheckLine(line)
if exists('b:tutor_metadata') && has_key(b:tutor_metadata, 'expect')
let bufn = bufnr('%')
let ctext = getline(a:line)
- let signs = sign_getplaced('.', {'lnum': a:line})[0].signs
+ let signs = sign_getplaced(bufn, {'lnum': a:line})[0].signs
if !empty(signs)
call sign_unplace('', {'id': signs[0].id})
endif
diff --git a/runtime/autoload/zig/fmt.vim b/runtime/autoload/zig/fmt.vim
new file mode 100644
index 0000000000..b78c1994dd
--- /dev/null
+++ b/runtime/autoload/zig/fmt.vim
@@ -0,0 +1,100 @@
+" Adapted from fatih/vim-go: autoload/go/fmt.vim
+"
+" Copyright 2011 The Go Authors. All rights reserved.
+" Use of this source code is governed by a BSD-style
+" license that can be found in the LICENSE file.
+"
+" Upstream: https://github.com/ziglang/zig.vim
+
+function! zig#fmt#Format() abort
+ " Save cursor position and many other things.
+ let view = winsaveview()
+
+ if !executable('zig')
+ echohl Error | echomsg "no zig binary found in PATH" | echohl None
+ return
+ endif
+
+ let cmdline = 'zig fmt --stdin --ast-check'
+ let current_buf = bufnr('')
+
+ " The formatted code is output on stdout, the errors go on stderr.
+ if exists('*systemlist')
+ silent let out = systemlist(cmdline, current_buf)
+ else
+ silent let out = split(system(cmdline, current_buf))
+ endif
+ if len(out) == 1
+ if out[0] == "error: unrecognized parameter: '--ast-check'"
+ let cmdline = 'zig fmt --stdin'
+ if exists('*systemlist')
+ silent let out = systemlist(cmdline, current_buf)
+ else
+ silent let out = split(system(cmdline, current_buf))
+ endif
+ endif
+ endif
+ let err = v:shell_error
+
+
+ if err == 0
+ " remove undo point caused via BufWritePre.
+ try | silent undojoin | catch | endtry
+
+ " Replace the file content with the formatted version.
+ if exists('*deletebufline')
+ call deletebufline(current_buf, len(out), line('$'))
+ else
+ silent execute ':' . len(out) . ',' . line('$') . ' delete _'
+ endif
+ call setline(1, out)
+
+ " No errors detected, close the loclist.
+ call setloclist(0, [], 'r')
+ lclose
+ elseif get(g:, 'zig_fmt_parse_errors', 1)
+ let errors = s:parse_errors(expand('%'), out)
+
+ call setloclist(0, [], 'r', {
+ \ 'title': 'Errors',
+ \ 'items': errors,
+ \ })
+
+ let max_win_height = get(g:, 'zig_fmt_max_window_height', 5)
+ " Prevent the loclist from becoming too long.
+ let win_height = min([max_win_height, len(errors)])
+ " Open the loclist, but only if there's at least one error to show.
+ execute 'silent! lwindow ' . win_height
+ endif
+
+ call winrestview(view)
+
+ if err != 0
+ echohl Error | echomsg "zig fmt returned error" | echohl None
+ return
+ endif
+
+ " Run the syntax highlighter on the updated content and recompute the folds if
+ " needed.
+ syntax sync fromstart
+endfunction
+
+" parse_errors parses the given errors and returns a list of parsed errors
+function! s:parse_errors(filename, lines) abort
+ " list of errors to be put into location list
+ let errors = []
+ for line in a:lines
+ let tokens = matchlist(line, '^\(.\{-}\):\(\d\+\):\(\d\+\)\s*\(.*\)')
+ if !empty(tokens)
+ call add(errors,{
+ \"filename": a:filename,
+ \"lnum": tokens[2],
+ \"col": tokens[3],
+ \"text": tokens[4],
+ \ })
+ endif
+ endfor
+
+ return errors
+endfunction
+" vim: sw=2 ts=2 et