Universal structural navigation and editing.
The goal of this extension is to enable structural navigation and editing regardless of language.
Inspired by the Lisp editing modes Lispy, Paredit and Interlisp SEdit.
Code-strider is powered by Tree-sitter, a parser generator for fast, incremental, error-resistant parsers, and a community of Tree-sitter grammar authors and maintainers.
Prototype. Expect buggy behavior. However, all the features in this README should work as advertised.
This editing interface is modal. You can either navigate around the code or insert text; but not both at the same time. The navigational mode is active by default.
All keybindings are configurable. The defaults are influenced by Vim.
Use the arrow keys to easily move over source code fragments.
These are bound to the smart movement commands move-up
, move-down
, move-left
, move-right
, which will try to move to code-structures in the desired direction.
The commands follow-structure
[f] and follow-structure-last
[Shift+f] should preferably be used to navigate further inside a selected node.
To select the parent of the currently selected node use move-parent
[g].
If any movement operation did not select your wished for node, you can return to previously selected nodes by using back-to-previous-selection
[b]. (Note: this undo-stack is cleared when changing or modifying the file.)
It is possible to move directly on the Tree-sitter AST with the tree-move-...
commands.
The commands parent, next, previous, first child
are by default bound to alt
+ h j k l
respectively.
insert-before
[i] Insert directly before the current nodeinsert-after
[a] Insert directly after the current nodeinsert-below
[o] Start inserting text on a line below the currently selected nodeinsert-above
[Shift-o] Start inserting text on a line above the currently selected nodedelete-insert
[c] Change the currently selected node by deleting its text and entering insert-mode.
To exit insert-mode, simply press [Escape] (exit-insert-mode
).
For convenience the default VS Code undo
command is bound to [u].
greedy-delete
(default binding: [Backspace]) Delete the currently targeted structure and everything around it up until the next named node.
slurp-backward
[7] Include the previous sibling as first childslurp-forward
[8] Include the next sibling as last childbarf-backward
[Shift-7] Extract the first child as previous siblingbarf-forward
[Shift-8] Extract the last child as next sibling
Currently, only useful in HTML. While it is possible to use the commands in any language, the results are most definitely not what you would expect. The algorithms for slurping and barfing are currently tuned for use on HTML code.
Theoretically, slurping and barfing are inverse operations, but in the current implementation line breaks are removed by the slurping
and not restored by barfing
.
(The formatting changes are not intentional and should be fixed.)
Bash
C
Clojure
CSS
Fennel
Go
Haskell
HTML
Java
JavaScript
JSON
Kotlin
Lua
Markdown
Nix
OCaml
PHP
Python
SCSS
TypeScript
YAML
More to come. The goal is to support all languages supported by Tree-sitter. So all of them :)
Try the AST viewer if you are curious about the abstract syntax tree of your code.
Activate it by opening the command palette [F1] and selecting the Toggle AST viewer
command.
Note: The AST viewer does not update during insert-mode.
No dependencies. This extension bundles the WASM builds of Tree-sitter, thus, no native dependencies are required.
In the future I might try to integrate native tree-sitter again, but that is currently quite complicated. The extension would need to be compiled with the exact same version of VS Code where it will be used.
Default mode ("code-strider.defaultMode"
)
Specify the mode in which the extension starts when opening (or switching to) a file.
When starting in insert
mode the extension is essentially deactivated until the toggle-structural-navigation
command is executed.
Options:
structural
: Start with structural navigation on.insert
: Start with structural navigation off. (default)
This extension contributes the language Nix
. These are only partial definitions. Basically only mapping their respective file suffixes to a language identifier. This allows consistent detection of all supported languages independent of any other extensions.
You can create custom key bindings which are only active during either Code-strider navigation or insert-mode. The following contexts can be used in a key binding's when
expression:
code-strider:is-editor-supported
indicates whether this extension is active in the currently active text editor (this is true if the language is supported).code-strider:is-insert-mode
indicates whether text insertion is active.
For example, all default key bindings active during the structured-navigation mode use this expression:
"when": "editorTextFocus && code-strider:is-editor-supported && !code-strider:is-insert-mode"
-
The extension does not (re-)initialize when changing the language mode of a file. It is necessary to switch to another editor and back to detect the language change.
-
If you move the AST viewer manually (e.g. by dragging it into another editor group), the selections will no longer update. Workaround: Change the editor layout instead. For example, use
View: Two rows editor layout
after opening the AST viewer to move it to the bottom row. -
The extension will crash if a file is deleted during parsing. Workaround: reload VS Code (Action:
Developer: Reload Window
) -
This extension is not cat-proof, yet. For example: Holding the [delete] key in structural navigation mode might block the extension host process. Workaround: reload VS Code (Action:
Developer: Reload Window
)
Requirements: NodeJS (12)
npm install
For testing and running, either use the npm commands from the scripts
section in package.json
or use the launch configs in VS Code (.vscode
).
Run tests: npm test
Compile (fast): npm run build
Compile (optimized): npm run build-prod
Automatically recompile on file changes: npm run watch
Start VS Code and load the extension: npm start
The start
script has codium
hard-coded. Replace it if you want to use VS Code, or use it directly:
code --extensionDevelopmentPath $(pwd)
The path parameter has to be absolute, so use $(pwd)
instead of .
.
Make sure to build first (npm run build
) before starting with npm start
.
Tree-sitter: The MIT License (MIT) Copyright (c) 2018 Max Brunsfeld
This extension bundles several Tree-sitter grammmars, which can be found in the wasm
directory with their respective licenses.
Their sources are documented in the build-wasm.nix
script.
Copyright 2021 Timo Gebauer
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
See COPYING
for a copy of the GNU General Public License.
Or https://www.gnu.org/licenses/.