diff options
45 files changed, 604 insertions, 496 deletions
diff --git a/.github/actions/cache/action.yml b/.github/actions/cache/action.yml index da36c71a1d..07f8feaa84 100644 --- a/.github/actions/cache/action.yml +++ b/.github/actions/cache/action.yml @@ -16,7 +16,7 @@ runs: # files to search through. - uses: actions/cache@v3 with: - path: ${{ env.DEPS_BUILD_DIR }} + path: .deps key: ${{ env.CACHE_KEY }}-${{ hashFiles('cmake**', 'ci/**', '.github/workflows/test.yml', 'CMakeLists.txt', 'runtime/CMakeLists.txt', 'src/nvim/**/CMakeLists.txt') }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 10e3e2bdeb..fa1f74e4d1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -71,46 +71,3 @@ jobs: - name: Install run: make install - - with-external-deps: - runs-on: ubuntu-22.04 - timeout-minutes: 10 - steps: - - uses: actions/checkout@v3 - - - name: Install dependencies - run: | - sudo add-apt-repository ppa:neovim-ppa/stable - ./.github/scripts/install_deps.sh - sudo apt-get install -y \ - libluajit-5.1-dev \ - libmsgpack-dev \ - libtermkey-dev \ - libtree-sitter-dev \ - libunibilium-dev \ - libuv1-dev \ - lua-busted \ - lua-filesystem \ - lua-inspect \ - lua-lpeg \ - lua-nvim \ - luajit - # libvterm-dev \ - # lua-luv-dev - - # Remove comments from packages once we start using these external - # dependencies. - - - name: Build third-party deps - run: | - # Ideally all dependencies should external for this job, but some - # dependencies don't have the required version available. We use the - # bundled versions for these with the hopes of being able to remove them - # later on. - cmake -S cmake.deps -B .deps -G Ninja -D USE_BUNDLED=OFF -D USE_BUNDLED_LUV=ON -D USE_BUNDLED_LIBVTERM=ON - cmake --build .deps - - - name: Build - run: | - cmake -B build -G Ninja - cmake --build build diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 22be9bf719..e6ff09d351 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,7 +19,6 @@ env: ASAN_OPTIONS: detect_leaks=1:check_initialization_order=1:handle_abort=1:handle_sigill=1:log_path=${{ github.workspace }}/build/log/asan:intercept_tls_get_addr=0 BIN_DIR: ${{ github.workspace }}/bin BUILD_DIR: ${{ github.workspace }}/build - DEPS_BUILD_DIR: ${{ github.workspace }}/nvim-deps INSTALL_PREFIX: ${{ github.workspace }}/nvim-install LOG_DIR: ${{ github.workspace }}/build/log NVIM_LOG_FILE: ${{ github.workspace }}/build/.nvimlog @@ -72,8 +71,8 @@ jobs: - name: Build third-party deps run: | - cmake -S cmake.deps -B $DEPS_BUILD_DIR -G Ninja - cmake --build $DEPS_BUILD_DIR + cmake -S cmake.deps -B .deps -G Ninja + cmake --build .deps - if: success() || failure() && steps.abort_job.outputs.status == 'success' name: configure @@ -193,8 +192,8 @@ jobs: - name: Build third-party deps run: | - cmake -S cmake.deps -B $DEPS_BUILD_DIR -G Ninja ${{ matrix.deps_flags }} - cmake --build $DEPS_BUILD_DIR + cmake -S cmake.deps -B .deps -G Ninja ${{ matrix.deps_flags }} + cmake --build .deps - name: Build run: | @@ -273,8 +272,8 @@ jobs: - name: Build third-party deps run: | - cmake -S cmake.deps -B $DEPS_BUILD_DIR -G "Ninja Multi-Config" - cmake --build $DEPS_BUILD_DIR + cmake -S cmake.deps -B .deps -G "Ninja Multi-Config" + cmake --build .deps - name: Configure run: cmake -B build -G "Ninja Multi-Config" -D CMAKE_C_COMPILER=gcc @@ -309,8 +308,8 @@ jobs: - name: Build deps run: | - cmake -S cmake.deps -B $env:DEPS_BUILD_DIR -G Ninja -D CMAKE_BUILD_TYPE='RelWithDebInfo' - cmake --build $env:DEPS_BUILD_DIR + cmake -S cmake.deps -B .deps -G Ninja -D CMAKE_BUILD_TYPE='RelWithDebInfo' + cmake --build .deps - name: Build run: | @@ -330,9 +329,6 @@ jobs: # Sanity check python -c "import pynvim; print(str(pynvim))" - gem.cmd install --pre neovim - Get-Command -CommandType Application neovim-ruby-host.bat - node --version npm.cmd --version @@ -360,3 +356,46 @@ jobs: $env:PATH = "C:\msys64\usr\bin;$env:PATH" & "C:\msys64\mingw64\bin\mingw32-make.exe" -C $(Convert-Path test\old\testdir) VERBOSE=1 $env:PATH = $OldPath + + with-external-deps: + runs-on: ubuntu-22.04 + timeout-minutes: 10 + steps: + - uses: actions/checkout@v3 + + - name: Install dependencies + run: | + sudo add-apt-repository ppa:neovim-ppa/stable + ./.github/scripts/install_deps.sh + sudo apt-get install -y \ + libluajit-5.1-dev \ + libmsgpack-dev \ + libtermkey-dev \ + libtree-sitter-dev \ + libunibilium-dev \ + libuv1-dev \ + lua-filesystem \ + lua-lpeg \ + lua-mpack \ + luajit + # libvterm-dev \ + # lua-luv-dev + + # Remove comments from packages once we start using these external + # dependencies. + + - uses: ./.github/actions/cache + + - name: Build third-party deps + run: | + # Ideally all dependencies should external for this job, but some + # dependencies don't have the required version available. We use the + # bundled versions for these with the hopes of being able to remove them + # later on. + cmake -S cmake.deps -B .deps -G Ninja -D USE_BUNDLED=OFF -D USE_BUNDLED_LUV=ON -D USE_BUNDLED_LIBVTERM=ON + cmake --build .deps + + - name: Build + run: | + cmake -B build -G Ninja + cmake --build build diff --git a/cmake.deps/CMakeLists.txt b/cmake.deps/CMakeLists.txt index 42f97a5c2b..0d3e3886f5 100644 --- a/cmake.deps/CMakeLists.txt +++ b/cmake.deps/CMakeLists.txt @@ -34,11 +34,11 @@ if(HAS_OG_FLAG) set(DEFAULT_MAKE_CFLAGS CFLAGS+=-Og ${DEFAULT_MAKE_CFLAGS}) endif() -set(DEPS_INSTALL_DIR "${CMAKE_BINARY_DIR}/usr" CACHE PATH "Dependencies install directory.") -set(DEPS_BIN_DIR "${DEPS_INSTALL_DIR}/bin" CACHE PATH "Dependencies binary install directory.") -set(DEPS_LIB_DIR "${DEPS_INSTALL_DIR}/lib" CACHE PATH "Dependencies library install directory.") -set(DEPS_BUILD_DIR "${CMAKE_BINARY_DIR}/build" CACHE PATH "Dependencies build directory.") -set(DEPS_DOWNLOAD_DIR "${DEPS_BUILD_DIR}/downloads" CACHE PATH "Dependencies download directory.") +set(DEPS_INSTALL_DIR "${CMAKE_BINARY_DIR}/usr") +set(DEPS_BIN_DIR "${DEPS_INSTALL_DIR}/bin") +set(DEPS_LIB_DIR "${DEPS_INSTALL_DIR}/lib") +set(DEPS_BUILD_DIR "${CMAKE_BINARY_DIR}/build") +set(DEPS_DOWNLOAD_DIR "${DEPS_BUILD_DIR}/downloads") list(APPEND DEPS_CMAKE_ARGS -D CMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR}) diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index 5e918a19f4..0e04e9035b 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -223,6 +223,7 @@ getreg([{regname} [, 1 [, {list}]]]) String or List contents of a register getreginfo([{regname}]) Dict information about a register getregtype([{regname}]) String type of a register +getscriptinfo() List list of sourced scripts gettabinfo([{expr}]) List list of tab pages gettabvar({nr}, {varname} [, {def}]) any variable {varname} in tab {nr} or {def} @@ -3576,6 +3577,16 @@ getregtype([{regname}]) *getregtype()* Can also be used as a |method|: > GetRegname()->getregtype() +getscriptinfo() *getscriptinfo()* + Returns a |List| with information about all the sourced Vim + scripts in the order they were sourced. + + Each item in the returned List is a |Dict| with the following + items: + autoload always set to FALSE. + name vim script file name. + sid script ID |<SID>|. + gettabinfo([{tabnr}]) *gettabinfo()* If {tabnr} is not specified, then information about all the tab pages is returned as a |List|. Each List item is a diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index d13dc4a782..ca65251a9f 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -676,7 +676,7 @@ buf_request_all({bufnr}, {method}, {params}, {callback}) finished. Unlike `buf_request`, this will collect all the responses from each server instead of handling them. A map of client_id:request_result will be provided to the - callback + callback. Return: ~ fun() cancel A function that will cancel all requests @@ -697,9 +697,9 @@ buf_request_sync({bufnr}, {method}, {params}, {timeout_ms}) result. Defaults to 1000 Return: ~ - table<integer, any>|nil result, string|nil err Map of - client_id:request_result. On timeout, cancel or error, returns `(nil, - err)` where `err` is a string describing the failure reason. + (table) result Map of client_id:request_result. + (string|nil) err On timeout, cancel, or error, `err` is a string + describing the failure reason, and `result` is nil. client() *vim.lsp.client* LSP client object. You can get an active client object via diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 7df96874ea..78cd05b7d5 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -237,7 +237,10 @@ The following deprecated functions or APIs were removed. changes need to be contributed there first.) See https://github.com/neovim/neovim/pull/20674. -- 'hkmap', 'hkmapp' and 'aleph' options were removed. Use 'keymap' option instead. +• 'hkmap', 'hkmapp' and 'aleph' options were removed. Use 'keymap' option instead. + +• |LanguageTree:parse()| no longer returns changed regions. Please use the + `on_changedtree` callbacks instead. ============================================================================== DEPRECATIONS *news-deprecations* diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index b22d673eb9..9051375da2 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -5278,6 +5278,14 @@ NormalNC Normal text in non-current windows. Pmenu Popup menu: Normal item. *hl-PmenuSel* PmenuSel Popup menu: Selected item. + *hl-PmenuKind* +PmenuKind Popup menu: Normal item "kind". + *hl-PmenuKindSel* +PmenuKindSel Popup menu: Selected item "kind". + *hl-PmenuExtra* +PmenuExtra Popup menu: Normal item "extra text". + *hl-PmenuExtraSel* +PmenuExtraSel Popup menu: Selected item "extra text". *hl-PmenuSbar* PmenuSbar Popup menu: Scrollbar. *hl-PmenuThumb* diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt index 8a0145127c..ddca307e74 100644 --- a/runtime/doc/treesitter.txt +++ b/runtime/doc/treesitter.txt @@ -1111,7 +1111,6 @@ LanguageTree:parse({self}) *LanguageTree:parse()* Return: ~ TSTree[] - (table|nil) Change list LanguageTree:register_cbs({self}, {cbs}) *LanguageTree:register_cbs()* Registers callbacks for the |LanguageTree|. diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt index ed16f837cf..17a34b1236 100644 --- a/runtime/doc/usr_41.txt +++ b/runtime/doc/usr_41.txt @@ -1056,6 +1056,14 @@ Prompt Buffer: *promptbuffer-functions* prompt_setinterrupt() set interrupt callback for a buffer prompt_setprompt() set the prompt text for a buffer +Registers: *register-functions* + getreg() get contents of a register + getreginfo() get information about a register + getregtype() get type of a register + setreg() set contents and type of a register + reg_executing() return the name of the register being executed + reg_recording() return the name of the register being recorded + Context Stack: *ctx-functions* ctxget() return context at given index from top ctxpop() pop and restore top context @@ -1072,6 +1080,7 @@ Various: *various-functions* did_filetype() check if a FileType autocommand was used eventhandler() check if invoked by an event handler getpid() get process ID of Vim + getscriptinfo() get list of sourced vim scripts libcall() call a function in an external library libcallnr() idem, returning a number @@ -1079,13 +1088,6 @@ Various: *various-functions* undofile() get the name of the undo file undotree() return the state of the undo tree - getreg() get contents of a register - getreginfo() get information about a register - getregtype() get type of a register - setreg() set contents and type of a register - reg_executing() return the name of the register being executed - reg_recording() return the name of the register being recorded - shiftwidth() effective value of 'shiftwidth' wordcount() get byte/word/char count of buffer diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index c85d38a50e..39665a3d4f 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -1,3 +1,4 @@ +---@diagnostic disable: invisible local default_handlers = require('vim.lsp.handlers') local log = require('vim.lsp.log') local lsp_rpc = require('vim.lsp.rpc') @@ -369,7 +370,7 @@ do --- @field offset_encoding "utf-8"|"utf-16"|"utf-32" --- --- @class CTBufferState - --- @field uri string uri of the buffer + --- @field name string name of the buffer --- @field lines string[] snapshot of buffer lines from last didChange --- @field lines_tmp string[] --- @field pending_changes table[] List of debounced changes in incremental sync mode @@ -488,12 +489,8 @@ do if buf_state then buf_state.refs = buf_state.refs + 1 else - local uri = vim.uri_from_bufnr(bufnr) - if not uv.fs_stat(api.nvim_buf_get_name(bufnr)) then - uri = uri:gsub('^file://', 'buffer://') - end buf_state = { - uri = uri, + name = api.nvim_buf_get_name(bufnr), lines = {}, lines_tmp = {}, pending_changes = {}, @@ -508,26 +505,12 @@ do end ---@private - ---@param client table - ---@param bufnr integer - ---@return string uri - function changetracking._get_uri(client, bufnr) + function changetracking._get_and_set_name(client, bufnr, name) local state = state_by_group[get_group(client)] or {} local buf_state = (state.buffers or {})[bufnr] - return assert(buf_state.uri, 'Must have an URI set') - end - - ---@private - ---@param client table - ---@param bufnr integer - ---@param uri string - ---@return string uri - function changetracking._get_and_set_uri(client, bufnr, uri) - local state = state_by_group[get_group(client)] or {} - local buf_state = (state.buffers or {})[bufnr] - local old_uri = buf_state.uri - buf_state.uri = uri - return old_uri + local old_name = buf_state.name + buf_state.name = name + return old_name end ---@private @@ -614,7 +597,7 @@ do { text = buf_get_full_text(bufnr) }, } end - local uri = buf_state.uri + local uri = vim.uri_from_bufnr(bufnr) for _, client in pairs(state.clients) do if not client.is_stopped() and lsp.buf_is_attached(bufnr, client.id) then client.notify('textDocument/didChange', { @@ -727,14 +710,11 @@ local function text_document_did_open_handler(bufnr, client) return end local filetype = nvim_buf_get_option(bufnr, 'filetype') - local uri = vim.uri_from_bufnr(bufnr) - if not uv.fs_stat(api.nvim_buf_get_name(bufnr)) then - uri = uri:gsub('^file://', 'buffer://') - end + local params = { textDocument = { version = 0, - uri = uri, + uri = vim.uri_from_bufnr(bufnr), languageId = client.config.get_language_id(bufnr, filetype), text = buf_get_full_text(bufnr), }, @@ -1058,7 +1038,7 @@ function lsp.start_client(config) --- Returns the default handler if the user hasn't set a custom one. --- ---@param method (string) LSP method name - ---@return function|nil The handler for the given method, if defined, or the default from |vim.lsp.handlers| + ---@return lsp-handler|nil The handler for the given method, if defined, or the default from |vim.lsp.handlers| local function resolve_handler(method) return handlers[method] or default_handlers[method] end @@ -1611,11 +1591,11 @@ local function text_document_did_save_handler(bufnr) local text = once(buf_get_full_text) for_each_buffer_client(bufnr, function(client) local name = api.nvim_buf_get_name(bufnr) - local old_uri = changetracking._get_and_set_uri(client, bufnr, uri) - if old_uri and name ~= old_uri then + local old_name = changetracking._get_and_set_name(client, bufnr, name) + if old_name and name ~= old_name then client.notify('textDocument/didClose', { textDocument = { - uri = old_uri, + uri = vim.uri_from_fname(old_name), }, }) client.notify('textDocument/didOpen', { @@ -1720,12 +1700,8 @@ function lsp.buf_attach_client(bufnr, client_id) end) end, on_detach = function() + local params = { textDocument = { uri = uri } } for_each_buffer_client(bufnr, function(client, _) - local params = { - textDocument = { - uri = changetracking._get_uri(client, bufnr), - }, - } changetracking.reset_buf(client, bufnr) if vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'openClose') then client.notify('textDocument/didClose', params) @@ -1962,7 +1938,7 @@ api.nvim_create_autocmd('VimLeavePre', { ---@param bufnr (integer) Buffer handle, or 0 for current. ---@param method (string) LSP method name ---@param params table|nil Parameters to send to the server ----@param handler function|nil See |lsp-handler| +---@param handler lsp-handler|nil See |lsp-handler| --- If nil, follows resolution strategy defined in |lsp-handler-configuration| --- ---@return table<integer, integer>, fun() 2-tuple: @@ -2022,9 +1998,10 @@ end ---@param bufnr (integer) Buffer handle, or 0 for current. ---@param method (string) LSP method name ---@param params (table|nil) Parameters to send to the server ----@param callback (function) The callback to call when all requests are finished. +---@param callback fun(request_results: table<integer, {error: lsp.ResponseError, result: any}>) (function) +--- The callback to call when all requests are finished. --- Unlike `buf_request`, this will collect all the responses from each server instead of handling them. ---- A map of client_id:request_result will be provided to the callback +--- A map of client_id:request_result will be provided to the callback. --- ---@return fun() cancel A function that will cancel all requests function lsp.buf_request_all(bufnr, method, params, callback) @@ -2067,9 +2044,8 @@ end ---@param timeout_ms (integer|nil) Maximum time in milliseconds to wait for a --- result. Defaults to 1000 --- ----@return table<integer, any>|nil result, string|nil err Map of client_id:request_result. ---- On timeout, cancel or error, returns `(nil, err)` where `err` is a string describing ---- the failure reason. +---@return table<integer, {err: lsp.ResponseError, result: any}>|nil (table) result Map of client_id:request_result. +---@return string|nil err On timeout, cancel, or error, `err` is a string describing the failure reason, and `result` is nil. function lsp.buf_request_sync(bufnr, method, params, timeout_ms) local request_results diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index 27dd68645a..1686e22c48 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -854,7 +854,6 @@ function protocol.make_client_capabilities() } end -local if_nil = vim.F.if_nil --- Creates a normalized object describing LSP server capabilities. ---@param server_capabilities table Table of capabilities supported by the server ---@return table Normalized table of capabilities @@ -892,178 +891,5 @@ function protocol.resolve_capabilities(server_capabilities) return server_capabilities end ----@private ---- Creates a normalized object describing LSP server capabilities. --- @deprecated access resolved_capabilities instead ----@param server_capabilities table Table of capabilities supported by the server ----@return table Normalized table of capabilities -function protocol._resolve_capabilities_compat(server_capabilities) - local general_properties = {} - local text_document_sync_properties - do - local TextDocumentSyncKind = protocol.TextDocumentSyncKind - local textDocumentSync = server_capabilities.textDocumentSync - if textDocumentSync == nil then - -- Defaults if omitted. - text_document_sync_properties = { - text_document_open_close = false, - text_document_did_change = TextDocumentSyncKind.None, - -- text_document_did_change = false; - text_document_will_save = false, - text_document_will_save_wait_until = false, - text_document_save = false, - text_document_save_include_text = false, - } - elseif type(textDocumentSync) == 'number' then - -- Backwards compatibility - if not TextDocumentSyncKind[textDocumentSync] then - return nil, 'Invalid server TextDocumentSyncKind for textDocumentSync' - end - text_document_sync_properties = { - text_document_open_close = true, - text_document_did_change = textDocumentSync, - text_document_will_save = false, - text_document_will_save_wait_until = false, - text_document_save = true, - text_document_save_include_text = false, - } - elseif type(textDocumentSync) == 'table' then - text_document_sync_properties = { - text_document_open_close = if_nil(textDocumentSync.openClose, false), - text_document_did_change = if_nil(textDocumentSync.change, TextDocumentSyncKind.None), - text_document_will_save = if_nil(textDocumentSync.willSave, true), - text_document_will_save_wait_until = if_nil(textDocumentSync.willSaveWaitUntil, true), - text_document_save = if_nil(textDocumentSync.save, false), - text_document_save_include_text = if_nil( - type(textDocumentSync.save) == 'table' and textDocumentSync.save.includeText, - false - ), - } - else - return nil, string.format('Invalid type for textDocumentSync: %q', type(textDocumentSync)) - end - end - general_properties.completion = server_capabilities.completionProvider ~= nil - general_properties.hover = server_capabilities.hoverProvider or false - general_properties.goto_definition = server_capabilities.definitionProvider or false - general_properties.find_references = server_capabilities.referencesProvider or false - general_properties.document_highlight = server_capabilities.documentHighlightProvider or false - general_properties.document_symbol = server_capabilities.documentSymbolProvider or false - general_properties.workspace_symbol = server_capabilities.workspaceSymbolProvider or false - general_properties.document_formatting = server_capabilities.documentFormattingProvider or false - general_properties.document_range_formatting = server_capabilities.documentRangeFormattingProvider - or false - general_properties.call_hierarchy = server_capabilities.callHierarchyProvider or false - general_properties.execute_command = server_capabilities.executeCommandProvider ~= nil - - if server_capabilities.renameProvider == nil then - general_properties.rename = false - elseif type(server_capabilities.renameProvider) == 'boolean' then - general_properties.rename = server_capabilities.renameProvider - else - general_properties.rename = true - end - - if server_capabilities.codeLensProvider == nil then - general_properties.code_lens = false - general_properties.code_lens_resolve = false - elseif type(server_capabilities.codeLensProvider) == 'table' then - general_properties.code_lens = true - general_properties.code_lens_resolve = server_capabilities.codeLensProvider.resolveProvider - or false - else - error('The server sent invalid codeLensProvider') - end - - if server_capabilities.codeActionProvider == nil then - general_properties.code_action = false - elseif - type(server_capabilities.codeActionProvider) == 'boolean' - or type(server_capabilities.codeActionProvider) == 'table' - then - general_properties.code_action = server_capabilities.codeActionProvider - else - error('The server sent invalid codeActionProvider') - end - - if server_capabilities.declarationProvider == nil then - general_properties.declaration = false - elseif type(server_capabilities.declarationProvider) == 'boolean' then - general_properties.declaration = server_capabilities.declarationProvider - elseif type(server_capabilities.declarationProvider) == 'table' then - general_properties.declaration = server_capabilities.declarationProvider - else - error('The server sent invalid declarationProvider') - end - - if server_capabilities.typeDefinitionProvider == nil then - general_properties.type_definition = false - elseif type(server_capabilities.typeDefinitionProvider) == 'boolean' then - general_properties.type_definition = server_capabilities.typeDefinitionProvider - elseif type(server_capabilities.typeDefinitionProvider) == 'table' then - general_properties.type_definition = server_capabilities.typeDefinitionProvider - else - error('The server sent invalid typeDefinitionProvider') - end - - if server_capabilities.implementationProvider == nil then - general_properties.implementation = false - elseif type(server_capabilities.implementationProvider) == 'boolean' then - general_properties.implementation = server_capabilities.implementationProvider - elseif type(server_capabilities.implementationProvider) == 'table' then - general_properties.implementation = server_capabilities.implementationProvider - else - error('The server sent invalid implementationProvider') - end - - local workspace = server_capabilities.workspace - local workspace_properties = {} - if workspace == nil or workspace.workspaceFolders == nil then - -- Defaults if omitted. - workspace_properties = { - workspace_folder_properties = { - supported = false, - changeNotifications = false, - }, - } - elseif type(workspace.workspaceFolders) == 'table' then - workspace_properties = { - workspace_folder_properties = { - supported = if_nil(workspace.workspaceFolders.supported, false), - changeNotifications = if_nil(workspace.workspaceFolders.changeNotifications, false), - }, - } - else - error('The server sent invalid workspace') - end - - local signature_help_properties - if server_capabilities.signatureHelpProvider == nil then - signature_help_properties = { - signature_help = false, - signature_help_trigger_characters = {}, - } - elseif type(server_capabilities.signatureHelpProvider) == 'table' then - signature_help_properties = { - signature_help = true, - -- The characters that trigger signature help automatically. - signature_help_trigger_characters = server_capabilities.signatureHelpProvider.triggerCharacters - or {}, - } - else - error('The server sent invalid signatureHelpProvider') - end - - local capabilities = vim.tbl_extend( - 'error', - text_document_sync_properties, - signature_help_properties, - workspace_properties, - general_properties - ) - - return capabilities -end - return protocol -- vim:sw=2 ts=2 et diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index c9613dc7a7..342fad33c2 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -2032,12 +2032,7 @@ end ---@returns `TextDocumentIdentifier` ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier function M.make_text_document_params(bufnr) - bufnr = bufnr or 0 - local uri = vim.uri_from_bufnr(bufnr) - if not uv.fs_stat(api.nvim_buf_get_name(bufnr)) then - uri = uri:gsub('^file://', 'buffer://') - end - return { uri = uri } + return { uri = vim.uri_from_bufnr(bufnr or 0) } end --- Create the workspace params @@ -2070,7 +2065,7 @@ function M.make_formatting_params(options) insertSpaces = vim.bo.expandtab, }) return { - textDocument = M.make_text_document_params(0), + textDocument = { uri = vim.uri_from_bufnr(0) }, options = options, } end diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index 6869fae92c..bdfe281a5b 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -228,7 +228,6 @@ end --- determine if any child languages should be created. --- ---@return TSTree[] ----@return table|nil Change list function LanguageTree:parse() if self:is_valid() then self:_log('valid') @@ -302,18 +301,12 @@ function LanguageTree:parse() }) self:for_each_child(function(child) - local _, child_changes = child:parse() - - -- Propagate any child changes so they are included in the - -- the change list for the callback. - if child_changes then - vim.list_extend(changes, child_changes) - end + child:parse() end) self._valid = true - return self._trees, changes + return self._trees end --- Invokes the callback for each |LanguageTree| and its children recursively diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index b02c740471..edd0b178d4 100755 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -393,6 +393,7 @@ get_target_property(prop main_lib INTERFACE_INCLUDE_DIRECTORIES) foreach(gen_include ${prop}) list(APPEND gen_cflags "-I${gen_include}") endforeach() +list(APPEND gen_cflags "-I${DEPS_PREFIX}/include") if(APPLE AND CMAKE_OSX_SYSROOT) list(APPEND gen_cflags "-isysroot") list(APPEND gen_cflags "${CMAKE_OSX_SYSROOT}") diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 32378ed244..de766c14b9 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -938,10 +938,11 @@ static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdin /// - force: (boolean, default true) Override any previous definition. /// - preview: (function) Preview callback for 'inccommand' |:command-preview| /// @param[out] err Error details, if any. -void nvim_create_user_command(String name, Object command, Dict(user_command) *opts, Error *err) +void nvim_create_user_command(uint64_t channel_id, String name, Object command, + Dict(user_command) *opts, Error *err) FUNC_API_SINCE(9) { - create_user_command(name, command, opts, 0, err); + create_user_command(channel_id, name, command, opts, 0, err); } /// Delete a user-defined command. @@ -959,7 +960,7 @@ void nvim_del_user_command(String name, Error *err) /// @param buffer Buffer handle, or 0 for current buffer. /// @param[out] err Error details, if any. /// @see nvim_create_user_command -void nvim_buf_create_user_command(Buffer buffer, String name, Object command, +void nvim_buf_create_user_command(uint64_t channel_id, Buffer buffer, String name, Object command, Dict(user_command) *opts, Error *err) FUNC_API_SINCE(9) { @@ -970,7 +971,7 @@ void nvim_buf_create_user_command(Buffer buffer, String name, Object command, buf_T *save_curbuf = curbuf; curbuf = target_buf; - create_user_command(name, command, opts, UC_BUFFER, err); + create_user_command(channel_id, name, command, opts, UC_BUFFER, err); curbuf = save_curbuf; } @@ -1011,8 +1012,8 @@ void nvim_buf_del_user_command(Buffer buffer, String name, Error *err) api_set_error(err, kErrorTypeException, "Invalid command (not found): %s", name.data); } -void create_user_command(String name, Object command, Dict(user_command) *opts, int flags, - Error *err) +void create_user_command(uint64_t channel_id, String name, Object command, Dict(user_command) *opts, + int flags, Error *err) { uint32_t argt = 0; int64_t def = -1; @@ -1205,11 +1206,13 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, }); } - if (uc_add_command(name.data, name.size, rep, argt, def, flags, compl, compl_arg, compl_luaref, - preview_luaref, addr_type_arg, luaref, force) != OK) { - api_set_error(err, kErrorTypeException, "Failed to create user command"); - // Do not goto err, since uc_add_command now owns luaref, compl_luaref, and compl_arg - } + WITH_SCRIPT_CONTEXT(channel_id, { + if (uc_add_command(name.data, name.size, rep, argt, def, flags, compl, compl_arg, compl_luaref, + preview_luaref, addr_type_arg, luaref, force) != OK) { + api_set_error(err, kErrorTypeException, "Failed to create user command"); + // Do not goto err, since uc_add_command now owns luaref, compl_luaref, and compl_arg + } + }); return; diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index ddaed3a254..2d9ffcba06 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -157,7 +157,8 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) /// - win: |window-ID|. Used for setting window local option. /// - buf: Buffer number. Used for setting buffer local option. /// @param[out] err Error details, if any -void nvim_set_option_value(String name, Object value, Dict(option) *opts, Error *err) +void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict(option) *opts, + Error *err) FUNC_API_SINCE(9) { int scope = 0; @@ -202,7 +203,9 @@ void nvim_set_option_value(String name, Object value, Dict(option) *opts, Error }); } - access_option_value_for(name.data, &numval, &stringval, scope, opt_type, to, false, err); + WITH_SCRIPT_CONTEXT(channel_id, { + access_option_value_for(name.data, &numval, &stringval, scope, opt_type, to, false, err); + }); } /// Gets the option information for all options. diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 0f27040fd3..315ccd13e6 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -579,7 +579,7 @@ ArrayOf(String) nvim__get_runtime(Array pat, Boolean all, Dict(runtime) *opts, E if (source) { for (size_t i = 0; i < res.size; i++) { String name = res.items[i].data.string; - (void)do_source(name.data, false, DOSO_NONE); + (void)do_source(name.data, false, DOSO_NONE, NULL); } } diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 289939b2ca..52c5732f23 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -3136,7 +3136,7 @@ static void diffgetput(const int addr_count, const int idx_cur, const int idx_fr if (added != 0) { // Adjust marks. This will change the following entries! - mark_adjust(lnum, lnum + count - 1, (long)MAXLNUM, added, kExtmarkUndo); + mark_adjust(lnum, lnum + count - 1, (long)MAXLNUM, added, kExtmarkNOOP); if (curwin->w_cursor.lnum >= lnum) { // Adjust the cursor position if it's in/after the changed // lines. diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 9eb4802d97..6e8dc8fc02 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1510,14 +1510,14 @@ bool prompt_curpos_editable(void) // Undo the previous edit_putchar(). void edit_unputchar(void) { - if (pc_status != PC_STATUS_UNSET && pc_row >= msg_scrolled) { + if (pc_status != PC_STATUS_UNSET) { if (pc_status == PC_STATUS_RIGHT) { curwin->w_wcol++; } if (pc_status == PC_STATUS_RIGHT || pc_status == PC_STATUS_LEFT) { redrawWinline(curwin, curwin->w_cursor.lnum); } else { - grid_puts(&curwin->w_grid, pc_bytes, pc_row - msg_scrolled, pc_col, pc_attr); + grid_puts(&curwin->w_grid, pc_bytes, pc_row, pc_col, pc_attr); } } } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 9b42375120..384e088bcf 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -114,9 +114,6 @@ bool *eval_lavars_used = NULL; static int echo_attr = 0; // attributes used for ":echo" -// The names of packages that once were loaded are remembered. -static garray_T ga_loaded = { 0, 0, sizeof(char *), 4, NULL }; - /// Info used by a ":for" loop. typedef struct { int fi_semicolon; // true if ending in '; var]' @@ -503,7 +500,7 @@ void eval_clear(void) # endif // autoloaded script names - ga_clear_strings(&ga_loaded); + free_autoload_scriptnames(); // unreferenced lists and dicts (void)garbage_collect(false); @@ -7530,80 +7527,6 @@ const char *find_option_end(const char **const arg, int *const scope) return p; } -/// Return the autoload script name for a function or variable name -/// Caller must make sure that "name" contains AUTOLOAD_CHAR. -/// -/// @param[in] name Variable/function name. -/// @param[in] name_len Name length. -/// -/// @return [allocated] autoload script name. -char *autoload_name(const char *const name, const size_t name_len) - FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT -{ - // Get the script file name: replace '#' with '/', append ".vim". - char *const scriptname = xmalloc(name_len + sizeof("autoload/.vim")); - memcpy(scriptname, "autoload/", sizeof("autoload/") - 1); - memcpy(scriptname + sizeof("autoload/") - 1, name, name_len); - size_t auchar_idx = 0; - for (size_t i = sizeof("autoload/") - 1; - i - sizeof("autoload/") + 1 < name_len; - i++) { - if (scriptname[i] == AUTOLOAD_CHAR) { - scriptname[i] = '/'; - auchar_idx = i; - } - } - memcpy(scriptname + auchar_idx, ".vim", sizeof(".vim")); - - return scriptname; -} - -/// If name has a package name try autoloading the script for it -/// -/// @param[in] name Variable/function name. -/// @param[in] name_len Name length. -/// @param[in] reload If true, load script again when already loaded. -/// -/// @return true if a package was loaded. -bool script_autoload(const char *const name, const size_t name_len, const bool reload) -{ - // If there is no '#' after name[0] there is no package name. - const char *p = memchr(name, AUTOLOAD_CHAR, name_len); - if (p == NULL || p == name) { - return false; - } - - bool ret = false; - char *tofree = autoload_name(name, name_len); - char *scriptname = tofree; - - // Find the name in the list of previously loaded package names. Skip - // "autoload/", it's always the same. - int i = 0; - for (; i < ga_loaded.ga_len; i++) { - if (strcmp(((char **)ga_loaded.ga_data)[i] + 9, scriptname + 9) == 0) { - break; - } - } - if (!reload && i < ga_loaded.ga_len) { - ret = false; // Was loaded already. - } else { - // Remember the name if it wasn't loaded already. - if (i == ga_loaded.ga_len) { - GA_APPEND(char *, &ga_loaded, scriptname); - tofree = NULL; - } - - // Try loading the package from $VIMRUNTIME/autoload/<name>.vim - if (source_runtime(scriptname, 0) == OK) { - ret = true; - } - } - - xfree(tofree); - return ret; -} - static var_flavour_T var_flavour(char *varname) FUNC_ATTR_PURE { diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index ae10a7e035..66032adbaf 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -189,6 +189,7 @@ return { gettabinfo={args={0, 1}, base=1}, gettabvar={args={2, 3}, base=1}, gettabwinvar={args={3, 4}, base=1}, + getscriptinfo={}, gettagstack={args={0, 1}, base=1}, gettext={args=1, base=1}, getwininfo={args={0, 1}, base=1}, diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c index 8e3e68d9b7..855a5f7538 100644 --- a/src/nvim/ex_session.c +++ b/src/nvim/ex_session.c @@ -909,7 +909,7 @@ void ex_loadview(exarg_T *eap) return; } - if (do_source(fname, false, DOSO_NONE) == FAIL) { + if (do_source(fname, false, DOSO_NONE, NULL) == FAIL) { semsg(_(e_notopen), fname); } xfree(fname); diff --git a/src/nvim/generators/gen_eval.lua b/src/nvim/generators/gen_eval.lua index baed6a74c2..fb1dd82a26 100644 --- a/src/nvim/generators/gen_eval.lua +++ b/src/nvim/generators/gen_eval.lua @@ -48,6 +48,7 @@ hashpipe:write([[ #include "nvim/menu.h" #include "nvim/move.h" #include "nvim/quickfix.h" +#include "nvim/runtime.h" #include "nvim/search.h" #include "nvim/sign.h" #include "nvim/testing.h" diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h index 95c81ac9db..a5586659c7 100644 --- a/src/nvim/highlight_defs.h +++ b/src/nvim/highlight_defs.h @@ -100,6 +100,10 @@ typedef enum { HLF_SPL, // SpellLocal HLF_PNI, // popup menu normal item HLF_PSI, // popup menu selected item + HLF_PNK, // popup menu normal item "kind" + HLF_PSK, // popup menu selected item "kind" + HLF_PNX, // popup menu normal item "menu" (extra text) + HLF_PSX, // popup menu selected item "menu" (extra text) HLF_PSB, // popup menu scrollbar HLF_PST, // popup menu scrollbar thumb HLF_TP, // tabpage line @@ -165,6 +169,10 @@ EXTERN const char *hlf_names[] INIT(= { [HLF_SPL] = "SpellLocal", [HLF_PNI] = "Pmenu", [HLF_PSI] = "PmenuSel", + [HLF_PNK] = "PmenuKind", + [HLF_PSK] = "PmenuKindSel", + [HLF_PNX] = "PmenuExtra", + [HLF_PSX] = "PmenuExtraSel", [HLF_PSB] = "PmenuSbar", [HLF_PST] = "PmenuThumb", [HLF_TP] = "TabLine", diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c index 70ee6c757c..5d8649b429 100644 --- a/src/nvim/highlight_group.c +++ b/src/nvim/highlight_group.c @@ -150,6 +150,10 @@ static const char *highlight_init_both[] = { "default link QuickFixLine Search", "default link CursorLineSign SignColumn", "default link CursorLineFold FoldColumn", + "default link PmenuKind Pmenu", + "default link PmenuKindSel PmenuSel", + "default link PmenuExtra Pmenu", + "default link PmenuExtraSel PmenuSel", "default link Substitute Search", "default link Whitespace NonText", "default link MsgSeparator StatusLine", diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 078bc4fea9..11a02ea402 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -2061,10 +2061,15 @@ void nlua_set_sctx(sctx_T *current) break; } char *source_path = fix_fname(info->source + 1); - get_current_script_id(&source_path, current); - xfree(source_path); - current->sc_lnum = info->currentline; + int sid = find_script_by_name(source_path); + if (sid > 0) { + xfree(source_path); + } else { + new_script_item(source_path, &sid); + } + current->sc_sid = sid; current->sc_seq = -1; + current->sc_lnum = info->currentline; cleanup: xfree(info); diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index b6e56c35d6..852e10c8d8 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -22,7 +22,6 @@ #include "nvim/api/private/helpers.h" #include "nvim/ascii.h" #include "nvim/buffer_defs.h" -#include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/ex_eval.h" @@ -38,6 +37,7 @@ #include "nvim/memory.h" #include "nvim/pos.h" #include "nvim/regexp.h" +#include "nvim/runtime.h" #include "nvim/types.h" #include "nvim/vim.h" diff --git a/src/nvim/main.c b/src/nvim/main.c index be1714b207..ea5f511fc6 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -1937,7 +1937,7 @@ static void do_system_initialization(void) dir_len += 1; } memcpy(vimrc + dir_len, path_tail, sizeof(path_tail)); - if (do_source(vimrc, false, DOSO_NONE) != FAIL) { + if (do_source(vimrc, false, DOSO_NONE, NULL) != FAIL) { xfree(vimrc); xfree(config_dirs); return; @@ -1949,7 +1949,7 @@ static void do_system_initialization(void) #ifdef SYS_VIMRC_FILE // Get system wide defaults, if the file name is defined. - (void)do_source(SYS_VIMRC_FILE, false, DOSO_NONE); + (void)do_source(SYS_VIMRC_FILE, false, DOSO_NONE, NULL); #endif } @@ -1978,7 +1978,7 @@ static bool do_user_initialization(void) // init.lua if (os_path_exists(init_lua_path) - && do_source(init_lua_path, true, DOSO_VIMRC)) { + && do_source(init_lua_path, true, DOSO_VIMRC, NULL)) { if (os_path_exists(user_vimrc)) { semsg(_("E5422: Conflicting configs: \"%s\" \"%s\""), init_lua_path, user_vimrc); @@ -1992,7 +1992,7 @@ static bool do_user_initialization(void) xfree(init_lua_path); // init.vim - if (do_source(user_vimrc, true, DOSO_VIMRC) != FAIL) { + if (do_source(user_vimrc, true, DOSO_VIMRC, NULL) != FAIL) { do_exrc = p_exrc; if (do_exrc) { do_exrc = (path_full_compare(VIMRC_FILE, user_vimrc, false, true) != kEqualFiles); @@ -2018,7 +2018,7 @@ static bool do_user_initialization(void) memmove(vimrc, dir, dir_len); vimrc[dir_len] = PATHSEP; memmove(vimrc + dir_len + 1, path_tail, sizeof(path_tail)); - if (do_source(vimrc, true, DOSO_VIMRC) != FAIL) { + if (do_source(vimrc, true, DOSO_VIMRC, NULL) != FAIL) { do_exrc = p_exrc; if (do_exrc) { do_exrc = (path_full_compare(VIMRC_FILE, vimrc, false, true) != kEqualFiles); @@ -2084,7 +2084,7 @@ static void source_startup_scripts(const mparm_T *const parmp) || strequal(parmp->use_vimrc, "NORC")) { // Do nothing. } else { - if (do_source(parmp->use_vimrc, false, DOSO_NONE) != OK) { + if (do_source(parmp->use_vimrc, false, DOSO_NONE, NULL) != OK) { semsg(_("E282: Cannot read from \"%s\""), parmp->use_vimrc); } } diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 0c78d7ada5..470eae2090 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -92,8 +92,9 @@ typedef enum { "N:CursorLineNr,G:CursorLineSign,O:CursorLineFold" \ "r:Question,s:StatusLine,S:StatusLineNC,c:VertSplit,t:Title,v:Visual,V:VisualNOS,w:WarningMsg," \ "W:WildMenu,f:Folded,F:FoldColumn,A:DiffAdd,C:DiffChange,D:DiffDelete,T:DiffText,>:SignColumn," \ - "-:Conceal,B:SpellBad,P:SpellCap,R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel,x:PmenuSbar," \ - "X:PmenuThumb,*:TabLine,#:TabLineSel,_:TabLineFill,!:CursorColumn,.:CursorLine,o:ColorColumn," \ + "-:Conceal,B:SpellBad,P:SpellCap,R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel," \ + "[:PmenuKind,]:PmenuKindSel,{:PmenuExtra,}:PmenuExtraSel,x:PmenuSbar,X:PmenuThumb," \ + "*:TabLine,#:TabLineSel,_:TabLineFill,!:CursorColumn,.:CursorLine,o:ColorColumn," \ "q:QuickFixLine,0:Whitespace,I:NormalNC" // Default values for 'errorformat'. diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index cdf8d5720b..8db36e594c 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -407,8 +407,6 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i void pum_redraw(void) { int row = 0; - int attr_norm = win_hl_attr(curwin, HLF_PNI); - int attr_select = win_hl_attr(curwin, HLF_PSI); int attr_scroll = win_hl_attr(curwin, HLF_PSB); int attr_thumb = win_hl_attr(curwin, HLF_PST); int i; @@ -418,9 +416,14 @@ void pum_redraw(void) int w; int thumb_pos = 0; int thumb_height = 1; - int round; int n; +#define HA(hlf) (win_hl_attr(curwin, (hlf))) + // "word" "kind" "extra text" + const int attrsNorm[3] = { HA(HLF_PNI), HA(HLF_PNK), HA(HLF_PNX) }; + const int attrsSel[3] = { HA(HLF_PSI), HA(HLF_PSK), HA(HLF_PSX) }; +#undef HA + int grid_width = pum_width; int col_off = 0; bool extra_space = false; @@ -482,7 +485,8 @@ void pum_redraw(void) for (i = 0; i < pum_height; i++) { int idx = i + pum_first; - int attr = (idx == pum_selected) ? attr_select : attr_norm; + const int *const attrs = (idx == pum_selected) ? attrsSel : attrsNorm; + int attr = attrs[0]; // start with "word" highlight grid_puts_line_start(&pum_grid, row); @@ -496,26 +500,25 @@ void pum_redraw(void) } // Display each entry, use two spaces for a Tab. - // Do this 3 times: For the main text, kind and extra info + // Do this 3 times: + // 0 - main text + // 1 - kind + // 2 - extra info int grid_col = col_off; int totwidth = 0; - for (round = 1; round <= 3; round++) { + for (int round = 0; round < 3; round++) { + attr = attrs[round]; width = 0; s = NULL; switch (round) { + case 0: + p = pum_array[idx].pum_text; break; case 1: - p = pum_array[idx].pum_text; - break; - + p = pum_array[idx].pum_kind; break; case 2: - p = pum_array[idx].pum_kind; - break; - - case 3: - p = pum_array[idx].pum_extra; - break; + p = pum_array[idx].pum_extra; break; } if (p != NULL) { @@ -592,17 +595,17 @@ void pum_redraw(void) } } - if (round > 1) { + if (round > 0) { n = pum_kind_width + 1; } else { n = 1; } // Stop when there is nothing more to display. - if ((round == 3) - || ((round == 2) - && (pum_array[idx].pum_extra == NULL)) + if ((round == 2) || ((round == 1) + && (pum_array[idx].pum_extra == NULL)) + || ((round == 0) && (pum_array[idx].pum_kind == NULL) && (pum_array[idx].pum_extra == NULL)) || (pum_base_width + n >= pum_width)) { diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index a6ed95ec64..c9667d58ed 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -75,6 +75,11 @@ struct source_cookie { garray_T exestack = { 0, 0, sizeof(estack_T), 50, NULL }; garray_T script_items = { 0, 0, sizeof(scriptitem_T *), 20, NULL }; +/// The names of packages that once were loaded are remembered. +static garray_T ga_loaded = { 0, 0, sizeof(char *), 4, NULL }; + +static int last_current_SID_seq = 0; + /// Initialize the execution stack. void estack_init(void) { @@ -263,7 +268,7 @@ void set_context_in_runtime_cmd(expand_T *xp, const char *arg) static void source_callback(char *fname, void *cookie) { - (void)do_source(fname, false, DOSO_NONE); + (void)do_source(fname, false, DOSO_NONE, cookie); } /// Find the file "name" in all directories in "path" and invoke @@ -852,7 +857,7 @@ static void source_all_matches(char *pat) } for (int i = 0; i < num_files; i++) { - (void)do_source(files[i], false, DOSO_NONE); + (void)do_source(files[i], false, DOSO_NONE, NULL); } FreeWild(num_files, files); } @@ -1698,7 +1703,7 @@ static void cmd_source(char *fname, exarg_T *eap) || eap->cstack->cs_idx >= 0); // ":source" read ex commands - } else if (do_source(fname, false, DOSO_NONE) == FAIL) { + } else if (do_source(fname, false, DOSO_NONE, NULL) == FAIL) { semsg(_(e_notopen), fname); } } @@ -1951,9 +1956,12 @@ int do_source_str(const char *cmd, const char *traceback_name) /// @param fname /// @param check_other check for .vimrc and _vimrc /// @param is_vimrc DOSO_ value +/// @param ret_sid if not NULL and we loaded the script before, don't load it again /// /// @return FAIL if file could not be opened, OK otherwise -int do_source(char *fname, int check_other, int is_vimrc) +/// +/// If a scriptitem_T was found or created "*ret_sid" is set to the SID. +int do_source(char *fname, int check_other, int is_vimrc, int *ret_sid) { struct source_cookie cookie; char *p; @@ -1979,6 +1987,15 @@ int do_source(char *fname, int check_other, int is_vimrc) goto theend; } + // See if we loaded this script before. + int sid = find_script_by_name(fname_exp); + if (sid > 0 && ret_sid != NULL) { + // Already loaded and no need to load again, return here. + *ret_sid = sid; + retval = OK; + goto theend; + } + // Apply SourceCmd autocommands, they should get the file and source it. if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL) && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp, @@ -2077,7 +2094,24 @@ int do_source(char *fname, int check_other, int is_vimrc) save_funccal(&funccalp_entry); const sctx_T save_current_sctx = current_sctx; - si = get_current_script_id(&fname_exp, ¤t_sctx); + + current_sctx.sc_lnum = 0; + + // Always use a new sequence number. + current_sctx.sc_seq = ++last_current_SID_seq; + + if (sid > 0) { + // loading the same script again + si = SCRIPT_ITEM(sid); + } else { + // It's new, generate a new SID. + si = new_script_item(fname_exp, &sid); + fname_exp = xstrdup(si->sn_name); // used for autocmd + if (ret_sid != NULL) { + *ret_sid = sid; + } + } + current_sctx.sc_sid = sid; // Keep the sourcing name/lnum, for recursive calls. estack_push(ETYPE_SCRIPT, si->sn_name, 0); @@ -2187,42 +2221,23 @@ theend: return retval; } -/// Check if fname was sourced before to finds its SID. -/// If it's new, generate a new SID. -/// -/// @param[in,out] fnamep pointer to file path of script -/// @param[out] ret_sctx sctx of this script -scriptitem_T *get_current_script_id(char **fnamep, sctx_T *ret_sctx) +/// Find an already loaded script "name". +/// If found returns its script ID. If not found returns -1. +int find_script_by_name(char *name) { - static int last_current_SID_seq = 0; - - sctx_T script_sctx = { .sc_seq = ++last_current_SID_seq, - .sc_lnum = 0, - .sc_sid = 0 }; - scriptitem_T *si = NULL; - assert(script_items.ga_len >= 0); - for (script_sctx.sc_sid = script_items.ga_len; script_sctx.sc_sid > 0; script_sctx.sc_sid--) { + for (int sid = script_items.ga_len; sid > 0; sid--) { // We used to check inode here, but that doesn't work: // - If a script is edited and written, it may get a different // inode number, even though to the user it is the same script. // - If a script is deleted and another script is written, with a // different name, the inode may be re-used. - si = SCRIPT_ITEM(script_sctx.sc_sid); - if (si->sn_name != NULL && path_fnamecmp(si->sn_name, *fnamep) == 0) { - // Found it! - break; + scriptitem_T *si = SCRIPT_ITEM(sid); + if (si->sn_name != NULL && path_fnamecmp(si->sn_name, name) == 0) { + return sid; } } - if (script_sctx.sc_sid == 0) { - si = new_script_item(*fnamep, &script_sctx.sc_sid); - *fnamep = xstrdup(si->sn_name); - } - if (ret_sctx != NULL) { - *ret_sctx = script_sctx; - } - - return si; + return -1; } /// ":scriptnames" @@ -2329,6 +2344,11 @@ void free_scriptnames(void) } #endif +void free_autoload_scriptnames(void) +{ + ga_clear_strings(&ga_loaded); +} + linenr_T get_sourced_lnum(LineGetter fgetline, void *cookie) FUNC_ATTR_PURE { @@ -2337,6 +2357,29 @@ linenr_T get_sourced_lnum(LineGetter fgetline, void *cookie) : SOURCING_LNUM; } +/// "getscriptinfo()" function +void f_getscriptinfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + tv_list_alloc_ret(rettv, script_items.ga_len); + + list_T *l = rettv->vval.v_list; + + for (int i = 1; i <= script_items.ga_len; i++) { + scriptitem_T *si = SCRIPT_ITEM(i); + + if (si->sn_name == NULL) { + continue; + } + + dict_T *d = tv_dict_alloc(); + tv_list_append_dict(l, d); + tv_dict_add_str(d, S_LEN("name"), si->sn_name); + tv_dict_add_nr(d, S_LEN("sid"), i); + // Vim9 autoload script (:h vim9-autoload), not applicable to Nvim. + tv_dict_add_bool(d, S_LEN("autoload"), false); + } +} + /// Get one full line from a sourced file. /// Called by do_cmdline() when it's called from do_source(). /// @@ -2597,3 +2640,79 @@ bool source_finished(LineGetter fgetline, void *cookie) return getline_equal(fgetline, cookie, getsourceline) && ((struct source_cookie *)getline_cookie(fgetline, cookie))->finished; } + +/// Return the autoload script name for a function or variable name +/// Caller must make sure that "name" contains AUTOLOAD_CHAR. +/// +/// @param[in] name Variable/function name. +/// @param[in] name_len Name length. +/// +/// @return [allocated] autoload script name. +char *autoload_name(const char *const name, const size_t name_len) + FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT +{ + // Get the script file name: replace '#' with '/', append ".vim". + char *const scriptname = xmalloc(name_len + sizeof("autoload/.vim")); + memcpy(scriptname, "autoload/", sizeof("autoload/") - 1); + memcpy(scriptname + sizeof("autoload/") - 1, name, name_len); + size_t auchar_idx = 0; + for (size_t i = sizeof("autoload/") - 1; + i - sizeof("autoload/") + 1 < name_len; + i++) { + if (scriptname[i] == AUTOLOAD_CHAR) { + scriptname[i] = '/'; + auchar_idx = i; + } + } + memcpy(scriptname + auchar_idx, ".vim", sizeof(".vim")); + + return scriptname; +} + +/// If name has a package name try autoloading the script for it +/// +/// @param[in] name Variable/function name. +/// @param[in] name_len Name length. +/// @param[in] reload If true, load script again when already loaded. +/// +/// @return true if a package was loaded. +bool script_autoload(const char *const name, const size_t name_len, const bool reload) +{ + // If there is no '#' after name[0] there is no package name. + const char *p = memchr(name, AUTOLOAD_CHAR, name_len); + if (p == NULL || p == name) { + return false; + } + + bool ret = false; + char *tofree = autoload_name(name, name_len); + char *scriptname = tofree; + + // Find the name in the list of previously loaded package names. Skip + // "autoload/", it's always the same. + int i = 0; + for (; i < ga_loaded.ga_len; i++) { + if (strcmp(((char **)ga_loaded.ga_data)[i] + 9, scriptname + 9) == 0) { + break; + } + } + if (!reload && i < ga_loaded.ga_len) { + ret = false; // Was loaded already. + } else { + // Remember the name if it wasn't loaded already. + if (i == ga_loaded.ga_len) { + GA_APPEND(char *, &ga_loaded, scriptname); + tofree = NULL; + } + + // Try loading the package from $VIMRUNTIME/autoload/<name>.vim + // Use "ret_sid" to avoid loading the same script again. + int ret_sid; + if (do_in_runtimepath(scriptname, 0, source_callback, &ret_sid) == OK) { + ret = true; + } + } + + xfree(tofree); + return ret; +} diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index d4161b9ca2..14fef19399 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -4026,7 +4026,7 @@ static void syn_cmd_include(exarg_T *eap, int syncing) prev_toplvl_grp = curwin->w_s->b_syn_topgrp; curwin->w_s->b_syn_topgrp = sgl_id; if (source - ? do_source(eap->arg, false, DOSO_NONE) == FAIL + ? do_source(eap->arg, false, DOSO_NONE, NULL) == FAIL : source_runtime(eap->arg, DIP_ALL) == FAIL) { semsg(_(e_notopen), eap->arg); } diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 08abf82f47..48ac491ade 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -2832,6 +2832,24 @@ describe('API', function() type = "boolean", was_set = true }, meths.get_option_info'showcmd') + + meths.set_option_value('showcmd', true, {}) + + eq({ + allows_duplicates = true, + commalist = false, + default = true, + flaglist = false, + global_local = false, + last_set_chan = 1, + last_set_linenr = 0, + last_set_sid = -9, + name = "showcmd", + scope = "global", + shortname = "sc", + type = "boolean", + was_set = true + }, meths.get_option_info'showcmd') end) end) diff --git a/test/functional/editor/mode_insert_spec.lua b/test/functional/editor/mode_insert_spec.lua index cd51a65be3..b00661ac3a 100644 --- a/test/functional/editor/mode_insert_spec.lua +++ b/test/functional/editor/mode_insert_spec.lua @@ -1,6 +1,7 @@ -- Insert-mode tests. local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local expect = helpers.expect local command = helpers.command @@ -48,6 +49,48 @@ describe('insert-mode', function() feed('i<C-r>"') expect('påskägg') end) + + it('double quote is removed after hit-enter prompt #22609', function() + local screen = Screen.new(60, 6) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, + [1] = {foreground = Screen.colors.Blue}, + [2] = {foreground = Screen.colors.SlateBlue}, + [3] = {bold = true}, + [4] = {reverse = true, bold = true}, + [5] = {background = Screen.colors.Red, foreground = Screen.colors.Red}, + [6] = {background = Screen.colors.Red, foreground = Screen.colors.White}, + [7] = {foreground = Screen.colors.SeaGreen, bold = true}, + }) + screen:attach() + feed('i<C-R>') + screen:expect([[ + {1:^"} | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {3:-- INSERT --} | + ]]) + feed('={}<CR>') + screen:expect([[ + {1:"} | + {0:~ }| + {4: }| + ={5:{}{2:}} | + {6:E731: using Dictionary as a String} | + {7:Press ENTER or type command to continue}^ | + ]]) + feed('<CR>') + screen:expect([[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {3:-- INSERT --} | + ]]) + end) end) describe('Ctrl-O', function() diff --git a/test/functional/ex_cmds/verbose_spec.lua b/test/functional/ex_cmds/verbose_spec.lua index 000e746f1c..e55372e993 100644 --- a/test/functional/ex_cmds/verbose_spec.lua +++ b/test/functional/ex_cmds/verbose_spec.lua @@ -7,7 +7,7 @@ local exec_capture = helpers.exec_capture local write_file = helpers.write_file local call_viml_function = helpers.meths.call_function -describe('lua :verbose', function() +local function last_set_tests(cmd) local script_location, script_file -- All test cases below use the same nvim instance. setup(function() @@ -46,7 +46,7 @@ endfunction\ let &tw = s:return80()\ ", true) ]]) - exec(':source '..script_file) + exec(cmd .. ' ' .. script_file) end) teardown(function() @@ -106,6 +106,9 @@ test_group FileType end) it('"Last set" for command defined by nvim_command', function() + if cmd == 'luafile' then + pending('nvim_command does not set the script context') + end local result = exec_capture(':verbose command Bdelete') eq(string.format([[ Name Args Address Complete Definition @@ -123,7 +126,7 @@ test_group FileType script_location), result) end) - it('"Last set for function', function() + it('"Last set" for function', function() local result = exec_capture(':verbose function Close_Window') eq(string.format([[ function Close_Window() abort @@ -140,6 +143,14 @@ test_group FileType Last set from %s line 22]], script_location), result) end) +end + +describe('lua :verbose when using :source', function() + last_set_tests('source') +end) + +describe('lua :verbose when using :luafile', function() + last_set_tests('luafile') end) describe('lua verbose:', function() diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua index 9cc2f6fa27..001cd5770a 100644 --- a/test/functional/fixtures/fake-lsp-server.lua +++ b/test/functional/fixtures/fake-lsp-server.lua @@ -293,8 +293,6 @@ function tests.text_document_sync_save_bool() end; body = function() notify('start') - expect_notification('textDocument/didClose') - expect_notification('textDocument/didOpen') expect_notification('textDocument/didSave', {textDocument = { uri = "file://" }}) notify('shutdown') end; @@ -316,8 +314,6 @@ function tests.text_document_sync_save_includeText() end; body = function() notify('start') - expect_notification('textDocument/didClose') - expect_notification('textDocument/didOpen') expect_notification('textDocument/didSave', { textDocument = { uri = "file://" @@ -464,7 +460,7 @@ function tests.basic_check_buffer_open() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "buffer://"; + uri = "file://"; version = 0; }; }) @@ -491,13 +487,13 @@ function tests.basic_check_buffer_open_and_change() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "buffer://"; + uri = "file://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "buffer://"; + uri = "file://"; version = 3; }; contentChanges = { @@ -527,13 +523,13 @@ function tests.basic_check_buffer_open_and_change_noeol() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n"); - uri = "buffer://"; + uri = "file://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "buffer://"; + uri = "file://"; version = 3; }; contentChanges = { @@ -562,13 +558,13 @@ function tests.basic_check_buffer_open_and_change_multi() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "buffer://"; + uri = "file://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "buffer://"; + uri = "file://"; version = 3; }; contentChanges = { @@ -577,7 +573,7 @@ function tests.basic_check_buffer_open_and_change_multi() }) expect_notification('textDocument/didChange', { textDocument = { - uri = "buffer://"; + uri = "file://"; version = 4; }; contentChanges = { @@ -607,13 +603,13 @@ function tests.basic_check_buffer_open_and_change_multi_and_close() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "buffer://"; + uri = "file://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "buffer://"; + uri = "file://"; version = 3; }; contentChanges = { @@ -622,7 +618,7 @@ function tests.basic_check_buffer_open_and_change_multi_and_close() }) expect_notification('textDocument/didChange', { textDocument = { - uri = "buffer://"; + uri = "file://"; version = 4; }; contentChanges = { @@ -631,7 +627,7 @@ function tests.basic_check_buffer_open_and_change_multi_and_close() }) expect_notification('textDocument/didClose', { textDocument = { - uri = "buffer://"; + uri = "file://"; }; }) expect_notification("finish") @@ -665,13 +661,13 @@ function tests.basic_check_buffer_open_and_change_incremental() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "buffer://"; + uri = "file://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "buffer://"; + uri = "file://"; version = 3; }; contentChanges = { @@ -708,13 +704,13 @@ function tests.basic_check_buffer_open_and_change_incremental_editing() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n"); - uri = "buffer://"; + uri = "file://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "buffer://"; + uri = "file://"; version = 3; }; contentChanges = { diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index b1b39501f7..2cd3123dcd 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -1171,6 +1171,25 @@ describe('lua: nvim_buf_attach on_bytes', function() } end) + it('works with :diffput and :diffget', function() + local check_events = setup_eventcheck(verify, {"AAA"}) + command('diffthis') + command('new') + command('diffthis') + meths.buf_set_lines(0, 0, -1, true, {"AAA", "BBB"}) + feed('G') + command('diffput') + check_events { + { "test1", "bytes", 1, 3, 1, 0, 4, 0, 0, 0, 1, 0, 4 }; + } + meths.buf_set_lines(0, 0, -1, true, {"AAA", "CCC"}) + feed('<C-w>pG') + command('diffget') + check_events { + { "test1", "bytes", 1, 4, 1, 0, 4, 1, 0, 4, 1, 0, 4 }; + } + end) + local function test_lockmarks(mode) local description = (mode ~= "") and mode or "(baseline)" it("test_lockmarks " .. description .. " %delete _", function() diff --git a/test/functional/plugin/lsp/helpers.lua b/test/functional/plugin/lsp/helpers.lua index caab174b4d..86f7da0d2c 100644 --- a/test/functional/plugin/lsp/helpers.lua +++ b/test/functional/plugin/lsp/helpers.lua @@ -13,6 +13,7 @@ function M.clear_notrace() -- solution: don't look too closely for dragons clear {env={ NVIM_LUA_NOTRACK="1"; + NVIM_APPNAME="nvim_lsp_test"; VIMRUNTIME=os.getenv"VIMRUNTIME"; }} end @@ -85,6 +86,7 @@ local function fake_lsp_server_setup(test_name, timeout_ms, options, settings) cmd_env = { NVIM_LOG_FILE = fake_lsp_logfile; NVIM_LUA_NOTRACK = "1"; + NVIM_APPNAME = "nvim_lsp_test"; }; cmd = { vim.v.progpath, '-l', fake_lsp_code, test_name, tostring(timeout), diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 56c53a6fed..c621a5eae2 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -57,6 +57,7 @@ describe('LSP', function() return lsp.start_client { cmd_env = { NVIM_LOG_FILE = fake_lsp_logfile; + NVIM_APPNAME = "nvim_lsp_test"; }; cmd = { vim.v.progpath, '-l', fake_lsp_code, test_name; diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua index e261f0dfab..7e28caea04 100644 --- a/test/functional/ui/cursor_spec.lua +++ b/test/functional/ui/cursor_spec.lua @@ -212,10 +212,10 @@ describe('ui/cursor', function() if m.blinkwait then m.blinkwait = 700 end end if m.hl_id then - m.hl_id = 60 + m.hl_id = 64 m.attr = {background = Screen.colors.DarkGray} end - if m.id_lm then m.id_lm = 62 end + if m.id_lm then m.id_lm = 66 end end -- Assert the new expectation. diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index c681453294..944319c443 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -3490,6 +3490,68 @@ describe('builtin popupmenu', function() pasted | ]]) end) + + describe('"kind" and "menu"', function() + before_each(function() + screen:try_resize(30, 8) + exec([[ + func CompleteFunc( findstart, base ) + if a:findstart + return 0 + endif + return { + \ 'words': [ + \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'W', }, + \ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'W', }, + \ { 'word': 'aword3', 'menu': 'extra text 3', 'kind': 'W', }, + \]} + endfunc + set completeopt=menu + set completefunc=CompleteFunc + ]]) + end) + + -- oldtest: Test_pum_highlights_default() + it('default highlight groups', function() + feed('iaw<C-X><C-u>') + screen:expect([[ + aword1^ | + {s:aword1 W extra text 1 }{1: }| + {n:aword2 W extra text 2 }{1: }| + {n:aword3 W extra text 3 }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- }{5:match 1 of 3} | + ]]) + end) + + -- oldtest: Test_pum_highlights_custom() + it('custom highlight groups', function() + exec([[ + hi PmenuKind guifg=Red guibg=Magenta + hi PmenuKindSel guifg=Red guibg=Grey + hi PmenuExtra guifg=White guibg=Magenta + hi PmenuExtraSel guifg=Black guibg=Grey + ]]) + local attrs = screen:get_default_attr_ids() + attrs.kn = {foreground = Screen.colors.Red, background = Screen.colors.Magenta} + attrs.ks = {foreground = Screen.colors.Red, background = Screen.colors.Grey} + attrs.xn = {foreground = Screen.colors.White, background = Screen.colors.Magenta} + attrs.xs = {foreground = Screen.colors.Black, background = Screen.colors.Grey} + feed('iaw<C-X><C-u>') + screen:expect([[ + aword1^ | + {s:aword1 }{ks:W }{xs:extra text 1 }{1: }| + {n:aword2 }{kn:W }{xn:extra text 2 }{1: }| + {n:aword3 }{kn:W }{xn:extra text 3 }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- }{5:match 1 of 3} | + ]], attrs) + end) + end) end) describe('builtin popupmenu with ui/ext_multigrid', function() diff --git a/test/old/testdir/sautest/autoload/sourced.vim b/test/old/testdir/sautest/autoload/sourced.vim index f69f00cb53..aac96b11ce 100644 --- a/test/old/testdir/sautest/autoload/sourced.vim +++ b/test/old/testdir/sautest/autoload/sourced.vim @@ -1,3 +1,4 @@ let g:loaded_sourced_vim += 1 -func! sourced#something() +func sourced#something() endfunc +call sourced#something() diff --git a/test/old/testdir/test_popup.vim b/test/old/testdir/test_popup.vim index 791cce4431..2cc676fb6d 100644 --- a/test/old/testdir/test_popup.vim +++ b/test/old/testdir/test_popup.vim @@ -1260,4 +1260,66 @@ func Test_pum_scrollbar() call delete('Xtest1') endfunc +" Test default highlight groups for popup menu +func Test_pum_highlights_default() + CheckScreendump + let lines =<< trim END + func CompleteFunc( findstart, base ) + if a:findstart + return 0 + endif + return { + \ 'words': [ + \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'W', }, + \ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'W', }, + \ { 'word': 'aword3', 'menu': 'extra text 3', 'kind': 'W', }, + \]} + endfunc + set completeopt=menu + set completefunc=CompleteFunc + END + call writefile(lines, 'Xscript', 'D') + let buf = RunVimInTerminal('-S Xscript', {}) + call TermWait(buf) + call term_sendkeys(buf, "iaw\<C-X>\<C-u>") + call TermWait(buf, 50) + call VerifyScreenDump(buf, 'Test_pum_highlights_01', {}) + call term_sendkeys(buf, "\<C-E>\<Esc>u") + call TermWait(buf) + call StopVimInTerminal(buf) +endfunc + +" Test custom highlight groups for popup menu +func Test_pum_highlights_custom() + CheckScreendump + let lines =<< trim END + func CompleteFunc( findstart, base ) + if a:findstart + return 0 + endif + return { + \ 'words': [ + \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'W', }, + \ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'W', }, + \ { 'word': 'aword3', 'menu': 'extra text 3', 'kind': 'W', }, + \]} + endfunc + set completeopt=menu + set completefunc=CompleteFunc + hi PmenuKind ctermfg=1 ctermbg=225 + hi PmenuKindSel ctermfg=1 ctermbg=7 + hi PmenuExtra ctermfg=243 ctermbg=225 + hi PmenuExtraSel ctermfg=0 ctermbg=7 + END + call writefile(lines, 'Xscript', 'D') + let buf = RunVimInTerminal('-S Xscript', {}) + call TermWait(buf) + call term_sendkeys(buf, "iaw\<C-X>\<C-u>") + call TermWait(buf, 50) + call VerifyScreenDump(buf, 'Test_pum_highlights_02', {}) + call term_sendkeys(buf, "\<C-E>\<Esc>u") + call TermWait(buf) + call StopVimInTerminal(buf) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_scriptnames.vim b/test/old/testdir/test_scriptnames.vim index 44ec146666..d804684722 100644 --- a/test/old/testdir/test_scriptnames.vim +++ b/test/old/testdir/test_scriptnames.vim @@ -1,5 +1,5 @@ -" Test for :scriptnames +" Test for the :scriptnames command func Test_scriptnames() call writefile(['let did_load_script = 123'], 'Xscripting') source Xscripting @@ -29,4 +29,16 @@ func Test_scriptnames() call assert_equal(msgs, execute('messages')) endfunc +" Test for the getscriptinfo() function +func Test_getscriptinfo() + call writefile(['let loaded_script_id = expand("<SID>")'], 'Xscript') + source Xscript + let l = getscriptinfo() + call assert_match('Xscript$', l[-1].name) + " Nvim does not support interpolated strings yet. + " call assert_equal(g:loaded_script_id, $"<SNR>{l[-1].sid}_") + call assert_equal(g:loaded_script_id, '<SNR>' . l[-1].sid . '_') + call delete('Xscript') +endfunc + " vim: shiftwidth=2 sts=2 expandtab |