nebulab / erb-formatter

Format ERB files with speed and precision
MIT License
135 stars 22 forks source link

Make it so that print-width actually means line length #55

Open pelletencate opened 2 months ago

pelletencate commented 2 months ago

Right now, the already wonderful --print-width option is seems to be used to limit the length of individually formatted components. This means it has no awareness of what else is on a line, meaning it could potentially exceed the configured line length. It also doesn't realize it should break up individual tags. A few examples

Two takeaways:

  1. Whenever the length of anything is being evaluated, the context (indentation, surrounding HTML) is not taken into account
  2. Whenever the formatter breaks up one line into multiple, the surrounding context isn't formatted. (Subjective, but I think most of us agree that for example multiline content in a HTML tag deserves the tags to be printed on separate lines, or multiline ERB deserves the <% and %> to be printed on separate lines)

Example 1: Normal HTML

Tags not breaking up, lines being longer than allowed:

<h2>This line is going to be 64 long, it should warp down!</h2>
<h2>This line is going to be 72 long, it should warp down as well!</h2>

<%# Expected %>
<h2>
  This line is going to be 64 long, it should warp down!
</h2>
<h2>
  This line is going to be 72 long, it should warp down as 
  well!
</h2>

<%# Observed %>
<h2>This line is going to be 64 long, it should warp down!</h2>
<h2>This line is going to be 72 long, it should warp down as
  well!</h2>

Example 2: ERB

Not considering indentation

<div class="a">
  <div class="b">
    <div class="c">
      <div class="d">
        <div class="e">
          <%= (1..10).map { |n| n * 5 }.reduce(:+) * Time.now.to_i % 1000 %>
          <%= 50.times { (1..10).map { |n| n * 5 }.reduce(:+) * Time.now.to_i % 1000 } %>
        </div>
      </div>
    </div>
  </div>
</div>

<%# Expected: Whatever syntax_tree does with max 47 width, e.g. %>
<div class="a">
  <div class="b">
    <div class="c">
      <div class="d">
        <div class="e">
          <%=
            (1..10).map { |n| n * 5 }.reduce(:+) *
              Time.now.to_i % 1000
          %>
          <%=
            50.times do
              (1..10).map { |n| n * 5 }.reduce(:+) *
                Time.now.to_i % 1000
            end
          %>
        </div>
      </div>
    </div>
  </div>
</div>

<%# Observed: Whatever syntax_tree does with max 60 width: %>
<div class="a">
  <div class="b">
    <div class="c">
      <div class="d">
        <div class="e">
          <%= (1..10).map { |n| n * 5 }.reduce(:+) * Time.now.to_i % 1000 %>
          <%= 50.times do
            (1..10).map { |n| n * 5 }.reduce(:+) * Time.now.to_i %
              1000
          end %>
        </div>
      </div>
    </div>
  </div>
</div>

Example 3: long attribute values

<div>
  <div>
    <div>
      <div class="this line has lots of classes lorem ipsum dolor sit amet consectetur adipiscing elit aliquam malesuada lobortis commodo aenean convallis dui consequat venenatis vel facilisis quis semper mi tempor ante"></div>
    </div>
  </div>
</div>

<%# Expected: %>
<div>
  <div>
    <div>
      <div
        class="
          this line has lots of classes lorem ipsum dolor
          sit amet consectetur adipiscing elit aliquam
          malesuada lobortis commodo aenean convallis dui
          consequat venenatis vel facilisis quis semper mi
          tempor ante
        "
      >
      </div>
    </div>
  </div>
</div>

<%# Observed: %>
<div>
  <div>
    <div>
      <div
        class="
          this line has lots of classes lorem ipsum dolor sit amet
          consectetur adipiscing elit aliquam malesuada lobortis
          commodo aenean convallis dui consequat venenatis vel
          facilisis quis semper mi tempor ante
        "
      ></div>
    </div>
  </div>
</div>