Saran
Saran

Reputation: 3884

How to duplicate selection with Sublime Text snippet

The quest

Turn this (with currHour being the current selection):

var currHour = now.getHours();

into this:

var currHour = now.getHours();
console.log('currHour=' + currHour);

Should work also for these cases:

currHour = now.getHours();

-->

currHour = now.getHours();
console.log('currHour=' + currHour);

and (where b is selected):

a = b;

-->

a = b;
console.log('b=' + b);

etc.


The Situation

Now, by following this answer I was able to produce the second line, with this:

<snippet>
  <content>
    <![CDATA[console.log('$SELECTION=' + $SELECTION);]]> </content>
  <description>Print selection to console.log</description>
</snippet>

NB: my snippet code ommits <scope> because the scope is implied by the location of the snippet file (under language-specific dir -- JavaScript).

NB2: the <tabTrigger> setting in the snippet was ommited intentionally, because I will use a keyboard shortcut:

{ "keys": ["ctrl+shift+o"], "command": "insert_snippet", "args": { "name": "Packages/User/JavaScript/console-log-selection.sublime-snippet" } },

OK, that brings me half way there...


The problem

The current "solution" requires of me to manually duplicate the selection before I can invoke the snippet. That is an inconvenient step I'd like to skip if I can. So, are there ways to make snippet duplicate the selection into new line?

Upvotes: 3

Views: 1868

Answers (4)

user3171187
user3171187

Reputation: 1

Hello I Used the code in the selected answer to create this.

It supports multiple selections and put the correct identation. Also it dosen't have to be a "var foo =" line

Upvotes: 0

skuroda
skuroda

Reputation: 19744

I'm not great with snippets, so there may be another way. Anyways, you can do it with a plugin.

import re
import sublime
import sublime_plugin
class ConsoleLog(sublime_plugin.TextCommand):
    def run(self, edit):
        view = self.view
        cursor = view.sel()[0]
        line_region = view.line(cursor)
        string = view.substr(line_region)
        match = re.search(r"(\s*)(var\s+)?(\w+)\s*=", string)
        if match:
            if cursor.empty():
                var_text = match.group(3)
            else:
                var_text = view.substr(cursor)
            view.insert(edit, line_region.end(), "\n%sconsole.log('%s = ' + %s);" % (match.group(1), var_text, var_text))
            end = view.line(line_region.end() + 1).end()
            view.sel().clear()
            view.sel().add(sublime.Region(end, end))

You just need to place the cursor on the line with your assignment operation. Bind your key binding to console_log. You can change the name as you see fit. Just be sure you change the name of the text command as well.

You could also modify your snippet so you don't have to type the text first. It seems unintuitive to type the variable name, select it, then hit your snippet key. Something like this may work better.

<snippet>
  <content>
    <![CDATA[console.log('$1 =' + $1);$2]]> </content>
  <description>Print selection to console.log</description>
</snippet>

Edit:

I used the plugin to generate the console.logs with the cursor on the lines containing var foo = bar and foo = bar. That is, it's two invocations of the plugin command. Though you could modify it to handle multiple cursors also.

var foo = bar
console.log('foo = ' + foo)

foo = bar
console.log('foo = ' + foo)

I also modified the plugin so it should use a variable assignment automatically if nothing is selected. If something is selected, it will use the selected text in the console log. If you don't want the empty selection stuff, just remove the if statement under if match: and replace it with var_text = view.substr(cursor)

Upvotes: 1

AGS
AGS

Reputation: 14498

A macro will do what you want in both cases:

Save this in

~/Library/Application Support/Sublime Text 2/Packages/User/saran_macro.sublime-macro

[
  {"command": "copy"},
  {"command": "move_to",  "args": {"to": "hardeol", "extend": false}},
  {"command": "insert",   "args": {"characters": "\nconsole.log('"}},
  {"command": "paste"},
  {"command": "insert",   "args": {"characters": "=' + "}},
  {"command": "paste"},
  {"command": "insert",   "args": {"characters":");"}}
]

Add this to your keybindings:

{ "keys": ["ctrl+shift+i"], "command": "run_macro_file", "args": { "file": "Packages/User/saran_macro.sublime-macro" } }

Whatever you highlight will be the variable in the macro.

Upvotes: 0

kbaskett248
kbaskett248

Reputation: 9

You can accomplish essentially what you want by combining a similar snippet with a macro.

The snippet:

<snippet>
  <content><![CDATA[
${TM_CURRENT_LINE/var *(.+?) *=.+/\nconsole.log\('$1=' + $1\);/}
]]> 
    </content>
  <description>Print selection to console.log</description>
</snippet>

The snippet figures out the variable name based on the current line and formats the console.log line using that variable.

The macro:

[
    {"command": "move_to",          "args": {"to": "hardeol", "extend": false}},
    {"command": "insert_snippet",   "args": {"name": "Packages/User/console-log-selection.sublime-snippet"}}
]

The macro uses an existing command - move_to - to get to the end of the line before inserting the snippet. This allows you to run the command from anywhere on the line.

Finally, the shortcut:

{ "keys": ["ctrl+shift+o"], 
  "command": "run_macro_file", 
  "args": { "file": "Packages/User/console-log-selection.sublime-macro" } 
},

This seems like the best approach for inserting the log line if the variable assignment line already exists.

Upvotes: 0

Related Questions