mirror of
https://github.com/alibaba/flutter-go.git
synced 2025-07-13 00:22:23 +08:00
Add:创建 flutter go web 版
This commit is contained in:
263
packages/flutter_web_ui/tool/unicode_sync_script.dart
Normal file
263
packages/flutter_web_ui/tool/unicode_sync_script.dart
Normal file
@ -0,0 +1,263 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
// TODO(mdebbar): To reduce the size of generated code, we could pack the data
|
||||
// into a smaller format, e.g:
|
||||
//
|
||||
// ```dart
|
||||
// const _rawData = [
|
||||
// 0x000A, 0x000A, 1,
|
||||
// 0x000B, 0x000C, 2,
|
||||
// 0x000D, 0x000D, 3,
|
||||
// 0x0020, 0x0020, 4,
|
||||
// // ...
|
||||
// ];
|
||||
// ```
|
||||
//
|
||||
// Then we could lazily build the lookup instance on demand.
|
||||
import 'dart:io';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
/// A tuple that holds a [start] and [end] of a unicode range and a [property].
|
||||
class PropertyTuple {
|
||||
const PropertyTuple(this.start, this.end, this.property);
|
||||
|
||||
final int start;
|
||||
final int end;
|
||||
final String property;
|
||||
|
||||
/// Checks if there's an overlap between this tuple's range and [other]'s
|
||||
/// range.
|
||||
bool isOverlapping(PropertyTuple other) {
|
||||
return start <= other.end && end >= other.start;
|
||||
}
|
||||
|
||||
/// Checks if the [other] tuple is adjacent to this tuple.
|
||||
///
|
||||
/// Two tuples are considered adjacent if:
|
||||
/// - The new tuple's range immediately follows this tuple's range, and
|
||||
/// - The new tuple has the same property as this tuple.
|
||||
bool isAdjacent(PropertyTuple other) {
|
||||
return other.start == end + 1 && property == other.property;
|
||||
}
|
||||
|
||||
/// Merges the ranges of the 2 [PropertyTuples] if they are adjacent.
|
||||
PropertyTuple extendRange(PropertyTuple extension) {
|
||||
assert(isAdjacent(extension));
|
||||
return PropertyTuple(start, extension.end, property);
|
||||
}
|
||||
}
|
||||
|
||||
/// Usage (from the root of the project):
|
||||
///
|
||||
/// ```
|
||||
/// dart tool/unicode_sync_script.dart <path/to/word/break/properties>
|
||||
/// ```
|
||||
///
|
||||
/// This script parses the unicode word break properties(1) and generates Dart
|
||||
/// code(2) that can perform lookups in the unicode ranges to find what property
|
||||
/// a letter has.
|
||||
///
|
||||
/// (1) The properties file can be downloaded from:
|
||||
/// https://www.unicode.org/Public/11.0.0/ucd/auxiliary/WordBreakProperty.txt
|
||||
///
|
||||
/// (2) The codegen'd Dart file is located at:
|
||||
/// lib/src/text/word_break_properties.dart
|
||||
void main(List<String> arguments) async {
|
||||
final String propertiesFile = arguments[0];
|
||||
final String codegenFile = path.join(
|
||||
path.dirname(Platform.script.toFilePath()),
|
||||
'../lib/src/engine/text/word_break_properties.dart',
|
||||
);
|
||||
WordBreakPropertiesSyncer(propertiesFile, codegenFile).perform();
|
||||
}
|
||||
|
||||
/// Base class that provides common logic for syncing all kinds of unicode
|
||||
/// properties (e.g. word break properties, line break properties, etc).
|
||||
///
|
||||
/// Subclasses implement the [template] method which receives as argument the
|
||||
/// list of data parsed by [processLines].
|
||||
abstract class PropertiesSyncer {
|
||||
PropertiesSyncer(this._src, this._dest);
|
||||
|
||||
final String _src;
|
||||
final String _dest;
|
||||
|
||||
void perform() async {
|
||||
final List<String> lines = await File(_src).readAsLines();
|
||||
final List<String> header = extractHeader(lines);
|
||||
final List<PropertyTuple> data = processLines(lines);
|
||||
|
||||
final IOSink sink = File(_dest).openWrite();
|
||||
sink.write(template(header, data));
|
||||
}
|
||||
|
||||
String template(List<String> header, List<PropertyTuple> data);
|
||||
}
|
||||
|
||||
/// Syncs Unicode's word break properties.
|
||||
class WordBreakPropertiesSyncer extends PropertiesSyncer {
|
||||
WordBreakPropertiesSyncer(String src, String dest) : super(src, dest);
|
||||
|
||||
@override
|
||||
String template(List<String> header, List<PropertyTuple> data) {
|
||||
return '''
|
||||
// Copyright 2019 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.
|
||||
|
||||
// AUTO-GENERATED FILE.
|
||||
// Generated by: tool/unicode_sync_script.dart
|
||||
//
|
||||
// Source:
|
||||
// ${header.join('\n// ')}
|
||||
|
||||
part of engine;
|
||||
|
||||
CharProperty getCharProperty(String text, int index) {
|
||||
if (index < 0 || index >= text.length) {
|
||||
return null;
|
||||
}
|
||||
return lookup.find(text.codeUnitAt(index));
|
||||
}
|
||||
|
||||
enum CharProperty {
|
||||
${getEnumValues(data).join(',\n ')}
|
||||
}
|
||||
|
||||
const UnicodePropertyLookup<CharProperty> lookup =
|
||||
UnicodePropertyLookup<CharProperty>(<UnicodeRange<CharProperty>>[
|
||||
${getLookupEntries(data).join(',\n ')}
|
||||
]);
|
||||
''';
|
||||
}
|
||||
|
||||
Iterable<String> getEnumValues(List<PropertyTuple> data) {
|
||||
return Set<String>.from(
|
||||
data.map<String>((PropertyTuple tuple) => tuple.property))
|
||||
.map(normalizePropertyName);
|
||||
}
|
||||
|
||||
Iterable<String> getLookupEntries(List<PropertyTuple> data) {
|
||||
data.sort(
|
||||
// Ranges don't overlap so it's safe to sort based on the start of each
|
||||
// range.
|
||||
(PropertyTuple tuple1, PropertyTuple tuple2) =>
|
||||
tuple1.start.compareTo(tuple2.start),
|
||||
);
|
||||
verifyNoOverlappingRanges(data);
|
||||
return combineAdjacentRanges(data)
|
||||
.map((PropertyTuple tuple) => generateLookupEntry(tuple));
|
||||
}
|
||||
|
||||
String generateLookupEntry(PropertyTuple tuple) {
|
||||
final String propertyStr =
|
||||
'CharProperty.${normalizePropertyName(tuple.property)}';
|
||||
return 'UnicodeRange<CharProperty>(${toHex(tuple.start)}, ${toHex(tuple.end)}, $propertyStr)';
|
||||
}
|
||||
}
|
||||
|
||||
/// Example:
|
||||
///
|
||||
/// ```
|
||||
/// UnicodeRange<CharProperty>(0x01C4, 0x0293, CharProperty.ALetter),
|
||||
/// UnicodeRange<CharProperty>(0x0294, 0x0294, CharProperty.ALetter),
|
||||
/// UnicodeRange<CharProperty>(0x0295, 0x02AF, CharProperty.ALetter),
|
||||
/// ```
|
||||
///
|
||||
/// will get combined into:
|
||||
///
|
||||
/// ```
|
||||
/// UnicodeRange<CharProperty>(0x01C4, 0x02AF, CharProperty.ALetter)
|
||||
/// ```
|
||||
List<PropertyTuple> combineAdjacentRanges(List<PropertyTuple> data) {
|
||||
final List<PropertyTuple> result = <PropertyTuple>[data.first];
|
||||
for (int i = 1; i < data.length; i++) {
|
||||
if (result.last.isAdjacent(data[i])) {
|
||||
result.last = result.last.extendRange(data[i]);
|
||||
} else {
|
||||
result.add(data[i]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int getRangeStart(String range) {
|
||||
return int.parse(range.split('..')[0], radix: 16);
|
||||
}
|
||||
|
||||
int getRangeEnd(String range) {
|
||||
if (range.contains('..')) {
|
||||
return int.parse(range.split('..')[1], radix: 16);
|
||||
}
|
||||
return int.parse(range, radix: 16);
|
||||
}
|
||||
|
||||
String toHex(int value) {
|
||||
return '0x${value.toRadixString(16).padLeft(4, '0').toUpperCase()}';
|
||||
}
|
||||
|
||||
void verifyNoOverlappingRanges(List<PropertyTuple> data) {
|
||||
for (int i = 1; i < data.length; i++) {
|
||||
if (data[i].isOverlapping(data[i - 1])) {
|
||||
throw Exception('Data contains overlapping ranges.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<String> extractHeader(List<String> lines) {
|
||||
final List<String> headerLines = <String>[];
|
||||
for (String line in lines) {
|
||||
if (line.contains('=======')) {
|
||||
break;
|
||||
}
|
||||
if (line.isNotEmpty) {
|
||||
headerLines.add(line);
|
||||
}
|
||||
}
|
||||
return headerLines;
|
||||
}
|
||||
|
||||
List<PropertyTuple> processLines(List<String> lines) {
|
||||
return lines
|
||||
.map(removeCommentFromLine)
|
||||
.where((String line) => line.isNotEmpty)
|
||||
.map(parseLineIntoPropertyTuple)
|
||||
.toList();
|
||||
}
|
||||
|
||||
String normalizePropertyName(String property) {
|
||||
return property.replaceAll('_', '');
|
||||
}
|
||||
|
||||
String removeCommentFromLine(String line) {
|
||||
final int poundIdx = line.indexOf('#');
|
||||
return (poundIdx == -1) ? line : line.substring(0, poundIdx);
|
||||
}
|
||||
|
||||
/// Examples:
|
||||
///
|
||||
/// 00C0..00D6 ; ALetter
|
||||
/// 037F ; ALetter
|
||||
///
|
||||
/// Would be parsed into:
|
||||
///
|
||||
/// ```dart
|
||||
/// PropertyTuple(192, 214, 'ALetter');
|
||||
/// PropertyTuple(895, 895, 'ALetter');
|
||||
/// ```
|
||||
PropertyTuple parseLineIntoPropertyTuple(String line) {
|
||||
final List<String> split = line.split(';');
|
||||
final String rangeStr = split[0].trim();
|
||||
final String propertyStr = split[1].trim();
|
||||
|
||||
final List<String> rangeSplit = rangeStr.contains('..')
|
||||
? rangeStr.split('..')
|
||||
: <String>[rangeStr, rangeStr];
|
||||
return PropertyTuple(
|
||||
int.parse(rangeSplit[0], radix: 16),
|
||||
int.parse(rangeSplit[1], radix: 16),
|
||||
propertyStr,
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user