From 6fd5067bc499467aaf3c953e2e88aacb8852f744 Mon Sep 17 00:00:00 2001 From: David JULIEN Date: Fri, 29 Apr 2022 00:20:18 +0200 Subject: [PATCH] [nvim] fix: snippets config --- .config/nvim/after/ftplugin/c.lua | 52 +-- .config/nvim/after/ftplugin/tex.lua | 162 ++++----- .config/nvim/lua/plugin/luasnip.lua | 521 ++++++++++++++-------------- 3 files changed, 367 insertions(+), 368 deletions(-) diff --git a/.config/nvim/after/ftplugin/c.lua b/.config/nvim/after/ftplugin/c.lua index e75fba3..b42e1a6 100644 --- a/.config/nvim/after/ftplugin/c.lua +++ b/.config/nvim/after/ftplugin/c.lua @@ -20,32 +20,32 @@ local f = ls.function_node local copy = utils.copy -ls.snippets = { - c = { - s("main", { - t({ "int main(int argc, char* argv[])" }), - t({ "", "{", "\t" }), +ls.add_snippets( "c", { + s("main", { + t({ "int main(int argc, char* argv[])" }), + t({ "", "{", "\t" }), + i(0), + t({ "", "\treturn 0;"}), + t({ "", "}"}), + }), + s("fn", { + -- Simple static text. + t("//Parameters: "), + -- function, first parameter is the function, second the Placeholders + -- whose text it gets as input. + f(copy, 2), + t({ "", "" }), + -- Placeholder/Insert. + i(1), + t("("), + -- Placeholder with initial text. + i(2, "int foo"), + -- Linebreak + t({ ")", "{", "\t" }), i(0), t({ "", "\treturn 0;"}), t({ "", "}"}), - }), - s("fn", { - -- Simple static text. - t("//Parameters: "), - -- function, first parameter is the function, second the Placeholders - -- whose text it gets as input. - f(copy, 2), - t({ "", "" }), - -- Placeholder/Insert. - i(1), - t("("), - -- Placeholder with initial text. - i(2, "int foo"), - -- Linebreak - t({ ")", "{", "\t" }), - i(0), - t({ "", "\treturn 0;"}), - t({ "", "}"}), - }), - }, -} + }), +}, { + key = "c" + }) diff --git a/.config/nvim/after/ftplugin/tex.lua b/.config/nvim/after/ftplugin/tex.lua index 71c702f..8ec747a 100644 --- a/.config/nvim/after/ftplugin/tex.lua +++ b/.config/nvim/after/ftplugin/tex.lua @@ -44,86 +44,86 @@ local function rec_ls() ) end -ls.snippets = { - tex = { - -- rec_ls is self-referencing. That makes this snippet 'infinite' eg. have as many - -- \item as necessary by utilizing a choiceNode. - s("ls", { - t({ "\\begin{itemize}", "\t\\item " }), - i(1), - t({ "" }), - d(2, rec_ls, {}), - t({ "", "\\end{itemize}", "" }), - }), - s("lsl", { - t({ "\\begin{itemize}[label=" }), - i(1), - t( { "]", "\t\\item " }), - i(2), - t({ "" }), - d(3, rec_ls, {}), - t({ "", "\\end{itemize}", "" }), - }), - s("frm", { - t({ "\\begin{" }), - i(1), - t({ "}[" }), - i(2), - t({ "]{" }), - f(copy, 1), - t({ ":" }), - i(3, "foo"), - t({ "}", "\t" }), - i(0), - t({ "", "\\end{" }), - f(copy, 1), - t({ "}", "" }), - }), - s("env", { - t({ "\\begin{" }), - i(1, "foo"), - t({ "}", "\t" }), - i(2), - t({ "", "\\end{" }), - f(copy,1), - t({ "}"}), - }), - s("tikz", { - t({ "\\begin{center}" }), - t({ "", "\t\\begin{tikzpicture}[main/.style = {draw,circle}]", "\t\t" }), - i(1), - t({ "", "\t\\end{tikzpicture}", "\\end{center}" }), - }), - s("ra", { t( "\\rightarrow" )}), - s("Ra", { t("\\Rightarrow" )}), - s("la", { t("\\leftarrow" )}), - s("La", { t("\\Leftarrow" )}), - s("lra", { t("\\leftrightarrow" )}), - s("Lra", { t("\\Leftrightarrow" )}), - s("bb", { - t({ "\\textbf{" }), - i(1), - t({ "}"}), - }), - s("tt", { - t({ "\\texttt{" }), +ls.add_snippets("tex", { + -- rec_ls is self-referencing. That makes this snippet 'infinite' eg. have as many + -- \item as necessary by utilizing a choiceNode. + s("ls", { + t({ "\\begin{itemize}", "\t\\item " }), + i(1), + t({ "" }), + d(2, rec_ls, {}), + t({ "", "\\end{itemize}", "" }), + }), + s("lsl", { + t({ "\\begin{itemize}[label=" }), + i(1), + t( { "]", "\t\\item " }), + i(2), + t({ "" }), + d(3, rec_ls, {}), + t({ "", "\\end{itemize}", "" }), + }), + s("frm", { + t({ "\\begin{" }), + i(1), + t({ "}[" }), + i(2), + t({ "]{" }), + f(copy, 1), + t({ ":" }), + i(3, "foo"), + t({ "}", "\t" }), + i(0), + t({ "", "\\end{" }), + f(copy, 1), + t({ "}", "" }), + }), + s("env", { + t({ "\\begin{" }), + i(1, "foo"), + t({ "}", "\t" }), + i(2), + t({ "", "\\end{" }), + f(copy,1), + t({ "}"}), + }), + s("tikz", { + t({ "\\begin{center}" }), + t({ "", "\t\\begin{tikzpicture}[main/.style = {draw,circle}]", "\t\t" }), + i(1), + t({ "", "\t\\end{tikzpicture}", "\\end{center}" }), + }), + s("ra", { t( "\\rightarrow" )}), + s("Ra", { t("\\Rightarrow" )}), + s("la", { t("\\leftarrow" )}), + s("La", { t("\\Leftarrow" )}), + s("lra", { t("\\leftrightarrow" )}), + s("Lra", { t("\\Leftrightarrow" )}), + s("bb", { + t({ "\\textbf{" }), i(1), t({ "}"}), - }), - s("ii", { - t({ "\\textit{" }), - i(1), - t({ "}"}), - }), - s("uu", { - t({ "\\underline{" }), - i(1), - t({ "}"}), - }), - s("fsc", { - t({ "\\textsc{" }), - i(1), - t({ "}"}), - }), - }, -} + }), + s("tt", { + t({ "\\texttt{" }), + i(1), + t({ "}"}), + }), + s("ii", { + t({ "\\textit{" }), + i(1), + t({ "}"}), + }), + s("uu", { + t({ "\\underline{" }), + i(1), + t({ "}"}), + }), + s("fsc", { + t({ "\\textsc{" }), + i(1), + t({ "}"}), + }), +}, { + key = "tex" +}) diff --git a/.config/nvim/lua/plugin/luasnip.lua b/.config/nvim/lua/plugin/luasnip.lua index 07650c3..b88b007 100644 --- a/.config/nvim/lua/plugin/luasnip.lua +++ b/.config/nvim/lua/plugin/luasnip.lua @@ -59,270 +59,269 @@ local function date_input(fmt) return sn(nil, i(1, os.date(fmt))) end -ls.snippets = { - -- When trying to expand a snippet, luasnip first searches the tables for - -- each filetype specified in 'filetype' followed by 'all'. - -- If ie. the filetype is 'lua.c' - -- - luasnip.lua - -- - luasnip.c - -- - luasnip.all - -- are searched in that order. - all = { +-- snippets are added via ls.add_snippets(filetype, snippets[, opts]), where +-- opts may specify the `type` of the snippets ("snippets" or "autosnippets", +-- for snippets that should expand directly after the trigger is typed). +-- +-- opts can also specify a key. By passing an unique key to each add_snippets, it's possible to reload snippets by +-- re-`:luafile`ing the file in which they are defined (eg. this one). +ls.add_snippets( "all", { -- trigger is fn. - s("fn", { - -- Simple static text. - t("//Parameters: "), - -- function, first parameter is the function, second the Placeholders - -- whose text it gets as input. - f(copy, 2), - t({ "", "function " }), - -- Placeholder/Insert. - i(1), - t("("), - -- Placeholder with initial text. - i(2, "int foo"), - -- Linebreak - t({ ") {", "\t" }), - -- Last Placeholder, exit Point of the snippet. EVERY 'outer' SNIPPET NEEDS Placeholder 0. - i(0), - t({ "", "}" }), - }), - s("class", { - -- Choice: Switch between two different Nodes, first parameter is its position, second a list of nodes. - c(1, { - t("public "), - t("private "), - }), - t("class "), - i(2), - t(" "), - c(3, { - t("{"), - -- sn: Nested Snippet. Instead of a trigger, it has a position, just like insert-nodes. !!! These don't expect a 0-node!!!! - -- Inside Choices, Nodes don't need a position as the choice node is the one being jumped to. - sn(nil, { - t("extends "), - i(1), - t(" {"), - }), - sn(nil, { - t("implements "), - i(1), - t(" {"), - }), - }), - t({ "", "\t" }), - i(0), - t({ "", "}" }), - }), - -- Use a dynamic_node to interpolate the output of a - -- function (see date_input above) into the initial - -- value of an insert_node. - s("novel", { - t("It was a dark and stormy night on "), - d(1, date_input, {}, "%A, %B %d of %Y"), - t(" and the clocks were striking thirteen."), - }), - -- Parsing snippets: First parameter: Snippet-Trigger, Second: Snippet body. - -- Placeholders are parsed into choices with 1. the placeholder text(as a snippet) and 2. an empty string. - -- This means they are not SELECTed like in other editors/Snippet engines. - ls.parser.parse_snippet( - "lspsyn", - "Wow! This ${1:Stuff} really ${2:works. ${3:Well, a bit.}}" - ), + s("fn", { + -- Simple static text. + t("//Parameters: "), + -- function, first parameter is the function, second the Placeholders + -- whose text it gets as input. + f(copy, 2), + t({ "", "function " }), + -- Placeholder/Insert. + i(1), + t("("), + -- Placeholder with initial text. + i(2, "int foo"), + -- Linebreak + t({ ") {", "\t" }), + -- Last Placeholder, exit Point of the snippet. EVERY 'outer' SNIPPET NEEDS Placeholder 0. + i(0), + t({ "", "}" }), + }), + s("class", { + -- Choice: Switch between two different Nodes, first parameter is its position, second a list of nodes. + c(1, { + t("public "), + t("private "), + }), + t("class "), + i(2), + t(" "), + c(3, { + t("{"), + -- sn: Nested Snippet. Instead of a trigger, it has a position, just like insert-nodes. !!! These don't expect a 0-node!!!! + -- Inside Choices, Nodes don't need a position as the choice node is the one being jumped to. + sn(nil, { + t("extends "), + i(1), + t(" {"), + }), + sn(nil, { + t("implements "), + i(1), + t(" {"), + }), + }), + t({ "", "\t" }), + i(0), + t({ "", "}" }), + }), + -- Use a dynamic_node to interpolate the output of a + -- function (see date_input above) into the initial + -- value of an insert_node. + s("novel", { + t("It was a dark and stormy night on "), + d(1, date_input, {}, "%A, %B %d of %Y"), + t(" and the clocks were striking thirteen."), + }), + -- Parsing snippets: First parameter: Snippet-Trigger, Second: Snippet body. + -- Placeholders are parsed into choices with 1. the placeholder text(as a snippet) and 2. an empty string. + -- This means they are not SELECTed like in other editors/Snippet engines. + ls.parser.parse_snippet( + "lspsyn", + "Wow! This ${1:Stuff} really ${2:works. ${3:Well, a bit.}}" + ), - -- When wordTrig is set to false, snippets may also expand inside other words. - ls.parser.parse_snippet( - { trig = "te", wordTrig = false }, - "${1:cond} ? ${2:true} : ${3:false}" - ), + -- When wordTrig is set to false, snippets may also expand inside other words. + ls.parser.parse_snippet( + { trig = "te", wordTrig = false }, + "${1:cond} ? ${2:true} : ${3:false}" + ), - -- When regTrig is set, trig is treated like a pattern, this snippet will expand after any number. - ls.parser.parse_snippet({ trig = "%d", regTrig = true }, "A Number!!"), - -- Using the condition, it's possible to allow expansion only in specific cases. - s("cond", { - t("will only expand in c-style comments"), - }, { - condition = function(line_to_cursor, matched_trigger, captures) - -- optional whitespace followed by // - return line_to_cursor:match("%s*//") - end, - }), - -- there's some built-in conditions in "luasnip.extras.expand_conditions". - s("cond2", { - t("will only expand at the beginning of the line"), - }, { - condition = conds.line_begin, - }), - -- The last entry of args passed to the user-function is the surrounding snippet. - s( - { trig = "a%d", regTrig = true }, - f(function(_, snip) - return "Triggered with " .. snip.trigger .. "." - end, {}) - ), - -- It's possible to use capture-groups inside regex-triggers. - s( - { trig = "b(%d)", regTrig = true }, - f(function(_, snip) - return "Captured Text: " .. snip.captures[1] .. "." - end, {}) - ), - s({ trig = "c(%d+)", regTrig = true }, { - t("will only expand for even numbers"), - }, { - condition = function(line_to_cursor, matched_trigger, captures) - return tonumber(captures[1]) % 2 == 0 - end, - }), - -- Use a function to execute any shell command and print its text. - s("bash", f(bash, {}, "ls")), - -- Short version for applying String transformations using function nodes. - s("transform", { - i(1, "initial text"), - t({ "", "" }), - -- lambda nodes accept an l._1,2,3,4,5, which in turn accept any string transformations. - -- This list will be applied in order to the first node given in the second argument. - l(l._1:match("[^i]*$"):gsub("i", "o"):gsub(" ", "_"):upper(), 1), - }), - s("transform2", { - i(1, "initial text"), - t("::"), - i(2, "replacement for e"), - t({ "", "" }), - -- Lambdas can also apply transforms USING the text of other nodes: - l(l._1:gsub("e", l._2), { 1, 2 }), - }), - s({ trig = "trafo(%d+)", regTrig = true }, { - -- env-variables and captures can also be used: - l(l.CAPTURE1:gsub("1", l.TM_FILENAME), {}), - }), - -- Set store_selection_keys = "" (for example) in your - -- luasnip.config.setup() call to access TM_SELECTED_TEXT. In - -- this case, select a URL, hit Tab, then expand this snippet. - s("link_url", { - t(''), - i(1), - t(""), - i(0), - }), - -- Shorthand for repeating the text in a given node. - s("repeat", { i(1, "text"), t({ "", "" }), r(1) }), - -- Directly insert the ouput from a function evaluated at runtime. - s("part", p(os.date, "%Y")), - -- use matchNodes to insert text based on a pattern/function/lambda-evaluation. - s("mat", { - i(1, { "sample_text" }), - t(": "), - m(1, "%d", "contains a number", "no number :("), - }), - -- The inserted text defaults to the first capture group/the entire - -- match if there are none - s("mat2", { - i(1, { "sample_text" }), - t(": "), - m(1, "[abc][abc][abc]"), - }), - -- It is even possible to apply gsubs' or other transformations - -- before matching. - s("mat3", { - i(1, { "sample_text" }), - t(": "), - m( - 1, - l._1:gsub("[123]", ""):match("%d"), - "contains a number that isn't 1, 2 or 3!" - ), - }), - -- `match` also accepts a function, which in turn accepts a string - -- (text in node, \n-concatted) and returns any non-nil value to match. - -- If that value is a string, it is used for the default-inserted text. - s("mat4", { - i(1, { "sample_text" }), - t(": "), - m(1, function(text) - return (#text % 2 == 0 and text) or nil - end), - }), - -- The nonempty-node inserts text depending on whether the arg-node is - -- empty. - s("nempty", { - i(1, "sample_text"), - n(1, "i(1) is not empty!"), - }), - -- dynamic lambdas work exactly like regular lambdas, except that they - -- don't return a textNode, but a dynamicNode containing one insertNode. - -- This makes it easier to dynamically set preset-text for insertNodes. - s("dl1", { - i(1, "sample_text"), - t({ ":", "" }), - dl(2, l._1, 1), - }), - -- Obviously, it's also possible to apply transformations, just like lambdas. - s("dl2", { - i(1, "sample_text"), - i(2, "sample_text_2"), - t({ "", "" }), - dl(3, l._1:gsub("\n", " linebreak ") .. l._2, { 1, 2 }), - }), - -- Alternative printf-like notation for defining snippets. It uses format - -- string with placeholders similar to the ones used with Python's .format(). - s( - "fmt1", - fmt("To {title} {} {}.", { - i(2, "Name"), - i(3, "Surname"), - title = c(1, { t("Mr."), t("Ms.") }), - }) - ), - -- To escape delimiters use double them, e.g. `{}` -> `{{}}`. - -- Multi-line format strings by default have empty first/last line removed. - -- Indent common to all lines is also removed. Use the third `opts` argument - -- to control this behaviour. - s( - "fmt2", - fmt( - [[ - foo({1}, {3}) {{ - return {2} * {4} - }} - ]], - { - i(1, "x"), - r(1), - i(2, "y"), - r(2), - } - ) - ), - -- Empty placeholders are numbered automatically starting from 1 or the last - -- value of a numbered placeholder. Named placeholders do not affect numbering. - s( - "fmt3", - fmt("{} {a} {} {1} {}", { - t("1"), - t("2"), - a = t("A"), - }) - ), - -- The delimiters can be changed from the default `{}` to something else. - s( - "fmt4", - fmt("foo() { return []; }", i(1, "x"), { delimiters = "[]" }) - ), - -- `fmta` is a convenient wrapper that uses `<>` instead of `{}`. - s("fmt5", fmta("foo() { return <>; }", i(1, "x"))), - -- By default all args must be used. Use strict=false to disable the check - s( - "fmt6", - fmt("use {} only", { t("this"), t("not this") }, { strict = false }) - ), - }, -} + -- When regTrig is set, trig is treated like a pattern, this snippet will expand after any number. + ls.parser.parse_snippet({ trig = "%d", regTrig = true }, "A Number!!"), + -- Using the condition, it's possible to allow expansion only in specific cases. + s("cond", { + t("will only expand in c-style comments"), + }, { + condition = function(line_to_cursor, matched_trigger, captures) + -- optional whitespace followed by // + return line_to_cursor:match("%s*//") + end, + }), + -- there's some built-in conditions in "luasnip.extras.expand_conditions". + s("cond2", { + t("will only expand at the beginning of the line"), + }, { + condition = conds.line_begin, + }), + -- The last entry of args passed to the user-function is the surrounding snippet. + s( + { trig = "a%d", regTrig = true }, + f(function(_, snip) + return "Triggered with " .. snip.trigger .. "." + end, {}) + ), + -- It's possible to use capture-groups inside regex-triggers. + s( + { trig = "b(%d)", regTrig = true }, + f(function(_, snip) + return "Captured Text: " .. snip.captures[1] .. "." + end, {}) + ), + s({ trig = "c(%d+)", regTrig = true }, { + t("will only expand for even numbers"), + }, { + condition = function(line_to_cursor, matched_trigger, captures) + return tonumber(captures[1]) % 2 == 0 + end, + }), + -- Use a function to execute any shell command and print its text. + s("bash", f(bash, {}, "ls")), + -- Short version for applying String transformations using function nodes. + s("transform", { + i(1, "initial text"), + t({ "", "" }), + -- lambda nodes accept an l._1,2,3,4,5, which in turn accept any string transformations. + -- This list will be applied in order to the first node given in the second argument. + l(l._1:match("[^i]*$"):gsub("i", "o"):gsub(" ", "_"):upper(), 1), + }), + s("transform2", { + i(1, "initial text"), + t("::"), + i(2, "replacement for e"), + t({ "", "" }), + -- Lambdas can also apply transforms USING the text of other nodes: + l(l._1:gsub("e", l._2), { 1, 2 }), + }), + s({ trig = "trafo(%d+)", regTrig = true }, { + -- env-variables and captures can also be used: + l(l.CAPTURE1:gsub("1", l.TM_FILENAME), {}), + }), + -- Set store_selection_keys = "" (for example) in your + -- luasnip.config.setup() call to access TM_SELECTED_TEXT. In + -- this case, select a URL, hit Tab, then expand this snippet. + s("link_url", { + t(''), + i(1), + t(""), + i(0), + }), + -- Shorthand for repeating the text in a given node. + s("repeat", { i(1, "text"), t({ "", "" }), r(1) }), + -- Directly insert the ouput from a function evaluated at runtime. + s("part", p(os.date, "%Y")), + -- use matchNodes to insert text based on a pattern/function/lambda-evaluation. + s("mat", { + i(1, { "sample_text" }), + t(": "), + m(1, "%d", "contains a number", "no number :("), + }), + -- The inserted text defaults to the first capture group/the entire + -- match if there are none + s("mat2", { + i(1, { "sample_text" }), + t(": "), + m(1, "[abc][abc][abc]"), + }), + -- It is even possible to apply gsubs' or other transformations + -- before matching. + s("mat3", { + i(1, { "sample_text" }), + t(": "), + m( + 1, + l._1:gsub("[123]", ""):match("%d"), + "contains a number that isn't 1, 2 or 3!" + ), + }), + -- `match` also accepts a function, which in turn accepts a string + -- (text in node, \n-concatted) and returns any non-nil value to match. + -- If that value is a string, it is used for the default-inserted text. + s("mat4", { + i(1, { "sample_text" }), + t(": "), + m(1, function(text) + return (#text % 2 == 0 and text) or nil + end), + }), + -- The nonempty-node inserts text depending on whether the arg-node is + -- empty. + s("nempty", { + i(1, "sample_text"), + n(1, "i(1) is not empty!"), + }), + -- dynamic lambdas work exactly like regular lambdas, except that they + -- don't return a textNode, but a dynamicNode containing one insertNode. + -- This makes it easier to dynamically set preset-text for insertNodes. + s("dl1", { + i(1, "sample_text"), + t({ ":", "" }), + dl(2, l._1, 1), + }), + -- Obviously, it's also possible to apply transformations, just like lambdas. + s("dl2", { + i(1, "sample_text"), + i(2, "sample_text_2"), + t({ "", "" }), + dl(3, l._1:gsub("\n", " linebreak ") .. l._2, { 1, 2 }), + }), + -- Alternative printf-like notation for defining snippets. It uses format + -- string with placeholders similar to the ones used with Python's .format(). + s( + "fmt1", + fmt("To {title} {} {}.", { + i(2, "Name"), + i(3, "Surname"), + title = c(1, { t("Mr."), t("Ms.") }), + }) + ), + -- To escape delimiters use double them, e.g. `{}` -> `{{}}`. + -- Multi-line format strings by default have empty first/last line removed. + -- Indent common to all lines is also removed. Use the third `opts` argument + -- to control this behaviour. + s( + "fmt2", + fmt( + [[ + foo({1}, {3}) {{ + return {2} * {4} + }} + ]], + { + i(1, "x"), + r(1), + i(2, "y"), + r(2), + } + ) + ), + -- Empty placeholders are numbered automatically starting from 1 or the last + -- value of a numbered placeholder. Named placeholders do not affect numbering. + s( + "fmt3", + fmt("{} {a} {} {1} {}", { + t("1"), + t("2"), + a = t("A"), + }) + ), + -- The delimiters can be changed from the default `{}` to something else. + s( + "fmt4", + fmt("foo() { return []; }", i(1, "x"), { delimiters = "[]" }) + ), + -- `fmta` is a convenient wrapper that uses `<>` instead of `{}`. + s("fmt5", fmta("foo() { return <>; }", i(1, "x"))), + -- By default all args must be used. Use strict=false to disable the check + s( + "fmt6", + fmt("use {} only", { t("this"), t("not this") }, { strict = false }) + ), +}, { + key = "all", + }) -- autotriggered snippets have to be defined in a separate table, luasnip.autosnippets. ls.autosnippets = {