[JAVA] J'ai créé un plug-in pour IntelliJ IDEA

Cet article "Calendrier de l'Avent DeNA IP Platform Division 2017" Ceci est l'article du 19ème jour.

Dans mon équipe, tous les ingénieurs côté serveur codent à l'aide d'IntelliJ IDEA. Récemment, je me suis soudainement demandé "Comment créer un plug-in IntelliJ IDEA?", Et pendant mes études, j'ai essayé de créer quelque chose comme une mascotte de bureau qui apparaît sur l'IDE, alors j'aimerais résumer le flux.

Ce que j'ai fait

Lorsque vous démarrez l'IDE, d'étranges créatures apparaîtront. Au fur et à mesure que vous codez, les valeurs d'expérience (Exp) s'accumulent. (Je voulais ajouter une fonction qui prend en charge le codage un peu plus, mais ce n'est pas grave) movie.gif

Environnement

IntelliJ IDEA est requis pour créer un plug-in. (L'édition communautaire est également acceptable) Il semble qu'il sera plus facile de déboguer pendant le développement du plug si le code source d'IntelliJ IDEA Community Edition est également supprimé, mais je ne l'ai pas utilisé cette fois. La procédure détaillée est décrite dans le Document officiel, je vais donc l'omettre.

J'essaierai de le faire pour le moment

Nouveau projet

[Fichier> Nouveau projet> Plugin de plateforme IntelliJ> Suivant] sur IntelliJ IDEA Donnez au nom du projet un nom approprié. (Cette fois, c'est Nunyu) new_project1.png

Faire un composant

Les trois types de composants suivants sont à la base du plug-in.

Cette fois, je veux que la mascotte apparaisse tout le temps dans les projets lorsque l'EDI démarre, donc je vais la créer avec le composant de niveau Application. Vous pouvez en créer un nouveau en cliquant avec le bouton droit sur le panneau Projet et en sélectionnant [Nouveau> Plugin DevKit> Composant d'application]. Le nom du composant est "Nunyu". new_component.png

Assurez-vous que cela fonctionne

En fait, le plug-in fonctionne maintenant sur l'IDE! Processus d'initialisation des composants Déconnectons-nous et exécutons-le avec ʻinitComponent`.

src/Nunyu.java


import com.intellij.openapi.diagnostic.Logger;
    ...
    @Override
    public void initComponent() {
        Logger.getInstance(Nunyu.class).info("Nunyu");
    }
    ...

Pour l'exécuter, sélectionnez [Exécuter> Déboguer] dans le menu. Ensuite, un autre IntelliJ IDEA sera lancé et le plug-in s'y exécutera. Et vous pouvez voir qu'il y a un message dans la console de débogage. debug.png

Essayez d'afficher la mascotte

Appeler JWindow

Laissez le composant hériter de JWindow pour afficher la fenêtre lors de l'initialisation et rendre l'image. Il s'agit de "Swing".

src/Nunyu.java


import com.intellij.openapi.components.ApplicationComponent;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Nunyu extends JWindow implements ApplicationComponent {
    private Image image;
    private ImagePanel imagePanel;

    public Nunyu() {
    }

    @Override
    public void initComponent() {
        initWindow();
        makeDraggable();
    }

    public void initWindow() {
        image = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/images/nunyu-alpha.png "));

        setSize(100, 100);
        setAlwaysOnTop(true);
        setBackground(new Color(1, 0, 0, 0));

        imagePanel = new ImagePanel();
        add(imagePanel);

        setVisible(true);
    }
    
    public void makeDraggable() {
        final Point startPos = new Point();
        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                startPos.setLocation(e.getPoint());
            }
        });
        addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                setLocation(e.getXOnScreen() - startPos.x, e.getYOnScreen() - startPos.y);
            }
        }); 
    }

    public class ImagePanel extends JPanel {
        public ImagePanel() {
            setOpaque(false);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(image, 0, 0, this);
        }

    }

    @Override
    public void disposeComponent() {
        // TODO: insert component disposal logic here
    }

    @Override
    @NotNull
    public String getComponentName() {
        return "Nunyu";
    }
}

nunyu-alpha.png

Maintenant, lorsque vous l'exécutez, vous verrez les mascottes que vous pouvez faire glisser! show1.png

Masquer la mascotte lorsque l'EDI est inactif

À ce rythme, même si l'EDI perd le focus, la mascotte restera affichée en haut et ne disparaîtra pas. C'est ennuyant. Ainsi, lorsque l'EDI perd le focus, j'ajouterai un processus pour effacer la mascotte en même temps.

src/Nunyu.java


    @Override
    public void initComponent() {
        initWindow();
        setupFocusEvent();
    }
    ...
    public void setupFocusEvent() {
        WindowManager.getInstance().addListener(new WindowManagerListener() {
            @Override
            public void frameCreated(IdeFrame frame) {
                WindowManager.getInstance().getFrame(frame.getProject()).addWindowFocusListener(new WindowFocusListener() {
                    @Override
                    public void windowGainedFocus(WindowEvent e) {
                        setVisible(true);
                    }

                    @Override
                    public void windowLostFocus(WindowEvent e) {
                        if (e.getOppositeWindow() == null) {
                            setVisible(false);
                        }
                    }
                });
            }

            @Override
            public void beforeFrameReleased(IdeFrame frame) {
            }
        });
    }

Ajoutez un écouteur WindowManagerListener et ajoutez un WindowFocusListener à cette fenêtre chaque fois qu'une image est créée sur l'EDI. Dans cet écouteur, implémentez windowGainedFocus, qui se déclenche lorsque la fenêtre obtient le focus, et windowLostFocus, qui se déclenche lorsque la fenêtre perd le focus. Je veux afficher la mascotte lorsque la fenêtre de l'EDI obtient le focus, donc je peux appeler setVisible (true). Inversement, si vous perdez le focus, vous pouvez utiliser ʻe.getOppositeWindow () pour obtenir la fenêtre qui sera le prochain focus, mais si c'est null, l'EDI n'aura pas le focus, donc setVisible Appel (faux) `.

Donner de l'expérience à la mascotte

Séquence de touches de l'éditeur de crochet

Maintenant, la prochaine fois que je coderai dans l'éditeur, j'essaierai de donner une valeur à l'expérience de la mascotte. Cela nécessite des frappes de l'éditeur de hook, mais étendons ʻeditorTypedHandler` pour y parvenir.

src/MyTypedHandler.java


import com.intellij.codeInsight.editorActions.AutoFormatTypedHandler;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actionSystem.TypedActionHandler;
import org.jetbrains.annotations.NotNull;

public class MyTypedHandler extends AutoFormatTypedHandler {
    public MyTypedHandler(TypedActionHandler originalHandler) {
        super(originalHandler);
    }

    @Override
    public void execute(@NotNull Editor editor, char charTyped, @NotNull DataContext dataContext) {
        super.execute(editor, charTyped, dataContext);
        Logger.getInstance(Nunyu.class).info("Typed: " + charTyped);
    }
}

resources/META-INF/plugin.xml


  ...
  <extensions defaultExtensionNs="com.intellij">
    <editorTypedHandler implementationClass="MyTypedHandler"/>
  </extensions>
  ...

Lorsqu'un caractère est saisi dans l'éditeur, ʻexecute () est appelé. Essayez de sortir la touche enfoncée dans le journal en appelant super.execute ()telle quelle pour ne pas changer le comportement par défaut. Essayez de l'exécuter maintenant et modifiez quelque chose sur l'EDI qui se lance. Vous pouvez voir que la clé que vous avez saisie apparaît dans le journal d'informations. Voici comment accrocher cette clé, mais il semble que [il y a aussi un moyen d'utiliserTypedHandlerDelegate`](https://qiita.com/shiraji/items/5a7a1654dc7b6da20a60), mais quand je l'ai essayé, je l'ai essayé dans l'IDE. Lorsque la fenêtre contextuelle de saisie semi-automatique est sortie, il semblait que l'événement ne se reproduirait pas, donc cela n'a pas fonctionné. (Honnêtement, je ne sais pas quelle est la bonne réponse.)

Persister les données

Même si je peux donner l'expérience de la mascotte, il est triste qu'elle soit réinitialisée lorsque l'EDI est redémarré. Alors, rendons possible de rendre permanente la valeur d'expérience donnée ensuite. Utilisez PersistentStateComponent pour conserver les données dans le plug-in.

src/MyService.java


import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;

@State(
        name = "MyService",
        storages = {
                @Storage("nunyu.xml"),
        }
)

class MyService implements PersistentStateComponent<MyService.State> {
    static class State {
        public Integer exp = 0;
    }

    State myState;

    public MyService() {
        this.myState = new State();
    }

    public State getState() {
        return myState;
    }

    public void loadState(State state) {
        myState = state;
    }

    public static MyService getInstance() {
        return ServiceManager.getService(MyService.class);
    }
}

J'ai implémenté une boîte qui a simplement l'entier ʻexp. Vous pouvez définir la destination à conserver avec l'annotation @ State`.

N'oubliez pas non plus de mentionner dans plugin.xml pour utiliser ce service.

resources/META-INF/plugin.xml


  ...
  <extensions defaultExtensionNs="com.intellij">
    <applicationService serviceInterface="MyService" serviceImplementation="MyService"/>
  </extensions>
  ...

Enregistrez-vous en tant que ʻapplicationServicecar il sera utilisé par les composants au niveau de l'application. Notez qu'il existe d'autresprojectService`, etc.

Relier

Tout d'abord, commençons par afficher la valeur d'expérience à l'écran. Réécrivez la méthode paintComponent () de la classe ʻImagePanel pour afficher le ʻexp de MyService. Préparez également la méthode repaint ()` afin de pouvoir redessiner à chaque fois que la valeur d'expérience augmente.

src/Nunyu.java


    ...
    public void repaint() {
        imagePanel.repaint();
    }
    ...
    public class ImagePanel extends JPanel {
        ...
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(image, 0, 0, this);

            g.drawString("Exp. " + MyService.getInstance().myState.exp, 0, 10);
        }
    }
    ...

Ensuite, écrivez un processus pour augmenter la valeur d'expérience au moment de la saisie clé et du redessiner.

src/MyService.java


    ...
    public void increment() {
        myState.exp++;
    }
    ...

src/MyTypedHandler.java


    ...
    @Override
    public void execute(@NotNull Editor editor, char charTyped, @NotNull DataContext dataContext) {
        super.execute(editor, charTyped, dataContext);
        ServiceManager.getService(MyService.class).increment();
        ApplicationManager.getApplication().getComponent(Nunyu.class).repaint();
    }
    ...

C'est tout. Au fur et à mesure que vous codez, votre expérience augmentera régulièrement!

finalement

Au fait, j'ai créé un plug-in qui ne servait à rien (rires), mais en procédant par essais et erreurs, j'ai en quelque sorte compris quelque chose comme comment créer un plug-in. Il était assez difficile de trouver des informations dans les documents, et je n'ai rien trouvé du genre "Que dois-je faire quand je veux faire quelque chose comme ça?!", Et même une si simple était très difficile. Il existe de nombreux plug-ins sur le marché, vous pouvez donc y rechercher du code utile, ou Rechercher dans la communauté. community & topic = 20036979 & utf8 =% E2% 9C% 93) et vous pouvez ou non trouver les informations que vous recherchez! Cet article était la fin d'une lutte, mais si vous avez des suggestions, veuillez commenter.

Recommended Posts

J'ai créé un plug-in pour IntelliJ IDEA
J'avais des problèmes au travail, j'ai donc créé un plug-in IntelliJ
J'ai créé un outil Diff pour les fichiers Java
J'ai créé une image Docker pour la version japonaise de SDAPS
J'ai créé un outil de vérification pour le module de version
J'ai fait une méthode pour demander la prime vendredi
J'ai créé un client API THETA qui peut être utilisé pour le développement de plugins
J'ai créé une application de chat.
J'ai créé une bibliothèque pour afficher des tutoriels sur Android.
J'ai créé un plug-in qui exécute jextract avec des tâches Gradle
J'ai créé une application shopify @java
J'ai créé une interface graphique avec Swing
J'ai fait une simple fonction de recommandation.
J'ai créé une application correspondante (application Android)
J'ai créé un outil de génération package.xml.
[Android] J'ai créé une application de podomètre.
J'ai créé une interface de ligne de commande avec WinMerge Plugin en utilisant JD-Core
J'ai posé une question qui peut être utilisée pour des entretiens techniques
Création d'une méthode pour demander Premium Friday (version Java 8)
J'ai créé une fonction de réponse pour l'extension Rails Tutorial (Partie 5):
[Ruby] J'ai créé un simple client Ping
IntelliJ IDEA Fonction pratique pour les débutants (importance ★ 4)
J'ai fait une méthode pour le vendredi premium avec une doublure
J'ai fait une mort risquée avec Ruby
J'ai créé une application Janken avec kotlin
J'ai créé une application de calculatrice sur Android
J'ai créé un nouvel outil de déploiement Java
IntelliJ IDEA Fonction pratique pour les débutants (importance ★ 5)
J'ai créé une application Janken avec Android
À propos du débogueur de flux du plugin IntelliJ IDEA
J'ai créé une fonction de réponse pour l'extension Rails Tutorial (Partie 2): Changer de modèle
J'ai créé un programme de jugement des nombres premiers en Java
04. J'ai fait un frontal avec SpringBoot + Thymeleaf
J'ai fait de l'art de la mosaïque avec des images Pokemon
J'ai créé une application par moi-même! (Application de gestion de la lecture)
J'ai créé une application Android pour le service MiRm
J'ai créé un jeu Janken en Java (CLI)
J'ai créé une application de visualisation qui affiche le PDF
J'ai créé un conteneur Docker pour exécuter Maven
J'ai créé une bibliothèque d'extension Ruby en C
J'ai créé un client API pour Nature Remo
J'ai créé une bibliothèque de graphiques simple pour les applications de smartphone [MP Android Chart Kai]
J'ai créé un robot LINE avec Rails + heroku
Paramètres IntelliJ IDEA
J'ai essayé d'utiliser le profileur d'IntelliJ IDEA
J'ai fait un portfolio avec Ruby On Rails
Notez que j'étais accro aux paramètres du projet Android d'IntelliJ IDEA
J'ai fait un jeu de problèmes de calcul simple en Java
[Ruby] J'ai fait un robot avec de l'anémone et du nokogiri.
J'ai essayé le nouveau profileur de fonctionnalités d'IntelliJ IDEA 2019.2.
J'ai fait un chat de dessin "chat de peinture 8 bits" avec WebAssembly
J'ai essayé d'installer le plug-in d'intégration Docker dans IntelliJ
J'ai créé un serveur et un client Restful au printemps.
J'ai créé une bibliothèque qui fonctionne comme un onglet dans Safari !!
J'ai créé un Wrapper qui appelle KNP depuis Java
Je souhaite créer une annotation générique pour un type
[Java] Une technique pour écrire des constructeurs, des getters et des setters d'un seul coup avec IntelliJ IDEA.
J'ai créé une fonction de réponse pour l'extension Rails Tutorial (Partie 4): une fonction qui rend l'utilisateur unique