blob: 1f50995a15d4c743a853afa0fb88822dd7b8ff0f [file] [log] [blame]
module Sass
# This module contains functionality that's shared between Haml and Sass.
module Shared
extend self
# Scans through a string looking for the interoplation-opening `#{`
# and, when it's found, yields the scanner to the calling code
# so it can handle it properly.
#
# The scanner will have any backslashes immediately in front of the `#{`
# as the second capture group (`scan[2]`),
# and the text prior to that as the first (`scan[1]`).
#
# @yieldparam scan [StringScanner] The scanner scanning through the string
# @return [String] The text remaining in the scanner after all `#{`s have been processed
def handle_interpolation(str)
scan = Sass::Util::MultibyteStringScanner.new(str)
yield scan while scan.scan(/(.*?)(\\*)\#\{/m)
scan.rest
end
# Moves a scanner through a balanced pair of characters.
# For example:
#
# Foo (Bar (Baz bang) bop) (Bang (bop bip))
# ^ ^
# from to
#
# @param scanner [StringScanner] The string scanner to move
# @param start [Character] The character opening the balanced pair.
# A `Fixnum` in 1.8, a `String` in 1.9
# @param finish [Character] The character closing the balanced pair.
# A `Fixnum` in 1.8, a `String` in 1.9
# @param count [Integer] The number of opening characters matched
# before calling this method
# @return [(String, String)] The string matched within the balanced pair
# and the rest of the string.
# `["Foo (Bar (Baz bang) bop)", " (Bang (bop bip))"]` in the example above.
def balance(scanner, start, finish, count = 0)
str = ''
scanner = Sass::Util::MultibyteStringScanner.new(scanner) unless scanner.is_a? StringScanner
regexp = Regexp.new("(.*?)[\\#{start.chr}\\#{finish.chr}]", Regexp::MULTILINE)
while scanner.scan(regexp)
str << scanner.matched
count += 1 if scanner.matched[-1] == start
count -= 1 if scanner.matched[-1] == finish
return [str, scanner.rest] if count == 0
end
end
# Formats a string for use in error messages about indentation.
#
# @param indentation [String] The string used for indentation
# @param was [Boolean] Whether or not to add `"was"` or `"were"`
# (depending on how many characters were in `indentation`)
# @return [String] The name of the indentation (e.g. `"12 spaces"`, `"1 tab"`)
def human_indentation(indentation, was = false)
if !indentation.include?(?\t)
noun = 'space'
elsif !indentation.include?(?\s)
noun = 'tab'
else
return indentation.inspect + (was ? ' was' : '')
end
singular = indentation.length == 1
if was
was = singular ? ' was' : ' were'
else
was = ''
end
"#{indentation.length} #{noun}#{'s' unless singular}#{was}"
end
end
end