L3MON4D3 / LuaSnip

Snippet Engine for Neovim written in Lua.
Apache License 2.0
3.37k stars 240 forks source link

Don't enter select mode for insert node #1214

Open RyanGibb opened 2 months ago

RyanGibb commented 2 months ago

I want to change the last few characters if an insert node. It's possible to exit the default select mode, and navigate to the end of the insert node's static text, and edit there. But to be more ergonomic I was wondering if it would be possible to enter insert mode at the end of the static text by default?

L3MON4D3 commented 2 months ago

Mhmm, I haven't considered having to do this at all, so it's only possible in very roundabout ways.. what's your exact usecase? Maybe there's a different approach

RyanGibb commented 2 months ago

My exact use case is entering https://ledger-cli.org/ entries, which look something like this:https://ledger-cli.org/doc/ledger3.html#Example-Journal-File

I have this snippet to create an entry:

local ls = require('luasnip')
local s = ls.snippet
local f = ls.function_node
local t = ls.text_node
local i = ls.insert_node
local c = ls.choice_node
local sn = ls.snippet_node
local d = ls.dynamic_node

local function date_input()
    return os.date('%Y-%m-%d')
end

local function amount_spacing(args)
    local account_length = #args[1][1]
    local amount = args[2][1]
    if amount == '' then
        return ''
    end
    local desired_column = vim.g.ledger_align_at or 50
    local current_column = 2 + account_length + 2 -- 2 spaces after account
    local period_position = amount:find('%.') or (#amount + 1)
    local pre_period_length = period_position - 1
    local total_length = current_column + pre_period_length
    local spaces_needed = desired_column - total_length
    if spaces_needed < 0 then spaces_needed = 1 end
    return string.rep(' ', spaces_needed)
end

local function recursive_accounts()
    return sn(nil, {
        t({ '', '  ' }), i(1, 'Account'), f(amount_spacing, { 1, 2 }),
        c(2, {
            t(''),
            sn(nil, { i(1, '£') })
        }),
        c(3, {
            t(''),
            d(nil, recursive_accounts)
        })
    })
end

ls.add_snippets('all', {
    s('ledger', {
        i(1, date_input()), t(' '), i(2, 'Description'),
        c(3, {
            sn(nil, { t({ '', '  ; ' }), i(1, 'Comment') }),
            t(''),
        }),
        t({ '', '  ' }), i(4, 'Account'), f(amount_spacing, { 4, 5 }),
        c(5, {
            sn(nil, { i(1, '£') }),
            t(''),
        }),
        d(6, recursive_accounts),
        t({ '', '', '' }),
    }),
})

An example of where I often want to change the default text, but only slightly, is the date: often it's just a day or two off.

L3MON4D3 commented 2 months ago

Okay, maybe first, in case you're unaware: if you leave your sessions running for a long time (across multiple days) implementing "insert date of today" like this will generate wrong results; you'd generally want to get the date right as you expand, so replacing i(1, date_input()) (which will evaluate the date at the time the snippet is added, so most likely at the beginning of the session) with f(date_input) would do the trick in that case

Assuming that your usecase is actually that you have to just have a "today-adjacent"-date as a starting-point, I agree, it would be really useful to allow an alternative placement of the cursor after jumping. I think it may be feasible to implement this as an option to the insertNode, so we'd have something like i(1, "YYYY-MM-DD", {cursor="after"}) where cursor is one of "after","before","select" I don't think we depend on text actually being selected, but I'll have to double-check that.

RyanGibb commented 2 months ago

Okay, maybe first, in case you're unaware: if you leave your sessions running for a long time (across multiple days) implementing "insert date of today" like this will generate wrong results; you'd generally want to get the date right as you expand, so replacing i(1, date_input()) (which will evaluate the date at the time the snippet is added, so most likely at the beginning of the session) with f(date_input) would do the trick in that case

Ah, thanks for the tip! I totally missed that.

I think it may be feasible to implement this as an option to the insertNode, so we'd have something like i(1, "YYYY-MM-DD", {cursor="after"}) where cursor is one of "after","before","select"

That sounds perfect!