Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions lib/ruby_lsp/erb_document.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ def initialize(source)
@ruby = +"" #: String
@current_pos = 0 #: Integer
@inside_ruby = false #: bool
@inside_erb_comment = false #: bool
end

#: -> void
Expand All @@ -100,12 +101,16 @@ def scan_char

case char
when "<"
if next_char == "%"
if !@inside_erb_comment && next_char == "%"
@inside_ruby = true
@current_pos += 1
push_char(" ")

if next_char == "=" && @source[@current_pos + 2] == "="
if next_char == "#"
@inside_erb_comment = true
@current_pos += 1
push_char(" ")
elsif next_char == "=" && @source[@current_pos + 2] == "="
@current_pos += 2
push_char(" ")
elsif next_char == "=" || next_char == "-"
Expand All @@ -121,6 +126,7 @@ def scan_char
if @inside_ruby && next_char == "%" &&
@source[@current_pos + 2] == ">"
@current_pos += 2
@inside_erb_comment = false
push_char(" ")
@inside_ruby = false
else
Expand All @@ -130,9 +136,10 @@ def scan_char
end
when "%"
if @inside_ruby && next_char == ">"
@inside_ruby = false
@current_pos += 1
@inside_erb_comment = false
push_char(" ")
@inside_ruby = false
else
push_char(
char, #: as !nil
Expand All @@ -159,7 +166,10 @@ def scan_char

#: (String char) -> void
def push_char(char)
if @inside_ruby
if @inside_erb_comment
@ruby << " " * char.length
@host_language << " " * char.length
elsif @inside_ruby
@ruby << char
@host_language << " " * char.length
else
Expand Down
47 changes: 47 additions & 0 deletions test/erb_document_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,53 @@ def test_erb_document_handles_windows_newlines
assert_equal(" \r\nbar ", document.parse_result.source.source)
end

def test_multiline_erb_comments_are_excluded_from_virtual_sources
source = +"<%# first line\ncomment_method(:argument)\n-%>\n<%= visible_call %>"
document = RubyLsp::ERBDocument.new(
source: source,
version: 1,
uri: URI("file:///foo.erb"),
global_state: @global_state,
)

document.parse!

expected_ruby = source.gsub(/[^\r\n]/, " ")
visible_call = "visible_call"
visible_call_start = source.index(visible_call)
expected_ruby[visible_call_start, visible_call.length] = visible_call

refute_predicate(document, :syntax_error?)
assert_equal(expected_ruby, document.parse_result.source.source)
assert_equal(source.gsub(/[^\r\n]/, " "), document.host_language_source)
end

def test_multiline_erb_comments_preserve_windows_newlines_and_resume_scanning
source = +"<%# first line\r\ncomment_method(:argument) %>\r\n<p>visible</p>\r\n<%= another_call %>"
document = RubyLsp::ERBDocument.new(
source: source,
version: 1,
uri: URI("file:///foo.erb"),
global_state: @global_state,
)

document.parse!

expected_ruby = source.gsub(/[^\r\n]/, " ")
another_call = "another_call"
another_call_start = source.index(another_call)
expected_ruby[another_call_start, another_call.length] = another_call

expected_host = source.gsub(/[^\r\n]/, " ")
visible_html = "<p>visible</p>"
visible_html_start = source.index(visible_html)
expected_host[visible_html_start, visible_html.length] = visible_html

refute_predicate(document, :syntax_error?)
assert_equal(expected_ruby, document.parse_result.source.source)
assert_equal(expected_host, document.host_language_source)
end

def test_erb_syntax_error_does_not_cause_crash
[
"<%=",
Expand Down
Loading