diff --git a/flutter_highlight/lib/flutter_highlight.dart b/flutter_highlight/lib/flutter_highlight.dart index 9afbc47..fd843ed 100644 --- a/flutter_highlight/lib/flutter_highlight.dart +++ b/flutter_highlight/lib/flutter_highlight.dart @@ -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; @@ -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 createState() => _HighlightViewState(); +} + +class _HighlightViewState extends State { + late List _nodes; + late List _spans; + List _convert(List nodes) { List spans = []; var currentSpans = spans; @@ -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 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; @@ -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, ), ), );