Skip to content

Commit 66864ff

Browse files
authored
Merge pull request #571 from leiserfg/capture-environ
Add LS_CAPTURE_n and LS_TRIGGER environment vars
2 parents 1770264 + c919d04 commit 66864ff

File tree

7 files changed

+78
-27
lines changed

7 files changed

+78
-27
lines changed

DOC.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,18 +1399,21 @@ If `jsregexp` is not available, transformation are replaced by a simple copy.
13991399
# VARIABLES
14001400

14011401
All `TM_something`-variables are supported with two additions:
1402-
`SELECT_RAW` and `SELECT_DEDENT`. These were introduced because
1402+
`LS_SELECT_RAW` and `LS_SELECT_DEDENT`. These were introduced because
14031403
`TM_SELECTED_TEXT` is designed to be compatible with vscodes' behavior, which
14041404
can be counterintuitive when the snippet can be expanded at places other than
14051405
the point where selection started (or when doing transformations on selected text).
1406+
Besides those we also provide `LS_TRIGGER` which contains the trigger of the snippet,
1407+
and `LS_CAPTURE_n` (where n is a positive integer) that contains the n-th capture
1408+
when using a regex with capture groups as `trig` in the snippet definition.
14061409

14071410
All variables can be used outside of lsp-parsed snippets as their values are
14081411
stored in a snippets' `snip.env`-table:
14091412
```lua
14101413
s("selected_text", f(function(args, snip)
14111414
local res, env = {}, snip.env
14121415
table.insert(res, "Selected Text (current line is " .. env.TM_LINE_NUMBER .. "):")
1413-
for _, ele in ipairs(env.SELECT_RAW) do table.insert(res, ele) end
1416+
for _, ele in ipairs(env.LS_SELECT_RAW) do table.insert(res, ele) end
14141417
return res
14151418
end, {}))
14161419
```
@@ -1436,9 +1439,11 @@ You can also add your own variables by using the `ls.env_namespace(name, opts)`
14361439
Is a function that receives a string and returns a value for the var with that name
14371440
or a table from var name to a value
14381441
(in this case, if the value is a function it will be executed lazily once per snippet expansion).
1439-
* `init`: `fn(pos: pair[int])->map[string, EnvVal]` Takes the 0-based position of the cursor and returns
1442+
* `init`: `fn(info: table)->map[string, EnvVal]` Returns
14401443
a table of variables that will set to the environment of the snippet on expansion,
14411444
use this for vars that have to be calculated in that moment or that depend on each other.
1445+
The `info` table argument contains `pos` (0-based position of the cursor on expansion),
1446+
the `trigger` of the snippet and the `captures` list.
14421447
* `eager`: `list[string]` names of variables that will be taken from `vars` and appended eagerly (like those in init)
14431448
* `multiline_vars`: `(fn(name:string)->bool)|map[sting, bool]|bool|string[]` Says if certain vars are a table or just a string,
14441449
can be a function that get's the name of the var and returns true if the var is a key,
@@ -1464,7 +1469,7 @@ ls.env_namespace("SYS", {vars=os.getenv, eager={"HOME"}})
14641469

14651470
-- then you can use $SYS_HOME which was eagerly initialized but also $SYS_USER (or any other system environment var) in your snippets
14661471

1467-
lsp.env_namespace("POS", {init=function(pos) return {"VAL": vim.inspect(pos)}} end)
1472+
lsp.env_namespace("POS", {init=function(info) return {"VAL": vim.inspect(info.pos)}} end)
14681473

14691474
-- then you can use $POS_VAL in your snippets
14701475

doc/luasnip.txt

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1340,11 +1340,15 @@ If `jsregexp` is not available, transformation are replaced by a simple copy.
13401340
==============================================================================
13411341
17. VARIABLES *luasnip-variables*
13421342

1343-
All `TM_something`-variables are supported with two additions: `SELECT_RAW` and
1344-
`SELECT_DEDENT`. These were introduced because `TM_SELECTED_TEXT` is designed
1345-
to be compatible with vscodes’ behavior, which can be counterintuitive when
1346-
the snippet can be expanded at places other than the point where selection
1347-
started (or when doing transformations on selected text).
1343+
All `TM_something`-variables are supported with two additions: `LS_SELECT_RAW`
1344+
and `LS_SELECT_DEDENT`. These were introduced because `TM_SELECTED_TEXT` is
1345+
designed to be compatible with vscodes’ behavior, which can be
1346+
counterintuitive when the snippet can be expanded at places other than the
1347+
point where selection started (or when doing transformations on selected text).
1348+
Besides those we also provide `LS_TRIGGER` which contains the trigger of the
1349+
snippet, and `LS_CAPTURE_n` (where n is a positive integer) that contains the
1350+
n-th capture when using a regex with capture groups as `trig` in the snippet
1351+
definition.
13481352

13491353
All variables can be used outside of lsp-parsed snippets as their values are
13501354
stored in a snippets’ `snip.env`-table:
@@ -1353,7 +1357,7 @@ stored in a snippets’ `snip.env`-table:
13531357
s("selected_text", f(function(args, snip)
13541358
local res, env = {}, snip.env
13551359
table.insert(res, "Selected Text (current line is " .. env.TM_LINE_NUMBER .. "):")
1356-
for _, ele in ipairs(env.SELECT_RAW) do table.insert(res, ele) end
1360+
for _, ele in ipairs(env.LS_SELECT_RAW) do table.insert(res, ele) end
13571361
return res
13581362
end, {}))
13591363
<
@@ -1376,9 +1380,11 @@ where:
13761380
Is a function that receives a string and returns a value for the var with that name
13771381
or a table from var name to a value
13781382
(in this case, if the value is a function it will be executed lazily once per snippet expansion).
1379-
- `init`: `fn(pos: pair[int])->map[string, EnvVal]` Takes the 0-based position of the cursor and returns
1383+
- `init`: `fn(info: table)->map[string, EnvVal]` Returns
13801384
a table of variables that will set to the environment of the snippet on expansion,
13811385
use this for vars that have to be calculated in that moment or that depend on each other.
1386+
The `info` table argument contains `pos` (0-based position of the cursor on expansion),
1387+
the `trigger` of the snippet and the `captures` list.
13821388
- `eager`: `list[string]` names of variables that will be taken from `vars` and appended eagerly (like those in init)
13831389
- `multiline_vars`: `(fn(name:string)->bool)|map[sting, bool]|bool|string[]` Says if certain vars are a table or just a string,
13841390
can be a function that get’s the name of the var and returns true if the var is a key,
@@ -1405,7 +1411,7 @@ A simple example to make it more clear:
14051411
14061412
-- then you can use $SYS_HOME which was eagerly initialized but also $SYS_USER (or any other system environment var) in your snippets
14071413
1408-
lsp.env_namespace("POS", {init=function(pos) return {"VAL": vim.inspect(pos)}} end)
1414+
lsp.env_namespace("POS", {init=function(info) return {"VAL": vim.inspect(info.pos)}} end)
14091415
14101416
-- then you can use $POS_VAL in your snippets
14111417

lua/luasnip/init.lua

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,9 @@ local function snip_expand(snippet, opts)
191191
snip.trigger = opts.expand_params.trigger or snip.trigger
192192
snip.captures = opts.expand_params.captures or {}
193193

194-
local env = Environ:new(opts.pos)
194+
local info =
195+
{ trigger = snip.trigger, captures = snip.captures, pos = opts.pos }
196+
local env = Environ:new(info)
195197

196198
local pos_id = vim.api.nvim_buf_set_extmark(
197199
0,

lua/luasnip/util/_builtin_vars.lua

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,19 +147,27 @@ function lazy_vars.BLOCK_COMMENT_END()
147147
end
148148

149149
-- These are the vars that have to be populated once the snippet starts to avoid any issue
150-
local function eager_vars(pos)
150+
local function eager_vars(info)
151151
local vars = {}
152+
local pos = info.pos
152153
vars.TM_CURRENT_LINE =
153154
vim.api.nvim_buf_get_lines(0, pos[1], pos[1] + 1, false)[1]
154155
vars.TM_CURRENT_WORD = util.word_under_cursor(pos, vars.TM_CURRENT_LINE)
155156
vars.TM_LINE_INDEX = tostring(pos[1])
156157
vars.TM_LINE_NUMBER = tostring(pos[1] + 1)
157-
vars.SELECT_RAW, vars.SELECT_DEDENT, vars.TM_SELECTED_TEXT =
158+
vars.LS_SELECT_RAW, vars.LS_SELECT_DEDENT, vars.TM_SELECTED_TEXT =
158159
util.get_selection()
160+
-- These are for backward compatibility, for now on all builtins that are not part of TM_ go in LS_
161+
vars.SELECT_RAW, vars.SELECT_DEDENT =
162+
vars.LS_SELECT_RAW, vars.LS_SELECT_DEDENT
163+
for i, cap in ipairs(info.captures) do
164+
vars["LS_CAPTURE_" .. i] = cap
165+
end
166+
vars.LS_TRIGGER = info.trigger
159167
return vars
160168
end
161169

162-
local builtin_ns = { SELECT = true }
170+
local builtin_ns = { SELECT = true, LS = true }
163171

164172
for name, _ in pairs(lazy_vars) do
165173
local parts = vim.split(name, "_")

lua/luasnip/util/environ.lua

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,15 @@ function Environ.is_table(var_fullname)
3939
return nmsp.is_table(varname)
4040
end
4141

42-
function Environ:new(pos, o)
42+
function Environ:new(info, o)
4343
o = o or {}
4444
setmetatable(o, self)
45+
vim.list_extend(info, info.pos) -- For compatibility with old user defined namespaces
4546

4647
for ns_name, ns in pairs(namespaces) do
4748
local eager_vars = {}
4849
if ns.init then
49-
eager_vars = ns.init(pos)
50+
eager_vars = ns.init(info)
5051
end
5152
for _, eager in ipairs(ns.eager) do
5253
if not eager_vars[eager] then

tests/integration/parser_spec.lua

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,7 @@ describe("Parser", function()
623623

624624
it("Inserts default when the variable is empty", function()
625625
ls_helpers.session_setup_luasnip()
626-
local snip = "${SELECT_DEDENT: a ${2:default}}"
626+
local snip = "${LS_SELECT_DEDENT: a ${2:default}}"
627627

628628
exec_lua("ls.lsp_expand([[" .. snip .. "]])")
629629

@@ -678,7 +678,7 @@ describe("Parser", function()
678678

679679
it("handles default correctly inside placeholder", function()
680680
ls_helpers.session_setup_luasnip()
681-
local snip = "${1: ${SELECT_DEDENT: a ${2:default}} }"
681+
local snip = "${1: ${LS_SELECT_DEDENT: a ${2:default}} }"
682682

683683
exec_lua("ls.lsp_expand([[" .. snip .. "]])")
684684

@@ -708,7 +708,7 @@ describe("Parser", function()
708708

709709
it("handles copy-source inside default.", function()
710710
ls_helpers.session_setup_luasnip()
711-
local snip = "${1: ${SELECT_DEDENT: a ${2:default} ${3:copied}}} $3"
711+
local snip = "${1: ${LS_SELECT_DEDENT: a ${2:default} ${3:copied}}} $3"
712712

713713
exec_lua("ls.lsp_expand([[" .. snip .. "]])")
714714

@@ -745,7 +745,7 @@ describe("Parser", function()
745745

746746
it("handles copy inside default", function()
747747
ls_helpers.session_setup_luasnip()
748-
local snip = "$1 ${2: ${SELECT_DEDENT: a ${3:default} $1} }"
748+
local snip = "$1 ${2: ${LS_SELECT_DEDENT: a ${3:default} $1} }"
749749

750750
-- indent, insert text, SELECT.
751751
exec_lua("ls.lsp_expand([[" .. snip .. "]])")

tests/unit/environ_spec.lua

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ describe("luasnip.util.environ", function()
1010
local Environ = require("luasnip.util.environ")
1111
%s
1212
13-
local env = Environ:new({0, 0})
13+
local env = Environ:new({pos={0, 0}, captures={}, trigger=""})
1414
local result = env["%s"]
1515
return #(result) > 0
1616
]=]):format(
@@ -30,7 +30,7 @@ describe("luasnip.util.environ", function()
3030
local Environ = require("luasnip.util.environ")
3131
%s
3232
33-
local env = Environ:new({0, 0})
33+
local env = Environ:new({pos={0, 0}, captures={}, trigger=""})
3434
return env["%s"]
3535
]=]):format(
3636
namespace_setup,
@@ -48,7 +48,7 @@ describe("luasnip.util.environ", function()
4848
([=[
4949
local Environ = require("luasnip.util.environ")
5050
%s
51-
local env = Environ:new({0, 0})
51+
local env = Environ:new({pos={0, 0}, captures={}, trigger=""})
5252
return env["%s"] == nil
5353
]=]):format(
5454
namespace_setup,
@@ -71,7 +71,7 @@ describe("luasnip.util.environ", function()
7171
([=[
7272
local Environ = require("luasnip.util.environ")
7373
%s
74-
local env = Environ:new({0, 0})
74+
local env = Environ:new({pos={0, 0}, captures={}, trigger=""})
7575
return rawget(env, "%s") ~= nil
7676
]=]):format(
7777
namespace_setup,
@@ -144,9 +144,16 @@ describe("luasnip.util.environ", function()
144144
false,
145145
"VAR"
146146
)
147+
check(
148+
"Init funtion old api",
149+
[[Environ.env_namespace("OLD", {init=function(pos) return {POS = table.concat(pos, ',')} end})]],
150+
"OLD_POS",
151+
true,
152+
"0,0"
153+
)
147154
check(
148155
"Init funtion",
149-
[[Environ.env_namespace("IN", {init=function(pos) return {POS = table.concat(pos, ',')} end})]],
156+
[[Environ.env_namespace("IN", {init=function(info) return {POS = table.concat(info.pos, ',')} end})]],
150157
"IN_POS",
151158
true,
152159
"0,0"
@@ -180,4 +187,26 @@ describe("luasnip.util.environ", function()
180187
"Environ with multiline_vars incorrect type",
181188
[[Environ.env_namespace("TES_T", {var={A='s', multiline_vars = 9 }})]]
182189
)
190+
191+
local function check_builtin(var_name, test)
192+
it("Test builtin " .. var_name, function()
193+
assert.is_true(
194+
exec_lua(
195+
([=[
196+
local Environ = require("luasnip.util.environ")
197+
local env = Environ:new({pos={0, 0}, captures={"one"}, trigger="trigg"})
198+
local result = env["%s"]
199+
local test = %s
200+
return test(result)
201+
]=]):format(
202+
var_name,
203+
test
204+
)
205+
)
206+
)
207+
end)
208+
end
209+
210+
check_builtin("LS_TRIGGER", [[function(r) return r == "trigg" end]])
211+
check_builtin("LS_CAPTURE_1", [[function(r) return r == "one" end]])
183212
end)

0 commit comments

Comments
 (0)