diff --git a/lib/coderay/helpers/file_type.rb b/lib/coderay/helpers/file_type.rb index 7de34d58..a8299054 100644 --- a/lib/coderay/helpers/file_type.rb +++ b/lib/coderay/helpers/file_type.rb @@ -1,5 +1,5 @@ module CodeRay - + # = FileType # # A simple filetype recognizer. @@ -8,18 +8,18 @@ module CodeRay # # # determine the type of the given # lang = FileType[file_name] - # + # # # return :text if the file type is unknown # lang = FileType.fetch file_name, :text - # + # # # try the shebang line, too # lang = FileType.fetch file_name, :text, true module FileType - + UnknownFileType = Class.new Exception - + class << self - + # Try to determine the file type of the file. # # +filename+ is a relative or absolute path to a file. @@ -30,7 +30,7 @@ def [] filename, read_shebang = false name = File.basename filename ext = File.extname(name).sub(/^\./, '') # from last dot, delete the leading dot ext2 = filename.to_s[/\.(.*)/, 1] # from first dot - + type = TypeFromExt[ext] || TypeFromExt[ext.downcase] || @@ -39,10 +39,10 @@ def [] filename, read_shebang = false TypeFromName[name] || TypeFromName[name.downcase] type ||= type_from_shebang(filename) if read_shebang - + type end - + # This works like Hash#fetch. # # If the filetype cannot be found, the +default+ value @@ -51,7 +51,7 @@ def fetch filename, default = nil, read_shebang = false if default && block_given? warn 'Block supersedes default value argument; use either.' end - + if type = self[filename, read_shebang] type else @@ -60,9 +60,9 @@ def fetch filename, default = nil, read_shebang = false raise UnknownFileType, 'Could not determine type of %p.' % filename end end - + protected - + def type_from_shebang filename return unless File.exist? filename File.open filename, 'r' do |f| @@ -73,9 +73,9 @@ def type_from_shebang filename end end end - + end - + TypeFromExt = { 'c' => :c, 'cfc' => :xml, @@ -86,7 +86,7 @@ def type_from_shebang filename 'dpr' => :delphi, 'erb' => :erb, 'gemspec' => :ruby, - 'go' => :go, + 'go' => :go, 'groovy' => :groovy, 'gvy' => :groovy, 'h' => :c, @@ -120,6 +120,8 @@ def type_from_shebang filename 'ru' => :ruby, # config.ru 'rxml' => :ruby, 'sass' => :sass, + 'sbt' => :scala, + 'scala' => :scala, 'sql' => :sql, 'taskpaper' => :taskpaper, 'template' => :json, # AWS CloudFormation template @@ -133,9 +135,9 @@ def type_from_shebang filename for cpp_alias in %w[cc cpp cp cxx c++ C hh hpp h++ cu] TypeFromExt[cpp_alias] = :cpp end - + TypeFromShebang = /\b(?:ruby|perl|python|sh)\b/ - + TypeFromName = { 'Capfile' => :ruby, 'Rakefile' => :ruby, @@ -145,7 +147,7 @@ def type_from_shebang filename 'Vagrantfile' => :ruby, 'Appraisals' => :ruby } - + end - + end diff --git a/lib/coderay/scanners/scala.rb b/lib/coderay/scanners/scala.rb new file mode 100644 index 00000000..044280d6 --- /dev/null +++ b/lib/coderay/scanners/scala.rb @@ -0,0 +1,171 @@ +module CodeRay + module Scanners + + # Scanner for Scala. + class Scala < Scanner + + register_for :scala + + autoload :BuiltinTypes, CodeRay.coderay_path('scanners', 'scala', 'builtin_types') + + KEYWORDS = %w[ + abstract case catch class def do else extends + finally for forSome if implicit import import lazy match new + object override package private protected + return sealed throw trait try type + val var while with yield + ] # :nodoc: + RESERVED = %w[ const goto ] # :nodoc: + CONSTANTS = %w[ false null true ] # :nodoc: + MAGIC_VARIABLES = %w[ this super ] # :nodoc: + TYPES = %w[ + boolean byte char class double enum float int interface long + short void + ] << '[]' # :nodoc: because int[] should be highlighted as a type + DIRECTIVES = %w[ + abstract extends final implements native private protected public + static strictfp synchronized throws transient volatile + ] # :nodoc: + + IDENT_KIND = WordList.new(:ident). + add(KEYWORDS, :keyword). + add(RESERVED, :reserved). + add(CONSTANTS, :predefined_constant). + add(MAGIC_VARIABLES, :local_variable). + add(TYPES, :type). + add(BuiltinTypes::List, :predefined_type). + add(BuiltinTypes::List.select { |builtin| builtin[/(Error|Exception)$/] }, :exception). + add(DIRECTIVES, :directive) # :nodoc: + + ESCAPE = / [bfnrtv\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: + STRING_CONTENT_PATTERN = { + "'" => /[^\\']+/, + '"' => /[^\\"]+/, + '/' => /[^\\\/]+/ + } # :nodoc: + IDENT = /[a-zA-Z_][A-Za-z_0-9]*/ # :nodoc: + + protected + + def scan_tokens encoder, options + + state = :initial + string_delimiter = nil + package_name_expected = false + class_name_follows = false + last_token_dot = false + + until eos? + + case state + + when :initial + + if match = scan(/ \s+ | \\\n /x) + encoder.text_token match, :space + next + + elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) + encoder.text_token match, :comment + next + + elsif match = scan(/ #{IDENT} | \[\] /ox) + kind = IDENT_KIND[match] + if last_token_dot + kind = :ident + elsif class_name_follows + kind = :class + class_name_follows = false + else + case match + when 'import' + package_name_expected = :include + when 'package' + package_name_expected = :namespace + when 'class', 'interface', 'trait' + class_name_follows = true + end + end + encoder.text_token match, kind + + elsif match = scan(/ \.(?!\d) | [,?:()\[\]}] | -- | \+\+ | && | \|\| | \*\*=? | [-+*\/%^~&|<>=!]=? | <<>>?=? /x) + encoder.text_token match, :operator + + elsif match = scan(/;/) + package_name_expected = false + encoder.text_token match, :operator + + elsif match = scan(/\{/) + class_name_follows = false + encoder.text_token match, :operator + + elsif check(/[\d.]/) + if match = scan(/0[xX][0-9A-Fa-f]+/) + encoder.text_token match, :hex + elsif match = scan(/(?>0[0-7]+)(?![89.eEfF])/) + encoder.text_token match, :octal + elsif match = scan(/\d+[fFdD]|\d*\.\d+(?:[eE][+-]?\d+)?[fFdD]?|\d+[eE][+-]?\d+[fFdD]?/) + encoder.text_token match, :float + elsif match = scan(/\d+[lL]?/) + encoder.text_token match, :integer + end + + elsif match = scan(/["']/) + state = :string + encoder.begin_group state + string_delimiter = match + encoder.text_token match, :delimiter + + elsif match = scan(/ @ #{IDENT} /ox) + encoder.text_token match, :annotation + + else + encoder.text_token getch, :error + + 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 state + state = :initial + string_delimiter = nil + elsif state == :string && (match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)) + if string_delimiter == "'" && !(match == "\\\\" || match == "\\'") + encoder.text_token match, :content + else + encoder.text_token match, :char + end + elsif match = scan(/\\./m) + encoder.text_token match, :content + elsif match = scan(/ \\ | $ /x) + encoder.end_group state + state = :initial + encoder.text_token match, :error unless match.empty? + else + raise_inspect "else case \" reached; %p not handled." % peek(1), encoder + end + + else + raise_inspect 'Unknown state', encoder + + end + + last_token_dot = match == '.' + + end + + if state == :string + encoder.end_group state + end + + encoder + end + + end + + end + end diff --git a/lib/coderay/scanners/scala/builtin_types.rb b/lib/coderay/scanners/scala/builtin_types.rb new file mode 100644 index 00000000..edcdcdd2 --- /dev/null +++ b/lib/coderay/scanners/scala/builtin_types.rb @@ -0,0 +1,539 @@ +module CodeRay + module Scanners + + module Scala::BuiltinTypes # :nodoc: + + #:nocov: + List = %w[ + Any + AnyVal + App + Array + Boolean + Byte + Char + Cloneable + Console + DelayedInit + Double + Dynamic + Enumeration + Equals + FallbackArrayBuilding + Float + Function + Function1 + Function2 + Immutable + Int + Long + MatchError + Mutable + None + NotImplementedError + NotNull + Option + PartialFunction + Predef + Product + Product1 + Product2 + Proxy + Responder + ScalaReflectionException + Serializable + SerialVersionUID + Short + Some + Specializable + StringContext + Symbol + Tuple1 + Tuple2 + UninitializedError + UninitializedFieldError + Unit + Annotation + ClassfileAnnotation + StaticAnnotation + TypeConstraint + BeanDescription + BeanDisplayName + BeanInfo + BeanInfoSkip + BeanProperty + BooleanBeanProperty + ScalaBeanInfo + AbstractIterable + AbstractIterator + AbstractMap + AbstractSeq + AbstractSet + AbstractTraversable + BitSet + BitSetLike + BufferedIterator + CustomParallelizable + DefaultMap + GenIterable + GenIterableLike + GenMap + GenMapLike + GenSeq + GenSeqLike + GenSet + GenSetLike + GenTraversable + GenTraversableLike + GenTraversableOnce + IndexedSeq + IndexedSeqLike + IndexedSeqOptimized + Iterable + IterableLike + IterableProxy + IterableProxyLike + IterableView + IterableViewLike + Iterator + JavaConversions + JavaConverters + LinearSeq + LinearSeqLike + LinearSeqOptimized + Map + MapLike + MapProxy + MapProxyLike + Parallel + Parallelizable + Searching + Seq + SeqLike + SeqProxy + SeqProxyLike + SeqView + SeqViewLike + Set + SetLike + SetProxy + SetProxyLike + SortedMap + SortedMapLike + SortedSet + SortedSetLike + Traversable + TraversableLike + TraversableOnce + TraversableProxy + TraversableProxyLike + TraversableView + TraversableViewLike + ViewMkString + Map + TrieMap + DecorateAsJava + DecorateAsScala + WrapAsJava + WrapAsScala + Wrappers + AtomicIndexFlag + BitSetFactory + CanBuildFrom + CanCombineFrom + ClassTagTraversableFactory + Clearable + DefaultSignalling + DelegatedContext + DelegatedSignalling + FilterMonadic + GenericClassTagCompanion + GenericClassTagTraversableTemplate + GenericCompanion + GenericOrderedCompanion + GenericOrderedTraversableTemplate + GenericParCompanion + GenericParMapCompanion + GenericParMapTemplate + GenericParTemplate + GenericSeqCompanion + GenericSetTemplate + GenericTraversableTemplate + GenMapFactory + GenSeqFactory + GenSetFactory + GenTraversableFactory + Growable + HasNewBuilder + HasNewCombiner + IdleSignalling + ImmutableMapFactory + ImmutableSetFactory + ImmutableSortedMapFactory + ImmutableSortedSetFactory + IndexedSeqFactory + IsSeqLike + IsTraversableLike + IsTraversableOnce + IterableForwarder + MapFactory + MutableMapFactory + MutableSetFactory + MutableSortedSetFactory + OrderedTraversableFactory + ParFactory + ParMapFactory + ParSetFactory + SeqFactory + SeqForwarder + SetFactory + Shrinkable + Signalling + Sizing + SliceInterval + Sorted + SortedMapFactory + SortedSetFactory + Subtractable + TaggedDelegatedContext + TraversableFactory + TraversableForwarder + VolatileAbort + AbstractMap + BitSet + DefaultMap + HashMap + HashSet + IndexedSeq + IntMap + Iterable + LinearSeq + List + ListMap + ListSet + LongMap + Map + MapLike + MapProxy + Nil + NumericRange + PagedSeq + Queue + Range + Seq + Set + SetProxy + SortedMap + SortedSet + Stack + Stream + StreamIterator + StreamView + StreamViewLike + StringLike + StringOps + Traversable + TreeMap + TreeSet + Vector + VectorBuilder + VectorIterator + WrappedString + AbstractBuffer + AbstractIterable + AbstractMap + AbstractSeq + AbstractSet + AnyRefMap + ArrayBuffer + ArrayBuilder + ArrayLike + ArrayOps + ArraySeq + ArrayStack + BitSet + Buffer + BufferLike + BufferProxy + Builder + Cloneable + DefaultEntry + DefaultMapModel + DoubleLinkedList + DoubleLinkedListLike + FlatHashTable + GrowingBuilder + HashEntry + HashMap + HashSet + HashTable + History + ImmutableMapAdaptor + ImmutableSetAdaptor + IndexedSeq + IndexedSeqLike + IndexedSeqOptimized + IndexedSeqView + Iterable + LazyBuilder + LinearSeq + LinkedEntry + LinkedHashMap + LinkedHashSet + LinkedList + LinkedListLike + ListBuffer + ListMap + LongMap + Map + MapBuilder + MapLike + MapProxy + MultiMap + MutableList + ObservableBuffer + ObservableMap + ObservableSet + OpenHashMap + PriorityQueue + PriorityQueueProxy + Publisher + Queue + QueueProxy + ResizableArray + RevertibleHistory + Seq + SeqLike + Set + SetBuilder + SetLike + SetProxy + SortedSet + Stack + StackProxy + StringBuilder + Subscriber + SynchronizedBuffer + SynchronizedMap + SynchronizedPriorityQueue + SynchronizedQueue + SynchronizedSet + SynchronizedStack + Traversable + TreeSet + Undoable + UnrolledBuffer + WeakHashMap + WrappedArray + WrappedArrayBuilder + AdaptiveWorkStealingForkJoinTasks + AdaptiveWorkStealingTasks + AdaptiveWorkStealingThreadPoolTasks + CollectionsHaveToParArray + Combiner + CombinerFactory + CompositeThrowable + ExecutionContextTasks + ExecutionContextTaskSupport + FactoryOps + ForkJoinTasks + ForkJoinTaskSupport + FutureThreadPoolTasks + HavingForkJoinPool + IterableSplitter + ParIterable + ParIterableLike + ParMap + ParMapLike + ParSeq + ParSeqLike + ParSet + ParSetLike + PreciseSplitter + SeqSplitter + Splitter + Task + Tasks + TaskSupport + ThreadPoolTasks + ThreadPoolTaskSupport + ThrowableOps + TraversableOps + HashSetCombiner + ParHashMap + ParHashSet + ParIterable + ParMap + ParRange + ParSeq + ParSet + ParVector + LazyCombiner + ParArray + ParFlatHashTable + ParHashMap + ParHashSet + ParHashTable + ParIterable + ParMap + ParMapLike + ParSeq + ParSet + ParSetLike + ParTrieMap + ResizableParArrayCombiner + UnrolledParArrayCombiner + End + Include + Index + Location + Message + NoLo + Remove + Reset + Script + Scriptable + Start + Update + Platform + Await + Awaitable + BlockContext + CanAwait + Channel + DelayedLazyVal + ExecutionContext + ExecutionContextExecutor + ExecutionContextExecutorService + Future + JavaConversions + Lock + OnCompleteRunnable + Promise + SyncChannel + SyncVar + Deadline + DoubleMult + Duration + DurationConversions + DurationDouble + DurationInt + DurationLong + FiniteDuration + IntMult + LongMult + AnsiColor + BufferedSource + Codec + LowPriorityCodecImplicits + Source + StdIn + BigDecimal + BigInt + Equiv + Fractional + Integral + LowPriorityEquiv + LowPriorityOrderingImplicits + Numeric + Ordered + Ordering + PartiallyOrdered + PartialOrdering + ScalaNumericAnyConversions + ScalaNumericConversions + PhantomReference + Reference + ReferenceQueue + ReferenceWrapper + SoftReference + WeakReference + AnyValManifest + ClassManifestDeprecatedApis + ClassManifestFactory + ClassTag + Manifest + ManifestFactory + NameTransformer + NoManifest + OptManifest + AbstractFunction0 + AbstractFunction1 + AbstractFunction2 + AbstractPartialFunction + ArrayCharSequence + Boxed + FractionalProxy + IntegralProxy + NonLocalReturnControl + Nothing$ + Null$ + OrderedProxy + RangedProxy + RichBoolean + RichByte + RichChar + RichDouble + RichException + RichFloat + RichInt + RichLong + RichShort + ScalaNumberProxy + ScalaRunTime + ScalaWholeNumberProxy + SeqCharSequence + StringAdd + StringFormat + Tuple2Zipped + Tuple3Zipped + ZippedTraversable2 + ZippedTraversable3 + BooleanProp + Prop + ShutdownHookThread + SystemProperties + BasicIO + FileProcessLogger + Process + ProcessBuilder + ProcessCreation + ProcessImplicits + ProcessIO + ProcessLogger + DocBreak + DocCons + DocGroup + DocNest + DocNil + DocText + Document + DynamicVariable + Either + Failure + Left + MurmurHash + Properties + Random + Right + Sorting + Success + Try + Breaks + ControlThrowable + Exception + NonFatal + NoStackTrace + TailCalls + ByteswapHashing + Hashing + MurmurHash3 + Regex + UnanchoredRegex + ] + #:nocov: + + end + + end +end