Merge remote-tracking branch 'origin/master'

This commit is contained in:
Kirill Likhodedov
2011-11-23 13:19:50 +03:00
107 changed files with 2104 additions and 951 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);
}
@@ -16,7 +16,7 @@
package com.intellij.codeInsight.completion.scope;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtilCore;
import org.jetbrains.annotations.Nullable;
/**
* Created by IntelliJ IDEA.
@@ -26,16 +26,12 @@ import com.intellij.psi.util.PsiUtilCore;
* To change this template use Options | File Templates.
*/
public class CompletionElement{
private final PsiType myQualifier;
private final PsiClass myQualifierClass;
private final Object myElement;
private final PsiSubstitutor mySubstitutor;
public CompletionElement(PsiType qualifier, Object element, PsiSubstitutor substitutor, final PsiClass qualifierClass){
public CompletionElement(Object element, PsiSubstitutor substitutor) {
myElement = element;
myQualifier = qualifier;
mySubstitutor = substitutor;
myQualifierClass = qualifierClass;
}
public PsiSubstitutor getSubstitutor(){
@@ -46,34 +42,22 @@ public class CompletionElement{
return myElement;
}
public Object getUniqueId(){
final String name;
@Nullable
Object getUniqueId(){
if(myElement instanceof PsiClass){
name = ((PsiClass)myElement).getQualifiedName();
return ((PsiClass)myElement).getQualifiedName();
}
else if(myElement instanceof PsiPackage){
name = ((PsiPackage)myElement).getQualifiedName();
if(myElement instanceof PsiPackage){
return ((PsiPackage)myElement).getQualifiedName();
}
else if(myElement instanceof PsiMethod){
if(myElement instanceof PsiMethod){
return ((PsiMethod)myElement).getSignature(mySubstitutor);
}
else if (myElement instanceof PsiField) {
final PsiField field = (PsiField)myElement;
final String s = field.getName();
if (myQualifierClass != null || !field.hasModifierProperty(PsiModifier.STATIC)) return "#" + s;
return field.getContainingClass().getQualifiedName() + "#" + s;
}
else if(myElement instanceof PsiElement){
name = PsiUtilCore.getName((PsiElement)myElement);
}
else{
name = "";
if (myElement instanceof PsiVariable) {
return "#" + ((PsiVariable)myElement).getName();
}
return name;
return null;
}
public PsiType getQualifier(){
return myQualifier;
}
}
@@ -224,7 +224,7 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme
}
if (satisfies(element, state) && isAccessible(element)) {
CompletionElement element1 = new CompletionElement(myQualifierType, element, state.get(PsiSubstitutor.KEY), myQualifierClass);
CompletionElement element1 = new CompletionElement((PsiNamedElement)element, state.get(PsiSubstitutor.KEY));
if (myResultNames.add(element1.getUniqueId())) {
myResults.add(element1);
}
@@ -257,7 +257,7 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme
public void setCompletionElements(@NotNull Object[] elements) {
for (Object element: elements) {
myResults.add(new CompletionElement(null, element, PsiSubstitutor.EMPTY, myQualifierClass));
myResults.add(new CompletionElement(element, PsiSubstitutor.EMPTY));
}
}
@@ -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();
}
@@ -152,7 +152,12 @@ public class JavaElementSignatureProvider extends AbstractElementSignatureProvid
return null;
}
protected PsiElement restoreBySignatureTokens(@NotNull PsiFile file, @NotNull PsiElement parent, @NotNull String type, @NotNull StringTokenizer tokenizer) {
protected PsiElement restoreBySignatureTokens(@NotNull PsiFile file,
@NotNull PsiElement parent,
@NotNull String type,
@NotNull StringTokenizer tokenizer,
@Nullable StringBuilder processingInfoStorage)
{
if (type.equals("imports")) {
if (!(file instanceof PsiJavaFile)) return null;
return ((PsiJavaFile)file).getImportList();
@@ -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;
@@ -0,0 +1,8 @@
interface Intf { Intf FOO = null; }
interface Intf2 extends Intf { Intf2 FOO = null; }
public class Bar implements Intf2 {
public static void fpp() {
F<caret>
}
}
@@ -494,6 +494,11 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase {
assertStringItems("boolean", "byte")
}
public void testDoubleConstant() throws Throwable {
configure()
assertStringItems("FOO", "Float")
}
public void testNotOnlyKeywordsInsideSwitch() throws Throwable {
doTest();
}
@@ -31,6 +31,7 @@ public class IFileElementType extends ILazyParseableElementType {
super(debugName, language);
}
@Nullable
@Override
public ASTNode parseContents(final ASTNode chameleon) {
final PsiElement psi = chameleon.getPsi();
@@ -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();
@@ -23,6 +23,9 @@ import org.jetbrains.annotations.Nullable;
* @version 1.0
*/
public interface Filter {
Filter[] EMPTY_ARRAY = new Filter[0];
class Result{
public final int highlightStartOffset;
public final int highlightEndOffset;
@@ -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;
@@ -474,8 +474,7 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler {
if (decision == AutoCompletionDecision.SHOW_LOOKUP) {
CompletionServiceImpl.setCompletionPhase(new CompletionPhase.ItemsCalculated(indicator));
indicator.getLookup().setCalculating(false);
indicator.showLookup();
if (isAutocompleteCommonPrefixOnInvocation() && items.length > 1) {
if (indicator.showLookup() && isAutocompleteCommonPrefixOnInvocation() && items.length > 1) {
indicator.fillInCommonPrefix(false);
}
}
@@ -304,8 +304,8 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
return "Completion" + hashCode();
}
public void showLookup() {
updateLookup();
public boolean showLookup() {
return updateLookup();
}
public CompletionParameters getParameters() {
@@ -320,14 +320,14 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
return myLookup;
}
private void updateLookup() {
private boolean updateLookup() {
ApplicationManager.getApplication().assertIsDispatchThread();
if (isOutdated()) return;
if (isOutdated()) return false;
boolean justShown = false;
if (!myLookup.isShown() && shouldShowLookup()) {
if (hideAutopopupIfMeaningless()) {
return;
return false;
}
if (StringUtil.isEmpty(myLookup.getAdvertisementText()) && !isAutopopupCompletion()) {
@@ -338,7 +338,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
}
if (!myLookup.showLookup()) {
return;
return false;
}
justShown = true;
}
@@ -347,6 +347,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
if (justShown) {
myLookup.ensureSelectionVisible();
}
return true;
}
private boolean shouldShowLookup() {
@@ -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 =
@@ -32,7 +32,9 @@ import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;
@@ -126,7 +128,9 @@ public class BaseIndentEnterHandler extends EnterHandlerDelegateAdapter {
}
protected String getSingleIndent(final PsiFile file) {
return StringUtil.repeatSymbol(' ', CodeStyleSettingsManager.getInstance().getCurrentSettings().getIndentSize(myLanguage.getAssociatedFileType()));
CodeStyleSettings currantSettings = CodeStyleSettingsManager.getSettings(file.getProject());
CommonCodeStyleSettings.IndentOptions indentOptions = currantSettings.getIndentOptions(file.getFileType());
return StringUtil.repeatSymbol(' ', indentOptions.INDENT_SIZE);
}
@Nullable
@@ -61,11 +61,7 @@ class MoverWrapper {
String textToInsert2 = document.getCharsSequence().subSequence(start2, end2).toString();
if (!StringUtil.endsWithChar(textToInsert2,'\n')) textToInsert2 += '\n';
myInfo.range2 = document.createRangeMarker(start2, end2);
final int startOffset1 = myInfo.range1.getStartOffset();
final int startOffset2 = myInfo.range2.getStartOffset();
final int endOffset1 = myInfo.range1.getEndOffset();
final int endOffset2 = myInfo.range2.getEndOffset();
if (startOffset1 < startOffset2) {
if (myInfo.range1.getStartOffset() < myInfo.range2.getStartOffset()) {
myInfo.range1.setGreedyToLeft(true);
myInfo.range1.setGreedyToRight(false);
myInfo.range2.setGreedyToLeft(true);
@@ -110,13 +106,14 @@ class MoverWrapper {
}
}
document.insertString(startOffset1, textToInsert2);
document.deleteString(startOffset1 +textToInsert2.length(), endOffset1);
document.insertString(myInfo.range1.getStartOffset(), textToInsert2);
document.deleteString(myInfo.range1.getStartOffset()+textToInsert2.length(), myInfo.range1.getEndOffset());
document.insertString(startOffset2, textToInsert);
if (endOffset2 > startOffset1 + textToInsert.length()) {
document.deleteString(startOffset2 + textToInsert.length(), endOffset2);
document.insertString(myInfo.range2.getStartOffset(), textToInsert);
int s = myInfo.range2.getStartOffset() + textToInsert.length();
int e = myInfo.range2.getEndOffset();
if (e > s) {
document.deleteString(s, e);
}
final Project project = file.getProject();
@@ -138,10 +135,10 @@ class MoverWrapper {
CodeFoldingManager.getInstance(project).allowFoldingOnCaretLine(editor);
if (hasSelection) {
restoreSelection(editor, selectionStart, selectionEnd, start, startOffset2);
restoreSelection(editor, selectionStart, selectionEnd, start, myInfo.range2.getStartOffset());
}
caretModel.moveToOffset(startOffset2 + caretRelativePos);
caretModel.moveToOffset(myInfo.range2.getStartOffset() + caretRelativePos);
if (myInfo.indentTarget) {
indentLinesIn(editor, file, document, project, myInfo.range2);
}
@@ -42,7 +42,9 @@ public abstract class AbstractElementSignatureProvider implements ElementSignatu
if (semicolonIndex >= 0) {
String parentSignature = signature.substring(semicolonIndex + 1);
if (processingInfoStorage != null) {
processingInfoStorage.append(String.format("Restoring parent by signature '%s'...%n", parentSignature));
processingInfoStorage.append(String.format(
"Provider '%s'. Restoring parent by signature '%s'...%n", getClass().getName(), parentSignature
));
}
parent = restoreBySignature(file, parentSignature, processingInfoStorage);
if (processingInfoStorage != null) {
@@ -59,17 +61,19 @@ public abstract class AbstractElementSignatureProvider implements ElementSignatu
String type = tokenizer.nextToken();
if (processingInfoStorage != null) {
processingInfoStorage.append(String.format(
"Restoring target element by signature '%s'. Parent: %s, same as the given parent: %b%n", signature, parent, parent == file
"Provider '%s'. Restoring target element by signature '%s'. Parent: %s, same as the given parent: %b%n",
getClass().getName(), signature, parent, parent == file
));
}
return restoreBySignatureTokens(file, parent, type, tokenizer);
return restoreBySignatureTokens(file, parent, type, tokenizer, processingInfoStorage);
}
@Nullable
protected abstract PsiElement restoreBySignatureTokens(@NotNull PsiFile file,
@NotNull PsiElement parent,
@NotNull String type,
@NotNull StringTokenizer tokenizer);
@NotNull StringTokenizer tokenizer,
@Nullable StringBuilder processingInfoStorage);
protected static <T extends PsiNamedElement> int getChildIndex(T element, PsiElement parent, String name, Class<T> hisClass) {
PsiElement[] children = parent.getChildren();
@@ -19,6 +19,7 @@ import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.StringTokenizer;
@@ -38,9 +39,16 @@ public class OffsetsElementSignatureProvider extends AbstractElementSignaturePro
protected PsiElement restoreBySignatureTokens(@NotNull PsiFile file,
@NotNull PsiElement parent,
@NotNull String type,
@NotNull StringTokenizer tokenizer)
@NotNull StringTokenizer tokenizer,
@Nullable StringBuilder processingInfoStorage)
{
if (!TYPE_MARKER.equals(type)) {
if (processingInfoStorage != null) {
processingInfoStorage.append(String.format(
"Stopping '%s' provider because given signature doesn't have expected type - can work with '%s' but got '%s'",
getClass().getName(), TYPE_MARKER, type
));
}
return null;
}
int start;
@@ -52,15 +60,28 @@ public class OffsetsElementSignatureProvider extends AbstractElementSignaturePro
catch (NumberFormatException e) {
return null;
}
if (processingInfoStorage != null) {
processingInfoStorage.append(String.format("Parsed target offsets - [%d; %d)", start, end));
}
PsiElement element = file.findElementAt(start);
if (processingInfoStorage != null) {
processingInfoStorage.append(String.format("Found the following element at start offset - '%s'", element));
}
if (element == null) {
return null;
}
TextRange range = element.getTextRange();
if (processingInfoStorage != null) {
processingInfoStorage.append(String.format("Target element range is %s", range));
}
while (range != null && range.getStartOffset() == start && range.getEndOffset() < end) {
element = element.getParent();
range = element.getTextRange();
if (processingInfoStorage != null) {
processingInfoStorage.append(String.format("Expanding element to '%s' and range to '%s'", element, range));
}
}
if (range == null || range.getStartOffset() != start || range.getEndOffset() != end) {
return null;
@@ -82,10 +103,17 @@ public class OffsetsElementSignatureProvider extends AbstractElementSignaturePro
indexFromRoot++;
}
if (processingInfoStorage != null) {
processingInfoStorage.append(String.format("Target element index is %d. Current index from root is %d", index, indexFromRoot));
}
if (index > indexFromRoot) {
int steps = index - indexFromRoot;
PsiElement result = element;
for (PsiElement e = result.getFirstChild(); steps > 0 && e != null && range.equals(e.getTextRange()); steps--, e = e.getFirstChild()) {
if (processingInfoStorage != null) {
processingInfoStorage.append(String.format("Clarifying target element to '%s', its range is %s", result, result.getTextRange()));
}
result = e;
}
return result;
@@ -95,15 +123,21 @@ public class OffsetsElementSignatureProvider extends AbstractElementSignaturePro
PsiElement result = element;
while (--steps >= 0) {
result = result.getParent();
if (processingInfoStorage != null) {
processingInfoStorage.append(String.format("Reducing target element to '%s', its range is %s", result, result.getTextRange()));
}
}
return result;
}
@Override
public String getSignature(@NotNull PsiElement element) {
TextRange range = element.getTextRange();
if (range.isEmpty()) {
return null;
}
StringBuilder buffer = new StringBuilder();
buffer.append(TYPE_MARKER).append("#");
TextRange range = element.getTextRange();
buffer.append(range.getStartOffset());
buffer.append(ELEMENT_TOKENS_SEPARATOR);
buffer.append(range.getEndOffset());
@@ -19,6 +19,7 @@ import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.StringTokenizer;
/**
@@ -41,9 +42,16 @@ public class PsiNamesElementSignatureProvider extends AbstractElementSignaturePr
protected PsiElement restoreBySignatureTokens(@NotNull PsiFile file,
@NotNull PsiElement parent,
@NotNull final String type,
@NotNull StringTokenizer tokenizer)
@NotNull StringTokenizer tokenizer,
@Nullable StringBuilder processingInfoStorage)
{
if (!TYPE_MARKER.equals(type)) {
if (processingInfoStorage != null) {
processingInfoStorage.append(String.format(
"Stopping '%s' provider because given signature doesn't have expected type - can work with '%s' but got '%s'",
getClass().getName(), TYPE_MARKER, type
));
}
return null;
}
String elementMarker = tokenizer.nextToken();
@@ -58,6 +66,12 @@ public class PsiNamesElementSignatureProvider extends AbstractElementSignaturePr
result = child;
}
else {
if (processingInfoStorage != null) {
processingInfoStorage.append(String.format(
"Stopping '%s' provider because it has top level marker but more than one non white-space child: %s",
getClass().getName(), Arrays.toString(children)
));
}
// More than one top-level non-white space children. Can't match.
return null;
}
@@ -32,7 +32,9 @@ import com.intellij.lang.LangBundle;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.diagnostic.Logger;
@@ -718,18 +720,19 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
}
public void finishLookup(char completionChar, @Nullable final LookupElement item) {
doHide(false, true);
if (item == null ||
item instanceof EmptyLookupItem ||
item.getObject() instanceof DeferredUserLookupValue &&
item.as(LookupItem.CLASS_CONDITION_KEY) != null &&
!((DeferredUserLookupValue)item.getObject()).handleUserSelection(item.as(LookupItem.CLASS_CONDITION_KEY), myProject)) {
doHide(false, true);
fireItemSelected(null, completionChar);
return;
}
final PsiFile file = getPsiFile();
if (file != null && !WriteCommandAction.ensureFilesWritable(myProject, Arrays.asList(file))) {
doHide(false, true);
fireItemSelected(null, completionChar);
return;
}
@@ -744,13 +747,21 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
if (!plainMatch) {
FeatureUsageTracker.getInstance().triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_CAMEL_HUMPS);
}
ApplicationManager.getApplication().runWriteAction(new Runnable() {
performGuardedChange(new Runnable() {
public void run() {
insertLookupString(item, prefix);
AccessToken token = WriteAction.start();
try {
insertLookupString(item, prefix);
}
finally {
token.finish();
}
}
});
doHide(false, true);
fireItemSelected(item, completionChar);
}
@@ -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) {
@@ -590,7 +590,7 @@ public class RunContentManagerImpl implements RunContentManager, Disposable {
return true;
}
final boolean destroyProcess;
if (Boolean.TRUE.equals(processHandler.getUserData(ProcessHandler.SILENTLY_DESTROY_ON_CLOSE))) {
if (processHandler.isSilentlyDestroyOnClose() || Boolean.TRUE.equals(processHandler.getUserData(ProcessHandler.SILENTLY_DESTROY_ON_CLOSE))) {
destroyProcess = true;
}
else {
@@ -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());
}
}
@@ -181,7 +181,7 @@ public abstract class AbstractNavBarUI implements NavBarUI {
}
protected Color getBackgroundColor() {
return new Color(0, 0, 0, 35);
return UIUtil.getSlightlyDarkerColor(UIUtil.getPanelBackground());
}
@Override
@@ -16,6 +16,7 @@
package com.intellij.ide.navigationToolbar.ui;
import com.intellij.ide.navigationToolbar.NavBarItem;
import com.intellij.util.ui.SameColor;
import com.intellij.util.ui.UIUtil;
import java.awt.*;
@@ -41,6 +42,6 @@ public class AquaNavBarUI extends AbstractNavBarUI {
@Override
protected Color getBackgroundColor() {
return new Color(0, 0, 0, 35);
return UIUtil.getSlightlyDarkerColor(new SameColor(200));
}
}
@@ -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);
@@ -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);
}
@@ -16,6 +16,7 @@
package com.intellij.ui.tabs.impl;
import com.intellij.ide.DataManager;
import com.intellij.ide.ui.UISettings;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
@@ -103,6 +104,18 @@ public class TabLabel extends JPanel {
});
}
@Override
public Insets getInsets() {
Insets insets = super.getInsets();
if (myTabs.isEditorTabs()) {
if (UISettings.getInstance().SHOW_CLOSE_BUTTON) {
return new Insets(insets.top, insets.left, insets.bottom, 3);
}
}
return insets;
}
public void setAligmentToCenter(boolean toCenter) {
if (myCentered == toCenter && myLabel.getParent() != null) return;
@@ -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;
@@ -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);
@@ -5903,59 +5923,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 +6036,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);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2010 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.
@@ -228,8 +228,8 @@ class CacheEntry implements Comparable<CacheEntry>, Cloneable {
@Override
public String toString() {
return "visual line: " + visualLine + ", offsets: " + startOffset + "-" + endOffset + ", fold regions: "
+ Arrays.toString(myFoldingData.getValues()) + ", tab data: " + myTabPositions;
return System.identityHashCode(this) + "=visual line: " + visualLine + ", offsets: " + startOffset + "-" + endOffset
+ ", fold regions: " + Arrays.toString(myFoldingData.getValues()) + ", tab data: " + myTabPositions;
}
@Override
@@ -452,7 +452,8 @@ public class CachingSoftWrapDataMapper implements SoftWrapDataMapper, SoftWrapAw
CacheEntry beforeLast = myCache.get(myCache.size() - 2);
CacheEntry last = myCache.get(myCache.size() - 1);
if (beforeLast.visualLine == last.visualLine
|| (beforeLast.visualLine + 1 == last.visualLine && last.startOffset - beforeLast.endOffset > 1))
|| (beforeLast.visualLine + 1 == last.visualLine && last.startOffset - beforeLast.endOffset > 1)
|| last.startOffset > myEditor.getDocument().getTextLength())
{
CharSequence editorState = "";
if (myEditor instanceof EditorImpl) {
@@ -481,6 +482,13 @@ public class CachingSoftWrapDataMapper implements SoftWrapDataMapper, SoftWrapAw
myBeforeChangeState.cacheShouldBeUpdated = false;
}
@Override
public void reset() {
myCache.clear();
myAffectedByUpdateCacheEntries.clear();
myNotAffectedByUpdateTailCacheEntries.clear();
}
@SuppressWarnings({"UseOfSystemOutOrSystemErr", "UnusedDeclaration", "CallToPrintStackTrace"})
private void dumpCache() {
Document document = myEditor.getDocument();
@@ -541,7 +549,7 @@ public class CachingSoftWrapDataMapper implements SoftWrapDataMapper, SoftWrapAw
int softWrapIndex = myStorage.getSoftWrapIndex(offset);
if (softWrapIndex >= 0) {
softWrapIndex++; // We want to process only soft wraps which offsets strictly more than the given one.
softWrapIndex++; // We want to process only soft wraps which offsets are strictly more than the given one.
}
else {
softWrapIndex = -softWrapIndex - 1;
@@ -118,6 +118,9 @@ public class SoftWrapApplianceManager implements SoftWrapFoldingListener, Docume
public void reset() {
myEventsStorage.release();
myEventsStorage.add(myEditor.getDocument(), new IncrementalCacheUpdateEvent(myEditor.getDocument()));
for (SoftWrapAwareDocumentParsingListener listener : myListeners) {
listener.reset();
}
}
public void release() {
@@ -205,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;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2010 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.
@@ -120,4 +120,9 @@ interface SoftWrapAwareDocumentParsingListener {
* should be rolled back if this param value is <code>false</code>
*/
void onRecalculationEnd(@NotNull IncrementalCacheUpdateEvent event, boolean normal);
/**
* Callback for asking to drop all cached information (if any).
*/
void reset();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2010 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.
@@ -120,4 +120,8 @@ public class SoftWrapAwareVisualSizeManager implements SoftWrapAwareDocumentPars
@Override
public void revertToOffset(int offset, int visualLine) {
}
@Override
public void reset() {
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2010 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.
@@ -31,7 +31,7 @@ class TabData implements Cloneable {
@Override
public String toString() {
return offset + ", width: " + widthInColumns;
return "[" + offset + ", width: " + widthInColumns + "]";
}
@Override
@@ -383,8 +383,8 @@ final class EditorTabbedContainer implements Disposable, CloseAction.CloseTarget
@Override
public void update(final AnActionEvent e) {
e.getPresentation().setIcon(myTabs instanceof JBEditorTabs && myTabs.isEditorTabs() ? myNewIcon : myIcon);
e.getPresentation().setHoveredIcon(myTabs instanceof JBEditorTabs && myTabs.isEditorTabs()? myNewHoveredIcon : myHoveredIcon);
e.getPresentation().setIcon(myTabs.isEditorTabs() ? myNewIcon : myIcon);
e.getPresentation().setHoveredIcon(myTabs.isEditorTabs()? myNewHoveredIcon : myHoveredIcon);
e.getPresentation().setVisible(UISettings.getInstance().SHOW_CLOSE_BUTTON);
}
@@ -621,6 +621,7 @@ public class EditorWindow {
if (tabCount != 0) {
final EditorWithProviderComposite firstEC = getEditorAt(0);
myPanel = new JPanel(new BorderLayout());
myPanel.setOpaque(false);
myPanel.setBorder(new AdaptiveBorder());
myPanel.setOpaque(false);
@@ -78,8 +78,7 @@ public class EditorsSplitters extends JPanel {
public EditorsSplitters(final FileEditorManagerImpl manager, DockManager dockManager, boolean createOwnDockableContainer) {
super(new BorderLayout());
setOpaque(true);
setBackground(UIUtil.isUnderAquaLookAndFeel() ? JBTabsImpl.MAC_AQUA_BG_COLOR : Color.GRAY);
setOpaque(false);
myManager = manager;
myFocusWatcher = new MyFocusWatcher();
setFocusTraversalPolicy(new MyFocusTraversalPolicy());
@@ -304,6 +303,7 @@ public class EditorsSplitters extends JPanel {
Splitter splitter;
if (panel == null) {
panel = new JPanel(new BorderLayout());
panel.setOpaque(false);
splitter = new Splitter(orientation, proportion, 0.1f, 0.9f);
panel.add(splitter, BorderLayout.CENTER);
splitter.setFirstComponent(readExternalPanel(first, null));
@@ -64,6 +64,7 @@ import com.intellij.ui.tabs.impl.JBTabsImpl;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.messages.impl.MessageListenerList;
import com.intellij.util.ui.SameColor;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.update.MergingUpdateQueue;
import com.intellij.util.ui.update.Update;
@@ -209,7 +210,17 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec
if (myPanels == null) {
synchronized (myInitLock) {
if (myPanels == null) {
myPanels = new JPanel(new BorderLayout());
myPanels = new JPanel(new BorderLayout()) {
@Override
public Color getBackground() {
boolean navBar = UISettings.getInstance().SHOW_NAVIGATION_BAR;
if (navBar) {
return UIUtil.getSlightlyDarkerColor(UIUtil.isUnderAquaLookAndFeel() ? new SameColor(200) : UIUtil.getPanelBackground());
} else {
return UIUtil.isUnderAquaLookAndFeel() ? new SameColor(189) : UIUtil.getPanelBackground();
}
}
};
myPanels.setBorder(new MyBorder());
mySplitters = new EditorsSplitters(this, myDockManager, true);
myPanels.add(mySplitters, BorderLayout.CENTER);
@@ -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">
@@ -31,6 +31,7 @@ import com.intellij.openapi.wm.ex.ToolWindowEx;
import com.intellij.openapi.wm.impl.commands.FinalizableCommand;
import com.intellij.reference.SoftReference;
import com.intellij.util.containers.HashMap;
import com.intellij.util.ui.UIUtil;
import javax.swing.*;
import java.awt.*;
@@ -1007,12 +1008,16 @@ final class ToolWindowsPane extends JLayeredPane implements Disposable {
myBottomImageRef=new SoftReference<BufferedImage>(null);
myTopImageRef=new SoftReference<BufferedImage>(null);
setOpaque(true);
setBackground(Color.gray);
add(splitter,JLayeredPane.DEFAULT_LAYER);
splitter.setBounds(0,0,getWidth(),getHeight());
enableEvents(ComponentEvent.COMPONENT_EVENT_MASK);
}
@Override
public Color getBackground() {
return SwingUtilities.getDeepestComponentAt(this, 0, 0) == this ? Color.GRAY : UIUtil.getPanelBackground();
}
/**
* TODO[vova] extract method
* Lazily creates and returns bottom image for animation.
@@ -33,7 +33,7 @@
<component id="92c6d" class="javax.swing.JTextField" binding="myProjectNameTextField">
<constraints>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
<preferred-size width="150" height="-1"/>
<preferred-size width="450" height="-1"/>
</grid>
</constraints>
<properties/>
@@ -56,6 +56,8 @@ public class NewDirectoryProjectDialog extends DialogWrapper {
private boolean myModifyingProjectName = false;
private static final Object EMPTY_PROJECT_GENERATOR = new Object();
private final String mySuggestedProjectName;
private boolean myProjectNameWasChanged = false;
protected NewDirectoryProjectDialog(Project project) {
super(project, true);
@@ -65,9 +67,12 @@ public class NewDirectoryProjectDialog extends DialogWrapper {
myLocationLabel.setLabelFor(myLocationField.getChildComponent());
myBaseDir = getBaseDir();
File projectName = FileUtil.findSequentNonexistentFile(new File(myBaseDir), "untitled", "");
myLocationField.setText(projectName.toString());
myProjectNameTextField.setText(projectName.getName());
File suggestedProjectDirectory = FileUtil.findSequentNonexistentFile(new File(myBaseDir), "untitled", "");
myLocationField.setText(suggestedProjectDirectory.toString());
myProjectNameTextField.setText(suggestedProjectDirectory.getName());
mySuggestedProjectName = suggestedProjectDirectory.getName();
FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
ComponentWithBrowseButton.BrowseFolderActionListener<JTextField> listener =
@@ -75,11 +80,16 @@ public class NewDirectoryProjectDialog extends DialogWrapper {
project,
descriptor,
TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT) {
protected void onFileChoosen(VirtualFile chosenFile) {
super.onFileChoosen(chosenFile);
myBaseDir = chosenFile.getPath();
myLocationField.setText(new File(chosenFile.getPath(), myProjectNameTextField.getText()).toString());
if (myProjectNameWasChanged) {
myLocationField.setText(new File(chosenFile.getPath(), myProjectNameTextField.getText()).toString());
} else {
myModifyingLocation = true;
myLocationField.setText(chosenFile.getPath());
myProjectNameTextField.setText(chosenFile.getName());
myModifyingLocation = false;
}
}
};
myLocationField.addActionListener(listener);
@@ -110,6 +120,7 @@ public class NewDirectoryProjectDialog extends DialogWrapper {
myProjectNameTextField.getDocument().addDocumentListener(new DocumentAdapter() {
protected void textChanged(final DocumentEvent e) {
if (!myModifyingLocation) {
myProjectNameWasChanged = true;
myModifyingProjectName = true;
File f = new File(myBaseDir);
myLocationField.setText(new File(f, myProjectNameTextField.getText()).getPath());
@@ -155,6 +166,10 @@ public class NewDirectoryProjectDialog extends DialogWrapper {
});
}
private boolean projectNameWasChanged() {
return mySuggestedProjectName != null && !mySuggestedProjectName.equals(myProjectNameTextField.getText());
}
private void checkValid() {
String projectName = myProjectNameTextField.getText();
if (projectName.trim().isEmpty()) {
@@ -817,6 +817,37 @@ public class SoftWrapApplianceOnDocumentModificationTest extends AbstractEditorP
((EditorImpl)myEditor).setPrefixTextAndAttributes(" ", new TextAttributes());
myEditor.getCaretModel().moveToOffset(text.length());
}
public void testSoftWrapCacheReset() throws IOException {
// Inspired by IDEA-76537 - the point is to drop cached document info on complete soft wraps recalculation
String text =
"\t first line\n" +
"\t second line\n" +
"\t third line";
// Make soft wraps to build a document info cache.
init(300, text);
// Modify document while soft wraps processing is off.
final EditorSettings settings = getEditor().getSettings();
settings.setUseSoftWraps(false);
int startOffset = text.indexOf("\t third") - 1;
getEditor().getDocument().deleteString(startOffset, text.length());
// Enable soft wraps and ensure that the cache is correctly re-built.
settings.setUseSoftWraps(true);
getEditor().getCaretModel().moveToOffset(getEditor().getDocument().getTextLength());
type("\n test");
final int offset = getEditor().getDocument().getTextLength() - 1;
final LogicalPosition logicalPosition = getEditor().offsetToLogicalPosition(offset);
assertEquals(offset, getEditor().logicalPositionToOffset(logicalPosition));
final VisualPosition visualPosition = getEditor().offsetToVisualPosition(offset);
assertEquals(visualPosition, getEditor().logicalToVisualPosition(logicalPosition));
assertEquals(logicalPosition, getEditor().visualToLogicalPosition(visualPosition));
}
private void init(final int visibleWidth, @NotNull String fileText) throws IOException {
init(visibleWidth, fileText, TestFileType.TEXT);
@@ -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"/>
@@ -189,6 +189,10 @@ public abstract class ProcessHandler extends UserDataHolderBase {
public boolean isStartNotified() {
return myState.get() > STATE_INITIAL;
}
public boolean isSilentlyDestroyOnClose() {
return false;
}
private ProcessListener createEventMulticaster() {
final Class<ProcessListener> listenerClass = ProcessListener.class;
@@ -101,6 +101,7 @@ public class Splitter extends JPanel {
super.add(myDivider);
myFocusWatcher = new FocusWatcher();
myFocusWatcher.install(this);
setOpaque(false);
}
public void setShowDividerControls(boolean showDividerControls) {
@@ -463,7 +464,7 @@ public class Splitter extends JPanel {
myResizeEnabled = true;
setFocusable(false);
enableEvents(MouseEvent.MOUSE_EVENT_MASK | MouseEvent.MOUSE_MOTION_EVENT_MASK);
setOpaque(false);
setOrientation(myVerticalSplit);
}
@@ -486,7 +487,7 @@ public class Splitter extends JPanel {
GridBagConstraints.CENTER, GridBagConstraints.EAST,
new Insets(0, leftInsetIcon, 0, 0), 0, 0));
if (myShowDividerControls) {
if (myShowDividerControls && false) {
int xMask = isVerticalSplit ? 1 : 0;
int yMask = isVerticalSplit ? 0 : 1;
@@ -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) {
@@ -465,6 +465,11 @@ public class UIUtil {
public static Color getInactiveTextColor() {
return UIManager.getColor("textInactiveText");
}
public static Color getSlightlyDarkerColor(Color c) {
float[] hsl = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), new float[3]);
return new Color(Color.HSBtoRGB(hsl[0], hsl[1], hsl[2] - .08f > 0 ? hsl[2] - .08f : hsl[2]));
}
/**
* @deprecated use com.intellij.util.ui.UIUtil#getTextFieldBackground()
@@ -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++) {
@@ -1 +1,10 @@
XXX
import java.sql.*;
public class Test {
public void runScript(Statement st) throws SQLException {
st.execute("create table some_table (id integer primary key)");
st.execute("insert into some_table values(1)");
st.execute("select * from some_table");
st.execute("drop table some_table");
}
}
@@ -1 +1,10 @@
XXX
import java.sql.*;
public class Test {
public void runScript(Statement st) throws SQLException {
st.execute("create table some_table (id integer primary key)");
st.execute("insert into some_table values(1)");
st.execute("<spot>select * from some_table</spot>");
st.execute("drop table some_table");
}
}
@@ -365,7 +365,7 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler {
}
}
private static class MyValidityState extends ResourcesValidityState {
private static class MyValidityState extends ResourceNamesValidityState {
private final String myCustomGenPathR;
private final Set<String> myNonExistingFiles;
private final int myPlatformToolsRevision;
@@ -15,6 +15,7 @@
*/
package org.jetbrains.android.compiler;
import com.android.resources.ResourceType;
import com.intellij.CommonBundle;
import com.intellij.compiler.impl.CompileContextImpl;
import com.intellij.compiler.impl.ModuleCompileScope;
@@ -46,8 +47,13 @@ import com.intellij.psi.PsiFile;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.HashSet;
import org.jetbrains.android.dom.resources.Attr;
import org.jetbrains.android.dom.resources.DeclareStyleable;
import org.jetbrains.android.dom.resources.ResourceElement;
import org.jetbrains.android.dom.resources.Resources;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.facet.AndroidRootUtil;
import org.jetbrains.android.resourceManagers.LocalResourceManager;
import org.jetbrains.android.sdk.AndroidPlatform;
import org.jetbrains.android.sdk.AndroidSdkType;
import org.jetbrains.android.util.AndroidUtils;
@@ -680,4 +686,75 @@ public class AndroidCompileUtil {
createSourceRootIfNotExist(sourceRootPath, module);
}
}
}
public static void collectAllResources(@NotNull final AndroidFacet facet, final Set<ResourceEntry> resourceSet) {
final LocalResourceManager manager = facet.getLocalResourceManager();
for (final String resType : ResourceType.getNames()) {
for (final ResourceElement element : manager.getValueResources(resType)) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
if (!element.isValid() || facet.getModule().isDisposed() || facet.getModule().getProject().isDisposed()) {
return;
}
final String name = element.getName().getValue();
if (name != null) {
resourceSet.add(new ResourceEntry(resType, name));
}
}
});
}
}
for (final Resources resources : manager.getResourceElements()) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
if (!resources.isValid() || facet.getModule().isDisposed() || facet.getModule().getProject().isDisposed()) {
return;
}
for (final Attr attr : resources.getAttrs()) {
final String name = attr.getName().getValue();
if (name != null) {
resourceSet.add(new ResourceEntry(ResourceType.ATTR.getName(), name));
}
}
for (final DeclareStyleable styleable : resources.getDeclareStyleables()) {
final String name = styleable.getName().getValue();
if (name != null) {
resourceSet.add(new ResourceEntry(ResourceType.DECLARE_STYLEABLE.getName(), name));
}
}
}
});
}
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
if (facet.getModule().isDisposed() || facet.getModule().getProject().isDisposed()) {
return;
}
for (String id : manager.getIds()) {
resourceSet.add(new ResourceEntry(ResourceType.ID.getName(), id));
}
}
});
final HashSet<VirtualFile> visited = new HashSet<VirtualFile>();
for (VirtualFile subdir : manager.getResourceSubdirs(null)) {
final HashSet<VirtualFile> resourceFiles = new HashSet<VirtualFile>();
AndroidUtils.collectFiles(subdir, visited, resourceFiles);
for (VirtualFile file : resourceFiles) {
resourceSet.add(new ResourceEntry(subdir.getName(), file.getName()));
}
}
}
}
@@ -166,7 +166,7 @@ public class AndroidMavenResourcesCompiler implements SourceGeneratingCompiler {
}
}
private static class MyValidityState extends ResourcesValidityState {
private static class MyValidityState extends ResourceNamesValidityState {
private final long[] myMavenArtifactsTimespamps;
private MyValidityState(Module module) {
@@ -0,0 +1,46 @@
package org.jetbrains.android.compiler;
import org.jetbrains.annotations.NotNull;
/**
* @author Eugene.Kudelevsky
*/
public class ResourceEntry {
private final String myType;
private final String myName;
ResourceEntry(@NotNull String type, @NotNull String name) {
myType = type;
myName = name;
}
@NotNull
public String getType() {
return myType;
}
@NotNull
public String getName() {
return myName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ResourceEntry entry = (ResourceEntry)o;
if (!myName.equals(entry.myName)) return false;
if (!myType.equals(entry.myType)) return false;
return true;
}
@Override
public int hashCode() {
int result = myType.hashCode();
result = 31 * result + myName.hashCode();
return result;
}
}
@@ -0,0 +1,78 @@
package org.jetbrains.android.compiler;
import com.android.sdklib.IAndroidTarget;
import com.intellij.openapi.compiler.ValidityState;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.HashSet;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.facet.AndroidRootUtil;
import org.jetbrains.android.sdk.AndroidPlatform;
import org.jetbrains.annotations.NotNull;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Set;
/**
* @author Eugene.Kudelevsky
*/
public class ResourceNamesValidityState implements ValidityState {
private final Set<ResourceEntry> myResourcesSet = new HashSet<ResourceEntry>();
private final String myAndroidTargetHashString;
private final long myManifestTimestamp;
public ResourceNamesValidityState(@NotNull Module module) {
final AndroidFacet facet = AndroidFacet.getInstance(module);
assert facet != null;
final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform();
final IAndroidTarget target = platform != null ? platform.getTarget() : null;
myAndroidTargetHashString = target != null ? target.hashString() : "";
final VirtualFile manifestFile = AndroidRootUtil.getManifestFile(facet.getModule());
myManifestTimestamp = manifestFile != null ? manifestFile.getModificationStamp() : -1;
AndroidCompileUtil.collectAllResources(facet, myResourcesSet);
}
public ResourceNamesValidityState(@NotNull DataInput in) throws IOException {
myAndroidTargetHashString = in.readUTF();
myManifestTimestamp = in.readLong();
final int resourcesCount = in.readInt();
for (int i = 0; i < resourcesCount; i++) {
final String type = in.readUTF();
final String name = in.readUTF();
myResourcesSet.add(new ResourceEntry(type, name));
}
}
@Override
public boolean equalsTo(ValidityState otherState) {
if (!(otherState instanceof ResourceNamesValidityState)) {
return false;
}
final ResourceNamesValidityState other = (ResourceNamesValidityState)otherState;
return other.myAndroidTargetHashString.equals(myAndroidTargetHashString) &&
other.myManifestTimestamp == myManifestTimestamp &&
other.myResourcesSet.equals(myResourcesSet);
}
@Override
public void save(DataOutput out) throws IOException {
out.writeUTF(myAndroidTargetHashString);
out.writeLong(myManifestTimestamp);
out.writeInt(myResourcesSet.size());
for (ResourceEntry resourceEntry : myResourcesSet) {
out.writeUTF(resourceEntry.getType());
out.writeUTF(resourceEntry.getName());
}
}
}
@@ -55,7 +55,6 @@ import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileAdapter;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiDocumentManager;
@@ -67,12 +66,10 @@ import com.intellij.psi.xml.XmlTag;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Processor;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.HashSet;
import com.intellij.util.xml.ConvertContext;
import com.intellij.util.xml.DomElement;
import org.jetbrains.android.compiler.AndroidAptCompiler;
import org.jetbrains.android.compiler.AndroidCompileUtil;
import org.jetbrains.android.compiler.AndroidIdlCompiler;
import org.jetbrains.android.compiler.AndroidRenderscriptCompiler;
import org.jetbrains.android.compiler.*;
import org.jetbrains.android.dom.manifest.Manifest;
import org.jetbrains.android.resourceManagers.LocalResourceManager;
import org.jetbrains.android.resourceManagers.ResourceManager;
@@ -96,7 +93,7 @@ public class AndroidFacet extends Facet<AndroidFacetConfiguration> {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.facet.AndroidFacet");
public static final FacetTypeId<AndroidFacet> ID = new FacetTypeId<AndroidFacet>("android");
private VirtualFileAdapter myListener;
private AndroidResourceFilesListener myListener;
private AvdManager myAvdManager = null;
@@ -351,6 +348,11 @@ public class AndroidFacet extends Facet<AndroidFacetConfiguration> {
if (project.isDisposed()) {
return;
}
final HashSet<ResourceEntry> resourceSet = new HashSet<ResourceEntry>();
AndroidCompileUtil.collectAllResources(AndroidFacet.this, resourceSet);
myListener.setResourceSet(resourceSet);
if (getConfiguration().REGENERATE_R_JAVA && AndroidAptCompiler.isToCompileModule(module, getConfiguration())) {
AndroidCompileUtil.generate(module, new AndroidAptCompiler());
}
@@ -18,18 +18,16 @@ package org.jetbrains.android.facet;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.GeneratingCompiler;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.vfs.*;
import com.intellij.util.containers.HashSet;
import com.intellij.util.ui.update.MergingUpdateQueue;
import com.intellij.util.ui.update.Update;
import org.jetbrains.android.compiler.AndroidAptCompiler;
import org.jetbrains.android.compiler.AndroidCompileUtil;
import org.jetbrains.android.compiler.AndroidIdlCompiler;
import org.jetbrains.android.compiler.AndroidRenderscriptCompiler;
import org.jetbrains.android.compiler.*;
import org.jetbrains.android.dom.manifest.Manifest;
import org.jetbrains.android.fileTypes.AndroidIdlFileType;
import org.jetbrains.android.fileTypes.AndroidRenderscriptFileType;
@@ -37,6 +35,8 @@ import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
import static org.jetbrains.android.util.AndroidUtils.findSourceRoot;
/**
@@ -47,12 +47,14 @@ import static org.jetbrains.android.util.AndroidUtils.findSourceRoot;
* To change this template use File | Settings | File Templates.
*/
class AndroidResourceFilesListener extends VirtualFileAdapter {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.facet.AndroidResourceFilesListener");
private final MergingUpdateQueue myQueue;
private final AndroidFacet myFacet;
private String myCachedPackage = null;
private volatile Set<ResourceEntry> myResourceSet = new HashSet<ResourceEntry>();
private static final Object RESOURCES_SET_LOCK = new Object();
public AndroidResourceFilesListener(final AndroidFacet facet) {
myFacet = facet;
myQueue = new MergingUpdateQueue("AndroidResourcesCompilationQueue", 300, true, null, myFacet, null, false);
@@ -117,11 +119,14 @@ class AndroidResourceFilesListener extends VirtualFileAdapter {
file.getFileType() == AndroidRenderscriptFileType.INSTANCE ||
getManifestFileName().equals(file.getName()) ||
(gp != null && gp.isDirectory() && getResDirName().equals(gp.getName()))) {
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
public void run() {
myQueue.queue(new MyUpdate(e));
}
});
myQueue.queue(new MyUpdate(e));
}
}
public void setResourceSet(@NotNull Set<ResourceEntry> resourceSet) {
synchronized (RESOURCES_SET_LOCK) {
myResourceSet = resourceSet;
}
}
@@ -137,54 +142,89 @@ class AndroidResourceFilesListener extends VirtualFileAdapter {
if (ApplicationManager.getApplication().isUnitTestMode()) {
return;
}
final GeneratingCompiler compilerToRun = ApplicationManager.getApplication().runReadAction(new Computable<GeneratingCompiler>() {
@Nullable
public GeneratingCompiler compute() {
if (myFacet.isDisposed()) return null;
Module myModule = myFacet.getModule();
Project project = myModule.getProject();
if (project.isDisposed()) return null;
VirtualFile file = myEvent.getFile();
Module module = ModuleUtil.findModuleForFile(file, project);
if (module == myModule) {
VirtualFile parent = myEvent.getParent();
if (parent != null) {
parent = parent.getParent();
if (AndroidAptCompiler.isToCompileModule(module, myFacet.getConfiguration()) &&
(myFacet.getConfiguration().REGENERATE_R_JAVA && parent == AndroidRootUtil.getResourceDir(module) ||
AndroidRootUtil.getManifestFile(module) == file)) {
Manifest manifest = myFacet.getManifest();
String aPackage = manifest != null ? manifest.getPackage().getValue() : null;
if (myCachedPackage != null && !myCachedPackage.equals(aPackage)) {
String aptGenDirPath = myFacet.getAptGenSourceRootPath();
AndroidCompileUtil.removeDuplicatingClasses(myModule, myCachedPackage, AndroidUtils.R_CLASS_NAME, null, aptGenDirPath);
}
myCachedPackage = aPackage;
myFacet.getLocalResourceManager().invalidateAttributeDefinitions();
return new AndroidAptCompiler();
}
if (myFacet.getConfiguration().REGENERATE_JAVA_BY_AIDL && file.getFileType() == AndroidIdlFileType.ourFileType) {
VirtualFile sourceRoot = findSourceRoot(myModule, file);
if (sourceRoot != null && AndroidRootUtil.getAidlGenDir(module, myFacet) != sourceRoot) {
return new AndroidIdlCompiler(project);
}
}
if (file.getFileType() == AndroidRenderscriptFileType.INSTANCE) {
final VirtualFile sourceRoot = findSourceRoot(myModule, file);
if (sourceRoot != null && AndroidRootUtil.getRenderscriptGenDir(myModule) != sourceRoot) {
return new AndroidRenderscriptCompiler();
}
}
}
}
return null;
return computeCompilerToRun();
}
});
if (compilerToRun != null) {
AndroidCompileUtil.generate(myFacet.getModule(), compilerToRun, true);
if (compilerToRun == null) {
return;
}
if (compilerToRun instanceof AndroidAptCompiler) {
final HashSet<ResourceEntry> resourceSet = new HashSet<ResourceEntry>();
DumbService.getInstance(myFacet.getModule().getProject()).waitForSmartMode();
AndroidCompileUtil.collectAllResources(myFacet, resourceSet);
synchronized (RESOURCES_SET_LOCK) {
if (resourceSet.equals(myResourceSet)) {
return;
}
myResourceSet = resourceSet;
}
}
AndroidCompileUtil.generate(myFacet.getModule(), compilerToRun, true);
}
@Nullable
private GeneratingCompiler computeCompilerToRun() {
if (myFacet.isDisposed()) {
return null;
}
final Module myModule = myFacet.getModule();
final Project project = myModule.getProject();
if (project.isDisposed()) {
return null;
}
final VirtualFile file = myEvent.getFile();
final Module module = ModuleUtil.findModuleForFile(file, project);
if (module != myModule) {
return null;
}
VirtualFile parent = myEvent.getParent();
if (parent == null) {
return null;
}
parent = parent.getParent();
if (AndroidAptCompiler.isToCompileModule(module, myFacet.getConfiguration()) &&
(myFacet.getConfiguration().REGENERATE_R_JAVA && parent == AndroidRootUtil.getResourceDir(module) ||
AndroidRootUtil.getManifestFile(module) == file)) {
final Manifest manifest = myFacet.getManifest();
final String aPackage = manifest != null ? manifest.getPackage().getValue() : null;
if (myCachedPackage != null && !myCachedPackage.equals(aPackage)) {
String aptGenDirPath = myFacet.getAptGenSourceRootPath();
AndroidCompileUtil.removeDuplicatingClasses(myModule, myCachedPackage, AndroidUtils.R_CLASS_NAME, null, aptGenDirPath);
}
myCachedPackage = aPackage;
myFacet.getLocalResourceManager().invalidateAttributeDefinitions();
return new AndroidAptCompiler();
}
if (myFacet.getConfiguration().REGENERATE_JAVA_BY_AIDL && file.getFileType() == AndroidIdlFileType.ourFileType) {
VirtualFile sourceRoot = findSourceRoot(myModule, file);
if (sourceRoot != null && AndroidRootUtil.getAidlGenDir(module, myFacet) != sourceRoot) {
return new AndroidIdlCompiler(project);
}
}
if (file.getFileType() == AndroidRenderscriptFileType.INSTANCE) {
final VirtualFile sourceRoot = findSourceRoot(myModule, file);
if (sourceRoot != null && AndroidRootUtil.getRenderscriptGenDir(myModule) != sourceRoot) {
return new AndroidRenderscriptCompiler();
}
}
return null;
}
@Override
@@ -192,10 +232,19 @@ class AndroidResourceFilesListener extends VirtualFileAdapter {
if (update instanceof MyUpdate) {
VirtualFile hisFile = ((MyUpdate)update).myEvent.getFile();
VirtualFile file = myEvent.getFile();
if (hisFile == file) return true;
if (hisFile == file) {
return true;
}
if (hisFile.getFileType() == AndroidIdlFileType.ourFileType || file.getFileType() == AndroidIdlFileType.ourFileType) {
return hisFile.getFileType() == file.getFileType();
}
if (hisFile.getFileType() == AndroidRenderscriptFileType.INSTANCE || file.getFileType() == AndroidRenderscriptFileType.INSTANCE) {
return hisFile.getFileType() == file.getFileType();
}
return true;
}
return false;
@@ -259,6 +259,9 @@ public abstract class ResourceManager {
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
if (!resources.isValid() || myModule.isDisposed() || myModule.getProject().isDisposed()) {
return;
}
result.addAll(getValueResources(resourceType, resources));
}
});
+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"/>
@@ -844,7 +844,9 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
String substring = text.substring(quote.length());
String[] parts;
IElementType elementType = literal.getFirstChild().getNode().getElementType();
PsiElement child = literal.getFirstChild();
if (child == null) child = literal;
IElementType elementType = child.getNode().getElementType();
boolean isSimpleString = elementType == GroovyTokenTypes.mSTRING_LITERAL ||
elementType == GroovyTokenTypes.mGSTRING_LITERAL ||
elementType == GroovyTokenTypes.mREGEX_LITERAL;
@@ -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);
}
@@ -709,13 +709,19 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
}
public boolean isReferenceTo(PsiElement element) {
PsiElement target = GroovyTargetElementEvaluator.correctSearchTargets(resolve());
if (getManager().areElementsEquivalent(element, target)) {
PsiElement baseTarget = resolve();
if (getManager().areElementsEquivalent(element, baseTarget)) {
return true;
}
PsiElement target = GroovyTargetElementEvaluator.correctSearchTargets(baseTarget);
if (target != baseTarget && getManager().areElementsEquivalent(element, target)) {
return true;
}
if (element instanceof PsiMethod && target instanceof PsiMethod) {
PsiMethod[] superMethods = ((PsiMethod)target).findSuperMethods(false);
//noinspection SuspiciousMethodCalls
if (Arrays.asList(superMethods).contains(element)) {
return true;
}
@@ -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

Some files were not shown because too many files have changed in this diff Show More