How do I setup "--" as a Sublime Text snippet tab trigger? - sublimetext2

I am currently working with fortran in Sublime Text and I'm adding some snippets to make the workflow faster.
Since fortran does not support the ++ or -- operators, I would like to make snippets that will change these operators to the explicit increment and decrement statements.
For example
a++
becomes
a = a + 1
and
a--
becomes
a = a - 1
I have successfully implemented the ++ snippet as follows.
<snippet>
<content><![CDATA[ = $TM_CURRENT_WORD + 1]]></content>
<tabTrigger>++</tabTrigger>
<description>i = i + 1</description>
<scope>source.fortran</scope>
</snippet>
However, my implementation of the -- snippet fails to trigger.
<snippet>
<content><![CDATA[ = $TM_CURRENT_WORD - 1]]></content>
<tabTrigger>--</tabTrigger>
<description>i = i - 1</description>
<scope>source.fortran</scope>
</snippet>
Does anyone have any suggestions on how to get the -- snippet to trigger? Thanks.

Adding a key binding for the 3-key sequence of minus,minus,tab will do the trick:
{ "keys": ["-", "-", "tab"],
"command": "insert_snippet",
"args": {"name":"Packages/Fortran/MinusMinus.sublime-snippet"}
}

Related

How to call a plugin from my .vimrc file?

I am using a VIM plugin called Goyo (for writing markdown files). It is similar to Distraction Free mode in SublimeText. I want to create a write-mode in my .vimrc that I can toggle. This toggle will set various options on in write-mode, such as set spell, set wrap etc.
I have everything working here, except calling the Goyo function. How can I execute the Goyo plugin from within my ToggleWrite() function?
Here is my code:
" Write toggle switch
let b:write = "no"
function! ToggleWrite()
if exists("b:write") && b:write == "yes"
let b:write = "no"
set nowrap
set nolinebreak
set textwidth=100
set wrapmargin=0
set nospell
" ↓↓↓ I want to call this ↓↓↓
":Goyo
else
let b:write = "yes"
set wrap
set linebreak
set textwidth=100
set wrapmargin=0
set spell
" ↓↓↓ I want to call this ↓↓↓
":Goyo 60x100%
endif
endfunction
" Set up the toggle sequence
nmap <expr> ,w ToggleWrite()
I put my comment as an answer:
Your mapping uses <expr>, which is not right in your case. You should try this mapping instead:
nmap ,w :call ToggleWrite()<cr>
or
nmap <silent> ,w :call ToggleWrite()<cr>
<expr> lets you make "custom" mappings, depending on the return of a function. It's rarely used in common cases.

Copy entire line shortcuts then paste it UNDER cursor

On Sublime Text 3 (but I guess it's the same with ST2), I know that when you copy ( CTRL + C ) when there is nothing selected, the entire line is copied but I need to know how to paste it below my cursor.
It currently paste it above it and it doesn't seem logical to me, is there a way to modify this behaviour ?
Following Dan Lowe's answer, I made this file :
http://pastebin.com/7nPWZCPh
and added this line
{ "keys": ["ctrl+shift+v"], "command": "run_macro_file", "args": {"file": "res://Packages/User/paste_no_line.sublime-macro"}},
to my user's keybindings.
Works as intended but I have two differente "paste command" now.
It's not that it pastes "above" or "below", it's that it is operating on the current line. When you copy without first making a selection, it copies the current line. When you paste that, it also operates on the current line -- it pastes the buffer into that line, and as a side effect, whatever was on that line is bumped out of the way to the next line. It can't be bumped upward instead - the file can only grow or add new lines downward, you can't grow upward beyond line 1.
As to how to modify the behavior, I would suggest trying to make a macro.
http://docs.sublimetext.info/en/latest/extensibility/macros.html
As you pointed out in the comments, a macro works but it leaves you with two different ways to do a paste, one for normal use and the other for this "entire line" behavior. That is unfortunate, though there is another (harder) solution. You could try to write a Sublime plugin to detect how to behave and do what you want in each case. This is a bit beyond my ability to do for you... but in thinking about this, I realized that the Vintage package already has a command for this, because its p and P keys paste before and after the cursor, respectively. I looked inside the Vintage package to find where they did it. Here is their code, though I couldn't explain to you exactly how it works. You would want to try to emulate ViPasteRight.
class ViPrefixableCommand(sublime_plugin.TextCommand):
# Ensure register and repeat are picked up from g_input_state, and that
# it'll be recorded on the undo stack
def run_(self, edit_token, args):
if not args:
args = {}
if g_input_state.register:
args['register'] = g_input_state.register
g_input_state.register = None
if g_input_state.prefix_repeat_digits:
args['repeat'] = digits_to_number(g_input_state.prefix_repeat_digits)
g_input_state.prefix_repeat_digits = []
if 'event' in args:
del args['event']
edit = self.view.begin_edit(edit_token, self.name(), args)
try:
return self.run(edit, **args)
finally:
self.view.end_edit(edit)
class ViPasteRight(ViPrefixableCommand):
def advance(self, pt):
if self.view.substr(pt) == '\n' or pt >= self.view.size():
return pt
else:
return pt + 1
def run(self, edit, register = '"', repeat = 1):
visual_mode = self.view.has_non_empty_selection_region()
if not visual_mode:
transform_selection(self.view, lambda pt: self.advance(pt))
self.view.run_command('paste_from_register', {'forward': not visual_mode,
'repeat': repeat,
'register': register})
class ViPasteLeft(ViPrefixableCommand):
def run(self, edit, register = '"', repeat = 1):
self.view.run_command('paste_from_register', {'forward': False,
'repeat': repeat,
'register': register})
And here is how they bind them to keys. If you wanted to try to adapt this you probably would not need the context, that is something they need due to Vintage mode's modal nature.
{ "keys": ["P"], "command": "vi_paste_left",
"context": [{"key": "setting.command_mode"}]
},
{ "keys": ["p"], "command": "vi_paste_right",
"context": [{"key": "setting.command_mode"}]
},
Here is the docs section about plugins, if you want to try to tackle it that way.
http://docs.sublimetext.info/en/latest/extensibility/plugins.html

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?
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)
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.
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.
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

Ctrl + D select in reverse

Is there a way to do the reverse selection in Sublime Text 2?
I know that you can skip (Ctrl + K, Ctrl + D), undo (Ctrl + Y) and cherry pick (hold alt) your selection from Ctrl + D but how do I tell sublime to multi-select in reverse order?
Let's say, instead of going up to down, I want to go down to up.
If anyone can please improve upon this plugin so that it scrolls the screen upwards as it selects, that would be greatly appreciated.
NOTE:  The OSX key binding that I chose for this example conflicts with duplicate_line, so that key binding would need to be commented out for this new key binding to work -- otherwise, select a different key binding that is not already taken.
{ "keys": ["super+shift+d"], "command": "inverse_find_under_expand" },
import sublime, sublime_plugin
class InverseFindUnderExpandCommand(sublime_plugin.TextCommand):
"Add the previous occurrence of the word under the cursor to the selection"
def run(self, edit):
sel = [s for s in self.view.sel()]
new_sel = []
for s in sel:
self.view.sel().clear()
self.view.sel().add(s)
self.view.window().run_command('find_under_prev')
for ns in self.view.sel():
new_sel.append(ns)
self.view.sel().clear()
for s in sel:
self.view.sel().add(s)
for s in new_sel:
self.view.sel().add(s)

Exiting a block enclosed in curly braces in Sublime

Say if I have the following code in Sublime:
if (condition) {
// code
}
When my cursor is at the end of // code, I would like to set a key bind (e.g. Tab) that will exit the if-statement block and move it to the end of }. Thanks.
The BracketHighlighter plugin can provide this functionality natively... sort of. In its example shortcuts file, Example.sublime-keymap, there is a "Go to Right Bracket" example key binding:
// Go to right bracket
{
"keys": ["ctrl+alt+super+down"],
"command": "bh_key",
"args":
{
"lines" : true,
"plugin":
{
"type": ["__all__"],
"command": "bh_modules.bracketselect",
"args": {"select": "right"}
}
}
},
The only problem is that the called bracketselect command moves the cursor to the left side of the right bracket, requiring another keypress to fully escape from the block. I don't think that's what you want.
Worry not! Thankfully, BracketHighlighter provides a very intuitive plugin API, and I found that I could modify the bracketselect plugin to create a command that would escape from a bracket-enclosed block—basically the same as bracketselect, but it moves the cursor to the right side of the closing bracket rather than the left, and doesn't need any extra arguments.
You'll first need to install BracketHighlighter if you haven't yet.
Next, save blockescape.py (see below if the link ever dies) to
Preferences -> Browse Packages... -> BracketHighlighter/bh_modules/blockescape.py
Then, add this entry to the top of your user key bindings (Preferences -> Key Bindings — User):
{
"keys": ["tab"],
"command": "bh_key",
"args":
{
"lines" : true,
"plugin":
{
"type": ["__all__"],
"command": "bh_modules.blockescape"
}
}
},
I wouldn't recommend using tab as your trigger key, because tab has an important role already with expansions. Of course, you could define a special context in which to use tab, but that is up to you.
In case Github is ever down, here's the plugin code:
import bh_plugin
import sublime
DEFAULT_TAGS = ["cfml", "html", "angle"]
class BlockEscape(bh_plugin.BracketPluginCommand):
def run(self, edit, name, tags=DEFAULT_TAGS):
current_left, current_right = self.selection[0].begin(), self.selection[0].end()
left, right = self.left, self.right
first, last = left.end, right.begin
if left.end != right.end:
if name in tags and left.size() > 1:
first, last = right.begin + 1, right.begin + 1
if first == current_left and last == current_right:
first, last = right.end, right.end
else:
first, last = right.begin, right.begin
if first == current_left and last == current_right:
first, last = right.end, right.end
else:
# There is no second bracket, so just select the first
if name in tags and left.size() > 1:
first, last = left.begin + 1, left.begin + 1
else:
first, last = right.end, right.end
if first == current_left and last == current_right:
first, last = right.end, right.end
self.selection = [sublime.Region(first+1, last+1)]
def plugin():
return BlockEscape
Since I more or less hacked the plugin together, it might not work properly. In that case, feel free to edit it yourself or leave a comment on the Gist page.
You can add the $0 in a snippet to tab to that location:
<snippet>
<description>If Condition</description>
<content><![CDATA[if (${1:/* condition */}){
${2:/* code */}
}${0}]]></content>
<tabTrigger>if</tabTrigger>
<scope>source.c</scope>
</snippet>