chore: adopt Dart 3.9 toolchain — honest floor + tall-style reformat (T-353)

Raise the declared minimums in pubspec.yaml to what our deps already
require: Flutter >=3.35.0 / Dart >=3.9.0 (was 3.19.0 / 3.5.0). alchemist
0.12 needs Flutter 3.32; Dart 3.9 first ships in Flutter 3.35, so 3.35 is
the binding floor. Pin the exact build toolchain in .fvmrc (Flutter
3.44.1).

Moving to the Dart 3.9 language level switches `dart format` to the new
"tall" style and enables two new lints. This commit is the resulting
mechanical churn, isolated from any behaviour change:
  - whole-tree `dart format` reformat (tall style)
  - `dart fix` for unnecessary_underscores + use_null_aware_elements

No runtime behaviour change; `make test` green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-11 12:11:53 +02:00
co-authored by Claude Opus 4.8
parent bcea5f15b7
commit 6d0ebab721
444 changed files with 7587 additions and 12849 deletions
+7 -2
View File
@@ -66,7 +66,9 @@ class _Kv extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(width: 90, child: ClideText(label, fontSize: 13, color: tokens.globalTextMuted)),
Expanded(child: ClideText(value, fontSize: 13, fontFamily: clideMonoFamily, maxLines: 1, overflow: TextOverflow.ellipsis)),
Expanded(
child: ClideText(value, fontSize: 13, fontFamily: clideMonoFamily, maxLines: 1, overflow: TextOverflow.ellipsis),
),
],
),
);
@@ -89,7 +91,10 @@ class _Licenses extends StatelessWidget {
final deps = snap.data!.dependencies;
return Container(
constraints: const BoxConstraints(maxHeight: 260),
decoration: BoxDecoration(border: Border.all(color: tokens.globalBorder), borderRadius: BorderRadius.circular(4)),
decoration: BoxDecoration(
border: Border.all(color: tokens.globalBorder),
borderRadius: BorderRadius.circular(4),
),
child: ListView.builder(
shrinkWrap: true,
padding: const EdgeInsets.symmetric(vertical: 4),
+69 -59
View File
@@ -26,67 +26,77 @@ class MenuBarExtension extends ClideExtension {
@override
List<ContributionPoint> get contributions => [
CommandContribution(
id: 'file.openFolder',
command: 'file.openFolder',
title: 'File: Open Folder…',
run: (_) async {
await _file.openFolder();
return IpcResponse.ok(id: '', data: const {});
},
),
CommandContribution(
id: 'file.newWindow',
command: 'file.newWindow',
title: 'File: New Window',
run: (_) async {
_file.newWindow();
return IpcResponse.ok(id: '', data: const {});
},
),
CommandContribution(
id: 'file.closeWorkspace',
command: 'file.closeWorkspace',
title: 'File: Close Project',
run: (_) async {
_file.closeWorkspace();
return IpcResponse.ok(id: '', data: const {});
},
),
CommandContribution(
id: 'help.about',
command: 'help.about',
title: 'Help: About clide',
run: (_) async {
services.dialog.show<Object>((ctx, dismiss) => AboutDialog(onDismiss: () => dismiss()));
return IpcResponse.ok(id: '', data: const {});
},
),
];
CommandContribution(
id: 'file.openFolder',
command: 'file.openFolder',
title: 'File: Open Folder…',
run: (_) async {
await _file.openFolder();
return IpcResponse.ok(id: '', data: const {});
},
),
CommandContribution(
id: 'file.newWindow',
command: 'file.newWindow',
title: 'File: New Window',
run: (_) async {
_file.newWindow();
return IpcResponse.ok(id: '', data: const {});
},
),
CommandContribution(
id: 'file.closeWorkspace',
command: 'file.closeWorkspace',
title: 'File: Close Project',
run: (_) async {
_file.closeWorkspace();
return IpcResponse.ok(id: '', data: const {});
},
),
CommandContribution(
id: 'help.about',
command: 'help.about',
title: 'Help: About clide',
run: (_) async {
services.dialog.show<Object>((ctx, dismiss) => AboutDialog(onDismiss: () => dismiss()));
return IpcResponse.ok(id: '', data: const {});
},
),
];
}
/// The curated File / View / Help tree (T-48). View ends with a `view.*`
/// auto-fill so newly-registered view commands surface without edits here.
List<TopMenu> buildClideMenuTree() => [
TopMenu(title: 'File', mnemonic: 0, nodes: [
const MenuCommandItem('file.openFolder', fallbackTitle: 'Open Folder…'),
const MenuCommandItem('file.newWindow', fallbackTitle: 'New Window'),
const MenuSeparator(),
MenuCommandItem('file.closeWorkspace', fallbackTitle: 'Close Project', enabledWhen: (s) => s.project.isOpen),
]),
TopMenu(title: 'View', mnemonic: 0, nodes: const [
MenuCommandItem('view.zoomIn'),
MenuCommandItem('view.zoomOut'),
MenuCommandItem('view.zoomReset'),
MenuSeparator(),
MenuCommandItem('sidebar.collapse'),
MenuCommandItem('context.collapse'),
MenuCommandItem('dock.toggle'),
MenuCommandItem('panel.focusMode'),
MenuSeparator(),
MenuAutoFill('view.'),
]),
TopMenu(title: 'Help', mnemonic: 0, nodes: const [
MenuCommandItem('help.about', fallbackTitle: 'About clide'),
]),
];
TopMenu(
title: 'File',
mnemonic: 0,
nodes: [
const MenuCommandItem('file.openFolder', fallbackTitle: 'Open Folder…'),
const MenuCommandItem('file.newWindow', fallbackTitle: 'New Window'),
const MenuSeparator(),
MenuCommandItem('file.closeWorkspace', fallbackTitle: 'Close Project', enabledWhen: (s) => s.project.isOpen),
],
),
TopMenu(
title: 'View',
mnemonic: 0,
nodes: const [
MenuCommandItem('view.zoomIn'),
MenuCommandItem('view.zoomOut'),
MenuCommandItem('view.zoomReset'),
MenuSeparator(),
MenuCommandItem('sidebar.collapse'),
MenuCommandItem('context.collapse'),
MenuCommandItem('dock.toggle'),
MenuCommandItem('panel.focusMode'),
MenuSeparator(),
MenuAutoFill('view.'),
],
),
TopMenu(
title: 'Help',
mnemonic: 0,
nodes: const [MenuCommandItem('help.about', fallbackTitle: 'About clide')],
),
];
+3 -12
View File
@@ -143,10 +143,7 @@ class _OpenFolderDialogState extends State<OpenFolderDialog> {
onSubmitted: (_) => unawaited(_submit()),
),
),
if (_error != null) ...[
const SizedBox(height: 8),
ClideText(_error!, color: tokens.statusError, fontSize: 12),
],
if (_error != null) ...[const SizedBox(height: 8), ClideText(_error!, color: tokens.statusError, fontSize: 12)],
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.end,
@@ -188,17 +185,11 @@ class NotARepoDialog extends StatelessWidget {
const SizedBox(height: 8),
ClideText(path, muted: true, fontSize: 13),
const SizedBox(height: 8),
const ClideText(
'A clide project root requires a git repository.',
muted: true,
fontSize: 13,
),
const ClideText('A clide project root requires a git repository.', muted: true, fontSize: 13),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
ClideButton(label: 'OK', onPressed: () => onDismiss()),
],
children: [ClideButton(label: 'OK', onPressed: () => onDismiss())],
),
],
),
+3 -14
View File
@@ -72,18 +72,11 @@ class MenuBar extends StatelessWidget {
return ListenableBuilder(
listenable: Listenable.merge([controller, kernel.commands, kernel.project]),
builder: (ctx, _) {
final menus = resolveMenus(
buildClideMenuTree(),
kernel.commands,
kernel,
bindingLabel: (id) => keymapBindingLabel(kernel.keymap, id),
);
final menus = resolveMenus(buildClideMenuTree(), kernel.commands, kernel, bindingLabel: (id) => keymapBindingLabel(kernel.keymap, id));
controller.setMnemonics([for (final m in menus) m.title[m.mnemonic].toLowerCase()]);
return Row(
mainAxisSize: MainAxisSize.min,
children: [
for (var i = 0; i < menus.length; i++) _TopMenuButton(index: i, menu: menus[i], controller: controller, kernel: kernel),
],
children: [for (var i = 0; i < menus.length; i++) _TopMenuButton(index: i, menu: menus[i], controller: controller, kernel: kernel)],
);
},
);
@@ -189,11 +182,7 @@ class _TopMenuButtonState extends State<_TopMenuButton> {
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(horizontal: clideInsetStandard),
color: open || hovered ? tokens.listItemHoverBackground : null,
child: ClideText(
widget.menu.title,
fontSize: 12,
color: open || hovered ? tokens.globalForeground : tokens.chromeForeground,
),
child: ClideText(widget.menu.title, fontSize: 12, color: open || hovered ? tokens.globalForeground : tokens.chromeForeground),
),
),
),
+5 -12
View File
@@ -108,12 +108,7 @@ String? keymapBindingLabel(KeymapService keymap, String commandId) {
/// menus. [bindingLabel] supplies the keybinding string for a command id
/// (typically [keymapBindingLabel] bound to the keymap); when it returns null
/// the command's own `defaultBinding` is used as a fallback.
List<ResolvedMenu> resolveMenus(
List<TopMenu> tree,
CommandRegistry registry,
KernelServices services, {
String? Function(String commandId)? bindingLabel,
}) {
List<ResolvedMenu> resolveMenus(List<TopMenu> tree, CommandRegistry registry, KernelServices services, {String? Function(String commandId)? bindingLabel}) {
final placed = <String>{
for (final m in tree)
for (final n in m.nodes)
@@ -140,12 +135,10 @@ List<ResolvedMenu> resolveMenus(
}
List<ResolvedNode> expand(MenuNode n) => switch (n) {
MenuCommandItem() => [resolveItem(n)],
MenuSeparator() => const [ResolvedSeparator()],
MenuAutoFill(:final prefix) => [
for (final c in _autoFill(registry, prefix, placed)) resolveItem(MenuCommandItem(c.command)),
],
};
MenuCommandItem() => [resolveItem(n)],
MenuSeparator() => const [ResolvedSeparator()],
MenuAutoFill(:final prefix) => [for (final c in _autoFill(registry, prefix, placed)) resolveItem(MenuCommandItem(c.command))],
};
return [
for (final m in tree) ResolvedMenu(title: m.title, mnemonic: m.mnemonic, items: [for (final n in m.nodes) ...expand(n)]),