Skip to content

Commit

Permalink
Merge branch 'stable'
Browse files Browse the repository at this point in the history
Conflicts:
	lib/sass/tree/visitors/perform.rb
	test/sass/engine_test.rb
  • Loading branch information
nex3 committed Oct 5, 2011
2 parents 50a4978 + c232c67 commit 8932111
Show file tree
Hide file tree
Showing 13 changed files with 223 additions and 87 deletions.
3 changes: 3 additions & 0 deletions doc-src/SASS_CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ to support any vendor prefix, as well as the plain `:any` selector.

* Fix a regression in 3.1.8 that broke the `+` combinator in selectors.

* Deprecate the loud-comment flag when used with silent comments (e.g. `//!`).
Using it with multi-line comments (e.g. `/*!`) still works.

## 3.1.8

* Deprecate parent selectors followed immediately by identifiers (e.g. `&foo`).
Expand Down
36 changes: 26 additions & 10 deletions lib/sass/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,10 @@ class Engine
#
# `children`: `Array<Line>`
# : The lines nested below this one.
class Line < Struct.new(:text, :tabs, :index, :offset, :filename, :children)
#
# `comment_tab_str`: `String?`
# : The prefix indentation for this comment, if it is a comment.
class Line < Struct.new(:text, :tabs, :index, :offset, :filename, :children, :comment_tab_str)
def comment?
text[0] == COMMENT_CHAR && (text[1] == SASS_COMMENT_CHAR || text[1] == CSS_COMMENT_CHAR)
end
Expand All @@ -112,6 +115,10 @@ def comment?
# which is not output as a CSS comment.
SASS_COMMENT_CHAR = ?/

# The character that indicates that a comment allows interpolation
# and should be preserved even in `:compressed` mode.
SASS_LOUD_COMMENT_CHAR = ?!

# The character that follows the general COMMENT_CHAR and designates a CSS comment,
# which is embedded in the CSS document.
CSS_COMMENT_CHAR = ?*
Expand Down Expand Up @@ -425,7 +432,8 @@ def try_comment(line, last, tab_str, comment_tab_str, index)
MSG
end

last.text << "\n" << $1
last.comment_tab_str ||= comment_tab_str
last.text << "\n" << line
true
end

Expand Down Expand Up @@ -491,8 +499,8 @@ def append_children(parent, children, root)
if child.is_a?(Tree::CommentNode) && child.silent
if continued_comment &&
child.line == continued_comment.line +
continued_comment.value.count("\n") + 1
continued_comment.value << "\n" << child.value
continued_comment.lines + 1
continued_comment.value += ["\n"] + child.value
next
end

Expand Down Expand Up @@ -543,7 +551,7 @@ def parse_line(parent, line, root)
when ?$
parse_variable(line)
when COMMENT_CHAR
parse_comment(line.text)
parse_comment(line)
when DIRECTIVE_CHAR
parse_directive(parent, line, root)
when ESCAPE_CHAR
Expand Down Expand Up @@ -605,11 +613,19 @@ def parse_variable(line)
end

def parse_comment(line)
if line[1] == CSS_COMMENT_CHAR || line[1] == SASS_COMMENT_CHAR
silent = line[1] == SASS_COMMENT_CHAR
Tree::CommentNode.new(
format_comment_text(line[2..-1], silent),
silent)
if line.text[1] == CSS_COMMENT_CHAR || line.text[1] == SASS_COMMENT_CHAR
silent = line.text[1] == SASS_COMMENT_CHAR
if loud = line.text[2] == SASS_LOUD_COMMENT_CHAR
value = self.class.parse_interp(line.text, line.index, line.offset, :filename => @filename)
value[0].slice!(2) # get rid of the "!"
else
value = [line.text]
end
value = with_extracted_values(value) do |str|
str = str.gsub(/^#{line.comment_tab_str}/m, '')[2..-1] # get rid of // or /*
format_comment_text(str, silent)
end
Tree::CommentNode.new(value, silent, loud)
else
Tree::RuleNode.new(parse_interp(line))
end
Expand Down
2 changes: 1 addition & 1 deletion lib/sass/less.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def build_with_sass(env)
WARNING: Sass doesn't support mixing in selector sequences.
Replacing "#{sel}" with "@extend #{base}"
WARNING
env << Node::SassNode.new(Sass::Tree::CommentNode.new("// #{sel};", true))
env << Node::SassNode.new(Sass::Tree::CommentNode.new("// #{sel};", true, false))
env << Node::SassNode.new(Sass::Tree::ExtendNode.new([base]))
end
end
Expand Down
30 changes: 22 additions & 8 deletions lib/sass/scss/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,28 @@ def whitespace
end

def process_comment(text, node)
single_line = text =~ /^\/\//
pre_str = single_line ? "" : @scanner.
string[0...@scanner.pos].
reverse[/.*?\*\/(.*?)($|\Z)/, 1].
reverse.gsub(/[^\s]/, ' ')
text = text.sub(/^\s*\/\//, '/*').gsub(/^\s*\/\//, ' *') + ' */' if single_line
comment = Sass::Tree::CommentNode.new(pre_str + text, single_line)
comment.line = @line - text.count("\n")
silent = text =~ /^\/\//
line = @line - text.count("\n")
if loud = text =~ %r{^/[/*]!}
value = Sass::Engine.parse_interp(text, line, @scanner.pos - text.size, :filename => @filename)
value[0].slice!(2) # get rid of the "!"
else
value = [text]
end

if silent
value = Sass::Util.with_extracted_values(value) do |str|
str.sub(/^\s*\/\//, '/*').gsub(/^\s*\/\//, ' *') + ' */'
end
else
value.unshift(@scanner.
string[0...@scanner.pos].
reverse[/.*?\*\/(.*?)($|\Z)/, 1].
reverse.gsub(/[^\s]/, ' '))
end

comment = Sass::Tree::CommentNode.new(value, silent, loud)
comment.line = line
node << comment
end

Expand Down
2 changes: 1 addition & 1 deletion lib/sass/shared.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ module Shared
# @return [String] The text remaining in the scanner after all `#{`s have been processed
def handle_interpolation(str)
scan = StringScanner.new(str)
yield scan while scan.scan(/(.*?)(\\*)\#\{/)
yield scan while scan.scan(/(.*?)(\\*)\#\{/m)
scan.rest
end

Expand Down
35 changes: 24 additions & 11 deletions lib/sass/tree/comment_node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,19 @@ module Sass::Tree
# @see Sass::Tree
class CommentNode < Node
# The text of the comment, not including `/*` and `*/`.
# Interspersed with {Sass::Script::Node}s representing `#{}`-interpolation
# if this is a loud comment.
#
# @return [String]
# @return [Array<String, Sass::Script::Node>]
attr_accessor :value

# The text of the comment
# after any interpolated SassScript has been resolved.
# Only set once \{Tree::Visitors::Perform} has been run.
#
# @return [String]
attr_accessor :resolved_value

# Whether the comment is loud.
#
# Loud comments start with ! and force the comment to be generated
Expand All @@ -23,14 +32,13 @@ class CommentNode < Node
# @return [Boolean]
attr_accessor :silent

# @param value [String] See \{#value}
# @param value [Array<String, Sass::Script::Node>] See \{#value}
# @param silent [Boolean] See \{#silent}
def initialize(value, silent)
@lines = []
# @param loud [Boolean] See \{#loud}
def initialize(value, silent, loud)
@value = Sass::Util.with_extracted_values(value) {|str| normalize_indentation str}
@silent = silent
@value = normalize_indentation value
@loud = @value =~ %r{^(/[\/\*])?!}
@value.sub!("#{$1}!", $1.to_s) if @loud
@loud = loud
super()
end

Expand All @@ -40,7 +48,7 @@ def initialize(value, silent)
# @return [Boolean] Whether or not this node and the other object
# are the same
def ==(other)
self.class == other.class && value == other.value && silent == other.silent
self.class == other.class && value == other.value && silent == other.silent && loud == other.loud
end

# Returns `true` if this is a silent comment
Expand All @@ -57,9 +65,14 @@ def invisible?
end
end

# Returns whether this comment should be interpolated for dynamic comment generation.
def evaluated?
@loud
# Returns the number of lines in the comment.
#
# @return [Fixnum]
def lines
@value.inject(0) do |s, e|
next s + e.count("\n") if e.is_a?(String)
next s
end
end

private
Expand Down
15 changes: 10 additions & 5 deletions lib/sass/tree/visitors/convert.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def visit_root(node)
visit(child) +
if nxt &&
(child.is_a?(Sass::Tree::CommentNode) &&
child.line + child.value.count("\n") + 1 == nxt.line) ||
child.line + child.lines + 1 == nxt.line) ||
(child.is_a?(Sass::Tree::ImportNode) && nxt.is_a?(Sass::Tree::ImportNode) &&
child.line + 1 == nxt.line) ||
(child.is_a?(Sass::Tree::VariableNode) && nxt.is_a?(Sass::Tree::VariableNode) &&
Expand All @@ -49,8 +49,13 @@ def visit_charset(node)
end

def visit_comment(node)
value = node.value.map do |r|
next r if r.is_a?(String)
"\#{#{r.to_sass(@options)}}"
end.join

content = if @format == :sass
content = node.value.gsub(/\*\/$/, '').rstrip
content = value.gsub(/\*\/$/, '').rstrip
if content =~ /\A[ \t]/
# Re-indent SCSS comments like this:
# /* foo
Expand Down Expand Up @@ -78,11 +83,11 @@ def visit_comment(node)
content.gsub!(/^/, tab_str)
content.rstrip + "\n"
else
spaces = (' ' * [@tabs - node.value[/^ */].size, 0].max)
spaces = (' ' * [@tabs - value[/^ */].size, 0].max)
content = if node.silent
node.value.gsub(/^[\/ ]\*/, '//').gsub(/ *\*\/$/, '')
value.gsub(/^[\/ ]\*/, '//').gsub(/ *\*\/$/, '')
else
node.value
value
end.gsub(/^/, spaces) + "\n"
content
end
Expand Down
44 changes: 36 additions & 8 deletions lib/sass/tree/visitors/perform.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,10 @@ def visit_root(node)
# Removes this node from the tree if it's a silent comment.
def visit_comment(node)
return [] if node.invisible?
if node.evaluated?
node.value.gsub!(/(^|[^\\])\#\{([^}]*)\}/) do |md|
$1+Sass::Script.parse($2, node.line, 0, node.options).perform(@environment).to_s
end
node.value = run_interp([Sass::Script::String.new(node.value)])
end
check_for_loud_silent_comment node
check_for_comment_interp node
node.resolved_value = run_interp_no_strip(node.value)
node.resolved_value.gsub!(/\\([\\#])/, '\1')
node
end

Expand Down Expand Up @@ -314,14 +312,18 @@ def stack_trace
trace
end

def run_interp(text)
def run_interp_no_strip(text)
text.map do |r|
next r if r.is_a?(String)
val = r.perform(@environment)
# Interpolated strings should never render with quotes
next val.value if val.is_a?(Sass::Script::String)
val.to_s
end.join.strip
end.join
end

def run_interp(text)
run_interp_no_strip(text).strip
end

def handle_include_loop!(node)
Expand All @@ -347,4 +349,30 @@ def handle_include_loop!(node)
end.join("\n")
raise Sass::SyntaxError.new(msg)
end

def check_for_loud_silent_comment(node)
return unless node.loud && node.silent
Sass::Util.sass_warn <<MESSAGE
WARNING:
On line #{node.line}#{" of '#{node.filename}'" if node.filename}
`//` comments will no longer be allowed to use the `!` flag in Sass 3.2.
Please change to `/*` comments.
MESSAGE
end

def check_for_comment_interp(node)
return if node.loud
node.value.each do |e|
next unless e.is_a?(String)
e.scan(/(\\*)#\{/) do |esc|
Sass::Util.sass_warn <<MESSAGE if esc.first.size.even?
WARNING:
On line #{node.line}#{" of '#{node.filename}'" if node.filename}
Comments will evaluate the contents of interpolations (\#{ ... }) in Sass 3.2.
Please escape the interpolation by adding a backslash before the `#`.
MESSAGE
return
end
end
end
end
14 changes: 2 additions & 12 deletions lib/sass/tree/visitors/to_css.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,11 @@ def visit_charset(node)

def visit_comment(node)
return if node.invisible?
spaces = (' ' * [@tabs - node.value[/^ */].size, 0].max)
spaces = (' ' * [@tabs - node.resolved_value[/^ */].size, 0].max)

content = node.value.gsub(/^/, spaces).gsub(%r{^(\s*)//(.*)$}) do |md|
content = node.resolved_value.gsub(/^/, spaces).gsub(%r{^(\s*)//(.*)$}) do |md|
"#{$1}/*#{$2} */"
end
if content =~ /[^\\]\#\{.*\}/
Sass::Util.sass_warn <<MESSAGE
WARNING:
On line #{node.line}#{" of '#{node.filename}'" if node.filename}
Comments will evaluate the contents of interpolations (\#{ ... }) in Sass 3.2.
Please escape the interpolation by adding a backslash before the hash sign.
MESSAGE
elsif content =~ /\\\#\{.*\}/
content.gsub!(/\\(\#\{.*\})/, '\1')
end
content.gsub!(/\n +(\* *(?!\/))?/, ' ') if (node.style == :compact || node.style == :compressed) && !node.loud
content
end
Expand Down
Loading

0 comments on commit 8932111

Please sign in to comment.