HighlightedDiff.of constructor

HighlightedDiff.of(
  1. FileDiff diff, {
  2. required Highlighter highlighter,
  3. required SyntaxTheme theme,
  4. String? language,
  5. Duration? budget,
})

Highlights diff. The language comes from language if given, otherwise from the file extension. Unknown languages stay plain.

With a budget, full texts are tokenized for at most that long, and tokenize continues. Lines not tokenized yet are plain.

Implementation

factory HighlightedDiff.of(
  FileDiff diff, {
  required Highlighter highlighter,
  required SyntaxTheme theme,
  String? language,
  Duration? budget,
}) {
  final grammar = _grammarFor(diff, highlighter, language);
  if (grammar == null) {
    // Plain: each line is one token, made when it's asked for.
    return HighlightedDiff._(
      theme,
      const {},
      const {},
      oldPlain: _textOf(diff, old: true),
      newPlain: _textOf(diff, old: false),
    );
  }
  final oldLines = diff.oldLines;
  final newLines = diff.newLines;
  if (oldLines != null && newLines != null) {
    final highlighted = HighlightedDiff._(
      theme,
      const {},
      const {},
      oldDocument: TokenizedDocument(grammar),
      newDocument: TokenizedDocument(grammar),
    );
    final clock = Stopwatch()..start();
    highlighted._newDocument!.update(newLines.join('\n'), budget: budget);
    highlighted._oldDocument!.update(
      oldLines.join('\n'),
      budget: _left(budget, clock),
    );
    return highlighted;
  }

  final old = <int, List<ThemedToken>>{};
  final newer = <int, List<ThemedToken>>{};
  void tokenize(
    Iterable<(int, String)> numbered,
    Map<int, List<ThemedToken>> out,
  ) {
    StateStack? state;
    for (final (number, text) in numbered) {
      final tokens = grammar.tokenizeLine(text, state);
      state = tokens.endState;
      out[number] = themeTokens(text, tokens.tokens, theme);
    }
  }

  for (final hunk in diff.hunks) {
    tokenize([
      for (final l in hunk.lines)
        if (_onSide(l, old: true)) (l.oldNumber!, l.text),
    ], old);
    tokenize([
      for (final l in hunk.lines)
        if (_onSide(l, old: false)) (l.newNumber!, l.text),
    ], newer);
  }
  return HighlightedDiff._(theme, old, newer);
}