How to use conditions/context in ST3 macros? - macros

I am trying to modify the Ctrl+Enter-macro so that it appends a semicolon to the end of the line before writing a newline, similar to this question.
The basic solution is pretty simple
[
{"command": "move_to", "args": {"to": "hardeol"}},
{"command": "insert", "args": {"characters": ";\n"}}
]
, however, it has two problems:
1) If there is already a semicolon at eol, it will be duplicated. Is there a way to include a condition of ( preceding_text == ";" ) similar to keybindings'
{ "key": "preceding_text", "operator": "regex_match", "operand": ";$" }
and have the macro run one of two different insert commands depending on that?
2) As it is, the plugin runs independent of language, also inserting semicolons, for example, in html. Again, is there a way to make inserting the semicolon optional depending on the scope?

I found a pretty good workaround. I still don't know, if it's possible to add this kind of condition in the macro itself, but it can be substituted by adding the conditions in the key-bindings.
First, create a second macro "Packages/User/Add Line Semicolon.sublime-macro" with
[
{"command": "move_to", "args": {"to": "hardeol"}},
{"command": "insert", "args": {"characters": ";\n"}}
]
In the user-keybindings add
{ "keys": ["ctrl+enter"], "command": "run_macro_file", "args": {"file": "res://Packages/User/Add Line Semicolon.sublime-macro"}, "context":
[
{ "key": "following_text", "operator": "not_regex_contains", "operand": ";$", "match_all": false },
{ "key": "selector", "operator": "equal", "operand": "(source.css, source.scss) - comment", "match_all": false },
]
},
This listens to the same keys as the normal ctrl+enter, but calls the new macro and only triggers if certain conditions are met.
First, the text after the cursor may not end with a semicolon. If there's already a semicolon at the end of line, this binding will not trigger and the shortcut will be passed through to the default binding instead. Note that, since it only checks the text after the caret, this will not work if your cursor is already at the end of the line.
Secondly, the position of the caret must have the appropriate scope. For this example, I just included css and scss files, and it only matches if you're not currently in a comment. Again, if the condition fails, the shortcut will be passed through to the default macro.

Related

Code scope depending "when" rules for keybindings?

i'm new in VSCode, but in Sublime Text it's possible to assign shortkeys with a code scope context, like:
{
"keys": ["tab"],
"command": "insert",
"args":
{
"characters": "\n"
},
"context": [
{
"key": "selector",
"operand": "source.css meta.rule.css meta.declaration-list.css",
"operator": "equal",
"match_all": true
}]
}
That means, when my cursor is at the scope source.css meta.rule.css meta.declaration-list.css and when I press tab key, I'll insert new line. Can I do like that in VSCode, because I try to search for the list of "when" rules, that's what I had found Visual Studio Code list of keyboard shortcuts options and there is nothing about code scope context, or comparing current line text, or something like that.

How to set hotkey to move cursor out of quotes/parenthesis?

In Sublime I could easily set a more complex hotkey that lets me exit quotes and parenthesis by pressing Enter. It is here below:
// Move out of single and double quotes with `Enter`
{
"keys": ["enter"],
"command": "move",
"args": {"by": "characters", "forward": true},
"context": [
{ "key": "following_text", "operator": "regex_match", "operand": "(?:\"|').*", "match_all": true },
{ "key": "preceding_text", "operator": "regex_contains", "operand": "(?:\"|')", "match_all": true }
]
},
In VS Code, is there any way to achieve this? This in keybindings.json moves the cursor, but it is active when I don't want too. Thanks.
{ "key": "enter", "command": "cursorRight",
"when": "editorTextFocus" }
Check out this extension which does what you want - https://marketplace.visualstudio.com/items?itemName=albert.TabOut
And you can find the implementation here - https://github.com/albertromkes/tabout
I found Ctrl+Shift+\ useful for moving out of quotes. Also, it could be remapped by searching jumpToBracket in Keyboard Shortcuts.
See full VSCode keyboard binding here.
In VS Code, you can type the closing quote (i.e. if using double quotes)
{shift+'}
while you are INSIDE the quotes to have it exit outside the closing quote. This also works for parenthesis and brackets, just type the closing one (i.e. ) or ]). You can also jump straight to a new line by pressing
{ctrl+enter}
which exits out of any brackets, parenthesis, quotes you are already in. These 2 methods here should be embedded in standard VS Code AFAIK.

Sublime Text 2 - Auto-indent for brackets and HTML tags

(Note: In these examples, I will use the pipe symbol "|" to represent the cursor)
In Sublime Text 2, when I type a brace, it automatically adds a matching brace like this:
{|}
with the cursor in between the two braces. Then when I hit Enter, it automatically adds an extra new line and an indent, resulting in:
{
|
}
However, the same indent behavior does not happen with brackets and HTML elements. For example, if I type a bracket "[", it does automatically add the matching bracket like:
[|]
But when I hit Enter, the result is:
[
|]
It doesn't add an extra line or indent. Similarly, when I type "div.some-class", then Tab, I get:
<div class="some-class">|</div>
But when I hit Enter, I get
<div class="some-class">
|</div>
Not what I want. The only case that is working correctly is with the braces. But in all 3 cases (braces, brackets, html elements), I want an extra line and indent added. So they should all look like:
Braces:
{
|
}
Brackets:
[
|
]
HTML elements:
<div class="some-class">
|
</div>
How can I accomplish this?
Install EMMET Plugin, it will do that plus tons of extra great features especially for writing HTML and CSS. :)
If you haven't already install Package control (for easily installing new packages/plugins), install it using instructions here.
Then you can simply press CTRL+SHIFT+P and write Package Control : Instal Package and find EMMET and install it. Once done restart Sublime Text and it should work :)
Explanation
I've just figured out for myself how to do one of the things on your list.
I've modified the regex that runs when you press the "enter" key.
The old regex checked for this "operand": "\\{$" and this "operand": "^\\}"
I added or checks using the pipe | to also check for [ and ( in the same manner: "operand": "\\{$|\\[$|\\($" and "operand": "^\\}|^\\]|^\\)"
Directions
Navigate to Preferences>Key Bindings - User
Personally, I keep this file organized by putting short, simple bindings at the top, and larger, block bindings/concerns at the bottom. I consider the following to be a larger block.
Paste this new code in the file:
// Auto-insert line and indent on square bracket and bracket (parenthesis)
{ "keys": ["enter"], "command": "run_macro_file", "args": {"file": "res://Packages/Default/Add Line in Braces.sublime-macro"}, "context":
[
{ "key": "setting.auto_indent", "operator": "equal", "operand": true },
{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
{ "key": "preceding_text", "operator": "regex_contains", "operand": "\\{$|\\[$|\\($", "match_all": true },
{ "key": "following_text", "operator": "regex_contains", "operand": "^\\}|^\\]|^\\)", "match_all": true }
]
},
{ "keys": ["shift+enter"], "command": "run_macro_file", "args": {"file": "res://Packages/Default/Add Line in Braces.sublime-macro"}, "context":
[
{ "key": "setting.auto_indent", "operator": "equal", "operand": true },
{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
{ "key": "preceding_text", "operator": "regex_contains", "operand": "\\{$|\\[$|\\($", "match_all": true },
{ "key": "following_text", "operator": "regex_contains", "operand": "^\\}|^\\]|^\\)", "match_all": true }
]
},
A few notes:
My code does this for parenthesis as I said. (Sublime refers to parenthesis as "brackets", distinguished from "square brackets" and "braces".)
If you don't want this to work on parenthesis, change the first "operand" check to this: "operand": "\\{$|\\[$" and the "operand" check on the next line to this: "operand": "^\\}|^\\]"
Last, I'm guessing Sublime parses it correctly either way, but I have a comma , at the end of my closing brace, which would assume you've got some more key bindings that follow. If it's the last binding before the closing square bracket at the end of the file, you should remove the comma.
Also, in Sublime Text 3 at least, your questions about the <div> indent has been fixed.

How to avoid auto-close (, {, [ in user defined Sublime Text 3 snippet?

I'm trying to write a fairly innocent-looking snippet fro ST3. For inserting
\left<open-parens> \right<close-parens>
into a latex document while in a math scope.
What I have now, is this:
<snippet>
<content><![CDATA[\\left${1:(} $0 \\right${1/(\()|(\{)|(\[)/(?1:\))(?2:\})(?3:\])/}]]></content>
<tabTrigger>lft</tabTrigger>
<scope>text.tex.latex string.other.math.tex,meta.function.environment.math.latex</scope>
</snippet>
The usage is intended as follows:
Type lst,tab;
\left( \right) is inserted with the ( selected;
If user wants (, tab to land in in middle;
Else type { or [ to have corresponding closing parens inserted after \right
I have verified that the regex is working as intended (by trying out versions of the snippet with ${1:(} replaced by ${1:{} and ${1:[}.
However in usage, when typing any start parens, ST calls it's own snippet, a) inserting the close parens immediately after and b) removing focus from my snippet, so the the regex is never called.
The first problem, I have been able to alleviate, by capturing the opening parenses and call a tiny snippet, inserting the character itself. E.g:
{ "keys": ["{"], "command": "insert_snippet", "args": {"contents": "$0{"}, "context": [
{"key": "selector", "operator": "equal", "operand": "text.tex.latex string.other.math.tex, meta.function.environment.math.latex"},
{"key": "preceding_text", "operator": "regex_contains", "operand": "\\\\left\\($", "match_all": true }] },
But then I discovered b).
A solution would involve either of:
Prevent execution of built-in auto-close snippets, depending on context and "key": "preceding_text".
Making my own mini-snippet return to the former (i.e. after typing [focus returns to the lst-snippet).
How can this be achieved?
This isn't really the answer I'm looking for, but rather a working solution to this specific issue.
The use becomes a little different in looks but the keystrokes required are the same.
What I do is this:
Change the lft-snippet to:
<content><![CDATA[\\left${1:$0\right}]]></content>
For each parens-type define a new keybinding, that overrides the default and does something useful, e.g. for the [] add this to a keymap file:
{ "keys": ["["], "command": "insert_snippet", "args": {"contents": "[ $0 $SELECTION]"}, "context":
[
{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
{ "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true },
{ "key": "selector", "operator": "equal", "operand": "text.tex.latex string.other.math.tex, meta.function.environment.math.latex"},
{ "key": "preceding_text", "operator": "regex_contains", "operand": "\\\\left\\\\right$", "match_all": true }
]
},
As a positive side effect the lft-snippet becomes a lot easier to read (removing the regex).
I would still very much like to know of ways to accomplish this in a more general way.

How to disable/override the enter key for autocomplete?

In Sublime Text 3, I want to disable the enter key to select an item from the autocomplete drop down, and only allow the tab key to do so.
I found this section in the inbuilt Default (OSX).sublime-keymap file:
{ "keys": ["enter"], "command": "commit_completion", "context":
[
{ "key": "auto_complete_visible" },
{ "key": "setting.auto_complete_commit_on_tab", "operand": false }
]
},
It seems that if I remove this from the config that enter will not select an item in the drop down. Unfortunately it is not recommended to change this file, and only to override it in my User files. I don't think I actually can edit it without modifying the .app contents.
I tried to override it by removing different sections, and also remove everything except "keys": ["enter"], but nothing seems to work.
How would I go about achieving this without modifying the inbuilt Default (OSX).sublime-keymap and only the User/Default (OSX).sublime-keymap file?
I have never used Sublime Text 3, but I don't think the following has changed since Sublime Text 2.
What you want to achieve is actually a standard feature in Sublime Text. You just have to turn it on.
This line from your the code you quoted …
{ "key": "setting.auto_complete_commit_on_tab", "operand": false }
… means "only execute the command if the setting called 'auto_complete_commit_on_tab' is set to false". So simply turn on that setting.
In Default/Preferences.sublime-settings:
// By default, auto complete will commit the current completion on enter.
// This setting can be used to make it complete on tab instead.
// Completing on tab is generally a superior option, as it removes
// ambiguity between committing the completion and inserting a newline.
"auto_complete_commit_on_tab": false,
Put "auto_complete_commit_on_tab": true in User/Preferences.sublime-settings. Both mentioned files can be accessed via the Preferences menu.
You can assign it to a non existent command. Try adding the following to User/Default (OSX).sublime-keymap
{ "keys": ["enter"], "command": "noop", "context":
[
{ "key": "auto_complete_visible" },
{ "key": "setting.auto_complete_commit_on_tab", "operand": false }
]
}
Granted if you install/write a plugin that has a command noop you will need to change this command.
Edit
Lydell's solution is better :) Forgot about that setting (though it is in the context so I should have known...). Guess my answer is a more generic "how to disable a keybinding".
tried the solutions given above but they didn't work.
after some work this is what i came up with.
{ "keys": ["enter"], "command": "hide_auto_complete", "context":
[
{ "key": "auto_complete_visible" },
{ "key": "setting.auto_complete_commit_on_tab", "operand": false }
], "command": "insert", "args": {"characters": "\n"}
}