From 7c4503669d431e46add40b3bec3bf6c5e5b186ca Mon Sep 17 00:00:00 2001 From: Lyonel Zamora Date: Tue, 8 Nov 2022 11:49:06 -0500 Subject: [PATCH 1/4] feat(extras): added open_snippet_list --- lua/luasnip/extras/snippet_list.lua | 96 +++++++++++++++++++++++++++++ lua/luasnip/init.lua | 10 +-- 2 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 lua/luasnip/extras/snippet_list.lua diff --git a/lua/luasnip/extras/snippet_list.lua b/lua/luasnip/extras/snippet_list.lua new file mode 100644 index 000000000..b490b4cf8 --- /dev/null +++ b/lua/luasnip/extras/snippet_list.lua @@ -0,0 +1,96 @@ +local available = require("luasnip").available + +local function snip_info(snippet) + return { + name = snippet.name, + trigger = snippet.trigger, + description = snippet.dscr, + wordTrig = snippet.wordTrig and true or false, + regTrig = snippet.regTrig and true or false, + docstring = snippet:get_docstring(), + } +end + +local function get_name(buf) + return "LuaSnip://Snippets" +end + +local win_opts = { foldmethod = "indent" } +local buf_opts = { filetype = "lua" } + +local function set_win_opts(win, opts) + for opt, val in pairs(opts) do + vim.api.nvim_win_set_option(win, opt, val) + end +end + +local function set_buf_opts(buf, opts) + for opt, val in pairs(opts) do + vim.api.nvim_buf_set_option(buf, opt, val) + end +end + +local function make_scratch_buf(buf) + local opts = { + buftype = "nofile", + bufhidden = "wipe", + buflisted = false, + swapfile = false, + modified = false, + modeline = false, + } + + set_buf_opts(buf, opts) +end + +local function display_split(opts) + opts = opts or {} + opts.win_opts = opts.win_opts or win_opts + opts.buf_opts = opts.buf_opts or buf_opts + opts.get_name = opts.get_name or get_name + + return function(printer_result) + -- create and open buffer on right vertical split + vim.cmd("botright vnew") + + -- get buf and win handle + local buf = vim.api.nvim_get_current_buf() + local win = vim.api.nvim_get_current_win() + + -- make scratch buffer + vim.api.nvim_buf_set_name(buf, opts.get_name(buf)) + make_scratch_buf(buf) + + -- disable diagnostics + vim.diagnostic.disable(buf) + + -- set any extra win and buf opts + set_win_opts(win, opts.win_opts) + set_buf_opts(buf, opts.buf_opts) + + -- dump snippets + local replacement = vim.split(printer_result, "\n") + vim.api.nvim_buf_set_lines(buf, 0, 0, false, replacement) + + -- make it unmodifiable at this point + vim.api.nvim_buf_set_option(buf, "modifiable", false) + end +end + +local function open(opts) + opts = opts or {} + opts.snip_info = opts.snip_info or snip_info + opts.printer = opts.printer or vim.inspect + opts.display = opts.display or display_split() + + -- load snippets before changing windows/buffers + local snippets = available(opts.snip_info) + + -- open snippets + opts.display(opts.printer(snippets)) +end + +return { + open = open, + options = { display = display_split }, +} diff --git a/lua/luasnip/init.lua b/lua/luasnip/init.lua index c9efe199c..d234091c1 100644 --- a/lua/luasnip/init.lua +++ b/lua/luasnip/init.lua @@ -53,7 +53,7 @@ local function get_snippets(ft, opts) return snippet_collection.get_snippets(ft, opts.type or "snippets") or {} end -local function get_context(snip) +local function default_snip_info(snip) return { name = snip.name, trigger = snip.trigger, @@ -63,19 +63,21 @@ local function get_context(snip) } end -local function available() +local function available(snip_info) + snip_info = snip_info or default_snip_info + local fts = util.get_snippet_filetypes() local res = {} for _, ft in ipairs(fts) do res[ft] = {} for _, snip in ipairs(get_snippets(ft)) do if not snip.invalidated then - table.insert(res[ft], get_context(snip)) + table.insert(res[ft], snip_info(snip)) end end for _, snip in ipairs(get_snippets(ft, { type = "autosnippets" })) do if not snip.invalidated then - table.insert(res[ft], get_context(snip)) + table.insert(res[ft], snip_info(snip)) end end end From 6f78b197d0593e9396e1462ef4ea7955f2ce7b3f Mon Sep 17 00:00:00 2001 From: Lyonel Zamora Date: Tue, 29 Nov 2022 14:49:17 -0500 Subject: [PATCH 2/4] docs(extras): add Snippet List --- DOC.md | 168 +++++++++++++++++++++++++++++++++++++++++++++++- doc/luasnip.txt | 156 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 319 insertions(+), 5 deletions(-) diff --git a/DOC.md b/DOC.md index fa238bce6..69297d5ed 100644 --- a/DOC.md +++ b/DOC.md @@ -1516,6 +1516,164 @@ callback will have access to the `POSTFIX_MATCH` field as well. } ``` +## Snippet List + +```lua +local sl = require("luasnip.extras.snippet_list") +``` + +Makes an `open` function available to use to open currently available snippets +in a different buffer/window/tab. + +`sl.open(opts:table|nil)` + +* `opts`: optional arguments: + * `snip_info`: `snip_info(snippet) -> table representation of snippet` + * `printer`: `printer(snippets:table) -> any` + * `display`: `display(snippets:any)` + +Benefits include: syntax highlighting, searching, and customizability. + +Simple Example: +```lua +sl.open() +``` + + + +![default](https://user-images.githubusercontent.com/43832900/204893019-3a83d6bc-9e01-4750-bdf4-f6af967af807.png) + + + +Customization Examples: +```lua +-- making our own snip_info +local function snip_info(snippet) + return { name = snippet.name } +end + +-- using it +sl.open({snip_info = snip_info}) +``` + + + +![snip_info](https://user-images.githubusercontent.com/43832900/204893340-c7296a70-370a-4ad3-8997-23887f311b74.png) + + + +```lua +-- making our own printer +local function printer(snippets) + local res = "" + + for ft, snips in pairs(snippets) do + res = res .. ft .. "\n" + for _, snip in pairs(snips) do + res = res .. " " .. "Name: " .. snip.name .. "\n" + res = res .. " " .. "Desc: " .. snip.description[1] .. "\n" + res = res .. " " .. "Trigger: " .. snip.trigger .. "\n" + res = res .. " ----" .. "\n" + end + end + + return res +end + + +-- using it +sl.open({printer = printer}) +``` + + + +![printer](https://user-images.githubusercontent.com/43832900/204893406-4fc397e2-6d42-43f3-b52d-59ac448e764c.png) + + + +```lua +-- making our own display +local function display(printer_result) + -- right vertical split + vim.cmd("botright vnew") + + -- get buf and win handle + local buf = vim.api.nvim_get_current_buf() + local win = vim.api.nvim_get_current_win() + + -- setting window and buffer options + vim.api.nvim_win_set_option(win, "foldmethod", "manual") + vim.api.nvim_buf_set_option(buf, "filetype", "javascript") + + vim.api.nvim_buf_set_option(buf, "buftype", "nofile") + vim.api.nvim_buf_set_option(buf, "bufhidden", "wipe") + vim.api.nvim_buf_set_option(buf, "buflisted", false) + + vim.api.nvim_buf_set_name(buf, "Custom Display buf " .. buf) + + -- dump snippets + local replacement = vim.split(printer_result) + vim.api.nvim_buf_set_lines(buf, 0, 0, false, replacement) +end + +-- using it +sl.open({display = display}) +``` + + + +![display](https://user-images.githubusercontent.com/43832900/205133425-a3fffa1c-bbec-4aea-927b-5faed14856d7.png) + + + +There is a **caveat** with implementing your own printer and/or display +function. The **default** behavior for the printer function is to return a +string representation of the snippets. The display function uses the results +from the printer function, therefore by **default** the display function is +expecting that result to be a string. + +This doesn't have to be the case however. You can for example implement your +own printer function that returns a table representation of the snippets +**but** you would have to then implement your own display function or some +other function in order to stringify this result. + +An `options` table is available which has functionality in it that can be used +to customize 'common' settings. + +* `sl.options`: options table: + * `display`: `display(opts:table|nil) -> function(printer_result:string)` + +You can see from the example above that making a custom display is a fairly +involved process. What if you just wanted to change a buffer option like the +name or just the filetype? This is where `sl.options.display` comes in. It +allows you to customize buffer and window options while keeping the default +behavior. + +`sl.options.display(opts:table|nil) -> function(printer_result:string)` + +* `opts`: optional arguments: + * `win_opts`: `table which has a {window_option = value} form` + * `buf_opts`: `table which has a {buffer_option = value} form` + * `get_name`: `get_name(buf) -> string` + +Let's recreate the custom display example above: +```lua +-- keeping the default display behavior but modifying window/buffer +local modified_default_display = sl.options.display({ + buf_opts = {filetype = "javascript"}, + win_opts = {foldmethod = "manual"}, + get_name = function(buf) return "Custom Display buf " .. buf end + }) + +-- using it +sl.open({display = modified_default_display}) +``` + + + +![modified display](https://user-images.githubusercontent.com/43832900/205133441-f4363bab-bdab-4c60-af9d-7285d59eca03.png) + + # EXTEND_DECORATOR @@ -2715,8 +2873,14 @@ print a short message to the log. current node as an argnode (will actually only update them if the text in any of the argnodes changed). -- `available()`: return a table of all snippets defined for the current - filetypes(s) (`{ft1={snip1, snip2}, ft2={snip3, snip4}}`). +- `available(snip_info)`: return a table of all snippets defined for the + current filetypes(s) (`{ft1={snip1, snip2}, ft2={snip3, snip4}}`). + The structure of the snippet is defined by `snip_info` which is a function + (`snip_info(snip)`) that takes in a snippet (`snip`), finds the desired + information on it, and returns it. + `snip_info` is an optional argument as a default has already been defined. + You can use it for more granular control over the table of snippets that is + returned. - `exit_out_of_region(node)`: checks whether the cursor is still within the range of the snippet `node` belongs to. If yes, no change occurs, if No, the diff --git a/doc/luasnip.txt b/doc/luasnip.txt index cd555032f..f51ab542e 100644 --- a/doc/luasnip.txt +++ b/doc/luasnip.txt @@ -1,4 +1,4 @@ -*luasnip.txt* For NVIM v0.5.0 Last change: 2022 December 20 +*luasnip.txt* For NVIM v0.8.0 Last change: 2023 January 06 ============================================================================== Table of Contents *luasnip-table-of-contents* @@ -33,6 +33,7 @@ Table of Contents *luasnip-table-of-contents* - Select_choice |luasnip-select_choice| - filetype_functions |luasnip-filetype_functions| - POSTFIX SNIPPET |luasnip-postfix-snippet| + - Snippet List |luasnip-snippet-list| 14. EXTEND_DECORATOR |luasnip-extend_decorator| 15. LSP-SNIPPETS |luasnip-lsp-snippets| - Snipmate Parser |luasnip-snipmate-parser| @@ -1472,6 +1473,150 @@ callback will have access to the `POSTFIX_MATCH` field as well. < +SNIPPET LIST *luasnip-snippet-list* + +> + local sl = require("luasnip.extras.snippet_list") +< + + +Makes an `open` function available to use to open currently available snippets +in a different buffer/window/tab. + +`sl.open(opts:table|nil)` + + +- `opts`: optional arguments: + - `snip_info`: `snip_info(snippet) -> table representation of snippet` + - `printer`: `printer(snippets:table) -> any` + - `display`: `display(snippets:any)` + + +Benefits include: syntax highlighting, searching, and customizability. + +Simple Example: + +> + sl.open() +< + + +Customization Examples: + +> + -- making our own snip_info + local function snip_info(snippet) + return { name = snippet.name } + end + + -- using it + sl.open({snip_info = snip_info}) +< + + +> + -- making our own printer + local function printer(snippets) + local res = "" + + for ft, snips in pairs(snippets) do + res = res .. ft .. "\n" + for _, snip in pairs(snips) do + res = res .. " " .. "Name: " .. snip.name .. "\n" + res = res .. " " .. "Desc: " .. snip.description[1] .. "\n" + res = res .. " " .. "Trigger: " .. snip.trigger .. "\n" + res = res .. " ----" .. "\n" + end + end + + return res + end + + + -- using it + sl.open({printer = printer}) +< + + +> + -- making our own display + local function display(printer_result) + -- right vertical split + vim.cmd("botright vnew") + + -- get buf and win handle + local buf = vim.api.nvim_get_current_buf() + local win = vim.api.nvim_get_current_win() + + -- setting window and buffer options + vim.api.nvim_win_set_option(win, "foldmethod", "manual") + vim.api.nvim_buf_set_option(buf, "filetype", "javascript") + + vim.api.nvim_buf_set_option(buf, "buftype", "nofile") + vim.api.nvim_buf_set_option(buf, "bufhidden", "wipe") + vim.api.nvim_buf_set_option(buf, "buflisted", false) + + vim.api.nvim_buf_set_name(buf, "Custom Display buf " .. buf) + + -- dump snippets + local replacement = vim.split(printer_result) + vim.api.nvim_buf_set_lines(buf, 0, 0, false, replacement) + end + + -- using it + sl.open({display = display}) +< + + +There is a **caveat** with implementing your own printer and/or display +function. The **default** behavior for the printer function is to return a +string representation of the snippets. The display function uses the results +from the printer function, therefore by **default** the display function is +expecting that result to be a string. + +This doesn’t have to be the case however. You can for example implement your +own printer function that returns a table representation of the snippets +**but** you would have to then implement your own display function or some +other function in order to stringify this result. + +An `options` table is available which has functionality in it that can be used +to customize 'common' settings. + + +- `sl.options`: options table: + - `display`: `display(opts:table|nil) -> function(printer_result:string)` + + +You can see from the example above that making a custom display is a fairly +involved process. What if you just wanted to change a buffer option like the +name or just the filetype? This is where `sl.options.display` comes in. It +allows you to customize buffer and window options while keeping the default +behavior. + +`sl.options.display(opts:table|nil) -> function(printer_result:string)` + + +- `opts`: optional arguments: + - `win_opts`: `table which has a {window_option = value} form` + - `buf_opts`: `table which has a {buffer_option = value} form` + - `get_name`: `get_name(buf) -> string` + + +Let’s recreate the custom display example above: + +> + -- keeping the default display behavior but modifying window/buffer + local modified_default_display = sl.options.display({ + buf_opts = {filetype = "javascript"}, + win_opts = {foldmethod = "manual"}, + get_name = function(buf) return "Custom Display buf " .. buf end + }) + + -- using it + sl.open({display = modified_default_display}) +< + + ============================================================================== 14. EXTEND_DECORATOR *luasnip-extend_decorator* @@ -2668,8 +2813,13 @@ print a short message to the log. - `active_update_dependents()`: update all function/dynamicNodes that have the current node as an argnode (will actually only update them if the text in any of the argnodes changed). -- `available()`: return a table of all snippets defined for the current - filetypes(s) (`{ft1={snip1, snip2}, ft2={snip3, snip4}}`). +- `available(snip_info)`: return a table of all snippets defined for the current + filetypes(s) (`{ft1={snip1, snip2}, ft2={snip3, snip4}}`). The structure of the + snippet is defined by `snip_info` which is a function (`snip_info(snip)`) that + takes in a snippet (`snip`) and uses it to define the desired table. + `snip_info` is an optional argument as a default has already been defined. You + can use it for more granular control over the table of snippets that is + returned. - `exit_out_of_region(node)`: checks whether the cursor is still within the range of the snippet `node` belongs to. If yes, no change occurs, if No, the snippet is exited and following snippets’ regions are checked and potentially exited From f86ce5e7d144e76e793d844d4a84113ab10bd405 Mon Sep 17 00:00:00 2001 From: lyonelz96 Date: Sat, 7 Jan 2023 21:59:11 +0000 Subject: [PATCH 3/4] Auto generate docs --- doc/luasnip.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/luasnip.txt b/doc/luasnip.txt index f51ab542e..3ae2065ba 100644 --- a/doc/luasnip.txt +++ b/doc/luasnip.txt @@ -1,4 +1,4 @@ -*luasnip.txt* For NVIM v0.8.0 Last change: 2023 January 06 +*luasnip.txt* For NVIM v0.8.0 Last change: 2023 January 07 ============================================================================== Table of Contents *luasnip-table-of-contents* @@ -2816,9 +2816,9 @@ print a short message to the log. - `available(snip_info)`: return a table of all snippets defined for the current filetypes(s) (`{ft1={snip1, snip2}, ft2={snip3, snip4}}`). The structure of the snippet is defined by `snip_info` which is a function (`snip_info(snip)`) that - takes in a snippet (`snip`) and uses it to define the desired table. - `snip_info` is an optional argument as a default has already been defined. You - can use it for more granular control over the table of snippets that is + takes in a snippet (`snip`), finds the desired information on it, and returns + it. `snip_info` is an optional argument as a default has already been defined. + You can use it for more granular control over the table of snippets that is returned. - `exit_out_of_region(node)`: checks whether the cursor is still within the range of the snippet `node` belongs to. If yes, no change occurs, if No, the snippet From bd0623a3af6e32100af472944f62ddfc8807f81c Mon Sep 17 00:00:00 2001 From: L3MON4D3 Date: Sun, 8 Jan 2023 09:24:03 +0000 Subject: [PATCH 4/4] Auto generate docs --- doc/luasnip.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/luasnip.txt b/doc/luasnip.txt index 3ae2065ba..4e54ce3a7 100644 --- a/doc/luasnip.txt +++ b/doc/luasnip.txt @@ -1,4 +1,4 @@ -*luasnip.txt* For NVIM v0.8.0 Last change: 2023 January 07 +*luasnip.txt* For NVIM v0.8.0 Last change: 2023 January 08 ============================================================================== Table of Contents *luasnip-table-of-contents*