プラグイン作って覚えたことを淡々と記録するよ(カーソル位置の語を取得するぞ編)
#ようやく遊びの時間が終焉を迎えるので,急いでまとめとかないと。
まずはこれ。「カーソル位置の語を取得する」。
楽勝かと思いきや,意外(?)とそうでもない。といっても,BrowseWordAtCaretちゅうプラグインがすでにあるので,こいつのコード丸パクリで済んだから,結果的には楽勝と言えよう。
ぐだぐだ書くよりコード見た方が早い。
// EditorActionはAnActionの子ども。 // Editor内だけで反応するAnAction作るのに便利。 public class PopupAction extends EditorAction { public PopupAction() { super(new BrowseWordAtCaretHandler()); } // EditorActionHandlerがEditorActionのキモで... private static class BrowseWordAtCaretHandler extends EditorActionHandler { // Actionが発火するとこいつが呼ばれる public void execute(Editor editor, DataContext dataContext) { String targetString = null; SelectionModel selection = editor.getSelectionModel(); if (selection.hasSelection()) { // 何か選択中だったら,そのテキストを抜く targetString = selection.getSelectedText(); } else { // 未選択ならカーソル位置の語を抜く Document document = editor.getDocument(); if (document.getTextLength() > 0) { String text = document.getText(); // どうもdocument.getText()だと,テキスト全体が抜き出されるんで, // こんな具合に,カーソル位置にある語を抜き出さないとダメっぽい。 int currentOffset = editor.getCaretModel().getOffset(); int wordStartOffset = getWordStartOffset(text, currentOffset); int wordEndOffset = getWordEndOffset(text, currentOffset); targetString = text.substring(wordStartOffset, wordEndOffset); // ついでだから,抜き出した語を選択状態にしちゃる selection.setSelection(wordStartOffset, wordEndOffset); } } if (targetString != null && targetString.trim().length() > 0) { // 選択中のテキストまたは,カーソル位置の語を抜けたので, // なんかする(...ポップアップを表示するんだけど) } } // ここは,BrowseWordAtCaretをまんまパクっただけ。 // 何やってるかは,推して知るべし。 private int getWordStartOffset(String text, int currentOffset) { StringCharacterIterator sci = new StringCharacterIterator(text, currentOffset); for (; isWordchar(sci.previous()); ) ; return sci.getIndex() + 1; } private int getWordEndOffset(String text, int currentOffset) { StringCharacterIterator sci = new StringCharacterIterator(text, currentOffset <= 0 ? 0 : currentOffset - 1); for (; isWordchar(sci.next()); ) ; return sci.getIndex(); } // ここを旨い具合に実装すれば,2バイト文字も抜き出せるんだろうな... private boolean isWordchar(char currentChar) { return 'A' <= currentChar && currentChar <= 'Z' || 'a' <= currentChar && currentChar <= 'z' || currentChar == '_' || '0' <= currentChar && currentChar <= '9' || '\300' <= currentChar && currentChar <= '\377' && currentChar != '\327' && currentChar != '\367'; } } }
OpenAPIで全部出来なかったとは言え,こんだけで組めた事を考えれば簡単なほうか。
おまけ:こんな感じに選択状態になったらIntentionを表示するって方法もあるよ。
これは簡単で,さっきのPopupActionにIntentionActionを実装して...
public class PopupAction extends EditorAction implements IntentionAction { public PopupAction() { super(new BrowseWordAtCaretHandler()); } //----> ここから @NotNull public String getText() { // Intentionの項目名称 return "ここを翻訳"; } @NotNull public String getFamilyName() { return "popup"; } public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { // このIntentionの発動条件(選択してれば発動する) return editor.getSelectionModel().hasSelection(); } public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { // このIntentionの処理を書く // ...選択中のテキストを抜いてポップアップを表示するのだ。 } public boolean startInWriteAction() { return false; } //<---- ここまでが IntentionAction で要るメソッド :
なんかテキトウなProjectComponentを作り,IntentionManagerに登録したら,おしまい。
赤子の手をひねるくらい簡単だの。
public class PopupProjectComponent implements ProjectComponent { public void projectOpened() { IntentionManager.getInstance().addAction(new PopupAction()); } :
ちなみに,参考にしたのはSyncEditプラグインだ。