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>
142 lines
3.2 KiB
Dart
142 lines
3.2 KiB
Dart
/// State model for the pql sidebar panel.
|
|
///
|
|
/// Manages search, DSL query execution, and markdown file listing.
|
|
/// All data comes through pql.* IPC verbs.
|
|
library;
|
|
|
|
import 'dart:async';
|
|
|
|
import 'package:clide/kernel/kernel.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
enum PqlView { query, markdown }
|
|
|
|
enum SearchMode { search, dsl }
|
|
|
|
class PqlController extends ChangeNotifier {
|
|
PqlController({required this.ipc});
|
|
|
|
final DaemonClient ipc;
|
|
|
|
PqlView _view = PqlView.query;
|
|
PqlView get view => _view;
|
|
|
|
SearchMode _searchMode = SearchMode.search;
|
|
SearchMode get searchMode => _searchMode;
|
|
|
|
String? _error;
|
|
String? get error => _error;
|
|
|
|
bool _loading = false;
|
|
bool get loading => _loading;
|
|
|
|
List<Map<String, Object?>> _results = const [];
|
|
List<Map<String, Object?>> get results => _results;
|
|
|
|
Map<String, Object?> _planStatus = const {};
|
|
Map<String, Object?> get planStatus => _planStatus;
|
|
|
|
void switchView(PqlView v) {
|
|
if (_view == v) return;
|
|
_view = v;
|
|
_results = const [];
|
|
_error = null;
|
|
notifyListeners();
|
|
switch (v) {
|
|
case PqlView.markdown:
|
|
unawaited(loadMarkdownFiles());
|
|
case PqlView.query:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void toggleSearchMode() => setSearchMode(_searchMode == SearchMode.search ? SearchMode.dsl : SearchMode.search);
|
|
|
|
void setSearchMode(SearchMode mode) {
|
|
if (_searchMode == mode) return;
|
|
_searchMode = mode;
|
|
_results = const [];
|
|
_error = null;
|
|
notifyListeners();
|
|
}
|
|
|
|
Future<void> search(String terms) async {
|
|
if (terms.trim().isEmpty) {
|
|
_results = const [];
|
|
_error = null;
|
|
notifyListeners();
|
|
return;
|
|
}
|
|
_loading = true;
|
|
_error = null;
|
|
notifyListeners();
|
|
|
|
final r = await ipc.request('pql.search', args: {'terms': terms, 'limit': 50});
|
|
|
|
_loading = false;
|
|
if (!r.ok) {
|
|
_error = r.error?.message;
|
|
_results = const [];
|
|
notifyListeners();
|
|
return;
|
|
}
|
|
_results = _castList(r.data['results']);
|
|
notifyListeners();
|
|
}
|
|
|
|
Future<void> loadMarkdownFiles({String? glob}) async {
|
|
_loading = true;
|
|
notifyListeners();
|
|
|
|
final r = await ipc.request('pql.files', args: {'glob': glob ?? '**/*.md', 'limit': 200});
|
|
|
|
_loading = false;
|
|
if (!r.ok) {
|
|
_error = r.error?.message;
|
|
notifyListeners();
|
|
return;
|
|
}
|
|
_error = null;
|
|
_results = _castList(r.data['files']);
|
|
notifyListeners();
|
|
}
|
|
|
|
Future<void> runQuery(String dsl) async {
|
|
if (dsl.trim().isEmpty) return;
|
|
_loading = true;
|
|
_error = null;
|
|
notifyListeners();
|
|
|
|
final r = await ipc.request('pql.query', args: {'query': dsl, 'limit': 200});
|
|
|
|
_loading = false;
|
|
if (!r.ok) {
|
|
_error = r.error?.message;
|
|
_results = const [];
|
|
notifyListeners();
|
|
return;
|
|
}
|
|
_results = _castList(r.data['results']);
|
|
notifyListeners();
|
|
}
|
|
|
|
Future<void> loadPlanStatus() async {
|
|
final r = await ipc.request('pql.plan.status');
|
|
if (r.ok) {
|
|
_planStatus = r.data;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
void clearError() {
|
|
if (_error == null) return;
|
|
_error = null;
|
|
notifyListeners();
|
|
}
|
|
|
|
static List<Map<String, Object?>> _castList(Object? raw) {
|
|
if (raw is! List) return const [];
|
|
return [for (final e in raw) (e as Map).cast<String, Object?>()];
|
|
}
|
|
}
|