馃 my neovim config:)
1if vim.g.loaded_ember then
2 return
3end
4
5vim.g.loaded_ember = true
6
7---@type table<vim.lsp.protocol.Method, fun(params: table, callback:fun(err: lsp.ResponseError?, result: any))>
8local handlers = {}
9local ms = vim.lsp.protocol.Methods
10
11local chars = {}
12for i = 32, 126 do
13 table.insert(chars, string.char(i))
14end
15
16---@type lsp.InitializeResult
17local initializeResult = {
18 capabilities = {
19 hoverProvider = true,
20 definitionProvider = true,
21 referencesProvider = true,
22 completionProvider = {
23 triggerCharacters = chars,
24 },
25 },
26 serverInfo = {
27 name = "ember_ls",
28 version = "0.0.1",
29 },
30}
31
32handlers[ms.initialize] = function(_, callback)
33 callback(nil, initializeResult)
34end
35
36-- hover ======================================================================
37
38---@param _ lsp.HoverParams
39---@param callback fun(err?: lsp.ResponseError, result: lsp.Hover)
40handlers[ms.textDocument_hover] = function(_, callback)
41 local word = vim.fn.expand("<cword>")
42 local url_format = "https://api.dictionaryapi.dev/api/v2/entries/en/%s"
43
44 vim.system(
45 { "curl", url_format:format(word) },
46 vim.schedule_wrap(function(out)
47 local contents
48 if out.code ~= 0 then
49 contents = "word fetch failed"
50 else
51 local ok, decoded = pcall(vim.json.decode, out.stdout)
52 if ok and decoded and decoded[1] then
53 contents = decoded[1].meanings[1].definitions[1].definition
54 else
55 contents = decoded.message -- this api gives a nice message if no result
56 end
57 end
58 callback(nil, { contents = contents })
59 end)
60 )
61end
62
63-- completion =================================================================
64
65---@param params lsp.CompletionParams
66---@return string word_to_complete
67local get_word_to_complete = function(params)
68 local col = params.position.character + 1
69 local line = vim.api.nvim_get_current_line()
70 local line_to_cursor = line:sub(1, col)
71 local regex = vim.regex("\\k*$")
72
73 return line:sub(regex:match_str(line_to_cursor) + 1, col)
74end
75
76---@return vim.lsp.inline_completion.Item[]
77local function completion_buffer(params)
78 local word = get_word_to_complete(params)
79
80 local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false)
81 local matches = vim.fn.matchstrlist(lines, [[\<\k\+\>]])
82 vim.list.unique(matches, function(x)
83 ---@diagnostic disable-next-line: undefined-field
84 return x.text
85 end)
86 matches = vim.fn.matchfuzzy(matches, word, { key = "text" })
87 return vim
88 .iter(matches)
89 :map(function(v)
90 -- dont match current word
91 if v.text == word then
92 return
93 end
94 return {
95 label = v.text,
96 kind = vim.lsp.protocol.CompletionItemKind["Text"],
97 }
98 end)
99 :totable()
100end
101
102local get_spell_candidates = vim.func._memoize("concat", function(w)
103 local entries = vim.fn.spellsuggest(w)
104 entries = vim.fn.matchfuzzy(entries, w, { limit = 5 })
105
106 return vim
107 .iter(entries)
108 :map(function(v)
109 if string.find(v, "[ ']") ~= nil then
110 return
111 end
112 return {
113 label = v,
114 kind = vim.lsp.protocol.CompletionItemKind["Text"],
115 }
116 end)
117 :totable()
118end)
119
120---@return vim.lsp.inline_completion.Item[]
121local function completion_spell(params)
122 local word = get_word_to_complete(params)
123
124 return get_spell_candidates(word)
125end
126
127---@param params lsp.CompletionParams
128---@param callback fun(err?: lsp.ResponseError, result: lsp.CompletionItem[])
129handlers[ms.textDocument_completion] = function(params, callback)
130 local items = {}
131 if vim.wo.spell then
132 vim.list_extend(items, completion_spell(params))
133 end
134 vim.list_extend(items, completion_buffer(params))
135
136 callback(nil, {
137 items = items,
138 isIncomplete = #items > 0,
139 })
140end
141
142-- init =======================================================================
143
144---@type vim.lsp.ClientConfig
145local cfg = {
146 name = "ember_ls",
147 cmd = function()
148 return {
149 request = function(method, params, callback)
150 if handlers[method] then
151 handlers[method](params, callback)
152 end
153 end,
154 notify = function() end,
155 is_closing = function() end,
156 terminate = function() end,
157 }
158 end,
159}
160
161vim.lsp.config("ember_ls", cfg)