mirror of
https://github.com/ralsina/tartrazine.git
synced 2025-07-17 08:49:59 +00:00
82 lines
2.6 KiB
Crystal
82 lines
2.6 KiB
Crystal
require "yaml"
|
|
|
|
# Use linguist's heuristics to disambiguate between languages
|
|
# This is *shamelessly* stolen from https://github.com/github-linguist/linguist
|
|
# and ported to Crystal. Deepest thanks to the authors of Linguist
|
|
# for licensing it liberally.
|
|
#
|
|
# Consider this code (c) 2017 GitHub, Inc. even if I wrote it.
|
|
module Linguist
|
|
class Heuristic
|
|
include YAML::Serializable
|
|
|
|
property disambiguations : Array(Disambiguation)
|
|
property named_patterns : Hash(String, String | Array(String))
|
|
|
|
# Run the heuristics on the given filename and content
|
|
def run(filename, content)
|
|
ext = File.extname filename
|
|
disambiguation = disambiguations.find do |item|
|
|
item.extensions.includes? ext
|
|
end
|
|
disambiguation.try &.run(content, named_patterns)
|
|
end
|
|
end
|
|
|
|
class Disambiguation
|
|
include YAML::Serializable
|
|
property extensions : Array(String)
|
|
property rules : Array(LangRule)
|
|
|
|
def run(content, named_patterns)
|
|
rules.each do |rule|
|
|
if rule.match(content, named_patterns)
|
|
return rule.language
|
|
end
|
|
end
|
|
nil
|
|
end
|
|
end
|
|
|
|
class LangRule
|
|
include YAML::Serializable
|
|
property pattern : (String | Array(String))?
|
|
property negative_pattern : (String | Array(String))?
|
|
property named_pattern : String?
|
|
property and : Array(LangRule)?
|
|
property language : String | Array(String)?
|
|
|
|
# ameba:disable Metrics/CyclomaticComplexity
|
|
def match(content, named_patterns)
|
|
# This rule matches without conditions
|
|
return true if !pattern && !negative_pattern && !named_pattern && !and
|
|
|
|
if pattern
|
|
p_arr = [] of String
|
|
p_arr << pattern.as(String) if pattern.is_a? String
|
|
p_arr = pattern.as(Array(String)) if pattern.is_a? Array(String)
|
|
return true if p_arr.any? { |pat| ::Regex.new(pat).matches?(content) }
|
|
end
|
|
if negative_pattern
|
|
p_arr = [] of String
|
|
p_arr << negative_pattern.as(String) if negative_pattern.is_a? String
|
|
p_arr = negative_pattern.as(Array(String)) if negative_pattern.is_a? Array(String)
|
|
return true if p_arr.none? { |pat| ::Regex.new(pat).matches?(content) }
|
|
end
|
|
if named_pattern
|
|
p_arr = [] of String
|
|
if named_patterns[named_pattern].is_a? String
|
|
p_arr << named_patterns[named_pattern].as(String)
|
|
else
|
|
p_arr = named_patterns[named_pattern].as(Array(String))
|
|
end
|
|
result = p_arr.any? { |pat| ::Regex.new(pat).matches?(content) }
|
|
end
|
|
if and
|
|
result = and.as(Array(LangRule)).all?(&.match(content, named_patterns))
|
|
end
|
|
result
|
|
end
|
|
end
|
|
end
|