1
0
Fork 0
mirror of https://github.com/haml/haml.git synced 2022-11-09 12:33:31 -05:00

[Sass] Handle newlines in selectors differently.

Allow newlines to appear anywhere in selectors
and produce output appropriately.
The indented syntax still only allows newlines following a comma;
this change is for SCSS.
This commit is contained in:
Nathan Weizenbaum 2009-12-21 12:51:09 -08:00
parent e4ac61fa11
commit a887d2a0e8
3 changed files with 50 additions and 44 deletions

View file

@ -25,7 +25,7 @@ module Sass
class RuleNode
# @see Node#to_sass
def to_sass(tabs, opts = {})
name = rules.first
name = rule
name = "\\" + name if name[0] == ?:
str = "\n#{' ' * tabs}#{name}#{children.any? { |c| c.is_a? PropNode } ? "\n" : ''}"
@ -126,8 +126,8 @@ module Sass
# @param root [Tree::Node] The parent node
def expand_commas(root)
root.children.map! do |child|
next child unless Tree::RuleNode === child && child.rules.first.include?(',')
child.rules.first.split(',').map do |rule|
next child unless Tree::RuleNode === child && child.rule.include?(',')
child.rule.split(',').map do |rule|
node = Tree::RuleNode.new(rule.strip)
node.children = child.children
node
@ -174,15 +174,15 @@ module Sass
current_rule = nil
root.children.select { |c| Tree::RuleNode === c }.each do |child|
root.children.delete child
first, rest = child.rules.first.scan(/^(&?(?: .|[^ ])[^.#: \[]*)([.#: \[].*)?$/).first
first, rest = child.rule.scan(/^(&?(?: .|[^ ])[^.#: \[]*)([.#: \[].*)?$/).first
if current_rule.nil? || current_rule.rules.first != first
if current_rule.nil? || current_rule.rule != first
current_rule = Tree::RuleNode.new(first)
root << current_rule
end
if rest
child.rules = ["&" + rest]
child.rule = "&" + rest
current_rule << child
else
current_rule.children += child.children
@ -208,7 +208,7 @@ module Sass
def remove_parent_refs(root)
root.children.each do |child|
if child.is_a?(Tree::RuleNode)
child.rules.first.gsub! /^& +/, ''
child.rule.gsub! /^& +/, ''
remove_parent_refs child
end
end
@ -249,10 +249,10 @@ module Sass
while rule.children.size == 1 && rule.children.first.is_a?(Tree::RuleNode)
child = rule.children.first
if child.rules.first[0] == ?&
rule.rules = [child.rules.first.gsub(/^&/, rule.rules.first)]
if child.rule[0] == ?&
rule.rule = child.rule.gsub(/^&/, rule.rule)
else
rule.rules = ["#{rule.rules.first} #{child.rules.first}"]
rule.rule = "#{rule.rule} #{child.rule}"
end
rule.children = child.children
@ -282,7 +282,7 @@ module Sass
next child unless child.is_a?(Tree::RuleNode)
if prev_rule && prev_rule.children == child.children
prev_rule.rules.first << ", #{child.rules.first}"
prev_rule.rule << ", #{child.rule}"
next nil
end

View file

@ -312,17 +312,18 @@ END
def check_for_no_children(node)
return unless node.is_a?(Tree::RuleNode) && node.children.empty?
warning = (node.rules.size == 1) ? <<SHORT : <<LONG
WARNING on line #{node.line}:
Selector #{node.rules.first.inspect} doesn't have any properties and will not be rendered.
SHORT
warning = (node.rule.include?("\n")) ? <<LONG : <<SHORT
WARNING on line #{node.line}:
Selector
#{node.rules.join("\n ")}
#{node.rule.gsub("\n", "\n ")}
doesn't have any properties and will not be rendered.
LONG
WARNING on line #{node.line}:
Selector #{node.rule.inspect} doesn't have any properties and will not be rendered.
SHORT
warn(warning.strip)
end

View file

@ -21,7 +21,7 @@ module Sass::Tree
# "bip, bop, bup"]
#
# @return [Array<String>]
attr_accessor :rules
attr_accessor :rule
# The CSS selectors for this rule,
# parsed for commas and parent-references.
@ -84,7 +84,7 @@ module Sass::Tree
# @param rule [String] The first CSS rule. See \{#rules}
def initialize(rule)
@rules = [rule]
@rule = rule
@tabs = 0
super()
end
@ -95,19 +95,19 @@ module Sass::Tree
# @return [Boolean] Whether or not this node and the other object
# are the same
def ==(other)
self.class == other.class && rules == other.rules && super
self.class == other.class && rule == other.rule && super
end
# Adds another {RuleNode}'s rules to this one's.
#
# @param node [RuleNode] The other node
def add_rules(node)
@rules += node.rules
@rule << "\n" << node.rule
end
# @return [Boolean] Whether or not this rule is continued on the next line
def continued?
@rules.last[-1] == ?,
@rule[-1] == ?,
end
protected
@ -120,12 +120,17 @@ module Sass::Tree
tabs = tabs + self.tabs
rule_separator = style == :compressed ? ',' : ', '
line_separator = [:nested, :expanded].include?(style) ? ",\n" : rule_separator
line_separator =
case style
when :nested, :expanded; "\n"
when :compressed; ""
else; " "
end
rule_indent = ' ' * (tabs - 1)
per_rule_indent, total_indent = [:nested, :expanded].include?(style) ? [rule_indent, ''] : ['', rule_indent]
total_rule = total_indent + resolved_rules.map do |line|
per_rule_indent + line.join(rule_separator)
total_rule = total_indent + resolved_rules.join(rule_separator).split("\n").map do |line|
per_rule_indent + line.strip
end.join(line_separator)
to_return = ''
@ -171,7 +176,7 @@ module Sass::Tree
# @param environment [Sass::Environment] The lexical environment containing
# variable and mixin values
def perform!(environment)
@parsed_rules = @rules.map {|r| parse_selector(interpolate(r, environment))}
@parsed_rules = parse_selector(interpolate(@rule, environment))
super
end
@ -210,32 +215,29 @@ module Sass::Tree
def resolve_parent_refs(super_rules)
if super_rules.nil?
return @parsed_rules.map do |line|
line.map do |rule|
if rule.include?(:parent)
raise Sass::SyntaxError.new("Base-level rules cannot contain the parent-selector-referencing character '#{PARENT}'.")
end
return @parsed_rules.map do |rule|
if rule.include?(:parent)
raise Sass::SyntaxError.new("Base-level rules cannot contain the parent-selector-referencing character '#{PARENT}'.")
end
rule.join
end.compact
rule.join
end
end
new_rules = []
super_rules.each do |super_line|
@parsed_rules.each do |line|
super_rules.each do |super_rule|
@parsed_rules.each do |rule|
new_rules << []
super_line.each do |super_rule|
line.each do |rule|
rule = [:parent, " ", *rule] unless rule.include?(:parent)
# An initial newline of the child rule
# should be moved to the beginning of the entire rule
rule.first.slice!(0) if nl = (rule.first.is_a?(String) && rule.first[0] == ?\n)
rule = [nl ? "\n" : "", :parent, " ", *rule] unless rule.include?(:parent)
new_rules.last << rule.map do |segment|
next segment unless segment == :parent
super_rule
end.join
end
end
new_rules.last << rule.map do |segment|
next segment unless segment == :parent
super_rule
end.join
end
end
new_rules
@ -251,7 +253,10 @@ module Sass::Tree
when '&'; rules.last << :parent
when ','
scanner.scan(/\s*/)
rules << [] if scanner.rest?
if scanner.rest?
rules << []
rules.last << "\n" if scanner.matched.include?("\n")
end
when '"'
rules.last << '"' << scanner.scan(/([^"\\]|\\.)*/)
# We don't want to enforce that strings are closed,