Kakoune-inspired key bindings for Visual Studio Code.
Dance provides Kakoune-inspired commands and key bindings for Visual Studio Code.
These key bindings are (mostly) compatible with Kakoune's, but are meant to be an addition to Visual Studio Code, rather than an emulation layer on top of it.
For most commands, the usage is the same as in Kakoune. However, the following changes have been made:
Dance by default uses caret-based selections just like VSCode. This means a selection is anchored between two carets (i.e. positions between characters), and may be empty.
If you prefer character-based selections like Kakoune, please set "dance.selectionBehavior": "character"
in your
settings. This will make Dance treat selections as inclusive ranges between two characters, and implies that each
selection will contain at least one character. (This behavior is recommended for Kakoune-users who have already
developed muscle memory, e.g. hitting ;d
to delete one character.)
Pipes no longer accept shell commands, but instead accept 'expressions', those being:
#<shell command>
: Pipes each selection into a shell command (the shell is taken from the terminal.external.exec
value).
/<pattern>[/<replacement>[/<flags>]
: A RegExp literal, as defined in JavaScript. Do note the addition of a replacement
, for commands that add or replace text.
<JS expression>
: A JavaScript expression in which the following variables are available:
$
: Text of the current selection.$$
: Array of the text of all the selections.i
: Index of the current selection.Depending on the result of the expression, it will be inserted differently:
string
: Inserted directly.number
: Inserted in its string representation.boolean
: Inserted as true
or false
.null
: Inserted as null
.undefined
: Inserted as an empty string.object
: Inserted as JSON./(\d+),(\d+)/$1.$2/g
replaces 12,34
into 12.34
.i + 1
replaces 1,1,1,1,1
into 1,2,3,4,5
, assuming that each selection is on a different digit.A few changes were made from Kakoune, mostly out of personal preference, and to make the extension integrate better in VS Code. If you disagree with any of these changes, you're welcome to open an issue to discuss it, or to add an option for it by submitting a PR.
editor.lineNumbers
configuration value to on
in insert
mode, and relative
in normal mode."
maps to the system clipboard.Dance uses the built-in VS Code key bindings, and therefore does not override the type
command.
However, it sometimes needs access to the type
command, in dialogs and register selection,
for instance. Consequently, it is not compatible with extensions that always override the type
command, such as VSCodeVim; these extensions must therefore be disabled.
This project is still a WIP. It has gotten better over the years, but may have annoying bugs and lack some features, especially for Kakoune users. Despite this, several users use Dance daily.
In the following list, if a command is implemented, then its extending equivalent
(activated while pressing Shift
) then likely is implemented as well.
Most (but not all) commands defined in commands
are implemented.
a
, i
, o
, and their Alt
/ Shift
equivalents.Escape
.Dance was designed to nicely interopate with other extensions: it does not override
the type
command, and allows any extension to execute its commands.
It should therefore be possible to create other extensions that work with Dance. If
you'd like to add new features to Dance directly, please file an issue.
There are unfortunately still bugs lurking around features missing. If you'd like to fix bugs or add features, please look at the issues and file one if no other issue matches your request. This will ensure that no two people work on the same feature at the same time, and will be a good place to ask for help in case you want to tackle this yourself.
When contributing, please be mindful of the existing coding conventions and naming.
Your PR will be rebased on top of master
in order to keep a clean commit history.
Please avoid unnecessary commits (git commit --amend
is your friend).
We recently started adding tests to Dance. Most tests are in test/suite/commands
,
as plain text files that are separated into several sections.
Tests can be run and debugged in VS Code in the run menu, under "Run Extension Tests".
Each section has a name, which is any string that has no whitespace.
Except for the first section (implicitly named 0
or root
), each section
is associated with some transition that consists of several Dance commands to run.
For instance, let's look at the following code:
...
//== 0 > 1
//= dance.select.line
...
//== 1 > 2
//= dance.select.line.extend
...
//== 1 > 3
//= dance.select.line
//= dance.select.line.extend
...
It defines three sections:
1
, which is reached after executing dance.select.line
from section 0
.2
, which is reached after executing dance.select.line.extend
from section 1
.3
, which is reached after executing dance.select.line
and then dance.select.line.extend
from section 1
.As you can see, several sections can depend on the same parent section. Do note that
sections must be defined in order; that is, a section a
cannot depend on a section b
if section b
is defined after a
.
Each section has content (the ...
in the example above). That content is plain text to which
one or more selections must be added using a {...}
/ |{...}
syntax, where ...
is a number.
{0}
represents the anchor of the 1st selection, and |{2}
represents the active position of the 3rd selection.
Selections can be given in any order, but must be complete; that is, if a selection 3
is given, then the
selections 0
, 1
, and 2
must be defined at some point too. The anchor can be omitted, and will default to
the active position.
For each transition, a test will be generated making sure that executing the corresponding commands will lead to some document with selections at some locations.
Let's look at the following code:
{0}f|{0}oo
//== 0 > 1
//= dance.right
f{0}o|{0}o
//== 1 > 2
//= dance.delete.yank
f{0}o|{0}
The first generated test asserts that calling dance.right
in the document foo
where f
is the main selection
leads to a document foo
with the first o
selected.
The second generated test asserts that calling dance.delete.yank
in the document foo
where the first o
is
the main selection leads to a document fo
with o
selected.
.caret
will we run with selectionBehavior == "caret"
. Otherwise,
selectionBehavior == "character"
is used.//= {"command": "dance.objects.performSelection", "args": [{"object": "parens", "action": "selectToEnd"}]}
//= dance.select.to.included
//= type:c