Want to write a snippet plugin and had a couple of beginner questions

So, I installed kak-snippets and was relatively impressed after I modified the regex’s for the base language a bit(to allow for any amount of whitespaces proceeding the syntax) as well as trailing whitespace(so donut_flag=false) doesn’t trigger expansion. this did have the issue of the inserted code not respecting indentation, but that could be solved by using lookbehind as opposed to ^(\s*)D...).

It kind of gave me an idea how much coding could be sped up simply by having a fairly exclusive set of snippets for the base language, and I had a bunch of ideas on how to improve on it but I was thinking I’d start from scratch, mainly because if I can make it something cross-editor then that means a larger userbase(and hopefully more contributors)

I’m still really new to kakoune, as well as trying to write code intended to be used by other people, and currently I’m still trying to wrap my head around the syntax. anyway here are my questions

  1. How is the execution of plugins being handled? in the case of kak-snippets is this being executed only as called and the entire directory structure being reparsed on each call or is it keeping some buffer of relevant regexes in memory tied to that kakoune session?

  2. as far as performance is concerned, is a directory style structure containing regexes the best approach to take or are there better solutions for snippets?
    NOTE: I actually was planning on reusing this, but creating a tmp ram directory for storing snippets relevant to the current buffer, partially because disk reads, partially because the relevant snippets were likely to change at the users discretion. I mainly wanted to know if there was a better alternative.

  3. is the buffer being passed to the plugin limited to the current line? mainly curious because ideally else if should only be triggered if proceeded by }\s or }\n and I would rather have both options for users who need to adhere to a particular convention.

  4. Not just limited to kak but when is it generally acceptable to break from a standard convention, such as the one for lsps or in this case snippets? While I plan for the majority of my snippets will adhere to the current standard convention, my current idea was to have a subset of them will have features not available within those constraints (such as attached commands to be executed, loading a different snippet directory into the current snippet buffer or generating values).

somewhat related but not entirely… is there a good way to edit a directory as if it were a file? renaming regex based directories is a major PIA

I’m not sure if this is exactly what you’re looking for, but moreutils includes a tool called vidir that takes a directory name and opens $EDITOR with a buffer that looks like:

1       file1.c
2       file2.py
3       readme.md

You can delete a file by deleting its line, you can rename a file by editing the filename field, and if you switch two filenames around it’s smart enough to rename the first one to a temporary file, rename the second file to the first name, then rename the temporary file to the second name, so no data is lost.

2 Likes

If you are going to make a snippets plugin I encourage you to take a look at

I’d love if Kakoune had a similar plugin. But of course, it’s very complex.

Or https://github.com/joaotavora/yasnippet. It also features many interesting ideas.

After writing my own snippet plugin for Vim, I’ve realized that for me the main feature of snippet plugin is being able to edit nested snippets. Because when I write code, LSP provides function call parameters as a snippets, and if I call function in the function I nest snippets and can escape those with single key. Unfortunately I have no idea how to implement this feature without using complex environment defined in some language that will keep an eye on what’s user is doing with snippets, thus will have some state.

Other must have features of a snippet manager are:

  • usage of standardized syntax, so it is easy to port snippets from other frameworks, and tools that generate those as you type, such as LSP. The most widespread now I believe is this
  • integration with completion system, e.g. being able what snippets are available and what to expect from each.
  • speed, though Kakoune doesn’t need an emulation of mirrors, thanks to multiple cursors and phantom selections, so this should not be a problem.

I’m not sure if you’re talking about my kakoune-snippets plugin, but if so:

  1. The directory structure is only parsed once at startup, and any time you manually call snippets-directory-reload. The core snippets.kak plugin keeps all the relevant data within memory.
  2. The directory structure doesn’t really matter much because of 1. To quickly check if any snippet matches, anytime a character inserted, a single regex containing an OR of all triggers is tested.
  3. It’s not limited to the current line, although there is an (aribtrary) limit of 20 characters before the last one.

Thanks for all your feedback. I’m still kinda wrapping my head around how to go about designing it.

Is there any situation in which a snippet wouldn’t be triggered at the start of the line(not counting indentation)

Is it possible to pass the current line number to a script/executable? I was thinking that stuff like auto completing function documentation might be done by manipulating the current line, the current indentation, and knowing the size of a snippet prior to text insertion. For every line added between snippet start and snippet end, you could update the snippet end value.

Is there any limit on buffers? I want to have auto completed snippets separate from tag completed snippets(mainly to use auto complete for language grammar and tab complete for stuff like file to list)

I’m not sure, but some snippet managers allow to define trigger in such a way that it explicitly states that snippet must be expanded only on the beginning of the line without any indentation, and perhaps the opposite feature is possible.

Ah, I was mainly curious because for the auto expansion it would make sense to remove the regex from the snippet name and have the plugin check different cases(mainly if this is the first entry from line start) you could keep all the snippets in the same buffer but have the various cases sorted and separated by a delimiter of some sort… Such as all the snippets that have to be at line start. Followed by all the snippets that require either a preceding ((}\n\s*)|(^\s*}\s) followed by all the snippets that have to be the first entry(\s*), this way the entire buffer doesn’t have to be parsed, just the relevant snippets. While it shouldn’t matter much in the grand scheme of things it could slow things down if you have an arbitrarily large number of snippets relevant to the current file.

Also I think it would be better to have 2 (or technically 4 if you count defaults as separate from contextually relevant) types of snippets, and just have special instructions separate from the snippet itself to be executed if a particular snippet is loaded(or alternatively have a special set of instructions stored alongside the snippet if they are being parsed from something like a TOML or JSON file).

That way all snippets can be written in a way to be universal, and the special instructions to be executed can be variable depending on the current editor (if the goal is something truly editor agnostic)

I really want to write this in rust, partially because I’m trying to learn rust, partially because of efficiency for both iteration and regexes. Rust’s regex engine doesn’t have look behind capability, which I realized isn’t a good fit anyway given that look behind can only be set to a finite number of characters (rather than something like from beginning of the line) but from what I read is faster when for cases where this isn’t necessary.

Why put snippets into buffer? If you will use external language, such as Perl or Python or Rust (which I think is the only way to have comprehensive snippet support) you can store options in key snippet map, and just request if there is such a key, and if there is expand. I think using buffer for such task is additional complexity and error prone, because you’ll have to separate snippets and determine edges in some way.

Is there a benefit in storing the possible keys inside a Kakoune variable instead of inside a collection in a remote service? Now that I’m saying it I’m realizing I don’t know how do these things interact with the lsp. However, I suppose being able to propose snippets depending on the file and position is more general.

Just so I understand you correctly you mean storing the snippets inside the program itself and running it as a daemon right? it definitely makes more sense to do that, honestly I wasn’t sure if people would prefer it to be an executable called as needed(thus leaving storage to kakoune/the editor in question) or for it to be a daemon that takes care of everything related to the task and the editor just passes information and follows whatever instruction the daemon provides.

Plus I was kind of wary of what to do if the user has say 7 different editors open at once… would it be better to have one daemon that can handle multiple sessions or to have a single daemon per session, the former sounds like a speed trap, the latter sounds like a memory hog.

now that I think about it, as far as the daemon thing goes, you might be able to have the best of both worlds. I’m a huge fan of the idea around hexagonal design, and this could be a situation where it makes sense to have a single daemon that handles storage, and then a smaller set of task related logic that is either run as a straight executable, or a smaller daemon attached to each session

that’s one way. another is to use str-to-str map in Kakoune and access it via external program

I wasn’t aware kakoune had a map. What all options for data storage does kakoune have?

:help options