Textadept and Snippets

A guide on efficiency(being lazy).

You may have heard in passing about snippets. You may have even used them in your previous editor. Still, once you learn Textadept’s way of making a snippet, you may just absolutely hate how other text editors practice the same functionality.

Before I ever touched the grace that is Textadept, I was once a Sublime Text 2 user. I don’t know if you ever seen how a snippet would look like in Sublime Text 2, but either way, let me give you an example of what a for snippet would look like for rust under Sublime Text 2:

Kind of weird, but not too bad. Everything is under XML with the actual content of the snippet written in a raw string. The tabtrigger is what would initiate the snippet, when pressing tab, and the scope being what lexer to use for the snippet. The pieces under ${number:name} are what you would replace or leave with the original name as you keep tapping tab to walk through the snippet. The numbers are the order of when that section would be triggered for editing. The weird part in the snippet is how a plugin/module for Sublime Text 2 would normally be written in python and configurations under json, not in xml. The xml piece is actually for other types of configurations where json isn’t used for whatever reason.

Now let me show you what the same for loop snippet would be on a Textadept module for rust:

snippets.rust = {
['for'] = 'for %1(i) in %2(iterator){\n\t%0\n}'
}

The sub-table rust, under the main table snippets, identifies the lexer. The key for would be the tabtrigger, as in sublime text, and the string would be the actual snippet. The %number(name) would follow the same rules as in Sublime Text. Also, note that you can use special characters to identify a tab or newspace instead of actually doing the spacing like on Sublime Text. Now, I don’t know about you, but being able to do what took 10 lines concatenated into 3 is one hell of difference. Oh and since everything of modules/plugins is written in Lua on Textadept, the same goes for snippets. No XML/JSON/Python hell for you.

It gets better. What if you wanted to do multiple snippets under Sublime Text? Well, the actual gist given above is actually named a certain way with its own extension. You would have to write a new file with the same structure for each and EVERY snippet you would want to make. I’m a person who tends to make about 30+ snippets for each of the languages I tend to venture through… Not very productive doing snippets on Sublime Text.

In Textadept however, you can simply add another key to the table snippets.rust with the snippet you want. You are now done. Let me show you another example to express the ease:

snippets.rust = {
['for'] = 'for %1(i) in %2(iterator){\n\t%0\n}',
['forr'] = 'for %1(i) in range(%2(0), %3(10)) {\n\t%0\n}'
}

Oh, but it gets even better than simple table additions for snippets. Sometimes, you may want your snippet to have an option that you may use but not all the time. What you would do to achieve such a snippet task is put the piece of code nested under another piece of %number(). Let me show what I mean:

snippets.rust = {
fn = “fn %1(name)(%2(&self)) %3(-> %4(type) ){\n\t%0\n}”,
}

Here you can see that the snippet call is done using the fn. The fn follows normally, however once you get up to %3 trigger, you should see that it contains a nested tab trigger. If you would want to use that tab trigger, all you would have to do is press tab and the trigger would initialize. However, if you didn’t want to use the trigger, when you reach %3, you would press backspace once and continue on your merry way with the next trigger. What this means is that you can can potentially ignore pieces of tab triggers inside tab triggers. Inception here we come! (I’ll walk myself out…)

Before we venture to the last of the snippets example, let me give a little insight. Only Lua keywords require the full keystring references like [‘for’] or [‘if’]. You can write without the full keystring as shown above with fn when the tab trigger is not a Lua keyword or function. Though, if you wanted to add one snippet call from another configuration but didn’t want to replace the current snippet table for your lexer, then you can do a direct call like `snippets.rust[‘keyword’]`.

Anyway, here is one last example to show how crazy things can get:

snippets.rust['gfn'] = “fn %1(name)<%2(T)>(%3(%4(param): %2)) %5(-> %6(%2)) {\n\t%0\n}”

Ok, there’s quite a lot of happening here. I will try to explain as best of my abilities to do so. The first piece is the call. I’m using the direct initialization without replacing the table that holds all the other snippets I may have on a separate configuration for that lexer. In other words, that’s the snippets.rust[‘gfn’] piece. Next, on trigger %3 I have two nested triggers; %4 and %2. These triggers would only initialize when I don’t press backspace for %3. At the same time, notice that %2 actually is provided three times on the snippet, on %2(T), %3, and %5. The first one with %2(T) is actually the definition of the trigger. Once I put say f64 on %2, all other %2 would be f64 for the trigger without me having to keep placing the type each time. The last trigger %5 would be the same trigger I used on the fn snippet nested trigger. Finally you might’ve noticed how I used %0 on all the snippet examples shown above. This trigger is only initiated once you finish walking through all the other triggers in the snippet. It’s the powerhouse that makes the whole snippet smooth for quick coding on Textadept.

Thanks for reading and I hope what was explained here can help you use Textadept even more efficiently with snippet and cry in your sleep if you used Sublime Text to do the same thing. (I still wake up in the middle of night cause of it…)

Finally, if you are Rustacean and want to use my snippets, here is the link to the Textadept module of love for Rust I been perfecting: