PlantUMLのsyntaxもサポートしたエディター機能付きのIntelliJ Pluginを作ってみた


PlantUMLのsyntaxもサポートしたエディター機能付きのIntelliJ Pluginを作ったので、機能の紹介と、ニッチではあると思いますが開発で得た知見をまとめてみました。

また有料プラグインとして出していまして今後もアクティブに開発を進めていく予定ですので、フィードバックをいただけるととても嬉しいです。
https://plugins.jetbrains.com/plugin/14821-plantuml-studio

# 機能紹介

editorの部分はsyntax highlightやcompletionなど、通常の言語に付いている機能を出来るだけPlantUMLにも対応させました。
図を表示させる部分は既存の[PlantUML Integratoin](https://plugins.jetbrains.com/plugin/7017-plantuml-integration)の機能を踏襲しつつ、
project内のPlantUML fileを閲覧できるviewerを実装しました。

## editor

### syntax highlight

![スクリーンショット 2020-08-11 9.04.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122818/9d0c8ae8-6c8a-b776-8ff3-4185dd92a67c.png)

クラス図など各図ごとに構文解析を定義していて、現状対応しているのは、シーケンス図, ユースケース図, クラス図, オブジェクト図, アクティビティ図（new version）, コンポーネント図, ステート図です。
対応できていないその他の図は今後対応を進めていく予定です。

### completion

静的な `class` , `object` のようなキーワードと、動的なidentifierのcompletionに対応しています。

![completion.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122818/663e819c-4281-86a6-87df-4147c520913e.gif)


### refactor

identifierのrenameができます。

![refactor.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122818/09acdeac-5a8e-5af5-3bd3-fd81972e3a47.gif)


### code formatting

{} などのブロック構文を入力する際に自動インデントに対応しています。
![indent.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122818/83256283-c5e2-dcf9-ac69-ee324eaa85c4.gif)

また、メニューの「Code」> 「Reformat Code」による一括変換にも対応しています。

![code formatting.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122818/46a9f435-ea05-b119-6c68-9da0849e2ca3.gif)


### anto inserting

blockの入力をスムーズにするために、blockのend tokenの自動入力に対応しています。
![end_token_auto_inserting.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122818/d030eade-42a2-789c-8bf0-8ebe87658252.gif)

## file viewer

自分がproject内にドキュメントとしてPlantUMLのコードを置く運用をしていて、
PlantUMLのfileの一覧を眺めるような機能が欲しかったので簡易的ではありますが作ってみました。

![file viewer.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122818/ddf59944-9619-cba4-2b14-58c35c271a80.gif)


# 制作過程

ニッチな分野ですが、IntelliJ pluginの開発に興味がある人やpluginの動作の仕組みを知りたい方に向けて制作過程と、そこから得た知見を書いてみようと思います。

## PlantUML Studioの開発着手にいたるまで

### 事始め

今年の初めあたりから個人開発者というキャリアに興味を持って、何か良いアイデアがないかを考え始めました。

開発する対象として、何か自分の身近にある課題を解消するものが良いと思い、考えてみたところ、
直近の自分の大きな課題として、 `集中してプログラミングをすると頭が疲れてきてパフォーマンスが落ちる` という課題があり、これを何かしら少しでも解消するものはないか、と考え始めました。

この課題を掘り下げるために、直近の取り組んだタスクを分析して、どういうステップで頭が疲れるのかを考えてみたり、認知負荷についての本を読んでみたり、右往左往していたところ、「この課題に取り組んでいるのはIDEだ！」と気づきました。

そこで、IntelliJのblogを漁っていた時に、2019年からpluginのmarketplaceをリリースしていることを知りました。
他に具体的なアイデアもなく、Plugin Markertplaceなら個人開発者としてネックだなと感じていたお金を払ってもらう部分をIntelliJのライセンスプラットフォームに乗っかることができるという具体的なメリットもあったので、一旦Pluginの開発に絞ってアイデアを検討してみることにしました。

### IntelliJ Plugin開発の勉強

IntelliJ Plugin開発に関する知識がゼロからのスタートだったので、まずは[公式サイト](https://jetbrains.org/intellij/sdk/docs/intro/welcome.html)を眺めてみることに。
情報量が多くて困惑していたところ、[チュートリアル](https://jetbrains.org/intellij/sdk/docs/tutorials/action_system/working_with_custom_actions.html)があったので、まずは手元で動かしてみることに。

チュートリアルを手元で動かしてみることで、最低限の動作をさせるのに必要な設定とコードが解り、Plugin開発の理解が少し進みました。

**IntelliJ Plugin開発の導入としては最新バージョンのPlugin SDKで最低限の機能で手元で動かすのをお勧めします**
**また、公式サイトの情報はやはり丁寧に書かれていて価値が高いので、一通りざっと目を通して、どのあたりにどんな内容が書いてあるかを把握しておくと良いと思います**

### 知見を得るためのCode Reading Noteの開発

IntelliJ Pluginの開発の勉強と並行して、何を作るかのアイデアを検討していてその結果、下記の2つを作ってみることに決めました。

- コードを読んで理解したことをコードの近くにメモしておけるもの `Code Reading Note`
    - プログラミングで頭が疲れる課題からの発想
    - コードを読んで理解する作業は結構頭を使っている気がする
    - 一度理解したことをメモしておらず、何度も同じことを繰り返していることがある気がする
    - 理解したことをコードの近くにメモしておけるようになっていれば良いのでは？
- PlantUMLのsyntaxもサポートしたエディター機能付きのインテグレーション `PlantUML Studio`
    - 現状syntaxをサポートしたエディター機能付きのものはない
    - PlantUML自体はすでに結構ニーズがあり、既存のPlugin [PlantUML Integration](https://plugins.jetbrains.com/auth#access_token=1597213626551.6ee795af-5472-40b9-b586-e882ffbff43d.63993070-b5d0-4c93-9bae-350b85a35e69.0-0-0-0-0%3B1.MC0CFQCO7hwiVI5NzpsDgBe2tzbMGINfwwIUH84WS7Y2NN%2FaZI15jd%2BALJ%2BwSEk%3D&token_type=Bearer&expires_in=3600&scope=0-0-0-0-0&state=eed0994e-757e-4ed6-9df8-bcf7cdd24b47)のDL数もかなり多い
    - これが実現できれば解りやすい価値が作れるのでは？

プロダクトとして需要がありそうなのはPlantUML Studioかなと思いつつ、開発の難易度が高そうだったので、まずはCode Reading Noteを作りながら開発の知見を貯めていこうという方針で行くことに。

（ちなみにCode Reading Noteは[こちら](https://plugins.jetbrains.com/plugin/14068-code-reading-note)で公開しています。）

Code Reading Noteは比較的簡単そうとはいえ、チュートリアルからのギャップが大きくどこから手をつけて良いか解らない状態に。。

そこで、Code Reading Noteの発想の元でもある、[ビルドインのBookmark機能](https://www.jetbrains.com/help/rider/Navigation_and_Search__Bookmarks.html#66138)のコードを模写してみることに。

ちなみにIntelliJのコードはOSSとして公開されています。
https://github.com/JetBrains/intellij-community

Bookmark機能を模写してみることで、Code Reading Noteを実装する上でのIntelliJ API上の主要なクラスや基本的な使い方が解り、開発の取っ掛かりを掴むことが出来ました。

**自分が作ろうとしているPluginの似たようなジャンルのPluginのOSSがあれば、ストックしておいていつでも見れるようにしておくと良いと思います（IntelliJ コア部分のコードとPluginのコードは使用できるAPIが若干違ったりするので、PluginのOSSの方が直接的に参考にできるのでお勧めです）**

Bookmark機能の模写により開発のとっかかりは掴めたものの、馴染みのないプラットフォーム上での開発でかなり苦労しましたが、
公式ドキュメントやコードや開発コミュニティを行ったり来たりしながらなんとか形にすることが出来ました。

[開発コミュニティ](https://intellij-support.jetbrains.com/hc/en-us/community/topics/200366979-IntelliJ-IDEA-Open-API-and-Plugin-Development)は現在は[slack](https://plugins.jetbrains.com/slack?_ga=2.259457740.714264234.1597203027-441154740.1595328042&_gac=1.187486682.1596508262.Cj0KCQjw6575BRCQARIsAMp-ksMZsWO84IB-go8pt4CoRC5744iqvTanxgsEDih7PGE3FUw40j4v9mwaAlVNEALw_wcB)に移行していて、質問する場所としては機能していなそうですが、過去の知見が溜まっているので、何か困ったらキーワード検索をしてみる価値はあると思います。

ただ検索機能が乏しいのと、解決していないスレッドもたくさんあるので期待値は低めで使用するのが良さそうに思います。

何か困った時に一番役に立ったのはコードを読むことでした。
コード内のコメントも結構書かれています。（ex: [FileEditorManager](https://github.com/JetBrains/intellij-community/blob/master/platform/core-api/src/com/intellij/openapi/fileEditor/FileDocumentManager.java)）

コードベースのボリュームが大きいのでどこから読んで良いか難しいと思いますが、チュートリアルや模写などで使用したクラスの定義元にjumpしてみて、同じパッケージにどういったクラスがあるかをざっと眺めてみてみると良いかもしれません。

また、 `**Util`系のクラスはAPIとしても便利ですし、コードを読むと関連するクラスの使い方が解るので、調べているクラスのパッケージ周辺にUtil系のクラスがないか探してみると良いかもしれません。（ex: [VfsUtil](https://github.com/JetBrains/intellij-community/blob/master/platform/analysis-api/src/com/intellij/openapi/vfs/VfsUtil.java)）


### Java自体への理解

自分はJavaの開発経験もそれほどなかったので、良書として著名な[Effective Java](https://www.amazon.co.jp/Effective-Java-%E7%AC%AC3%E7%89%88-Joshua-Bloch/dp/4621303252/ref=pd_lpo_14_t_0/358-1818627-9368347?_encoding=UTF8&pd_rd_i=4621303252&pd_rd_r=0d8a6672-e07d-4c67-b146-e244ab57df3c&pd_rd_w=ikRul&pd_rd_wg=iT4Ks&pf_rd_p=4b55d259-ebf0-4306-905a-7762d1b93740&pf_rd_r=GN9PT6D4K2VJ770X7VGM&psc=1&refRID=GN9PT6D4K2VJ770X7VGM)を毎日少しずつ読み進めていました。

本の中で書かれているテクニックが実際のコードで結構使われていて結構嬉しかったので、まだ読んでいない方はぜひお勧めです。

また、IntelliJのUI周りはSwingというGUIツールキットをベースにして作られているので、この辺りも理解しておくと良いと思います。
自分は[Java Swing](https://www.amazon.co.jp/Java-Swing-Marc-Loy/dp/0596004087/ref=sr_1_12?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=java+swing&qid=1597214978&s=books&sr=1-12)を読みましたが、本自体が古くて、コードが見難かったり、丁寧に説明されている部分とコードのAPIをそのまま貼り付けているだけのような部分の差が激しかったりして、Effective Javaほどオススメはできませんが、Swingに馴染みがない方は読んでみても良いかもしれません。


## PlantUML Studioの開発

Code Reading Noteの開発でPlugin開発に基本的な部分はわかり始めたものの、所詮は1つのサンプルを作ったに過ぎず、
少し違ったことをやろうと思うと途端に手が止まってしまって、何を調べていいかも解らないし、そもそもPlantUMLの構文はちゃんとサポートできるのかもかなり不確定、という感じのスタートでした。

特にPlugin SDKの言語サポートの部分に関しての知識はゼロだったので、まずはそこからやろうということで、公式ドキュメントの言語サポートの部分を読み始めました。
[チュートリアル](https://jetbrains.org/intellij/sdk/docs/tutorials/custom_language_support_tutorial.html)があったので、通してやってみた結果、うっすらと言語サポートの全体像が把握出来ました。

うっすらとは全体像が把握できたとはいえ、 [Grammer-kit](https://github.com/JetBrains/Grammar-Kit)や[JFlex](https://jflex.de/manual.html)など、言語サポートの主要な部分が初めて触る技術だったため、自分でゼロから作っていけるという感じはしない状態でした。
また、PlantUML自体もユーザーではあったものの構文に対する理解も浅い状態でした。

そこで、一旦PlantUMLはクラス図のみの対応に絞って、不完全でもいいからそれっぽいものを作ってみて知見を貯めようと割り切って作り始めることにしました。
やはりチュートリアルだけの知識では手も足も出ない感じだったので、[Grammer-kit](https://github.com/JetBrains/Grammar-Kit)と[JFlex](https://jflex.de/manual.html)のドキュメントを読み漁りながら、
OSSで公開されているgoとelixirの言語サポートのコードを参考にしながらなんとか形にしていきました。

PlantUMLの構文に関しては、最初は[公式ドキュメント](https://plantuml.com/en/class-diagram)と[Real World PlantUML](https://real-world-plantuml.com/)の見ながら進めていましたが、対応漏れが多く、結局は本家の[PlantUMLのコード](https://github.com/plantuml/plantuml)を読みながら進めていく形に落ち着きました。

結果、かなり苦戦はしたもののクラス図の構文サポートを形にすることが出来ました。
PlantUMLの本家のコードもある程度読めるようになったので、この辺りで少し完成への希望が出てきたような気がします。

色々学んだ結果、2つめ以降の図の対応は割とスムーズにいきましたが、図ごとに言語と構文サポートを定義する形になっているので、結果5つの言語サポートをする形になってしまいました。
結構な労力がかかった上、メンテナンスコストも結構高そうな感じになってしまいました。

下記が5つの図のリストです。（トリビアですがクラス図とオブジェクト図、ユースケース図とコンポーネント図は内部的な同じ図になっていてとても助かりました）

- クラス、オブジェクト
- ユースケース、コンポーネント
- シーケンス
- アクティビティ
- ステート

図ごとに言語を定義するやり方でいいのか、1つの言語でうまいこと出来ないかを検討してみましたが、自分の理解では現実的ではなさそうだと判断したので、やむなくこのやり方で通す形になりました。
（まあ有料で出すのでこのぐらいの労力はあって然るべきかという思いと、既存のPluginがsyntaxサポートをしていない理由も解るなという思いになりました）

ちなみに図をレンダリングする部分は、本家のPlantUMLもjavaで実装されているので、API経由で図のイメージを生成できることもあり割とスムーズに作ることが出来ました。

ということで、ここから得た知見は。。

**チュートリアルと公式ドキュメントはやはり必須**

**学習コストの高さは諦めて受け入れる**
（類似した言語がOSSであれば話は別ですが、そうでなければ関連技術をちゃんと理解した上で、結構な量の試行錯誤が求められると思います）

**正規表現マスター（の気分）になれる**
構文サポートは正規表現をかなり駆使するので、結果として正規表現がかなり読めるようになりました。



## Marketplaceへの申請からリリースまで

最後に[Marketplace](https://plugins.jetbrains.com/marketplace)への申請からリリースまでの経過を書きます。

申請する前の段階では、Marketplaceに掲載されているPluginの数もそれほど多くなく、組織で開発しているものが多かったので、個人がいきなり申請しても全然相手にされないんじゃないかという気持ちが正直ありました。
そうしたらきっぱり諦めてOSSとして出そうかなとも思っていました。

結果的にはそういったことは杞憂に終わり、申請から約2週間でリリースすることが出来ました。
申請からリリースまでのステップは下記のような感じです。

- [Marketplace](https://plugins.jetbrains.com/marketplace)の下記の申請フォームから申請
- メールで「どんなPluginを出そうとしているの？」と連絡が来たので応える
- [Trying out the Marketplace](https://plugins.jetbrains.com/docs/marketplace/submit-a-request-to-sell-plugins-at-the-marketplace.html)の手順をサポートしてもらいつつこなしていく
- 価格などのSales info情報を送る前あたりで、「もっと気軽にコミュニケーションを取れるように」ということでslackに招待される
- [Trying out the Marketplace](https://plugins.jetbrains.com/docs/marketplace/submit-a-request-to-sell-plugins-at-the-marketplace.html)の手順を終え、リリースの準備が出来たと連絡する
- 「[https://plugins.jetbrains.com/](https://plugins.jetbrains.com/)にOrganizationを作って、Pluginをアップロードしてください」と言われたので、その通りに行うとOrganizationがPaid Plugin用に設定されて、支配先情報などが設定できるようになり、PluginもMarketplace上で表示される形でリリースされる

といった感じでした。
連絡のレスポンスもスムーズで、土日を挟んだ時はさすがに遅れることもありましたが、気になった質問にも誠実に応えていただけて、思っていたよりかなりスムーズにリリースまで漕ぎ着けることが出来ました。

# 最後に

正直そもそも需要があるのか、各環境でちゃんと動作するのかなど解らないことだらけですが、とりあえず形にしてリリースすることが出来てよかったです。
Pluginへのフィードバックはもちろん、Plugin開発に関する相談などありましたが気軽に連絡ください:slight_smile:

twitter: [https://twitter.com/kitabatakep](https://twitter.com/kitabatakep)
mail: kitabatake.programmer@gmail.com