Skip to content

[Qustion] How to get correct current node position using get_buf_position in nested snippets? #747

@Bekaboo

Description

@Bekaboo

Question:
I want to map <Tab> in such a way that it performs jump(1)only when the cursor is at the end of the current snippet node, take the following snippet as an example:

s({ trig = '//' }, { t '\\frac{', i(1), t '}{', i(2), t '}' })

what it looks like after expanding the snippet and inserting some text in i(1):

\frac{abcd + (abcd|)}{}

where | indicates the position of the cursor.

In the situation shown above, pressing <Tab> will not trigger jump(1) but instead calls a "fallback" function. The fallback function will, for example, moves the cursor out of the brackets if possible, like this:

\frac{abcd + (abcd)|}{}

now pressing <Tab> will trigger jump(1) since the cursor is at the end of current node:

\frac{abcd + (abcd)}{|}

I (kind of) achieved this with the following config (I manage the behavior of <Tab> in nvim-cmp config):

local cmp = require('cmp')
local luasnip = require('luasnip')
cmp.setup({
    -- ....
    mapping = {
        ['<Tab>'] = cmp.mapping(function(fallback)
          if vim.fn.mode() == 'i' then
            if luasnip.expandable() then
              luasnip.expand()
            elseif luasnip.jumpable(1) then
              local session = require('luasnip.session')
              local current = session.current_nodes[vim.api.nvim_get_current_buf()]
              local _, current_end = current:get_buf_position()
              current_end[1] = current_end[1] + 1 -- (1, 0) indexed
              local cursor = vim.api.nvim_win_get_cursor(0)
              vim.notify('current_end: ' .. vim.inspect(current_end) .. ' cursor: ' .. vim.inspect(cursor))
              if current_end[1] == cursor[1] and current_end[2] == cursor[2] then
                luasnip.jump(1)
              else
                fallback()
              end
            else
              fallback()
            end
          end
        end, { 'i', 'c' }),
    }
    -- ....
})

the notify in the mapping serves for debug purpose only.

The problem is, when I'm inside a nested node, i.e. a snippet triggered inside another snippet, the position of
the end of the current node I get is incorrect. For instance, assume we have another snippet:

s({ trig = '**' }, { t '\\cdot ' })

What it looks like after triggering this snippet inside the first snippet given above with some text inserted after:

\frac{abcd \cdot abcd|}{}

in this case, the current_end I get is the end of \cdot instead of the index before the closing curly braces, which is the end of the insert node.

here is a short video demonstrating the problem, notice the messages in the command line:

simplescreenrecorder-2023-01-27_11.11.16.mp4

Any help is appreciated!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions