Add initial support for workspace folders (#1265)

* add g:lsp_experimental_workspace_folders

* send client capabilities for workspaceFolders if g:lsp_experimental_workspace_folders is enabled

* fix g:lsp_experimental_workspace_folders missing s

* send workspaceFolders if workspaceFolder capability is defined via client

* add local copy add opened workspace folders

* Add support for workspace folders

* document Workspace folders

* add indent

* fix doc indent
This commit is contained in:
Prabir Shrestha
2022-02-12 12:28:43 -08:00
committed by GitHub
parent 66b56c026f
commit 3d0fc4072b
4 changed files with 70 additions and 3 deletions

View File

@@ -1,7 +1,8 @@
let s:enabled = 0
let s:already_setup = 0
let s:Stream = lsp#callbag#makeSubject()
let s:servers = {} " { lsp_id, server_info, init_callbacks, init_result, buffers: { path: { changed_tick } }
" workspace_folders = { 'uri': { uri, name } }
let s:servers = {} " { lsp_id, server_info, workspace_folders, init_callbacks, init_result, buffers: { path: { changed_tick } }
let s:last_command_id = 0
let s:notification_callbacks = [] " { name, callback }
@@ -167,10 +168,12 @@ function! lsp#register_server(server_info) abort
if has_key(s:servers, l:server_name)
call lsp#log('lsp#register_server', 'server already registered', l:server_name)
endif
" NOTE: workspace_folders is dict for faster lookup instead of array
let s:servers[l:server_name] = {
\ 'server_info': a:server_info,
\ 'lsp_id': 0,
\ 'buffers': {},
\ 'workspace_folders': {},
\ }
call lsp#log('lsp#register_server', 'server registered', l:server_name)
doautocmd <nomodeline> User lsp_register_server
@@ -565,7 +568,8 @@ function! lsp#default_get_supported_capabilities(server_info) abort
\ },
\ 'workspace': {
\ 'applyEdit': v:true,
\ 'configuration': v:true
\ 'configuration': v:true,
\ 'workspaceFolders': g:lsp_experimental_workspace_folders ? v:true : v:false,
\ },
\ }
endfunction
@@ -598,6 +602,7 @@ function! s:ensure_init(buf, server_name, cb) abort
let l:root_uri = lsp#utils#get_default_root_uri()
endif
let l:server['server_info']['_root_uri_resolved'] = l:root_uri
let l:server['workspace_folders'][l:root_uri] = { 'name': l:root_uri, 'uri': l:root_uri }
if has_key(l:server_info, 'capabilities')
let l:capabilities = l:server_info['capabilities']
@@ -617,6 +622,15 @@ function! s:ensure_init(buf, server_name, cb) abort
\ },
\ }
let l:workspace_capabilities = get(l:capabilities, 'workspace', {})
if get(l:workspace_capabilities, 'workspaceFolders', v:false)
" TODO: extract folder name for l:root_uri
let l:server_info['workspaceFolders'] = [
\ { 'uri': l:root_uri, 'name': l:root_uri }
\ ]
let l:request['params']['workspaceFolders'] = l:server_info['workspaceFolders']
endif
if has_key(l:server_info, 'initialization_options')
let l:request.params['initializationOptions'] = l:server_info['initialization_options']
endif
@@ -645,7 +659,6 @@ endfunction
function! s:text_changes(buf, server_name) abort
let l:sync_kind = lsp#capabilities#get_text_document_change_sync_kind(a:server_name)
" When syncKind is None, return null for contentChanges.
if l:sync_kind == 0
return v:null
@@ -729,6 +742,10 @@ function! s:ensure_open(buf, server_name, cb) abort
return
endif
if lsp#capabilities#has_workspace_folders_change_notifications(a:server_name)
call s:workspace_add_folder(a:server_name)
endif
call s:update_file_content(a:buf, a:server_name, lsp#utils#buffer#_get_lines(a:buf))
let l:buffer_info = { 'changed_tick': getbufvar(a:buf, 'changedtick'), 'version': 1, 'uri': l:path }
@@ -748,6 +765,24 @@ function! s:ensure_open(buf, server_name, cb) abort
call a:cb(l:msg)
endfunction
function! s:workspace_add_folder(server_name) abort
if !g:lsp_experimental_workspace_folders | return | endif
let l:server = s:servers[a:server_name]
let l:server_info = l:server['server_info']
let l:root_uri = has_key(l:server_info, 'root_uri') ? l:server_info['root_uri'](l:server_info) : lsp#utils#get_default_root_uri()
if !has_key(l:server['workspace_folders'], l:root_uri)
let l:workspace_folder = { 'name': l:root_uri, 'uri': l:root_uri }
call lsp#log('adding workspace folder', a:server_name, l:workspace_folder)
call s:send_notification(a:server_name, {
\ 'method': 'workspace/didChangeWorkspaceFolders',
\ 'params': {
\ 'added': [l:workspace_folder],
\ }
\ })
let l:server['workspace_folders'][l:root_uri] = l:workspace_folder
endif
endfunction
function! s:send_request(server_name, data) abort
let l:lsp_id = s:servers[a:server_name]['lsp_id']
let l:data = copy(a:data)
@@ -789,6 +824,7 @@ function! s:on_exit(server_name, id, data, event) abort
if has_key(l:server, 'init_result')
unlet l:server['init_result']
endif
let l:server['workspace_folders'] = {}
call lsp#stream(1, { 'server': '$vimlsp',
\ 'response': { 'method': '$/vimlsp/lsp_server_exit', 'params': { 'server': a:server_name } } })
doautocmd <nomodeline> User lsp_server_exit

View File

@@ -33,6 +33,22 @@ function! lsp#capabilities#has_rename_prepare_provider(server_name) abort
return s:has_provider(a:server_name, 'renameProvider', 'prepareProvider')
endfunction
function! lsp#capabilities#has_workspace_folders_change_notifications(server_name) abort
let l:capabilities = lsp#get_server_capabilities(a:server_name)
if type(l:capabilities) == type({}) && !empty(l:capabilities)
let l:workspace = get(l:capabilities, 'workspace', {})
if type(l:workspace) == type({}) && !empty(l:workspace)
let l:workspace_folders = get(l:workspace, 'workspaceFolders', {})
if type(l:workspace_folders) == type({}) && !empty(l:workspace_folders)
if get(l:workspace_folders, 'supported', v:false) && get(l:workspace_folders, 'changeNotifications', '') ==# 'workspace/didChangeWorkspaceFolders'
return v:true
endif
endif
endif
endif
return v:false
endfunction
function! lsp#capabilities#has_document_formatting_provider(server_name) abort
return s:has_provider(a:server_name, 'documentFormattingProvider')
endfunction

View File

@@ -157,6 +157,7 @@ CONTENTS *vim-lsp-contents*
Folding |vim-lsp-folding|
Semantic highlighting |vim-lsp-semantic|
Popup Formatting |vim-lsp-popup-format|
Workspace Folders |vim-lsp-workspace-folders|
License |vim-lsp-license|
Maintainers |vim-lsp-maintainers|
@@ -2023,6 +2024,18 @@ For customization, see
|formatprg|.
==============================================================================
Workspace Folders *vim-lsp-workspace-folders*
Workspace folders is an experimental feature of vim-lsp. To enable workspace
folders set `let g:lsp_experimental_workspace_folders = 1`. In the future this
flag will be removed and workspace folders will be enabled by default.
When a new buffer is opened, if the server supports workspace folder, it will
call `root_uri` function to detect the workspace folder. If the folder is not
part of workspace folder, it will automatically notify the server to add the
workspace folder.
=============================================================================
License *vim-lsp-license*
The MIT License (MIT)

View File

@@ -73,6 +73,8 @@ let g:lsp_untitled_buffer_enabled = get(g:, 'lsp_untitled_buffer_enabled', 1)
let g:lsp_get_supported_capabilities = get(g:, 'lsp_get_supported_capabilities', [function('lsp#default_get_supported_capabilities')])
let g:lsp_experimental_workspace_folders = get(g:, 'lsp_experimental_workspace_folders', 0)
if g:lsp_auto_enable
augroup lsp_auto_enable
autocmd!