Escrevendo plugins do IntelliJ IDEA

Escrevendo plugins do IntelliJ IDEA

*1. Introdução *

Nos últimos anos, IntelliJ do JetBrains tornou-se rapidamente o principal IDE para desenvolvedores de Java. Em nosso https://www..com/java-in-2018 [relatório do estado de Java] mais recente, o IntelliJ foi o IDE preferido por 55% dos entrevistados, contra 48% no ano anterior.

Um recurso que torna o IntelliJ tão atraente para os desenvolvedores Java é a capacidade de estender e criar novas funcionalidades usando plug-ins. Neste tutorial, veremos como escrever um plug-in IntelliJ para demonstrar algumas das maneiras de estender o IDE.

E observe que, embora este artigo seja focado nos plug-ins do IntelliJ, todos os IDEs do JetBrains compartilham código comum. Portanto,* muitas das técnicas usadas aqui podem ser aplicadas a outros IDEs do JetBrain *, como PyCharm, RubyMine e muito mais.

*2. Funcionalidade de plug-in *

A funcionalidade de plug-in para IntelliJ geralmente se enquadra em uma das 4 categorias:

  • Idiomas personalizados : a capacidade de escrever, interpretar e compilar código escrito em diferentes idiomas

  • Estruturas : suporte para estruturas de terceiros, como o Spring

  • Ferramentas : integração com ferramentas externas, como Gradle

  • Complementos da interface do usuário : novos itens de menu, janelas e botões de ferramentas e muito mais

Os plugins geralmente se enquadram em várias categorias. Por exemplo, o plugin Git fornecido com o IntelliJ, interage com o executável git instalado no sistema. O plug-in fornece sua janela de ferramenta e itens de menu pop-up, além de integrar-se ao fluxo de trabalho de criação de projeto, janela de preferências e muito mais.

*3. Criando um plug-in *

A maneira mais fácil de começar com os plug-ins do IntelliJ é usando o Plugin DevKit. Isso pode ser acessado no menu New> Project:

link:/wp-content/uploads/2018/08/intellij-plugin.jpg [imagem:/wp-content/uploads/2018/08/intellij-plugin.jpg [imagem, largura = 957, altura = 629]]

*Observe que devemos usar um JDK do JetBrains* para garantir que as classes de plug-in necessárias estejam disponíveis no caminho de classe. O IntelliJ deve vir com um JDK adequado por padrão, mas, se não, podemos fazer o download de https://bintray.com/jetbrains/intellij-jdk[here].

Até o momento em que escrevemos, podemos usar apenas o Java 8 para escrever plugins IntelliJ . Isso ocorre porque o JetBrains atualmente não fornece um JDK oficial para Java 9 ou superior.

*4. Exemplo de plug-in *

Para demonstrar a criação de um plug-in IntelliJ, criaremos um plug-in que fornece acesso rápido ao popular site Stack Overflow de várias áreas do IDE. Nós vamos adicionar:

  • Um item de menu Ferramentas para visitar a página Faça uma pergunta *Um item de menu pop-up no editor de texto e na saída do console para pesquisar o estouro de pilha em busca de texto destacado.

====* 4.1 Criando ações *

As ações são o componente principal usado para escrever os plugins do IntelliJ. As ações são acionadas por eventos no IDE, como clicar em um item de menu ou botão da barra de ferramentas.

A primeira etapa na criação de uma ação é criar uma classe Java que estenda AnAction. Para nosso plug-in Stack Overflow, criaremos 2 ações.

A primeira ação abre a página Faça uma pergunta em uma nova janela do navegador:

public class AskQuestionAction extends AnAction {
   @Override
   public void actionPerformed(AnActionEvent e) {
       BrowserUtil.browse("https://stackoverflow.com/questions/ask");
   }
}

Usamos a classe BrowserUtil incorporada porque ela lida com todas as nuances da abertura de uma página da web em diferentes sistemas operacionais e navegadores.

A segunda ação abre a página de pesquisa Estouro de pilha e passa o texto de pesquisa como uma sequência de consultas. Desta vez, implementaremos dois métodos.

O primeiro método que implementamos é exatamente como nossa primeira ação e trata da abertura de um navegador da web.

Primeiro, porém, precisamos coletar dois valores para o StackOverflow. Um é a etiqueta do idioma e o outro é o texto a ser pesquisado.

Para obter a tag de idioma, usaremos a Interface de estrutura do programa.* Esta API analisa todos os arquivos em um projeto e fornece uma maneira programática de inspecioná-los. *

Nesse caso, usamos o PSI para determinar a linguagem de programação de um arquivo:

PsiFile file = e.getData(CommonDataKeys.PSI_FILE);
Language lang = e.getData(CommonDataKeys.PSI_FILE).getLanguage();
String languageTag = "+[" + lang.getDisplayName().toLowerCase() + "]";

Observe que o PSI também fornece detalhes específicos do idioma sobre um arquivo. Por exemplo,* poderíamos usar o PSI para encontrar todos os métodos públicos em uma classe Java. *

Para obter o texto a ser pesquisado, usaremos o Editor API para recuperar o texto destacado na tela:

final Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
CaretModel caretModel = editor.getCaretModel();
String selectedText = caretModel.getCurrentCaret().getSelectedText();

Mesmo que essa ação seja a mesma para as janelas do editor e do console, o acesso ao texto selecionado funciona da mesma maneira.

Agora, podemos juntar tudo isso em uma declaração actionPerformed:

@Override
public void actionPerformed(AnActionEvent e) {

    PsiFile file = e.getData(CommonDataKeys.PSI_FILE);
    Language lang = e.getData(CommonDataKeys.PSI_FILE).getLanguage();
    String languageTag = "+[" + lang.getDisplayName().toLowerCase() + "]";

    Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
    CaretModel caretModel = editor.getCaretModel();
    String selectedText = caretModel.getCurrentCaret().getSelectedText()

    String query = selectedText.replace(' ', '+') + languageTag;
    BrowserUtil.browse("https://stackoverflow.com/search?q=" + query);
}

Essa ação também substitui um segundo método chamado update. Isso nos permite ativar ou desativar a ação sob diferentes condições.

Nesse caso, desabilitamos a ação de pesquisa quando não há texto selecionado:

@Override
public void update(AnActionEvent e) {
     Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
     CaretModel caretModel = editor.getCaretModel();
     e.getPresentation().setEnabledAndVisible(caretModel.getCurrentCaret().hasSelection());
}

====* 4.2 Registrando ações *

Depois de escrevermos nossas ações,* precisamos registrá-las no IDE *. Existem duas maneiras de fazer isso.

A primeira maneira é usar o arquivo plugin.xml, criado para nós quando iniciamos um novo projeto.

Por padrão, o arquivo terá um elemento _ <actions> _ vazio, que é onde adicionaremos nossas ações:

<actions>
    <action
      id="StackOverflow.AskQuestion.ToolsMenu"
      class="com..intellij.stackoverflowplugin.AskQuestionAction"
      text="Ask Question on Stack Overflow"
      description="Ask a Question on Stack Overflow">
        <add-to-group group-id="ToolsMenu" anchor="last"/>
    </action>
    <action
      id="StackOverflow.Search.Editor"
      class="com..intellij.stackoverflowplugin.SearchAction"
      text="Search on Stack Overflow"
      description="Search on Stack Overflow">
        <add-to-group group-id="EditorPopupMenu" anchor="last"/>
    </action>
    <action
      id="StackOverflow.Search.Console"
      class="com..intellij.stackoverflowplugin.SearchAction"
      text="Search on Stack Overflow"
      description="Search on Stack Overflow">
        <add-to-group group-id="ConsoleEditorPopupMenu" anchor="last"/>
    </action>
</actions>

O uso do arquivo XML para registrar ações garantirá que eles sejam registrados durante a inicialização do IDE, o que geralmente é preferível.

A segunda maneira de registrar ações é programaticamente usando a classe ActionManager:

ActionManager.getInstance().registerAction("StackOverflow.SearchAction", new SearchAction());

Isso tem a vantagem de nos permitir registrar ações dinamicamente. Por exemplo, se escrevermos um plug-in para integrar-se a uma API remota, convém registrar um conjunto diferente de ações com base na versão da API que chamamos.

A desvantagem dessa abordagem é que as ações não são registradas na inicialização. Temos que criar uma instância de ApplicationComponent para gerenciar ações, o que requer mais codificação e configuração XML.

*5. Testando o plug-in *

Como em qualquer programa, escrever um plugin IntelliJ requer teste. Para um plug-in pequeno como o que escrevemos, é suficiente garantir que o plug-in seja compilado e que as ações que criamos funcionem conforme o esperado quando clicamos neles.

Podemos testar manualmente (e depurar) nosso plug-in usando uma configuração de execução de plug-in:

link:/wp-content/uploads/2018/08/intellij-plugin-run-configuration.jpg [imagem:/wp-content/uploads/2018/08/intellij-plugin-run-configuration.jpg [imagem, largura = 680, altura = 486]]

Isso iniciará uma nova instância do IntelliJ com o nosso plugin ativado. Isso nos permite clicar nos diferentes itens de menu que criamos e garantir que as páginas de estouro de pilha adequadas sejam abertas.

Se você deseja fazer testes de unidade mais tradicionais, o IntelliJ fornece um ambiente sem cabeça para executar testes de unidade. Podemos escrever testes usando qualquer estrutura de teste que desejamos, e os testes são executados usando componentes reais e não desmontados do IDE.

===* 6. Implantando o plug-in *

O plugin DevKit fornece uma maneira simples de empacotar plugins para que possamos instalá-los e distribuí-los. Simplesmente clique com o botão direito do mouse no projeto do plug-in e selecione "Preparar o módulo do plug-in para implantação". Isso irá gerar um arquivo JAR dentro do diretório do projeto.

O arquivo JAR gerado contém os arquivos de código e configuração necessários para carregar no IntelliJ. Você pode instalá-lo localmente ou publicá-lo em um repositório de plugins para uso por outras pessoas.

A captura de tela abaixo mostra um dos novos itens de menu Estouro de pilha em ação:

link:/wp-content/uploads/2018/08/intellij-stackoverflow-pluginjpg.jpg [imagem:/wp-content/uploads/2018/08/intellij-stackoverflow-pluginjpg.jpg [imagem, largura = 728, altura = 295]]

===* 7. Conclusão*

Neste artigo, desenvolvemos um plug-in simples que destaca apenas algumas das maneiras de aprimorar o IDE do IntelliJ.

Enquanto trabalhamos principalmente com ações, o SDK do plugin IntelliJ oferece várias maneiras de adicionar novas funcionalidades ao IDE. Para uma leitura mais detalhada, consulte o guia oficial de primeiros passos.

Como sempre, o código completo do nosso exemplo de plug-in pode ser encontrado em nosso GitHub repositório.