manateelazycat / lsp-bridge

A blazingly fast LSP client for Emacs
GNU General Public License v3.0
1.46k stars 214 forks source link

LSP Tailwind fails #882

Closed artemkovalyov closed 8 months ago

artemkovalyov commented 8 months ago

Hi there, I tried to add the Tailwindcss LSP server to my project which worked. But for any completion request, it always has 0 candidates.

What would be the usual way to connect a new server? I tried it as a single server on a Svelte file together with a multiserver configuration with Svelte LSP. Svelte returns the results, Tailwind does not.

I activated debug but there's nothing obvious.

--- [12:57:49.819310] Send textDocument/completion request (4771) to 'tailwindcss' for project someoneinmyhead
{
   "id": 4771,
   "method": "textDocument/completion",
   "params": {
      "position": {
         "line": 11,
         "character": 117
      },
      "context": {
         "triggerKind": 1
      },
      "textDocument": {
         "uri": "file:///umetra/someoneinmyhead/src/lib/components/NavBar.svelte"
      }
   },
   "message_type": "request",
   "jsonrpc": "2.0"
}

--- [12:57:49.820308] Recv textDocument/completion response (4771) from 'tailwindcss' for project someoneinmyhead

--- [12:57:49.820385] Got completion candidates (0) from 'tailwindcss' for file NavBar.svelte

--- [12:57:49.820424] Record completion candidates (0) from 'tailwindcss' for file NavBar.svelte
Eval in Emacs: (lsp-bridge-completion--record-items '"/umetra/someoneinmyhead/src/lib/components/NavBar.svelte" '"" '() '(:line 11 :character 117) '"tailwindcss" '("\"" "'" "`" " " "." "(" "[" "!" "/" ":") '("tailwindcss"))
{
   "jsonrpc": "2.0",
   "id": 4771,
   "result": null
}

What would you recommend doing from here?

artemkovalyov commented 8 months ago

How do I send initializationOptions ? I tried smth like this, but didn't work:

{
  "name": "tailwindcss",
  "languageId": "tailwindcss",
  "command": ["tailwindcss-language-server", "--stdio"],
  "settings": {
    "tailwindCSS": {
      "emmetCompletions": false,
      "showPixelEquivalents": true,
      "rootFontSize": 16,
      "validate": true,
      "hovers": true,
      "suggestions": true,
      "codeActions": true,
      "lint": {
        "invalidScreen": "error",
        "invalidVariant": "error",
        "invalidTailwindDirective": "error",
        "invalidApply": "error",
        "invalidConfigPath": "error",
        "cssConflict": "warning",
        "recommendedVariantOrder": "warning"
      },
      "experimental": {
        "classRegex": ""
      },
      "classAttributes": ["class", "className", "ngClass"]
    }
  }
}
manateelazycat commented 8 months ago

We have tried supporting Tailwind LSP server, but Tailwind LSP server does not return any completion information.

Therefore, lsp-bridge has a built-in backend for Tailwind. Although it cannot perform syntax completion like Tailwind LSP server, it will complete Tailwind's CSS keywords, which requires you to add the tailwind.config.js file in the project root location.

artemkovalyov commented 8 months ago

Hey, @manateelazycat, thanks for getting back. This backend is cool but I believe it doesn't reflect custom changes, does it?

Somehow this backend from lsp-mode works pretty Ok. It's slow, but it gives relevant completion.

I traced their logs, here's how the eventual configuration looks like:

[Trace - 07:18:09 PM] Sending response 'workspace/configuration - (1)'. Processing request took 0ms
Params: {
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "emmetCompletions": false,
      "showPixelEquivalents": true,
      "rootFontSize": 16,
      "validate": true,
      "hovers": true,
      "suggestions": true,
      "codeActions": true,
      "lint": {
        "invalidScreen": "error",
        "invalidVariant": "error",
        "invalidTailwindDirective": "error",
        "invalidApply": "error",
        "invalidConfigPath": "error",
        "cssConflict": "warning",
        "recommendedVariantOrder": "warning"
      },
      "experimental": {
        "classRegex": ""
      },
      "classAttributes": [
        "class",
        "className",
        "ngClass"
      ]
    }
  ]
}

The actual config in code looks like this.

Could it be vital? I struggled to understand how to properly provide these settings via the lsp-bridge config. If you help, I'll happily contribute:) I didn't find a way to send those initializationOptions to see if it could be a quick fix.

artemkovalyov commented 8 months ago

The response is indeed returned. I use the same server, basically same machine with the server globally installed: Tailwing would be a super cool secondary LSP for so many servers and it would require then less maintenance.

[Trace - 07:34:31 PM] Received response 'textDocument/completion - (29)' in 622ms.
Result: {
  "isIncomplete": null,
  "items": [
    {
      "kind": 9,
      "data": {
        "_projectKey": "0",
        "_type": "variant"
      },
      "command": {
        "title": "",
        "command": "editor.action.triggerSuggest"
      },
      "sortText": "-00000000",
      "label": "*:",
      "detail": "& > *",
      "additionalTextEdits": [],
      "textEdit": {
        "newText": "*:",
        "range": {
          "start": {
            "line": 11,
            "character": 116
          },
          "end": {
            "line": 11,
            "character": 125
          }
        }
      }
    },
    {
      "kind": 9,
      "data": {
        "_projectKey": "0",
        "_type": "variant"
      },
      "command": {
        "title": "",
        "command": "editor.action.triggerSuggest"
      },
      "sortText": "-00000001",
      "label": "first-letter:",
      "detail": "&::first-letter",
      "additionalTextEdits": [],
      "textEdit": {
        "newText": "first-letter:",
        "range": {
          "start": {
            "line": 11,
            "character": 116
          },
          "end": {
            "line": 11,
            "character": 125
          }
        }
      }
    },
    {
      "kind": 9,
      "data": {
        "_projectKey": "0",
        "_type": "variant"
      },
      "command": {
        "title": "",
        "command": "editor.action.triggerSuggest"
      },
      "sortText": "-00000002",
      "label": "first-line:",
      "detail": "&::first-line",
      "additionalTextEdits": [],
      "textEdit": {
        "newText": "first-line:",
        "range": {
          "start": {
            "line": 11,
            "character": 116
          },
          "end": {
            "line": 11,
            "character": 125
          }
        }
      }
    },
artemkovalyov commented 8 months ago

Can you advise how I influence the initialize request? Meaning how to I add anything into it's fields by leveraging lsp-bridge config files?

manateelazycat commented 8 months ago

Hey, @manateelazycat, thanks for getting back. This backend is cool but I believe it doesn't reflect custom changes, does it?

Somehow this backend from lsp-mode works pretty Ok. It's slow, but it gives relevant completion.

I traced their logs, here's how the eventual configuration looks like:

[Trace - 07:18:09 PM] Sending response 'workspace/configuration - (1)'. Processing request took 0ms
Params: {
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "emmetCompletions": false,
      "showPixelEquivalents": true,
      "rootFontSize": 16,
      "validate": true,
      "hovers": true,
      "suggestions": true,
      "codeActions": true,
      "lint": {
        "invalidScreen": "error",
        "invalidVariant": "error",
        "invalidTailwindDirective": "error",
        "invalidApply": "error",
        "invalidConfigPath": "error",
        "cssConflict": "warning",
        "recommendedVariantOrder": "warning"
      },
      "experimental": {
        "classRegex": ""
      },
      "classAttributes": [
        "class",
        "className",
        "ngClass"
      ]
    }
  ]
}

The actual config in code looks like this.

Could it be vital? I struggled to understand how to properly provide these settings via the lsp-bridge config. If you help, I'll happily contribute:) I didn't find a way to send those initializationOptions to see if it could be a quick fix.

If you want send response to workspace/configuration, please track https://github.com/manateelazycat/lsp-bridge/blob/7c703394448d9610a1048100e4fbbc926c977885/core/lspserver.py#L644

and

https://github.com/manateelazycat/lsp-bridge/blob/7c703394448d9610a1048100e4fbbc926c977885/core/lspserver.py#L503

If you want response to initialize , example send customize initializationOptions, you need create tailwindcss.json under directory lspbridge/langserver, then fill initializationOptions field in tailwindcss.json, example

https://github.com/manateelazycat/lsp-bridge/blob/7c703394448d9610a1048100e4fbbc926c977885/langserver/jdtls.json#L15

artemkovalyov commented 8 months ago

Thanks for quickly getting back. I played with configuration in many ways and tried to compare the communication logs, but no luck or magic so far. I might ask the author of the lsp-tailwind package. There everything works well, hover, autocomplete, etc.

I'm lacking knowledge a bit, to hack with it further, but your suggestion helped me move forward with ideas. lsp-bridge is absolutely great and solves quite some fundamental issues around LSP support.

artemkovalyov commented 8 months ago

@manateelazycat, my debugging via logs didn't yield result yet. The server configuration sequences look pretty similar now but completion requests return nothing for lsp-bridge while for very similar requests for lsp-mode it does work. I used the latest tailwindcss server version for both clients on the very same project. Attaching session logs if someone can help: lsp-bridge-log.json lsp-mode-log.json

Here's my config, tailwindcss.json

Any ideas how to debug it further? Are there logs generated by python for server calls, serialization, etc.? Feels like I miss smth obvious knowing it works.

manateelazycat commented 8 months ago

We have tried the log you fed back more than a year ago. We don’t know why the /competitions request is still not returned after normal feedback from the request request. We don’t know the reason.

artemkovalyov commented 8 months ago

@manateelazycat, alright, it makes sense. If I figure out that black magic one day, I'll contribute;) Lsp-bridge is a great tool.