-
Notifications
You must be signed in to change notification settings - Fork 59
Description
I've had several issues getting vue-mode to work right with lsp. I work in vue with typescript and scss. I couldn't get typescript-mode working right (it wouldn't style (font lock?) the code without first entering a .ts file) in the ts section of the vue file, and I couldn't get syntax checking (lsp and then eslint) working right. I'm sure this is all my own fault, and because I don't understand emacs well enough. However, yesterday I gave up, and since I'd heard about emacs "polymode" (https://polymode.github.io/), I gave that a try. The following blog post was also helpful https://masteringemacs.org/article/polymode-multiple-major-modes-how-to-use-sql-python-in-one-buffer . This SE answer helped me with the regexps: https://superuser.com/a/1553876 .
The big advantage is that you define each section of the code by regexps for the start and end of the section, and you then define the major mode in each section freely. No major mode defining multiple major modes, just three separate major modes which you configure in whatever way you want.
The code that follows, from my init.el/.emacs, made that work for a vue file. This is terribly quick and dirty, but I still wanted to share it. Lsp and flycheck is only set up the way I want for the typescript section, so far.
(use-package polymode
:mode ("\\.vue\\'" . poly-vue-mode) ; use-package allows us to set .vue files to a poly-vue-mode, which I will define below
:config
(define-hostmode poly-vue-hostmode :mode 'html-mode) ; The "host" mode is html-mode
(define-innermode poly-typescript-vue-innermode ; The first inner mode is for typescript
:mode 'typescript-mode
:head-matcher "^[ \t]*<script.*>"
:tail-matcher "^[ \t]*</script.*>"
:head-mode 'host
:tail-mode 'host)
(define-innermode poly-scss-vue-innermode ; The second inner mode is for scss
:mode 'scss-mode
:head-matcher "^[ \t]*<style.*>"
:tail-matcher "^[ \t]*</style.*>"
:head-mode 'host
:tail-mode 'host
)
(define-polymode poly-vue-mode ; Define a new polymode, with two inner modes
:hostmode 'poly-vue-hostmode
:innermodes '(poly-typescript-vue-innermode poly-scss-vue-innermode))
)
It assumes the script section will always be typescript. It assumes the style section will always be scss. That's pretty lazy in comparison with what vue-mode does.
However, then I can separately define lsp, typescript-mode and scss-mode, with whatever settings I want. I get the vetur lsp server (I think that's because I've selected vetur in lsp-mode when I first opened a .vue file).
For example
This gets me typescript-mode with lsp and eslint checking.
(use-package typescript-mode
:ensure-system-package (typescript-language-server . "npm i -g typescript-language-server") ; This requires the (ensure-system-package) module in emacs
:mode ("\\.ts\\'")
:config
; Need to add the next checker only after lsp has been enabled
(add-hook 'lsp-after-initialize-hook (lambda ()
(flycheck-add-next-checker 'lsp 'javascript-eslint)))
(setq typescript-indent-level 2))
This sets up lsp-mode, and enables lsp for typescript-mode, html-mode and scss mode. Note that I don't know if the :config section is reasonable or correct, but it's what I've got right now.
(use-package lsp-mode
:hook
(java-mode . lsp)
(typescript-mode . lsp)
(html-mode . lsp)
(scss-mode . lsp)
(lsp-mode . lsp-enable-which-key-integration)
:init
(setq lsp-keymap-prefix "C-c C-l l") ; Must bind this before package is loaded
:config
(setq lsp-completion-provider :capf)
(setq lsp-enable-snippet t)
(setq lsp-enable-indentation t)
(setq lsp-semantic-highlighting t)
(setq lsp-auto-configure t)
;; Settings for Vue.js (vetur) language server
(setq lsp-vetur-use-workspace-dependencies t)
(setq lsp-typescript-preferences-quote-style "single")
)
It seems to just work!