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:
@@ -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),
|
||||
|
||||
@@ -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')],
|
||||
),
|
||||
];
|
||||
|
||||
@@ -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())],
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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)]),
|
||||
|
||||
Reference in New Issue
Block a user