about summary refs log tree commit diff
path: root/app/lib/command_tag/processor.rb
diff options
context:
space:
mode:
authorFire Demon <firedemon@creature.cafe>2020-07-27 16:55:20 -0500
committerFire Demon <firedemon@creature.cafe>2020-08-30 05:45:16 -0500
commit86747d91b98490a036722349c07907d93e16428b (patch)
tree3d4ced656baccf721feacc0d96c29a3e05569c4b /app/lib/command_tag/processor.rb
parent962d3bee1cc1c6be693d9116330f8a0eb7b4553d (diff)
[Command Tags] Add support for strings and interpolation in templates; escapes
Diffstat (limited to 'app/lib/command_tag/processor.rb')
-rw-r--r--app/lib/command_tag/processor.rb58
1 files 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