Skip to content

Commit 2afa6da

Browse files
authored
Improve icon preview and completion performance (#5887)
1 parent a88371d commit 2afa6da

File tree

4 files changed

+51
-103
lines changed

4 files changed

+51
-103
lines changed

flutter-idea/src/io/flutter/editor/FlutterCompletionContributor.java

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,11 @@
66
package io.flutter.editor;
77

88
import com.intellij.codeInsight.lookup.LookupElementBuilder;
9-
import com.intellij.openapi.application.ApplicationManager;
109
import com.intellij.openapi.project.Project;
1110
import com.intellij.util.ui.ColorIcon;
1211
import com.intellij.util.ui.EmptyIcon;
1312
import com.jetbrains.lang.dart.ide.completion.DartCompletionExtension;
1413
import com.jetbrains.lang.dart.ide.completion.DartServerCompletionContributor;
15-
import io.flutter.sdk.FlutterSdk;
1614
import org.apache.commons.lang.StringUtils;
1715
import org.dartlang.analysis.server.protocol.CompletionSuggestion;
1816
import org.dartlang.analysis.server.protocol.Element;
@@ -29,7 +27,7 @@ public class FlutterCompletionContributor extends DartCompletionExtension {
2927
@Override
3028
@Nullable
3129
public LookupElementBuilder createLookupElement(@NotNull final Project project, @NotNull final CompletionSuggestion suggestion) {
32-
final Icon icon = findIcon(suggestion, project);
30+
final Icon icon = findIcon(suggestion);
3331
if (icon != null) {
3432
final LookupElementBuilder lookup =
3533
DartServerCompletionContributor.createLookupElement(project, suggestion).withTypeText("", icon, false);
@@ -40,8 +38,7 @@ public LookupElementBuilder createLookupElement(@NotNull final Project project,
4038
return null;
4139
}
4240

43-
@Nullable
44-
private static Icon findIcon(@NotNull final CompletionSuggestion suggestion, @NotNull Project project) {
41+
private static Icon findIcon(@NotNull final CompletionSuggestion suggestion) {
4542
final Element element = suggestion.getElement();
4643
if (element != null) {
4744
final String returnType = element.getReturnType();
@@ -62,12 +59,12 @@ else if (Objects.equals(declaringType, "CupertinoColors")) {
6259
}
6360
}
6461
else if (Objects.equals(declaringType, "Icons")) {
65-
final Icon icon = FlutterIconLineMarkerProvider.getMaterialIconByName(project, getSdkHomePath(project), name);
62+
final Icon icon = FlutterMaterialIcons.getIconForName(name);
6663
// If we have no icon, show an empty node (which is preferable to the default "IconData" text).
6764
return icon != null ? icon : EMPTY_ICON;
6865
}
6966
else if (Objects.equals(declaringType, "CupertinoIcons")) {
70-
final Icon icon = FlutterIconLineMarkerProvider.getCupertinoIconByName(project, getSdkHomePath(project), name);
67+
final Icon icon = FlutterCupertinoIcons.getIconForName(name);
7168
// If we have no icon, show an empty node (which is preferable to the default "IconData" text).
7269
return icon != null ? icon : EMPTY_ICON;
7370
}
@@ -77,17 +74,4 @@ else if (Objects.equals(declaringType, "CupertinoIcons")) {
7774

7875
return null;
7976
}
80-
81-
@NotNull
82-
private static String getSdkHomePath(@NotNull Project project) {
83-
final FlutterSdk sdk = FlutterSdk.getFlutterSdk(project);
84-
if (sdk == null) {
85-
assert ApplicationManager.getApplication() != null;
86-
if (ApplicationManager.getApplication().isUnitTestMode()) {
87-
return "testData/sdk";
88-
}
89-
throw new NullPointerException("Flutter SDK not found");
90-
}
91-
return sdk.getHomePath();
92-
}
9377
}

flutter-idea/src/io/flutter/editor/FlutterIconLineMarkerProvider.java

Lines changed: 44 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
import org.jetbrains.yaml.psi.YamlRecursivePsiElementVisitor;
4343

4444
import javax.swing.*;
45-
import java.io.FileNotFoundException;
4645
import java.util.*;
4746

4847
import static io.flutter.dart.DartPsiUtil.*;
@@ -75,36 +74,6 @@ public static void initialize() {
7574
BuiltInPaths.put("CupertinoIcons", CupertinoRelativeIconsPath);
7675
}
7776

78-
@Nullable
79-
public static Icon getCupertinoIconByName(@Nullable Project project, @NotNull String sdkHomePath, @NotNull String iconName) {
80-
if (project == null) return null;
81-
final IconInfo iconDef =
82-
findStandardDefinition("CupertinoIcons", iconName, project, sdkHomePath + BuiltInPaths.get("CupertinoIcons"), sdkHomePath);
83-
if (iconDef == null) return null;
84-
final String path = FlutterSdkUtil.getPathToCupertinoIconsPackage(project);
85-
// <pub_cache>/hosted/pub.dartlang.org/cupertino_icons-v.m.n/assets/CupertinoIcons.ttf
86-
return findStandardIconFromDef(iconName, iconDef, path + CupertinoRelativeAssetPath);
87-
}
88-
89-
@Nullable
90-
public static Icon getMaterialIconByName(@Nullable Project project, @NotNull String sdkHomePath, @NotNull String iconName) {
91-
if (project == null) return null;
92-
final IconInfo iconDef =
93-
findStandardDefinition("Icons", iconName, project, sdkHomePath + BuiltInPaths.get("Icons"), sdkHomePath);
94-
if (iconDef == null) return null;
95-
// <flutter-sdk>/bin/cache/artifacts/material_fonts/MaterialIcons-Regular.otf
96-
return findStandardIconFromDef(iconName, iconDef, sdkHomePath + MaterialRelativeAssetPath);
97-
}
98-
99-
@Nullable
100-
public static Icon getMaterialIconFromCodepoint(@Nullable Project project, int codepoint) {
101-
if (project == null) return null;
102-
final FlutterSdk sdk = FlutterSdk.getFlutterSdk(project);
103-
if (sdk == null) return null;
104-
final IconPreviewGenerator generator = new IconPreviewGenerator(sdk.getHomePath() + MaterialRelativeAssetPath);
105-
return generator.convert(codepoint);
106-
}
107-
10877
@Nullable("null means disabled")
10978
@Override
11079
public @GutterName String getName() {
@@ -118,10 +87,9 @@ public LineMarkerInfo<?> getLineMarkerInfo(@NotNull PsiElement element) {
11887
return sdk == null ? null : getLineMarkerInfo(element, sdk);
11988
}
12089

121-
@SuppressWarnings("MissingRecentApi")
12290
@VisibleForTesting
12391
@Nullable
124-
static LineMarkerInfo<?> getLineMarkerInfo(@NotNull PsiElement element, @NotNull FlutterSdk sdk) {
92+
LineMarkerInfo<?> getLineMarkerInfo(@NotNull PsiElement element, @NotNull FlutterSdk sdk) {
12593
if ((element.getNode() != null ? element.getNode().getElementType() : null) != DartTokenTypes.IDENTIFIER) return null;
12694

12795
final String name = element.getText();
@@ -178,12 +146,30 @@ static LineMarkerInfo<?> getLineMarkerInfo(@NotNull PsiElement element, @NotNull
178146
assert parentNode != null;
179147
if (parentNode.getElementType() == DartTokenTypes.CALL_EXPRESSION) {
180148
// Check font family and package
181-
return getIconFromArguments(DartPsiImplUtil.getArguments((DartCallExpression)parent), element, sdk);
149+
final DartArguments arguments = DartPsiImplUtil.getArguments((DartCallExpression)parent);
150+
if (arguments == null) return null;
151+
final String family = getValueOfNamedArgument(arguments, "fontFamily");
152+
final PsiElement fontPackage = getNamedArgumentExpression(arguments, "fontPackage");
153+
final String argument = getValueOfPositionalArgument(arguments, 0);
154+
if (argument == null) return null;
155+
final Icon icon = getIconFromPackage(fontPackage, family, argument, element.getProject(), sdk);
156+
if (icon != null) {
157+
return createLineMarker(element, icon);
158+
}
182159
}
183160
else if (parentNode.getElementType() == DartTokenTypes.SIMPLE_TYPE) {
184161
parent = getNewExprFromType(parent);
185162
if (parent == null) return null;
186-
return getIconFromArguments(DartPsiImplUtil.getArguments((DartNewExpression)parent), element, sdk);
163+
final DartArguments arguments = DartPsiImplUtil.getArguments((DartNewExpression)parent);
164+
if (arguments == null) return null;
165+
final String family = getValueOfNamedArgument(arguments, "fontFamily");
166+
final PsiElement fontPackage = getNamedArgumentExpression(arguments, "fontPackage");
167+
final String argument = getValueOfPositionalArgument(arguments, 0);
168+
if (argument == null) return null;
169+
final Icon icon = getIconFromPackage(fontPackage, family, argument, element.getProject(), sdk);
170+
if (icon != null) {
171+
return createLineMarker(element, icon);
172+
}
187173
}
188174
else {
189175
final PsiElement idNode = refExpr.getFirstChild();
@@ -195,10 +181,17 @@ else if (parentNode.getElementType() == DartTokenTypes.SIMPLE_TYPE) {
195181
final String selector = AstBufferUtil.getTextSkippingWhitespaceComments(selectorNode.getNode());
196182
final Icon icon;
197183
if (name.equals("Icons")) {
198-
icon = getMaterialIconByName(element.getProject(), sdk.getHomePath(), selector);
184+
final IconInfo iconDef = findStandardDefinition(name, selector, element.getProject(), knownPath, sdk);
185+
if (iconDef == null) return null;
186+
// <flutter-sdk>/bin/cache/artifacts/material_fonts/MaterialIcons-Regular.otf
187+
icon = findStandardIconFromDef(name, iconDef, sdk.getHomePath() + MaterialRelativeAssetPath);
199188
}
200189
else if (name.equals("CupertinoIcons")) {
201-
icon = getCupertinoIconByName(element.getProject(), sdk.getHomePath(), selector);
190+
final IconInfo iconDef = findStandardDefinition(name, selector, element.getProject(), knownPath, sdk);
191+
if (iconDef == null) return null;
192+
final String path = FlutterSdkUtil.getPathToCupertinoIconsPackage(element.getProject());
193+
// <pub_cache>/hosted/pub.dartlang.org/cupertino_icons-v.m.n/assets/CupertinoIcons.ttf
194+
icon = findStandardIconFromDef(name, iconDef, path + CupertinoRelativeAssetPath);
202195
}
203196
else {
204197
// Note: I want to keep this code until I'm sure we won't use pubspec.yaml.
@@ -234,33 +227,16 @@ else if (name.equals("CupertinoIcons")) {
234227
}
235228

236229
@Nullable
237-
private static LineMarkerInfo<PsiElement> getIconFromArguments(@Nullable DartArguments arguments,
238-
@NotNull PsiElement element,
239-
@NotNull FlutterSdk sdk) {
240-
if (arguments == null) return null;
241-
final String family = getValueOfNamedArgument(arguments, "fontFamily");
242-
final PsiElement fontPackage = getNamedArgumentExpression(arguments, "fontPackage");
243-
final String argument = getValueOfPositionalArgument(arguments, 0);
244-
if (argument == null) return null;
245-
final Icon icon = getIconFromPackage(fontPackage, family, argument, element.getProject(), sdk);
246-
return icon == null ? null : createLineMarker(element, icon);
247-
}
248-
249-
@Nullable
250-
private static IconInfo findStandardDefinition(@NotNull String className,
251-
@NotNull String iconName,
252-
@NotNull Project project,
253-
@Nullable String path,
254-
@NotNull String sdkHomePath) {
230+
private IconInfo findStandardDefinition(@NotNull String className, @NotNull String iconName, @NotNull Project project, @Nullable String path, @NotNull FlutterSdk sdk) {
255231
if (path != null) {
256232
return findDefinition(className, iconName, project, path);
257233
}
258234
assert Objects.requireNonNull(ApplicationManager.getApplication()).isUnitTestMode();
259-
return findDefinition(className, iconName, project, sdkHomePath + BuiltInPaths.get(className));
235+
return findDefinition(className, iconName, project, sdk.getHomePath() + BuiltInPaths.get(className));
260236
}
261237

262238
@Nullable
263-
private static Icon findStandardIconFromDef(@NotNull String name, @NotNull IconInfo iconDef, @NotNull String path) {
239+
private Icon findStandardIconFromDef(@NotNull String name, @NotNull IconInfo iconDef, @NotNull String path) {
264240
assert LocalFileSystem.getInstance() != null;
265241
final VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(path);
266242
if (virtualFile == null) return null;
@@ -270,11 +246,7 @@ private static Icon findStandardIconFromDef(@NotNull String name, @NotNull IconI
270246

271247
// Note: package flutter_icons is not currently supported because it takes forever to analyze it.
272248
@Nullable
273-
private static Icon getIconFromPackage(@Nullable PsiElement aPackage,
274-
@Nullable String family,
275-
@NotNull String argument,
276-
@NotNull Project project,
277-
@NotNull FlutterSdk sdk) {
249+
private Icon getIconFromPackage(@Nullable PsiElement aPackage, @Nullable String family, @NotNull String argument, @NotNull Project project, @NotNull FlutterSdk sdk) {
278250
final int code;
279251
try {
280252
code = parseLiteralNumber(argument);
@@ -285,17 +257,16 @@ private static Icon getIconFromPackage(@Nullable PsiElement aPackage,
285257
family = family == null ? "MaterialIcons" : family;
286258
if (aPackage == null) {
287259
// Looking for IconData with no package -- package specification not currently supported.
288-
final String assetPath = family.equals("MaterialIcons")
289-
? sdk.getHomePath() + MaterialRelativeAssetPath
290-
: FlutterSdkUtil.getPathToCupertinoIconsPackage(project) + CupertinoRelativeAssetPath;
291-
final IconPreviewGenerator generator = new IconPreviewGenerator(assetPath);
260+
final String relativeAssetPath = family.equals("MaterialIcons") ? MaterialRelativeAssetPath : CupertinoRelativeAssetPath;
261+
// TODO Base path is wrong for cupertino -- is there a test for this branch (IconData with cupertino family)?
262+
final IconPreviewGenerator generator = new IconPreviewGenerator(sdk.getHomePath() + relativeAssetPath);
292263
return generator.convert(code);
293264
}
294265
return null;
295266
}
296267

297268
@Nullable
298-
private static LineMarkerInfo<PsiElement> createLineMarker(@Nullable PsiElement element, @NotNull Icon icon) {
269+
private LineMarkerInfo<PsiElement> createLineMarker(@Nullable PsiElement element, @NotNull Icon icon) {
299270
if (element == null) return null;
300271
assert element.getTextRange() != null;
301272
//noinspection MissingRecentApi
@@ -304,27 +275,24 @@ private static LineMarkerInfo<PsiElement> createLineMarker(@Nullable PsiElement
304275
}
305276

306277
@Nullable
307-
private static IconInfo findDefinition(@NotNull String className,
308-
@NotNull String iconName,
309-
@NotNull Project project,
310-
@NotNull String path) {
278+
private IconInfo findDefinition(@NotNull String className, @NotNull String iconName, @NotNull Project project, @NotNull String path) {
311279
assert LocalFileSystem.getInstance() != null;
312280
final VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(path);
313-
if (virtualFile == null) throw new Error("FILE NOT FOUND: " + path);//return null;
281+
if (virtualFile == null) return null;
314282
final PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile);
315283
if (psiFile == null) {
316-
throw new Error("CANNOT CREATE PSI FILE");//return null;
284+
return null;
317285
}
318286
final IconInfoVisitor visitor = new IconInfoVisitor(iconName);
319287
psiFile.accept(visitor);
320288
return visitor.info;
321289
}
322290

323291
@Nullable
324-
private static Icon findIconFromDef(@NotNull String iconClassName, @NotNull IconInfo iconDef, @NotNull String path) {
292+
private Icon findIconFromDef(@NotNull String iconClassName, @NotNull IconInfo iconDef, @NotNull String path) {
325293
assert LocalFileSystem.getInstance() != null;
326294
final VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(path);
327-
if (virtualFile == null) throw new Error("FILE NOT FOUND: " + path);//return null;
295+
if (virtualFile == null) return null;
328296
VirtualFile parent = virtualFile;
329297
while (parent != null && !parent.getName().equals("lib")) {
330298
parent = parent.getParent();
@@ -374,7 +342,7 @@ public boolean visitFile(@NotNull VirtualFile file) {
374342
return null;
375343
}
376344

377-
public static double findPattern(@NotNull String t, @NotNull String p) {
345+
public double findPattern(@NotNull String t, @NotNull String p) {
378346
// This is from https://github.com/tdebatty/java-string-similarity
379347
// It's MIT license file is: https://github.com/tdebatty/java-string-similarity/blob/master/LICENSE.md
380348
final JaroWinkler jw = new JaroWinkler();

flutter-idea/src/io/flutter/view/DiagnosticsTreeCellRenderer.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,10 @@
1212
import com.intellij.ui.SimpleTextAttributes;
1313
import com.intellij.ui.speedSearch.SpeedSearchSupply;
1414
import com.intellij.util.ui.UIUtil;
15-
import io.flutter.editor.FlutterIconLineMarkerProvider;
15+
import io.flutter.editor.FlutterMaterialIcons;
1616
import io.flutter.inspector.DiagnosticLevel;
1717
import io.flutter.inspector.DiagnosticsNode;
1818
import io.flutter.utils.ColorIconMaker;
19-
import io.flutter.utils.UIUtils;
2019
import org.apache.commons.lang.StringUtils;
2120
import org.jetbrains.annotations.NotNull;
2221

@@ -155,7 +154,7 @@ else if (isLinkedChild || panel.currentShowNode == value) {
155154
case "IconData": {
156155
final int codePoint = getIntMember(properties, "codePoint");
157156
if (codePoint > 0) {
158-
final Icon icon = FlutterIconLineMarkerProvider.getMaterialIconFromCodepoint(UIUtils.findVisibleProject(), codePoint);
157+
final Icon icon = FlutterMaterialIcons.getIconForHex(String.format("%1$04x", codePoint));
159158
if (icon != null) {
160159
this.addIcon(icon);
161160
this.setIconOpaque(false);

flutter-idea/src/io/flutter/view/InspectorPanel.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import com.intellij.xdebugger.XSourcePosition;
2525
import io.flutter.FlutterBundle;
2626
import io.flutter.FlutterUtils;
27-
import io.flutter.editor.FlutterIconLineMarkerProvider;
2827
import io.flutter.editor.FlutterMaterialIcons;
2928
import io.flutter.inspector.*;
3029
import io.flutter.run.daemon.FlutterApp;
@@ -53,8 +52,6 @@
5352
import java.util.*;
5453
import java.util.concurrent.CompletableFuture;
5554

56-
import static io.flutter.utils.UIUtils.findVisibleProject;
57-
5855
public class InspectorPanel extends JPanel implements Disposable, InspectorService.InspectorServiceClient, InspectorTabPanel {
5956
/**
6057
* Maximum frame rate to refresh the inspector panel at to avoid taxing the
@@ -1348,7 +1345,7 @@ protected void customizeCellRenderer(JTable table, @Nullable Object value, boole
13481345
// IconData(U+0E88F)
13491346
final int codePoint = getIntProperty(properties, "codePoint");
13501347
if (codePoint > 0) {
1351-
final Icon icon = FlutterIconLineMarkerProvider.getMaterialIconFromCodepoint(UIUtils.findVisibleProject(), codePoint);
1348+
final Icon icon = FlutterMaterialIcons.getIconForHex(String.format("%1$04x", codePoint));
13521349
if (icon != null) {
13531350
this.setIcon(icon);
13541351
this.setIconOpaque(false);

0 commit comments

Comments
 (0)