Я пишу плагин для IntelliJ IDEA, и, к сожалению, ссылки на API, похоже, немного не хватает для всей системы плагинов (кроме нескольких очень полезных руководств на сайте JetBrains.) Этот плагин предназначен для пользовательского языка, которыйСвязывает с определенными типами файлов, и API анализатора является управляемым наряду с ассоциациями файлов и системами шаблонов, но то, что я не могу понять, кажется, что это должно быть действительно легко решить в отличие от них.
Я хотел бы создать горячую клавишу, которая при использовании в редакторе (без элементов меню или значков панели инструментов, только комбинация клавиш), которая будет вставлять символ Unicode, или, альтернативно, если есть активный выбор, будет переносить выделенный текст впара символов Unicode.
Например, что-то, чтобы поймать ALT_SHIFT+[
в моем типе файла, и если нет выбора, он вставил бы символ ⦓
в текущую позицию каретки, если есть выбор, то это будетобернуть этот выбор в ⦓
... ⦔
Это кажетсявыполнимо, поскольку файлы .java
фактически используют комбинацию ALT+SHIFT+[
для изменения выбора в IntelliJ, тогда как мой пользовательский тип файла в настоящее время просто игнорирует его.
Пользовательский тип файла наследуется от LanguageFileType
в пакете com.intellij.openapi.fileTypes
.
Редактировать:
Добавление кода, полученного в результате, на случай, если кто-нибудь еще столкнется с этим вопросом:
HotkeyAction (необходимо зарегистрироваться в плагине.xml)
public class HotkeyAction extends AnAction {
private static final Logger logger = Logger.getInstance("Aquae");
private ArrayList<HotkeyHandler> hotkeyHandlers;
public HotkeyAction() {
super();
this.hotkeyHandlers = new ArrayList<HotkeyHandler>();
this.AddBracketShortcut(true,
"{", KeyStroke.getKeyStroke(VK_OPEN_BRACKET, SHIFT_MASK, false),
"}", KeyStroke.getKeyStroke(VK_CLOSE_BRACKET, SHIFT_MASK, false));
this.AddBracketShortcut(true,
"⧼", KeyStroke.getKeyStroke(VK_OPEN_BRACKET, CTRL_MASK | SHIFT_MASK, false),
"⧽", KeyStroke.getKeyStroke(VK_CLOSE_BRACKET, CTRL_MASK | SHIFT_MASK, false));
this.AddBracketShortcut(true,
"⦓", KeyStroke.getKeyStroke(VK_OPEN_BRACKET, ALT_MASK | SHIFT_MASK, false),
"⦔", KeyStroke.getKeyStroke(VK_CLOSE_BRACKET, ALT_MASK | SHIFT_MASK, false));
this.AddBracketShortcut(true,
"⦃", KeyStroke.getKeyStroke(VK_OPEN_BRACKET, CTRL_MASK | ALT_MASK | SHIFT_MASK, false),
"⦄", KeyStroke.getKeyStroke(VK_CLOSE_BRACKET, CTRL_MASK | ALT_MASK | SHIFT_MASK, false));
this.AddBracketShortcut(true,
"(", KeyStroke.getKeyStroke(VK_9, SHIFT_MASK, false),
")", KeyStroke.getKeyStroke(VK_0, SHIFT_MASK, false));
this.AddBracketShortcut(true,
"⦗", KeyStroke.getKeyStroke(VK_9, CTRL_MASK | SHIFT_MASK, false),
"⦘", KeyStroke.getKeyStroke(VK_0, CTRL_MASK | SHIFT_MASK, false));
this.AddBracketShortcut(true,
"⦅", KeyStroke.getKeyStroke(VK_9, ALT_MASK | SHIFT_MASK, false),
"⦆", KeyStroke.getKeyStroke(VK_0, ALT_MASK | SHIFT_MASK, false));
this.AddBracketShortcut(true,
"⸨", KeyStroke.getKeyStroke(VK_9, CTRL_MASK | ALT_MASK | SHIFT_MASK, false),
"⸩", KeyStroke.getKeyStroke(VK_0, CTRL_MASK | ALT_MASK | SHIFT_MASK, false));
this.AddBracketShortcut(true,
"[", KeyStroke.getKeyStroke(VK_OPEN_BRACKET, 0, false),
"]", KeyStroke.getKeyStroke(VK_CLOSE_BRACKET, 0, false));
this.AddBracketShortcut(true,
"⁅", KeyStroke.getKeyStroke(VK_OPEN_BRACKET, CTRL_MASK, false),
"⁆", KeyStroke.getKeyStroke(VK_CLOSE_BRACKET, CTRL_MASK, false));
this.AddBracketShortcut(true,
"【", KeyStroke.getKeyStroke(VK_OPEN_BRACKET, ALT_MASK, false),
"】", KeyStroke.getKeyStroke(VK_CLOSE_BRACKET, ALT_MASK, false));
this.AddBracketShortcut(true,
"〚", KeyStroke.getKeyStroke(VK_OPEN_BRACKET, CTRL_MASK | ALT_MASK, false),
"〛", KeyStroke.getKeyStroke(VK_CLOSE_BRACKET, CTRL_MASK | ALT_MASK, false));
this.AddBracketShortcut(true,
"<", KeyStroke.getKeyStroke(VK_COMMA, SHIFT_MASK, false),
">", KeyStroke.getKeyStroke(VK_PERIOD, SHIFT_MASK, false));
this.AddBracketShortcut(true,
"᚜", KeyStroke.getKeyStroke(VK_COMMA, CTRL_MASK | SHIFT_MASK, false),
"᚛", KeyStroke.getKeyStroke(VK_PERIOD, CTRL_MASK | SHIFT_MASK, false));
this.AddBracketShortcut(true,
"⦑", KeyStroke.getKeyStroke(VK_COMMA, ALT_MASK | SHIFT_MASK, false),
"⦒", KeyStroke.getKeyStroke(VK_PERIOD, ALT_MASK | SHIFT_MASK, false));
this.AddBracketShortcut(true,
"⟪", KeyStroke.getKeyStroke(VK_COMMA, CTRL_MASK | ALT_MASK | SHIFT_MASK, false),
"⟫", KeyStroke.getKeyStroke(VK_PERIOD, CTRL_MASK | ALT_MASK | SHIFT_MASK, false));
}
HotkeyAction(ArrayList<HotkeyHandler> keyStrokes) {
super();
this.hotkeyHandlers = new ArrayList<HotkeyHandler>();
}
public void AddBracketShortcut(boolean completeWithoutSelection, String open, KeyStroke openKeyStroke, String close, KeyStroke closeKeyStroke) {
HotkeyBracketInsertionHandler handler = new HotkeyBracketInsertionHandler(completeWithoutSelection, open, openKeyStroke, close, closeKeyStroke);
this.hotkeyHandlers.add(handler);
KeymapManager.getInstance().getActiveKeymap().addShortcut("org.aquae.slip.HotkeyAction", handler.getOpenShortcut());
KeymapManager.getInstance().getActiveKeymap().addShortcut("org.aquae.slip.HotkeyAction", handler.getCloseShortcut());
}
@Override
public void actionPerformed(AnActionEvent anActionEvent) {
String s = "";
InputEvent inputEvent = anActionEvent.getInputEvent();
logger.warn(inputEvent.toString());
boolean hit = false;
Project project = anActionEvent.getProject();
if (inputEvent instanceof KeyEvent) {
KeyEvent keyEvent = (KeyEvent) inputEvent;
int mask = 0;
s = String.valueOf(keyEvent.getKeyChar());
if (inputEvent.isShiftDown()) {
s = "SHIFT" + (s.length() > 0 ? " + " + s : "");
mask |= SHIFT_DOWN_MASK;
}
if (inputEvent.isAltDown()) {
s = "ALT" + (s.length() > 0 ? " + " + s : "");
mask |= ALT_DOWN_MASK;
}
if (inputEvent.isControlDown()) {
s = "CTRL" + (s.length() > 0 ? " + " + s : "");
mask |= CTRL_DOWN_MASK;
}
logger.warn("KeyCode = " + keyEvent.getKeyCode());
logger.warn("Modifiers = " + keyEvent.getModifiers());
logger.warn(s);
for (HotkeyHandler hotkeyHandler : this.hotkeyHandlers) {
if (hotkeyHandler.match(anActionEvent)) {
hit = true;
if (hotkeyHandler instanceof HotkeyBracketInsertionHandler) {
HotkeyBracketInsertionHandler hotkeyBracketInsertionHandler = (HotkeyBracketInsertionHandler) hotkeyHandler;
logger.warn(hotkeyBracketInsertionHandler.getOpen() + "x" + hotkeyBracketInsertionHandler.getClose());
WriteCommandAction.runWriteCommandAction(project, () -> { hotkeyHandler.execute(project, anActionEvent); });
}
break;
}
}
if (!hit) {
logger.warn(s);
}
}
}
}
HotkeyHandler
public abstract class HotkeyHandler {
protected ArrayList<KeyStroke> _keyStrokes;
protected ArrayList<Shortcut> _shortcuts;
public HotkeyHandler(ArrayList<KeyStroke> keyStrokes) {
this._keyStrokes = keyStrokes;
this._shortcuts = new ArrayList<Shortcut>();
for (KeyStroke keyStroke : keyStrokes) {
this._shortcuts.add(new KeyboardShortcut(keyStroke, null));
}
}
abstract void execute(Project project, AnActionEvent anActionEvent);
public boolean indifferentMatch(int i, KeyEvent keyEvent) {
KeyStroke keyStroke = this._keyStrokes.get(i);
if (keyStroke.getKeyCode() == keyEvent.getKeyCode()) {
int modifiers = keyEvent.getModifiers();
if ((keyStroke.getModifiers() & (CTRL_MASK | CTRL_DOWN_MASK)) > 0) {
if ((modifiers & (CTRL_MASK | CTRL_DOWN_MASK)) < 1) { return (false); }
if ((modifiers & CTRL_MASK) > 0) { modifiers -= CTRL_MASK; }
if ((modifiers & CTRL_DOWN_MASK) > 0) { modifiers -= CTRL_DOWN_MASK; }
}
if ((keyStroke.getModifiers() & (ALT_MASK | ALT_DOWN_MASK)) > 0) {
if ((modifiers & (ALT_MASK | ALT_DOWN_MASK)) < 1) { return (false); }
if ((modifiers & ALT_MASK) > 0) { modifiers -= ALT_MASK; }
if ((modifiers & ALT_DOWN_MASK) > 0) { modifiers -= ALT_DOWN_MASK; }
}
if ((keyStroke.getModifiers() & (SHIFT_MASK | SHIFT_DOWN_MASK)) > 0) {
if ((modifiers & (SHIFT_MASK | SHIFT_DOWN_MASK)) < 1) { return (false); }
if ((modifiers & SHIFT_MASK) > 0) { modifiers -= SHIFT_MASK; }
if ((modifiers & SHIFT_DOWN_MASK) > 0) { modifiers -= SHIFT_DOWN_MASK; }
}
if (modifiers < 1) { return (true); }
}
return (false);
}
public boolean match(AnActionEvent anActionEvent) {
InputEvent inputEvent = anActionEvent.getInputEvent();
if (!(inputEvent instanceof KeyEvent)) { return (false); }
KeyEvent keyEvent = (KeyEvent) inputEvent;
for (int i = this._keyStrokes.size() - 1; i >= 0; i--) {
if (this.indifferentMatch(i, keyEvent)) { return (true); }
}
return (false);
}
public KeyStroke getKeyStroke(int i) { return (this._keyStrokes.get(i)); }
public ArrayList<KeyStroke> getKeyStrokes() { return (this._keyStrokes); }
public Shortcut getShortcut(int i) { return (this._shortcuts.get(i)); }
public ArrayList<Shortcut> getShortcuts() { return (this._shortcuts); }
}
HotkeyBracketInsertionHandler
public class HotkeyBracketInsertionHandler extends HotkeyHandler {
private static final Logger logger = Logger.getInstance("Aquae");
private boolean _completeWithoutSelection;
private String _open;
private String _close;
public HotkeyBracketInsertionHandler(boolean completeWithoutSelection, String open, KeyStroke openKeyStroke, String close, KeyStroke closeKeyStroke) {
super(new ArrayList<KeyStroke>() {{
add(openKeyStroke);
add(closeKeyStroke);
}});
this._completeWithoutSelection = completeWithoutSelection;
this._open = open;
this._close = close;
}
@Override
void execute(Project project, AnActionEvent anActionEvent) {
InputEvent inputEvent = anActionEvent.getInputEvent();
if (!(inputEvent instanceof KeyEvent)) { return; }
KeyEvent keyEvent = (KeyEvent) inputEvent;
FileEditorManager fileEditorManager = FileEditorManager.getInstance(project);
Editor textEditor = fileEditorManager.getSelectedTextEditor();
final Document document = textEditor.getDocument();
final CaretModel caretModel = textEditor.getCaretModel();
final int caretOffset = caretModel.getOffset();
if (caretOffset < 0) { return; }
final SelectionModel selectionModel = textEditor.getSelectionModel();
boolean rev = (caretOffset == selectionModel.getSelectionStart()) && (caretOffset != selectionModel.getSelectionEnd());
boolean opening = this.indifferentMatch(0, keyEvent);
if (opening) {
if (this._completeWithoutSelection || selectionModel.hasSelection()) {
document.insertString(selectionModel.getSelectionEnd(), this._close);
document.insertString(selectionModel.getSelectionStart(), this._open);
caretModel.moveToOffset((rev ? selectionModel.getSelectionStart() : selectionModel.getSelectionEnd()) + (!selectionModel.hasSelection() ? this._open.length() : 0));
selectionModel.setSelection(selectionModel.getSelectionStart(), selectionModel.getSelectionEnd());
} else {
document.insertString(selectionModel.getSelectionStart(), this._open);
caretModel.moveToOffset(selectionModel.getSelectionEnd() + this._open.length());
}
} else {
if (this._close.length() < 1) { return; }
if (selectionModel.hasSelection()) {
document.insertString(selectionModel.getSelectionStart(), this._close);
document.deleteString(selectionModel.getSelectionStart(), selectionModel.getSelectionEnd());
caretModel.moveToOffset(rev ? selectionModel.getSelectionStart() : selectionModel.getSelectionEnd());
selectionModel.setSelection(selectionModel.getSelectionStart(), selectionModel.getSelectionEnd());
} else {
document.insertString(selectionModel.getSelectionStart(), this._close);
selectionModel.removeSelection();
caretModel.moveToOffset(selectionModel.getSelectionEnd() + this._close.length());
}
}
}
public String getClose() { return (this._close); }
public KeyStroke getCloseKeyStroke() { return (this._keyStrokes.get(1)); }
public Shortcut getCloseShortcut() { return (this._shortcuts.get(1)); }
public String getOpen() { return (this._open); }
public KeyStroke getOpenKeyStroke() { return (this._keyStrokes.get(0)); }
public Shortcut getOpenShortcut() { return (this._shortcuts.get(0)); }
}
HotkeyPromoter (необходимо зарегистрировать в plugin.xml)
public class HotkeyPromoter implements ActionPromoter {
@Override
public List<AnAction> promote(List<AnAction> actions, DataContext dataContext) {
AnAction action = ContainerUtil.findInstance(actions, HotkeyAction.class);
return (action != null ? Collections.singletonList(action) : Collections.emptyList());
}
}