autocompletePaths method

List<String> autocompletePaths(
  1. String partialPath, {
  2. int? limit,
})

Autocomplete suggestions for a partial hierarchical path.

The partial path is split into segments. Completed segments navigate down the tree; the final (possibly empty) segment is used as a prefix filter on children at that level. Returns up to limit full paths (with / appended for nodes that have children).

Implementation

List<String> autocompletePaths(String partialPath, {int? limit}) {
  final effectiveLimit = limit ?? defaultHierarchySearchLimit;
  final normalized = partialPath.replaceAll('.', hierarchyPathSeparator);
  final endsWithSep = normalized.endsWith(hierarchyPathSeparator);
  final parts = _splitPath(partialPath);

  // Navigate to the deepest complete segment.
  var current = root;
  final completedParts = <String>[root.name];

  final navParts = endsWithSep || parts.isEmpty
      ? parts
      : parts.sublist(0, parts.length - 1);
  for (final seg in navParts) {
    // If the segment matches the current node name, stay at this level
    // (handles the root name appearing as the first path segment).
    if (current.name == seg) {
      continue;
    }
    final child = current.children.where((c) => c.name == seg).firstOrNull;
    if (child == null) {
      return const [];
    }
    current = child;
    completedParts.add(child.name);
  }

  // The trailing prefix to filter on (empty if path ends with separator).
  final prefix = (endsWithSep || parts.isEmpty) ? '' : parts.last;

  final suggestions = <String>[];

  // When the prefix matches the current (root-level) node itself and we
  // haven't navigated past it, suggest the root path so that typing a
  // partial root name produces a completion.
  if (prefix.isNotEmpty &&
      completedParts.length == 1 &&
      current == root &&
      current.name.startsWith(prefix)) {
    final rootPath = current.name;
    suggestions.add(current.children.isNotEmpty
        ? '$rootPath$hierarchyPathSeparator'
        : rootPath);
  }

  for (final child in current.children) {
    if (prefix.isEmpty || child.name.startsWith(prefix)) {
      final pathParts = [...completedParts, child.name];
      final path = pathParts.join(hierarchyPathSeparator);
      suggestions.add(
          child.children.isNotEmpty ? '$path$hierarchyPathSeparator' : path);
      if (suggestions.length >= effectiveLimit) {
        break;
      }
    }
  }
  return suggestions;
}