Code scope depending "when" rules for keybindings? - visual-studio-code

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.

Related

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.

How to use conditions/context in ST3 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.

Sublime text find_under_expand not working in macro

While attempting to learn dark-lisp, I tried to write to macro's to wrap a selection with ()'s.
something
// run wrap-after
(something )
// run wrap-before
( something)
I created my wrap snippets, recorded two macros respectively and assigned key-bindings to the macros.
They look like this
[
{"command": "find_under_expand"},
{ "args": { "name": "Packages/User/snippets/wrap-after.sublime-snippet" }, "command": "insert_snippet" }
]
When I run the macro, it doesn't behave as expected.
| = cursor
som|ething
// press macro keybinding
som( )ething
// expected
(something )
I don't think it matters, but here's my keybinding as well
{"keys": ["ctrl+alt+d"], "command": "run_macro_file", "args": {"file": "Packages/User/macros/wrap-after.sublime-macro"}},
{"keys": ["ctrl+alt+a"], "command": "run_macro_file", "args": {"file": "Packages/User/macros/wrap-before.sublime-macro"}},
find_under_expand seems to not work. I also found it on some unofficial docs, but sublime wasn't having it.
You can start to debug these errors further in sublime by bringing up the console: ctrl+~ on mac. The console gave me Unknown macro command find_under_expand.
In this case, you can use expand_selection as the command with args.
Macro:
[
{
"command": "expand_selection",
"args": {
"to": "word"
}
},
{
"command": "insert_snippet",
"args":
{
"name": "Packages/User/wrap-after.sublime-snippet"
}
},
]
wrap-after.sublime-snippet
<snippet>
<content><![CDATA[($SELECTION )]]></content>
<description>this is a description for your snippet</description>
</snippet>

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"}
}