Class: Metanorma::Standoc::MonospaceProtectPreprocessor

Inherits:
Asciidoctor::Extensions::Preprocessor
  • Object
show all
Defined in:
lib/metanorma/converter/macros_nosub.rb

Overview

protect monospace text from character substitutions

Constant Summary collapse

PASS_INLINE_MACROS =
%w(pass pass-format identifier std-link stem)
.join("|").freeze
PASS_INLINE_MACRO_STR =
<<~REGEX.freeze
  (
    \\b(?<![-\\\\])                        # word-separator, no hyphen or backslash
    (?:                                    # don't capture these!
      (?:#{PASS_INLINE_MACROS}):[^\\s\\[]* | # macro name, :, second key. OR:
      span:uri \\b [^\\s\\[]*              # span:uri, third key
    )
    \\[.*?(?<!\\\\)\\]                     # [ ... ] not preceded by \\
  )
REGEX
PASS_INLINE_MACRO_RX =
/#{PASS_INLINE_MACRO_STR}/xo
MonospaceRx =

Regex to match single or double backticks with content Matches: ‘text` or “text“ Avoids: escaped backticks `

/(?<!\\)(`{1,2})(.+?)(?<!\\)\1/

Instance Method Summary collapse

Instance Method Details

#inlinemonospace(text) ⇒ Object



150
151
152
153
154
155
156
# File 'lib/metanorma/converter/macros_nosub.rb', line 150

def inlinemonospace(text)
  text.include?("`") or return text
  /^\[.*\]\s*$/.match?(text) and return text
  pass_inline_split(text) do |x|
    monospace_escape(x)
  end.join
end

#monospace_escape(text) ⇒ Object



158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/metanorma/converter/macros_nosub.rb', line 158

def monospace_escape(text)
  text.gsub(MonospaceRx) do
    backticks = $1
    content = $2
    # Skip if content already starts with ++ (already protected)
    if content.start_with?("++") && content.end_with?("++")
      "#{backticks}#{content}#{backticks}"
    else
      # Protect content from character replacements but allow quotes substitution
      # Escape unescaped ] to prevent premature closing of pass:[...]
      protected_content = content.gsub(/(?<!\\)\]/, "\\]")
      "pass:c,q,a,m,p[#{backticks}#{protected_content}#{backticks}]"
    end
  end
end

#pass_inline_split(text) ⇒ Object



139
140
141
142
143
# File 'lib/metanorma/converter/macros_nosub.rb', line 139

def pass_inline_split(text)
  text.split(PASS_INLINE_MACRO_RX).each.map do |x|
    PASS_INLINE_MACRO_RX.match?(x) ? x : yield(x)
  end
end

#process(document, reader) ⇒ Object



115
116
117
118
119
120
121
122
# File 'lib/metanorma/converter/macros_nosub.rb', line 115

def process(document, reader)
  p = Metanorma::Utils::LineStatus.new
  lines = reader.lines.map do |t|
    p.process(t)
    !p.pass && t.include?("`") ? inlinemonospace(t) : t
  end
  ::Asciidoctor::PreprocessorReader.new document, lines
end