From 86747d91b98490a036722349c07907d93e16428b Mon Sep 17 00:00:00 2001 From: Fire Demon Date: Mon, 27 Jul 2020 16:55:20 -0500 Subject: [Command Tags] Add support for strings and interpolation in templates; escapes --- app/lib/command_tag/processor.rb | 58 ++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/app/lib/command_tag/processor.rb b/app/lib/command_tag/processor.rb index 574bf6ad4..edc0302bd 100644 --- a/app/lib/command_tag/processor.rb +++ b/app/lib/command_tag/processor.rb @@ -18,12 +18,13 @@ class CommandTag::Processor MENTIONS_OR_HASHTAGS_RE = /(?:(?:#{Account::MENTION_RE}|#{Tag::HASHTAG_RE})\s*)+/.freeze PARSEABLE_RE = /^\s*(?:#{MENTIONS_OR_HASHTAGS_RE})?#!|%%.+?%%/.freeze STATEMENT_RE = /^\s*#!\s*[^\n]+ (?:start|begin|do)$.*?\n\s*#!\s*(?:end|stop|done)\s*$|^\s*#!\s*.*?\s*$/im.freeze - TEMPLATE_RE = /%%\s*(.+?)\s*%%/.freeze + TEMPLATE_RE = /%%\s*(\S+.*?)\s*%%/.freeze ESCAPE_MAP = { '\n' => "\n", '\r' => "\r", '\t' => "\t", '\\\\' => '\\', + '\%' => '%', }.freeze def initialize(account, status) @@ -95,40 +96,45 @@ class CommandTag::Processor def parse_templates(text) text.gsub(TEMPLATE_RE) do - next if Regexp.last_match(1).blank? - - template = Regexp.last_match(1).scan(/('[^']*')|("[^"]*")|(\S+)/).flatten.compact - next if template[0].blank? - - name = normalize(template[0]) - separator = "\n" - - if template.count > 2 - if %w(by with using sep separator delim delimiter).include?(template[-2].downcase) - separator = unescape_literals(template[-1]) - template = template[0..-3] - elsif !template[-1].match?(/\A[-+]?[0-9]+\z/) - separator = unescape_literals(template[-1]) - template.pop + template = unescape_literals(Regexp.last_match(1)) + next if template.blank? + next template[1..-2] if template.match?(/\A'.*'\z/) + + template = template.match?(/\A".*"\z/) ? template[1..-2] : "\#{#{template}}" + template.gsub(/#\{\s*(.*?)\s*\}/) do + next if Regexp.last_match(1).blank? + + parts = Regexp.last_match(1).scan(/'([^']*)'|"([^"]*)"|(\S+)/).flatten.compact + name = normalize(parts[0]) + separator = "\n" + + if parts.count > 2 + if %w(by with using sep separator delim delimiter).include?(parts[-2].downcase) + separator = parts[-1] + parts = parts[0..-3] + elsif !parts[-1].match?(/\A[-+]?[0-9]+\z/) + separator = parts[-1] + parts.pop + end end - end - index_start = to_integer(template[1]) - index_end = to_integer(template[2]) + index_start = to_integer(parts[1]) + index_end = to_integer(parts[2]) - if ['all', '[]'].include?(template[1]) - var(name).join(separator) - elsif index_end.zero? - var(name)[index_start].presence || '' - else - var(name)[index_start..index_end].presence || '' + if ['all', '[]'].include?(parts[1]) + var(name).join(separator) + elsif index_end.zero? + var(name)[index_start].presence || '' + else + var(name)[index_start..index_end].presence || '' + end end end end def parse_statements @text.gsub!(STATEMENT_RE) do - statement = Regexp.last_match(0).strip[2..-1] + statement = unescape_literals(Regexp.last_match(0).strip[2..-1]) next if statement.blank? statement_array = statement.scan(/'([^']*)'|"([^"]*)"|(\S+)|\s+(?:start|begin|do)\s*$\n+(.*)/im).flatten.compact -- cgit