autoload/buf.vim | 6 ++++++ autoload/handlers.vim | 44 ++++++++++++++++++++++++++++++++++++-------- autoload/lsp.vim | 82 +++++++++++++++++++++++++++++++++++++++++++++++------ autoload/lspoptions.vim | 18 ++++++++++++++++++ autoload/util.vim | 3 ++- doc/lsp.txt | 49 ++++++++++++++++++++++++++++++++++++++++++------- plugin/lsp.vim | 1 + diff --git a/autoload/buf.vim b/autoload/buf.vim index fb2309ccbbe120cc1a9619d9394312240b008978..92ab8a44ad45bfda943e0ba7510e93455f228b44 100644 --- a/autoload/buf.vim +++ b/autoload/buf.vim @@ -1,5 +1,7 @@ vim9script +import lspOptions from './lspoptions.vim' + def s:lspDiagSevToSignName(severity: number): string var typeMap: list = ['LspDiagError', 'LspDiagWarning', 'LspDiagInfo', 'LspDiagHint'] @@ -12,6 +14,10 @@ # New LSP diagnostic messages received from the server for a file. # Update the signs placed in the buffer for this file export def LspDiagsUpdated(lspserver: dict, bnr: number) + if !lspOptions.autoHighlightDiags + return + endif + if bnr == -1 || !lspserver.diagsMap->has_key(bnr) return endif diff --git a/autoload/handlers.vim b/autoload/handlers.vim index d5e91c8cab46e72f5a60233948eddfc181f5ca02..7a40de4a75e51c278e02200e4f7de7bacd3f3d2c 100644 --- a/autoload/handlers.vim +++ b/autoload/handlers.vim @@ -4,6 +4,7 @@ # Handlers for messages from the LSP server # Refer to https://microsoft.github.io/language-server-protocol/specification # for the Language Server Protocol (LSP) specificaiton. +import lspOptions from './lspoptions.vim' import {WarnMsg, ErrMsg, TraceLog, @@ -25,16 +26,25 @@ # TODO: Check all the buffers with filetype corresponding to this LSP server # and then setup the below mapping for those buffers. # map characters that trigger signature help - if g:LSP_Show_Signature && caps->has_key('signatureHelpProvider') + if lspOptions.showSignature && caps->has_key('signatureHelpProvider') var triggers = caps.signatureHelpProvider.triggerCharacters for ch in triggers exe 'inoremap ' .. ch .. ' ' .. ch .. "=lsp#showSignature()" endfor endif - if g:LSP_24x7_Complete && caps->has_key('completionProvider') + if lspOptions.autoComplete && caps->has_key('completionProvider') var triggers = caps.completionProvider.triggerCharacters lspserver.completionTriggerChars = triggers + endif + + if lspOptions.autoHighlight && caps->has_key('documentHighlightProvider') + && caps.documentHighlightProvider + # Highlight all the occurrences of the current keyword + augroup LSPBufferAutocmds + autocmd CursorMoved call lsp#docHighlightClear() + | call lsp#docHighlight() + augroup END endif # send a "initialized" notification to server @@ -120,15 +130,33 @@ var startcol = 0 if sig->has_key('parameters') && result->has_key('activeParameter') var params_len = sig.parameters->len() if params_len > 0 && result.activeParameter < params_len - var label = sig.parameters[result.activeParameter].label + var label = '' + if sig.parameters[result.activeParameter]->has_key('documentation') + if sig.parameters[result.activeParameter].documentation->type() + == v:t_string + label = sig.parameters[result.activeParameter].documentation + endif + else + label = sig.parameters[result.activeParameter].label + endif hllen = label->len() startcol = text->stridx(label) endif endif - var popupID = text->popup_atcursor({moved: 'any'}) - prop_type_add('signature', {bufnr: popupID->winbufnr(), highlight: 'LineNr'}) - if hllen > 0 - prop_add(1, startcol + 1, {bufnr: popupID->winbufnr(), length: hllen, type: 'signature'}) + if lspOptions.echoSignature + echon "\r\r" + echon '' + echon strpart(text, 0, startcol) + echoh LineNr + echon strpart(text, startcol, hllen) + echoh None + echon strpart(text, startcol + hllen) + else + var popupID = text->popup_atcursor({moved: 'any'}) + prop_type_add('signature', {bufnr: popupID->winbufnr(), highlight: 'LineNr'}) + if hllen > 0 + prop_add(1, startcol + 1, {bufnr: popupID->winbufnr(), length: hllen, type: 'signature'}) + endif endif enddef @@ -212,7 +240,7 @@ d.user_data = item completeItems->add(d) endfor - if g:LSP_24x7_Complete + if lspOptions.autoComplete if completeItems->empty() # no matches return diff --git a/autoload/lsp.vim b/autoload/lsp.vim index 25c3ef71af9dea42a42ed9d9c30b533aa50bf862..932aa95e48ca7900e07d4c64b0e055a301bf25b1 100644 --- a/autoload/lsp.vim +++ b/autoload/lsp.vim @@ -2,6 +2,7 @@ vim9script # Vim9 LSP client +import lspOptions from './lspoptions.vim' import NewLspServer from './lspserver.vim' import {WarnMsg, ErrMsg, @@ -29,6 +30,13 @@ # Buffer number to LSP server map var bufnrToServer: dict> = {} var lspInitializedOnce = false + +# Set user configurable LSP options +def lsp#setOptions(lspOpts: dict) + for key in lspOpts->keys() + lspOptions[key] = lspOpts[key] + endfor +enddef def s:lspInitOnce() # Signs used for LSP diagnostics @@ -238,6 +246,12 @@ # No diagnostic for the current cursor location return '' endif + # Display the diagnostic message only if the mouse is over the first two + # columns + if v:beval_col >= 3 + return '' + endif + return diagInfo.message enddef @@ -283,18 +297,13 @@ lspserver.startServer() endif lspserver.textdocDidOpen(bnr, ftype) - # file saved notification handler - autocmd BufWritePost call s:lspSavedFile() - # add a listener to track changes to this buffer listener_add(function('lsp#bufchange_listener'), bnr) # set options for insert mode completion - if g:LSP_24x7_Complete + if lspOptions.autoComplete setbufvar(bnr, '&completeopt', 'menuone,popup,noinsert,noselect') setbufvar(bnr, '&completepopup', 'border:off') - # autocmd for 24x7 insert mode completion - autocmd TextChangedI call lsp#complete() # in insert mode stops completion and inserts a inoremap pumvisible() ? "\\" : "\" else @@ -304,10 +313,10 @@ endif endif setbufvar(bnr, '&balloonexpr', 'LspDiagExpr()') - exe 'autocmd InsertLeave call lsp#leftInsertMode()' # map characters that trigger signature help - if g:LSP_Show_Signature && lspserver.caps->has_key('signatureHelpProvider') + if lspOptions.showSignature && + lspserver.caps->has_key('signatureHelpProvider') var triggers = lspserver.caps.signatureHelpProvider.triggerCharacters for ch in triggers exe 'inoremap ' .. ch .. ' ' .. ch @@ -315,6 +324,28 @@ .. "=lsp#showSignature()" endfor endif + # Set buffer local autocmds + augroup LSPBufferAutocmds + # file saved notification handler + exe 'autocmd BufWritePost call s:lspSavedFile()' + + if lspOptions.autoComplete + # Trigger 24x7 insert mode completion when text is changed + exe 'autocmd TextChangedI call lsp#complete()' + endif + + # Update the diagnostics when insert mode is stopped + exe 'autocmd InsertLeave call lsp#leftInsertMode()' + + if lspOptions.autoHighlight && + lspserver.caps->has_key('documentHighlightProvider') + && lspserver.caps.documentHighlightProvider + # Highlight all the occurrences of the current keyword + exe 'autocmd CursorMoved ' + .. 'call lsp#docHighlightClear() | call lsp#docHighlight()' + endif + augroup END + bufnrToServer[bnr] = lspserver enddef @@ -500,6 +531,39 @@ WarnMsg('No diagnostic messages found for current line') else echo diag.message endif +enddef + +# get the count of error in the current buffer +def lsp#errorCount(): dict + var res = {'Error': 0, 'Warn': 0, 'Info': 0, 'Hint': 0} + var ftype = &filetype + if ftype == '' + return res + endif + + var lspserver: dict = s:lspGetServer(ftype) + if lspserver->empty() || !lspserver.running + return res + endif + + var bnr: number = bufnr() + if lspserver.diagsMap->has_key(bnr) + for item in lspserver.diagsMap[bnr]->values() + if item->has_key('severity') + if item.severity == 1 + res.Error = res.Error + 1 + elseif item.severity == 2 + res.Warn = res.Warn + 1 + elseif item.severity == 3 + res.Info = res.Info + 1 + elseif item.severity == 4 + res.Hint = res.Hint + 1 + endif + endif + endfor + endif + + return res enddef # sort the diaganostics messages for a buffer by line number @@ -1106,7 +1170,7 @@ if fname == '' return endif - var newName: string = input("Enter new name: ", expand('')) + var newName: string = input("Rename symbol: ", expand('')) if newName == '' return endif diff --git a/autoload/lspoptions.vim b/autoload/lspoptions.vim new file mode 100644 index 0000000000000000000000000000000000000000..ab7daa0b0ec8ae263d1892ef671e2ac689a150a6 --- /dev/null +++ b/autoload/lspoptions.vim @@ -0,0 +1,18 @@ +vim9script + +# LSP plugin options +# User can override these by calling the lsp#setOptions() function. +export var lspOptions: dict = { + # In insert mode, complete the current symbol automatically + # Otherwise, use omni-completion + autoComplete: true, + # In normal mode, highlight the current symbol automatically + autoHighlight: false, + # In insert mode, show the current symbol signature automatically + showSignature: true, + # In insert mode, echo the current symbol signature in the status line + # instead of showing it in a popup + echoSignature: false, + # Automatically highlight diagnostics messages from LSP server + autoHighlightDiags: true +} diff --git a/autoload/util.vim b/autoload/util.vim index 54c334eae263165c1b3a1e31b51cbe8831a2ad65..38ece443b8524de84ccda0eec4df019d9c4ee12b 100644 --- a/autoload/util.vim +++ b/autoload/util.vim @@ -56,7 +56,8 @@ if uri_decoded =~? '^file:///\a:' # MS-Windows URI uri_decoded = uri_decoded[8 : ] uri_decoded = uri_decoded->substitute('/', '\\', 'g') - else + # On GNU/Linux (pattern not end with `:`) + elseif uri_decoded =~? '^file:///\a' uri_decoded = uri_decoded[7 : ] endif diff --git a/doc/lsp.txt b/doc/lsp.txt index ac38cf2bd404da730f5352590c4030a13b659251..9f80f656e0c0907e43461dac9b136206b3e40a35 100644 --- a/doc/lsp.txt +++ b/doc/lsp.txt @@ -2,12 +2,12 @@ *lsp.txt* Language Server Protocol (LSP) Plugin for Vim9 Author: Yegappan Lakshmanan (yegappan AT yahoo DOT com) For Vim version 8.2.2342 and above -Last change: Feb 24, 2021 +Last change: Nov 14, 2021 ============================================================================== *lsp-license* License: MIT License -Copyright (c) 2020 Yegappan Lakshmanan +Copyright (c) 2020-2021 Yegappan Lakshmanan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -172,6 +172,31 @@ The LSP servers are added using the lsp#addServer() function. This function accepts a list of LSP servers with the above information. + *lsp-options* +Some of the LSP plugin features can be enabled or disabled by using the +lsp#setOptions() function. This function accepts a dictionary argument with the +following optional items: + + autoComplete In insert mode, automatically complete the current + symbol. Otherwise use omni-completion. By default this + is set to true. + autoHighlight In normal mode, automatically highlight all the + occurrences of the symbol under the cursor. By default + this is set to false. + showSignature In insert mode, automatically show the current symbol + signature in a popup. By default this is set to true. + echoSignature In insert mode, echo the current symbol signature + instead of showing it in a popup. By default this is + set to false. + autoHighlightDiags Automatically place signs on the lines with a + diagnostic message from the LSP server. By default + this is set to true. + +For example, to disable the automatic placement of signs for the LSP +diagnostic messages, you can add the following line to your .vimrc file: + + call lsp#setOptions({'autoHighlightDiags': v:false}) + ============================================================================== 5. Commands *lsp-commands* @@ -214,10 +239,20 @@ or method) before the cursor in a popup. The popup is also automatically displayed in insert mode after entering a symbol name followed by a - separator (e.g. a opening parenthesis). Unless if: > - let g:LSP_Show_Signature = v:false + separator (e.g. a opening parenthesis). To disable + this, you can set the showSignature option to false in + your .vimrc file: > + + call lsp#setOptions({'showSignature': v:false}) < Default is true. + + You can get the function signature echoed in cmdline + rather than displayed in popup if you use > + + call lsp#setOptions({'echoSignature': v:true}) +< + Default is false. *:LspDiagShow* :LspDiagShow Creates a new location list with the diagnostics @@ -365,10 +400,10 @@ By default, in insert mode, the LSP plugin automatically displays the matches for the symbol under the cursor in an insert-completion popup menu. You can use the keys described in |popupmenu-keys| with this menu. -To disable the auto-compeltion, you can set the LSP_24x7_Complete variable -to v:false in your .vimrc file: > +To disable the auto-compeltion, you can set the autoComplete option to v:false +in your .vimrc file: > - let g:LSP_24x7_Complete = v:false + call lsp#setOptions({'autoComplete': v:false}) < If this variable is set, then the LSP plugin doesn't automatically start completion in insert mode and instead supports omni-completion (|compl-omni|). diff --git a/plugin/lsp.vim b/plugin/lsp.vim index f7021fe7cf3a7d26d10f8f80bd24119e3d043451..0f324c41c0ab62d7fbdea086be27c53c54628a00 100644 --- a/plugin/lsp.vim +++ b/plugin/lsp.vim @@ -5,6 +5,7 @@ if v:version < 802 || !has('patch-8.2.2342') finish endif + " Perform completion in insert mode automatically. Otherwise use " omni-complete. if !exists('g:LSP_24x7_Complete')