├── .stylua.toml
├── README.md
└── lua
└── luasnip-snippets
├── config.lua
├── init.lua
├── nodes.lua
├── snippets
├── all.lua
├── cpp
│ ├── commons.lua
│ ├── default.lua
│ ├── init.lua
│ ├── lambda_fn.lua
│ ├── postfix.lua
│ ├── qt.lua
│ ├── selection.lua
│ └── statements.lua
├── dart
│ ├── _treesitter.lua
│ └── init.lua
├── lua
│ ├── default.lua
│ ├── init.lua
│ └── vim.lua
├── nix.lua
├── rust
│ ├── default.lua
│ ├── impl_block.lua
│ ├── init.lua
│ ├── lambda_fn.lua
│ ├── postfix.lua
│ └── test_fn.lua
└── typescript.lua
└── utils
├── comment.lua
├── common_cond.lua
├── cond.lua
├── dummy_types.lua
├── init.lua
├── tbl.lua
└── treesitter.lua
/.stylua.toml:
--------------------------------------------------------------------------------
1 | indent_type = "Spaces"
2 | indent_width = 2
3 | column_width = 80
4 | call_parentheses = "NoSingleTable"
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
LuaSnip Snippets
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | A collection of snippets for various programming language. Some snippets are
13 | highly inspired by Jetbrain's IDEs.
14 |
15 | ## 📦 Installation
16 |
17 | ```lua
18 | {
19 | "TwIStOy/luasnip-snippets",
20 | dependencies = { "L3MON4D3/LuaSnip" },
21 | event = { "InsertEnter" },
22 | config = function()
23 | -- register all snippets into LuaSnip
24 | require("luasnip-snippets").setup()
25 | end
26 | }
27 | ```
28 |
29 | `autosnippet` feature should be enabled in `LuaSnip`.
30 |
31 | ```lua
32 | local ls = require('luasnip')
33 | ls.setup({
34 | enable_autosnippets = true,
35 | })
36 | ```
37 |
38 | # ⚙️ Configuration
39 |
40 | Config Example:
41 |
42 | ```lua
43 | ---@type LSSnippets.Config
44 | {
45 | user = {
46 | -- user's name, used in todo-related snippets now
47 | name = nil,
48 | },
49 | snippet = {
50 | lua = {
51 | -- enable neovim related snippets in lua
52 | vim_snippet = false,
53 | },
54 | cpp = {
55 | quick_type = {
56 | -- use `std::unordered_map` instead of `absl::flat_hash_map`
57 | extra_trig = {
58 | { trig = 'm', params = 2, template = 'std::unordered_map<%s, %s>' }
59 | },
60 | -- enable qt-related snippets
61 | qt = true,
62 | -- whether to add cpplint related comments in some snippets
63 | cpplint = true,
64 | },
65 | },
66 | rust = {
67 | -- add `#[rstest]` to test function's attribute choices, if the test mod has already use `rstest` directly
68 | rstest_support = false,
69 | },
70 | },
71 | disable_auto_expansion = {
72 | -- disable these snippets' auto expansion
73 | cpp = { "i32", "i64" },
74 | },
75 | disable_langs = {
76 | -- disable these language's snippets
77 | -- "dart"
78 | }
79 | }
80 | ```
81 |
82 | ## Snippets
83 |
84 |
85 | All
86 |
87 | #### Normal Snippets
88 |
89 | | Trig | Desc |
90 | | :-----: | ---------------------------------- |
91 | | `todo` | Expand to linewise `TODO` comment |
92 | | `fixme` | Expand to linewise `FIXME` comment |
93 | | `note` | Expand to linewise `NOTE` comment |
94 |
95 |
96 |
97 |
98 | Lua
99 |
100 | Snippets with `*` are available only when `vim_snippet` is enabled.
101 |
102 | #### Normal Snippets
103 |
104 | | Trig | Desc | Context Required |
105 | | :-----: | ------------------------------------------ | :--------------: |
106 | | `fn` | Expands to function definition. | No |
107 | | `req` | Expands to `require(...)` statement. | No |
108 | | `ifn`\* | Expand to `vim.F.if_nil(...)` expresstion. | No |
109 |
110 | #### Postfix Snippets
111 |
112 | ```scheme
113 | [
114 | (function_call)
115 | (identifier)
116 | (expression_list)
117 | (dot_index_expression)
118 | (bracket_index_expression)
119 | ] @any_expr
120 | [
121 | (dot_index_expression)
122 | (bracket_index_expression)
123 | ] @index_expr
124 | ```
125 |
126 | | Trig | Desc (placehoder: `?`) | Expr before cursor |
127 | | :-------: | ----------------------------------------- | :----------------: |
128 | | `.ipairs` | Expands to `ipairs(?)` for-loop. | `any_expr` |
129 | | `.pairs` | Expands to `pairs(?)` for-loop. | `any_expr` |
130 | | `.isnil` | Expands to `if ? == nil then` statement. | `any_expr` |
131 | | `.tget`\* | Expands to `vim.tbl_get(...)` expression. | `index_expr` |
132 |
133 | #### Auto-snippets
134 |
135 | | Trig | Desc | Context Required | Could Disable AutoExpansion |
136 | | :--: | ------------------------------------------------------ | :--------------: | :-------------------------: |
137 | | `#i` | Expands to `require(...)` statement with type hinting. | No | No |
138 |
139 |
140 |
141 |
142 | Cpp
143 |
144 | #### Normal Snippets
145 |
146 | | Trig | Desc | Context Required | Qt | Support Selection |
147 | | :---------: | -------------------------------------------------------------------------------------------------- | :-----------------: | :-: | :---------------: |
148 | | `fn` | Expands to lambda function in argument list or function body, otherwise expand to normal function. | No | | Yes |
149 | | `\|trans` | Expands to ranges::views::transform pipe. | No | | |
150 | | `\|filter` | Expands to ranges::views::filter pipe. | No | | |
151 | | `cpo` | Expands to customize point object. | No | | |
152 | | `ns%s(%S+)` | Expands to namespace block (including comments). | No | | |
153 | | `itf` | Expands to a struct with default virtual destruction. | No | | |
154 | | `pvf` | Expands to a pure virtual function declaration. | In Class | | |
155 | | `qcls` | Expands to a class inherts from QObject. | No | Yes | |
156 | | `#if` | Wrap selected code in `#if ... #endif` block. | After cut selection | No | |
157 | | `if` | Wrap selected code in `if (...)` block. | After cut selection | No | |
158 | | `do` | Wrap selected code in `do ... while(0)` block. | After cut selection | No | |
159 | | `while` | Wrap selected code in `while (...)` block. | After cut selection | No | |
160 | | `#de` | Wrap selected code in `#define ...` block. | After cut selection | No | |
161 |
162 | #### Auto-snippets
163 |
164 | | Trig | Desc | Context Required | Could Disable AutoExpansion | Qt | Support Selection |
165 | | :------: | --------------------------------------------------------- | :---------------------------: | :-------------------------: | :-: | :---------------: |
166 | | `ctor!` | Expands to default constructor. | In Class | No | | |
167 | | `dtor!` | Expands to default destructor. | In Class | No | | |
168 | | `cc!` | Expands to default copy constructor. | In Class | No | | |
169 | | `mv!` | Expands to default move constructor. | In Class | No | | |
170 | | `ncc!` | Expands to delete copy constructor. | In Class | No | | |
171 | | `nmv!` | Expands to delete move constructor. | In Class | No | | |
172 | | `ncm!` | Expands to delete copy and move constructor. | In Class | No | | |
173 | | `once` | Expands to `pragma once` marker at the front of the file. | All lines before are comments | Yes | | |
174 | | `u8` | Expands to `uint8_t`. | No | Yes | | |
175 | | `u16` | Expands to `uint16_t`. | No | Yes | | |
176 | | `u32` | Expands to `uint32_t`. | No | Yes | | |
177 | | `u64` | Expands to `uint64_t`. | No | Yes | | |
178 | | `i8` | Expands to `int8_t`. | No | Yes | | |
179 | | `i16` | Expands to `int16_t`. | No | Yes | | |
180 | | `i32` | Expands to `int32_t`. | No | Yes | | |
181 | | `i64` | Expands to `int64_t`. | No | Yes | | |
182 | | `t(%s)!` | Evaluates (QET) marker, and expand to typename. | No | No | | |
183 | | `#"` | Expands to include statement with quotes. `#include ""`. | No | Yes | | |
184 | | `#<` | Expands to include statement with `<>`. `#include <>`. | No | Yes | | |
185 | | `#q` | Expands to include qt generated moc file. | No | Yes | Yes | |
186 | | `#?` | Expands to `ifdef ... endif` fragment. | No | Yes | | Yes |
187 |
188 | ##### Quick Expand Type markers
189 |
190 | | Marker | Expand Type | Parameter |
191 | | :----: | :-------------------- | :-------: |
192 | | `v` | `std::vector` | 1 |
193 | | `i` | `int32_t` | 0 |
194 | | `u` | `uint32_t` | 0 |
195 | | `s` | `std::string` | 0 |
196 | | `m` | `absl::flat_hash_map` | 2 |
197 | | `t` | `std::tuple` | `*` |
198 |
199 | Example:
200 |
201 | ```
202 | tvi! -> std::vector
203 | tmss! -> absl::flat_hash_map
204 | ```
205 |
206 | #### Postfix Snippets
207 |
208 | ```scheme
209 | [
210 | (identifier)
211 | (field_identifier)
212 | ] @indent
213 |
214 | [
215 | (call_expression)
216 | (identifier)
217 | (template_function)
218 | (subscript_expression)
219 | (field_expression)
220 | (user_defined_literal)
221 | ] @any_expr
222 | ```
223 |
224 | | Trig | Desc (placehoder: `?`) | Expr before cursor | Selection Version |
225 | | :-------: | -------------------------------------------------------------------- | :----------------: | :---------------: |
226 | | `.be` | Expands to begin and end exprs. | `any_expr` | Yes |
227 | | `.cbe` | Expands to cbegin and cend exprs. | `any_expr` | Yes |
228 | | `.mv` | Wraps with `std::move(?)`. | `any_expr` | Yes |
229 | | `.fwd` | Wraps with `std::forward(?)`. | `any_expr` | Yes |
230 | | `.val` | Wraps with `std::declval>()`. | `any_expr` | Yes |
231 | | `.dt` | Wraps with `decltype(?)`. | `any_expr` | Yes |
232 | | `.uu` | Wraps with `(void)?`. | `any_expr` | Yes |
233 | | `.ts` | Switches indent's coding style between `CamelCase` and `snake_case`. | `indent` | Yes |
234 | | `.sc` | Wraps with `static_cast<>(?)`. | `any_expr` | Yes |
235 | | `.rc` | Wraps with `reinterpret_cast<>(?)`. | `any_expr` | Yes |
236 | | `.single` | Wraps with `ranges::views::single(?)`. | `any_expr` | Yes |
237 | | `.await` | Expands to `co_await ?`. | `any_expr` | Yes |
238 | | `.in` | Expands to `if (...find)` statements. | `any_expr` | |
239 |
240 | #### Cpplint
241 |
242 | Currently, some snippets will be expanded with cpplint related comments, e.g. `once`(which will expand to `#pragma once // NOLINT(build/header_guard)`).
243 |
244 | You can control whether to add cpplint related comments in these snippets by:
245 |
246 | - Updating `snippet.cpp.cpplint` in your config. This will affect all buffers.
247 | - Setting buffer variable `b:LuasnipSnippetsCppCppLint`. This will only affect the current buffer, and it will override the global setting.
248 |
249 |
250 |
251 |
252 | Rust
253 |
254 | #### Normal Snippets
255 |
256 | | Trig | Desc | Context Required |
257 | | :---: | -------------------------------------------------------------------------------------------------------------------------------------------- | :--------------: |
258 | | `fn` | Expands to lambda function in argument list or function body, otherwise expand to normal function. | No |
259 | | `pc` | Expands to `pub(crate)`. | No |
260 | | `ps` | Expands to `pub(super)`. | No |
261 | | `ii` | Expands to `#[inline]`. | No |
262 | | `ia` | Expands to `#[inline(always)]`. | No |
263 | | `tfn` | Expands to a test function. `#[test]` or `#[tokio::test]` supported. With `snippet.rust.rstest_support` enabled, `#[rstest]` also supported. | No |
264 | | `pm` | Expands to a public method definition. | In impl block |
265 |
266 | #### Postfix Snippets
267 |
268 | ```scheme
269 | [
270 | (struct_expression)
271 | (call_expression)
272 | (identifier)
273 | (field_expression)
274 | ] @expr
275 |
276 | [
277 | (struct_expression)
278 | (call_expression)
279 | (identifier)
280 | (field_expression)
281 |
282 | (generic_type)
283 | (scoped_type_identifier)
284 | (reference_type)
285 | ] @expr_or_type
286 | ```
287 |
288 | | Trig | Desc (placehoder: `?`) | Expr before cursor |
289 | | :--------: | ----------------------------------------------------------- | :----------------: |
290 | | `.rc` | Wraps with `Rc::new(?)` if expr, `Rc>` if type. | `expr_or_type` |
291 | | `.arc` | Wraps with `Arc::new(?)` if expr, `Arc>` if type. | `expr_or_type` |
292 | | `.box` | Wraps with `Box::new(?)` if expr, `Box>` if type. | `expr_or_type` |
293 | | `.mu` | Wraps with `Mutex::new(?)` if expr, `Mutex>` if type. | `expr_or_type` |
294 | | `.rw` | Wraps with `RwLock::new(?)` if expr, `RwLock>` if type. | `expr_or_type` |
295 | | `.cell` | Wraps with `Cell::new(?)` if expr, `Cell>` if type. | `expr_or_type` |
296 | | `.refcell` | Wraps with `RefCell::new(?)` if expr, `RefCell>` if type. | `expr_or_type` |
297 | | `.ref` | Wraps with `&?`. | `expr_or_type` |
298 | | `.refm` | Wraps with `&mut ?`. | `expr_or_type` |
299 | | `.ok` | Wraps with `Ok(?)`. | `expr` |
300 | | `.err` | Wraps with `Err(?)`. | `expr` |
301 | | `.some` | Wraps with `Some(?)`. | `expr` |
302 | | `.println` | Wraps with `println!("{:?}", ?)`. | `expr` |
303 | | `.match` | Wraps with `match ? {}`. | `expr` |
304 |
305 |
306 |
307 |
308 | Dart
309 |
310 | #### Normal Snippets
311 |
312 | | Trig | Desc | Context Required |
313 | | :---: | ------------------------------------------------ | :--------------: |
314 | | `fn` | Expands to function definition. | No |
315 | | `wfn` | Expands to function definition returns a widget. | No |
316 | | `afn` | Expands to an async function definition. | No |
317 |
318 | #### Auto-snippets
319 |
320 | | Trig | Desc | Context Required |
321 | | :-----: | ----------------------------------------- | :--------------: |
322 | | `ctor!` | Expands to class constructor function. | In Class |
323 | | `js!` | Expands to json-related methods. | In Class |
324 | | `init!` | Expands to `initState` override function. | No |
325 | | `dis!` | Expands to `dispose` override function. | No |
326 | | `for!` | Expands to for-loop. | No |
327 | | `sfw!` | Expands to `StatefulWidget` class. | No |
328 | | `slw!` | Expands to `StatelessWidget` class. | No |
329 |
330 |
331 |
332 |
333 | Nix
334 |
335 | #### Normal Snippets
336 |
337 | | Trig | Desc | Context Required |
338 | | :-------: | -------------------------------- | :--------------: |
339 | | `@module` | Expands to a nix module declare. | No |
340 |
341 | #### Postfix Snippets
342 |
343 | ```scheme
344 | [
345 | (identifier)
346 | ] @identifier
347 | [
348 | ((binding
349 | expression: (_) @expr
350 | ))
351 | ] @binding
352 | ```
353 |
354 | | Trig | Desc (placehoder: `?`) | Expr before cursor |
355 | | :------: | --------------------------------------- | :----------------: |
356 | | `.on` | Expands to enable option statement. | `identifier` |
357 | | `.split` | Expands bindings to full attrset style. | `binding` |
358 |
359 |
360 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/config.lua:
--------------------------------------------------------------------------------
1 | ---@class LSSnippets.Config.User
2 | ---@field name? string
3 | ---@field email? string
4 |
5 | ---@class LSSnippets.Config.Snippet.Lua
6 | ---@field vim_snippet? boolean
7 | ---@field cond? fun():boolean
8 |
9 | ---@class LSSnippets.Config.Snippet.Cpp.QuickType
10 | ---@field extra_trig? LSSnippets.Config.Snippet.Cpp.QuickType.Shortcut[]
11 |
12 | ---@class LSSnippets.Config.Snippet.Cpp.QuickType.Shortcut
13 | ---@field trig string One character trigger. Supports lowercase letters only.
14 | ---@field params number Number of template parameters.
15 | ---@field template string Template string.
16 |
17 | ---@class LSSnippets.Config.Snippet.Cpp
18 | ---@field quick_type? LSSnippets.Config.Snippet.Cpp.QuickType
19 | ---@field qt? boolean Enable Qt related snippets.
20 | ---@field cpplint? boolean Whether to add cpplint related comments in some snippets.
21 |
22 | ---@class LSSnippets.Config.Snippet.Rust
23 | ---@field rstest_support? boolean
24 |
25 | ---@alias LSSnippets.Config.Snippet.DisableSnippets string[]
26 | ---@alias LSSnippets.SupportLangs 'cpp'|'dart'|'lua'|'rust'|'nix'|'typescript'|'*'
27 |
28 | ---@class LSSnippets.Config.Snippet
29 | ---@field lua? LSSnippets.Config.Snippet.Lua
30 | ---@field cpp? LSSnippets.Config.Snippet.Cpp
31 | ---@field rust? LSSnippets.Config.Snippet.Rust
32 |
33 | ---@class LSSnippets.Config
34 | ---@field copyright_header? string
35 | ---@field user? LSSnippets.Config.User
36 | ---@field snippet? LSSnippets.Config.Snippet
37 | ---@field disable_auto_expansion? table
38 | ---@field disable_langs? LSSnippets.SupportLangs[]
39 | local config = {}
40 |
41 | ---@param opts? LSSnippets.Config
42 | local function setup(opts)
43 | opts = opts or {}
44 | config = vim.tbl_deep_extend("force", config, opts)
45 | end
46 |
47 | ---@return any
48 | local function get(key)
49 | local keys = vim.split(key, ".", {
50 | plain = true,
51 | trimempty = true,
52 | })
53 | local value = config
54 | for _, k in ipairs(keys) do
55 | value = value[k]
56 | if value == nil then
57 | return nil
58 | end
59 | end
60 | return value
61 | end
62 |
63 | ---@generic T
64 | ---@param key string
65 | ---@param default T
66 | ---@return T
67 | local function get_default(key, default)
68 | local value = get(key)
69 | return value == nil and default or value
70 | end
71 |
72 | ---@return boolean
73 | local function auto_expansion_disabled(lang, trig)
74 | ---@type luasnip-snippets.utils.tbl
75 | local Tbl = require("luasnip-snippets.utils.tbl")
76 | local disabled_trigs =
77 | vim.F.if_nil(vim.tbl_get(config, "disable_auto_expansion", lang), {})
78 | return Tbl.list_contains(disabled_trigs, trig)
79 | end
80 |
81 | ---@class luasnip-snippets.config
82 | local M = {
83 | setup = setup,
84 | get = get,
85 | get_default = get_default,
86 | auto_expansion_disabled = auto_expansion_disabled,
87 | }
88 |
89 | return M
90 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/init.lua:
--------------------------------------------------------------------------------
1 | local M = {}
2 |
3 | ---@alias SnippetOrBuilder LuaSnip.Snippet|fun():SnippetOrBuilder
4 |
5 | ---Register snippets to luasnip.
6 | ---@param ft string filetype
7 | ---@param snippets SnippetOrBuilder[]
8 | local function add_snippets(ft, snippets)
9 | local ls = require("luasnip")
10 | local ret = {}
11 | for _, snippet in ipairs(snippets) do
12 | if type(snippet) == "function" then
13 | snippet = snippet()
14 | end
15 | ret[#ret + 1] = snippet
16 | end
17 | ls.add_snippets(ft, ret)
18 | end
19 |
20 | ---Load snippets from ft module.
21 | ---@param ft string
22 | ---@return SnippetOrBuilder[]
23 | local function load_snippets(ft)
24 | local snippets = require("luasnip-snippets.snippets." .. ft)
25 | if type(snippets) == "function" then
26 | snippets = snippets()
27 | end
28 | return snippets
29 | end
30 |
31 | ---Load and register snippets.
32 | ---@param fts string[]
33 | local function load_and_add_snippet(fts)
34 | for _, ft in ipairs(fts) do
35 | local snippets = load_snippets(ft)
36 | add_snippets(ft, snippets)
37 | end
38 | end
39 |
40 | ---@param opts? LSSnippets.Config
41 | function M.setup(opts)
42 | local Config = require("luasnip-snippets.config")
43 | Config.setup(opts)
44 |
45 | -- register snippets
46 | load_and_add_snippet(vim.tbl_filter(function(l)
47 | return not vim.tbl_contains(Config.get("disable_langs") or {}, l)
48 | end, {
49 | "cpp",
50 | "rust",
51 | "lua",
52 | "dart",
53 | "nix",
54 | "all",
55 | "typescript",
56 | }))
57 | end
58 |
59 | return M
60 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/nodes.lua:
--------------------------------------------------------------------------------
1 | ---@param idx number
2 | ---@param placeholder? string
3 | ---@param opts? table
4 | local function insert_node(idx, placeholder, opts)
5 | local ls = require("luasnip")
6 | if idx == 0 then
7 | return ls.insert_node(idx)
8 | end
9 | opts = opts or {}
10 | local extra_opts = {
11 | node_ext_opts = {
12 | active = {
13 | virt_text = {
14 | {
15 | " " .. idx .. ": " .. (opts.desc or placeholder or "insert"),
16 | "Comment",
17 | },
18 | },
19 | },
20 | },
21 | }
22 | opts = vim.tbl_extend("keep", opts, extra_opts)
23 | return ls.insert_node(idx, placeholder, opts)
24 | end
25 |
26 | ---@param idx number
27 | ---@param choices table
28 | ---@param opts? table
29 | local function choice_node(idx, choices, opts)
30 | local ls = require("luasnip")
31 | opts = opts or {}
32 | local extra_opts = {
33 | node_ext_opts = {
34 | active = {
35 | virt_text = {
36 | { " " .. idx .. ": " .. (opts.desc or "choice"), "Comment" },
37 | },
38 | },
39 | },
40 | }
41 | opts = vim.tbl_extend("keep", opts, extra_opts)
42 | return ls.choice_node(idx, choices, opts)
43 | end
44 |
45 | ---@alias LSSnippets.TrigMatcher fun(line_to_cursor: string, trigger: string): string, table
46 | ---@alias LSSnippets.CustomTrigEngine fun(trigger: string): LSSnippets.TrigMatcher
47 | ---@alias LSSnippets.TrigEngine "plain"|"pattern"|"ecma"|"vim"|LSSnippets.CustomTrigEngine
48 |
49 | ---@class LSSnippets.SnippetOptions
50 | ---@field [1] string Trigger
51 | ---@field name string? Snippet name
52 | ---@field dscr string? Snippet description
53 | ---@field mode string? Snippet mode, "w" for word trigger, "h" for hidden, "A" for autosnippet, "b" for line begin, "r" for regex pattern
54 | ---@field engine LSSnippets.TrigEngine? Snippet trigger engine. If "r" in mode, defaults to "pattern".
55 | ---@field hidden boolean? Hidden from completion, If "h" in mode, defaults to true.
56 | ---@field nodes LuaSnip.Node[] Expansion nodes
57 | ---@field priority number? Snippet priority
58 | ---@field lang string? Language of the snippet
59 | ---@field cond LSSnippets.ConditionObject? Condition object, including condition and show_condition
60 | ---@field resolveExpandParams nil|fun(snippet: LuaSnip.Snippet, line_to_cursor: string, matched_trigger: string, captures: table): table Function to decide whether the snippet can be expanded or not.
61 | ---@field opts table? Other options
62 |
63 | ---@param opts LSSnippets.SnippetOptions
64 | local function construct_snippet(opts)
65 | local CommonCond = require("luasnip-snippets.utils.common_cond")
66 | local ls = require("luasnip")
67 | ---@type luasnip-snippets.config
68 | local Config = require("luasnip-snippets.config")
69 |
70 | local trig = opts[1]
71 | local name = vim.F.if_nil(opts.name, trig)
72 | local dscr = vim.F.if_nil(opts.dscr, "Snippet: " .. name)
73 | local mode = vim.F.if_nil(opts.mode, "")
74 | local wordTrig = mode:match("w") ~= nil
75 | local trigEngine = vim.F.if_nil(opts.engine, "plain")
76 | if mode:match("r") ~= nil and opts.engine == nil then
77 | trigEngine = "pattern"
78 | end
79 | local hidden = vim.F.if_nil(opts.hidden, mode:match("h") ~= nil)
80 | local snippetType = mode:match("A") ~= nil and "autosnippet" or "snippet"
81 | if
82 | snippetType == "autosnippet"
83 | and opts.lang ~= nil
84 | and Config.auto_expansion_disabled(opts.lang, trig)
85 | then
86 | snippetType = "snippet"
87 | end
88 | local nodes = opts.nodes
89 | local priority = opts.priority or nil
90 | local cond = opts.cond or nil
91 | if mode:match("b") ~= nil then
92 | local line_begin = CommonCond.at_line_begin(trig)
93 | cond = cond and (cond + line_begin) or line_begin
94 | end
95 | local trig_arg = {
96 | trig = trig,
97 | name = name,
98 | dscr = dscr,
99 | wordTrig = wordTrig,
100 | trigEngine = trigEngine,
101 | hidden = hidden,
102 | priority = priority,
103 | snippetType = snippetType,
104 | condition = cond and cond.condition,
105 | show_condition = cond and cond.show_condition,
106 | resolveExpandParams = opts.resolveExpandParams,
107 | }
108 | return ls.s(trig_arg, nodes, opts.opts)
109 | end
110 |
111 | ---Construct a snippet for simple expansion. (word) -> (expand)
112 | ---@param word string
113 | ---@param expand string
114 | ---@param mode? string
115 | local function word_expand(word, expand, mode)
116 | local ls = require("luasnip")
117 |
118 | mode = mode or "w"
119 | if mode:match("w") == nil then
120 | mode = mode .. "w"
121 | end
122 | return construct_snippet {
123 | word,
124 | name = ("(%s) %s"):format(word, expand),
125 | dscr = ("Quickly expands %s to %s"):format(word, expand),
126 | mode = mode,
127 | nodes = ls.text_node(expand),
128 | }
129 | end
130 |
131 | ---@class luasnip-snippets.nodes
132 | local M = {
133 | insert_node = insert_node,
134 | choice_node = choice_node,
135 | construct_snippet = construct_snippet,
136 | word_expand = word_expand,
137 | }
138 |
139 | return M
140 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/snippets/all.lua:
--------------------------------------------------------------------------------
1 | ---@param keyword string
2 | local todo_comment = function(keyword)
3 | local ls = require("luasnip")
4 | local f = ls.function_node
5 | local snippet = require("luasnip-snippets.nodes").construct_snippet
6 | local Config = require("luasnip-snippets.config")
7 |
8 | return snippet {
9 | keyword,
10 | mode = "bw",
11 | nodes = {
12 | f(function()
13 | local CommentFt = require("luasnip-snippets.utils.comment")
14 | local ft = vim.api.nvim_get_option_value("filetype", {
15 | buf = 0,
16 | })
17 | local pattern = CommentFt.get(ft, 1)
18 | local name = Config.get("user.name")
19 | if pattern == nil then
20 | -- keep the input
21 | pattern = "%s"
22 | end
23 | if type(pattern) == "table" then
24 | pattern = pattern[1]
25 | end
26 | local marker
27 | if name == nil then
28 | marker = (" %s: "):format(keyword:upper())
29 | else
30 | marker = (" %s(%s): "):format(keyword:upper(), name)
31 | end
32 | return pattern:format(marker)
33 | end, {}),
34 | },
35 | }
36 | end
37 |
38 | return {
39 | todo_comment("todo"),
40 | todo_comment("fixme"),
41 | todo_comment("note"),
42 | }
43 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/snippets/cpp/commons.lua:
--------------------------------------------------------------------------------
1 | local header_ext = {
2 | "hh",
3 | "h",
4 | "hpp",
5 | "hxx",
6 | "h++",
7 | "inl",
8 | "ipp",
9 | "tcc",
10 | }
11 |
12 | local function in_header_file()
13 | local ext = vim.fn.expand("%:e")
14 | if vim.list_contains(header_ext, ext) then
15 | return true
16 | end
17 | return false
18 | end
19 |
20 | ---@param lines string[]
21 | ---@return string[]
22 | local function fix_leading_whitespace(lines, indent)
23 | indent = vim.F.if_nil(indent, 2)
24 | local leading_whitespace = string.rep(" ", indent)
25 | local ret = {}
26 | local first = true
27 | for _, line in ipairs(lines) do
28 | if not first then
29 | table.insert(ret, leading_whitespace .. line)
30 | else
31 | first = false
32 | table.insert(ret, line)
33 | end
34 | end
35 | return ret
36 | end
37 |
38 | local function add_trailing_slash(lines)
39 | local ret = {}
40 | local max_len = 0
41 | for _, line in ipairs(lines) do
42 | max_len = math.max(max_len, #line)
43 | end
44 | for _, line in ipairs(lines) do
45 | local len = #line
46 | local diff = max_len - len
47 | table.insert(ret, line .. string.rep(" ", diff) .. " \\")
48 | end
49 | return ret
50 | end
51 |
52 | return {
53 | header_ext = header_ext,
54 | in_header_file = in_header_file,
55 | fix_leading_whitespace = fix_leading_whitespace,
56 | add_trailing_slash = add_trailing_slash,
57 | }
58 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/snippets/cpp/default.lua:
--------------------------------------------------------------------------------
1 | local ls = require("luasnip")
2 | ---@type luasnip-snippets.nodes
3 | local Nodes = require("luasnip-snippets.nodes")
4 | local snippet = Nodes.construct_snippet
5 | local i = Nodes.insert_node
6 | local c = Nodes.choice_node
7 | local fmta = require("luasnip.extras.fmt").fmta
8 | local f = ls.function_node
9 | local t = ls.text_node
10 | local rep = require("luasnip.extras").rep
11 | local CommonCond = require("luasnip-snippets.utils.common_cond")
12 | ---@type luasnip-snippets.config
13 | local Config = require("luasnip-snippets.config")
14 | ---@type luasnip-snippets.utils
15 | local Utils = require("luasnip-snippets.utils")
16 |
17 | local function cpo_snippet()
18 | local function cpo_func_to_namespace(name)
19 | -- try to convert name from pascal case to snake case
20 | if name:match("^[A-Z]") then
21 | -- is pascal case now, change to snake case
22 | name = name:gsub("(%u+)(%u%l)", "%1_%2")
23 | name = name:gsub("([a-z0-9])([A-Z])", "%1_%2")
24 | name = name:gsub("-", "_")
25 | name = name:lower()
26 | end
27 | return ("%s_fn"):format(name)
28 | end
29 | return snippet {
30 | "cpo",
31 | name = "(cpo) Customization point object",
32 | dscr = "Expands to a customization point object",
33 | mode = "bw",
34 | nodes = fmta(
35 | [[
36 | namespace {
37 | struct Fn {
38 | template<>
39 | decltype(auto) operator()(T&& value) const noexcept(_noexcept) {
40 |
41 | }
42 | };
43 | } // namespace
44 | inline constexpr ::Fn {};
45 | ]],
46 | {
47 | name = i(1, "function name"),
48 | ns_name = f(function(args)
49 | return cpo_func_to_namespace(args[1][1])
50 | end, { 1 }),
51 | cursor = i(0),
52 | }
53 | ),
54 | }
55 | end
56 |
57 | ---@param bits number
58 | ---@param unsigned boolean
59 | local function int_type_snippet(bits, unsigned)
60 | local prefix = unsigned and "u" or ""
61 | local trig = (unsigned and "u" or "i") .. bits
62 | local expand = ("%sint%s_t"):format(prefix, bits)
63 | return snippet {
64 | trig,
65 | name = ("(%s) %s"):format(trig, expand),
66 | desc = ("Expands to %s"):format(expand),
67 | mode = "wA",
68 | lang = "cpp",
69 | nodes = {
70 | t(expand),
71 | },
72 | }
73 | end
74 |
75 | ---@param trig string
76 | ---@param func string
77 | local function ranges_views_snippet(trig, func)
78 | return snippet {
79 | trig,
80 | name = ("(%s) %s"):format(trig, func:gsub("^%l", string.upper)),
81 | dscr = ("Expands to %s view"):format(func),
82 | nodes = fmta(
83 | [[
84 | | ::views::([&](auto&& value) {
85 |
86 | })
87 | ]],
88 | {
89 | namespace = c(1, {
90 | t("ranges"),
91 | t("std"),
92 | }, { desc = "library" }),
93 | body = i(0),
94 | func = t(func),
95 | }
96 | ),
97 | }
98 | end
99 |
100 | local all_lines_before_are_all_comments =
101 | CommonCond.generate_all_lines_before_match_cond {
102 | "^%s*//.*$",
103 | "^%s*$",
104 | }
105 |
106 | local default_quick_markers = {
107 | v = { params = 1, template = "std::vector<%s>" },
108 | i = { params = 0, template = "int32_t" },
109 | s = { params = 0, template = "std::string" },
110 | u = { params = 0, template = "uint32_t" },
111 | m = { params = 2, template = "absl::flat_hash_map<%s, %s>" },
112 | t = { params = -1, template = "std::tuple<%s>" },
113 | }
114 |
115 | ---@param shortcut string
116 | ---@return string?
117 | local function quick_type(shortcut)
118 | ---@type luasnip-snippets.config
119 | local quick_markers = Config.get("snippet.cpp.quick_type.extra_trig") or {}
120 | local markers = vim.deepcopy(default_quick_markers)
121 | for _, marker in ipairs(quick_markers) do
122 | markers[marker.trig] = {
123 | params = marker.params,
124 | template = marker.template,
125 | }
126 | end
127 |
128 | ---@param s string
129 | ---@return string?, string?
130 | local function expect_typename(s)
131 | local first, rest = s:match("^(%l)(.*)$")
132 | if first == nil then
133 | return nil, nil
134 | end
135 |
136 | local trig = markers[first]
137 | if trig == nil then
138 | return nil, nil
139 | end
140 |
141 | if trig.params == -1 then
142 | local parameters = {}
143 | while #rest > 0 do
144 | local typename, sub_rest = expect_typename(rest)
145 | if typename == nil or sub_rest == nil then
146 | break
147 | end
148 | parameters[#parameters + 1] = typename
149 | rest = sub_rest
150 | end
151 | return (trig.template):format(table.concat(parameters, ", ")), rest
152 | end
153 |
154 | if trig.params == 0 then
155 | return trig.template, rest
156 | end
157 |
158 | local parameters = {}
159 | for _ = 1, trig.params do
160 | local typename, sub_rest = expect_typename(rest)
161 | if typename == nil or sub_rest == nil then
162 | return nil, rest
163 | end
164 | parameters[#parameters + 1] = typename
165 | rest = sub_rest
166 | end
167 |
168 | return string.format(trig.template, unpack(parameters)), rest
169 | end
170 |
171 | local result, rest = expect_typename(shortcut)
172 | if rest and #rest > 0 then
173 | print(("After QET eval, rest not empty: %s"):format(rest))
174 | end
175 | if result == nil then
176 | return shortcut
177 | else
178 | return result
179 | end
180 | end
181 |
182 | return {
183 | cpo_snippet,
184 |
185 | ranges_views_snippet("|trans", "transform"),
186 | ranges_views_snippet("|filter", "filter"),
187 |
188 | -- progma once
189 | snippet {
190 | "once",
191 | name = "(once) #Progma once",
192 | dscr = "Expands to progma once with comments",
193 | mode = "bwA",
194 | lang = "cpp",
195 | cond = all_lines_before_are_all_comments,
196 | nodes = {
197 | f(function()
198 | local buffer_settings =
199 | Utils.get_buf_var(0, "LuasnipSnippetsCppCppLint")
200 |
201 | local use_cpplint = vim.F.if_nil(
202 | buffer_settings,
203 | Config.get_default("snippet.cpp.cpplint", true)
204 | )
205 | if use_cpplint then
206 | return { "#pragma once // NOLINT(build/header_guard)", "" }
207 | else
208 | return { "#pragma once", "" }
209 | end
210 | end),
211 | },
212 | },
213 |
214 | -- include short cuts
215 | snippet {
216 | '#"',
217 | name = 'include ""',
218 | dscr = "#include with quotes",
219 | mode = "bA",
220 | lang = "cpp",
221 | nodes = {
222 | t('#include "'),
223 | i(1, "header"),
224 | t('"'),
225 | },
226 | },
227 | snippet {
228 | "#<",
229 | name = "include <>",
230 | dscr = "#include with <>",
231 | mode = "bA",
232 | lang = "cpp",
233 | nodes = {
234 | t("#include <"),
235 | i(1, "header"),
236 | t(">"),
237 | },
238 | },
239 |
240 | -- preprocessor directives short cuts
241 | snippet {
242 | "#?",
243 | name = "#ifdef",
244 | dscr = "Expands to #ifdef ... #endif",
245 | mode = "bA",
246 | lang = "cpp",
247 | nodes = fmta(
248 | [[
249 | #
250 |
251 | #endif //
252 | ]],
253 | {
254 | directive = c(1, {
255 | t("ifdef"),
256 | t("ifndef"),
257 | }, { desc = "Directive" }),
258 | name = i(2, "name"),
259 | cursor = i(0),
260 | selected = f(function(_, snip)
261 | local _, env = {}, snip.env
262 | return env.LS_SELECT_RAW
263 | end),
264 | name_r = rep(2),
265 | }
266 | ),
267 | },
268 |
269 | -- fast int types
270 | int_type_snippet(8, true),
271 | int_type_snippet(8, false),
272 | int_type_snippet(16, true),
273 | int_type_snippet(16, false),
274 | int_type_snippet(32, true),
275 | int_type_snippet(32, false),
276 | int_type_snippet(64, true),
277 | int_type_snippet(64, false),
278 |
279 | -- quick expand, expand stl types
280 | -- v = std::vector
281 | -- i = int32_t
282 | -- s = std::string
283 | -- u = uint32_t
284 | -- m = absl::flat_hash_map
285 | -- t = std::tuple
286 | ls.s({
287 | trig = "t(%l+)!",
288 | wordTrig = true,
289 | regTrig = true,
290 | snippetType = "autosnippet",
291 | name = "(t) Quick types",
292 | desc = "Expands to a type",
293 | }, {
294 | f(function(_, snip)
295 | local shortcut = snip.captures[1]
296 | return quick_type(shortcut)
297 | end),
298 | }),
299 |
300 | snippet {
301 | "ns%s+(%S+)",
302 | name = "namespace",
303 | dscr = "namespace",
304 | mode = "br",
305 | nodes = fmta(
306 | [[
307 | namespace {
308 |
309 | } // namespace
310 | ]],
311 | {
312 | body = i(0),
313 | name = f(function(_, snip)
314 | local parts = vim.split(snip.captures[1], "::", {
315 | plain = true,
316 | trimempty = true,
317 | })
318 | local names = {}
319 | for _, part in ipairs(parts) do
320 | local nest_parts = vim.split(part, ".", {
321 | plain = true,
322 | trimempty = true,
323 | })
324 | vim.list_extend(names, nest_parts)
325 | end
326 | return table.concat(names, "::")
327 | end),
328 | }
329 | ),
330 | },
331 | }
332 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/snippets/cpp/init.lua:
--------------------------------------------------------------------------------
1 | local Utils = require("luasnip-snippets.utils")
2 |
3 | local function setup()
4 | local collections = {
5 | "statements",
6 | "lambda_fn",
7 | "postfix",
8 | "selection",
9 | "default",
10 | }
11 |
12 | local Config = require("luasnip-snippets.config")
13 | local qt_enabled = vim.F.if_nil(Config.get("snippet.cpp.qt"), true)
14 |
15 | if qt_enabled then
16 | collections[#collections + 1] = "qt"
17 | end
18 |
19 | return Utils.concat_snippets("luasnip-snippets.snippets.cpp", collections)
20 | end
21 |
22 | return setup
23 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/snippets/cpp/lambda_fn.lua:
--------------------------------------------------------------------------------
1 | local ls = require("luasnip")
2 | local UtilsTS = require("luasnip-snippets.utils.treesitter")
3 | local d = ls.dynamic_node
4 | local sn = ls.snippet_node
5 | local t = ls.text_node
6 | local fmta = require("luasnip.extras.fmt").fmta
7 | local CppCommons = require("luasnip-snippets.snippets.cpp.commons")
8 | local i = require("luasnip-snippets.nodes").insert_node
9 | local c = require("luasnip-snippets.nodes").choice_node
10 | local f = ls.function_node
11 |
12 | ---@class LSSnippets.Cpp.Fn.Env
13 | ---@field CPP_ARGUMENT_START { [1]: number, [2]: number }?
14 | ---@field CPP_FUNCTION_BODY_START { [1]: number, [2]: number }?
15 | ---@field CPP_CLASS_BODY_START { [1]: number, [2]: number }?
16 | ---@field CPP_IN_HEADER_FILE boolean
17 | ---@field CPP_IN_QUALIFIED_FUNCTION boolean
18 | ---@field LS_SELECT_RAW? string[]
19 |
20 | ---Returns if the node's declarator is qualified or not.
21 | ---@param node TSNode? `function_definition` node
22 | ---@return boolean
23 | local function is_qualified_function(node)
24 | if node == nil then
25 | return false
26 | end
27 | print(node:type())
28 | assert(node:type() == "function_definition")
29 | local declarators = node:field("declarator")
30 | if declarators == nil or #declarators == 0 then
31 | return false
32 | end
33 | local declarator = declarators[1]
34 | print(declarator:type())
35 | assert(declarator:type() == "function_declarator")
36 | declarators = declarator:field("declarator")
37 | if declarators == nil or #declarators == 0 then
38 | return false
39 | end
40 | declarator = declarators[1]
41 | print(declarator:type())
42 | if declarator:type() == "qualified_identifier" then
43 | return true
44 | end
45 | return false
46 | end
47 |
48 | local function inject_expanding_environment(_, _, match, captures)
49 | local row, col = unpack(vim.api.nvim_win_get_cursor(0))
50 | local buf = vim.api.nvim_get_current_buf()
51 |
52 | return UtilsTS.invoke_after_reparse_buffer(buf, match, function(parser, _)
53 | local pos = {
54 | row - 1,
55 | col - #match,
56 | }
57 | local node = parser:named_node_for_range {
58 | pos[1],
59 | pos[2],
60 | pos[1],
61 | pos[2],
62 | }
63 |
64 | local ret = {
65 | trigger = match,
66 | capture = captures,
67 | env_override = {
68 | CPP_ARGUMENT_START = UtilsTS.start_pos(
69 | UtilsTS.find_first_parent(node, {
70 | "argument_list",
71 | "parameter_list",
72 | })
73 | ),
74 | CPP_FUNCTION_BODY_START = UtilsTS.start_pos(
75 | UtilsTS.find_first_parent(node, {
76 | "function_definition",
77 | "lambda_expression",
78 | "field_declaration",
79 | })
80 | ),
81 | CPP_CLASS_BODY_START = UtilsTS.start_pos(
82 | UtilsTS.find_first_parent(node, {
83 | "struct_specifier",
84 | "class_specifier",
85 | })
86 | ),
87 | CPP_IN_HEADER_FILE = CppCommons.in_header_file(),
88 | CPP_IN_QUALIFIED_FUNCTION = is_qualified_function(
89 | UtilsTS.find_first_parent(node, {
90 | "function_definition",
91 | })
92 | ),
93 | },
94 | }
95 |
96 | vim.api.nvim_win_set_cursor(0, { row, col })
97 | return ret
98 | end)
99 | end
100 |
101 | ---@param env LSSnippets.Cpp.Fn.Env
102 | local function make_lambda_snippet_node(env)
103 | local captures = t("&")
104 | if env.CPP_CLASS_BODY_START or env.CPP_IN_QUALIFIED_FUNCTION then
105 | -- inside a member function
106 | captures = c(3, {
107 | t("this, &"),
108 | t("this"),
109 | t("&"),
110 | })
111 | end
112 |
113 | local fmt_args = {
114 | captures = captures,
115 | body = i(0),
116 | specifier = c(1, {
117 | t(""),
118 | t(" mutable"),
119 | }),
120 | selected = f(function()
121 | return CppCommons.fix_leading_whitespace(env.LS_SELECT_RAW)
122 | end),
123 | args = i(2),
124 | }
125 |
126 | return sn(
127 | nil,
128 | fmta(
129 | [[
130 | []() {
131 |
132 | }
133 | ]],
134 | fmt_args
135 | )
136 | )
137 | end
138 |
139 | ---@param env LSSnippets.Cpp.Fn.Env
140 | local function make_function_snippet_node(env)
141 | local fmt_args = {
142 | body = i(0),
143 | inline_inline = t(""),
144 | }
145 | local storage_specifiers = {
146 | t(""),
147 | t("static "),
148 | }
149 | if not env.CPP_IN_HEADER_FILE then
150 | storage_specifiers[#storage_specifiers + 1] = t("inline ")
151 | storage_specifiers[#storage_specifiers + 1] = t("static inline ")
152 | else
153 | fmt_args.inline_inline = t("inline ")
154 | end
155 |
156 | local specifiers = {
157 | t(""),
158 | t(" noexcept"),
159 | }
160 | if env.CPP_CLASS_BODY_START then
161 | specifiers[#specifiers + 1] = t(" const")
162 | specifiers[#specifiers + 1] = t(" const noexcept")
163 | end
164 | fmt_args.storage_specifier =
165 | c(1, storage_specifiers, { desc = "storage specifier" })
166 | fmt_args.ret = i(2, "auto", { desc = "return type" })
167 | fmt_args.name = i(3, "name", { desc = "function name" })
168 | fmt_args.args = i(4, "args", { desc = "function arguments" })
169 | fmt_args.specifier = c(5, specifiers, { desc = "specifier" })
170 | fmt_args.selected = f(function()
171 | return CppCommons.fix_leading_whitespace(env.LS_SELECT_RAW)
172 | end)
173 | return sn(
174 | nil,
175 | fmta(
176 | [[
177 | auto () ->> {
178 |
179 | }
180 | ]],
181 | fmt_args
182 | )
183 | )
184 | end
185 |
186 | return {
187 | ls.s(
188 | {
189 | trig = "fn",
190 | wordTrig = true,
191 | name = "(fn) Function-Definition/Lambda",
192 | resolveExpandParams = inject_expanding_environment,
193 | },
194 | d(1, function(_, parent)
195 | local env = parent.env
196 | local last_type, last_type_row, last_type_col
197 | local keys = {
198 | "CPP_ARGUMENT_START",
199 | "CPP_FUNCTION_BODY_START",
200 | "CPP_CLASS_BODY_START",
201 | }
202 | for _, key in ipairs(keys) do
203 | if env[key] ~= nil then
204 | if last_type == nil then
205 | last_type = key
206 | last_type_row = env[key][1]
207 | last_type_col = env[key][2]
208 | else
209 | if
210 | last_type_row < env[key][1]
211 | or (last_type_row == env[key][1] and last_type_col < env[key][2])
212 | then
213 | last_type = key
214 | last_type_row = env[key][1]
215 | last_type_col = env[key][2]
216 | end
217 | end
218 | end
219 | end
220 |
221 | if
222 | last_type == "CPP_ARGUMENT_START"
223 | or last_type == "CPP_FUNCTION_BODY_START"
224 | then
225 | return make_lambda_snippet_node(env)
226 | else
227 | return make_function_snippet_node(env)
228 | end
229 | end, {})
230 | ),
231 | }
232 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/snippets/cpp/postfix.lua:
--------------------------------------------------------------------------------
1 | local ls = require("luasnip")
2 | local f = ls.function_node
3 | local tsp = require("luasnip.extras.treesitter_postfix")
4 | local Utils = require("luasnip-snippets.utils")
5 | local fmt = require("luasnip.extras.fmt").fmt
6 | local fmta = require("luasnip.extras.fmt").fmta
7 | local i = require("luasnip-snippets.nodes").insert_node
8 | ---@type luasnip-snippets.nodes
9 | local Nodes = require("luasnip-snippets.nodes")
10 | local snippet = Nodes.construct_snippet
11 | local CommonCond = require("luasnip-snippets.utils.common_cond")
12 |
13 | local expr_query = [[
14 | [
15 | (call_expression)
16 | (identifier)
17 | (template_function)
18 | (subscript_expression)
19 | (field_expression)
20 | (user_defined_literal)
21 | ] @prefix
22 | ]]
23 |
24 | local indent_query = [[
25 | [
26 | (identifier)
27 | (field_identifier)
28 | ] @prefix
29 | ]]
30 |
31 | ---@param trig string
32 | ---@param expand string
33 | ---@param dscr string?
34 | local function expr_tsp(trig, expand, dscr)
35 | local name = ("(%s) %s"):format(trig, expand)
36 | if dscr == nil then
37 | dscr = ("Wraps an expression with %s"):format(expand)
38 | else
39 | dscr = dscr:format(expand)
40 | end
41 | local replaced = expand:gsub("?", "%%s")
42 |
43 | return {
44 | snippet {
45 | trig,
46 | name = name,
47 | dscr = dscr,
48 | mode = "w",
49 | lang = "cpp",
50 | cond = CommonCond.has_select_raw,
51 | nodes = {
52 | f(function(_, snip)
53 | local _, env = {}, snip.env
54 | return Utils.replace_all(env.LS_SELECT_RAW, replaced)
55 | end),
56 | },
57 | },
58 | tsp.treesitter_postfix({
59 | trig = "." .. trig,
60 | name = name,
61 | dscr = dscr,
62 | wordTrig = false,
63 | reparseBuffer = "live",
64 | matchTSNode = {
65 | query = expr_query,
66 | query_lang = "cpp",
67 | },
68 | }, {
69 | f(function(_, parent)
70 | return Utils.replace_all(parent.snippet.env.LS_TSMATCH, replaced)
71 | end, {}),
72 | }),
73 | }
74 | end
75 |
76 | return {
77 | expr_tsp(
78 | "be",
79 | "?.begin(), ?.end()",
80 | "Completes an expr with both begin() and end()"
81 | ),
82 | expr_tsp(
83 | "cbe",
84 | "?.cbegin(), ?.cend()",
85 | "Completes an expr with both cbegin() and cend()"
86 | ),
87 | expr_tsp("mv", "std::move(?)"),
88 | expr_tsp("fwd", "std::forward(?)"),
89 | expr_tsp("val", "std::declval>()"),
90 | expr_tsp("dt", "decltype(?)"),
91 | expr_tsp("uu", "(void)?"),
92 | expr_tsp("single", "ranges::views::single(?)"),
93 | expr_tsp("await", "co_await ?"),
94 |
95 | tsp.treesitter_postfix({
96 | trig = ".ts",
97 | name = "(.ts) Toggle style",
98 | dscr = "Toggle previous indent's style",
99 | wordTrig = false,
100 | reparseBuffer = "live",
101 | matchTSNode = {
102 | query = indent_query,
103 | query_lang = "cpp",
104 | },
105 | }, {
106 | f(function(_, parent)
107 | -- switch name style from snake to pascal or vice versa
108 | -- name must be a oneline identifier
109 | local name = table.concat(parent.snippet.env.LS_TSMATCH, "\n")
110 | if name:match("^[A-Z]") then
111 | -- is pascal case now, change to snake case
112 | name = name:gsub("(%u+)(%u%l)", "%1_%2")
113 | name = name:gsub("([a-z0-9])([A-Z])", "%1_%2")
114 | name = name:gsub("-", "_")
115 | return name:lower()
116 | else
117 | -- is snake case now, change to pascal case
118 | return name
119 | :gsub("_(%l)", function(s)
120 | return s:upper()
121 | end)
122 | :gsub("^%l", string.upper)
123 | :gsub("_$", "")
124 | end
125 | end, {}),
126 | }),
127 |
128 | tsp.treesitter_postfix(
129 | {
130 | trig = ".sc",
131 | name = "(.sc) static_cast(?)",
132 | dscr = "Wraps an expression with static_cast(?)",
133 | wordTrig = false,
134 | reparseBuffer = "live",
135 | matchTSNode = {
136 | query = expr_query,
137 | query_lang = "cpp",
138 | },
139 | },
140 | fmt(
141 | [[
142 | static_cast<{body}>({expr}){end}
143 | ]],
144 | {
145 | body = i(1),
146 | expr = f(function(_, parent)
147 | return Utils.replace_all(parent.snippet.env.LS_TSMATCH, "%s")
148 | end, {}),
149 | ["end"] = i(0),
150 | }
151 | )
152 | ),
153 |
154 | snippet {
155 | "sc",
156 | name = "(sc) static_cast(...)",
157 | dscr = "Wraps an expression with static_cast(...)",
158 | mode = "w",
159 | lang = "cpp",
160 | cond = CommonCond.has_select_raw,
161 | nodes = fmt(
162 | [[
163 | static_cast<{body}>({selected}){cursor}
164 | ]],
165 | {
166 | cursor = i(0),
167 | body = i(1),
168 | selected = f(function(_, snip)
169 | local _, env = {}, snip.env
170 | return Utils.replace_all(env.LS_SELECT_RAW, "%s")
171 | end),
172 | }
173 | ),
174 | },
175 |
176 | tsp.treesitter_postfix(
177 | {
178 | trig = ".rc",
179 | name = "(.rc) reinterpret_cast(?)",
180 | dscr = "Wraps an expression with reinterpret_cast(?)",
181 | wordTrig = false,
182 | reparseBuffer = "live",
183 | matchTSNode = {
184 | query = expr_query,
185 | query_lang = "cpp",
186 | },
187 | },
188 | fmt(
189 | [[
190 | reinterpret_cast<{body}>({expr}){end}
191 | ]],
192 | {
193 | body = i(1),
194 | expr = f(function(_, parent)
195 | return Utils.replace_all(parent.snippet.env.LS_TSMATCH, "%s")
196 | end, {}),
197 | ["end"] = i(0),
198 | }
199 | )
200 | ),
201 |
202 | snippet {
203 | "rc",
204 | name = "(rc) reinterpret_cast(...)",
205 | dscr = "Wraps an expression with reinterpret_cast(...)",
206 | mode = "w",
207 | lang = "cpp",
208 | cond = CommonCond.has_select_raw,
209 | nodes = fmt(
210 | [[
211 | reinterpret_cast<{body}>({selected}){cursor}
212 | ]],
213 | {
214 | cursor = i(0),
215 | body = i(1),
216 | selected = f(function(_, snip)
217 | local _, env = {}, snip.env
218 | return Utils.replace_all(env.LS_SELECT_RAW, "%s")
219 | end),
220 | }
221 | ),
222 | },
223 |
224 | tsp.treesitter_postfix(
225 | {
226 | trig = ".in",
227 | name = "(.in) if (...find)",
228 | dscr = "Expands to an if-expr to find an element in map-like object",
229 | wordTrig = false,
230 | reparseBuffer = "live",
231 | matchTSNode = {
232 | query = expr_query,
233 | query_lang = "cpp",
234 | },
235 | },
236 | fmta(
237 | [[
238 | if (auto it = .find(); it != .end()) {
239 |
240 | }
241 | ]],
242 | {
243 | cursor = i(0),
244 | key = i(1, "Key"),
245 | expr = f(function(_, parent)
246 | return Utils.replace_all(parent.snippet.env.LS_TSMATCH, "%s")
247 | end, {}),
248 | }
249 | )
250 | ),
251 | }
252 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/snippets/cpp/qt.lua:
--------------------------------------------------------------------------------
1 | local ls = require("luasnip")
2 | local UtilsTS = require("luasnip-snippets.utils.treesitter")
3 | local d = ls.dynamic_node
4 | local sn = ls.snippet_node
5 | local t = ls.text_node
6 | local fmta = require("luasnip.extras.fmt").fmta
7 | local snippet = require("luasnip-snippets.nodes").construct_snippet
8 | local i = require("luasnip-snippets.nodes").insert_node
9 | local rep = require("luasnip.extras").rep
10 |
11 | return {
12 | snippet {
13 | "qcls",
14 | name = "Q_OBJECT class",
15 | dscr = "Declare a class with Q_OBJECT macro",
16 | mode = "bw",
17 | nodes = fmta(
18 | [[
19 | class <> : public QObject {
20 | Q_OBJECT
21 |
22 | public:
23 | ~<>() = default;
24 | };
25 | ]],
26 | {
27 | i(1, "Class Name"),
28 | rep(1),
29 | }
30 | ),
31 | },
32 | snippet {
33 | "#q",
34 | name = "include qt MOC",
35 | dscr = "#include qt generated MOC file",
36 | mode = "bA",
37 | lang = "cpp",
38 | nodes = {
39 | t((function()
40 | local filename = vim.fn.expand("%:t")
41 | return ('#include "moc_%s"'):format(filename)
42 | end)()),
43 | },
44 | },
45 | }
46 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/snippets/cpp/selection.lua:
--------------------------------------------------------------------------------
1 | local ls = require("luasnip")
2 | ---@type luasnip-snippets.nodes
3 | local Nodes = require("luasnip-snippets.nodes")
4 | local snippet = Nodes.construct_snippet
5 | local i = Nodes.insert_node
6 | local c = Nodes.choice_node
7 | local fmta = require("luasnip.extras.fmt").fmta
8 | local f = ls.function_node
9 | local t = ls.text_node
10 | local rep = require("luasnip.extras").rep
11 | local CommonCond = require("luasnip-snippets.utils.common_cond")
12 | ---@type luasnip-snippets.utils.cond
13 | local Cond = require("luasnip-snippets.utils.cond")
14 | ---@type luasnip-snippets.config
15 | local Config = require("luasnip-snippets.config")
16 | ---@type luasnip-snippets.utils
17 | local Utils = require("luasnip-snippets.utils")
18 | local CppCommons = require("luasnip-snippets.snippets.cpp.commons")
19 |
20 | local has_select_raw = CommonCond.has_select_raw
21 |
22 | return {
23 | snippet {
24 | "#if",
25 | name = "(#if) #if ... #endif",
26 | dscr = "Wrap selected code in #if ... #endif block",
27 | mode = "bw",
28 | lang = "cpp",
29 | cond = has_select_raw,
30 | nodes = fmta(
31 | [[
32 | #if
33 |
34 | #endif //
35 | ]],
36 | {
37 | condition = i(1, "condition"),
38 | cursor = i(0),
39 | selected = f(function(_, snip)
40 | local _, env = {}, snip.env
41 | return env.LS_SELECT_RAW
42 | end),
43 | condition_r = rep(1),
44 | }
45 | ),
46 | },
47 |
48 | snippet {
49 | "if",
50 | name = "(if) if (...) { ... }",
51 | dscr = "Wrap selected code in if (...) { ... } block",
52 | mode = "bw",
53 | lang = "cpp",
54 | cond = has_select_raw,
55 | nodes = fmta(
56 | [[
57 | if () {
58 |
59 | }
60 | ]],
61 | {
62 | condition = i(1, "condition"),
63 | cursor = i(0),
64 | selected = f(function(_, snip)
65 | local _, env = {}, snip.env
66 | return CppCommons.fix_leading_whitespace(env.LS_SELECT_RAW)
67 | end),
68 | }
69 | ),
70 | },
71 |
72 | snippet {
73 | "do",
74 | name = "(do) do { ... } while (0)",
75 | dscr = "Wrap selected code in do { ... } while (0) block",
76 | mode = "bw",
77 | lang = "cpp",
78 | cond = has_select_raw,
79 | nodes = fmta(
80 | [[
81 | do {
82 |
83 | } while (0);
84 | ]],
85 | {
86 | cursor = i(0),
87 | selected = f(function(_, snip)
88 | local _, env = {}, snip.env
89 | return CppCommons.fix_leading_whitespace(env.LS_SELECT_RAW)
90 | end),
91 | }
92 | ),
93 | },
94 |
95 | snippet {
96 | "while",
97 | name = "(while) while (...) { ... }",
98 | dscr = "Wrap selected code in while (...) { ... } block",
99 | mode = "bw",
100 | lang = "cpp",
101 | cond = has_select_raw,
102 | nodes = fmta(
103 | [[
104 | while () {
105 |
106 | }
107 | ]],
108 | {
109 | condition = i(1, "condition"),
110 | cursor = i(0),
111 | selected = f(function(_, snip)
112 | local _, env = {}, snip.env
113 | return CppCommons.fix_leading_whitespace(env.LS_SELECT_RAW)
114 | end),
115 | }
116 | ),
117 | },
118 |
119 | snippet {
120 | "#de",
121 | name = "(#de) #define ...",
122 | dscr = "Wrap selected code in #define block",
123 | mode = "bw",
124 | lang = "cpp",
125 | cond = has_select_raw,
126 | nodes = fmta(
127 | [[
128 | #define () \
129 |
130 | ]],
131 | {
132 | name = i(1, "condition"),
133 | cursor = i(0),
134 | selected = f(function(_, snip)
135 | local _, env = {}, snip.env
136 | return CppCommons.fix_leading_whitespace(
137 | CppCommons.add_trailing_slash(env.LS_SELECT_RAW)
138 | )
139 | end),
140 | }
141 | ),
142 | },
143 | }
144 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/snippets/cpp/statements.lua:
--------------------------------------------------------------------------------
1 | local ls = require("luasnip")
2 | local UtilsTS = require("luasnip-snippets.utils.treesitter")
3 | local d = ls.dynamic_node
4 | local sn = ls.snippet_node
5 | local t = ls.text_node
6 | local fmta = require("luasnip.extras.fmt").fmta
7 | local snippet = require("luasnip-snippets.nodes").construct_snippet
8 | local i = require("luasnip-snippets.nodes").insert_node
9 | local c = require("luasnip-snippets.nodes").choice_node
10 | local rep = require("luasnip.extras").rep
11 |
12 | local function inject_class_name(_, line_to_cursor, match, captures)
13 | -- check if at the line begin
14 | if not line_to_cursor:sub(1, -(#match + 1)):match("^%s*$") then
15 | return nil
16 | end
17 |
18 | local row, col = unpack(vim.api.nvim_win_get_cursor(0))
19 | local buf = vim.api.nvim_get_current_buf()
20 |
21 | return UtilsTS.invoke_after_reparse_buffer(
22 | buf,
23 | match,
24 | function(parser, source)
25 | local pos = {
26 | row - 1,
27 | col - #match, -- match has been removed from source
28 | }
29 | local node = parser:named_node_for_range {
30 | pos[1],
31 | pos[2],
32 | pos[1],
33 | pos[2],
34 | }
35 | if node == nil then
36 | return nil
37 | end
38 |
39 | local class_node = UtilsTS.find_first_parent(node, {
40 | "struct_specifier",
41 | "class_specifier",
42 | })
43 | if class_node == nil then
44 | return nil
45 | end
46 | local name_nodes = class_node:field("name")
47 | if name_nodes == nil or #name_nodes == 0 then
48 | return nil
49 | end
50 | local name_node = name_nodes[1]
51 | local ret = {
52 | trigger = match,
53 | captures = captures,
54 | env_override = {
55 | CLASS_NAME = vim.treesitter.get_node_text(name_node, source),
56 | },
57 | }
58 | return ret
59 | end
60 | )
61 | end
62 |
63 | ---Construct class constructors
64 | ---@param trig string
65 | ---@param template string
66 | local function constructor_snip(trig, name, template)
67 | return ls.s(
68 | {
69 | trig = trig,
70 | name = ("(%s) %s"):format(trig, name),
71 | wordTrig = true,
72 | trigEngine = "plain",
73 | hidden = true,
74 | snippetType = "autosnippet",
75 | -- condition = cond and cond.condition,
76 | -- show_condition = cond and cond.show_condition,
77 | resolveExpandParams = inject_class_name,
78 | },
79 | d(1, function(_, parent)
80 | local env = parent.env
81 | return sn(
82 | nil,
83 | fmta(template, {
84 | cls = t(env.CLASS_NAME),
85 | })
86 | )
87 | end)
88 | )
89 | end
90 |
91 | return {
92 | constructor_snip(
93 | "ctor!",
94 | "Default constructor",
95 | [[
96 | () = default;
97 | ]]
98 | ),
99 | constructor_snip(
100 | "dtor!",
101 | "Default destructor",
102 | [[
103 | ~() = default;
104 | ]]
105 | ),
106 | constructor_snip(
107 | "cc!",
108 | "Copy constructor",
109 | [[
110 | (const & rhs) = default;
111 | ]]
112 | ),
113 | constructor_snip(
114 | "mv!",
115 | "Move constructor",
116 | [[
117 | (&& rhs) = default;
118 | ]]
119 | ),
120 | constructor_snip(
121 | "ncc!",
122 | "No copy constructor",
123 | [[
124 | (const &) = delete;
125 | ]]
126 | ),
127 | constructor_snip(
128 | "nmv!",
129 | "No move constructor",
130 | [[
131 | (&&) = delete;
132 | ]]
133 | ),
134 | constructor_snip(
135 | "ncm!",
136 | "No copy and move constructor",
137 | [[
138 | (const &) = delete;
139 | (&&) = delete;
140 | ]]
141 | ),
142 | snippet {
143 | "itf",
144 | name = "Interface",
145 | dscr = "Declare interface",
146 | mode = "bw",
147 | nodes = fmta(
148 | [[
149 | struct <> {
150 | virtual ~<>() = default;
151 |
152 | <>
153 | };
154 | ]],
155 | {
156 | i(1, "Interface"),
157 | rep(1),
158 | i(0),
159 | }
160 | ),
161 | },
162 | snippet {
163 | "pvf",
164 | name = "Pure virtual function",
165 | dscr = "Declare pure virtual function",
166 | mode = "bw",
167 | resolveExpandParams = inject_class_name,
168 | nodes = fmta("virtual () = 0;", {
169 | name = i(1, "func", { dscr = "Function name" }),
170 | args = i(2, "args", { dscr = "Function arguments" }),
171 | specifier = c(3, { t(""), t("const") }, { dscr = "Function specifier" }),
172 | ret_t = i(4, "void", { dscr = "Return type" }),
173 | }),
174 | },
175 | }
176 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/snippets/dart/_treesitter.lua:
--------------------------------------------------------------------------------
1 | local UtilsTS = require("luasnip-snippets.utils.treesitter")
2 |
3 | ---@class LSSnippets.snippet.dart.Declaration
4 | ---@field ty string
5 | ---@field nullable boolean
6 | ---@field identifier string
7 | ---@field final boolean
8 |
9 | --[[
10 | declaration [11, 2] - [11, 23]
11 | type_identifier [11, 2] - [11, 6]
12 | type_arguments [11, 6] - [11, 11]
13 | type_identifier [11, 7] - [11, 10]
14 | nullable_type [11, 11] - [11, 12]
15 | initialized_identifier_list [11, 13] - [11, 23]
16 | initialized_identifier [11, 13] - [11, 17]
17 | identifier [11, 13] - [11, 17]
18 | initialized_identifier [11, 19] - [11, 23]
19 | identifier [11, 19] - [11, 23]
20 | ]]
21 |
22 | ---@param node TSNode
23 | ---@param source string|number
24 | ---@return LSSnippets.snippet.dart.Declaration[]
25 | local function _handle_declaration(node, source)
26 | local ty
27 | local nullable = false
28 | local final = false
29 | local fields = {}
30 |
31 | for c in node:iter_children() do
32 | if c:type() == "type_identifier" then
33 | ty = vim.treesitter.get_node_text(c, source)
34 | elseif c:type() == "type_arguments" then
35 | ty = ty .. vim.treesitter.get_node_text(c, source)
36 | elseif c:type() == "nullable_type" then
37 | nullable = true
38 | elseif c:type() == "final_builtin" then
39 | final = true
40 | elseif c:type() == "initialized_identifier_list" then
41 | for cc in c:iter_children() do
42 | if cc:type() == "initialized_identifier" then
43 | local id_node = cc:child(0)
44 | assert(id_node ~= nil)
45 | fields[#fields + 1] = vim.treesitter.get_node_text(id_node, source)
46 | end
47 | end
48 | end
49 | end
50 |
51 | local ret = {}
52 | for _, field in ipairs(fields) do
53 | ret[#ret + 1] = {
54 | ty = ty,
55 | nullable = nullable,
56 | final = final,
57 | identifier = field,
58 | }
59 | end
60 |
61 | return ret
62 | end
63 |
64 | ---@param _ any
65 | ---@param line_to_cursor string
66 | ---@param match string
67 | ---@param captures any
68 | local function resolve_class_decls(_, line_to_cursor, match, captures)
69 | -- check if at the line begin
70 | if not line_to_cursor:sub(1, -(#match + 1)):match("^%s*$") then
71 | return nil
72 | end
73 |
74 | local row, col = unpack(vim.api.nvim_win_get_cursor(0))
75 | local buf = vim.api.nvim_get_current_buf()
76 | ---@param parser LanguageTree
77 | ---@param source number|string
78 | return UtilsTS.invoke_after_reparse_buffer(
79 | buf,
80 | match,
81 | function(parser, source)
82 | local pos = {
83 | row - 1,
84 | col - #match,
85 | }
86 | local node =
87 | parser:named_node_for_range { pos[1], pos[2], pos[1], pos[2] }
88 | if node == nil then
89 | return nil
90 | end
91 | local class_node = UtilsTS.find_first_parent(node, "class_definition")
92 | if class_node == nil then
93 | return nil
94 | end
95 |
96 | local name = class_node:field("name")
97 | if name == nil or #name == 0 then
98 | return nil
99 | end
100 | local class_name = vim.treesitter.get_node_text(name[1], source)
101 |
102 | local body = class_node:field("body")
103 | if body == nil or #body == 0 then
104 | return nil
105 | end
106 |
107 | local decls = {}
108 |
109 | for c in body[1]:iter_children() do
110 | if c:type() == "declaration" then
111 | vim.list_extend(decls, _handle_declaration(c, source))
112 | end
113 | end
114 |
115 | return {
116 | trigger = match,
117 | captures = captures,
118 | env_override = {
119 | CLASS_NAME = class_name,
120 | CLASS_DECLS = decls,
121 | },
122 | }
123 | end
124 | )
125 | end
126 |
127 | ---@param _ any
128 | ---@param line_to_cursor string
129 | ---@param match string
130 | ---@param captures any
131 | local function resolve_maybe_class_decl(_, line_to_cursor, match, captures)
132 | -- check if at the line begin
133 | if not line_to_cursor:sub(1, -(#match + 1)):match("^%s*$") then
134 | return nil
135 | end
136 |
137 | local row, col = unpack(vim.api.nvim_win_get_cursor(0))
138 | local buf = vim.api.nvim_get_current_buf()
139 | ---@param parser LanguageTree
140 | ---@param source number|string
141 | return UtilsTS.invoke_after_reparse_buffer(
142 | buf,
143 | match,
144 | function(parser, source)
145 | local pos = {
146 | row - 1,
147 | col - #match,
148 | }
149 | local node =
150 | parser:named_node_for_range { pos[1], pos[2], pos[1], pos[2] }
151 | if node == nil then
152 | return nil
153 | end
154 |
155 | local env = {}
156 |
157 | local class_node = UtilsTS.find_first_parent(node, "class_definition")
158 | if class_node == nil then
159 | env.IN_CLASS = false
160 | else
161 | env.IN_CLASS = true
162 | local name = class_node:field("name")
163 | if name == nil or #name == 0 then
164 | return nil
165 | end
166 | env.CLASS_NAME = vim.treesitter.get_node_text(name[1], source)
167 |
168 | local body = class_node:field("body")
169 | if body == nil or #body == 0 then
170 | return nil
171 | end
172 |
173 | local decls = {}
174 | for c in body[1]:iter_children() do
175 | if c:type() == "declaration" then
176 | vim.list_extend(decls, _handle_declaration(c, source))
177 | end
178 | end
179 | env.CLASS_DECLS = decls
180 | end
181 |
182 | return {
183 | trigger = match,
184 | captures = captures,
185 | env_override = env,
186 | }
187 | end
188 | )
189 | end
190 |
191 | return {
192 | resolve_class_decls = resolve_class_decls,
193 | resolve_maybe_class_decl = resolve_maybe_class_decl,
194 | }
195 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/snippets/dart/init.lua:
--------------------------------------------------------------------------------
1 | ---@param class_name string
2 | ---@param decls LSSnippets.snippet.dart.Declaration[]
3 | local function _build_constructor(class_name, decls)
4 | local lines = {}
5 | local all_final = true
6 | for _, decl in ipairs(decls) do
7 | if not decl.final then
8 | all_final = false
9 | break
10 | end
11 | end
12 |
13 | if all_final then
14 | lines[#lines + 1] = ("const %s({"):format(class_name)
15 | else
16 | lines[#lines + 1] = ("%s({"):format(class_name)
17 | end
18 | for _, decl in ipairs(decls) do
19 | lines[#lines + 1] = ("%sthis.%s,"):format(
20 | decl.nullable and " " or " required ",
21 | decl.identifier
22 | )
23 | end
24 | lines[#lines + 1] = "});"
25 |
26 | return lines
27 | end
28 |
29 | return function()
30 | local snippet = require("luasnip-snippets.nodes").construct_snippet
31 | local i = require("luasnip-snippets.nodes").insert_node
32 | local ls = require("luasnip")
33 | local f = ls.function_node
34 | local dart_ts = require("luasnip-snippets.snippets.dart._treesitter")
35 | local sn = ls.snippet_node
36 | local d = ls.dynamic_node
37 | local t = ls.text_node
38 | local fmta = require("luasnip.extras.fmt").fmta
39 | local extras = require("luasnip.extras")
40 | local rep = extras.rep
41 |
42 | return {
43 | snippet {
44 | "ctor!",
45 | name = "(ctor!) constructor",
46 | dscr = "Expands to class constructor",
47 | mode = "bwA",
48 | resolveExpandParams = dart_ts.resolve_class_decls,
49 | nodes = {
50 | f(function(_, parent)
51 | local env = parent.snippet.env
52 | return _build_constructor(env.CLASS_NAME, env.CLASS_DECLS)
53 | end, {}),
54 | },
55 | },
56 |
57 | snippet {
58 | "js!",
59 | name = "(js!) $_xxxFromJson/ToJson() methods",
60 | dscr = "Expands to common json-related(FromJson/ToJson) methods",
61 | mode = "bwA",
62 | resolveExpandParams = dart_ts.resolve_maybe_class_decl,
63 | nodes = d(1, function(_, parent)
64 | local env = parent.env
65 | if env.IN_CLASS then
66 | local lines = {
67 | "factory %s.fromJson(Map json) =>",
68 | "_$%sFromJson(json);",
69 | "Map toJson() => _$%sToJson(this);",
70 | }
71 | local ret = {}
72 | for _, value in ipairs(lines) do
73 | ret[#ret + 1] = value:format(env.CLASS_NAME)
74 | end
75 | return sn(nil, t(ret))
76 | else
77 | return sn(
78 | nil,
79 | fmta(
80 | [[
81 | @JsonSerializable()
82 | class {
83 | factory .fromJson(Map<> json) =>>
84 | _$FromJson(json);
85 | Map<> toJson() =>> _$ToJson(this);
86 | }
87 | ]],
88 | {
89 | name = i(1, "ClassName"),
90 | rep_name = rep(1),
91 | }
92 | )
93 | )
94 | end
95 | end),
96 | },
97 |
98 | snippet {
99 | "init!",
100 | name = "(init!) initState",
101 | dscr = "Expands to initState() with override marker",
102 | mode = "bwA",
103 | nodes = fmta(
104 | [[
105 | @override
106 | void initState() {
107 | super.initState();
108 |
109 | }
110 | ]],
111 | {
112 | body = i(0),
113 | }
114 | ),
115 | },
116 |
117 | snippet {
118 | "dis!",
119 | name = "(dis!) dispose()",
120 | dscr = "Expands to dispose() with override marker",
121 | mode = "bwA",
122 | nodes = fmta(
123 | [[
124 | @override
125 | void dispose() {
126 |
127 | super.dispose();
128 | }
129 | ]],
130 | {
131 | body = i(0),
132 | }
133 | ),
134 | },
135 |
136 | snippet {
137 | "for!",
138 | name = "(for!) for (... in ...)",
139 | dscr = "Expands to a for loop in variable",
140 | mode = "bwhA",
141 | nodes = fmta(
142 | [[
143 | for (var item in ) {
144 |
145 | }
146 | ]],
147 | {
148 | iterable = i(1, "Iterable"),
149 | body = i(0),
150 | }
151 | ),
152 | },
153 |
154 | snippet {
155 | "fn",
156 | name = "(fn) function",
157 | dscr = "Expands to a simple function definition",
158 | mode = "bw",
159 | nodes = fmta(
160 | [[
161 | () {
162 |
163 | }
164 | ]],
165 | {
166 | body = i(0),
167 | name = i(1, "FuncName", { desc = "function name" }),
168 | args = i(2, "", { desc = "arguments" }),
169 | ret = i(3, "void", { desc = "return type" }),
170 | }
171 | ),
172 | },
173 |
174 | snippet {
175 | "wfn",
176 | name = "(wfn) widget function",
177 | dscr = "Expands to a function definition returns a Widget",
178 | mode = "bw",
179 | nodes = fmta(
180 | [[
181 | Widget _build(BuildContext context) {
182 |
183 | }
184 | ]],
185 | {
186 | body = i(0),
187 | name = i(1, "FuncName", { desc = "function name" }),
188 | }
189 | ),
190 | },
191 |
192 | snippet {
193 | "afn",
194 | name = "(afn) async function",
195 | dscr = "Expands to an async function definition",
196 | mode = "bw",
197 | nodes = fmta(
198 | [[
199 | Future<<>> () async {
200 |
201 | }
202 | ]],
203 | {
204 | body = i(0),
205 | name = i(1, "FuncName", { desc = "function name" }),
206 | args = i(2, "", { desc = "arguments" }),
207 | ret = i(3, "void", { desc = "return type" }),
208 | }
209 | ),
210 | },
211 |
212 | snippet {
213 | "sfw!",
214 | name = "(sfw!) StatefulWidget",
215 | dscr = "Expands to a StatefulWidget class",
216 | mode = "bwA",
217 | nodes = fmta(
218 | [[
219 | class extends StatefulWidget {
220 | const ({super.key});
221 |
222 | @override
223 | State<<>> createState() =>> _State();
224 | }
225 |
226 | class _State extends State<<>> {
227 | @override
228 | void initState() {
229 | super.initState();
230 | // TODO(hawtian): Implement initState
231 | }
232 |
233 | @override
234 | Widget build(BuildContext context) {
235 | // TODO(hawtian): Implement build
236 | throw UnimplementedError();
237 | }
238 | }
239 | ]],
240 | {
241 | name = i(1, "ClassName"),
242 | rep_name = rep(1),
243 | }
244 | ),
245 | },
246 |
247 | snippet {
248 | "slw!",
249 | name = "(slw!) StatelessWidget class",
250 | dscr = "Expands to a StatelessWidget class",
251 | mode = "bwA",
252 | nodes = fmta(
253 | [[
254 | class extends StatelessWidget {
255 | ({super.key});
256 |
257 | @override
258 | Widget build(BuildContext context) {
259 | // TODO(hawtian): Implement build
260 | throw UnimplementedError();
261 | }
262 | }
263 | ]],
264 | {
265 | name = i(1, "ClassName"),
266 | rep_name = rep(1),
267 | }
268 | ),
269 | },
270 | }
271 | end
272 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/snippets/lua/default.lua:
--------------------------------------------------------------------------------
1 | local snippet = require("luasnip-snippets.nodes").construct_snippet
2 | local fmt = require("luasnip.extras.fmt").fmt
3 | local i = require("luasnip-snippets.nodes").insert_node
4 | local ls = require("luasnip")
5 | local f = ls.function_node
6 | local tsp = require("luasnip.extras.treesitter_postfix")
7 | local rep = require("luasnip.extras").rep
8 |
9 | local function last_lua_module_section(args)
10 | local text = args[1][1] or ""
11 | local split = vim.split(text, ".", { plain = true })
12 |
13 | local options = {}
14 | for len = 0, #split - 1 do
15 | local node =
16 | ls.t(table.concat(vim.list_slice(split, #split - len, #split), "_"))
17 | table.insert(options, node)
18 | end
19 |
20 | return ls.sn(nil, {
21 | ls.c(1, options),
22 | })
23 | end
24 |
25 | local expr_query = [[
26 | [
27 | (function_call)
28 | (identifier)
29 | (expression_list)
30 | (dot_index_expression)
31 | (bracket_index_expression)
32 | ] @prefix
33 | ]]
34 |
35 | return {
36 | snippet {
37 | "fn",
38 | name = "(fn) function",
39 | dscr = "Expands to function definition",
40 | mode = "w",
41 | nodes = fmt(
42 | [[
43 | function {}({})
44 | {}
45 | end
46 | ]],
47 | {
48 | i(1, "function name", { desc = "Function Name" }),
49 | i(2, "arguments", { desc = "Function Arguments" }),
50 | i(0),
51 | }
52 | ),
53 | },
54 |
55 | snippet {
56 | "req",
57 | name = "require(...)",
58 | dscr = "Require statement",
59 | mode = "wb",
60 | nodes = fmt([[local {} = require("{}")]], {
61 | ls.d(2, last_lua_module_section, { 1 }),
62 | i(1, "module"),
63 | }),
64 | },
65 |
66 | snippet {
67 | '#i',
68 | name = "require(...)",
69 | dscr = "Expands to require statement with type annotation",
70 | mode = "bwA",
71 | nodes = fmt(
72 | [[
73 | ---@type {}
74 | local {} = require("{}")
75 | ]],
76 | {
77 | rep(1),
78 | f(function(args)
79 | local module_name = args[1][1]
80 | local parts = vim.split(module_name, ".", {
81 | plain = true,
82 | trimempty = true,
83 | })
84 | module_name = parts[#parts]
85 | parts = vim.split(module_name, "/", {
86 | plain = true,
87 | trimempty = true,
88 | })
89 | module_name = parts[#parts]
90 | return module_name:gsub("^%l", string.upper)
91 | end, { 1 }),
92 | i(1, "module"),
93 | }
94 | ),
95 | },
96 |
97 | tsp.treesitter_postfix(
98 | {
99 | trig = ".ipairs",
100 | name = "(.ipairs) for in ipairs(...)",
101 | dscr = "Expands expression to for in ipairs(...) do ... end",
102 | wordTrig = false,
103 | reparseBuffer = "live",
104 | matchTSNode = {
105 | query = expr_query,
106 | query_lang = "lua",
107 | },
108 | },
109 | fmt(
110 | [[
111 | for i, value in ipairs({}) do
112 | {}
113 | end
114 | ]],
115 | {
116 | f(function(_, parent)
117 | local match = parent.snippet.env.LS_TSMATCH
118 | return match
119 | end, {}),
120 | i(0),
121 | }
122 | )
123 | ),
124 |
125 | tsp.treesitter_postfix(
126 | {
127 | trig = ".pairs",
128 | name = "(.pairs) for in pairs(...)",
129 | dscr = "Expands expression to for in pairs(...) do ... end",
130 | wordTrig = false,
131 | reparseBuffer = "live",
132 | matchTSNode = {
133 | query = expr_query,
134 | query_lang = "lua",
135 | },
136 | },
137 | fmt(
138 | [[
139 | for key, value in pairs({}) do
140 | {}
141 | end
142 | ]],
143 | {
144 | f(function(_, parent)
145 | local match = parent.snippet.env.LS_TSMATCH
146 | return match
147 | end, {}),
148 | i(0),
149 | }
150 | )
151 | ),
152 |
153 | tsp.treesitter_postfix(
154 | {
155 | trig = ".isnil",
156 | name = "(.isnil) if ... == nil",
157 | dscr = "Expands expression to if ... == nil then ... end",
158 | wordTrig = false,
159 | reparseBuffer = "live",
160 | matchTSNode = {
161 | query = expr_query,
162 | query_lang = "lua",
163 | },
164 | },
165 | fmt(
166 | [[
167 | if {} == nil then
168 | {}
169 | end
170 | ]],
171 | {
172 | f(function(_, parent)
173 | local match = parent.snippet.env.LS_TSMATCH
174 | return match
175 | end, {}),
176 | i(0, "return"),
177 | }
178 | )
179 | ),
180 | }
181 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/snippets/lua/init.lua:
--------------------------------------------------------------------------------
1 | ---@type luasnip-snippets.utils
2 | local Utils = require("luasnip-snippets.utils")
3 |
4 | ---@type luasnip-snippets.config
5 | local Config = require("luasnip-snippets.config")
6 |
7 | local function setup()
8 | local submodules = {
9 | "default",
10 | }
11 |
12 | if Config.get("snippet.lua.vim_snippet") then
13 | submodules[#submodules + 1] = "vim"
14 | end
15 |
16 | return Utils.concat_snippets("luasnip-snippets.snippets.lua", submodules)
17 | end
18 |
19 | return setup
20 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/snippets/lua/vim.lua:
--------------------------------------------------------------------------------
1 | ---@type luasnip-snippets.nodes
2 | local Nodes = require("luasnip-snippets.nodes")
3 | ---@type luasnip-snippets.config
4 | local Config = require("luasnip-snippets.config")
5 | ---@type luasnip-snippets.utils.cond
6 | local Cond = require("luasnip-snippets.utils.cond")
7 | ---@type luasnip-snippets.utils.treesitter
8 | local UtilsTS = require("luasnip-snippets.utils.treesitter")
9 | ---@type luasnip-snippets.utils
10 | local Utils = require("luasnip-snippets.utils")
11 |
12 | local fmt = require("luasnip.extras.fmt").fmt
13 | local i = require("luasnip-snippets.nodes").insert_node
14 | local ls = require("luasnip")
15 | local f = ls.function_node
16 | local tsp = require("luasnip.extras.treesitter_postfix")
17 |
18 | ---@param opts LSSnippets.SnippetOptions
19 | local function snippet(opts)
20 | local cond = Config.get("snippet.lua.cond")
21 | if cond then
22 | local cond_obj = Cond.make_condition(cond, cond)
23 | local previous_cond = opts.cond
24 | if previous_cond ~= nil then
25 | opts.cond = previous_cond + cond_obj
26 | else
27 | opts.cond = cond_obj
28 | end
29 | end
30 | return Nodes.construct_snippet(opts)
31 | end
32 |
33 | local index_expression_query = [[
34 | [
35 | (dot_index_expression)
36 | (bracket_index_expression)
37 | ] @prefix
38 | ]]
39 |
40 | local index_expression_matcher = UtilsTS.make_type_matcher {
41 | "dot_index_expression",
42 | "bracket_index_expression",
43 | }
44 |
45 | ---@param context LSSnippets.ProcessMatchesContext
46 | ---@param previous any
47 | local function inject_matches(context, previous)
48 | local fields = {}
49 | local node = context.prefix_node
50 | while node ~= nil and index_expression_matcher[node:type()] == 1 do
51 | local field = context.ts_parser:get_node_text(node:field("field")[1])
52 | if node:type() == "dot_index_expression" then
53 | fields[#fields + 1] = ('"%s"'):format(field)
54 | else
55 | fields[#fields + 1] = field
56 | end
57 | node = node:field("table")[1]
58 | end
59 | fields[#fields + 1] = context.ts_parser:get_node_text(node)
60 | Utils.reverse_list(fields)
61 |
62 | previous = vim.tbl_deep_extend("force", previous, {
63 | env_override = {
64 | INDEX_FIELDS = fields,
65 | },
66 | })
67 |
68 | return previous
69 | end
70 |
71 | return {
72 | snippet {
73 | "ifn",
74 | name = "(ifn) vim.F.if_nil",
75 | dscr = "Wraps an expression in vim.F.if_nil",
76 | mode = "w",
77 | nodes = fmt("vim.F.if_nil({}, {})", {
78 | i(1, "expr", { desc = "Expression" }),
79 | i(2, "{}", { desc = "Default value" }),
80 | }),
81 | },
82 |
83 | UtilsTS.treesitter_postfix({
84 | trig = ".tget",
85 | name = "(.tget) vim.tbl_get(...)",
86 | dscr = "Expands index_expression to vim.tbl_get syntax",
87 | wordTrig = false,
88 | reparseBuffer = "live",
89 | matchTSNode = {
90 | query = index_expression_query,
91 | query_lang = "lua",
92 | },
93 | injectMatches = inject_matches,
94 | }, {
95 | f(function(_, parent)
96 | local fields = parent.snippet.env.INDEX_FIELDS
97 | return ("vim.tbl_get(%s)"):format(table.concat(fields, ", "))
98 | end, {}),
99 | }),
100 | }
101 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/snippets/nix.lua:
--------------------------------------------------------------------------------
1 | local ls = require("luasnip")
2 | local f = ls.function_node
3 | local snippet = require("luasnip-snippets.nodes").construct_snippet
4 | local fmta = require("luasnip.extras.fmt").fmta
5 | local extras = require("luasnip.extras")
6 | local rep = extras.rep
7 | local i = require("luasnip-snippets.nodes").insert_node
8 | local tsp = require("luasnip.extras.treesitter_postfix")
9 | local Utils = require("luasnip-snippets.utils")
10 | ---@type luasnip-snippets.utils.treesitter
11 | local UtilsTS = require("luasnip-snippets.utils.treesitter")
12 |
13 | local identifier_query = [[
14 | [
15 | (identifier)
16 | ] @prefix
17 | ]]
18 |
19 | local function identifier_tsp(trig, expand, dscr)
20 | local name = ("(%s) %s"):format(trig, expand)
21 | if dscr == nil then
22 | dscr = ("Wraps an expression with %s"):format(expand)
23 | else
24 | dscr = dscr:format(expand)
25 | end
26 | local replaced = expand:gsub("?", "%%s")
27 |
28 | return tsp.treesitter_postfix({
29 | trig = trig,
30 | name = name,
31 | dscr = dscr,
32 | wordTrig = false,
33 | reparseBuffer = "live",
34 | matchTSNode = {
35 | query = identifier_query,
36 | query_lang = "nix",
37 | },
38 | }, {
39 | f(function(_, parent)
40 | return Utils.replace_all(parent.snippet.env.LS_TSMATCH, replaced)
41 | end, {}),
42 | })
43 | end
44 |
45 | local bind_query = [[
46 | [
47 | ((binding
48 | expression: (_) @expr
49 | ))
50 | ] @prefix
51 | ]]
52 |
53 | ---@param context LSSnippets.ProcessMatchesContext
54 | ---@param previous any
55 | local function inject_bind_matches(context, previous)
56 | vim.print("???")
57 | local node = context.prefix_node
58 | local attr_path = node:field("attrpath")[1]
59 | local attrs_nodes = attr_path:field("attr")
60 | local attrs = {}
61 |
62 | for _, attr in ipairs(attrs_nodes) do
63 | local attr_text = context.ts_parser:get_node_text(attr)
64 | attrs[#attrs + 1] = attr_text
65 | end
66 |
67 | previous = vim.tbl_deep_extend("force", previous, {
68 | env_override = {
69 | ATTRS = attrs,
70 | },
71 | })
72 |
73 | return previous
74 | end
75 |
76 | return {
77 | snippet {
78 | "@module",
79 | name = "(@module) ...",
80 | dscr = "Expands to a common module skeleton",
81 | mode = "bw",
82 | nodes = fmta(
83 | [[
84 | {
85 | config,
86 | lib,
87 | pkgs,
88 | ...
89 | }: let
90 | cfg = config.;
91 | in {
92 | options. = {
93 | enable = lib.mkEnableOption "Enable module ";
94 | };
95 |
96 | config = lib.mkIf cfg.enable {
97 | };
98 | }
99 | ]],
100 | {
101 | module = i(1, "module", { desc = "Module name" }),
102 | module_r = rep(1),
103 | }
104 | ),
105 | },
106 |
107 | identifier_tsp(
108 | ".on",
109 | "? = { enable = true; };",
110 | "Completes an identifier with an enable option"
111 | ),
112 |
113 | UtilsTS.treesitter_postfix({
114 | trig = ".split",
115 | name = "(.split) foo.bar = xxx; -> foo = { bar = xxx; };",
116 | dscr = "Split a dot expression into full attrset declaration",
117 | wordTrig = false,
118 | reparseBuffer = "live",
119 | matchTSNode = {
120 | query = bind_query,
121 | query_lang = "nix",
122 | },
123 | injectMatches = inject_bind_matches,
124 | }, {
125 | f(function(_, parent)
126 | vim.print(parent.snippet.env)
127 | local attrs = parent.snippet.env.ATTRS
128 | local expr = table.concat(parent.snippet.env.LS_TSCAPTURE_EXPR, "\n")
129 | Utils.reverse_list(attrs)
130 |
131 | local generate_bindings = function(first, attr, previous)
132 | if first then
133 | return ("%s = %s;"):format(attr, previous)
134 | else
135 | return ("%s = { %s };"):format(attr, previous)
136 | end
137 | end
138 |
139 | for j, attr in ipairs(attrs) do
140 | expr = generate_bindings(j == 1, attr, expr)
141 | end
142 |
143 | return expr
144 | end, {}),
145 | }),
146 | }
147 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/snippets/rust/default.lua:
--------------------------------------------------------------------------------
1 | local ls = require("luasnip")
2 | local t = ls.text_node
3 | local snippet = require("luasnip-snippets.nodes").construct_snippet
4 |
5 | return {
6 | snippet {
7 | "pc",
8 | name = "(pc) pub(crate) ...",
9 | dscr = "Expands to pub(crate) visibility",
10 | mode = "bw",
11 | nodes = {
12 | t("pub(crate) "),
13 | },
14 | },
15 | snippet {
16 | "ps",
17 | name = "(ps) pub(super) ...",
18 | dscr = "Expands to pub(super) visibility",
19 | mode = "bw",
20 | nodes = {
21 | t("pub(super) "),
22 | },
23 | },
24 | snippet {
25 | "ii",
26 | name = "(ii) #[inline] ...",
27 | dscr = "Expands to #[inline] attribute",
28 | mode = "bw",
29 | nodes = {
30 | t("#[inline]"),
31 | },
32 | },
33 | snippet {
34 | "ia",
35 | name = "(ia) #[inline(always)] ...",
36 | dscr = "Expands to #[inline(always)] attribute",
37 | mode = "bw",
38 | nodes = {
39 | t("#[inline(always)]"),
40 | },
41 | },
42 | }
43 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/snippets/rust/impl_block.lua:
--------------------------------------------------------------------------------
1 | local UtilsTS = require("luasnip-snippets.utils.treesitter")
2 | local ls = require("luasnip")
3 | local t = ls.text_node
4 | local fmta = require("luasnip.extras.fmt").fmta
5 | local i = require("luasnip-snippets.nodes").insert_node
6 | local c = require("luasnip-snippets.nodes").choice_node
7 |
8 | local function require_impl_block(_, _, match, captures)
9 | local row, col = unpack(vim.api.nvim_win_get_cursor(0))
10 | local buf = vim.api.nvim_get_current_buf()
11 |
12 | return UtilsTS.invoke_after_reparse_buffer(buf, match, function(parser, _)
13 | local pos = {
14 | row - 1,
15 | col - #match,
16 | }
17 | local node = parser:named_node_for_range {
18 | pos[1],
19 | pos[2],
20 | pos[1],
21 | pos[2],
22 | }
23 |
24 | local ret = {
25 | trigger = match,
26 | capture = captures,
27 | env_override = {
28 | IMPL_ITEM_START = UtilsTS.start_pos(
29 | UtilsTS.find_first_parent(node, { "impl_item" })
30 | ),
31 | FUNCTION_ITEM_START = UtilsTS.start_pos(
32 | UtilsTS.find_first_parent(node, { "function_item" })
33 | ),
34 | CLOSURE_EXPRESSION_START = UtilsTS.start_pos(
35 | UtilsTS.find_first_parent(node, { "closure_expression" })
36 | ),
37 | },
38 | }
39 |
40 | vim.api.nvim_win_set_cursor(0, { row, col })
41 |
42 | if
43 | ret.env_override.IMPL_ITEM_START ~= nil
44 | and ret.env_override.FUNCTION_ITEM_START == nil
45 | and ret.env_override.CLOSURE_EXPRESSION_START == nil
46 | then
47 | return ret
48 | end
49 |
50 | return nil
51 | end)
52 | end
53 |
54 | return {
55 | ls.s(
56 | {
57 | trig = "pm",
58 | wordTrig = true,
59 | name = "(pm) pub method",
60 | resolveExpandParams = require_impl_block,
61 | },
62 | fmta(
63 | [[
64 | pub fn (<_self>) {
65 |
66 | }
67 | ]],
68 | {
69 | body = i(0),
70 | name = i(1, "new_fn", { desc = "function name" }),
71 | _self = c(2, {
72 | t("&self"),
73 | t("&mut self"),
74 | t("self"),
75 | }, { desc = "self" }),
76 | }
77 | )
78 | ),
79 | }
80 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/snippets/rust/init.lua:
--------------------------------------------------------------------------------
1 | local Utils = require("luasnip-snippets.utils")
2 |
3 | local function setup()
4 | return Utils.concat_snippets("luasnip-snippets.snippets.rust", {
5 | "default",
6 | "postfix",
7 | "lambda_fn",
8 | "test_fn",
9 | "impl_block",
10 | })
11 | end
12 |
13 | return setup
14 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/snippets/rust/lambda_fn.lua:
--------------------------------------------------------------------------------
1 | local UtilsTS = require("luasnip-snippets.utils.treesitter")
2 | local ls = require("luasnip")
3 | local d = ls.dynamic_node
4 | local sn = ls.snippet_node
5 | local t = ls.text_node
6 | local fmta = require("luasnip.extras.fmt").fmta
7 | local i = require("luasnip-snippets.nodes").insert_node
8 | local c = require("luasnip-snippets.nodes").choice_node
9 |
10 | local function inject_expanding_environment(_, _, match, captures)
11 | local row, col = unpack(vim.api.nvim_win_get_cursor(0))
12 | local buf = vim.api.nvim_get_current_buf()
13 |
14 | return UtilsTS.invoke_after_reparse_buffer(buf, match, function(parser, _)
15 | local pos = {
16 | row - 1,
17 | col - #match,
18 | }
19 | local node = parser:named_node_for_range {
20 | pos[1],
21 | pos[2],
22 | pos[1],
23 | pos[2],
24 | }
25 |
26 | local ret = {
27 | trigger = match,
28 | capture = captures,
29 | env_override = {
30 | IMPL_ITEM_START = UtilsTS.start_pos(
31 | UtilsTS.find_first_parent(node, { "impl_item" })
32 | ),
33 | FUNCTION_ITEM_START = UtilsTS.start_pos(
34 | UtilsTS.find_first_parent(node, { "function_item" })
35 | ),
36 | CLOSURE_EXPRESSION_START = UtilsTS.start_pos(
37 | UtilsTS.find_first_parent(node, { "closure_expression" })
38 | ),
39 | },
40 | }
41 |
42 | vim.api.nvim_win_set_cursor(0, { row, col })
43 | return ret
44 | end)
45 | end
46 |
47 | ---@class LSSnippets.Rust.Fn.Env
48 | ---@field IMPL_ITEM_START? { [1]: number, [2]: number }
49 | ---@field FUNCTION_ITEM_START? { [1]: number, [2]: number }
50 | ---@field CLOSURE_EXPRESSION_START? { [1]: number, [2]: number }
51 |
52 | return {
53 | ls.s(
54 | {
55 | trig = "fn",
56 | wordTrig = true,
57 | name = "(fn) Function-Definition/Lambda",
58 | resolveExpandParams = inject_expanding_environment,
59 | },
60 | d(1, function(_, parent)
61 | local env = parent.env
62 | if
63 | env.FUNCTION_ITEM_START ~= nil or env.CLOSURE_EXPRESSION_START ~= nil
64 | then
65 | -- closure expression
66 | return sn(
67 | nil,
68 | fmta(
69 | [[
70 | || {
71 |
72 | }
73 | ]],
74 | {
75 | modifier = c(1, {
76 | t(""),
77 | t("async "),
78 | t("move "),
79 | }, { desc = "function modifier" }),
80 | args = i(2, "args"),
81 | body = i(0),
82 | }
83 | )
84 | )
85 | else
86 | -- function item
87 | return sn(
88 | nil,
89 | fmta(
90 | [[
91 | fn () {
92 |
93 | }
94 | ]],
95 | {
96 | modifier = c(1, {
97 | t(""),
98 | t("async "),
99 | }, { desc = "function modifier" }),
100 | visible = c(2, {
101 | t(""),
102 | t("pub "),
103 | t("pub(crate) "),
104 | t("pub(super) "),
105 | }, { desc = "visibility" }),
106 | name = i(3, "new_fn", { desc = "function name" }),
107 | args = i(4, "args", { desc = "function arguments" }),
108 | body = i(0),
109 | }
110 | )
111 | )
112 | end
113 | end, {})
114 | ),
115 | }
116 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/snippets/rust/postfix.lua:
--------------------------------------------------------------------------------
1 | local ls = require("luasnip")
2 | local f = ls.function_node
3 | local tsp = require("luasnip.extras.treesitter_postfix")
4 | local Utils = require("luasnip-snippets.utils")
5 |
6 | local expr_query = [[
7 | [
8 | (struct_expression)
9 | (unit_expression)
10 | (call_expression)
11 | (identifier)
12 | (field_expression)
13 | (integer_literal)
14 | (string_literal)
15 | ] @prefix
16 | ]]
17 |
18 | local expr_or_type_query = [[
19 | [
20 | (struct_expression)
21 | (call_expression)
22 | (unit_expression)
23 | (identifier)
24 | (field_expression)
25 | (integer_literal)
26 | (string_literal)
27 |
28 | (type_identifier)
29 | (generic_type)
30 | (scoped_type_identifier)
31 | (reference_type)
32 | (primitive_type)
33 | ] @prefix
34 | ]]
35 |
36 | local expr_node_types = {
37 | ["struct_expression"] = true,
38 | ["call_expression"] = true,
39 | ["identifier"] = true,
40 | ["field_expression"] = true,
41 | ["integer_literal"] = true,
42 | ["string_literal"] = true,
43 | }
44 |
45 | local function expr_or_type_tsp(trig, typename, expr_callback, type_callback)
46 | local name = ("(%s) %s"):format(trig, typename)
47 | local dscr = ("Wrap expression/type with %s"):format(typename)
48 | return tsp.treesitter_postfix({
49 | trig = trig,
50 | name = name,
51 | dscr = dscr,
52 | wordTrig = false,
53 | reparseBuffer = "live",
54 | matchTSNode = {
55 | query = expr_or_type_query,
56 | query_lang = "rust",
57 | },
58 | }, {
59 | f(function(_, parent)
60 | local env = parent.snippet.env
61 | local data = env.LS_TSDATA
62 | if expr_node_types[data.prefix.type] then
63 | -- is expr
64 | return expr_callback(env.LS_TSMATCH)
65 | else
66 | -- is type
67 | return type_callback(env.LS_TSMATCH)
68 | end
69 | end),
70 | })
71 | end
72 |
73 | local function result_ok_type_callback(match)
74 | return Utils.replace_all(match, "Result<%s, _>")
75 | end
76 |
77 | local function result_err_type_callback(match)
78 | return Utils.replace_all(match, "Result<_, %s>")
79 | end
80 |
81 | local function build_simple_replace_callback(replaced)
82 | return function(match)
83 | return Utils.replace_all(match, replaced)
84 | end
85 | end
86 |
87 | local function new_expr_or_type_tsp(trig, typename)
88 | local expr_callback = function(match)
89 | return Utils.replace_all(match, typename .. "::new(%s)")
90 | end
91 | local type_callback = function(match)
92 | return Utils.replace_all(match, typename .. "<%s>")
93 | end
94 | return expr_or_type_tsp(trig, typename, expr_callback, type_callback)
95 | end
96 |
97 | local function both_replace_expr_or_type_tsp(trig, pattern)
98 | local template = pattern:gsub("?", "%%s")
99 | return expr_or_type_tsp(
100 | trig,
101 | pattern,
102 | build_simple_replace_callback(template),
103 | build_simple_replace_callback(template)
104 | )
105 | end
106 |
107 | return {
108 | new_expr_or_type_tsp(".rc", "Rc"),
109 | new_expr_or_type_tsp(".arc", "Arc"),
110 | new_expr_or_type_tsp(".box", "Box"),
111 | new_expr_or_type_tsp(".mu", "Mutex"),
112 | new_expr_or_type_tsp(".rw", "RwLock"),
113 | new_expr_or_type_tsp(".cell", "Cell"),
114 | new_expr_or_type_tsp(".refcell", "RefCell"),
115 | both_replace_expr_or_type_tsp(".ref", "&?"),
116 | both_replace_expr_or_type_tsp(".refm", "&mut ?"),
117 | expr_or_type_tsp(
118 | ".ok",
119 | "Ok(?)",
120 | build_simple_replace_callback("Ok(%s)"),
121 | result_ok_type_callback
122 | ),
123 | expr_or_type_tsp(
124 | ".err",
125 | "Err(?)",
126 | build_simple_replace_callback("Err(%s)"),
127 | result_err_type_callback
128 | ),
129 | expr_or_type_tsp(
130 | ".some",
131 | "Some(?)",
132 | build_simple_replace_callback("Some(%s)"),
133 | build_simple_replace_callback("Option<%s>")
134 | ),
135 |
136 | tsp.treesitter_postfix({
137 | trig = ".println",
138 | name = [[(.println) println!("{:?}", ?)]],
139 | dscr = [[Wrap expression with println!("{:?}", ?)]],
140 | wordTrig = false,
141 | reparseBuffer = "live",
142 | matchTSNode = {
143 | query = expr_query,
144 | query_lang = "rust",
145 | },
146 | }, {
147 | f(function(_, parent)
148 | return Utils.replace_all(
149 | parent.snippet.env.LS_TSMATCH,
150 | [[println!("{:?}", %s)]]
151 | )
152 | end, {}),
153 | }),
154 |
155 | tsp.treesitter_postfix({
156 | trig = ".match",
157 | name = [[(.match) match ?]],
158 | dscr = [[Wrap expression with match ? block]],
159 | wordTrig = false,
160 | reparseBuffer = "live",
161 | matchTSNode = {
162 | query = expr_query,
163 | query_lang = "rust",
164 | },
165 | }, {
166 | f(function(_, parent)
167 | return Utils.replace_all(
168 | parent.snippet.env.LS_TSMATCH,
169 | [[match %s {
170 | }]]
171 | )
172 | end, {}),
173 | }),
174 | }
175 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/snippets/rust/test_fn.lua:
--------------------------------------------------------------------------------
1 | local UtilsTS = require("luasnip-snippets.utils.treesitter")
2 | local Config = require("luasnip-snippets.config")
3 | local UtilsTbl = require("luasnip-snippets.utils.tbl")
4 | local ls = require("luasnip")
5 | local d = ls.dynamic_node
6 | local sn = ls.snippet_node
7 | local t = ls.text_node
8 | local f = ls.function_node
9 | local fmta = require("luasnip.extras.fmt").fmta
10 | local i = require("luasnip-snippets.nodes").insert_node
11 | local c = require("luasnip-snippets.nodes").choice_node
12 |
13 | ---@param left string[]
14 | ---@param right string[]
15 | ---@param sep string
16 | ---@return string[]
17 | local function dot_concat(left, right, sep)
18 | local ret = {}
19 |
20 | for _, l in ipairs(left) do
21 | for _, r in ipairs(right) do
22 | ret[#ret + 1] = l .. sep .. r
23 | end
24 | end
25 |
26 | return ret
27 | end
28 |
29 | ---@param node TSNode?
30 | ---@return string[]
31 | local function flat_scoped_use_list(source, node)
32 | if node == nil then
33 | return {}
34 | end
35 | if node:type() ~= "scoped_use_list" then
36 | return {
37 | vim.treesitter.get_node_text(node, source),
38 | }
39 | end
40 |
41 | local path_nodes = node:field("path")
42 | if #path_nodes == 0 then
43 | return {}
44 | end
45 |
46 | local paths = {}
47 | for _, path_node in ipairs(path_nodes) do
48 | vim.list_extend(paths, flat_scoped_use_list(source, path_node))
49 | end
50 |
51 | local items = {}
52 | local name_nodes = node:field("name")
53 | for _, name_node in ipairs(name_nodes) do
54 | vim.list_extend(items, flat_scoped_use_list(source, name_node))
55 | end
56 | local list_nodes = node:field("list")
57 | local allow_list = {
58 | scoped_use_list = 1,
59 | use_wildcard = 1,
60 | identifier = 1,
61 | }
62 | for _, list_node in ipairs(list_nodes) do
63 | for child in list_node:iter_children() do
64 | if allow_list[child:type()] == 1 then
65 | vim.list_extend(items, flat_scoped_use_list(source, child))
66 | end
67 | end
68 | end
69 |
70 | return dot_concat(paths, items, "::")
71 | end
72 |
73 | local function inject_expanding_environment(_, _, match, captures)
74 | local row, col = unpack(vim.api.nvim_win_get_cursor(0))
75 | local buf = vim.api.nvim_get_current_buf()
76 |
77 | return UtilsTS.invoke_after_reparse_buffer(
78 | buf,
79 | match,
80 | function(parser, source)
81 | local pos = {
82 | row - 1,
83 | col - #match,
84 | }
85 | local node = parser:named_node_for_range {
86 | pos[1],
87 | pos[2],
88 | pos[1],
89 | pos[2],
90 | }
91 |
92 | local ret = {
93 | trigger = match,
94 | capture = captures,
95 | env_override = {
96 | IMPL_ITEM_START = UtilsTS.start_pos(
97 | UtilsTS.find_first_parent(node, { "impl_item" })
98 | ),
99 | FUNCTION_ITEM_START = UtilsTS.start_pos(
100 | UtilsTS.find_first_parent(node, { "function_item" })
101 | ),
102 | CLOSURE_EXPRESSION_START = UtilsTS.start_pos(
103 | UtilsTS.find_first_parent(node, { "closure_expression" })
104 | ),
105 | },
106 | }
107 |
108 | ---@type TSNode?
109 | local mod_item = UtilsTS.find_first_parent(node, { "mod_item" })
110 | if mod_item ~= nil then
111 | ret.env_override["MOD_ITEM_START"] =
112 | UtilsTS.start_pos(UtilsTS.find_first_parent(node, { "mod_item" }))
113 | local name_node = mod_item:field("name")[1]
114 | if name_node ~= nil then
115 | ret.env_override["MOD_ITEM_NAME"] =
116 | vim.treesitter.get_node_text(name_node, source)
117 | end
118 | local prev = mod_item:prev_sibling()
119 | local attributes = {}
120 | -- try to fild
121 | while true do
122 | if prev == nil then
123 | break
124 | end
125 | if
126 | prev:type() == "line_comment" or prev:type() == "block_comment"
127 | then
128 | -- skip this
129 | elseif prev:type() == "attribute_item" then
130 | attributes[#attributes + 1] =
131 | vim.treesitter.get_node_text(prev, source)
132 | else
133 | break
134 | end
135 | prev = prev:prev_sibling()
136 | end
137 | ret.env_override["ATTRIBUTES_ITEMS"] = attributes
138 |
139 | if Config.get("snippet.rust.rstest_support") == true then
140 | -- check if this mod contains `use rstest::rstest;`
141 | local use_list = {}
142 | for _, body in ipairs(mod_item:field("body")) do
143 | for child in body:iter_children() do
144 | if child:type() == "use_declaration" then
145 | local nodes = child:field("argument")
146 | for _, use_node in ipairs(nodes) do
147 | local node_type = use_node:type()
148 | if node_type == "scoped_use_list" then
149 | vim.list_extend(
150 | use_list,
151 | flat_scoped_use_list(source, use_node)
152 | )
153 | elseif node_type == "scoped_identifier" then
154 | use_list[#use_list + 1] =
155 | vim.treesitter.get_node_text(use_node, source)
156 | end
157 | end
158 | end
159 | end
160 | end
161 | ret.env_override["USE_LIST"] = use_list
162 | end
163 | end
164 |
165 | vim.api.nvim_win_set_cursor(0, { row, col })
166 | return ret
167 | end
168 | )
169 | end
170 |
171 | return {
172 | ls.s(
173 | {
174 | trig = "tfn",
175 | wordTrig = true,
176 | name = "(tfn) Test function definition",
177 | resolveExpandParams = inject_expanding_environment,
178 | },
179 | d(1, function(_, parent)
180 | local env = parent.env
181 | local in_test_cfg = false
182 | if env["ATTRIBUTES_ITEMS"] ~= nil then
183 | for _, v in ipairs(env["ATTRIBUTES_ITEMS"]) do
184 | if v == "#[cfg(test)]" then
185 | in_test_cfg = true
186 | break
187 | end
188 | end
189 | end
190 |
191 | if in_test_cfg and env.MOD_ITEM_NAME == "tests" then
192 | local test_fn_attrs = {
193 | t("#[test]"),
194 | t("#[tokio::test]"),
195 | }
196 |
197 | if Config.get("snippet.rust.rstest_support") == true then
198 | local use_list = env["USE_LIST"] or {}
199 | if vim.list_contains(use_list, "rstest::rstest") then
200 | test_fn_attrs[#test_fn_attrs + 1] = t("#[rstest]")
201 | elseif vim.list_contains(use_list, "rstest::*") then
202 | test_fn_attrs[#test_fn_attrs + 1] = t("#[rstest]")
203 | end
204 | end
205 |
206 | -- function item
207 | return sn(
208 | nil,
209 | fmta(
210 | [[
211 |
212 | fn test_() {
213 |
214 | }
215 | ]],
216 | {
217 | modifier = f(function(args, _)
218 | if vim.tbl_get(args, 1, 1) == "#[tokio::test]" then
219 | return "async "
220 | else
221 | return ""
222 | end
223 | end, { 2 }),
224 | name = i(1, "new_fn", { desc = "function name" }),
225 | attr = c(2, test_fn_attrs, { desc = "function attributes" }),
226 | body = i(0),
227 | }
228 | )
229 | )
230 | else
231 | -- function item
232 | return sn(
233 | nil,
234 | fmta(
235 | [[
236 | fn () {
237 |
238 | }
239 | ]],
240 | {
241 | modifier = c(1, {
242 | t(""),
243 | t("async "),
244 | }, { desc = "function modifier" }),
245 | visible = c(2, {
246 | t(""),
247 | t("pub "),
248 | t("pub(crate) "),
249 | t("pub(super) "),
250 | }, { desc = "visibility" }),
251 | name = i(3, "new_fn", { desc = "function name" }),
252 | args = i(4, "args", { desc = "function arguments" }),
253 | body = i(0),
254 | }
255 | )
256 | )
257 | end
258 | end, {})
259 | ),
260 | }
261 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/snippets/typescript.lua:
--------------------------------------------------------------------------------
1 | local ls = require("luasnip")
2 | local f = ls.function_node
3 | local snippet = require("luasnip-snippets.nodes").construct_snippet
4 | local fmta = require("luasnip.extras.fmt").fmta
5 | local extras = require("luasnip.extras")
6 | local rep = extras.rep
7 | local i = require("luasnip-snippets.nodes").insert_node
8 | local tsp = require("luasnip.extras.treesitter_postfix")
9 | local Utils = require("luasnip-snippets.utils")
10 |
11 | return {
12 | snippet {
13 | "pvf",
14 | name = "(pvf) public abstract function",
15 | dscr = "Expands to public abstract function declaration",
16 | mode = "bw",
17 | nodes = fmta(
18 | [[
19 | public abstract (): ;
20 | ]],
21 | {
22 | name = i(1, "name", { desc = "Function Name" }),
23 | args = i(2, "", { desc = "Function Arguments" }),
24 | retType = i(3, "void", { desc = "Return Type" }),
25 | }
26 | ),
27 | },
28 | }
29 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/utils/comment.lua:
--------------------------------------------------------------------------------
1 | ---Code from Comment.nvim
2 | ---https://github.com/numToStr/Comment.nvim/blob/master/lua/Comment/ft.lua
3 |
4 | ---Common commentstring shared b/w multiple languages
5 | local M = {
6 | cxx_l = "//%s",
7 | cxx_b = "/*%s*/",
8 | dbl_hash = "##%s",
9 | dash = "--%s",
10 | dash_bracket = "--[[%s]]",
11 | handlebars = "{{!--%s--}}",
12 | hash = "#%s",
13 | hash_bracket = "#[[%s]]",
14 | haskell_b = "{-%s-}",
15 | fsharp_b = "(*%s*)",
16 | html = "",
17 | latex = "%%s",
18 | semicolon = ";%s",
19 | lisp_l = ";;%s",
20 | lisp_b = "#|%s|#",
21 | twig = "{#%s#}",
22 | vim = '"%s',
23 | lean_b = "/-%s-/",
24 | }
25 |
26 | ---Lang table that contains commentstring (linewise/blockwise) for multiple filetypes
27 | ---Structure = { filetype = { linewise, blockwise } }
28 | ---@type table
29 | local L = setmetatable({
30 | arduino = { M.cxx_l, M.cxx_b },
31 | applescript = { M.hash },
32 | astro = { M.html },
33 | autohotkey = { M.semicolon, M.cxx_b },
34 | bash = { M.hash },
35 | beancount = { M.semicolon },
36 | bib = { M.latex },
37 | c = { M.cxx_l, M.cxx_b },
38 | cabal = { M.dash },
39 | cmake = { M.hash, M.hash_bracket },
40 | conf = { M.hash },
41 | conkyrc = { M.dash, M.dash_bracket },
42 | coq = { M.fsharp_b },
43 | cpp = { M.cxx_l, M.cxx_b },
44 | cs = { M.cxx_l, M.cxx_b },
45 | css = { M.cxx_b, M.cxx_b },
46 | cuda = { M.cxx_l, M.cxx_b },
47 | dart = { M.cxx_l, M.cxx_b },
48 | dhall = { M.dash, M.haskell_b },
49 | dosbatch = { "REM%s" },
50 | dot = { M.cxx_l, M.cxx_b },
51 | dts = { M.cxx_l, M.cxx_b },
52 | editorconfig = { M.hash },
53 | eelixir = { M.html, M.html },
54 | elixir = { M.hash },
55 | elm = { M.dash, M.haskell_b },
56 | elvish = { M.hash },
57 | faust = { M.cxx_l, M.cxx_b },
58 | fennel = { M.semicolon },
59 | fish = { M.hash },
60 | func = { M.lisp_l },
61 | fsharp = { M.cxx_l, M.fsharp_b },
62 | gdb = { M.hash },
63 | gdscript = { M.hash },
64 | gitignore = { M.hash },
65 | gleam = { M.cxx_l },
66 | glsl = { M.cxx_l, M.cxx_b },
67 | gnuplot = { M.hash, M.hash_bracket },
68 | go = { M.cxx_l, M.cxx_b },
69 | gomod = { M.cxx_l },
70 | graphql = { M.hash },
71 | groovy = { M.cxx_l, M.cxx_b },
72 | handlebars = { M.handlebars, M.handlebars },
73 | haskell = { M.dash, M.haskell_b },
74 | haxe = { M.cxx_l, M.cxx_b },
75 | heex = { M.html, M.html },
76 | html = { M.html, M.html },
77 | htmldjango = { M.html, M.html },
78 | idris = { M.dash, M.haskell_b },
79 | idris2 = { M.dash, M.haskell_b },
80 | ini = { M.hash },
81 | java = { M.cxx_l, M.cxx_b },
82 | javascript = { M.cxx_l, M.cxx_b },
83 | javascriptreact = { M.cxx_l, M.cxx_b },
84 | jsonc = { M.cxx_l },
85 | jsonnet = { M.cxx_l, M.cxx_b },
86 | julia = { M.hash, "#=%s=#" },
87 | kotlin = { M.cxx_l, M.cxx_b },
88 | lean = { M.dash, M.lean_b },
89 | lean3 = { M.dash, M.lean_b },
90 | lidris = { M.dash, M.haskell_b },
91 | lilypond = { M.latex, "%{%s%}" },
92 | lisp = { M.lisp_l, M.lisp_b },
93 | lua = { M.dash, M.dash_bracket },
94 | luau = { M.dash, M.dash_bracket },
95 | markdown = { M.html, M.html },
96 | make = { M.hash },
97 | mbsyncrc = { M.dbl_hash },
98 | mermaid = { "%%%s" },
99 | meson = { M.hash },
100 | nextflow = { M.cxx_l, M.cxx_b },
101 | nim = { M.hash, "#[%s]#" },
102 | nix = { M.hash, M.cxx_b },
103 | nu = { M.hash },
104 | ocaml = { M.fsharp_b, M.fsharp_b },
105 | odin = { M.cxx_l, M.cxx_b },
106 | plantuml = { "'%s", "/'%s'/" },
107 | purescript = { M.dash, M.haskell_b },
108 | python = { M.hash }, -- Python doesn't have block comments
109 | php = { M.cxx_l, M.cxx_b },
110 | prisma = { M.cxx_l },
111 | proto = { M.cxx_l, M.cxx_b },
112 | quarto = { M.html, M.html },
113 | r = { M.hash }, -- R doesn't have block comments
114 | racket = { M.lisp_l, M.lisp_b },
115 | rasi = { M.cxx_l, M.cxx_b },
116 | readline = { M.hash },
117 | rego = { M.hash },
118 | remind = { M.hash },
119 | rescript = { M.cxx_l, M.cxx_b },
120 | robot = { M.hash }, -- Robotframework doesn't have block comments
121 | ron = { M.cxx_l, M.cxx_b },
122 | ruby = { M.hash },
123 | rust = { M.cxx_l, M.cxx_b },
124 | sbt = { M.cxx_l, M.cxx_b },
125 | scala = { M.cxx_l, M.cxx_b },
126 | scheme = { M.lisp_l, M.lisp_b },
127 | sh = { M.hash },
128 | solidity = { M.cxx_l, M.cxx_b },
129 | supercollider = { M.cxx_l, M.cxx_b },
130 | sql = { M.dash, M.cxx_b },
131 | stata = { M.cxx_l, M.cxx_b },
132 | svelte = { M.html, M.html },
133 | swift = { M.cxx_l, M.cxx_b },
134 | sxhkdrc = { M.hash },
135 | tablegen = { M.cxx_l, M.cxx_b },
136 | teal = { M.dash, M.dash_bracket },
137 | terraform = { M.hash, M.cxx_b },
138 | tex = { M.latex },
139 | template = { M.dbl_hash },
140 | tmux = { M.hash },
141 | toml = { M.hash },
142 | twig = { M.twig, M.twig },
143 | typescript = { M.cxx_l, M.cxx_b },
144 | typescriptreact = { M.cxx_l, M.cxx_b },
145 | typst = { M.cxx_l, M.cxx_b },
146 | v = { M.cxx_l, M.cxx_b },
147 | verilog = { M.cxx_l },
148 | vhdl = { M.dash },
149 | vim = { M.vim },
150 | vifm = { M.vim },
151 | vue = { M.html, M.html },
152 | xdefaults = { "!%s" },
153 | xml = { M.html, M.html },
154 | xonsh = { M.hash }, -- Xonsh doesn't have block comments
155 | yaml = { M.hash },
156 | yuck = { M.lisp_l },
157 | zig = { M.cxx_l }, -- Zig doesn't have block comments
158 | }, {
159 | -- Support for compound filetype i.e. 'ios.swift', 'ansible.yaml' etc.
160 | __index = function(this, k)
161 | local base, fallback = string.match(k, "^(.-)%.(.*)")
162 | if not (base or fallback) then
163 | return nil
164 | end
165 | return this[base] or this[fallback]
166 | end,
167 | })
168 |
169 | local ft = {}
170 |
171 | ---Sets a commentstring(s) for a filetype/language
172 | ---@param lang string Filetype/Language of the buffer
173 | ---@param val string|string[]
174 | ---@return table self Returns itself
175 | ---@usage [[
176 | ---local ft = require('Comment.ft')
177 | ---
178 | -----1. Using method signature
179 | ----- Set only line comment or both
180 | ----- You can also chain the set calls
181 | ---ft.set('yaml', '#%s').set('javascript', {'//%s', '/*%s*/'})
182 | ---
183 | ----- 2. Metatable magic
184 | ---ft.javascript = {'//%s', '/*%s*/'}
185 | ---ft.yaml = '#%s'
186 | ---
187 | ----- 3. Multiple filetypes
188 | ---ft({'go', 'rust'}, {'//%s', '/*%s*/'})
189 | ---ft({'toml', 'graphql'}, '#%s')
190 | ---@usage ]]
191 | function ft.set(lang, val)
192 | L[lang] = type(val) == "string" and { val } or val --[[ @as string[] ]]
193 | return ft
194 | end
195 |
196 | ---Get line/block/both commentstring(s) for a given filetype
197 | ---@param lang string Filetype/Language of the buffer
198 | ---@param ctype? integer See |comment.utils.ctype|. If given `nil`, it'll
199 | ---return a copy of { line, block } commentstring.
200 | ---@return nil|string|string[] #Returns stored commentstring
201 | ---@usage [[
202 | ---local ft = require('Comment.ft')
203 | ---local U = require('Comment.utils')
204 | ---
205 | ----- 1. Primary filetype
206 | ---ft.get('rust', U.ctype.linewise) -- `//%s`
207 | ---ft.get('rust') -- `{ '//%s', '/*%s*/' }`
208 | ---
209 | ----- 2. Compound filetype
210 | ----- NOTE: This will return `yaml` commenstring(s),
211 | ----- as `ansible` commentstring is not found.
212 | ---ft.get('ansible.yaml', U.ctype.linewise) -- `#%s`
213 | ---ft.get('ansible.yaml') -- { '#%s' }
214 | ---@usage ]]
215 | function ft.get(lang, ctype)
216 | local tuple = L[lang]
217 | if not tuple then
218 | return nil
219 | end
220 | if not ctype then
221 | return vim.deepcopy(tuple)
222 | end
223 | return tuple[ctype]
224 | end
225 |
226 | ---@export ft
227 | return setmetatable(ft, {
228 | __newindex = function(this, k, v)
229 | this.set(k, v)
230 | end,
231 | __call = function(this, langs, spec)
232 | for _, lang in ipairs(langs) do
233 | this.set(lang, spec)
234 | end
235 | return this
236 | end,
237 | })
238 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/utils/common_cond.lua:
--------------------------------------------------------------------------------
1 | local Cond = require("luasnip-snippets.utils.cond")
2 | local Utils = require("luasnip-snippets.utils")
3 |
4 | local function line_begin_cond(line_to_cursor, matched_trigger, _)
5 | if matched_trigger == nil or line_to_cursor == nil then
6 | return false
7 | end
8 | return line_to_cursor:sub(1, -(#matched_trigger + 1)):match("^%s*$")
9 | end
10 |
11 | local function line_begin_show_maker(trig)
12 | local function line_begin_show(line_to_cursor)
13 | if line_to_cursor == nil then
14 | return false
15 | end
16 | local _, col = unpack(vim.api.nvim_win_get_cursor(0))
17 | local line = vim.api.nvim_get_current_line()
18 | local trigger = line:sub(1, col):match("%S+$")
19 | if trigger == nil then
20 | return false
21 | end
22 | if #trigger > #trig then
23 | return false
24 | end
25 | return trigger == trig:sub(1, #trigger)
26 | end
27 | return line_begin_show
28 | end
29 |
30 | ---@param trig string
31 | ---@return LSSnippets.ConditionObject
32 | local function at_line_begin(trig)
33 | return Cond.make_condition(line_begin_cond, line_begin_show_maker(trig))
34 | end
35 |
36 | local function generate_all_lines_before_match_cond(pattern)
37 | if type(pattern) == "string" then
38 | pattern = { pattern }
39 | end
40 |
41 | local function condition()
42 | local row, _ = unpack(vim.api.nvim_win_get_cursor(0))
43 | local lines = vim.api.nvim_buf_get_lines(0, 0, row - 1, false)
44 | for _, line in ipairs(lines) do
45 | local match = false
46 | for _, p in ipairs(pattern) do
47 | if line:match(p) then
48 | match = true
49 | break
50 | end
51 | end
52 | if not match then
53 | return false
54 | end
55 | end
56 | return true
57 | end
58 | return Cond.make_condition(condition, condition)
59 | end
60 |
61 | local function has_select_raw_fn(_, _, _)
62 | return Utils.get_buf_var(0, "LUASNIP_SELECT_RAW") ~= nil
63 | end
64 | local has_select_raw = Cond.make_condition(has_select_raw_fn, has_select_raw_fn)
65 |
66 | return {
67 | at_line_begin = at_line_begin,
68 | generate_all_lines_before_match_cond = generate_all_lines_before_match_cond,
69 | has_select_raw = has_select_raw,
70 | }
71 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/utils/cond.lua:
--------------------------------------------------------------------------------
1 | ---@class luasnip-snippets.utils.cond
2 | local M = {}
3 |
4 | ---@class LSSnippets.ConditionFuncObject
5 | ---@operator unm: LSSnippets.ConditionFuncObject
6 | ---@operator add(LSSnippets.ConditionFuncObject): LSSnippets.ConditionFuncObject
7 | ---@operator div(LSSnippets.ConditionFuncObject): LSSnippets.ConditionFuncObject
8 | ---@operator pow(LSSnippets.ConditionFuncObject): LSSnippets.ConditionFuncObject
9 | ---@operator call(): boolean
10 | local ConditionFuncObject = {
11 | -- not '-'
12 | __unm = function(o1)
13 | return M.make_condition_func(function(...)
14 | return not o1(...)
15 | end)
16 | end,
17 | -- and '+'
18 | __add = function(o1, o2)
19 | return M.make_condition_func(function(...)
20 | return o1(...) and o2(...)
21 | end)
22 | end,
23 | -- or '/'
24 | __div = function(o1, o2)
25 | return M.make_condition_func(function(...)
26 | return o1(...) or o2(...)
27 | end)
28 | end,
29 | -- xor '^'
30 | __pow = function(o1, o2)
31 | return M.make_condition_func(function(...)
32 | return o1(...) ~= o2(...)
33 | end)
34 | end,
35 | -- use table like a function by overloading __call
36 | __call = function(tab, line_to_cursor, matched_trigger, captures)
37 | return tab.func(line_to_cursor, matched_trigger, captures)
38 | end,
39 | }
40 |
41 | ---@class LSSnippets.ConditionObject
42 | ---@field condition LSSnippets.ConditionFuncObject
43 | ---@field show_condition LSSnippets.ConditionFuncObject
44 | local ConditionObject = {
45 | ---@param tbl LSSnippets.ConditionObject
46 | ---@return LSSnippets.ConditionObject
47 | __unm = function(tbl)
48 | return M.make_condition(-tbl.condition, -tbl.show_condition)
49 | end,
50 | ---@param o1 LSSnippets.ConditionObject
51 | ---@param o2 LSSnippets.ConditionObject
52 | ---@return LSSnippets.ConditionObject
53 | __add = function(o1, o2)
54 | return M.make_condition(
55 | o1.condition + o2.condition,
56 | o1.show_condition + o2.show_condition
57 | )
58 | end,
59 | ---@param o1 LSSnippets.ConditionObject
60 | ---@param o2 LSSnippets.ConditionObject
61 | ---@return LSSnippets.ConditionObject
62 | __div = function(o1, o2)
63 | return M.make_condition(
64 | o1.condition / o2.condition,
65 | o1.show_condition / o2.show_condition
66 | )
67 | end,
68 | ---@param o1 LSSnippets.ConditionObject
69 | ---@param o2 LSSnippets.ConditionObject
70 | ---@return LSSnippets.ConditionObject
71 | __pow = function(o1, o2)
72 | return M.make_condition(
73 | o1.condition ^ o2.condition,
74 | o1.show_condition ^ o2.show_condition
75 | )
76 | end,
77 | }
78 |
79 | ---@param fn function
80 | ---@return LSSnippets.ConditionFuncObject
81 | function M.make_condition_func(fn)
82 | return setmetatable({ func = fn }, ConditionFuncObject)
83 | end
84 |
85 | ---@param condition function|LSSnippets.ConditionFuncObject
86 | ---@param show_condition function|LSSnippets.ConditionFuncObject
87 | ---@return LSSnippets.ConditionObject
88 | function M.make_condition(condition, show_condition)
89 | if type(condition) == "function" then
90 | condition = M.make_condition_func(condition)
91 | end
92 | if type(show_condition) == "function" then
93 | show_condition = M.make_condition_func(show_condition)
94 | end
95 |
96 | return setmetatable({
97 | condition = condition,
98 | show_condition = show_condition,
99 | }, ConditionObject)
100 | end
101 |
102 | return M
103 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/utils/dummy_types.lua:
--------------------------------------------------------------------------------
1 | -- dummy
2 | ---@class LuaSnip.Snippet
3 |
4 | ---@class LuaSnip.Node
5 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/utils/init.lua:
--------------------------------------------------------------------------------
1 | ---@class luasnip-snippets.utils
2 | local M = {}
3 |
4 | ---Replace all occurences of %s in template with match.
5 | ---@param match string|string[]
6 | ---@param template string
7 | ---@return string[]
8 | function M.replace_all(match, template)
9 | match = vim.F.if_nil(match, "")
10 | ---@type string
11 | local match_str = ""
12 | if type(match) == "table" then
13 | match_str = table.concat(match, "\n")
14 | else
15 | match_str = match
16 | end
17 |
18 | local ret = template:gsub("%%s", match_str)
19 | local ret_lines = vim.split(ret, "\n", {
20 | trimempty = false,
21 | })
22 |
23 | return ret_lines
24 | end
25 |
26 | ---Load and concat snippets.
27 | ---@param base string
28 | ---@param snippets string[]
29 | ---@return LuaSnip.Snippet[]
30 | function M.concat_snippets(base, snippets)
31 | local ret = {}
32 | for _, snippet in ipairs(snippets) do
33 | local snippet_module = require(base .. "." .. snippet)
34 | if type(snippet_module) == "function" then
35 | snippet_module = snippet_module()
36 | end
37 | vim.list_extend(ret, snippet_module)
38 | end
39 | -- flatten the list
40 | local flat_ret = {}
41 | for _, snippet in ipairs(ret) do
42 | if vim.islist(snippet) then
43 | vim.list_extend(flat_ret, snippet)
44 | else
45 | flat_ret[#flat_ret + 1] = snippet
46 | end
47 | end
48 | return flat_ret
49 | end
50 |
51 | function M.reverse_list(lst)
52 | for i = 1, math.floor(#lst / 2) do
53 | local j = #lst - i + 1
54 | lst[i], lst[j] = lst[j], lst[i]
55 | end
56 | end
57 |
58 | function M.get_buf_var(bufnr, key)
59 | local succ, value = pcall(vim.api.nvim_buf_get_var, bufnr, key)
60 | if succ then
61 | return value
62 | end
63 | end
64 |
65 | return M
66 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/utils/tbl.lua:
--------------------------------------------------------------------------------
1 | ---@class luasnip-snippets.utils.tbl
2 | local M = {}
3 |
4 | function M.list_contains(t, value)
5 | for _, v in ipairs(t) do
6 | if v == value then
7 | return true
8 | end
9 | end
10 | return false
11 | end
12 |
13 | return M
14 |
--------------------------------------------------------------------------------
/lua/luasnip-snippets/utils/treesitter.lua:
--------------------------------------------------------------------------------
1 | ---@class luasnip-snippets.utils.treesitter
2 | local M = {}
3 |
4 | ---Invoke the given function after the matched trigger removed and the buffer
5 | ---has been reparsed.
6 | ---@generic T
7 | ---@param ori_bufnr number
8 | ---@param match string
9 | ---@param fun fun(parser: vim.treesitter.LanguageTree, source: string):T
10 | ---@return T
11 | function M.invoke_after_reparse_buffer(ori_bufnr, match, fun)
12 | local function reparse_buffer()
13 | local row, col = unpack(vim.api.nvim_win_get_cursor(0))
14 | local lines = vim.api.nvim_buf_get_lines(ori_bufnr, 0, -1, false)
15 | local current_line = lines[row]
16 | local current_line_left = current_line:sub(1, col - #match)
17 | local current_line_right = current_line:sub(col + 1)
18 | lines[row] = current_line_left .. current_line_right
19 | local lang = vim.treesitter.language.get_lang(vim.bo[ori_bufnr].filetype)
20 | or vim.bo[ori_bufnr].filetype
21 |
22 | local source = table.concat(lines, "\n")
23 | ---@type vim.treesitter.LanguageTree
24 | local parser = vim.treesitter.get_string_parser(source, lang)
25 | parser:parse(true)
26 |
27 | return parser, source
28 | end
29 |
30 | local parser, source = reparse_buffer()
31 |
32 | local ret = { fun(parser, source) }
33 |
34 | parser:destroy()
35 |
36 | return unpack(ret)
37 | end
38 |
39 | ---@param types table | string
40 | ---@return table
41 | function M.make_type_matcher(types)
42 | if type(types) == "string" then
43 | return { [types] = 1 }
44 | end
45 |
46 | if type(types) == "table" then
47 | if (vim.islist or vim.tbl_islist)(types) then
48 | local new_types = {}
49 | for _, v in ipairs(types) do
50 | new_types[v] = 1
51 | end
52 | return new_types
53 | end
54 | end
55 |
56 | return types
57 | end
58 |
59 | ---Find the first parent node whose type in `types`.
60 | ---@param node TSNode?
61 | ---@param types table|string
62 | ---@return TSNode|nil
63 | function M.find_first_parent(node, types)
64 | local matcher = M.make_type_matcher(types)
65 |
66 | ---@param root TSNode|nil
67 | ---@return TSNode|nil
68 | local function find_parent_impl(root)
69 | if root == nil then
70 | return nil
71 | end
72 | if matcher[root:type()] == 1 then
73 | return root
74 | end
75 | return find_parent_impl(root:parent())
76 | end
77 |
78 | return find_parent_impl(node)
79 | end
80 |
81 | ---Returns the start pos of a `TSNode`
82 | ---@param node TSNode?
83 | ---@return { [1]: number, [2]: number }?
84 | function M.start_pos(node)
85 | if node == nil then
86 | return nil
87 | end
88 | local start_row, start_col, _, _ = vim.treesitter.get_node_range(node)
89 | return { start_row, start_col }
90 | end
91 |
92 | --- Normalize the arguments passed to treesitter_postfix into a function that
93 | --- returns treesitter-matches to the specified query+captures.
94 | ---@param opts LuaSnip.extra.MatchTSNodeOpts
95 | ---@return LuaSnip.extra.MatchTSNodeFunc
96 | function M.generate_match_tsnode_func(opts)
97 | local ts = require("luasnip.extras._treesitter")
98 | local match_opts = {}
99 |
100 | if opts.query then
101 | match_opts.query = vim.treesitter.query.parse(opts.query_lang, opts.query)
102 | else
103 | match_opts.query =
104 | vim.treesitter.query.get(opts.query_lang, opts.query_name or "luasnip")
105 | end
106 |
107 | match_opts.generator = ts.captures_iter(opts.match_captures or "prefix")
108 |
109 | if type(opts.select) == "function" then
110 | match_opts.selector = opts.select
111 | elseif type(opts.select) == "string" then
112 | match_opts.selector = ts.builtin_tsnode_selectors[opts.select]
113 | assert(match_opts.selector, "Selector " .. opts.select .. "is not known")
114 | else
115 | match_opts.selector = ts.builtin_tsnode_selectors.any
116 | end
117 |
118 | ---@param parser LuaSnip.extra.TSParser
119 | ---@param pos { [1]: number, [2]: number }
120 | return function(parser, pos)
121 | return parser:match_at(
122 | match_opts, --[[@as LuaSnip.extra.MatchTSNodeOpts]]
123 | pos
124 | )
125 | end
126 | end
127 |
128 | ---@class LSSnippets.ProcessMatchesContext
129 | ---@field ts_parser LuaSnip.extra.TSParser
130 | ---@field best_match LuaSnip.extra.NamedTSMatch
131 | ---@field prefix_node TSNode
132 | ---@field matched_trigger string
133 | ---@field captures any
134 | ---@field pos { [1]: number, [2]: number }
135 |
136 | ---@alias LSSnippets.ProcessMatchesFunc fun(context: LSSnippets.ProcessMatchesContext, previous: table): table
137 |
138 | ---@param context LSSnippets.ProcessMatchesContext
139 | ---@param previous any
140 | function M.inject_tsmatches(context, previous)
141 | local start_row, start_col, _, _ = context.prefix_node:range()
142 |
143 | local env = {
144 | LS_TSMATCH = vim.split(
145 | context.ts_parser:get_node_text(context.prefix_node),
146 | "\n"
147 | ),
148 | -- filled subsequently.
149 | LS_TSDATA = {},
150 | }
151 | for capture_name, node in pairs(context.best_match) do
152 | env["LS_TSCAPTURE_" .. capture_name:upper()] =
153 | vim.split(context.ts_parser:get_node_text(node), "\n")
154 |
155 | local from_r, from_c, to_r, to_c = node:range()
156 | env.LS_TSDATA[capture_name] = {
157 | type = node:type(),
158 | range = { { from_r, from_c }, { to_r, to_c } },
159 | }
160 | end
161 |
162 | previous = vim.tbl_extend("force", previous, {
163 | trigger = context.matched_trigger,
164 | captures = context.captures,
165 | clear_region = {
166 | from = {
167 | start_row,
168 | start_col,
169 | },
170 | to = {
171 | context.pos[1],
172 | context.pos[2] + #context.matched_trigger,
173 | },
174 | },
175 | env_override = env,
176 | })
177 |
178 | return previous
179 | end
180 |
181 | ---@param match_tsnode LuaSnip.extra.MatchTSNodeFunc
182 | ---@param process_funcs LSSnippets.ProcessMatchesFunc[]
183 | function M.generate_resolve_expand_param(match_tsnode, process_funcs)
184 | ---@param snippet any
185 | ---@param line_to_cursor string
186 | ---@param matched_trigger string
187 | ---@param captures any
188 | ---@param parser vim.treesitter.LanguageTree
189 | ---@param source number|string
190 | ---@param bufnr number
191 | ---@param pos { [1]: number, [2]: number }
192 | return function(
193 | snippet,
194 | line_to_cursor,
195 | matched_trigger,
196 | captures,
197 | parser,
198 | source,
199 | bufnr,
200 | pos
201 | )
202 | local ts = require("luasnip.extras._treesitter")
203 |
204 | local ts_parser = ts.TSParser.new(bufnr, parser, source)
205 | if ts_parser == nil then
206 | return
207 | end
208 |
209 | local row, col = unpack(pos)
210 |
211 | local best_match, prefix_node = match_tsnode(ts_parser, { row, col })
212 |
213 | if best_match == nil or prefix_node == nil then
214 | return nil
215 | end
216 |
217 | ---@type LSSnippets.ProcessMatchesContext
218 | local context = {
219 | ts_parser = ts_parser,
220 | best_match = best_match,
221 | prefix_node = prefix_node,
222 | matched_trigger = matched_trigger,
223 | captures = captures,
224 | pos = pos,
225 | }
226 | local ret = {}
227 | for _, process_func in ipairs(process_funcs) do
228 | ret = process_func(context, ret)
229 | end
230 |
231 | return ret
232 | end
233 | end
234 |
235 | ---Optionally parse the buffer
236 | ---@param reparse boolean|string|nil
237 | ---@param real_resolver function
238 | ---@return fun(snippet, line_to_cursor, matched_trigger, captures):table?
239 | function M.wrap_with_reparse_context(reparse, real_resolver)
240 | local util = require("luasnip.util.util")
241 | local ts = require("luasnip.extras._treesitter")
242 |
243 | local function make_reparse_enter_and_leave_func(
244 | bufnr,
245 | trigger_region,
246 | trigger
247 | )
248 | if reparse == "live" then
249 | local context = ts.FixBufferContext.new(bufnr, trigger_region, trigger)
250 | return function()
251 | return context:enter()
252 | end, function(_)
253 | context:leave()
254 | end
255 | elseif reparse == "copy" then
256 | local parser, source =
257 | ts.reparse_buffer_after_removing_match(bufnr, trigger_region)
258 | return function()
259 | return parser, source
260 | end, function()
261 | parser:destroy()
262 | end
263 | else
264 | return function()
265 | return vim.treesitter.get_parser(bufnr), bufnr
266 | end, function(_) end
267 | end
268 | end
269 |
270 | return function(snippet, line_to_cursor, matched_trigger, captures)
271 | local bufnr = vim.api.nvim_win_get_buf(0)
272 | local cursor = util.get_cursor_0ind()
273 | local trigger_region = {
274 | row = cursor[1],
275 | col_range = {
276 | -- includes from, excludes to.
277 | cursor[2] - #matched_trigger,
278 | cursor[2],
279 | },
280 | }
281 |
282 | local enter, leave =
283 | make_reparse_enter_and_leave_func(bufnr, trigger_region, matched_trigger)
284 | local parser, source = enter()
285 | if parser == nil or source == nil then
286 | return nil
287 | end
288 |
289 | local ret = real_resolver(
290 | snippet,
291 | line_to_cursor,
292 | matched_trigger,
293 | captures,
294 | parser,
295 | source,
296 | bufnr,
297 | { cursor[1], cursor[2] - #matched_trigger }
298 | )
299 |
300 | leave()
301 |
302 | return ret
303 | end
304 | end
305 |
306 | function M.treesitter_postfix(context, nodes, opts)
307 | local node_util = require("luasnip.nodes.util")
308 | local snip = require("luasnip.nodes.snippet").S
309 |
310 | opts = opts or {}
311 | vim.validate {
312 | context = { context, { "string", "table" } },
313 | nodes = { nodes, "table" },
314 | opts = { opts, "table" },
315 | }
316 |
317 | context = node_util.wrap_context(context)
318 | context.wordTrig = false
319 |
320 | ---@type LuaSnip.extra.MatchTSNodeFunc
321 | local match_tsnode_func
322 | if type(context.matchTSNode) == "function" then
323 | match_tsnode_func = context.matchTSNode
324 | else
325 | match_tsnode_func = M.generate_match_tsnode_func(context.matchTSNode)
326 | end
327 |
328 | local expand_params_resolver =
329 | M.generate_resolve_expand_param(match_tsnode_func, {
330 | M.inject_tsmatches,
331 | context.injectMatches,
332 | })
333 |
334 | context.resolveExpandParams =
335 | M.wrap_with_reparse_context(context.reparseBuffer, expand_params_resolver)
336 |
337 | return snip(context, nodes, opts)
338 | end
339 |
340 | return M
341 |
--------------------------------------------------------------------------------