/vue-ts-mode

Vue major mode for Emacs based on tree-sitter

Primary LanguageEmacs Lisp

vue-ts-mode

A tree-sitter-based Vue major mode for Emacs.

Features

Font Lock / Syntax Highlighting

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.

Indentation

Basic indentation for templates. script/style indentation imported from their respective built-in tree-sitter modes.

Language specific comment syntax

Automatically set comment variables for HTML in templates and JS/TS/CSS in their respective embedded language blocks.

imenu

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.

Extras

Auto-close HTML tags

Automatically close the nearest start tag after inserting </. Enabled by default. Disable it using the custom variable vue-ts-mode-auto-close-tags.

Auto-open line between HTML 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.

Structural Navigation

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.

Structural Editing

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, and vue-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.

Known Issues

JS/TS highlighting in interpolations/bindings

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

<script> tag highlight

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.

No special SCSS/Less highlighting

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.

Comments

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.

Alternatives

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

Acknowledgements

  • 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.