mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-123396 Multiple carets: offer completion from other caret, if primary caret has no completion variants
This commit is contained in:
+1
-1
@@ -144,6 +144,6 @@ public class JavaPostfixTemplateProvider implements PostfixTemplateProvider {
|
||||
}
|
||||
|
||||
private static boolean isSemicolonNeeded(@NotNull PsiFile file, @NotNull Editor editor) {
|
||||
return JavaCompletionContributor.semicolonNeeded(editor, file, CompletionInitializationContext.calcStartOffset(editor));
|
||||
return JavaCompletionContributor.semicolonNeeded(editor, file, CompletionInitializationContext.calcStartOffset(editor.getCaretModel().getCurrentCaret()));
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
class Foo {{
|
||||
System.<caret>
|
||||
System.<caret>
|
||||
}}
|
||||
+5
@@ -1423,6 +1423,11 @@ class XInternalError {}
|
||||
checkResult()
|
||||
}
|
||||
|
||||
public void testMulticaretCompletionFromNonPrimaryCaret() {
|
||||
configure()
|
||||
myFixture.assertPreferredCompletionItems(0, "arraycopy")
|
||||
}
|
||||
|
||||
public void "test complete lowercase class name"() {
|
||||
myFixture.addClass("package foo; public class myClass {}")
|
||||
myFixture.configureByText "a.java", """
|
||||
|
||||
+10
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2010 JetBrains s.r.o.
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,8 +16,8 @@
|
||||
package com.intellij.codeInsight.completion;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.editor.Caret;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.SelectionModel;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.util.PsiUtilBase;
|
||||
@@ -45,26 +45,24 @@ public class CompletionInitializationContext {
|
||||
private final OffsetMap myOffsetMap;
|
||||
private String myDummyIdentifier = DUMMY_IDENTIFIER;
|
||||
|
||||
public CompletionInitializationContext(final Editor editor, final PsiFile file, final CompletionType completionType, int invocationCount) {
|
||||
public CompletionInitializationContext(final Editor editor, final Caret caret, final PsiFile file, final CompletionType completionType, int invocationCount) {
|
||||
myEditor = editor;
|
||||
myFile = file;
|
||||
myCompletionType = completionType;
|
||||
myInvocationCount = invocationCount;
|
||||
myOffsetMap = new OffsetMap(editor.getDocument());
|
||||
|
||||
myOffsetMap.addOffset(START_OFFSET, calcStartOffset(editor));
|
||||
myOffsetMap.addOffset(SELECTION_END_OFFSET, calcSelectionEnd(editor));
|
||||
myOffsetMap.addOffset(IDENTIFIER_END_OFFSET, calcDefaultIdentifierEnd(editor, calcSelectionEnd(editor)));
|
||||
myOffsetMap.addOffset(START_OFFSET, calcStartOffset(caret));
|
||||
myOffsetMap.addOffset(SELECTION_END_OFFSET, calcSelectionEnd(caret));
|
||||
myOffsetMap.addOffset(IDENTIFIER_END_OFFSET, calcDefaultIdentifierEnd(editor, calcSelectionEnd(caret)));
|
||||
}
|
||||
|
||||
private static int calcSelectionEnd(Editor editor) {
|
||||
final SelectionModel selectionModel = editor.getSelectionModel();
|
||||
return selectionModel.hasSelection() ? selectionModel.getSelectionEnd() : editor.getCaretModel().getOffset();
|
||||
private static int calcSelectionEnd(Caret caret) {
|
||||
return caret.hasSelection() ? caret.getSelectionEnd() : caret.getOffset();
|
||||
}
|
||||
|
||||
public static int calcStartOffset(Editor editor) {
|
||||
final SelectionModel selectionModel = editor.getSelectionModel();
|
||||
return selectionModel.hasSelection() ? selectionModel.getSelectionStart() : editor.getCaretModel().getOffset();
|
||||
public static int calcStartOffset(Caret caret) {
|
||||
return caret.hasSelection() ? caret.getSelectionStart() : caret.getOffset();
|
||||
}
|
||||
|
||||
static int calcDefaultIdentifierEnd(Editor editor, int startFrom) {
|
||||
|
||||
+41
-6
@@ -71,6 +71,8 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class CodeCompletionHandlerBase {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.CodeCompletionHandlerBase");
|
||||
private static final Key<Boolean> CARET_PROCESSED = Key.create("CodeCompletionHandlerBase.caretProcessed");
|
||||
|
||||
@NotNull private final CompletionType myCompletionType;
|
||||
final boolean invokedExplicitly;
|
||||
final boolean synchronous;
|
||||
@@ -108,6 +110,13 @@ public class CodeCompletionHandlerBase {
|
||||
}
|
||||
|
||||
public final void invokeCompletion(@NotNull final Project project, @NotNull final Editor editor, int time, boolean hasModifiers, boolean restarted) {
|
||||
clearCaretMarkers(editor);
|
||||
invokeCompletion(project, editor, time, hasModifiers, restarted, editor.getCaretModel().getPrimaryCaret());
|
||||
}
|
||||
|
||||
public final void invokeCompletion(@NotNull final Project project, @NotNull final Editor editor, int time, boolean hasModifiers, boolean restarted, @NotNull final Caret caret) {
|
||||
markCaretAsProcessed(caret);
|
||||
|
||||
if (invokedExplicitly) {
|
||||
CompletionLookupArranger.applyLastCompletionStatisticsUpdate();
|
||||
}
|
||||
@@ -162,12 +171,12 @@ public class CodeCompletionHandlerBase {
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments();
|
||||
CompletionAssertions.checkEditorValid(editor);
|
||||
|
||||
final PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(editor, project);
|
||||
final PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(caret, project);
|
||||
assert psiFile != null : "no PSI file: " + FileDocumentManager.getInstance().getFile(editor.getDocument());
|
||||
psiFile.putUserData(PsiFileEx.BATCH_REFERENCE_PROCESSING, Boolean.TRUE);
|
||||
CompletionAssertions.assertCommitSuccessful(editor, psiFile);
|
||||
|
||||
initializationContext[0] = runContributorsBeforeCompletion(editor, psiFile, invocationCount);
|
||||
initializationContext[0] = runContributorsBeforeCompletion(editor, psiFile, invocationCount, caret);
|
||||
}
|
||||
};
|
||||
ApplicationManager.getApplication().runWriteAction(runnable);
|
||||
@@ -186,9 +195,9 @@ public class CodeCompletionHandlerBase {
|
||||
insertDummyIdentifier(initializationContext[0], hasModifiers, invocationCount);
|
||||
}
|
||||
|
||||
private CompletionInitializationContext runContributorsBeforeCompletion(Editor editor, PsiFile psiFile, int invocationCount) {
|
||||
private CompletionInitializationContext runContributorsBeforeCompletion(Editor editor, PsiFile psiFile, int invocationCount, Caret caret) {
|
||||
final Ref<CompletionContributor> current = Ref.create(null);
|
||||
CompletionInitializationContext context = new CompletionInitializationContext(editor, psiFile, myCompletionType, invocationCount) {
|
||||
CompletionInitializationContext context = new CompletionInitializationContext(editor, caret, psiFile, myCompletionType, invocationCount) {
|
||||
CompletionContributor dummyIdentifierChanger;
|
||||
|
||||
@Override
|
||||
@@ -400,8 +409,15 @@ public class CodeCompletionHandlerBase {
|
||||
final LookupElement[] items, boolean hasModifiers) {
|
||||
if (items.length == 0) {
|
||||
LookupManager.getInstance(indicator.getProject()).hideActiveLookup();
|
||||
indicator.handleEmptyLookup(true);
|
||||
checkNotSync(indicator, items);
|
||||
|
||||
Caret nextCaret = getNextCaretToProcess(indicator.getEditor());
|
||||
if (nextCaret != null) {
|
||||
invokeCompletion(indicator.getProject(), indicator.getEditor(), indicator.getParameters().getInvocationCount(), hasModifiers, false, nextCaret);
|
||||
}
|
||||
else {
|
||||
indicator.handleEmptyLookup(true);
|
||||
checkNotSync(indicator, items);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -866,4 +882,23 @@ public class CodeCompletionHandlerBase {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static void clearCaretMarkers(@NotNull Editor editor) {
|
||||
for (Caret caret : editor.getCaretModel().getAllCarets()) {
|
||||
caret.putUserData(CARET_PROCESSED, null);
|
||||
}
|
||||
}
|
||||
|
||||
private static void markCaretAsProcessed(@NotNull Caret caret) {
|
||||
caret.putUserData(CARET_PROCESSED, Boolean.TRUE);
|
||||
}
|
||||
|
||||
private static Caret getNextCaretToProcess(@NotNull Editor editor) {
|
||||
for (Caret caret : editor.getCaretModel().getAllCarets()) {
|
||||
if (caret.getUserData(CARET_PROCESSED) == null) {
|
||||
return caret;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,7 +566,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable,
|
||||
public void perform(Caret caret) {
|
||||
EditorModificationUtil.deleteSelectedText(hostEditor);
|
||||
final int caretOffset = hostEditor.getCaretModel().getOffset();
|
||||
int lookupStart = caretOffset - prefix;
|
||||
int lookupStart = Math.max(caretOffset - prefix, 0);
|
||||
|
||||
int len = hostEditor.getDocument().getTextLength();
|
||||
LOG.assertTrue(lookupStart >= 0 && lookupStart <= len,
|
||||
|
||||
Reference in New Issue
Block a user