-
Notifications
You must be signed in to change notification settings - Fork 88
/
flutter_highlight.dart
101 lines (86 loc) · 2.87 KB
/
flutter_highlight.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:highlight/highlight.dart' show highlight, Node;
/// Highlight Flutter Widget
class HighlightView 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<String, TextStyle> theme;
/// Padding
final EdgeInsetsGeometry? padding;
/// Text styles
///
/// Specify text styles such as font family and font size
final TextStyle? textStyle;
HighlightView(
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<TextSpan> _convert(List<Node> nodes) {
List<TextSpan> spans = [];
var currentSpans = spans;
List<List<TextSpan>> stack = [];
_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) {
List<TextSpan> 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: RichText(
text: TextSpan(
style: _textStyle,
children: _convert(highlight.parse(source, language: language).nodes!),
),
),
);
}
}