To customize Sublime Text's behaviour on when to indent newlines, depending on the current line, one can change the whatever.tmPreferences
file appropriately setting the increaseIndentPattern
and decreaseIndentPattern
options, like shown for example in this other answer.
However, I can't seem to work out how to generate the following behaviour: given a line like
[<cursor here>]
with the cursor between the square brakets, pressing enter
I want the following result:
[
<cursor here>
]
This is for example what happens when modifying an xml
file one presses enter between two brackets, like in <sometag><cursor here></sometag>
.
I tried to look into the tmPreferences
files for the xml
but to no avail.
A similar question has been asked here, but the present one is different for several reasons:
How can this behaviour be implemented?
To make a keybinding that will be shipped with a package, create a Default.sublime-keymap
file in your package.
Normally Sublime Text looks at the syntax being used to highlight the document, as opposed to the file extensions used, to determine whether keybindings/plugins should be active etc. This is mainly so that it will work on files that haven't been saved yet. If you want to follow this guideline, you can use the selector
keybinding context. In the case of XML files, you would probably want to use source.xml
. Otherwise, you will need to create an EventListener that defines a on_query_context
method to check the view.file_name()
. You could use the os.path.splitext
method to retrieve the file extension.
If you are truly dealing with XML, then you could use the default auto_indent_tag
keybinding as inspiration:
{ "keys": ["enter"], "command": "auto_indent_tag", "context":
[
{ "key": "setting.auto_indent", "operator": "equal", "operand": true },
{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
{ "key": "selector", "operator": "equal", "operand": "punctuation.definition.tag.begin", "match_all": true },
{ "key": "preceding_text", "operator": "regex_contains", "operand": ">$", "match_all": true },
{ "key": "following_text", "operator": "regex_contains", "operand": "^</", "match_all": true },
]
},
to build something like:
{ "keys": ["enter"], "command": "insert_snippet", "args": { "contents": "\n\t$1\n" }, "context":
[
{ "key": "setting.auto_indent", "operator": "equal", "operand": true },
{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
{ "key": "selector", "operator": "equal", "operand": "text.xml punctuation.definition.tag.begin", "match_all": true },
{ "key": "preceding_text", "operator": "regex_contains", "operand": ">$", "match_all": true },
{ "key": "following_text", "operator": "regex_contains", "operand": "^</", "match_all": true },
]
},
The regular expressions used here are very simple, just checking the the text immediately before the caret is >
and the text immediately after the caret is </
. This is possible because the selector
checks that a) we are in an XML syntax, and b) the text immediately after the caret is scoped as punctuation.definition.tag.begin
. (You can manually check the scope immediately to the right of the caret from the Tools menu -> Developer -> Show Scope Name.) If you are using a custom syntax, you will need to ensure you adjust these accordingly.
In this case, because we are using a keybinding on the Enter key, the indentation rules specified in tmPreferences
files are ignored.