package cn.yiiguxing.plugin.translate.action; import cn.yiiguxing.plugin.translate.Utils; import cn.yiiguxing.plugin.translate.compat.SelectWordUtilCompat; import com.intellij.codeInsight.editorActions.SelectWordUtil; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.SelectionModel; import com.intellij.openapi.util.TextRange; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.ArrayList; /** * 自动从光标周围取词 */ @SuppressWarnings("WeakerAccess") abstract class AutoSelectAction extends AnAction { private final SelectWordUtil.CharCondition mWordPartCondition; private final boolean mCheckSelection; public AutoSelectAction(@Nullable SelectWordUtil.CharCondition isWordPartCondition, boolean checkSelection) { this(null, null, null, isWordPartCondition, checkSelection); } public AutoSelectAction(Icon icon, boolean checkSelection) { this(null, null, icon, null, checkSelection); } public AutoSelectAction(@Nullable String text, @Nullable String description, @Nullable Icon icon, @Nullable SelectWordUtil.CharCondition isWordPartCondition, boolean checkSelection) { super(text, description, icon); setEnabledInModalContext(true); this.mWordPartCondition = isWordPartCondition != null ? isWordPartCondition : SelectWordUtilCompat.DEFAULT_CONDITION; this.mCheckSelection = checkSelection; } /** * 返回取词模式 */ @NotNull protected abstract AutoSelectionMode getAutoSelectionMode(); /** * 更新Action * * @param e 事件 * @param active 是否活动的,表示是否可以取到词 */ protected void onUpdate(AnActionEvent e, boolean active) { } /** * 执行操作 * * @param e 事件 * @param editor 编辑器 * @param selectionRange 取词的范围 */ protected void onActionPerformed(AnActionEvent e, @NotNull Editor editor, @NotNull TextRange selectionRange) { } @Override public final void update(AnActionEvent e) { boolean active = false; Editor editor = getEditor(e); if (editor != null) { SelectionModel selectionModel = editor.getSelectionModel(); active = (mCheckSelection && selectionModel.hasSelection()) || canSelect(editor); } onUpdate(e, active); } @Override public final void actionPerformed(AnActionEvent e) { if (ApplicationManager.getApplication().isHeadlessEnvironment()) return; final Editor editor = getEditor(e); if (editor != null) { TextRange selectionRange = getSelectionRange(e); if (selectionRange != null && !selectionRange.isEmpty()) { onActionPerformed(e, editor, selectionRange); } } } private boolean canSelect(Editor editor) { final int offset = editor.getCaretModel().getOffset(); Document document = editor.getDocument(); int textLength = document.getTextLength(); if (textLength == 0) return false; String text = document.getText(new TextRange(Math.max(0, offset - 1), Math.min(textLength, offset + 1))); for (int i = 0; i < text.length(); i++) { if (mWordPartCondition.value(text.charAt(i))) { return true; } } return false; } @Nullable protected static Editor getEditor(AnActionEvent e) { return CommonDataKeys.EDITOR.getData(e.getDataContext()); } @Nullable private TextRange getSelectionRange(AnActionEvent e) { TextRange selectionRange = null; Editor editor = getEditor(e); if (editor != null) { SelectionModel selectionModel = editor.getSelectionModel(); if (mCheckSelection && selectionModel.hasSelection()) { selectionRange = new TextRange(selectionModel.getSelectionStart(), selectionModel.getSelectionEnd()); } else { final ArrayList<TextRange> ranges = new ArrayList<TextRange>(); final int offset = editor.getCaretModel().getOffset(); final AutoSelectionMode selectionMode = Utils.requireNonNull(getAutoSelectionMode(), "Method getAutoSelectionMode() can not return null."); final boolean exclusiveMode = selectionMode == AutoSelectionMode.EXCLUSIVE; SelectWordUtilCompat.addWordOrLexemeSelection(exclusiveMode, editor, offset, ranges, mWordPartCondition); if (!ranges.isEmpty()) { if (exclusiveMode) { selectionRange = ranges.get(0); } else { TextRange maxRange = null; for (TextRange range : ranges) { if (maxRange == null || range.contains(maxRange)) { maxRange = range; } } selectionRange = maxRange; } } } } return selectionRange; } }