Efficiently bind different keys to the same command - keyboard-shortcuts

I'm developing a Prolog REPL plugin for SublimeText2. Like the prolog interpreter itself I want to offer multiple different keybindings for the same actions; e.g. one can use both ; and n to dismiss a solution presented by the repl. Currently, to achieve this I just duplicate the keybinding:
{ "keys": [";"], "command": "mycmd", "args": {},
"context":
[
{ "key": "setting.some_setting", "operator": "equal", "operand": true },
{ "key": "replmode_p"}
]
},
{ "keys": ["n"], "command": "mycmd", (etc ...) }
This blows up the size of the keybindings file considerably as many of the definitions are rather large because they only apply to specific contexts. Is there a way to do this without duplicating the bindings, or anything else I can do to optimize this?

Just a quick browse through Preferences->Key Bindings-Default shows multiple entries for the same commands, for example
{ "keys": ["backspace"], "command": "left_delete" },
{ "keys": ["shift+backspace"], "command": "left_delete" },
{ "keys": ["ctrl+shift+backspace"], "command": "left_delete" },
and
{ "keys": ["shift+delete"], "command": "cut" },
{ "keys": ["ctrl+insert"], "command": "copy" },
{ "keys": ["shift+insert"], "command": "paste" },
{ "keys": ["ctrl+x"], "command": "cut" },
{ "keys": ["ctrl+;"], "command": "cut" },
{ "keys": ["ctrl+c"], "command": "copy" },
{ "keys": ["ctrl+v"], "command": "paste" },
just in the first 40 lines (on Windows), so unfortunately I think the answer is no. The only way I could think of doing it,
{ "keys": ["ctrl+k", "ctrl+d"], "command": "find_under_expand_skip" },
maps a double key sequence to the action - hitting CtrlK, then hitting CtrlD runs the command.
Sorry!

Related

Change syntax highlighting of embedded code based on a previous line's keyword?

I'm trying to write a TextMate grammar for a VS Code language extension. Take the following example
(lang=css attribute2=something-else)
"""
.css-class {
background: gray;
}
"""
The (...) part is an "attributes" section, and the """ ... """ is a code section. I'm trying to highlight everything in the code section according to the lang attribute.
The problem is, they are two distinct sections where one might be present without the other in other parts of the file. For example, you can have attributes without the code block.
In the grammars section of package.json I have
"embeddedLanguages": {
"meta.embedded.block.css": "css",
"meta.embedded.block.javascript": "javascript"
}
In the tmLanguage.json file I have both patterns in the repository property.
"attributes": {
"begin": "\\(",
"end": "\\)",
"captures": {
"0": {
"name": "punctuation.definition.annotation punctuation.section.group punctuation.section.parens"
}
},
"patterns": [
{
"begin": "[a-zA-Z_][a-zA-Z0-9_\\.-]*",
"beginCaptures": {
"0": {
"name": "entity.other.attribute-name"
}
},
"end": "(?=\\s*+[^=\\s])",
"patterns": [
{
"begin": "=",
"beginCaptures": {
"0": {
"name": "punctuation.separator.key-value"
}
},
"end": "(?<=[^\\s=])(?!\\s*=)|(?=/?>)",
"patterns": [
{
"match": "([^0-9-.\\s='\"][^\\s='\")]*)",
"name": "string.unquoted.html"
},
{
"match": "=",
"name": "invalid.illegal.unexpected-equals-sign"
},
{
"include": "#strings"
},
{
"include": "#number"
}
]
}
]
}
]
},
"fenced-code": {
"begin": "\\(.*lang=(css|javascript).*\\)\\s*(\"\"\")",
"beginCaptures": {
"1": {
"name": "string.quoted.triple"
}
},
"end": "\"\"\"",
"endCaptures": {
"0": {
"name": "string.quoted.triple"
}
},
"contentName": "meta.embedded.block.$1",
"patterns": [
{
"include": "source.css"
}
]
}
I have a third pattern not shown where I'm using these together by including them in its patterns array. They seem to be mutually exclusive though. I can have the attributes, and I can have a code block if I start the pattern at """, but if I start the code pattern with \\(.*lang=(css|javascript).*\\)\\s*(\"\"\") to capture the lang attribute, the attributes stop getting highlighting.
Is this even possible? I've never worked with TextMate grammars outside of a VS Code theme and VS Code doesn't seem to have deep documentation on the more "advanced" (I guess) things like this.
I tried using VS Code's HTML grammar for its uses of embedded code, but I don't think the HTML one needs to swap syntax based on something in a previous line.
Update
The fenced-code pattern I have below allows the attributes pattern highlighting while also having the code block with dynamic contentName property, i.e. "meta.embedded.block.$2" becomes meta.embedded.block.css when "css" is found in attributes.
"fenced-code": {
"begin": "(\\(.*lang=(css|javascript).*\\))\\s*(\"\"\")",
"beginCaptures": {
"1": {
"patterns": [
{
"include": "#attributes"
}
]
},
"3": {
"name": "string.quoted.triple"
}
},
"end": "\"\"\"",
"endCaptures": {
"0": {
"name": "string.quoted.triple"
}
},
"contentName": "meta.embedded.block.$2",
"patterns": [
{
"include": "source.css"
},
{
"include": "source.js"
}
]
}
However, there's two things wrong so far.
It only works when the opening """ is on the same line as the attributes section
fenced-code's patterns array doesn't seem to allow a dynamic include, i.e. "patterns": [{"include": "source.$2}]. I'm not sure if including the different languages as I did above will work

Can't select nth element of same class with xpath / selenium IDE

Don't understand why the following loop doesn't work except for nth element with same class fails on the 2nd element (I'm presuming 1st element works because it's also the root in xpath):
{
"Command": "storeEval",
"Target": "$('.className').length",
"Value": "max"
},
{
"Command": "store",
"Target": "1",
"Value": "i"
},
{
"Command": "while",
"Target": "(${i} < ${max})",
"Value": ""
},
{
"Command": "echo",
"Target": "Current value of i = ${i}",
"Value": "i"
},
{
"Command": "storeAttribute",
"Target": "//a[contains(#class, 'className')][${i}]#href",
"Value": "link"
},
{
"Command": "endWhile",
"Target": "",
"Value": ""
}
For debugging, I tried to change ...[${i}] to [2] and it fails with both Kantu & Ranorex Selocity. However, From my reading of xpath / Selenium IDE documentation, this syntax should be correct. Any advice?
PS. For reference, the .className is actually .rf-project-cover__title on the page https://www.behance.net/search?field=132&content=projects&sort=published_date&time=week
I think you want to search, then extract i-th item, so you need brackets:
(//a[contains(#class, 'className')])[${i}]
for example:
(//a[contains(#class, 'rf-project-cover__title')])[2]
returns item with link text my portfolio

Multiple actions on one keyboard shortcut in vscode

Is it possible to have multiple actions assigned to one keyboard shortcut in visual studio code?
For example:
Move cursor up x 3 set to "ctrl + w"
Thanks in advance.
It's possible with extensions like Commands [Note: Created by the post's author]
settings.json
"commands.commands": {
"down3": {
"sequence": [
"cursorDown",
"cursorDown",
"cursorDown",
],
},
},
keybindings.json
{
"key": "ctrl+w",
"command": "down3",
},
Or with just keybindings.json
{
"key": "ctrl+w",
"command": "commands.run",
"args": [
"cursorDown",
"cursorDown",
"cursorDown"
]
},
Feature request to support Macro like keybindings #871.
Although, for this particular example it's better to use the built-in command (to avoid any jumpiness):
{
"key": "ctrl+w",
"command": "cursorMove",
"args": {
"to": "down",
"by": "line",
"value": 3
}
}
https://code.visualstudio.com/api/references/commands
I use the macros extension:
in settings.json:
"macros": {
"showGit": ["workbench.view.scm", "git-graph.view"]
}
then in keybindings.json:
{
"key": "ctrl+shift+g",
"command": "showGit"
}

I want tab to insert a tab in Sublime Text but it activates the autocomplete

I am using Sublime CodeIntel which I like for the autocomplete, however it pops up and inserts words while I am trying to insert tabs. I want tab to always insert a tab unless the character before my cursor is a letter.
I reckon this could be done with a user keymap for the tab key to look at context, but I don't know how to do it.
Something like the following should work. You may need to play with the order of the key bindings. Add the following to your user key bindings
{
"keys": ["tab"], "command": "insert", "args": {"characters": "\t" }, "context": [
{ "key": "preceding_text", "operator": "regex_contains", "operand": "[^a-zA-Z]$", "match_all": true }
]
}
Note that I don't have SublimeCodeIntel installed, so unsure how it will behave with that.
As a nice debugging tip, enter sublime.log_commands(True) into the ST console to see what command is being executed for a particular key binding. May be useful in confirming that the command is running as you expect.
A quick work around would be using Autohotkey if you are on windows.
you can assign any keys to 4 spaces like below
`::
Send {Space 4} ; when pressed ` enters four times Space bar
Return
Try this... Overrides tab key to function as indent key and insert tab char only
Preferences > Key Bindings
[
{ "keys": ["tab"], "command": "insert", "args": {"characters": "\t"} },
{ "keys": ["tab"], "command": "reindent", "context":
[
{ "key": "setting.auto_indent", "operator": "equal", "operand": true },
{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
{ "key": "preceding_text", "operator": "regex_match", "operand": "^$", "match_all": true },
{ "key": "following_text", "operator": "regex_match", "operand": "^$", "match_all": true }
]
},
{ "keys": ["tab"], "command": "indent", "context":
[
{ "key": "text", "operator": "regex_contains", "operand": "\n" }
]
},
{ "keys": ["tab"], "command": "next_field", "context":
[
{ "key": "has_next_field", "operator": "equal", "operand": true }
]
}
]

Add shortcut key for multiple plugins in Sublime Text 3

I'm using CodeFormatter and SassBeautify plugins in Sublime Text 3 in order to provide syntax highlighting and formatting for .scss files as well as .js/.html files. I've been able to set up shortcut keys for either plugin, but not to work for both, depending on the type of file I'm in.
[{
"keys": ["ctrl+alt+f"],
"command": "sass_beautify"
}, {
"keys": ["ctrl+alt+f"],
"command": "code_formatter"
}]
Can someone suggest how do to it? I've tried to understand "contexts" but not well enough to do this.
Am I doing this all wrong? Is there another way I should be achieving this?
Corrected keymap file:
[{
"keys": ["ctrl+alt+f"],
"command": "sass_beautify",
"context": [{
"key": "selector",
"operator": "equal",
"operand": "source.scss"
}]
}, {
"keys": ["ctrl+alt+f"],
"command": "code_formatter",
"context": [{
"key": "selector",
"operator": "not_equal",
"operand": "source.scss"
}]
}]
Add something similar to the following as a context entry
{ "key": "selector", "operator": "equal", "operand": "source.scss", "match_all": true }
{ "key": "selector", "operator": "equal", "operand": "(text.html, source.js)", "match_all": true }
The operand values are scope entries. There is a platform specific key binding to display scopes in the status bar, but I don't recall what they are off the top of my head. I personally use https://github.com/facelessuser/ScopeHunter to inspect scopes.