LuaSnip icon indicating copy to clipboard operation
LuaSnip copied to clipboard

Treesitter Postfix not working

Open ilhamfu opened this issue 2 years ago • 25 comments

Trying to make snippet for rust, but for some reason cannot match the call expression here is the snippet code

treesitter_postfix({
	trig = ".testing",
	matchTSNode = {
		query = [[(call_expression) @prefix]],
		query_lang = "rust",
	},
}, { t("hello") }),

whenever i try to use the snippet for example on piece of code like this

conn.interact(|conn|{todo!()})

instean replacing the code with "hello" it append it instead

ilhamfu avatar Nov 12 '23 08:11 ilhamfu

The entire match to the query should be replaced, so it seems like the query matches an empty string for some reason.. What does the ts-node-tree look like after the trigger is inserted (":TSPlaygroundToggle")?

L3MON4D3 avatar Nov 12 '23 11:11 L3MON4D3

you mean like this

          field_expression [12, 8] - [12, 42]
            value: call_expression [12, 8] - [12, 37]
              function: field_expression [12, 8] - [12, 21]
                value: identifier [12, 8] - [12, 12]
                field: field_identifier [12, 13] - [12, 21]
              arguments: arguments [12, 21] - [12, 37]
                closure_expression [12, 22] - [12, 36]
                  parameters: closure_parameters [12, 22] - [12, 28]
                    identifier [12, 23] - [12, 27]
                  body: macro_invocation [12, 29] - [12, 36]
                    macro: identifier [12, 29] - [12, 33]
                    token_tree [12, 34] - [12, 36]
                      unit_expression [12, 34] - [12, 36]
            field: field_identifier [12, 38] - [12, 42]

ilhamfu avatar Nov 12 '23 11:11 ilhamfu

Yup :+1: Just did a test on my side, and here it's working fine (ts_px_add just immediately adds the postfix-snippet, so should be the same as your code)

https://github.com/L3MON4D3/LuaSnip/assets/41961280/7427780e-e036-4f20-8e5c-700c408b7a9c

Not sure what things may be going wrong for you, if you can produce a MWE I can look into it some more

L3MON4D3 avatar Nov 12 '23 19:11 L3MON4D3

probably my config, i use lazyvim with custom tweaks, i think it break some stuff. i will try to look into it

ilhamfu avatar Nov 13 '23 05:11 ilhamfu

same here

IWANABETHATGUY avatar Nov 17 '23 16:11 IWANABETHATGUY

config


local treesitter_postfix = require("luasnip.extras.treesitter_postfix").treesitter_postfix
local postfix_builtin = require("luasnip.extras.treesitter_postfix").builtin

ls.add_snippets("javascript", {
  treesitter_postfix({
    trig = ".mv",
    matchTSNode = postfix_builtin.tsnode_matcher.find_topmost_types({
      "call_expression",
      "identifier"
    }),
  }, f(function(_, parent)
      print(parent.snippet.env.LS_TSMATCH)
      -- local node_content = table.concat(parent.snippet.env.LS_TSMATCH, '\n')
      -- local replaced_content = ("std::move(%s)"):format(node_content)
      -- return vim.split(ret_str, "\n", { trimempty = false })
    end))

})

record.webm

IWANABETHATGUY avatar Nov 17 '23 17:11 IWANABETHATGUY

sorry for late response. does adding the snippet using loaders.from_lua affect the result? the snippet is actually part of my project based snippet here is my snippets

local tsp = require("luasnip.extras.treesitter_postfix").treesitter_postfix

return {
	s(
		"otw-task-runner",
		fmt(
			[[
                pub(crate) async fn {}<Service, DbService, MsgService>(
                    service: &TaskRunnerInner<Service, DbService, MsgService>,
                    payload: {},
                ) -> anyhow::Result<()>
                where
                    Service: 'static + Send + Sync + TaskRunnerService,
                    DbService: 'static + Send + Sync + DatabaseService,
                    MsgService: 'static + Send + Sync + MessageService,
                {{
                    {}
                }}]],
			{
				i(1, "runner"),
				i(2, "Payload"),
				i(3, "todo!()"),
			}
		)
	),
	tsp({
		trig = ".inner",
		matchTSNode = {
			query = [[ 
    (struct_item) @prefix
    ]],
			query_lang = "rust",
		},
	}, {
		t("hlleo"),
	}),
}, {}

and the .inner snippet also showing up even if Treesitter query doesn't match up

ilhamfu avatar Nov 29 '23 03:11 ilhamfu

config

local treesitter_postfix = require("luasnip.extras.treesitter_postfix").treesitter_postfix
local postfix_builtin = require("luasnip.extras.treesitter_postfix").builtin

ls.add_snippets("javascript", {
  treesitter_postfix({
    trig = ".mv",
    matchTSNode = postfix_builtin.tsnode_matcher.find_topmost_types({
      "call_expression",
      "identifier"
    }),
  }, f(function(_, parent)
      print(parent.snippet.env.LS_TSMATCH)
      -- local node_content = table.concat(parent.snippet.env.LS_TSMATCH, '\n')
      -- local replaced_content = ("std::move(%s)"):format(node_content)
      -- return vim.split(ret_str, "\n", { trimempty = false })
    end))

})

the LS_TSMATCH return nil for some reason

ilhamfu avatar Nov 29 '23 03:11 ilhamfu

config

local treesitter_postfix = require("luasnip.extras.treesitter_postfix").treesitter_postfix
local postfix_builtin = require("luasnip.extras.treesitter_postfix").builtin

ls.add_snippets("javascript", {
  treesitter_postfix({
    trig = ".mv",
    matchTSNode = postfix_builtin.tsnode_matcher.find_topmost_types({
      "call_expression",
      "identifier"
    }),
  }, f(function(_, parent)
      print(parent.snippet.env.LS_TSMATCH)
      -- local node_content = table.concat(parent.snippet.env.LS_TSMATCH, '\n')
      -- local replaced_content = ("std::move(%s)"):format(node_content)
      -- return vim.split(ret_str, "\n", { trimempty = false })
    end))

})

2023.11.18.01.10.09.webm

The config works for me.

https://github.com/L3MON4D3/LuaSnip/assets/6359934/0a572f2d-96d4-4db2-a923-8ce0578803d7

Maybe something wrong in your ts parser?

TwIStOy avatar Nov 29 '23 08:11 TwIStOy

config

local treesitter_postfix = require("luasnip.extras.treesitter_postfix").treesitter_postfix
local postfix_builtin = require("luasnip.extras.treesitter_postfix").builtin

ls.add_snippets("javascript", {
  treesitter_postfix({
    trig = ".mv",
    matchTSNode = postfix_builtin.tsnode_matcher.find_topmost_types({
      "call_expression",
      "identifier"
    }),
  }, f(function(_, parent)
      print(parent.snippet.env.LS_TSMATCH)
      -- local node_content = table.concat(parent.snippet.env.LS_TSMATCH, '\n')
      -- local replaced_content = ("std::move(%s)"):format(node_content)
      -- return vim.split(ret_str, "\n", { trimempty = false })
    end))

})

2023.11.18.01.10.09.webm

The config works for me.

CleanShot.2023-11-29.at.16.43.17.mp4 Maybe something wrong in your ts parser?

What is your version of neovim?

IWANABETHATGUY avatar Nov 29 '23 09:11 IWANABETHATGUY

config

local treesitter_postfix = require("luasnip.extras.treesitter_postfix").treesitter_postfix
local postfix_builtin = require("luasnip.extras.treesitter_postfix").builtin

ls.add_snippets("javascript", {
  treesitter_postfix({
    trig = ".mv",
    matchTSNode = postfix_builtin.tsnode_matcher.find_topmost_types({
      "call_expression",
      "identifier"
    }),
  }, f(function(_, parent)
      print(parent.snippet.env.LS_TSMATCH)
      -- local node_content = table.concat(parent.snippet.env.LS_TSMATCH, '\n')
      -- local replaced_content = ("std::move(%s)"):format(node_content)
      -- return vim.split(ret_str, "\n", { trimempty = false })
    end))

})

2023.11.18.01.10.09.webm

The config works for me. CleanShot.2023-11-29.at.16.43.17.mp4 Maybe something wrong in your ts parser?

What is your version of neovim?

master

TwIStOy avatar Nov 29 '23 10:11 TwIStOy

same issue, parent.snippet.env.LS_TSMATCH is nil

yifan0414 avatar Feb 27 '24 11:02 yifan0414

I'm stuck here and can't move. image and cpu 100% here image

yifan0414 avatar Feb 27 '24 12:02 yifan0414

I took a look at this a little bit and found it fails for me in https://github.com/L3MON4D3/LuaSnip/blob/f3b3d3446bcbfa62d638b1903ff00a78b2b730a1/lua/luasnip/extras/treesitter_postfix.lua#L244 at check_node_exclude_pos

The values at this point are

end_row:96 == pos[1]:96
end_col:7 == pos[2]:4

Removing the check_node_exclude_pos makes parent.snippet.env.LS_TSMATCH contain data. But it contains the match with the postfix trigger. eg test/xx with /xx being the trigger. I assume the check at check_node_exclude_pos fails because the trigger was not correctly removed? Hence the 4 vs 7 comparison?

Also I get two callback to my function node. One with parent.snippet.env.LS_TSMATCH="$LS_TSMATCH" and the other with parent.snippet.env.LS_TSMATCH={ "test/xx" }. Not sure if this is normal.

hfn92 avatar Feb 27 '24 19:02 hfn92

this fixed it for me https://github.com/hfn92/LuaSnip/commit/9d1bf4a4fd7cd6c4d15d415d8e5b7a764e85d402 but not sure how much sense this makes ... and I still get the $LS_TSMATCH from the fake_expand on the first expand.

hfn92 avatar Mar 07 '24 15:03 hfn92

I'm stuck here and can't move. image and cpu 100% here image

can you try this #1145 see if the problem is solved

TwIStOy avatar Mar 21 '24 03:03 TwIStOy

@TwIStOy seem solved, but treesitter still unavailable image image image

I'm not sure if it's my own problem

yifan0414 avatar Mar 21 '24 04:03 yifan0414

i can't reproduce this on my machine. it seems like there's no captures can be found in the match. maybe you can use function node to show which captures are found

TwIStOy avatar Mar 21 '24 06:03 TwIStOy

@yifan0414 have tried my branch (https://github.com/hfn92/LuaSnip/tree/fix)? maybe it fixes it for you as well

hfn92 avatar Mar 21 '24 11:03 hfn92

@hfn92 yes, it fixes my problem!. But I have a question, why even if the capture conditions are not met, the snippet will still be displayed. If you try to complete with Enter, an error will be shown. However, if the capture conditions are met, it will work correctly. image image

yifan0414 avatar Mar 21 '24 12:03 yifan0414

@yifan0414 I don't know exactly what happens, I was just playing around to see if I can fix this issue for me :sweat_smile: I don't know exactly whats going on but in first callback when resolving, 'LS_TSMATCH' is nil. I have a check in my callback to verify that LS_TSMATCH is not nil. This solves this error for me.

hfn92 avatar Mar 21 '24 12:03 hfn92

@yifan0414 Can you try to add reparseBuffer = "live" to your postfix snippet? This will remove trig first, then reparse the buffer, then try to expand the snippet. And what's your neovim and nvim-treesitter version?

TwIStOy avatar Mar 21 '24 14:03 TwIStOy

@hfn92 The LS_TSMATCH must not contains the trig. So only these nodes before current cursor are considered. Remove exclude current cursor check seems not a good idea. That may cause LS_TSMATCH is nil in callbacks.

TwIStOy avatar Mar 21 '24 15:03 TwIStOy

@TwIStOy The nil LS_TSMATCH was being triggered from some fake_expand function, it only happens once.

I'm not claiming I know whats going here, but check_node_exclude_pos always failed for me because it compared length of node + trigger with length of node \w0 trigger. Removing the trigger fixed this for me

hfn92 avatar Mar 21 '24 16:03 hfn92

@TwIStOy reparseBuffer = "live" fixes it for me. Thanks!

hfn92 avatar Mar 21 '24 16:03 hfn92

@TwIStOy The nil LS_TSMATCH was being triggered from some fake_expand function, it only happens once.

Oh hey, fake_expand is used for generating docstrings for nvim-cmp, if you want to handle that gracefully, make sure to add a codepath that detects this (ie. LS_TSMATCH == nil) and returns some sane values (we can't provide them when generating docstrings, unfortunately)

L3MON4D3 avatar Apr 01 '24 13:04 L3MON4D3

@TwIStOy The nil LS_TSMATCH was being triggered from some fake_expand function, it only happens once.

Oh hey, fake_expand is used for generating docstrings for nvim-cmp, if you want to handle that gracefully, make sure to add a codepath that detects this (ie. LS_TSMATCH == nil) and returns some sane values (we can't provide them when generating docstrings, unfortunately)

Ah I see, thank you!

hfn92 avatar Apr 01 '24 18:04 hfn92