lib/erb/formatter.rb in erb-formatter-0.1.1 vs lib/erb/formatter.rb in erb-formatter-0.2.0

- old
+ new

@@ -1,18 +1,18 @@ # frozen_string_literal: false -# $DEBUG = true +# @debug = true require "erb" require "cgi" require "ripper" require 'securerandom' require 'strscan' require 'pp' require 'stringio' class ERB::Formatter - VERSION = "0.1.1" + VERSION = "0.2.0" autoload :IgnoreList, 'erb/formatter/ignore_list' class Error < StandardError; end # https://stackoverflow.com/a/317081 @@ -60,18 +60,19 @@ def self.format(source, filename: nil) new(source, filename: filename).html end - def initialize(source, line_width: 80, filename: nil) + def initialize(source, line_width: 80, filename: nil, debug: $DEBUG) @original_source = source @filename = filename || '(erb)' @line_width = line_width @source = source.dup @html = +"" + @debug = debug - html.extend DebugShovel if $DEBUG + html.extend DebugShovel if @debug @tag_stack = [] @pre_pos = 0 build_uid = -> { ['erb', SecureRandom.uuid, 'tag'].join.delete('-') } @@ -166,17 +167,17 @@ end end def tag_stack_push(tag_name, code) tag_stack << [tag_name, code] - p PUSH: tag_stack if $DEBUG + p PUSH: tag_stack if @debug end def tag_stack_pop(tag_name, code) if tag_name == tag_stack.last&.first tag_stack.pop - p POP_: tag_stack if $DEBUG + p POP_: tag_stack if @debug else raise "Unmatched close tag, tried with #{[tag_name, code]}, but #{tag_stack.last} was on the stack" end end @@ -199,27 +200,37 @@ indent = " " * tag_stack.size "\n#{indent}#{string.strip}" end def format_text(text) + p format_text: text if @debug starting_space = text.match?(/\A\s/) final_newlines_count = text.match(/(\s*)\z/m).captures.last.count("\n") html << "\n" if final_newlines_count > 1 return if text.match?(/\A\s*\z/m) # empty text = text.gsub(/\s+/m, ' ').strip - offset = (starting_space ? indented("") : "").size + offset = indented("").size + # Restore full line width if there are less than 40 columns available + offset = 0 if (line_width - offset) <= 40 + available_width = line_width - offset + lines = [] until text.empty? - lines << text.slice!(0..text.rindex(' ', -(line_width - offset))) + if text.size >= available_width + last_space_index = text[0..available_width].rindex(' ') + lines << text.slice!(0..last_space_index) + else + lines << text.slice!(0..-1) + end offset = 0 end - + p lines: lines if @debug html << lines.shift.strip unless starting_space lines.each do |line| html << indented(line) end end @@ -251,36 +262,38 @@ def format_ruby(code, autoclose: false) if autoclose code += "\nend" unless ERB_OPEN_BLOCK["#{code}\nend"] code += "\n}" unless ERB_OPEN_BLOCK["#{code}\n}"] end - p RUBY_IN_: code if $DEBUG + p RUBY_IN_: code if @debug offset = tag_stack.size * 2 if defined? Rubocop code = format_code_with_rubocop(code, line_width - offset) if (offset + code.size) > line_width elsif defined?(Rufo) code = Rufo.format(code) rescue code end lines = code.strip.lines lines = lines[0...-1] if autoclose - code = lines.map { indented(_1) }.join.strip - p RUBY_OUT: code if $DEBUG + code = lines.map { |l| indented(l) }.join.strip + p RUBY_OUT: code if @debug code end def format_erb_tags(string) + p format_erb_tags: string if @debug if %w[style script].include?(tag_stack.last&.first) html << string.rstrip return end erb_scanner = StringScanner.new(string.to_s) erb_pre_pos = 0 until erb_scanner.eos? if erb_scanner.scan_until(erb_tags_regexp) + p PRE_MATCH: [erb_pre_pos, '..', erb_scanner.pre_match] erb_pre_match = erb_scanner.pre_match erb_pre_match = erb_pre_match[erb_pre_pos..] erb_pre_pos = erb_scanner.pos erb_code = erb_tags[erb_scanner.captures.first] @@ -306,10 +319,11 @@ else ruby_code = format_ruby(ruby_code, autoclose: false) html << (erb_pre_match.match?(/\s+\z/) ? indented(full_erb_tag) : full_erb_tag) end else + p ERB_REST: erb_scanner.rest if @debug rest = erb_scanner.rest.to_s format_text(rest) erb_scanner.terminate end end @@ -317,14 +331,16 @@ def format scanner = StringScanner.new(source) until scanner.eos? - if matched = scanner.scan_until(tags_regexp) + p format_pre_match: [pre_pos, '..', scanner.pre_match[pre_pos..]] if @debug pre_match = scanner.pre_match[pre_pos..] - self.pre_pos = scanner.pos + p POS: pre_pos...scanner.pos, advanced: source[pre_pos...scanner.pos] if @debug + p MATCHED: matched if @debug + self.pre_pos = scanner.charpos # Don't accept `name= "value"` attributes raise "Bad attribute, please fix spaces after the equal sign." if BAD_ATTR.match? pre_match format_erb_tags(pre_match) if pre_match @@ -350,9 +366,10 @@ tag_stack_push(tag_name, full_tag) unless tag_self_closing else raise "Unrecognized content: #{matched.inspect}" end else + p format_rest: scanner.rest if @debug format_erb_tags(scanner.rest.to_s) scanner.terminate end end