1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
local util = require 'lspconfig.util'
local function get_default_mavenrepo()
local repo = vim.env.HOME .. '/.m2/repository/dk/au/ece/vdmj'
if vim.uv.fs_stat(repo) then
return repo
else
return vim.env.HOME .. '/.m2/repository/com/fujitsu'
end
end
local function get_jar_path(config, package, version)
return table.concat({ config.options.mavenrepo, package, version, package .. '-' .. version .. '.jar' }, '/')
end
local function with_precision(version, is_high_precision)
return is_high_precision and version:gsub('([%d.]+)', '%1-P') or version
end
local function get_latest_installed_version(repo)
local path = repo .. '/lsp'
local sort = vim.fn.sort
local subdirs = function(file)
local stat = vim.uv.fs_stat(table.concat({ path, file }, '/'))
return stat.type == 'directory' and 1 or 0
end
local candidates = vim.fn.readdir(path, subdirs)
local sorted = sort(sort(candidates, 'l'), 'N')
return sorted[#sorted]
end
-- Special case, as vdmj store particular settings under root_dir/.vscode
local function find_vscode_ancestor(startpath)
return util.search_ancestors(startpath, function(path)
if vim.fn.isdirectory(path .. '/.vscode') == 1 then
return path
end
end)
end
return {
default_config = {
cmd = { 'java' },
filetypes = { 'vdmsl', 'vdmpp', 'vdmrt' },
root_dir = function(fname)
return vim.fs.dirname(vim.fs.find('.git', { path = fname, upward = true })[1]) or find_vscode_ancestor(fname)
end,
options = {
java = vim.env.JAVA_HOME and (vim.env.JAVA_HOME .. '/bin/java') or 'java',
java_opts = { '-Xmx3000m', '-Xss1m' },
annotation_paths = {},
mavenrepo = get_default_mavenrepo(),
logfile = vim.fn.stdpath('cache') .. '/vdm-lsp.log',
debugger_port = -1,
high_precision = false,
},
},
docs = {
description = [[
https://github.com/nickbattle/vdmj
The VDMJ language server can be installed by cloning the VDMJ repository and
running `mvn clean install`.
Various options are provided to configure the language server (see below). In
particular:
- `annotation_paths` is a list of folders and/or jar file paths for annotations
that should be used with the language server;
- any value of `debugger_port` less than zero will disable the debugger; note
that if a non-zero value is used, only one instance of the server can be active
at a time.
More settings for VDMJ can be changed in a file called `vdmj.properties` under
`root_dir/.vscode`. For a description of the available settings, see
[Section 7 of the VDMJ User Guide](https://raw.githubusercontent.com/nickbattle/vdmj/master/vdmj/documentation/UserGuide.pdf).
Note: proof obligations and combinatorial testing are not currently supported
by neovim.
]],
},
on_new_config = function(config, root_dir)
local version = with_precision(
config.options.version or get_latest_installed_version(config.options.mavenrepo),
config.options.high_precision
)
local classpath = table.concat({
get_jar_path(config, 'vdmj', version),
get_jar_path(config, 'annotations', version),
get_jar_path(config, 'lsp', version),
root_dir .. '/.vscode',
unpack(config.options.annotation_paths),
}, ':')
local java_cmd = {
config.options.java,
config.options.java_opts,
'-Dlsp.log.filename=' .. config.options.logfile,
'-cp',
classpath,
}
local dap = {}
if config.options.debugger_port >= 0 then
-- TODO: LS will fail to start if port is already in use
dap = { '-dap', tostring(config.options.debugger_port) }
end
local vdmj_cmd = {
'lsp.LSPServerStdio',
'-' .. vim.bo.filetype,
dap,
}
config.cmd = util.tbl_flatten { java_cmd, vdmj_cmd }
end,
}
|