installReferenceHandlers method

void installReferenceHandlers()

Implementation

void installReferenceHandlers() {
  register(["label"], (cmd, ctx, stream) {
    final arg = ctx.parseArgument() ?? TextNode("\\label");
    final key = switch (arg) {
      TextNode() => arg.content,
      GroupNode() => ParseUtils.extractText(arg.childrenNodes),
      _ => "",
    };
    return LabelNode(key);
  });

  register(["ref"], (cmd, ctx, stream) {
    final arg = ctx.parseArgument() ?? TextNode("\\ref");
    final key = switch (arg) {
      TextNode() => arg.content,
      GroupNode() => ParseUtils.extractText(arg.childrenNodes),
      _ => "",
    };
    return RefNode(key);
  });

  register(["eqref"], (cmd, ctx, stream) {
    final arg = ctx.parseArgument() ?? TextNode("\\eqref");
    final key = switch (arg) {
      TextNode() => arg.content,
      GroupNode() => ParseUtils.extractText(arg.childrenNodes),
      _ => "",
    };
    return EqRefNode(key);
  });

  register(["tag"], (cmd, ctx, stream) {
    // Check if \tag is followed by *
    final peekToken = stream.peek();
    final starred =
        peekToken is TextToken && peekToken.content.startsWith("*");
    if (starred) {
      final textToken = stream.peek() as TextToken;
      stream.advance();
      final remaining = textToken.content.replaceFirst(RegExp(r'^\*'), '');
      if (remaining.isNotEmpty) {
        // Unlikely to happen, kept for safety
      }
    }
    final arg = ctx.parseArgument() ?? TextNode("");
    return TagNode(arg, starred: starred);
  });

  register(["notag", "nonumber"], (_, __, ___) {
    return TagNode(GroupNode([]), starred: true);
  });

  register(["intertext", "shortintertext"], (_, ctx, __) {
    final arg = ctx.parseArgument() ?? TextNode("");
    final text = arg is GroupNode
        ? ParseUtils.extractText(arg.childrenNodes)
        : ParseUtils.extractText([arg]);
    return TextModeNode(text);
  });

  register(["substack"], (_, ctx, stream) {
    if (stream.peek() is! LeftBraceToken) {
      return TextNode("\\substack");
    }
    stream.advance(); // consume {

    final rows = <List<LatexNode>>[];
    var currentRow = <LatexNode>[];

    while (!stream.isEOF()) {
      final token = stream.peek();
      if (token is RightBraceToken) {
        stream.advance();
        break;
      } else if (token is NewLineToken) {
        stream.advance();
        rows.add(List.from(currentRow));
        currentRow = <LatexNode>[];
      } else {
        final node = ctx.parseExpression();
        if (node != null) currentRow.add(node);
      }
    }

    if (currentRow.isNotEmpty) {
      rows.add(currentRow);
    }

    return SubstackNode(rows);
  });
}