diff --git a/platform/lang-impl/src/com/intellij/codeInsight/CodeInsightUtilBase.java b/platform/lang-impl/src/com/intellij/codeInsight/CodeInsightUtilBase.java index 7e9b614fe803..63dfe57da45a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/CodeInsightUtilBase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/CodeInsightUtilBase.java @@ -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; } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java index 76ff61bc5e10..00cf65981960 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java @@ -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; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/HippieWordCompletionHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/HippieWordCompletionHandler.java index d6ca655a7114..4f502326e482 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/HippieWordCompletionHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/HippieWordCompletionHandler.java @@ -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(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java index 665ddff6cc09..af94efd3cd4e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java @@ -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) { diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/GuardBlockTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/GuardBlockTest.java index 4e880b76bd66..01b205322c72 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/GuardBlockTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/GuardBlockTest.java @@ -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 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); } }