| // 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. |
| |
| // Regenerates the material icons file. |
| // See https://github.com/flutter/flutter/wiki/Updating-Material-Design-Fonts |
| |
| import 'dart:convert' show LineSplitter; |
| import 'dart:io'; |
| |
| import 'package:args/args.dart'; |
| import 'package:path/path.dart' as path; |
| |
| const String kOptionCodepointsPath = 'codepoints'; |
| const String kOptionIconsPath = 'icons'; |
| const String kOptionDryRun = 'dry-run'; |
| |
| const String kDefaultCodepointsPath = 'bin/cache/artifacts/material_fonts/codepoints'; |
| const String kDefaultIconsPath = 'packages/flutter/lib/src/material/icons.dart'; |
| |
| const String kBeginGeneratedMark = '// BEGIN GENERATED'; |
| const String kEndGeneratedMark = '// END GENERATED'; |
| |
| const Map<String, String> kIdentifierRewrites = const <String, String>{ |
| '360': 'threesixty', |
| '3d_rotation': 'threed_rotation', |
| '4k': 'four_k', |
| 'class': 'class_', |
| }; |
| |
| final Set<String> kMirroredIcons = new Set<String>.from(<String>[ |
| // This list is obtained from: |
| // http://google.github.io/material-design-icons/#icons-in-rtl |
| 'arrow_back', |
| 'arrow_back_ios', |
| 'arrow_forward', |
| 'arrow_forward_ios', |
| 'arrow_left', |
| 'arrow_right', |
| 'assignment', |
| 'assignment_return', |
| 'backspace', |
| 'battery_unknown', |
| 'call_made', |
| 'call_merge', |
| 'call_missed', |
| 'call_missed_outgoing', |
| 'call_received', |
| 'call_split', |
| 'chevron_left', |
| 'chevron_right', |
| 'chrome_reader_mode', |
| 'device_unknown', |
| 'dvr', |
| 'event_note', |
| 'featured_play_list', |
| 'featured_video', |
| 'first_page', |
| 'flight_land', |
| 'flight_takeoff', |
| 'format_indent_decrease', |
| 'format_indent_increase', |
| 'format_list_bulleted', |
| 'forward', |
| 'functions', |
| 'help', |
| 'help_outline', |
| 'input', |
| 'keyboard_backspace', |
| 'keyboard_tab', |
| 'label', |
| 'label_important', |
| 'label_outline', |
| 'last_page', |
| 'launch', |
| 'list', |
| 'live_help', |
| 'mobile_screen_share', |
| 'multiline_chart', |
| 'navigate_before', |
| 'navigate_next', |
| 'next_week', |
| 'note', |
| 'open_in_new', |
| 'playlist_add', |
| 'queue_music', |
| 'redo', |
| 'reply', |
| 'reply_all', |
| 'screen_share', |
| 'send', |
| 'short_text', |
| 'show_chart', |
| 'sort', |
| 'star_half', |
| 'subject', |
| 'trending_flat', |
| 'toc', |
| 'trending_down', |
| 'trending_up', |
| 'undo', |
| 'view_list', |
| 'view_quilt', |
| 'wrap_text', |
| ]); |
| |
| void main(List<String> args) { |
| // If we're run from the `tools` dir, set the cwd to the repo root. |
| if (path.basename(Directory.current.path) == 'tools') |
| Directory.current = Directory.current.parent.parent; |
| |
| final ArgParser argParser = new ArgParser(); |
| argParser.addOption(kOptionCodepointsPath, defaultsTo: kDefaultCodepointsPath); |
| argParser.addOption(kOptionIconsPath, defaultsTo: kDefaultIconsPath); |
| argParser.addFlag(kOptionDryRun, defaultsTo: false); |
| final ArgResults argResults = argParser.parse(args); |
| |
| final File iconFile = new File(path.absolute(argResults[kOptionIconsPath])); |
| if (!iconFile.existsSync()) { |
| stderr.writeln('Icons file not found: ${iconFile.path}'); |
| exit(1); |
| } |
| final File codepointsFile = new File(path.absolute(argResults[kOptionCodepointsPath])); |
| if (!codepointsFile.existsSync()) { |
| stderr.writeln('Codepoints file not found: ${codepointsFile.path}'); |
| exit(1); |
| } |
| |
| final String iconData = iconFile.readAsStringSync(); |
| final String codepointData = codepointsFile.readAsStringSync(); |
| final String newIconData = regenerateIconsFile(iconData, codepointData); |
| |
| if (argResults[kOptionDryRun]) |
| stdout.writeln(newIconData); |
| else |
| iconFile.writeAsStringSync(newIconData); |
| } |
| |
| String regenerateIconsFile(String iconData, String codepointData) { |
| final StringBuffer buf = new StringBuffer(); |
| bool generating = false; |
| for (String line in LineSplitter.split(iconData)) { |
| if (!generating) |
| buf.writeln(line); |
| if (line.contains(kBeginGeneratedMark)) { |
| generating = true; |
| final String iconDeclarations = generateIconDeclarations(codepointData); |
| buf.write(iconDeclarations); |
| } else if (line.contains(kEndGeneratedMark)) { |
| generating = false; |
| buf.writeln(line); |
| } |
| } |
| return buf.toString(); |
| } |
| |
| String generateIconDeclarations(String codepointData) { |
| return LineSplitter.split(codepointData) |
| .map((String l) => l.trim()) |
| .where((String l) => l.isNotEmpty) |
| .map(getIconDeclaration) |
| .join(); |
| } |
| |
| String getIconDeclaration(String line) { |
| final List<String> tokens = line.split(' '); |
| if (tokens.length != 2) |
| throw new FormatException('Unexpected codepoint data: $line'); |
| final String name = tokens[0]; |
| final String codepoint = tokens[1]; |
| final String identifier = kIdentifierRewrites[name] ?? name; |
| final String description = name.replaceAll('_', ' '); |
| final String rtl = kMirroredIcons.contains(name) ? ', matchTextDirection: true' : ''; |
| return ''' |
| |
| /// <p><i class="material-icons md-36">$name</i> — material icon named "$description".</p> |
| static const IconData $identifier = const IconData(0x$codepoint, fontFamily: 'MaterialIcons'$rtl); |
| '''; |
| } |