Sublime Forum

Snippet - wrap current line or selection

#1

Hello I want to create shortcut for quicker typing headlines. Now my keybind look like this:
{"keys": ["alt+shift+h","alt+shift+1"], "command": "insert_snippet", "args": {"contents": "<h1>${0:$SELECTION}</h1>"} },

This works well if i have selected some text. I want that wrap current line if I haven’t selected text. Is that possible?
I was looked at internet for something like ${0:$SELECTION:OR:LINE} but I cant find that. Is there such a thing?

0 Likes

#2

This is possible, but it requires a bit more setup work. There’s no shortcut for having a snippet wrap the current line without having the text selected, so you need a second key binding that knows how to carry out additional actions first.

First, you need to create a sublime-macro file that does the work of selecting the current line for you followed by inserting your snippet. One way to do that is via the macro recorder that’s built in, but for expediency you can also save the following text into a file in your User package:

[
  {
    "command": "expand_selection",
    "args": {"to": "line"}
  },
  {
    "command": "move",
    "args": {"by": "characters", "extend": true, "forward": false}
  },
  {
    "command": "insert_snippet",
    "args": {"contents": "<h1>${0:$SELECTION}</h1>"}
  }
]

The User package can be found by using Preferences: Browse Packages from the command palette or main menu. You want to save the file in the User folder you find there as a sublime-macro file. The name you give it is not important, but you need to remember it. Here I’ve named my file wrap_line_in_h1.sublime-macro.

This macro will expand the selection on all lines with a cursor out to be the full line, and then it “backs” the selection up one because by default this command will literally select the whole line, which includes the newline that ends the line; I’m guessing you don’t want that.

Once that’s done, it executes insert_snippet as in your binding, but here it knows explicitly that it needs to wrap the selection because it just selected something.

To use this, you need the following two key bindings:

    { "keys": ["alt+shift+h", "alt+shift+1"], "command": "insert_snippet",
      "args": {
        "contents": "<h1>${0:$SELECTION}</h1>"
      }
    },

    { "keys": ["alt+shift+h", "alt+shift+1"], "command": "run_macro_file",
      "args": {
            "file": "res://Packages/User/wrap_line_in_h1.sublime-macro"
      },
      "context": [
          { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
      ],
    },

Both of these bindings have the same keys set, but the second one has a context on it that makes it apply only when the selection is currently empty (i.e. there is nothing selected); the first one is just the binding you outlined in your question.

The one with the context executes the macro you created above, so change the file argument if you named the file something different than I did here.

It’s important that the bindings be in your file in this particular order; Sublime effectively looks “bottom-up” for bindings that match a key and uses the first one it finds that applies to the current situation, so the one with the context needs to come second in the file so that Sublime will use it when the selection is not empty.

For more details on what exactly is going on here (should you be interested in that), I have a video covering macros in Sublime Text as well as how contexts in key bindings work.

1 Like

#3

Thank you for your help and your time. I like your youtube channel. I suppose that I need the one macro file for each keybind (h1,h2,h3,h4). That there is no way how to use only one super macro-file.

BTW, have that these solutions some impact for SublimeText3 performance and start rate?

0 Likes

#4

Not directly, no. However, you can use the same two key bindings as above but with an insert_snippet content like this:

"contents": "<${1:h1}>${0:$SELECTION}</${1/([^ ]+).*/$1/}>"

This one uses snippet fields to do the wrap the same as before, but once the wrap is done the selection will be on the h1 part of <h1></h1>; you can then just press Tab to jump the selection to the selected text and keep the h1, or type the heading that you want (e.g. h2) to replace both end tags first.

This is actually what the menu option and key binding for wrapping the selected text in a a tag do, only the default tag there is <p> and not <h1>.

In the technical sense yes because there are more files for it to find and load at startup, but in the practical sense no because if it takes an extra 1/1000th of a second for Sublime to start up, you’re unlikely to notice it. :wink:

0 Likes