Shopify / ruby-lsp

An opinionated language server for Ruby
https://shopify.github.io/ruby-lsp/
MIT License
1.39k stars 128 forks source link

Add support for providing features on ERB files #1055

Open vinistock opened 9 months ago

vinistock commented 9 months ago

I think there's a path to add support for ERB without a ton of effort. We can try to require erb from the main bundle and provide features only if it is a dependency.

Basically, we can use the ERB gem to parse the .erb file and extract the Ruby code. Then we parse the Ruby code with Prism and provide features for it.

require "erb"
erb = "<% x = 32 %><p><%= x %></p>"
ruby_code = ERB.new(erb).src # => "#coding:UTF-8\n_erbout = +'';  x = 32 ; _erbout.<< \"<p>\".freeze; _erbout.<<(( x ).to_s); _erbout.<< \"</p>\".freeze; _erbout"

Prism.parse(ruby_code) # => AST

In terms of the codebase, I think the best way forward would be turning creating an abstract parent class Document and turning our existing document class into RubyDocument. Then we can create an ErbDocument class to handle the specific details of ERB.

Notes

Diagnostics, formatting and on type formatting need to happen differently on ERB files. For example, if some is using [].each do %> and breaks the line, we need to insert <% end %> and not just end. Similarly, we can see if erb lint is available to provide diagnostics and potentially format the code too.

It might be worth separating these requests into RubyFormatting and ErbFormatting.

Morriar commented 9 months ago

You may need a custom Engine to parse the ERB supported by Rails properly: https://github.com/Shopify/spoom/blob/at-deadcode/lib/spoom/deadcode/erb.rb#L8.

The complexity is correctly mapping lines and columns to the original ERB source.

vinistock commented 9 months ago

Thanks for pointing that out. I suppose if Rails is available in the Gemfile, we'll probably be able to require their own custom engine and use it.

vinistock commented 7 months ago

Attempt at erasing the HTML

# typed: strict
# frozen_string_literal: true

require "prism"
require "strscan"

original = File.read("index.html.erb")
scanner = StringScanner.new(original)
output = +""

until scanner.eos?
  non_ruby_code = scanner.scan_until(/<%(-|=)?/)
  break unless non_ruby_code

  output << non_ruby_code.gsub(/[^\n]/, " ")

  ruby_code = scanner.scan_until(/(-)?%>/)
  break unless ruby_code

  output << ruby_code[...-2]
  output << "  "
end

puts output

p Prism.parse(output)
collimarco commented 7 months ago

+1 for ERB support

ERB support is really important for Rails projects

vinistock commented 5 months ago

We can use VS Code's embedded language features to forward HTML operations to the built-in language server and get features: https://code.visualstudio.com/api/language-extensions/embedded-languages.

github-actions[bot] commented 2 months ago

This issue is being marked as stale because there was no activity in the last 2 months

ParadoxV5 commented 1 month ago

:up: anti-stale bump

We can use VS Code's embedded language features to forward HTML operations […]

Remember that ERB isn’t only about Rails and HTML. ERB can generate CSS, JS, RBS, C, Ruby, even Python, you name it.