1. 소개

지난 몇 년 동안  JetBrains의 IntelliJ  는 Java 개발자를 위한 최고의 IDE가 되었습니다. 가장 최근  의 Java 현황 보고서 에서 IntelliJ는 응답자의 61%가 선택한 IDE로 전년도의 55%에서 증가했습니다.

IntelliJ가 Java 개발자에게 매력적인 이유 중 하나는 플러그인을 사용하여 새로운 기능을 확장하고 생성할 수 있다는 것입니다.

이 예제에서는 IDE를 확장할 수 있는 몇 가지 방법을 보여주기 위해 Gradle과 함께 새로운 권장 방식을 사용하여 IntelliJ 플러그인을 작성하는 방법을 살펴보겠습니다. 이 문서는 Plugin Devkit을 사용하여 동일한 플러그인을 만드는 방법을 설명 하는 이전 문서를 리믹스한 것입니다.

2. 주요 플러그인 종류

가장 일반적인 유형의 플러그인에는 다음과 같은 기능이 포함됩니다.

  • 사용자 지정 언어 지원: 다른 언어로 작성된 코드를 작성, 해석 및 컴파일하는 기능
  • 프레임워크 통합: Spring과 같은 타사 프레임워크 지원
  • 도구 통합: Gradle과 같은 외부 도구와의 통합
  • 사용자 인터페이스 애드온: 새로운 메뉴 항목, 도구 창, 진행률 표시줄 등

플러그인은 종종 여러 카테고리로 분류됩니다 . 예를 들어  IntelliJ와 함께 제공 되는 Git 플러그인 은 시스템에 설치된 git 실행 파일과 상호 작용합니다. 플러그인은 도구 창과 팝업 메뉴 항목을 제공하는 동시에 프로젝트 생성 워크플로, 기본 설정 창 등에 통합됩니다.

3. 플러그인 만들기

플러그인을 생성하는 데 지원되는 두 가지 방법이 있습니다. Plugin Devkit 을 사용하는 대신 Gradle 을 사용 하는 새 프로젝트에 권장되는 방법을 사용합니다 .

Gradle 기반 플러그인 생성은 New > Project 메뉴를 사용하여 수행됩니다.

이미지 사진 2020-05-23

필요한 플러그인 클래스를 클래스 경로에서 사용할 수 있도록 하려면 Java 및 IntelliJ 플랫폼 플러그인을 포함 해야 합니다.

이 글을 쓰는 시점에서  우리는 IntelliJ 플러그인 작성에 JDK 8만 사용할 수 있습니다 .

4. 플러그인 예시

IDE의 여러 영역에서 인기 있는 Stack Overflow 웹 사이트에 빠르게 액세스할 수 있는 플러그인을 만들 것입니다. 다음이 포함됩니다.

  • 질문하기 페이지를 방문하기 위한 도구 메뉴 항목
  • 강조 표시된 텍스트에 대한 스택 오버플로를 검색하기 위한 텍스트 편집기 및 콘솔 출력의 팝업 메뉴 항목

4.1. 작업 만들기

작업은 플러그인에 액세스하는 가장 일반적인 방법 입니다. 작업은 메뉴 항목 또는 도구 모음 버튼 클릭과 같은 IDE의 이벤트에 의해 트리거됩니다.

작업을 만드는 첫 번째 단계는  AnAction 을 확장하는 Java 클래스를 만드는 것 입니다. Stack Overflow 플러그인의 경우 두 가지 작업을 만듭니다.

첫 번째 작업은 새 브라우저 창에서 질문하기 페이지를 엽니다.

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

내장된  BrowserUtil 클래스를 사용하여 다양한 운영 체제 및 브라우저에서 웹 페이지를 여는 모든 미묘한 차이를 처리합니다.

StackOverflow에서 검색을 수행하려면 언어 태그와 검색할 텍스트라는 두 가지 매개변수가 필요합니다.

언어 태그를 얻기 위해  프로그램 구조 인터페이스 (PSI)를 사용합니다. 이 API는 프로젝트의 모든 파일을 구문 분석하고 프로그래밍 방식으로 검사할 수 있는 방법을 제공합니다.

이 경우 PSI를 사용하여 파일의 프로그래밍 언어를 결정합니다.

Optional<PsiFile> psiFile = Optional.ofNullable(e.getData(LangDataKeys.PSI_FILE));
String languageTag = psiFile.map(PsiFile::getLanguage)
  .map(Language::getDisplayName)
  .map(String::toLowerCase)
  .map(lang -> "[" + lang + "]")
  .orElse("");

검색할 텍스트를 얻기 위해  Editor  API를 사용하여 화면에서 강조 표시된 텍스트를 검색합니다.

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

이 작업은 편집기 창과 콘솔 창 모두에서 동일하지만 선택한 텍스트에 액세스하는 것은 동일한 방식으로 작동합니다.

이제 actionPerformed  선언 에 이 모든 것을 함께 넣을 수 있습니다  .

@Override
public void actionPerformed(@NotNull AnActionEvent e) {
    Optional<PsiFile> psiFile = Optional.ofNullable(e.getData(LangDataKeys.PSI_FILE));
    String languageTag = psiFile.map(PsiFile::getLanguage)
      .map(Language::getDisplayName)
      .map(String::toLowerCase)
      .map(lang -> "[" + lang + "]")
      .orElse("");

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

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

이 작업은 다른 조건에서 작업을 활성화하거나 비활성화할 수 있는 update 라는 두 번째 메서드를 재정의합니다  . 이 경우 선택한 텍스트가 없으면 검색 작업을 비활성화합니다.

Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
CaretModel caretModel = editor.getCaretModel();
e.getPresentation().setEnabledAndVisible(caretModel.getCurrentCaret().hasSelection());

4.2. 액션 등록

작업을 작성했으면  IDE에 등록해야 합니다 . 두 가지 방법이 있습니다.

첫 번째 방법은   새 프로젝트를 시작할 때 생성되는 plugin.xml 파일을 사용하는 것입니다.

기본적으로 파일에는 작업을 추가할 빈 <actions> 요소가 있습니다.

<actions>
    <action
      id="StackOverflow.AskQuestion.ToolsMenu"
      class="com.baeldung.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.baeldung.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.baeldung.intellij.stackoverflowplugin.SearchAction"
      text="Search on Stack Overflow"
      description="Search on Stack Overflow">
        <add-to-group group-id="ConsoleEditorPopupMenu" anchor="last"/>
    </action>
</actions>

XML 파일을 사용하여 작업을 등록하면 IDE 시작 중에 등록되며 일반적으로 선호됩니다.

액션을 등록하는 두 번째 방법은 프로그래밍 방식으로  ActionManager  클래스를 사용하는 것입니다.

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

이렇게 하면 동적으로 작업을 등록할 수 있다는 이점이 있습니다. 예를 들어 원격 API와 통합하기 위해 플러그인을 작성하는 경우 호출하는 API 버전에 따라 다른 작업 집합을 등록할 수 있습니다.

이 접근 방식의 단점은 시작 시 작업이 등록되지 않는다는 것입니다.  더 많은 코딩과 XML 구성이 필요한 액션을 관리하기 위해 ApplicationComponent 인스턴스를 생성  해야 합니다.

5. 플러그인 테스트

다른 프로그램과 마찬가지로 IntelliJ 플러그인을 작성하려면 테스트가 필요합니다. 우리가 작성한 것과 같은 작은 플러그인의 경우 플러그인이 컴파일되고 우리가 만든 작업이 클릭할 때 예상대로 작동하는지 확인하는 것으로 충분합니다.

Gradle 도구 창을 열고 runIde 작업 을 실행하여 플러그인을 수동으로 테스트(및 디버그)할 수 있습니다 .

이미지 사진 2020-05-25

이렇게 하면 플러그인이 활성화된 IntelliJ의 새 인스턴스가 시작됩니다. 그렇게 하면 우리가 만든 다른 메뉴 항목을 클릭하고 적절한 스택 오버플로 페이지가 열리는지 확인할 수 있습니다.

보다 전통적인 단위 테스트를 수행하려는 경우 IntelliJ는  단위 테스트를 실행할 수 있는 헤드리스 환경 을 제공합니다. 우리는 원하는 테스트 프레임워크를 사용하여 테스트를 작성할 수 있으며 테스트는 IDE에서 모킹되지 않은 실제 구성 요소를 사용하여 실행됩니다.

6. 플러그인 배포

Gradle 플러그인은 설치 및 배포가 가능하도록 플러그인을 패키징하는 간단한 방법을 제공합니다. Gradle 도구 창을 열고 buildPlugin 작업을 실행하기만 하면 됩니다. 이렇게 하면 build/distributions 디렉터리 내에 ZIP 파일이 생성됩니다.

생성된 ZIP 파일에는 IntelliJ에 로드하는 데 필요한 코드 및 구성 파일이 포함되어 있습니다. 로컬에 설치하거나 다른 사람이 사용할 수 있도록 플러그인 저장소  에 게시할 수 있습니다.

아래 스크린샷은 작동 중인 새로운 스택 오버플로 메뉴 항목 중 하나를 보여줍니다.

Bildschirmfoto-2020-05-25

7. 결론

이 기사에서는 IntelliJ IDE를 개선할 수 있는 방법을 강조하는 간단한 플러그인을 개발했습니다.

우리는 주로 액션으로 작업하지만 IntelliJ 플러그인 SDK는 IDE에 새로운 기능을 추가하는 여러 가지 방법을 제공합니다. 자세한 내용은 공식 시작 사용방법(예제) 를 확인하세요 .

항상 그렇듯이 샘플 플러그인의 전체 코드는 GitHub 에서 찾을 수 있습니다 .

Generic footer banner