Giter VIP home page Giter VIP logo

lsp-volar's Introduction

lsp-volar

Language support for Vue3

This package has been merged into lsp-mode, so you can use lsp-mode directly. There will only be some experimental updates here. Once stable, they will be submitted to lsp-mode.

Installation

Doom Emacs

in packages.el

(package! lsp-volar :recipe (:host github :repo "jadestrong/lsp-volar"))

in config.el

(use-package! lsp-volar)

straight.el

First, place the following bootstrap code in your init-file:

(defvar bootstrap-version)
(let ((bootstrap-file
       (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
      (bootstrap-version 5))
  (unless (file-exists-p bootstrap-file)
    (with-current-buffer
        (url-retrieve-synchronously
         "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
         'silent 'inhibit-cookies)
      (goto-char (point-max))
      (eval-print-last-sexp)))
  (load bootstrap-file nil 'nomessage))

Then install lsp-volar package:

(straight-use-package
 '(lsp-volar :type git :host github :repo "jadestrong/lsp-volar"))

Last use it:

(use-package lsp-volar
  :straight t)

Changelog

  1. Breaking change [2022-10-29] You must upgrade @volar/vue-language-server to the latest version, see this MR. Now lsp-volar will only start one server(vue-semantic-server).

  2. After volar 0.32.1 @volar/server was renamed to @volar/vue-language-server , so you need resintall the new package.

  3. In volar 0.30.0 you can skip calculate auto import by set lsp-typescript-suggest-auto-imports to nil to improve the completion speed. Check this issue.

    lsp-typescript-suggest-auto-imports is a setting registed by lsp-vetur.

    This will disable the auto completation of third-party libraries and affect the experience, so you don't have to set it to nil unless you feel that there is a significant performance imporvement after disabling it .

Hacks

If you prompt \u0000 lsp-warn when performing autocomplete in Vue template, you need to use advice-add to override the following function lsp--create-filter-function to filter the special characters. see this issue vuejs/language-tools#1118 .

In doom-emacs, you can place this code in your ~/.doom.d/config.el ,otherwise, you need to use advice-add to replace defadvice! .

(defadvice! +lsp--create-filter-function (workspace)
  :override #'lsp--create-filter-function
  (let ((body-received 0)
        leftovers body-length body chunk)
    (lambda (_proc input)
      (setf chunk (if (s-blank? leftovers)
                      input
                    (concat leftovers input)))

      (let (messages)
        (while (not (s-blank? chunk))
          (if (not body-length)
              ;; Read headers
              (if-let ((body-sep-pos (string-match-p "\r\n\r\n" chunk)))
                  ;; We've got all the headers, handle them all at once:
                  (setf body-length (lsp--get-body-length
                                     (mapcar #'lsp--parse-header
                                             (split-string
                                              (substring-no-properties chunk
                                                                       (or (string-match-p "Content-Length" chunk)
                                                                           (error "Unable to find Content-Length header."))
                                                                       body-sep-pos)
                                              "\r\n")))
                        body-received 0
                        leftovers nil
                        chunk (substring-no-properties chunk (+ body-sep-pos 4)))

                ;; Haven't found the end of the headers yet. Save everything
                ;; for when the next chunk arrives and await further input.
                (setf leftovers chunk
                      chunk nil))
            (let* ((chunk-length (string-bytes chunk))
                   (left-to-receive (- body-length body-received))
                   (this-body (if (< left-to-receive chunk-length)
                                  (prog1 (substring-no-properties chunk 0 left-to-receive)
                                    (setf chunk (substring-no-properties chunk left-to-receive)))
                                (prog1 chunk
                                  (setf chunk nil))))
                   (body-bytes (string-bytes this-body)))
              (push this-body body)
              (setf body-received (+ body-received body-bytes))
              (when (>= chunk-length left-to-receive)
                (condition-case err
                    (with-temp-buffer
                      (apply #'insert
                             (nreverse
                              (prog1 body
                                (setf leftovers nil
                                      body-length nil
                                      body-received nil
                                      body nil))))
                      (decode-coding-region (point-min)
                                            (point-max)
                                            'utf-8)
                      (goto-char (point-min))
                      (while (search-forward "\\u0000" nil t)
                        (replace-match "" nil t))
                      (goto-char (point-min))
                      (push (lsp-json-read-buffer) messages))

                  (error
                   (lsp-warn "Failed to parse the following chunk:\n'''\n%s\n'''\nwith message %s"
                             (concat leftovers input)
                             err)))))))
        (mapc (lambda (msg)
                (lsp--parser-on-message msg workspace))
              (nreverse messages))))))

Language Server

  1. M-x lsp-install-server select vue-semantic-server
  2. Or use npm/yarn , npm install -g @volar/vue-language-server

Customization

lsp-volar

lsp-volar-take-over-mode

It is enabled by default. If you want disable it, add (setq lsp-volar-take-over-mode nil) to your config file. What is Take Over Mode?

lsp-volar-activate-file

If your project don't have a package.json file with vue dependencies in workspace-root, such as a yarn workspace / mono-repo project, you can add a file with a custom name to force enable @volar/server for this project. The default file name is .volarrc. You can specify any file name by modifying the file lsp-volar-activate-file variable.

lsp-volar-completion-tag-casing

Type: (choice (const both) (const kebabCase) (const pascalCase))

Default: both

Casing conversion for tag completion

lsp-volar-completion-attr-casing

Type: (choice (const kebabCase) (const camelCase))

Default: kebabCase

Casing conversion for attr completion.

Reference

  1. Tutorial: nvim-lspconfig - how to set up multiple language servers
  2. I have multiple language servers registered for language FOO. Which one will be used when opening a project?
  3. I have multiple language servers for language FOO and I want to select the server per project, what can I do?
  4. multiple servers

lsp-volar's People

Contributors

jadestrong avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

lsp-volar's Issues

[QA] multiple features

does lsp volar support:

  • import component to script block when write name in template section ? (as lsp code action)
  • what about eslint check component use in template section when import in script setup section ?
  • does this mode work with web-mode ?

thank you

Error on volar server startup - the argument 'id' must be a non-empty string

I'm using doom emacs and volar version 0.30.2 from the AUR package volar-server-bin, but I've seen this error when using a version installed by lsp-mode as well.
All 3 volar-* processes have this in their logs when I enable lsp-mode logging and browse to a vue file:

[Trace - 08:22:56 ] Sending request 'initialize - (1)'.
Params: {
  "processId": null,
  "rootPath": "/home/ohmree/code/js/my-vue-project",
  "clientInfo": {
    "name": "emacs",
    "version": "GNU Emacs 28.0.90 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.30, cairo version 1.17.4)\n of 2021-12-14"
  },
  "rootUri": "file:///home/ohmree/code/js/my-vue-project",
  "capabilities": {
    "workspace": {
      "workspaceEdit": {
        "documentChanges": true,
        "resourceOperations": [
          "create",
          "rename",
          "delete"
        ]
      },
      "applyEdit": true,
      "symbol": {
        "symbolKind": {
          "valueSet": [
            1,
            2,
            3,
            4,
            5,
            6,
            7,
            8,
            9,
            10,
            11,
            12,
            13,
            14,
            15,
            16,
            17,
            18,
            19,
            20,
            21,
            22,
            23,
            24,
            25,
            26
          ]
        }
      },
      "executeCommand": {
        "dynamicRegistration": false
      },
      "didChangeWatchedFiles": {
        "dynamicRegistration": true
      },
      "workspaceFolders": true,
      "configuration": true,
      "semanticTokens": {
        "refreshSupport": false
      },
      "codeLens": {
        "refreshSupport": true
      },
      "fileOperations": {
        "didCreate": false,
        "willCreate": false,
        "didRename": false,
        "willRename": false,
        "didDelete": false,
        "willDelete": false
      }
    },
    "textDocument": {
      "declaration": {
        "linkSupport": true
      },
      "definition": {
        "linkSupport": true
      },
      "implementation": {
        "linkSupport": true
      },
      "typeDefinition": {
        "linkSupport": true
      },
      "synchronization": {
        "willSave": true,
        "didSave": true,
        "willSaveWaitUntil": true
      },
      "documentSymbol": {
        "symbolKind": {
          "valueSet": [
            1,
            2,
            3,
            4,
            5,
            6,
            7,
            8,
            9,
            10,
            11,
            12,
            13,
            14,
            15,
            16,
            17,
            18,
            19,
            20,
            21,
            22,
            23,
            24,
            25,
            26
          ]
        },
        "hierarchicalDocumentSymbolSupport": true
      },
      "formatting": {
        "dynamicRegistration": true
      },
      "rangeFormatting": {
        "dynamicRegistration": true
      },
      "semanticTokens": {
        "dynamicRegistration": true,
        "requests": {
          "range": true,
          "full": true
        },
        "tokenModifiers": [
          "declaration",
          "definition",
          "readonly",
          "static",
          "deprecated",
          "abstract",
          "async",
          "modification",
          "documentation",
          "defaultLibrary"
        ],
        "tokenTypes": [
          "comment",
          "keyword",
          "string",
          "number",
          "regexp",
          "operator",
          "namespace",
          "type",
          "struct",
          "class",
          "interface",
          "enum",
          "typeParameter",
          "function",
          "method",
          "member",
          "property",
          "event",
          "macro",
          "variable",
          "parameter",
          "label",
          "enumConstant",
          "enumMember",
          "dependent",
          "concept"
        ],
        "formats": [
          "relative"
        ]
      },
      "rename": {
        "dynamicRegistration": true,
        "prepareSupport": true
      },
      "codeAction": {
        "dynamicRegistration": true,
        "isPreferredSupport": true,
        "codeActionLiteralSupport": {
          "codeActionKind": {
            "valueSet": [
              "",
              "quickfix",
              "refactor",
              "refactor.extract",
              "refactor.inline",
              "refactor.rewrite",
              "source",
              "source.organizeImports"
            ]
          }
        },
        "resolveSupport": {
          "properties": [
            "edit",
            "command"
          ]
        },
        "dataSupport": true
      },
      "completion": {
        "completionItem": {
          "snippetSupport": true,
          "documentationFormat": [
            "markdown",
            "plaintext"
          ],
          "resolveAdditionalTextEditsSupport": true,
          "insertReplaceSupport": true,
          "deprecatedSupport": true,
          "resolveSupport": {
            "properties": [
              "documentation",
              "details",
              "additionalTextEdits",
              "command"
            ]
          },
          "insertTextModeSupport": {
            "valueSet": [
              1,
              2
            ]
          }
        },
        "contextSupport": true
      },
      "signatureHelp": {
        "signatureInformation": {
          "parameterInformation": {
            "labelOffsetSupport": true
          }
        }
      },
      "documentLink": {
        "dynamicRegistration": true,
        "tooltipSupport": true
      },
      "hover": {
        "contentFormat": [
          "markdown",
          "plaintext"
        ]
      },
      "foldingRange": {
        "dynamicRegistration": true
      },
      "callHierarchy": {
        "dynamicRegistration": false
      },
      "publishDiagnostics": {
        "relatedInformation": true,
        "tagSupport": {
          "valueSet": [
            1,
            2
          ]
        },
        "versionSupport": true
      },
      "linkedEditingRange": {
        "dynamicRegistration": true
      }
    },
    "window": {
      "workDoneProgress": true,
      "showMessage": null,
      "showDocument": {
        "support": true
      }
    }
  },
  "initializationOptions": {
    "svelte": {
      "plugin": {
        "html": {
          "documentSymbols": {
            "enable": true
          },
          "tagComplete": {
            "enable": true
          },
          "completions": {
            "emmet": true,
            "enable": true
          },
          "hover": {
            "enable": true
          },
          "enable": true
        }
      }
    },
    "typescript": {
      "autoClosingTags": true,
      "check": {
        "npmIsInstalled": true
      },
      "disableAutomaticTypeAcquisition": false,
      "format": {
        "enable": true,
        "insertSpaceAfterCommaDelimiter": true,
        "insertSpaceAfterConstructor": false,
        "insertSpaceAfterFunctionKeywordForAnonymousFunctions": true,
        "insertSpaceAfterKeywordsInControlFlowStatements": true,
        "insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false,
        "insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true,
        "insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false,
        "insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false,
        "insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false,
        "insertSpaceAfterSemicolonInForStatements": true,
        "insertSpaceAfterTypeAssertion": false,
        "insertSpaceBeforeAndAfterBinaryOperators": true,
        "insertSpaceBeforeFunctionParenthesis": false,
        "placeOpenBraceOnNewLineForControlBlocks": false,
        "placeOpenBraceOnNewLineForFunctions": false
      },
      "implementationsCodeLens": {
        "enabled": false
      },
      "preferences": {
        "importModuleSpecifier": "auto",
        "quoteStyle": "auto",
        "renameShorthandProperties": true
      },
      "referencesCodeLens": {
        "enabled": false
      },
      "reportStyleChecksAsWarnings": true,
      "suggest": {
        "autoImports": true,
        "completeFunctionCalls": false,
        "completeJSDocs": true,
        "enabled": true,
        "paths": true
      },
      "suggestionActions": {
        "enabled": true
      },
      "surveys": {
        "enabled": true
      },
      "tsc": {
        "autoDetect": "on"
      },
      "tsserver": {
        "log": "off",
        "trace": "off"
      },
      "updateImportsOnFileMove": {
        "enabled": "prompt"
      },
      "validate": {
        "enable": true
      },
      "serverPath": ""
    },
    "html": {
      "trace": {
        "server": "off"
      },
      "autoClosingTags": true,
      "validate": {
        "styles": true,
        "scripts": true
      },
      "suggest": {
        "html5": true
      },
      "format": {
        "wrapAttributes": "auto",
        "extraLiners": "head, body, /html",
        "endWithNewline": false,
        "indentHandlebars": false,
        "preserveNewLines": true,
        "indentInnerHtml": false,
        "contentUnformatted": "pre,code,textarea",
        "unformatted": "wbr",
        "wrapLineLength": 120,
        "enable": true
      },
      "hover": true
    },
    "vetur": {
      "languageFeatures": {
        "codeActions": true
      }
    },
    "languageFeatures": {
      "references": true,
      "definition": true,
      "typeDefinition": true,
      "callHierarchy": true,
      "hover": true,
      "rename": true,
      "renameFileRefactoring": true,
      "signatureHelp": true,
      "codeAction": true,
      "completion": {
        "defaultTagNameCase": "both",
        "defaultAttrNameCase": "kebabCase",
        "getDocumentNameCasesRequest": false,
        "getDocumentSelectionRequest": false
      },
      "schemaRequestService": true
    }
  },
  "workDoneToken": "1"
}


[Trace - 08:22:56 ] Received response 'initialize - (1)' in 554ms.
Result: {
  "code": -32603,
  "message": "Request initialize failed with message: The argument 'id' must be a non-empty string. Received ''"
}

`lsp-volar--activate-p` unconditionally enables volar on projects that have a vite config

See title, the project was generated by doing pnpm create vite and choosing vanilla-ts.

With the create-vite generated project I also got this f-join error, the cause of which I was able to find using doom-debug-mode.
On another project it didn't seem like I was getting this error, so I didn't think about looking at the stack trace but I have confirmed that when I add the vite config (lsp-volar--activate-p "main.ts") returns non-nil, and nil when I remove it.

I'm using doom emacs and have installed this package according to the doom-specific instructions in the readme.

Sorry if this counts as a duplicate, I just thought I'd share an observation I had when running into issues that weren't necessarily the volarrc-related error mentioned earlier.

EDIT: trying to find a fix for this (that isn't removing the volar-server binary from my system) I came up with this:

;; $DOOMDIR/config.el
(after! lsp-javascript
  (set-lsp-priority! 'ts-ls 2))

It doesn't completely prevent volar from running in non-vue projects but it replaces one of its processes with ts-ls which at least works correctly for regular typescript code, with the minor annoyance that there's a constant loading bar in the bottom right corner (which I'm assuming is because the volar startup process is getting nowhere without an actual vue file).

If anyone knows of a better hack until this gets fixed I'd love to know about it.

EDIT 2:
Setting lsp-volar-take-over-mode to nil seems to work better than the hack in my first edit (assuming the user is fine with the performance implications described here).

Volar is adding 3 language servers

Hi. I'm using spacemacs and for some reason when LSP starts in vue-mode it adds 3 language servers. Those are:

(server-id volar-api, priority 0), (server-id eslint, priority -1), (server-id volar-doc, priority 0), (server-id volar-html, priority 0)

You can see all three in this screenshot:
image

This makes things like doc help and go to definition show the same thing three times. Here's an example:

image

image

And also it adds wherever I'm at in the file 3 times to the header:

image

This is unexpected behavior. Is there a work around so that it's only using, say, volar-api given that they all seem to have the same functionality?

save error

lsp--apply-workspace-edit: Wrong type argument: hash-table-p, (#s(hash-table size 1 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("documentChanges" [#s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("textDocument" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("uri" "file:///Users/buck/Project/vite-vue/src/App.vue" "version" 0)) "edits" [#s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("newText" "../../../.emacs.d/.backups/!Users!buck!Project!vite-vue!src!components!HelloWorld.vue~" "range" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("start" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("line" 3 "character" 24)) "end" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("line" 3 "character" 51))))))])) #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("textDocument" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("uri" "file:///Users/buck/Project/vite-vue/src/App.vue" "version" 0)) "edits" [#s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("newText" "../../../.emacs.d/.backups/!Users!buck!Project!vite-vue!src!components!HelloWorld.vue~" "range" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("start" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("line" 3 "character" 24)) "end" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("line" 3 "character" 51))))))]))])) #s(hash-table size 1 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("documentChanges" [#s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("textDocument" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("uri" "file:///Users/buck/Project/vite-vue/src/App.vue" "version" 0)) "edits" [#s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("newText" "../../../.emacs.d/.backups/!Users!buck!Project!vite-vue!src!components!HelloWorld.vue~" "range" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("start" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("line" 3 "character" 24)) "end" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("line" 3 "character" 51))))))])) #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("textDocument" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("uri" "file:///Users/buck/Project/vite-vue/src/App.vue" "version" 0)) "edits" [#s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("newText" "../../../.emacs.d/.backups/!Users!buck!Project!vite-vue!src!components!HelloWorld.vue~" "range" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("start" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("line" 3 "character" 24)) "end" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("line" 3 "character" 51))))))]))])))

Project create with Vue CLI does not start LS

A project that was created with Vue CLI does not start the Language Server. Volar is not included as available servers to be used, even if the filetype is .vue.

These are the available language servers that lsp-mode offers when opening a file:
image

This issue is not present when the volar-start project is used.

I've checked/tried the following:

  • vue is included in the package.json dependencies
  • .volarrc is added to the root of the project

Disable document.getDocumentVersionRequest

I think volar uses its own method that doesn't align with the spec - it's vue/docVersion. This results in stuff like this:
image

I actually had the exact same problem in my custom volar lsp config in neovim, and I solved it by disabling getting the doc version: https://github.com/sethidden/dotfiles/commit/502a1437cb31c919cd0ee44933fcf6f107c1e4a0#diff-23e3c33e20e88165b0a3ff0e996bd3347b820b0b36731dab1a04a4f9cbc3373aR185

By the way: now that lsp-volar is merged into lsp-mode, do you know it it's possible to get the latest commit of lsp-mode in doom? I see that lsp-mode has 2 releases per year which is a really long wait. Was wondering if it's possible to get it earlier

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.