diff --git a/lib/ruby_lsp/erb_document.rb b/lib/ruby_lsp/erb_document.rb index ae9852b72..90a4475c8 100644 --- a/lib/ruby_lsp/erb_document.rb +++ b/lib/ruby_lsp/erb_document.rb @@ -82,6 +82,7 @@ def initialize(source) @ruby = +"" #: String @current_pos = 0 #: Integer @inside_ruby = false #: bool + @inside_erb_comment = false #: bool end #: -> void @@ -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 == "-" @@ -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 @@ -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 @@ -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 diff --git a/test/erb_document_test.rb b/test/erb_document_test.rb index 21b2ce8a9..4ce150093 100644 --- a/test/erb_document_test.rb +++ b/test/erb_document_test.rb @@ -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

visible

\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 = "

visible

" + 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 [ "<%=",