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