fromTomlString static method
Parse an alacritty-style TOML document. Unknown keys are ignored; any missing or malformed field keeps its default. Pure — no file IO.
Implementation
static TerminalConfig fromTomlString(String input) {
final map = TomlDocument.parse(input).toMap();
final d = TerminalConfig.defaults();
Map<String, dynamic> section(Map m, String key) =>
(m[key] is Map) ? Map<String, dynamic>.from(m[key] as Map) : const {};
int color(Map m, String key, int fallback) {
final v = m[key];
if (v is String) {
final c = parseColor(v);
if (c != null) return c;
}
return fallback;
}
final colorsM = section(map, 'colors');
final primary = section(colorsM, 'primary');
final normal = section(colorsM, 'normal');
final bright = section(colorsM, 'bright');
final selectionM = section(colorsM, 'selection');
final searchM = section(colorsM, 'search');
final hintsM = section(colorsM, 'hints');
final hintStartM = section(hintsM, 'start');
final matchesM = section(searchM, 'matches');
final focusedM = section(searchM, 'focused_match');
const names = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'];
final ansi = List<int>.generate(16, (i) {
final group = i < 8 ? normal : bright;
return color(group, names[i % 8], d.colors.ansi[i]);
});
final fontM = section(map, 'font');
List<String> fallbackList() {
final v = fontM['fallback'];
if (v is List) return v.map((e) => '$e').toList();
return d.font.fallback;
}
double dbl(Map m, String key, double fallback) {
final v = m[key];
if (v is num) return v.toDouble();
return fallback;
}
int integer(Map m, String key, int fallback) {
final v = m[key];
if (v is int) return v;
if (v is num) return v.toInt();
return fallback;
}
String str(Map m, String key, String fallback) {
final v = m[key];
return v is String ? v : fallback;
}
bool boolean(Map m, String key, bool fallback) {
final v = m[key];
return v is bool ? v : fallback;
}
final cursorM = section(map, 'cursor');
final scrollM = section(map, 'scrolling');
final mouseM = section(map, 'mouse');
final bellM = section(map, 'bell');
final imeM = section(map, 'ime');
final shellM = section(map, 'shell');
final windowM = section(map, 'window');
final paddingM = section(windowM, 'padding');
final selectionM2 = section(map, 'selection');
final terminalM = section(map, 'terminal');
final cursorStyleM = section(cursorM, 'style');
final colorsCursorM = section(colorsM, 'cursor');
List<String> strList(Map m, String key) {
final v = m[key];
if (v is List) return v.map((e) => '$e').toList();
return const [];
}
Map<String, String> strMap(Map m, String key) {
final v = m[key];
if (v is Map) {
return v.map((k, val) => MapEntry('$k', '$val'));
}
return const {};
}
String? strOrNull(Map m, String key) {
final v = m[key];
return v is String ? v : null;
}
int? colorOrNull(Map m, String key) {
final v = m[key];
if (v is String) return parseColor(v);
return null;
}
FontStyleConfig? fontStyleFrom(Map m, String key) {
final v = m[key];
if (v is! Map) return null;
return FontStyleConfig(
family: strOrNull(v, 'family'),
style: strOrNull(v, 'style'),
);
}
final rawBindings = <RawKeyBinding>[];
final kb = map['keyboard'];
final rawList = (kb is Map && kb['bindings'] is List)
? kb['bindings'] as List
: const [];
for (final e in rawList) {
if (e is! Map) continue;
final keyName = e['key'];
if (keyName is! String) continue;
rawBindings.add(RawKeyBinding(
key: keyName,
mods: e['mods'] is String ? e['mods'] as String : '',
mode: e['mode'] is String ? e['mode'] as String : '',
action: e['action'] is String ? e['action'] as String : null,
chars: e['chars'] is String ? e['chars'] as String : null,
));
}
return TerminalConfig(
colors: TerminalColors(
background: color(primary, 'background', d.colors.background),
foreground: color(primary, 'foreground', d.colors.foreground),
selection: color(selectionM, 'background', d.colors.selection),
ansi: ansi,
searchMatchBg: color(matchesM, 'background', d.colors.searchMatchBg),
searchMatchFg: color(matchesM, 'foreground', d.colors.searchMatchFg),
searchFocusedBg: color(focusedM, 'background', d.colors.searchFocusedBg),
searchFocusedFg: color(focusedM, 'foreground', d.colors.searchFocusedFg),
hintStartFg: color(hintStartM, 'foreground', d.colors.hintStartFg),
hintStartBg: color(hintStartM, 'background', d.colors.hintStartBg),
cursorText: colorOrNull(colorsCursorM, 'text') ?? d.colors.cursorText,
cursorBody: colorOrNull(colorsCursorM, 'cursor') ?? d.colors.cursorBody,
),
font: FontConfig(
family: str(fontM, 'family', d.font.family),
fallback: fallbackList(),
size: dbl(fontM, 'size', d.font.size),
lineHeight: dbl(fontM, 'line_height', d.font.lineHeight),
bold: fontStyleFrom(fontM, 'bold') ?? d.font.bold,
italic: fontStyleFrom(fontM, 'italic') ?? d.font.italic,
boldItalic: fontStyleFrom(fontM, 'bold_italic') ?? d.font.boldItalic,
),
cursor: CursorConfig(
blinkInterval: integer(cursorM, 'blink_interval', d.cursor.blinkInterval),
defaultShape: _cursorShapeFromName(str(cursorStyleM, 'shape', ''), d.cursor.defaultShape),
defaultBlinking:
str(cursorStyleM, 'blinking', '').toLowerCase() == 'on' ? true : d.cursor.defaultBlinking,
blinkTimeout: integer(cursorM, 'blink_timeout', d.cursor.blinkTimeout),
),
scrolling: ScrollConfig(
history: integer(scrollM, 'history', d.scrolling.history),
multiplier: integer(scrollM, 'multiplier', d.scrolling.multiplier),
),
mouse: MouseConfig(
doubleClickThreshold:
integer(mouseM, 'double_click_threshold', d.mouse.doubleClickThreshold),
),
bell: BellConfig(
color: color(bellM, 'color', d.bell.color),
duration: integer(bellM, 'duration', d.bell.duration),
animation: str(bellM, 'animation', d.bell.animation),
),
ime: ImeConfig(
preeditBg: color(imeM, 'preedit_bg', d.ime.preeditBg),
preeditFg: color(imeM, 'preedit_fg', d.ime.preeditFg),
underline: boolean(imeM, 'underline', d.ime.underline),
),
shell: ShellConfig(
program: strOrNull(shellM, 'program'),
args: strList(shellM, 'args'),
workingDirectory: strOrNull(shellM, 'working_directory'),
env: strMap(shellM, 'env'),
),
keyboard: KeyboardConfig(bindings: rawBindings),
window: WindowConfig(
padding: WindowPadding(
dbl(paddingM, 'x', d.window.padding.x),
dbl(paddingM, 'y', d.window.padding.y),
),
opacity: dbl(windowM, 'opacity', d.window.opacity),
decorations: str(windowM, 'decorations', d.window.decorations),
),
selection: SelectionConfig(
semanticEscapeChars:
str(selectionM2, 'semantic_escape_chars', d.selection.semanticEscapeChars),
),
terminal: TerminalBehaviorConfig(
osc52: osc52FromString(str(terminalM, 'osc52', ''), d.terminal.osc52),
),
);
}