garbas/vim-snipmate

trigger on naïve reverse search

Closed this issue · 3 comments

as is, it seems there's some sort of tokenisation / syntax awareness involved when parsing triggers, but it would be nice here to ignore all that and trigger from a raw reverse character search instead

#180 seems a similar issue. i write a lot of latex, and there are times when i want to expand a snippet while in the middle of writing a word or so. say i want to write incredible, with an emph. i want inem<Tab> to expand to in\emph{${1:${VISUAL:text}}}${0}, but instead nothing happens. similarly, .5tw should become .5\textwidth, or sentence end... sentence end\dots (which works, but fails if both .. and ... are defined)

is there any reason this couldn't be made into a setting?

@shmibs I want to make sure I understand your request here before I make any statements on feasibility.

Right now, SnipMate will break the WORD before the cursor on non-word characters (/\W/), and then sort of build up possible triggers from the cursor backwards until it either runs out of possibilities or it finds a valid trigger.

In a case like inem<tab> triggering on em, how are you envisioning that SnipMate should determine what the possible triggers are? Should it try every character combination?

I want to be clear on this because the current process takes time. I think there's room for optimization in the code still, but it's not fast.

This does raise the question of what constitutes a valid trigger. As I said, right now just about anything is valid (which leads to issues like #65). I've thought about solving this by having valid triggers follow the same rules as abbreviations, but that would break a lot of existing snippets in just honza/vim-snippets alone.

i've very little idea of how vimscript works, but in another language the first instinct for what i'm imagining would be to avoid any type of word segmentation etc and instead build in ram a tree of sparse hashes or so for a deterministic parser.

so if sub triggers a snippet then i would inject it into this structure so a finite-state automaton, reverse searching from the current cursor position, would see b→u→s (trigger state). and, if there was a superstring snippet like ssub, it would take preference, with the parser looking for a trailing (actually leading) s before accepting sub.

this seems like it shouldn't be difficult, but again i have no idea if there's some reason vim couldn't manage it (e.g. if you're using some restrictive completion built-in?)

edit: and the idea would be from there to either toggle between this "naïve" mode and one that requires there be a word-break after (really before) the snippet, or else make the "required leading chars" configurable or so, so if someone wants em to only trigger at the start of a line or after a space character, that would be easy too, and i could just leave that set empty to require no wordbreak.

@shmibs I'll be honest. I still don't fully understand your last post. I don't see where a finite state automaton fits in SnipMate. I don't see what a tree should be built out of. All my attempts to understand have me stopping immediately due to performance constraints.

SnipMate currently doesn't do anything unless you're either in a snippet or trying to trigger a snippet, and honestly even that is kind of slow. Every potential trigger has to be checked against all snippets available, and SnipMate regularly rereads files so that snippets are autoloaded. Any sort of beforehand computation would need to completely redone when just moving the cursor up or down a line. I'm sorry, but I don't so how you're suggesting I implement what you want without also causing a significant performance impact on Vim usage in general.

Having said that, I just pushed a feature in c318076 that could theoretically be used to do what you want. The commit would allow users to modify the lookups SnipMate performs before actually triggering anything. I know you said you're not very familiar with VimL, but you clearly understand your idea better than I do. So if you can spend some time learning VimL, you can create a function that's called when one of these autocommands execute, and your function can give SnipMate those lookups.

Here's some basic mockup code:

" We're suing the Pre here because I expect this will be time intensive and we won't want to waste time with SnipMate's normal lookups
au User SnipLookupPre call ShmibsFunc()

function! ShmibsFunc() abort
    let b:snip_lookups = []
    " This is where you'd determine if you want 'sub' or 'ssub' or 'tem' or what have you. b:snip_word is the WORD before the cursor so you can use that
    " For each one you actually want tried, add it to the list. For example:
    call append(ret, 'sub')
    call append(ret, 'ssub')
    " The list is already available to SnipMate so nothing else needs to be done
endfunction

Now I'm going to ahead and mark this closed. If you want to have further discussion about how SnipMate determines potential triggers, I'd be happy to do that within this issue. If you're having trouble with the autocommand itself though, I'd prefer a new issue be created.

Thank you!