text function

Parser text([
  1. LiquidConfig? config
])

Text parser - parses plain text content until a delimiter is encountered.

If config is provided, uses custom delimiters to determine text boundaries.

Optimized to parse multiple characters at once using a pattern-based approach:

  • Characters that are not delimiter start chars or whitespace are always safe text
  • A delimiter start char is safe only if not followed by the rest of the delimiter
  • Whitespace is safe only if not followed by strip delimiters

The whitespace check is critical for Liquid's whitespace control feature: {{- and {%- strip preceding whitespace, so we must stop parsing text before whitespace that precedes these delimiters.

This is much more efficient than the naive approach of checking (varStart() | tagStart()).neg() for each character, which requires 11 parser activations per character vs 2-3 for this pattern-based approach.

Implementation

Parser text([LiquidConfig? config]) {
  final cfg = config ?? LiquidConfig.standard;

  // Build character class for delimiter start characters
  final delimiterChars = cfg.delimiterStartChars;

  // Any character except delimiter start chars and whitespace is definitely safe
  final safeCharPattern = '^$delimiterChars \t\r\n';
  final safeChar = pattern(safeCharPattern);

  // A delimiter start char is safe if not followed by the rest of the delimiter
  final safeBrace = _safeDelimiterChar(cfg);

  // Whitespace is safe if not followed by strip delimiters
  final safeWhitespace =
      pattern(' \t\r\n') &
      (string(cfg.varStartStrip) | string(cfg.tagStartStrip)).not();

  // A text character is either:
  // - A safe char (not delimiter start or whitespace)
  // - A safe brace (delimiter start not followed by rest of delimiter)
  // - Safe whitespace (whitespace not followed by strip delimiters)
  final textChar =
      safeChar | safeBrace | safeWhitespace.map((values) => values[0]);

  // Parse one or more text characters and combine into a single TextNode
  return textChar
      .plus()
      .flatten()
      .map((text) => TextNode(text))
      .labeled('text block');
}