// ignore_for_file: depend_on_referenced_packages import 'package:flutter/material.dart'; import 'package:highlight/highlight.dart' show highlight, Node; // adapted from package `flutter_highlight` v0.7.0 `HighlightView` // TODO TLAD use the TextSpan getter when this is fixed: https://github.com/git-touch/highlight/issues/6 /// Highlight Flutter Widget class AvesHighlightView extends StatelessWidget { /// The original code to be highlighted final String source; /// Highlight language /// /// It is recommended to give it a value for performance /// /// [All available languages](https://github.com/pd4d10/highlight/tree/master/highlight/lib/languages) final String? language; /// Highlight theme /// /// [All available themes](https://github.com/pd4d10/highlight/blob/master/flutter_highlight/lib/themes) final Map theme; /// Padding final EdgeInsetsGeometry? padding; /// Text styles /// /// Specify text styles such as font family and font size final TextStyle? textStyle; AvesHighlightView({ super.key, required String input, this.language, this.theme = const {}, this.padding, this.textStyle, int tabSize = 8, // TODO: https://github.com/flutter/flutter/issues/50087 }) : source = input.replaceAll('\t', ' ' * tabSize); List _convert(List nodes) { final spans = []; var currentSpans = spans; final stack = >[]; void _traverse(Node node) { if (node.value != null) { currentSpans.add(node.className == null ? TextSpan(text: node.value) : TextSpan(text: node.value, style: theme[node.className!])); } else if (node.children != null) { final tmp = []; currentSpans.add(TextSpan(children: tmp, style: theme[node.className!])); stack.add(currentSpans); currentSpans = tmp; node.children!.forEach((n) { _traverse(n); if (n == node.children!.last) { currentSpans = stack.isEmpty ? spans : stack.removeLast(); } }); } } for (var node in nodes) { _traverse(node); } return spans; } 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 Widget build(BuildContext context) { var _textStyle = TextStyle( fontFamily: _defaultFontFamily, color: theme[_rootKey]?.color ?? _defaultFontColor, ); if (textStyle != null) { _textStyle = _textStyle.merge(textStyle); } return Container( color: theme[_rootKey]?.backgroundColor ?? _defaultBackgroundColor, padding: padding, child: SelectableText.rich( TextSpan( style: _textStyle, children: _convert(highlight.parse(source, language: language).nodes!), ), ), ); } }