Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dmitry Trofimov
2011-11-23 12:48:50 +01:00
79 changed files with 1673 additions and 845 deletions
Binary file not shown.
Binary file not shown.
@@ -426,14 +426,4 @@ public class JVMNameUtil {
}
return "";
}
public static PsiClass getTopLevelParentClass(PsiClass psiClass) {
PsiClass enclosing = PsiTreeUtil.getParentOfType(psiClass, PsiClass.class, true);
while (enclosing != null) {
psiClass = enclosing;
enclosing = PsiTreeUtil.getParentOfType(enclosing, PsiClass.class, true);
}
return psiClass;
}
}
@@ -85,7 +85,7 @@ public class PositionManagerImpl implements PositionManager {
}
if (PsiUtil.isLocalOrAnonymousClass(psiClass)) {
PsiClass parent = JVMNameUtil.getTopLevelParentClass(psiClass);
PsiClass parent = TopLevelParentClassProvider.getTopLevelParentClass(psiClass);
if (parent == null) {
return;
@@ -244,7 +244,7 @@ public class PositionManagerImpl implements PositionManager {
}
if(PsiUtil.isLocalOrAnonymousClass(psiClass)) {
final PsiClass parentNonLocal = JVMNameUtil.getTopLevelParentClass(psiClass);
final PsiClass parentNonLocal = TopLevelParentClassProvider.getTopLevelParentClass(psiClass);
if(parentNonLocal == null) {
LOG.error("Local or anonymous class has no non-local parent");
return null;
@@ -0,0 +1,47 @@
/*
* Copyright 2000-2011 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.debugger.engine;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.psi.PsiClass;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.Nullable;
/**
* @author Max Medvedev
*/
public abstract class TopLevelParentClassProvider {
private static final ExtensionPointName<TopLevelParentClassProvider> EP_NAME =
ExtensionPointName.create("com.intellij.topLevelClassProvider");
public static PsiClass getTopLevelParentClass(PsiClass psiClass) {
for (TopLevelParentClassProvider provider : EP_NAME.getExtensions()) {
final PsiClass custom = provider.getCustomTopLevelParentClass(psiClass);
if (custom != null) return custom;
}
PsiClass enclosing = PsiTreeUtil.getParentOfType(psiClass, PsiClass.class, true);
while (enclosing != null) {
psiClass = enclosing;
enclosing = PsiTreeUtil.getParentOfType(enclosing, PsiClass.class, true);
}
return psiClass;
}
@Nullable
protected abstract PsiClass getCustomTopLevelParentClass(PsiClass psiClass);
}
@@ -98,7 +98,7 @@ public class StringLiteralCopyPasteProcessor implements CopyPastePreProcessor {
numberOfSymbolsToCopy = Math.min(escapedEndOffset, fileEndOffset) - Math.max(fileStartOffset, escapedStartOffset);
if (numberOfSymbolsToCopy > 0) {
textWasChanged = true;
buffer.append(unescapeStringCharacters(text.substring(givenTextStartOffset, givenTextStartOffset + numberOfSymbolsToCopy)));
buffer.append(unescape(text.substring(givenTextStartOffset, givenTextStartOffset + numberOfSymbolsToCopy), element));
givenTextStartOffset += numberOfSymbolsToCopy;
}
@@ -112,7 +112,12 @@ public class StringLiteralCopyPasteProcessor implements CopyPastePreProcessor {
}
return textWasChanged ? buffer.toString() : null;
}
@NotNull
protected String unescape(String text, PsiElement token) {
return unescapeStringCharacters(text);
}
public String preprocessOnPaste(final Project project, final PsiFile file, final Editor editor, String text, final RawText rawText) {
final Document document = editor.getDocument();
PsiDocumentManager.getInstance(project).commitDocument(document);
@@ -139,9 +144,10 @@ public class StringLiteralCopyPasteProcessor implements CopyPastePreProcessor {
@NonNls String breaker = getLineBreaker(token);
final String[] lines = LineTokenizer.tokenize(text.toCharArray(), false, true);
for (int i = 0; i < lines.length; i++) {
String line = lines[i];
buffer.append(escapeCharCharacters(line, token, escapeSlashes));
if (i != lines.length - 1) buffer.append(breaker);
buffer.append(escapeCharCharacters(lines[i], token, escapeSlashes));
if (i != lines.length - 1 || "\n".equals(breaker) && text.endsWith("\n")) {
buffer.append(breaker);
}
}
text = buffer.toString();
}
@@ -16,12 +16,17 @@
package com.intellij.ide.util;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifier;
import com.intellij.psi.presentation.java.SymbolPresentationUtil;
import com.intellij.psi.search.PsiElementProcessor;
import com.intellij.psi.search.searches.DeepestSuperMethodsSearch;
import com.intellij.ui.components.JBList;
import com.intellij.usageView.UsageViewUtil;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
@@ -102,4 +107,51 @@ public class SuperMethodWarningUtil {
return null;
}
public static void checkSuperMethod(final PsiMethod method,
final String actionString,
final PsiElementProcessor<PsiMethod> processor,
final Editor editor) {
PsiClass aClass = method.getContainingClass();
if (aClass == null) {
processor.execute(method);
return;
}
PsiMethod superMethod = method.findDeepestSuperMethod();
if (superMethod == null) {
processor.execute(method);
return;
}
final PsiClass containingClass = superMethod.getContainingClass();
if (containingClass == null) {
processor.execute(method);
return;
}
if (ApplicationManager.getApplication().isUnitTestMode()) {
processor.execute(superMethod);
return;
}
final PsiMethod[] methods = new PsiMethod[]{superMethod, method};
final String renameBase = actionString + " base method";
final String renameCurrent = actionString + " only current method";
final JBList list = new JBList(renameBase, renameCurrent);
JBPopupFactory.getInstance().createListPopupBuilder(list)
.setTitle(method.getName() + (containingClass.isInterface() && !aClass.isInterface() ? " implements" : " overrides") + " method of " +
SymbolPresentationUtil.getSymbolPresentableText(containingClass))
.setMovable(false)
.setResizable(false)
.setRequestFocus(true)
.setItemChoosenCallback(new Runnable() {
public void run() {
final Object value = list.getSelectedValue();
if (value instanceof String) {
processor.execute(methods[value.equals(renameBase) ? 0 : 1]);
}
}
}).createPopup().showInBestPositionFor(editor);
}
}
@@ -65,9 +65,6 @@ public class JavaRefactoringSupportProvider extends RefactoringSupportProvider {
@Override
public boolean isMemberInplaceRenameAvailable(PsiElement elementToRename, PsiElement context) {
if (elementToRename instanceof PsiMethod && ((PsiMethod)elementToRename).findDeepestSuperMethods().length > 0) {
return false;
}
return elementToRename instanceof PsiMember;
}
@@ -0,0 +1,150 @@
/*
* Copyright 2000-2011 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.impl.light;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.search.SearchScope;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class LightField extends LightElement implements PsiField {
private final PsiField myField;
private final PsiClass myContainingClass;
public LightField(@NotNull final PsiManager manager, @NotNull final PsiField field, @NotNull final PsiClass containingClass) {
super(manager, JavaLanguage.INSTANCE);
myField = field;
myContainingClass = containingClass;
}
@Override
public void setInitializer(@Nullable final PsiExpression initializer) throws IncorrectOperationException {
throw new IncorrectOperationException("Not supported");
}
@NotNull
@Override
public SearchScope getUseScope() {
return myField.getUseScope();
}
@Override
public String getName() {
return myField.getName();
}
@NotNull
@Override
public PsiIdentifier getNameIdentifier() {
return myField.getNameIdentifier();
}
@Override
public PsiDocComment getDocComment() {
return myField.getDocComment();
}
@Override
public boolean isDeprecated() {
return myField.isDeprecated();
}
@Override
public PsiClass getContainingClass() {
return myContainingClass;
}
@NotNull
@Override
public PsiType getType() {
return myField.getType();
}
@Override
public PsiTypeElement getTypeElement() {
return myField.getTypeElement();
}
@Override
public PsiExpression getInitializer() {
return myField.getInitializer();
}
@Override
public boolean hasInitializer() {
return myField.hasInitializer();
}
@Override
public void normalizeDeclaration() throws IncorrectOperationException {
throw new IncorrectOperationException("Not supported");
}
@Override
public Object computeConstantValue() {
return myField.computeConstantValue();
}
@Override
public PsiElement setName(@NonNls @NotNull final String name) throws IncorrectOperationException {
throw new IncorrectOperationException("Not supported");
}
@Override
public PsiType getTypeNoResolve() {
return myField.getTypeNoResolve();
}
@Override
public PsiModifierList getModifierList() {
return myField.getModifierList();
}
@Override
public boolean hasModifierProperty(@Modifier @NonNls @NotNull final String name) {
return myField.hasModifierProperty(name);
}
@Override
public String getText() {
return myField.getText();
}
@Override
public PsiElement copy() {
return new LightField(myManager, (PsiField)myField.copy(), myContainingClass);
}
@Override
public TextRange getTextRange() {
return new TextRange(-1, -1);
}
@Override
public boolean isValid() {
return myContainingClass.isValid();
}
@Override
public String toString() {
return "PsiField:" + getName();
}
}
@@ -18,8 +18,10 @@ package com.intellij.refactoring.rename;
import com.intellij.ide.util.SuperMethodWarningUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.Pass;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiElementProcessor;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.search.searches.MethodReferencesSearch;
@@ -237,6 +239,25 @@ public class RenameJavaMethodProcessor extends RenameJavaMemberProcessor {
return SuperMethodWarningUtil.checkSuperMethod(psiMethod, RefactoringBundle.message("to.rename"));
}
@Override
public void substituteElementToRename(@NotNull PsiElement element,
@NotNull Editor editor,
@NotNull final Pass<PsiElement> renameCallback) {
PsiMethod psiMethod = (PsiMethod)element;
if (psiMethod.isConstructor()) {
super.substituteElementToRename(element, editor, renameCallback);
}
else {
SuperMethodWarningUtil.checkSuperMethod(psiMethod, "Rename", new PsiElementProcessor<PsiMethod>() {
@Override
public boolean execute(@NotNull PsiMethod method) {
renameCallback.pass(method);
return false;
}
}, editor);
}
}
private static void findSubmemberHidesMemberCollisions(final PsiMethod method, final String newName, final List<UsageInfo> result) {
final PsiClass containingClass = method.getContainingClass();
if (containingClass == null) return;
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 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.
@@ -14,22 +14,23 @@
* limitations under the License.
*/
/*
* @author max
*/
package com.intellij.psi.impl.java.stubs;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.impl.cache.TypeInfo;
import com.intellij.psi.stubs.NamedStub;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author max
*/
public interface PsiMethodStub extends NamedStub<PsiMethod> {
boolean isConstructor();
boolean isVarArgs();
boolean isAnnotationMethod();
String getDefaultValueText();
@Nullable String getDefaultValueText();
@NotNull TypeInfo getReturnTypeText(boolean doResolve);
boolean isDeprecated();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 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.
@@ -174,8 +174,9 @@ public class PsiMethodStubImpl extends StubBase<PsiMethod> implements PsiMethodS
builder.append(getName()).append(":").append(TypeInfo.createTypeText(getReturnTypeText(false)));
if (getDefaultValueText() != null) {
builder.append(" default=").append(getDefaultValueText());
final String defaultValue = getDefaultValueText();
if (defaultValue != null) {
builder.append(" default=").append(defaultValue);
}
builder.append("]");
@@ -41,10 +41,6 @@ public class LightMethod extends LightElement implements PsiMethod {
private final PsiMethod myMethod;
private final PsiClass myContainingClass;
public LightMethod(PsiMethod method, PsiClass containingClass) {
this(method.getManager(), method, containingClass);
}
public LightMethod(PsiManager manager, PsiMethod method, PsiClass containingClass) {
super(manager, JavaLanguage.INSTANCE);
myMethod = method;
@@ -60,6 +60,22 @@ class Foo { List a; Map b; }
assertEquals 0, foldRegion.startOffset
assertEquals text.indexOf("import") - 1, foldRegion.endOffset
}
public void testSubsequentCollapseBlock() {
def text = """\
class Test {
void test(int i) {
if (i > 1) {
<caret>i++;
}
}
}
"""
configure text
myFixture.performEditorAction 'CollapseBlock'
myFixture.performEditorAction 'CollapseBlock'
assertEquals(text.indexOf('}', text.indexOf('i++')), myFixture.editor.caretModel.offset)
}
private def configure(String text) {
myFixture.configureByText("a.java", text)
@@ -0,0 +1,43 @@
/*
* Copyright 2000-2011 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.editor.ex;
import java.util.Iterator;
import java.util.NoSuchElementException;
public interface DisposableIterator<T> extends Iterator<T> {
void dispose();
DisposableIterator EMPTY = new DisposableIterator() {
@Override
public void dispose() {
}
@Override
public boolean hasNext() {
return false;
}
@Override
public Object next() {
throw new NoSuchElementException();
}
@Override
public void remove() {
throw new IllegalAccessError();
}
};
}
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.editor.impl;
import com.intellij.openapi.editor.ex.DisposableIterator;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.Trinity;
import com.intellij.util.IncorrectOperationException;
@@ -22,14 +23,12 @@ import com.intellij.util.Processor;
import com.intellij.util.SmartList;
import com.intellij.util.WalkingState;
import com.intellij.util.concurrency.AtomicFieldUpdater;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.TLongHashSet;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.lang.ref.ReferenceQueue;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.locks.Lock;
@@ -495,15 +494,18 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
}
@NotNull
Iterator<T> overlappingIterator(final int startOffset, final int endOffset) {
DisposableIterator<T> overlappingIterator(final int startOffset, final int endOffset) {
final IntervalNode<T> firstOverlap = findMinOverlappingWith(getRoot(), new TextRangeInterval(startOffset, endOffset), modCount, 0);
if (firstOverlap == null) {
return ContainerUtil.emptyIterator();
return DisposableIterator.EMPTY;
}
final int firstOverlapDelta = firstOverlap.computeDeltaUpToRoot();
final int firstOverlapStart = firstOverlap.intervalStart() + firstOverlapDelta;
final int modCountBefore = modCount;
return new Iterator<T>() {
l.readLock().lock();
return new DisposableIterator<T>() {
private IntervalNode<T> currentNode = firstOverlap;
private int deltaUpToRootExclusive = firstOverlapDelta-firstOverlap.delta;
private int indexInCurrentList = 0;
@@ -513,39 +515,33 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
public boolean hasNext() {
if (current != null) return true;
if (currentNode == null) return false;
try {
l.readLock().lock();
if (modCount != modCountBefore) throw new ConcurrentModificationException();
while (indexInCurrentList != currentNode.intervals.size()) {
T t = currentNode.intervals.get(indexInCurrentList++).get();
if (t != null) {
current = t;
return true;
}
}
indexInCurrentList = 0;
while (true) {
currentNode = nextNode(currentNode);
if (currentNode == null) {
return false;
}
if (overlaps(currentNode, startOffset, endOffset, deltaUpToRootExclusive)) {
assert currentNode.intervalStart() + deltaUpToRootExclusive + currentNode.delta >= firstOverlapStart;
indexInCurrentList = 0;
while (indexInCurrentList != currentNode.intervals.size()) {
T t = currentNode.intervals.get(indexInCurrentList++).get();
if (t != null) {
current = t;
return true;
}
}
indexInCurrentList = 0;
}
if (modCount != modCountBefore) throw new ConcurrentModificationException();
while (indexInCurrentList != currentNode.intervals.size()) {
T t = currentNode.intervals.get(indexInCurrentList++).get();
if (t != null) {
current = t;
return true;
}
}
finally {
l.readLock().unlock();
indexInCurrentList = 0;
while (true) {
currentNode = nextNode(currentNode);
if (currentNode == null) {
return false;
}
if (overlaps(currentNode, startOffset, endOffset, deltaUpToRootExclusive)) {
assert currentNode.intervalStart() + deltaUpToRootExclusive + currentNode.delta >= firstOverlapStart;
indexInCurrentList = 0;
while (indexInCurrentList != currentNode.intervals.size()) {
T t = currentNode.intervals.get(indexInCurrentList++).get();
if (t != null) {
current = t;
return true;
}
}
indexInCurrentList = 0;
}
}
}
@@ -562,6 +558,11 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
throw new IncorrectOperationException();
}
@Override
public void dispose() {
l.readLock().unlock();
}
// next node in in-order traversal
private IntervalNode<T> nextNode(@NotNull IntervalNode<T> root) {
assert root.isValid();
@@ -52,9 +52,13 @@ public abstract class PsiCachedValue<T> extends CachedValueBase<T> {
@Override
protected boolean isDependencyOutOfDate(Object dependency, long oldTimeStamp) {
return !(dependency instanceof PsiElement && myLastPsiTimeStamp == myManager.getModificationTracker().getModificationCount()) &&
super.isDependencyOutOfDate(dependency, oldTimeStamp);
if (dependency instanceof PsiElement &&
myLastPsiTimeStamp == myManager.getModificationTracker().getModificationCount() &&
((PsiElement)dependency).isPhysical()) {
return false;
}
return super.isDependencyOutOfDate(dependency, oldTimeStamp);
}
@Override
@@ -20,11 +20,11 @@ package com.intellij.ide;
*/
public interface StandardTargetWeights {
float PROJECT_WEIGHT = 1;
float FAVORITES_WEIGHT = 1.01f;
float PACKAGES_WEIGHT = 2;
float J2EE_WEIGHT = 3;
float STRUCTURE_WEIGHT = 4;
float COMMANDER_WEIGHT = 5;
float FAVORITES_WEIGHT = 6;
float SCOPE_WEIGHT = 6.5f;
float NAV_BAR_WEIGHT = 8;
float CHANGES_VIEW = 9;
@@ -125,7 +125,6 @@ public class EnterHandler extends BaseEnterHandler {
if (result == EnterHandlerDelegate.Result.Stop) return;
if (result != EnterHandlerDelegate.Result.Continue) {
text = document.getCharsSequence();
if (result == EnterHandlerDelegate.Result.DefaultForceIndent) {
forceIndent = true;
}
@@ -133,6 +132,7 @@ public class EnterHandler extends BaseEnterHandler {
}
}
text = document.getCharsSequence(); // update after changes done in preprocessEnter()
caretOffset = caretOffsetRef.get().intValue();
boolean isFirstColumn = caretOffset == 0 || text.charAt(caretOffset - 1) == '\n';
final boolean insertSpace =
@@ -409,6 +409,7 @@ public abstract class LogConsoleBase extends AdditionalTabComponent implements L
myConsole.print(fragment.getText(), consoleViewType);
}
}
return true;
}
else {
final LogFilterModel.MyProcessingResult processingResult = myModel.processLine(line);
@@ -422,11 +423,12 @@ public abstract class LogConsoleBase extends AdditionalTabComponent implements L
myConsole.print(messagePrefix, type);
}
myConsole.print(line + "\n", type);
return true;
}
}
}
return false;
}
return true;
}
@NotNull
@@ -180,9 +180,6 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider {
myPanel.removeAll();
myPanel.add(myHistoryViewer.getComponent(), BorderLayout.CENTER);
myFullEditor = fileManager.openTextEditor(new OpenFileDescriptor(getProject(), virtualFile, 0), true);
configureFullEditor();
setConsoleFilePinned(fileManager);
myHistoryViewer.setHorizontalScrollbarVisible(true);
myCurrentEditor = myFullEditor;
}
@@ -201,7 +198,7 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider {
public void setFullEditorActions(ActionGroup actionGroup) {
myFullEditorActions = actionGroup;
configureFullEditor();
configureFullEditor(myFullEditor);
}
public void setShowSeparatorLine(boolean showSeparatorLine) {
@@ -539,6 +536,11 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider {
for (FileEditor fileEditor : source.getAllEditors(file)) {
if (!(fileEditor instanceof TextEditor)) continue;
final Editor editor = ((TextEditor)fileEditor).getEditor();
// todo what if it is splitted?
myCurrentEditor = editor;
myFullEditor = editor;
configureFullEditor(editor);
setConsoleFilePinned((FileEditorManagerEx)source);
EmptyAction.registerActionShortcuts(editor.getComponent(), myConsoleEditor.getComponent());
editor.getCaretModel().addCaretListener(new CaretListener() {
public void caretPositionChanged(CaretEvent e) {
@@ -595,20 +597,18 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider {
}
editorManager.closeFile(file);
myFullEditor = editorManager.openTextEditor(new OpenFileDescriptor(getProject(), newVFile, offset), focusEditor);
configureFullEditor();
setConsoleFilePinned(editorManager);
}
}
}
private void configureFullEditor() {
if (myFullEditor == null || myFullEditorActions == null) return;
private void configureFullEditor(final Editor editor) {
if (editor == null || myFullEditorActions == null) return;
final JPanel header = new JPanel(new BorderLayout());
final ActionToolbar actionToolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, myFullEditorActions, true);
actionToolbar.setTargetComponent(myFullEditor.getContentComponent());
actionToolbar.setTargetComponent(editor.getContentComponent());
header.add(actionToolbar.getComponent(), BorderLayout.EAST);
myFullEditor.setHeaderComponent(header);
myFullEditor.getSettings().setLineMarkerAreaShown(false);
editor.setHeaderComponent(header);
editor.getSettings().setLineMarkerAreaShown(false);
}
public void setInputText(final String query) {
@@ -220,7 +220,8 @@ public class PsiCopyPasteManager {
if (myElements == null || myElements.length == 0) {
return null;
}
return myElements [0].getProject();
final PsiElement element = myElements[0];
return element.isValid() ? element.getProject() : null;
}
}
@@ -52,7 +52,11 @@ import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.ui.*;
import com.intellij.util.*;
import com.intellij.ui.treeStructure.actions.CollapseAllAction;
import com.intellij.util.ArrayUtil;
import com.intellij.util.EditSourceOnDoubleClickHandler;
import com.intellij.util.EditSourceOnEnterKeyHandler;
import com.intellij.util.IconUtil;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.tree.TreeUtil;
import org.jetbrains.annotations.NotNull;
@@ -68,6 +72,10 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author anna
* @author Konstantin Bulenkov
*/
public class FavoritesTreeViewPanel extends JPanel implements DataProvider {
private final FavoritesTreeStructure myFavoritesTreeStructure;
private FavoritesViewTreeBuilder myBuilder;
@@ -167,6 +175,7 @@ public class FavoritesTreeViewPanel extends JPanel implements DataProvider {
return CustomShortcutSet.fromString("DELETE");
}
})
.addExtraAction(AnActionButton.fromAction(new CollapseAllAction(myTree)))
.setLineBorder(0, 0, 0, 0)
.createPanel();
panel.setBorder(IdeBorderFactory.createEmptyBorder(0));
@@ -16,19 +16,26 @@
package com.intellij.ide.favoritesTreeView;
import com.intellij.ide.SelectInContext;
import com.intellij.ide.SelectInManager;
import com.intellij.ide.StandardTargetWeights;
import com.intellij.ide.impl.ProjectViewSelectInTarget;
import com.intellij.ide.impl.SelectInTargetPsiWrapper;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFileSystemItem;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowId;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* User: anna
* Date: Feb 25, 2005
* @author anna
* @author Konstantin Bulenkov
*/
public class FavoritesViewSelectInTarget extends ProjectViewSelectInTarget {
public class FavoritesViewSelectInTarget extends SelectInTargetPsiWrapper {
public FavoritesViewSelectInTarget(final Project project) {
super(project);
}
@@ -37,8 +44,68 @@ public class FavoritesViewSelectInTarget extends ProjectViewSelectInTarget {
return SelectInManager.FAVORITES;
}
@Override
public String getToolWindowId() {
return SelectInManager.FAVORITES;
}
@Override
protected void select(Object selector, VirtualFile virtualFile, boolean requestFocus) {
select(myProject, selector, null, null, virtualFile, requestFocus);
}
@Override
protected void select(PsiElement element, boolean requestFocus) {
PsiElement toSelect = null;
if (element instanceof PsiFile || element instanceof PsiDirectory) {
toSelect = element;
}
else {
final PsiFile containingFile = element.getContainingFile();
if (containingFile == null) return;
final FileViewProvider viewProvider = containingFile.getViewProvider();
toSelect = viewProvider.getPsi(viewProvider.getBaseLanguage());
}
if (toSelect == null) return;
PsiElement originalElement = toSelect.getOriginalElement();
final VirtualFile virtualFile = PsiUtilBase.getVirtualFile(originalElement);
select(originalElement, virtualFile, requestFocus);
}
public static ActionCallback select(@NotNull Project project,
final Object toSelect,
@Nullable final String viewId,
@Nullable final String subviewId,
final VirtualFile virtualFile,
final boolean requestFocus) {
final ActionCallback result = new ActionCallback();
ToolWindowManager windowManager=ToolWindowManager.getInstance(project);
final ToolWindow favoritesToolWindow = windowManager.getToolWindow(ToolWindowId.FAVORITES_VIEW);
if (favoritesToolWindow != null) {
final FavoritesTreeViewPanel panel = UIUtil.findComponentOfType(favoritesToolWindow.getComponent(), FavoritesTreeViewPanel.class);
if (panel != null) {
final Runnable runnable = new Runnable() {
public void run() {
panel.selectElement(toSelect, virtualFile, requestFocus);
result.setDone();
}
};
if (requestFocus) {
favoritesToolWindow.activate(runnable, false);
} else {
favoritesToolWindow.show(runnable);
}
}
}
return result;
}
protected boolean canSelect(final PsiFileSystemItem file) {
if (!super.canSelect(file)) return false;
return findSuitableFavoritesList(file.getVirtualFile(), myProject, null) != null;
}
@@ -63,9 +130,4 @@ public class FavoritesViewSelectInTarget extends ProjectViewSelectInTarget {
protected boolean canWorkWithCustomObjects() {
return false;
}
public boolean isSubIdSelectable(String subId, SelectInContext context) {
final FavoritesManager favoritesManager = FavoritesManager.getInstance(myProject);
return favoritesManager.contains(subId, context.getVirtualFile());
}
}
@@ -51,7 +51,6 @@ import com.intellij.util.EditSourceOnDoubleClickHandler;
import com.intellij.util.OpenSourceUtil;
import com.intellij.util.PlatformIcons;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.tree.TreeUtil;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -503,17 +502,7 @@ abstract class TodoPanel extends SimpleToolWindowPanel implements OccurenceNavig
@Nullable
private OccurenceInfo goToPointer(TodoItemNode pointer) {
if (pointer == null) return null;
DefaultMutableTreeNode node = myTodoTreeBuilder.getNodeForElement(pointer);
if (node == null) {
myTodoTreeBuilder.buildNodeForElement(pointer);
node = myTodoTreeBuilder.getNodeForElement(pointer);
if (node == null) {
// TODO[vova] it seems that this check isn't required any more bacause it was side effect of SCR#7063
// TODO[vova] try to remove this check in Aurora
return null;
}
}
TreeUtil.selectPath(myTree, new TreePath(node.getPath()));
myTodoTreeBuilder.select(pointer);
return new OccurenceInfo(
new OpenFileDescriptor(myProject, pointer.getValue().getTodoItem().getFile().getVirtualFile(),
pointer.getValue().getRangeMarker().getStartOffset()),
@@ -371,7 +371,10 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec
});
if (ok[0]) {
((InjectedLanguageManagerImpl)InjectedLanguageManager.getInstance(myProject)).startRunInjectors(document, synchronously);
// otherwise changes maybe not synced to the document yet, and injectors will crash
if (!mySynchronizer.isDocumentAffectedByTransactions(document)) {
((InjectedLanguageManagerImpl)InjectedLanguageManager.getInstance(myProject)).startRunInjectors(document, synchronously);
}
// run after commit actions outside write action
runAfterCommitActions(document);
if (DebugUtil.DO_EXPENSIVE_CHECKS) {
@@ -21,6 +21,7 @@ import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Pass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileSystemItem;
@@ -161,6 +162,18 @@ public abstract class RenamePsiElementProcessor {
return element;
}
/**
* Substitutes element to be renamed and initiate rename procedure. Should be used in order to prevent modal dialogs to appear during inplace rename
* @param element the element on which refactoring was invoked
* @param editor the editor in which inplace refactoring was invoked
* @param renameCallback rename procedure which should be called on the chosen substitution
*/
public void substituteElementToRename(@NotNull final PsiElement element, @NotNull Editor editor, @NotNull Pass<PsiElement> renameCallback) {
final PsiElement psiElement = substituteElementToRename(element, editor);
if (psiElement == null) return;
renameCallback.pass(psiElement);
}
public void findCollisions(final PsiElement element, final String newName, final Map<? extends PsiElement, String> allRenames,
final List<UsageInfo> result) {
}
@@ -0,0 +1,41 @@
/*
* Copyright 2000-2011 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.refactoring.rename.inplace;
import com.intellij.codeInsight.completion.CompletionContributor;
import com.intellij.codeInsight.completion.CompletionParameters;
import com.intellij.codeInsight.completion.CompletionResultSet;
import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
import com.intellij.codeInsight.template.impl.TemplateState;
import com.intellij.openapi.editor.Editor;
/**
* User: anna
* Date: 11/22/11
*/
public class CompletionContributorForInplaceRename extends CompletionContributor {
@Override
public void fillCompletionVariants(CompletionParameters parameters, CompletionResultSet result) {
final Editor editor = parameters.getLookup().getEditor();
final TemplateState state = TemplateManagerImpl.getTemplateState(editor);
if (state != null) {
if (editor.getUserData(VariableInplaceRenamer.INPLACE_RENAMER) != null) {
result.stopHere();
}
}
}
}
@@ -18,12 +18,15 @@ package com.intellij.refactoring.rename.inplace;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.lang.LanguageRefactoringSupport;
import com.intellij.lang.refactoring.RefactoringSupportProvider;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.Pass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiNameIdentifierOwner;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.rename.RenamePsiElementProcessor;
import org.jetbrains.annotations.NotNull;
/**
@@ -45,9 +48,20 @@ public class MemberInplaceRenameHandler extends VariableInplaceRenameHandler {
}
@Override
protected VariableInplaceRenamer createRenamer(@NotNull PsiElement elementToRename, Editor editor) {
public VariableInplaceRenamer doRename(@NotNull final PsiElement elementToRename, final Editor editor, final DataContext dataContext) {
if (elementToRename instanceof PsiNameIdentifierOwner) {
return new MemberInplaceRenamer((PsiNameIdentifierOwner)elementToRename, editor);
RenamePsiElementProcessor.forElement(elementToRename).substituteElementToRename(elementToRename, editor, new Pass<PsiElement>() {
@Override
public void pass(PsiElement element) {
final MemberInplaceRenamer renamer = new MemberInplaceRenamer((PsiNameIdentifierOwner)elementToRename, element, editor);
boolean startedRename = renamer.performInplaceRename();
if (!startedRename) {
performDialogRename(elementToRename, editor, dataContext);
}
}
});
} else {
performDialogRename(elementToRename, editor, dataContext);
}
return null;
}
@@ -25,6 +25,7 @@ import com.intellij.openapi.command.impl.FinishMarkAction;
import com.intellij.openapi.command.impl.StartMarkAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
@@ -34,6 +35,7 @@ import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.ProjectScope;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.rename.RenameProcessor;
import com.intellij.refactoring.rename.RenamePsiElementProcessor;
@@ -53,10 +55,15 @@ import java.util.List;
*/
public class MemberInplaceRenamer extends VariableInplaceRenamer {
protected final String myOldName;
private final PsiElement mySubstituted;
private RangeMarker mySubstitutedRange;
public MemberInplaceRenamer(@NotNull PsiNameIdentifierOwner elementToRename, Editor editor) {
public MemberInplaceRenamer(@NotNull PsiNameIdentifierOwner elementToRename, PsiElement substituted, Editor editor) {
super(elementToRename, editor);
myOldName = elementToRename.getName();
mySubstituted = substituted;
mySubstitutedRange = mySubstituted != null && mySubstituted != myElementToRename && mySubstituted.getTextRange() != null ? myEditor.getDocument().createRangeMarker(mySubstituted.getTextRange()) : null;
showDialogAdvertisement("RenameElement");
}
@@ -99,8 +106,7 @@ public class MemberInplaceRenamer extends VariableInplaceRenamer {
final ArrayList<PsiReference> references = new ArrayList<PsiReference>(super.collectRefs(referencesSearchScope));
final PsiNamedElement variable = getVariable();
if (variable != null) {
final RenamePsiElementProcessor processor = RenamePsiElementProcessor.forElement(variable);
final PsiElement substituted = processor.substituteElementToRename(variable, myEditor);
final PsiElement substituted = getSubstituted();
if (substituted != null && substituted != variable) {
references.addAll(ReferencesSearch.search(substituted, referencesSearchScope, false).findAll());
}
@@ -126,11 +132,10 @@ public class MemberInplaceRenamer extends VariableInplaceRenamer {
boolean showChooser = super.appendAdditionalElement(stringUsages);
PsiNamedElement variable = getVariable();
if (variable != null) {
RenamePsiElementProcessor processor = RenamePsiElementProcessor.forElement(variable);
final PsiElement substituted = processor.substituteElementToRename(variable, myEditor);
final PsiElement substituted = getSubstituted();
if (substituted != null) {
appendAdditionalElement(stringUsages, variable, substituted);
processor = RenamePsiElementProcessor.forElement(substituted);
RenamePsiElementProcessor processor = RenamePsiElementProcessor.forElement(substituted);
final HashMap<PsiElement, String> allRenames = new HashMap<PsiElement, String>();
PsiFile currentFile = PsiDocumentManager.getInstance(myProject).getPsiFile(myEditor.getDocument());
processor.prepareRenaming(substituted, "", allRenames, new LocalSearchScope(currentFile));
@@ -163,9 +168,8 @@ public class MemberInplaceRenamer extends VariableInplaceRenamer {
final NamesValidator namesValidator = LanguageNamesValidation.INSTANCE.forLanguage(variable.getLanguage());
LOG.assertTrue(namesValidator != null);
if (namesValidator.isIdentifier(newName, myProject)) {
RenamePsiElementProcessor processor = RenamePsiElementProcessor.forElement(variable);
final PsiElement substitutedElement = processor.substituteElementToRename(variable, myEditor);
if (substitutedElement == null) {
final PsiElement substituted = getSubstituted();
if (substituted == null) {
return;
}
@@ -173,13 +177,14 @@ public class MemberInplaceRenamer extends VariableInplaceRenamer {
.message("renaming.0.1.to.2", UsageViewUtil.getType(variable), UsageViewUtil.getDescriptiveName(variable), newName);
CommandProcessor.getInstance().executeCommand(myProject, new Runnable() {
public void run() {
final RenamePsiElementProcessor elementProcessor = RenamePsiElementProcessor.forElement(substitutedElement);
final RenamePsiElementProcessor elementProcessor = RenamePsiElementProcessor.forElement(substituted);
final RenameProcessor
renameProcessor = new RenameProcessor(myProject, substitutedElement, newName,
elementProcessor.isToSearchInComments(substitutedElement),
elementProcessor.isToSearchForTextOccurrences(substitutedElement));
renameProcessor = new RenameProcessor(myProject, substituted, newName,
elementProcessor.isToSearchInComments(substituted),
elementProcessor.isToSearchForTextOccurrences(substituted));
for (AutomaticRenamerFactory factory : Extensions.getExtensions(AutomaticRenamerFactory.EP_NAME)) {
if (factory.isApplicable(substitutedElement) && factory.getOptionName() != null) {
if (factory.isApplicable(substituted) && factory.getOptionName() != null) {
if (factory.isEnabled()) {
renameProcessor.addRenamerFactory(factory);
}
@@ -254,4 +259,16 @@ public class MemberInplaceRenamer extends VariableInplaceRenamer {
if (ex[0] != null) throw ex[0];
return markAction[0];
}
@Nullable
public PsiElement getSubstituted() {
if (mySubstituted != null && mySubstituted.isValid()) return mySubstituted;
if (mySubstitutedRange != null) {
final PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(myEditor.getDocument());
if (psiFile != null) {
return PsiTreeUtil.getParentOfType(psiFile.findElementAt(mySubstitutedRange.getStartOffset()), PsiNameIdentifierOwner.class);
}
}
return getVariable();
}
}
@@ -112,23 +112,26 @@ public class VariableInplaceRenameHandler implements RenameHandler {
boolean startedRename = renamer == null ? false : renamer.performInplaceRename();
if (!startedRename) {
try {
ourPreventInlineRenameFlag.set(Boolean.TRUE);
RenameHandler handler = RenameHandlerRegistry.getInstance().getRenameHandler(dataContext);
assert handler != null;
handler.invoke(
elementToRename.getProject(),
editor,
elementToRename.getContainingFile(), dataContext
);
} finally {
ourPreventInlineRenameFlag.set(null);
}
performDialogRename(elementToRename, editor, dataContext);
}
return renamer;
}
protected static void performDialogRename(PsiElement elementToRename, Editor editor, DataContext dataContext) {
try {
ourPreventInlineRenameFlag.set(Boolean.TRUE);
RenameHandler handler = RenameHandlerRegistry.getInstance().getRenameHandler(dataContext);
assert handler != null;
handler.invoke(
elementToRename.getProject(),
editor,
elementToRename.getContainingFile(), dataContext
);
} finally {
ourPreventInlineRenameFlag.set(null);
}
}
@Nullable
protected VariableInplaceRenamer createRenamer(@NotNull PsiElement elementToRename, Editor editor) {
return new VariableInplaceRenamer((PsiNameIdentifierOwner)elementToRename, editor);
@@ -932,7 +932,8 @@ public class FileBasedIndex implements ApplicationComponent {
public static @Nullable Throwable getCauseToRebuildIndex(RuntimeException e) {
Throwable cause = e.getCause();
if (cause instanceof StorageException || cause instanceof IOException || cause instanceof IllegalArgumentException) return cause;
if (cause instanceof StorageException || cause instanceof IOException ||
cause instanceof IllegalArgumentException || cause instanceof IllegalStateException) return cause;
return null;
}
@@ -30,6 +30,7 @@ public abstract class AnActionButton extends AnAction implements ShortcutProvide
private boolean myEnabled = true;
private boolean myVisible = true;
private ShortcutSet myShortcut;
private AnAction myAction = null;
private JComponent myContextComponent;
public AnActionButton(String text) {
@@ -47,6 +48,29 @@ public abstract class AnActionButton extends AnAction implements ShortcutProvide
public AnActionButton() {
}
public static AnActionButton fromAction(final AnAction action) {
final Presentation presentation = action.getTemplatePresentation();
return new AnActionButton(presentation.getText(),
presentation.getDescription(),
presentation.getIcon()) {
@Override
public void actionPerformed(AnActionEvent e) {
action.actionPerformed(e);
}
@Override
public void updateButton(AnActionEvent e) {
action.update(e);
final boolean enabled = e.getPresentation().isEnabled();
final boolean visible = e.getPresentation().isVisible();
if (enabled && visible) {
super.updateButton(e);
}
}
};
}
public boolean isEnabled() {
return myEnabled;
@@ -66,9 +90,17 @@ public abstract class AnActionButton extends AnAction implements ShortcutProvide
@Override
public final void update(AnActionEvent e) {
final boolean enabled = isEnabled() && isContextComponentOk();
boolean myActionVisible = true;
boolean myActionEnabled = true;
if (myAction != null) {
myAction.update(e);
myActionEnabled = myAction.getTemplatePresentation().isEnabled();
myActionVisible = myAction.getTemplatePresentation().isVisible();
}
final boolean enabled = isEnabled() && isContextComponentOk() && myActionEnabled;
e.getPresentation().setEnabled(enabled);
e.getPresentation().setVisible(isVisible());
e.getPresentation().setVisible(isVisible() && myActionVisible);
if (enabled) {
updateButton(e);
}
@@ -23,8 +23,10 @@ import javax.swing.*;
public class TabsUtil {
public static final int TAB_VERTICAL_PADDING = 3;
public static final int TABS_BORDER = 1;
public static final int TAB_VERTICAL_PADDING = 2;
public static final int TABS_BORDER = 1;
public static final int ACTIVE_TAB_UNDERLINE_HEIGHT = 4;
private TabsUtil() {
}
@@ -21,6 +21,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.ui.tabs.JBTabsPosition;
import com.intellij.ui.tabs.TabInfo;
import com.intellij.ui.tabs.TabsUtil;
import com.intellij.util.ui.SameColor;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
@@ -69,16 +70,24 @@ public class JBEditorTabs extends JBTabsImpl {
int _height = effectiveBounds.height - insets.top - insets.bottom;
if ((!isSingleRow() && label.getBounds().y > 0 /* for multiline */) || (isSingleRow() && isHorizontalTabs())) {
if (isSingleRow() && getPosition() == JBTabsPosition.bottom) {
_y += TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT;
} else {
_height -= TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT;
}
}
Color tabColor = label.getInfo().getTabColor();
if (tabColor != null) {
//g2d.setPaint(new LinearGradientPaint(_x, _y, _x, _y + effectiveBounds.height, new float[] {.3f, .6f, 1f}, new Color[] {new SameColor(170), new SameColor(150), new SameColor(90)}));
g2d.setPaint(new GradientPaint(_x, _y, new SameColor(170), _x, _y + effectiveBounds.height, new SameColor(150)));
g2d.setPaint(new GradientPaint(_x, _y, new SameColor(200), _x, _y + effectiveBounds.height, new SameColor(130)));
g2d.fillRect(_x, _y, _width, _height);
g2d.setColor(new Color(tabColor.getRed(), tabColor.getGreen(), tabColor.getBlue(), 150));
g2d.fillRect(_x, _y, _width, _height);
} else {
g2d.setPaint(new GradientPaint(_x, _y, new Color(255, 255, 255, 140), _x, _y + effectiveBounds.height, new Color(255, 255, 255, 90)));
g2d.setPaint(new GradientPaint(_x, _y, new Color(255, 255, 255, 180), _x, _y + effectiveBounds.height, new Color(255, 255, 255, 100)));
g2d.fillRect(_x, _y, _width, _height);
}
@@ -130,7 +139,9 @@ public class JBEditorTabs extends JBTabsImpl {
int y = r2.y + insets.top;
int height = maxLength - insets.top - insets.bottom;
if (getTabsPosition() == JBTabsPosition.bottom) {
y = r2.height - height - insets.top;
y = r2.height - height - insets.top + TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT;
} else {
height -= TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT;
}
rectangle = new Rectangle(maxOffset, y, r2.width - maxOffset - insets.left - insets.right, height);
@@ -163,22 +174,20 @@ public class JBEditorTabs extends JBTabsImpl {
int _x = r.x;
int _y = r.y;
int _height = r.height;
//g2d.setColor(Color.WHITE);
//g2d.draw(
// selectedShape.labelPath.transformLine(i.left, selectedShape.labelPath.getMaxY()
// - selectedShape.labelPath.deltaY(3), selectedShape.path.getMaxX(), selectedShape.labelPath.getMaxY() - selectedShape.labelPath.deltaY(3)));
if (getPosition() == JBTabsPosition.left || getPosition() == JBTabsPosition.right) {
g2d.setColor(new Color(0, 0, 0, 45));
g2d.draw(
selectedShape.labelPath.transformLine(i.left, selectedShape.labelPath.getMaxY()
- selectedShape.labelPath.deltaY(4), selectedShape.path.getMaxX(),
selectedShape.labelPath.getMaxY() - selectedShape.labelPath.deltaY(4)));
g2d.setColor(new Color(0, 0, 0, 45));
g2d.draw(
selectedShape.labelPath.transformLine(i.left, selectedShape.labelPath.getMaxY()
- selectedShape.labelPath.deltaY(4), selectedShape.path.getMaxX(), selectedShape.labelPath.getMaxY() - selectedShape.labelPath.deltaY(4)));
g2d.setColor(new Color(0, 0, 0, 15));
g2d.draw(
selectedShape.labelPath.transformLine(i.left, selectedShape.labelPath.getMaxY()
- selectedShape.labelPath.deltaY(5), selectedShape.path.getMaxX(), selectedShape.labelPath.getMaxY() - selectedShape.labelPath.deltaY(5)));
g2d.setColor(new Color(0, 0, 0, 15));
g2d.draw(
selectedShape.labelPath.transformLine(i.left, selectedShape.labelPath.getMaxY()
- selectedShape.labelPath.deltaY(5), selectedShape.path.getMaxX(),
selectedShape.labelPath.getMaxY() - selectedShape.labelPath.deltaY(5)));
}
Color tabColor = label.getInfo().getTabColor();
if (tabColor != null) {
@@ -201,26 +210,31 @@ public class JBEditorTabs extends JBTabsImpl {
selectedShape.labelPath.deltaY(1),
selectedShape.labelPath.getMaxX() - selectedShape.labelPath.deltaX(1), selectedShape.labelPath.getMaxY() -
selectedShape.labelPath.deltaY(4)));
// side shadow
g2d.setColor(new Color(0, 0, 0, 30));
g2d.draw(selectedShape.labelPath
.transformLine(selectedShape.labelPath.getMaxX() + selectedShape.labelPath.deltaX(1), selectedShape.labelPath.getY() +
selectedShape.labelPath.deltaY(1),
selectedShape.labelPath.getMaxX() + selectedShape.labelPath.deltaX(1), selectedShape.labelPath.getMaxY() -
selectedShape.labelPath.deltaY(4)));
boolean horizontal = getPosition() == JBTabsPosition.top || getPosition() == JBTabsPosition.bottom;
g2d.draw(selectedShape.labelPath
.transformLine(selectedShape.labelPath.getX() - selectedShape.labelPath.deltaX(horizontal ? 2 : 1), selectedShape.labelPath.getY() +
selectedShape.labelPath.deltaY(1),
selectedShape.labelPath.getX() - selectedShape.labelPath.deltaX(horizontal ? 2 : 1), selectedShape.labelPath.getMaxY() -
selectedShape.labelPath.deltaY(4)));
if (!isHorizontalTabs()) {
// side shadow
g2d.setColor(new Color(0, 0, 0, 30));
g2d.draw(selectedShape.labelPath
.transformLine(selectedShape.labelPath.getMaxX() + selectedShape.labelPath.deltaX(1), selectedShape.labelPath.getY() +
selectedShape.labelPath.deltaY(1),
selectedShape.labelPath.getMaxX() + selectedShape.labelPath.deltaX(1), selectedShape.labelPath.getMaxY() -
selectedShape.labelPath.deltaY(4)));
boolean horizontal = getPosition() == JBTabsPosition.top || getPosition() == JBTabsPosition.bottom;
g2d.draw(selectedShape.labelPath
.transformLine(selectedShape.labelPath.getX() - selectedShape.labelPath.deltaX(horizontal ? 2 : 1),
selectedShape.labelPath.getY() +
selectedShape.labelPath.deltaY(1),
selectedShape.labelPath.getX() - selectedShape.labelPath.deltaX(horizontal ? 2 : 1),
selectedShape.labelPath.getMaxY() -
selectedShape.labelPath.deltaY(4)));
}
g2d.setColor(new Color(0, 0, 0, 50));
g2d.draw(selectedShape.labelPath.transformLine(i.left, selectedShape.labelPath.getMaxY(),
selectedShape.path.getMaxX(), selectedShape.labelPath.getMaxY()));
selectedShape.path.getMaxX(),
selectedShape.labelPath.getMaxY()));
}
@Override
@@ -235,7 +249,7 @@ public class JBEditorTabs extends JBTabsImpl {
shape.insets = shape.path.transformInsets(getLayoutInsets());
shape.labelPath = shape.path.createTransform(getSelectedLabel().getBounds());
shape.labelBottomY = shape.labelPath.getMaxY() - shape.labelPath.deltaY(3);
shape.labelBottomY = shape.labelPath.getMaxY() - shape.labelPath.deltaY(TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT - 1);
shape.labelTopY =
shape.labelPath.getY() + (getPosition() == JBTabsPosition.top || getPosition() == JBTabsPosition.bottom ? shape.labelPath.deltaY(1) : 0) ;
shape.labelLeftX = shape.labelPath.getX() + (getPosition() == JBTabsPosition.top || getPosition() == JBTabsPosition.bottom ? 0 : shape.labelPath.deltaX(
@@ -253,8 +267,8 @@ public class JBEditorTabs extends JBTabsImpl {
int lastX = shape.path.getWidth() - shape.path.deltaX(shape.insets.right);
shape.path.lineTo(lastX, shape.labelBottomY);
shape.path.lineTo(lastX, shape.labelBottomY + shape.labelPath.deltaY(3));
shape.path.lineTo(leftX, shape.labelBottomY + shape.labelPath.deltaY(3));
shape.path.lineTo(lastX, shape.labelBottomY + shape.labelPath.deltaY(TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT - 1));
shape.path.lineTo(leftX, shape.labelBottomY + shape.labelPath.deltaY(TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT - 1));
shape.path.closePath();
shape.fillPath = shape.path.copy();
@@ -29,6 +29,7 @@ import com.intellij.ui.SimpleColoredText;
import com.intellij.ui.components.panels.Wrapper;
import com.intellij.ui.tabs.JBTabsPosition;
import com.intellij.ui.tabs.TabInfo;
import com.intellij.ui.tabs.TabsUtil;
import com.intellij.ui.tabs.UiDecorator;
import com.intellij.util.PairConsumer;
import com.intellij.util.ui.Centerizer;
@@ -223,11 +224,11 @@ public class TabLabel extends JPanel {
}
private int getNonSelectedOffset() {
return myTabs.isEditorTabs() ? 0 : 2;
return myTabs.isEditorTabs() ? -(TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT / 2) + 1 : 2;
}
private int getSelectedOffset() {
return myTabs.isEditorTabs() ? 0 : 1;
return myTabs.isEditorTabs() ? -(TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT / 2) + 1 : 1;
}
@Override
@@ -236,7 +237,7 @@ public class TabLabel extends JPanel {
final JBTabsPosition pos = myTabs.getTabsPosition();
switch (pos) {
case top: case bottom: size.height += getSelectedOffset(); break;
case top: case bottom: size.height += myTabs.isEditorTabs() ? TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT : getSelectedOffset(); break;
case left: case right: size.width += getSelectedOffset(); break;
}
@@ -16,6 +16,7 @@
package com.intellij.ui.tabs.impl.table;
import com.intellij.ui.tabs.TabInfo;
import com.intellij.ui.tabs.TabsUtil;
import com.intellij.ui.tabs.impl.JBTabsImpl;
import com.intellij.ui.tabs.impl.LayoutPassInfo;
import com.intellij.ui.tabs.impl.TabLabel;
@@ -118,6 +119,9 @@ public class TableLayout extends TabLayout {
final Insets insets = myTabs.getLayoutInsets();
int eachY = insets.top;
int eachX;
int row = 0;
final int tabUnderlineFix = myTabs.isEditorTabs() ? TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT : 0;
for (TableRow eachRow : data.table) {
eachX = insets.left;
@@ -142,14 +146,15 @@ public class TableLayout extends TabLayout {
width = data.toFitRec.width + insets.left - eachX;
}
myTabs.layout(label, eachX, eachY, width, myTabs.myHeaderFitSize.height);
myTabs.layout(label, eachX, eachY, width, row < data.table.size() - 1 ? myTabs.myHeaderFitSize.height - tabUnderlineFix : myTabs.myHeaderFitSize.height);
label.setAligmentToCenter(deltaToFit > 0);
boolean lastCell = i == eachRow.myColumns.size() - 1;
eachX += width + (lastCell ? 0 : myTabs.getInterTabSpaceLength());
}
eachY += myTabs.myHeaderFitSize.height - 1 + myTabs.getInterTabSpaceLength();
eachY += myTabs.myHeaderFitSize.height - 1 + myTabs.getInterTabSpaceLength() - (row < data.table.size() - 1 ? tabUnderlineFix : 0);
row++;
}
if (myTabs.getSelectedInfo() != null) {
@@ -104,7 +104,7 @@ public class ActionInstallPlugin extends AnAction implements DumbAware {
}
final InstalledPluginsTableModel installedPluginsModel = (InstalledPluginsTableModel)installed.getPluginsModel();
for (PluginNode node : list) {
installedPluginsModel.appendDescriptor(node);
installedPluginsModel.appendOrUpdateDescriptor(node);
}
installed.setRequireShutdown(true);
}
@@ -91,7 +91,7 @@ public class InstalledPluginsManagerMain extends PluginManagerMain {
return;
}
PluginDownloader.install(file, file.getName());
((InstalledPluginsTableModel)pluginsModel).appendDescriptor(pluginDescriptor);
((InstalledPluginsTableModel)pluginsModel).appendOrUpdateDescriptor(pluginDescriptor);
select(pluginDescriptor);
setRequireShutdown(true);
}
@@ -84,11 +84,17 @@ public class InstalledPluginsTableModel extends PluginTableModel {
setSortKey(new RowSorter.SortKey(getNameColumn(), SortOrder.ASCENDING));
}
public void appendDescriptor(IdeaPluginDescriptor descriptor) {
myInstalled.add(descriptor);
view.add(descriptor);
setEnabled(descriptor, true);
fireTableDataChanged();
public void appendOrUpdateDescriptor(IdeaPluginDescriptor descriptor) {
final PluginId descrId = descriptor.getPluginId();
final IdeaPluginDescriptor existing = PluginManager.getPlugin(descrId);
if (existing != null) {
updateExistingPluginInfo(descriptor, existing);
} else {
myInstalled.add(descriptor);
view.add(descriptor);
setEnabled(descriptor, true);
fireTableDataChanged();
}
}
public static int getCheckboxColumn() {
@@ -18,6 +18,7 @@ package com.intellij.injected.editor;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.ex.DisposableIterator;
import com.intellij.openapi.editor.ex.MarkupModelEx;
import com.intellij.openapi.editor.ex.RangeHighlighterEx;
import com.intellij.openapi.editor.ex.SweepProcessor;
@@ -25,15 +26,13 @@ import com.intellij.openapi.editor.impl.event.MarkupModelListener;
import com.intellij.openapi.editor.markup.HighlighterTargetArea;
import com.intellij.openapi.editor.markup.RangeHighlighter;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.util.ProperTextRange;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.openapi.util.ProperTextRange;
import com.intellij.util.Consumer;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import java.util.Iterator;
/**
* @author cdr
*/
@@ -146,7 +145,7 @@ public class MarkupModelWindow extends UserDataHolderBase implements MarkupModel
@NotNull
@Override
public Iterator<RangeHighlighterEx> overlappingIterator(int startOffset, int endOffset) {
public DisposableIterator<RangeHighlighterEx> overlappingIterator(int startOffset, int endOffset) {
// todo convert
return myHostModel.overlappingIterator(startOffset, endOffset);
}
@@ -26,8 +26,6 @@ import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Iterator;
/**
* @author max
*/
@@ -46,7 +44,7 @@ public interface MarkupModelEx extends MarkupModel {
boolean processRangeHighlightersOutside(int start, int end, @NotNull Processor<? super RangeHighlighterEx> processor);
@NotNull
Iterator<RangeHighlighterEx> overlappingIterator(int startOffset, int endOffset);
DisposableIterator<RangeHighlighterEx> overlappingIterator(int startOffset, int endOffset);
// optimization: creates highlighter and fires only one event: highlighterCreated
RangeHighlighterEx addRangeHighlighterAndChangeAttributes(int startOffset,
@@ -320,26 +320,32 @@ public class EditorUtil {
EditorEx editorImpl = (EditorEx)editor;
int offset = start;
IterationState state = new IterationState(editorImpl, start, end, false);
int fontType = state.getMergedAttributes().getFontType();
int column = currentColumn[0];
int spaceSize = getSpaceWidth(fontType, editorImpl);
for (; column < columnNumber && offset < end; offset++) {
if (offset >= state.getEndOffset()) {
state.advance();
fontType = state.getMergedAttributes().getFontType();
}
int column;
try {
int fontType = state.getMergedAttributes().getFontType();
column = currentColumn[0];
int spaceSize = getSpaceWidth(fontType, editorImpl);
for (; column < columnNumber && offset < end; offset++) {
if (offset >= state.getEndOffset()) {
state.advance();
fontType = state.getMergedAttributes().getFontType();
}
char c = text.charAt(offset);
if (c == '\t') {
int prevX = x;
x = nextTabStop(x, editorImpl);
column += columnsNumber(x - prevX, spaceSize);
}
else {
x += charWidth(c, fontType, editorImpl);
column++;
char c = text.charAt(offset);
if (c == '\t') {
int prevX = x;
x = nextTabStop(x, editorImpl);
column += columnsNumber(x - prevX, spaceSize);
}
else {
x += charWidth(c, fontType, editorImpl);
column++;
}
}
}
finally {
state.dispose();
}
if (column == columnNumber) {
return offset;
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 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.
@@ -46,6 +46,7 @@ import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.diff.FilesTooBigForDiffException;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.util.List;
@@ -186,21 +187,21 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener,
public void moveToOffset(int offset, boolean locateBeforeSoftWrap) {
assertIsDispatchThread();
validateCallContext();
moveToLogicalPosition(myEditor.offsetToLogicalPosition(offset), locateBeforeSoftWrap);
if (!ignoreWrongMoves && !myEditor.offsetToLogicalPosition(myOffset).equals(myEditor.offsetToLogicalPosition(offset))) {
StringBuilder documentInfo = new StringBuilder();
Document document = myEditor.getDocument();
for (int line = 0; line < document.getLineCount(); line++) {
documentInfo.append(line).append(": ").append(document.getLineStartOffset(line)).append("-")
.append(document.getLineEndOffset(line)).append(", ");
}
if (documentInfo.length() > 0) {
documentInfo.setLength(documentInfo.length() - 1);
}
final LogicalPosition logicalPosition = myEditor.offsetToLogicalPosition(offset);
moveToLogicalPosition(logicalPosition, locateBeforeSoftWrap, null);
if (!ignoreWrongMoves && !myEditor.offsetToLogicalPosition(myOffset).equals(logicalPosition)) {
StringBuilder debugBuffer = new StringBuilder();
moveToLogicalPosition(logicalPosition, locateBeforeSoftWrap, debugBuffer);
int textStart = Math.max(0, Math.min(offset, myOffset) - 1);
final DocumentEx document = myEditor.getDocument();
int textEnd = Math.min(document.getTextLength() - 1, Math.max(offset, myOffset) + 1);
CharSequence text = document.getCharsSequence().subSequence(textStart, textEnd);
LOG.error(
"caret moved to wrong offset. Requested: offset=" + offset + ", logical position=" + myEditor.offsetToLogicalPosition(offset)
"caret moved to wrong offset. Requested: offset=" + offset + ", logical position=" + logicalPosition
+ " but actual: offset=" + myOffset + ", logical position=" + myLogicalCaret + "(" + myEditor.offsetToLogicalPosition(myOffset)
+ "). " + myEditor.dumpState()
+ "\n interested text [" + textStart + "; " + textEnd + "): '" + text + "'"
+ "\n debug trace: " + debugBuffer
);
}
}
@@ -361,11 +362,16 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener,
@Override
public void moveToLogicalPosition(@NotNull LogicalPosition pos) {
moveToLogicalPosition(pos, false);
moveToLogicalPosition(pos, false, null);
}
private void moveToLogicalPosition(LogicalPosition pos, boolean locateBeforeSoftWrap) {
private void moveToLogicalPosition(@NotNull LogicalPosition pos, boolean locateBeforeSoftWrap, @Nullable StringBuilder debugBuffer) {
assertIsDispatchThread();
if (debugBuffer != null) {
debugBuffer.append(String.format(
"Start moveToLogicalPosition(). Locate before soft wrap: %b, position: %s", locateBeforeSoftWrap, pos
));
}
myDesiredX = -1;
validateCallContext();
int column = pos.column;
@@ -377,10 +383,16 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener,
Document doc = myEditor.getDocument();
if (column < 0) {
if (debugBuffer != null) {
debugBuffer.append("Resetting target logical column to zero as it is negative (" + column + ")");
}
column = 0;
softWrapColumns = 0;
}
if (line < 0) {
if (debugBuffer != null) {
debugBuffer.append("Resetting target logical line to zero as it is negative (" + line + ")");
}
line = 0;
softWrapLinesBefore = 0;
softWrapLinesCurrent = 0;
@@ -388,9 +400,17 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener,
int lineCount = doc.getLineCount();
if (lineCount == 0) {
if (debugBuffer != null) {
debugBuffer.append("Resetting target logical line to zero as the document is empty");
}
line = 0;
}
else if (line > lineCount - 1) {
if (debugBuffer != null) {
debugBuffer.append(String.format(
"Resetting target logical line (%d) to %d as it is greater than total document lines number", line, lineCount - 1
));
}
line = lineCount - 1;
softWrapLinesBefore = 0;
softWrapLinesCurrent = 0;
@@ -400,12 +420,21 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener,
if (!editorSettings.isVirtualSpace() && line < lineCount && !myEditor.getSelectionModel().hasBlockSelection()) {
int lineEndOffset = doc.getLineEndOffset(line);
int lineEndColumnNumber = myEditor.offsetToLogicalPosition(lineEndOffset).column;
final LogicalPosition endLinePosition = myEditor.offsetToLogicalPosition(lineEndOffset);
int lineEndColumnNumber = endLinePosition.column;
if (column > lineEndColumnNumber) {
int oldColumn = column;
column = lineEndColumnNumber;
if (softWrapColumns != 0) {
softWrapColumns -= column - lineEndColumnNumber;
}
if (debugBuffer != null) {
debugBuffer.append(String.format(
"Resetting target logical column (%d) to %d because caret is not allowed to be located after line end (offset: %d, "
+ "logical position: %s). Current soft wrap columns value: %d",
oldColumn, lineEndColumnNumber, lineEndOffset, endLinePosition, softWrapColumns
));
}
}
}
@@ -424,12 +453,17 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener,
logicalPositionToUse = new LogicalPosition(line, column);
}
setCurrentLogicalCaret(logicalPositionToUse);
final int offset = myEditor.logicalPositionToOffset(myLogicalCaret);
if (debugBuffer != null) {
debugBuffer.append(String.format("Resulting logical position to use: %s. It's mapped to offset %d", myLogicalCaret, offset));
}
FoldRegion collapsedAt = myEditor.getFoldingModel().getCollapsedRegionAtOffset(offset);
if (collapsedAt != null && offset > collapsedAt.getStartOffset()) {
if (debugBuffer != null) {
debugBuffer.append("Scheduling expansion of fold region ").append(collapsedAt);
}
Runnable runnable = new Runnable() {
@Override
public void run() {
@@ -447,6 +481,9 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener,
myVisibleCaret = myEditor.logicalToVisualPosition(myLogicalCaret);
myOffset = myEditor.logicalPositionToOffset(myLogicalCaret);
if (debugBuffer != null) {
debugBuffer.append(String.format("Storing offset %d (mapped from logical position %s)", myOffset, myLogicalCaret));
}
LOG.assertTrue(myOffset >= 0 && myOffset <= myEditor.getDocument().getTextLength());
myVisualLineStart = myEditor.logicalPositionToOffset(myEditor.visualToLogicalPosition(new VisualPosition(myVisibleCaret.line, 0)));
@@ -458,7 +495,13 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener,
if (locateBeforeSoftWrap && SoftWrapHelper.isCaretAfterSoftWrap(myEditor)) {
int lineToUse = myVisibleCaret.line - 1;
if (lineToUse >= 0) {
moveToVisualPosition(new VisualPosition(lineToUse, EditorUtil.getLastVisualLineColumnNumber(myEditor, lineToUse)));
final VisualPosition visualPosition = new VisualPosition(lineToUse, EditorUtil.getLastVisualLineColumnNumber(myEditor, lineToUse));
if (debugBuffer != null) {
debugBuffer.append(String.format(
"Adjusting caret position by moving it before soft wrap. Moving to visual position %s", visualPosition
));
}
moveToVisualPosition(visualPosition);
return;
}
}
@@ -561,7 +604,7 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener,
finishUpdate();
DocumentEventImpl event = (DocumentEventImpl)e;
final Document document = myEditor.getDocument();
final DocumentEx document = myEditor.getDocument();
boolean performSoftWrapAdjustment = e.getNewLength() > 0 // We want to put caret just after the last added symbol
// There is a possible case that the user removes text just before the soft wrap. We want to keep caret
// on a visual line with soft wrap start then.
@@ -576,7 +619,7 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener,
final int line;
try {
line = event.translateLineViaDiff(myLogicalCaret.line);
moveToLogicalPosition(new LogicalPosition(line, myLogicalCaret.column), performSoftWrapAdjustment);
moveToLogicalPosition(new LogicalPosition(line, myLogicalCaret.column), performSoftWrapAdjustment, null);
}
catch (FilesTooBigForDiffException e1) {
LOG.info(e1);
@@ -585,7 +628,7 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener,
}
}
else {
if (document instanceof DocumentEx && ((DocumentEx)document).isInBulkUpdate()) return;
if (document.isInBulkUpdate()) return;
int startOffset = e.getOffset();
int oldEndOffset = startOffset + e.getOldLength();
@@ -399,64 +399,69 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
int docLength = document.getTextLength();
int patchedStartOffset = startOffset < docLength ? document.getLineStartOffset(document.getLineNumber(startOffset)) : docLength;
int patchedEndOffset = endOffset <= docLength ? document.getLineEndOffset(document.getLineNumber(endOffset)) + 1 : docLength;
Iterator<RangeHighlighterEx> docHighlighters = docMarkup.overlappingIterator(patchedStartOffset, patchedEndOffset);
DisposableIterator<RangeHighlighterEx> docHighlighters = docMarkup.overlappingIterator(patchedStartOffset, patchedEndOffset);
final MarkupModelEx editorMarkup = (MarkupModelEx)myEditor.getMarkupModel();
Iterator<RangeHighlighterEx> editorHighlighters = editorMarkup.overlappingIterator(startOffset, endOffset);
DisposableIterator<RangeHighlighterEx> editorHighlighters = editorMarkup.overlappingIterator(startOffset, endOffset);
RangeHighlighterEx lastDocHighlighter = null;
RangeHighlighterEx lastEditorHighlighter = null;
try {
RangeHighlighterEx lastDocHighlighter = null;
RangeHighlighterEx lastEditorHighlighter = null;
while (true) {
if (lastDocHighlighter == null && docHighlighters.hasNext()) {
lastDocHighlighter = docHighlighters.next();
if (!lastDocHighlighter.isValid() || lastDocHighlighter.getAffectedAreaStartOffset() > endOffset) {
lastDocHighlighter = null;
continue;
}
if (lastDocHighlighter.getAffectedAreaEndOffset() < startOffset) {
lastDocHighlighter = null;
continue;
}
}
while (true) {
if (lastDocHighlighter == null && docHighlighters.hasNext()) {
lastDocHighlighter = docHighlighters.next();
if (!lastDocHighlighter.isValid() || lastDocHighlighter.getAffectedAreaStartOffset() > endOffset) {
if (lastEditorHighlighter == null && editorHighlighters.hasNext()) {
lastEditorHighlighter = editorHighlighters.next();
if (!lastEditorHighlighter.isValid() || lastEditorHighlighter.getAffectedAreaStartOffset() > endOffset) {
lastEditorHighlighter = null;
continue;
}
if (lastEditorHighlighter.getAffectedAreaEndOffset() < startOffset) {
lastEditorHighlighter = null;
continue;
}
}
if (lastDocHighlighter == null && lastEditorHighlighter == null) return;
final RangeHighlighterEx lowerHighlighter;
if (less(lastDocHighlighter, lastEditorHighlighter)) {
lowerHighlighter = lastDocHighlighter;
lastDocHighlighter = null;
continue;
}
if (lastDocHighlighter.getAffectedAreaEndOffset() < startOffset) {
lastDocHighlighter = null;
continue;
}
}
if (lastEditorHighlighter == null && editorHighlighters.hasNext()) {
lastEditorHighlighter = editorHighlighters.next();
if (!lastEditorHighlighter.isValid() || lastEditorHighlighter.getAffectedAreaStartOffset() > endOffset) {
else {
lowerHighlighter = lastEditorHighlighter;
lastEditorHighlighter = null;
continue;
}
if (lastEditorHighlighter.getAffectedAreaEndOffset() < startOffset) {
lastEditorHighlighter = null;
continue;
assert lowerHighlighter != null;
if (!lowerHighlighter.isValid()) continue;
int startLineIndex = lowerHighlighter.getDocument().getLineNumber(startOffset);
if (startLineIndex < 0 || startLineIndex >= document.getLineCount()) continue;
int endLineIndex = lowerHighlighter.getDocument().getLineNumber(endOffset);
if (endLineIndex < 0 || endLineIndex >= document.getLineCount()) continue;
if (lowerHighlighter.getEditorFilter().avaliableIn(myEditor)) {
processor.process(lowerHighlighter);
}
}
if (lastDocHighlighter == null && lastEditorHighlighter == null) return;
final RangeHighlighterEx lowerHighlighter;
if (less(lastDocHighlighter, lastEditorHighlighter)) {
lowerHighlighter = lastDocHighlighter;
lastDocHighlighter = null;
}
else {
lowerHighlighter = lastEditorHighlighter;
lastEditorHighlighter = null;
}
assert lowerHighlighter != null;
if (!lowerHighlighter.isValid()) continue;
int startLineIndex = lowerHighlighter.getDocument().getLineNumber(startOffset);
if (startLineIndex < 0 || startLineIndex >= document.getLineCount()) continue;
int endLineIndex = lowerHighlighter.getDocument().getLineNumber(endOffset);
if (endLineIndex < 0 || endLineIndex >= document.getLineCount()) continue;
if (lowerHighlighter.getEditorFilter().avaliableIn(myEditor)) {
processor.process(lowerHighlighter);
}
}
finally {
docHighlighters.dispose();
editorHighlighters.dispose();
}
}
@@ -968,7 +973,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
@Override
public boolean isAnnotationsShown() {
return myTextAnnotationGutters.size() > 0;
return !myTextAnnotationGutters.isEmpty();
}
@Override
@@ -1122,7 +1127,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
}
}
if (toolTip != null && toolTip.length() != 0) {
if (toolTip != null && !toolTip.isEmpty()) {
final Ref<Point> t = new Ref<Point>(e.getPoint());
int line = myEditor.yPositionToLogicalLine(e.getY());
ArrayList<GutterIconRenderer> row = myLineToGutterRenderers.get(line);
@@ -985,10 +985,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
// We mark that we're under such circumstances then.
boolean activeSoftWrapProcessed = logicalPosition.softWrapLinesOnCurrentLogicalLine <= 0;
int column = 0;
int prevX = 0;
CharSequence text = myDocument.getCharsNoThreadCheck();
char c = ' ';
LogicalPosition endLogicalPosition = visualToLogicalPosition(new VisualPosition(line+1, 0));
int endOffset = logicalPositionToOffset(endLogicalPosition);
@@ -1004,125 +1001,133 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
IterationState state = new IterationState(this, offset, endOffset, false);
int fontType = state.getMergedAttributes().getFontType();
int spaceSize = EditorUtil.getSpaceWidth(fontType, this);
try {
int fontType = state.getMergedAttributes().getFontType();
int spaceSize = EditorUtil.getSpaceWidth(fontType, this);
int x = 0;
int charWidth;
boolean onSoftWrapDrawing = false;
outer:
while (true) {
charWidth = -1;
if (offset >= textLength) {
break;
}
int x = 0;
int charWidth;
boolean onSoftWrapDrawing = false;
char c = ' ';
int prevX = 0;
int column = 0;
outer:
while (true) {
charWidth = -1;
if (offset >= textLength) {
break;
}
if (offset >= state.getEndOffset()) {
state.advance();
fontType = state.getMergedAttributes().getFontType();
}
if (offset >= state.getEndOffset()) {
state.advance();
fontType = state.getMergedAttributes().getFontType();
}
SoftWrap softWrap = mySoftWrapModel.getSoftWrap(offset);
if (softWrap != null) {
if (activeSoftWrapProcessed) {
prevX = x;
charWidth = getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED);
x += charWidth;
if (x >= px) {
onSoftWrapDrawing = true;
SoftWrap softWrap = mySoftWrapModel.getSoftWrap(offset);
if (softWrap != null) {
if (activeSoftWrapProcessed) {
prevX = x;
charWidth = getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED);
x += charWidth;
if (x >= px) {
onSoftWrapDrawing = true;
}
else {
column++;
}
break outer;
}
else {
column++;
}
break outer;
}
else {
CharSequence softWrapText = softWrap.getText();
for (int i = 1/*Assuming line feed is located at the first position*/; i < softWrapText.length(); i++) {
c = softWrapText.charAt(i);
CharSequence softWrapText = softWrap.getText();
for (int i = 1/*Assuming line feed is located at the first position*/; i < softWrapText.length(); i++) {
c = softWrapText.charAt(i);
prevX = x;
charWidth = charToVisibleWidth(c, fontType, x);
x += charWidth;
if (x >= px) {
break outer;
}
column += EditorUtil.columnsNumber(c, x, prevX, spaceSize);
}
// Process 'after soft wrap' sign.
prevX = x;
charWidth = charToVisibleWidth(c, fontType, x);
charWidth = mySoftWrapModel.getMinDrawingWidthInPixels(SoftWrapDrawingType.AFTER_SOFT_WRAP);
x += charWidth;
if (x >= px) {
onSoftWrapDrawing = true;
break outer;
}
column++;
activeSoftWrapProcessed = true;
}
}
FoldRegion region = state.getCurrentFold();
if (region != null) {
char[] placeholder = region.getPlaceholderText().toCharArray();
for (char aPlaceholder : placeholder) {
c = aPlaceholder;
x += EditorUtil.charWidth(c, fontType, this);
if (x >= px) {
break outer;
}
column += EditorUtil.columnsNumber(c, x, prevX, spaceSize);
column++;
}
// Process 'after soft wrap' sign.
offset = region.getEndOffset();
}
else {
prevX = x;
charWidth = mySoftWrapModel.getMinDrawingWidthInPixels(SoftWrapDrawingType.AFTER_SOFT_WRAP);
c = text.charAt(offset);
charWidth = charToVisibleWidth(c, fontType, x);
if (charWidth == 0) {
break;
}
x += charWidth;
if (x >= px) {
onSoftWrapDrawing = true;
break outer;
break;
}
column++;
activeSoftWrapProcessed = true;
column += EditorUtil.columnsNumber(c, x, prevX, spaceSize);
offset++;
}
}
FoldRegion region = state.getCurrentFold();
if (region != null) {
char[] placeholder = region.getPlaceholderText().toCharArray();
for (char aPlaceholder : placeholder) {
c = aPlaceholder;
x += EditorUtil.charWidth(c, fontType, this);
if (x >= px) {
break outer;
}
column++;
if (charWidth < 0) {
charWidth = EditorUtil.charWidth(c, fontType, this);
}
if (charWidth < 0) {
charWidth = spaceSize;
}
if (x >= px && c == '\t' && !onSoftWrapDrawing) {
if (mySettings.isCaretInsideTabs()) {
column += (px - prevX) / spaceSize;
if ((px - prevX) % spaceSize > spaceSize / 2) column++;
}
else if ((x - px) * 2 < x - prevX) {
column += EditorUtil.columnsNumber(c, x, prevX, spaceSize);
}
offset = region.getEndOffset();
}
else {
prevX = x;
c = text.charAt(offset);
charWidth = charToVisibleWidth(c, fontType, x);
if (charWidth == 0) {
break;
}
x += charWidth;
if (x >= px) {
break;
if ((x - px) * 2 < charWidth) column++;
}
column += EditorUtil.columnsNumber(c, x, prevX, spaceSize);
offset++;
}
}
if (charWidth < 0) {
charWidth = EditorUtil.charWidth(c, fontType, this);
}
if (charWidth < 0) {
charWidth = spaceSize;
}
if (x >= px && c == '\t' && !onSoftWrapDrawing) {
if (mySettings.isCaretInsideTabs()) {
column += (px - prevX) / spaceSize;
if ((px - prevX) % spaceSize > spaceSize / 2) column++;
}
else if ((x - px) * 2 < x - prevX) {
column += EditorUtil.columnsNumber(c, x, prevX, spaceSize);
}
}
else {
if (x >= px) {
if ((x - px) * 2 < charWidth) column++;
}
else {
int diff = px - x;
column += diff / spaceSize;
if (diff % spaceSize * 2 >= spaceSize) {
column++;
else {
int diff = px - x;
column += diff / spaceSize;
if (diff % spaceSize * 2 >= spaceSize) {
column++;
}
}
}
}
return new VisualPosition(line, column);
return new VisualPosition(line, column);
}
finally {
state.dispose();
}
}
/**
@@ -1299,68 +1304,73 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
CharSequence text = myDocument.getCharsNoThreadCheck();
int textLength = myDocument.getTextLength();
IterationState state = new IterationState(this, startOffset, startOffset + length, false);
int fontType = state.getMergedAttributes().getFontType();
int spaceSize = EditorUtil.getSpaceWidth(fontType, this);
try {
int fontType = state.getMergedAttributes().getFontType();
int spaceSize = EditorUtil.getSpaceWidth(fontType, this);
int column = 0;
outer:
while (column < length) {
if (offset >= textLength) break;
int column = 0;
outer:
while (column < length) {
if (offset >= textLength) break;
if (offset >= state.getEndOffset()) {
state.advance();
fontType = state.getMergedAttributes().getFontType();
}
// We need to consider 'before soft wrap drawing'.
SoftWrap softWrap = getSoftWrapModel().getSoftWrap(offset);
if (softWrap != null && offset > startOffset) {
column++;
x += getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED);
// Assuming that first soft wrap symbol is line feed or all soft wrap symbols before the first line feed are spaces.
break;
}
FoldRegion region = state.getCurrentFold();
if (region != null) {
char[] placeholder = region.getPlaceholderText().toCharArray();
for (char aPlaceholder : placeholder) {
x += EditorUtil.charWidth(aPlaceholder, fontType, this);
column++;
if (column >= length) break outer;
if (offset >= state.getEndOffset()) {
state.advance();
fontType = state.getMergedAttributes().getFontType();
}
offset = region.getEndOffset();
}
else {
char c = text.charAt(offset);
if (c == '\n') {
// We need to consider 'before soft wrap drawing'.
SoftWrap softWrap = getSoftWrapModel().getSoftWrap(offset);
if (softWrap != null && offset > startOffset) {
column++;
x += getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED);
// Assuming that first soft wrap symbol is line feed or all soft wrap symbols before the first line feed are spaces.
break;
}
if (c == '\t') {
int prevX = x;
x = EditorUtil.nextTabStop(x, this);
int columnDiff = (x - prevX) / spaceSize;
if ((x - prevX) % spaceSize > 0) {
// There is a possible case that tabulation symbol takes more than one visual column to represent and it's shown at
// soft-wrapped line. Soft wrap sign width may be not divisible by space size, hence, part of tabulation symbol represented
// as a separate visual column may take less space than space width.
columnDiff++;
FoldRegion region = state.getCurrentFold();
if (region != null) {
char[] placeholder = region.getPlaceholderText().toCharArray();
for (char aPlaceholder : placeholder) {
x += EditorUtil.charWidth(aPlaceholder, fontType, this);
column++;
if (column >= length) break outer;
}
column += columnDiff;
offset = region.getEndOffset();
}
else {
x += EditorUtil.charWidth(c, fontType, this);
column++;
char c = text.charAt(offset);
if (c == '\n') {
break;
}
if (c == '\t') {
int prevX = x;
x = EditorUtil.nextTabStop(x, this);
int columnDiff = (x - prevX) / spaceSize;
if ((x - prevX) % spaceSize > 0) {
// There is a possible case that tabulation symbol takes more than one visual column to represent and it's shown at
// soft-wrapped line. Soft wrap sign width may be not divisible by space size, hence, part of tabulation symbol represented
// as a separate visual column may take less space than space width.
columnDiff++;
}
column += columnDiff;
}
else {
x += EditorUtil.charWidth(c, fontType, this);
column++;
}
offset++;
}
offset++;
}
}
if (column != length) {
x += EditorUtil.getSpaceWidth(fontType, this) * (length - column);
}
if (column != length) {
x += EditorUtil.getSpaceWidth(fontType, this) * (length - column);
}
return x;
return x;
}
finally {
state.dispose();
}
}
public int visibleLineToY(int line) {
@@ -1910,7 +1920,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
int start = clipStartOffset;
int end = clipEndOffset;
getSoftWrapModel().registerSoftWrapsIfNecessary();
IterationState iterationState = new IterationState(this, start, end, isPaintSelection());
LineIterator lIterator = createLineIterator();
lIterator.start(start);
@@ -1918,112 +1927,118 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
return;
}
TextAttributes attributes = iterationState.getMergedAttributes();
Color backColor = getBackgroundColor(attributes);
int fontType = attributes.getFontType();
CharSequence text = myDocument.getCharsNoThreadCheck();
int lastLineIndex = Math.max(0, myDocument.getLineCount() - 1);
IterationState iterationState = new IterationState(this, start, end, isPaintSelection());
try {
TextAttributes attributes = iterationState.getMergedAttributes();
Color backColor = getBackgroundColor(attributes);
int fontType = attributes.getFontType();
CharSequence text = myDocument.getCharsNoThreadCheck();
int lastLineIndex = Math.max(0, myDocument.getLineCount() - 1);
// There is a possible case that we need to draw background from the start of soft wrap-introduced visual line. Given position
// has valid 'y' coordinate then at it shouldn't be affected by soft wrap that corresponds to the visual line start offset.
// Hence, we store information about soft wrap to be skipped for further processing and adjust 'x' coordinate value if necessary.
TIntHashSet softWrapsToSkip = new TIntHashSet();
SoftWrap softWrap = getSoftWrapModel().getSoftWrap(start);
if (softWrap != null) {
softWrapsToSkip.add(softWrap.getStart());
Color color = null;
if (backColor != null && !backColor.equals(defaultBackground)) {
color = backColor;
}
// There is a possible case that target clip points to soft wrap-introduced visual line and that it's an active
// line (caret cursor is located on it). We want to draw corresponding 'caret line' background for soft wraps-introduced
// virtual space then.
if (color == null && position.y == getCaretModel().getVisualPosition().line * getLineHeight()) {
color = getColorsScheme().getColor(EditorColors.CARET_ROW_COLOR);
}
if (color != null) {
drawBackground(g, color, softWrap.getIndentInPixels(), position, defaultBackground, clip);
}
position.x = softWrap.getIndentInPixels();
}
// There is a possible case that caret is located at soft-wrapped line. We don't need to paint caret row background
// on a last visual line of that soft-wrapped line then. Below is a holder for the flag that indicates if caret row
// background is already drawn.
boolean[] caretRowPainted = new boolean[1];
while (!iterationState.atEnd() && !lIterator.atEnd()) {
int hEnd = iterationState.getEndOffset();
int lEnd = lIterator.getEnd();
if (hEnd >= lEnd) {
FoldRegion collapsedFolderAt = myFoldingModel.getCollapsedRegionAtOffset(start);
if (collapsedFolderAt == null) {
position.x = drawSoftWrapAwareBackground(g, backColor, text, start, lEnd - lIterator.getSeparatorLength(), position, fontType,
defaultBackground, clip, softWrapsToSkip, caretRowPainted);
if (lIterator.getLineNumber() < lastLineIndex) {
if (backColor != null && !backColor.equals(defaultBackground)) {
g.setColor(backColor);
g.fillRect(position.x, position.y, clip.x + clip.width - position.x, lineHeight);
}
}
else {
paintAfterFileEndBackground(iterationState,
g,
position, clip,
lineHeight, defaultBackground, caretRowPainted);
break;
}
position.x = 0;
if (position.y > clip.y + clip.height) break;
position.y += lineHeight;
start = lEnd;
// There is a possible case that we need to draw background from the start of soft wrap-introduced visual line. Given position
// has valid 'y' coordinate then at it shouldn't be affected by soft wrap that corresponds to the visual line start offset.
// Hence, we store information about soft wrap to be skipped for further processing and adjust 'x' coordinate value if necessary.
TIntHashSet softWrapsToSkip = new TIntHashSet();
SoftWrap softWrap = getSoftWrapModel().getSoftWrap(start);
if (softWrap != null) {
softWrapsToSkip.add(softWrap.getStart());
Color color = null;
if (backColor != null && !backColor.equals(defaultBackground)) {
color = backColor;
}
lIterator.advance();
// There is a possible case that target clip points to soft wrap-introduced visual line and that it's an active
// line (caret cursor is located on it). We want to draw corresponding 'caret line' background for soft wraps-introduced
// virtual space then.
if (color == null && position.y == getCaretModel().getVisualPosition().line * getLineHeight()) {
color = getColorsScheme().getColor(EditorColors.CARET_ROW_COLOR);
}
if (color != null) {
drawBackground(g, color, softWrap.getIndentInPixels(), position, defaultBackground, clip);
}
position.x = softWrap.getIndentInPixels();
}
else {
FoldRegion collapsedFolderAt = iterationState.getCurrentFold();
if (collapsedFolderAt != null) {
softWrap = mySoftWrapModel.getSoftWrap(collapsedFolderAt.getStartOffset());
if (softWrap != null) {
position.x = drawSoftWrapAwareBackground(
g, backColor, text, collapsedFolderAt.getStartOffset(), collapsedFolderAt.getStartOffset(), position, fontType,
defaultBackground, clip, softWrapsToSkip, caretRowPainted
);
// There is a possible case that caret is located at soft-wrapped line. We don't need to paint caret row background
// on a last visual line of that soft-wrapped line then. Below is a holder for the flag that indicates if caret row
// background is already drawn.
boolean[] caretRowPainted = new boolean[1];
while (!iterationState.atEnd() && !lIterator.atEnd()) {
int hEnd = iterationState.getEndOffset();
int lEnd = lIterator.getEnd();
if (hEnd >= lEnd) {
FoldRegion collapsedFolderAt = myFoldingModel.getCollapsedRegionAtOffset(start);
if (collapsedFolderAt == null) {
position.x = drawSoftWrapAwareBackground(g, backColor, text, start, lEnd - lIterator.getSeparatorLength(), position, fontType,
defaultBackground, clip, softWrapsToSkip, caretRowPainted);
if (lIterator.getLineNumber() < lastLineIndex) {
if (backColor != null && !backColor.equals(defaultBackground)) {
g.setColor(backColor);
g.fillRect(position.x, position.y, clip.x + clip.width - position.x, lineHeight);
}
}
else {
paintAfterFileEndBackground(iterationState,
g,
position, clip,
lineHeight, defaultBackground, caretRowPainted);
break;
}
position.x = 0;
if (position.y > clip.y + clip.height) break;
position.y += lineHeight;
start = lEnd;
}
position.x = drawBackground(g, backColor, collapsedFolderAt.getPlaceholderText(), position, fontType, defaultBackground, clip);
lIterator.advance();
}
else {
if (hEnd > lEnd - lIterator.getSeparatorLength()) {
position.x = drawSoftWrapAwareBackground(
g, backColor, text, start, lEnd - lIterator.getSeparatorLength(), position, fontType,
defaultBackground, clip, softWrapsToSkip, caretRowPainted
);
FoldRegion collapsedFolderAt = iterationState.getCurrentFold();
if (collapsedFolderAt != null) {
softWrap = mySoftWrapModel.getSoftWrap(collapsedFolderAt.getStartOffset());
if (softWrap != null) {
position.x = drawSoftWrapAwareBackground(
g, backColor, text, collapsedFolderAt.getStartOffset(), collapsedFolderAt.getStartOffset(), position, fontType,
defaultBackground, clip, softWrapsToSkip, caretRowPainted
);
}
position.x = drawBackground(g, backColor, collapsedFolderAt.getPlaceholderText(), position, fontType, defaultBackground, clip);
}
else {
position.x = drawSoftWrapAwareBackground(
g, backColor, text, start, hEnd, position, fontType, defaultBackground, clip, softWrapsToSkip, caretRowPainted
);
if (hEnd > lEnd - lIterator.getSeparatorLength()) {
position.x = drawSoftWrapAwareBackground(
g, backColor, text, start, lEnd - lIterator.getSeparatorLength(), position, fontType,
defaultBackground, clip, softWrapsToSkip, caretRowPainted
);
}
else {
position.x = drawSoftWrapAwareBackground(
g, backColor, text, start, hEnd, position, fontType, defaultBackground, clip, softWrapsToSkip, caretRowPainted
);
}
}
}
iterationState.advance();
attributes = iterationState.getMergedAttributes();
backColor = getBackgroundColor(attributes);
fontType = attributes.getFontType();
start = iterationState.getStartOffset();
iterationState.advance();
attributes = iterationState.getMergedAttributes();
backColor = getBackgroundColor(attributes);
fontType = attributes.getFontType();
start = iterationState.getStartOffset();
}
}
flushBackground(g, clip);
if (lIterator.getLineNumber() >= lastLineIndex && position.y <= clip.y + clip.height) {
paintAfterFileEndBackground(iterationState, g, position, clip, lineHeight, defaultBackground, caretRowPainted);
}
}
flushBackground(g, clip);
if (lIterator.getLineNumber() >= lastLineIndex && position.y <= clip.y + clip.height) {
paintAfterFileEndBackground(iterationState, g, position, clip, lineHeight, defaultBackground, caretRowPainted);
finally {
iterationState.dispose();
}
// Perform additional activity if soft wrap is added or removed during repainting.
@@ -2356,92 +2371,97 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
return;
}
IterationState iterationState = new IterationState(this, start, clipEndOffset, isPaintSelection());
LineIterator lIterator = createLineIterator();
lIterator.start(start);
if (lIterator.atEnd()) {
return;
}
TextAttributes attributes = iterationState.getMergedAttributes();
Color currentColor = attributes.getForegroundColor();
if (currentColor == null) {
currentColor = getForegroundColor();
}
Color effectColor = attributes.getEffectColor();
EffectType effectType = attributes.getEffectType();
int fontType = attributes.getFontType();
g.setColor(currentColor);
final char[] chars = myDocument.getRawChars();
while (!iterationState.atEnd() && !lIterator.atEnd()) {
int hEnd = iterationState.getEndOffset();
int lEnd = lIterator.getEnd();
if (hEnd >= lEnd) {
FoldRegion collapsedFolderAt = myFoldingModel.getCollapsedRegionAtOffset(start);
if (collapsedFolderAt == null) {
drawStringWithSoftWraps(g, chars, start, lEnd - lIterator.getSeparatorLength(), position, clip, effectColor,
effectType, fontType, currentColor, logicalPosition);
position.x = 0;
if (position.y > clip.y + clip.height) {
break;
}
position.y += lineHeight;
start = lEnd;
}
// myBorderEffect.eolReached(g, this);
lIterator.advance();
IterationState iterationState = new IterationState(this, start, clipEndOffset, isPaintSelection());
try {
TextAttributes attributes = iterationState.getMergedAttributes();
Color currentColor = attributes.getForegroundColor();
if (currentColor == null) {
currentColor = getForegroundColor();
}
else {
FoldRegion collapsedFolderAt = iterationState.getCurrentFold();
if (collapsedFolderAt != null) {
SoftWrap softWrap = mySoftWrapModel.getSoftWrap(collapsedFolderAt.getStartOffset());
if (softWrap != null) {
position.x = drawStringWithSoftWraps(
g, chars, collapsedFolderAt.getStartOffset(), collapsedFolderAt.getStartOffset(), position, clip, effectColor, effectType,
fontType, currentColor, logicalPosition
);
}
int foldingXStart = position.x;
position.x = drawString(
g, collapsedFolderAt.getPlaceholderText(), position, clip, effectColor, effectType, fontType, currentColor
);
//drawStringWithSoftWraps(g, collapsedFolderAt.getPlaceholderText(), position, clip, effectColor, effectType,
// fontType, currentColor, logicalPosition);
BorderEffect.paintFoldedEffect(g, foldingXStart, position.y, position.x, getLineHeight(), effectColor, effectType);
Color effectColor = attributes.getEffectColor();
EffectType effectType = attributes.getEffectType();
int fontType = attributes.getFontType();
g.setColor(currentColor);
final char[] chars = myDocument.getRawChars();
while (!iterationState.atEnd() && !lIterator.atEnd()) {
int hEnd = iterationState.getEndOffset();
int lEnd = lIterator.getEnd();
if (hEnd >= lEnd) {
FoldRegion collapsedFolderAt = myFoldingModel.getCollapsedRegionAtOffset(start);
if (collapsedFolderAt == null) {
drawStringWithSoftWraps(g, chars, start, lEnd - lIterator.getSeparatorLength(), position, clip, effectColor,
effectType, fontType, currentColor, logicalPosition);
position.x = 0;
if (position.y > clip.y + clip.height) {
break;
}
position.y += lineHeight;
start = lEnd;
}
// myBorderEffect.eolReached(g, this);
lIterator.advance();
}
else {
position.x = drawStringWithSoftWraps(g, chars, start, Math.min(hEnd, lEnd - lIterator.getSeparatorLength()) , position, clip,
effectColor, effectType, fontType, currentColor, logicalPosition);
FoldRegion collapsedFolderAt = iterationState.getCurrentFold();
if (collapsedFolderAt != null) {
SoftWrap softWrap = mySoftWrapModel.getSoftWrap(collapsedFolderAt.getStartOffset());
if (softWrap != null) {
position.x = drawStringWithSoftWraps(
g, chars, collapsedFolderAt.getStartOffset(), collapsedFolderAt.getStartOffset(), position, clip, effectColor, effectType,
fontType, currentColor, logicalPosition
);
}
int foldingXStart = position.x;
position.x = drawString(
g, collapsedFolderAt.getPlaceholderText(), position, clip, effectColor, effectType, fontType, currentColor
);
//drawStringWithSoftWraps(g, collapsedFolderAt.getPlaceholderText(), position, clip, effectColor, effectType,
// fontType, currentColor, logicalPosition);
BorderEffect.paintFoldedEffect(g, foldingXStart, position.y, position.x, getLineHeight(), effectColor, effectType);
}
else {
position.x = drawStringWithSoftWraps(g, chars, start, Math.min(hEnd, lEnd - lIterator.getSeparatorLength()) , position, clip,
effectColor, effectType, fontType, currentColor, logicalPosition);
}
iterationState.advance();
attributes = iterationState.getMergedAttributes();
currentColor = attributes.getForegroundColor();
if (currentColor == null) {
currentColor = getForegroundColor();
}
effectColor = attributes.getEffectColor();
effectType = attributes.getEffectType();
fontType = attributes.getFontType();
start = iterationState.getStartOffset();
}
}
iterationState.advance();
attributes = iterationState.getMergedAttributes();
currentColor = attributes.getForegroundColor();
if (currentColor == null) {
currentColor = getForegroundColor();
}
effectColor = attributes.getEffectColor();
effectType = attributes.getEffectType();
fontType = attributes.getFontType();
start = iterationState.getStartOffset();
FoldRegion collapsedFolderAt = iterationState.getCurrentFold();
if (collapsedFolderAt != null) {
int foldingXStart = position.x;
int foldingXEnd =
drawStringWithSoftWraps(g, collapsedFolderAt.getPlaceholderText(), position, clip, effectColor, effectType,
fontType, currentColor, logicalPosition);
BorderEffect.paintFoldedEffect(g, foldingXStart, position.y, foldingXEnd, getLineHeight(), effectColor, effectType);
// myBorderEffect.collapsedFolderReached(g, this);
}
}
FoldRegion collapsedFolderAt = iterationState.getCurrentFold();
if (collapsedFolderAt != null) {
int foldingXStart = position.x;
int foldingXEnd =
drawStringWithSoftWraps(g, collapsedFolderAt.getPlaceholderText(), position, clip, effectColor, effectType,
fontType, currentColor, logicalPosition);
BorderEffect.paintFoldedEffect(g, foldingXStart, position.y, foldingXEnd, getLineHeight(), effectColor, effectType);
// myBorderEffect.collapsedFolderReached(g, this);
finally {
iterationState.dispose();
}
flushCachedChars(g);
@@ -2479,8 +2499,13 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
public String dumpState() {
return "use soft wraps: " + (mySoftWrapModel.isSoftWrappingEnabled() ? "on" : "off") + ", soft wraps data: " + getSoftWrapModel()
+ "\n\nfolding data: " + getFoldingModel() + "\n\ndocument info: " + myDocument.dumpState();
return "prefix: '" + (myPrefixText == null ? "none" : new String(myPrefixText))
+ "', allow caret inside tab: " + mySettings.isCaretInsideTabs()
+ ", allow caret after line end: " + mySettings.isVirtualSpace()
+ ", soft wraps: " + (mySoftWrapModel.isSoftWrappingEnabled() ? "on" : "off")
+ ", soft wraps data: " + getSoftWrapModel()
+ "\n\nfolding data: " + getFoldingModel()
+ "\n\ndocument info: " + myDocument.dumpState();
}
private class CachedFontContent {
@@ -3305,6 +3330,10 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
while (start <= end) {
i = (start + end) / 2;
FoldRegion region = topLevelCollapsed[i];
if (!region.isValid()) {
// Folding model is inconsistent (update in progress).
return null;
}
int regionVisualLine = offsetToVisualLine(region.getEndOffset() - 1);
if (regionVisualLine < visualPos.line) {
start = i + 1;
@@ -5903,59 +5932,64 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
IterationState state = new IterationState(EditorImpl.this, offset, endOffset, false);
int fontType = state.getMergedAttributes().getFontType();
try {
int fontType = state.getMergedAttributes().getFontType();
int maxPreviousSoftWrappedWidth = -1;
int maxPreviousSoftWrappedWidth = -1;
while (offset < documentLength && line < lineCount) {
char c = text.charAt(offset);
if (offset >= state.getEndOffset()) {
state.advance();
fontType = state.getMergedAttributes().getFontType();
}
while (softWrapsIndex < softWraps.size() && line < lineCount) {
SoftWrap softWrap = softWraps.get(softWrapsIndex);
if (softWrap.getStart() > offset) {
break;
while (offset < documentLength && line < lineCount) {
char c = text.charAt(offset);
if (offset >= state.getEndOffset()) {
state.advance();
fontType = state.getMergedAttributes().getFontType();
}
softWrapsIndex++;
if (softWrap.getStart() == offset) {
maxPreviousSoftWrappedWidth = Math.max(maxPreviousSoftWrappedWidth, x);
x = softWrap.getIndentInPixels();
while (softWrapsIndex < softWraps.size() && line < lineCount) {
SoftWrap softWrap = softWraps.get(softWrapsIndex);
if (softWrap.getStart() > offset) {
break;
}
softWrapsIndex++;
if (softWrap.getStart() == offset) {
maxPreviousSoftWrappedWidth = Math.max(maxPreviousSoftWrappedWidth, x);
x = softWrap.getIndentInPixels();
}
}
FoldRegion collapsed = state.getCurrentFold();
if (collapsed != null) {
String placeholder = collapsed.getPlaceholderText();
for (int i = 0; i < placeholder.length(); i++) {
x += EditorUtil.charWidth(placeholder.charAt(i), fontType, EditorImpl.this);
}
offset = collapsed.getEndOffset();
line = myDocument.getLineNumber(offset);
}
else if (c == '\t') {
x = EditorUtil.nextTabStop(x, EditorImpl.this);
offset++;
}
else if (c == '\n') {
int width = Math.max(x, maxPreviousSoftWrappedWidth);
myLineWidths.set(line, width);
maxCalculatedLine = Math.max(maxCalculatedLine, line);
if (line + 1 >= lineCount || myLineWidths.getQuick(line + 1) != -1) break;
offset++;
x = 0;
//noinspection AssignmentToForLoopParameter
line++;
if (line == lineCount - 1) {
lastLineLengthCalculated = true;
}
}
else {
x += ComplementaryFontsRegistry.getFontAbleToDisplay(c, fontSize, fontType, fontName).charWidth(c, myEditorComponent);
offset++;
}
}
FoldRegion collapsed = state.getCurrentFold();
if (collapsed != null) {
String placeholder = collapsed.getPlaceholderText();
for (int i = 0; i < placeholder.length(); i++) {
x += EditorUtil.charWidth(placeholder.charAt(i), fontType, EditorImpl.this);
}
offset = collapsed.getEndOffset();
line = myDocument.getLineNumber(offset);
}
else if (c == '\t') {
x = EditorUtil.nextTabStop(x, EditorImpl.this);
offset++;
}
else if (c == '\n') {
int width = Math.max(x, maxPreviousSoftWrappedWidth);
myLineWidths.set(line, width);
maxCalculatedLine = Math.max(maxCalculatedLine, line);
if (line + 1 >= lineCount || myLineWidths.getQuick(line + 1) != -1) break;
offset++;
x = 0;
//noinspection AssignmentToForLoopParameter
line++;
if (line == lineCount - 1) {
lastLineLengthCalculated = true;
}
}
else {
x += ComplementaryFontsRegistry.getFontAbleToDisplay(c, fontSize, fontType, fontName).charWidth(c, myEditorComponent);
offset++;
}
}
finally {
state.dispose();
}
}
@@ -6011,35 +6045,40 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
@Override
public int calcColumnNumber(@NotNull CharSequence text, int start, int offset, int tabSize) {
IterationState state = new IterationState(this, start, start+offset, false);
int fontType = state.getMergedAttributes().getFontType();
int column = 0;
int x = 0;
int spaceSize = EditorUtil.getSpaceWidth(fontType, this);
for (int i = start; i < offset; i++) {
if (i >= state.getEndOffset()) {
state.advance();
fontType = state.getMergedAttributes().getFontType();
try {
int fontType = state.getMergedAttributes().getFontType();
int column = 0;
int x = 0;
int spaceSize = EditorUtil.getSpaceWidth(fontType, this);
for (int i = start; i < offset; i++) {
if (i >= state.getEndOffset()) {
state.advance();
fontType = state.getMergedAttributes().getFontType();
}
SoftWrap softWrap = getSoftWrapModel().getSoftWrap(i);
if (softWrap != null) {
column++; // For 'after soft wrap' drawing.
x = getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.AFTER_SOFT_WRAP);
}
char c = text.charAt(i);
if (c == '\t') {
int prevX = x;
x = EditorUtil.nextTabStop(x, this);
column += EditorUtil.columnsNumber(c, x, prevX, spaceSize);
}
else {
x += EditorUtil.charWidth(c, fontType, this);
column++;
}
}
SoftWrap softWrap = getSoftWrapModel().getSoftWrap(i);
if (softWrap != null) {
column++; // For 'after soft wrap' drawing.
x = getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.AFTER_SOFT_WRAP);
}
char c = text.charAt(i);
if (c == '\t') {
int prevX = x;
x = EditorUtil.nextTabStop(x, this);
column += EditorUtil.columnsNumber(c, x, prevX, spaceSize);
}
else {
x += EditorUtil.charWidth(c, fontType, this);
column++;
}
return column;
}
finally {
state.dispose();
}
return column;
}
@Override
@@ -2,6 +2,7 @@ package com.intellij.openapi.editor.impl;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.ex.DisposableIterator;
import com.intellij.openapi.editor.ex.MarkupModelEx;
import com.intellij.openapi.editor.ex.RangeHighlighterEx;
import com.intellij.openapi.editor.ex.SweepProcessor;
@@ -13,12 +14,9 @@ import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.util.Key;
import com.intellij.util.Consumer;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Iterator;
/**
* This is mock implementation to be used in null-object pattern where necessary.
* @author max
@@ -126,8 +124,8 @@ public class EmptyMarkupModel implements MarkupModelEx {
@NotNull
@Override
public Iterator<RangeHighlighterEx> overlappingIterator(int startOffset, int endOffset) {
return ContainerUtil.emptyIterator();
public DisposableIterator<RangeHighlighterEx> overlappingIterator(int startOffset, int endOffset) {
return DisposableIterator.EMPTY;
}
@Override
@@ -35,15 +35,13 @@ import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
@SuppressWarnings({"ForLoopReplaceableByForEach"}) // Way too many garbage in AbstractList.iterator() produced otherwise.
public final class IterationState {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.IterationState");
private final TextAttributes myMergedAttributes = new TextAttributes();
private final HighlighterIterator myHighlighterIterator;
private final HighlighterSweep myView = new HighlighterSweep();
private final HighlighterSweep myDoc = new HighlighterSweep();
private final HighlighterSweep myView;
private final HighlighterSweep myDoc;
private int myStartOffset;
@@ -71,6 +69,9 @@ public final class IterationState {
private final EditorEx myEditor;
private final Color myReadOnlyColor;
/**
* You MUST CALL {@link #dispose()} afterwards
*/
public IterationState(@NotNull EditorEx editor, int start, int end, boolean useCaretAndSelection) {
ApplicationManager.getApplication().assertReadAccessAllowed();
myDocument = (DocumentEx)editor.getDocument();
@@ -104,22 +105,29 @@ public final class IterationState {
myCurrentHighlighters = new ArrayList<RangeHighlighterEx>();
MarkupModelEx editorMarkup = (MarkupModelEx)editor.getMarkupModel();
myView.init(editorMarkup, start, myEnd);
myView = new HighlighterSweep(editorMarkup, start, myEnd);
final MarkupModelEx docMarkup = (MarkupModelEx)DocumentMarkupModel.forDocument(editor.getDocument(), editor.getProject(), true);
myDoc.init(docMarkup, start, myEnd);
myDoc = new HighlighterSweep(docMarkup, start, myEnd);
myEndOffset = myStartOffset;
advance();
}
private class HighlighterSweep {
private RangeHighlighterEx myNextHighlighter = null;
private PushBackIterator<RangeHighlighterEx> myIterator;
public void dispose() {
myView.dispose();
myDoc.dispose();
}
private void init(@NotNull MarkupModelEx markupModel, int start, int end) {
myIterator = new PushBackIterator<RangeHighlighterEx>(markupModel.overlappingIterator(start, end));
private class HighlighterSweep {
private RangeHighlighterEx myNextHighlighter;
private final PushBackIterator<RangeHighlighterEx> myIterator;
private final DisposableIterator<RangeHighlighterEx> myDisposableIterator;
private HighlighterSweep(@NotNull MarkupModelEx markupModel, int start, int end) {
myDisposableIterator = markupModel.overlappingIterator(start, end);
myIterator = new PushBackIterator<RangeHighlighterEx>(myDisposableIterator);
int skipped = 0;
while (myIterator.hasNext()) {
RangeHighlighterEx highlighter = myIterator.next();
@@ -176,6 +184,10 @@ public final class IterationState {
}
return Integer.MAX_VALUE;
}
public void dispose() {
myDisposableIterator.dispose();
}
}
private boolean skipHighlighter(@NotNull RangeHighlighterEx highlighter) {
@@ -230,6 +242,7 @@ public final class IterationState {
private int getGuardedBlockEnd(int start) {
List<RangeMarker> blocks = myDocument.getGuardedBlocks();
int min = myEnd;
//noinspection ForLoopReplaceableByForEach
for (int i = 0; i < blocks.size(); i++) {
RangeMarker block = blocks.get(i);
if (block.getStartOffset() > start) {
@@ -257,7 +270,6 @@ public final class IterationState {
private void advanceSegmentHighlighters() {
myDoc.advance();
myView.advance();
for (int i = myCurrentHighlighters.size() - 1; i >= 0; i--) {
@@ -296,6 +308,7 @@ public final class IterationState {
private int getMinSegmentHighlightersEnd() {
int end = myEnd;
//noinspection ForLoopReplaceableByForEach
for (int i = 0; i < myCurrentHighlighters.size(); i++) {
RangeHighlighterEx highlighter = myCurrentHighlighters.get(i);
if (highlighter.getAffectedAreaEndOffset() < end) {
@@ -332,6 +345,7 @@ public final class IterationState {
ContainerUtil.quickSort(myCurrentHighlighters, LayerComparator.INSTANCE);
}
//noinspection ForLoopReplaceableByForEach
for (int i = 0; i < size; i++) {
RangeHighlighterEx highlighter = myCurrentHighlighters.get(i);
if (highlighter.getTextAttributes() == TextAttributes.ERASE_MARKER) {
@@ -342,6 +356,7 @@ public final class IterationState {
List<TextAttributes> cachedAttributes = myCachedAttributesList;
cachedAttributes.clear();
//noinspection ForLoopReplaceableByForEach
for (int i = 0; i < size; i++) {
RangeHighlighterEx highlighter = myCurrentHighlighters.get(i);
if (selection != null && highlighter.getLayer() < HighlighterLayer.SELECTION) {
@@ -387,6 +402,7 @@ public final class IterationState {
EffectType effectType = null;
int fontType = 0;
//noinspection ForLoopReplaceableByForEach
for (int i = 0; i < cachedAttributes.size(); i++) {
TextAttributes attrs = cachedAttributes.get(i);
@@ -453,6 +469,7 @@ public final class IterationState {
ContainerUtil.quickSort(myCurrentHighlighters, LayerComparator.INSTANCE);
//noinspection ForLoopReplaceableByForEach
for (int i = 0; i < myCurrentHighlighters.size(); i++) {
RangeHighlighterEx highlighter = myCurrentHighlighters.get(i);
if (caret != null && highlighter.getLayer() < HighlighterLayer.CARET_ROW) {
@@ -28,6 +28,7 @@ import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.ex.DisposableIterator;
import com.intellij.openapi.editor.ex.MarkupModelEx;
import com.intellij.openapi.editor.ex.RangeHighlighterEx;
import com.intellij.openapi.editor.ex.SweepProcessor;
@@ -45,7 +46,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx {
@@ -257,7 +257,7 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx
@Override
@NotNull
public Iterator<RangeHighlighterEx> overlappingIterator(int startOffset, int endOffset) {
public DisposableIterator<RangeHighlighterEx> overlappingIterator(int startOffset, int endOffset) {
return myHighlighterTree.overlappingIterator(startOffset, endOffset);
}
@@ -208,51 +208,56 @@ public class SoftWrapApplianceManager implements SoftWrapFoldingListener, Docume
myContext.text = document.getCharsSequence();
myContext.tokenStartOffset = start;
IterationState iterationState = new IterationState(myEditor, start, document.getTextLength(), false);
TextAttributes attributes = iterationState.getMergedAttributes();
myContext.fontType = attributes.getFontType();
myContext.rangeEndOffset = event.getNewEndOffset();
EditorPosition position = new EditorPosition(logical, start, myEditor, myRepresentationHelper);
Point point = myEditor.visualPositionToXY(visual);
position.x = point.x;
int spaceWidth = EditorUtil.getSpaceWidth(myContext.fontType, myEditor);
myContext.logicalLineData.update(logical.line, spaceWidth, myEditor);
myContext.currentPosition = position;
myContext.lineStartPosition = position.clone();
myContext.fontType2spaceWidth.put(myContext.fontType, spaceWidth);
myContext.softWrapStartOffset = position.offset;
myContext.contentComponent = myEditor.getContentComponent();
myContext.reservedWidthInPixels = myPainter.getMinDrawingWidth(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED);
// Perform soft wraps calculation.
while (!iterationState.atEnd() && myContext.currentPosition.offset <= event.getNewEndOffset()) {
FoldRegion currentFold = iterationState.getCurrentFold();
if (currentFold == null) {
myContext.tokenEndOffset = iterationState.getEndOffset();
processNonFoldToken();
}
else {
boolean continueProcessing = processCollapsedFoldRegion(currentFold);
if (!continueProcessing) {
return false;
}
// 'myOffset2widthInPixels' contains information necessary to processing soft wraps that lay before the current offset.
// We do know that soft wraps are not allowed to go backward after processed collapsed fold region, hence, we drop
// information about processed symbols width.
myOffset2widthInPixels.clear();
}
iterationState.advance();
attributes = iterationState.getMergedAttributes();
try {
TextAttributes attributes = iterationState.getMergedAttributes();
myContext.fontType = attributes.getFontType();
myContext.tokenStartOffset = iterationState.getStartOffset();
myOffset2fontType.fill(myContext.tokenStartOffset, iterationState.getEndOffset(), myContext.fontType);
myContext.rangeEndOffset = event.getNewEndOffset();
EditorPosition position = new EditorPosition(logical, start, myEditor, myRepresentationHelper);
Point point = myEditor.visualPositionToXY(visual);
position.x = point.x;
int spaceWidth = EditorUtil.getSpaceWidth(myContext.fontType, myEditor);
myContext.logicalLineData.update(logical.line, spaceWidth, myEditor);
myContext.currentPosition = position;
myContext.lineStartPosition = position.clone();
myContext.fontType2spaceWidth.put(myContext.fontType, spaceWidth);
myContext.softWrapStartOffset = position.offset;
myContext.contentComponent = myEditor.getContentComponent();
myContext.reservedWidthInPixels = myPainter.getMinDrawingWidth(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED);
// Perform soft wraps calculation.
while (!iterationState.atEnd() && myContext.currentPosition.offset <= event.getNewEndOffset()) {
FoldRegion currentFold = iterationState.getCurrentFold();
if (currentFold == null) {
myContext.tokenEndOffset = iterationState.getEndOffset();
processNonFoldToken();
}
else {
boolean continueProcessing = processCollapsedFoldRegion(currentFold);
if (!continueProcessing) {
return false;
}
// 'myOffset2widthInPixels' contains information necessary to processing soft wraps that lay before the current offset.
// We do know that soft wraps are not allowed to go backward after processed collapsed fold region, hence, we drop
// information about processed symbols width.
myOffset2widthInPixels.clear();
}
iterationState.advance();
attributes = iterationState.getMergedAttributes();
myContext.fontType = attributes.getFontType();
myContext.tokenStartOffset = iterationState.getStartOffset();
myOffset2fontType.fill(myContext.tokenStartOffset, iterationState.getEndOffset(), myContext.fontType);
}
notifyListenersOnVisualLineEnd();
}
finally {
iterationState.dispose();
}
notifyListenersOnVisualLineEnd();
return true;
}
@@ -5,7 +5,7 @@
<xy x="63" y="44" width="604" height="510"/>
</constraints>
<properties/>
<border type="etched"/>
<border type="none"/>
<children>
<component id="6b492" class="javax.swing.JLabel">
<constraints>
@@ -52,7 +52,7 @@
<properties>
<contentType value="text/html"/>
<maximumSize width="2147483647" height="25"/>
<text value="&lt;html&gt;&#13;&#10; &lt;head&gt;&#13;&#10; &#13;&#10; &lt;/head&gt;&#13;&#10; &lt;body&gt;&#13;&#10; &lt;/body&gt;&#13;&#10;&lt;/html&gt;&#13;&#10;"/>
<text value="&lt;html&gt;&#13;&#10; &lt;head&gt;&#13;&#10;&#13;&#10; &lt;/head&gt;&#13;&#10; &lt;body&gt;&#13;&#10; &lt;p style=&quot;margin-top: 0&quot;&gt;&#13;&#10; &#13;&#10; &lt;/p&gt;&#13;&#10; &lt;/body&gt;&#13;&#10;&lt;/html&gt;&#13;&#10;"/>
</properties>
</component>
<vspacer id="bf1d9">
@@ -53,7 +53,7 @@ class BaseLabel extends JLabel {
private void updateFont() {
Font f = UIUtil.getLabelFont();
Font baseFont = f.deriveFont(f.getStyle(), Math.max(11, f.getSize() - 1));
Font baseFont = f.deriveFont(f.getStyle(), Math.max(11, f.getSize() - 2));
if (myBold) {
setFont(baseFont.deriveFont(Font.BOLD));
}
@@ -70,7 +70,6 @@ public class ToolWindowContentUi extends JPanel implements ContentUI, PropertyCh
ContentLayout myComboLayout = new ComboContentLayout(this);
private ToolWindowContentUiType myType = ToolWindowContentUiType.TABBED;
private DefaultActionGroup ourGroup;
private static DefaultActionGroup myGroup;
public ToolWindowContentUi(ToolWindowImpl window) {
@@ -101,7 +101,7 @@ ide.tabbedPane.dragOutMultiplier=1.2
ide.mac.filechooser.showhidden.files=false
ide.mac.filechooser.native=true
ide.mac.message.dialogs.as.sheets=false
ide.mac.message.dialogs.as.sheets=true
ide.mac.inplaceDialogMnemonicsFix=true
debugger.valueTooltipAutoShow=true
@@ -457,6 +457,7 @@
<selectInTarget implementation="com.intellij.ide.navigationToolbar.SelectInNavBarTarget"/>
<selectInTarget implementation="com.intellij.ide.impl.StructureViewSelectInTarget"/>
<selectInTarget implementation="com.intellij.ide.impl.ProjectViewSelectInExplorerTarget"/>
<selectInTarget implementation="com.intellij.ide.favoritesTreeView.FavoritesViewSelectInTarget"/>
<elementLookupRenderer implementation="com.intellij.codeInsight.template.impl.TemplateLookupRenderer"/>
@@ -653,6 +654,7 @@
<fileIconProvider implementation="com.intellij.ide.FileIconPatcherImpl"/>
<renameHandler implementation="com.intellij.refactoring.rename.inplace.VariableInplaceRenameHandler"/>
<renameHandler implementation="com.intellij.refactoring.rename.inplace.MemberInplaceRenameHandler"/>
<completion.contributor language="any" implementationClass="com.intellij.refactoring.rename.inplace.CompletionContributorForInplaceRename" order="first"/>
<projectService serviceInterface="com.intellij.openapi.vcs.changes.ui.ChangesFileNameDecorator"
serviceImplementation="com.intellij.openapi.vcs.changes.ui.WolfChangesFileNameDecorator"/>
@@ -1655,6 +1655,32 @@ public class StringUtil {
idx += 2;
}
}
public static String unescapeSlashes(@NotNull final String str) {
final StringBuilder buf = StringBuilderSpinAllocator.alloc();
try {
unescapeSlashes(buf, str);
return buf.toString();
}
finally {
StringBuilderSpinAllocator.dispose(buf);
}
}
private static void unescapeSlashes(StringBuilder buf, String str) {
final int length = str.length();
final int last = length - 1;
for (int i = 0; i < length; i++) {
char ch = str.charAt(i);
if (ch == '\\' && i != last) {
i++;
ch = str.charAt(i);
if (ch != '/') buf.append('\\');
}
buf.append(ch);
}
}
public static void quote(@NotNull final StringBuilder builder) {
quote(builder, '\"');
@@ -15,11 +15,12 @@
*/
package com.intellij.util.containers;
import com.intellij.util.ArrayUtil;
import java.util.Arrays;
import java.util.List;
public class Queue<T> {
private final static Object[] EMPTY = new Object[0];
private Object[] myArray;
private int myFirst;
private int myLast;
@@ -29,7 +30,7 @@ public class Queue<T> {
private boolean isWrapped;
public Queue(int initialCapacity) {
myArray = initialCapacity > 0 ? new Object[initialCapacity] : EMPTY;
myArray = initialCapacity > 0 ? new Object[initialCapacity] : ArrayUtil.EMPTY_OBJECT_ARRAY;
}
public void addLast(T object) {
@@ -16,6 +16,7 @@
package com.intellij.util.io;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.io.FileSystemUtil;
import com.intellij.openapi.util.io.FileUtil;
@@ -25,6 +26,8 @@ import java.io.*;
* @author max
*/
public class SafeFileOutputStream extends OutputStream {
private static final Logger LOG = Logger.getInstance("#com.intellij.util.io.SafeFileOutputStream");
private final File myTargetFile;
private final boolean myPreserveAttributes;
private final OutputStream myBackDoorStream;
@@ -51,6 +54,7 @@ public class SafeFileOutputStream extends OutputStream {
myBackDoorStream.write(b);
}
catch (IOException e) {
LOG.warn(e);
failed = true;
throw e;
}
@@ -61,6 +65,7 @@ public class SafeFileOutputStream extends OutputStream {
myBackDoorStream.write(b);
}
catch (IOException e) {
LOG.warn(e);
failed = true;
throw e;
}
@@ -72,6 +77,7 @@ public class SafeFileOutputStream extends OutputStream {
myBackDoorStream.write(b, off, len);
}
catch (IOException e) {
LOG.warn(e);
failed = true;
throw e;
}
@@ -83,6 +89,7 @@ public class SafeFileOutputStream extends OutputStream {
myBackDoorStream.flush();
}
catch (IOException e) {
LOG.warn(e);
failed = true;
throw e;
}
@@ -94,13 +101,18 @@ public class SafeFileOutputStream extends OutputStream {
myBackDoorStream.close();
}
catch (IOException e) {
LOG.warn(e);
FileUtil.delete(backdoorFile());
throw e;
}
if (failed) {
throw new IOException("Failed to save to backup file (" + backdoorFile() + "). Original file (" + myTargetFile + ") left unchanged.");
}
final int permissions = myPreserveAttributes ? FileSystemUtil.getPermissions(myTargetFile) : -1;
if (failed || !FileUtil.delete(myTargetFile)) {
throw new IOException("Failed to save to " + myTargetFile + ". No data were harmed. Attempt result left at " + backdoorFile());
if (!FileUtil.delete(myTargetFile) && myTargetFile.exists()) {
throw new IOException("Failed to save to " + myTargetFile + ". The file left unchanged. Attempt result stored to " + backdoorFile());
}
FileUtil.rename(backdoorFile(), myTargetFile);
@@ -48,6 +48,15 @@ public class QueueTest extends TestCase {
testEmpty();
}
public void testQuibble() {
com.intellij.util.containers.Queue queue = new com.intellij.util.containers.Queue(0);
String xxx = "xxx";
queue.addLast(xxx);
CHECK.compareAll(queue.toArray(), new String[] {xxx});
Object x = queue.pullFirst();
assertEquals(xxx,x);
assertTrue(queue.isEmpty());
}
public void testCycling() {
com.intellij.util.containers.Queue queue = new com.intellij.util.containers.Queue(10);
for (int i = 0; i < 9; i++) {
@@ -234,6 +234,10 @@ public abstract class AndroidLogcatToolWindowView implements Disposable {
myFiltersList.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting()) {
return;
}
final String filterName = (String)myFiltersList.getSelectedValue();
final ConfiguredFilter filter = filterName != null ? compileConfiguredFilter(filterName) : null;
@@ -289,6 +289,7 @@ public class AndroidModuleBuilder extends JavaModuleBuilder {
if (contentRoot.findChild(SdkConstants.FN_ANDROID_MANIFEST_XML) == null) {
AndroidUtils.printMessageToConsole(project, "The project wasn't generated by 'android' tool.",
ConsoleViewContentType.ERROR_OUTPUT);
return;
}
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@@ -68,7 +68,7 @@ public class GitPull extends GitRepositoryAction {
final Label beforeLabel = LocalHistory.getInstance().putSystemLabel(project, "Before update");
final AtomicReference<GitLineHandler> handlerReference = new AtomicReference<GitLineHandler>();
new Task.Modal(project, GitBundle.message("pulling.title", dialog.getRemote()), false) {
new Task.Modal(project, GitBundle.message("pulling.title", dialog.getRemote()), true) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
GitRepository repository = GitRepositoryManager.getInstance(project).getRepositoryForRoot(dialog.gitRoot());
@@ -103,8 +103,9 @@ public class GitPull extends GitRepositoryAction {
final GitRevisionNumber currentRev = new GitRevisionNumber(revision);
GitTask pullTask = new GitTask(project, handlerReference.get(), GitBundle.message("pulling.title", dialog.getRemote()));
pullTask.setProgressIndicator(indicator);
pullTask.setProgressAnalyzer(new GitStandardProgressAnalyzer());
pullTask.executeModal(new GitTaskResultHandlerAdapter() {
pullTask.execute(true, false, new GitTaskResultHandlerAdapter() {
@Override
protected void onSuccess() {
GitMergeUtil.showUpdates(GitPull.this, project, exceptions, root, currentRev, beforeLabel, getActionName(), ActionInfo.UPDATE);
@@ -159,7 +159,7 @@ public class GitAnnotationProvider implements AnnotationProvider, VcsCacheableAn
h.endOptions();
h.addRelativePaths(repositoryFilePath);
String output = h.run();
GitFileAnnotation annotation = new GitFileAnnotation(myProject, file, revision == null);
GitFileAnnotation annotation = new GitFileAnnotation(myProject, file, revision == null, revision == null ? null : revision.getRevisionNumber());
class CommitInfo {
Date date;
String author;
@@ -228,7 +228,7 @@ public class GitAnnotationProvider implements AnnotationProvider, VcsCacheableAn
String annotatedContent,
boolean forCurrentRevision, VcsRevisionNumber revisionNumber) {
final GitFileAnnotation gitFileAnnotation =
new GitFileAnnotation(myProject, vcsAnnotation.getFilePath().getVirtualFile(), forCurrentRevision);
new GitFileAnnotation(myProject, vcsAnnotation.getFilePath().getVirtualFile(), forCurrentRevision, revisionNumber);
gitFileAnnotation.addLogEntries(session.getRevisionList());
final VcsLineAnnotationData basicAnnotation = vcsAnnotation.getBasicAnnotation();
final int size = basicAnnotation.getNumLines();
@@ -57,6 +57,7 @@ public class GitFileAnnotation implements FileAnnotation {
* The project reference
*/
private final Project myProject;
private final VcsRevisionNumber myBaseRevision;
/**
* Annotation change listeners
*/
@@ -103,6 +104,7 @@ public class GitFileAnnotation implements FileAnnotation {
return author == null ? "" : author;
}
};
private final GitVcs myVcs;
/**
* A constructor
@@ -110,10 +112,13 @@ public class GitFileAnnotation implements FileAnnotation {
* @param project the project of annotation provider
* @param file the git root
* @param monitorFlag if false the file system will not be listened for changes (used for annotated files from the repository).
* @param revision
*/
public GitFileAnnotation(@NotNull final Project project, @NotNull VirtualFile file, final boolean monitorFlag) {
public GitFileAnnotation(@NotNull final Project project, @NotNull VirtualFile file, final boolean monitorFlag, final VcsRevisionNumber revision) {
myProject = project;
myVcs = GitVcs.getInstance(myProject);
myFile = file;
myBaseRevision = revision == null ? (myVcs.getDiffProvider().getCurrentRevision(file)) : revision;
myMonitorFlag = monitorFlag;
if (myMonitorFlag) {
myFileListener = new VirtualFileAdapter() {
@@ -121,6 +126,8 @@ public class GitFileAnnotation implements FileAnnotation {
public void contentsChanged(final VirtualFileEvent event) {
if (myFile != event.getFile()) return;
if (!event.isFromRefresh()) return;
final VcsRevisionNumber currentRevision = myVcs.getDiffProvider().getCurrentRevision(myFile);
if (currentRevision != null && currentRevision.equals(revision)) return;
fireAnnotationChanged();
}
};
@@ -391,6 +398,11 @@ public class GitFileAnnotation implements FileAnnotation {
private void checkAndFire() {
// for the case of commit changes... remove annotation gutter
if (FileStatus.NOT_CHANGED.equals(FileStatusManager.getInstance(myProject).getStatus(myFile))) {
if (myBaseRevision != null) {
final VcsRevisionNumber currentRevision = myVcs.getDiffProvider().getCurrentRevision(myFile);
// revision is not when monitorFlag is true
if (currentRevision != null && currentRevision.equals(myBaseRevision)) return;
}
fireAnnotationChanged();
}
}
+2
View File
@@ -252,6 +252,8 @@
<weigher key="proximity" implementationClass="org.jetbrains.plugins.groovy.lang.completion.weighers.GrReferenceListWeigher"
id="groovyReferenceListWeigher" order="before openedInEditor" />
<topLevelClassProvider implementation="org.jetbrains.plugins.groovy.debugger.GroovyTopLevelParentClassProvider"/>
<debuggerClassFilterProvider implementation="org.jetbrains.plugins.groovy.debugger.filters.GroovyDebuggerClassFilterProvider"/>
<useScopeEnlarger implementation="org.jetbrains.plugins.groovy.lang.psi.impl.search.GrPrivateFieldScopeEnlarger"/>
@@ -94,8 +94,8 @@ public class GroovyCodeFragmentFactory implements CodeFragmentFactory {
javaText.append("groovy.lang.MetaClass |mc;\n");
javaText.append("java.lang.Class |clazz;\n");
if (!isStatic) {
javaText.append("|clazz = ((java.lang.Object)this).getClass();\n");
javaText.append("|mc = ((groovy.lang.GroovyObject)this).getMetaClass();\n");
javaText.append("|clazz = this.getClass();\n");
javaText.append("|mc = this.getMetaClass();\n");
} else {
assert contextClass != null;
javaText.append("|clazz = java.lang.Class.forName(\"").append(contextClass.getQualifiedName()).append("\");\n");
@@ -118,16 +118,16 @@ public class GroovyCodeFragmentFactory implements CodeFragmentFactory {
javaText.append("groovy.lang.ExpandoMetaClass |emc = new groovy.lang.ExpandoMetaClass(|clazz);\n");
if (!isStatic) {
javaText.append("|emc.setProperty(\"").append(EVAL_NAME).append("\", |closure);\n");
javaText.append("((groovy.lang.GroovyObject)this).setMetaClass(|emc);\n");
javaText.append("this.setMetaClass(|emc);\n");
} else {
javaText.append("((groovy.lang.GroovyObject)|emc.getProperty(\"static\")).setProperty(\"").append(EVAL_NAME).append("\", |closure);\n");
javaText.append("|emc.getProperty(\"static\").setProperty(\"").append(EVAL_NAME).append("\", |closure);\n");
javaText.append("groovy.lang.GroovySystem.getMetaClassRegistry().setMetaClass(|clazz, |emc);\n");
}
javaText.append("|emc.initialize();\n");
javaText.append(unwrapVals(values));
if (!isStatic) {
javaText.append("java.lang.Object |res = ((groovy.lang.MetaClassImpl)|emc).invokeMethod(this, \"").append(EVAL_NAME).append("\", |resVals);\n");
javaText.append("((groovy.lang.GroovyObject)this).setMetaClass(|mc);"); //try/finally is not supported
javaText.append("this.setMetaClass(|mc);"); //try/finally is not supported
} else {
javaText.append("java.lang.Object |res = ((groovy.lang.MetaClassImpl)|emc).invokeStaticMethod(|clazz, \"").append(EVAL_NAME).append("\", |resVals);\n");
javaText.append("groovy.lang.GroovySystem.getMetaClassRegistry().setMetaClass(|clazz, |mc);\n");
@@ -0,0 +1,51 @@
/*
* Copyright 2000-2011 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.debugger;
import com.intellij.debugger.engine.TopLevelParentClassProvider;
import com.intellij.psi.PsiAnonymousClass;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
/**
* @author Max Medvedev
*/
public class GroovyTopLevelParentClassProvider extends TopLevelParentClassProvider {
@Nullable
@Override
protected PsiClass getCustomTopLevelParentClass(PsiClass psiClass) {
if (!(psiClass instanceof GrTypeDefinition)) return null;
PsiClass enclosing = PsiTreeUtil.getParentOfType(psiClass, PsiClass.class, true);
while (enclosing != null) {
psiClass = enclosing;
enclosing = PsiTreeUtil.getParentOfType(enclosing, PsiClass.class, true);
}
if (psiClass instanceof PsiAnonymousClass) {
final PsiFile file = psiClass.getContainingFile();
if (file instanceof GroovyFile) {
return ((GroovyFile)file).getScriptClass();
}
}
return psiClass;
}
}
@@ -64,7 +64,12 @@ public class GroovyLiteralCopyPasteProcessor extends StringLiteralCopyPasteProce
IElementType tokenType = token.getNode().getElementType();
if (tokenType == mREGEX_CONTENT || tokenType == mREGEX_LITERAL) {
return StringUtil.escapeSlashes(s);
if (escapeSlashes) {
return StringUtil.escapeSlashes(s);
}
else {
return s;
}
}
String chars;
@@ -87,4 +92,17 @@ public class GroovyLiteralCopyPasteProcessor extends StringLiteralCopyPasteProce
StringUtil.escapeStringCharacters(s.length(), s, chars, escapeSlashes, buffer);
return buffer.toString();
}
@NotNull
@Override
protected String unescape(String text, PsiElement token) {
final IElementType tokenType = token.getNode().getElementType();
if (tokenType == mREGEX_CONTENT || tokenType == mREGEX_LITERAL) {
return StringUtil.unescapeSlashes(text);
}
return super.unescape(text, token);
}
}
@@ -23,4 +23,5 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpres
* @author ilyas
*/
public interface GrLiteral extends GrExpression, PsiLiteral {
void setStringValue(String value);
}
@@ -0,0 +1,21 @@
package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.literals;
import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrExpressionImpl;
import org.jetbrains.plugins.groovy.lang.resolve.GroovyStringLiteralManipulator;
public abstract class GrAbstractLiteral extends GrExpressionImpl implements GrLiteral {
public GrAbstractLiteral(@NotNull ASTNode node) {
super(node);
}
@Override
public void setStringValue(String value) {
new GroovyStringLiteralManipulator().handleContentChange(this, value);
}
}
@@ -43,7 +43,7 @@ import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.*;
/**
* @author ilyas
*/
public class GrLiteralImpl extends GrExpressionImpl implements GrLiteral, PsiLanguageInjectionHost {
public class GrLiteralImpl extends GrAbstractLiteral implements GrLiteral, PsiLanguageInjectionHost {
private static final Function<GrLiteralImpl,PsiType> TYPE_CALCULATOR = new NullableFunction<GrLiteralImpl, PsiType>() {
@Override
@@ -35,7 +35,7 @@ import java.util.List;
/**
* @author ilyas
*/
public class GrStringImpl extends GrExpressionImpl implements GrString {
public class GrStringImpl extends GrAbstractLiteral implements GrString {
private static final Function<GrStringImpl,PsiType> TYPE_CALCULATOR = new Function<GrStringImpl, PsiType>() {
@Override
public PsiType fun(GrStringImpl grString) {
@@ -25,39 +25,6 @@ import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
class GroovyCopyPasteTest extends LightCodeInsightFixtureTestCase {
int myAddImportsOld
public void testEscapeSlashesInRegex() {
myFixture.configureByText 'a.groovy', '<selection>a/b</selection>'
myFixture.performEditorAction IdeActions.ACTION_COPY
myFixture.configureByText 'b.groovy', 'def x = /smth<caret>/'
myFixture.performEditorAction IdeActions.ACTION_PASTE
myFixture.checkResult 'def x = /smtha\\/b<caret>/'
}
public void testEscapeSlashesInRegexFromRegex() {
myFixture.configureByText 'a.groovy', 'def x = /<selection>a\\/b</selection>/'
myFixture.performEditorAction IdeActions.ACTION_COPY
myFixture.configureByText 'b.groovy', 'def x = /smth<caret>/'
myFixture.performEditorAction IdeActions.ACTION_PASTE
myFixture.checkResult 'def x = /smtha\\/b<caret>/'
}
void testDontEscapeSymbolsInRegex(){
myFixture.configureByText 'a.groovy', '''def x = <selection>a/b</selection>'''
myFixture.performEditorAction IdeActions.ACTION_COPY
myFixture.configureByText 'b.groovy', 'def x = /<caret> /'
myFixture.performEditorAction IdeActions.ACTION_PASTE
myFixture.checkResult '''def x = /a\\/b /'''
}
public void testEscapeDollarInGString() {
myFixture.configureByText 'a.groovy', '''def x = '<selection>$a</selection>b/'''
myFixture.performEditorAction IdeActions.ACTION_COPY
myFixture.configureByText 'b.groovy', 'def x = "smth<caret>h"'
myFixture.performEditorAction IdeActions.ACTION_PASTE
myFixture.checkResult 'def x = "smth$a<caret>h"'
}
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -73,41 +40,64 @@ class GroovyCopyPasteTest extends LightCodeInsightFixtureTestCase {
settings.ADD_IMPORTS_ON_PASTE = myAddImportsOld;
super.tearDown();
}
private void doTest(String fromFileName, String fromText, String toText, String expected) {
myFixture.configureByText fromFileName, fromText
myFixture.performEditorAction IdeActions.ACTION_COPY
myFixture.configureByText 'b.groovy', toText
myFixture.performEditorAction IdeActions.ACTION_PASTE
myFixture.checkResult expected
}
public void testEscapeSlashesInRegex() {
doTest 'a.groovy', '<selection>a/b</selection>', 'def x = /smth<caret>/', 'def x = /smtha\\/b<caret>/'
}
public void testEscapeSlashesInRegexFromRegex() {
doTest 'a.groovy', 'def x = /<selection>a\\/b</selection>/', 'def x = /smth<caret>/', 'def x = /smtha\\/b<caret>/'
}
void testDontEscapeSymbolsInRegex(){
doTest 'a.groovy', '''def x = <selection>a/b</selection>''', 'def x = /<caret> /', '''def x = /a\\/b /'''
}
public void testEscapeDollarInGString() {
doTest 'a.groovy', '''def x = '<selection>$a</selection>b/''', 'def x = "smth<caret>h"', 'def x = "smth\\$a<caret>h"'
}
public void testRestoreImports() {
myFixture.addClass("package foo; public class Foo {}")
myFixture.configureByText 'a.groovy', '''import foo.*; <selection>Foo f</selection>'''
myFixture.performEditorAction IdeActions.ACTION_COPY
myFixture.configureByText 'b.groovy', '<caret>'
myFixture.performEditorAction IdeActions.ACTION_PASTE
myFixture.checkResult '''import foo.Foo
doTest 'a.groovy', '''import foo.*; <selection>Foo f</selection>''', '<caret>', '''import foo.Foo
Foo f'''
}
public void testPasteMultilineIntoMultilineGString() throws Exception {
myFixture.configureByText 'a.txt', '<selection>a/b\nc/d</selection>'
myFixture.performEditorAction IdeActions.ACTION_COPY
myFixture.configureByText 'b.groovy', 'def x = """smth<caret>"""'
myFixture.performEditorAction IdeActions.ACTION_PASTE
myFixture.checkResult 'def x = """smtha/b\nc/d<caret>"""'
doTest 'a.txt', '<selection>a/b\nc/d</selection>', 'def x = """smth<caret>"""', 'def x = """smtha/b\nc/d<caret>"""'
}
public void testPasteMultilineIntoString() throws Exception {
myFixture.configureByText 'a.txt', '<selection>a\nd</selection>'
myFixture.performEditorAction IdeActions.ACTION_COPY
myFixture.configureByText 'b.groovy', "def x = 'smth<caret>'"
myFixture.performEditorAction IdeActions.ACTION_PASTE
myFixture.checkResult "def x = 'smtha\\n' +\n 'd<caret>'"
doTest 'a.txt', '<selection>a\nd</selection>', "def x = 'smth<caret>'", "def x = 'smtha\\n' +\n 'd<caret>'"
}
public void testPasteMultilineIntoGString() throws Exception {
myFixture.configureByText 'a.txt', '<selection>a\nd</selection>'
myFixture.performEditorAction IdeActions.ACTION_COPY
myFixture.configureByText 'b.groovy', 'def x = "smth<caret>"'
myFixture.performEditorAction IdeActions.ACTION_PASTE
myFixture.checkResult 'def x = "smtha\\n" +\n "d<caret>"'
doTest 'a.txt', '<selection>a\nd</selection>', 'def x = "smth<caret>"', 'def x = "smtha\\n" +\n "d<caret>"'
}
public void testGStringEolReplace() throws Exception {
doTest 'a.txt',
'''<selection>first
second
</selection>''',
'''def x = """
<selection>foo
</selection>"""''',
'''def x = """
first
second
<caret>"""'''
}
}
@@ -211,6 +211,22 @@ cl.parseClass('''$mcText''', 'MyClass.groovy').foo(2)
eval 'a', '2'
}
}
void testAnonymousClassInScript() {
myFixture.addFileToProject('Foo.groovy', '''\
new Runnable() {
void run() {
print 'foo'
}
}.run()
''')
addBreakpoint 'Foo.groovy', 2
runDebugger 'Foo', {
waitForBreakpoint()
eval '1+1', '2'
}
}
private def addBreakpoint(String fileName, int line) {
VirtualFile file = null
@@ -80,22 +80,26 @@ public final class ErrorAnalyzer {
@Nullable final GuiEditor editor,
@NotNull final IRootContainer rootContainer,
@Nullable final ProgressIndicator progress) {
if (module.isDisposed()) {
return;
}
// 1. Validate class to bind
final String classToBind = rootContainer.getClassToBind();
final PsiClass psiClass;
if(classToBind != null){
if (classToBind != null) {
psiClass = FormEditingUtil.findClassToBind(module, classToBind);
if(psiClass == null){
if (psiClass == null) {
final QuickFix[] fixes = editor != null ? new QuickFix[]{new CreateClassToBindFix(editor, classToBind)} : QuickFix.EMPTY_ARRAY;
final ErrorInfo errorInfo = new ErrorInfo(null, null, UIDesignerBundle.message("error.class.does.not.exist", classToBind),
HighlightDisplayLevel.ERROR, fixes);
rootContainer.putClientProperty(CLIENT_PROP_CLASS_TO_BIND_ERROR, errorInfo);
}
else{
else {
rootContainer.putClientProperty(CLIENT_PROP_CLASS_TO_BIND_ERROR, null);
}
}
else{
else {
rootContainer.putClientProperty(CLIENT_PROP_CLASS_TO_BIND_ERROR, null);
psiClass = null;
}
@@ -116,13 +120,13 @@ public final class ErrorAnalyzer {
final String binding = component.getBinding();
// a. Check that field exists and field is not static
if(psiClass != null && binding != null) {
if (psiClass != null && binding != null) {
if (validateFieldInClass(component, binding, component.getComponentClassName(), psiClass, editor, module)) return true;
}
// b. Check that binding is unique
if (binding != null) {
if(usedBindings.contains(binding)){
if (usedBindings.contains(binding)) {
// TODO[vova] implement
component.putClientProperty(
CLIENT_PROP_BINDING_ERROR,
@@ -162,14 +166,14 @@ public final class ErrorAnalyzer {
// Clear previous error (if any)
component.putClientProperty(CLIENT_PROP_ERROR_ARRAY, null);
if(!(component instanceof IContainer)){
if (!(component instanceof IContainer)) {
return true;
}
final IContainer container = (IContainer)component;
if(container instanceof IRootContainer){
if (container instanceof IRootContainer) {
final IRootContainer rootContainer = (IRootContainer)container;
if(rootContainer.getComponentCount() > 1){
if (rootContainer.getComponentCount() > 1) {
// TODO[vova] implement
putError(component, new ErrorInfo(
component, null, UIDesignerBundle.message("error.multiple.toplevel.components"),
@@ -178,13 +182,13 @@ public final class ErrorAnalyzer {
));
}
}
else if(container.isXY() && container.getComponentCount() > 0){
else if (container.isXY() && container.getComponentCount() > 0) {
// TODO[vova] implement
putError(component, new ErrorInfo(
component, null, UIDesignerBundle.message("error.panel.not.laid.out"),
HighlightDisplayLevel.ERROR,
QuickFix.EMPTY_ARRAY
)
component, null, UIDesignerBundle.message("error.panel.not.laid.out"),
HighlightDisplayLevel.ERROR,
QuickFix.EMPTY_ARRAY
)
);
}
return true;
@@ -199,14 +203,14 @@ public final class ErrorAnalyzer {
if (formPsiFile != null && rootContainer instanceof RadRootContainer) {
final List<FormInspectionTool> formInspectionTools = new ArrayList<FormInspectionTool>();
final FormInspectionTool[] registeredFormInspections = Extensions.getExtensions(FormInspectionTool.EP_NAME);
for(FormInspectionTool formInspectionTool: registeredFormInspections) {
for (FormInspectionTool formInspectionTool : registeredFormInspections) {
if (formInspectionTool.isActive(formPsiFile) && !rootContainer.isInspectionSuppressed(formInspectionTool.getShortName(), null)) {
formInspectionTools.add(formInspectionTool);
}
}
if (formInspectionTools.size() > 0 && editor != null) {
for(FormInspectionTool tool: formInspectionTools) {
for (FormInspectionTool tool : formInspectionTools) {
tool.startCheckForm(rootContainer);
}
FormEditingUtil.iterate(
@@ -215,7 +219,7 @@ public final class ErrorAnalyzer {
public boolean visit(final RadComponent component) {
if (progress != null && progress.isCanceled()) return false;
for(FormInspectionTool tool: formInspectionTools) {
for (FormInspectionTool tool : formInspectionTools) {
if (rootContainer.isInspectionSuppressed(tool.getShortName(), component.getId())) continue;
ErrorInfo[] errorInfos = tool.checkComponent(editor, component);
if (errorInfos != null) {
@@ -231,7 +235,7 @@ public final class ErrorAnalyzer {
}
}
);
for(FormInspectionTool tool: formInspectionTools) {
for (FormInspectionTool tool : formInspectionTools) {
tool.doneCheckForm(rootContainer);
}
}
@@ -20,6 +20,7 @@ import com.intellij.openapi.util.Comparing;
import com.intellij.uiDesigner.radComponents.RadComponent;
import com.intellij.uiDesigner.radComponents.RadRootContainer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Anton Katilin
@@ -39,9 +40,9 @@ final class ComponentPtrDescriptor extends NodeDescriptor<ComponentPtr> {
myPtr=ptr;
}
public boolean update(){
public boolean update() {
myPtr.validate();
if(!myPtr.isValid()){
if(!myPtr.isValid()) {
myPtr=null;
return true;
}
@@ -49,7 +50,10 @@ final class ComponentPtrDescriptor extends NodeDescriptor<ComponentPtr> {
final String oldBinding = myBinding;
final String oldTitle = myTitle;
final RadComponent component = myPtr.getComponent();
if(component instanceof RadRootContainer){
if (component.getModule().isDisposed()) {
return false;
}
if(component instanceof RadRootContainer) {
myBinding = ((RadRootContainer)component).getClassToBind();
}
else{
@@ -59,6 +63,7 @@ final class ComponentPtrDescriptor extends NodeDescriptor<ComponentPtr> {
return !Comparing.equal(oldBinding,myBinding) || !Comparing.equal(oldTitle, myTitle);
}
@Nullable
public RadComponent getComponent() {
return myPtr != null ? myPtr.getComponent() : null;
}
@@ -42,13 +42,8 @@ final class ComponentTreeStructure extends AbstractTreeStructure{
private final GuiEditor myEditor;
public ComponentTreeStructure(@NotNull final GuiEditor editor){
myRootElement=new Object() {
@Override
public String toString() {
return "root of component tree structure " + ComponentTreeStructure.this.toString();
}
};
myEditor=editor;
myRootElement = new ComponentTreeStructureRoot();
myEditor = editor;
}
public Object getRootElement(){
@@ -107,7 +102,7 @@ final class ComponentTreeStructure extends AbstractTreeStructure{
}
public Object getParentElement(final Object element){
if(element==myRootElement){
if (element instanceof ComponentTreeStructureRoot) {
return null;
}
else if (element instanceof LwInspectionSuppression[] || element instanceof RadButtonGroup[]) {
@@ -180,4 +175,11 @@ final class ComponentTreeStructure extends AbstractTreeStructure{
public boolean hasSomethingToCommit(){
return false;
}
private class ComponentTreeStructureRoot {
@Override
public String toString() {
return "root of component tree structure " + ComponentTreeStructure.this.toString();
}
}
}
+1
View File
@@ -121,6 +121,7 @@
<extensionPoint name="javaMainMethodProvider" interface="com.intellij.codeInsight.runner.JavaMainMethodProvider"/>
<extensionPoint name="debuggerClassFilterProvider" interface="com.intellij.ui.classFilter.DebuggerClassFilterProvider"/>
<extensionPoint name="topLevelClassProvider" interface="com.intellij.debugger.engine.TopLevelParentClassProvider"/>
<extensionPoint name="debuggerEditorTextProvider" beanClass="com.intellij.lang.LanguageExtensionPoint" />
@@ -615,7 +615,7 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag {
final int s = result.size();
XmlTag[] tags = s > 0 ? ContainerUtil.toArray(result, new XmlTag[s]) : EMPTY;
return Result.create(tags, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT);
return Result.create(tags, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT, getContainingFile());
}
});