// Quick-fix model for the flow editor's diagnostics. // // Each analyzer issue can carry one or more `QuickFix` records // describing a one-click remediation. The editor renders these // as action buttons on the hover tooltip and inside the bottom // diagnostic strip. Two categories exist today: // // * `ReplaceLineValueFix` — purely textual; the editor // applies it directly by mutating the controller's // buffer. // * `InstallCapabilityFix` — needs the host (Studio) to talk // to the Hub. The editor invokes the host-provided // callback and reanalyzes once it returns. // // New fix kinds can be added by extending the sealed base; both // surfaces (tooltip + strip) switch on the runtime type, so // adding a kind also means adding a case there. import 'dart:ui' show Offset; import 'package:flutter/foundation.dart'; @immutable sealed class QuickFix { /// One-line button label rendered in the UI (verb-first, /// imperative). Kept short so the strip layout doesn't reflow /// when multiple fixes are present. final String label; const QuickFix(this.label); } /// Replace the trailing value of `[line]` with [replacement]. /// Used by the unknown-type warning to offer the closest /// matching valid type token (e.g. `byes` → `bytes`). @immutable class ReplaceLineValueFix extends QuickFix { /// Zero-based line index inside the document. final int line; /// The token to substitute for the existing value (the /// substring after the colon, with surrounding whitespace /// preserved by the applier). final String replacement; const ReplaceLineValueFix({ required this.line, required this.replacement, required String label, }) : super(label); } /// Ask the host (Studio) to install the named capability via /// the Hub's store-backed install. The editor delegates to the /// [InstallCapabilityCallback] passed into `FlowEditorPage` /// and reanalyzes the document once the host returns. @immutable class InstallCapabilityFix extends QuickFix { /// The capability spec the operator wrote (with or without an /// `@version` tail). The host is responsible for parsing the /// version part if it matters; the editor never strips it. final String capability; const InstallCapabilityFix({ required this.capability, required String label, }) : super(label); } /// Ask the host to register a new module source for an unknown /// capability — used when the capability isn't in the public /// store. The host's handler typically prompts the operator /// for a local path (`chain install --link`) or a URL /// (`chain install `), then installs and reanalyzes. /// /// This is the recovery path for private modules: the public /// store doesn't know about `acme.internal/directory-lookup`, /// but the operator can point the hub at the local clone. @immutable class AddModuleSourceFix extends QuickFix { /// The capability the operator wrote — the host uses it to /// pre-fill its prompt ("Where can `` be /// installed from?"). final String capability; const AddModuleSourceFix({ required this.capability, required String label, }) : super(label); } /// Host-side install handler signature. Returns the new /// installed-capability list after the install completes (used /// by the editor to refresh its analyzer without round-tripping /// through the parent widget tree). Returns `null` on failure; /// in that case the editor keeps the prior list and the issue /// stays visible. typedef InstallCapabilityCallback = Future?> Function(String capability); /// Host-side "add module source" handler. Receives the bare /// capability spec the operator typed; expected to prompt the /// operator for a local path / URL and then install it. /// Same return contract as [InstallCapabilityCallback]. typedef AddModuleSourceCallback = Future?> Function(String capability); /// Hover-tooltip request — the controller emits one of these /// via a ValueNotifier when the pointer enters an issue range, /// and clears it when the pointer leaves both the range and the /// tooltip. The editor host listens and renders an overlay. @immutable class IssueHoverRequest { /// Zero-based line of the issue the pointer is over. final int line; /// Human-readable issue message (lifted from /// `Issue.message`). final String message; /// Issue severity. Drives the dot colour in the tooltip. final IssueHoverSeverity severity; /// Pre-computed quick fixes the tooltip should render as /// action buttons. Empty when the editor has nothing /// actionable to offer. final List fixes; /// Global cursor position at hover time — the host overlay /// uses it to anchor the tooltip near the pointer. final Offset globalPosition; const IssueHoverRequest({ required this.line, required this.message, required this.severity, required this.fixes, required this.globalPosition, }); } enum IssueHoverSeverity { error, warning, info }