diff --git a/src/formatters/html.cr b/src/formatters/html.cr index 715d793..b6037cc 100644 --- a/src/formatters/html.cr +++ b/src/formatters/html.cr @@ -68,8 +68,7 @@ module Tartrazine line_id = linkable_line_numbers? ? "id=\"#{line_number_id_prefix}#{i + 1}\"" : "" outp << "#{line_label} " line.each do |token| - fragment = "#{HTML.escape(token[:value])}" - outp << fragment + outp << "#{HTML.escape(token[:value])}" end end outp << "" @@ -105,15 +104,17 @@ module Tartrazine # Given a token type, return the CSS class to use. def get_css_class(token : String) : String - return class_prefix + Abbreviations[token] if theme.styles.has_key?(token) - - # Themes don't contain information for each specific - # token type. However, they may contain information - # for a parent style. Worst case, we go to the root - # (Background) style. - class_prefix + Abbreviations[theme.style_parents(token).reverse.find { |parent| - theme.styles.has_key?(parent) - }] + if !theme.styles.has_key? token + # Themes don't contain information for each specific + # token type. However, they may contain information + # for a parent style. Worst case, we go to the root + # (Background) style. + parent = theme.style_parents(token).reverse.find { |dad| + theme.styles.has_key?(dad) + } + theme.styles[token] = theme.styles[parent] + end + class_prefix + Abbreviations[token] end # Is this line in the highlighted ranges? diff --git a/src/lexer.cr b/src/lexer.cr index 20f074a..1f8c924 100644 --- a/src/lexer.cr +++ b/src/lexer.cr @@ -225,9 +225,9 @@ module Tartrazine # A Lexer state. A state has a name and a list of rules. # The state machine has a state stack containing references # to states to decide which rules to apply. - class State + struct State property name : String = "" - property rules = [] of Rule + property rules = [] of BaseRule def +(other : State) new_state = State.new diff --git a/src/rules.cr b/src/rules.cr index 632eec1..4de1d61 100644 --- a/src/rules.cr +++ b/src/rules.cr @@ -15,30 +15,12 @@ module Tartrazine alias Match = BytesRegex::Match alias MatchData = Array(Match) - class Rule - property pattern : Regex = Regex.new "" + abstract struct BaseRule + abstract def match(text : Bytes, pos, lexer) : Tuple(Bool, Int32, Array(Token)) + abstract def initialize(node : XML::Node) + property actions : Array(Action) = [] of Action - def match(text : Bytes, pos, lexer) : Tuple(Bool, Int32, Array(Token)) - match = pattern.match(text, pos) - # We don't match if the match doesn't move the cursor - # because that causes infinite loops - return false, pos, [] of Token if match.empty? || match[0].size == 0 - tokens = [] of Token - actions.each do |action| - tokens += action.emit(match, lexer) - end - return true, pos + match[0].size, tokens - end - - def initialize(node : XML::Node, multiline, dotall, ignorecase) - @xml = node.to_s - pattern = node["pattern"] - pattern = "(?m)" + pattern if multiline - @pattern = Regex.new(pattern, multiline, dotall, ignorecase, true) - add_actions(node) - end - def add_actions(node : XML::Node) node.children.each do |child| next unless child.element? @@ -47,9 +29,32 @@ module Tartrazine end end + struct Rule < BaseRule + property pattern : Regex = Regex.new "" + property actions : Array(Action) = [] of Action + + def match(text : Bytes, pos, lexer) : Tuple(Bool, Int32, Array(Token)) + match = pattern.match(text, pos) + + # No match + return false, pos, [] of Token if match.size == 0 + return true, pos + match[0].size, actions.flat_map { |action| action.emit(match, lexer) } + end + + def initialize(node : XML::Node) + end + + def initialize(node : XML::Node, multiline, dotall, ignorecase) + pattern = node["pattern"] + pattern = "(?m)" + pattern if multiline + @pattern = Regex.new(pattern, multiline, dotall, ignorecase, true) + add_actions(node) + end + end + # This rule includes another state. If any of the rules of the # included state matches, this rule matches. - class IncludeStateRule < Rule + struct IncludeStateRule < BaseRule property state : String = "" def match(text, pos, lexer) : Tuple(Bool, Int32, Array(Token)) @@ -62,7 +67,6 @@ module Tartrazine end def initialize(node : XML::Node) - @xml = node.to_s include_node = node.children.find { |child| child.name == "include" } @@ -72,17 +76,14 @@ module Tartrazine end # This rule always matches, unconditionally - class UnconditionalRule < Rule + struct UnconditionalRule < BaseRule + NO_MATCH = [] of Match + def match(text, pos, lexer) : Tuple(Bool, Int32, Array(Token)) - tokens = [] of Token - actions.each do |action| - tokens += action.emit([] of Match, lexer) - end - return true, pos, tokens + return true, pos, actions.flat_map { |action| action.emit(NO_MATCH, lexer) } end def initialize(node : XML::Node) - @xml = node.to_s add_actions(node) end end