mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
invoke TypedHandlerDelegate.checkAutoPopup only for the primary caret (completion popup is supposed to be shown only for it)
(for IDEA-135620)
This commit is contained in:
+11
-4
@@ -23,6 +23,8 @@ import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Handler, extending IDE behaviour on typing in editor.
|
||||
*
|
||||
* @author yole
|
||||
*/
|
||||
public abstract class TypedHandlerDelegate {
|
||||
@@ -30,17 +32,22 @@ public abstract class TypedHandlerDelegate {
|
||||
|
||||
/**
|
||||
* If the specified character triggers auto-popup, schedules the auto-popup appearance. This method is called even
|
||||
* in overwrite mode, when the rest of typed handler delegate methods are not called.
|
||||
* in overwrite mode, when the rest of typed handler delegate methods are not called. It is invoked only for the primary caret.
|
||||
*/
|
||||
public Result checkAutoPopup(char charTyped, final Project project, final Editor editor, final PsiFile file) {
|
||||
return Result.CONTINUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before selected text is deleted.
|
||||
* This method is supposed to be overridden by handlers having custom behaviour with respect to selection.
|
||||
*/
|
||||
public Result beforeSelectionRemoved(char c, final Project project, final Editor editor, final PsiFile file) {
|
||||
return Result.CONTINUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before the specified character typed by the user is inserted in the editor.
|
||||
*
|
||||
* @return true if the typing has been processed (in this case, no further delegates are called and the character is not inserted),
|
||||
* false otherwise.
|
||||
*/
|
||||
public Result beforeCharTyped(char c, final Project project, final Editor editor, final PsiFile file, final FileType fileType) {
|
||||
return Result.CONTINUE;
|
||||
|
||||
+47
-70
@@ -23,10 +23,10 @@ import com.intellij.openapi.editor.SelectionModel;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -37,52 +37,59 @@ import org.jetbrains.annotations.NotNull;
|
||||
public class SelectionQuotingTypedHandler extends TypedHandlerDelegate {
|
||||
public static final ExtensionPointName<DequotingFilter> EP_NAME =
|
||||
ExtensionPointName.create("com.intellij.selectionDequotingFilter");
|
||||
private TextRange myReplacedTextRange;
|
||||
private boolean myRestoreStickySelection;
|
||||
private boolean myLtrSelection;
|
||||
|
||||
@Override
|
||||
public Result checkAutoPopup(char c, Project project, Editor editor, PsiFile psiFile) {
|
||||
// TODO[oleg] provide adequate API not to use this hack
|
||||
// beforeCharTyped always works with removed selection
|
||||
public Result beforeSelectionRemoved(char c, Project project, Editor editor, PsiFile file) {
|
||||
SelectionModel selectionModel = editor.getSelectionModel();
|
||||
if(CodeInsightSettings.getInstance().SURROUND_SELECTION_ON_QUOTE_TYPED && selectionModel.hasSelection() && isDelimiter(c)) {
|
||||
if(CodeInsightSettings.getInstance().SURROUND_SELECTION_ON_QUOTE_TYPED && selectionModel.hasSelection() && isDelimiter(c)) {
|
||||
String selectedText = selectionModel.getSelectedText();
|
||||
if (selectedText.length() < 1) {
|
||||
return super.checkAutoPopup(c, project, editor, psiFile);
|
||||
}
|
||||
|
||||
final int selectionStart = selectionModel.getSelectionStart();
|
||||
final int selectionEnd = selectionModel.getSelectionEnd();
|
||||
if (selectedText.length() > 1) {
|
||||
final char firstChar = selectedText.charAt(0);
|
||||
final char lastChar = selectedText.charAt(selectedText.length() - 1);
|
||||
if (isSimilarDelimiters(firstChar, c) && lastChar == getMatchingDelimiter(firstChar) &&
|
||||
(isQuote(firstChar) || firstChar != c) && !shouldSkipReplacementOfQuotesOrBraces(psiFile, editor, selectedText, c) &&
|
||||
selectedText.indexOf(lastChar, 1) == selectedText.length() - 1) {
|
||||
selectedText = selectedText.substring(1, selectedText.length() - 1);
|
||||
if (!StringUtil.isEmpty(selectedText)) {
|
||||
final int selectionStart = selectionModel.getSelectionStart();
|
||||
final int selectionEnd = selectionModel.getSelectionEnd();
|
||||
if (selectedText.length() > 1) {
|
||||
final char firstChar = selectedText.charAt(0);
|
||||
final char lastChar = selectedText.charAt(selectedText.length() - 1);
|
||||
if (isSimilarDelimiters(firstChar, c) && lastChar == getMatchingDelimiter(firstChar) &&
|
||||
(isQuote(firstChar) || firstChar != c) && !shouldSkipReplacementOfQuotesOrBraces(file, editor, selectedText, c) &&
|
||||
selectedText.indexOf(lastChar, 1) == selectedText.length() - 1) {
|
||||
selectedText = selectedText.substring(1, selectedText.length() - 1);
|
||||
}
|
||||
}
|
||||
final int caretOffset = selectionModel.getSelectionStart();
|
||||
final char c2 = getMatchingDelimiter(c);
|
||||
final String newText = String.valueOf(c) + selectedText + c2;
|
||||
boolean ltrSelection = selectionModel.getLeadSelectionOffset() != selectionModel.getSelectionEnd();
|
||||
boolean restoreStickySelection = editor instanceof EditorEx && ((EditorEx)editor).isStickySelection();
|
||||
selectionModel.removeSelection();
|
||||
editor.getDocument().replaceString(selectionStart, selectionEnd, newText);
|
||||
TextRange replacedTextRange = Registry.is("editor.smarterSelectionQuoting")
|
||||
? new TextRange(caretOffset + 1, caretOffset + newText.length() - 1)
|
||||
: new TextRange(caretOffset, caretOffset + newText.length());
|
||||
// selection is removed here
|
||||
if (replacedTextRange.getEndOffset() <= editor.getDocument().getTextLength()) {
|
||||
if (restoreStickySelection) {
|
||||
EditorEx editorEx = (EditorEx)editor;
|
||||
CaretModel caretModel = editorEx.getCaretModel();
|
||||
caretModel.moveToOffset(ltrSelection ? replacedTextRange.getStartOffset() : replacedTextRange.getEndOffset());
|
||||
editorEx.setStickySelection(true);
|
||||
caretModel.moveToOffset(ltrSelection ? replacedTextRange.getEndOffset() : replacedTextRange.getStartOffset());
|
||||
}
|
||||
else {
|
||||
if (ltrSelection || editor instanceof EditorWindow) {
|
||||
editor.getSelectionModel().setSelection(replacedTextRange.getStartOffset(), replacedTextRange.getEndOffset());
|
||||
}
|
||||
else {
|
||||
editor.getSelectionModel().setSelection(replacedTextRange.getEndOffset(), replacedTextRange.getStartOffset());
|
||||
}
|
||||
if (Registry.is("editor.smarterSelectionQuoting")) {
|
||||
editor.getCaretModel().moveToOffset(ltrSelection ? replacedTextRange.getEndOffset() : replacedTextRange.getStartOffset());
|
||||
}
|
||||
}
|
||||
}
|
||||
return Result.STOP;
|
||||
}
|
||||
final int caretOffset = selectionModel.getSelectionStart();
|
||||
final char c2 = getMatchingDelimiter(c);
|
||||
final String newText = String.valueOf(c) + selectedText + c2;
|
||||
myLtrSelection = selectionModel.getLeadSelectionOffset() != selectionModel.getSelectionEnd();
|
||||
if (editor instanceof EditorEx) {
|
||||
myRestoreStickySelection = ((EditorEx)editor).isStickySelection();
|
||||
}
|
||||
else {
|
||||
myRestoreStickySelection = false;
|
||||
}
|
||||
selectionModel.removeSelection();
|
||||
editor.getDocument().replaceString(selectionStart, selectionEnd, newText);
|
||||
if (Registry.is("editor.smarterSelectionQuoting")) {
|
||||
myReplacedTextRange = new TextRange(caretOffset + 1, caretOffset + newText.length() - 1);
|
||||
} else {
|
||||
myReplacedTextRange = new TextRange(caretOffset, caretOffset + newText.length());
|
||||
}
|
||||
return Result.STOP;
|
||||
}
|
||||
return super.checkAutoPopup(c, project, editor, psiFile);
|
||||
return super.beforeSelectionRemoved(c, project, editor, file);
|
||||
}
|
||||
|
||||
private static boolean shouldSkipReplacementOfQuotesOrBraces(PsiFile psiFile, Editor editor, String selectedText, char c) {
|
||||
@@ -116,36 +123,6 @@ public class SelectionQuotingTypedHandler extends TypedHandlerDelegate {
|
||||
return (isBracket(c1) && isBracket(c2)) || (isQuote(c1) && isQuote(c2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result beforeCharTyped(final char charTyped, final Project project, final Editor editor, final PsiFile file, final FileType fileType) {
|
||||
// TODO[oleg] remove this hack when API changes
|
||||
if (myReplacedTextRange != null) {
|
||||
if (myReplacedTextRange.getEndOffset() <= editor.getDocument().getTextLength()) {
|
||||
if (myRestoreStickySelection && editor instanceof EditorEx) {
|
||||
EditorEx editorEx = (EditorEx)editor;
|
||||
CaretModel caretModel = editorEx.getCaretModel();
|
||||
caretModel.moveToOffset(myLtrSelection ? myReplacedTextRange.getStartOffset() : myReplacedTextRange.getEndOffset());
|
||||
editorEx.setStickySelection(true);
|
||||
caretModel.moveToOffset(myLtrSelection ? myReplacedTextRange.getEndOffset() : myReplacedTextRange.getStartOffset());
|
||||
}
|
||||
else {
|
||||
if (myLtrSelection || editor instanceof EditorWindow) {
|
||||
editor.getSelectionModel().setSelection(myReplacedTextRange.getStartOffset(), myReplacedTextRange.getEndOffset());
|
||||
}
|
||||
else {
|
||||
editor.getSelectionModel().setSelection(myReplacedTextRange.getEndOffset(), myReplacedTextRange.getStartOffset());
|
||||
}
|
||||
if (Registry.is("editor.smarterSelectionQuoting")) {
|
||||
editor.getCaretModel().moveToOffset(myLtrSelection ? myReplacedTextRange.getEndOffset() : myReplacedTextRange.getStartOffset());
|
||||
}
|
||||
}
|
||||
}
|
||||
myReplacedTextRange = null;
|
||||
return Result.STOP;
|
||||
}
|
||||
return Result.CONTINUE;
|
||||
}
|
||||
|
||||
public static abstract class DequotingFilter {
|
||||
public abstract boolean skipReplacementQuotesOrBraces(@NotNull PsiFile file,
|
||||
@NotNull Editor editor,
|
||||
|
||||
@@ -162,18 +162,20 @@ public class TypedHandler extends TypedActionHandlerBase {
|
||||
|
||||
final TypedHandlerDelegate[] delegates = Extensions.getExtensions(TypedHandlerDelegate.EP_NAME);
|
||||
|
||||
boolean handled = false;
|
||||
for (TypedHandlerDelegate delegate : delegates) {
|
||||
final TypedHandlerDelegate.Result result = delegate.checkAutoPopup(charTyped, project, editor, file);
|
||||
handled = result == TypedHandlerDelegate.Result.STOP;
|
||||
if (result != TypedHandlerDelegate.Result.CONTINUE) {
|
||||
break;
|
||||
if (caret == originalEditor.getCaretModel().getPrimaryCaret()) {
|
||||
boolean handled = false;
|
||||
for (TypedHandlerDelegate delegate : delegates) {
|
||||
final TypedHandlerDelegate.Result result = delegate.checkAutoPopup(charTyped, project, editor, file);
|
||||
handled = result == TypedHandlerDelegate.Result.STOP;
|
||||
if (result != TypedHandlerDelegate.Result.CONTINUE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!handled) {
|
||||
autoPopupCompletion(editor, charTyped, project, file);
|
||||
autoPopupParameterInfo(editor, charTyped, project, file);
|
||||
if (!handled) {
|
||||
autoPopupCompletion(editor, charTyped, project, file);
|
||||
autoPopupParameterInfo(editor, charTyped, project, file);
|
||||
}
|
||||
}
|
||||
|
||||
if (!editor.isInsertMode()) {
|
||||
@@ -181,6 +183,16 @@ public class TypedHandler extends TypedActionHandlerBase {
|
||||
return;
|
||||
}
|
||||
|
||||
for (TypedHandlerDelegate delegate : delegates) {
|
||||
final TypedHandlerDelegate.Result result = delegate.beforeSelectionRemoved(charTyped, project, editor, file);
|
||||
if (result == TypedHandlerDelegate.Result.STOP) {
|
||||
return;
|
||||
}
|
||||
if (result == TypedHandlerDelegate.Result.DEFAULT) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
EditorModificationUtil.deleteSelectedText(editor);
|
||||
|
||||
FileType fileType = getFileType(file, editor);
|
||||
|
||||
Reference in New Issue
Block a user