Skip to content

Commit d832b12

Browse files
authored
Adds caching to speed up the expression evaluation autocomplete (flutter#3463)
1 parent 104fc82 commit d832b12

4 files changed

Lines changed: 26 additions & 10 deletions

File tree

packages/devtools_app/lib/src/debugger/debugger_controller.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ class DebuggerController extends DisposableController
175175

176176
final _showFileOpener = ValueNotifier<bool>(false);
177177

178+
final _clazzCache = <ClassRef, Class>{};
179+
178180
/// Jump to the given ScriptRef and optional SourcePosition.
179181
void showScriptLocation(
180182
ScriptLocation scriptLocation, {
@@ -272,7 +274,7 @@ class DebuggerController extends DisposableController
272274
/// May return null.
273275
Future<Class> classFor(ClassRef classRef) async {
274276
try {
275-
return await getObject(classRef);
277+
return _clazzCache[classRef] ??= await getObject(classRef);
276278
} catch (_) {}
277279
return null;
278280
}
@@ -840,6 +842,7 @@ class DebuggerController extends DisposableController
840842
}
841843

842844
void _clearAutocompleteCaches() {
845+
_clazzCache.clear();
843846
libraryMemberAutocompleteCache.clear();
844847
libraryMemberAndImportsAutocompleteCache.clear();
845848
}

packages/devtools_app/lib/src/debugger/evaluate.dart

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ class _ExpressionEvalFieldState extends State<ExpressionEvalField>
3333
AutoCompleteController _autoCompleteController;
3434
int historyPosition = -1;
3535

36+
String _activeWord = '';
37+
List<String> _matches = [];
38+
3639
final evalTextFieldKey = GlobalKey(debugLabel: 'evalTextFieldKey');
3740

3841
@override
@@ -74,7 +77,7 @@ class _ExpressionEvalFieldState extends State<ExpressionEvalField>
7477
final textFieldEditingValue = searchTextFieldController.value;
7578
final selection = textFieldEditingValue.selection;
7679

77-
final parts = AutoCompleteSearchControllerMixin.activeEdtingParts(
80+
final parts = AutoCompleteSearchControllerMixin.activeEditingParts(
7881
searchingValue,
7982
selection,
8083
handleFields: isField,
@@ -85,7 +88,14 @@ class _ExpressionEvalFieldState extends State<ExpressionEvalField>
8588
_autoCompleteController.clearSearchAutoComplete();
8689
return;
8790
}
88-
final matches = await autoCompleteResultsFor(parts, widget.controller);
91+
92+
final matches = parts.activeWord.startsWith(_activeWord)
93+
? _filterMatches(_matches, parts.activeWord)
94+
: await autoCompleteResultsFor(parts, widget.controller);
95+
96+
_matches = matches;
97+
_activeWord = parts.activeWord;
98+
8999
if (matches.length == 1 && matches.first == parts.activeWord) {
90100
// It is not useful to show a single autocomplete that is exactly what
91101
// the already typed.
@@ -180,7 +190,7 @@ class _ExpressionEvalFieldState extends State<ExpressionEvalField>
180190
final editingValue = textFieldEditingValue.text;
181191
final selection = textFieldEditingValue.selection;
182192

183-
final parts = AutoCompleteSearchControllerMixin.activeEdtingParts(
193+
final parts = AutoCompleteSearchControllerMixin.activeEditingParts(
184194
editingValue,
185195
selection,
186196
handleFields: _autoCompleteController.search.endsWith('.'),
@@ -200,6 +210,12 @@ class _ExpressionEvalFieldState extends State<ExpressionEvalField>
200210
);
201211
}
202212

213+
List<String> _filterMatches(List<String> previousMatches, String activeWord) {
214+
return previousMatches
215+
.where((match) => match.startsWith(activeWord))
216+
.toList();
217+
}
218+
203219
void _handleExpressionEval() async {
204220
final expressionText = searchTextFieldController.value.text.trim();
205221
updateSearchField(_autoCompleteController, newValue: '', caretPosition: 0);
@@ -512,10 +528,7 @@ Future<Set<String>> _autoCompleteMembersFor(
512528
if (classRef == null) {
513529
return {};
514530
}
515-
// TODO(jacobr): consider using controller.autocompleteCache to cache the list
516-
// of autocomplete candidates for each class. The main challenge with caching
517-
// is _isAccessible depends on the current source location so makes caching
518-
// difficult.
531+
519532
final result = <String>{};
520533
final clazz = await controller.classFor(classRef);
521534
if (clazz != null) {

packages/devtools_app/lib/src/ui/search.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ mixin AutoCompleteSearchControllerMixin on SearchControllerMixin {
473473
/// activeWord is "cl"
474474
/// leftSide is "controller."
475475
/// rightSide is " + 1000 + myChart.tra"
476-
static EditingParts activeEdtingParts(
476+
static EditingParts activeEditingParts(
477477
String editing,
478478
TextSelection selection, {
479479
bool handleFields = false,

packages/devtools_app/test/auto_complete_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ void main() {
1111
// [caretPosition] if null (default) TextSelection is set to EOL.
1212
EditingParts testEdit(String editing, [int caretPosition]) {
1313
final position = caretPosition == null ? editing.length : caretPosition;
14-
return AutoCompleteSearchControllerMixin.activeEdtingParts(
14+
return AutoCompleteSearchControllerMixin.activeEditingParts(
1515
editing,
1616
TextSelection(baseOffset: position, extentOffset: position),
1717
handleFields: true,

0 commit comments

Comments
 (0)