A tree-sitter-based Vue major mode for Emacs.
Basic HTML, JS/TS, and CSS highlighting, plus additional highlighting for Vue-specific constructs like top-level SFC tags, built-in elements/components (template, transition, etc.), directives, etc.
Basic indentation for templates. script/style indentation imported from their respective built-in tree-sitter modes.
Automatically set comment variables for HTML in templates and JS/TS/CSS in their respective embedded language blocks.
Includes:
- Top level <template>, <script>, and <style> tags included in imenu,
- Elements inside of <template>
- the simple entries from typescript-ts-mode.
Plans to add JS, CSS, and possibly other entries.
Automatically close the nearest start tag after inserting </
.
Enabled by default. Disable it using the custom variable vue-ts-mode-auto-close-tags
.
Automatically insert an extra newline between an element’s start and end tags.
Starting from a state like this (where “|” is the cursor):
<div>|</div>
and pressing return (or otherwise running newline-and-indent
as a command) will result in a state like this:
<div>
|
</div>
Enabled by default. Disable it using the custom variable vue-ts-mode-auto-open-tags
.
Note that, at time of writing, none of these are bound to any keymap.
vue-ts-mode-element-match
: jump between the start/end tags of the element at point.vue-ts-mode-element-next
/vue-ts-mode-element-previous
: jump to start of the next/previous element from point.
Note that, at time of writing, none of these are bound to any keymap.
vue-ts-mode-element-transpose
: swap the element at point with its sibling. Swap with previous sibling if a prefix arg is provided.vue-ts-mode-attributes-toggle-wrap
,vue-ts-mode-attributes-wrap
, andvue-ts-mode-attributes-unwrap
: wrap puts all attributes on their own line (as in the style guide), unwrap puts all attributes and tag brackets on the same line, and toggle toggles between the two.
The current tree-sitter integration in Emacs treats all embedded language ranges as a single document of that language, combined. At best, font-locking sometimes works. At worst, I’ve run into Emacs freezing completely. I’m experimenting with creating an individual parser per interpolation, but I’ve not had much success with it and I’m not sure what the performance will look like for larger components. If I can get it to function, I may put it behind a flag that’s off by default
No support for jsx/tsx
Also: there’s code in the current built-in js/ts tree-sitter font lock settings that breaks on new versions of the parsers. It’s supposed to handle the differences in parser versions, but it doesn’t work correctly. I’ve got some advice in my personal config that fixes it, but I’m unsure as to whether or not I’ll include that here.
Only plain CSS so far. The main codebase I work in uses Less for styling, and while certain constructs result in parser errors and some syntax highlighting issues, it gets the job done.
I plan to add SCSS support at some point. There’s no tree-sitter grammar that I’m aware of for Less.
The aforementioned language specific commenting is incomplete. Basic line/region commenting works, but auto fill / comment continuation doesn’t. I need to familiarize myself more with how those work in Emacs.
Tried-and-true. Supports Vue and a bunch of other web template/component formats. Depending on how vue-ts-mode pans out, I may create an alternative “vue-ts-minor-mode” that can be used alongside web-mode for Vue-specific structural nav/editing/refactoring factored out of the work I’ve done here.
An alternative vue-ts-mode, started around the same time
- Some workarounds come from astro-ts-mode
- https://github.com/ikatyang/tree-sitter-vue, the tree-sitter grammar that supports this major mode
- web-mode, an awesome package for doing all kinds of web-dev in Emacs, including Vue. Serves as inspiration for some of the fancier features of this package.