Heredoc ending indentation #149

Closed
bogdan opened this Issue Apr 7, 2013 · 9 comments

Projects

None yet

3 participants

@bogdan
bogdan commented Apr 7, 2013

Income text

def doc
  <<-Z
The documentation
Z
end

When entire file is autoindented: ggVG=

Heredoc ending statement gets some extra spaces before:

def doc
  <<-Z
The documentation
  Z
end

I think this is wrong default and indentation script should always leave it where it is.

@AndrewRadev
Member

Sorry for taking so long to respond.

I think that adding the indentation for the closing Z is a good idea, since you're using the <<- form of heredocs, and they're specifically created (as far as I know) to be able to provide a closing delimiter with additional indentation in the beginning. If you want to place the Z at column 0, then I believe you should use the << form, as in:

def doc
  <<Z
The documentation
Z
end

However, it seems like this form is also auto-indented :). This is a problem, since the resulting file is no longer syntactically valid. I'll try to fix this case.

@bogdan
bogdan commented May 10, 2013

Heh, didn't know about <<Z thanks for explaining this.

@AndrewRadev
Member

I've pushed a commit to master that should fix this issue. A closing delimiter at column 0 should stay at column zero when the file is reindented. Could you check it out and let me know if it seems to work?

@bogdan
bogdan commented May 13, 2013

<<Z works fine.

I still think that closing intentation for <<-Z should work in the same way.
As you said: it is desired to leave some space at the last line. But I don't think that autoindentation should change the number of spaces.

e.g:

def a
  <<-Z
zz
         Z

should not be indented to:

def a
  <<-Z
zz
  Z

Because it is for programmer to decide how many spaces should be there. Vim plugin will never know it for sure.

@AndrewRadev
Member

Because it is for programmer to decide how many spaces should be there. Vim plugin will never know it for sure.

I don't think this is a good argument. Vim-ruby couldn't be sure about any indentation at all. The example can easily be applied to anything else:

def a
  loop do
    "zz"
        end
end

This is perfectly valid code. The reason we indent the "end" aligned to the "loop" is simply because of convention, not because of a strict rule. While the do-end pair is a very strict convention, a lot of other things are not as clear, like if-clauses with assignment:

# the current indentation rule
foo = if bar
        "one"
      else
        "two"
      end

# a different option
foo = if bar
  "one"
else
  "two"
end

# yet another option
foo = if bar
    "one"
  else
    "two"
  end

All of these are valid and all of these have different (subjective) benefits and drawbacks. The way vim-ruby indents these is simply based on the most popular style. I believe the rule for heredocs is the same. As far as I know, most people indent the closing heredoc aligned with the opening one, so this is what we do. Honestly, I have a couple of indenting rules that I'm not a fan of myself, but most people seem to like them, so I simply don't do global gg=Gs, but re-indent only parts of the code instead. It's annoying, I admit, and there's a lot of value in making this easier to modify by users, but it's difficult to provide a simple enough interface for this, since the rules themselves are not very simple.

In the end, I maintain that this is useful behavior, so I'll close the ticket, unless someone can weigh in with a convincing argument to reopen. Sorry for the inconvenience.

@bogdan
bogdan commented May 19, 2013

As you said indentation is just a convention.
Every type of indentation produce same behavior. In other words if I reindent all code in any way it behavior should not change.

In your examples indentation doesn't matter.

but here:

  <<-Z
    hello
  Z

Indentation matter. If I align this code it will behave diffidently and program could be broken.

Heredoc is not just the doc. It may generate SQL or Shell script that suppose to have specific number of spaces not just for formatting but for correct behavior.

Anyway it is for you to decide. I won't insist anymore.

@AndrewRadev
Member

The indentation algorithm leaves the string itself intact. If you have the following code:

puts (<<-PYTHON).inspect
  def one(two):
    three
PYTHON

And you want to wrap it in a function, like so:

def python_code
puts (<<-PYTHON).inspect
  def one(two):
    three
PYTHON
end

When you reindent this piece of code, you'll get:

def python_code
  puts (<<-PYTHON).inspect
  def one(two):
    three
  PYTHON
end

The string itself was not touched. Any indentation that was there is exactly the same. The only thing that changed its indentation is the delimiter itself, and if you run both versions of the code, the result would be, in both cases:

"  def one(two):\n    three\n"

The indentation of the delimiters doesn't affect the spacing of the string, which is why vim-ruby should not mess up the result.

@bogdan
bogdan commented May 20, 2013

hm, it seems you are right. Thanks for clearing this for me.

I am not sure why did I get a constant feeling that it appends a spaces at last line to resulting string.

@AndrewRadev
Member

It might have been a result of a different use case or something. Honestly, up until this issue, I've never investigated heredoc output in much depth, so I can see how the whitespace thing might not be clear. Anyway, glad we reached agreement in the end :).

@dkearns dkearns added the indent label Sep 17, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment