diff options
38 files changed, 948 insertions, 814 deletions
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 7d41c17894..0000000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,3 +0,0 @@ -/.github/ @jamessan -/ci/ @jamessan -/scripts/ @jamessan diff --git a/.github/workflows/env.sh b/.github/workflows/env.sh index d1bc412399..acdbc5da1e 100755 --- a/.github/workflows/env.sh +++ b/.github/workflows/env.sh @@ -42,6 +42,7 @@ EOF tsan) cat <<EOF >> "$GITHUB_ENV" TSAN_OPTIONS=log_path=$GITHUB_WORKSPACE/build/log/tsan +CLANG_SANITIZER=TSAN EOF ;; lint) diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 76fc8793fa..a2e0566eb1 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -1,8 +1,9 @@ name: "Pull Request Labeler" on: pull_request_target: - types: opened + types: [opened] jobs: + triage: runs-on: ubuntu-latest permissions: @@ -12,8 +13,10 @@ jobs: - uses: actions/labeler@main with: repo-token: "${{ secrets.GITHUB_TOKEN }}" + type-scope: runs-on: ubuntu-latest + needs: ["triage"] permissions: contents: write pull-requests: write @@ -23,8 +26,81 @@ jobs: PR_NUMBER: ${{ github.event.pull_request.number }} PR_TITLE: ${{ github.event.pull_request.title }} steps: - # Extract type and try to add it as a label - - run: gh pr edit "$PR_NUMBER" --add-label "$(echo "$PR_TITLE" | sed -E 's|([[:alpha:]]+)(\(.*\))?!?:.*|\1|')" || true + - name: "Extract commit type and add as label" + continue-on-error: true + run: gh pr edit "$PR_NUMBER" --add-label "$(echo "$PR_TITLE" | sed -E 's|([[:alpha:]]+)(\(.*\))?!?:.*|\1|')" + - name: "Extract commit scope and add as label" + continue-on-error: true + run: gh pr edit "$PR_NUMBER" --add-label "$(echo "$PR_TITLE" | sed -E 's|[[:alpha:]]+\((.+)\)!?:.*|\1|')" + + add-reviewer: + # This job currently doesn't work due to a bug in GitHub CLI. + # + # Issue: https://github.com/cli/cli/issues/4844 + # PR that will fix it: https://github.com/cli/cli/pull/4876 + # + # The current workaround is to temporarily add "continue-on-error" flag so + # the whole workflow doesn't get flagged as a failure. + runs-on: ubuntu-latest + needs: ["triage", "type-scope"] + permissions: + contents: write + pull-requests: write + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + PR_NUMBER: ${{ github.event.pull_request.number }} + continue-on-error: true + steps: + - name: Get labels + id: labels + run: echo "::set-output name=labels::$(gh pr view $PR_NUMBER --json labels --jq '.labels.[].name' | tr '\n' '%')" + + # The % at the end of the label is a hack to avoid selecting a label that + # is substring of another label. So if there is a label "cinema" then we + # don't accidentally want to interpret that as the label "ci" + + - if: contains(steps.labels.outputs.labels, 'api%') + run: gh pr edit $PR_NUMBER --add-reviewer bfredl,gpanders,muniter + + - if: contains(steps.labels.outputs.labels, 'ci%') + run: gh pr edit $PR_NUMBER --add-reviewer jamessan + + - if: contains(steps.labels.outputs.labels, 'diagnostic%') + run: gh pr edit $PR_NUMBER --add-reviewer gpanders + + - if: contains(steps.labels.outputs.labels, 'distribution%') + run: gh pr edit $PR_NUMBER --add-reviewer jamessan + + - if: contains(steps.labels.outputs.labels, 'documentation%') + run: gh pr edit $PR_NUMBER --add-reviewer clason + + - if: contains(steps.labels.outputs.labels, 'extmarks%') + run: gh pr edit $PR_NUMBER --add-reviewer bfredl + + - if: contains(steps.labels.outputs.labels, 'filetype%') + run: gh pr edit $PR_NUMBER --add-reviewer clason,gpanders + + - if: contains(steps.labels.outputs.labels, 'gui%') + run: gh pr edit $PR_NUMBER --add-reviewer glacambre,smolck + + - if: contains(steps.labels.outputs.labels, 'platform:windows%') + run: gh pr edit $PR_NUMBER --add-reviewer erw7 + + - if: contains(steps.labels.outputs.labels, 'lsp%') + run: gh pr edit $PR_NUMBER --add-reviewer mfussenegger,mjlbach + + - if: contains(steps.labels.outputs.labels, 'terminal%') + run: gh pr edit $PR_NUMBER --add-reviewer erw7 + + - if: contains(steps.labels.outputs.labels, 'treesitter%') + run: gh pr edit $PR_NUMBER --add-reviewer bfredl,vigoux + + - if: contains(steps.labels.outputs.labels, 'typo%') + run: gh pr edit $PR_NUMBER --add-reviewer dundargoc + + - if: contains(steps.labels.outputs.labels, 'ui%') + run: gh pr edit $PR_NUMBER --add-reviewer bfredl - # Extract scope and try to add it as a label - - run: gh pr edit "$PR_NUMBER" --add-label "$(echo "$PR_TITLE" | sed -E 's|[[:alpha:]]+\((.+)\)!?:.*|\1|')" || true + - if: contains(steps.labels.outputs.labels, 'vim-patch%') + run: gh pr edit $PR_NUMBER --add-reviewer janlazo,seandewar diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c43c5c494..e0f05e1205 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -408,6 +408,19 @@ main(void) if(TS_HAS_SET_MATCH_LIMIT) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNVIM_TS_HAS_SET_MATCH_LIMIT") endif() +check_c_source_compiles(" +#include <stdlib.h> +#include <tree_sitter/api.h> +int +main(void) +{ + ts_set_allocator(malloc, calloc, realloc, free); + return 0; +} +" TS_HAS_SET_ALLOCATOR) +if(TS_HAS_SET_ALLOCATOR) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNVIM_TS_HAS_SET_ALLOCATOR") +endif() # Note: The test lib requires LuaJIT; it will be skipped if LuaJIT is missing. option(PREFER_LUA "Prefer Lua over LuaJIT in the nvim executable." OFF) diff --git a/runtime/autoload/man.vim b/runtime/autoload/man.vim index 90d353f9de..a954e1b1a3 100644 --- a/runtime/autoload/man.vim +++ b/runtime/autoload/man.vim @@ -7,7 +7,6 @@ let s:loaded_man = 1 let s:find_arg = '-w' let s:localfile_arg = v:true " Always use -l if possible. #6683 -let s:section_arg = '-S' function! man#init() abort try @@ -216,16 +215,38 @@ endfunction function! s:get_path(sect, name) abort " Some man implementations (OpenBSD) return all available paths from the - " search command, so we get() the first one. #8341 - if empty(a:sect) - return substitute(get(split(s:system(['man', s:find_arg, a:name])), 0, ''), '\n\+$', '', '') + " 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. + let results = split(s:system(['man', s:find_arg, a:sect, a:name])) + + if empty(results) + return '' endif - " '-s' flag handles: - " - tokens like 'printf(echo)' - " - sections starting with '-' - " - 3pcap section (found on macOS) - " - commas between sections (for section priority) - return substitute(get(split(s:system(['man', s:find_arg, s:section_arg, a:sect, a:name])), 0, ''), '\n\+$', '', '') + + " 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 @@ -243,40 +264,72 @@ endfunction " then we don't do it again in step 2. function! s:verify_exists(sect, name) abort let sect = a:sect - if empty(sect) - let sect = get(b:, 'man_default_sects', '') - endif - try - return s:get_path(sect, a:name) - catch /^command error (/ - endtry - - if !empty(get(b:, 'man_default_sects', '')) && sect !=# b:man_default_sects + 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 - return s:get_path(b:man_default_sects, a:name) + let res = s:get_path(sect, a:name) + if !empty(res) + return res + endif catch /^command error (/ endtry - endif - if !empty(sect) - try - return s:get_path('', a:name) - 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) - return s:get_path('', a:name) + 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 diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index 4f76c7c7a6..80c1f58323 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -1240,19 +1240,32 @@ inspect({object}, {options}) *vim.inspect()* https://github.com/kikito/inspect.lua https://github.com/mpeterv/vinspect -notify({msg}, {log_level}, {opts}) *vim.notify()* - Notification provider +notify({msg}, {level}, {opts}) *vim.notify()* + Display a notification to the user. - Without a runtime, writes to :Messages + This function can be overridden by plugins to display + notifications using a custom provider (such as the system + notification provider). By default, writes to |:messages|. Parameters: ~ - {msg} string Content of the notification to show to - the user - {log_level} number|nil enum from vim.log.levels - {opts} table|nil additional options (timeout, etc) + {msg} string Content of the notification to show to the + user. + {level} number|nil One of the values from + |vim.log.levels|. + {opts} table|nil Optional parameters. Unused by default. - See also: ~ - :help nvim_notify +notify_once({msg}, {level}, {opts}) *vim.notify_once()* + Display a notification only one time. + + Like |vim.notify()|, but subsequent calls with the same + message will not display a notification. + + Parameters: ~ + {msg} string Content of the notification to show to the + user. + {level} number|nil One of the values from + |vim.log.levels|. + {opts} table|nil Optional parameters. Unused by default. on_key({fn}, {ns_id}) *vim.on_key()* Adds Lua function {fn} with namespace id {ns_id} as a listener @@ -1316,6 +1329,18 @@ paste({lines}, {phase}) *vim.paste()* See also: ~ |paste| +pretty_print({...}) *vim.pretty_print()* + Prints given arguments in human-readable format. Example: > + -- Print highlight group Normal and store it's contents in a variable. + local hl_normal = vim.pretty_print(vim.api.nvim_get_hl_by_name("Normal", true)) +< + + Return: ~ + given arguments. + + See also: ~ + |vim.inspect()| + region({bufnr}, {pos1}, {pos2}, {regtype}, {inclusive}) *vim.region()* Get a table of lines with start, end columns for a region marked by two points @@ -1847,4 +1872,81 @@ add({filetypes}) *vim.filetype.add()* {filetypes} table A table containing new filetype maps (see example). + +============================================================================== +Lua module: keymap *lua-keymap* + +del({modes}, {lhs}, {opts}) *vim.keymap.del()* + Remove an existing mapping. Examples: > + + vim.keymap.del('n', 'lhs') + + vim.keymap.del({'n', 'i', 'v'}, '<leader>w', { buffer = 5 }) +< + + Parameters: ~ + {opts} table A table of optional arguments: + • buffer: (number or boolean) Remove a mapping + from the given buffer. When "true" or 0, use the + current buffer. + + See also: ~ + |vim.keymap.set()| + +set({mode}, {lhs}, {rhs}, {opts}) *vim.keymap.set()* + Add a new |mapping|. Examples: > + + -- Can add mapping to Lua functions + vim.keymap.set('n', 'lhs', function() print("real lua function") end) + + -- Can use it to map multiple modes + vim.keymap.set({'n', 'v'}, '<leader>lr', vim.lsp.buf.references, { buffer=true }) + + -- Can add mapping for specific buffer + vim.keymap.set('n', '<leader>w', "<cmd>w<cr>", { silent = true, buffer = 5 }) + + -- Expr mappings + vim.keymap.set('i', '<Tab>', function() + return vim.fn.pumvisible() == 1 and "<C-n>" or "<Tab>" + end, { expr = true }) + -- <Plug> mappings + vim.keymap.set('n', '[%', '<Plug>(MatchitNormalMultiBackward)') +< + + Note that in a mapping like: > + + vim.keymap.set('n', 'asdf', require('jkl').my_fun) +< + + the require('jkl') gets evaluated during this call in order to + access the function. If you want to avoid this cost at startup + you can wrap it in a function, for example: > + + vim.keymap.set('n', 'asdf', function() return require('jkl').my_fun() end) +< + + Parameters: ~ + {mode} string|table Same mode short names as + |nvim_set_keymap()|. Can also be list of modes to + create mapping on multiple modes. + {lhs} string Left-hand side |{lhs}| of the mapping. + {rhs} string|function Right-hand side |{rhs}| of the + mapping. Can also be a Lua function. + {opts} table A table of |:map-arguments| such as + "silent". In addition to the options listed in + |nvim_set_keymap()|, this table also accepts the + following keys: + • replace_keycodes: (boolean, default true) When + both this and expr is "true", + |nvim_replace_termcodes()| is applied to the + result of Lua expr maps. + • remap: (boolean) Make the mapping recursive. + This is the inverse of the "noremap" option from + |nvim_set_keymap()|. Default `true` if `lhs` is + a string starting with `<plug>` + (case-insensitive), `false` otherwise. + + See also: ~ + |nvim_set_keymap()| + vim:tw=78:ts=8:ft=help:norl: diff --git a/runtime/filetype.vim b/runtime/filetype.vim index 7fdbfe32d8..907f806f31 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -493,7 +493,7 @@ au BufNewFile,BufRead */debian/patches/* call dist#ft#Dep3patch() " Diff files au BufNewFile,BufRead *.diff,*.rej setf diff au BufNewFile,BufRead *.patch - \ if getline(1) =~ '^From [0-9a-f]\{40\} Mon Sep 17 00:00:00 2001$' | + \ if getline(1) =~# '^From [0-9a-f]\{40,\} Mon Sep 17 00:00:00 2001$' | \ setf gitsendemail | \ else | \ setf diff | @@ -672,6 +672,7 @@ autocmd BufRead,BufNewFile *.gift setf gift " Git au BufNewFile,BufRead COMMIT_EDITMSG,MERGE_MSG,TAG_EDITMSG setf gitcommit +au BufNewFile,BufRead NOTES_EDITMSG,EDIT_DESCRIPTION setf gitcommit au BufNewFile,BufRead *.git/config,.gitconfig,/etc/gitconfig setf gitconfig au BufNewFile,BufRead */.config/git/config setf gitconfig au BufNewFile,BufRead .gitmodules,*.git/modules/*/config setf gitconfig @@ -680,12 +681,8 @@ if !empty($XDG_CONFIG_HOME) endif au BufNewFile,BufRead git-rebase-todo setf gitrebase au BufRead,BufNewFile .gitsendemail.msg.?????? setf gitsendemail -au BufNewFile,BufRead .msg.[0-9]* - \ if getline(1) =~ '^From.*# This line is ignored.$' | - \ setf gitsendemail | - \ endif au BufNewFile,BufRead *.git/* - \ if getline(1) =~ '^\x\{40\}\>\|^ref: ' | + \ if getline(1) =~# '^\x\{40,\}\>\|^ref: ' | \ setf git | \ endif diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 54b20f7391..28cffdf072 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -15,7 +15,7 @@ local function starsetf(ft) end end, { -- Starset matches should always have lowest priority - priority = -1, + priority = -math.huge, }} end @@ -868,6 +868,8 @@ local filename = { ["TAG_EDITMSG"] = "gitcommit", ["MERGE_MSG"] = "gitcommit", ["COMMIT_EDITMSG"] = "gitcommit", + ["NOTES_EDITMSG"] = "gitcommit", + ["EDIT_DESCRIPTION"] = "gitcommit", [".gitconfig"] = "gitconfig", [".gitmodules"] = "gitconfig", ["/.config/git/config"] = "gitconfig", @@ -1454,6 +1456,25 @@ local function dispatch(ft, path, bufnr, ...) end ---@private +local function match_pattern(name, path, tail, pat) + -- If the pattern contains a / match against the full path, otherwise just the tail + local fullpat = "^" .. pat .. "$" + local matches + if pat:find("/") then + -- Similar to |autocmd-pattern|, if the pattern contains a '/' then check for a match against + -- both the short file name (as typed) and the full file name (after expanding to full path + -- and resolving symlinks) + matches = name:match(fullpat) or path:match(fullpat) + else + matches = tail:match(fullpat) + end + return matches +end + +--- Set the filetype for the given buffer from a file name. +--- +---@param name string File name (can be an absolute or relative path) +---@param bufnr number|nil The buffer to set the filetype for. Defaults to the current buffer. function M.match(name, bufnr) -- When fired from the main filetypedetect autocommand the {bufnr} argument is omitted, so we use -- the current buffer. The {bufnr} argument is provided to allow extensibility in case callers @@ -1474,21 +1495,18 @@ function M.match(name, bufnr) return end - -- Next, check the file path against available patterns - for _, v in ipairs(pattern_sorted) do + -- Next, check the file path against available patterns with non-negative priority + local j = 1 + for i, v in ipairs(pattern_sorted) do local k = next(v) - local ft = v[k][1] - -- If the pattern contains a / match against the full path, otherwise just the tail - local pat = "^" .. k .. "$" - local matches - if k:find("/") then - -- Similar to |autocmd-pattern|, if the pattern contains a '/' then check for a match against - -- both the short file name (as typed) and the full file name (after expanding to full path - -- and resolving symlinks) - matches = name:match(pat) or path:match(pat) - else - matches = tail:match(pat) + local opts = v[k][2] + if opts.priority < 0 then + j = i + break end + + local ft = v[k][1] + local matches = match_pattern(name, path, tail, k) if matches then if dispatch(ft, path, bufnr, matches) then return @@ -1496,11 +1514,25 @@ function M.match(name, bufnr) end end - -- Finally, check file extension + -- Next, check file extension local ext = vim.fn.fnamemodify(name, ":e") if dispatch(extension[ext], path, bufnr) then return end + + -- Finally, check patterns with negative priority + for i = j, #pattern_sorted do + local v = pattern_sorted[i] + local k = next(v) + + local ft = v[k][1] + local matches = match_pattern(name, path, tail, k) + if matches then + if dispatch(ft, path, bufnr, matches) then + return + end + end + end end return M diff --git a/runtime/lua/vim/keymap.lua b/runtime/lua/vim/keymap.lua new file mode 100644 index 0000000000..d53b790746 --- /dev/null +++ b/runtime/lua/vim/keymap.lua @@ -0,0 +1,135 @@ +local keymap = {} + +--- Add a new |mapping|. +--- Examples: +--- <pre> +--- -- Can add mapping to Lua functions +--- vim.keymap.set('n', 'lhs', function() print("real lua function") end) +--- +--- -- Can use it to map multiple modes +--- vim.keymap.set({'n', 'v'}, '<leader>lr', vim.lsp.buf.references, { buffer=true }) +--- +--- -- Can add mapping for specific buffer +--- vim.keymap.set('n', '<leader>w', "<cmd>w<cr>", { silent = true, buffer = 5 }) +--- +--- -- Expr mappings +--- vim.keymap.set('i', '<Tab>', function() +--- return vim.fn.pumvisible() == 1 and "<C-n>" or "<Tab>" +--- end, { expr = true }) +--- -- <Plug> mappings +--- vim.keymap.set('n', '[%%', '<Plug>(MatchitNormalMultiBackward)') +--- </pre> +--- +--- Note that in a mapping like: +--- <pre> +--- vim.keymap.set('n', 'asdf', require('jkl').my_fun) +--- </pre> +--- +--- the require('jkl') gets evaluated during this call in order to access the function. If you want to +--- avoid this cost at startup you can wrap it in a function, for example: +--- <pre> +--- vim.keymap.set('n', 'asdf', function() return require('jkl').my_fun() end) +--- </pre> +--- +---@param mode string|table Same mode short names as |nvim_set_keymap()|. +--- Can also be list of modes to create mapping on multiple modes. +---@param lhs string Left-hand side |{lhs}| of the mapping. +---@param rhs string|function Right-hand side |{rhs}| of the mapping. Can also be a Lua function. +-- +---@param opts table A table of |:map-arguments| such as "silent". In addition to the options +--- listed in |nvim_set_keymap()|, this table also accepts the following keys: +--- - replace_keycodes: (boolean, default true) When both this and expr is "true", +--- |nvim_replace_termcodes()| is applied to the result of Lua expr maps. +--- - remap: (boolean) Make the mapping recursive. This is the +--- inverse of the "noremap" option from |nvim_set_keymap()|. +--- Default `true` if `lhs` is a string starting with `<plug>` (case-insensitive), `false` otherwise. +---@see |nvim_set_keymap()| +function keymap.set(mode, lhs, rhs, opts) + vim.validate { + mode = {mode, {'s', 't'}}, + lhs = {lhs, 's'}, + rhs = {rhs, {'s', 'f'}}, + opts = {opts, 't', true} + } + + opts = vim.deepcopy(opts) or {} + local is_rhs_luaref = type(rhs) == "function" + mode = type(mode) == 'string' and {mode} or mode + + if is_rhs_luaref and opts.expr and opts.replace_keycodes ~= false then + local user_rhs = rhs + rhs = function () + return vim.api.nvim_replace_termcodes(user_rhs(), true, true, true) + end + end + -- clear replace_keycodes from opts table + opts.replace_keycodes = nil + + if opts.remap == nil then + -- remap by default on <plug> mappings and don't otherwise. + opts.noremap = is_rhs_luaref or rhs:lower():match("^<plug>") == nil + else + -- remaps behavior is opposite of noremap option. + opts.noremap = not opts.remap + opts.remap = nil + end + + if is_rhs_luaref then + opts.callback = rhs + rhs = '' + end + + if opts.buffer then + local bufnr = opts.buffer == true and 0 or opts.buffer + opts.buffer = nil + for _, m in ipairs(mode) do + vim.api.nvim_buf_set_keymap(bufnr, m, lhs, rhs, opts) + end + else + opts.buffer = nil + for _, m in ipairs(mode) do + vim.api.nvim_set_keymap(m, lhs, rhs, opts) + end + end +end + +--- Remove an existing mapping. +--- Examples: +--- <pre> +--- vim.keymap.del('n', 'lhs') +--- +--- vim.keymap.del({'n', 'i', 'v'}, '<leader>w', { buffer = 5 }) +--- </pre> +---@param opts table A table of optional arguments: +--- - buffer: (number or boolean) Remove a mapping from the given buffer. +--- When "true" or 0, use the current buffer. +---@see |vim.keymap.set()| +--- +function keymap.del(modes, lhs, opts) + vim.validate { + mode = {modes, {'s', 't'}}, + lhs = {lhs, 's'}, + opts = {opts, 't', true} + } + + opts = opts or {} + modes = type(modes) == 'string' and {modes} or modes + + local buffer = false + if opts.buffer ~= nil then + buffer = opts.buffer == true and 0 or opts.buffer + opts.buffer = nil + end + + if buffer == false then + for _, mode in ipairs(modes) do + vim.api.nvim_del_keymap(mode, lhs) + end + else + for _, mode in ipairs(modes) do + vim.api.nvim_buf_del_keymap(buffer, mode, lhs) + end + end +end + +return keymap diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 7df0064b6b..fc9c991c05 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -306,7 +306,6 @@ local function once(fn) end end - local changetracking = {} do --@private @@ -327,6 +326,7 @@ do if not state then state = { pending_changes = {}; + last_flush = {}; use_incremental_sync = ( if_nil(client.config.flags.allow_incremental_sync, true) and client.resolved_capabilities.text_document_did_change == protocol.TextDocumentSyncKind.Incremental @@ -347,8 +347,11 @@ do function changetracking.reset_buf(client, bufnr) changetracking.flush(client) local state = state_by_client[client.id] - if state and state.buffers then - state.buffers[bufnr] = nil + if state then + if state.buffers then + state.buffers[bufnr] = nil + end + state.last_flush = {} end end @@ -362,6 +365,33 @@ do end ---@private + -- + -- Adjust debounce time by taking time of last didChange notification into + -- consideration. If the last didChange happened more than `debounce` time ago, + -- debounce can be skipped and otherwise maybe reduced. + -- + -- This turns the debounce into a kind of client rate limiting + local function next_debounce(debounce, state, bufnr) + if debounce == 0 then + return 0 + end + local ns_to_ms = 0.000001 + local last_flush = state.last_flush[bufnr] + if not last_flush then + return debounce + end + local now = uv.hrtime() + local ms_since_last_flush = (now - last_flush) * ns_to_ms + local remaining_debounce = debounce - ms_since_last_flush + if remaining_debounce > 0 then + return remaining_debounce + else + state.last_flush[bufnr] = now + return 0 + end + end + + ---@private function changetracking.prepare(bufnr, firstline, lastline, new_lastline) local incremental_changes = function(client) local cached_buffers = state_by_client[client.id].buffers @@ -383,8 +413,12 @@ do return end local state = state_by_client[client.id] - local debounce = client.config.flags.debounce_text_changes or 150 + changetracking._reset_timer(state) + local debounce = next_debounce(client.config.flags.debounce_text_changes or 150, state, bufnr) if debounce == 0 then + if state.pending_change then + state.pending_change() + end local changes = state.use_incremental_sync and incremental_changes(client) or full_changes() client.notify("textDocument/didChange", { textDocument = { @@ -395,7 +429,6 @@ do }) return end - changetracking._reset_timer(state) if state.use_incremental_sync then -- This must be done immediately and cannot be delayed -- The contents would further change and startline/endline may no longer fit @@ -406,6 +439,7 @@ do end state.pending_change = function() state.pending_change = nil + state.last_flush[bufnr] = uv.hrtime() if client.is_stopped() or not vim.api.nvim_buf_is_valid(bufnr) then return end diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 543fdb0237..c1d777ae6c 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -627,14 +627,19 @@ end --- Executes an LSP server command. --- ----@param command A valid `ExecuteCommandParams` object +---@param command_params table A valid `ExecuteCommandParams` object ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand -function M.execute_command(command) +function M.execute_command(command_params) validate { - command = { command.command, 's' }, - arguments = { command.arguments, 't', true } + command = { command_params.command, 's' }, + arguments = { command_params.arguments, 't', true } } - request('workspace/executeCommand', command) + command_params = { + command=command_params.command, + arguments=command_params.arguments, + workDoneToken=command_params.workDoneToken, + } + request('workspace/executeCommand', command_params ) end return M diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 8850d25233..f38b469f3c 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -243,7 +243,7 @@ end ---@param client_id number ---@private function M.save(diagnostics, bufnr, client_id) - vim.api.nvim_echo({{'vim.lsp.diagnostic.save is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.notify_once('vim.lsp.diagnostic.save is deprecated. See :h deprecated', vim.log.levels.WARN) local namespace = M.get_namespace(client_id) vim.diagnostic.set(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id)) end @@ -257,7 +257,7 @@ end --- If nil, diagnostics of all clients are included. ---@return table with diagnostics grouped by bufnr (bufnr: Diagnostic[]) function M.get_all(client_id) - vim.api.nvim_echo({{'vim.lsp.diagnostic.get_all is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.notify_once('vim.lsp.diagnostic.get_all is deprecated. See :h deprecated', vim.log.levels.WARN) local result = {} local namespace if client_id then @@ -279,7 +279,7 @@ end --- Else, return just the diagnostics associated with the client_id. ---@param predicate function|nil Optional function for filtering diagnostics function M.get(bufnr, client_id, predicate) - vim.api.nvim_echo({{'vim.lsp.diagnostic.get is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.notify_once('vim.lsp.diagnostic.get is deprecated. See :h deprecated', vim.log.levels.WARN) predicate = predicate or function() return true end if client_id == nil then local all_diagnostics = {} @@ -341,7 +341,7 @@ end ---@param severity DiagnosticSeverity ---@param client_id number the client id function M.get_count(bufnr, severity, client_id) - vim.api.nvim_echo({{'vim.lsp.diagnostic.get_count is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.notify_once('vim.lsp.diagnostic.get_count is deprecated. See :h deprecated', vim.log.levels.WARN) severity = severity_lsp_to_vim(severity) local opts = { severity = severity } if client_id ~= nil then @@ -358,7 +358,7 @@ end ---@param opts table See |vim.lsp.diagnostic.goto_next()| ---@return table Previous diagnostic function M.get_prev(opts) - vim.api.nvim_echo({{'vim.lsp.diagnostic.get_prev is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.notify_once('vim.lsp.diagnostic.get_prev is deprecated. See :h deprecated', vim.log.levels.WARN) if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -376,7 +376,7 @@ end ---@param opts table See |vim.lsp.diagnostic.goto_next()| ---@return table Previous diagnostic position function M.get_prev_pos(opts) - vim.api.nvim_echo({{'vim.lsp.diagnostic.get_prev_pos is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.notify_once('vim.lsp.diagnostic.get_prev_pos is deprecated. See :h deprecated', vim.log.levels.WARN) if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -393,7 +393,7 @@ end --- ---@param opts table See |vim.lsp.diagnostic.goto_next()| function M.goto_prev(opts) - vim.api.nvim_echo({{'vim.lsp.diagnostic.goto_prev is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.notify_once('vim.lsp.diagnostic.goto_prev is deprecated. See :h deprecated', vim.log.levels.WARN) if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -411,7 +411,7 @@ end ---@param opts table See |vim.lsp.diagnostic.goto_next()| ---@return table Next diagnostic function M.get_next(opts) - vim.api.nvim_echo({{'vim.lsp.diagnostic.get_next is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.notify_once('vim.lsp.diagnostic.get_next is deprecated. See :h deprecated', vim.log.levels.WARN) if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -429,7 +429,7 @@ end ---@param opts table See |vim.lsp.diagnostic.goto_next()| ---@return table Next diagnostic position function M.get_next_pos(opts) - vim.api.nvim_echo({{'vim.lsp.diagnostic.get_next_pos is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.notify_once('vim.lsp.diagnostic.get_next_pos is deprecated. See :h deprecated', vim.log.levels.WARN) if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -444,7 +444,7 @@ end --- ---@deprecated Prefer |vim.diagnostic.goto_next()| function M.goto_next(opts) - vim.api.nvim_echo({{'vim.lsp.diagnostic.goto_next is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.notify_once('vim.lsp.diagnostic.goto_next is deprecated. See :h deprecated', vim.log.levels.WARN) if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -468,7 +468,7 @@ end --- - severity_limit (DiagnosticSeverity): --- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid. function M.set_signs(diagnostics, bufnr, client_id, _, opts) - vim.api.nvim_echo({{'vim.lsp.diagnostic.set_signs is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.notify_once('vim.lsp.diagnostic.set_signs is deprecated. See :h deprecated', vim.log.levels.WARN) local namespace = M.get_namespace(client_id) if opts and not opts.severity and opts.severity_limit then opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} @@ -489,7 +489,7 @@ end --- - severity_limit (DiagnosticSeverity): --- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid. function M.set_underline(diagnostics, bufnr, client_id, _, opts) - vim.api.nvim_echo({{'vim.lsp.diagnostic.set_underline is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.notify_once('vim.lsp.diagnostic.set_underline is deprecated. See :h deprecated', vim.log.levels.WARN) local namespace = M.get_namespace(client_id) if opts and not opts.severity and opts.severity_limit then opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} @@ -511,7 +511,7 @@ end --- - severity_limit (DiagnosticSeverity): --- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid. function M.set_virtual_text(diagnostics, bufnr, client_id, _, opts) - vim.api.nvim_echo({{'vim.lsp.diagnostic.set_virtual_text is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.notify_once('vim.lsp.diagnostic.set_virtual_text is deprecated. See :h deprecated', vim.log.levels.WARN) local namespace = M.get_namespace(client_id) if opts and not opts.severity and opts.severity_limit then opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} @@ -530,7 +530,7 @@ end ---@return an array of [text, hl_group] arrays. This can be passed directly to --- the {virt_text} option of |nvim_buf_set_extmark()|. function M.get_virtual_text_chunks_for_line(bufnr, _, line_diags, opts) - vim.api.nvim_echo({{'vim.lsp.diagnostic.get_virtual_text_chunks_for_line is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.notify_once('vim.lsp.diagnostic.get_virtual_text_chunks_for_line is deprecated. See :h deprecated', vim.log.levels.WARN) return vim.diagnostic._get_virt_text_chunks(diagnostic_lsp_to_vim(line_diags, bufnr), opts) end @@ -548,7 +548,7 @@ end ---@param position table|nil The (0,0)-indexed position ---@return table {popup_bufnr, win_id} function M.show_position_diagnostics(opts, buf_nr, position) - vim.api.nvim_echo({{'vim.lsp.diagnostic.show_position_diagnostics is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.notify_once('vim.lsp.diagnostic.show_position_diagnostics is deprecated. See :h deprecated', vim.log.levels.WARN) opts = opts or {} opts.scope = "cursor" opts.pos = position @@ -572,7 +572,7 @@ end ---@param client_id number|nil the client id ---@return table {popup_bufnr, win_id} function M.show_line_diagnostics(opts, buf_nr, line_nr, client_id) - vim.api.nvim_echo({{'vim.lsp.diagnostic.show_line_diagnostics is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.notify_once('vim.lsp.diagnostic.show_line_diagnostics is deprecated. See :h deprecated', vim.log.levels.WARN) opts = opts or {} opts.scope = "line" opts.pos = line_nr @@ -596,7 +596,7 @@ end --- client. The default is to redraw diagnostics for all attached --- clients. function M.redraw(bufnr, client_id) - vim.api.nvim_echo({{'vim.lsp.diagnostic.redraw is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.notify_once('vim.lsp.diagnostic.redraw is deprecated. See :h deprecated', vim.log.levels.WARN) bufnr = get_bufnr(bufnr) if not client_id then return vim.lsp.for_each_buffer_client(bufnr, function(client) @@ -624,7 +624,7 @@ end --- - {workspace}: (boolean, default true) --- - Set the list with workspace diagnostics function M.set_qflist(opts) - vim.api.nvim_echo({{'vim.lsp.diagnostic.set_qflist is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.notify_once('vim.lsp.diagnostic.set_qflist is deprecated. See :h deprecated', vim.log.levels.WARN) opts = opts or {} if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -656,7 +656,7 @@ end --- - {workspace}: (boolean, default false) --- - Set the list with workspace diagnostics function M.set_loclist(opts) - vim.api.nvim_echo({{'vim.lsp.diagnostic.set_loclist is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.notify_once('vim.lsp.diagnostic.set_loclist is deprecated. See :h deprecated', vim.log.levels.WARN) opts = opts or {} if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -684,7 +684,7 @@ end -- send diagnostic information and the client will still process it. The -- diagnostics are simply not displayed to the user. function M.disable(bufnr, client_id) - vim.api.nvim_echo({{'vim.lsp.diagnostic.disable is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.notify_once('vim.lsp.diagnostic.disable is deprecated. See :h deprecated', vim.log.levels.WARN) if not client_id then return vim.lsp.for_each_buffer_client(bufnr, function(client) M.disable(bufnr, client.id) @@ -705,7 +705,7 @@ end --- client. The default is to enable diagnostics for all attached --- clients. function M.enable(bufnr, client_id) - vim.api.nvim_echo({{'vim.lsp.diagnostic.enable is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.notify_once('vim.lsp.diagnostic.enable is deprecated. See :h deprecated', vim.log.levels.WARN) if not client_id then return vim.lsp.for_each_buffer_client(bufnr, function(client) M.enable(bufnr, client.id) diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index dcd68a3433..89c5ebe8f7 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -10,14 +10,6 @@ local uv = vim.loop local npcall = vim.F.npcall local split = vim.split -local _warned = {} -local warn_once = function(message) - if not _warned[message] then - vim.api.nvim_err_writeln(message) - _warned[message] = true - end -end - local M = {} local default_border = { @@ -201,6 +193,11 @@ end local function get_lines(bufnr, rows) rows = type(rows) == "table" and rows or { rows } + -- This is needed for bufload and bufloaded + if bufnr == 0 then + bufnr = vim.api.nvim_get_current_buf() + end + ---@private local function buf_lines() local lines = {} @@ -1822,7 +1819,7 @@ function M.make_given_range_params(start_pos, end_pos, bufnr, offset_encoding) end_pos = {end_pos, 't', true}; offset_encoding = {offset_encoding, 's', true}; } - bufnr = bufnr or 0 + bufnr = bufnr or vim.api.nvim_get_current_buf() offset_encoding = offset_encoding or M._get_offset_encoding(bufnr) local A = list_extend({}, start_pos or api.nvim_buf_get_mark(bufnr, '<')) local B = list_extend({}, end_pos or api.nvim_buf_get_mark(bufnr, '>')) @@ -1928,7 +1925,6 @@ function M.lookup_section(settings, section) end M._get_line_byte_from_position = get_line_byte_from_position -M._warn_once = warn_once M.buf_versions = {} diff --git a/runtime/scripts.vim b/runtime/scripts.vim index 3790b1c10f..e41405a6c5 100644 --- a/runtime/scripts.vim +++ b/runtime/scripts.vim @@ -384,7 +384,7 @@ else set ft=scheme " Git output - elseif s:line1 =~# '^\(commit\|tree\|object\) \x\{40\}\>\|^tag \S\+$' + elseif s:line1 =~# '^\(commit\|tree\|object\) \x\{40,\}\>\|^tag \S\+$' set ft=git " Gprof (gnu profiler) diff --git a/runtime/syntax/checkhealth.vim b/runtime/syntax/checkhealth.vim index dff880a0bc..37f1822740 100644 --- a/runtime/syntax/checkhealth.vim +++ b/runtime/syntax/checkhealth.vim @@ -12,7 +12,9 @@ unlet! b:current_syntax syn case match " We do not care about markdown syntax errors -syn clear markdownError +if hlexists('markdownError') + syn clear markdownError +endif syn keyword healthError ERROR[:] containedin=markdownCodeBlock,mkdListItemLine syn keyword healthWarning WARNING[:] containedin=markdownCodeBlock,mkdListItemLine diff --git a/scripts/gen_vimdoc.py b/scripts/gen_vimdoc.py index 3810ebd9d0..3e9fb21039 100755 --- a/scripts/gen_vimdoc.py +++ b/scripts/gen_vimdoc.py @@ -129,6 +129,7 @@ CONFIG = { 'uri.lua', 'ui.lua', 'filetype.lua', + 'keymap.lua', ], 'files': ' '.join([ os.path.join(base_dir, 'src/nvim/lua/vim.lua'), @@ -136,6 +137,7 @@ CONFIG = { os.path.join(base_dir, 'runtime/lua/vim/uri.lua'), os.path.join(base_dir, 'runtime/lua/vim/ui.lua'), os.path.join(base_dir, 'runtime/lua/vim/filetype.lua'), + os.path.join(base_dir, 'runtime/lua/vim/keymap.lua'), ]), 'file_patterns': '*.lua', 'fn_name_prefix': '', @@ -151,6 +153,7 @@ CONFIG = { 'uri': 'vim', 'ui': 'vim.ui', 'filetype': 'vim.filetype', + 'keymap': 'vim.keymap', }, 'append_only': [ 'shared.lua', diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 38a82343c3..f9603acbda 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -1387,6 +1387,11 @@ void add_user_command(String name, Object command, Dict(user_command) *opts, int LuaRef luaref = LUA_NOREF; LuaRef compl_luaref = LUA_NOREF; + if (mb_islower(name.data[0])) { + api_set_error(err, kErrorTypeValidation, "'name' must begin with an uppercase letter"); + goto err; + } + if (HAS_KEY(opts->range) && HAS_KEY(opts->count)) { api_set_error(err, kErrorTypeValidation, "'range' and 'count' are mutually exclusive"); goto err; diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 4f4da7c2a9..340fec230c 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -82,6 +82,14 @@ typedef struct { garray_T dout_ga; // used for internal diff } diffout_T; +// used for recording hunks from xdiff +typedef struct { + linenr_T lnum_orig; + long count_orig; + linenr_T lnum_new; + long count_new; +} diffhunk_T; + // two diff inputs and one result typedef struct { diffin_T dio_orig; // original file input @@ -852,7 +860,7 @@ static void diff_try_update(diffio_T *dio, int idx_orig, exarg_T *eap) } // Read the diff output and add each entry to the diff list. - diff_read(idx_orig, idx_new, &dio->dio_diff); + diff_read(idx_orig, idx_new, dio); clear_diffin(&dio->dio_new); clear_diffout(&dio->dio_diff); @@ -1078,7 +1086,7 @@ static int diff_file_internal(diffio_T *diffio) emit_cfg.ctxlen = 0; // don't need any diff_context here emit_cb.priv = &diffio->dio_diff; - emit_cb.out_line = xdiff_out; + emit_cfg.hunk_func = xdiff_out; if (xdl_diff(&diffio->dio_orig.din_mmfile, &diffio->dio_new.din_mmfile, ¶m, &emit_cfg, &emit_cb) < 0) { @@ -1519,20 +1527,20 @@ void ex_diffoff(exarg_T *eap) /// @param idx_orig idx of original file /// @param idx_new idx of new file /// @dout diff output -static void diff_read(int idx_orig, int idx_new, diffout_T *dout) +static void diff_read(int idx_orig, int idx_new, diffio_T *dio) { FILE *fd = NULL; int line_idx = 0; diff_T *dprev = NULL; diff_T *dp = curtab->tp_first_diff; diff_T *dn, *dpl; + diffout_T *dout = &dio->dio_diff; char_u linebuf[LBUFLEN]; // only need to hold the diff line char_u *line; long off; int i; - linenr_T lnum_orig, lnum_new; - long count_orig, count_new; int notset = true; // block "*dp" not set yet + diffhunk_T *hunk; enum { DIFF_ED, DIFF_UNIFIED, @@ -1549,70 +1557,79 @@ static void diff_read(int idx_orig, int idx_new, diffout_T *dout) } } + if (!dio->dio_internal) { + hunk = xmalloc(sizeof(*hunk)); + } + for (;;) { - if (fd == NULL) { + if (dio->dio_internal) { if (line_idx >= dout->dout_ga.ga_len) { break; // did last line } - line = ((char_u **)dout->dout_ga.ga_data)[line_idx++]; + hunk = ((diffhunk_T **)dout->dout_ga.ga_data)[line_idx++]; } else { - if (vim_fgets(linebuf, LBUFLEN, fd)) { - break; // end of file - } - line = linebuf; - } - - if (diffstyle == DIFF_NONE) { - // Determine diff style. - // ed like diff looks like this: - // {first}[,{last}]c{first}[,{last}] - // {first}a{first}[,{last}] - // {first}[,{last}]d{first} - // - // unified diff looks like this: - // --- file1 2018-03-20 13:23:35.783153140 +0100 - // +++ file2 2018-03-20 13:23:41.183156066 +0100 - // @@ -1,3 +1,5 @@ - if (isdigit(*line)) { - diffstyle = DIFF_ED; - } else if ((STRNCMP(line, "@@ ", 3) == 0)) { - diffstyle = DIFF_UNIFIED; - } else if ((STRNCMP(line, "--- ", 4) == 0) // -V501 - && (vim_fgets(linebuf, LBUFLEN, fd) == 0) // -V501 - && (STRNCMP(line, "+++ ", 4) == 0) - && (vim_fgets(linebuf, LBUFLEN, fd) == 0) // -V501 - && (STRNCMP(line, "@@ ", 3) == 0)) { - diffstyle = DIFF_UNIFIED; + if (fd == NULL) { + if (line_idx >= dout->dout_ga.ga_len) { + break; // did last line + } + line = ((char_u **)dout->dout_ga.ga_data)[line_idx++]; } else { - // Format not recognized yet, skip over this line. Cygwin diff - // may put a warning at the start of the file. - continue; + if (vim_fgets(linebuf, LBUFLEN, fd)) { + break; // end of file + } + line = linebuf; } - } - if (diffstyle == DIFF_ED) { - if (!isdigit(*line)) { - continue; // not the start of a diff block - } - if (parse_diff_ed(line, &lnum_orig, &count_orig, - &lnum_new, &count_new) == FAIL) { - continue; - } - } else { - assert(diffstyle == DIFF_UNIFIED); - if (STRNCMP(line, "@@ ", 3) != 0) { - continue; // not the start of a diff block + if (diffstyle == DIFF_NONE) { + // Determine diff style. + // ed like diff looks like this: + // {first}[,{last}]c{first}[,{last}] + // {first}a{first}[,{last}] + // {first}[,{last}]d{first} + // + // unified diff looks like this: + // --- file1 2018-03-20 13:23:35.783153140 +0100 + // +++ file2 2018-03-20 13:23:41.183156066 +0100 + // @@ -1,3 +1,5 @@ + if (isdigit(*line)) { + diffstyle = DIFF_ED; + } else if ((STRNCMP(line, "@@ ", 3) == 0)) { + diffstyle = DIFF_UNIFIED; + } else if ((STRNCMP(line, "--- ", 4) == 0) // -V501 + && (vim_fgets(linebuf, LBUFLEN, fd) == 0) // -V501 + && (STRNCMP(line, "+++ ", 4) == 0) + && (vim_fgets(linebuf, LBUFLEN, fd) == 0) // -V501 + && (STRNCMP(line, "@@ ", 3) == 0)) { + diffstyle = DIFF_UNIFIED; + } else { + // Format not recognized yet, skip over this line. Cygwin diff + // may put a warning at the start of the file. + continue; + } } - if (parse_diff_unified(line, &lnum_orig, &count_orig, - &lnum_new, &count_new) == FAIL) { - continue; + + if (diffstyle == DIFF_ED) { + if (!isdigit(*line)) { + continue; // not the start of a diff block + } + if (parse_diff_ed(line, hunk) == FAIL) { + continue; + } + } else { + assert(diffstyle == DIFF_UNIFIED); + if (STRNCMP(line, "@@ ", 3) != 0) { + continue; // not the start of a diff block + } + if (parse_diff_unified(line, hunk) == FAIL) { + continue; + } } } // Go over blocks before the change, for which orig and new are equal. // Copy blocks from orig to new. while (dp != NULL - && lnum_orig > dp->df_lnum[idx_orig] + dp->df_count[idx_orig]) { + && hunk->lnum_orig > dp->df_lnum[idx_orig] + dp->df_count[idx_orig]) { if (notset) { diff_copy_entry(dprev, dp, idx_orig, idx_new); } @@ -1622,19 +1639,19 @@ static void diff_read(int idx_orig, int idx_new, diffout_T *dout) } if ((dp != NULL) - && (lnum_orig <= dp->df_lnum[idx_orig] + dp->df_count[idx_orig]) - && (lnum_orig + count_orig >= dp->df_lnum[idx_orig])) { + && (hunk->lnum_orig <= dp->df_lnum[idx_orig] + dp->df_count[idx_orig]) + && (hunk->lnum_orig + hunk->count_orig >= dp->df_lnum[idx_orig])) { // New block overlaps with existing block(s). // First find last block that overlaps. for (dpl = dp; dpl->df_next != NULL; dpl = dpl->df_next) { - if (lnum_orig + count_orig < dpl->df_next->df_lnum[idx_orig]) { + if (hunk->lnum_orig + hunk->count_orig < dpl->df_next->df_lnum[idx_orig]) { break; } } // If the newly found block starts before the old one, set the // start back a number of lines. - off = dp->df_lnum[idx_orig] - lnum_orig; + off = dp->df_lnum[idx_orig] - hunk->lnum_orig; if (off > 0) { for (i = idx_orig; i < idx_new; ++i) { @@ -1642,15 +1659,15 @@ static void diff_read(int idx_orig, int idx_new, diffout_T *dout) dp->df_lnum[i] -= off; } } - dp->df_lnum[idx_new] = lnum_new; - dp->df_count[idx_new] = count_new; + dp->df_lnum[idx_new] = hunk->lnum_new; + dp->df_count[idx_new] = hunk->count_new; } else if (notset) { // new block inside existing one, adjust new block - dp->df_lnum[idx_new] = lnum_new + off; - dp->df_count[idx_new] = count_new - off; + dp->df_lnum[idx_new] = hunk->lnum_new + off; + dp->df_count[idx_new] = hunk->count_new - off; } else { // second overlap of new block with existing block - dp->df_count[idx_new] += count_new - count_orig + dp->df_count[idx_new] += hunk->count_new - hunk->count_orig + dpl->df_lnum[idx_orig] + dpl->df_count[idx_orig] - (dp->df_lnum[idx_orig] + @@ -1659,7 +1676,7 @@ static void diff_read(int idx_orig, int idx_new, diffout_T *dout) // Adjust the size of the block to include all the lines to the // end of the existing block or the new diff, whatever ends last. - off = (lnum_orig + count_orig) + off = (hunk->lnum_orig + hunk->count_orig) - (dpl->df_lnum[idx_orig] + dpl->df_count[idx_orig]); if (off < 0) { @@ -1691,10 +1708,10 @@ static void diff_read(int idx_orig, int idx_new, diffout_T *dout) // Allocate a new diffblock. dp = diff_alloc_new(curtab, dprev, dp); - dp->df_lnum[idx_orig] = lnum_orig; - dp->df_count[idx_orig] = count_orig; - dp->df_lnum[idx_new] = lnum_new; - dp->df_count[idx_new] = count_new; + dp->df_lnum[idx_orig] = hunk->lnum_orig; + dp->df_count[idx_orig] = hunk->count_orig; + dp->df_lnum[idx_new] = hunk->lnum_new; + dp->df_count[idx_new] = hunk->count_new; // Set values for other buffers, these must be equal to the // original buffer, otherwise there would have been a change @@ -1718,6 +1735,10 @@ static void diff_read(int idx_orig, int idx_new, diffout_T *dout) notset = true; } + if (!dio->dio_internal) { + xfree(hunk); + } + if (fd != NULL) { fclose(fd); } @@ -3026,8 +3047,7 @@ linenr_T diff_lnum_win(linenr_T lnum, win_T *wp) /// Handle an ED style diff line. /// Return FAIL if the line does not contain diff info. /// -static int parse_diff_ed(char_u *line, linenr_T *lnum_orig, long *count_orig, linenr_T *lnum_new, - long *count_new) +static int parse_diff_ed(char_u *line, diffhunk_T *hunk) { char_u *p; long f1, l1, f2, l2; @@ -3061,18 +3081,18 @@ static int parse_diff_ed(char_u *line, linenr_T *lnum_orig, long *count_orig, li } if (difftype == 'a') { - *lnum_orig = f1 + 1; - *count_orig = 0; + hunk->lnum_orig = f1 + 1; + hunk->count_orig = 0; } else { - *lnum_orig = f1; - *count_orig = l1 - f1 + 1; + hunk->lnum_orig = f1; + hunk->count_orig = l1 - f1 + 1; } if (difftype == 'd') { - *lnum_new = f2 + 1; - *count_new = 0; + hunk->lnum_new = f2 + 1; + hunk->count_new = 0; } else { - *lnum_new = f2; - *count_new = l2 - f2 + 1; + hunk->lnum_new = f2; + hunk->count_new = l2 - f2 + 1; } return OK; } @@ -3081,8 +3101,7 @@ static int parse_diff_ed(char_u *line, linenr_T *lnum_orig, long *count_orig, li /// Parses unified diff with zero(!) context lines. /// Return FAIL if there is no diff information in "line". /// -static int parse_diff_unified(char_u *line, linenr_T *lnum_orig, long *count_orig, - linenr_T *lnum_new, long *count_new) +static int parse_diff_unified(char_u *line, diffhunk_T *hunk) { char_u *p; long oldline, oldcount, newline, newcount; @@ -3120,10 +3139,10 @@ static int parse_diff_unified(char_u *line, linenr_T *lnum_orig, long *count_ori newline = 1; } - *lnum_orig = oldline; - *count_orig = oldcount; - *lnum_new = newline; - *count_new = newcount; + hunk->lnum_orig = oldline; + hunk->count_orig = oldcount; + hunk->lnum_new = newline; + hunk->count_new = newcount; return OK; } @@ -3135,25 +3154,17 @@ static int parse_diff_unified(char_u *line, linenr_T *lnum_orig, long *count_ori /// Callback function for the xdl_diff() function. /// Stores the diff output in a grow array. /// -static int xdiff_out(void *priv, mmbuffer_t *mb, int nbuf) +static int xdiff_out(long start_a, long count_a, long start_b, long count_b, + void *priv) { diffout_T *dout = (diffout_T *)priv; - char_u *p; - - // The header line always comes by itself, text lines in at least two - // parts. We drop the text part. - if (nbuf > 1) { - return 0; - } - - // sanity check - if (STRNCMP(mb[0].ptr, "@@ ", 3) != 0) { - return 0; - } + diffhunk_T *p = xmalloc(sizeof(*p)); ga_grow(&dout->dout_ga, 1); - - p = vim_strnsave((char_u *)mb[0].ptr, mb[0].size); - ((char_u **)dout->dout_ga.ga_data)[dout->dout_ga.ga_len++] = p; + p->lnum_orig = start_a + 1; + p->count_orig = count_a; + p->lnum_new = start_b + 1; + p->count_new = count_b; + ((diffhunk_T **)dout->dout_ga.ga_data)[dout->dout_ga.ga_len++] = p; return 0; } diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 5eef4350b7..aa37d1b2dd 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -3620,7 +3620,7 @@ static bool ins_compl_prep(int c) // Ignore end of Select mode mapping and mouse scroll buttons. if (c == K_SELECT || c == K_MOUSEDOWN || c == K_MOUSEUP || c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_EVENT - || c == K_COMMAND) { + || c == K_COMMAND || c == K_LUA) { return retval; } diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 71c34f98ff..3a285cdf90 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -4370,7 +4370,7 @@ static char_u *replace_makeprg(exarg_T *eap, char_u *p, char_u **cmdlinep) ++i; } len = (int)STRLEN(p); - new_cmdline = xmalloc(STRLEN(program) + i * (len - 2) + 1); + new_cmdline = xmalloc(STRLEN(program) + (size_t)i * (len - 2) + 1); ptr = new_cmdline; while ((pos = (char_u *)strstr((char *)program, "$*")) != NULL) { i = (int)(pos - program); @@ -6028,7 +6028,7 @@ static size_t uc_check_code(char_u *code, size_t len, char_u *buf, ucmd_T *cmd, break; } - case ct_MODS: { + case ct_MODS: result = quote ? 2 : 0; if (buf != NULL) { if (quote) { @@ -6044,7 +6044,6 @@ static size_t uc_check_code(char_u *code, size_t len, char_u *buf, ucmd_T *cmd, *buf = '"'; } break; - } case ct_REGISTER: result = eap->regname ? 1 : 0; diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index c814974fe7..cfdbe7b344 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1131,12 +1131,12 @@ void ex_lua(exarg_T *const eap) } // When =expr is used transform it to print(vim.inspect(expr)) if (code[0] == '=') { - len += sizeof("print(vim.inspect())") - sizeof("="); + len += sizeof("vim.pretty_print()") - sizeof("="); // code_buf needs to be 1 char larger then len for null byte in the end. // lua nlua_typval_exec doesn't expect null terminated string so len // needs to end before null byte. char *code_buf = xmallocz(len); - vim_snprintf(code_buf, len+1, "print(vim.inspect(%s))", code+1); + vim_snprintf(code_buf, len+1, "vim.pretty_print(%s)", code+1); xfree(code); code = code_buf; } diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 60a000843f..f4067ad02f 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -129,6 +129,10 @@ void tslua_init(lua_State *L) build_meta(L, TS_META_QUERY, query_meta); build_meta(L, TS_META_QUERYCURSOR, querycursor_meta); build_meta(L, TS_META_TREECURSOR, treecursor_meta); + +#ifdef NVIM_TS_HAS_SET_ALLOCATOR + ts_set_allocator(xmalloc, xcalloc, xrealloc, xfree); +#endif } int tslua_has_language(lua_State *L) diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua index 6ef46ee844..731e7d8d36 100644 --- a/src/nvim/lua/vim.lua +++ b/src/nvim/lua/vim.lua @@ -115,6 +115,9 @@ setmetatable(vim, { elseif key == 'ui' then t.ui = require('vim.ui') return t.ui + elseif key == 'keymap' then + t.keymap = require('vim.keymap') + return t.keymap end end }) @@ -422,23 +425,43 @@ function vim.defer_fn(fn, timeout) end ---- Notification provider +--- Display a notification to the user. --- ---- Without a runtime, writes to :Messages ----@see :help nvim_notify ----@param msg string Content of the notification to show to the user ----@param log_level number|nil enum from |vim.log.levels| ----@param opts table|nil additional options (timeout, etc) -function vim.notify(msg, log_level, opts) -- luacheck: no unused - if log_level == vim.log.levels.ERROR then +--- This function can be overridden by plugins to display notifications using a +--- custom provider (such as the system notification provider). By default, +--- writes to |:messages|. +--- +---@param msg string Content of the notification to show to the user. +---@param level number|nil One of the values from |vim.log.levels|. +---@param opts table|nil Optional parameters. Unused by default. +function vim.notify(msg, level, opts) -- luacheck: no unused args + if level == vim.log.levels.ERROR then vim.api.nvim_err_writeln(msg) - elseif log_level == vim.log.levels.WARN then + elseif level == vim.log.levels.WARN then vim.api.nvim_echo({{msg, 'WarningMsg'}}, true, {}) else vim.api.nvim_echo({{msg}}, true, {}) end end +do + local notified = {} + + --- Display a notification only one time. + --- + --- Like |vim.notify()|, but subsequent calls with the same message will not + --- display a notification. + --- + ---@param msg string Content of the notification to show to the user. + ---@param level number|nil One of the values from |vim.log.levels|. + ---@param opts table|nil Optional parameters. Unused by default. + function vim.notify_once(msg, level, opts) -- luacheck: no unused args + if not notified[msg] then + vim.notify(msg, level, opts) + notified[msg] = true + end + end +end ---@private function vim.register_keystroke_callback() @@ -666,4 +689,23 @@ vim._expand_pat_get_parts = function(lua_string) return parts, search_index end +---Prints given arguments in human-readable format. +---Example: +---<pre> +--- -- Print highlight group Normal and store it's contents in a variable. +--- local hl_normal = vim.pretty_print(vim.api.nvim_get_hl_by_name("Normal", true)) +---</pre> +---@see |vim.inspect()| +---@return given arguments. +function vim.pretty_print(...) + local objects = {} + for i = 1, select('#', ...) do + local v = select(i, ...) + table.insert(objects, vim.inspect(v)) + end + + print(table.concat(objects, ' ')) + return ... +end + return module diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c index 3397296b3a..2a72d1e6a0 100644 --- a/src/nvim/memfile.c +++ b/src/nvim/memfile.c @@ -247,7 +247,7 @@ bhdr_T *mf_new(memfile_T *mfp, bool negative, unsigned page_count) } else { // need to allocate memory for this block // If the number of pages matches use the bhdr_T from the free list and // allocate the data. - void *p = xmalloc(mfp->mf_page_size * page_count); + void *p = xmalloc((size_t)mfp->mf_page_size * page_count); hp = mf_rem_free(mfp); hp->bh_data = p; } @@ -269,7 +269,7 @@ bhdr_T *mf_new(memfile_T *mfp, bool negative, unsigned page_count) // Init the data to all zero, to avoid reading uninitialized data. // This also avoids that the passwd file ends up in the swap file! - (void)memset(hp->bh_data, 0, mfp->mf_page_size * page_count); + (void)memset(hp->bh_data, 0, (size_t)mfp->mf_page_size * page_count); return hp; } @@ -528,7 +528,7 @@ bool mf_release_all(void) static bhdr_T *mf_alloc_bhdr(memfile_T *mfp, unsigned page_count) { bhdr_T *hp = xmalloc(sizeof(bhdr_T)); - hp->bh_data = xmalloc(mfp->mf_page_size * page_count); + hp->bh_data = xmalloc((size_t)mfp->mf_page_size * page_count); hp->bh_page_count = page_count; return hp; } diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 08521c0dc3..9925971783 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -1032,9 +1032,9 @@ void ml_recover(bool checkext) line_count = 0; idx = 0; // start with first index in block 1 error = 0; - buf->b_ml.ml_stack_top = 0; + buf->b_ml.ml_stack_top = 0; // -V1048 buf->b_ml.ml_stack = NULL; - buf->b_ml.ml_stack_size = 0; // no stack yet + buf->b_ml.ml_stack_size = 0; // -V1048 if (curbuf->b_ffname == NULL) { cannot_open = true; @@ -4139,7 +4139,7 @@ long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp, bool no_ff) || (offset != 0 && offset > size + buf->b_ml.ml_chunksize[curix].mlcs_totalsize - + ffdos * buf->b_ml.ml_chunksize[curix].mlcs_numlines))) { + + (long)ffdos * buf->b_ml.ml_chunksize[curix].mlcs_numlines))) { curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines; size += buf->b_ml.ml_chunksize[curix].mlcs_totalsize; if (offset && ffdos) { diff --git a/src/nvim/screen.c b/src/nvim/screen.c index b1ca8c5805..538604cf79 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -4130,7 +4130,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc if (((wp->w_p_cuc && (int)wp->w_virtcol >= VCOL_HLC - eol_hl_off && (int)wp->w_virtcol < - grid->Columns * (row - startrow + 1) + v + (long)grid->Columns * (row - startrow + 1) + v && lnum != wp->w_cursor.lnum) || draw_color_col || line_attr_lowprio || line_attr || diff_hlf != (hlf_T)0 || has_virttext)) { @@ -6762,7 +6762,7 @@ void grid_clear_line(ScreenGrid *grid, unsigned off, int width, bool valid) void grid_invalidate(ScreenGrid *grid) { - (void)memset(grid->attrs, -1, grid->Rows * grid->Columns * sizeof(sattr_T)); + (void)memset(grid->attrs, -1, sizeof(sattr_T) * grid->Rows * grid->Columns); } bool grid_invalid_row(ScreenGrid *grid, int row) diff --git a/src/nvim/state.c b/src/nvim/state.c index 68bc76660d..1fe8bb671d 100644 --- a/src/nvim/state.c +++ b/src/nvim/state.c @@ -180,7 +180,7 @@ char *get_mode(void) buf[1] = 'x'; } } - } else if (State & CMDLINE) { + } else if ((State & CMDLINE) || exmode_active) { buf[0] = 'c'; if (exmode_active) { buf[1] = 'v'; diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim index cc767a9bcf..c0ac4393c4 100644 --- a/src/nvim/testdir/test_alot.vim +++ b/src/nvim/testdir/test_alot.vim @@ -27,6 +27,7 @@ source test_join.vim source test_jumps.vim source test_fileformat.vim source test_filetype.vim +source test_filetype_lua.vim source test_lambda.vim source test_menu.vim source test_messages.vim diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index 4da68539fb..45a10cc193 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -195,7 +195,7 @@ let s:filename_checks = { \ 'gedcom': ['file.ged', 'lltxxxxx.txt', '/tmp/lltmp', '/tmp/lltmp-file', 'any/tmp/lltmp', 'any/tmp/lltmp-file'], \ 'gemtext': ['file.gmi', 'file.gemini'], \ 'gift': ['file.gift'], - \ 'gitcommit': ['COMMIT_EDITMSG', 'MERGE_MSG', 'TAG_EDITMSG'], + \ 'gitcommit': ['COMMIT_EDITMSG', 'MERGE_MSG', 'TAG_EDITMSG', 'NOTES_EDITMSG', 'EDIT_DESCRIPTION'], \ 'gitconfig': ['file.git/config', '.gitconfig', '.gitmodules', 'file.git/modules//config', '/.config/git/config', '/etc/gitconfig', '/etc/gitconfig.d/file', '/.gitconfig.d/file', 'any/.config/git/config', 'any/.gitconfig.d/file', 'some.git/config', 'some.git/modules/any/config'], \ 'gitolite': ['gitolite.conf', '/gitolite-admin/conf/file', 'any/gitolite-admin/conf/file'], \ 'gitrebase': ['git-rebase-todo'], @@ -1042,7 +1042,58 @@ func Test_dep3patch_file() call assert_notequal('dep3patch', &filetype) bwipe! - call delete('debian/patches', 'rf') + call delete('debian', 'rf') +endfunc + +func Test_patch_file() + filetype on + + call writefile([], 'Xfile.patch') + split Xfile.patch + call assert_equal('diff', &filetype) + bwipe! + + call writefile(['From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001'], 'Xfile.patch') + split Xfile.patch + call assert_equal('gitsendemail', &filetype) + bwipe! + + call writefile(['From 0000000000000000000000000000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001'], 'Xfile.patch') + split Xfile.patch + call assert_equal('gitsendemail', &filetype) + bwipe! + + call delete('Xfile.patch') + filetype off +endfunc + +func Test_git_file() + filetype on + + call assert_true(mkdir('Xrepo.git', 'p')) + + call writefile([], 'Xrepo.git/HEAD') + split Xrepo.git/HEAD + call assert_equal('', &filetype) + bwipe! + + call writefile(['0000000000000000000000000000000000000000'], 'Xrepo.git/HEAD') + split Xrepo.git/HEAD + call assert_equal('git', &filetype) + bwipe! + + call writefile(['0000000000000000000000000000000000000000000000000000000000000000'], 'Xrepo.git/HEAD') + split Xrepo.git/HEAD + call assert_equal('git', &filetype) + bwipe! + + call writefile(['ref: refs/heads/master'], 'Xrepo.git/HEAD') + split Xrepo.git/HEAD + call assert_equal('git', &filetype) + bwipe! + + call delete('Xrepo.git', 'rf') + filetype off endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_filetype_lua.vim b/src/nvim/testdir/test_filetype_lua.vim new file mode 100644 index 0000000000..f73e4ca33f --- /dev/null +++ b/src/nvim/testdir/test_filetype_lua.vim @@ -0,0 +1,2 @@ +let g:do_filetype_lua = 1 +source test_filetype.vim diff --git a/src/nvim/testdir/test_search_stat.vim b/src/nvim/testdir/test_search_stat.vim index 335a51268d..f7f7467e91 100644 --- a/src/nvim/testdir/test_search_stat.vim +++ b/src/nvim/testdir/test_search_stat.vim @@ -73,7 +73,6 @@ func Test_search_stat() let stat = '\[2/50\]' let g:a = execute(':unsilent :norm! n') call assert_notmatch(pat .. stat, g:a) - call writefile(getline(1, '$'), 'sample.txt') " n does not update search stat call assert_equal( \ #{current: 50, exact_match: 1, total: 50, incomplete: 0, maxcount: 99}, diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua index bc2759ade7..450a76ddac 100644 --- a/test/functional/api/keymap_spec.lua +++ b/test/functional/api/keymap_spec.lua @@ -820,6 +820,16 @@ describe('nvim_set_keymap, nvim_del_keymap', function() eq(99, exec_lua[[return SomeValue]]) end) + it('does not reset pum in lua mapping', function() + eq(0, exec_lua [[ + VisibleCount = 0 + vim.api.nvim_set_keymap ('i', '<F2>', '', {callback = function() VisibleCount = VisibleCount + vim.fn.pumvisible() end}) + return VisibleCount + ]]) + feed('i<C-X><C-V><F2><F2><esc>') + eq(2, exec_lua[[return VisibleCount]]) + end) + it('can overwrite lua mappings', function() eq(0, exec_lua [[ GlobalCount = 0 diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua index 4220d68ee1..2fa84e8313 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -224,6 +224,23 @@ describe('startup', function() end end) + it('-e sets ex mode', function() + local screen = Screen.new(25, 3) + clear('-e') + screen:attach() + -- Verify we set the proper mode both before and after :vi. + feed("put =mode(1)<CR>vi<CR>:put =mode(1)<CR>") + screen:expect([[ + cv | + ^n | + :put =mode(1) | + ]]) + + eq('cv\n', + funcs.system({nvim_prog, '-n', '-es' }, + { 'put =mode(1)', 'print', '' })) + end) + it('fails on --embed with -es/-Es', function() matches('nvim[.exe]*: %-%-embed conflicts with %-es/%-Es', funcs.system({nvim_prog, '--embed', '-es' })) @@ -651,11 +668,7 @@ describe('runtime:', function() mkdir_p(ftdetect_folder) write_file(ftdetect_file , [[vim.g.lua_ftdetect = 1]]) - -- TODO(shadmansaleh): Figure out why this test fails without - -- setting VIMRUNTIME - clear{ args_rm={'-u'}, env={XDG_CONFIG_HOME=xconfig, - XDG_DATA_HOME=xdata, - VIMRUNTIME='runtime/'}} + clear{ args_rm={'-u'}, env=xenv } eq(1, eval('g:lua_ftdetect')) rmdir(ftdetect_folder) diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index f152a487af..1845786c4b 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -451,6 +451,7 @@ function module.new_argv(...) 'GCOV_ERROR_FILE', 'XDG_DATA_DIRS', 'TMPDIR', + 'VIMRUNTIME', }) do if not env_tbl[k] then env_tbl[k] = os.getenv(k) diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index b3c3f937ac..b8346df290 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -149,6 +149,15 @@ describe(':lua command', function() eq([["hello"]], helpers.exec_capture(':lua = x()')) helpers.exec_lua("x = {a = 1, b = 2}") eq("{\n a = 1,\n b = 2\n}", helpers.exec_capture(':lua =x')) + helpers.exec_lua([[function x(success) + if success then + return true, "Return value" + else + return false, nil, "Error message" + end + end]]) + eq([[true "Return value"]], helpers.exec_capture(':lua =x(true)')) + eq([[false nil "Error message"]], helpers.exec_capture(':lua =x(false)')) end) end) diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua index 756591571e..1b2cb61cc2 100644 --- a/test/functional/lua/filetype_spec.lua +++ b/test/functional/lua/filetype_spec.lua @@ -3,9 +3,6 @@ local exec_lua = helpers.exec_lua local eq = helpers.eq local clear = helpers.clear local pathroot = helpers.pathroot -local meths = helpers.meths -local curbufmeths = helpers.curbufmeths -local funcs = helpers.funcs local root = pathroot() @@ -98,572 +95,4 @@ describe('vim.filetype', function() return vim.bo.filetype ]]) end) - - it('correctly detects filetypes from test_filetype', function() - -- Checks copied from test_filetype.vim - local filename_checks = { - ['8th'] = {'file.8th'}, - ['a2ps'] = {'/etc/a2ps.cfg', '/etc/a2ps/file.cfg', 'a2psrc', '.a2psrc', 'any/etc/a2ps.cfg', 'any/etc/a2ps/file.cfg'}, - ['a65'] = {'file.a65'}, - ['aap'] = {'file.aap'}, - ['abap'] = {'file.abap'}, - ['abc'] = {'file.abc'}, - ['abel'] = {'file.abl'}, - ['acedb'] = {'file.wrm'}, - ['ada'] = {'file.adb', 'file.ads', 'file.ada', 'file.gpr'}, - ['ahdl'] = {'file.tdf'}, - ['aidl'] = {'file.aidl'}, - ['alsaconf'] = {'.asoundrc', '/usr/share/alsa/alsa.conf', '/etc/asound.conf', 'any/etc/asound.conf', 'any/usr/share/alsa/alsa.conf'}, - ['aml'] = {'file.aml'}, - ['ampl'] = {'file.run'}, - ['ant'] = {'build.xml'}, - ['apache'] = {'.htaccess', '/etc/httpd/file.conf', '/etc/apache2/sites-2/file.com', '/etc/apache2/some.config', '/etc/apache2/conf.file/conf', '/etc/apache2/mods-some/file', '/etc/apache2/sites-some/file', '/etc/httpd/conf.d/file.config', '/etc/apache2/conf.file/file', '/etc/apache2/file.conf', '/etc/apache2/file.conf-file', '/etc/apache2/mods-file/file', '/etc/apache2/sites-file/file', '/etc/apache2/sites-file/file.com', '/etc/httpd/conf.d/file.conf', '/etc/httpd/conf.d/file.conf-file', 'access.conf', 'access.conf-file', 'any/etc/apache2/conf.file/file', 'any/etc/apache2/file.conf', 'any/etc/apache2/file.conf-file', 'any/etc/apache2/mods-file/file', 'any/etc/apache2/sites-file/file', 'any/etc/apache2/sites-file/file.com', 'any/etc/httpd/conf.d/file.conf', 'any/etc/httpd/conf.d/file.conf-file', 'any/etc/httpd/file.conf', 'apache.conf', 'apache.conf-file', 'apache2.conf', 'apache2.conf-file', 'httpd.conf', 'httpd.conf-file', 'srm.conf', 'srm.conf-file', '/etc/httpd/mods-some/file', '/etc/httpd/sites-some/file', '/etc/httpd/conf.file/conf'}, - ['apachestyle'] = {'/etc/proftpd/file.config,/etc/proftpd/conf.file/file', '/etc/proftpd/conf.file/file', '/etc/proftpd/file.conf', '/etc/proftpd/file.conf-file', 'any/etc/proftpd/conf.file/file', 'any/etc/proftpd/file.conf', 'any/etc/proftpd/file.conf-file', 'proftpd.conf', 'proftpd.conf-file'}, - ['applescript'] = {'file.scpt'}, - ['aptconf'] = {'apt.conf', '/.aptitude/config', 'any/.aptitude/config'}, - ['arch'] = {'.arch-inventory', '=tagging-method'}, - ['arduino'] = {'file.ino', 'file.pde'}, - ['art'] = {'file.art'}, - ['asciidoc'] = {'file.asciidoc', 'file.adoc'}, - ['asn'] = {'file.asn', 'file.asn1'}, - ['asterisk'] = {'asterisk/file.conf', 'asterisk/file.conf-file', 'some-asterisk/file.conf', 'some-asterisk/file.conf-file'}, - ['atlas'] = {'file.atl', 'file.as'}, - ['autohotkey'] = {'file.ahk'}, - ['autoit'] = {'file.au3'}, - ['automake'] = {'GNUmakefile.am', 'makefile.am', 'Makefile.am'}, - ['ave'] = {'file.ave'}, - ['awk'] = {'file.awk', 'file.gawk'}, - ['b'] = {'file.mch', 'file.ref', 'file.imp'}, - ['bzl'] = {'file.bazel', 'file.bzl', 'WORKSPACE'}, - ['bc'] = {'file.bc'}, - ['bdf'] = {'file.bdf'}, - ['bib'] = {'file.bib'}, - ['beancount'] = {'file.beancount'}, - ['bindzone'] = {'named.root', '/bind/db.file', '/named/db.file', 'any/bind/db.file', 'any/named/db.file'}, - ['blank'] = {'file.bl'}, - ['bsdl'] = {'file.bsd', 'file.bsdl', 'bsd', 'some-bsd'}, - ['bst'] = {'file.bst'}, - ['bzr'] = {'bzr_log.any', 'bzr_log.file'}, - ['c'] = {'enlightenment/file.cfg', 'file.qc', 'file.c', 'some-enlightenment/file.cfg'}, - ['cabal'] = {'file.cabal'}, - ['cabalconfig'] = {'cabal.config'}, - ['cabalproject'] = {'cabal.project', 'cabal.project.local'}, - ['calendar'] = {'calendar', '/.calendar/file', '/share/calendar/any/calendar.file', '/share/calendar/calendar.file', 'any/share/calendar/any/calendar.file', 'any/share/calendar/calendar.file'}, - ['catalog'] = {'catalog', 'sgml.catalogfile', 'sgml.catalog', 'sgml.catalog-file'}, - ['cdl'] = {'file.cdl'}, - ['cdrdaoconf'] = {'/etc/cdrdao.conf', '/etc/defaults/cdrdao', '/etc/default/cdrdao', '.cdrdao', 'any/etc/cdrdao.conf', 'any/etc/default/cdrdao', 'any/etc/defaults/cdrdao'}, - ['cdrtoc'] = {'file.toc'}, - ['cf'] = {'file.cfm', 'file.cfi', 'file.cfc'}, - ['cfengine'] = {'cfengine.conf'}, - ['cfg'] = {'file.cfg', 'file.hgrc', 'filehgrc', 'hgrc', 'some-hgrc'}, - ['ch'] = {'file.chf'}, - ['chaiscript'] = {'file.chai'}, - ['chaskell'] = {'file.chs'}, - ['chill'] = {'file..ch'}, - ['chordpro'] = {'file.chopro', 'file.crd', 'file.cho', 'file.crdpro', 'file.chordpro'}, - ['cl'] = {'file.eni'}, - ['clean'] = {'file.dcl', 'file.icl'}, - ['clojure'] = {'file.clj', 'file.cljs', 'file.cljx', 'file.cljc'}, - ['cmake'] = {'CMakeLists.txt', 'file.cmake', 'file.cmake.in'}, - ['cmusrc'] = {'any/.cmus/autosave', 'any/.cmus/rc', 'any/.cmus/command-history', 'any/.cmus/file.theme', 'any/cmus/rc', 'any/cmus/file.theme', '/.cmus/autosave', '/.cmus/command-history', '/.cmus/file.theme', '/.cmus/rc', '/cmus/file.theme', '/cmus/rc'}, - ['cobol'] = {'file.cbl', 'file.cob', 'file.lib'}, - ['coco'] = {'file.atg'}, - ['conaryrecipe'] = {'file.recipe'}, - ['conf'] = {'auto.master'}, - ['config'] = {'configure.in', 'configure.ac', '/etc/hostname.file'}, - ['context'] = {'tex/context/any/file.tex', 'file.mkii', 'file.mkiv', 'file.mkvi', 'file.mkxl', 'file.mklx'}, - ['cpp'] = {'file.cxx', 'file.c++', 'file.hh', 'file.hxx', 'file.hpp', 'file.ipp', 'file.moc', 'file.tcc', 'file.inl', 'file.tlh'}, - ['crm'] = {'file.crm'}, - ['crontab'] = {'crontab', 'crontab.file', '/etc/cron.d/file', 'any/etc/cron.d/file'}, - ['cs'] = {'file.cs', 'file.csx'}, - ['csc'] = {'file.csc'}, - ['csdl'] = {'file.csdl'}, - ['csp'] = {'file.csp', 'file.fdr'}, - ['css'] = {'file.css'}, - ['cterm'] = {'file.con'}, - ['cucumber'] = {'file.feature'}, - ['cuda'] = {'file.cu', 'file.cuh'}, - ['cupl'] = {'file.pld'}, - ['cuplsim'] = {'file.si'}, - ['cvs'] = {'cvs123'}, - ['cvsrc'] = {'.cvsrc'}, - ['cynpp'] = {'file.cyn'}, - ['dart'] = {'file.dart', 'file.drt'}, - ['datascript'] = {'file.ds'}, - ['dcd'] = {'file.dcd'}, - ['debchangelog'] = {'changelog.Debian', 'changelog.dch', 'NEWS.Debian', 'NEWS.dch', '/debian/changelog'}, - ['debcontrol'] = {'/debian/control', 'any/debian/control'}, - ['debcopyright'] = {'/debian/copyright', 'any/debian/copyright'}, - ['debsources'] = {'/etc/apt/sources.list', '/etc/apt/sources.list.d/file.list', 'any/etc/apt/sources.list', 'any/etc/apt/sources.list.d/file.list'}, - ['def'] = {'file.def'}, - ['denyhosts'] = {'denyhosts.conf'}, - ['desc'] = {'file.desc'}, - ['desktop'] = {'file.desktop', '.directory', 'file.directory'}, - ['dictconf'] = {'dict.conf', '.dictrc'}, - ['dictdconf'] = {'dictd.conf', 'dictdfile.conf', 'dictd-file.conf'}, - ['diff'] = {'file.diff', 'file.rej'}, - ['dircolors'] = {'.dir_colors', '.dircolors', '/etc/DIR_COLORS', 'any/etc/DIR_COLORS'}, - ['dnsmasq'] = {'/etc/dnsmasq.conf', '/etc/dnsmasq.d/file', 'any/etc/dnsmasq.conf', 'any/etc/dnsmasq.d/file'}, - ['dockerfile'] = {'Containerfile', 'Dockerfile', 'file.Dockerfile', 'Dockerfile.debian', 'Containerfile.something'}, - ['dosbatch'] = {'file.bat', 'file.sys'}, - ['dosini'] = {'.editorconfig', '/etc/pacman.conf', '/etc/yum.conf', 'file.ini', 'npmrc', '.npmrc', 'php.ini', 'php.ini-5', 'php.ini-file', '/etc/yum.repos.d/file', 'any/etc/pacman.conf', 'any/etc/yum.conf', 'any/etc/yum.repos.d/file', 'file.wrap'}, - ['dot'] = {'file.dot', 'file.gv'}, - ['dracula'] = {'file.drac', 'file.drc', 'filelvs', 'filelpe', 'drac.file', 'lpe', 'lvs', 'some-lpe', 'some-lvs'}, - ['dtd'] = {'file.dtd'}, - ['dts'] = {'file.dts', 'file.dtsi'}, - ['dune'] = {'jbuild', 'dune', 'dune-project', 'dune-workspace'}, - ['dylan'] = {'file.dylan'}, - ['dylanintr'] = {'file.intr'}, - ['dylanlid'] = {'file.lid'}, - ['ecd'] = {'file.ecd'}, - ['edif'] = {'file.edf', 'file.edif', 'file.edo'}, - ['elinks'] = {'elinks.conf'}, - ['elixir'] = {'file.ex', 'file.exs', 'mix.lock'}, - ['eelixir'] = {'file.eex', 'file.leex'}, - ['elm'] = {'file.elm'}, - ['elmfilt'] = {'filter-rules'}, - ['epuppet'] = {'file.epp'}, - ['erlang'] = {'file.erl', 'file.hrl', 'file.yaws'}, - ['eruby'] = {'file.erb', 'file.rhtml'}, - ['esmtprc'] = {'anyesmtprc', 'esmtprc', 'some-esmtprc'}, - ['esqlc'] = {'file.ec', 'file.EC'}, - ['esterel'] = {'file.strl'}, - ['eterm'] = {'anyEterm/file.cfg', 'Eterm/file.cfg', 'some-Eterm/file.cfg'}, - ['exim'] = {'exim.conf'}, - ['expect'] = {'file.exp'}, - ['exports'] = {'exports'}, - ['factor'] = {'file.factor'}, - ['falcon'] = {'file.fal'}, - ['fan'] = {'file.fan', 'file.fwt'}, - ['fennel'] = {'file.fnl'}, - ['fetchmail'] = {'.fetchmailrc'}, - ['fgl'] = {'file.4gl', 'file.4gh', 'file.m4gl'}, - ['fish'] = {'file.fish'}, - ['focexec'] = {'file.fex', 'file.focexec'}, - ['forth'] = {'file.ft', 'file.fth'}, - ['fortran'] = {'file.f', 'file.for', 'file.fortran', 'file.fpp', 'file.ftn', 'file.f77', 'file.f90', 'file.f95', 'file.f03', 'file.f08'}, - ['fpcmake'] = {'file.fpc'}, - ['framescript'] = {'file.fsl'}, - ['freebasic'] = {'file.fb', 'file.bi'}, - ['fsharp'] = {'file.fs', 'file.fsi', 'file.fsx'}, - ['fstab'] = {'fstab', 'mtab'}, - ['fvwm'] = {'/.fvwm/file', 'any/.fvwm/file'}, - ['gdb'] = {'.gdbinit', 'gdbinit'}, - ['gdmo'] = {'file.mo', 'file.gdmo'}, - ['gedcom'] = {'file.ged', 'lltxxxxx.txt', '/tmp/lltmp', '/tmp/lltmp-file', 'any/tmp/lltmp', 'any/tmp/lltmp-file'}, - ['gemtext'] = {'file.gmi', 'file.gemini'}, - ['gift'] = {'file.gift'}, - ['gitcommit'] = {'COMMIT_EDITMSG', 'MERGE_MSG', 'TAG_EDITMSG'}, - ['gitconfig'] = {'file.git/config', '.gitconfig', '.gitmodules', 'file.git/modules//config', '/.config/git/config', '/etc/gitconfig', '/etc/gitconfig.d/file', '/.gitconfig.d/file', 'any/.config/git/config', 'any/.gitconfig.d/file', 'some.git/config', 'some.git/modules/any/config'}, - ['gitolite'] = {'gitolite.conf', '/gitolite-admin/conf/file', 'any/gitolite-admin/conf/file'}, - ['gitrebase'] = {'git-rebase-todo'}, - ['gitsendemail'] = {'.gitsendemail.msg.xxxxxx'}, - ['gkrellmrc'] = {'gkrellmrc', 'gkrellmrc_x'}, - ['gnash'] = {'gnashrc', '.gnashrc', 'gnashpluginrc', '.gnashpluginrc'}, - ['gnuplot'] = {'file.gpi'}, - ['go'] = {'file.go'}, - ['gomod'] = {'go.mod'}, - ['gp'] = {'file.gp', '.gprc'}, - ['gpg'] = {'/.gnupg/options', '/.gnupg/gpg.conf', '/usr/any/gnupg/options.skel', 'any/.gnupg/gpg.conf', 'any/.gnupg/options', 'any/usr/any/gnupg/options.skel'}, - ['grads'] = {'file.gs'}, - ['gretl'] = {'file.gretl'}, - ['groovy'] = {'file.gradle', 'file.groovy'}, - ['group'] = {'any/etc/group', 'any/etc/group-', 'any/etc/group.edit', 'any/etc/gshadow', 'any/etc/gshadow-', 'any/etc/gshadow.edit', 'any/var/backups/group.bak', 'any/var/backups/gshadow.bak', '/etc/group', '/etc/group-', '/etc/group.edit', '/etc/gshadow', '/etc/gshadow-', '/etc/gshadow.edit', '/var/backups/group.bak', '/var/backups/gshadow.bak'}, - ['grub'] = {'/boot/grub/menu.lst', '/boot/grub/grub.conf', '/etc/grub.conf', 'any/boot/grub/grub.conf', 'any/boot/grub/menu.lst', 'any/etc/grub.conf'}, - ['gsp'] = {'file.gsp'}, - ['gtkrc'] = {'.gtkrc', 'gtkrc', '.gtkrc-file', 'gtkrc-file'}, - ['haml'] = {'file.haml'}, - ['hamster'] = {'file.hsm'}, - ['haskell'] = {'file.hs', 'file.hsc', 'file.hs-boot', 'file.hsig'}, - ['haste'] = {'file.ht'}, - ['hastepreproc'] = {'file.htpp'}, - ['hb'] = {'file.hb'}, - ['hercules'] = {'file.vc', 'file.ev', 'file.sum', 'file.errsum'}, - ['hex'] = {'file.hex', 'file.h32'}, - ['hgcommit'] = {'hg-editor-file.txt'}, - ['hog'] = {'file.hog', 'snort.conf', 'vision.conf'}, - ['hollywood'] = {'file.hws'}, - ['hostconf'] = {'/etc/host.conf', 'any/etc/host.conf'}, - ['hostsaccess'] = {'/etc/hosts.allow', '/etc/hosts.deny', 'any/etc/hosts.allow', 'any/etc/hosts.deny'}, - ['i3config'] = {'/home/user/.i3/config', '/home/user/.config/i3/config', '/etc/i3/config', '/etc/xdg/i3/config'}, - ['logcheck'] = {'/etc/logcheck/file.d-some/file', '/etc/logcheck/file.d/file', 'any/etc/logcheck/file.d-some/file', 'any/etc/logcheck/file.d/file'}, - ['modula3'] = {'file.m3', 'file.mg', 'file.i3', 'file.ig'}, - ['natural'] = {'file.NSA', 'file.NSC', 'file.NSG', 'file.NSL', 'file.NSM', 'file.NSN', 'file.NSP', 'file.NSS'}, - ['neomuttrc'] = {'Neomuttrc', '.neomuttrc', '.neomuttrc-file', '/.neomutt/neomuttrc', '/.neomutt/neomuttrc-file', 'Neomuttrc', 'Neomuttrc-file', 'any/.neomutt/neomuttrc', 'any/.neomutt/neomuttrc-file', 'neomuttrc', 'neomuttrc-file'}, - ['opl'] = {'file.OPL', 'file.OPl', 'file.OpL', 'file.Opl', 'file.oPL', 'file.oPl', 'file.opL', 'file.opl'}, - ['pcmk'] = {'file.pcmk'}, - ['r'] = {'file.r'}, - ['rhelp'] = {'file.rd'}, - ['rmd'] = {'file.rmd', 'file.smd'}, - ['rnoweb'] = {'file.rnw', 'file.snw'}, - ['rrst'] = {'file.rrst', 'file.srst'}, - ['template'] = {'file.tmpl'}, - ['htmlm4'] = {'file.html.m4'}, - ['httest'] = {'file.htt', 'file.htb'}, - ['ibasic'] = {'file.iba', 'file.ibi'}, - ['icemenu'] = {'/.icewm/menu', 'any/.icewm/menu'}, - ['icon'] = {'file.icn'}, - ['indent'] = {'.indent.pro', 'indentrc'}, - ['inform'] = {'file.inf', 'file.INF'}, - ['initng'] = {'/etc/initng/any/file.i', 'file.ii', 'any/etc/initng/any/file.i'}, - ['inittab'] = {'inittab'}, - ['ipfilter'] = {'ipf.conf', 'ipf6.conf', 'ipf.rules'}, - ['iss'] = {'file.iss'}, - ['ist'] = {'file.ist', 'file.mst'}, - ['j'] = {'file.ijs'}, - ['jal'] = {'file.jal', 'file.JAL'}, - ['jam'] = {'file.jpl', 'file.jpr', 'JAM-file.file', 'JAM.file', 'Prl-file.file', 'Prl.file'}, - ['java'] = {'file.java', 'file.jav'}, - ['javacc'] = {'file.jj', 'file.jjt'}, - ['javascript'] = {'file.js', 'file.javascript', 'file.es', 'file.mjs', 'file.cjs'}, - ['javascriptreact'] = {'file.jsx'}, - ['jess'] = {'file.clp'}, - ['jgraph'] = {'file.jgr'}, - ['jovial'] = {'file.jov', 'file.j73', 'file.jovial'}, - ['jproperties'] = {'file.properties', 'file.properties_xx', 'file.properties_xx_xx', 'some.properties_xx_xx_file'}, - ['json'] = {'file.json', 'file.jsonp', 'file.json-patch', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', '.babelrc', '.eslintrc', '.prettierrc', '.firebaserc', 'file.slnf'}, - ['jsonc'] = {'file.jsonc'}, - ['jsp'] = {'file.jsp'}, - ['julia'] = {'file.jl'}, - ['kconfig'] = {'Kconfig', 'Kconfig.debug', 'Kconfig.file'}, - ['kivy'] = {'file.kv'}, - ['kix'] = {'file.kix'}, - ['kotlin'] = {'file.kt', 'file.ktm', 'file.kts'}, - ['kscript'] = {'file.ks'}, - ['kwt'] = {'file.k'}, - ['lace'] = {'file.ace', 'file.ACE'}, - ['latte'] = {'file.latte', 'file.lte'}, - ['ld'] = {'file.ld'}, - ['ldif'] = {'file.ldif'}, - ['less'] = {'file.less'}, - ['lex'] = {'file.lex', 'file.l', 'file.lxx', 'file.l++'}, - ['lftp'] = {'lftp.conf', '.lftprc', 'anylftp/rc', 'lftp/rc', 'some-lftp/rc'}, - ['lhaskell'] = {'file.lhs'}, - ['libao'] = {'/etc/libao.conf', '/.libao', 'any/.libao', 'any/etc/libao.conf'}, - ['lifelines'] = {'file.ll'}, - ['lilo'] = {'lilo.conf', 'lilo.conf-file'}, - ['limits'] = {'/etc/limits', '/etc/anylimits.conf', '/etc/anylimits.d/file.conf', '/etc/limits.conf', '/etc/limits.d/file.conf', '/etc/some-limits.conf', '/etc/some-limits.d/file.conf', 'any/etc/limits', 'any/etc/limits.conf', 'any/etc/limits.d/file.conf', 'any/etc/some-limits.conf', 'any/etc/some-limits.d/file.conf'}, - ['liquid'] = {'file.liquid'}, - ['lisp'] = {'file.lsp', 'file.lisp', 'file.asd', 'file.el', 'file.cl', '.emacs', '.sawfishrc', 'sbclrc', '.sbclrc'}, - ['lite'] = {'file.lite', 'file.lt'}, - ['litestep'] = {'/LiteStep/any/file.rc', 'any/LiteStep/any/file.rc'}, - ['loginaccess'] = {'/etc/login.access', 'any/etc/login.access'}, - ['logindefs'] = {'/etc/login.defs', 'any/etc/login.defs'}, - ['logtalk'] = {'file.lgt'}, - ['lotos'] = {'file.lot', 'file.lotos'}, - ['lout'] = {'file.lou', 'file.lout'}, - ['lprolog'] = {'file.sig'}, - ['lsl'] = {'file.lsl'}, - ['lss'] = {'file.lss'}, - ['lua'] = {'file.lua', 'file.rockspec', 'file.nse'}, - ['lynx'] = {'lynx.cfg'}, - ['matlab'] = {'file.m'}, - ['m3build'] = {'m3makefile', 'm3overrides'}, - ['m3quake'] = {'file.quake', 'cm3.cfg'}, - ['m4'] = {'file.at'}, - ['mail'] = {'snd.123', '.letter', '.letter.123', '.followup', '.article', '.article.123', 'pico.123', 'mutt-xx-xxx', 'muttng-xx-xxx', 'ae123.txt', 'file.eml', 'reportbug-file'}, - ['mailaliases'] = {'/etc/mail/aliases', '/etc/aliases', 'any/etc/aliases', 'any/etc/mail/aliases'}, - ['mailcap'] = {'.mailcap', 'mailcap'}, - ['make'] = {'file.mk', 'file.mak', 'file.dsp', 'makefile', 'Makefile', 'makefile-file', 'Makefile-file', 'some-makefile', 'some-Makefile'}, - ['mallard'] = {'file.page'}, - ['manconf'] = {'/etc/man.conf', 'man.config', 'any/etc/man.conf'}, - ['map'] = {'file.map'}, - ['maple'] = {'file.mv', 'file.mpl', 'file.mws'}, - ['markdown'] = {'file.markdown', 'file.mdown', 'file.mkd', 'file.mkdn', 'file.mdwn', 'file.md'}, - ['mason'] = {'file.mason', 'file.mhtml', 'file.comp'}, - ['master'] = {'file.mas', 'file.master'}, - ['mel'] = {'file.mel'}, - ['meson'] = {'meson.build', 'meson_options.txt'}, - ['messages'] = {'/log/auth', '/log/cron', '/log/daemon', '/log/debug', '/log/kern', '/log/lpr', '/log/mail', '/log/messages', '/log/news/news', '/log/syslog', '/log/user', - '/log/auth.log', '/log/cron.log', '/log/daemon.log', '/log/debug.log', '/log/kern.log', '/log/lpr.log', '/log/mail.log', '/log/messages.log', '/log/news/news.log', '/log/syslog.log', '/log/user.log', - '/log/auth.err', '/log/cron.err', '/log/daemon.err', '/log/debug.err', '/log/kern.err', '/log/lpr.err', '/log/mail.err', '/log/messages.err', '/log/news/news.err', '/log/syslog.err', '/log/user.err', - '/log/auth.info', '/log/cron.info', '/log/daemon.info', '/log/debug.info', '/log/kern.info', '/log/lpr.info', '/log/mail.info', '/log/messages.info', '/log/news/news.info', '/log/syslog.info', '/log/user.info', - '/log/auth.warn', '/log/cron.warn', '/log/daemon.warn', '/log/debug.warn', '/log/kern.warn', '/log/lpr.warn', '/log/mail.warn', '/log/messages.warn', '/log/news/news.warn', '/log/syslog.warn', '/log/user.warn', - '/log/auth.crit', '/log/cron.crit', '/log/daemon.crit', '/log/debug.crit', '/log/kern.crit', '/log/lpr.crit', '/log/mail.crit', '/log/messages.crit', '/log/news/news.crit', '/log/syslog.crit', '/log/user.crit', - '/log/auth.notice', '/log/cron.notice', '/log/daemon.notice', '/log/debug.notice', '/log/kern.notice', '/log/lpr.notice', '/log/mail.notice', '/log/messages.notice', '/log/news/news.notice', '/log/syslog.notice', '/log/user.notice'}, - ['mf'] = {'file.mf'}, - ['mgl'] = {'file.mgl'}, - ['mgp'] = {'file.mgp'}, - ['mib'] = {'file.mib', 'file.my'}, - ['mix'] = {'file.mix', 'file.mixal'}, - ['mma'] = {'file.nb'}, - ['mmp'] = {'file.mmp'}, - ['modconf'] = {'/etc/modules.conf', '/etc/modules', '/etc/conf.modules', '/etc/modprobe.file', 'any/etc/conf.modules', 'any/etc/modprobe.file', 'any/etc/modules', 'any/etc/modules.conf'}, - ['modula2'] = {'file.m2', 'file.mi'}, - ['monk'] = {'file.isc', 'file.monk', 'file.ssc', 'file.tsc'}, - ['moo'] = {'file.moo'}, - ['mp'] = {'file.mp'}, - ['mplayerconf'] = {'mplayer.conf', '/.mplayer/config', 'any/.mplayer/config'}, - ['mrxvtrc'] = {'mrxvtrc', '.mrxvtrc'}, - ['msidl'] = {'file.odl', 'file.mof'}, - ['msql'] = {'file.msql'}, - ['mupad'] = {'file.mu'}, - ['mush'] = {'file.mush'}, - ['muttrc'] = {'Muttngrc', 'Muttrc', '.muttngrc', '.muttngrc-file', '.muttrc', '.muttrc-file', '/.mutt/muttngrc', '/.mutt/muttngrc-file', '/.mutt/muttrc', '/.mutt/muttrc-file', '/.muttng/muttngrc', '/.muttng/muttngrc-file', '/.muttng/muttrc', '/.muttng/muttrc-file', '/etc/Muttrc.d/file', '/etc/Muttrc.d/file.rc', 'Muttngrc-file', 'Muttrc-file', 'any/.mutt/muttngrc', 'any/.mutt/muttngrc-file', 'any/.mutt/muttrc', 'any/.mutt/muttrc-file', 'any/.muttng/muttngrc', 'any/.muttng/muttngrc-file', 'any/.muttng/muttrc', 'any/.muttng/muttrc-file', 'any/etc/Muttrc.d/file', 'muttngrc', 'muttngrc-file', 'muttrc', 'muttrc-file'}, - ['mysql'] = {'file.mysql'}, - ['n1ql'] = {'file.n1ql', 'file.nql'}, - ['named'] = {'namedfile.conf', 'rndcfile.conf', 'named-file.conf', 'named.conf', 'rndc-file.conf', 'rndc-file.key', 'rndc.conf', 'rndc.key'}, - ['nanorc'] = {'/etc/nanorc', 'file.nanorc', 'any/etc/nanorc'}, - ['ncf'] = {'file.ncf'}, - ['netrc'] = {'.netrc'}, - ['nginx'] = {'file.nginx', 'nginxfile.conf', 'filenginx.conf', 'any/etc/nginx/file', 'any/usr/local/nginx/conf/file', 'any/nginx/file.conf'}, - ['ninja'] = {'file.ninja'}, - ['nqc'] = {'file.nqc'}, - ['nroff'] = {'file.tr', 'file.nr', 'file.roff', 'file.tmac', 'file.mom', 'tmac.file'}, - ['nsis'] = {'file.nsi', 'file.nsh'}, - ['obj'] = {'file.obj'}, - ['ocaml'] = {'file.ml', 'file.mli', 'file.mll', 'file.mly', '.ocamlinit', 'file.mlt', 'file.mlp', 'file.mlip', 'file.mli.cppo', 'file.ml.cppo'}, - ['occam'] = {'file.occ'}, - ['octave'] = {'octaverc', '.octaverc', 'octave.conf'}, - ['omnimark'] = {'file.xom', 'file.xin'}, - ['opam'] = {'opam', 'file.opam', 'file.opam.template'}, - ['openroad'] = {'file.or'}, - ['ora'] = {'file.ora'}, - ['pamconf'] = {'/etc/pam.conf', '/etc/pam.d/file', 'any/etc/pam.conf', 'any/etc/pam.d/file'}, - ['pamenv'] = {'/etc/security/pam_env.conf', '/home/user/.pam_environment', '.pam_environment', 'pam_env.conf'}, - ['papp'] = {'file.papp', 'file.pxml', 'file.pxsl'}, - ['pascal'] = {'file.pas', 'file.dpr', 'file.lpr'}, - ['passwd'] = {'any/etc/passwd', 'any/etc/passwd-', 'any/etc/passwd.edit', 'any/etc/shadow', 'any/etc/shadow-', 'any/etc/shadow.edit', 'any/var/backups/passwd.bak', 'any/var/backups/shadow.bak', '/etc/passwd', '/etc/passwd-', '/etc/passwd.edit', '/etc/shadow', '/etc/shadow-', '/etc/shadow.edit', '/var/backups/passwd.bak', '/var/backups/shadow.bak'}, - ['pbtxt'] = {'file.pbtxt'}, - ['pccts'] = {'file.g'}, - ['pdf'] = {'file.pdf'}, - ['perl'] = {'file.plx', 'file.al', 'file.psgi', 'gitolite.rc', '.gitolite.rc', 'example.gitolite.rc'}, - ['pf'] = {'pf.conf'}, - ['pfmain'] = {'main.cf'}, - ['php'] = {'file.php', 'file.php9', 'file.phtml', 'file.ctp'}, - ['lpc'] = {'file.lpc', 'file.ulpc'}, - ['pike'] = {'file.pike', 'file.pmod'}, - ['cmod'] = {'file.cmod'}, - ['pilrc'] = {'file.rcp'}, - ['pine'] = {'.pinerc', 'pinerc', '.pinercex', 'pinercex'}, - ['pinfo'] = {'/etc/pinforc', '/.pinforc', 'any/.pinforc', 'any/etc/pinforc'}, - ['pli'] = {'file.pli', 'file.pl1'}, - ['plm'] = {'file.plm', 'file.p36', 'file.pac'}, - ['plp'] = {'file.plp'}, - ['plsql'] = {'file.pls', 'file.plsql'}, - ['po'] = {'file.po', 'file.pot'}, - ['pod'] = {'file.pod'}, - ['poke'] = {'file.pk'}, - ['postscr'] = {'file.ps', 'file.pfa', 'file.afm', 'file.eps', 'file.epsf', 'file.epsi', 'file.ai'}, - ['pov'] = {'file.pov'}, - ['povini'] = {'.povrayrc'}, - ['ppd'] = {'file.ppd'}, - ['ppwiz'] = {'file.it', 'file.ih'}, - ['privoxy'] = {'file.action'}, - ['proc'] = {'file.pc'}, - ['procmail'] = {'.procmail', '.procmailrc'}, - ['prolog'] = {'file.pdb'}, - ['promela'] = {'file.pml'}, - ['proto'] = {'file.proto'}, - ['protocols'] = {'/etc/protocols', 'any/etc/protocols'}, - ['ps1'] = {'file.ps1', 'file.psd1', 'file.psm1', 'file.pssc'}, - ['ps1xml'] = {'file.ps1xml'}, - ['psf'] = {'file.psf'}, - ['psl'] = {'file.psl'}, - ['puppet'] = {'file.pp'}, - ['pyret'] = {'file.arr'}, - ['pyrex'] = {'file.pyx', 'file.pxd'}, - ['python'] = {'file.py', 'file.pyw', '.pythonstartup', '.pythonrc', 'file.ptl', 'file.pyi', 'SConstruct'}, - ['quake'] = {'anybaseq2/file.cfg', 'anyid1/file.cfg', 'quake3/file.cfg', 'baseq2/file.cfg', 'id1/file.cfg', 'quake1/file.cfg', 'some-baseq2/file.cfg', 'some-id1/file.cfg', 'some-quake1/file.cfg'}, - ['radiance'] = {'file.rad', 'file.mat'}, - ['raku'] = {'file.pm6', 'file.p6', 'file.t6', 'file.pod6', 'file.raku', 'file.rakumod', 'file.rakudoc', 'file.rakutest'}, - ['ratpoison'] = {'.ratpoisonrc', 'ratpoisonrc'}, - ['rbs'] = {'file.rbs'}, - ['rc'] = {'file.rc', 'file.rch'}, - ['rcs'] = {'file,v'}, - ['readline'] = {'.inputrc', 'inputrc'}, - ['remind'] = {'.reminders', 'file.remind', 'file.rem', '.reminders-file'}, - ['rego'] = {'file.rego'}, - ['resolv'] = {'resolv.conf'}, - ['reva'] = {'file.frt'}, - ['rexx'] = {'file.rex', 'file.orx', 'file.rxo', 'file.rxj', 'file.jrexx', 'file.rexxj', 'file.rexx', 'file.testGroup', 'file.testUnit'}, - ['rib'] = {'file.rib'}, - ['rnc'] = {'file.rnc'}, - ['rng'] = {'file.rng'}, - ['robots'] = {'robots.txt'}, - ['routeros'] = {'file.rsc'}, - ['rpcgen'] = {'file.x'}, - ['rpl'] = {'file.rpl'}, - ['rst'] = {'file.rst'}, - ['rtf'] = {'file.rtf'}, - ['ruby'] = {'.irbrc', 'irbrc', 'file.rb', 'file.rbw', 'file.gemspec', 'file.ru', 'Gemfile', 'file.builder', 'file.rxml', 'file.rjs', 'file.rant', 'file.rake', 'rakefile', 'Rakefile', 'rantfile', 'Rantfile', 'rakefile-file', 'Rakefile-file', 'Puppetfile'}, - ['rust'] = {'file.rs'}, - ['samba'] = {'smb.conf'}, - ['sas'] = {'file.sas'}, - ['sass'] = {'file.sass'}, - ['sather'] = {'file.sa'}, - ['sbt'] = {'file.sbt'}, - ['scala'] = {'file.scala', 'file.sc'}, - ['scheme'] = {'file.scm', 'file.ss', 'file.sld', 'file.rkt', 'file.rktd', 'file.rktl'}, - ['scilab'] = {'file.sci', 'file.sce'}, - ['screen'] = {'.screenrc', 'screenrc'}, - ['sexplib'] = {'file.sexp'}, - ['scdoc'] = {'file.scd'}, - ['scss'] = {'file.scss'}, - ['sd'] = {'file.sd'}, - ['sdc'] = {'file.sdc'}, - ['sdl'] = {'file.sdl', 'file.pr'}, - ['sed'] = {'file.sed'}, - ['sensors'] = {'/etc/sensors.conf', '/etc/sensors3.conf', 'any/etc/sensors.conf', 'any/etc/sensors3.conf'}, - ['services'] = {'/etc/services', 'any/etc/services'}, - ['setserial'] = {'/etc/serial.conf', 'any/etc/serial.conf'}, - ['sh'] = {'.bashrc', 'file.bash', '/usr/share/doc/bash-completion/filter.sh','/etc/udev/cdsymlinks.conf', 'any/etc/udev/cdsymlinks.conf'}, - ['sieve'] = {'file.siv', 'file.sieve'}, - ['simula'] = {'file.sim'}, - ['sinda'] = {'file.sin', 'file.s85'}, - ['sisu'] = {'file.sst', 'file.ssm', 'file.ssi', 'file.-sst', 'file._sst', 'file.sst.meta', 'file.-sst.meta', 'file._sst.meta'}, - ['skill'] = {'file.il', 'file.ils', 'file.cdf'}, - ['slang'] = {'file.sl'}, - ['slice'] = {'file.ice'}, - ['solution'] = {'file.sln'}, - ['slpconf'] = {'/etc/slp.conf', 'any/etc/slp.conf'}, - ['slpreg'] = {'/etc/slp.reg', 'any/etc/slp.reg'}, - ['slpspi'] = {'/etc/slp.spi', 'any/etc/slp.spi'}, - ['slrnrc'] = {'.slrnrc'}, - ['slrnsc'] = {'file.score'}, - ['sm'] = {'sendmail.cf'}, - ['svelte'] = {'file.svelte'}, - ['smarty'] = {'file.tpl'}, - ['smcl'] = {'file.hlp', 'file.ihlp', 'file.smcl'}, - ['smith'] = {'file.smt', 'file.smith'}, - ['sml'] = {'file.sml'}, - ['snobol4'] = {'file.sno', 'file.spt'}, - ['sparql'] = {'file.rq', 'file.sparql'}, - ['spec'] = {'file.spec'}, - ['spice'] = {'file.sp', 'file.spice'}, - ['spup'] = {'file.speedup', 'file.spdata', 'file.spd'}, - ['spyce'] = {'file.spy', 'file.spi'}, - ['sql'] = {'file.tyb', 'file.typ', 'file.tyc', 'file.pkb', 'file.pks'}, - ['sqlj'] = {'file.sqlj'}, - ['sqr'] = {'file.sqr', 'file.sqi'}, - ['squid'] = {'squid.conf'}, - ['squirrel'] = {'file.nut'}, - ['srec'] = {'file.s19', 'file.s28', 'file.s37', 'file.mot', 'file.srec'}, - ['sshconfig'] = {'ssh_config', '/.ssh/config', '/etc/ssh/ssh_config.d/file.conf', 'any/etc/ssh/ssh_config.d/file.conf', 'any/.ssh/config', 'any/.ssh/file.conf'}, - ['sshdconfig'] = {'sshd_config', '/etc/ssh/sshd_config.d/file.conf', 'any/etc/ssh/sshd_config.d/file.conf'}, - ['st'] = {'file.st'}, - ['stata'] = {'file.ado', 'file.do', 'file.imata', 'file.mata'}, - ['stp'] = {'file.stp'}, - ['sudoers'] = {'any/etc/sudoers', 'sudoers.tmp', '/etc/sudoers', 'any/etc/sudoers.d/file'}, - ['svg'] = {'file.svg'}, - ['svn'] = {'svn-commitfile.tmp', 'svn-commit-file.tmp', 'svn-commit.tmp'}, - ['swift'] = {'file.swift'}, - ['swiftgyb'] = {'file.swift.gyb'}, - ['sil'] = {'file.sil'}, - ['sysctl'] = {'/etc/sysctl.conf', '/etc/sysctl.d/file.conf', 'any/etc/sysctl.conf', 'any/etc/sysctl.d/file.conf'}, - ['systemd'] = {'any/systemd/file.automount', 'any/systemd/file.dnssd', 'any/systemd/file.link', 'any/systemd/file.mount', 'any/systemd/file.netdev', 'any/systemd/file.network', 'any/systemd/file.nspawn', 'any/systemd/file.path', 'any/systemd/file.service', 'any/systemd/file.slice', 'any/systemd/file.socket', 'any/systemd/file.swap', 'any/systemd/file.target', 'any/systemd/file.timer', '/etc/systemd/some.conf.d/file.conf', '/etc/systemd/system/some.d/file.conf', '/etc/systemd/system/some.d/.#file', '/etc/systemd/system/.#otherfile', '/home/user/.config/systemd/user/some.d/mine.conf', '/home/user/.config/systemd/user/some.d/.#file', '/home/user/.config/systemd/user/.#otherfile', '/.config/systemd/user/.#', '/.config/systemd/user/.#-file', '/.config/systemd/user/file.d/.#', '/.config/systemd/user/file.d/.#-file', '/.config/systemd/user/file.d/file.conf', '/etc/systemd/file.conf.d/file.conf', '/etc/systemd/system/.#', '/etc/systemd/system/.#-file', '/etc/systemd/system/file.d/.#', '/etc/systemd/system/file.d/.#-file', '/etc/systemd/system/file.d/file.conf', '/systemd/file.automount', '/systemd/file.dnssd', '/systemd/file.link', '/systemd/file.mount', '/systemd/file.netdev', '/systemd/file.network', '/systemd/file.nspawn', '/systemd/file.path', '/systemd/file.service', '/systemd/file.slice', '/systemd/file.socket', '/systemd/file.swap', '/systemd/file.target', '/systemd/file.timer', 'any/.config/systemd/user/.#', 'any/.config/systemd/user/.#-file', 'any/.config/systemd/user/file.d/.#', 'any/.config/systemd/user/file.d/.#-file', 'any/.config/systemd/user/file.d/file.conf', 'any/etc/systemd/file.conf.d/file.conf', 'any/etc/systemd/system/.#', 'any/etc/systemd/system/.#-file', 'any/etc/systemd/system/file.d/.#', 'any/etc/systemd/system/file.d/.#-file', 'any/etc/systemd/system/file.d/file.conf'}, - ['systemverilog'] = {'file.sv', 'file.svh'}, - ['tags'] = {'tags'}, - ['tak'] = {'file.tak'}, - ['taskdata'] = {'pending.data', 'completed.data', 'undo.data'}, - ['taskedit'] = {'file.task'}, - ['tcl'] = {'file.tcl', 'file.tm', 'file.tk', 'file.itcl', 'file.itk', 'file.jacl', '.tclshrc', 'tclsh.rc', '.wishrc'}, - ['teraterm'] = {'file.ttl'}, - ['terminfo'] = {'file.ti'}, - ['tex'] = {'file.latex', 'file.sty', 'file.dtx', 'file.ltx', 'file.bbl'}, - ['texinfo'] = {'file.texinfo', 'file.texi', 'file.txi'}, - ['texmf'] = {'texmf.cnf'}, - ['text'] = {'file.text', 'file.txt', 'README', 'LICENSE', 'COPYING', 'AUTHORS', '/usr/share/doc/bash-completion/AUTHORS', '/etc/apt/apt.conf.d/README', '/etc/Muttrc.d/README'}, - ['tf'] = {'file.tf', '.tfrc', 'tfrc'}, - ['tidy'] = {'.tidyrc', 'tidyrc', 'tidy.conf'}, - ['tilde'] = {'file.t.html'}, - ['tli'] = {'file.tli'}, - ['tmux'] = {'tmuxfile.conf', '.tmuxfile.conf', '.tmux-file.conf', '.tmux.conf', 'tmux-file.conf', 'tmux.conf', 'tmux.conf.local'}, - ['toml'] = {'file.toml', 'Gopkg.lock', 'Pipfile', '/home/user/.cargo/config'}, - ['tpp'] = {'file.tpp'}, - ['treetop'] = {'file.treetop'}, - ['trustees'] = {'trustees.conf'}, - ['tsalt'] = {'file.slt'}, - ['tsscl'] = {'file.tsscl'}, - ['tssgm'] = {'file.tssgm'}, - ['tssop'] = {'file.tssop'}, - ['twig'] = {'file.twig'}, - ['typescriptreact'] = {'file.tsx'}, - ['uc'] = {'file.uc'}, - ['udevconf'] = {'/etc/udev/udev.conf', 'any/etc/udev/udev.conf'}, - ['udevperm'] = {'/etc/udev/permissions.d/file.permissions', 'any/etc/udev/permissions.d/file.permissions'}, - ['udevrules'] = {'/etc/udev/rules.d/file.rules', '/usr/lib/udev/rules.d/file.rules', '/lib/udev/rules.d/file.rules'}, - ['uil'] = {'file.uit', 'file.uil'}, - ['updatedb'] = {'/etc/updatedb.conf', 'any/etc/updatedb.conf'}, - ['upstart'] = {'/usr/share/upstart/file.conf', '/usr/share/upstart/file.override', '/etc/init/file.conf', '/etc/init/file.override', '/.init/file.conf', '/.init/file.override', '/.config/upstart/file.conf', '/.config/upstart/file.override', 'any/.config/upstart/file.conf', 'any/.config/upstart/file.override', 'any/.init/file.conf', 'any/.init/file.override', 'any/etc/init/file.conf', 'any/etc/init/file.override', 'any/usr/share/upstart/file.conf', 'any/usr/share/upstart/file.override'}, - ['upstreamdat'] = {'upstream.dat', 'UPSTREAM.DAT', 'upstream.file.dat', 'UPSTREAM.FILE.DAT', 'file.upstream.dat', 'FILE.UPSTREAM.DAT'}, - ['upstreaminstalllog'] = {'upstreaminstall.log', 'UPSTREAMINSTALL.LOG', 'upstreaminstall.file.log', 'UPSTREAMINSTALL.FILE.LOG', 'file.upstreaminstall.log', 'FILE.UPSTREAMINSTALL.LOG'}, - ['upstreamlog'] = {'fdrupstream.log', 'upstream.log', 'UPSTREAM.LOG', 'upstream.file.log', 'UPSTREAM.FILE.LOG', 'file.upstream.log', 'FILE.UPSTREAM.LOG', 'UPSTREAM-file.log', 'UPSTREAM-FILE.LOG'}, - ['usserverlog'] = {'usserver.log', 'USSERVER.LOG', 'usserver.file.log', 'USSERVER.FILE.LOG', 'file.usserver.log', 'FILE.USSERVER.LOG'}, - ['usw2kagtlog'] = {'usw2kagt.log', 'USW2KAGT.LOG', 'usw2kagt.file.log', 'USW2KAGT.FILE.LOG', 'file.usw2kagt.log', 'FILE.USW2KAGT.LOG'}, - ['vb'] = {'file.sba', 'file.vb', 'file.vbs', 'file.dsm', 'file.ctl'}, - ['vera'] = {'file.vr', 'file.vri', 'file.vrh'}, - ['verilog'] = {'file.v'}, - ['verilogams'] = {'file.va', 'file.vams'}, - ['vgrindefs'] = {'vgrindefs'}, - ['vhdl'] = {'file.hdl', 'file.vhd', 'file.vhdl', 'file.vbe', 'file.vst', 'file.vhdl_123', 'file.vho', 'some.vhdl_1', 'some.vhdl_1-file'}, - ['vim'] = {'file.vim', 'file.vba', '.exrc', '_exrc', 'some-vimrc', 'some-vimrc-file', 'vimrc', 'vimrc-file'}, - ['viminfo'] = {'.viminfo', '_viminfo'}, - ['vmasm'] = {'file.mar'}, - ['voscm'] = {'file.cm'}, - ['vrml'] = {'file.wrl'}, - ['vroom'] = {'file.vroom'}, - ['vue'] = {'file.vue'}, - ['wast'] = {'file.wast', 'file.wat'}, - ['webmacro'] = {'file.wm'}, - ['wget'] = {'.wgetrc', 'wgetrc'}, - ['winbatch'] = {'file.wbt'}, - ['wml'] = {'file.wml'}, - ['wsh'] = {'file.wsf', 'file.wsc'}, - ['wsml'] = {'file.wsml'}, - ['wvdial'] = {'wvdial.conf', '.wvdialrc'}, - ['xdefaults'] = {'.Xdefaults', '.Xpdefaults', '.Xresources', 'xdm-config', 'file.ad', '/Xresources/file', '/app-defaults/file', 'Xresources', 'Xresources-file', 'any/Xresources/file', 'any/app-defaults/file'}, - ['xhtml'] = {'file.xhtml', 'file.xht'}, - ['xinetd'] = {'/etc/xinetd.conf', '/etc/xinetd.d/file', 'any/etc/xinetd.conf', 'any/etc/xinetd.d/file'}, - ['xmath'] = {'file.msc', 'file.msf'}, - ['xml'] = {'/etc/blkid.tab', '/etc/blkid.tab.old', 'file.xmi', 'file.csproj', 'file.csproj.user', 'file.fsproj', 'file.fsproj.user', 'file.vbproj', 'file.vbproj.user', 'file.ui', 'file.tpm', '/etc/xdg/menus/file.menu', 'fglrxrc', 'file.xlf', 'file.xliff', 'file.xul', 'file.wsdl', 'file.wpl', 'any/etc/blkid.tab', 'any/etc/blkid.tab.old', 'any/etc/xdg/menus/file.menu', 'file.atom', 'file.rss', 'file.cdxml', 'file.psc1', 'file.mpd'}, - ['xmodmap'] = {'anyXmodmap', 'Xmodmap', 'some-Xmodmap', 'some-xmodmap', 'some-xmodmap-file', 'xmodmap', 'xmodmap-file'}, - ['xf86conf'] = {'xorg.conf', 'xorg.conf-4'}, - ['xpm'] = {'file.xpm'}, - ['xpm2'] = {'file.xpm2'}, - ['xquery'] = {'file.xq', 'file.xql', 'file.xqm', 'file.xquery', 'file.xqy'}, - ['xs'] = {'file.xs'}, - ['xsd'] = {'file.xsd'}, - ['xslt'] = {'file.xsl', 'file.xslt'}, - ['yacc'] = {'file.yy', 'file.yxx', 'file.y++'}, - ['yaml'] = {'file.yaml', 'file.yml'}, - ['raml'] = {'file.raml'}, - ['z8a'] = {'file.z8a'}, - ['zig'] = {'file.zig'}, - ['zimbu'] = {'file.zu'}, - ['zimbutempl'] = {'file.zut'}, - ['zsh'] = {'.zprofile', '/etc/zprofile', '.zfbfmarks', 'file.zsh', '.zcompdump', '.zlogin', '.zlogout', '.zshenv', '.zshrc', '.zcompdump-file', '.zlog', '.zlog-file', '.zsh', '.zsh-file', 'any/etc/zprofile', 'zlog', 'zlog-file', 'zsh', 'zsh-file'}, - ['help'] = {funcs.getenv('VIMRUNTIME') .. '/doc/help.txt'}, - } - - local filename_case_checks = { - ['modula2'] = {'file.DEF', 'file.MOD'}, - ['bzl'] = {'file.BUILD', 'BUILD'}, - } - - local function check_items(checks) - meths.set_option('swapfile', false) - for ft, names in pairs(checks) do - for _, name in ipairs(names) do - meths.command('new') - meths.command('edit ' .. funcs.fnameescape(name)) - if curbufmeths.get_option('filetype') == '' and curbufmeths.get_option('readonly') then -- luacheck: ignore 542 - -- File exists but not able to edit it (permission denied) - else - eq(ft, curbufmeths.get_option('filetype')) - end - meths.command('bwipe!') - end - end - meths.command('set swapfile&') - end - - meths.set_var('do_filetype_lua', 1) - meths.command('filetype on') - check_items(filename_checks) - if funcs.has('fname_case') == 1 then - check_items(filename_case_checks) - end - meths.command('filetype off') - end) end) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 9bf376b6fe..642dc59bbc 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -2203,6 +2203,40 @@ describe('lua stdlib', function() end) end) + it('vim.notify_once', function() + local screen = Screen.new(60,5) + screen:set_default_attr_ids({ + [0] = {bold=true, foreground=Screen.colors.Blue}, + [1] = {foreground=Screen.colors.Red}, + }) + screen:attach() + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]} + exec_lua [[vim.notify_once("I'll only tell you this once...", vim.log.levels.WARN)]] + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {1:I'll only tell you this once...} | + ]]} + feed('<C-l>') + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]} + exec_lua [[vim.notify_once("I'll only tell you this once...")]] + screen:expect_unchanged() + end) + describe('vim.schedule_wrap', function() it('preserves argument lists', function() exec_lua [[ @@ -2298,3 +2332,82 @@ describe('lua: require("mod") from packages', function() eq('I am fancy_z.lua', exec_lua [[ return require'fancy_z' ]]) end) end) + +describe('vim.keymap', function() + it('can make a mapping', function() + eq(0, exec_lua [[ + GlobalCount = 0 + vim.keymap.set('n', 'asdf', function() GlobalCount = GlobalCount + 1 end) + return GlobalCount + ]]) + + feed('asdf\n') + + eq(1, exec_lua[[return GlobalCount]]) + end) + + it('can make an expr mapping', function() + exec_lua [[ + vim.keymap.set('n', 'aa', function() return ':lua SomeValue = 99<cr>' end, {expr = true}) + ]] + + feed('aa') + + eq(99, exec_lua[[return SomeValue]]) + end) + + it('can overwrite a mapping', function() + eq(0, exec_lua [[ + GlobalCount = 0 + vim.keymap.set('n', 'asdf', function() GlobalCount = GlobalCount + 1 end) + return GlobalCount + ]]) + + feed('asdf\n') + + eq(1, exec_lua[[return GlobalCount]]) + + exec_lua [[ + vim.keymap.set('n', 'asdf', function() GlobalCount = GlobalCount - 1 end) + ]] + + feed('asdf\n') + + eq(0, exec_lua[[return GlobalCount]]) + end) + + it('can unmap a mapping', function() + eq(0, exec_lua [[ + GlobalCount = 0 + vim.keymap.set('n', 'asdf', function() GlobalCount = GlobalCount + 1 end) + return GlobalCount + ]]) + + feed('asdf\n') + + eq(1, exec_lua[[return GlobalCount]]) + + exec_lua [[ + vim.keymap.del('n', 'asdf') + ]] + + feed('asdf\n') + + eq(1, exec_lua[[return GlobalCount]]) + eq('\nNo mapping found', helpers.exec_capture('nmap asdf')) + end) + + it('can do <Plug> mappings', function() + eq(0, exec_lua [[ + GlobalCount = 0 + vim.keymap.set('n', '<plug>(asdf)', function() GlobalCount = GlobalCount + 1 end) + vim.keymap.set('n', 'ww', '<plug>(asdf)') + return GlobalCount + ]]) + + feed('ww\n') + + eq(1, exec_lua[[return GlobalCount]]) + end) + +end) diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index 1ff451434d..beb43e0271 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -292,10 +292,9 @@ describe(':terminal buffer', function() command('quit') end) - it('does not segfault when pasting empty buffer #13955', function() - feed_command('terminal') + it('does not segfault when pasting empty register #13955', function() feed('<c-\\><c-n>') - feed_command('put a') -- buffer a is empty + feed_command('put a') -- register a is empty helpers.assert_alive() end) end) |