IDEA-118389 Forbid completion inside guard blocks

This commit is contained in:
peter
2014-01-13 17:14:16 +01:00
parent 44f1ff0c4b
commit f85e0e5bb5
5 changed files with 61 additions and 25 deletions
@@ -107,10 +107,16 @@ public class CodeInsightUtilBase extends CodeInsightUtilCore {
// returns true on success
public static boolean prepareEditorForWrite(@NotNull Editor editor) {
if (!editor.isViewer()) return true;
showReadOnlyViewWarning(editor);
return false;
}
public static void showReadOnlyViewWarning(Editor editor) {
if (ApplicationManager.getApplication().isHeadlessEnvironment()) return;
JComponent component = HintUtil.createInformationLabel("This view is read-only");
final LightweightHint hint = new LightweightHint(component);
HintManagerImpl.getInstanceImpl().showEditorHint(hint, editor, HintManager.UNDER,
HintManager.HIDE_BY_ANY_KEY | HintManager.HIDE_BY_TEXT_CHANGE | HintManager.HIDE_BY_SCROLLING, 0, false);
return false;
}
}
@@ -109,6 +109,10 @@ public class CodeCompletionHandlerBase {
}
public final void invokeCompletion(@NotNull final Project project, @NotNull final Editor editor, int time, boolean hasModifiers, boolean restarted) {
if (invokedExplicitly) {
CompletionLookupArranger.applyLastCompletionStatisticsUpdate();
}
final PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(editor, project);
assert psiFile != null : "no PSI file: " + FileDocumentManager.getInstance().getFile(editor.getDocument());
@@ -116,17 +120,13 @@ public class CodeCompletionHandlerBase {
CompletionAssertions.checkEditorValid(editor);
if (editor.isViewer()) {
if (editor.isViewer() || editor.getDocument().getOffsetGuard(editor.getCaretModel().getOffset()) != null) {
editor.getDocument().fireReadOnlyModificationAttempt();
CodeInsightUtilBase.showReadOnlyViewWarning(editor);
return;
}
if (invokedExplicitly) {
CompletionLookupArranger.applyLastCompletionStatisticsUpdate();
}
if (!CodeInsightUtilBase.prepareEditorForWrite(editor) ||
!FileDocumentManager.getInstance().requestWriting(editor.getDocument(), project)) {
if (!FileDocumentManager.getInstance().requestWriting(editor.getDocument(), project)) {
return;
}
@@ -17,6 +17,7 @@
package com.intellij.codeInsight.completion.actions;
import com.intellij.codeInsight.CodeInsightActionHandler;
import com.intellij.codeInsight.CodeInsightUtilBase;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.completion.impl.CamelHumpMatcher;
import com.intellij.codeInsight.highlighting.HighlightManager;
@@ -54,6 +55,12 @@ public class HippieWordCompletionHandler implements CodeInsightActionHandler {
public void invoke(@NotNull Project project, @NotNull final Editor editor, @NotNull PsiFile file) {
if (!FileModificationService.getInstance().prepareFileForWrite(file)) return;
if (editor.isViewer() || editor.getDocument().getOffsetGuard(editor.getCaretModel().getOffset()) != null) {
editor.getDocument().fireReadOnlyModificationAttempt();
CodeInsightUtilBase.showReadOnlyViewWarning(editor);
return;
}
LookupManager.getInstance(project).hideActiveLookup();
final CharSequence charsSequence = editor.getDocument().getCharsSequence();
@@ -654,7 +654,13 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
myFinishing = true;
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
insertLookupString(item, getPrefixLength(item));
myEditor.getDocument().startGuardedBlockChecking();
try {
insertLookupString(item, getPrefixLength(item));
}
finally {
myEditor.getDocument().stopGuardedBlockChecking();
}
}
});
@@ -768,12 +774,14 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
checkValid();
assert !myChangeGuard : "already in change";
myEditor.getDocument().startGuardedBlockChecking();
myChangeGuard = true;
boolean result;
try {
result = myOffsets.performGuardedChange(change, debug);
}
finally {
myEditor.getDocument().stopGuardedBlockChecking();
myChangeGuard = false;
}
if (!result || myDisposed) {
@@ -1,20 +1,22 @@
package com.intellij.openapi.editor.impl;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.testFramework.LightPlatformCodeInsightTestCase;
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
/**
* @author cdr
*/
public class GuardBlockTest extends LightPlatformCodeInsightTestCase {
private static RangeMarker createGuard(final int start, final int end) {
final Document document = getEditor().getDocument();
public class GuardBlockTest extends LightPlatformCodeInsightFixtureTestCase {
private RangeMarker createGuard(final int start, final int end) {
final Document document = myFixture.getEditor().getDocument();
return document.createGuardedBlock(start, end);
}
public void testZero() throws Exception {
configureFromFileText("x.txt", "xxxx");
myFixture.configureByText("x.txt", "xxxx");
RangeMarker guard = createGuard(0, 0);
guard.setGreedyToLeft(true);
guard.setGreedyToRight(true);
@@ -23,14 +25,14 @@ public class GuardBlockTest extends LightPlatformCodeInsightTestCase {
}
public void testInTheMiddle() throws Exception {
configureFromFileText("x.txt", "xxxxxxxx");
myFixture.configureByText("x.txt", "xxxxxxxx");
createGuard(1, 4);
checkUnableToTypeIn(2);
checkCanTypeIn(0);
}
public void testGreedy() throws Exception {
configureFromFileText("x.txt", "012345678");
myFixture.configureByText("x.txt", "012345678");
{
RangeMarker guard = createGuard(0, 5);
guard.setGreedyToLeft(true);
@@ -45,7 +47,7 @@ public class GuardBlockTest extends LightPlatformCodeInsightTestCase {
checkUnableToTypeIn(0);
}
public void testGreedyEnd() throws Exception {
configureFromFileText("x.txt", "012345678");
myFixture.configureByText("x.txt", "012345678");
{
RangeMarker guard = createGuard(0, 5);
guard.setGreedyToLeft(true);
@@ -54,22 +56,35 @@ public class GuardBlockTest extends LightPlatformCodeInsightTestCase {
checkUnableToTypeIn(5);
}
private static void checkUnableToTypeIn(int offset) {
String text = getEditor().getDocument().getText();
private void checkUnableToTypeIn(int offset) {
String text = myFixture.getEditor().getDocument().getText();
try {
getEditor().getCaretModel().moveToOffset(offset);
type("y");
myFixture.getEditor().getCaretModel().moveToOffset(offset);
myFixture.type("y");
}
catch (RuntimeException e) {
assertEquals("Unable to perform an action since it changes read-only fragments of the current document",e.getMessage());
assertEquals(text, getEditor().getDocument().getText());
assertEquals(text, myFixture.getEditor().getDocument().getText());
return;
}
fail("must be read only at "+offset);
}
private static void checkCanTypeIn(int offset) {
getEditor().getCaretModel().moveToOffset(offset);
type("yy");
private void checkCanTypeIn(int offset) {
myFixture.getEditor().getCaretModel().moveToOffset(offset);
myFixture.type("yy");
}
public void testNoCompletion() throws Exception {
String text = "abc abd a<caret> abx";
myFixture.configureByText("x.txt", text);
createGuard(0, myFixture.getFile().getTextLength());
assertNull(myFixture.completeBasic());
myFixture.checkResult(text);
myFixture.performEditorAction(IdeActions.ACTION_HIPPIE_BACKWARD_COMPLETION);
assertNull(LookupManager.getInstance(getProject()).getActiveLookup());
myFixture.checkResult(text);
}
}