-
-
Notifications
You must be signed in to change notification settings - Fork 248
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add function for editing current snippet.
- Loading branch information
Showing
2 changed files
with
206 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
local log = require("luasnip.util.log").new("snip_edit") | ||
local Source = require("luasnip.session.snippet_collection.source") | ||
|
||
local M = {} | ||
|
||
-- return: 4-tuple, {start_line, start_col, end_line, end_col}, range of | ||
-- function-call. | ||
local function lua_find_function_call_node_at(bufnr, line) | ||
local has_parser, parser = pcall(vim.treesitter.get_parser, bufnr) | ||
if not has_parser then | ||
log.warn("Cannot determine range of function-call: treesitter-parser for lua not installed.") | ||
return nil | ||
end | ||
|
||
local root = parser:parse()[1]:root() | ||
local query = vim.treesitter.parse_query("lua", [[(function_call) @f_call]]) | ||
for _, node, _ in query:iter_captures(root, bufnr, line, line+300) do | ||
if node:range() == line then | ||
return {node:range()} | ||
end | ||
end | ||
log.warn("Cannot determine range of function-call: Query for `(function_call)` starting at line %s did not yield a result.") | ||
return nil | ||
end | ||
|
||
local function range_highlight(line_start, line_end, hl_duration_ms) | ||
-- make sure line_end is also visible. | ||
vim.api.nvim_win_set_cursor(0, {line_end, 0}) | ||
vim.api.nvim_win_set_cursor(0, {line_start, 0}) | ||
|
||
if hl_duration_ms > 0 then | ||
local hl_buf = vim.api.nvim_get_current_buf() | ||
|
||
-- highlight snippet for 1000ms | ||
local id = vim.api.nvim_buf_set_extmark(hl_buf, ls.session.ns_id, line_start-1, 0, { | ||
-- one line below, at col 0 => entire last line is highlighted. | ||
end_row = line_end-1+1, | ||
hl_group = "Visual" | ||
}) | ||
vim.defer_fn(function() | ||
vim.api.nvim_buf_del_extmark(hl_buf, ls.session.ns_id, id) | ||
end, hl_duration_ms) | ||
end | ||
end | ||
|
||
local function json_find_snippet_definition(bufnr, snippet_name) | ||
local has_parser, parser = pcall(vim.treesitter.get_parser, bufnr) | ||
if not has_parser then | ||
log.warn("Cannot determine definition of snippet: treesitter-parser for json(c) not installed.") | ||
return nil | ||
end | ||
|
||
local root = parser:parse()[1]:root() | ||
-- for a, b in root:child(0):iter_children() do | ||
-- Insp(a:field("key")[1]:child(1):range()) | ||
-- end | ||
-- don't want to pass through if this file is json or jsonc, just use | ||
-- parser-language. | ||
local query = vim.treesitter.parse_query(parser:lang(), ([[ | ||
(pair | ||
key: (string (string_content) @key (#eq? @key "%s")) | ||
) @snippet | ||
]]):format(snippet_name)) | ||
for id, node, _ in query:iter_captures(root, bufnr) do | ||
if query.captures[id] == "snippet" and node:parent():parent() == root then | ||
return {node:range()} | ||
end | ||
end | ||
|
||
return nil | ||
end | ||
|
||
local function win_edit(file) | ||
vim.api.nvim_command(":e " .. file) | ||
end | ||
|
||
function M.jump_to_snippet(snip, opts) | ||
opts = opts or {} | ||
local hl_duration_ms = opts.hl_duration_ms or 1500 | ||
local edit_fn = opts.edit_fn or win_edit | ||
|
||
local source = Source.get(snip) | ||
if not source then | ||
print("Snippet does not have a source.") | ||
return | ||
end | ||
|
||
edit_fn(source.file) | ||
-- assumption: after this, file is the current buffer. | ||
|
||
if source.line and source.line_end then | ||
-- happy path: we know both begin and end of snippet-definition. | ||
range_highlight(source.line, source.line_end, hl_duration_ms) | ||
return | ||
end | ||
|
||
local fcall_range | ||
if vim.api.nvim_buf_get_name(0):match("%.lua$") then | ||
if source.line then | ||
-- in lua-file, can get region of definition via treesitter. | ||
-- 0: current buffer. | ||
fcall_range = lua_find_function_call_node_at(0, source.line-1) | ||
if not fcall_range then | ||
vim.api.nvim_win_set_cursor(0, {source.line, 0}) | ||
return | ||
end | ||
else | ||
print("Can't jump to snippet: source does not provide line.") | ||
return | ||
end | ||
-- matches *.json or *.jsonc. | ||
elseif vim.api.nvim_buf_get_name(0):match("%.jsonc?$") then | ||
-- 0: current buffer. | ||
fcall_range = json_find_snippet_definition(0, snip.name) | ||
if not fcall_range then | ||
print("Could not find range of snippet `" .. snip.name .. "`.") | ||
return | ||
end | ||
else | ||
print("Unknown filetype, don't know how to highlight snippet.") | ||
return | ||
end | ||
|
||
-- 1 is line_from, 3 is line_end. | ||
-- +1 since range is row-0-indexed. | ||
range_highlight(fcall_range[1]+1, fcall_range[3]+1, hl_duration_ms) | ||
|
||
local new_source = Source.from_location( | ||
source.file, | ||
{ line = fcall_range[1]+1, line_end = fcall_range[3]+1 }) | ||
Source.set(snip, new_source) | ||
end | ||
|
||
function M.jump_to_active_snippet(opts) | ||
local active_node = require("luasnip.session").current_nodes[vim.api.nvim_get_current_buf()] | ||
if not active_node then | ||
print("No active snippet.") | ||
return | ||
end | ||
|
||
local snip = active_node.parent.snippet | ||
M.jump_to_snippet(snip, opts) | ||
end | ||
|
||
return M |