lib/hamlit/concerns/indentable.rb in hamlit-1.6.0 vs lib/hamlit/concerns/indentable.rb in hamlit-1.6.1

- old
+ new

@@ -6,16 +6,18 @@ module Concerns module Indentable include Concerns::Error def reset_indent + @indent_logs = [] @current_indent = 0 end # Return nearest line's indent level since next line. This method ignores # empty line. It returns -1 if next_line does not exist. def next_indent + return 1 if !@indent_space && fetch_indent(next_line).length > 0 count_indent(next_line) end def next_width count_width(next_line) @@ -26,57 +28,53 @@ block.call ensure @current_indent -= 1 end - def count_indent(line, strict: false) + def count_indent(line) return EOF unless line - width = count_width(line) + return 0 if indent_rule == 0 - return (width + 1) / 2 unless strict - compile_error!('Expected to count even-width indent') if width.odd? - - width / 2 + line.match(/\A[ \t]+/).to_s.length / indent_rule end def count_width(line) return EOF unless line - line[/\A +/].to_s.length + line[/\A[ \t]+/].to_s.length end def same_indent?(line) return false unless line count_indent(line) == @current_indent end # Validate current line's indentation def validate_indentation!(ast) - width = next_width - return false if width == @current_indent * 2 + return true unless next_line - if width != Hamlit::EOF && (width > @current_indent * 2 || width.odd?) - ast << [:newline] - ast << syntax_error( - "inconsistent indentation: #{2 * @current_indent} spaces used for indentation, "\ - "but the rest of the document was indented using #{width} spaces" - ) + indent = fetch_indent(next_line) + if indent.include?(' ') && indent.include?("\t") + syntax_error!("Indentation can't use both tabs and spaces.") end - true + @indent_logs << indent + + if !@indent_space && @indent_logs.last != '' + @indent_space = @indent_logs.last + end + validate_indentation_consistency!(indent) + + next_indent != @current_indent end # Validate the template is using consitent indentation, 2 spaces or a tab. - def validate_indentation_consistency!(template) - last_indent = '' + def validate_indentation_consistency!(indent) + return false if indent.empty? + return false if !@indent_space || @indent_space.empty? - indents = template.scan(/^[ \t]+/) - indents.each do |indent| - if last_indent.include?(' ') && indent.include?("\t") || - last_indent.include?("\t") && indent.include?(' ') - syntax_error!(%Q{Inconsistent indentation: #{indent_label(indent)} used for indentation, but the rest of the document was indented using #{indent_label(last_indent)}.}) - end - - last_indent = indent + if indent[0] != @indent_space[0] || indent.length < @indent_space.length + syntax_error!("Inconsistent indentation: #{indent_label(indent)} used for indentation, "\ + "but the rest of the document was indented using #{indent_label(@indent_space)}.") end end def indent_label(indent) return %Q{"#{indent}"} if indent.include?(' ') && indent.include?("\t") @@ -85,22 +83,46 @@ length = indent.match(/[ \t]+/).to_s.length "#{length} #{label}#{'s' if length > 1}" end - # Replace hard tabs into 2 spaces - def replace_hard_tabs(template) - lines = [] - template.each_line do |line| - lines << line.gsub(/^\t+/) do |match| - ' ' * (match.length * 2) - end - end - lines.join - end - def has_block? + return false unless next_line + return fetch_indent(next_line).length > 0 unless @indent_space + next_indent > @current_indent + end + + private + + def indent_label(indent) + return %Q{"#{indent}"} if indent.include?(' ') && indent.include?("\t") + + label = indent.include?(' ') ? 'space' : 'tab' + length = indent.match(/[ \t]+/).to_s.length + + "#{length} #{label}#{'s' if length > 1}" + end + + def count_width(line) + return EOF unless line + line[/\A +/].to_s.length + end + + def next_space + next_line[/\A +/].to_s + end + + def next_width + count_width(next_line) + end + + def indent_rule + (@indent_space || '').length + end + + def fetch_indent(str) + str.match(/^[ \t]+/).to_s end end end end