parseText function

List<TextSegment> parseText(
  1. String? text
)

Implementation

List<TextSegment> parseText(String? text) {
  final segments = <TextSegment>[];

  if (text == null || text.isEmpty) {
    return segments;
  }

  RegExp exp = RegExp(
      r'(?<keyword>(#|@)([\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]+)|(?<url>(?:(?:https?|ftp):\/\/)?[-a-z0-9@:%._\+~#=]{1,256}\.[a-z0-9]{1,6}(\/[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)?)|(?<tag>(<[\w+>?][^<]*[<\/\w+>?]+)))',
      unicode: true);
  final matches = exp.allMatches(text);
  var start = 0;
  for (var match in matches) {
    /// it means that there is some text before matched word e.g text = some text some text [matched word]
    /// in simple words this block is adding text segment which is before @mention, #hashtag etc
    if (match.start > start) {
      // add this text to [segments] e.g add "some text some text"
      if (segments.isNotEmpty && segments.last.isText) {
        segments.last.text += text.substring(start, match.start);
      } else {
        segments.add(TextSegment(text.substring(start, match.start)));
      }
      // set the [start] to the point where match was found
      start = match.start;
    }

    final url = match.namedGroup('url');
    final keyword = match.namedGroup('keyword');

    if (url != null) {
      segments.add(TextSegment(url, url, false, false, false, null, true));
    } else if (keyword != null) {
      // if there is ' ' or '\n' before keyword i.e is there is blank space or \n before @mention, #hashtag etc e.g " @mention", "\n @mention"
      final isWord = match.start == 0 ||
          [' ', '\n'].contains(text.substring(match.start - 1, start));
      // if there is not ' ' or '\n' then continue the loop e.g in the case "sometext@mention"
      if (!isWord) {
        continue;
      }

      final isHashtag = keyword.startsWith('#');
      final isMention = keyword.startsWith('@');
      final isTag = keyword.startsWith('<');
      late String keywordToDisplay; //@mention, #hashtag
      String? tagName; // name of custom tag e.g tag1, tag2, admin
      /// if keyword is custom tag e.g <tag>some text</tag>
      /// extract 'tag' and remove <tag>, </tag> from keyword using regex
      if (isTag) {
        final regexTag = RegExp(r"<[^>]+>"); // <>
        final regexRemoveTag = RegExp(r"[<>]"); // <>
        final regexStartTag = RegExp(r"<\w+>"); // <tag>
        final regexEndTag = RegExp(r"<\/*\w*>*"); //</tag>
        tagName = regexTag.firstMatch(keyword)?.group(0);
        tagName = tagName?.replaceAll(regexRemoveTag, "");
        debugPrint("tagName: $tagName");
        keywordToDisplay = keyword.replaceAll(regexStartTag, "");
        keywordToDisplay = keywordToDisplay.replaceAll(regexEndTag, "");
      } else {
        keywordToDisplay = keyword;
      }
      segments.add(TextSegment(keywordToDisplay, keyword.substring(1),
          isHashtag, isMention, isTag, tagName));
    }

    start = match.end;
  }

  /// it means that there is some text after matched word e.g text = [matched word] some text some text
  /// in simple words this block is adding text segment which is after @mention, #hashtag etc
  if (start < text.length) {
    if (segments.isNotEmpty && segments.last.isText) {
      segments.last.text += text.substring(start);
    } else {
      segments.add(TextSegment(text.substring(start)));
    }
  }

  return segments;
}