Create a matcher that matches when a specific character is typed. Useful for @mentions and #tags.
771238
function triggerCharacter({
  char = '@',
  allowSpaces = false,
  startOfLine = false,
}) {

  return $position => {
    // Matching expressions used for later
    const escapedChar = `\\${char}`
    const suffix = new RegExp(`\\s${escapedChar}$`)
    const prefix = startOfLine ? '^' : ''
    const regexp = allowSpaces
      ? new RegExp(`${prefix}${escapedChar}.*?(?=\\s${escapedChar}|$)`, 'gm')
      : new RegExp(`${prefix}(?:^)?${escapedChar}[^\\s${escapedChar}]*`, 'gm')

    // Lookup the boundaries of the current node
    const textFrom = $position.before()
    const textTo = $position.end()
    const text = $position.doc.textBetween(textFrom, textTo, '\0', '\0')

    let match = regexp.exec(text)
    let position
    while (match !== null) {
      // JavaScript doesn't have lookbehinds; this hacks a check that first character is " "
      // or the line beginning
      const matchPrefix = match.input.slice(Math.max(0, match.index - 1), match.index)

      if (/^[\s\0]?$/.test(matchPrefix)) {
        // The absolute position of the match in the document
        const from = match.index + $position.start()
        let to = from + match[0].length

        // Edge case handling; if spaces are allowed and we're directly in between
        // two triggers
        if (allowSpaces && suffix.test(text.slice(to - 1, to + 1))) {
            match[0] += ' '
            to += 1
        }

        // If the $position is located within the matched substring, return that range
        if (from < $position.pos && to >= $position.pos) {
          position = {
            range: {
              from,
              to,
            },
            query: match[0].slice(char.length),
            text: match[0],
          }
        }
      }

      match = regexp.exec(text)
    }

    return position
  }
}
1095545
static Matcher ignoreCase(Matcher matcher) {
    if (matcher instanceof CharClassMatcher) {
      CharClassMatcher m = matcher.as();
      return new CharClassMatcher(m.set(), true);
    } else if (matcher instanceof CharSeqMatcher) {
      CharSeqMatcher m = matcher.as();
      return new CharSeqMatcher(m.pattern(), true);
    } else if (matcher instanceof IndexOfMatcher) {
      IndexOfMatcher m = matcher.as();
      return new IndexOfMatcher(m.pattern(), m.next(), true);
    } else if (matcher instanceof StartsWithMatcher) {
      StartsWithMatcher m = matcher.as();
      return new StartsWithMatcher(m.pattern(), true);
    } else {
      return matcher;
    }
  }
455055
static Matcher inlineMatchAnyPrecedingOr(Matcher matcher) {
    if (matcher instanceof ZeroOrMoreMatcher) {
      ZeroOrMoreMatcher zm = matcher.as();
      if (zm.repeated() instanceof AnyMatcher && zm.next() instanceof OrMatcher) {
        List<Matcher> matchers = zm.next().<OrMatcher>as().matchers();
        List<Matcher> ms = new ArrayList<>();
        for (Matcher m : matchers) {
          ms.add(new ZeroOrMoreMatcher(AnyMatcher.INSTANCE, m));
        }
        return OrMatcher.create(ms);
      }
    }
    return matcher;
  }
66296
private static boolean match(String regExp, String userInput) {
        Pattern pattern = Pattern.compile(regExp);
        Matcher matcher = pattern.matcher(userInput);
        if (matcher.find())
            return true;
        else
            return false;
    }
1060391
def match_value?(actual, expected)
      case expected
      when Symbol
        if Parser::AST::Node === actual
          actual.to_source == ":#{expected}"
        else
          actual.to_sym == expected
        end
      when String
        if Parser::AST::Node === actual
          actual.to_source == expected ||
            (actual.to_source[0] == ':' && actual.to_source[1..-1] == expected) ||
            actual.to_source[1...-1] == expected
        else
          actual.to_s == expected
        end
      when Regexp
        if Parser::AST::Node === actual
          actual.to_source =~ Regexp.new(expected.to_s, Regexp::MULTILINE)
        else
          actual.to_s =~ Regexp.new(expected.to_s, Regexp::MULTILINE)
        end
      when Array
        return false unless expected.length == actual.length
        actual.zip(expected).all? { |a, e| match_value?(a, e) }
      when NilClass
        actual.nil?
      when Numeric
        if Parser::AST::Node === actual
          actual.children[0] == expected
        else
          actual == expected
        end
      when TrueClass
        :true == actual.type
      when FalseClass
        :false == actual.type
      when Parser::AST::Node
        actual == expected
      else
        raise Synvert::Core::MethodNotSupported.new "#{expected.class} is not handled for match_value?"
      end
    end
1157172
static Matcher convertSingleCharClassToSeq(Matcher matcher) {
    if (matcher instanceof CharClassMatcher) {
      Optional<Character> opt = matcher.<CharClassMatcher>as().set().character();
      if (opt.isPresent()) {
        return new CharSeqMatcher(opt.get());
      }
    }
    return matcher;
  }
155667
def chars_after(chars, match):
    
    if match.end >= len(match.input_string):
        return True
    return match.input_string[match.end] in chars
1052401
def handleMatch(self, m):
        username = self.unescape(m.group(2))

        """"""
        if MARTOR_ENABLE_CONFIGS['mention'] == 'true':
            if username in [u.username for u in User.objects.exclude(is_active=False)]:
                url = '{0}{1}/'.format(MARTOR_MARKDOWN_BASE_MENTION_URL, username)
                el = markdown.util.etree.Element('a')
                el.set('href', url)
                el.set('class', 'direct-mention-link')
                el.text = markdown.util.AtomicString('@' + username)
                return el
125438
def _compile_template_re(delimiters):
    
    # The possible tag type characters following the opening tag,
    # excluding "=" and "{".
    tag_types = "!>&/#^"

    # TODO: are we following this in the spec?
    #
    #   The tag's content MUST be a non-whitespace character sequence
    #   NOT containing the current closing delimiter.
    #
    tag = r"""
        (?P<whitespace>[\ \t]*)
        %(otag)s \s*
        (?:
          (?P<change>=) \s* (?P<delims>.+?)   \s* = |
          (?P<raw>{)    \s* (?P<raw_name>.+?) \s* } |
          (?P<tag>[%(tag_types)s]?)  \s* (?P<tag_key>[\s\S]+?)
        )
        \s* %(ctag)s
    """ % {'tag_types': tag_types, 'otag': re.escape(delimiters[0]), 'ctag': re.escape(delimiters[1])}

    return re.compile(tag, re.VERBOSE)
290238
def match_any_char(self, chars, offset=0):
        """"""
        if not self.has_space(offset=offset):
            return ''
        current = self.string[self.pos + offset]
        return current if current in chars else ''
624669
def match(self, other):
        
        if self.sub_type != '*' and other.sub_type != '*' and other.sub_type != self.sub_type:
            return False

        if self.main_type != '*' and other.main_type != '*' and other.main_type != self.main_type:
            return False

        return True
493258
function _stringsByCharOrder(magicWord, givenMagicWord) {
  let charNumber = 0

  function _findMatchingCharacter(matchChar, string) {
    let found = false
    for (let j = charNumber; j < string.length; j++) {
      const stringChar = string[j]
      if (stringChar === matchChar) {
        found = true
        charNumber = j + 1
        break
      }
    }
    return found
  }

  for (let i = 0; i < givenMagicWord.length; i++) {
    const matchChar = givenMagicWord[i]
    const found = _findMatchingCharacter(matchChar, magicWord)
    if (!found) {
      return _matchRankMap.noMatch
    }
  }
  return _matchRankMap.matches
}
753675
def _match_display_text(self, element_key, string, string_match_type, match):
        """"""
        if string is None or string_match_type is None:
            raise NullArgument()
        match_value = self._get_string_match_value(string, string_match_type)
        self._add_match(element_key + '.text', match_value, match)
752214
protected boolean nestedMatch(Matcher<?> matcher, Object item, Description mismatch) {
        return Nested.matches(this, matcher, item, mismatch);
    }
668583
public T match(CharSequence text, boolean matchPrefix)
    {
        if (root == null)
        {
            throw new IllegalStateException("not compiled");
        }
        int length = text.length();
        for (int ii=0;ii<length;ii++)
        {
            switch (match(text.charAt(ii)))
            {
                case Error:
                    return null;
                case Ok:
                    if (matchPrefix)
                    {
                        T uniqueMatch = state.getUniqueMatch();
                        if (uniqueMatch != null)
                        {
                            state = root;
                            return uniqueMatch;
                        }
                    }
                    break;
                case Match:
                    return getMatched();
            }
        }
        return null;
    }
601686
def _name_matches(name, matches):
    '''
    
    '''
    for m in matches:
        if name.endswith(m):
            return True
        if name.lower().endswith('_' + m.lower()):
            return True
        if name.lower() == m.lower():
            return True
    return False
799448
def to_prawn
      MATCHERS.inject(@text) do |final_string, (markdown_matcher, prawn_tag)|
        final_string.gsub(markdown_matcher, prawn_tag)
      end
    end