diff --git a/.travis.yml b/.travis.yml index 0ea3d0ad9f..6d14f60cc0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ sudo: false dist: trusty language: ruby rvm: - - "1.9.3" - "2.0" - "2.1" - "2.2" @@ -15,4 +14,4 @@ bundler_args: --without development before_install: gem update bundler script: - bundle exec rake - - if ruby -e 'exit RUBY_VERSION >= "2.0.0"' ; then bundle exec rubocop ; fi + - bundle exec rubocop diff --git a/Gemfile b/Gemfile index 3752111db9..bead2078da 100644 --- a/Gemfile +++ b/Gemfile @@ -5,10 +5,10 @@ gemspec gem 'bundler', '~> 1.15' gem 'rake' -gem 'minitest' +gem 'minitest', '>= 5.0' gem 'minitest-power_assert' -gem 'rubocop', '~> 0.49.1' if RUBY_VERSION >= '2.0.0' +gem 'rubocop', '~> 0.49.1' # don't try to install redcarpet under jruby gem 'redcarpet', :platforms => :ruby diff --git a/lib/rouge/lexer.rb b/lib/rouge/lexer.rb index e666c14bb2..e6eb822d44 100644 --- a/lib/rouge/lexer.rb +++ b/lib/rouge/lexer.rb @@ -22,7 +22,9 @@ def lex(stream, opts={}, &b) new(opts).lex(stream, &b) end - # Given a string, return the correct lexer class. + # Given a name in string, return the correct lexer class. + # @param [String] name + # @return [Class,nil] def find(name) registry[name.to_s] end @@ -148,16 +150,23 @@ def guesses(info={}) # The source itself, which, if guessing by mimetype or filename # fails, will be searched for shebangs, tags, and # other hints. + # @param [Proc] fallback called if multiple lexers are detected. + # If omitted, Guesser::Ambiguous is raised. # # @see Lexer.detect? # @see Lexer.guesses - def guess(info={}) + # @return [Class] + def guess(info={}, &fallback) lexers = guesses(info) return Lexers::PlainText if lexers.empty? return lexers[0] if lexers.size == 1 - raise Guesser::Ambiguous.new(lexers) + if fallback + fallback.call(lexers) + else + raise Guesser::Ambiguous.new(lexers) + end end def guess_by_mimetype(mt) diff --git a/lib/rouge/lexers/haskell.rb b/lib/rouge/lexers/haskell.rb index ce812a203d..4c0163f840 100644 --- a/lib/rouge/lexers/haskell.rb +++ b/lib/rouge/lexers/haskell.rb @@ -148,7 +148,7 @@ def self.detect?(text) state :character do rule /\\/ do token Str::Escape - push :character_end + goto :character_end push :escape end @@ -174,7 +174,7 @@ def self.detect?(text) rule /\^[\]\[A-Z@\^_]/, Str::Escape, :pop! rule /#{ascii.join('|')}/, Str::Escape, :pop! rule /o[0-7]+/i, Str::Escape, :pop! - rule /x[\da-f]/i, Str::Escape, :pop! + rule /x[\da-f]+/i, Str::Escape, :pop! rule /\d+/, Str::Escape, :pop! rule /\s+\\/, Str::Escape, :pop! end diff --git a/lib/rouge/lexers/kotlin.rb b/lib/rouge/lexers/kotlin.rb index 8e4f69d764..64ea10be46 100644 --- a/lib/rouge/lexers/kotlin.rb +++ b/lib/rouge/lexers/kotlin.rb @@ -3,8 +3,10 @@ module Rouge module Lexers class Kotlin < RegexLexer + # https://kotlinlang.org/docs/reference/grammar.html + title "Kotlin" - desc "Kotlin " + desc "Kotlin Programming Language (http://kotlinlang.org)" tag 'kotlin' filenames '*.kt' @@ -41,26 +43,23 @@ class Kotlin < RegexLexer rule %r'"(\\\\|\\"|[^"\n])*["\n]'m, Str rule %r"'\\.'|'[^\\]'", Str::Char rule %r"[0-9](\.[0-9]+)?([eE][+-][0-9]+)?[flFL]?|0[xX][0-9a-fA-F]+[Ll]?", Num - rule %r'(companion)(\s+)(object)' do + rule %r'\b(companion)(\s+)(object)\b' do groups Keyword, Text, Keyword end - rule %r'(class|data\s+class|interface|object)(\s+)' do + rule %r'\b(class|data\s+class|interface|object)(\s+)' do groups Keyword::Declaration, Text push :class end - rule %r'(package|import)(\s+)' do + rule %r'\b(package|import)(\s+)' do groups Keyword, Text push :package end - rule %r'(val|var)(\s+)' do + rule %r'\b(val|var)(\s+)' do groups Keyword::Declaration, Text push :property end - rule %r'(fun)(\s+)' do - groups Keyword, Text - push :function - end - rule /(?:#{keywords.join('|')})\b/, Keyword + rule %r/\bfun\b/, Keyword + rule /\b(?:#{keywords.join('|')})\b/, Keyword rule id, Name end @@ -75,10 +74,6 @@ class Kotlin < RegexLexer state :property do rule id, Name::Property, :pop! end - - state :function do - rule id, Name::Function, :pop! - end end end end diff --git a/rouge.gemspec b/rouge.gemspec index 58da089358..23c16f4fdc 100644 --- a/rouge.gemspec +++ b/rouge.gemspec @@ -15,4 +15,5 @@ Gem::Specification.new do |s| s.files = Dir['Gemfile', 'LICENSE', 'rouge.gemspec', 'lib/**/*.rb', 'lib/**/*.yml', 'bin/rougify', 'lib/rouge/demos/*'] s.executables = %w(rougify) s.licenses = ['MIT', 'BSD-2-Clause'] + s.required_ruby_version = '>= 2.0' end diff --git a/spec/lexer_spec.rb b/spec/lexer_spec.rb index 55ca6738ec..f7220270b2 100644 --- a/spec/lexer_spec.rb +++ b/spec/lexer_spec.rb @@ -11,6 +11,14 @@ assert { Rouge::Lexer.guesses(filename: 'foo.pl').map { |c| c.tag }.sort == ['perl', 'prolog'].sort } end + it 'raises errors in .guess by default' do + assert { (Rouge::Lexer.guess(filename: 'foo.pl') rescue nil) == nil } + end + + it 'customizes ambiguous cases in .guess' do + assert { Rouge::Lexer.guess(filename: 'foo.pl') { :fallback } == :fallback } + end + it 'makes a simple lexer' do a_lexer = Class.new(Rouge::RegexLexer) do state :root do diff --git a/spec/visual/samples/haskell b/spec/visual/samples/haskell index ec6f366aea..77c7f9df12 100644 --- a/spec/visual/samples/haskell +++ b/spec/visual/samples/haskell @@ -377,3 +377,9 @@ check i n x f (Result (Just False) args : rs) = do progressReport :: Bool -> Int -> Int -> IO () progressReport _ _ _ = return () +foo :: String +foo = replicate n '\x1f363' + where n = 32 + +bar :: String +bar = "\x1f389\x1f363\x1f389" diff --git a/spec/visual/samples/kotlin b/spec/visual/samples/kotlin index aa05aa9b31..83f9d8e849 100644 --- a/spec/visual/samples/kotlin +++ b/spec/visual/samples/kotlin @@ -128,3 +128,13 @@ fun makeField(s: String): Field { return Field(longestLine.length, lines.size) { i, j -> lines[i][j] == '*' } } +fun genericFunction() { + return +} + +fun String.extensionFunction() { + return +} + +fun String.genericExtensionFunction() { + return