helix: Tailwind language server shows errors

Helix showing me this:

Async job failed: protocol error: Method not found: Unhandled method textDocument/completion

And there is my languages.toml

[[language]]
name = "tailwind"
scope = "source.svelte"
roots = [".npmrc"]
file-types = ["svelte"]
language-server = { command = "/home/yura/.local/share/nvim/lsp_servers/tailwindcss_npm/node_modules/@tailwindcss/language-server/bin/tailwindcss-language-server", args = ["--stdio"] }

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 71 (21 by maintainers)

Commits related to this issue

Most upvoted comments

I looked into this some, it appears that the tailwindcss language server expects the config to be an object, and so crashes when a config is not provided, which means the language server never registers the textDocument/completion handler.

Here are the specific lines

      userLanguages: params.initializationOptions.userLanguages
        ? params.initializationOptions.userLanguages
        : {},

Tailwindcss never checks to make sure initializationOptions is in fact an object.

My configuration file that does not produce that error looks like this

[[language]]
name = "tailwindcss"
scope = "source.css"
injection-regex = "(postcss|css|html)"
file-types = ["css"]
roots = ["tailwind.config.js","tailwind.config.cjs"]
language-server = { command = "tailwindcss-language-server", args = ["-vvv", "--stdio"] }
indent = { tab-width = 2, unit = "  " }
config = { } # <---- this is the partial fix

But even though the error went away (and the logs show the language server working), it’s still not giving completions. (The server keeps returning null for the list of completions)

2022-11-08T16:06:58.671 helix_lsp::transport [INFO] -> {"jsonrpc":"2.0","method":"textDocument/completion","params":{"position":{"character":16,"line":1},"textDocument":{"uri":"file:///home/andrew/Code/js/spry/landing-svelte/src/routes/+page.svelte"}},"id":4}
2022-11-08T16:06:58.674 helix_lsp::transport [INFO] <- {"jsonrpc":"2.0","id":4,"result":null}

I haven’t figured the issue out, but I thought I would write down what I’ve discovered so far.

Update: In a .postcss file after setting the language to tailwindcss, autocomplete works, it is just in svelte that it isn’t working

Update 2:

I solved it! Tailwindcss determines which type of file you are in based on the language-id parameter, so a working configuration for svelte files (only) is below.

[[language]]
name = "tailwind-svelte"
scope = "source.svelte"
file-types = ["svelte"]
roots = ["tailwind.config.js","tailwind.config.cjs"]
language-server = { language-id = "svelte", command = "tailwindcss-language-server", args = ["--stdio"] }
config = { }

You need to modify each language tailwindcss works with and overwrite it with tailwindcss and the correct language-id. Unfortunately, this overwrites the existing language server for all those languages. Until #2507 is merged, there isn’t a way to add two language servers to the same language. Once that PR is merged a configuration file for tailwindcss (for Svelte, CSS, and HTML) would look like this (which is the config I am currently using after building the PR myself).

[[language]]
name = "svelte"
scope = "source.svelte"
file-types = ["svelte"]
roots = ["tailwind.config.js","tailwind.config.cjs"]
language-servers = [ "tailwindcss-svelte", "svelteserver" ]

[language-server.tailwindcss-svelte]
language-id = "svelte"
command = "tailwindcss-language-server"
args = ["--stdio"]
config = { }

[[language]]
name = "css"
scope = "source.css"
file-types = ["css", "postcss"]
language-servers = [ "tailwindcss-css", "vscode-css-language-server" ]

[language-server.tailwindcss-css]
language-id = "css"
command = "tailwindcss-language-server"
args = ["--stdio"]
config = { }

[[language]]
name = "html"
scope = "text.html.basic"
file-types = ["html"]
language-servers = [ "tailwindcss-html", "vscode-html-language-server" ]

[language-server.tailwindcss-html]
language-id = "html"
command = "tailwindcss-language-server"
args = ["--stdio"]
config = { }

TailwindLSP was working for me on node v16. On v18 not so much. I tried to debug it(this branch) Helix doesn’t respond to these two requests:

2023-05-21T18:18:29.678 helix_lsp::transport [INFO] tailwindcss-vue <- {"jsonrpc":"2.0","id":0,"method":"workspace/configuration","params":{"items":[{"section":"editor"}]}}
2023-05-21T18:18:29.678 helix_lsp::transport [INFO] tailwindcss-vue <- {"jsonrpc":"2.0","id":1,"method":"workspace/configuration","params":{"items":[{"section":"tailwindCSS"}]}}

I tried to stop these two requests and insert default values(from other editors) and it works(Linux) for React, Vue and Svelte 😃

tw

npm npm i helix-twcss -g

#other language servers and languages
...
# tailwind react
[language-server.tailwindcss-react]
language-id = "javascriptreact"
command = "hx-tw"
config = { }
args = ["--stdio"]
timeout = 3

# tailwind vue
[language-server.tailwindcss-vue]
language-id = "vue"
command = "hx-tw"
args = ["--stdio"]
timeout = 5

[[language]]
name = "vue"
scope = "source.vue"
file-types = ["vue"]
roots = ["package.json", "tailwind.config.js","tailwind.config.cjs", ".prettierrc.json"]
language-servers = ["volar","tailwindcss-vue"]
injection-regex = "vue"
formatter = {command = "prettier", args = ["--parser", "vue"]}
auto-format = true

[[language]]
name = "tsx"
language-servers = ["tailwindcss-react", "tsreact"]
roots = ["tailwind.config.js","tailwind.config.cjs", ".prettierrc.json"]

[[language]]
name = "jsx"
language-servers = ["tailwindcss-react", "tsreact"]
roots = ["tailwind.config.js","tailwind.config.cjs", ".prettierrc.json"]
...

Until helix client doesn’t respond to workspace/configuration I will use this.

In case anyone else lands here wondering why it still doesn’t work despite all the above, for me the trick was installing the insiders version of @tailwindcss/language-server instead of the default latest stable release. I see this was mentioned above but I wanted to highlight it and give a little more detail.

npm install -g @tailwindcss/language-server@insiders

Then (because the config for the language server is built in) all you have to do is add it to the list for your file type:

[[language]]
name = "tsx"
language-servers = [ "typescript-language-server", "tailwindcss-ls" ]

Before installing insiders I was getting errors like this

2023-10-26T12:44:18.885 helix_lsp::client [WARN] language server failed to terminate gracefully - server closed the stream
2023-10-26T12:44:18.899 helix_lsp::transport [ERROR] tailwindcss-ls err: <- StreamClosed

For anyone still following the latest version of tailwindcss-language-server was just released (with the fix needed to make this work properly, version 0.0.14). I’m making a package in nixpkgs for those using nixos https://github.com/NixOS/nixpkgs/pull/264899

Anyone do this with tsx files ?

helix-twcss has been updated. Let’s hope this tailwindlabs/tailwindcss-intellisense#803 gets merged so we don’t need to maintain separate language server.

Once https://github.com/tailwindlabs/tailwindcss-intellisense/pull/656 is released the config will be able to be empty without causing tailwind to crash, which fixes this bug.

@sukidhar Your language-id needs to be under the language definition, not the language-server definition.

Example:

[language-server.lexical]
command = "/Users/jelkand/dev/lexical/_build/dev/package/lexical/bin/start_lexical.sh"

[language-server.tailwind-heex]
command = "tailwindcss-language-server"
args = ["--stdio"]

[[language]]
name = "elixir"
language-servers = ["lexical"]
auto-format = true

[[language]]
name = "heex"
language-id = "phoenix-heex"
language-servers = ["tailwind-heex", "lexical"]
auto-format = true

The hyphen stuff is a helix problem that will be fixed with the event system

The fix has been merged in the tailwindcss intellisense: https://github.com/tailwindlabs/tailwindcss-intellisense/pull/803

@jelkand did you ever to manage to get tailwind working with elixir (so inside ~H)?

I haven’t tested this extensively, but providing language-id = "phoenix-heex" also provides tailwind autocomplete within the H sigils. Lexical doesn’t seem to mind and still provides autocomplete too.

https://github.com/helix-editor/helix/commit/68fce3e160c64c488567f0e80f8d57bbbdd9dd82 was merged… I suggest updating your configs to avoid cruft and bloat. Keep it clean 😃

you can use the insiders build: npm install @tailwindcss/language-server@insiders

@swlkr maybe you want to move this into a discussion. I’m happy to help because I have working version for javascript/typescript with tailwind running with npx. I do get null answers when I try to use it with elixir.

any info for this? not working and even broke svelte syntax highlighting and completions

my languages.toml file:

[[language]]
name = "tailwind"
scope = "source.svelte"
file-types = ["svelte"]
roots = ["tailwind.config.js","tailwind.config.cjs"]
language-server = { command = "tailwindcss-language-server", args = ["--stdio"] }

Could you file an issue upstream ? There is a new developper on the project that is very responsive. If its a simple fix, it will likely be taken care of.

For anyone still following the latest version of tailwindcss-language-server was just released (with the fix needed to make this work properly, version 0.0.14). I’m making a package in nixpkgs for those using nixos NixOS/nixpkgs#264899

Can confirm v0.0.14 of @tailwindcss/language-server works (atleast for svelte files)! One issue I am noticing though is that the hyphens in Tailwind’s class names is causing the LSP suggestions to break.

Here is my working config:

[[language]]
name = "svelte"
indent = { tab-width = 4, unit = "\t" }
auto-format = true
roots = ["svelte.config.js"]
language-servers = ["tailwindcss-ls", "svelteserver"]

Here are screenshots of that hyphen issue, also for some reason certain html elements don’t have syntax highlighting on the opening tag, oh well. Without hyphens: image Then with hyphens: image

I can’t make this work with svelteserver, is either one or the other depending on which one is declared first in language-servers.

Edit:

i ended up implementing something similar to @uros-5 (before realizing it had been done before) in https://github.com/catdevnull/helix/tree/multiple-lsp-hover. thanks!

uros’ implementation is better for the jsx/svelte + tailwind use case because it just pushes the result of the first server that returns. but mine “tries” (but probably fails, didn’t test) to get hovers from all servers to merge them all together in the same hover window, which could be helpful for some weird use case where you want to see multiple hovers from multiple servers.

Applied the changes in this commit manually since master is way ahead and recompiled, now it works fine.

To be sure, the fix was upstreamed on master. They mentioned they were about to do a release this week, but its still pending. Ive been in touch with upstream and i will add this to nixpkgs after the release for those interested.

I have made a pull request to get Tailwind into Helix officially, please could everyone involved in this thread hop over and have a look as you all have more experience than me! 😃

https://github.com/helix-editor/helix/pull/8442

seems like the other pr to fix tailwind with helix hasn’t been released yet: https://github.com/tailwindlabs/tailwindcss-intellisense/pull/803 try the insiders command recommended in this pr

i ended up implementing something similar to @uros-5 (before realizing it had been done before) in https://github.com/catdevnull/helix/tree/multiple-lsp-hover. thanks!

uros’ implementation is better for the jsx/svelte + tailwind use case because it just pushes the result of the first server that returns. but mine “tries” (but probably fails, didn’t test) to get hovers from all servers to merge them all together in the same hover window, which could be helpful for some weird use case where you want to see multiple hovers from multiple servers.

There seems to be some bugs in Tailwind’s language server, more info here: https://github.com/tailwindlabs/tailwindcss-intellisense/issues/802

So far, I don’t think Helix’s lsp implementation is to blame.

EDIT: helix-twcss ? how do I do that?

Please read previous comments… It’s not that hard.

as mentioned above, it still does not show any hover. sorry I missed that. this is my languages.toml configuration do you see anything that might be wrong?

[[language]]
name = "typescript"
scope = "source.ts"
injection-regex = "(ts|typescript)"
language-servers = [{except-features = ["format"], name = "typescript-language-server"}, "tailwindcss-react", "eslint"]
roots = ["tailwind.config.js","tailwind.config.cjs", ".prettierrc.json"]
file-types = ["ts", "mts", "cts"]
formatter = { command = 'prettier', args = ["--stdin-filepath", "file.ts"] }
indent = { tab-width = 4, unit = "\t" }
auto-format = true

[[language]]
language-servers = [{except-features = ["format"], name = "typescript-language-server"}, "tailwindcss-react", "eslint"]
roots = ["tailwind.config.js","tailwind.config.cjs", ".prettierrc.json"]
name = "javascript"
scope = "source.js"
injection-regex = "(js|javascript)"
file-types = ["js", "mjs", "cjs"]
formatter = { command = 'prettier', args = ["--stdin-filepath", "file.js"] }
indent = { tab-width = 4, unit = "\t" }
auto-format = true

[[language]]
language-servers = [{except-features = ["format"], name = "typescript-language-server"}, "tailwindcss-react", "eslint"]
roots = ["tailwind.config.js","tailwind.config.cjs", ".prettierrc.json"]
name = "jsx"
scope = "source.jsx"
injection-regex = "jsx"
file-types = ["jsx"]
formatter = { command = 'prettier', args = ["--stdin-filepath", "file.jsx"] }
indent = { tab-width = 4, unit = "\t" }
auto-format = true

[[language]]
language-servers = [{except-features = ["format"], name = "typescript-language-server"}, "tailwindcss-react" , "eslint"]
roots = ["tailwind.config.js","tailwind.config.cjs", ".prettierrc.json"]
name = "tsx"
scope = "source.tsx"
injection-regex = "(tsx)" # |typescript
file-types = ["tsx"]
formatter = { command = 'prettier', args = ["--stdin-filepath", "file.tsx"] }
indent = { tab-width = 4, unit = "\t" }
auto-format = true

[[language]]
name = "html"
scope = "text.html.basic"
injection-regex = "html"
file-types = ["html"]
language-servers = ["tailwindcss-react","vscode-html-language-server"]
roots = ["tailwind.config.js","tailwind.config.cjs", ".prettierrc.json"]
auto-format = true
indent = { tab-width = 4, unit = "\t" }

[[language]]
name = "css"
scope = "source.css"
injection-regex = "css"
file-types = ["css"]
language-servers = ["tailwindcss-react", "vscode-css-language-server"]
roots = ["tailwind.config.js","tailwind.config.cjs", ".prettierrc.json"]
auto-format = true
indent = { tab-width = 4, unit = "\t" }

[language-server.tailwindcss-react]
language-id = "javascriptreact"
command = "hx-tw"
config = { }
args = ["--stdio"]
timeout = 3

[language-server.eslint]
args = ["--stdio"]
command = "vscode-eslint-language-server"

[language-server.eslint.config]
format = true
nodePath = ""
onIgnoredFiles = "off"
quiet = false
rulesCustomizations = []
run = "onType"
validate = "on"

[language-server.eslint.config.codeAction]
[language-server.eslint.config.codeAction.disableRuleComment]
enable = true
location = "separateLine"

[language-server.eslint.config.codeAction.showDocumentation]
enable = true

[language-server.eslint.config.codeActionOnSave]
enable = true
mode = "all"

[language-server.eslint.config.workingDirectory]
mode = "location"

[language-server.typescript-language-server]
args = ["--stdio"]
command = "typescript-language-server"

[language-server.typescript-language-server.config]
documentFormatting = false

EDIT: helix-twcss ? how do I do that?

Please read previous comments… It’s not that hard.

Don’t have much time right now…

language-id is a language specific element (a language-server can support multiple different languages). So this should be under the relevant language svelte, but by default if language-id under the language isn’t defined, the name attribute is used instead.

What may give some insight is running helix with the verbose flag (-v) and checking the logs (in linux ~/.cache/helix/helix.log).

For tsx the language-id that is used by default is typescriptreact which follows the recommendation in https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentItem

Current problem is that with #2507, hover doesn’t work if tailwindcss is not first language added to language-servers

When Svelte or Vue are second in that array then their features are not working.

I tried to change that, and it works 😃

My temp fork.