Sublime Forum

Snippet question [LaTeX]

#1

Hi everyone.

I am trying to translate some of these Vim snippets to Sublime ones for using LaTeX.

I don’t know Vim, so for the moment I prefer using Sublime which feels more comfortable.
I already have LaTeX Tools, but they are not still optimized as I would like.

Specifically, three questions:

  1. is it possibile to make text auto-expand? I mean, without hitting tab after typing the trigger? So I can type just the letters (e.g. !> to become --> without pressing tab).
    Maybe using other packages or plugins.

  2. is it possibile to have a snippet / package / plugin to make phat\hat{p}, or any other letters for instances?
    In Vim it’s
    snippet "([a-zA-Z])hat" "hat" riA \hat{!p snip.rv=match.group(1)} endsnippet

  3. similarly, is it possible to have v,.\vec{v} and v.,\vec{v} so that the order of , and . doesn’t mat­ter?
    The Vim script is
    snippet "(\\?\w+)(,\.|\.,)" "Vector postfix" riA \vec{'!p snip.rv=match.group(1)'} endsnippet

0 Likes

#2

You can do that via a normal key binding:

    { "keys": ["!", ">"], "command": "insert_snippet", "args": {
        "contents": "-->"
    }},

Depending on your use case you might need to apply a context to the binding to make it only apply in the right circumstances when you do something like this; otherwise the only way to type these two characters without the expansion is to force a delay between pressing them both.

For something like this you may need a plugin of some sort; snippets and completions trigger based on the text, but it’s a lookup like “this trigger means that expansion” and the trigger text isn’t available to the completion itself.

The selected text is available to snippets when they expand, so you could achieve something like this by selecting the text first and then triggering the command that would expand it, which may be a viable solution. This is how the default functionality to wrap text in a tag works, for example.

Taking that a step further you could create a macro that selects the previous character then triggers the expansion and then bind a key with a context that triggers it based on a regex, so that may work well also.

For a plugin, the plugin would trigger when pressing tab in the correct circumstances and the plugin could then grab text out of the buffer to expand it as desired. I’m pretty sure that I have written an example of that here on the forum but I can’t seem to find it at the moment. There may also be packages that allow that as well.

One of the contexts that you can apply to a key is that the text prior to the cursor matches a regex; so in that regard as long as you can come up with a way to expand the item using either of the above two options, you could apply a context that matches on regex to get it to expand to the same thing in both cases.

0 Likes

#3

I’m interested in trying this approach.

However, I don’t know how to achieve this part. Could you help me a bit further?

And this part, I’m really new to Sublime and writing this kind of code, I’ve just had some experience in school with Javascript and C, but never really used regex and personalised a text editor.

Thanks a lot for the precious help.

0 Likes

#4

Essentially the idea is that when you create a key binding, along with specifying the key you’re pressing and the command to execute, you can also provide a context that says in what situations your binding is active. Sublime has quite a few of these that you can use out of the box, and plugins and packages can provide their own as well. This video covers the topic in a little more detail (coincidentally it released today even though it’s been in the queue for a week, timing!).

Regular expressions are a big topic unto themselves, so I would recommend a google search for some beginner tutorials on that topic (this link is the first hit in Google for this).

Additionally to this, Sublime has a macro system that allows you to record and play back actions as well, though it’s important to note that it only records changes you’re making to the buffer directly (like typing or cursor movements, but not things like interacting with the Find panel and such).

So one solution to this particular question is that you can create a macro that assumes that the cursor and text are in a current state (like being at the end of phat) and performs the modifications you need, and then bind a key to execute that macro only when the condition is present.

You can use the items in the Tools menu to start and stop recording a macro as well as saving it to disk (which is important in this case). An example of that (slightly reformatted to be shorter here in the forum) is this:

[
	{
		"command": "move",
		"args": {"by": "characters", "forward": false },
	},
	{
		"command": "move",
		"args": {"by": "characters", "forward": false },
	},
	{
		"command": "move",
		"args": {"by": "characters", "forward": false },
	},
	{
		"command": "move",
		"args": {"by": "characters", "extend": true, "forward": false },
	},
	{
		"command": "cut",
	},
	{
		"command": "insert", "args": {"characters": "\\"},
	},
	{
		"command": "move",
		"args": {"by": "characters", "forward": true },
	},
	{
		"command": "move",
		"args": {"by": "characters", "forward": true },
	},
	{
		"command": "move",
		"args": {"by": "characters", "forward": true },
	},
	{
		"command": "insert_snippet",
		"args": {"contents": "{$0}"},
	},
	{
		"command": "paste"
	}
]

This moves the cursor left three characters, then left once more while selecting that character (here the p in phat, cuts that character out and inserts the \ character needed, then goes forward three characters and inserts {} before pasting what it cut. That sequence converts phat to \hat{p}.

To use this, use Packages > Browse Packages and find the User package, and then save it in there with any name you want as a sublime-macro file; in this example I saved it as hat.sublime-macro. You can also of course use the items in the Tools menu to record the steps yourself and save them that way.

Now that the macro is in place, you can create a key binding like this:

    { "keys": ["tab"], "command": "run_macro_file", "args": {
        "file": "res://Packages/User/hat.sublime-macro"
    }, "context": [
        { "key": "selector", "operator": "equal", "operand": "text.tex.latex" },
        { "key": "preceding_text", "operator": "regex_match", "operand": "[a-z]hat$" },
    ]},

So when the Tab key is pressed, execute the macro from above (adjust the filename as needed if you use a different name), but only do that when the current file is a latex file and when the text prior to the cursor is a lower case letter followed by hat. So phat becomes \hat{p}, that becomes \hat{t} and so on.

This is possible using the same mechanism as my first answer above, but with two key bindings (one for each of the two possible ways you’re typing this):

    { "keys": ["v", ",", "."], "command": "insert", "args": {
        "characters": "\\vec{v}"
    }, "context": [
        { "key": "selector", "operator": "equal", "operand": "text.tex.latex" },
    ]},

    { "keys": ["v", ".", ","], "command": "insert", "args": {
        "characters": "\\vec{v}"
    }, "context": [
        { "key": "selector", "operator": "equal", "operand": "text.tex.latex" },
    ]},

This is the same principle as above, only these have a context that makes them only trigger in Latex files (you can remove that part if you wish) since otherwise you lose the ability to type those keys in that sequence. Arguably that’s not entirely likely.

You could also do the \hat{p} example by binding "h", "a", "t" to the macro above, though that would definitely stop you from being able to type things like the word hat without unforseen consequences.

For reference purposes, the plugin that I spoke of in the previous answer can be found in the following post where another user was asking if it was possible to include the tab trigger in the completion. It’s not directly usable in your case, but it illustrates how a plugin could be used to manipulate the state of the buffer in combination with a key binding that has an appropriate context so ensure that it only triggers in the correct circumstances.

0 Likes