summaryrefslogtreecommitdiff
path: root/lib/coderay
diff options
context:
space:
mode:
authorKornelius Kalnbach <murphy@rubychan.de>2016-02-13 16:57:03 +0100
committerKornelius Kalnbach <murphy@rubychan.de>2016-02-13 16:57:03 +0100
commitff47c7a8cb46bb901f569aafb6f43ecc953571c1 (patch)
tree085a6f34630c8dd1f0293ac7f7b38b7029a6884f /lib/coderay
parent31c252ae9fd4b7e2f1ea2fd0009e7808d7691bcc (diff)
parent0a1f500d524ff0fb5eeafef051ccbb641954a87a (diff)
downloadcoderay-ff47c7a8cb46bb901f569aafb6f43ecc953571c1.tar.gz
Merge branch 'master' into tweak-function-colors
Diffstat (limited to 'lib/coderay')
-rw-r--r--lib/coderay/encoders/debug_lint.rb13
-rw-r--r--lib/coderay/encoders/html.rb28
-rw-r--r--lib/coderay/encoders/lint.rb59
-rw-r--r--lib/coderay/helpers/file_type.rb10
-rw-r--r--lib/coderay/helpers/plugin.rb22
-rw-r--r--lib/coderay/scanners/css.rb4
-rw-r--r--lib/coderay/scanners/debug.rb26
-rw-r--r--lib/coderay/scanners/diff.rb2
-rw-r--r--lib/coderay/scanners/go.rb208
-rw-r--r--lib/coderay/scanners/raydebug.rb31
-rw-r--r--lib/coderay/scanners/ruby.rb19
-rw-r--r--lib/coderay/scanners/ruby/patterns.rb7
-rw-r--r--lib/coderay/scanners/ruby/string_state.rb22
-rw-r--r--lib/coderay/scanners/sass.rb37
-rw-r--r--lib/coderay/scanners/sql.rb42
-rw-r--r--lib/coderay/styles/alpha.rb4
-rwxr-xr-xlib/coderay/token_kinds.rb8
-rw-r--r--lib/coderay/version.rb2
18 files changed, 422 insertions, 122 deletions
diff --git a/lib/coderay/encoders/debug_lint.rb b/lib/coderay/encoders/debug_lint.rb
index 17a0795..a4eba2c 100644
--- a/lib/coderay/encoders/debug_lint.rb
+++ b/lib/coderay/encoders/debug_lint.rb
@@ -1,6 +1,8 @@
module CodeRay
module Encoders
+ load :lint
+
# = Debug Lint Encoder
#
# Debug encoder with additional checks for:
@@ -15,12 +17,9 @@ module Encoders
register_for :debug_lint
- InvalidTokenStream = Class.new StandardError
- EmptyToken = Class.new InvalidTokenStream
- IncorrectTokenGroupNesting = Class.new InvalidTokenStream
-
def text_token text, kind
- raise EmptyToken, 'empty token' if text.empty?
+ raise Lint::EmptyToken, 'empty token for %p' % [kind] if text.empty?
+ raise Lint::UnknownTokenKind, 'unknown token kind %p (text was %p)' % [kind, text] unless TokenKinds.has_key? kind
super
end
@@ -30,7 +29,7 @@ module Encoders
end
def end_group kind
- raise IncorrectTokenGroupNesting, 'We are inside %s, not %p (end_group)' % [@opened.reverse.map(&:inspect).join(' < '), kind] if @opened.last != kind
+ raise Lint::IncorrectTokenGroupNesting, 'We are inside %s, not %p (end_group)' % [@opened.reverse.map(&:inspect).join(' < '), kind] if @opened.last != kind
@opened.pop
super
end
@@ -41,7 +40,7 @@ module Encoders
end
def end_line kind
- raise IncorrectTokenGroupNesting, 'We are inside %s, not %p (end_line)' % [@opened.reverse.map(&:inspect).join(' < '), kind] if @opened.last != kind
+ raise Lint::IncorrectTokenGroupNesting, 'We are inside %s, not %p (end_line)' % [@opened.reverse.map(&:inspect).join(' < '), kind] if @opened.last != kind
@opened.pop
super
end
diff --git a/lib/coderay/encoders/html.rb b/lib/coderay/encoders/html.rb
index 20f2409..942b9c8 100644
--- a/lib/coderay/encoders/html.rb
+++ b/lib/coderay/encoders/html.rb
@@ -25,7 +25,8 @@ module Encoders
# == Options
#
# === :tab_width
- # Convert \t characters to +n+ spaces (a number.)
+ # Convert \t characters to +n+ spaces (a number or false.)
+ # false will keep tab characters untouched.
#
# Default: 8
#
@@ -180,7 +181,7 @@ module Encoders
@break_lines = (options[:break_lines] == true)
- @HTML_ESCAPE = HTML_ESCAPE.merge("\t" => ' ' * options[:tab_width])
+ @HTML_ESCAPE = HTML_ESCAPE.merge("\t" => options[:tab_width] ? ' ' * options[:tab_width] : "\t")
@opened = []
@last_opened = nil
@@ -197,13 +198,15 @@ module Encoders
@last_opened = nil
end
- @out.extend Output
- @out.css = @css
- if options[:line_numbers]
- Numbering.number! @out, options[:line_numbers], options
+ if @out.respond_to? :to_str
+ @out.extend Output
+ @out.css = @css
+ if options[:line_numbers]
+ Numbering.number! @out, options[:line_numbers], options
+ end
+ @out.wrap! options[:wrap]
+ @out.apply_title! options[:title]
end
- @out.wrap! options[:wrap]
- @out.apply_title! options[:title]
if defined?(@real_out) && @real_out
@real_out << @out
@@ -285,7 +288,7 @@ module Encoders
def make_span_for_kinds method, hint
Hash.new do |h, kinds|
- h[kinds.is_a?(Symbol) ? kinds : kinds.dup] = begin
+ begin
css_class = css_class_for_kinds(kinds)
title = HTML.token_path_to_hint hint, kinds if hint
@@ -297,6 +300,9 @@ module Encoders
"<span#{title}#{" class=\"#{css_class}\"" if css_class}>"
end
end
+ end.tap do |span|
+ h.clear if h.size >= 100
+ h[kinds] = span
end
end
end
@@ -309,8 +315,8 @@ module Encoders
def break_lines text, style
reopen = ''
- @opened.each_with_index do |k, index|
- reopen << (@span_for_kinds[index > 0 ? [k, *@opened[0...index]] : k] || '<span>')
+ @opened.each_with_index do |kind, index|
+ reopen << (@span_for_kinds[index > 0 ? [kind, *@opened[0...index]] : kind] || '<span>')
end
text.gsub("\n", "#{'</span>' * @opened.size}#{'</span>' if style}\n#{reopen}#{style}")
end
diff --git a/lib/coderay/encoders/lint.rb b/lib/coderay/encoders/lint.rb
new file mode 100644
index 0000000..88c8bd1
--- /dev/null
+++ b/lib/coderay/encoders/lint.rb
@@ -0,0 +1,59 @@
+module CodeRay
+module Encoders
+
+ # = Lint Encoder
+ #
+ # Checks for:
+ #
+ # - empty tokens
+ # - incorrect nesting
+ #
+ # It will raise an InvalidTokenStream exception when any of the above occurs.
+ #
+ # See also: Encoders::DebugLint
+ class Lint < Debug
+
+ register_for :lint
+
+ InvalidTokenStream = Class.new StandardError
+ EmptyToken = Class.new InvalidTokenStream
+ UnknownTokenKind = Class.new InvalidTokenStream
+ IncorrectTokenGroupNesting = Class.new InvalidTokenStream
+
+ def text_token text, kind
+ raise EmptyToken, 'empty token for %p' % [kind] if text.empty?
+ raise UnknownTokenKind, 'unknown token kind %p (text was %p)' % [kind, text] unless TokenKinds.has_key? kind
+ end
+
+ def begin_group kind
+ @opened << kind
+ end
+
+ def end_group kind
+ raise IncorrectTokenGroupNesting, 'We are inside %s, not %p (end_group)' % [@opened.reverse.map(&:inspect).join(' < '), kind] if @opened.last != kind
+ @opened.pop
+ end
+
+ def begin_line kind
+ @opened << kind
+ end
+
+ def end_line kind
+ raise IncorrectTokenGroupNesting, 'We are inside %s, not %p (end_line)' % [@opened.reverse.map(&:inspect).join(' < '), kind] if @opened.last != kind
+ @opened.pop
+ end
+
+ protected
+
+ def setup options
+ @opened = []
+ end
+
+ def finish options
+ raise 'Some tokens still open at end of token stream: %p' % [@opened] unless @opened.empty?
+ end
+
+ end
+
+end
+end
diff --git a/lib/coderay/helpers/file_type.rb b/lib/coderay/helpers/file_type.rb
index 6d4fa92..7de34d5 100644
--- a/lib/coderay/helpers/file_type.rb
+++ b/lib/coderay/helpers/file_type.rb
@@ -38,7 +38,7 @@ module CodeRay
(TypeFromExt[ext2.downcase] if ext2) ||
TypeFromName[name] ||
TypeFromName[name.downcase]
- type ||= shebang(filename) if read_shebang
+ type ||= type_from_shebang(filename) if read_shebang
type
end
@@ -63,7 +63,7 @@ module CodeRay
protected
- def shebang filename
+ def type_from_shebang filename
return unless File.exist? filename
File.open filename, 'r' do |f|
if first_line = f.gets
@@ -86,6 +86,7 @@ module CodeRay
'dpr' => :delphi,
'erb' => :erb,
'gemspec' => :ruby,
+ 'go' => :go,
'groovy' => :groovy,
'gvy' => :groovy,
'h' => :c,
@@ -116,7 +117,7 @@ module CodeRay
'rhtml' => :erb,
'rjs' => :ruby,
'rpdf' => :ruby,
- 'ru' => :ruby,
+ 'ru' => :ruby, # config.ru
'rxml' => :ruby,
'sass' => :sass,
'sql' => :sql,
@@ -140,6 +141,9 @@ module CodeRay
'Rakefile' => :ruby,
'Rantfile' => :ruby,
'Gemfile' => :ruby,
+ 'Guardfile' => :ruby,
+ 'Vagrantfile' => :ruby,
+ 'Appraisals' => :ruby
}
end
diff --git a/lib/coderay/helpers/plugin.rb b/lib/coderay/helpers/plugin.rb
index d14c5a9..9a724ff 100644
--- a/lib/coderay/helpers/plugin.rb
+++ b/lib/coderay/helpers/plugin.rb
@@ -30,7 +30,7 @@ module CodeRay
# * a file could not be found
# * the requested Plugin is not registered
PluginNotFound = Class.new LoadError
- HostNotFound = Class.new LoadError
+ HostNotFound = Class.new LoadError
PLUGIN_HOSTS = []
PLUGIN_HOSTS_BY_ID = {} # dummy hash
@@ -49,8 +49,8 @@ module CodeRay
def [] id, *args, &blk
plugin = validate_id(id)
begin
- plugin = plugin_hash.[] plugin, *args, &blk
- end while plugin.is_a? Symbol
+ plugin = plugin_hash.[](plugin, *args, &blk)
+ end while plugin.is_a? String
plugin
end
@@ -95,7 +95,7 @@ module CodeRay
def map hash
for from, to in hash
from = validate_id from
- to = validate_id to
+ to = validate_id to
plugin_hash[from] = to unless plugin_hash.has_key? from
end
end
@@ -197,22 +197,22 @@ module CodeRay
File.join plugin_path, "#{plugin_id}.rb"
end
- # Converts +id+ to a Symbol if it is a String,
- # or returns +id+ if it already is a Symbol.
+ # Converts +id+ to a valid plugin ID String, or returns +nil+.
#
# Raises +ArgumentError+ for all other objects, or if the
# given String includes non-alphanumeric characters (\W).
def validate_id id
- if id.is_a? Symbol or id.nil?
- id
- elsif id.is_a? String
+ case id
+ when Symbol
+ id.to_s
+ when String
if id[/\w+/] == id
- id.downcase.to_sym
+ id.downcase
else
raise ArgumentError, "Invalid id given: #{id}"
end
else
- raise ArgumentError, "String or Symbol expected, but #{id.class} given."
+ raise ArgumentError, "Symbol or String expected, but #{id.class} given."
end
end
diff --git a/lib/coderay/scanners/css.rb b/lib/coderay/scanners/css.rb
index 9ed4618..55d5239 100644
--- a/lib/coderay/scanners/css.rb
+++ b/lib/coderay/scanners/css.rb
@@ -25,7 +25,7 @@ module Scanners
HexColor = /#(?:#{Hex}{6}|#{Hex}{3})/
- Num = /-?(?:[0-9]*\.[0-9]+|[0-9]+)/
+ Num = /-?(?:[0-9]*\.[0-9]+|[0-9]+)n?/
Name = /#{NMChar}+/
Ident = /-?#{NMStart}#{NMChar}*/
AtKeyword = /@#{Ident}/
@@ -53,7 +53,7 @@ module Scanners
end
def scan_tokens encoder, options
- states = Array(options[:state] || @state)
+ states = Array(options[:state] || @state).dup
value_expected = @value_expected
until eos?
diff --git a/lib/coderay/scanners/debug.rb b/lib/coderay/scanners/debug.rb
index 566bfa7..83ede9a 100644
--- a/lib/coderay/scanners/debug.rb
+++ b/lib/coderay/scanners/debug.rb
@@ -1,9 +1,11 @@
+require 'set'
+
module CodeRay
module Scanners
# = Debug Scanner
#
- # Interprets the output of the Encoders::Debug encoder.
+ # Interprets the output of the Encoders::Debug encoder (basically the inverse function).
class Debug < Scanner
register_for :debug
@@ -11,6 +13,11 @@ module Scanners
protected
+ def setup
+ super
+ @known_token_kinds = TokenKinds.keys.map(&:to_s).to_set
+ end
+
def scan_tokens encoder, options
opened_tokens = []
@@ -21,16 +28,19 @@ module Scanners
encoder.text_token match, :space
elsif match = scan(/ (\w+) \( ( [^\)\\]* ( \\. [^\)\\]* )* ) \)? /x)
- kind = self[1].to_sym
- match = self[2].gsub(/\\(.)/m, '\1')
- unless TokenKinds.has_key? kind
- kind = :error
- match = matched
+ if @known_token_kinds.include? self[1]
+ encoder.text_token self[2].gsub(/\\(.)/m, '\1'), self[1].to_sym
+ else
+ encoder.text_token matched, :unknown
end
- encoder.text_token match, kind
elsif match = scan(/ (\w+) ([<\[]) /x)
- kind = self[1].to_sym
+ if @known_token_kinds.include? self[1]
+ kind = self[1].to_sym
+ else
+ kind = :unknown
+ end
+
opened_tokens << kind
case self[2]
when '<'
diff --git a/lib/coderay/scanners/diff.rb b/lib/coderay/scanners/diff.rb
index fd1aed6..74a6c27 100644
--- a/lib/coderay/scanners/diff.rb
+++ b/lib/coderay/scanners/diff.rb
@@ -100,7 +100,7 @@ module Scanners
next
elsif match = scan(/-/)
deleted_lines_count += 1
- if options[:inline_diff] && deleted_lines_count == 1 && (changed_lines_count = 1 + check(/.*(?:\n\-.*)*/).count("\n")) && match?(/(?>.*(?:\n\-.*){#{changed_lines_count - 1}}(?:\n\+.*){#{changed_lines_count}})$(?!\n\+)/)
+ if options[:inline_diff] && deleted_lines_count == 1 && (changed_lines_count = 1 + check(/.*(?:\n\-.*)*/).count("\n")) && changed_lines_count <= 100_000 && match?(/(?>.*(?:\n\-.*){#{changed_lines_count - 1}}(?:\n\+.*){#{changed_lines_count}})$(?!\n\+)/)
deleted_lines = Array.new(changed_lines_count) { |i| skip(/\n\-/) if i > 0; scan(/.*/) }
inserted_lines = Array.new(changed_lines_count) { |i| skip(/\n\+/) ; scan(/.*/) }
diff --git a/lib/coderay/scanners/go.rb b/lib/coderay/scanners/go.rb
new file mode 100644
index 0000000..99fdd63
--- /dev/null
+++ b/lib/coderay/scanners/go.rb
@@ -0,0 +1,208 @@
+module CodeRay
+module Scanners
+
+ class Go < Scanner
+
+ register_for :go
+ file_extension 'go'
+
+ # http://golang.org/ref/spec#Keywords
+ KEYWORDS = [
+ 'break', 'default', 'func', 'interface', 'select',
+ 'case', 'defer', 'go', 'map', 'struct',
+ 'chan', 'else', 'goto', 'package', 'switch',
+ 'const', 'fallthrough', 'if', 'range', 'type',
+ 'continue', 'for', 'import', 'return', 'var',
+ ] # :nodoc:
+
+ # http://golang.org/ref/spec#Types
+ PREDEFINED_TYPES = [
+ 'bool',
+ 'uint8', 'uint16', 'uint32', 'uint64',
+ 'int8', 'int16', 'int32', 'int64',
+ 'float32', 'float64',
+ 'complex64', 'complex128',
+ 'byte', 'rune', 'string', 'error',
+ 'uint', 'int', 'uintptr',
+ ] # :nodoc:
+
+ PREDEFINED_CONSTANTS = [
+ 'nil', 'iota',
+ 'true', 'false',
+ ] # :nodoc:
+
+ PREDEFINED_FUNCTIONS = %w[
+ append cap close complex copy delete imag len
+ make new panic print println real recover
+ ] # :nodoc:
+
+ IDENT_KIND = WordList.new(:ident).
+ add(KEYWORDS, :keyword).
+ add(PREDEFINED_TYPES, :predefined_type).
+ add(PREDEFINED_CONSTANTS, :predefined_constant).
+ add(PREDEFINED_FUNCTIONS, :predefined) # :nodoc:
+
+ ESCAPE = / [rbfntv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x # :nodoc:
+ UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x # :nodoc:
+
+ protected
+
+ def scan_tokens encoder, options
+
+ state = :initial
+ label_expected = true
+ case_expected = false
+ label_expected_before_preproc_line = nil
+ in_preproc_line = false
+
+ until eos?
+
+ case state
+
+ when :initial
+
+ if match = scan(/ \s+ | \\\n /x)
+ if in_preproc_line && match != "\\\n" && match.index(?\n)
+ in_preproc_line = false
+ case_expected = false
+ label_expected = label_expected_before_preproc_line
+ end
+ encoder.text_token match, :space
+
+ elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx)
+ encoder.text_token match, :comment
+
+ elsif match = scan(/ <?- (?![\d.]) | [+*=<>?:;,!&^|()\[\]{}~%]+ | \/=? | \.(?!\d) /x)
+ if case_expected
+ label_expected = true if match == ':'
+ case_expected = false
+ end
+ encoder.text_token match, :operator
+
+ elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x)
+ kind = IDENT_KIND[match]
+ if kind == :ident && label_expected && !in_preproc_line && scan(/:(?!:)/)
+ kind = :label
+ label_expected = false
+ match << matched
+ else
+ label_expected = false
+ if kind == :keyword
+ case match
+ when 'case', 'default'
+ case_expected = true
+ end
+ end
+ end
+ encoder.text_token match, kind
+
+ elsif match = scan(/L?"/)
+ encoder.begin_group :string
+ if match[0] == ?L
+ encoder.text_token 'L', :modifier
+ match = '"'
+ end
+ encoder.text_token match, :delimiter
+ state = :string
+
+ elsif match = scan(/ ` ([^`]+)? (`)? /x)
+ encoder.begin_group :shell
+ encoder.text_token '`', :delimiter
+ encoder.text_token self[1], :content if self[1]
+ encoder.text_token self[2], :delimiter if self[2]
+ encoder.end_group :shell
+
+ elsif match = scan(/ \# \s* if \s* 0 /x)
+ match << scan_until(/ ^\# (?:elif|else|endif) .*? $ | \z /xm) unless eos?
+ encoder.text_token match, :comment
+
+ elsif match = scan(/#[ \t]*(\w*)/)
+ encoder.text_token match, :preprocessor
+ in_preproc_line = true
+ label_expected_before_preproc_line = label_expected
+ state = :include_expected if self[1] == 'include'
+
+ elsif match = scan(/ L?' (?: [^\'\n\\] | \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) )? '? /ox)
+ label_expected = false
+ encoder.text_token match, :char
+
+ elsif match = scan(/\$/)
+ encoder.text_token match, :ident
+
+ elsif match = scan(/-?\d*(\.\d*)?([eE][+-]?\d+)?i/)
+ label_expected = false
+ encoder.text_token match, :imaginary
+
+ elsif match = scan(/-?0[xX][0-9A-Fa-f]+/)
+ label_expected = false
+ encoder.text_token match, :hex
+
+ elsif match = scan(/-?(?:0[0-7]+)(?![89.eEfF])/)
+ label_expected = false
+ encoder.text_token match, :octal
+
+ elsif match = scan(/-?(?:\d*\.\d+|\d+\.)(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+/)
+ label_expected = false
+ encoder.text_token match, :float
+
+ elsif match = scan(/-?(?:\d+)(?![.eEfF])L?L?/)
+ label_expected = false
+ encoder.text_token match, :integer
+
+ else
+ encoder.text_token getch, :error
+
+ end
+
+ when :string
+ if match = scan(/[^\\\n"]+/)
+ encoder.text_token match, :content
+ elsif match = scan(/"/)
+ encoder.text_token match, :delimiter
+ encoder.end_group :string
+ state = :initial
+ label_expected = false
+ elsif match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
+ encoder.text_token match, :char
+ elsif match = scan(/ \\ /x)
+ encoder.text_token match, :error
+ elsif match = scan(/$/)
+ encoder.end_group :string
+ state = :initial
+ label_expected = false
+ else
+ raise_inspect "else case \" reached; %p not handled." % peek(1), encoder
+ end
+
+ when :include_expected
+ if match = scan(/<[^>\n]+>?|"[^"\n\\]*(?:\\.[^"\n\\]*)*"?/)
+ encoder.text_token match, :include
+ state = :initial
+
+ elsif match = scan(/\s+/)
+ encoder.text_token match, :space
+ state = :initial if match.index ?\n
+
+ else
+ state = :initial
+
+ end
+
+ else
+ raise_inspect 'Unknown state', encoder
+
+ end
+
+ end
+
+ if state == :string
+ encoder.end_group :string
+ end
+
+ encoder
+ end
+
+ end
+
+end
+end
diff --git a/lib/coderay/scanners/raydebug.rb b/lib/coderay/scanners/raydebug.rb
index d39d962..1effdc8 100644
--- a/lib/coderay/scanners/raydebug.rb
+++ b/lib/coderay/scanners/raydebug.rb
@@ -1,9 +1,11 @@
+require 'set'
+
module CodeRay
module Scanners
- # = Debug Scanner
+ # = Raydebug Scanner
#
- # Parses the output of the Encoders::Debug encoder.
+ # Highlights the output of the Encoders::Debug encoder.
class Raydebug < Scanner
register_for :raydebug
@@ -12,6 +14,11 @@ module Scanners
protected
+ def setup
+ super
+ @known_token_kinds = TokenKinds.keys.map(&:to_s).to_set
+ end
+
def scan_tokens encoder, options
opened_tokens = []
@@ -26,20 +33,22 @@ module Scanners
encoder.text_token kind, :class
encoder.text_token '(', :operator
match = self[2]
- encoder.text_token match, kind.to_sym unless match.empty?
+ unless match.empty?
+ if @known_token_kinds.include? kind
+ encoder.text_token match, kind.to_sym
+ else
+ encoder.text_token match, :plain
+ end
+ end
encoder.text_token match, :operator if match = scan(/\)/)
elsif match = scan(/ (\w+) ([<\[]) /x)
- kind = self[1]
- case self[2]
- when '<'
- encoder.text_token kind, :class
- when '['
- encoder.text_token kind, :class
+ encoder.text_token self[1], :class
+ if @known_token_kinds.include? self[1]
+ kind = self[1].to_sym
else
- raise 'CodeRay bug: This case should not be reached.'
+ kind = :unknown
end
- kind = kind.to_sym
opened_tokens << kind
encoder.begin_group kind
encoder.text_token self[2], :operator
diff --git a/lib/coderay/scanners/ruby.rb b/lib/coderay/scanners/ruby.rb
index 80165ca..5b8de42 100644
--- a/lib/coderay/scanners/ruby.rb
+++ b/lib/coderay/scanners/ruby.rb
@@ -164,15 +164,19 @@ module Scanners
end
elsif match = scan(/ ' (?:(?>[^'\\]*) ')? | " (?:(?>[^"\\\#]*) ")? /mx)
- encoder.begin_group :string
if match.size == 1
+ kind = check(self.class::StringState.simple_key_pattern(match)) ? :key : :string
+ encoder.begin_group kind
encoder.text_token match, :delimiter
- state = self.class::StringState.new :string, match == '"', match # important for streaming
+ state = self.class::StringState.new kind, match == '"', match # important for streaming
else
+ kind = value_expected == true && scan(/:/) ? :key : :string
+ encoder.begin_group kind
encoder.text_token match[0,1], :delimiter
encoder.text_token match[1..-2], :content if match.size > 2
encoder.text_token match[-1,1], :delimiter
- encoder.end_group :string
+ encoder.end_group kind
+ encoder.text_token ':', :operator if kind == :key
value_expected = false
end
@@ -191,11 +195,14 @@ module Scanners
encoder.text_token match, :error
method_call_expected = false
else
- encoder.text_token match, self[1] ? :float : :integer # TODO: send :hex/:octal/:binary
+ kind = self[1] ? :float : :integer # TODO: send :hex/:octal/:binary
+ match << 'r' if match !~ /e/i && scan(/r/)
+ match << 'i' if scan(/i/)
+ encoder.text_token match, kind
end
value_expected = false
- elsif match = scan(/ [-+!~^\/]=? | [:;] | [*|&]{1,2}=? | >>? /x)
+ elsif match = scan(/ [-+!~^\/]=? | [:;] | &\. | [*|&]{1,2}=? | >>? /x)
value_expected = true
encoder.text_token match, :operator
@@ -208,7 +215,7 @@ module Scanners
encoder.end_group kind
heredocs ||= [] # create heredocs if empty
heredocs << self.class::StringState.new(kind, quote != "'", delim,
- self[1] == '-' ? :indented : :linestart)
+ self[1] ? :indented : :linestart)
value_expected = false
elsif value_expected && match = scan(/#{patterns::FANCY_STRING_START}/o)
diff --git a/lib/coderay/scanners/ruby/patterns.rb b/lib/coderay/scanners/ruby/patterns.rb
index ed071d2..e5a156d 100644
--- a/lib/coderay/scanners/ruby/patterns.rb
+++ b/lib/coderay/scanners/ruby/patterns.rb
@@ -114,7 +114,7 @@ module Scanners
# NOTE: This is not completely correct, but
# nobody needs heredoc delimiters ending with \n.
HEREDOC_OPEN = /
- << (-)? # $1 = float
+ << ([-~])? # $1 = float
(?:
( [A-Za-z_0-9]+ ) # $2 = delim
|
@@ -157,13 +157,16 @@ module Scanners
yield
])
- FANCY_STRING_START = / % ( [QqrsWwx] | (?![a-zA-Z0-9]) ) ([^a-zA-Z0-9]) /x
+ FANCY_STRING_START = / % ( [iIqQrswWx] | (?![a-zA-Z0-9]) ) ([^a-zA-Z0-9]) /x
FANCY_STRING_KIND = Hash.new(:string).merge({
+ 'i' => :symbol,
+ 'I' => :symbol,
'r' => :regexp,
's' => :symbol,
'x' => :shell,
})
FANCY_STRING_INTERPRETED = Hash.new(true).merge({
+ 'i' => false,
'q' => false,
's' => false,
'w' => false,
diff --git a/lib/coderay/scanners/ruby/string_state.rb b/lib/coderay/scanners/ruby/string_state.rb
index 2f398d1..95f1e83 100644
--- a/lib/coderay/scanners/ruby/string_state.rb
+++ b/lib/coderay/scanners/ruby/string_state.rb
@@ -16,7 +16,6 @@ module Scanners
STRING_PATTERN = Hash.new do |h, k|
delim, interpreted = *k
- # delim = delim.dup # workaround for old Ruby
delim_pattern = Regexp.escape(delim)
if closing_paren = CLOSING_PAREN[delim]
delim_pattern << Regexp.escape(closing_paren)
@@ -29,12 +28,21 @@ module Scanners
# '| [|?*+(){}\[\].^$]'
# end
- h[k] =
- if interpreted && delim != '#'
- / (?= [#{delim_pattern}] | \# [{$@] ) /mx
- else
- / (?= [#{delim_pattern}] ) /mx
- end
+ if interpreted && delim != '#'
+ / (?= [#{delim_pattern}] | \# [{$@] ) /mx
+ else
+ / (?= [#{delim_pattern}] ) /mx
+ end.tap do |pattern|
+ h[k] = pattern if (delim.respond_to?(:ord) ? delim.ord : delim[0]) < 256
+ end
+ end
+
+ def self.simple_key_pattern delim
+ if delim == "'"
+ / (?> (?: [^\\']+ | \\. )* ) ' : /mx
+ else
+ / (?> (?: [^\\"\#]+ | \\. | \#\$[\\"] | \#\{[^\{\}]+\} | \#(?!\{) )* ) " : /mx
+ end
end
def initialize kind, interpreted, delim, heredoc = false
diff --git a/lib/coderay/scanners/sass.rb b/lib/coderay/scanners/sass.rb
index e20bebe..e3296b9 100644
--- a/lib/coderay/scanners/sass.rb
+++ b/lib/coderay/scanners/sass.rb
@@ -7,11 +7,6 @@ module Scanners
register_for :sass
file_extension 'sass'
- STRING_CONTENT_PATTERN = {
- "'" => /(?:[^\n\'\#]+|\\\n|#{RE::Escape}|#(?!\{))+/,
- '"' => /(?:[^\n\"\#]+|\\\n|#{RE::Escape}|#(?!\{))+/,
- }
-
protected
def setup
@@ -19,8 +14,9 @@ module Scanners
end
def scan_tokens encoder, options
- states = Array(options[:state] || @state)
- string_delimiter = nil
+ states = Array(options[:state] || @state).dup
+
+ encoder.begin_group :string if states.last == :sqstring || states.last == :dqstring
until eos?
@@ -48,7 +44,7 @@ module Scanners
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)
+ encoder.text_token match, value_expected ? :value : (check(/.*:(?![a-z])/) ? :key : :tag)
next
elsif !value_expected && (match = scan(/\*/))
encoder.text_token match, :tag
@@ -91,24 +87,23 @@ module Scanners
next
end
- when :string
- if match = scan(STRING_CONTENT_PATTERN[string_delimiter])
+ when :sqstring, :dqstring
+ if match = scan(states.last == :sqstring ? /(?:[^\n\'\#]+|\\\n|#{RE::Escape}|#(?!\{))+/o : /(?:[^\n\"\#]+|\\\n|#{RE::Escape}|#(?!\{))+/o)
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.end_group states.last
encoder.text_token match, :error unless match.empty?
states.pop
else
- raise_inspect "else case #{string_delimiter} reached; %p not handled." % peek(1), encoder
+ raise_inspect "else case #{states.last} reached; %p not handled." % peek(1), encoder
end
when :include
@@ -119,7 +114,7 @@ module Scanners
else
#:nocov:
- raise_inspect 'Unknown state', encoder
+ raise_inspect 'Unknown state: %p' % [states.last], encoder
#:nocov:
end
@@ -157,15 +152,15 @@ module Scanners
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)/)
+ # no nesting, just scan the string until delimiter
+ content = scan_until(/(?=#{match}|\}|\z)/)
encoder.text_token content, :content unless content.empty?
- encoder.text_token string_delimiter, :delimiter if scan(/#{string_delimiter}/)
+ encoder.text_token match, :delimiter if scan(/#{match}/)
encoder.end_group :string
else
- states.push :string
+ states.push match == "'" ? :sqstring : :dqstring
end
elsif match = scan(/#{RE::Function}/o)
@@ -214,14 +209,16 @@ module Scanners
end
+ states.pop if states.last == :include
+
if options[:keep_state]
- @state = states
+ @state = states.dup
end
while state = states.pop
if state == :sass_inline
encoder.end_group :inline
- elsif state == :string
+ elsif state == :sqstring || state == :dqstring
encoder.end_group :string
end
end
diff --git a/lib/coderay/scanners/sql.rb b/lib/coderay/scanners/sql.rb
index 93aeaf3..7d57f77 100644
--- a/lib/coderay/scanners/sql.rb
+++ b/lib/coderay/scanners/sql.rb
@@ -57,6 +57,12 @@ module Scanners
STRING_PREFIXES = /[xnb]|_\w+/i
+ STRING_CONTENT_PATTERN = {
+ '"' => / (?: [^\\"] | "" )+ /x,
+ "'" => / (?: [^\\'] | '' )+ /x,
+ '`' => / (?: [^\\`] | `` )+ /x,
+ }
+
def scan_tokens encoder, options
state = :initial
@@ -90,7 +96,7 @@ module Scanners
state = :string
encoder.text_token match, :delimiter
- elsif match = scan(/ @? [A-Za-z_][A-Za-z_0-9]* /x)
+ elsif match = scan(/ @? [A-Za-z_][A-Za-z_0-9\$]* /x)
encoder.text_token match, name_expected ? :ident : (match[0] == ?@ ? :variable : IDENT_KIND[match])
name_expected = false
@@ -115,40 +121,26 @@ module Scanners
end
elsif state == :string
- if match = scan(/[^\\"'`]+/)
- string_content << match
- next
+ if match = scan(STRING_CONTENT_PATTERN[string_type])
+ encoder.text_token match, :content
elsif match = scan(/["'`]/)
if string_type == match
if peek(1) == string_type # doubling means escape
- string_content << string_type << getch
- next
- end
- unless string_content.empty?
- encoder.text_token string_content, :content
- string_content = ''
+ encoder.text_token match + getch, :content
+ else
+ encoder.text_token match, :delimiter
+ encoder.end_group :string
+ state = :initial
+ string_type = nil
end
- encoder.text_token match, :delimiter
- encoder.end_group :string
- state = :initial
- string_type = nil
else
- string_content << match
+ encoder.text_token match, :content
end
elsif match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
- unless string_content.empty?
- encoder.text_token string_content, :content
- string_content = ''
- end
encoder.text_token match, :char
elsif match = scan(/ \\ . /mox)
- string_content << match
- next
+ encoder.text_token match, :content
elsif match = scan(/ \\ | $ /x)
- unless string_content.empty?
- encoder.text_token string_content, :content
- string_content = ''
- end
encoder.text_token match, :error unless match.empty?
encoder.end_group :string
state = :initial
diff --git a/lib/coderay/styles/alpha.rb b/lib/coderay/styles/alpha.rb
index 7d01372..f21cefe 100644
--- a/lib/coderay/styles/alpha.rb
+++ b/lib/coderay/styles/alpha.rb
@@ -108,7 +108,7 @@ table.CodeRay td { padding: 2px 4px; vertical-align: top; }
.operator { }
.predefined { color:#369; font-weight:bold }
.predefined-constant { color:#069 }
-.predefined-type { color:#0a5; font-weight:bold }
+.predefined-type { color:#0a8; font-weight:bold }
.preprocessor { color:#579 }
.pseudo-class { color:#00C; font-weight:bold }
.regexp { background-color:hsla(300,100%,50%,0.06); }
@@ -126,7 +126,7 @@ table.CodeRay td { padding: 2px 4px; vertical-align: top; }
.string .modifier { color: #E40 }
.symbol { color:#A60 }
.symbol .content { color:#A60 }
-.symbol .delimiter { color:#630 }
+.symbol .delimiter { color:#740 }
.tag { color:#070; font-weight:bold }
.type { color:#339; font-weight:bold }
.value { color: #088 }
diff --git a/lib/coderay/token_kinds.rb b/lib/coderay/token_kinds.rb
index 9137a49..f911862 100755
--- a/lib/coderay/token_kinds.rb
+++ b/lib/coderay/token_kinds.rb
@@ -1,10 +1,7 @@
module CodeRay
# A Hash of all known token kinds and their associated CSS classes.
- TokenKinds = Hash.new do |h, k|
- warn 'Undefined Token kind: %p' % [k] if $CODERAY_DEBUG
- false
- end
+ TokenKinds = Hash.new(false)
# speedup
TokenKinds.compare_by_identity if TokenKinds.respond_to? :compare_by_identity
@@ -83,5 +80,6 @@ module CodeRay
:plain => false # almost all scanners
)
- TokenKinds[:method] = TokenKinds[:function]
+ TokenKinds[:method] = TokenKinds[:function]
+ TokenKinds[:unknown] = TokenKinds[:plain]
end
diff --git a/lib/coderay/version.rb b/lib/coderay/version.rb
index 4b4f085..7ea3f70 100644
--- a/lib/coderay/version.rb
+++ b/lib/coderay/version.rb
@@ -1,3 +1,3 @@
module CodeRay
- VERSION = '1.1.0'
+ VERSION = '1.1.1'
end