Skip to content

Commit 4460833

Browse files
authored
Allow workspace_config to be a function (#1400)
It is sometimes useful to generate `workspace_config` using a callback. For example, if the produced config needs to include some information from the actual workspace.
1 parent e82e73a commit 4460833

File tree

4 files changed

+218
-5
lines changed

4 files changed

+218
-5
lines changed

autoload/lsp.vim

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,7 @@ function! s:ensure_conf(buf, server_name, cb) abort
716716
call s:send_notification(a:server_name, {
717717
\ 'method': 'workspace/didChangeConfiguration',
718718
\ 'params': {
719-
\ 'settings': l:server_info['workspace_config'],
719+
\ 'settings': lsp#utils#workspace_config#get(a:server_name),
720720
\ }
721721
\ })
722722
endif
@@ -934,7 +934,8 @@ function! s:on_request(server_name, id, request) abort
934934
call lsp#utils#workspace_edit#apply_workspace_edit(a:request['params']['edit'])
935935
call s:send_response(a:server_name, { 'id': a:request['id'], 'result': { 'applied': v:true } })
936936
elseif a:request['method'] ==# 'workspace/configuration'
937-
let l:response_items = map(a:request['params']['items'], { key, val -> lsp#utils#workspace_config#get_value(a:server_name, val) })
937+
let l:config = lsp#utils#workspace_config#get(a:server_name)
938+
let l:response_items = map(a:request['params']['items'], { key, val -> lsp#utils#workspace_config#projection(l:config, val) })
938939
call s:send_response(a:server_name, { 'id': a:request['id'], 'result': l:response_items })
939940
elseif a:request['method'] ==# 'workspace/workspaceFolders'
940941
let l:server_info = s:servers[a:server_name]['server_info']
@@ -1309,6 +1310,13 @@ function! lsp#update_workspace_config(server_name, workspace_config) abort
13091310
let l:server = s:servers[a:server_name]
13101311
let l:server_info = l:server['server_info']
13111312
if has_key(l:server_info, 'workspace_config')
1313+
if type(l:server_info['workspace_config']) == v:t_func
1314+
call lsp#utils#error('''workspace_config'' is a function, so
1315+
\ lsp#update_workspace_config() can not be used. Either
1316+
\ replace function with a dictionary, or adjust the value
1317+
\ generated by the function as necessary.')
1318+
return
1319+
endif
13121320
call s:merge_dict(l:server_info['workspace_config'], a:workspace_config)
13131321
else
13141322
let l:server_info['workspace_config'] = a:workspace_config

autoload/lsp/utils/workspace_config.vim

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,23 @@
1-
function! lsp#utils#workspace_config#get_value(server_name, item) abort
1+
function! lsp#utils#workspace_config#get(server_name) abort
22
try
33
let l:server_info = lsp#get_server_info(a:server_name)
4-
let l:config = l:server_info['workspace_config']
4+
let l:config_type = type(l:server_info['workspace_config'])
5+
6+
if l:config_type == v:t_func
7+
let l:config = l:server_info['workspace_config'](l:server_info)
8+
else
9+
let l:config = l:server_info['workspace_config']
10+
endif
11+
12+
return l:config
13+
catch
14+
return v:null
15+
endtry
16+
endfunction
17+
18+
function! lsp#utils#workspace_config#projection(config, item) abort
19+
try
20+
let l:config = a:config
521

622
for l:section in split(a:item['section'], '\.')
723
let l:config = l:config[l:section]
@@ -12,3 +28,8 @@ function! lsp#utils#workspace_config#get_value(server_name, item) abort
1228
return v:null
1329
endtry
1430
endfunction
31+
32+
function! lsp#utils#workspace_config#get_value(server_name, item) abort
33+
let l:config = lsp#utils#workspace_config#get(a:server_name)
34+
return lsp#utils#workspace_config#projection(l:config, a:item)
35+
endfunction

doc/vim-lsp.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1281,7 +1281,8 @@ The vim |dict| containing information about the server.
12811281
'blocklist': ['javascript', 'typescript']
12821282
<
12831283
* workspace_config:
1284-
optional vim |dict|
1284+
optional
1285+
vim |dict| or a function returning a vim |dict|
12851286
Used to pass workspace configuration to the server after
12861287
initialization. Configuration settings are language-server specific.
12871288

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
Describe lsp#utils#workspace_config
2+
3+
Describe lsp#utils#workspace_config#get
4+
It should return the workspace config, when it is a dict
5+
let l:name = 'Unit Test Server'
6+
7+
call lsp#register_server({
8+
\ 'name': l:name,
9+
\ 'workspace_config': {
10+
\ 'a': {
11+
\ 'a1': v:true,
12+
\ 'a2': {
13+
\ 'a21': 'disabled',
14+
\ },
15+
\ },
16+
\ 'b': 'path/to/file',
17+
\ }
18+
\ })
19+
20+
let l:config = lsp#utils#workspace_config#get(l:name)
21+
22+
Assert Equals(l:config['a']['a1'], v:true)
23+
Assert Equals(l:config['a']['a2']['a21'], 'disabled')
24+
Assert Equals(l:config['b'], 'path/to/file')
25+
end
26+
27+
It should return the workspace config, produced by a callback
28+
let l:name = 'Unit Test Server'
29+
30+
let l:callResult = {}
31+
32+
call lsp#register_server({
33+
\ 'name': l:name,
34+
\ 'workspace_config': {server_info->l:callResult},
35+
\ })
36+
37+
let l:config = lsp#utils#workspace_config#get(l:name)
38+
Assert Equals(l:config, {})
39+
40+
let l:callResult = {
41+
\ 'a': {
42+
\ 'a1': v:true,
43+
\ 'a2': {
44+
\ 'a21': 'disabled',
45+
\ },
46+
\ },
47+
\ 'b': 'path/to/file'
48+
\ }
49+
50+
let l:config = lsp#utils#workspace_config#get(l:name)
51+
Assert Equals(l:config['a']['a1'], v:true)
52+
Assert Equals(l:config['a']['a2']['a21'], 'disabled')
53+
Assert Equals(l:config['b'], 'path/to/file')
54+
end
55+
End
56+
57+
Describe lsp#utils#workspace_config#project
58+
It should return a projection of a dictionary
59+
let l:config = {
60+
\ 'a': {
61+
\ 'a1': v:true,
62+
\ 'a2': {
63+
\ 'a21': 'disabled',
64+
\ },
65+
\ },
66+
\ 'b': 'path/to/file',
67+
\ }
68+
69+
let l:config_a_a1 = lsp#utils#workspace_config#projection(
70+
\ l:config,
71+
\ { 'section': 'a.a1' },
72+
\ )
73+
let l:config_a_a2_a21 = lsp#utils#workspace_config#projection(
74+
\ l:config,
75+
\ { 'section': 'a.a2.a21' },
76+
\ )
77+
let l:config_b = lsp#utils#workspace_config#projection(
78+
\ l:config,
79+
\ { 'section': 'b' },
80+
\ )
81+
let l:config_c = lsp#utils#workspace_config#projection(
82+
\ l:config,
83+
\ { 'section': 'c' },
84+
\ )
85+
86+
Assert Equals(l:config_a_a1, v:true)
87+
Assert Equals(l:config_a_a2_a21, 'disabled')
88+
Assert Equals(l:config_b, 'path/to/file')
89+
Assert Equals(l:config_c, v:null)
90+
end
91+
End
92+
93+
Describe lsp#utils#workspace_config#get_value
94+
It should return a projection of the workspace config, when it is a dict
95+
let l:name = 'Unit Test Server'
96+
97+
call lsp#register_server({
98+
\ 'name': l:name,
99+
\ 'workspace_config': {
100+
\ 'a': {
101+
\ 'a1': v:true,
102+
\ 'a2': {
103+
\ 'a21': 'disabled',
104+
\ },
105+
\ },
106+
\ 'b': "path/to/file",
107+
\ }
108+
\ })
109+
110+
let l:config_a_a1 = lsp#utils#workspace_config#get_value(
111+
\ l:name,
112+
\ { 'section': 'a.a1' },
113+
\ )
114+
let l:config_a_a2_a21 = lsp#utils#workspace_config#get_value(
115+
\ l:name,
116+
\ { 'section': 'a.a2.a21' },
117+
\ )
118+
let l:config_b = lsp#utils#workspace_config#get_value(
119+
\ l:name,
120+
\ { 'section': 'b' },
121+
\ )
122+
let l:config_c = lsp#utils#workspace_config#get_value(
123+
\ l:name,
124+
\ { 'section': 'c' },
125+
\ )
126+
127+
Assert Equals(l:config_a_a1, v:true)
128+
Assert Equals(l:config_a_a2_a21, 'disabled')
129+
Assert Equals(l:config_b, 'path/to/file')
130+
Assert Equals(l:config_c, v:null)
131+
end
132+
133+
It should return a projection of the workspace config, produced by a callback
134+
let l:name = 'Unit Test Server'
135+
136+
let l:callResult = {}
137+
138+
call lsp#register_server({
139+
\ 'name': l:name,
140+
\ 'workspace_config': {server_info->l:callResult},
141+
\ })
142+
143+
let l:config = lsp#utils#workspace_config#get_value(
144+
\ l:name,
145+
\ { 'section': '' },
146+
\ )
147+
Assert Equals(l:config, {})
148+
149+
let l:callResult = {
150+
\ 'a': {
151+
\ 'a1': v:true,
152+
\ 'a2': {
153+
\ 'a21': 'disabled',
154+
\ },
155+
\ },
156+
\ 'b': "path/to/file",
157+
\ }
158+
159+
let l:config_a_a1 = lsp#utils#workspace_config#get_value(
160+
\ l:name,
161+
\ { 'section': 'a.a1' },
162+
\ )
163+
let l:config_a_a2_a21 = lsp#utils#workspace_config#get_value(
164+
\ l:name,
165+
\ { 'section': 'a.a2.a21' },
166+
\ )
167+
let l:config_b = lsp#utils#workspace_config#get_value(
168+
\ l:name,
169+
\ { 'section': 'b' },
170+
\ )
171+
let l:config_c = lsp#utils#workspace_config#get_value(
172+
\ l:name,
173+
\ { 'section': 'c' },
174+
\ )
175+
176+
Assert Equals(l:config_a_a1, v:true)
177+
Assert Equals(l:config_a_a2_a21, 'disabled')
178+
Assert Equals(l:config_b, 'path/to/file')
179+
Assert Equals(l:config_c, v:null)
180+
end
181+
End
182+
End
183+

0 commit comments

Comments
 (0)