Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Is it possible to match text after cursor? #851

Closed
Bekaboo opened this issue Mar 29, 2023 · 9 comments
Closed

[Feature] Is it possible to match text after cursor? #851

Bekaboo opened this issue Mar 29, 2023 · 9 comments

Comments

@Bekaboo
Copy link
Contributor

Bekaboo commented Mar 29, 2023

First thanks for making this plugin, it works really fast and smooth and boosts
my speed in neovim, especially for latex files.

I want to make a snippet for quickly creating math environments. In latex there
there are inline maths and display maths:

Snippet for inline math is relatively simple:

s({ trig = '$$', snippetType = 'autosnippet' } , { t '$', i(0), t '$' })

In the snippet above, I can put my cursor in the middle of the dollars after
inserting two consecutive dollar signs.

However, for display math, things get tricky, what I want to achieve is:

  1. I first type two consecutive dollar signs, the snippet for inline math is
    triggered:

    $|$
    
  2. Then I press $ again in between the two dollars, the snippet for display
    math is triggered:

    $$
         |
    $$
    

    This requires the snippet to be able to detect texts after the cursor
    and remove some of them after the snippet is expanded if needed.

    I looked at the documentation carefully, but I didn't find a way to do this.
    Is it possible to do this with the current version of the plugin?

Thanks in advance! :)

@L3MON4D3
Copy link
Owner

Whew, that's pretty specific, but also a cool idea :D

You could make use of external_update_dynamic_node, and initially insert the inline-math-snippet, and, on update, insert the display-math snippet.
You'd have to then somehow trigger update on $ in INSERT, either via a binding (this is a bit unfortunate, since it requires either a global keybind (which inserts $ if you're not inside the snippet) or you'd have to set/remove the keybind on enter/leave, which might end up a bit finnicky) or by including TextChangedI in your update_events, and just monitoring the inserted text for $ (this would require #838, for finding the node whose text you want to query)

Not trivial, unfortunately :/

@Bekaboo
Copy link
Contributor Author

Bekaboo commented Mar 29, 2023

Thanks for your suggestion, actually I have come up with an ugly but working solution during the time:

s({ trig = '$$', snippetType = 'autosnippet' } , {
  d(1, function()
    local line = api.nvim_get_current_line()
    local col = api.nvim_win_get_cursor(0)[2]
    if line:sub(col, col) == '$' then
      api.nvim_set_current_line(line:sub(1, col-1) .. line:sub(col+1))
      return sn(nil, { t { '$$', '' }, i(1), t { '', '$$' } })
    else
      return sn(nil, { t '$', i(1), t '$' })
    end
  end),
})

I also want to report a bug here that if I set the jump index of the snippet above to 0, I get an error from LuaSnip saying:

Error detected while processing TextChangedI Autocommands for "*":
Error executing lua callback: ...local/share/nvim/lazy/LuaSnip/lua/luasnip/nodes/util.lua:24: attempt to get length of local 'position_so_far' (a nil value)
stack traceback:
        ...local/share/nvim/lazy/LuaSnip/lua/luasnip/nodes/util.lua:24: in function 'init_insert_positions'
        ...hare/nvim/lazy/LuaSnip/lua/luasnip/nodes/dynamicNode.lua:175: in function 'update'
        ...al/share/nvim/lazy/LuaSnip/lua/luasnip/nodes/snippet.lua:812: in function 'update'
        ...al/share/nvim/lazy/LuaSnip/lua/luasnip/nodes/snippet.lua:503: in function 'trigger_expand'
        ...zeng/.local/share/nvim/lazy/LuaSnip/lua/luasnip/init.lua:243: in function 'snip_expand'
        ...zeng/.local/share/nvim/lazy/LuaSnip/lua/luasnip/init.lua:328: in function 'expand_auto'
        ...ng/.local/share/nvim/lazy/LuaSnip/lua/luasnip/config.lua:264: in function <...ng/.local/share/nvim/lazy/LuaSnip/lua/luasnip/config.lua:262>

the snippet that triggers the bug is (just change the jump index from 1 to 0):

s({ trig = '$$', snippetType = 'autosnippet' } , {
  d(0, function()
    local line = api.nvim_get_current_line()
    local col = api.nvim_win_get_cursor(0)[2]
    if line:sub(col, col) == '$' then
      api.nvim_set_current_line(line:sub(1, col-1) .. line:sub(col+1))
      return sn(nil, { t { '$$', '' }, i(0), t { '', '$$' } })
    else
      return sn(nil, { t '$', i(0), t '$' })
    end
  end),
})

Can you reproduce it?

EDIT: remove unrelated lines.
EDIT: typo

@leiserfg
Copy link
Contributor

leiserfg commented Mar 29, 2023

For this specific case is not better to use a choice node alternating between an input and an input surrounded by two texts (with the $ and the end of line) ?

@Bekaboo
Copy link
Contributor Author

Bekaboo commented Mar 29, 2023

@leiserfg That is a good idea too, thanks for your suggestion.

@leiserfg
Copy link
Contributor

Something like this should work:

    s({ trig = "$$", snippetType = "autosnippet" }, {
      t "$",
      c(1, {
        i(1),
        sn(1, {
          t { "$", "" },
          i(1),
          t { "", "$" },
        }),
      }),
      t "$",
    }),

@Bekaboo
Copy link
Contributor Author

Bekaboo commented Mar 29, 2023

@leiserfg Thanks for the snippet, but I think I prefer the way that does not use a choice node. If I use a choice node, for inserting a display math, I have press $$<C-n> instead of $$$, which feels more natural to me.

The problem here is that I cannot set the jump index of the dynamic node and the insert node inside it to 0. Hopefully it can be fixed someday.

@L3MON4D3
Copy link
Owner

For this specific case is not better to use a choice node alternating between an input and an input surrounded by two texts (with the $ and the end of line) ?

Talk about not seeing the forest for the trees xD
This solution is much more elegant👍👍

@L3MON4D3
Copy link
Owner

Thanks for your suggestion, actually I have come up with an ugly but working solution during the time:

s({ trig = '$$', snippetType = 'autosnippet' } , {
  d(1, function()
    local line = api.nvim_get_current_line()
    local col = api.nvim_win_get_cursor(0)[2]
    if line:sub(col, col) == '$' then
      api.nvim_set_current_line(line:sub(1, col-1) .. line:sub(col+1))
      return sn(nil, { t { '$$', '' }, i(1), t { '', '$$' } })
    else
      return sn(nil, { t '$', i(1), t '$' })
    end
  end),
})

I also want to report a bug here that if I set the jump index of the snippet above to 0, I get an error from LuaSnip saying:

Error detected while processing TextChangedI Autocommands for "*":
Error executing lua callback: ...local/share/nvim/lazy/LuaSnip/lua/luasnip/nodes/util.lua:24: attempt to get length of local 'position_so_far' (a nil value)
stack traceback:
        ...local/share/nvim/lazy/LuaSnip/lua/luasnip/nodes/util.lua:24: in function 'init_insert_positions'
        ...hare/nvim/lazy/LuaSnip/lua/luasnip/nodes/dynamicNode.lua:175: in function 'update'
        ...al/share/nvim/lazy/LuaSnip/lua/luasnip/nodes/snippet.lua:812: in function 'update'
        ...al/share/nvim/lazy/LuaSnip/lua/luasnip/nodes/snippet.lua:503: in function 'trigger_expand'
        ...zeng/.local/share/nvim/lazy/LuaSnip/lua/luasnip/init.lua:243: in function 'snip_expand'
        ...zeng/.local/share/nvim/lazy/LuaSnip/lua/luasnip/init.lua:328: in function 'expand_auto'
        ...ng/.local/share/nvim/lazy/LuaSnip/lua/luasnip/config.lua:264: in function <...ng/.local/share/nvim/lazy/LuaSnip/lua/luasnip/config.lua:262>

the snippet that triggers the bug is (just change the jump index from 1 to 0):

s({ trig = '$$', snippetType = 'autosnippet' } , {
  d(0, function()
    local line = api.nvim_get_current_line()
    local col = api.nvim_win_get_cursor(0)[2]
    if line:sub(col, col) == '$' then
      api.nvim_set_current_line(line:sub(1, col-1) .. line:sub(col+1))
      return sn(nil, { t { '$$', '' }, i(0), t { '', '$$' } })
    else
      return sn(nil, { t '$', i(0), t '$' })
    end
  end),
})

Can you reproduce it?

EDIT: remove unrelated lines. EDIT: typo

Ah yeah the 0-jump-index can only be occupied by an insertNode, you'll have to live with that limitation, unfortunately :/

@Bekaboo
Copy link
Contributor Author

Bekaboo commented Mar 30, 2023

@L3MON4D3 Oh I forget that only insert nodes can have jump index 0, please forgive my ignorance!

For future readers that come across this issue, an ugly (but working) solution is:

    s({
      trig = '$',
      condition = function()
        local line = api.nvim_get_current_line()
        local col = api.nvim_win_get_cursor(0)[2]
        return line:sub(col + 1, col + 1) == '$'
      end,
    }, { t({ '$', '' }), ifn(1), i(0), t({ '', '$' }) })
    s(
      { trig = '$$', priority = 999 },
      { t('$'), i(0), t('$') }
    )

the snippet above will not put a final jump destination after expanding the snippet, which is exactly what I want.

@Bekaboo Bekaboo closed this as completed Mar 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants