forked from L3MON4D3/LuaSnip
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request L3MON4D3#285 from leiserfg/on-the-fly
Add On the fly snippets.
- Loading branch information
Showing
8 changed files
with
325 additions
and
1 deletion.
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
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,94 @@ | ||
-- Minimal parser combinator, | ||
-- only for internal use so not exposed elsewhere nor documented in the oficial doc | ||
-- | ||
local M = {} | ||
|
||
-- Consumes strings matching a pattern, generates the matched string | ||
function M.pattern(pat) | ||
return function(text, pos) | ||
local s, e = text:find(pat, pos) | ||
|
||
if s then | ||
local v = text:sub(s, e) | ||
return true, v, pos + #v | ||
else | ||
return false, nil, pos | ||
end | ||
end | ||
end | ||
|
||
-- Matches whatever `p matches and generates whatever p generates after | ||
-- transforming it with `f | ||
function M.map(p, f) | ||
return function(text, pos) | ||
local succ, val, new_pos = p(text, pos) | ||
if succ then | ||
return true, f(val), new_pos | ||
end | ||
return false, nil, pos | ||
end | ||
end | ||
|
||
-- Matches and generates the same as the first of it's children that matches something | ||
function M.any(...) | ||
local parsers = { ... } | ||
return function(text, pos) | ||
for _, p in ipairs(parsers) do | ||
local succ, val, new_pos = p(text, pos) | ||
if succ then | ||
return true, val, new_pos | ||
end | ||
end | ||
return false, nil, pos | ||
end | ||
end | ||
|
||
-- Matches all what its children do in sequence, generates a table of its children generations | ||
function M.seq(...) | ||
local parsers = { ... } | ||
return function(text, pos) | ||
local original_pos = pos | ||
local values = {} | ||
for _, p in ipairs(parsers) do | ||
local succ, val, new_pos = p(text, pos) | ||
pos = new_pos | ||
if not succ then | ||
return false, nil, original_pos | ||
end | ||
table.insert(values, val) | ||
end | ||
return true, values, pos | ||
end | ||
end | ||
|
||
-- Matches cero or more times what it child do in sequence, generates a table with those generations | ||
function M.star(p) | ||
return function(text, pos) | ||
local len = #text | ||
local values = {} | ||
|
||
while pos <= len do | ||
local succ, val, new_pos = p(text, pos) | ||
if succ then | ||
pos = new_pos | ||
table.insert(values, val) | ||
else | ||
break | ||
end | ||
end | ||
return #values > 0, values, pos | ||
end | ||
end | ||
|
||
-- Consumes a literal string, does not generates | ||
function M.literal(t) | ||
return function(text, pos) | ||
if text:sub(pos, pos + #t - 1) == t then | ||
return true, nil, pos + #t | ||
else | ||
return false, text:sub(pos, pos + #t), pos + #t | ||
end | ||
end | ||
end | ||
|
||
return M |
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,89 @@ | ||
local ls = require("luasnip") | ||
local cp = require("luasnip.util.functions").copy | ||
local p = require("luasnip.extras._parser_combinator") | ||
local dedent = require("luasnip.util.str").dedent | ||
local M = {} | ||
|
||
local T = { EOL = "EOL", TXT = "TXT", INP = "INP" } | ||
|
||
local chunk = p.any( | ||
p.map(p.literal("$$"), function() | ||
return { T.TXT, "$" } | ||
end), | ||
p.map(p.literal("\n"), function() | ||
return { T.EOL } | ||
end), | ||
p.map(p.seq(p.literal("$"), p.pattern("%w+")), function(c) | ||
return { T.INP, c[1] } | ||
end), | ||
p.map(p.pattern("[^\n$]*"), function(c) | ||
return { T.TXT, c } | ||
end) | ||
) | ||
|
||
M._snippet_chunks = p.star(chunk) | ||
|
||
function M._txt_to_snip(txt) | ||
local t = ls.t | ||
local s = ls.s | ||
local i = ls.i | ||
local f = ls.f | ||
txt = dedent(txt) | ||
|
||
-- The parser does not handle empty strings | ||
if txt == "" then | ||
return s("", t({ "" })) | ||
end | ||
|
||
local _, chunks, _ = M._snippet_chunks(txt, 1) | ||
|
||
local current_text_arg = { "" } | ||
local nodes = {} | ||
local know_inputs = {} | ||
local last_input_pos = 0 | ||
|
||
for _, part in ipairs(chunks) do | ||
if part[1] == T.TXT then | ||
current_text_arg[#current_text_arg] = current_text_arg[#current_text_arg] | ||
.. part[2] | ||
elseif #current_text_arg > 1 or current_text_arg[1] ~= "" then | ||
table.insert(nodes, t(current_text_arg)) | ||
current_text_arg = { "" } | ||
end | ||
|
||
if part[1] == T.EOL then | ||
table.insert(current_text_arg, "") | ||
elseif part[1] == T.INP then | ||
local inp_pos = know_inputs[part[2]] | ||
if inp_pos then | ||
table.insert(nodes, f(cp, { inp_pos })) | ||
else | ||
last_input_pos = last_input_pos + 1 | ||
know_inputs[part[2]] = last_input_pos | ||
table.insert(nodes, i(last_input_pos, part[2])) | ||
end | ||
end | ||
end | ||
if #current_text_arg > 1 or current_text_arg[1] ~= "" then | ||
table.insert(nodes, t(current_text_arg)) | ||
end | ||
return s("", nodes) | ||
end | ||
|
||
local last_snip = nil | ||
local last_reg = nil | ||
|
||
-- Create snippets On The Fly | ||
-- It's advaisable not to use the default register as luasnip will probably | ||
-- override it | ||
function M.on_the_fly(regname) | ||
regname = regname or "" | ||
local reg = table.concat(vim.fn.getreg(regname, 1, true), "\n") -- Avoid eol in the last line | ||
if last_reg ~= reg then | ||
last_reg = reg | ||
last_snip = M._txt_to_snip(reg) | ||
end | ||
ls.snip_expand(last_snip) | ||
end | ||
|
||
return M |
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,21 @@ | ||
-- Some string processing utility functions | ||
local M = {} | ||
|
||
function M.dedent(s) | ||
local lst = vim.split(s, "\n") | ||
if #lst > 0 then | ||
local ind_size = math.huge | ||
for i, _ in ipairs(lst) do | ||
local i1, i2 = lst[i]:find("^%s*[^%s]") | ||
if i1 and i2 < ind_size then | ||
ind_size = i2 | ||
end | ||
end | ||
for i, _ in ipairs(lst) do | ||
lst[i] = lst[i]:sub(ind_size, -1) | ||
end | ||
end | ||
return table.concat(lst, "\n") | ||
end | ||
|
||
return M |
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,42 @@ | ||
local helpers = require("test.functional.helpers")(after_each) | ||
local exec_lua = helpers.exec_lua | ||
|
||
describe("luasnip.extra.otf", function() | ||
local function check(test_name, input, output) | ||
it(test_name, function() | ||
assert.are.same( | ||
output, | ||
exec_lua( | ||
[=[ | ||
local _, parts, _ = require("luasnip.extras.otf")._snippet_chunks(..., 1) | ||
return parts | ||
]=], | ||
input | ||
) | ||
) | ||
end) | ||
end | ||
|
||
helpers.exec("set rtp+=" .. os.getenv("LUASNIP_SOURCE")) | ||
|
||
check("Only text", "one", { { "TXT", "one" } }) | ||
check("Text and inputs", "local $val = require'module'.$color", { | ||
{ "TXT", "local " }, | ||
{ "INP", "val" }, | ||
{ "TXT", " = require'module'." }, | ||
{ "INP", "color" }, | ||
}) | ||
|
||
check( | ||
"Multiline text with escapes", | ||
"$something is more important than $$\nbut you can have both --$someone", | ||
{ | ||
{ "INP", "something" }, | ||
{ "TXT", " is more important than " }, | ||
{ "TXT", "$" }, | ||
{ "EOL" }, | ||
{ "TXT", "but you can have both --" }, | ||
{ "INP", "someone" }, | ||
} | ||
) | ||
end) |
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,22 @@ | ||
local helpers = require("test.functional.helpers")(after_each) | ||
local exec_lua = helpers.exec_lua | ||
|
||
describe("luasnip.util.str:dedent", function() | ||
local function check(test_name, input, output) | ||
it(test_name, function() | ||
assert.are.same( | ||
output, | ||
exec_lua( | ||
'return require("luasnip.util.str").dedent([[' | ||
.. input | ||
.. "]])" | ||
) | ||
) | ||
end) | ||
end | ||
|
||
check("2 and 0", " one", "one") | ||
check("0 and 2", "one\n two", "one\n two") | ||
check("2 and 1", " one\n two", " one\ntwo") | ||
check("2 and 2", " one\n two", "one\ntwo") | ||
end) |