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

Fix heredoc start + comma formatter #6222

Merged
merged 1 commit into from Jun 25, 2018

Conversation

straight-shoota
Copy link
Member

Fixes #6197

This is not a great fix, but it seems to work. If anyone has a better solution, go ahead.

@asterite
Copy link
Member

I think the bug is in format_literal_elements, but the code is way to complex by now to fix it in another way...

@bcardiff
Copy link
Member

I would ask @makenowjust if there is another solution that can be thought, but otherwise LGTM.

Can we add a spec with more than one hash entry with heredocs?

@bcardiff bcardiff added this to the 0.25.1 milestone Jun 21, 2018
@straight-shoota
Copy link
Member Author

@asterite Thanks for the advice. It helped a lot 👍

The complexity is not even that much of a problem. I got it to work (mostly) and format_literal_elements certainly a much better place to fix this.
I'm still left with a rather strange indent on the last line, I can't really figure why that is inserted at in finish_list when @wrote_newline is true. It seems only to be an issue when heredocs are involved, but not with a quoted string literal for example.

@makenowjust
Copy link
Contributor

At least this implementation is not complete. Example:

{
  :foo => <<-FOO ,
          foo
          FOO
}

is formatted to

{
  :foo => <<-FOO
          foo foo
          FOO
,
  }

I agree with @asterite and such a specialization for heredoc is already used in format_args_simple (at line 2483) for example. I'll try to fix this.

@makenowjust
Copy link
Contributor

makenowjust commented Jun 21, 2018 via email

@makenowjust
Copy link
Contributor

@straight-shoota When @wrote_newline is true, it means newline is wrote already but indent is not wrote. So inserting newline here is correct in general.

@@ -828,17 +828,23 @@ module Crystal
accept element
end

element_is_heredoc = !@lexer.heredocs.empty?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this variable name is not correct. It should be named has_heredoc_in_line or has_heredoc as short.

write "," unless last || found_comment
if !found_comment && (!last || element_is_heredoc)
write ","
wrote_comma = true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrote_comma is assigned here, but it is not reset. So this affects other iterations.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable is limited to block scope and won't be copied over between iterations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Sorry.

@straight-shoota
Copy link
Member Author

@makenowjust Yes, writing an indent is correct. But it seems that @indent should be 0 at that point, yet it is actually still 2.

[
  <<-EOF,
  foo
  EOF
  ]

# without comma:
[
  <<-EOF
  foo
  EOF
]

# quoted string literal
[
  "foo",
]

@makenowjust
Copy link
Contributor

@straight-shoota I think this patch fixes indent issue:

diff --git a/src/compiler/crystal/tools/formatter.cr b/src/compiler/crystal/tools/formatter.cr
index 29d13c5c0..3fb1f89c3 100644
--- a/src/compiler/crystal/tools/formatter.cr
+++ b/src/compiler/crystal/tools/formatter.cr
@@ -623,7 +623,7 @@ module Crystal
       next_token

       @string_continuation = old_string_continuation
-      @indent = old_indent
+      @indent = old_indent unless is_heredoc

       false
     end

@straight-shoota
Copy link
Member Author

Awesome! Thank you very much @makenowjust
I had been looking for places where @indent was changed, but it seems I missed that spot.

@asterite
Copy link
Member

Also, feel free to redactor/improvr/destroy the current formatter for better readability. It started simple but grew complex, mainly because the syntax of the language is so wide and complex too.

Copy link
Member

@bcardiff bcardiff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What a nice collaboration we end up having here! 💚

Thanks @makenowjust for jumping in and @straight-shoota for dealing with the issue.

assert_format "[\n <<-EOF,\n foo\n EOF\n <<-BAR,\n bar\n BAR\n]"
assert_format "Hash{\n foo => <<-EOF,\n foo\n EOF\n}"
assert_format "Hash{\n foo => <<-EOF,\n foo\n EOF\n bar => <<-BAR,\n bar\n BAR\n}"
assert_format "Hash{\n foo => <<-EOF\n foo\n EOF\n}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really right? I think it should append comma. So correct assertion is:

assert_format "Hash{\n  foo => <<-EOF\n  foo\n  EOF\n}", "Hash{\n  foo => <<-EOF,\n  foo\n  EOF\n}"

Because this code:

{
  foo: 42
}

is formatted to:

{
  foo: 42,
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's probably better. But it seems a bit more difficult because of the special treatment of newline in next_token. And it requires changes in a some other examples, that are - currently - explicitly not adding a comma there:

https://github.com/straight-shoota/crystal/blob/4c63cd398fdf2f98ee05a6e12506e979d692c5ab/spec/compiler/formatter/formatter_spec.cr#L1135-L1138

I'd suggest to leave this PR as a fix for the immediate issue.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @straight-shoota here. Not adding a comma although is inconsistent with non heredoc hash/array literals, at least is not producing invalid code.

@sdogruyol @makenowjust WDYT?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, this is OK 👍

@RX14
Copy link
Contributor

RX14 commented Jun 25, 2018

Would greatly appreciate a fix to not appending a comma, or at least an issue so we can pretend we haven't forgotten about it.

@bcardiff
Copy link
Member

@RX14 precisely this PR does not append a comma in multiline hashes with heredocs, what is missing is the comma to be consistent with other hashes

@straight-shoota straight-shoota deleted the jm/fix/6197 branch June 25, 2018 14:37
@RX14
Copy link
Contributor

RX14 commented Jun 25, 2018

@bcardiff I understood that, I just worded it weirdly, should have said fix for instead of fix to.

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

Successfully merging this pull request may close these issues.

Formatter: heredoc + comma produces invalid code
7 participants