Skip to content

Migrate the FlutterSampleNotificationProvider to the new EditorNotificationProvider API (#7840) #7842

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 0 additions & 40 deletions flutter-idea/src/io/flutter/samples/FlutterSampleActionsPanel.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,87 +6,99 @@
package io.flutter.samples;

import com.google.common.annotations.VisibleForTesting;
import com.intellij.ide.BrowserUtil;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.colors.EditorColors;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.TextEditor;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.ui.EditorNotificationPanel;
import com.intellij.ui.EditorNotifications;
import com.intellij.ui.EditorNotificationProvider;
import com.intellij.ui.HyperlinkLabel;
import com.jetbrains.lang.dart.psi.DartClass;
import icons.FlutterIcons;
import io.flutter.sdk.FlutterSdk;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.regex.Pattern;

public class FlutterSampleNotificationProvider extends EditorNotifications.Provider<EditorNotificationPanel> implements DumbAware {
private static final Key<EditorNotificationPanel> KEY = Key.create("flutter.sample");

public class FlutterSampleNotificationProvider implements EditorNotificationProvider {
@NotNull final Project project;

public FlutterSampleNotificationProvider(@NotNull Project project) {
this.project = project;
}

@NotNull
@Override
public Key<EditorNotificationPanel> getKey() {
return KEY;
}

@Nullable
@Override
public EditorNotificationPanel createNotificationPanel(@NotNull VirtualFile file,
@NotNull FileEditor fileEditor,
@NotNull Project project) {
if (!(fileEditor instanceof TextEditor textEditor)) {
return null;
}

public Function<? super @NotNull FileEditor, ? extends @Nullable JComponent> collectNotificationData(@NotNull Project project,
@NotNull VirtualFile file) {
final FlutterSdk sdk = FlutterSdk.getFlutterSdk(project);
if (sdk == null) {
return null;
}

final String flutterPackagePath = sdk.getHomePath() + "/packages/flutter/lib/src/";
final String filePath = file.getPath();

// Only show for files in the flutter sdk.
final String filePath = file.getPath();
if (!filePath.startsWith(flutterPackagePath)) {
return null;
}

return fileEditor -> createPanelForSamples(fileEditor, project, file, filePath, sdk, flutterPackagePath);
}

@Nullable
private EditorNotificationPanel createPanelForSamples(@NotNull FileEditor fileEditor,
@NotNull Project project,
@NotNull VirtualFile file,
@NotNull String filePath,
@NotNull FlutterSdk sdk,
@NotNull String flutterPackagePath) {
if (!(fileEditor instanceof TextEditor textEditor)) {
return null;
}

final Editor editor = textEditor.getEditor();
final Document document = editor.getDocument();
final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project);
if (psiDocumentManager == null) {
return null;
}

final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document);
final PsiFile psiFile = psiDocumentManager.getPsiFile(document);
if (psiFile == null || !psiFile.isValid()) {
return null;
}

// Run the code to query the document in a read action.
final List<FlutterSample> samples = ApplicationManager.getApplication().
runReadAction((Computable<List<FlutterSample>>)() -> {
//noinspection CodeBlock2Expr
return getSamplesFromDoc(flutterPackagePath, document, filePath);
});

return samples.isEmpty() ? null : new FlutterSampleActionsPanel(samples);
if (samples != null && !samples.isEmpty()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can samples be null here or can you skip this check? (It looks like getSamplesFromDoc at worst returns an empty list?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ApplicationManager.getApplication() and runReadAction can actually be null, hence this check.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! So maybe this is new Java. I would have expected ApplicationManager.getApplication(). runReadAction to throw an NPE if getApplication returns null, but cool!

return new FlutterSampleActionsPanel(samples);
}
return null;
}

private List<FlutterSample> getSamplesFromDoc(String flutterPackagePath, Document document, String filePath) {
@NotNull
private List<FlutterSample> getSamplesFromDoc(@NotNull String flutterPackagePath, @NotNull Document document, @NotNull String filePath) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you mark this @NotNull?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

final List<FlutterSample> samples = new ArrayList<>();

// Find all candidate class definitions.
Expand All @@ -111,7 +123,8 @@ private List<FlutterSample> getSamplesFromDoc(String flutterPackagePath, Documen
try {
// Context: https://github.com/flutter/flutter-intellij/issues/5634
dartdoc = DartDocumentUtils.getDartdocFor(document, declaration);
}catch (IndexOutOfBoundsException e) {
}
catch (IndexOutOfBoundsException e) {
// ignore
}
if (dartdoc != null && containsDartdocFlutterSample(dartdoc)) {
Expand All @@ -127,7 +140,6 @@ private List<FlutterSample> getSamplesFromDoc(String flutterPackagePath, Documen
}
}
}

return samples;
}

Expand All @@ -153,3 +165,28 @@ public static boolean containsDartdocFlutterSample(@NotNull List<String> lines)
return false;
}
}

class FlutterSampleActionsPanel extends EditorNotificationPanel {
FlutterSampleActionsPanel(@NotNull List<FlutterSample> samples) {
super(EditorColors.GUTTER_BACKGROUND);

icon(FlutterIcons.Flutter);
text("View example on flutter.dev");

for (int i = 0; i < samples.size(); i++) {
if (i != 0) {
myLinksPanel.add(new JSeparator(SwingConstants.VERTICAL));
}

final FlutterSample sample = samples.get(i);

final HyperlinkLabel label = createActionLabel(sample.getClassName(), () -> browseTo(sample));
label.setToolTipText(sample.getHostedDocsUrl());
}
}

private void browseTo(FlutterSample sample) {
BrowserUtil.browse(sample.getHostedDocsUrl());
}
}

Loading