anchor.diff:    AutoCompleteController autoCompleteController;
   
     final _scriptsCache = <String, ScriptRef>{};
  -  final _fileNamesCache = <String, String>{};
   
     final fileSearchFieldKey = GlobalKey(debugLabel: 'fileSearchFieldKey');
   
     String _query;
  -  List<ScriptRef> _matches;
  +  FileSearchResults _searchResults;
   
     @override
     void initState() {
  
positive.code:     // If the current query is a continuation of the previous query, then
      // filter down the previous matches. Otherwise search through all scripts:
      final scripts = currentQuery.startsWith(previousQuery)
          ? _matches
          : widget.debuggerController.sortedScripts.value;
  
      final matches = _findMatches(currentQuery, scripts);
      if (matches.isEmpty) {
        autoCompleteController.searchAutoComplete.value = [];
      } else {
        final topMatches = _takeTopMatches(matches);
        topMatches.forEach(_addScriptRefToCache);
        autoCompleteController.searchAutoComplete.value = topMatches
            .map((scriptRef) =>
                _createAutoCompleteMatch(scriptRef.uri, currentQuery))
            .toList();
      }
  
      _query = currentQuery;
      _matches = matches;
    }
  
    void _handleAutoCompleteOverlay() {
  
negative.code:   void _onClose() {
      autoCompleteController.closeAutoCompleteOverlay();
      widget.debuggerController.toggleFileOpenerVisibility(false);
      _fileNamesCache.clear();
      _scriptsCache.clear();
    }
  
    FileSearchResults _createSearchResults(
      String query,
      List<ScriptRef> scriptRefs,
    ) {
      if (query.isEmpty) {
        return FileSearchResults.emptyQuery(scriptRefs);
      }
  
      return FileSearchResults.withQuery(
        allScripts: scriptRefs,
        query: FileQuery(query),
      );
    }
  }
  
  class FileQuery {
    FileQuery(this.query) : assert(query.isNotEmpty);
  
    FileQuery.empty() : query = '';
  
    final String query;
  
    bool get isEmpty => query.isEmpty;
  
    bool isExactFullPathMatch(ScriptRef script) {
      if (isEmpty) return false;
      return script.uri.caseInsensitiveContains(query);
    }
  
    AutoCompleteMatch createExactFullPathAutoCompleteMatch(ScriptRef script) {
      if (isEmpty) return AutoCompleteMatch(script.uri);
  
      final matchedSegments = _findExactSegments(script.uri);
      return AutoCompleteMatch(script.uri, matchedSegments: matchedSegments);
    }
  
    bool isFuzzyMatch(ScriptRef script) {
      if (isEmpty) return false;
  
      final fileName = _fileName(script.uri);
      return fileName.caseInsensitiveFuzzyMatch(query);
    }
  
    AutoCompleteMatch createFuzzyMatchAutoCompleteMatch(ScriptRef script) {
      if (isEmpty) return AutoCompleteMatch(script.uri);
  
      final fileName = _fileName(script.uri);
      final fileNameIdx = script.uri.lastIndexOf(fileName);
      final matchedSegments = _findFuzzySegments(fileName)
          .map((range) =>
              Range(range.begin + fileNameIdx, range.end + fileNameIdx))
          .toList();
  
      return AutoCompleteMatch(script.uri, matchedSegments: matchedSegments);
    }
  
    List<Range> _findExactSegments(String file) {
      final autoCompleteResultSegments = <Range>[];
      final start = file.indexOf(query);
      final end = start + query.length;
      autoCompleteResultSegments.add(Range(start, end));
      return autoCompleteResultSegments;
    }
  
    List<Range> _findFuzzySegments(String file) {
      final autoCompleteResultSegments = <Range>[];
      var queryIndex = 0;
      for (int matchIndex = 0; matchIndex < file.length; matchIndex++) {
        if (queryIndex == query.length) break;
        if (file[matchIndex] == query[queryIndex]) {
          final start = matchIndex;
          final end = matchIndex + 1;
          autoCompleteResultSegments.add(Range(start, end));
          queryIndex++;
        }
      }
      return autoCompleteResultSegments;
    }
  
    String _fileName(String fullPath) {
      return _fileNamesCache[fullPath] ??= fullPath.split('/').last;
    }
  }
  
  class FileSearchResults {
    factory FileSearchResults.emptyQuery(List<ScriptRef> allScripts) {
      return FileSearchResults._(
        query: FileQuery.empty(),
        allScripts: allScripts,
        exactFullPathMatches: [],
        fuzzyMatches: [],
      );
    }
  
    factory FileSearchResults.withQuery({
      @required FileQuery query,
      @required List<ScriptRef> allScripts,
    }) {
      assert(!query.isEmpty);
      final List<ScriptRef> exactFullPathMatches = [];
      final List<ScriptRef> fuzzyMatches = [];
  
      for (final scriptRef in allScripts) {
        if (query.isExactFullPathMatch(scriptRef)) {
          exactFullPathMatches.add(scriptRef);
        } else if (query.isFuzzyMatch(scriptRef)) {
          fuzzyMatches.add(scriptRef);
        }
      }
  
      return FileSearchResults._(
        query: query,
        allScripts: allScripts,
        exactFullPathMatches: exactFullPathMatches,
        fuzzyMatches: fuzzyMatches,
      );
    }
  
    FileSearchResults._({
      @required this.query,
      @required this.allScripts,
      @required List<ScriptRef> exactFullPathMatches,
      @required List<ScriptRef> fuzzyMatches,
    })  : _exactFullPathMatches = exactFullPathMatches,
          _fuzzyMatches = fuzzyMatches;
  
    final List<ScriptRef> allScripts;
    final FileQuery query;
    final List<ScriptRef> _exactFullPathMatches;
    final List<ScriptRef> _fuzzyMatches;
  
    FileSearchResults get topMatches => _buildTopMatches();
  
    List<ScriptRef> get scriptRefs =>
        query.isEmpty ? allScripts : [..._exactFullPathMatches, ..._fuzzyMatches];
  
    List<AutoCompleteMatch> get autoCompleteMatches => query.isEmpty
        ? allScripts.map((script) => AutoCompleteMatch(script.uri)).toList()
        : [
            ..._exactFullPathMatches
                .map(query.createExactFullPathAutoCompleteMatch)
                .toList(),
            ..._fuzzyMatches
                .map(query.createFuzzyMatchAutoCompleteMatch)
                .toList(),
          ];
  
    FileSearchResults copyWith({
      List<ScriptRef> allScripts,
      FileQuery query,
      List<ScriptRef> exactFullPathMatches,
      List<ScriptRef> fuzzyMatches,
    }) {
      return FileSearchResults._(
        query: query ?? this.query,
        allScripts: allScripts ?? this.allScripts,
        exactFullPathMatches: exactFullPathMatches ?? _exactFullPathMatches,
        fuzzyMatches: fuzzyMatches ?? _fuzzyMatches,
      );
    }
  
    FileSearchResults _buildTopMatches() {
      if (query.isEmpty) {
        return copyWith(
          allScripts: allScripts.sublist(0, numOfMatchesToShow),
        );
      }
  
      if (scriptRefs.length <= numOfMatchesToShow) {
        return copyWith();
      }
  
      final topMatches = [];
      int matchesLeft = numOfMatchesToShow;
      for (final matches in [_exactFullPathMatches, _fuzzyMatches]) {
        final selected = _takeMatches(matches, matchesLeft);
        topMatches.add(selected);
        matchesLeft -= selected.length;
      }
  
      return copyWith(
        exactFullPathMatches: topMatches[0],
        fuzzyMatches: topMatches[1],
      );
    }
  
    List<ScriptRef> _takeMatches(List<ScriptRef> matches, int numToTake) {
      if (numToTake <= 0) {
        return [];
      }
      if (matches.length > numToTake) {
        return matches.sublist(0, numToTake);
      }
      return matches;
    }
  }
  