Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use it with Ruby on Rails bundled tailwind #34

Closed
gobijan opened this issue Mar 24, 2022 · 19 comments · Fixed by #35
Closed

Use it with Ruby on Rails bundled tailwind #34

gobijan opened this issue Mar 24, 2022 · 19 comments · Fixed by #35

Comments

@gobijan
Copy link
Contributor

gobijan commented Mar 24, 2022

Hi I'm creating a new Rails project with
rails new example -c tailwind

This setup works without npm installed by providing the official tailwindcss executable that is standalone and puts a shim here:
~/.rbenv/shims/tailwindcss

However when I want to use the LSP now I can't because it says tailwind is not installed even though I clearly have access to it and it works in my rails project.

Is there a way to specify the tailwind executable or install the language server globally?
How can this work with Rails?

@davidwebca
Copy link

Just chiming in for clarity: Rails now ship with the new pkg powered binary: https://tailwindcss.com/blog/standalone-cli. Rails and Phoenix are moving away from including npm scripts and bundling by default citing the default support for ES6 and http2 in-browser being good enough to provide unbundled code and "liberating" users by letting them choose the bundler of their choice if need be.

That being said, it just means that the plugin should be adapting "is_tailwind_installed" to check for the binary as fallback for not finding the node module. I would suggest to prioritize the node_module if it's found first, over the binary, in case someone installs the binary globally but is still working on a project with local node modules.

@predragnikolic
Copy link
Member

I'm will probably drop the is_allowed_to_start logic entirely

def is_allowed_to_start(

I left this comment a while ago,
#30 (comment)
For me it seems better to just let the server start
and let the server decide if it can start in a workspace or not.

@davidwebca
Copy link

Yeah, I think that would remove useless complexity on your end and you could simply gracefully log a message in the console if you can't find any tailwind executables. I don't know how other people manage their LSP servers, but I enable most of mine globally since I work with the same stack very often so it makes sense. 🤷

@rwols
Copy link
Member

rwols commented Mar 25, 2022

This kind of method is there to guard against a modal dialog informing the user that the server won’t start. If the tailwindcss server doesn’t reply with an error to the initialize request then it’s okay to remove this check. If not, then you could expect new issues about this server not starting in web projects that are not set up for tailwind.

@gobijan
Copy link
Contributor Author

gobijan commented Mar 25, 2022

The selectors should probably also get extended to include text.html.ruby, text.html.rails, text.haml

@predragnikolic
Copy link
Member

Created a PR to fix this.
If anyone of you can test this it would be nice.
If not, I'll probably merge this sometime this week.


The selectors should probably also get extended to include text.html.ruby, text.html.rails, text.haml

I do not develop in ruby/rails,
so I am not sure what syntax you need to have installed to have syntax highlighting in html files.

If you can create a PR for that, I would happily review it.

@gobijan
Copy link
Contributor Author

gobijan commented Mar 28, 2022

Adding this PR too it now works out of the box for Rails :)
https://github.com/sublimelsp/LSP-tailwindcss/pull/36/files

@hovsater
Copy link

hovsater commented Jul 4, 2022

Have it been tested to work? I just tried it out and it does not seem to work for me. I'm running Rails 7 with the standalone version of Tailwind and I do not get autocompletions in Rails related files (.html.erb).

@hovsater
Copy link

hovsater commented Jul 4, 2022

Actually got it working by adding a language id override for text.html.rails to html. I went into Preferences: LSP Language ID Mapping Overrides and added the following:

{
	"text.html.rails": "html"
}

What didn't seem to work however was going into Preferences: LSP-tailwindcss Settings and setting tailwindCSS.includeLanguages to the following:

{
	"settings":
	{
		"tailwindCSS.includeLanguages": {
			"rails": "html"
		}
	},
}

Not sure why. According to the tailwindcss-intellisense documentation it should be enough. I've attached the LSP debug output below.

LSP debug output
:: --> LSP-tailwindcss initialize(1): {'rootUri': 'file:///Users/kevin/code/timetrail', 'workspaceFolders': [{'uri': 'file:///Users/kevin/code/timetrail', 'name': 'timetrail'}], 'processId': 91406, 'rootPath': '/Users/kevin/code/timetrail', 'clientInfo': {'version': '1.16.3', 'name': 'Sublime Text LSP'}, 'initializationOptions': {}, 'capabilities': {'workspace': {'workspaceEdit': {'failureHandling': 'abort', 'documentChanges': True}, 'didChangeConfiguration': {'dynamicRegistration': True}, 'codeLens': {'refreshSupport': True}, 'semanticTokens': {'refreshSupport': True}, 'workspaceFolders': True, 'executeCommand': {}, 'applyEdit': True, 'configuration': 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]}, 'dynamicRegistration': True, 'tagSupport': {'valueSet': [1]}}}, 'textDocument': {'formatting': {'dynamicRegistration': True}, 'declaration': {'dynamicRegistration': True, 'linkSupport': True}, 'rangeFormatting': {'dynamicRegistration': True}, 'signatureHelp': {'dynamicRegistration': True, 'signatureInformation': {'parameterInformation': {'labelOffsetSupport': True}, 'documentationFormat': ['markdown', 'plaintext']}}, 'implementation': {'dynamicRegistration': True, 'linkSupport': True}, 'codeAction': {'dataSupport': True, 'dynamicRegistration': True, 'resolveSupport': {'properties': ['edit']}, 'disabledSupport': True, 'codeActionLiteralSupport': {'codeActionKind': {'valueSet': ['quickfix', 'refactor', 'refactor.extract', 'refactor.inline', 'refactor.rewrite', 'source.organizeImports']}}}, 'completion': {'dynamicRegistration': True, 'completionItemKind': {'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]}, 'completionItem': {'snippetSupport': True, 'insertTextModeSupport': {'valueSet': [2]}, 'resolveSupport': {'properties': ['detail', 'documentation', 'additionalTextEdits']}, 'labelDetailsSupport': True, 'documentationFormat': ['markdown', 'plaintext'], 'deprecatedSupport': True, 'tagSupport': {'valueSet': [1]}}, 'insertTextMode': 2}, 'synchronization': {'willSaveWaitUntil': True, 'dynamicRegistration': True, 'willSave': True, 'didSave': 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]}, 'dynamicRegistration': True, 'hierarchicalDocumentSymbolSupport': True, 'tagSupport': {'valueSet': [1]}}, 'rename': {'prepareSupport': True, 'dynamicRegistration': True}, 'colorProvider': {'dynamicRegistration': True}, 'selectionRange': {'dynamicRegistration': True}, 'semanticTokens': {'formats': ['relative'], 'multilineTokenSupport': True, 'tokenTypes': ['struct', 'type', 'number', 'class', 'string', 'enumMember', 'enum', 'event', 'macro', 'operator', 'comment', 'modifier', 'method', 'namespace', 'property', 'function', 'variable', 'interface', 'keyword', 'regexp', 'typeParameter', 'parameter'], 'dynamicRegistration': True, 'augmentsSyntaxTokens': True, 'overlappingTokenSupport': False, 'tokenModifiers': ['modification', 'declaration', 'documentation', 'async', 'static', 'defaultLibrary', 'abstract', 'definition', 'readonly', 'deprecated'], 'requests': {'range': True, 'full': {'delta': True}}}, 'publishDiagnostics': {'dataSupport': True, 'versionSupport': True, 'relatedInformation': True, 'codeDescriptionSupport': True, 'tagSupport': {'valueSet': [1, 2]}}, 'documentHighlight': {'dynamicRegistration': True}, 'references': {'dynamicRegistration': True}, 'definition': {'dynamicRegistration': True, 'linkSupport': True}, 'documentLink': {'dynamicRegistration': True, 'tooltipSupport': True}, 'codeLens': {'dynamicRegistration': True}, 'hover': {'dynamicRegistration': True, 'contentFormat': ['markdown', 'plaintext']}, 'typeDefinition': {'dynamicRegistration': True, 'linkSupport': True}}, 'general': {'regularExpressions': {'engine': 'ECMAScript'}, 'markdown': {'version': '3.2.2', 'parser': 'Python-Markdown'}}, 'window': {'workDoneProgress': True, 'showDocument': {'support': True}, 'showMessage': {'messageActionItem': {'additionalPropertiesSupport': True}}}}}
:: <<< LSP-tailwindcss 1: {'capabilities': {'textDocumentSync': {'change': {'syncKind': 1}, 'didClose': {}, 'didOpen': {}, 'save': {}}}}
::  -> LSP-tailwindcss initialized: {}
::  -> LSP-tailwindcss workspace/didChangeConfiguration: {'settings': {'tailwindCSS': {'emmetCompletions': False, 'files': {'exclude': ['**/.git/**', '**/node_modules/**', '**/.hg/**']}, 'rootFontSize': 16, 'showPixelEquivalents': True, 'experimental': {'classRegex': []}, 'lint': {'invalidConfigPath': 'error', 'invalidTailwindDirective': 'error', 'cssConflict': 'warning', 'invalidVariant': 'error', 'invalidApply': 'error', 'invalidScreen': 'error', 'recommendedVariantOrder': 'warning'}, 'colorDecorators': True, 'classAttributes': ['class', 'className', 'ngClass'], 'validate': True, 'includeLanguages': {'rails': 'html'}}}}
::  -> LSP-tailwindcss textDocument/didOpen: {'textDocument': {'version': 0, 'uri': 'file:///Users/kevin/code/timetrail/app/views/layouts/application.html.erb', 'text': '<!DOCTYPE html>\n<html>\n  <head>\n    <title><%= yield(:title) || "Timetrail" %></title>\n    <meta name="viewport" content="width=device-width,initial-scale=1">\n    <%= csrf_meta_tags %>\n    <%= csp_meta_tag %>\n    <%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %>\n\n    <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>\n    <%= javascript_importmap_tags %>\n  </head>\n\n  <body>\n    <main class="container mx-auto mt-28 px-5 flex">\n      <%= yield %>\n    </main>\n  </body>\n</html>\n', 'languageId': 'rails'}}
:: <-- LSP-tailwindcss workspace/configuration(0): {'items': [{'section': 'editor'}]}
:: >>> LSP-tailwindcss 0: [None]
:: <-- LSP-tailwindcss workspace/configuration(1): {'items': [{'section': 'tailwindCSS'}]}
:: >>> LSP-tailwindcss 1: [{'emmetCompletions': False, 'files': {'exclude': ['**/.git/**', '**/node_modules/**', '**/.hg/**']}, 'rootFontSize': 16, 'showPixelEquivalents': True, 'experimental': {'classRegex': []}, 'lint': {'invalidConfigPath': 'error', 'invalidTailwindDirective': 'error', 'cssConflict': 'warning', 'invalidVariant': 'error', 'invalidApply': 'error', 'invalidScreen': 'error', 'recommendedVariantOrder': 'warning'}, 'colorDecorators': True, 'classAttributes': ['class', 'className', 'ngClass'], 'validate': True, 'includeLanguages': {'rails': 'html'}}]
LSP-tailwindcss: 
LSP-tailwindcss: warn - The RTL features in Tailwind CSS are currently in preview.
LSP-tailwindcss: warn - Preview features are not covered by semver, and may be improved in breaking ways at any time.
LSP-tailwindcss: Failed to load workspace modules.
LSP-tailwindcss: Using bundled version of `tailwindcss`: v3.0.11
LSP-tailwindcss: Using bundled version of `postcss`: v8.3.9
:: <-  LSP-tailwindcss window/logMessage: {'message': 'Failed to load workspace modules.', 'type': 4}
:: <-  LSP-tailwindcss window/logMessage: {'message': 'Using bundled version of `tailwindcss`: v3.0.11', 'type': 4}
:: <-  LSP-tailwindcss window/logMessage: {'message': 'Using bundled version of `postcss`: v8.3.9', 'type': 4}
:: <-- LSP-tailwindcss workspace/configuration(2): {'items': [{'scopeUri': 'file:///Users/kevin/code/timetrail/app/views/layouts/application.html.erb', 'section': 'editor'}]}
:: >>> LSP-tailwindcss 2: [None]
:: <-- LSP-tailwindcss workspace/configuration(3): {'items': [{'scopeUri': 'file:///Users/kevin/code/timetrail/app/views/layouts/application.html.erb', 'section': 'tailwindCSS'}]}
:: >>> LSP-tailwindcss 3: [{'emmetCompletions': False, 'files': {'exclude': ['**/.git/**', '**/node_modules/**', '**/.hg/**']}, 'rootFontSize': 16, 'showPixelEquivalents': True, 'experimental': {'classRegex': []}, 'lint': {'invalidConfigPath': 'error', 'invalidTailwindDirective': 'error', 'cssConflict': 'warning', 'invalidVariant': 'error', 'invalidApply': 'error', 'invalidScreen': 'error', 'recommendedVariantOrder': 'warning'}, 'colorDecorators': True, 'classAttributes': ['class', 'className', 'ngClass'], 'validate': True, 'includeLanguages': {'rails': 'html'}}]
:: <-- LSP-tailwindcss client/registerCapability(4): {'registrations': [{'id': '2e6173b0-d563-4368-99fd-6a5440cd39e6', 'registerOptions': {'documentSelector': None}, 'method': 'textDocument/hover'}, {'id': '7dfc4c36-f3e8-4826-9212-4be446123513', 'registerOptions': {'documentSelector': None}, 'method': 'textDocument/documentColor'}, {'id': 'c93b12e0-98c3-4edf-ae06-ace9c9e3778f', 'registerOptions': {'documentSelector': None}, 'method': 'textDocument/codeAction'}, {'id': 'bbab881b-0741-48c0-b6b9-c288cb5d276e', 'registerOptions': {'documentSelector': None, 'resolveProvider': True, 'triggerCharacters': ['"', "'", '`', ' ', '.', '[', '!', '/', ':']}, 'method': 'textDocument/completion'}]}
:: >>> LSP-tailwindcss 4: None
:: <-  LSP-tailwindcss textDocument/publishDiagnostics: {'diagnostics': [], 'uri': 'file:///Users/kevin/code/timetrail/app/views/layouts/application.html.erb'}
:: --> LSP-tailwindcss textDocument/codeAction(2): {'context': {'diagnostics': []}, 'textDocument': {'uri': 'file:///Users/kevin/code/timetrail/app/views/layouts/application.html.erb'}, 'range': {'end': {'character': 0, 'line': 0}, 'start': {'character': 0, 'line': 0}}}
:: <<< LSP-tailwindcss 2: []

@rchl
Copy link
Member

rchl commented Jul 4, 2022

As far as I can see by inspecting the vscode extension, the includeLanguages is handled on the extension side and thus does absolutely nothing in ST. What might work is setting a "text.html.rails": "rails" mapping and then passing option:

{
	"initializationOptions": {
		"userLanguages": {
			"rails": "whatever"
		}
	},
}

@rchl
Copy link
Member

rchl commented Jul 4, 2022

Of course your solution should be fine too for this specific server if it doesn't care about languageId (I don't think it would treat rails and html any different but I haven't studied its code very thoroughly so it might).

@hovsater
Copy link

hovsater commented Jul 4, 2022

As far as I can see by inspecting the vscode extension, the includeLanguages is handled on the extension side and thus does absolutely nothing in ST.

Are you sure? I found the following reference to includeLanguages from within the server itself.

https://github.com/tailwindlabs/tailwindcss-intellisense/blob/8fce24db9c480a9615e175fb3acaac91f7a0a7c1/packages/tailwindcss-intellisense/src/lsp/server.ts#L56

These settings are also editable from within this package as can be seen my opening Preferences: LSP-tailwindcss Settings. My thought were that these settings were listened to using the DidChangeConfiguration Notification event.

What might work is setting a "text.html.rails": "rails" mapping

This isn't necessary as the default rules will take the last part of any scope by default.

@rchl
Copy link
Member

rchl commented Jul 4, 2022

Are you sure? I found the following reference to includeLanguages from within the server itself.

tailwindlabs/tailwindcss-intellisense@8fce24d/packages/tailwindcss-intellisense/src/lsp/server.ts#L56

That's the only reference which means that it's not really used anywhere.

This isn't necessary as the default rules will take the last part of any scope by default.

Right. So the alternative is to not touch the mapping but include the initializationOptions I've posted.

@hovsater
Copy link

hovsater commented Jul 4, 2022

Right. So the alternative is to not touch the mapping but include the initializationOptions I've posted.

Yes, I could do that as a "work around" for now. I think what I'm trying to convey (sorry, if I'm not being clear) is that we should probably support these settings. They don't seem to be specific to the VSCode extension. Settings are being read from a given source. The server asks for them via the Configuration Request. The client then notifies the server about changes using the DidChangeConfiguration Notification.

I believe what's lacking is some initial "glue code" in this package. We could read the settings before starting the server, and pass tailwindcss.includeLanguages in the appropriate place in the initializationOptions (userLanguages in this case).

If the above doesn't make sense, I'd argue that we shouldn't really have these settings available at all. But given that they're defined, I believe the intention is that we can make use of them. Looking at the debug info I posted earlier as well, it looks like the settings are picked up correctly by the plugin as it is today, so it's just a matter of hooking them up.

Excerpt from the LSP communication

:: <-- LSP-tailwindcss workspace/configuration(3): {'items': [{'scopeUri': 'file:///Users/kevin/code/timetrail/app/views/layouts/application.html.erb', 'section': 'tailwindCSS'}]}
:: >>> LSP-tailwindcss 3: [{'rootFontSize': 16, 'emmetCompletions': False, 'colorDecorators': True, 'showPixelEquivalents': True, 'lint': {'invalidConfigPath': 'error', 'invalidVariant': 'error', 'cssConflict': 'warning', 'invalidApply': 'error', 'invalidTailwindDirective': 'error', 'invalidScreen': 'error', 'recommendedVariantOrder': 'warning'}, 'files': {'exclude': ['**/.git/**', '**/node_modules/**', '**/.hg/**']}, 'experimental': {'classRegex': []}, 'classAttributes': ['class', 'className', 'ngClass'], 'validate': True, 'includeLanguages': {'rails': 'html'}}]

I'd be happy to submit a pull request for it if we think it makes sense. 🙂

@rchl
Copy link
Member

rchl commented Jul 4, 2022

It would be easiest to add the initializationOptions.userLanguages for all supported languageIds but ideally we would handle that through tailwindcss.includeLanguages to match the original documentation.

Will just clarify that the server doesn't process tailwindcss.includeLanguages at all nor does the DidChangeConfiguration request needs to receive those. The VSCode extension logic just updates the languages global and restarts the server from that handler so that the updated initializationOptions.userLanguages can be send. The VSCode extension also uses tailwindcss.includeLanguages to let VSCode know that it handles additional languages but that's VSCode-specific equivalent of our selector.

@hovsater
Copy link

hovsater commented Jul 4, 2022

Will just clarify that the server doesn't process tailwindcss.includeLanguages at all nor does the DidChangeConfiguration request needs to receive those. The VSCode extension logic just updates the languages global and restarts the server from that handler so that that updated initializationOptions.userLanguages can be send.

@rchl thanks for clarifying. 🙏 I went through the source code again and you're right. Given that, I think it makes sense to bootstrap the server with whatever you've provided in tailwind.includeLanguages just for the sake of staying aligned with how it's done elsewhere.

However, I could also see us dropping tailwind.includedLanguages altogether and default initializationOptions.userLanguages to include whatever languages we do support (given our selector) that currently does not match Tailwind default languages. For instance, we could map rails to erb.

@rwols
Copy link
Member

rwols commented Jul 4, 2022

However, I could also see us dropping tailwind.includedLanguages

That's usually how we deal with server settings that are actually handled in the (VScode) extension. But, whatever solution is fine by me.

@hovsater
Copy link

hovsater commented Jul 4, 2022

@rwols yeah, perhaps that's the better option. In doing so, we could make a pass over the current settings and remove anything else that is VSCode extension specific. I guess that would be overall less confusing. There are still options that are worth keeping like tailwindCSS.experimental.classRegex though. 🙂

@rchl
Copy link
Member

rchl commented Jul 5, 2022

However, I could also see us dropping tailwind.includedLanguages

That's usually how we deal with server settings that are actually handled in the (VScode) extension. But, whatever solution is fine by me.

The downside of that is that then we need to document our alternative rather than redirect to official documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants