forked from lxm_flutter/FlutterUnit
.
This commit is contained in:
44
lib/components/permanent/code/code_panel.dart
Executable file
44
lib/components/permanent/code/code_panel.dart
Executable file
@@ -0,0 +1,44 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'high_light_code.dart';
|
||||
import 'highlighter_style.dart';
|
||||
|
||||
class CodeWidget extends StatelessWidget {
|
||||
CodeWidget({Key key, @required this.code, this.style, this.fontSize = 13,this.fontFamily})
|
||||
: super(key: key);
|
||||
|
||||
final String code;
|
||||
final HighlighterStyle style;
|
||||
final double fontSize;
|
||||
final String fontFamily;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget body;
|
||||
if (code == null) {
|
||||
return Container();
|
||||
} else {
|
||||
Widget _codeWidget;
|
||||
try {
|
||||
_codeWidget = RichText(
|
||||
text: TextSpan(
|
||||
style: TextStyle(fontSize: fontSize,fontFamily: fontFamily),
|
||||
children: <TextSpan>[DartHighlighter(style).format(code)],
|
||||
),
|
||||
);
|
||||
} catch (err) {
|
||||
_codeWidget = Text(code);
|
||||
}
|
||||
body = SingleChildScrollView(
|
||||
child: Container(
|
||||
child: _codeWidget,
|
||||
padding: EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: style.backgroundColor ?? Color(0xffF6F8FA),
|
||||
borderRadius: BorderRadius.all(Radius.circular(5.0))),
|
||||
),
|
||||
);
|
||||
}
|
||||
return body;
|
||||
}
|
||||
}
|
||||
316
lib/components/permanent/code/high_light_code.dart
Executable file
316
lib/components/permanent/code/high_light_code.dart
Executable file
@@ -0,0 +1,316 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:string_scanner/string_scanner.dart';
|
||||
|
||||
import 'highlighter_style.dart';
|
||||
|
||||
/// final SyntaxHighlighterStyle style = SyntaxHighlighterStyle.lightThemeStyle();
|
||||
/// DartSyntaxHighlighter(style).format(source)
|
||||
|
||||
|
||||
|
||||
abstract class Highlighter { // ignore: one_member_abstracts
|
||||
TextSpan format(String src);
|
||||
}
|
||||
|
||||
//暗黑模式下的高亮样式
|
||||
class DartHighlighter extends Highlighter {
|
||||
DartHighlighter([this._style]) {
|
||||
_spans = <_HighlightSpan>[];
|
||||
_style ??= HighlighterStyle.fromColors(HighlighterStyle.lightColor);
|
||||
}
|
||||
|
||||
HighlighterStyle _style;
|
||||
|
||||
static const List<String> _keywords = <String>[
|
||||
'abstract', 'as', 'assert', 'async', 'await', 'break', 'case', 'catch',
|
||||
'class', 'const', 'continue', 'default', 'deferred', 'do', 'dynamic', 'else',
|
||||
'enum', 'export', 'external', 'extends', 'factory', 'false', 'final',
|
||||
'finally', 'for', 'get', 'if', 'implements', 'import', 'in', 'is', 'library',
|
||||
'new', 'null', 'operator', 'part', 'rethrow', 'return', 'set', 'static',
|
||||
'super', 'switch', 'sync', 'this', 'throw', 'true', 'try', 'typedef', 'var',
|
||||
'void', 'while', 'with', 'yield'
|
||||
];
|
||||
|
||||
static const List<String> _builtInTypes = <String>[
|
||||
'int', 'double', 'num', 'bool'
|
||||
];
|
||||
|
||||
String _src;
|
||||
StringScanner _scanner;
|
||||
|
||||
List<_HighlightSpan> _spans;
|
||||
|
||||
@override
|
||||
TextSpan format(String src) {
|
||||
_src = src;
|
||||
_scanner = StringScanner(_src);
|
||||
|
||||
if (_generateSpans()) {
|
||||
// Successfully parsed the code
|
||||
final List<TextSpan> formattedText = <TextSpan>[];
|
||||
int currentPosition = 0;
|
||||
|
||||
for (_HighlightSpan span in _spans) {
|
||||
if (currentPosition != span.start)
|
||||
formattedText.add(TextSpan(text: _src.substring(currentPosition, span.start)));
|
||||
|
||||
formattedText.add(TextSpan(style: span.textStyle(_style), text: span.textForSpan(_src)));
|
||||
|
||||
currentPosition = span.end;
|
||||
}
|
||||
|
||||
if (currentPosition != _src.length)
|
||||
formattedText.add(TextSpan(text: _src.substring(currentPosition, _src.length)));
|
||||
|
||||
return TextSpan(style: _style.baseStyle, children: formattedText);
|
||||
} else {
|
||||
// Parsing failed, return with only basic formatting
|
||||
return TextSpan(style: _style.baseStyle, text: src);
|
||||
}
|
||||
}
|
||||
|
||||
bool _generateSpans() {
|
||||
int lastLoopPosition = _scanner.position;
|
||||
|
||||
while (!_scanner.isDone) {
|
||||
// Skip White space
|
||||
_scanner.scan(RegExp(r'\s+'));
|
||||
|
||||
// Block comments
|
||||
if (_scanner.scan(RegExp(r'/\*(.|\n)*\*/'))) {
|
||||
_spans.add(_HighlightSpan(
|
||||
_HighlightType.comment,
|
||||
_scanner.lastMatch.start,
|
||||
_scanner.lastMatch.end
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Line comments
|
||||
if (_scanner.scan('//')) {
|
||||
final int startComment = _scanner.lastMatch.start;
|
||||
|
||||
bool eof = false;
|
||||
int endComment;
|
||||
if (_scanner.scan(RegExp(r'.*\n'))) {
|
||||
endComment = _scanner.lastMatch.end - 1;
|
||||
} else {
|
||||
eof = true;
|
||||
endComment = _src.length;
|
||||
}
|
||||
|
||||
_spans.add(_HighlightSpan(
|
||||
_HighlightType.comment,
|
||||
startComment,
|
||||
endComment
|
||||
));
|
||||
|
||||
if (eof)
|
||||
break;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Raw r"String"
|
||||
if (_scanner.scan(RegExp(r'r".*"'))) {
|
||||
_spans.add(_HighlightSpan(
|
||||
_HighlightType.string,
|
||||
_scanner.lastMatch.start,
|
||||
_scanner.lastMatch.end
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Raw r'String'
|
||||
if (_scanner.scan(RegExp(r"r'.*'"))) {
|
||||
_spans.add(_HighlightSpan(
|
||||
_HighlightType.string,
|
||||
_scanner.lastMatch.start,
|
||||
_scanner.lastMatch.end
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Multiline """String"""
|
||||
if (_scanner.scan(RegExp(r'"""(?:[^"\\]|\\(.|\n))*"""'))) {
|
||||
_spans.add(_HighlightSpan(
|
||||
_HighlightType.string,
|
||||
_scanner.lastMatch.start,
|
||||
_scanner.lastMatch.end
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Multiline '''String'''
|
||||
if (_scanner.scan(RegExp(r"'''(?:[^'\\]|\\(.|\n))*'''"))) {
|
||||
_spans.add(_HighlightSpan(
|
||||
_HighlightType.string,
|
||||
_scanner.lastMatch.start,
|
||||
_scanner.lastMatch.end
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
// "String"
|
||||
if (_scanner.scan(RegExp(r'"(?:[^"\\]|\\.)*"'))) {
|
||||
_spans.add(_HighlightSpan(
|
||||
_HighlightType.string,
|
||||
_scanner.lastMatch.start,
|
||||
_scanner.lastMatch.end
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
// 'String'
|
||||
if (_scanner.scan(RegExp(r"'(?:[^'\\]|\\.)*'"))) {
|
||||
_spans.add(_HighlightSpan(
|
||||
_HighlightType.string,
|
||||
_scanner.lastMatch.start,
|
||||
_scanner.lastMatch.end
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Double
|
||||
if (_scanner.scan(RegExp(r'\d+\.\d+'))) {
|
||||
_spans.add(_HighlightSpan(
|
||||
_HighlightType.number,
|
||||
_scanner.lastMatch.start,
|
||||
_scanner.lastMatch.end
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Integer
|
||||
if (_scanner.scan(RegExp(r'\d+'))) {
|
||||
_spans.add(_HighlightSpan(
|
||||
_HighlightType.number,
|
||||
_scanner.lastMatch.start,
|
||||
_scanner.lastMatch.end)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Punctuation
|
||||
if (_scanner.scan(RegExp(r'[\[\]{}().!=<>&\|\?\+\-\*/%\^~;:,]'))) {
|
||||
_spans.add(_HighlightSpan(
|
||||
_HighlightType.punctuation,
|
||||
_scanner.lastMatch.start,
|
||||
_scanner.lastMatch.end
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Meta data
|
||||
if (_scanner.scan(RegExp(r'@\w+'))) {
|
||||
_spans.add(_HighlightSpan(
|
||||
_HighlightType.keyword,
|
||||
_scanner.lastMatch.start,
|
||||
_scanner.lastMatch.end
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Words
|
||||
if (_scanner.scan(RegExp(r'\w+'))) {
|
||||
_HighlightType type;
|
||||
|
||||
String word = _scanner.lastMatch[0];
|
||||
if (word.startsWith('_'))
|
||||
word = word.substring(1);
|
||||
|
||||
if (_keywords.contains(word))
|
||||
type = _HighlightType.keyword;
|
||||
else if (_builtInTypes.contains(word))
|
||||
type = _HighlightType.keyword;
|
||||
else if (_firstLetterIsUpperCase(word))
|
||||
type = _HighlightType.klass;
|
||||
else if (word.length >= 2 && word.startsWith('k') && _firstLetterIsUpperCase(word.substring(1)))
|
||||
type = _HighlightType.constant;
|
||||
|
||||
if (type != null) {
|
||||
_spans.add(_HighlightSpan(
|
||||
type,
|
||||
_scanner.lastMatch.start,
|
||||
_scanner.lastMatch.end
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Check if this loop did anything
|
||||
if (lastLoopPosition == _scanner.position) {
|
||||
// Failed to parse this file, abort gracefully
|
||||
return false;
|
||||
}
|
||||
lastLoopPosition = _scanner.position;
|
||||
}
|
||||
|
||||
_simplify();
|
||||
return true;
|
||||
}
|
||||
|
||||
void _simplify() {
|
||||
for (int i = _spans.length - 2; i >= 0; i -= 1) {
|
||||
if (_spans[i].type == _spans[i + 1].type && _spans[i].end == _spans[i + 1].start) {
|
||||
_spans[i] = _HighlightSpan(
|
||||
_spans[i].type,
|
||||
_spans[i].start,
|
||||
_spans[i + 1].end
|
||||
);
|
||||
_spans.removeAt(i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool _firstLetterIsUpperCase(String str) {
|
||||
if (str.isNotEmpty) {
|
||||
final String first = str.substring(0, 1);
|
||||
return first == first.toUpperCase();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
enum _HighlightType {
|
||||
number,
|
||||
comment,
|
||||
keyword,
|
||||
string,
|
||||
punctuation,
|
||||
klass,
|
||||
constant
|
||||
}
|
||||
|
||||
class _HighlightSpan {
|
||||
_HighlightSpan(this.type, this.start, this.end);
|
||||
final _HighlightType type;
|
||||
final int start;
|
||||
final int end;
|
||||
|
||||
String textForSpan(String src) {
|
||||
return src.substring(start, end);
|
||||
}
|
||||
|
||||
TextStyle textStyle(HighlighterStyle style) {
|
||||
if (type == _HighlightType.number)
|
||||
return style.numberStyle;
|
||||
else if (type == _HighlightType.comment)
|
||||
return style.commentStyle;
|
||||
else if (type == _HighlightType.keyword)
|
||||
return style.keywordStyle;
|
||||
else if (type == _HighlightType.string)
|
||||
return style.stringStyle;
|
||||
else if (type == _HighlightType.punctuation)
|
||||
return style.punctuationStyle;
|
||||
else if (type == _HighlightType.klass)
|
||||
return style.classStyle;
|
||||
else if (type == _HighlightType.constant)
|
||||
return style.constantStyle;
|
||||
else
|
||||
return style.baseStyle;
|
||||
}
|
||||
}
|
||||
136
lib/components/permanent/code/highlighter_style.dart
Normal file
136
lib/components/permanent/code/highlighter_style.dart
Normal file
@@ -0,0 +1,136 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020-04-11
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
|
||||
class HighlighterStyle {
|
||||
//句法高亮样式
|
||||
const HighlighterStyle(
|
||||
{ //构造函数
|
||||
this.baseStyle, //基础样式
|
||||
this.numberStyle, //数字的样式
|
||||
this.commentStyle, //注释样式
|
||||
this.keywordStyle, //关键字样式
|
||||
this.stringStyle, //字符串样式
|
||||
this.punctuationStyle, //标点符号样式
|
||||
this.classStyle, //类名
|
||||
this.backgroundColor,
|
||||
this.constantStyle});
|
||||
|
||||
static List<int> get lightColor => [
|
||||
0xFF000000, //基础
|
||||
0xFF00b0e8, //数字
|
||||
0xFF9E9E9E, //注释
|
||||
0xFF9C27B0, //关键
|
||||
0xFF43A047, //字符串
|
||||
0xFF000000, //标点符号
|
||||
0xFF3D62F5, //类名
|
||||
0xFF795548, //常量
|
||||
0xffF6F8FA, //背景
|
||||
];
|
||||
|
||||
static List<int> get darkColor => [
|
||||
0xFFFFFFFF, //基础
|
||||
0xFFDF935F, //数字
|
||||
0xFF9E9E9E, //注释
|
||||
0xFF80CBC4, //关键字
|
||||
0xFFB9CA4A, //字符串
|
||||
0xFFFFFFFF, //标点符号
|
||||
0xFF7AA6DA, //类名
|
||||
0xFF795548, //常量
|
||||
0xFF1D1F21, //背景
|
||||
];
|
||||
|
||||
static List<int> get gitHub =>
|
||||
[
|
||||
0xFF333333, //基础
|
||||
0xFF008081, //数字
|
||||
0xFF9D9D8D, //注释
|
||||
0xFF009999, //关键字
|
||||
0xFFDD1045, //字符串
|
||||
0xFF333333, //标点符号
|
||||
0xFF6F42C1, //类名
|
||||
0xFF795548, //常量
|
||||
0xFFF8F8F8, //背景
|
||||
];
|
||||
|
||||
static List<int> get zenburn => [
|
||||
0xFFDCDCDC, //普通字
|
||||
0xFF87C5C8, //数字
|
||||
0xFF8F8F8F, //注释
|
||||
0xFFE4CEAB, //关键字
|
||||
0xFFCC9493, //字符串
|
||||
0xFFDCDCDC, //标点符号
|
||||
0xFFEFEF90, //类名
|
||||
0xFFEF5350, //常量
|
||||
0xFF3F3F3F, //背景
|
||||
];
|
||||
|
||||
static List<int> get mf =>[
|
||||
0xFF707D95, //基础
|
||||
0xFF6897BB, //数字
|
||||
0xFF629755, //注释
|
||||
0xFFCC7832, //关键
|
||||
0xFFF14E9F, //字符串
|
||||
0xFFFFBB33, //标点符号
|
||||
0xFF66CCFF, //类名
|
||||
0xFF9876AA, //常量
|
||||
0xFF2B2B2B //背景
|
||||
];
|
||||
|
||||
static List<int> get solarized =>[
|
||||
0xFF657B83, // 普通字
|
||||
0xFFD33682, // 数字
|
||||
0xFF93A1A1, // 注释
|
||||
0xFF859900, // 关键字
|
||||
0xFF2AA198, // 字符串
|
||||
0xFF859900, // 标点符号
|
||||
0xFF268BD2, // 类名
|
||||
0xFF268BD2, //常量
|
||||
0xFFDDD6C1, // 背景
|
||||
];
|
||||
|
||||
factory HighlighterStyle.fromColors(List<int> colors) => HighlighterStyle(
|
||||
baseStyle: TextStyle(
|
||||
color: Color(colors[0]),
|
||||
),
|
||||
numberStyle: TextStyle(
|
||||
color: Color(colors[1]),
|
||||
),
|
||||
commentStyle: TextStyle(
|
||||
color: Color(
|
||||
colors[2],
|
||||
),
|
||||
fontStyle: FontStyle.italic),
|
||||
keywordStyle: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(
|
||||
colors[3],
|
||||
),
|
||||
),
|
||||
stringStyle: TextStyle(
|
||||
color: Color(colors[4]),
|
||||
),
|
||||
punctuationStyle: TextStyle(
|
||||
color: Color(colors[5]),
|
||||
),
|
||||
classStyle: TextStyle(
|
||||
color: Color(colors[6]),
|
||||
),
|
||||
constantStyle: TextStyle(
|
||||
color: Color(colors[7]),
|
||||
),
|
||||
backgroundColor: Color(colors[8]),
|
||||
);
|
||||
final TextStyle baseStyle;
|
||||
final TextStyle numberStyle;
|
||||
final TextStyle commentStyle;
|
||||
final TextStyle keywordStyle;
|
||||
final TextStyle stringStyle;
|
||||
final TextStyle punctuationStyle;
|
||||
final TextStyle classStyle;
|
||||
final TextStyle constantStyle;
|
||||
final Color backgroundColor;
|
||||
}
|
||||
Reference in New Issue
Block a user