package com.werfad; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.IdeActions; import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.actionSystem.EditorActionHandler; import com.intellij.openapi.editor.actionSystem.EditorActionManager; import com.intellij.openapi.editor.actionSystem.TypedAction; import com.intellij.openapi.editor.actionSystem.TypedActionHandler; import com.intellij.openapi.util.TextRange; import com.werfad.finder.*; import com.werfad.utils.EditorUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.awt.*; import java.util.Collections; import java.util.List; public final class JumpHandler implements TypedActionHandler { private static final JumpHandler INSTANCE = new JumpHandler(); static final int MODE_CHAR1 = 0; static final int MODE_CHAR2 = 1; static final int MODE_WORD0 = 2; static final int MODE_WORD1 = 3; static final int MODE_LINE = 4; private static TypedActionHandler mOldTypedHandler; private static EditorActionHandler mOldEscActionHandler; private static final MarksCanvas mMarksCanvas = new MarksCanvas(); private static boolean isStart; private static Finder finder; private static List<MarksCanvas.Mark> lastMarks = Collections.emptyList(); private static boolean isCanvasAdded = false; static JumpHandler getInstance() { return INSTANCE; } public void execute(@NotNull Editor e, char c, @NotNull DataContext dc) { List<MarksCanvas.Mark> marks = finder.input(e, c, lastMarks); if (marks != null) { lastMarks = marks; jumpOrShowCanvas(e, lastMarks); } } private EditorActionHandler escActionHandler = new EditorActionHandler() { @Override protected void doExecute(@NotNull Editor editor, @Nullable Caret caret, DataContext dataContext) { stop(); } }; private void jumpOrShowCanvas(Editor e, List<MarksCanvas.Mark> marks) { if (marks.isEmpty()) { stop(); } else if (marks.size() == 1) { // only one found, just jump to it e.getCaretModel().moveToOffset(marks.get(0).getOffset()); stop(); } else { if (!isCanvasAdded) { mMarksCanvas.sync(e); e.getContentComponent().add(mMarksCanvas); e.getContentComponent().repaint(); isCanvasAdded = true; } mMarksCanvas.setData(marks); } } /** * start search mode * * @param mode mode enum, see {@link #MODE_CHAR1} {@link #MODE_CHAR2} etc */ public final void start(@NotNull Editor e, int mode) { if (!isStart) { isStart = true; EditorActionManager manager = EditorActionManager.getInstance(); TypedAction typedAction = manager.getTypedAction(); mOldTypedHandler = typedAction.getRawHandler(); typedAction.setupRawHandler(this); mOldEscActionHandler = manager.getActionHandler(IdeActions.ACTION_EDITOR_ESCAPE); manager.setActionHandler(IdeActions.ACTION_EDITOR_ESCAPE, escActionHandler); switch (mode) { case MODE_CHAR1: finder = new Char1Finder(); break; case MODE_CHAR2: finder = new Char2Finder(); break; case MODE_WORD0: finder = new Word0Finder(); break; case MODE_WORD1: finder = new Word1Finder(); break; case MODE_LINE: finder = new LineFinder(); break; default: throw new RuntimeException("Invalid start mode: " + mode); } TextRange visibleBorderOffset = EditorUtils.getVisibleRangeOffset(e); String visibleString = e.getDocument().getText(visibleBorderOffset); List<MarksCanvas.Mark> marks = finder.start(e, visibleString, visibleBorderOffset); if (marks != null) { lastMarks = marks; this.jumpOrShowCanvas(e, lastMarks); } } } private void stop() { if (isStart) { isStart = false; EditorActionManager manager = EditorActionManager.getInstance(); manager.getTypedAction().setupRawHandler(mOldTypedHandler); if (mOldEscActionHandler != null) { manager.setActionHandler(IdeActions.ACTION_EDITOR_ESCAPE, mOldEscActionHandler); } Container parent = mMarksCanvas.getParent(); if (parent != null) { parent.remove(mMarksCanvas); parent.repaint(); } isCanvasAdded = false; } } }