Phosphor icons: resolve by name via a generated map (T-314)
Replace the 49 hand-maintained named consts with one generated
label→codepoint map (phosphor_glyphs.g.dart, 1512 glyphs from the glyph
table via tool/gen_phosphor_glyphs.dart). Feature code now references
glyphs by their exact kebab-case name — PhosphorIcons.byName('folder') —
with no raw codepoints; this also lets a Lua extension name an icon
without crossing the FFI boundary with a codepoint.
byName is total: an unknown name degrades to the `placeholder` box so the
bug is visible (it's a real error), while phosphor_glyphs_test asserts
every byName('...') literal in lib/ resolves — recovering the typo check a
const gave. Migrated the 89 call sites. Adds EmptyIconPainter for an
intentional blank that still reserves the icon box; ClideFilterBox gains
showIcon to keep the slot aligned when blank.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
/// Guards the Phosphor label→codepoint indirection (T-314). The named consts
|
||||
/// are gone; code resolves glyphs by string via [PhosphorIcons.byName]. A
|
||||
/// string key loses the compiler's typo check, so this test recovers it: every
|
||||
/// `byName('…')` string literal in `lib/` must exist in the generated map —
|
||||
/// across all call sites, executed or not.
|
||||
library;
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:clide/widgets/src/icons/phosphor_glyphs.g.dart';
|
||||
import 'package:clide/widgets/widgets.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
test('the generated glyph map covers the full Phosphor set', () {
|
||||
expect(kPhosphorGlyphs.length, greaterThanOrEqualTo(1500));
|
||||
expect(kPhosphorGlyphs.containsKey('folder'), isTrue);
|
||||
// The fallback glyph must itself resolve, or byName would throw on a miss.
|
||||
expect(kPhosphorGlyphs.containsKey(PhosphorIcons.fallbackName), isTrue);
|
||||
});
|
||||
|
||||
test('every byName(\'…\') literal in lib/ resolves to a real glyph', () {
|
||||
final call = RegExp(r"byName\(\s*'([a-z0-9-]+)'\s*\)");
|
||||
final missing = <String, String>{}; // label -> first file it appears in
|
||||
for (final entity in Directory('lib').listSync(recursive: true)) {
|
||||
if (entity is! File || !entity.path.endsWith('.dart')) continue;
|
||||
for (final m in call.allMatches(entity.readAsStringSync())) {
|
||||
final label = m.group(1)!;
|
||||
if (!kPhosphorGlyphs.containsKey(label)) {
|
||||
missing.putIfAbsent(label, () => entity.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
expect(missing, isEmpty, reason: 'unknown Phosphor glyph name(s) in byName(): $missing');
|
||||
});
|
||||
|
||||
test('byName resolves a known name to its codepoint', () {
|
||||
expect(PhosphorIcons.byName('folder').codePoint, kPhosphorGlyphs['folder']);
|
||||
expect(PhosphorIcons.byName('caret-line-left').codePoint, kPhosphorGlyphs['caret-line-left']);
|
||||
});
|
||||
|
||||
test('byName degrades an unknown name to the placeholder fallback (never throws)', () {
|
||||
final fallback = kPhosphorGlyphs[PhosphorIcons.fallbackName];
|
||||
expect(PhosphorIcons.byName('definitely-not-a-real-glyph').codePoint, fallback);
|
||||
expect(PhosphorIcons.fallbackName, 'placeholder');
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user