Skip to content
Open
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
2 changes: 1 addition & 1 deletion spec/compiler/formatter/formatter_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -1966,7 +1966,7 @@ describe Crystal::Formatter do

assert_format "<<-HTML\n hello \n HTML"
assert_format "<<-HTML\n hello \n world \n HTML"
assert_format " <<-HTML\n hello \n world \n HTML", "<<-HTML\n hello \n world \n HTML"
assert_format " <<-HTML \n hello \n world \n HTML", "<<-HTML\n hello \n world \n HTML"

assert_format "x, y = <<-FOO, <<-BAR\n hello\n FOO\n world\n BAR"
assert_format "x, y, z = <<-FOO, <<-BAR, <<-BAZ\n hello\n FOO\n world\n BAR\n qux\nBAZ"
Expand Down
71 changes: 14 additions & 57 deletions src/compiler/crystal/tools/formatter.cr
Original file line number Diff line number Diff line change
Expand Up @@ -529,10 +529,10 @@ module Crystal
end
end

private def write_sanitized_string_body(escape)
private def write_sanitized_string_body(escape, no_rstrip = false)
body = @token.invalid_escape ? @token.value.as(String) : @token.raw
body = Lexer.escape_forbidden_characters(body) if escape
write body
write body, no_rstrip: no_rstrip
end

def visit(node : StringInterpolation)
Expand Down Expand Up @@ -569,25 +569,20 @@ module Crystal
if is_heredoc && @token.type.string?
token_is_indent = @token.raw.bytesize == node.heredoc_indent && @token.raw.each_char.all? &.ascii_whitespace?
if token_is_indent
write @token.raw
write @token.raw, no_rstrip: true
next_string_token
end
end

visit_string_interpolation_body(node, delimiter_state, column, is_regex: is_regex, is_heredoc: is_heredoc)

heredoc_end = @line

check :DELIMITER_END
write @token.raw

if is_heredoc
if indent_difference > 0
@heredoc_fixes << HeredocFix.new(heredoc_line, @line, indent_difference)
end
(heredoc_line...heredoc_end).each do |line|
@no_rstrip_lines.add line
end
write_line
end

Expand Down Expand Up @@ -637,7 +632,7 @@ module Crystal
else
loop do
check :STRING
write_sanitized_string_body(delimiter_state.allow_escapes && !is_regex)
write_sanitized_string_body(delimiter_state.allow_escapes && !is_regex, no_rstrip: is_heredoc)
next_string_token

# On heredoc, pieces of contents are combined due to removing indentation.
Expand Down Expand Up @@ -1756,22 +1751,12 @@ module Crystal
write_line
write value

# `write` doesn't update `@line` for embedded newlines.
# Track the output lines from the formatted macro body explicitly,
# then ignore line mutations while consuming original macro tokens.
increment_lines(value.count('\n'))
line = @line

next_macro_token

until @token.type.macro_end?
next_macro_token
end

if @line != line
increment_lines(line - @line)
end

skip_space_or_newline
check :MACRO_END
write_indent
Expand Down Expand Up @@ -1821,12 +1806,6 @@ module Crystal
end

def visit(node : MacroLiteral)
line = @line
@token.raw.scan("\n") do
line -= 1
@no_rstrip_lines.add line
end

raw = @token.raw

# If the macro literal has a backlash, but we are subformatting
Expand All @@ -1836,7 +1815,7 @@ module Crystal
raw = raw.gsub("\\", "\\" * (@subformat_nesting + 1))
end

write raw
write raw, no_rstrip: true
next_macro_token
false
end
Expand Down Expand Up @@ -2217,21 +2196,10 @@ module Crystal
# will already have it.
write_indent

increment_lines(macro_node_line + value.lines.size + 1 - @line)

line = @line

# We have to potentially skip multiple macro literal tokens
while @token.type.macro_literal?
next_macro_token
end

# Skipping the macro literal tokens might have altered `@line`:
# restore it to what it was before the macro tokens (we are
# already accounting for the lines in a different way).
if @line != line
increment_lines(line - @line)
end
else
inside_macro { no_indent node }
end
Expand Down Expand Up @@ -4538,11 +4506,8 @@ module Crystal
end

def next_token
current_line_number = @lexer.line_number
@token = @lexer.next_token
if @token.type.delimiter_start?
increment_lines(@lexer.line_number - current_line_number)
elsif @token.type.newline?
if @token.type.newline?
if !@lexer.heredocs.empty? && !@consuming_heredocs
write_line
consume_heredocs
Expand All @@ -4552,9 +4517,7 @@ module Crystal
end

def next_string_token
current_line_number = @lexer.line_number
@token = @lexer.next_string_token(@token.delimiter_state)
increment_lines(@lexer.line_number - current_line_number)
@token
end

Expand All @@ -4563,14 +4526,10 @@ module Crystal
end

def next_macro_token
current_line_number = @lexer.line_number

char = @lexer.current_char
@token = @lexer.next_macro_token(@macro_state, false)
@macro_state = @token.macro_state

increment_lines(@lexer.line_number - current_line_number)

# Unescape
if char == '\\' && !@token.raw.starts_with?(char)
@token.raw = "\\#{@token.raw}"
Expand Down Expand Up @@ -4863,7 +4822,7 @@ module Crystal
indent(indent) { yield }
end

def write(string : String)
def write(string : String, no_rstrip : Bool = false)
@output << string
@line_output << string
last_newline = string.rindex('\n')
Expand All @@ -4872,6 +4831,13 @@ module Crystal
else
@column += string.size
end
lines_count = string.count('\n')

@no_rstrip_lines.add @line if no_rstrip
lines_count.times do
increment_line
@no_rstrip_lines.add @line if no_rstrip
end

@wrote_newline = false
@wrote_double_newlines = false
Expand Down Expand Up @@ -4909,14 +4875,6 @@ module Crystal
@comment_columns.pop
end

def increment_lines(count)
if count < 0
(-count).times { decrement_line }
else
count.times { increment_line }
end
end

def finish
raise "BUG: unclosed parenthesis" if @paren_count > 0

Expand Down Expand Up @@ -5218,7 +5176,6 @@ module Crystal
write "\\"
write @lexer.skip_macro_whitespace
@macro_state.whitespace = true
increment_line
true
else
false
Expand Down
Loading