Sha256: 09b37e2172a8a7ee9dee6863ba64e4f0eeb175871111bf6005a59f99b5a239b6

Contents?: true

Size: 1.98 KB

Versions: 85

Compression:

Stored size: 1.98 KB

Contents

# frozen_string_literal: true

module Parser

  class Lexer::Dedenter
    # Tab (\t) counts as 8 spaces
    TAB_WIDTH = 8

    def initialize(dedent_level)
      @dedent_level = dedent_level
      @at_line_begin = true
      @indent_level  = 0
    end

    # For a heredoc like
    #   <<-HERE
    #     a
    #     b
    #   HERE
    # this method gets called with "  a\n" and "  b\n"
    #
    # However, the following heredoc:
    #
    #   <<-HERE
    #     a\
    #     b
    #   HERE
    # calls this method only once with a string "  a\\\n  b\n"
    #
    # This is important because technically it's a single line,
    # but it has to be concatenated __after__ dedenting.
    #
    # It has no effect for non-squiggly heredocs, i.e. it simply removes "\\\n"
    # Of course, lexer could do it but once again: it's all because of dedenting.
    #
    def dedent(string)
      original_encoding = string.encoding
      # Prevent the following error when processing binary encoded source.
      # "\xC0".split # => ArgumentError (invalid byte sequence in UTF-8)
      lines = string.force_encoding(Encoding::BINARY).split("\\\n")
      lines.map! {|s| s.force_encoding(original_encoding) }

      if @at_line_begin
        lines_to_dedent = lines
      else
        _first, *lines_to_dedent = lines
      end

      lines_to_dedent.each do |line|
        left_to_remove = @dedent_level
        remove = 0

        line.each_char do |char|
          break if left_to_remove <= 0
          case char
          when ?\s
            remove += 1
            left_to_remove -= 1
          when ?\t
            break if TAB_WIDTH * (remove / TAB_WIDTH + 1) > @dedent_level
            remove += 1
            left_to_remove -= TAB_WIDTH
          else
            # no more spaces or tabs
            break
          end
        end

        line.slice!(0, remove)
      end

      string.replace(lines.join)

      @at_line_begin = string.end_with?("\n")
    end

    def interrupt
      @at_line_begin = false
    end
  end

end

Version data entries

85 entries across 79 versions & 14 rubygems

Version Path
primary_connect_proto-0.20.0 vendor/bundle/ruby/3.0.0/gems/parser-3.0.2.0/lib/parser/lexer/dedenter.rb
primary_connect_proto-0.20.0 vendor/bundle/ruby/2.6.0/gems/parser-3.0.2.0/lib/parser/lexer/dedenter.rb
primary_connect_proto-0.19.0 vendor/bundle/ruby/3.0.0/gems/parser-3.0.2.0/lib/parser/lexer/dedenter.rb
primary_connect_proto-0.18.0 vendor/bundle/ruby/3.0.0/gems/parser-3.0.2.0/lib/parser/lexer/dedenter.rb
primary_connect_proto-0.18.0 vendor/bundle/ruby/2.6.0/gems/parser-3.0.2.0/lib/parser/lexer/dedenter.rb
primary_connect_proto-0.17.0 vendor/bundle/ruby/2.6.0/gems/parser-3.0.2.0/lib/parser/lexer/dedenter.rb
primary_connect_proto-0.17.0 vendor/bundle/ruby/3.0.0/gems/parser-3.0.2.0/lib/parser/lexer/dedenter.rb
primary_connect_proto-0.12.1 vendor/bundle/ruby/2.7.0/gems/parser-3.0.2.0/lib/parser/lexer/dedenter.rb
primary_connect_proto-0.10.2 vendor/bundle/ruby/2.7.0/gems/parser-3.0.2.0/lib/parser/lexer/dedenter.rb
primary_connect_proto-0.10.1 vendor/bundle/ruby/2.7.0/gems/parser-3.0.2.0/lib/parser/lexer/dedenter.rb
primary_connect_proto-0.9.0 vendor/bundle/ruby/2.6.0/gems/parser-3.0.2.0/lib/parser/lexer/dedenter.rb
primary_connect_proto-0.8.2 vendor/bundle/ruby/2.7.0/gems/parser-3.0.2.0/lib/parser/lexer/dedenter.rb
primary_connect_proto-0.8.1 vendor/bundle/ruby/2.7.0/gems/parser-3.0.2.0/lib/parser/lexer/dedenter.rb
primary_connect_proto-0.8.0 vendor/bundle/ruby/2.6.0/gems/parser-3.0.2.0/lib/parser/lexer/dedenter.rb
primary_connect_proto-0.7.3 vendor/bundle/ruby/2.6.0/gems/parser-3.0.2.0/lib/parser/lexer/dedenter.rb
primary_connect_proto-0.7.2 vendor/bundle/ruby/2.6.0/gems/parser-3.0.2.0/lib/parser/lexer/dedenter.rb
primary_connect_proto-0.7.1 vendor/bundle/ruby/2.6.0/gems/parser-3.0.2.0/lib/parser/lexer/dedenter.rb
primary_connect_proto-0.7.0 vendor/bundle/ruby/2.6.0/gems/parser-3.0.2.0/lib/parser/lexer/dedenter.rb
primary_connect_proto-0.6.0 vendor/bundle/ruby/2.6.0/gems/parser-3.0.2.0/lib/parser/lexer/dedenter.rb
plaid-14.13.0 vendor/bundle/ruby/3.0.0/gems/parser-2.7.2.0/lib/parser/lexer/dedenter.rb