summaryrefslogtreecommitdiff
path: root/lua/blink/cmp/sources/snippets/utils.lua
diff options
context:
space:
mode:
Diffstat (limited to 'lua/blink/cmp/sources/snippets/utils.lua')
-rw-r--r--lua/blink/cmp/sources/snippets/utils.lua89
1 files changed, 89 insertions, 0 deletions
diff --git a/lua/blink/cmp/sources/snippets/utils.lua b/lua/blink/cmp/sources/snippets/utils.lua
new file mode 100644
index 0000000..f0903b7
--- /dev/null
+++ b/lua/blink/cmp/sources/snippets/utils.lua
@@ -0,0 +1,89 @@
+local utils = {
+ parse_cache = {},
+}
+
+--- Parses the json file and notifies the user if there's an error
+---@param path string
+---@param json string
+function utils.parse_json_with_error_msg(path, json)
+ local ok, parsed = pcall(vim.json.decode, json)
+ if not ok then
+ vim.notify(
+ 'Failed to parse json file "' .. path .. '" for blink.cmp snippets. Error: ' .. parsed,
+ vim.log.levels.ERROR,
+ { title = 'blink.cmp' }
+ )
+ return {}
+ end
+ return parsed
+end
+
+---@type fun(path: string): string|nil
+function utils.read_file(path)
+ local file = io.open(path, 'r')
+ if not file then return nil end
+ local content = file:read('*a')
+ file:close()
+ return content
+end
+
+---@type fun(input: string): vim.snippet.Node<vim.snippet.SnippetData>|nil
+function utils.safe_parse(input)
+ if utils.parse_cache[input] then return utils.parse_cache[input] end
+
+ local safe, parsed = pcall(vim.lsp._snippet_grammar.parse, input)
+ if not safe then return nil end
+
+ utils.parse_cache[input] = parsed
+ return parsed
+end
+
+---@type fun(snippet: blink.cmp.Snippet, fallback: string): table
+function utils.read_snippet(snippet, fallback)
+ local snippets = {}
+ local prefix = snippet.prefix or fallback
+ local description = snippet.description or fallback
+ local body = snippet.body
+
+ if type(description) == 'table' then description = vim.fn.join(description, '') end
+
+ if type(prefix) == 'table' then
+ for _, p in ipairs(prefix) do
+ snippets[p] = {
+ prefix = p,
+ body = body,
+ description = description,
+ }
+ end
+ else
+ snippets[prefix] = {
+ prefix = prefix,
+ body = body,
+ description = description,
+ }
+ end
+ return snippets
+end
+
+function utils.get_tab_stops(snippet)
+ local expanded_snippet = require('blink.cmp.sources.snippets.utils').safe_parse(snippet)
+ if not expanded_snippet then return end
+
+ local tabstops = {}
+ local grammar = require('vim.lsp._snippet_grammar')
+ local line = 1
+ local character = 1
+ for _, child in ipairs(expanded_snippet.data.children) do
+ local lines = tostring(child) == '' and {} or vim.split(tostring(child), '\n')
+ line = line + math.max(#lines - 1, 0)
+ character = #lines == 0 and character or #lines > 1 and #lines[#lines] or (character + #lines[#lines])
+ if child.type == grammar.NodeType.Placeholder or child.type == grammar.NodeType.Tabstop then
+ table.insert(tabstops, { index = child.data.tabstop, line = line, character = character })
+ end
+ end
+
+ table.sort(tabstops, function(a, b) return a.index < b.index end)
+ return tabstops
+end
+
+return utils