diff --git a/.github/workflows/mac_neovim.yml b/.github/workflows/mac_neovim.yml index 897fd2e2d..c06dee23e 100644 --- a/.github/workflows/mac_neovim.yml +++ b/.github/workflows/mac_neovim.yml @@ -51,19 +51,11 @@ jobs: repository: thinca/vim-themis path: ./vim-themis ref: v1.5.5 - - name: Cache gopls - id: cache-gopls - uses: actions/cache@v4 - with: - path: bin/gopls - key: ${{ runner.os }}-${{ env.VIM_LSP_GO_VERSION }}-${{ env.VIM_LSP_GOPLS_VERSION }}-${{ env.VIM_LSP_GOPLS_CACHE_VER }}-gopls - name: Install Go for gopls - if: steps.cache-gopls.outputs.cache-hit != 'true' uses: actions/setup-go@v5 with: go-version: ${{ env.VIM_LSP_GO_VERSION }} - name: Install gopls - if: steps.cache-gopls.outputs.cache-hit != 'true' shell: bash run: | go install golang.org/x/tools/gopls@v${{ env.VIM_LSP_GOPLS_VERSION }} diff --git a/.github/workflows/mac_vim.yml b/.github/workflows/mac_vim.yml index 0a1d7c7f8..1da6efbd1 100644 --- a/.github/workflows/mac_vim.yml +++ b/.github/workflows/mac_vim.yml @@ -27,19 +27,11 @@ jobs: repository: thinca/vim-themis path: ./vim-themis ref: v1.5.5 - - name: Cache gopls - id: cache-gopls - uses: actions/cache@v4 - with: - path: bin/gopls - key: ${{ runner.os }}-${{ env.VIM_LSP_GO_VERSION }}-${{ env.VIM_LSP_GOPLS_VERSION }}-${{ env.VIM_LSP_GOPLS_CACHE_VER }}-gopls - name: Install Go for gopls - if: steps.cache-gopls.outputs.cache-hit != 'true' uses: actions/setup-go@v5 with: go-version: ${{ env.VIM_LSP_GO_VERSION }} - name: Install gopls - if: steps.cache-gopls.outputs.cache-hit != 'true' shell: bash run: | go install golang.org/x/tools/gopls@v${{ env.VIM_LSP_GOPLS_VERSION }} diff --git a/autoload/health/lsp.vim b/autoload/health/lsp.vim index 782da42fa..726eb7809 100644 --- a/autoload/health/lsp.vim +++ b/autoload/health/lsp.vim @@ -8,7 +8,7 @@ endf function! health#lsp#check() abort - call health#report_start('server status') + call s:report_start('server status') let l:server_status = lsp#collect_server_status() let l:has_printed = v:false @@ -17,21 +17,21 @@ function! health#lsp#check() abort let l:status_msg = printf('%s: %s', l:k, l:report.status) if l:report.status == 'running' - call health#report_ok(l:status_msg) + call s:report_ok(l:status_msg) elseif l:report.status == 'failed' call health#report_error(l:status_msg, 'See :help g:lsp_log_verbose to debug server failure.') else - call health#report_warn(l:status_msg) + call s:report_warn(l:status_msg) endif let l:has_printed = v:true endfor if !l:has_printed - call health#report_warn('no servers connected') + call s:report_warn('no servers connected') endif for l:k in sort(keys(l:server_status)) - call health#report_start(printf('server configuration: %s', l:k)) + call s:report_start(printf('server configuration: %s', l:k)) let l:report = l:server_status[l:k] let l:msg = "\t\n" @@ -54,12 +54,35 @@ function! health#lsp#check() abort call health#report_info(l:msg) endfor - call health#report_start('Performance') + call s:report_start('Performance') if lsp#utils#has_lua() && g:lsp_use_lua - call health#report_ok('Using lua for faster performance.') + call s:report_ok('Using lua for faster performance.') else - call health#report_warn('Missing requirements to enable lua for faster performance.') + call s:report_warn('Missing requirements to enable lua for faster performance.') endif endf +function! s:report_start(report) abort + if has('nvim-0.10') + call v:lua.vim.health.start(a:report) + else + call health#report_start(a:report) + endif +endf + +function! s:report_warn(report) abort + if has('nvim-0.10') + call v:lua.vim.health.warn(a:report) + else + call health#report_warn(a:report) + endif +endf + +function! s:report_ok(report) abort + if has('nvim-0.10') + call v:lua.vim.health.ok(a:report) + else + call health#report_ok(a:report) + endif +endf diff --git a/autoload/lsp.vim b/autoload/lsp.vim index a2ab0106c..dbb9d77bb 100644 --- a/autoload/lsp.vim +++ b/autoload/lsp.vim @@ -750,7 +750,7 @@ function! s:text_changes(buf, server_name) abort endif " When syncKind is Incremental and previous content is saved. - if l:sync_kind == 2 && has_key(s:file_content, a:buf) + if l:sync_kind == 2 && has_key(s:file_content, a:buf) && has_key(s:file_content[a:buf], a:server_name) " compute diff let l:old_content = s:get_last_file_content(a:buf, a:server_name) let l:new_content = lsp#utils#buffer#_get_lines(a:buf) diff --git a/autoload/lsp/capabilities.vim b/autoload/lsp/capabilities.vim index b9a72f955..374538260 100644 --- a/autoload/lsp/capabilities.vim +++ b/autoload/lsp/capabilities.vim @@ -189,6 +189,10 @@ function! lsp#capabilities#get_code_action_kinds(server_name) abort return [] endfunction +function! lsp#capabilities#has_completion_provider(server_name) abort + return s:has_provider(a:server_name, 'completionProvider') +endfunction + function! lsp#capabilities#has_completion_resolve_provider(server_name) abort return s:has_provider(a:server_name, 'completionProvider', 'resolveProvider') endfunction diff --git a/autoload/lsp/omni.vim b/autoload/lsp/omni.vim index 663691f48..160ca10e7 100644 --- a/autoload/lsp/omni.vim +++ b/autoload/lsp/omni.vim @@ -204,8 +204,7 @@ endfunction function! s:find_complete_servers() abort let l:server_names = [] for l:server_name in lsp#get_allowed_servers() - let l:init_capabilities = lsp#get_server_capabilities(l:server_name) - if has_key(l:init_capabilities, 'completionProvider') + if lsp#capabilities#has_completion_provider(l:server_name) " TODO: support triggerCharacters call add(l:server_names, l:server_name) endif diff --git a/autoload/lsp/ui/vim/completion.vim b/autoload/lsp/ui/vim/completion.vim index 3cf00d937..5989ba0e5 100644 --- a/autoload/lsp/ui/vim/completion.vim +++ b/autoload/lsp/ui/vim/completion.vim @@ -197,11 +197,7 @@ function! s:resolve_completion_item(completion_item, server_name) abort endif " check server capabilities. - let l:capabilities = lsp#get_server_capabilities(a:server_name) - if !has_key(l:capabilities, 'completionProvider') - \ || type(l:capabilities['completionProvider']) != v:t_dict - \ || !has_key(l:capabilities['completionProvider'], 'resolveProvider') - \ || !l:capabilities['completionProvider']['resolveProvider'] + if !lsp#capabilities#has_completion_resolve_provider(a:server_name) return a:completion_item endif diff --git a/autoload/lsp/ui/vim/output.vim b/autoload/lsp/ui/vim/output.vim index 5914a1d22..9955f3be7 100644 --- a/autoload/lsp/ui/vim/output.vim +++ b/autoload/lsp/ui/vim/output.vim @@ -102,6 +102,7 @@ function! s:get_float_positioning(height, width) abort let l:height = min([l:height, max([&lines - &cmdheight - l:row, &previewheight])]) let l:style = 'minimal' + let l:border = 'double' " Positioning is not window but screen relative let l:opts = { \ 'relative': 'editor', @@ -110,6 +111,7 @@ function! s:get_float_positioning(height, width) abort \ 'width': l:width, \ 'height': l:height, \ 'style': l:style, + \ 'border': l:border, \ } return l:opts endfunction diff --git a/autoload/lsp/utils/text_edit.vim b/autoload/lsp/utils/text_edit.vim index 6f64b47d0..e6e0c835e 100644 --- a/autoload/lsp/utils/text_edit.vim +++ b/autoload/lsp/utils/text_edit.vim @@ -200,18 +200,17 @@ function! s:_compare(text_edit1, text_edit2) abort return a:text_edit1.range.start.character - a:text_edit2.range.start.character endif return l:diff -endfunction +endfunction " " _switch " function! s:_switch(path) abort - if bufnr(a:path) >= 0 - execute printf('keepalt keepjumps %sbuffer!', bufnr(a:path)) - else - execute printf('keepalt keepjumps edit! %s', fnameescape(a:path)) + if bufnr(a:path) == -1 + execute printf('badd %s', fnameescape(a:path)) endif -endfunction + execute printf('keepalt keepjumps %sbuffer!', bufnr(a:path)) +endfunction " " delete diff --git a/autoload/vital/_lsp/VS/Vim/Window.vim b/autoload/vital/_lsp/VS/Vim/Window.vim index c373af984..db54988f7 100644 --- a/autoload/vital/_lsp/VS/Vim/Window.vim +++ b/autoload/vital/_lsp/VS/Vim/Window.vim @@ -45,9 +45,55 @@ endfunction if has('nvim') function! s:info(winid) abort let l:info = getwininfo(a:winid)[0] + + if s:is_floating(a:winid) + let l:config = nvim_win_get_config(a:winid) + let l:config.border = get(l:config, 'border', 'none') + if type(l:config.border) !=# type([]) + if index(['rounded', 'single', 'double', 'solid'], l:config.border) >= 0 + let l:width_off = 2 + let l:height_off = 2 + elseif l:config.border ==# 'shadow' + let l:width_off = 1 + let l:height_off = 1 + else + let l:width_off = 0 + let l:height_off = 0 + endif + else + let l:has_top = v:false + let l:has_top = l:has_top || get(l:config.border, 0, '') !=# '' + let l:has_top = l:has_top || get(l:config.border, 1, '') !=# '' + let l:has_top = l:has_top || get(l:config.border, 2, '') !=# '' + let l:has_right = v:false + let l:has_right = l:has_right || get(l:config.border, 2, '') !=# '' + let l:has_right = l:has_right || get(l:config.border, 3, '') !=# '' + let l:has_right = l:has_right || get(l:config.border, 4, '') !=# '' + let l:has_bottom = v:false + let l:has_bottom = l:has_bottom || get(l:config.border, 4, '') !=# '' + let l:has_bottom = l:has_bottom || get(l:config.border, 5, '') !=# '' + let l:has_bottom = l:has_bottom || get(l:config.border, 6, '') !=# '' + let l:has_left = v:false + let l:has_left = l:has_left || get(l:config.border, 6, '') !=# '' + let l:has_left = l:has_left || get(l:config.border, 7, '') !=# '' + let l:has_left = l:has_left || get(l:config.border, 0, '') !=# '' + + let l:width_off = (l:has_left ? 1 : 0) + (l:has_right ? 1 : 0) + let l:height_off = (l:has_top ? 1 : 0) + (l:has_bottom ? 1 : 0) + endif + let l:left = get(l:config, '') + let l:info.core_width = l:config.width - l:width_off + let l:info.core_height = l:config.height - l:height_off + else + let l:info.core_width = l:info.width + let l:info.core_height = l:info.height + endif + return { \ 'width': l:info.width, \ 'height': l:info.height, + \ 'core_width': l:info.core_width, + \ 'core_height': l:info.core_height, \ 'topline': l:info.topline, \ } endfunction @@ -58,6 +104,8 @@ else return { \ 'width': l:info.width, \ 'height': l:info.height, + \ 'core_width': l:info.core_width, + \ 'core_height': l:info.core_height, \ 'topline': l:info.firstline \ } endif @@ -67,6 +115,8 @@ else function! l:ctx.callback() abort let self.info.width = winwidth(0) let self.info.height = winheight(0) + let self.info.core_width = self.info.width + let self.info.core_height = self.info.height let self.info.topline = line('w0') endfunction call s:do(a:winid, { -> l:ctx.callback() }) @@ -106,7 +156,7 @@ function! s:scroll(winid, topline) abort function! l:ctx.callback(winid, topline) abort let l:wininfo = s:info(a:winid) let l:topline = a:topline - let l:topline = min([l:topline, line('$') - l:wininfo.height + 1]) + let l:topline = min([l:topline, line('$') - l:wininfo.core_height + 1]) let l:topline = max([l:topline, 1]) if l:topline == l:wininfo.topline diff --git a/autoload/vital/lsp.vim b/autoload/vital/lsp.vim index c2b0a92a4..5b7b10270 100644 --- a/autoload/vital/lsp.vim +++ b/autoload/vital/lsp.vim @@ -218,7 +218,7 @@ endfunction " @vimlint(EVL102, 0, l:__) " @vimlint(EVL102, 0, l:_) -" s:_get_module() returns module object wihch has all script local functions. +" s:_get_module() returns module object which has all script local functions. function! s:_get_module(name) abort dict let funcname = s:_import_func_name(self.plugin_name(), a:name) try diff --git a/autoload/vital/lsp.vital b/autoload/vital/lsp.vital index b5602cc7e..1737ce2fe 100644 --- a/autoload/vital/lsp.vital +++ b/autoload/vital/lsp.vital @@ -1,8 +1,9 @@ lsp -b1e91b41f5028d65fa3d31a425ff21591d5d957f +969a97cb6b3e634490ba168db0f2606c410cf9a7 VS.LSP.MarkupContent -VS.Vim.Window.FloatingWindow -VS.Vim.Syntax.Markdown +VS.LSP.Text VS.Vim.Buffer +VS.Vim.Syntax.Markdown VS.Vim.Window +VS.Vim.Window.FloatingWindow diff --git a/doc/vim-lsp.txt b/doc/vim-lsp.txt index f47f6ac4c..bf5676ea9 100644 --- a/doc/vim-lsp.txt +++ b/doc/vim-lsp.txt @@ -58,9 +58,9 @@ CONTENTS *vim-lsp-contents* g:lsp_diagnostics_virtual_text_wrap |g:lsp_diagnostics_virtual_text_wrap| g:lsp_document_code_action_signs_enabled - |g:lsp_document_code_actions_signs_enabled| + |g:lsp_document_code_action_signs_enabled| g:lsp_document_code_action_signs_delay - |g:lsp_document_code_actions_signs_delay| + |g:lsp_document_code_action_signs_delay| g:lsp_inlay_hints_enabled |g:lsp_inlay_hints_enabled| g:lsp_inlay_hints_delay @@ -271,7 +271,7 @@ You can use tcp to connect to LSP servers that don't support stdio. Set host and port to tcp. The Godot game engine uses 6008 as its LSP port and godot ftplugins define gdscript or gdscript3 filetype: > - au User lsp_setup + au User lsp_setup \ call lsp#register_server({ \ 'name': 'godot', \ 'tcp': "localhost:6008", @@ -290,7 +290,7 @@ vim-lsp supports the |:CheckHealth| command which can be useful when debugging lsp configuration issues. This command is implemented in vim with the -[vim-healthcheck](https://github.com/rhysd/vim-healthcheck) plugin. +[vim-healthcheck](https://github.com/rhysd/vim-healthcheck) plugin. WIKI *vim-lsp-configure-wiki* For documentation on how to configure other language servers refer @@ -905,7 +905,7 @@ g:lsp_max_buffer_size *g:lsp_max_buffer_size* `g:lsp_max_buffer_size` (measured in bytes), the following features are disabled: * Semantic highlighting - + This functionality can be disabled by setting `g:lsp_max_buffer_size` to a negative value. @@ -1402,6 +1402,13 @@ The vim |dict| containing information about the server. Example: > 'config': { 'diagnostics': v:false } < + * env: + optional vim |dict| + Used to pass environment variables to the cmd. + Example: > + 'env': { 'GOFLAGS': '-tags=wireinject' } +< + refresh_pattern *vim-lsp-refresh_pattern* Type: |String| (|pattern|) Default: `'\k*$'` @@ -2245,7 +2252,7 @@ Popup Formatting *vim-lsp-popup-format* Popup windows use the |gq| operator for formatting content to the window. -For customization, see +For customization, see |formatprg|. ============================================================================== diff --git a/test/lsp/utils/text_edit.vimspec b/test/lsp/utils/text_edit.vimspec index 67776d307..494c07086 100644 --- a/test/lsp/utils/text_edit.vimspec +++ b/test/lsp/utils/text_edit.vimspec @@ -2,6 +2,7 @@ function! s:set_text(lines) % delete _ put =a:lines execute 'normal ggdd' + execute 'file my-file' endfunction function! s:get_text() @@ -642,6 +643,45 @@ Describe lsp#utils#text_edit Assert Equals(getbufline(l:target, 1), ['aiueo']) End + + It should apply edits to buffer and unloaded file + let l:text = ['plop'] + call s:set_text(l:text) + let l:buffer_text = s:get_text() + Assert Equals(l:buffer_text, ['plop', '']) + let l:target = globpath(&runtimepath, 'test/lsp/utils/text_edit.vimspec') + call lsp#utils#text_edit#apply_text_edits( + \ lsp#utils#path_to_uri(expand('%')), + \ [{ + \ 'range': { + \ 'start': { + \ 'line': 0, + \ 'character': 0, + \ }, + \ 'end': { + \ 'line': 1, + \ 'character': 0, + \ } + \ }, + \ 'newText': "buffer\n" + \ }]) + call lsp#utils#text_edit#apply_text_edits(lsp#utils#path_to_uri(l:target), [{ + \ 'range': { + \ 'start': { + \ 'line': 0, + \ 'character': 0, + \ }, + \ 'end': { + \ 'line': 1, + \ 'character': 0, + \ } + \ }, + \ 'newText': "unloaded\n" + \ }]) + + Assert Equals(getbufline(l:target, 1), ['unloaded']) + Assert Equals(getbufline(expand('%'), 1), ['buffer']) + End End End