Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cache parsing results across widget rebuilds #33

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 52 additions & 17 deletions flutter_highlight/lib/flutter_highlight.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'package:flutter/widgets.dart';
import 'package:highlight/highlight.dart' show highlight, Node;

/// Highlight Flutter Widget
class HighlightView extends StatelessWidget {
class HighlightView extends StatefulWidget {
/// The original code to be highlighted
final String source;

Expand Down Expand Up @@ -36,6 +36,23 @@ class HighlightView extends StatelessWidget {
int tabSize = 8, // TODO: https://github.com/flutter/flutter/issues/50087
}) : source = input.replaceAll('\t', ' ' * tabSize);

static const _rootKey = 'root';
static const _defaultFontColor = Color(0xff000000);
static const _defaultBackgroundColor = Color(0xffffffff);

// TODO: dart:io is not available at web platform currently
// See: https://github.com/flutter/flutter/issues/39998
// So we just use monospace here for now
static const _defaultFontFamily = 'monospace';

@override
State<HighlightView> createState() => _HighlightViewState();
}

class _HighlightViewState extends State<HighlightView> {
late List<Node> _nodes;
late List<TextSpan> _spans;

List<TextSpan> _convert(List<Node> nodes) {
List<TextSpan> spans = [];
var currentSpans = spans;
Expand All @@ -45,10 +62,11 @@ class HighlightView extends StatelessWidget {
if (node.value != null) {
currentSpans.add(node.className == null
? TextSpan(text: node.value)
: TextSpan(text: node.value, style: theme[node.className!]));
: TextSpan(text: node.value, style: widget.theme[node.className!]));
} else if (node.children != null) {
List<TextSpan> tmp = [];
currentSpans.add(TextSpan(children: tmp, style: theme[node.className!]));
currentSpans
.add(TextSpan(children: tmp, style: widget.theme[node.className!]));
stack.add(currentSpans);
currentSpans = tmp;

Expand All @@ -68,32 +86,49 @@ class HighlightView extends StatelessWidget {
return spans;
}

static const _rootKey = 'root';
static const _defaultFontColor = Color(0xff000000);
static const _defaultBackgroundColor = Color(0xffffffff);
void _parse() =>
_nodes = highlight.parse(widget.source, language: widget.language).nodes!;

// TODO: dart:io is not available at web platform currently
// See: https://github.com/flutter/flutter/issues/39998
// So we just use monospace here for now
static const _defaultFontFamily = 'monospace';
void _generateSpans() => _spans = _convert(_nodes);

@override
void initState() {
super.initState();
_parse();
_generateSpans();
}

@override
void didUpdateWidget(HighlightView oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.source != oldWidget.source ||
widget.language != oldWidget.language) {
_parse();
_generateSpans();
} else if (widget.theme != oldWidget.theme) {
_generateSpans();
}
}

@override
Widget build(BuildContext context) {
var _textStyle = TextStyle(
fontFamily: _defaultFontFamily,
color: theme[_rootKey]?.color ?? _defaultFontColor,
fontFamily: HighlightView._defaultFontFamily,
color: widget.theme[HighlightView._rootKey]?.color ??
HighlightView._defaultFontColor,
);
if (textStyle != null) {
_textStyle = _textStyle.merge(textStyle);
if (widget.textStyle != null) {
_textStyle = _textStyle.merge(widget.textStyle);
}

return Container(
color: theme[_rootKey]?.backgroundColor ?? _defaultBackgroundColor,
padding: padding,
color: widget.theme[HighlightView._rootKey]?.backgroundColor ??
HighlightView._defaultBackgroundColor,
padding: widget.padding,
child: RichText(
text: TextSpan(
style: _textStyle,
children: _convert(highlight.parse(source, language: language).nodes!),
children: _spans,
),
),
);
Expand Down