Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ serde_derive = "1"
serde_json = "1"
crossbeam = "0.7.3"
jsonrpc-core = "12"
lsp-types = "0.60"
lsp-types = { version = "0.70.0", features = ["proposed"] }
url = "2"
pathdiff = "0"
diff = "0"
Expand Down
74 changes: 74 additions & 0 deletions autoload/LanguageClient.vim
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,16 @@ function! s:MatchDelete(ids) abort
endfor
endfunction

function! s:ApplySemanticHighlights(bufnr, ns_id, clears, highlights) abort
for clear in a:clears
call nvim_buf_clear_namespace(a:bufnr, a:ns_id, clear.line_start, clear.line_end)
endfor

for hl in a:highlights
call nvim_buf_add_highlight(a:bufnr, a:ns_id, hl.group, hl.line, hl.character_start, hl.character_end)
endfor
endfunction

" Batch version of nvim_buf_add_highlight
function! s:AddHighlights(source, highlights) abort
for hl in a:highlights
Expand Down Expand Up @@ -1376,6 +1386,70 @@ function! LanguageClient_contextMenu() abort
return LanguageClient_handleContextMenuItem(l:options[l:selection - 1])
endfunction

function! LanguageClient_showSemanticScopes(...) abort
let l:params = get(a:000, 0, {})
let l:Callback = get(a:000, 1, function('s:print_semantic_scopes'))

return LanguageClient#Call('languageClient/semanticScopes', l:params, l:Callback)
endfunction

function! s:print_semantic_scopes(response) abort
let l:scope_mappings = a:response.result

let l:msg = ''
for mapping in l:scope_mappings
let l:msg .= "Highlight Group:\n"
let l:msg .= ' ' . l:mapping.hl_group . "\n"

let l:msg .= "Semantic Scope:\n"
let l:spaces = ' '
for l:scope_name in l:mapping.scope
let l:msg .= l:spaces . l:scope_name . "\n"
let l:spaces .= ' '
endfor
let l:msg .= "\n"
endfor

echo l:msg
endfunction

function! LanguageClient#showSemanticHighlightSymbols(...) abort
let l:params = get(a:000, 0, {})
let l:Callback = get(a:000, 1, v:null)

return LanguageClient#Call('languageClient/showSemanticHighlightSymbols', l:params, l:Callback)
endfunction

function! LanguageClient_showCursorSemanticHighlightSymbols(...) abort
let l:params = get(a:000, 0, {})
let l:Callback = get(a:000, 1, function('s:print_cursor_semantic_symbol'))

return LanguageClient#showSemanticHighlightSymbols(l:params, l:Callback)
endfunction

function! s:print_cursor_semantic_symbol(response) abort
let l:symbols = a:response.result
let l:lines = []

for symbol in l:symbols
if l:symbol.line + 1 == line('.') &&
\ symbol.character_start < col('.') &&
\ col('.') <= symbol.character_end
let l:spaces = ''
for scope_name in l:symbol.scope
call add(l:lines, l:spaces . l:scope_name)
let l:spaces .= ' '
endfor
endif
endfor

if len(l:lines) > 0
call s:OpenHoverPreview('SemanticScopes', l:lines, 'text')
else
call s:Echowarn('No Symbol Under Cursor or No Semantic Highlighting')
endif
endfunction

function! LanguageClient#debugInfo(...) abort
let l:params = get(a:000, 0, {})
let l:Callback = get(a:000, 1, v:null)
Expand Down
112 changes: 112 additions & 0 deletions doc/LanguageClient.txt
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,106 @@ the root of a project is detected using g:LanguageClient_rootMarkers.
Default: 1 to display the messages
Valid options: 1 | 0

2.30 g:LanguageClient_semanticHighlightMaps *g:LanguageClient_semanticHighlightMaps*

String to list/map map. Defines the mapping of semantic highlighting "scopes" to
highlight groups. This depends on the LSP server supporting the proposed
semantic highlighting protocol, see:

https://github.com/microsoft/language-server-protocol/issues/18
https://github.com/microsoft/vscode-languageserver-node/issues/368


Like |g:LanguageClient_serverCommands| this is a map where the keys are
filetypes. However each submap has |regexp| keys and highlight group names
as values (see |highlight-groups|).
>
let g:LanguageClient_semanticHighlightMaps = {
\ 'java': {
\ '^entity.name.function.java': 'Function',
\ '^entity.name.type.class.java': 'Type',
\ '^[^:]*entity.name.function.java': 'Function',
\ '^[^:]entity.name.type.class.java': 'Type'
\ }
\ }

The |regexp| in the keys will be used to match semantic scopes. Then any symbols
that have a semantic scope that matches the key will be highlighted with the
associated highlight group value. Currently there is no defined order if a
semantic scope can match multiple keys, so it is recommended to make the keys
more specific to only match the desired scope(s).

There are a fixed set of semantic scopes defined by the LSP server on startup.
These can be viewed by calling |LanguageClient_showSemanticScopes| which will
show all the semantic scopes and their currently mapped highlight group for
the currently open buffer's filetype.
>
call LanguageClient_showSemanticScopes()

== Output from eclipse.jdt.ls ==

Highlight Group:
None
Semantic Scope:
invalid.deprecated.java
meta.class.java
source.java

Highlight Group:
None
Semantic Scope:
variable.other.autoboxing.java
meta.method.body.java
meta.method.java
meta.class.body.java
meta.class.java
source.java

...

Each semantic scope is a list of strings. They are printed with increasing
indent to make it easier to read. For example the first scope is:
>
['invalid.deprecated.java', 'meta.class.java', 'source.java']

It is currently isn't mapped to any highlight group as indicated by the None.

Often its more useful to find what semantic scope corresponds to a piece of
text. This can be done by calling |LanguageClient_showCursorSemanticHighlightSymbols|
while hovering over the text of interest.
>
call LanguageClient_showCursorSemanticHighlightSymbols()

When matching the semantic scopes to keys in |LanguageClient_semanticHighlightMaps|,
the scopes are concatentated using |LanguageClient_semanticScopeSeparator|
which is set to the string |':'| by default. For the previous example the
semantic scope would have this string form using the default separator:
>
invalid.deprecated.java:meta.class.java:source.java

Here are a couple of example |regexp| keys that can/cannot match this scope:
>
'meta.class.java' =~ 'invalid.deprecated.java:meta.class.java:source.java'
'^meta.class.java' !~ 'invalid.deprecated.java:meta.class.java:source.java'
'^invalid.deprecated.java' =~ 'invalid.deprecated.java:meta.class.java:source.java'
'source.java$' =~ 'invalid.deprecated.java:meta.class.java:source.java'
'meta.class.java:source.java' =~ 'invalid.deprecated.java:meta.class.java:source.java'
'invalid.deprecated.java:.*:source.java' =~ 'invalid.deprecated.java:meta.class.java:source.java'

Example configuration for eclipse.jdt.ls:
>
let g:LanguageClient_semanticHighlightMaps = {}
let g:LanguageClient_semanticHighlightMaps['java'] = {
\ '^storage.modifier.static.java:entity.name.function.java': 'JavaStaticMemberFunction',
\ '^meta.definition.variable.java:meta.class.body.java:meta.class.java': 'JavaMemberVariable',
\ '^entity.name.function.java': 'Function',
\ '^[^:]*entity.name.function.java': 'Function',
\ '^[^:]*entity.name.type.class.java': 'Type',
\ }

highlight! JavaStaticMemberFunction ctermfg=Green cterm=none guifg=Green gui=none
highlight! JavaMemberVariable ctermfg=White cterm=italic guifg=White gui=italic

==============================================================================
3. Commands *LanguageClientCommands*

Expand Down Expand Up @@ -678,6 +778,18 @@ Signature: LanguageClient#java_classFileContents(...)

Call java/classFileContents.

*LanguageClient_showSemanticScopes*
Signature: LanguageClient_showSemanticScopes(...)

Get all Semantic Scopes and their associated highlight groups for the current
filetype (filetype of the currently open buffer) and print them.

*LanguageClient_showCursorSemanticHighlightSymbols*
Signature: LanguageClient_showCursorSemanticHighlightSymbols(...)

Get the Semantic Scope of the symbol currently under the cursor.
The result gets displayed in a popup.

*LanguageClient#explainErrorAtPoint*
Signature: LanguageClient#explainErrorAtPoint(...)

Expand Down
4 changes: 4 additions & 0 deletions plugin/LanguageClient.vim
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ if !exists('g:LanguageClient_serverCommands')
let g:LanguageClient_serverCommands = {}
endif

if !exists('g:LanguageClient_semanticHighlightMaps')
let g:LanguageClient_semanticHighlightMaps = {}
endif

function! LanguageClient_textDocument_hover(...)
return call('LanguageClient#textDocument_hover', a:000)
endfunction
Expand Down
1 change: 1 addition & 0 deletions src/language_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::vim::Vim;
use std::ops::DerefMut;

pub struct LanguageClient {
pub version: Arc<String>,
pub state_mutex: Arc<Mutex<State>>,
pub clients_mutex: Arc<Mutex<HashMap<LanguageId, Arc<Mutex<()>>>>>,
}
Expand Down
Loading