summaryrefslogtreecommitdiff
path: root/lib/coderay/scanners
diff options
context:
space:
mode:
authorKornelius Kalnbach <murphy@rubychan.de>2013-06-11 18:10:54 +0200
committerKornelius Kalnbach <murphy@rubychan.de>2013-06-11 18:10:54 +0200
commit916711c9983483c39f9a68c29e21a0ed40004bd2 (patch)
treea3a98ac92db67a75625525b4d559b7db7ac89965 /lib/coderay/scanners
parent0c98047ea276f393daa8249cf9c124ebc08266d2 (diff)
parent2e4e83bf84282d6ce7fbc9eeff2cbe1c79788a9b (diff)
downloadcoderay-916711c9983483c39f9a68c29e21a0ed40004bd2.tar.gz
Merge branch 'master' into paint-integration
Diffstat (limited to 'lib/coderay/scanners')
-rw-r--r--lib/coderay/scanners/c.rb2
-rw-r--r--lib/coderay/scanners/cpp.rb2
-rw-r--r--lib/coderay/scanners/css.rb41
-rw-r--r--lib/coderay/scanners/diff.rb2
-rw-r--r--lib/coderay/scanners/java.rb2
-rw-r--r--lib/coderay/scanners/java_script.rb36
-rw-r--r--lib/coderay/scanners/json.rb2
-rw-r--r--lib/coderay/scanners/python.rb2
-rw-r--r--lib/coderay/scanners/ruby.rb2
-rw-r--r--lib/coderay/scanners/sass.rb227
-rw-r--r--lib/coderay/scanners/sql.rb2
11 files changed, 284 insertions, 36 deletions
diff --git a/lib/coderay/scanners/c.rb b/lib/coderay/scanners/c.rb
index 8d24b99..84b6e8e 100644
--- a/lib/coderay/scanners/c.rb
+++ b/lib/coderay/scanners/c.rb
@@ -148,7 +148,7 @@ module Scanners
encoder.text_token match, :char
elsif match = scan(/ \\ | $ /x)
encoder.end_group :string
- encoder.text_token match, :error
+ encoder.text_token match, :error unless match.empty?
state = :initial
label_expected = false
else
diff --git a/lib/coderay/scanners/cpp.rb b/lib/coderay/scanners/cpp.rb
index 9da62f4..e61f56f 100644
--- a/lib/coderay/scanners/cpp.rb
+++ b/lib/coderay/scanners/cpp.rb
@@ -160,7 +160,7 @@ module Scanners
encoder.text_token match, :char
elsif match = scan(/ \\ | $ /x)
encoder.end_group :string
- encoder.text_token match, :error
+ encoder.text_token match, :error unless match.empty?
state = :initial
label_expected = false
else
diff --git a/lib/coderay/scanners/css.rb b/lib/coderay/scanners/css.rb
index 7b731ef..732f9c5 100644
--- a/lib/coderay/scanners/css.rb
+++ b/lib/coderay/scanners/css.rb
@@ -7,27 +7,25 @@ module Scanners
KINDS_NOT_LOC = [
:comment,
- :class, :pseudo_class, :type,
- :constant, :directive,
+ :class, :pseudo_class, :tag,
+ :id, :directive,
:key, :value, :operator, :color, :float, :string,
- :error, :important,
+ :error, :important, :type,
] # :nodoc:
module RE # :nodoc:
Hex = /[0-9a-fA-F]/
- Unicode = /\\#{Hex}{1,6}(?:\r\n|\s)?/ # differs from standard because it allows uppercase hex too
- Escape = /#{Unicode}|\\[^\r\n\f0-9a-fA-F]/
- NMChar = /[-_a-zA-Z0-9]|#{Escape}/
- NMStart = /[_a-zA-Z]|#{Escape}/
- NL = /\r\n|\r|\n|\f/
- String1 = /"(?:[^\n\r\f\\"]|\\#{NL}|#{Escape})*"?/ # TODO: buggy regexp
- String2 = /'(?:[^\n\r\f\\']|\\#{NL}|#{Escape})*'?/ # TODO: buggy regexp
+ Unicode = /\\#{Hex}{1,6}\b/ # differs from standard because it allows uppercase hex too
+ Escape = /#{Unicode}|\\[^\n0-9a-fA-F]/
+ NMChar = /[-_a-zA-Z0-9]/
+ NMStart = /[_a-zA-Z]/
+ String1 = /"(?:[^\n\\"]+|\\\n|#{Escape})*"?/ # TODO: buggy regexp
+ String2 = /'(?:[^\n\\']+|\\\n|#{Escape})*'?/ # TODO: buggy regexp
String = /#{String1}|#{String2}/
HexColor = /#(?:#{Hex}{6}|#{Hex}{3})/
- Color = /#{HexColor}/
- Num = /-?(?:[0-9]+|[0-9]*\.[0-9]+)/
+ Num = /-?(?:[0-9]*\.[0-9]+|[0-9]+)/
Name = /#{NMChar}+/
Ident = /-?#{NMStart}#{NMChar}*/
AtKeyword = /@#{Ident}/
@@ -35,16 +33,15 @@ module Scanners
reldimensions = %w[em ex px]
absdimensions = %w[in cm mm pt pc]
- Unit = Regexp.union(*(reldimensions + absdimensions + %w[s]))
+ Unit = Regexp.union(*(reldimensions + absdimensions + %w[s dpi dppx deg]))
Dimension = /#{Num}#{Unit}/
- Comment = %r! /\* (?: .*? \*/ | .* ) !mx
- Function = /(?:url|alpha|attr|counters?)\((?:[^)\n\r\f]|\\\))*\)?/
+ Function = /(?:url|alpha|attr|counters?)\((?:[^)\n]|\\\))*\)?/
- Id = /##{Name}/
+ Id = /(?!#{HexColor}\b(?!-))##{Name}/
Class = /\.#{Name}/
- PseudoClass = /:#{Name}/
+ PseudoClass = /::?#{Ident}/
AttributeSelector = /\[[^\]]*\]?/
end
@@ -52,7 +49,7 @@ module Scanners
def setup
@state = :initial
- @value_expected = nil
+ @value_expected = false
end
def scan_tokens encoder, options
@@ -67,13 +64,13 @@ module Scanners
elsif case states.last
when :initial, :media
if match = scan(/(?>#{RE::Ident})(?!\()|\*/ox)
- encoder.text_token match, :type
+ encoder.text_token match, :tag
next
elsif match = scan(RE::Class)
encoder.text_token match, :class
next
elsif match = scan(RE::Id)
- encoder.text_token match, :constant
+ encoder.text_token match, :id
next
elsif match = scan(RE::PseudoClass)
encoder.text_token match, :pseudo_class
@@ -158,7 +155,7 @@ module Scanners
elsif match = scan(/(?: #{RE::Dimension} | #{RE::Percentage} | #{RE::Num} )/ox)
encoder.text_token match, :float
- elsif match = scan(/#{RE::Color}/o)
+ elsif match = scan(/#{RE::HexColor}/o)
encoder.text_token match, :color
elsif match = scan(/! *important/)
@@ -170,7 +167,7 @@ module Scanners
elsif match = scan(RE::AtKeyword)
encoder.text_token match, :directive
- elsif match = scan(/ [+>:;,.=()\/] /x)
+ elsif match = scan(/ [+>~:;,.=()\/] /x)
if match == ':'
value_expected = true
elsif match == ';'
diff --git a/lib/coderay/scanners/diff.rb b/lib/coderay/scanners/diff.rb
index 38efaf4..af0f755 100644
--- a/lib/coderay/scanners/diff.rb
+++ b/lib/coderay/scanners/diff.rb
@@ -45,7 +45,7 @@ module Scanners
if match = scan(/--- |\+\+\+ |=+|_+/)
encoder.begin_line line_kind = :head
encoder.text_token match, :head
- if match = scan(/.*?(?=$|[\t\n\x00]| \(revision)/)
+ if match = scan(/[^\x00\n]+?(?=$|[\t\n]| \(revision)/)
encoder.text_token match, :filename
if options[:highlight_code] && match != '/dev/null'
file_type = CodeRay::FileType.fetch(match, :text)
diff --git a/lib/coderay/scanners/java.rb b/lib/coderay/scanners/java.rb
index c1490ac..b282864 100644
--- a/lib/coderay/scanners/java.rb
+++ b/lib/coderay/scanners/java.rb
@@ -147,7 +147,7 @@ module Scanners
elsif match = scan(/ \\ | $ /x)
encoder.end_group state
state = :initial
- encoder.text_token match, :error
+ encoder.text_token match, :error unless match.empty?
else
raise_inspect "else case \" reached; %p not handled." % peek(1), encoder
end
diff --git a/lib/coderay/scanners/java_script.rb b/lib/coderay/scanners/java_script.rb
index 43ecb18..9eb0a0a 100644
--- a/lib/coderay/scanners/java_script.rb
+++ b/lib/coderay/scanners/java_script.rb
@@ -54,10 +54,17 @@ module Scanners
protected
+ def setup
+ @state = :initial
+ end
+
def scan_tokens encoder, options
- state = :initial
- string_delimiter = nil
+ state, string_delimiter = options[:state] || @state
+ if string_delimiter
+ encoder.begin_group state
+ end
+
value_expected = true
key_expected = false
function_expected = false
@@ -72,9 +79,10 @@ module Scanners
value_expected = true if !value_expected && match.index(?\n)
encoder.text_token match, :space
- elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx)
+ elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .*() ) !mx)
value_expected = true
encoder.text_token match, :comment
+ state = :open_multi_line_comment if self[1]
elsif check(/\.?\d/)
key_expected = value_expected = false
@@ -175,20 +183,36 @@ module Scanners
encoder.text_token match, :content
elsif match = scan(/ \\ | $ /x)
encoder.end_group state
- encoder.text_token match, :error
+ encoder.text_token match, :error unless match.empty?
+ string_delimiter = nil
key_expected = value_expected = false
state = :initial
else
- raise_inspect "else case \" reached; %p not handled." % peek(1), encoder
+ raise_inspect "else case #{string_delimiter} reached; %p not handled." % peek(1), encoder
end
+ when :open_multi_line_comment
+ if match = scan(%r! .*? \*/ !mx)
+ state = :initial
+ else
+ match = scan(%r! .+ !mx)
+ end
+ value_expected = true
+ encoder.text_token match, :comment if match
+
else
- raise_inspect 'Unknown state', encoder
+ #:nocov:
+ raise_inspect 'Unknown state: %p' % [state], encoder
+ #:nocov:
end
end
+ if options[:keep_state]
+ @state = state, string_delimiter
+ end
+
if [:string, :regexp].include? state
encoder.end_group state
end
diff --git a/lib/coderay/scanners/json.rb b/lib/coderay/scanners/json.rb
index 0c90c34..4e0f462 100644
--- a/lib/coderay/scanners/json.rb
+++ b/lib/coderay/scanners/json.rb
@@ -70,7 +70,7 @@ module Scanners
encoder.text_token match, :content
elsif match = scan(/ \\ | $ /x)
encoder.end_group state
- encoder.text_token match, :error
+ encoder.text_token match, :error unless match.empty?
state = :initial
else
raise_inspect "else case \" reached; %p not handled." % peek(1), encoder
diff --git a/lib/coderay/scanners/python.rb b/lib/coderay/scanners/python.rb
index cbdbbdb..a9492ab 100644
--- a/lib/coderay/scanners/python.rb
+++ b/lib/coderay/scanners/python.rb
@@ -133,7 +133,7 @@ module Scanners
elsif match = scan(/ \\ | $ /x)
encoder.end_group string_type
string_type = nil
- encoder.text_token match, :error
+ encoder.text_token match, :error unless match.empty?
state = :initial
else
raise_inspect "else case \" reached; %p not handled." % peek(1), encoder, state
diff --git a/lib/coderay/scanners/ruby.rb b/lib/coderay/scanners/ruby.rb
index c5cf1e2..c282f31 100644
--- a/lib/coderay/scanners/ruby.rb
+++ b/lib/coderay/scanners/ruby.rb
@@ -96,7 +96,7 @@ module Scanners
/#{patterns::METHOD_NAME}/o)
kind = patterns::IDENT_KIND[match]
- if kind == :ident && value_expected != :colon_expected && scan(/:(?!:)/)
+ if value_expected != :colon_expected && scan(/:(?!:)/)
value_expected = true
encoder.text_token match, :key
encoder.text_token ':', :operator
diff --git a/lib/coderay/scanners/sass.rb b/lib/coderay/scanners/sass.rb
new file mode 100644
index 0000000..167051d
--- /dev/null
+++ b/lib/coderay/scanners/sass.rb
@@ -0,0 +1,227 @@
+module CodeRay
+module Scanners
+
+ # A scanner for Sass.
+ class Sass < CSS
+
+ register_for :sass
+ file_extension 'sass'
+
+ STRING_CONTENT_PATTERN = {
+ "'" => /(?:[^\n\'\#]+|\\\n|#{RE::Escape}|#(?!\{))+/,
+ '"' => /(?:[^\n\"\#]+|\\\n|#{RE::Escape}|#(?!\{))+/,
+ }
+
+ protected
+
+ def setup
+ @state = :initial
+ end
+
+ def scan_tokens encoder, options
+ states = Array(options[:state] || @state)
+ string_delimiter = nil
+
+ until eos?
+
+ if bol? && (match = scan(/(?>( +)?(\/[\*\/])(.+)?)(?=\n)/))
+ encoder.text_token self[1], :space if self[1]
+ encoder.begin_group :comment
+ encoder.text_token self[2], :delimiter
+ encoder.text_token self[3], :content if self[3]
+ if match = scan(/(?:\n+#{self[1]} .*)+/)
+ encoder.text_token match, :content
+ end
+ encoder.end_group :comment
+ elsif match = scan(/\n|[^\n\S]+\n?/)
+ encoder.text_token match, :space
+ if match.index(/\n/)
+ value_expected = false
+ states.pop if states.last == :include
+ end
+
+ elsif states.last == :sass_inline && (match = scan(/\}/))
+ encoder.text_token match, :inline_delimiter
+ encoder.end_group :inline
+ states.pop
+
+ elsif case states.last
+ when :initial, :media, :sass_inline
+ if match = scan(/(?>#{RE::Ident})(?!\()/ox)
+ encoder.text_token match, value_expected ? :value : (check(/.*:/) ? :key : :tag)
+ next
+ elsif !value_expected && (match = scan(/\*/))
+ encoder.text_token match, :tag
+ next
+ elsif match = scan(RE::Class)
+ encoder.text_token match, :class
+ next
+ elsif match = scan(RE::Id)
+ encoder.text_token match, :id
+ next
+ elsif match = scan(RE::PseudoClass)
+ encoder.text_token match, :pseudo_class
+ next
+ elsif match = scan(RE::AttributeSelector)
+ # TODO: Improve highlighting inside of attribute selectors.
+ encoder.text_token match[0,1], :operator
+ encoder.text_token match[1..-2], :attribute_name if match.size > 2
+ encoder.text_token match[-1,1], :operator if match[-1] == ?]
+ next
+ elsif match = scan(/(\=|@mixin +)#{RE::Ident}/o)
+ encoder.text_token match, :function
+ next
+ elsif match = scan(/@import\b/)
+ encoder.text_token match, :directive
+ states << :include
+ next
+ elsif match = scan(/@media\b/)
+ encoder.text_token match, :directive
+ # states.push :media_before_name
+ next
+ end
+
+ when :block
+ if match = scan(/(?>#{RE::Ident})(?!\()/ox)
+ if value_expected
+ encoder.text_token match, :value
+ else
+ encoder.text_token match, :key
+ end
+ next
+ end
+
+ when :string
+ if match = scan(STRING_CONTENT_PATTERN[string_delimiter])
+ encoder.text_token match, :content
+ elsif match = scan(/['"]/)
+ encoder.text_token match, :delimiter
+ encoder.end_group :string
+ string_delimiter = nil
+ states.pop
+ elsif match = scan(/#\{/)
+ encoder.begin_group :inline
+ encoder.text_token match, :inline_delimiter
+ states.push :sass_inline
+ elsif match = scan(/ \\ | $ /x)
+ encoder.end_group :string
+ encoder.text_token match, :error unless match.empty?
+ states.pop
+ else
+ raise_inspect "else case #{string_delimiter} reached; %p not handled." % peek(1), encoder
+ end
+
+ when :include
+ if match = scan(/[^\s'",]+/)
+ encoder.text_token match, :include
+ next
+ end
+
+ else
+ #:nocov:
+ raise_inspect 'Unknown state', encoder
+ #:nocov:
+
+ end
+
+ elsif match = scan(/\$#{RE::Ident}/o)
+ encoder.text_token match, :variable
+ next
+
+ elsif match = scan(/&/)
+ encoder.text_token match, :local_variable
+
+ elsif match = scan(/\+#{RE::Ident}/o)
+ encoder.text_token match, :include
+ value_expected = true
+
+ elsif match = scan(/\/\*(?:.*?\*\/|.*)|\/\/.*/)
+ encoder.text_token match, :comment
+
+ elsif match = scan(/#\{/)
+ encoder.begin_group :inline
+ encoder.text_token match, :inline_delimiter
+ states.push :sass_inline
+
+ elsif match = scan(/\{/)
+ value_expected = false
+ encoder.text_token match, :operator
+ states.push :block
+
+ elsif match = scan(/\}/)
+ value_expected = false
+ encoder.text_token match, :operator
+ if states.last == :block || states.last == :media
+ states.pop
+ end
+
+ elsif match = scan(/['"]/)
+ encoder.begin_group :string
+ string_delimiter = match
+ encoder.text_token match, :delimiter
+ if states.include? :sass_inline
+ content = scan_until(/(?=#{string_delimiter}|\}|\z)/)
+ encoder.text_token content, :content unless content.empty?
+ encoder.text_token string_delimiter, :delimiter if scan(/#{string_delimiter}/)
+ encoder.end_group :string
+ else
+ states.push :string
+ end
+
+ elsif match = scan(/#{RE::Function}/o)
+ encoder.begin_group :function
+ start = match[/^[-\w]+\(/]
+ encoder.text_token start, :delimiter
+ if match[-1] == ?)
+ encoder.text_token match[start.size..-2], :content
+ encoder.text_token ')', :delimiter
+ else
+ encoder.text_token match[start.size..-1], :content
+ end
+ encoder.end_group :function
+
+ elsif match = scan(/[a-z][-a-z_]*(?=\()/o)
+ encoder.text_token match, :predefined
+
+ elsif match = scan(/(?: #{RE::Dimension} | #{RE::Percentage} | #{RE::Num} )/ox)
+ encoder.text_token match, :float
+
+ elsif match = scan(/#{RE::HexColor}/o)
+ encoder.text_token match, :color
+
+ elsif match = scan(/! *(?:important|optional)/)
+ encoder.text_token match, :important
+
+ elsif match = scan(/(?:rgb|hsl)a?\([^()\n]*\)?/)
+ encoder.text_token match, :color
+
+ elsif match = scan(/@else if\b|#{RE::AtKeyword}/)
+ encoder.text_token match, :directive
+ value_expected = true
+
+ elsif match = scan(/ == | != | [-+*\/>~:;,.=()] /x)
+ if match == ':'
+ value_expected = true
+ elsif match == ';'
+ value_expected = false
+ end
+ encoder.text_token match, :operator
+
+ else
+ encoder.text_token getch, :error
+
+ end
+
+ end
+
+ if options[:keep_state]
+ @state = states
+ end
+
+ encoder
+ end
+
+ end
+
+end
+end
diff --git a/lib/coderay/scanners/sql.rb b/lib/coderay/scanners/sql.rb
index bcbffd5..b757278 100644
--- a/lib/coderay/scanners/sql.rb
+++ b/lib/coderay/scanners/sql.rb
@@ -148,7 +148,7 @@ module CodeRay module Scanners
encoder.text_token string_content, :content
string_content = ''
end
- encoder.text_token match, :error
+ encoder.text_token match, :error unless match.empty?
state = :initial
else
raise "else case \" reached; %p not handled." % peek(1), encoder