Merge branch 'master' of git.labs.intellij.net:idea/community

This commit is contained in:
Michael Golubev
2013-11-01 12:24:24 +01:00
108 changed files with 1849 additions and 1431 deletions
-1
View File
@@ -3,7 +3,6 @@
<CLASSES>
<root url="jar://$PROJECT_DIR$/lib/jna-utils.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/jna.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/jna-platform.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
@@ -1113,6 +1113,11 @@
<option name="EFFECT_TYPE" value="-1" />
</value>
</option>
<option name="PY.BUILTIN_NAME">
<value>
<option name="FOREGROUND" value="8888c6" />
</value>
</option>
<option name="REGEXP.BRACES">
<value>
<option name="FOREGROUND" value="e8bf6a" />
@@ -15,6 +15,8 @@
*/
package com.intellij.debugger.impl;
import org.jetbrains.annotations.NotNull;
import java.io.File;
/**
@@ -23,9 +25,10 @@ import java.io.File;
* Time: 2:23:38 PM
*/
public class HotSwapFile {
@NotNull
final File file;
public HotSwapFile(File file) {
public HotSwapFile(@NotNull File file) {
this.file = file;
}
}
@@ -157,7 +157,12 @@ public class HotSwapManager extends AbstractProjectComponent {
private void reloadClasses(DebuggerSession session, Map<String, HotSwapFile> classesToReload, HotSwapProgress progress) {
final long newSwapTime = System.currentTimeMillis();
new ReloadClassesWorker(session, progress).reloadClasses(classesToReload);
setTimeStamp(session, newSwapTime);
if (progress.isCancelled()) {
session.setModifiedClassesScanRequired(true);
}
else {
setTimeStamp(session, newSwapTime);
}
}
public static Map<DebuggerSession, Map<String, HotSwapFile>> findModifiedClasses(List<DebuggerSession> sessions, Map<String, List<String>> generatedPaths) {
@@ -220,7 +225,13 @@ public class HotSwapManager extends AbstractProjectComponent {
swapProgress.setTitle(DebuggerBundle.message("progress.hotswap.scanning.classes"));
scanClassesCommand.run();
return swapProgress.isCancelled() ? new HashMap<DebuggerSession, Map<String, HotSwapFile>>() : modifiedClasses;
if (swapProgress.isCancelled()) {
for (DebuggerSession session : sessions) {
session.setModifiedClassesScanRequired(true);
}
return new HashMap<DebuggerSession, Map<String, HotSwapFile>>();
}
return modifiedClasses;
}
public static void reloadModifiedClasses(final Map<DebuggerSession, Map<String, HotSwapFile>> modifiedClasses, final HotSwapProgress reloadClassesProgress) {
@@ -240,6 +251,10 @@ public class HotSwapManager extends AbstractProjectComponent {
debuggerSession, modifiedClasses.get(debuggerSession), reloadClassesProgress
);
}
protected void commandCancelled() {
debuggerSession.setModifiedClassesScanRequired(true);
}
});
}
@@ -19,11 +19,11 @@ import com.intellij.debugger.engine.DebugProcessImpl;
import com.intellij.debugger.engine.events.DebuggerCommandImpl;
import com.intellij.openapi.util.Pair;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class MultiProcessCommand implements Runnable{
private final List<Pair<DebugProcessImpl, DebuggerCommandImpl>> myCommands = new ArrayList<Pair<DebugProcessImpl, DebuggerCommandImpl>>();
private final List<Pair<DebugProcessImpl, DebuggerCommandImpl>> myCommands = new LinkedList<Pair<DebugProcessImpl, DebuggerCommandImpl>>();
public void run() {
while(true) {
@@ -40,7 +40,10 @@ public class MultiProcessCommand implements Runnable{
public void cancel() {
synchronized(myCommands) {
myCommands.clear();
while (!myCommands.isEmpty()) {
Pair<DebugProcessImpl, DebuggerCommandImpl> pair = myCommands.remove(0);
pair.getSecond().notifyCancelled();
}
}
}
@@ -31,6 +31,7 @@ import com.intellij.util.ui.UIUtil;
import com.sun.jdi.ReferenceType;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
@@ -113,35 +114,44 @@ class ReloadClassesWorker {
try {
RedefineProcessor redefineProcessor = new RedefineProcessor(virtualMachineProxy);
int processedClassesCount = 0;
for (final String qualifiedName : modifiedClasses.keySet()) {
processedClassesCount++;
int processedEntriesCount = 0;
for (final Map.Entry<String, HotSwapFile> entry : modifiedClasses.entrySet()) {
if (redefineProcessor.getProcessedClassesCount() == 0 && myProgress.isCancelled()) {
// once at least one class has been actually reloaded, do not interrupt the whole process
break;
}
processedEntriesCount++;
final String qualifiedName = entry.getKey();
if (qualifiedName != null) {
myProgress.setText(qualifiedName);
myProgress.setFraction(processedClassesCount / (double)modifiedClasses.size());
myProgress.setFraction(processedEntriesCount / (double)modifiedClasses.size());
}
final HotSwapFile fileDescr = modifiedClasses.get(qualifiedName);
final byte[] content;
try {
content = FileUtil.loadFileBytes(fileDescr.file);
redefineProcessor.processClass(qualifiedName, entry.getValue().file);
}
catch (IOException e) {
reportProblem(qualifiedName, e);
continue;
}
redefineProcessor.processClass(qualifiedName, content);
}
if (redefineProcessor.getProcessedClassesCount() == 0 && myProgress.isCancelled()) {
// once at least one class has been actually reloaded, do not interrupt the whole process
return;
}
redefineProcessor.processPending();
myProgress.setFraction(1);
final int partiallyRedefinedClassesCount = redefineProcessor.getPartiallyRedefinedClassesCount();
if (partiallyRedefinedClassesCount == 0) {
myProgress.addMessage(myDebuggerSession, MessageCategory.INFORMATION,
DebuggerBundle.message("status.classes.reloaded", redefineProcessor.getProcessedClassesCount()));
myProgress.addMessage(
myDebuggerSession, MessageCategory.INFORMATION, DebuggerBundle.message("status.classes.reloaded", redefineProcessor.getProcessedClassesCount())
);
}
else {
final String message = DebuggerBundle.message("status.classes.not.all.versions.reloaded", partiallyRedefinedClassesCount,
redefineProcessor.getProcessedClassesCount());
final String message = DebuggerBundle.message(
"status.classes.not.all.versions.reloaded", partiallyRedefinedClassesCount, redefineProcessor.getProcessedClassesCount()
);
myProgress.addMessage(myDebuggerSession, MessageCategory.WARNING, message);
}
@@ -233,10 +243,13 @@ class ReloadClassesWorker {
myVirtualMachineProxy = virtualMachineProxy;
}
public void processClass(String qualifiedName, byte[] content) throws Throwable {
public void processClass(String qualifiedName, File file) throws Throwable {
final List<ReferenceType> vmClasses = myVirtualMachineProxy.classesByName(qualifiedName);
if (vmClasses.isEmpty()) return;
if (vmClasses.isEmpty()) {
return;
}
final byte[] content = FileUtil.loadFileBytes(file);
if (vmClasses.size() == 1) {
myRedefineMap.put(vmClasses.get(0), content);
if (myRedefineMap.size() >= CLASSES_CHUNK_SIZE) {
@@ -269,8 +269,7 @@ public class HotSwapUIImpl extends HotSwapUI implements ProjectComponent {
return result.get();
}
private static void reloadModifiedClasses(final Map<DebuggerSession, Map<String, HotSwapFile>> modifiedClasses,
final HotSwapProgressImpl progress) {
private static void reloadModifiedClasses(final Map<DebuggerSession, Map<String, HotSwapFile>> modifiedClasses, final HotSwapProgressImpl progress) {
ProgressManager.getInstance().runProcess(new Runnable() {
public void run() {
HotSwapManager.reloadModifiedClasses(modifiedClasses, progress);
@@ -324,7 +324,7 @@ public class HighlightUtil extends HighlightUtilBase {
static boolean isIntersection(PsiTypeElement castTypeElement, PsiType castType) {
if (castType instanceof PsiIntersectionType) return true;
return PsiTreeUtil.getChildrenOfType(castTypeElement, PsiTypeElement.class) != null;
return castType instanceof PsiClassType && PsiTreeUtil.getChildrenOfType(castTypeElement, PsiTypeElement.class) != null;
}
@Nullable
@@ -1,20 +0,0 @@
package com.intellij.codeInsight.completion.methodChains;
/**
* @author Dmitry Batkovich
*/
public final class Constants {
private Constants() {
}
/**
* magic numbers
*/
public static final int SINGLETON_MAGIC_RATIO = 100;
public static final int SINGLETON_MAGIC_RATIO2 = 5;
public static final int CHAIN_SEARCH_MAGIC_RATIO = 12;
}
@@ -1,117 +0,0 @@
package com.intellij.compilerOutputIndex.impl;
import com.intellij.codeInsight.completion.methodChains.ChainCompletionStringUtil;
import com.intellij.compilerOutputIndex.api.fs.AsmUtil;
import org.jetbrains.asm4.ClassReader;
import org.jetbrains.asm4.ClassVisitor;
import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Opcodes;
import org.jetbrains.asm4.tree.ClassNode;
import java.util.ArrayList;
import java.util.List;
/**
* @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com>
*/
public class ClassFileData {
private final List<MethodData> myMethodDatas;
public ClassFileData(final ClassNode classNode) {
this(classNode, true);
}
public ClassFileData(final ClassNode classNode, final boolean checkForPrimitiveReturn) {
myMethodDatas = new ArrayList<MethodData>();
classNode.accept(new ClassVisitor(Opcodes.ASM4) {
@Override
public MethodVisitor visitMethod(final int access,
final String name,
final String desc,
final String signature,
final String[] exceptions) {
final MethodDataAccumulator methodDataAccumulator = new MethodDataAccumulator(checkForPrimitiveReturn);
myMethodDatas.add(methodDataAccumulator.getMethodData());
return methodDataAccumulator;
}
});
}
public List<MethodData> getMethodDatas() {
return myMethodDatas;
}
public static class MethodData {
private final List<MethodInsnSignature> myMethodInsnSignatures = new ArrayList<MethodInsnSignature>();
private void addSign(final MethodInsnSignature signature) {
myMethodInsnSignatures.add(signature);
}
public List<MethodInsnSignature> getMethodInsnSignatures() {
return myMethodInsnSignatures;
}
}
private static class MethodDataAccumulator extends MethodVisitor {
private final MethodData myMethodData = new MethodData();
private final boolean myCheckForPrimitiveReturn;
public MethodDataAccumulator(final boolean checkForPrimitiveReturn) {
super(Opcodes.ASM4);
myCheckForPrimitiveReturn = checkForPrimitiveReturn;
}
private MethodData getMethodData() {
return myMethodData;
}
@Override
public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) {
if (MethodIncompleteSignature.CONSTRUCTOR_METHOD_NAME.equals(name)) {
return;
}
final String ownerClassName = AsmUtil.getQualifiedClassName(owner);
if (ChainCompletionStringUtil.isPrimitiveOrArrayOfPrimitives(ownerClassName)) {
return;
}
if (myCheckForPrimitiveReturn) {
final String returnType = AsmUtil.getReturnType(desc);
if (ChainCompletionStringUtil.isPrimitiveOrArrayOfPrimitives(returnType)) {
return;
}
}
myMethodData.addSign(new MethodInsnSignature(opcode, owner, name, desc));
}
}
public static class MethodInsnSignature {
private final int myOpcode;
private final String myOwner;
private final String myName;
private final String myDesc;
private MethodInsnSignature(final int opcode, final String owner, final String name, final String desc) {
myOpcode = opcode;
myOwner = owner;
myName = name;
myDesc = desc;
}
public int getOpcode() {
return myOpcode;
}
public String getOwner() {
return myOwner;
}
public String getName() {
return myName;
}
public String getDesc() {
return myDesc;
}
}
}
@@ -1,48 +0,0 @@
package com.intellij.compilerOutputIndex.impl;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset;
import com.intellij.compilerOutputIndex.api.indexer.CompilerOutputBaseIndex;
import com.intellij.openapi.project.Project;
import com.intellij.util.indexing.StorageException;
import com.intellij.util.indexing.ValueContainer;
import com.intellij.util.io.KeyDescriptor;
import java.util.TreeSet;
/**
* @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com>
*/
public abstract class CompilerOutputBaseGramsIndex<K> extends CompilerOutputBaseIndex<K, Multiset<MethodIncompleteSignature>> {
protected CompilerOutputBaseGramsIndex(final KeyDescriptor<K> keyDescriptor, final Project project) {
super(keyDescriptor, new GuavaHashMultiSetExternalizer<MethodIncompleteSignature>(MethodIncompleteSignature.createKeyDescriptor()), project);
}
public TreeSet<UsageIndexValue> getValues(final K key) {
try {
final ValueContainer<Multiset<MethodIncompleteSignature>> valueContainer = myIndex.getData(key);
final Multiset<MethodIncompleteSignature> rawValues = HashMultiset.create();
valueContainer.forEach(new ValueContainer.ContainerAction<Multiset<MethodIncompleteSignature>>() {
@Override
public boolean perform(final int id, final Multiset<MethodIncompleteSignature> values) {
for (final Multiset.Entry<MethodIncompleteSignature> entry : values.entrySet()) {
rawValues.add(entry.getElement(), entry.getCount());
}
return true;
}
});
return rawValuesToValues(rawValues);
} catch (StorageException e) {
throw new RuntimeException();
}
}
private static TreeSet<UsageIndexValue> rawValuesToValues(final Multiset<MethodIncompleteSignature> rawValues) {
final TreeSet<UsageIndexValue> values = new TreeSet<UsageIndexValue>();
for (final Multiset.Entry<MethodIncompleteSignature> entry : rawValues.entrySet()) {
values.add(new UsageIndexValue(entry.getElement(), entry.getCount()));
}
return values;
}
}
@@ -1,22 +0,0 @@
package com.intellij.compilerOutputIndex.impl.bigram;
import com.intellij.openapi.util.Pair;
import org.jetbrains.annotations.NotNull;
/**
* @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com>
*/
public class Bigram<E> extends Pair<E, E> {
public Bigram(@NotNull final E first, @NotNull final E second) {
super(first, second);
}
public Bigram<E> swap() {
return new Bigram<E>(second, first);
}
@Override
public String toString() {
return String.format("%s - %s", first, second);
}
}
@@ -1,87 +0,0 @@
package com.intellij.compilerOutputIndex.impl.bigram;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset;
import com.intellij.compilerOutputIndex.api.fs.AsmUtil;
import com.intellij.compilerOutputIndex.api.indexer.CompilerOutputIndexer;
import com.intellij.compilerOutputIndex.impl.ClassFileData;
import com.intellij.compilerOutputIndex.impl.CompilerOutputBaseGramsIndex;
import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignature;
import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignatureChain;
import com.intellij.openapi.project.Project;
import com.intellij.util.SmartList;
import com.intellij.util.indexing.DataIndexer;
import com.intellij.util.indexing.ID;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.asm4.ClassReader;
import org.jetbrains.asm4.Opcodes;
import org.jetbrains.asm4.tree.ClassNode;
import java.util.*;
/**
* @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com>
*/
public class BigramMethodsUsageIndex extends CompilerOutputBaseGramsIndex<MethodIncompleteSignature> {
public static BigramMethodsUsageIndex getInstance(final Project project) {
return CompilerOutputIndexer.getInstance(project).getIndex(BigramMethodsUsageIndex.class);
}
public BigramMethodsUsageIndex( final Project project) {
super(MethodIncompleteSignature.createKeyDescriptor(), project);
}
@Override
protected ID<MethodIncompleteSignature, Multiset<MethodIncompleteSignature>> getIndexId() {
return generateIndexId("BigramMethodsUsage");
}
@Override
protected int getVersion() {
return 0;
}
@Override
protected DataIndexer<MethodIncompleteSignature, Multiset<MethodIncompleteSignature>,ClassNode> getIndexer() {
//
// not fair way, but works fast
//
return new DataIndexer<MethodIncompleteSignature, Multiset<MethodIncompleteSignature>, ClassNode>() {
@NotNull
@Override
public Map<MethodIncompleteSignature, Multiset<MethodIncompleteSignature>> map(final ClassNode inputData) {
final Map<MethodIncompleteSignature, Multiset<MethodIncompleteSignature>> map =
new HashMap<MethodIncompleteSignature, Multiset<MethodIncompleteSignature>>();
for (final ClassFileData.MethodData data : new ClassFileData(inputData).getMethodDatas()) {
final SimpleBigramsExtractor extractor = new SimpleBigramsExtractor(new SimpleBigramsExtractor.BigramMethodIncompleteSignatureProcessor() {
@Override
public void process(final Bigram<MethodIncompleteSignature> bigram) {
final MethodIncompleteSignature secondGram = bigram.getSecond();
Multiset<MethodIncompleteSignature> occurrences = map.get(secondGram);
if (occurrences == null) {
occurrences = HashMultiset.create();
map.put(secondGram, occurrences);
}
occurrences.add(bigram.getFirst());
}
});
for (final ClassFileData.MethodInsnSignature ms : data.getMethodInsnSignatures()) {
final List<MethodIncompleteSignature> methodInvocations = new SmartList<MethodIncompleteSignature>();
final String ownerClassName = AsmUtil.getQualifiedClassName(ms.getOwner());
final String returnType = AsmUtil.getReturnType(ms.getDesc());
if (ms.getName().equals(MethodIncompleteSignature.CONSTRUCTOR_METHOD_NAME)) {
methodInvocations.add(MethodIncompleteSignature.constructor(ownerClassName));
}
else {
methodInvocations.add(new MethodIncompleteSignature(ownerClassName, returnType, ms.getName(), ms.getOpcode() == Opcodes.INVOKESTATIC));
}
extractor.addChain(new MethodIncompleteSignatureChain(methodInvocations));
}
}
return map;
}
};
}
}
@@ -1,55 +0,0 @@
package com.intellij.compilerOutputIndex.impl.bigram;
import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignature;
import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignatureChain;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* @author Dmitry Batkovich
*/
class SimpleBigramsExtractor {
private final Map<String, MethodIncompleteSignature> myHolder = new HashMap<String, MethodIncompleteSignature>();
private final BigramMethodIncompleteSignatureProcessor myProcessor;
public SimpleBigramsExtractor(final BigramMethodIncompleteSignatureProcessor processor) {
myProcessor = processor;
}
public void addChain(final MethodIncompleteSignatureChain chain) {
if (chain.isEmpty()) {
return;
}
final MethodIncompleteSignature firstInvocation = chain.getFirstInvocation();
assert firstInvocation != null;
final MethodIncompleteSignature head = firstInvocation.isStatic() ? null : myHolder.get(firstInvocation.getOwner());
for (final Bigram<MethodIncompleteSignature> bigram : toBigrams(head, chain)) {
myProcessor.process(bigram);
}
final MethodIncompleteSignature lastInvocation = chain.getLastInvocation();
assert lastInvocation != null;
myHolder.put(lastInvocation.getReturnType(), lastInvocation);
}
private static Collection<Bigram<MethodIncompleteSignature>> toBigrams(final @Nullable MethodIncompleteSignature head,
final @NotNull MethodIncompleteSignatureChain chain) {
MethodIncompleteSignature currentLast = null;
if (head != null) {
currentLast = head;
}
final List<Bigram<MethodIncompleteSignature>> bigrams = new ArrayList<Bigram<MethodIncompleteSignature>>(chain.size());
for (final MethodIncompleteSignature current : chain.list()) {
if (currentLast != null) {
bigrams.add(new Bigram<MethodIncompleteSignature>(currentLast, current));
}
currentLast = current;
}
return bigrams;
}
public interface BigramMethodIncompleteSignatureProcessor {
void process(Bigram<MethodIncompleteSignature> bigram);
}
}
@@ -1661,7 +1661,7 @@ public class JavaDocInfoGenerator {
return length;
}
if (type instanceof PsiDisjunctionType) {
if (type instanceof PsiDisjunctionType || type instanceof PsiIntersectionType) {
if (!generateLink) {
final String text = StringUtil.escapeXml(type.getCanonicalText());
buffer.append(text);
@@ -1669,9 +1669,17 @@ public class JavaDocInfoGenerator {
}
else {
int length = 0;
for (PsiType psiType : ((PsiDisjunctionType)type).getDisjunctions()) {
final String separator = type instanceof PsiDisjunctionType ? " | " : " & ";
final List<PsiType> componentTypes;
if (type instanceof PsiIntersectionType) {
componentTypes = Arrays.asList(((PsiIntersectionType)type).getConjuncts());
}
else {
componentTypes = ((PsiDisjunctionType)type).getDisjunctions();
}
for (PsiType psiType : componentTypes) {
if (length > 0) {
buffer.append(" | ");
buffer.append(separator);
length += 3;
}
length += generateType(buffer, psiType, context, generateLink);
@@ -219,6 +219,9 @@ public class InferenceSession {
}
}
for (InferenceVariable inferenceVariable : myInferenceVariables.values()) {
inferenceVariable.ignoreInstantiation();
}
mySiteSubstitutor = resolveBounds(myInferenceVariables.values(), mySiteSubstitutor, true);
for (InferenceVariable inferenceVariable : myInferenceVariables.values()) {
@@ -0,0 +1,35 @@
/*
* Copyright 2000-2013 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.
*/
interface PsiManager {
}
interface PsiElement {
PsiManager getManager();
}
interface PsiClass extends PsiElement {
}
interface PsiMethod extends PsiElement {
PsiClass getContainingClass();
}
interface PsiMethodCallExpression extends PsiElement {
PsiMethod resolveMethod();
}
public class TestCompletion {
public void method() {
PsiManager m = <caret>
}
}
@@ -0,0 +1,39 @@
/*
* Copyright 2000-2013 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.
*/
public class TestIndex {
public void statMethod(PsiMethodCallExpression e) {
e.resolveMethod().getContainingClass().getManager();
e.resolveMethod().getContainingClass().getManager();
e.resolveMethod().getContainingClass().getManager();
e.resolveMethod().getContainingClass().getManager();
e.resolveMethod().getContainingClass().getManager();
}
}
interface PsiManager {
}
interface PsiElement {
PsiManager getManager();
}
interface PsiClass extends PsiElement {
}
interface PsiMethod extends PsiElement {
PsiClass getContainingClass();
}
interface PsiMethodCallExpression extends PsiElement {
PsiMethod resolveMethod();
}
@@ -0,0 +1,31 @@
/*
* Copyright 2000-2013 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.patterns
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
/**
* @author peter
*/
public class VirtualFilePatternsTest extends LightCodeInsightFixtureTestCase {
public void testWithSuperParent() {
def file = myFixture.addFileToProject("foo/bar.txt", "").virtualFile
assert PlatformPatterns.virtualFile().withSuperParent(1, PlatformPatterns.virtualFile().withName("foo")).accepts(file)
assert !PlatformPatterns.virtualFile().withSuperParent(1, PlatformPatterns.virtualFile().withName("bar")).accepts(file)
assert !PlatformPatterns.virtualFile().withSuperParent(2, PlatformPatterns.virtualFile().withName("bar")).accepts(file)
assert !PlatformPatterns.virtualFile().withSuperParent(10, PlatformPatterns.virtualFile().withName("bar")).accepts(file)
assert !PlatformPatterns.virtualFile().withSuperParent(10, PlatformPatterns.virtualFile().withName("foo")).accepts(file)
}
}
@@ -23,13 +23,13 @@ import org.jetbrains.annotations.NotNull;
import java.io.IOException;
/**
* Is intended to test formatting in editor behavior, i.e. check how formatting affects things like caret position, selection etc.
*
* Is intended to test formatting in editor behavior, i.e. check how formatting affects things like caret position, selection etc.
*
* @author Denis Zhdanov
* @since 6/1/11 6:17 PM
*/
public class JavaFormatterInEditorTest extends LightPlatformCodeInsightTestCase {
public void testCaretPositionOnLongLineWrapping() throws IOException {
// Inspired by IDEA-70242
getCurrentCodeStyleSettings().getCommonSettings(JavaLanguage.INSTANCE).WRAP_LONG_LINES = true;
@@ -39,7 +39,7 @@ public class JavaFormatterInEditorTest extends LightPlatformCodeInsightTestCase
"\n" +
"class <caret>Test {\n" +
"}",
"import static java.util.concurrent\n" +
" .atomic.AtomicInteger.*;\n" +
"\n" +
@@ -47,10 +47,59 @@ public class JavaFormatterInEditorTest extends LightPlatformCodeInsightTestCase
"}"
);
}
public void testCaretPositionPreserved_WhenOnSameLineWithWhiteSpacesOnly() throws IOException {
String text = "class Test {\n" +
" void test() {\n" +
" <caret>\n" +
" }\n" +
"}";
doTest(text, text);
String before = "class Test {\n" +
" void test() {\n" +
" <caret> \n" +
" }\n" +
"}";
doTest(before, text);
}
public void testCaretPositionPreserved_WhenSomeFormattingNeeded() throws IOException {
String before = "public class Test {\n" +
" int a;\n" +
" \n" +
" public static void main(String[] args) {\n" +
" <caret>\n" +
" }\n" +
"\n" +
" static final long j = 2;\n" +
"}";
String after = "public class Test {\n" +
" int a;\n" +
"\n" +
" public static void main(String[] args) {\n" +
" <caret>\n" +
" }\n" +
"\n" +
" static final long j = 2;\n" +
"}";
doTest(before, after);
before = "public class Test {\n" +
" int a;\n" +
" \n" +
" public static void main(String[] args) {\n" +
" <caret> \n" +
" }\n" +
"\n" +
" static final long j = 2;\n" +
"}";
doTest(before, after);
}
public void doTest(@NotNull String before, @NotNull String after) throws IOException {
configureFromFileText(getTestName(false) + ".java", before);
CodeStyleManager.getInstance(getProject()).reformatText(getFile(), 0, getEditor().getDocument().getTextLength());
checkResultByText(after);
}
}
}
Binary file not shown.
-1
View File
@@ -21,7 +21,6 @@ jgoodies-forms.jar
jgoodies-looks-2.4.2.jar
jh.jar
jna-utils.jar
jna-platform.jar
jna.jar
jsch-0.1.50.jar
jsr166e.jar
@@ -118,7 +118,7 @@ public abstract class TreeElementPattern<ParentType, T extends ParentType, Self
PairProcessor<ParentType, ProcessingContext> processor) {
ParentType parent = t;
for (int i = 0; i < level; i++) {
if (parent == null) return false;
if (parent == null) return true;
parent = getParent(parent);
}
return processor.process(parent, context);
@@ -259,13 +259,13 @@ public class PsiTreeUtil {
}
@NotNull
public static <T extends PsiElement> Collection<T> findChildrenOfType(@Nullable PsiElement element, @NotNull Class<T> aClass) {
public static <T extends PsiElement> Collection<T> findChildrenOfType(@Nullable PsiElement element, @NotNull Class<? extends T> aClass) {
return findChildrenOfAnyType(element, aClass);
}
@NotNull
public static <T extends PsiElement> Collection<T> findChildrenOfAnyType(@Nullable final PsiElement element,
@NotNull final Class<T>... classes) {
@NotNull final Class<? extends T>... classes) {
if (element == null) {
return ContainerUtil.emptyList();
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 703 B

After

Width:  |  Height:  |  Size: 571 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -27,24 +27,26 @@ import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.Messages;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.ListSpeedSearch;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBList;
import com.intellij.ui.components.JBMovePanel;
import com.intellij.util.EventDispatcher;
import com.intellij.util.containers.ContainerUtilRt;
import com.intellij.util.ui.GridBag;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.ui.UIUtil;
import net.miginfocom.swing.MigLayout;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.event.DocumentEvent;
import javax.swing.plaf.basic.ComboPopup;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class FontOptions extends JPanel implements OptionsPanel{
@@ -55,162 +57,95 @@ public class FontOptions extends JPanel implements OptionsPanel{
@NotNull private final ColorAndFontOptions myOptions;
@NotNull private final DefaultListModel myAllFontsModel = new DefaultListModel();
@NotNull private final JBList myAllFontsList = new JBList(myAllFontsModel);
@NotNull private final DefaultListModel mySelectedFontsModel = new DefaultListModel();
@NotNull private final JBList mySelectedFontsList = new JBList(mySelectedFontsModel);
@NotNull private final JBMovePanel myFontsControl = new JBMovePanel(myAllFontsList, mySelectedFontsList) {
@SuppressWarnings("SSBasedInspection")
@Override
public void paint(Graphics g) {
super.paint(g);
if (myFontNames == null) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
initFontTables();
}
});
}
}
};
@NotNull private final JTextField myEditorFontSizeField = new MyTextField(4);
@NotNull private final JTextField myLineSpacingField = new MyTextField(4);
@NotNull private final JTextField myEditorFontSizeField = new JTextField(4);
@NotNull private final JTextField myLineSpacingField = new JTextField(4);
private final FontNameCombo myPrimaryCombo = new FontNameCombo(null);
private final JCheckBox myUseSecondaryFontCheckbox = new JCheckBox(ApplicationBundle.message("secondary.font"));
private final FontNameCombo mySecondaryCombo = new FontNameCombo(null);
@NotNull private final JBCheckBox myOnlyMonospacedCheckBox =
new JBCheckBox(ApplicationBundle.message("checkbox.show.only.monospaced.fonts"));
@Nullable private final Dimension myPreferredSize;
private boolean myIsInSchemeChange;
private final String myTitle;
public FontOptions(ColorAndFontOptions options) {
this(options, ApplicationBundle.message("group.editor.font"));
}
protected FontOptions(@NotNull ColorAndFontOptions options, final String title) {
super(new GridBagLayout());
setLayout(new MigLayout("ins 0, gap 5, flowx"));
Insets borderInsets = new Insets(IdeBorderFactory.TITLED_BORDER_TOP_INSET,
IdeBorderFactory.TITLED_BORDER_LEFT_INSET,
0,
IdeBorderFactory.TITLED_BORDER_RIGHT_INSET);
setBorder(IdeBorderFactory.createTitledBorder(title, false, borderInsets));
myOptions = options;
myTitle = title;
add(createEditorFontPanel(), new GridBag().weightx(1).weighty(1).fillCell().coverLine());
add(myOnlyMonospacedCheckBox, "sgx b, sx 2");
add(new JLabel(ApplicationBundle.message("primary.font")), "newline, ax right");
add(myPrimaryCombo, "sgx b");
add(new JLabel(ApplicationBundle.message("editbox.font.size")), "gapleft 20");
add(myEditorFontSizeField);
add(new JLabel(ApplicationBundle.message("editbox.line.spacing")), "gapleft 20");
add(myLineSpacingField);
add(new JLabel(ApplicationBundle.message("label.fallback.fonts.list.description"),
MessageType.INFO.getDefaultIcon(),
SwingConstants.LEFT),
new GridBag().anchor(GridBagConstraints.WEST));
myFontsControl.setShowButtons(JBMovePanel.ButtonType.LEFT, JBMovePanel.ButtonType.RIGHT);
myFontsControl.setListLabels(ApplicationBundle.message("title.font.available"), ApplicationBundle.message("title.font.selected"));
myFontsControl.setEnabled(false); // Disable the controls until fonts are loaded.
myFontsControl.setLeftInsertionStrategy(JBMovePanel.NATURAL_ORDER);
SwingConstants.LEFT), "newline, sx 5");
add(myUseSecondaryFontCheckbox, "newline, ax right");
add(mySecondaryCombo, "sgx b");
myOnlyMonospacedCheckBox.setBorder(null);
myUseSecondaryFontCheckbox.setBorder(null);
mySecondaryCombo.setEnabled(false);
myOnlyMonospacedCheckBox.setSelected(EditorColorsManager.getInstance().isUseOnlyMonospacedFonts());
new ListSpeedSearch(myAllFontsList);
new ListSpeedSearch(mySelectedFontsList);
// Almost all other color scheme pages use the following pattern:
//
// __________________________________________
// | color keys | color and font settings |
//
// Here page's height is calculated on the 'color and font settings' preferred height (debugged a lot to ensure that).
// The idea is to configure current page to use the same height as other pages. That's why we set it up to use the same preferred
// size as 'color and font settings' control.
myPreferredSize = new ColorAndFontDescriptionPanel().getPreferredSize();
if (myFontNames != null) {
onFontsInit();
}
initListeners();
}
@Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
@Override
public Dimension getPreferredSize() {
return myPreferredSize == null ? super.getPreferredSize() : myPreferredSize;
}
private void initListeners() {
myOnlyMonospacedCheckBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
boolean onlyMonospaced = myOnlyMonospacedCheckBox.isSelected();
EditorColorsManager.getInstance().setUseOnlyMonospacedFonts(onlyMonospaced);
onFontsInit();
EditorColorsManager.getInstance().setUseOnlyMonospacedFonts(myOnlyMonospacedCheckBox.isSelected());
myPrimaryCombo.updateModel();
mySecondaryCombo.updateModel();
}
});
mySelectedFontsModel.addListDataListener(new ListDataListener() {
myUseSecondaryFontCheckbox.addActionListener(new ActionListener() {
@Override
public void intervalAdded(ListDataEvent e) {
public void actionPerformed(ActionEvent e) {
mySecondaryCombo.setEnabled(myUseSecondaryFontCheckbox.isSelected());
syncFontFamilies();
}
@Override
public void intervalRemoved(ListDataEvent e) {
syncFontFamilies();
}
@Override
public void contentsChanged(ListDataEvent e) {
syncFontFamilies();
}
private void syncFontFamilies() {
if (myIsInSchemeChange) {
return;
}
FontPreferences fontPreferences = getFontPreferences();
fontPreferences.clearFonts();
Enumeration elements = mySelectedFontsModel.elements();
while (elements.hasMoreElements()) {
String fontFamily = (String)elements.nextElement();
// Don't save a single 'default' font family at the font preferences.
if (mySelectedFontsModel.getSize() > 1 || !FontPreferences.DEFAULT_FONT_NAME.equals(fontFamily)) {
fontPreferences.addFontFamily(fontFamily);
}
}
}
});
mySelectedFontsList.addListSelectionListener(new ListSelectionListener() {
ItemListener itemListener = new ItemListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
Object value = mySelectedFontsList.getSelectedValue();
if (value != null) {
boolean toRestore = myIsInSchemeChange;
myIsInSchemeChange = true;
try {
myEditorFontSizeField.setText(String.valueOf(getFontPreferences().getSize((String)value)));
}
finally {
myIsInSchemeChange = toRestore;
}
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
syncFontFamilies();
}
}
});
};
myPrimaryCombo.addItemListener(itemListener);
mySecondaryCombo.addItemListener(itemListener);
ActionListener actionListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
syncFontFamilies();
}
};
myPrimaryCombo.addActionListener(actionListener);
mySecondaryCombo.addActionListener(actionListener);
myEditorFontSizeField.getDocument().addDocumentListener(new DocumentAdapter() {
@Override
public void textChanged(DocumentEvent event) {
if (myIsInSchemeChange || !SwingUtilities.isEventDispatchThread()) return;
try {
int fontSize = Integer.parseInt(myEditorFontSizeField.getText());
if (fontSize < 1) fontSize = 1;
if (fontSize > OptionsConstants.MAX_EDITOR_FONT_SIZE) fontSize = OptionsConstants.MAX_EDITOR_FONT_SIZE;
Object selectedFont = mySelectedFontsList.getSelectedValue();
if (selectedFont != null) {
FontPreferences fontPreferences = getFontPreferences();
fontPreferences.register((String)selectedFont, fontSize);
}
}
catch (NumberFormatException e) {
// OK, ignore
}
finally {
updateDescription(true);
Object selectedFont = myPrimaryCombo.getSelectedItem();
if (selectedFont instanceof String) {
FontPreferences fontPreferences = getFontPreferences();
fontPreferences.register((String)selectedFont, getFontSizeFromField());
}
updateDescription(true);
}
});
@@ -218,26 +153,57 @@ public class FontOptions extends JPanel implements OptionsPanel{
@Override
public void textChanged(DocumentEvent event) {
if (myIsInSchemeChange) return;
float lineSpacing = 1;
try {
lineSpacing = Float.parseFloat(myLineSpacingField.getText());
}
catch (NumberFormatException e) {
// OK, ignore
}
finally {
if (lineSpacing <= 0) lineSpacing = 1;
if (lineSpacing > 30) lineSpacing = 30;
if (getLineSpacing() != lineSpacing) {
setCurrentLineSpacing(lineSpacing);
}
updateDescription(true);
float lineSpacing = getLineSpacingFromField();
if (getLineSpacing() != lineSpacing) {
setCurrentLineSpacing(lineSpacing);
}
updateDescription(true);
}
});
}
private int getFontSizeFromField() {
try {
return Math.min(OptionsConstants.MAX_EDITOR_FONT_SIZE, Math.max(1, Integer.parseInt(myEditorFontSizeField.getText())));
}
catch (NumberFormatException e) {
return OptionsConstants.DEFAULT_EDITOR_FONT_SIZE;
}
}
private float getLineSpacingFromField() {
try {
return Math.min(30, Math.max(1, Float.parseFloat(myLineSpacingField.getText())));
} catch (NumberFormatException e){
return 1;
}
}
private void syncFontFamilies() {
if (myIsInSchemeChange) {
return;
}
FontPreferences fontPreferences = getFontPreferences();
fontPreferences.clearFonts();
String primaryFontFamily = (String)myPrimaryCombo.getSelectedItem();
String secondaryFontFamily = mySecondaryCombo.isEnabled() ? (String)mySecondaryCombo.getSelectedItem() : null;
int fontSize = getFontSizeFromField();
if (primaryFontFamily != null ) {
if (!FontPreferences.DEFAULT_FONT_NAME.equals(primaryFontFamily)) {
fontPreferences.addFontFamily(primaryFontFamily);
}
fontPreferences.register(primaryFontFamily, fontSize);
}
if (secondaryFontFamily != null) {
if (!FontPreferences.DEFAULT_FONT_NAME.equals(secondaryFontFamily)){
fontPreferences.addFontFamily(secondaryFontFamily);
}
fontPreferences.register(secondaryFontFamily, fontSize);
}
updateDescription(true);
}
public static void showReadOnlyMessage(JComponent parent, final boolean sharedScheme) {
if (!sharedScheme) {
Messages.showMessageDialog(
@@ -262,65 +228,25 @@ public class FontOptions extends JPanel implements OptionsPanel{
myIsInSchemeChange = true;
myLineSpacingField.setText(Float.toString(getLineSpacing()));
mySelectedFontsModel.clear();
FontPreferences fontPreferences = getFontPreferences();
List<String> fontFamilies = fontPreferences.getEffectiveFontFamilies();
Set<String> selectedFonts = ContainerUtilRt.newHashSet();
Object selectedValue = mySelectedFontsList.getSelectedValue();
mySelectedFontsModel.clear();
if (fontFamilies.isEmpty()) {
// Add default font.
mySelectedFontsModel.addElement(fontPreferences.getFontFamily());
selectedFonts.add(fontPreferences.getFontFamily());
}
else {
for (String fontFamily : fontFamilies) {
mySelectedFontsModel.addElement(fontFamily);
selectedFonts.add(fontFamily);
}
}
int newSelectionIndex = 0;
if (selectedValue != null) {
newSelectionIndex = Math.max(0, mySelectedFontsModel.indexOf(selectedValue));
}
mySelectedFontsList.setSelectedIndex(newSelectionIndex);
for (int i = myAllFontsModel.size() - 1; i >= 0; i--) {
if (selectedFonts.contains(myAllFontsModel.getElementAt(i))) {
myAllFontsModel.remove(i);
}
}
myPrimaryCombo.setSelectedItem(fontPreferences.getFontFamily());
boolean isThereSecondaryFont = fontFamilies.size() > 1;
myUseSecondaryFontCheckbox.setSelected(isThereSecondaryFont);
mySecondaryCombo.setSelectedItem(isThereSecondaryFont ? fontFamilies.get(1) : null);
myEditorFontSizeField.setText(String.valueOf(fontPreferences.getSize(fontPreferences.getFontFamily())));
boolean enabled = !ColorAndFontOptions.isReadOnly(myOptions.getSelectedScheme());
myOnlyMonospacedCheckBox.setEnabled(enabled);
myLineSpacingField.setEnabled(enabled);
myEditorFontSizeField.setEditable(enabled);
myFontsControl.setEnabled(enabled);
boolean readOnly = ColorAndFontOptions.isReadOnly(myOptions.getSelectedScheme());
myPrimaryCombo.setEnabled(!readOnly);
mySecondaryCombo.setEnabled(isThereSecondaryFont && !readOnly);
myOnlyMonospacedCheckBox.setEnabled(!readOnly);
myLineSpacingField.setEnabled(!readOnly);
myEditorFontSizeField.setEditable(!readOnly);
myUseSecondaryFontCheckbox.setEnabled(!readOnly);
myIsInSchemeChange = false;
}
private void onFontsInit() {
assert myFontNames != null;
Object selectedValue = myAllFontsList.getSelectedValue();
myAllFontsModel.clear();
List<String> availableFonts = myOnlyMonospacedCheckBox.isSelected() ? myMonospacedFontNames : myFontNames;
int newSelectionIndex = 0;
int i = 0;
for (String name : availableFonts) {
if (!mySelectedFontsModel.contains(name)) { // Don't bother with performance here in assumption that fallback fonts sequence is short
myAllFontsModel.addElement(name);
if (name.equals(selectedValue)) {
newSelectionIndex = i;
}
i++;
}
}
myAllFontsList.setSelectedIndex(newSelectionIndex);
}
@NotNull
protected FontPreferences getFontPreferences() {
return getCurrentScheme().getFontPreferences();
@@ -352,44 +278,13 @@ public class FontOptions extends JPanel implements OptionsPanel{
return myOptions.getSelectedScheme();
}
private JPanel createEditorFontPanel() {
JPanel editorFontPanel = new JPanel(new GridBagLayout());
Insets borderInsets = new Insets(IdeBorderFactory.TITLED_BORDER_TOP_INSET,
IdeBorderFactory.TITLED_BORDER_LEFT_INSET,
0,
IdeBorderFactory.TITLED_BORDER_RIGHT_INSET);
editorFontPanel.setBorder(IdeBorderFactory.createTitledBorder(myTitle, false, borderInsets));
Insets insets = new Insets(0, 0, 5, 0);
GridBag constraints = new GridBag().insets(insets);
editorFontPanel.add(myOnlyMonospacedCheckBox, constraints);
insets.left = 8;
editorFontPanel.add(new JLabel(ApplicationBundle.message("editbox.font.size")), constraints);
insets.left = 2;
editorFontPanel.add(myEditorFontSizeField, constraints);
insets.left = 8;
editorFontPanel.add(new JLabel(ApplicationBundle.message("editbox.line.spacing")), constraints);
insets.left = 2;
editorFontPanel.add(myLineSpacingField, constraints);
editorFontPanel.add(new JLabel(""), new GridBag().insets(insets).weightx(1).fillCellHorizontally().coverLine());
editorFontPanel.add(myFontsControl, new GridBag().weightx(1).weighty(1).fillCell().coverLine().insets(insets));
return editorFontPanel;
}
@SuppressWarnings({"AssignmentToStaticFieldFromInstanceMethod"})
private void initFontTables() {
private void initFontTables(FontNameCombo popupCallback) {
if (myFontNames == null) {
myFontNames = new ArrayList<String>();
myMonospacedFontNames = new ArrayList<String>();
ProgressManager.getInstance().runProcessWithProgressSynchronously(new InitFontsRunnable(), ApplicationBundle.message("progress.analyzing.fonts"), false, null);
ProgressManager.getInstance().runProcessWithProgressSynchronously(new InitFontsRunnable(popupCallback), ApplicationBundle.message("progress.analyzing.fonts"), false, null);
}
}
@@ -421,18 +316,13 @@ public class FontOptions extends JPanel implements OptionsPanel{
return new HashSet<String>();
}
private static class MyTextField extends JTextField {
private MyTextField(int size) {
super(size);
}
@Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
}
private class InitFontsRunnable implements Runnable {
private final FontNameCombo myPopupCallback;
private InitFontsRunnable(FontNameCombo popupCallback) {
myPopupCallback = popupCallback;
}
@Override
public void run() {
ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
@@ -482,9 +372,93 @@ public class FontOptions extends JPanel implements OptionsPanel{
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
onFontsInit();
myPrimaryCombo.updateModel();
mySecondaryCombo.updateModel();
myPopupCallback.showPopup();
}
});
}
}
private class FontNameCombo extends JComboBox {
private final DefaultComboBoxModel myModel;
private Boolean myMonospacedOnly = null;
private FontNameCombo(String selectedName) {
setModel(myModel = new DefaultComboBoxModel());
updateModel();
setSelectedItem(selectedName);
}
private void updateModel() {
if (myFontNames == null || myMonospacedFontNames == null) return;
if (myMonospacedOnly == null || myMonospacedOnly.booleanValue() != EditorColorsManager.getInstance().isUseOnlyMonospacedFonts()) {
myMonospacedOnly = EditorColorsManager.getInstance().isUseOnlyMonospacedFonts();
Object tmp = getSelectedItem();
myModel.removeAllElements();
List toAdd = myMonospacedOnly ? myMonospacedFontNames : myFontNames;
for (Object o : toAdd) {
myModel.addElement(o);
}
if (myModel.getIndexOf(tmp) != -1) {
setSelectedItem(tmp);
} else {
setSelectedItem(FontPreferences.DEFAULT_FONT_NAME);
}
fireActionEvent();
revalidate();
repaint();
}
}
@Override
public void setSelectedItem(Object anObject) {
if (myModel.getSize() == 0 && anObject != null) {
myModel.addElement(anObject);
}
super.setSelectedItem(anObject);
}
@Nullable
private JList getPopupList() {
ComboPopup popup = ReflectionUtil.getField(getUI().getClass(), getUI(), ComboPopup.class, "popup");
return (popup != null) ? popup.getList() : null;
}
@Override
public void firePopupMenuWillBecomeVisible() {
super.firePopupMenuWillBecomeVisible();
if (myFontNames == null) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
initFontTables(FontNameCombo.this);
}
});
}
final JList list = getPopupList();
if (list != null && !(list.getCellRenderer() instanceof MyListCellRenderer)) {
list.setCellRenderer(new MyListCellRenderer());
}
}
}
private static class MyListCellRenderer extends DefaultListCellRenderer {
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value instanceof String) {
c.setFont(new Font((String) value, Font.PLAIN, 14));
}
return c;
}
}
}
@@ -32,23 +32,31 @@ public class CapitalizeAndUnderscoreMacro extends MacroBase {
super("capitalizeAndUnderscore", CodeInsightBundle.message("macro.capitalizeAndUnderscore.string"));
}
protected CapitalizeAndUnderscoreMacro(String name, String description) {
super(name, description);
}
@Override
protected Result calculateResult(@NotNull Expression[] params, ExpressionContext context, boolean quick) {
String text = getTextResult(params, context, true);
if (text != null && text.length() > 0) {
final String[] words = NameUtil.nameToWords(text);
boolean insertUnderscore = false;
final StringBuffer buf = new StringBuffer();
final StringBuilder buf = new StringBuilder();
for (String word : words) {
if (insertUnderscore) {
buf.append("_");
} else {
insertUnderscore = true;
}
buf.append(StringUtil.toUpperCase(word));
buf.append(convertCase(word));
}
return new TextResult(buf.toString());
}
return null;
}
protected String convertCase(String word) {
return StringUtil.toUpperCase(word);
}
}
@@ -13,24 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.refactoring.introduce.constant;
import com.intellij.ui.components.JBCheckBox;
import javax.swing.*;
package com.intellij.codeInsight.template.macro;
/**
* Created by Max Medvedev on 8/29/13
* @author yole
*/
public class GrInplaceIntroduceConstantPanel {
private JBCheckBox myMoveToAnotherClassJBCheckBox;
private JPanel myRootPane;
public boolean isMoveToAnotherClass() {
return myMoveToAnotherClassJBCheckBox.isSelected();
public class SnakeCaseMacro extends CapitalizeAndUnderscoreMacro {
public SnakeCaseMacro() {
super("snakeCase", "snakeCase(String)");
}
public JComponent getRootPane() {
return myRootPane;
@Override
protected String convertCase(String word) {
return word.toLowerCase();
}
}
@@ -38,6 +38,7 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.actions.TextComponentEditorAction;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.fileEditor.impl.EditorHistoryManager;
import com.intellij.openapi.keymap.KeymapManager;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.keymap.MacKeymapUtil;
import com.intellij.openapi.options.Configurable;
@@ -217,8 +218,10 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
private void run(KeyEvent event) {
final ActionManager actionManager = ActionManager.getInstance();
final AnAction action = actionManager.getAction("SearchEverywhere");
final AnAction action = actionManager.getAction(IdeActions.ACTION_SEARCH_EVERYWHERE);
if (KeymapManager.getInstance().getActiveKeymap().getShortcuts(IdeActions.ACTION_SEARCH_EVERYWHERE).length > 0) {
return;
}
final AnActionEvent anActionEvent = new AnActionEvent(event,
DataManager.getInstance().getDataContext(IdeFocusManager.findInstance().getFocusOwner()),
ActionPlaces.UNKNOWN,
@@ -314,10 +317,17 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
}
private void initTooltip(JLabel label) {
label.setToolTipText("<html><body>Search Everywhere<br/>Press <b>" +
"Double " +
(SystemInfo.isMac ? MacKeymapUtil.SHIFT : "Shift") +
"</b> to access<br/> - Classes<br/> - Files<br/> - Tool Windows<br/> - Actions<br/> - Settings</body></html>");
final Shortcut[] shortcuts = KeymapManager.getInstance().getActiveKeymap().getShortcuts(IdeActions.ACTION_SEARCH_EVERYWHERE);
final String shortcutText;
if (shortcuts.length == 0) {
shortcutText = "Double " + (SystemInfo.isMac ? MacKeymapUtil.SHIFT : "Shift");
} else {
shortcutText = KeymapUtil.getShortcutsText(shortcuts);
}
label.setToolTipText("<html><body>Search Everywhere<br/>Press <b>"
+ shortcutText
+ "</b> to access<br/> - Classes<br/> - Files<br/> - Tool Windows<br/> - Actions<br/> - Settings</body></html>");
}
@@ -589,7 +599,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
initSearchActions(myBalloon, myPopupField);
IdeFocusManager focusManager = IdeFocusManager.getInstance(e.getProject());
focusManager.requestFocus(myPopupField.getTextEditor(), true);
// FeatureUsageTracker.getInstance().triggerFeatureUsed("SearchEverywhere");
// FeatureUsageTracker.getInstance().triggerFeatureUsed(IdeActions.ACTION_SEARCH_EVERYWHERE);
}
private void initSearchActions(JBPopup balloon, MySearchTextField searchTextField) {
@@ -181,7 +181,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager {
// So, if 'virtual space in editor' is enabled, we save target visual column. Caret indent is ensured otherwise
int visualColumnToRestore = -1;
String caretIndentToRestore = null;
RangeMarker caretRangeMarker = null;
RangeMarker beforeCaretRangeMarker = null;
if (editor != null) {
Document document = editor.getDocument();
@@ -202,7 +202,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager {
if (fixCaretPosition) {
visualColumnToRestore = editor.getCaretModel().getVisualPosition().column;
caretIndentToRestore = document.getText(TextRange.create(lineStartOffset, caretOffset));
caretRangeMarker = document.createRangeMarker(lineStartOffset, caretOffset);
beforeCaretRangeMarker = document.createRangeMarker(0, lineStartOffset);
}
}
@@ -261,11 +261,11 @@ public class CodeStyleManagerImpl extends CodeStyleManager {
}
}
else {
if (caretRangeMarker == null || !caretRangeMarker.isValid() || caretIndentToRestore == null) {
if (beforeCaretRangeMarker == null || !beforeCaretRangeMarker.isValid() || caretIndentToRestore == null) {
return;
}
int offset = caretRangeMarker.getStartOffset();
caretRangeMarker.dispose();
int offset = beforeCaretRangeMarker.getEndOffset();
beforeCaretRangeMarker.dispose();
if (editor.getCaretModel().getVisualPosition().column == visualColumnToRestore) {
return;
}
@@ -484,10 +484,10 @@ public class CodeStyleManagerImpl extends CodeStyleManager {
* </ol>
* </pre>
* <p/>
* This method inserts that dummy comment (fallback to identifier <code>xxx</code>, see {@link CodeStyleManagerImpl#createDummy(PsiFile)})
* This method inserts that dummy comment (fallback to identifier <code>xxx</code>, see {@link CodeStyleManagerImpl#createDummy(PsiFile)})
* if necessary (if target line contains white space symbols only).
* <p/>
* <b>Note:</b> it's expected that the whole white space region that contains given offset is processed in a way that all
* {@link RangeMarker range markers} registered for the given offset are expanded to the whole white space region.
* E.g. there is a possible case that particular range marker serves for defining formatting range, hence, its start/end offsets
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -44,7 +44,7 @@ import java.util.List;
// This prevents languages with polyadic expressions or sequences
// from reusing it, use simpleChooser instead.
public abstract class OccurrencesChooser<T> {
public static enum ReplaceChoice {
public enum ReplaceChoice {
NO("Replace this occurrence only"), NO_WRITE("Replace all occurrences but write"), ALL("Replace all {0} occurrences");
private final String myDescription;
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -30,6 +30,7 @@ import com.intellij.lang.refactoring.NamesValidator;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.Shortcut;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.command.impl.FinishMarkAction;
@@ -327,7 +328,7 @@ public abstract class InplaceRefactoring {
new WriteCommandAction(myProject, getCommandName()) {
@Override
protected void run(com.intellij.openapi.application.Result result) throws Throwable {
protected void run(Result result) throws Throwable {
startTemplate(builder);
}
}.execute();
@@ -44,21 +44,12 @@ public class EditorTextFieldActionPromoter implements ActionPromoter {
private static final Comparator<AnAction> ACTIONS_COMPARATOR = new Comparator<AnAction>() {
@Override
public int compare(AnAction o1, AnAction o2) {
if (o1 instanceof EditorAction && o2 instanceof EditorAction) {
return 0;
}
if (o1 instanceof TextComponentEditorAction) {
return -1;
}
if (o2 instanceof TextComponentEditorAction) {
return 1;
}
if (o1 instanceof EditorAction) {
return 1;
}
if (o2 instanceof EditorAction) {
return -1;
}
boolean textFieldAction1 = o1 instanceof TextComponentEditorAction;
boolean textFieldAction2 = o2 instanceof TextComponentEditorAction;
boolean plainEditorAction1 = o1 instanceof EditorAction && !textFieldAction1;
boolean plainEditorAction2 = o2 instanceof EditorAction && !textFieldAction2;
if (textFieldAction1 && plainEditorAction2) return -1;
if (textFieldAction2 && plainEditorAction1) return 1;
return 0;
}
};
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -267,4 +267,5 @@ public interface IdeActions {
String MOVE_TO_ANOTHER_CHANGE_LIST = "ChangesView.Move";
String ACTION_RECENT_FILES = "RecentFiles";
String ACTION_SEARCH_EVERYWHERE = "SearchEverywhere";
}
@@ -37,7 +37,6 @@ import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.IdRunnable;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.wm.ex.WindowManagerEx;
@@ -80,9 +79,9 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar {
/**
* This array contains Rectangles which define bounds of the corresponding
* components in the toolbar. This list can be considerer as a cache of the
* components in the toolbar. This list can be consider as a cache of the
* Rectangle objects that are used in calculation of preferred sizes and
* layouting of components.
* components layout.
*/
private final List<Rectangle> myComponentBounds = new ArrayList<Rectangle>();
@@ -123,7 +122,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar {
private ActionButton mySecondaryActionsButton;
private final KeymapManagerEx myKeymapManager;
private int myFirstOusideIndex = -1;
private int myFirstOutsideIndex = -1;
private JBPopup myPopup;
private JComponent myTargetComponent;
@@ -183,7 +182,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar {
myTimerListener = new MyTimerListener();
myWeakTimerListener = new WeakTimerListener(actionManager, myTimerListener);
// If the panel doesn't handle mouse event then it will be passed to its parent.
// It means that if the panel is in slidindg mode then the focus goes to the editor
// It means that if the panel is in sliding mode then the focus goes to the editor
// and panel will be automatically hidden.
enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK | AWTEvent.COMPONENT_EVENT_MASK | AWTEvent.CONTAINER_EVENT_MASK);
setMiniMode(false);
@@ -300,7 +299,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar {
add(mySecondaryActionsButton);
}
if (Registry.is("search.everywhere.enabled") && (ActionPlaces.MAIN_TOOLBAR.equals(myPlace) || ActionPlaces.NAVIGATION_BAR.equals(myPlace))) {
if ((ActionPlaces.MAIN_TOOLBAR.equals(myPlace) || ActionPlaces.NAVIGATION_BAR.equals(myPlace))) {
final AnAction searchEverywhereAction = ActionManager.getInstance().getAction("SearchEverywhere");
if (searchEverywhereAction != null) {
try {
@@ -520,7 +519,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar {
if (full) {
if (myAutoPopupRec == null) {
myAutoPopupRec = new Rectangle(eachX, eachY, sizeToFit.width - eachX - 1, sizeToFit.height - 1);
myFirstOusideIndex = i;
myFirstOutsideIndex = i;
}
eachBound.x = Integer.MAX_VALUE;
eachBound.y = Integer.MAX_VALUE;
@@ -562,7 +561,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar {
if (full) {
if (myAutoPopupRec == null) {
myAutoPopupRec = new Rectangle(eachX, eachY, sizeToFit.width - 1, sizeToFit.height - eachY - 1);
myFirstOusideIndex = i;
myFirstOutsideIndex = i;
}
eachBound.x = Integer.MAX_VALUE;
eachBound.y = Integer.MAX_VALUE;
@@ -575,7 +574,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar {
}
private void calculateBoundsWrapImpl(Dimension sizeToFit, List<Rectangle> bounds) {
// We have to gracefull handle case when toolbar was not layed out yet.
// We have to graceful handle case when toolbar was not laid out yet.
// In this case we calculate bounds as it is a NOWRAP toolbar.
if (getWidth() == 0 || getHeight() == 0) {
try {
@@ -611,7 +610,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar {
}
final Rectangle each = bounds.get(i);
each.setBounds(xOffset, maxWidth, yOffset, maxHeight);
each.setBounds(xOffset, yOffset, maxWidth, maxHeight);
xOffset += maxWidth;
}
@@ -632,7 +631,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar {
}
final Rectangle each = bounds.get(i);
each.setBounds(xOffset, maxWidth, yOffset, maxHeight);
each.setBounds(xOffset, yOffset, maxWidth, maxHeight);
yOffset += maxHeight;
}
@@ -642,7 +641,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar {
if (myOrientation == SwingConstants.HORIZONTAL) {
// Calculate row height
int rowHeight = 0;
final Dimension[] dims = new Dimension[componentCount]; // we will use this dimesions later
final Dimension[] dims = new Dimension[componentCount]; // we will use this dimensions later
for (int i = 0; i < componentCount; i++) {
dims[i] = getChildPreferredSize(i);
final int height = dims[i].height;
@@ -670,7 +669,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar {
else {
// Calculate row width
int rowWidth = 0;
final Dimension[] dims = new Dimension[componentCount]; // we will use this dimesions later
final Dimension[] dims = new Dimension[componentCount]; // we will use this dimensions later
for (int i = 0; i < componentCount; i++) {
dims[i] = getChildPreferredSize(i);
final int width = dims[i].width;
@@ -717,13 +716,12 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar {
calculateBoundsAutoImp(size2Fit, bounds);
}
else {
throw new IllegalStateException("unknonw layoutPolicy: " + myLayoutPolicy);
throw new IllegalStateException("unknown layoutPolicy: " + myLayoutPolicy);
}
if (getComponentCount() > 0 && size2Fit.width < Integer.MAX_VALUE) {
final Component component = getComponent(getComponentCount() - 1);
if (component instanceof JComponent && ((JComponent)component).getClientProperty("SEARCH_EVERYWHERE") == Boolean.TRUE) {
final Rectangle rect = bounds.get(bounds.size() - 1);
int max = 0;
for (int i = 0; i < bounds.size() - 2; i++) {
max = Math.max(max, bounds.get(i).height);
@@ -799,7 +797,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar {
final Insets i = getInsets();
if (UIUtil.isUnderAquaBasedLookAndFeel() || UIUtil.isUnderDarcula()) {
if (getParent() != null) {
final JBColor col = new JBColor(Color.GRAY, Gray._111);
final JBColor col = new JBColor(Gray._128, Gray._111);
final Graphics2D g2 = (Graphics2D)g;
if (myOrientation == SwingConstants.HORIZONTAL) {
UIUtil.drawDoubleSpaceDottedLine(g2, i.top + 2, getParent().getSize().height - 2 - i.top - i.bottom, 3, col, false);
@@ -1029,7 +1027,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar {
}
else {
final DefaultActionGroup outside = new DefaultActionGroup();
for (int i = myFirstOusideIndex; i < myVisibleActions.size(); i++) {
for (int i = myFirstOutsideIndex; i < myVisibleActions.size(); i++) {
outside.add(myVisibleActions.get(i));
}
group = outside;
@@ -64,7 +64,8 @@ public class LocalFsFinder implements FileLookup.Finder, FileLookup {
return null;
}
public String normalize(@NotNull final String path) {
public String normalize(@NotNull String path) {
path = FileUtil.expandUserHome(path);
final File file = new File(path);
if (file.isAbsolute()) return file.getAbsolutePath();
@@ -31,7 +31,6 @@ import com.intellij.openapi.keymap.MacKeymapUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Splitter;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.*;
@@ -170,10 +169,14 @@ public class EditorsSplitters extends IdePanePanel {
painter.appendLine("No files are open").underlined(new JBColor(isDarkBackground ? Gray._210 : Gray._150, Gray._100));
if (Registry.is("search.everywhere.enabled")) {
painter.appendLine("Search Everywhere with Double " + (SystemInfo.isMac ? MacKeymapUtil.SHIFT : "Shift"))
.smaller().withBullet();
final Shortcut[] shortcuts = KeymapManager.getInstance().getActiveKeymap().getShortcuts(IdeActions.ACTION_SEARCH_EVERYWHERE);
final String everywhere;
if (shortcuts.length == 0) {
everywhere = "Search Everywhere with Double " + (SystemInfo.isMac ? MacKeymapUtil.SHIFT : "Shift");
} else {
everywhere = "Search Everywhere " + KeymapUtil.getShortcutsText(shortcuts);
}
painter.appendLine(everywhere).smaller().withBullet();
if (!isProjectViewVisible()) {
painter.appendLine("Open Project View with " + KeymapUtil.getShortcutText(new KeyboardShortcut(
@@ -475,6 +475,8 @@ error.illegal.scheme.name=Illegal scheme name
error.a.scheme.with.this.name.already.exists.or.was.deleted.without.applying.the.changes=A scheme with this name already exists or was deleted without applying the changes
title.select.font=Select Font
checkbox.show.only.monospaced.fonts=Show only monospaced fonts
primary.font=Primary font:
secondary.font=Secondary font:
editbox.enter.tag.name=Enter tag name:
title.tag.name=Tag Name
title.xml=XML
@@ -503,9 +505,7 @@ title.colors.and.fonts=Colors \\& Fonts
progress.analysing.font=Analysing font: {0}
button.edit.scopes=Edit Scopes...
group.editor.font=Editor Font
title.font.available=Available fonts:
title.font.selected=Selected fonts:
label.fallback.fonts.list.description=The ide tries to use the next font from 'Selected fonts' list for displaying a symbol if the current font fails to do that
label.fallback.fonts.list.description=If primary font fails IDE tries to use the secondary one
quickdoc.tooltip.font.size.by.wheel=Slider or Ctrl+Wheel change font size
label.font.size=Font size:
label.font.name=Name:
@@ -298,7 +298,6 @@ enable.graph.inference=false
comment.by.line.bulk.lines.trigger=100
scene.builder.start.executable=true
search.everywhere.enabled=true
junit_sm_runner=false
testng_sm_runner=false
show.flex.debug.design.view=false
@@ -432,6 +432,7 @@
<liveTemplateMacro implementation="com.intellij.codeInsight.template.macro.FileNameWithoutExtensionMacro"/>
<liveTemplateMacro implementation="com.intellij.codeInsight.template.macro.ReplaceUnderscoresToCamelCaseMacro"/>
<liveTemplateMacro implementation="com.intellij.codeInsight.template.macro.CapitalizeAndUnderscoreMacro"/>
<liveTemplateMacro implementation="com.intellij.codeInsight.template.macro.SnakeCaseMacro"/>
<liveTemplateMacro implementation="com.intellij.codeInsight.template.macro.CompleteMacro"/>
<liveTemplateMacro implementation="com.intellij.codeInsight.template.macro.CompleteSmartMacro"/>
@@ -663,7 +664,7 @@
<!-- HighlightManagerActions -->
<editorActionHandler action="EditorEscape" implementationClass="com.intellij.codeInsight.highlighting.EscapeHandler"
order="after hide-hints"/>
order="after hide-hints" id="hide-search"/>
<editorActionHandler action="EditorEscape" implementationClass="com.intellij.refactoring.rename.inplace.EscapeHandler"
order="before hide-hints"/>
@@ -129,7 +129,8 @@ public class PathMacrosImpl extends PathMacros implements ApplicationComponent,
"SelectionStartLine",
"SelectionEndLine",
"SelectionStartColumn",
"SelectionEndColumn"
"SelectionEndColumn",
"PyInterpreterDirectory"
);
public PathMacrosImpl() {
@@ -0,0 +1,52 @@
/*
* Copyright 2000-2013 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.gradle.codeInsight;
import com.intellij.codeInsight.completion.CompletionContributor;
import com.intellij.patterns.ElementPattern;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.gradle.util.GradleConstants;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCommandArgumentList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.literals.GrLiteralImpl;
import static com.intellij.patterns.PlatformPatterns.psiElement;
import static com.intellij.patterns.PlatformPatterns.psiFile;
import static com.intellij.patterns.StandardPatterns.string;
/**
* @author Vladislav.Soroka
* @since 11/1/13
*/
public abstract class AbstractGradleCompletionContributor extends CompletionContributor {
protected static final ElementPattern<PsiElement> GRADLE_FILE_PATTERN = psiElement()
.inFile(psiFile().withName(string().endsWith('.' + GradleConstants.EXTENSION)));
@Nullable
protected String findNamedArgumentValue(@Nullable GrCommandArgumentList argumentList, @NotNull String label) {
if (argumentList == null) return null;
GrNamedArgument namedArgument = argumentList.findNamedArgument(label);
if (namedArgument == null) return null;
GrExpression expression = namedArgument.getExpression();
if (!(expression instanceof GrLiteralImpl)) return null;
Object value = GrLiteralImpl.class.cast(expression).getValue();
return value == null ? null : String.valueOf(value);
}
}
@@ -22,19 +22,20 @@ import com.intellij.icons.AllIcons;
import com.intellij.patterns.ElementPattern;
import com.intellij.patterns.PatternCondition;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.indices.MavenArtifactSearchResult;
import org.jetbrains.idea.maven.indices.MavenArtifactSearcher;
import org.jetbrains.idea.maven.indices.MavenProjectIndicesManager;
import org.jetbrains.idea.maven.model.MavenArtifactInfo;
import org.jetbrains.idea.maven.model.MavenId;
import org.jetbrains.plugins.gradle.codeInsight.AbstractGradleCompletionContributor;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCommandArgumentList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.literals.GrLiteralImpl;
import java.util.List;
@@ -44,27 +45,31 @@ import static com.intellij.patterns.PlatformPatterns.psiElement;
* @author Vladislav.Soroka
* @since 10/31/13
*/
public class MavenDependenciesGradleCompletionContributor extends CompletionContributor {
public class MavenDependenciesGradleCompletionContributor extends AbstractGradleCompletionContributor {
private static final String GROUP_LABEL = "group";
private static final String NAME_LABEL = "name";
private static final String VERSION_LABEL = "version";
private static final PatternCondition<GrMethodCallExpression> EXPRESSION_PATTERN_CONDITION =
new PatternCondition<GrMethodCallExpression>("withInvokedExpressionText") {
private static final ElementPattern<PsiElement> DEPENDENCIES_CALL_PATTERN = psiElement()
.inside(true, psiElement(GrMethodCallExpression.class).with(new PatternCondition<GrMethodCallExpression>("withInvokedExpressionText") {
@Override
public boolean accepts(@NotNull GrMethodCallExpression expression, ProcessingContext context) {
GrExpression grExpression = expression.getInvokedExpression();
return grExpression != null && "dependencies".equals(grExpression.getText());
}
};
}));
private static final ElementPattern<PsiElement>
IN_BASIC_DEPENDENCY_NOTATION = psiElement().withSuperParent(
5, psiElement(GrMethodCallExpression.class).with(EXPRESSION_PATTERN_CONDITION));
private static final ElementPattern<PsiElement> IN_BASIC_DEPENDENCY_NOTATION = psiElement()
.and(GRADLE_FILE_PATTERN)
.withParent(GrLiteral.class)
.withSuperParent(2, psiElement(GrCommandArgumentList.class))
.and(DEPENDENCIES_CALL_PATTERN);
private static final ElementPattern<PsiElement>
IN_MAP_DEPENDENCY_NOTATION = psiElement().withSuperParent(
6, psiElement(GrMethodCallExpression.class).with(EXPRESSION_PATTERN_CONDITION));
private static final ElementPattern<PsiElement> IN_MAP_DEPENDENCY_NOTATION = psiElement()
.and(GRADLE_FILE_PATTERN)
.withParent(GrLiteral.class)
.withSuperParent(2, psiElement(GrNamedArgument.class))
.and(DEPENDENCIES_CALL_PATTERN);
public MavenDependenciesGradleCompletionContributor() {
@@ -144,16 +149,4 @@ public class MavenDependenciesGradleCompletionContributor extends CompletionCont
}
});
}
@Nullable
private static String findNamedArgumentValue(@Nullable GrCommandArgumentList argumentList, @NotNull String label) {
if (argumentList == null) return null;
GrNamedArgument namedArgument = argumentList.findNamedArgument(label);
if (namedArgument == null) return null;
GrExpression expression = namedArgument.getExpression();
if (!(expression instanceof GrLiteralImpl)) return null;
Object value = GrLiteralImpl.class.cast(expression).getValue();
return value == null ? null : String.valueOf(value);
}
}
@@ -25,18 +25,12 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager;
import java.util.List;
import java.util.Set;
/**
* @author Denis Zhdanov
* @since 8/14/13 12:58 PM
*/
public class GradleDependenciesContributor implements GradleMethodContextContributor {
private final static Set<String> BUILD_SCRIPT_BLOCKS = ContainerUtil.newHashSet(
"subprojects",
"allprojects",
"buildscript"
);
@Override
public void process(@NotNull List<String> methodCallInfo,
@@ -48,11 +42,6 @@ public class GradleDependenciesContributor implements GradleMethodContextContrib
String methodCall = ContainerUtil.getLastItem(methodCallInfo);
if (methodCall == null) return;
if (methodCallInfo.size() > 1 && BUILD_SCRIPT_BLOCKS.contains(methodCall)) {
methodCallInfo.remove(methodCallInfo.size() - 1);
methodCall = ContainerUtil.getLastItem(methodCallInfo);
}
if (!StringUtil.equals(methodCall, "dependencies")) return;
final GroovyPsiManager psiManager = GroovyPsiManager.getInstance(place.getProject());
@@ -155,19 +155,19 @@ public class GradleResolverUtil {
int argsCount = getGrMethodArumentsCount(args);
argsCount++; // Configuration name is delivered as an argument.
for (PsiMethod method : handlerClass.findMethodsByName(methodName, false)) {
if (method.getParameterList().getParametersCount() == argsCount) {
// handle setter's shortcut facilities
final String setter = GroovyPropertyUtils.getSetterName(methodName);
for (PsiMethod method : handlerClass.findMethodsByName(setter, false)) {
if (method.getParameterList().getParametersCount() == 1) {
builder.setNavigationElement(method);
return;
}
}
// handle setter's shortcut facilities
final String setter = GroovyPropertyUtils.getSetterName(methodName);
for (PsiMethod method : handlerClass.findMethodsByName(setter, false)) {
if (method.getParameterList().getParametersCount() == 1) {
builder.setNavigationElement(method);
return;
for (PsiMethod method : handlerClass.findMethodsByName(methodName, false)) {
if (method.getParameterList().getParametersCount() == argsCount) {
builder.setNavigationElement(method);
return;
}
}
@@ -186,10 +186,22 @@ public class GradleResolverUtil {
@NotNull ResolveState state,
@NotNull PsiElement place,
@NotNull String... fqNames) {
processDeclarations(null, psiManager, processor, state, place, fqNames);
}
public static void processDeclarations(@Nullable String methodName,
@NotNull GroovyPsiManager psiManager,
@NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
@NotNull PsiElement place,
@NotNull String... fqNames) {
for (String fqName : fqNames) {
PsiClass psiClass = psiManager.findClassWithCache(fqName, place.getResolveScope());
if (psiClass != null) {
psiClass.processDeclarations(processor, state, null, place);
if (methodName != null) {
processMethod(methodName, psiClass, processor, state, place);
}
}
}
}
@@ -68,6 +68,8 @@ public class GradleRootContributor implements GradleMethodContextContributor {
}
GroovyPsiManager psiManager = GroovyPsiManager.getInstance(place.getProject());
GradleResolverUtil.processDeclarations(psiManager, processor, state, place, GradleCommonClassNames.GRADLE_API_PROJECT);
GradleResolverUtil.processDeclarations(methodCallInfo.size() > 0 ? methodCallInfo.get(0) : null,
psiManager, processor, state, place,
GradleCommonClassNames.GRADLE_API_PROJECT);
}
}
@@ -18,6 +18,7 @@ package org.jetbrains.plugins.gradle.service.resolve;
import com.intellij.psi.*;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.ContainerUtilRt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.util.GradleConstants;
@@ -27,6 +28,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor;
import java.util.List;
import java.util.Set;
/**
* @author Denis Zhdanov
@@ -34,6 +36,15 @@ import java.util.List;
*/
public class GradleScriptContributor extends NonCodeMembersContributor {
public final static Set<String> BUILD_PROJECT_SCRIPT_BLOCKS = ContainerUtil.newHashSet(
"project",
"configure",
"subprojects",
"allprojects",
"buildscript"
);
@Override
public void processDynamicElements(@NotNull PsiType qualifierType,
PsiClass aClass,
@@ -67,6 +78,11 @@ public class GradleScriptContributor extends NonCodeMembersContributor {
}
}
final String methodCall = ContainerUtil.getLastItem(methodInfo);
if (methodInfo.size() > 1 && BUILD_PROJECT_SCRIPT_BLOCKS.contains(methodCall)) {
methodInfo.remove(methodInfo.size() - 1);
}
for (GradleMethodContextContributor contributor : GradleMethodContextContributor.EP_NAME.getExtensions()) {
contributor.process(methodInfo, processor, state, place);
}
@@ -59,13 +59,13 @@ public class GradleTaskContributor implements GradleMethodContextContributor {
processTaskAddition(methodCallInfo.get(0), GradleCommonClassNames.GRADLE_API_TASK_CONTAINER, processor, state, place);
}
else {
processTaskTypeParameter(processor, state, place);
processTaskTypeParameter(methodCallInfo.get(0), processor, state, place);
}
GradleImplicitContributor.processImplicitDeclarations(processor, state, place);
}
else if (methodCallInfo.size() >= 3) {
processTaskTypeParameter(processor, state, place);
processTaskTypeParameter(methodCallInfo.get(0), processor, state, place);
GradleImplicitContributor.processImplicitDeclarations(processor, state, place);
@@ -76,7 +76,7 @@ public class GradleTaskContributor implements GradleMethodContextContributor {
}
}
private static void processTaskTypeParameter(@NotNull PsiScopeProcessor processor,
private static void processTaskTypeParameter(@NotNull String methodCall, @NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
@NotNull PsiElement place) {
final int taskTypeParameterLevel = 3;
@@ -98,7 +98,7 @@ public class GradleTaskContributor implements GradleMethodContextContributor {
PsiImmediateClassType immediateClassType = (PsiImmediateClassType)psiType;
for (PsiType type : immediateClassType.getParameters()) {
GroovyPsiManager psiManager = GroovyPsiManager.getInstance(place.getProject());
GradleResolverUtil.processDeclarations(psiManager, processor, state, place, type.getCanonicalText());
GradleResolverUtil.processDeclarations(methodCall, psiManager, processor, state, place, type.getCanonicalText());
}
}
}
@@ -0,0 +1,277 @@
/*
* Copyright 2000-2013 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.refactoring.introduce;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.refactoring.introduce.inplace.AbstractInplaceIntroducer;
import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.GroovyFileType;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil;
import java.util.List;
/**
* Created by Max Medvedev on 10/28/13
*/
public abstract class GrAbstractInplaceIntroducer<Settings extends GrIntroduceSettings> extends AbstractInplaceIntroducer<GrVariable, PsiElement> {
private SmartTypePointer myTypePointer;
private OccurrencesChooser.ReplaceChoice myReplaceChoice;
private RangeMarker myVarMarker;
private final PsiFile myFile;
private final GrIntroduceContext myContext;
public GrAbstractInplaceIntroducer(String title,
OccurrencesChooser.ReplaceChoice replaceChoice,
GrIntroduceContext context) {
super(context.getProject(), context.getEditor(), context.getExpression(), context.getVar(), context.getOccurrences(), title, GroovyFileType.GROOVY_FILE_TYPE);
myReplaceChoice = replaceChoice;
myContext = context;
myFile = context.getPlace().getContainingFile();
}
public GrIntroduceContext getContext() {
return myContext;
}
@Override
public void setReplaceAllOccurrences(boolean allOccurrences) {
throw new IncorrectOperationException("don't invoke this method");
}
@Override
public GrExpression restoreExpression(PsiFile containingFile, GrVariable variable, RangeMarker marker, String exprText) {
if (exprText == null) return null;
if (variable == null || !variable.isValid()) return null;
final PsiElement refVariableElement = containingFile.findElementAt(marker.getStartOffset());
final PsiElement refVariableElementParent = refVariableElement != null ? refVariableElement.getParent() : null;
GrExpression expression =
refVariableElementParent instanceof GrNewExpression && refVariableElement.getNode().getElementType() == GroovyTokenTypes.kNEW
? (GrNewExpression)refVariableElementParent
: PsiTreeUtil.getParentOfType(refVariableElement, GrReferenceExpression.class);
if (expression instanceof GrReferenceExpression && !(expression.getParent() instanceof GrMethodCall)) {
final String referenceName = ((GrReferenceExpression)expression).getReferenceName();
if (((GrReferenceExpression)expression).resolve() == variable ||
Comparing.strEqual(variable.getName(), referenceName) ||
Comparing.strEqual(exprText, referenceName)) {
return (GrExpression)expression
.replace(GroovyPsiElementFactory.getInstance(myProject).createExpressionFromText(exprText, variable));
}
}
if (expression == null) {
expression = PsiTreeUtil.getParentOfType(refVariableElement, GrExpression.class);
}
while (expression instanceof GrReferenceExpression) {
final PsiElement parent = expression.getParent();
if (parent instanceof GrMethodCallExpression) {
if (parent.getText().equals(exprText)) return (GrExpression)parent;
}
if (parent instanceof GrExpression) {
expression = (GrExpression)parent;
if (expression.getText().equals(exprText)) {
return expression;
}
}
else {
return null;
}
}
if (expression != null && expression.isValid() && expression.getText().equals(exprText)) {
return expression;
}
if (refVariableElementParent instanceof GrExpression && refVariableElementParent.getText().equals(exprText)) {
return (GrExpression)refVariableElementParent;
}
return null;
}
@Override
protected void updateTitle(@Nullable GrVariable variable, String value) {
if (variable == null) {
super.updateTitle(variable, value);
}
else {
final String variableText = variable.getParent().getText();
final PsiElement identifier = variable.getNameIdentifierGroovy();
final int startOffsetInParent = identifier.getStartOffsetInParent() + variable.getStartOffsetInParent();
setPreviewText(
variableText.substring(0, startOffsetInParent) + value + variableText.substring(startOffsetInParent + identifier.getTextLength()));
revalidate();
}
}
@Override
protected void updateTitle(@Nullable GrVariable variable) {
if (variable == null) return;
setPreviewText(variable.getParent().getText());
revalidate();
}
@Nullable
@Override
protected PsiElement getNameIdentifier() {
return ((GrVariable)myElementToRename).getNameIdentifierGroovy();
}
@Override
protected GrVariable getVariable() {
if (myVarMarker == null) return null;
int offset = myVarMarker.getStartOffset();
PsiElement at = myFile.findElementAt(offset);
GrVariable var = PsiTreeUtil.getParentOfType(at, GrVariable.class);
return var;
}
@Override
protected void performIntroduce() {
final List<RangeMarker> markers = getOccurrenceMarkers();
GrIntroduceContext context = new GrIntroduceContext() {
@NotNull
@Override
public Project getProject() {
return myProject;
}
@Override
public Editor getEditor() {
return myEditor;
}
@Nullable
@Override
public GrExpression getExpression() {
return (GrExpression)getExpr();
}
@Nullable
@Override
public GrVariable getVar() {
return getLocalVariable();
}
@Nullable
@Override
public StringPartInfo getStringPart() {
return null;
}
@NotNull
@Override
public PsiElement[] getOccurrences() {
List<PsiElement> result = ContainerUtil.map(markers, new Function<RangeMarker, PsiElement>() {
@Override
public PsiElement fun(RangeMarker marker) {
return GroovyRefactoringUtil.findElementInRange(myFile, marker.getStartOffset(), marker.getEndOffset(), GrExpression.class);
}
});
return PsiUtilCore.toPsiElementArray(result);
}
@Override
public PsiElement getScope() {
return myScope;
}
@NotNull
@Override
public PsiElement getPlace() {
GrExpression expression = getExpression();
return expression != null ? expression : getLocalVariable();
}
};
runRefactoring(context, getSettings(), true);
}
@Nullable
@Override
protected GrVariable createFieldToStartTemplateOn(boolean replaceAll, String[] names) {
final Settings settings = getInitialSettingsForInplace(myContext, myReplaceChoice, names);
if (settings == null) return null;
SmartPsiElementPointer<GrVariable> pointer = ApplicationManager.getApplication().runWriteAction(new Computable<SmartPsiElementPointer<GrVariable>>() {
@Override
public SmartPsiElementPointer<GrVariable> compute() {
GrVariable var = runRefactoring(myContext, settings, false);
return var != null ? SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(var) : null;
}
});
if (pointer != null) {
GrVariable var = pointer.getElement();
if (var != null) {
myVarMarker = myContext.getEditor().getDocument().createRangeMarker(var.getTextRange());
}
return var;
}
else {
return null;
}
}
protected abstract GrVariable runRefactoring(GrIntroduceContext context, Settings settings, boolean processUsages);
@Nullable
protected abstract Settings getInitialSettingsForInplace(@NotNull GrIntroduceContext context,
@NotNull OccurrencesChooser.ReplaceChoice choice,
String[] names);
@Override
public boolean isReplaceAllOccurrences() {
return myReplaceChoice != OccurrencesChooser.ReplaceChoice.NO || myContext.getOccurrences().length == 1;
}
protected abstract Settings getSettings();
@Override
protected void restoreState(GrVariable psiField) {
PsiType declaredType = psiField.getDeclaredType();
myTypePointer = declaredType != null ? SmartTypePointerManager.getInstance(myProject).createSmartTypePointer(declaredType) : null;
super.restoreState(psiField);
}
@Nullable
protected PsiType getSelectedType() {
return myTypePointer != null ? myTypePointer.getType() : null;
}
}
@@ -32,7 +32,6 @@ import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.markup.RangeHighlighter;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Pass;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.wm.WindowManager;
@@ -77,7 +76,7 @@ import java.util.*;
import static org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.skipParentheses;
/**
* @author Maxim.Medvedev
* Created by Max Medvedev on 10/29/13
*/
public abstract class GrIntroduceHandlerBase<Settings extends GrIntroduceSettings, Scope extends PsiElement> implements RefactoringActionHandler {
private static final Logger LOG = Logger.getInstance(GrIntroduceHandlerBase.class);
@@ -144,15 +143,8 @@ public abstract class GrIntroduceHandlerBase<Settings extends GrIntroduceSetting
@Nullable
public abstract GrVariable runRefactoring(@NotNull GrIntroduceContext context, @NotNull Settings settings);
protected abstract GrInplaceIntroducer getIntroducer(@NotNull GrVariable var,
@NotNull GrIntroduceContext context,
@NotNull Settings settings,
@NotNull List<RangeMarker> occurrenceMarkers,
RangeMarker varRangeMarker,
@Nullable RangeMarker expressionRangeMarker,
@Nullable RangeMarker stringPartRangeMarker);
protected abstract Settings getSettingsForInplace(GrIntroduceContext context, OccurrencesChooser.ReplaceChoice choice);
protected abstract GrAbstractInplaceIntroducer<Settings> getIntroducer(@NotNull GrIntroduceContext context,
OccurrencesChooser.ReplaceChoice choice);
public static Map<OccurrencesChooser.ReplaceChoice, List<Object>> fillChoice(GrIntroduceContext context) {
HashMap<OccurrencesChooser.ReplaceChoice, List<Object>> map = ContainerUtil.newLinkedHashMap();
@@ -296,7 +288,8 @@ public abstract class GrIntroduceHandlerBase<Settings extends GrIntroduceSetting
};
if (scopes.length == 0) {
CommonRefactoringUtil.showErrorHint(project, editor, RefactoringBundle.getCannotRefactorMessage( getRefactoringName() + "is not available in current scope"),
CommonRefactoringUtil.showErrorHint(project, editor, RefactoringBundle
.getCannotRefactorMessage(getRefactoringName() + "is not available in current scope"),
getRefactoringName(), getHelpID());
}
else if (scopes.length == 1) {
@@ -310,11 +303,11 @@ public abstract class GrIntroduceHandlerBase<Settings extends GrIntroduceSetting
protected abstract void showScopeChooser(Scope[] scopes, Pass<Scope> callback, Editor editor);
public GrIntroduceContext getContext(@NotNull Project project,
@NotNull Editor editor,
@Nullable GrExpression expression,
@Nullable GrVariable variable,
@Nullable StringPartInfo stringPart,
@NotNull PsiElement scope) {
@NotNull Editor editor,
@Nullable GrExpression expression,
@Nullable GrVariable variable,
@Nullable StringPartInfo stringPart,
@NotNull PsiElement scope) {
if (variable != null) {
final List<PsiElement> list = Collections.synchronizedList(new ArrayList<PsiElement>());
ReferencesSearch.search(variable, new LocalSearchScope(scope)).forEach(new Processor<PsiReference>() {
@@ -348,48 +341,6 @@ public abstract class GrIntroduceHandlerBase<Settings extends GrIntroduceSetting
checkOccurrences(context.getOccurrences());
final boolean isInplace = isInplace(context.getEditor(), context.getPlace());
Pass<OccurrencesChooser.ReplaceChoice> callback = new Pass<OccurrencesChooser.ReplaceChoice>() {
@Override
public void pass(final OccurrencesChooser.ReplaceChoice choice) {
final Settings settings = isInplace ? getSettingsForInplace(context, choice) : showDialog(context);
if (settings == null) return;
CommandProcessor.getInstance().executeCommand(project, new Runnable() {
public void run() {
List<RangeMarker> occurrences = ContainerUtil.newArrayList();
Document document = editor.getDocument();
for (PsiElement element : context.getOccurrences()) {
occurrences.add(createRange(document, element));
}
RangeMarker expressionRangeMarker = createRange(document, context.getExpression());
RangeMarker stringPartRangeMarker = createRange(document, context.getStringPart());
RangeMarker varRangeMarker = createRange(document, context.getVar());
SmartPsiElementPointer<GrVariable> pointer =
ApplicationManager.getApplication().runWriteAction(new Computable<SmartPsiElementPointer<GrVariable>>() {
@Override
public SmartPsiElementPointer<GrVariable> compute() {
GrVariable var = runRefactoring(context, settings);
return var != null
? SmartPointerManager.getInstance(context.getProject()).createSmartPsiElementPointer(var)
: null;
}
});
GrVariable var = pointer != null ? pointer.getElement() : null;
if (isInplace && var != null) {
GrInplaceIntroducer introducer = getIntroducer(var, context, settings, occurrences, varRangeMarker, expressionRangeMarker, stringPartRangeMarker);
LinkedHashSet<String> suggestions = introducer.suggestNames(context);
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument());
introducer.performInplaceRefactoring(suggestions);
}
}
}, getRefactoringName(), getRefactoringName());
}
};
if (isInplace(context.getEditor(), context.getPlace())) {
Map<OccurrencesChooser.ReplaceChoice, List<Object>> occurrencesMap = fillChoice(context);
new OccurrencesChooser<Object>(editor) {
@@ -405,17 +356,34 @@ public abstract class GrIntroduceHandlerBase<Settings extends GrIntroduceSetting
return null;
}
}
}.showChooser(callback, occurrencesMap);
}.showChooser(new Pass<OccurrencesChooser.ReplaceChoice>() {
@Override
public void pass(final OccurrencesChooser.ReplaceChoice choice) {
getIntroducer(context, choice).startInplaceIntroduceTemplate();
}
}, occurrencesMap);
}
else {
callback.pass(null);
final Settings settings = showDialog(context);
if (settings == null) return false;
CommandProcessor.getInstance().executeCommand(context.getProject(), new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
runRefactoring(context, settings);
}
});
}
}, getRefactoringName(), null);
}
return true;
}
catch (GrRefactoringError e) {
CommonRefactoringUtil
.showErrorHint(project, editor, RefactoringBundle.getCannotRefactorMessage(e.getMessage()), getRefactoringName(), getHelpID());
CommonRefactoringUtil.showErrorHint(project, editor, RefactoringBundle.getCannotRefactorMessage(e.getMessage()), getRefactoringName(), getHelpID());
return false;
}
}
@@ -15,127 +15,118 @@
*/
package org.jetbrains.plugins.groovy.refactoring.introduce.constant;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
import com.intellij.refactoring.introduceField.IntroduceConstantHandler;
import com.intellij.ui.components.JBCheckBox;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrBinaryExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.refactoring.GroovyNameSuggestionUtil;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrInplaceIntroducer;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrAbstractInplaceIntroducer;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceContext;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceContextImpl;
import org.jetbrains.plugins.groovy.refactoring.introduce.StringPartInfo;
import org.jetbrains.plugins.groovy.refactoring.introduce.field.GroovyInplaceFieldValidator;
import javax.swing.*;
import java.util.LinkedHashSet;
import java.util.List;
/**
* Created by Max Medvedev on 8/29/13
*/
public class GrInplaceConstantIntroducer extends GrInplaceIntroducer {
public class GrInplaceConstantIntroducer extends GrAbstractInplaceIntroducer<GrIntroduceConstantSettings> {
private final GrInplaceIntroduceConstantPanel myPanel;
private final GrIntroduceContext myContext;
private final RangeMarker myExpressionRangeMarker;
private final RangeMarker myStringPartRangeMarker;
private final boolean myReplaceAll;
private String[] mySuggestedNames;
public GrInplaceConstantIntroducer(GrVariable var,
GrIntroduceContext context,
List<RangeMarker> occurrences,
boolean replaceAllOccurrences,
RangeMarker expressionRangeMarker,
RangeMarker stringPartRangeMarker) {
super(var, context.getEditor(), context.getProject(), GrIntroduceConstantHandler.REFACTORING_NAME, occurrences, context.getPlace());
public GrInplaceConstantIntroducer(GrIntroduceContext context, OccurrencesChooser.ReplaceChoice choice) {
super(IntroduceConstantHandler.REFACTORING_NAME, choice, context);
myContext = context;
myReplaceAll = replaceAllOccurrences;
myExpressionRangeMarker = expressionRangeMarker;
myStringPartRangeMarker = stringPartRangeMarker;
myPanel = new GrInplaceIntroduceConstantPanel();
mySuggestedNames = GroovyNameSuggestionUtil.suggestVariableNames(context.getExpression(), new GroovyInplaceFieldValidator(context),
true);
}
@Override
public LinkedHashSet<String> suggestNames(GrIntroduceContext context) {
return ContainerUtil.newLinkedHashSet(GroovyNameSuggestionUtil.suggestVariableNames(
context.getExpression(),
new GroovyInplaceFieldValidator(context),
getVariable().hasModifierProperty(PsiModifier.STATIC))
);
protected String getActionName() {
return null;
}
@Override
protected void moveOffsetAfter(boolean success) {
if (success) {
final GrVariable field = getVariable();
assert field != null;
GrIntroduceConstantProcessor processor = new GrIntroduceConstantProcessor(generateContext(), generateSettings()) {
@Override
protected GrVariableDeclaration addDeclaration(PsiClass targetClass, GrVariableDeclaration declaration) {
return (GrVariableDeclaration)field.getParent();
}
@Override
protected boolean checkErrors(@NotNull PsiClass targetClass) {
return false;
}
};
processor.run();
}
super.moveOffsetAfter(success);
}
private GrIntroduceContext generateContext() {
final List<RangeMarker> occurrenceMarkers = getOccurrenceMarkers();
List<PsiElement> occurrences = ContainerUtil.newArrayList();
for (RangeMarker marker : occurrenceMarkers) {
ContainerUtil.addIfNotNull(occurrences, findExpression(marker));
}
GrExpression expr = null;
if (myExpressionRangeMarker != null) expr = findExpression(myExpressionRangeMarker);
if (myStringPartRangeMarker != null) {
expr = findExpressionFromStringPartMarker(myStringPartRangeMarker);
occurrences.add(expr);
}
return new GrIntroduceContextImpl(myContext.getProject(), myContext.getEditor(), expr, null, null, PsiUtilCore.toPsiElementArray(
occurrences), myContext.getScope());
protected String[] suggestNames(boolean replaceAll, @Nullable GrVariable variable) {
return mySuggestedNames;
}
@Nullable
private GrExpression findExpressionFromStringPartMarker(RangeMarker marker) {
PsiFile file = PsiDocumentManager.getInstance(myContext.getProject()).getPsiFile(marker.getDocument());
if (file == null) return null;
PsiElement leaf = file.findElementAt(marker.getStartOffset());
GrBinaryExpression binary = PsiTreeUtil.getParentOfType(leaf, GrBinaryExpression.class);
if (binary != null) {
return binary.getRightOperand();
@Override
protected JComponent getComponent() {
return myPanel.getRootPane();
}
@Override
protected void saveSettings(@NotNull GrVariable variable) {
}
@Override
protected GrVariable runRefactoring(GrIntroduceContext context, GrIntroduceConstantSettings settings, boolean processUsages) {
if (processUsages) {
return new GrIntroduceConstantProcessor(context, settings).run();
}
else {
PsiElement scope = context.getScope();
return new GrIntroduceConstantProcessor(context, settings).addDeclaration(scope instanceof GroovyFileBase ? ((GroovyFileBase)scope).getScriptClass() : (PsiClass)scope).getVariables()[0];
}
return null;
}
@Nullable
private GrExpression findExpression(@NotNull RangeMarker marker) {
PsiFile file = PsiDocumentManager.getInstance(myContext.getProject()).getPsiFile(marker.getDocument());
if (file == null) return null;
PsiElement leaf = file.findElementAt(marker.getStartOffset());
if (leaf != null && leaf.getParent() instanceof GrReferenceExpression) {
return (GrExpression)leaf.getParent();
}
return null;
@Override
protected GrIntroduceConstantSettings getInitialSettingsForInplace(@NotNull final GrIntroduceContext context,
@NotNull final OccurrencesChooser.ReplaceChoice choice,
final String[] names) {
return new GrIntroduceConstantSettings() {
@Override
public String getVisibilityModifier() {
return PsiModifier.PUBLIC;
}
@Nullable
@Override
public PsiClass getTargetClass() {
return (PsiClass)context.getScope();
}
@Nullable
@Override
public String getName() {
return names[0];
}
@Override
public boolean replaceAllOccurrences() {
return isReplaceAllOccurrences();
}
@Nullable
@Override
public PsiType getSelectedType() {
GrExpression expression = context.getExpression();
GrVariable var = context.getVar();
StringPartInfo stringPart = context.getStringPart();
return var != null ? var.getDeclaredType() :
expression != null ? expression.getType() :
stringPart != null ? stringPart.getLiteral().getType() :
null;
}
};
}
private GrIntroduceConstantSettings generateSettings() {
@Override
protected GrIntroduceConstantSettings getSettings() {
return new GrIntroduceConstantSettings() {
@Override
public String getVisibilityModifier() {
@@ -145,18 +136,18 @@ public class GrInplaceConstantIntroducer extends GrInplaceIntroducer {
@Nullable
@Override
public String getName() {
return getVariable().getName();
return getInputName();
}
@Override
public boolean replaceAllOccurrences() {
return myReplaceAll;
return isReplaceAllOccurrences();
}
@Nullable
@Override
public PsiType getSelectedType() {
return getVariable().getDeclaredType();
return GrInplaceConstantIntroducer.this.getSelectedType();
}
@Nullable
@@ -167,17 +158,30 @@ public class GrInplaceConstantIntroducer extends GrInplaceIntroducer {
};
}
@Nullable
@Override
protected JComponent getComponent() {
//return myPanel.getRootPane();
return null;
}
@Nullable
@Override
protected PsiElement checkLocalScope() {
return getVariable().getContainingFile();
return ((PsiField)getVariable()).getContainingClass();
}
/**
* Created by Max Medvedev on 8/29/13
*/
public class GrInplaceIntroduceConstantPanel {
private JBCheckBox myMoveToAnotherClassJBCheckBox;
private JPanel myRootPane;
private JComponent myPreview;
public boolean isMoveToAnotherClass() {
return myMoveToAnotherClassJBCheckBox.isSelected();
}
public JComponent getRootPane() {
return myRootPane;
}
private void createUIComponents() {
myPreview = getPreviewComponent();
}
}
}
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.plugins.groovy.refactoring.introduce.constant.GrInplaceIntroduceConstantPanel">
<grid id="27dc6" binding="myRootPane" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.plugins.groovy.refactoring.introduce.constant.GrInplaceConstantIntroducer.GrInplaceIntroduceConstantPanel">
<grid id="27dc6" binding="myRootPane" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="500" height="400"/>
@@ -10,17 +10,24 @@
<children>
<vspacer id="3c553">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
<component id="1ff44" class="com.intellij.ui.components.JBCheckBox" binding="myMoveToAnotherClassJBCheckBox" default-binding="true">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<focusable value="false"/>
<requestFocusEnabled value="true"/>
<text value="&amp;Move to another class"/>
</properties>
</component>
<component id="3e5fd" class="javax.swing.JComponent" binding="myPreview" custom-create="true">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
</component>
</children>
</grid>
</form>
@@ -15,7 +15,6 @@
*/
package org.jetbrains.plugins.groovy.refactoring.introduce.constant;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.HelpID;
@@ -27,16 +26,11 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrBinaryExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.refactoring.GrRefactoringError;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle;
import org.jetbrains.plugins.groovy.refactoring.introduce.*;
import org.jetbrains.plugins.groovy.refactoring.introduce.field.GrFieldNameSuggester;
import org.jetbrains.plugins.groovy.refactoring.introduce.field.GroovyInplaceFieldValidator;
import java.util.List;
/**
* @author Maxim.Medvedev
@@ -99,65 +93,9 @@ public class GrIntroduceConstantHandler extends GrIntroduceFieldHandlerBase<GrIn
}
@Override
protected GrInplaceIntroducer getIntroducer(@NotNull final GrVariable var,
@NotNull GrIntroduceContext context,
@NotNull GrIntroduceConstantSettings settings,
@NotNull List<RangeMarker> occurrenceMarkers,
RangeMarker varRangeMarker, RangeMarker expressionRangeMarker,
RangeMarker stringPartRangeMarker) {
if (varRangeMarker != null) {
context.getEditor().getCaretModel().moveToOffset(var.getNameIdentifierGroovy().getTextRange().getStartOffset());
}
else if (expressionRangeMarker != null) {
context.getEditor().getCaretModel().moveToOffset(expressionRangeMarker.getStartOffset());
}
else if (stringPartRangeMarker != null) {
int offset = stringPartRangeMarker.getStartOffset();
PsiElement at = var.getContainingFile().findElementAt(offset);
GrExpression ref = PsiTreeUtil.getParentOfType(at, GrBinaryExpression.class).getRightOperand();
context.getEditor().getCaretModel().moveToOffset(ref.getTextRange().getStartOffset());
}
return new GrInplaceConstantIntroducer(var, context, occurrenceMarkers, settings.replaceAllOccurrences(), expressionRangeMarker, stringPartRangeMarker);
}
@Override
protected GrIntroduceConstantSettings getSettingsForInplace(final GrIntroduceContext context, final OccurrencesChooser.ReplaceChoice choice) {
return new GrIntroduceConstantSettings() {
@Override
public String getVisibilityModifier() {
return PsiModifier.PUBLIC;
}
@Nullable
@Override
public PsiClass getTargetClass() {
return (PsiClass)context.getScope();
}
@Nullable
@Override
public String getName() {
return new GrFieldNameSuggester(context, new GroovyInplaceFieldValidator(context), false).suggestNames().iterator().next();
}
@Override
public boolean replaceAllOccurrences() {
return choice == OccurrencesChooser.ReplaceChoice.ALL;
}
@Nullable
@Override
public PsiType getSelectedType() {
GrExpression expression = context.getExpression();
GrVariable var = context.getVar();
StringPartInfo stringPart = context.getStringPart();
return var != null ? var.getDeclaredType() :
expression != null ? expression.getType() :
stringPart != null ? stringPart.getLiteral().getType() :
null;
}
};
protected GrAbstractInplaceIntroducer<GrIntroduceConstantSettings> getIntroducer(@NotNull GrIntroduceContext context,
OccurrencesChooser.ReplaceChoice choice) {
return new GrInplaceConstantIntroducer(context, choice);
}
private static class ConstantChecker extends GroovyRecursiveElementVisitor {
@@ -69,8 +69,7 @@ public class GrIntroduceConstantProcessor {
return null;
}
final GrVariableDeclaration rawDeclaration = createField(targetClass);
final GrVariableDeclaration declaration = addDeclaration(targetClass, rawDeclaration);
final GrVariableDeclaration declaration = addDeclaration(targetClass);
final GrField field = (GrField)declaration.getVariables()[0];
if (context.getVar() != null) {
@@ -102,7 +101,8 @@ public class GrIntroduceConstantProcessor {
context.getEditor().getSelectionModel().removeSelection();
}
protected GrVariableDeclaration addDeclaration(PsiClass targetClass, GrVariableDeclaration declaration) {
protected GrVariableDeclaration addDeclaration(PsiClass targetClass) {
GrVariableDeclaration declaration = createField(targetClass);
final GrVariableDeclaration added;
if (targetClass instanceof GrEnumTypeDefinition) {
final GrEnumConstantList enumConstants = ((GrEnumTypeDefinition)targetClass).getEnumConstantList();
@@ -17,140 +17,133 @@ package org.jetbrains.plugins.groovy.refactoring.introduce.field;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.refactoring.introduce.inplace.KeyboardComboSwitcher;
import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
import com.intellij.refactoring.introduceField.IntroduceFieldHandler;
import com.intellij.ui.NonFocusableCheckBox;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrBinaryExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.refactoring.GroovyNameSuggestionUtil;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrAbstractInplaceIntroducer;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrFinalListener;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrInplaceIntroducer;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceContext;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceContextImpl;
import org.jetbrains.plugins.groovy.refactoring.introduce.StringPartInfo;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.EnumSet;
import java.util.LinkedHashSet;
import java.util.List;
/**
* @author Max Medvedev
*/
public class GrInplaceFieldIntroducer extends GrInplaceIntroducer {
private final GrInplaceIntroduceFieldPanel myPanel;
private final GrIntroduceContext myContext;
private final RangeMarker myExpressionRangeMarker;
private final RangeMarker myStringPartRangeMarker;
private final GrExpression myInitializer;
public class GrInplaceFieldIntroducer extends GrAbstractInplaceIntroducer<GrIntroduceFieldSettings> {
private GrInplaceIntroduceFieldPanel myPanel;
private final GrFinalListener finalListener;
private final boolean myReplaceAll;
private String[] mySuggestedNames;
private boolean myIsStatic;
@Nullable
@Override
protected PsiElement checkLocalScope() {
return getVariable().getContainingFile();
return ((PsiField)getVariable()).getContainingClass();
}
public GrInplaceFieldIntroducer(GrVariable var,
GrIntroduceContext context,
List<RangeMarker> occurrences,
boolean replaceAll,
@Nullable RangeMarker expressionRangeMarker,
@Nullable RangeMarker stringPartRangeMarker,
GrExpression initializer) {
super(var, context.getEditor(), context.getProject(), IntroduceFieldHandler.REFACTORING_NAME, occurrences, context.getPlace());
myContext = context;
myReplaceAll = replaceAll;
myExpressionRangeMarker = expressionRangeMarker;
myStringPartRangeMarker = stringPartRangeMarker;
myInitializer = initializer;
myPanel = new GrInplaceIntroduceFieldPanel(context.getProject(),
GrIntroduceFieldHandler.getApplicableInitPlaces(context, replaceAll));
public GrInplaceFieldIntroducer(GrIntroduceContext context, OccurrencesChooser.ReplaceChoice choice) {
super(IntroduceFieldHandler.REFACTORING_NAME, choice, context);
finalListener = new GrFinalListener(myEditor);
mySuggestedNames = GroovyNameSuggestionUtil.suggestVariableNames(context.getExpression(), new GroovyInplaceFieldValidator(getContext()), false);
}
@Override
protected void moveOffsetAfter(boolean success) {
if (success) {
final GrVariable field = getVariable();
assert field != null;
GrIntroduceFieldProcessor processor = new GrIntroduceFieldProcessor(generateContext(), generateSettings(), false) {
@NotNull
@Override
protected GrExpression getInitializer() {
return myInitializer;
}
@NotNull
@Override
protected GrVariableDeclaration insertField(@NotNull PsiClass targetClass, @NotNull GrVariableDeclaration declaration) {
return (GrVariableDeclaration)field.getParent();
}
};
processor.run();
}
super.moveOffsetAfter(success);
}
private GrIntroduceContext generateContext() {
final List<RangeMarker> occurrenceMarkers = getOccurrenceMarkers();
List<PsiElement> occurrences = ContainerUtil.newArrayList();
for (RangeMarker marker : occurrenceMarkers) {
ContainerUtil.addIfNotNull(occurrences, findExpression(marker));
}
GrExpression expr = null;
if (myExpressionRangeMarker != null) expr = findExpression(myExpressionRangeMarker);
if (myStringPartRangeMarker != null) {
expr = findExpressionFromStringPartMarker(myStringPartRangeMarker);
occurrences.add(expr);
}
return new GrIntroduceContextImpl(myContext.getProject(), myContext.getEditor(), expr, null, null, PsiUtilCore.toPsiElementArray(
occurrences), myContext.getScope());
protected GrVariable runRefactoring(GrIntroduceContext context, GrIntroduceFieldSettings settings, boolean processUsages) {
GrIntroduceFieldProcessor processor = new GrIntroduceFieldProcessor(context, settings);
return processUsages ? processor.run()
: processor.insertField((PsiClass)context.getScope()).getVariables()[0];
}
@Nullable
private GrExpression findExpressionFromStringPartMarker(RangeMarker marker) {
PsiFile file = PsiDocumentManager.getInstance(myContext.getProject()).getPsiFile(marker.getDocument());
if (file == null) return null;
PsiElement leaf = file.findElementAt(marker.getStartOffset());
GrBinaryExpression binary = PsiTreeUtil.getParentOfType(leaf, GrBinaryExpression.class);
if (binary != null) {
return binary.getRightOperand();
}
return null;
@Override
protected GrIntroduceFieldSettings getInitialSettingsForInplace(@NotNull final GrIntroduceContext context,
@NotNull final OccurrencesChooser.ReplaceChoice choice,
final String[] names) {
return new GrIntroduceFieldSettings() {
@Override
public boolean declareFinal() {
return false;
}
@Override
public Init initializeIn() {
return Init.FIELD_DECLARATION;
}
@Override
public String getVisibilityModifier() {
return PsiModifier.PRIVATE;
}
@Override
public boolean isStatic() {
boolean hasInstanceInScope = true;
PsiClass clazz = (PsiClass)context.getScope();
if (replaceAllOccurrences()) {
for (PsiElement occurrence : context.getOccurrences()) {
if (!PsiUtil.hasEnclosingInstanceInScope(clazz, occurrence, false)) {
hasInstanceInScope = false;
break;
}
}
}
else if (context.getExpression() != null) {
hasInstanceInScope = PsiUtil.hasEnclosingInstanceInScope(clazz, context.getExpression(), false);
}
else if (context.getStringPart() != null) {
hasInstanceInScope = PsiUtil.hasEnclosingInstanceInScope(clazz, context.getStringPart().getLiteral(), false);
}
return !hasInstanceInScope;
}
@Override
public boolean removeLocalVar() {
return context.getVar() != null;
}
@Nullable
@Override
public String getName() {
return names[0];
}
@Override
public boolean replaceAllOccurrences() {
return context.getVar() != null || choice == OccurrencesChooser.ReplaceChoice.ALL;
}
@Nullable
@Override
public PsiType getSelectedType() {
GrExpression expression = context.getExpression();
GrVariable var = context.getVar();
StringPartInfo stringPart = context.getStringPart();
return var != null ? var.getDeclaredType() :
expression != null ? expression.getType() :
stringPart != null ? stringPart.getLiteral().getType() :
null;
}
};
}
@Nullable
private GrExpression findExpression(@NotNull RangeMarker marker) {
PsiFile file = PsiDocumentManager.getInstance(myContext.getProject()).getPsiFile(marker.getDocument());
if (file == null) return null;
PsiElement leaf = file.findElementAt(marker.getStartOffset());
if (leaf != null && leaf.getParent() instanceof GrReferenceExpression) {
return (GrExpression)leaf.getParent();
}
return null;
}
private GrIntroduceFieldSettings generateSettings() {
@Override
protected GrIntroduceFieldSettings getSettings() {
return new GrIntroduceFieldSettings() {
@Override
public boolean declareFinal() {
@@ -169,7 +162,7 @@ public class GrInplaceFieldIntroducer extends GrInplaceIntroducer {
@Override
public boolean isStatic() {
return getVariable().hasModifierProperty(PsiModifier.STATIC);
return myIsStatic;
}
@Override
@@ -180,39 +173,57 @@ public class GrInplaceFieldIntroducer extends GrInplaceIntroducer {
@Nullable
@Override
public String getName() {
return getVariable().getName();
return getInputName();
}
@Override
public boolean replaceAllOccurrences() {
return myReplaceAll;
return isReplaceAllOccurrences();
}
@Nullable
@Override
public PsiType getSelectedType() {
return getVariable().getDeclaredType();
return GrInplaceFieldIntroducer.this.getSelectedType();
}
};
}
@Override
protected String getActionName() {
return IntroduceFieldHandler.REFACTORING_NAME;
}
@Override
protected String[] suggestNames(boolean replaceAll, @Nullable GrVariable variable) {
return mySuggestedNames;
}
@Override
protected void saveSettings(@NotNull GrVariable variable) {
}
@Override
protected void restoreState(GrVariable psiField) {
myIsStatic = psiField.hasModifierProperty(PsiModifier.STATIC);
super.restoreState(psiField);
}
@Nullable
@Override
protected JComponent getComponent() {
myPanel = new GrInplaceIntroduceFieldPanel(myProject, GrIntroduceFieldHandler.getApplicableInitPlaces(getContext(), isReplaceAllOccurrences()));
return myPanel.getRootPane();
}
@Override
public LinkedHashSet<String> suggestNames(GrIntroduceContext context) {
return ContainerUtil.newLinkedHashSet(
GroovyNameSuggestionUtil.suggestVariableNames(myInitializer, new GroovyInplaceFieldValidator(context), false));
}
public class GrInplaceIntroduceFieldPanel {
private final Project myProject;
private JPanel myRootPane;
private JComboBox myInitCB;
private NonFocusableCheckBox myDeclareFinalCB;
private JComponent myPreview;
public GrInplaceIntroduceFieldPanel(Project project, EnumSet<GrIntroduceFieldSettings.Init> initPlaces) {
myProject = project;
@@ -251,5 +262,9 @@ public class GrInplaceFieldIntroducer extends GrInplaceIntroducer {
public boolean isFinal() {
return myDeclareFinalCB.isSelected();
}
private void createUIComponents() {
myPreview = getPreviewComponent();
}
}
}
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.plugins.groovy.refactoring.introduce.field.GrInplaceFieldIntroducer.GrInplaceIntroduceFieldPanel">
<grid id="27dc6" binding="myRootPane" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="27dc6" binding="myRootPane" layout-manager="GridLayoutManager" row-count="3" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="540" height="63"/>
<xy x="20" y="20" width="540" height="88"/>
</constraints>
<properties/>
<border type="none"/>
@@ -11,7 +11,7 @@
<grid id="3dec1" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="0" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<grid row="1" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
@@ -35,13 +35,18 @@
</grid>
<component id="23db" class="com.intellij.ui.NonFocusableCheckBox" binding="myDeclareFinalCB">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<horizontalAlignment value="10"/>
<text value="Declare &amp;final"/>
</properties>
</component>
<component id="d8bd5" class="javax.swing.JComponent" binding="myPreview" custom-create="true">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
</component>
</children>
</grid>
</form>
@@ -16,25 +16,21 @@
package org.jetbrains.plugins.groovy.refactoring.introduce.field;
import com.intellij.codeInsight.TestFrameworks;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiModifier;
import com.intellij.psi.PsiType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.HelpID;
import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
import com.intellij.refactoring.introduceField.IntroduceFieldHandler;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrBinaryExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.refactoring.GrRefactoringError;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle;
@@ -100,133 +96,39 @@ public class GrIntroduceFieldHandler extends GrIntroduceFieldHandlerBase<GrIntro
@Override
public GrVariable runRefactoring(@NotNull GrIntroduceContext context, @NotNull GrIntroduceFieldSettings settings) {
return new GrIntroduceFieldProcessor(context, settings, isInplace(context.getEditor(), context.getPlace())).run();
return new GrIntroduceFieldProcessor(context, settings).run();
}
@Override
protected GrInplaceFieldIntroducer getIntroducer(@NotNull final GrVariable var,
@NotNull GrIntroduceContext context,
@NotNull GrIntroduceFieldSettings settings,
@NotNull List<RangeMarker> occurrenceMarkers,
@Nullable RangeMarker varRangeMarker,
@Nullable RangeMarker expressionRangeMarker,
@Nullable RangeMarker stringPartRangeMarker) {
if (varRangeMarker != null) {
context.getEditor().getCaretModel().moveToOffset(var.getNameIdentifierGroovy().getTextRange().getStartOffset());
}
else if (expressionRangeMarker != null) {
context.getEditor().getCaretModel().moveToOffset(expressionRangeMarker.getStartOffset());
}
else if (stringPartRangeMarker != null) {
int offset = stringPartRangeMarker.getStartOffset();
PsiElement at = var.getContainingFile().findElementAt(offset);
GrExpression ref = PsiTreeUtil.getParentOfType(at, GrBinaryExpression.class).getRightOperand();
context.getEditor().getCaretModel().moveToOffset(ref.getTextRange().getStartOffset());
}
GrExpression initializer =
GroovyPsiElementFactory.getInstance(context.getProject()).createExpressionFromText(var.getInitializerGroovy().getText());
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
var.setInitializerGroovy(null);
}
});
return new GrInplaceFieldIntroducer(var, context, occurrenceMarkers, settings.replaceAllOccurrences(), expressionRangeMarker,
stringPartRangeMarker, initializer);
@Override
protected GrAbstractInplaceIntroducer<GrIntroduceFieldSettings> getIntroducer(@NotNull GrIntroduceContext context,
OccurrencesChooser.ReplaceChoice choice) {
return new GrInplaceFieldIntroducer(context, choice);
}
static EnumSet<GrIntroduceFieldSettings.Init> getApplicableInitPlaces(GrIntroduceContext context, boolean replaceAll) {
EnumSet<GrIntroduceFieldSettings.Init> result = EnumSet.of(GrIntroduceFieldSettings.Init.FIELD_DECLARATION,
GrIntroduceFieldSettings.Init.CONSTRUCTOR);
EnumSet<GrIntroduceFieldSettings.Init> result = EnumSet.of(GrIntroduceFieldSettings.Init.FIELD_DECLARATION);
if (!(context.getScope() instanceof GroovyScriptClass || context.getScope() instanceof GroovyFileBase)) {
result.add(GrIntroduceFieldSettings.Init.CONSTRUCTOR);
}
GrTypeDefinition clazz = (GrTypeDefinition)context.getScope();
PsiElement scope = context.getScope();
if (replaceAll) {
PsiElement anchor = GrIntroduceHandlerBase.findAnchor(context.getOccurrences(), clazz);
PsiElement anchor = GrIntroduceHandlerBase.findAnchor(context.getOccurrences(), scope);
if (anchor != null) {
result.add(GrIntroduceFieldSettings.Init.CUR_METHOD);
}
}
if (TestFrameworks.getInstance().isTestClass(clazz)) {
if (scope instanceof GrTypeDefinition && TestFrameworks.getInstance().isTestClass((PsiClass)scope)) {
result.add(GrIntroduceFieldSettings.Init.SETUP_METHOD);
}
return result;
}
@Override
protected GrIntroduceFieldSettings getSettingsForInplace(final GrIntroduceContext context, final OccurrencesChooser.ReplaceChoice choice) {
return new GrIntroduceFieldSettings() {
@Override
public boolean declareFinal() {
return false;
}
@Override
public Init initializeIn() {
return Init.FIELD_DECLARATION;
}
@Override
public String getVisibilityModifier() {
return PsiModifier.PRIVATE;
}
@Override
public boolean isStatic() {
boolean hasInstanceInScope = true;
PsiClass clazz = (PsiClass)context.getScope();
if (replaceAllOccurrences()) {
for (PsiElement occurrence : context.getOccurrences()) {
if (!PsiUtil.hasEnclosingInstanceInScope(clazz, occurrence, false)) {
hasInstanceInScope = false;
break;
}
}
}
else if (context.getExpression() != null) {
hasInstanceInScope = PsiUtil.hasEnclosingInstanceInScope(clazz, context.getExpression(), false);
}
else if (context.getStringPart() != null) {
hasInstanceInScope = PsiUtil.hasEnclosingInstanceInScope(clazz, context.getStringPart().getLiteral(), false);
}
return !hasInstanceInScope;
}
@Override
public boolean removeLocalVar() {
return context.getVar() != null;
}
@Nullable
@Override
public String getName() {
return new GrFieldNameSuggester(context, new GroovyInplaceFieldValidator(context), false).suggestNames().iterator().next();
}
@Override
public boolean replaceAllOccurrences() {
return context.getVar() != null || choice == OccurrencesChooser.ReplaceChoice.ALL;
}
@Nullable
@Override
public PsiType getSelectedType() {
GrExpression expression = context.getExpression();
GrVariable var = context.getVar();
StringPartInfo stringPart = context.getStringPart();
return var != null ? var.getDeclaredType() :
expression != null ? expression.getType() :
stringPart != null ? stringPart.getLiteral().getType() :
null;
}
};
}
@NotNull
@Override
protected PsiElement[] findOccurrences(@NotNull GrExpression expression, @NotNull PsiElement scope) {
@@ -25,8 +25,10 @@ import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.codeStyle.GrReferenceAdjuster;
import org.jetbrains.plugins.groovy.lang.psi.GrQualifiedReference;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifier;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.*;
@@ -62,19 +64,19 @@ public class GrIntroduceFieldProcessor {
private final GrIntroduceContext context;
private final GrIntroduceFieldSettings settings;
private boolean myForInplacePrepare;
public GrIntroduceFieldProcessor(@NotNull GrIntroduceContext context, @NotNull GrIntroduceFieldSettings settings, boolean forInplacePrepare) {
public GrIntroduceFieldProcessor(@NotNull GrIntroduceContext context,
@NotNull GrIntroduceFieldSettings settings) {
this.context = context;
this.settings = settings;
myForInplacePrepare = forInplacePrepare;
}
public GrVariable run() {
final PsiClass targetClass = (PsiClass)context.getScope();
PsiElement scope = context.getScope();
final PsiClass targetClass = scope instanceof GroovyFileBase ? ((GroovyFileBase)scope).getScriptClass() : (PsiClass)scope;
if (targetClass == null) return null;
final GrVariableDeclaration declaration = insertField(targetClass, createField());
final GrVariableDeclaration declaration = insertField(targetClass);
final GrVariable field = declaration.getVariables()[0];
switch (settings.initializeIn()) {
@@ -119,7 +121,7 @@ public class GrIntroduceFieldProcessor {
else {
final GrExpression expression = context.getExpression();
assert expression != null;
if (!myForInplacePrepare && PsiUtil.isExpressionStatement(expression)) {
if (PsiUtil.isExpressionStatement(expression)) {
expression.delete();
}
else {
@@ -135,7 +137,8 @@ public class GrIntroduceFieldProcessor {
}
@NotNull
protected GrVariableDeclaration insertField(@NotNull PsiClass targetClass, @NotNull GrVariableDeclaration declaration) {
protected GrVariableDeclaration insertField(@NotNull PsiClass targetClass) {
GrVariableDeclaration declaration = createField(targetClass);
if (targetClass instanceof GrEnumTypeDefinition) {
final GrEnumConstantList enumConstants = ((GrEnumTypeDefinition)targetClass).getEnumConstantList();
return (GrVariableDeclaration)targetClass.addAfter(declaration, enumConstants);
@@ -304,7 +307,7 @@ public class GrIntroduceFieldProcessor {
}
if (replaced instanceof GrQualifiedReference<?>) {
org.jetbrains.plugins.groovy.codeStyle.GrReferenceAdjuster.shortenReference((GrQualifiedReference<?>)replaced);
GrReferenceAdjuster.shortenReference((GrQualifiedReference<?>)replaced);
}
if (isOriginal) {
updateCaretPosition(replaced);
@@ -326,13 +329,13 @@ public class GrIntroduceFieldProcessor {
return GroovyPsiElementFactory.getInstance(place.getProject()).createReferenceExpressionFromText(refText, place);
}
private GrVariableDeclaration createField() {
private GrVariableDeclaration createField(PsiClass targetClass) {
final String name = settings.getName();
final PsiType type = settings.getSelectedType();
final String modifier = settings.getVisibilityModifier();
List<String> modifiers = new ArrayList<String>();
if (context.getScope() instanceof GroovyScriptClass) {
if (targetClass instanceof GroovyScriptClass) {
modifiers.add("@" + GroovyCommonClassNames.GROOVY_TRANSFORM_FIELD);
}
if (settings.isStatic()) modifiers.add(PsiModifier.STATIC);
@@ -341,7 +344,7 @@ public class GrIntroduceFieldProcessor {
final String[] arr_modifiers = ArrayUtil.toStringArray(modifiers);
final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(context.getProject());
if (context.getScope() instanceof GroovyScriptClass) {
if (targetClass instanceof GroovyScriptClass) {
return factory.createVariableDeclaration(arr_modifiers, ((GrExpression)null), type, name);
}
else {
@@ -16,25 +16,31 @@
package org.jetbrains.plugins.groovy.refactoring.introduce.variable;
import com.intellij.codeInsight.template.TemplateBuilderImpl;
import com.intellij.openapi.actionSystem.Shortcut;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.keymap.Keymap;
import com.intellij.openapi.keymap.KeymapManager;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiType;
import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
import com.intellij.refactoring.util.CanonicalTypes;
import com.intellij.ui.NonFocusableCheckBox;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifier;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.SupertypeConstraint;
import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.TypeConstraint;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.refactoring.GroovyNameSuggestionUtil;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrAbstractInplaceIntroducer;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrFinalListener;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrInplaceIntroducer;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceContext;
import org.jetbrains.plugins.groovy.refactoring.introduce.StringPartInfo;
import org.jetbrains.plugins.groovy.settings.GroovyApplicationSettings;
import org.jetbrains.plugins.groovy.template.expressions.ChooseTypeExpression;
@@ -42,30 +48,40 @@ import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedHashSet;
import java.util.List;
/**
* @author Max Medvedev
* Created by Max Medvedev on 10/29/13
*/
public class GrInplaceVariableIntroducer extends GrInplaceIntroducer {
public abstract class GrInplaceVariableIntroducer extends GrAbstractInplaceIntroducer<GroovyIntroduceVariableSettings> {
private JCheckBox myCanBeFinalCb;
public GrInplaceVariableIntroducer(GrVariable elementToRename,
Editor editor,
Project project,
String title,
List<RangeMarker> occurrences,
@Nullable PsiElement elementToIntroduce) {
super(elementToRename, editor, project, title, occurrences, elementToIntroduce);
}
@Override
public LinkedHashSet<String> suggestNames(GrIntroduceContext context) {
return ContainerUtil.newLinkedHashSet(GroovyNameSuggestionUtil.suggestVariableNames(getVariable().getInitializerGroovy(), new GroovyVariableValidator(context)));
public GrInplaceVariableIntroducer(String title,
OccurrencesChooser.ReplaceChoice replaceChoice,
GrIntroduceContext context) {
super(title, replaceChoice, context);
setAdvertisementText(getAdvertisementText());
}
@Nullable
private static String getAdvertisementText() {
final Keymap keymap = KeymapManager.getInstance().getActiveKeymap();
final Shortcut[] shortcuts = keymap.getShortcuts("PreviousTemplateVariable");
if (shortcuts.length > 0) {
return "Press " + KeymapUtil.getShortcutText(shortcuts[0]) + " to change type";
}
return null;
}
@Override
protected String getActionName() {
return GrIntroduceVariableHandler.REFACTORING_NAME;
}
@Override
protected String[] suggestNames(boolean replaceAll, @Nullable GrVariable variable) {
return GroovyNameSuggestionUtil.suggestVariableNames(getContext().getExpression(), new GroovyVariableValidator(getContext()));
}
@Override
protected JComponent getComponent() {
myCanBeFinalCb = new NonFocusableCheckBox("Declare final");
@@ -91,22 +107,58 @@ public class GrInplaceVariableIntroducer extends GrInplaceIntroducer {
panel.setBorder(null);
if (myCanBeFinalCb != null) {
panel.add(myCanBeFinalCb, new GridBagConstraints(0, 1, 1, 1, 1, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
panel.add(myCanBeFinalCb, new GridBagConstraints(0, 1, 1, 1, 1, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL,
new Insets(5, 5, 5, 5), 0, 0));
}
panel.add(Box.createVerticalBox(), new GridBagConstraints(0, 2, 1, 1, 1, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(0,0,0,0), 0,0));
panel.add(Box.createVerticalBox(),
new GridBagConstraints(0, 2, 1, 1, 1, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
return panel;
}
@Nullable
@Override
public void finish(boolean success) {
super.finish(success);
protected GroovyIntroduceVariableSettings getInitialSettingsForInplace(@NotNull final GrIntroduceContext context,
@NotNull final OccurrencesChooser.ReplaceChoice choice,
final String[] names) {
return new GroovyIntroduceVariableSettings() {
private final CanonicalTypes.Type myType;
if (success) {
GroovyApplicationSettings.getInstance().INTRODUCE_LOCAL_SELECT_DEF = getVariable().getDeclaredType() == null;
}
{
GrExpression expression = context.getExpression();
StringPartInfo stringPart = context.getStringPart();
GrVariable var = context.getVar();
PsiType type = expression != null ? expression.getType() :
var != null ? var.getType() :
stringPart != null ? stringPart.getLiteral().getType() :
null;
myType = type != null ? CanonicalTypes.createTypeWrapper(type) : null;
}
@Override
public boolean isDeclareFinal() {
return myCanBeFinalCb != null ? myCanBeFinalCb.isSelected() : false;
}
@Nullable
@Override
public String getName() {
return names[0];
}
@Override
public boolean replaceAllOccurrences() {
return choice == OccurrencesChooser.ReplaceChoice.ALL;
}
@Nullable
@Override
public PsiType getSelectedType() {
return myType != null ? myType.getType(context.getPlace(), context.getPlace().getManager()) : null;
}
};
}
@Override
@@ -119,4 +171,40 @@ public class GrInplaceVariableIntroducer extends GrInplaceIntroducer {
: PsiUtil.findModifierInList(variable.getModifierList(), GrModifier.DEF);
builder.replaceElement(element, "Variable_type", typeExpression, true, true);
}
}
protected GroovyIntroduceVariableSettings getSettings() {
return new GroovyIntroduceVariableSettings() {
@Override
public boolean isDeclareFinal() {
return myCanBeFinalCb.isSelected();
}
@Nullable
@Override
public String getName() {
return GrInplaceVariableIntroducer.this.getInputName();
}
@Override
public boolean replaceAllOccurrences() {
return isReplaceAllOccurrences();
}
@Nullable
@Override
public PsiType getSelectedType() {
return GrInplaceVariableIntroducer.this.getSelectedType();
}
};
}
@Override
protected void saveSettings(@NotNull GrVariable variable) {
GroovyApplicationSettings.getInstance().INTRODUCE_LOCAL_SELECT_DEF = variable.getDeclaredType() == null;
}
@Override
protected int getCaretOffset() {
return getVariable().getNameIdentifierGroovy().getTextRange().getEndOffset();
}
}
@@ -46,26 +46,26 @@ import java.util.List;
/**
* @author Max Medvedev
*/
public class GrIntroduceLocalVariableProcessor {
public abstract class GrIntroduceLocalVariableProcessor {
private static final Logger LOG = Logger.getInstance(GrIntroduceLocalVariableProcessor.class);
private final GrIntroduceContext myContext;
private final GroovyIntroduceVariableSettings mySettings;
private final boolean myProcessUsages;
private final PsiElement[] myOccurrences;
private GrExpression myExpression;
private final GrIntroduceVariableHandler myHandler;
public GrIntroduceLocalVariableProcessor(@NotNull GrIntroduceContext context,
@NotNull GroovyIntroduceVariableSettings settings,
@NotNull PsiElement[] occurrences,
@NotNull GrExpression expression,
@NotNull GrIntroduceVariableHandler handler) {
boolean processUsages) {
myContext = context;
mySettings = settings;
myProcessUsages = processUsages;
myOccurrences = settings.replaceAllOccurrences() ? occurrences : new PsiElement[]{expression};
myExpression = expression;
myHandler = handler;
}
@NotNull
@@ -75,7 +75,7 @@ public class GrIntroduceLocalVariableProcessor {
preprocessOccurrences();
int expressionIndex = ArrayUtilRt.find(myOccurrences, myExpression);
final PsiElement[] replaced = processOccurrences();
final PsiElement[] replaced = myProcessUsages ? processOccurrences() : myOccurrences;
PsiElement replacedExpression = replaced[expressionIndex];
GrStatement anchor = getAnchor(replaced);
@@ -84,9 +84,7 @@ public class GrIntroduceLocalVariableProcessor {
return insertVariableDefinition(declaration, anchor, replacedExpression);
}
private void refreshPositionMarker(PsiElement e) {
myHandler.refreshPositionMarker(myContext.getEditor().getDocument().createRangeMarker(e.getTextRange()));
}
protected abstract void refreshPositionMarker(PsiElement e);
private static boolean isControlStatementBranch(GrStatement statement) {
return statement.getParent() instanceof GrLoopStatement && statement == ((GrLoopStatement)statement.getParent()).getBody() ||
@@ -13,24 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.refactoring.introduce.variable;
import com.intellij.openapi.actionSystem.Shortcut;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.keymap.Keymap;
import com.intellij.openapi.keymap.KeymapManager;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.util.Pass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiModifier;
import com.intellij.psi.PsiType;
import com.intellij.refactoring.HelpID;
import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
import com.intellij.refactoring.util.CanonicalTypes;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
@@ -48,10 +40,8 @@ import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceContext;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceHandlerBase;
import org.jetbrains.plugins.groovy.refactoring.introduce.StringPartInfo;
import java.util.List;
/**
* @author ilyas
* Created by Max Medvedev on 10/29/13
*/
public class GrIntroduceVariableHandler extends GrIntroduceHandlerBase<GroovyIntroduceVariableSettings, GrControlFlowOwner> {
public static final String DUMMY_NAME = "________________xxx_________________";
@@ -129,8 +119,7 @@ public class GrIntroduceVariableHandler extends GrIntroduceHandlerBase<GroovyInt
public GrVariable runRefactoring(@NotNull final GrIntroduceContext context, @NotNull final GroovyIntroduceVariableSettings settings) {
// Generating variable declaration
final GrVariableDeclaration varDecl = generateDeclaration(context, settings);
GrVariable insertedVar = processExpression(context, settings, varDecl);
GrVariable insertedVar = processExpression(context, settings, true);
if (context.getEditor() != null && getPositionMarker() != null) {
context.getEditor().getCaretModel().moveToOffset(getPositionMarker().getEndOffset());
@@ -140,72 +129,11 @@ public class GrIntroduceVariableHandler extends GrIntroduceHandlerBase<GroovyInt
}
@Override
protected GrInplaceVariableIntroducer getIntroducer(@NotNull GrVariable var,
@NotNull GrIntroduceContext context,
@NotNull GroovyIntroduceVariableSettings settings,
@NotNull List<RangeMarker> occurrenceMarkers,
RangeMarker varRangeMarker, RangeMarker expressionRangeMarker,
RangeMarker stringPartRangeMarker) {
context.getEditor().getCaretModel().moveToOffset(var.getTextOffset());
GrInplaceVariableIntroducer introducer = new GrInplaceVariableIntroducer(var, context.getEditor(), context.getProject(), REFACTORING_NAME, occurrenceMarkers, var);
introducer.setAdvertisementText(getAdvertisementText(var.getDeclaredType() != null));
return introducer;
}
@Nullable
private static String getAdvertisementText(final boolean hasTypeSuggestion) {
final Keymap keymap = KeymapManager.getInstance().getActiveKeymap();
if (hasTypeSuggestion) {
final Shortcut[] shortcuts = keymap.getShortcuts("PreviousTemplateVariable");
if (shortcuts.length > 0) {
return "Press " + KeymapUtil.getShortcutText(shortcuts[0]) + " to change type";
}
}
return null;
}
@Override
protected GroovyIntroduceVariableSettings getSettingsForInplace(final GrIntroduceContext context, final OccurrencesChooser.ReplaceChoice choice) {
return new GroovyIntroduceVariableSettings() {
private final CanonicalTypes.Type myType;
private final String myName;
{
GrExpression expression = context.getExpression();
StringPartInfo stringPart = context.getStringPart();
GrVariable var = context.getVar();
PsiType type = expression != null ? expression.getType() :
var != null ? var.getType() :
stringPart != null ? stringPart.getLiteral().getType() :
null;
myType = type != null ?CanonicalTypes.createTypeWrapper(type) : null;
myName = new GrVariableNameSuggester(context, new GroovyVariableValidator(context)).suggestNames().iterator().next();
}
protected GrInplaceVariableIntroducer getIntroducer(@NotNull GrIntroduceContext context, OccurrencesChooser.ReplaceChoice choice) {
return new GrInplaceVariableIntroducer(getRefactoringName(), choice, context) {
@Override
public boolean isDeclareFinal() {
return false;
}
@Nullable
@Override
public String getName() {
return myName;
}
@Override
public boolean replaceAllOccurrences() {
return choice == OccurrencesChooser.ReplaceChoice.ALL;
}
@Nullable
@Override
public PsiType getSelectedType() {
return myType != null ? myType.getType(context.getPlace(), context.getPlace().getManager()) : null;
protected GrVariable runRefactoring(GrIntroduceContext context, GroovyIntroduceVariableSettings settings, boolean processUsages) {
return processExpression(context, settings, processUsages);
}
};
}
@@ -231,24 +159,31 @@ public class GrIntroduceVariableHandler extends GrIntroduceHandlerBase<GroovyInt
@NotNull
private GrVariable processExpression(@NotNull GrIntroduceContext context,
@NotNull GroovyIntroduceVariableSettings settings,
@NotNull GrVariableDeclaration varDecl) {
boolean processUsages) {
GrVariableDeclaration varDecl = generateDeclaration(context, settings);
if (context.getStringPart() != null) {
final GrExpression ref = processLiteral(DUMMY_NAME, context.getStringPart(), context.getProject());
return doProcessExpression(context, settings, varDecl, new PsiElement[]{ref}, ref);
return doProcessExpression(context, settings, varDecl, new PsiElement[]{ref}, ref, processUsages);
}
else {
final GrExpression expression = context.getExpression();
assert expression != null;
return doProcessExpression(context, settings, varDecl, context.getOccurrences(), expression);
return doProcessExpression(context, settings, varDecl, context.getOccurrences(), expression, processUsages);
}
}
private GrVariable doProcessExpression(@NotNull GrIntroduceContext context,
private GrVariable doProcessExpression(@NotNull final GrIntroduceContext context,
@NotNull GroovyIntroduceVariableSettings settings,
@NotNull GrVariableDeclaration varDecl,
@NotNull PsiElement[] elements,
@NotNull GrExpression expression) {
return new GrIntroduceLocalVariableProcessor(context, settings, elements, expression, this).processExpression(varDecl);
@NotNull GrExpression expression, boolean processUsages) {
return new GrIntroduceLocalVariableProcessor(context, settings, elements, expression, processUsages) {
@Override
protected void refreshPositionMarker(PsiElement e) {
GrIntroduceVariableHandler.this.refreshPositionMarker(context.getEditor().getDocument().createRangeMarker(e.getTextRange()));
}
}.processExpression(varDecl);
}
@NotNull
@@ -109,6 +109,8 @@ public class HgLogProvider implements VcsLogProvider {
repository.update();
Collection<HgNameWithHashInfo> branches = repository.getBranches();
Collection<HgNameWithHashInfo> bookmarks = repository.getBookmarks();
Collection<HgNameWithHashInfo> tags = repository.getTags();
Collection<HgNameWithHashInfo> localTags = repository.getLocalTags();
Collection<VcsRef> refs = new ArrayList<VcsRef>(branches.size() + bookmarks.size());
@@ -123,17 +125,16 @@ public class HgLogProvider implements VcsLogProvider {
if (currentRevision != null) { // null => fresh repository
refs.add(new VcsRefImpl(myVcsObjectsFactory.createHash(currentRevision), "HEAD", HgRefManager.HEAD, root));
}
//refs.addAll(readTags(root));
for (HgNameWithHashInfo tagInfo : tags) {
refs.add(new VcsRefImpl(myVcsObjectsFactory.createHash(tagInfo.getHash()), tagInfo.getName(), HgRefManager.TAG, root));
}
for (HgNameWithHashInfo localTagInfo : localTags) {
refs.add(new VcsRefImpl(myVcsObjectsFactory.createHash(localTagInfo.getHash()), localTagInfo.getName(),
HgRefManager.LOCAL_TAG, root));
}
return refs;
}
//todo implement
/* @NotNull
private Collection<? extends VcsRef> readTags(@NotNull VirtualFile root) throws VcsException {
return Collections.emptyList();
}*/
@NotNull
@Override
public VcsKey getSupportedVcs() {
@@ -38,11 +38,13 @@ public class HgRefManager implements VcsLogRefManager {
private static final Color BRANCH_COLOR = new JBColor(new Color(0x75eec7), new Color(0x0D6D4F));
private static final Color BOOKMARK_COLOR = new JBColor(new Color(0xbcbcfc), new Color(0xbcbcfc).darker().darker());
private static final Color TAG_COLOR = JBColor.WHITE;
private static final Color LOCAL_TAG_COLOR = JBColor.CYAN;
public static final VcsRefType HEAD = new SimpleRefType(true, HEAD_COLOR);
public static final VcsRefType BRANCH = new SimpleRefType(true, BRANCH_COLOR);
public static final VcsRefType BOOKMARK = new SimpleRefType(true, BOOKMARK_COLOR);
public static final VcsRefType TAG = new SimpleRefType(false, TAG_COLOR);
public static final VcsRefType LOCAL_TAG = new SimpleRefType(false, LOCAL_TAG_COLOR);
// first has the highest priority
private static final List<VcsRefType> REF_TYPE_PRIORITIES = Arrays.asList(HEAD, BRANCH, BOOKMARK, TAG);
@@ -103,7 +105,6 @@ public class HgRefManager implements VcsLogRefManager {
@NotNull
@Override
public List<RefGroup> group(Collection<VcsRef> refs) {
// TODO group non-tracking refs into remotes
return ContainerUtil.map(sort(refs), new Function<VcsRef, RefGroup>() {
@Override
public RefGroup fun(final VcsRef ref) {
@@ -36,19 +36,25 @@ public class HgRepoInfo {
@Nullable private String myCurrentBookmark = null;
@NotNull private Set<HgNameWithHashInfo> myBranches = Collections.emptySet();
@NotNull private Set<HgNameWithHashInfo> myBookmarks = Collections.emptySet();
@NotNull private Set<HgNameWithHashInfo> myTags = Collections.emptySet();
@NotNull private Set<HgNameWithHashInfo> myLocalTags = Collections.emptySet();
public HgRepoInfo(@NotNull String currentBranch,
@Nullable String currentRevision,
@NotNull Repository.State state,
@NotNull Collection<HgNameWithHashInfo> branches,
@NotNull Collection<HgNameWithHashInfo> bookmarks,
@Nullable String currentBookmark) {
@Nullable String currentBookmark,
@NotNull Collection<HgNameWithHashInfo> tags,
@NotNull Collection<HgNameWithHashInfo> localTags) {
myCurrentBranch = currentBranch;
myCurrentRevision = currentRevision;
myState = state;
myBranches = new LinkedHashSet<HgNameWithHashInfo>(branches);
myBookmarks = new LinkedHashSet<HgNameWithHashInfo>(bookmarks);
myCurrentBookmark = currentBookmark;
myTags = new LinkedHashSet<HgNameWithHashInfo>(tags);
myLocalTags = new LinkedHashSet<HgNameWithHashInfo>(localTags);
}
@NotNull
@@ -66,6 +72,16 @@ public class HgRepoInfo {
return myBookmarks;
}
@NotNull
public Collection<HgNameWithHashInfo> getTags() {
return myTags;
}
@NotNull
public Collection<HgNameWithHashInfo> getLocalTags() {
return myLocalTags;
}
@Nullable
public String getCurrentRevision() {
return myCurrentRevision;
@@ -94,13 +110,15 @@ public class HgRepoInfo {
if (myCurrentBookmark != null ? !myCurrentBookmark.equals(info.myCurrentBookmark) : info.myCurrentBookmark != null) return false;
if (!myBranches.equals(info.myBranches)) return false;
if (!myBookmarks.equals(info.myBookmarks)) return false;
if (!myTags.equals(info.myTags)) return false;
if (!myLocalTags.equals(info.myLocalTags)) return false;
return true;
}
@Override
public int hashCode() {
return Objects.hashCode(myCurrentBranch, myCurrentRevision, myCurrentBookmark, myState, myBranches, myBookmarks);
return Objects.hashCode(myCurrentBranch, myCurrentRevision, myCurrentBookmark, myState, myBranches, myBookmarks, myTags, myLocalTags);
}
@Override
@@ -44,6 +44,12 @@ public interface HgRepository extends Repository {
@NotNull
Collection<HgNameWithHashInfo> getBookmarks();
@NotNull
Collection<HgNameWithHashInfo> getTags();
@NotNull
Collection<HgNameWithHashInfo> getLocalTags();
@Nullable
String getCurrentBookmark();
@@ -36,6 +36,8 @@ public class HgRepositoryFiles {
public static final String MERGE = "merge";
public static final String BRANCH = "branch";
public static final String BOOKMARKS = "bookmarks";
public static final String LOCAL_TAGS = "localtags";
public static final String TAGS = ".hgtags";
public static final String CURRENT_BOOKMARK = "bookmarks.current";
public static final String CONFIG_HGRC = "hgrc";
@@ -45,6 +47,8 @@ public class HgRepositoryFiles {
@NotNull private final String myMergePath;
@NotNull private final String myBranchPath;
@NotNull private final String myBookmarksPath;
@NotNull private final String myTagsPath;
@NotNull private final String myLocalTagsPath;
@NotNull private final String myCurrentBookmarkPath;
@NotNull private final String myConfigHgrcPath;
@@ -59,6 +63,8 @@ public class HgRepositoryFiles {
myBranchPath = hgDir.getPath() + slash(BRANCH);
myMergePath = hgDir.getPath() + slash(MERGE);
myBookmarksPath = hgDir.getPath() + slash(BOOKMARKS);
myTagsPath = hgDir.getParent().getPath() + slash(TAGS);
myLocalTagsPath = hgDir.getPath() + slash(LOCAL_TAGS);
myCurrentBookmarkPath = hgDir.getPath() + slash(CURRENT_BOOKMARK);
myConfigHgrcPath = hgDir.getPath() + slash(CONFIG_HGRC);
}
@@ -104,4 +110,12 @@ public class HgRepositoryFiles {
public boolean isConfigHgrcFile(String filePath) {
return filePath.equals(myConfigHgrcPath);
}
public boolean isTagsFile(String filePath) {
return filePath.equals(myTagsPath);
}
public boolean isLocalTagsFile(String filePath) {
return filePath.equals(myLocalTagsPath);
}
}
@@ -75,6 +75,13 @@ public class HgRepositoryImpl extends RepositoryImpl implements HgRepository {
return myHgDir;
}
@NotNull
@Override
public State getState() {
return myInfo.getState();
}
@Override
@NotNull
public String getCurrentBranch() {
@@ -105,6 +112,18 @@ public class HgRepositoryImpl extends RepositoryImpl implements HgRepository {
return myInfo.getCurrentBookmark();
}
@NotNull
@Override
public Collection<HgNameWithHashInfo> getTags() {
return myInfo.getTags();
}
@NotNull
@Override
public Collection<HgNameWithHashInfo> getLocalTags() {
return myInfo.getLocalTags();
}
@NotNull
@Override
public HgConfig getRepositoryConfig() {
@@ -142,7 +161,7 @@ public class HgRepositoryImpl extends RepositoryImpl implements HgRepository {
//in GitRepositoryImpl there are temporary state object for reader fields storing! Todo Check;
return
new HgRepoInfo(myReader.readCurrentBranch(), myReader.readCurrentRevision(), myReader.readState(), myReader.readBranches(),
myReader.readBookmarks(), myReader.readCurrentBookmark());
myReader.readBookmarks(), myReader.readCurrentBookmark(), myReader.readTags(), myReader.readLocalTags());
}
public void updateConfig() {
@@ -45,6 +45,8 @@ public class HgRepositoryReader {
@NotNull private final File myCurrentBranch; // .hg/branch
@NotNull private final File myBookmarksFile; //.hg/bookmarks
@NotNull private final File myCurrentBookmark; //.hg/bookmarks.current
@NotNull private final File myTagsFile; //.hgtags - not in .hg directory!!!
@NotNull private final File myLocalTagsFile; // .hg/localtags
@NotNull private final VcsLogObjectsFactory myVcsObjectsFactory;
public HgRepositoryReader(@NotNull File hgDir) {
@@ -56,6 +58,8 @@ public class HgRepositoryReader {
myCurrentBranch = new File(myHgDir, "branch");
myBookmarksFile = new File(myHgDir, "bookmarks");
myCurrentBookmark = new File(myHgDir, "bookmarks.current");
myLocalTagsFile = new File(myHgDir, "localtags");
myTagsFile = new File(myHgDir.getParentFile(), ".hgtags");
myVcsObjectsFactory = ServiceManager.getService(VcsLogObjectsFactory.class);
}
@@ -123,19 +127,34 @@ public class HgRepositoryReader {
@NotNull
public Collection<HgNameWithHashInfo> readBookmarks() {
// .hg/bookmarks contains hash + name, f.e. 25e44c95b2612e3cdf29a704dabf82c77066cb67 A_BookMark
Set<HgNameWithHashInfo> bookmarks = new HashSet<HgNameWithHashInfo>();
if (!myBookmarksFile.exists()) {
return bookmarks;
return readReference(myBookmarksFile);
}
@NotNull
public Collection<HgNameWithHashInfo> readTags() {
return readReference(myTagsFile);
}
@NotNull
public Collection<HgNameWithHashInfo> readLocalTags() {
return readReference(myLocalTagsFile);
}
@NotNull
private Collection<HgNameWithHashInfo> readReference(@NotNull File fileWithReferences) {
// files like .hg/bookmarks which contains hash + name, f.e. 25e44c95b2612e3cdf29a704dabf82c77066cb67 A_BookMark
Set<HgNameWithHashInfo> refs = new HashSet<HgNameWithHashInfo>();
if (!fileWithReferences.exists()) {
return refs;
}
String[] bookmarksWithHeads = RepositoryUtil.tryLoadFile(myBookmarksFile).split("\n");
for (String str : bookmarksWithHeads) {
String[] namesWithHashes = RepositoryUtil.tryLoadFile(fileWithReferences).split("\n");
for (String str : namesWithHashes) {
Matcher matcher = HASH_NAME.matcher(str);
if (matcher.matches()) {
bookmarks.add(new HgNameWithHashInfo(matcher.group(2), myVcsObjectsFactory.createHash(matcher.group(1))));
refs.add(new HgNameWithHashInfo(matcher.group(2), myVcsObjectsFactory.createHash(matcher.group(1))));
}
}
return bookmarks;
return refs;
}
@Nullable
@@ -92,6 +92,8 @@ final class HgRepositoryUpdater implements Disposable, BulkFileListener {
boolean branchFileChanged = false;
boolean mergeFileChanged = false;
boolean bookmarksFileChanged = false;
boolean tagsFileChanged = false;
boolean localTagsFileChanged = false;
boolean currentBookmarkFileChanged = false;
boolean configHgrcChanged = false;
for (VFileEvent event : events) {
@@ -112,6 +114,12 @@ final class HgRepositoryUpdater implements Disposable, BulkFileListener {
else if (myRepositoryFiles.isBookmarksFile(filePath)) {
bookmarksFileChanged = true;
}
else if (myRepositoryFiles.isTagsFile(filePath)) {
tagsFileChanged = true;
}
else if (myRepositoryFiles.isLocalTagsFile(filePath)) {
localTagsFileChanged = true;
}
else if (myRepositoryFiles.isCurrentBookmarksFile(filePath)) {
currentBookmarkFileChanged = true;
}
@@ -121,7 +129,13 @@ final class HgRepositoryUpdater implements Disposable, BulkFileListener {
}
}
if (branchHeadsChanged || branchFileChanged || mergeFileChanged || bookmarksFileChanged || currentBookmarkFileChanged) {
if (branchHeadsChanged ||
branchFileChanged ||
mergeFileChanged ||
bookmarksFileChanged ||
currentBookmarkFileChanged ||
tagsFileChanged ||
localTagsFileChanged) {
myUpdateQueue.add(Void.TYPE);
}
if (configHgrcChanged) {
+2
View File
@@ -0,0 +1,2 @@
25e44c95b2612e3cdf29a704dabf82c77066cb67 tag1
c4e6b94abdf018515b2300698e3eb9b441d53619 tag2
@@ -0,0 +1 @@
25e44c95b2612e3cdf29a704dabf82c77066cb67 localTag
@@ -40,7 +40,7 @@ public class HgRealRepositoryReaderTest extends HgPlatformTest {
super.setUp();
File hgDir = new File(myRepository.getPath(), ".hg");
assertTrue(hgDir.exists());
createBranches();
createBranchesAndTags();
myRepositoryReader = new HgRepositoryReader(hgDir);
}
@@ -62,6 +62,16 @@ public class HgRealRepositoryReaderTest extends HgPlatformTest {
Arrays.asList("default", "branchA", "branchB"));
}
public void testTags() {
TestRepositoryUtil.assertEqualCollections(HgUtil.getNamesWithoutHashes(myRepositoryReader.readTags()),
Arrays.asList("tag1", "tag2"));
}
public void testLocalTags() {
TestRepositoryUtil.assertEqualCollections(HgUtil.getNamesWithoutHashes(myRepositoryReader.readLocalTags()),
Arrays.asList("localTag"));
}
public void testCurrentBookmark() {
hg("update B_BookMark");
assertEquals(myRepositoryReader.readCurrentBookmark(), "B_BookMark");
@@ -72,19 +82,22 @@ public class HgRealRepositoryReaderTest extends HgPlatformTest {
Arrays.asList("A_BookMark", "B_BookMark", "C_BookMark"));
}
private void createBranches() {
private void createBranchesAndTags() {
cd(myRepository);
hg("bookmark A_BookMark");
hg("tag tag1");
String aFile = "A.txt";
touch(aFile, "base");
hg("add " + aFile);
hg("commit -m 'create file'");
hg("bookmark B_BookMark");
hg("branch branchA");
hg("tag tag2");
echo(aFile, " modify with a");
hg("commit -m 'create branchA'");
hg("up default");
hg("branch branchB");
hg("tag -l localTag");
echo(aFile, " modify with b");
hg("commit -m 'modify file in branchB'");
hg("bookmark C_BookMark");
@@ -37,6 +37,8 @@ public class HgRepositoryReaderTest extends HgPlatformTest {
@NotNull private File myHgDir;
@NotNull private Collection<String> myBranches;
@NotNull private Collection<String> myBookmarks;
@NotNull private Collection<String> myTags;
@NotNull private Collection<String> myLocalTags;
@Override
public void setUp() throws Exception {
@@ -52,14 +54,20 @@ public class HgRepositoryReaderTest extends HgPlatformTest {
File testBranchFile = new File(testHgDir, "branch");
File testBookmarkFile = new File(testHgDir, "bookmarks");
File testCurrentBookmarkFile = new File(testHgDir, "bookmarks.current");
File testTagFile = new File(testHgDir.getParentFile(), ".hgtags");
File testLocalTagFile = new File(testHgDir, "localtags");
FileUtil.copyDir(cacheDir, new File(myHgDir, "cache"));
FileUtil.copy(testBranchFile, new File(myHgDir, "branch"));
FileUtil.copy(testBookmarkFile, new File(myHgDir, "bookmarks"));
FileUtil.copy(testCurrentBookmarkFile, new File(myHgDir, "bookmarks.current"));
FileUtil.copy(testTagFile, new File(myHgDir.getParentFile(), ".hgtags"));
FileUtil.copy(testLocalTagFile, new File(myHgDir, "localtags"));
myRepositoryReader = new HgRepositoryReader(myHgDir);
myBranches = readBranches();
myBookmarks = readBookmarks();
myBookmarks = readRefs(testBookmarkFile);
myTags = readRefs(testTagFile);
myLocalTags = readRefs(testLocalTagFile);
}
public void testHEAD() {
@@ -81,6 +89,16 @@ public class HgRepositoryReaderTest extends HgPlatformTest {
TestRepositoryUtil.assertEqualCollections(bookmarks, myBookmarks);
}
public void testTags() {
Collection<String> tags = HgUtil.getNamesWithoutHashes(myRepositoryReader.readTags());
TestRepositoryUtil.assertEqualCollections(tags, myTags);
}
public void testLocalTags() {
Collection<String> localTags = HgUtil.getNamesWithoutHashes(myRepositoryReader.readLocalTags());
TestRepositoryUtil.assertEqualCollections(localTags, myLocalTags);
}
@NotNull
private Collection<String> readBranches() throws IOException {
Collection<String> branches = new HashSet<String>();
@@ -100,15 +118,14 @@ public class HgRepositoryReaderTest extends HgPlatformTest {
}
@NotNull
private Collection<String> readBookmarks() throws IOException {
Collection<String> bookmarks = new HashSet<String>();
File bookmarksFile = new File(myHgDir, "bookmarks");
String[] bookmarksWithHashes = FileUtil.loadFile(bookmarksFile).split("\n");
for (String str : bookmarksWithHashes) {
private static Collection<String> readRefs(@NotNull File refFile) throws IOException {
Collection<String> refs = new HashSet<String>();
String[] refsWithHashes = FileUtil.loadFile(refFile).split("\n");
for (String str : refsWithHashes) {
String[] refAndName = str.trim().split(" ");
assertEquals(2, refAndName.length);
bookmarks.add(refAndName[1]);
refs.add(refAndName[1]);
}
return bookmarks;
return refs;
}
}
@@ -27,6 +27,7 @@ import org.intellij.plugins.intelliLang.inject.config.BaseInjection;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
@@ -79,4 +80,10 @@ public class PyLanguageInjectionSupport extends AbstractLanguageInjectionSupport
// with multiple injection text ranges (PY-10691)
return true;
}
@Nullable
@Override
public String getHelpId() {
return "reference.settings.language.injection.generic.python";
}
}
+3 -1
View File
@@ -473,6 +473,8 @@
<postStartupActivity implementation="com.jetbrains.python.packaging.PyPIPackagesUpdater"/>
<postStartupActivity implementation="com.jetbrains.python.testing.PyTestRunnerUpdater"/>
<macro implementation="com.jetbrains.python.sdk.InterpreterDirectoryMacro"/>
<!-- User skeletons -->
<codeInsight.lineMarkerProvider language="Python" implementationClass="com.jetbrains.python.codeInsight.userSkeletons.PyUserSkeletonsLineMarkerProvider"/>
@@ -504,7 +506,6 @@
<!-- Packaging -->
<moduleService serviceInterface="com.jetbrains.python.packaging.PyPackageRequirementsSettings"
serviceImplementation="com.jetbrains.python.packaging.PyPackageRequirementsSettings"/>
</extensions>
<extensionPoints>
@@ -547,6 +548,7 @@
<dumbAnnotator implementation="com.jetbrains.python.validation.DocStringAnnotator"/>
<dumbAnnotator implementation="com.jetbrains.python.validation.PyDefinitionsAnnotator"/>
<dumbAnnotator implementation="com.jetbrains.python.validation.GeneratorInArgumentListAnnotator"/>
<dumbAnnotator implementation="com.jetbrains.python.validation.StarAnnotator"/>
<customTargetExpressionStubType implementation="com.jetbrains.python.psi.impl.stubs.PropertyStubType"/>
<dialectsTokenSetContributor implementation="com.jetbrains.python.PythonTokenSetContributor"/>
@@ -85,6 +85,9 @@ public class PyImportOptimizer implements ImportOptimizer {
}
LanguageLevel langLevel = LanguageLevel.forElement(myFile);
for (PyImportStatementBase importStatement : myImportBlock) {
if (importStatement instanceof PyFromImportStatement && ((PyFromImportStatement)importStatement).isFromFuture()) {
continue;
}
if (importStatement instanceof PyImportStatement && importStatement.getImportElements().length > 1) {
for (PyImportElement importElement : importStatement.getImportElements()) {
myMissorted = true;
@@ -96,7 +99,7 @@ public class PyImportOptimizer implements ImportOptimizer {
else {
PsiElement toImport;
if (importStatement instanceof PyFromImportStatement) {
toImport = ((PyFromImportStatement) importStatement).resolveImportSource();
toImport = ((PyFromImportStatement)importStatement).resolveImportSource();
}
else {
toImport = importStatement.getImportElements()[0].resolve();
@@ -140,12 +143,21 @@ public class PyImportOptimizer implements ImportOptimizer {
addImports(myThirdPartyImports);
addImports(myProjectImports);
PsiElement lastElement = myImportBlock.get(myImportBlock.size()-1);
myFile.deleteChildRange(myImportBlock.get(0), lastElement);
myFile.deleteChildRange(findFirstNonFutureImport(), lastElement);
for (PyImportStatementBase anImport : myBuiltinImports) {
anImport.putCopyableUserData(PyBlock.IMPORT_GROUP_BEGIN, null);
}
}
private PyImportStatementBase findFirstNonFutureImport() {
for (PyImportStatementBase importStatement: myImportBlock) {
if (!(importStatement instanceof PyFromImportStatement && ((PyFromImportStatement)importStatement).isFromFuture())) {
return importStatement;
}
}
return myImportBlock.get(0);
}
private static void markGroupBegin(List<PyImportStatementBase> imports) {
if (imports.size() > 0) {
imports.get(0).putCopyableUserData(PyBlock.IMPORT_GROUP_BEGIN, true);
@@ -154,7 +166,7 @@ public class PyImportOptimizer implements ImportOptimizer {
private void addImports(final List<PyImportStatementBase> imports) {
for (PyImportStatementBase newImport: imports) {
myFile.addBefore(newImport, myImportBlock.get(0));
myFile.addBefore(newImport, findFirstNonFutureImport());
}
}
}
@@ -16,6 +16,7 @@
package com.jetbrains.python.inspections;
import com.intellij.codeInspection.LocalInspectionToolSession;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElementVisitor;
@@ -138,7 +139,7 @@ public class PyArgumentListInspection extends PyInspection {
holder.registerProblem(arg, PyBundle.message("INSP.duplicate.star.arg"));
}
if (flags.contains(CallArgumentsMapping.ArgFlag.IS_POS_PAST_KWD)) {
holder.registerProblem(arg, PyBundle.message("INSP.cannot.appear.past.keyword.arg"));
holder.registerProblem(arg, PyBundle.message("INSP.cannot.appear.past.keyword.arg"), ProblemHighlightType.ERROR);
}
if (flags.contains(CallArgumentsMapping.ArgFlag.IS_UNMAPPED)) {
holder.registerProblem(arg, PyBundle.message("INSP.unexpected.arg"));
@@ -835,7 +835,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
}
private void addCreateClassFix(String refText, PsiElement element, List<LocalQuickFix> actions) {
if (refText.length() > 2 && Character.isUpperCase(refText.charAt(0)) && !Character.isUpperCase(refText.charAt(1)) &&
if (refText.length() > 2 && Character.isUpperCase(refText.charAt(0)) && !refText.toUpperCase().equals(refText) &&
PsiTreeUtil.getParentOfType(element, PyImportStatementBase.class) == null) {
PsiElement anchor = element;
if (element instanceof PyQualifiedExpression) {
@@ -21,14 +21,13 @@ import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.documentation.DocStringUtil;
import com.jetbrains.python.psi.PyFile;
import com.jetbrains.python.psi.PyStringLiteralExpression;
import org.jetbrains.annotations.NotNull;
/**
* Created by IntelliJ IDEA.
* Author: Alexey.Ivanov
* Date: 24.03.2010
* Time: 20:15:23
* @author Alexey.Ivanov
*/
public class MoveFromFutureImportQuickFix implements LocalQuickFix {
@NotNull
@@ -46,7 +45,13 @@ public class MoveFromFutureImportQuickFix implements LocalQuickFix {
PsiFile psiFile = problemElement.getContainingFile();
if (psiFile instanceof PyFile) {
PyFile file = (PyFile)psiFile;
file.addBefore(problemElement, file.getStatements().get(0));
PyStringLiteralExpression docString = DocStringUtil.findDocStringExpression(file);
if (docString != null) {
file.addAfter(problemElement, docString.getParent() /* PyExpressionStatement */);
}
else {
file.addBefore(problemElement, file.getStatements().get(0));
}
problemElement.delete();
}
}
@@ -221,6 +221,7 @@ public class PyStringLiteralLexer extends LexerBase {
if (myBuffer.charAt(i) == '\\') {
LOG.assertTrue(myState == AFTER_FIRST_QUOTE);
i++;
if (myIsRaw) return i;
if (i == myBufferEnd) {
myState = AFTER_LAST_QUOTE;
return i;
@@ -282,7 +283,7 @@ public class PyStringLiteralLexer extends LexerBase {
final int quote_limit = myIsTriple ? 3 : 1;
int qcnt = 0; // count consequent quotes
while (i < myBufferEnd) { // scan to next \something
if (myBuffer.charAt(i) == '\\') {
if (myBuffer.charAt(i) == '\\' && !myIsRaw) {
return i;
}
if (myState == BEFORE_FIRST_QUOTE && myBuffer.charAt(i) == myQuoteChar) {
@@ -292,7 +293,7 @@ public class PyStringLiteralLexer extends LexerBase {
qcnt = 0; // for last quote detection in the same pass
}
}
else if (myState == AFTER_FIRST_QUOTE && myBuffer.charAt(i) == myQuoteChar) { // done?
else if (myState == AFTER_FIRST_QUOTE && myBuffer.charAt(i) == myQuoteChar && (!myIsRaw || myBuffer.charAt(i-1) != '\\')) { // done?
qcnt += 1;
if (qcnt == quote_limit) {
myState = AFTER_LAST_QUOTE;
@@ -772,6 +772,7 @@ public class ExpressionParsing extends Parsing {
PsiBuilder.Marker starExpr = myBuilder.mark();
nextToken();
if (!parseBitwiseORExpression(isTargetExpression)) {
myBuilder.error(message("PARSE.expected.expression"));
starExpr.drop();
return false;
}
@@ -65,29 +65,9 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping {
public void mapArguments(PyCallExpression.PyMarkedCallee resolved_callee, @NotNull TypeEvalContext context) {
PyExpression[] arguments = myArgumentList.getArguments();
myMarkedCallee = resolved_callee;
List<PyExpression> unmatched_args = new LinkedList<PyExpression>();
Collections.addAll(unmatched_args, arguments);
final List<PyExpression> unmatched_subargs = new LinkedList<PyExpression>(); // unmatched nested arguments will go here
// detect starred args
for (PyExpression arg : arguments) {
if (arg instanceof PyStarArgument) {
PyStarArgument star_arg = (PyStarArgument)arg;
if (star_arg.isKeyword()) {
if (myKwdArg == null) myKwdArg = star_arg;
else {
markArgument(arg, ArgFlag.IS_DUP_KWD);
unmatched_args.remove(arg);
}
}
else {
if (myTupleArg == null) myTupleArg = star_arg;
else {
markArgument(arg, ArgFlag.IS_DUP_TUPLE);
unmatched_args.remove(arg);
}
}
}
}
List<PyExpression> unmatched_args = verifyArguments();
final List<PyParameter> parameters = PyUtil.getParameters(myMarkedCallee.getCallable(), context);
// prepare parameter slots
Map<PyNamedParameter, PyExpression> slots = new LinkedHashMap<PyNamedParameter, PyExpression>();
@@ -180,15 +160,8 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping {
for (PyExpression arg : unmatched_subargs) {
markArgument(arg, ArgFlag.IS_UNMAPPED);
}
// mark past-bound positional args
i = positional_bound;
while (i<arguments.length) {
PyExpression arg = arguments[i];
if (!(arg instanceof PyStarArgument) && !(arg instanceof PyKeywordArgument)) {
markArgument(arg, ArgFlag.IS_POS_PAST_KWD);
}
i += 1;
}
boolean seen_named_args = false;
// map named args to named params if possible
Map<String, PyNamedParameter> parameter_by_name = new LinkedHashMap<String, PyNamedParameter>();
@@ -352,6 +325,57 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping {
}
}
public List<PyExpression> verifyArguments() {
List<PyExpression> unmatched_args = new LinkedList<PyExpression>();
Collections.addAll(unmatched_args, myArgumentList.getArguments());
// detect starred args
for (PyExpression arg : myArgumentList.getArguments()) {
if (arg instanceof PyStarArgument) {
PyStarArgument star_arg = (PyStarArgument)arg;
if (star_arg.isKeyword()) {
if (myKwdArg == null) myKwdArg = star_arg;
else {
markArgument(arg, ArgFlag.IS_DUP_KWD);
unmatched_args.remove(arg);
}
}
else {
if (myTupleArg == null) myTupleArg = star_arg;
else {
markArgument(arg, ArgFlag.IS_DUP_TUPLE);
unmatched_args.remove(arg);
}
}
}
}
markPastBoundPositionalArguments(myArgumentList.getArguments());
return unmatched_args;
}
private void markPastBoundPositionalArguments(PyExpression[] arguments) {
boolean seenKwArg = false;
boolean seenKeyword = false;
boolean seenStar = false;
for (PyExpression arg : arguments) {
if (arg == myKwdArg) {
seenKwArg = true;
}
else if (arg instanceof PyKeywordArgument) {
seenKeyword = true;
}
else if (arg instanceof PyStarArgument) {
seenStar = true;
}
if (seenKeyword || seenKwArg || seenStar) {
if (!(arg instanceof PyStarArgument) && (seenKwArg || !(arg instanceof PyKeywordArgument))) {
markArgument(arg, ArgFlag.IS_POS_PAST_KWD);
}
}
}
}
private static boolean isPositionalArg(PyExpression arg) {
return !(arg instanceof PyKeywordArgument) && !(arg instanceof PyStarArgument);
}
@@ -269,8 +269,13 @@ public class PyArgumentListImpl extends PyElementImpl implements PyArgumentList
// following the spec: http://docs.python.org/ref/calls.html
PyCallExpression call = getCallExpression();
if (call != null) {
PyCallExpression.PyMarkedCallee resolved_callee = call.resolveCallee(resolveContext, offset);
if (resolved_callee != null) ret.mapArguments(resolved_callee, resolveContext.getTypeEvalContext());
PyCallExpression.PyMarkedCallee resolvedCallee = call.resolveCallee(resolveContext, offset);
if (resolvedCallee != null) {
ret.mapArguments(resolvedCallee, resolveContext.getTypeEvalContext());
}
else {
ret.verifyArguments();
}
}
return ret;
}
@@ -0,0 +1,73 @@
/*
* Copyright 2000-2013 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.jetbrains.python.sdk;
import com.intellij.ide.macro.Macro;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.PathUtil;
import org.jetbrains.annotations.Nullable;
/**
* @author yole
*/
public class InterpreterDirectoryMacro extends Macro {
@Override
public String getName() {
return "PyInterpreterDirectory";
}
@Override
public String getDescription() {
return "The directory containing the Python interpreter selected for the project";
}
@Nullable
@Override
public String expand(DataContext dataContext) throws ExecutionCancelledException {
Module module = LangDataKeys.MODULE.getData(dataContext);
if (module == null) {
Project project = CommonDataKeys.PROJECT.getData(dataContext);
if (project == null) {
return null;
}
Module[] modules = ModuleManager.getInstance(project).getModules();
if (modules.length == 0) {
return null;
}
module = modules[0];
}
Sdk sdk = PythonSdkType.findPythonSdk(module);
if (sdk != null) {
VirtualFile homeDir = sdk.getHomeDirectory();
if (homeDir == null) {
return null;
}
String path = PathUtil.getLocalPath(homeDir.getParent());
if (path != null) {
return FileUtil.toSystemDependentName(path);
}
}
return null;
}
}
@@ -25,7 +25,6 @@ import com.intellij.notification.Notification;
import com.intellij.notification.NotificationListener;
import com.intellij.notification.NotificationType;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
@@ -556,16 +555,22 @@ public class PythonSdkType extends SdkType {
@NotNull
public static Notification createInvalidSdkNotification(@Nullable final Project project) {
String message = "Cannot run the project interpreter.";
if (project != null && !project.isDisposed()) {
message += " <a href=\"xxx\">Configure...</a>";
}
return new Notification("xxx",
"Invalid Project Interpreter",
"Cannot run the project interpreter. <a href=\"xxx\">Configure...</a>",
message,
NotificationType.ERROR,
new NotificationListener() {
@Override
public void hyperlinkUpdate(@NotNull Notification notification,
@NotNull HyperlinkEvent event) {
final ShowSettingsUtil settings = ShowSettingsUtil.getInstance();
settings.showSettingsDialog(project, "Project Interpreter");
if (project != null && !project.isDisposed()) {
final ShowSettingsUtil settings = ShowSettingsUtil.getInstance();
settings.showSettingsDialog(project, "Project Interpreter");
}
notification.expire();
}
});
@@ -0,0 +1,32 @@
/*
* Copyright 2000-2013 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.jetbrains.python.validation;
import com.jetbrains.python.psi.PyStarExpression;
import com.jetbrains.python.psi.PyTargetExpression;
/**
* @author yole
*/
public class StarAnnotator extends PyAnnotator {
@Override
public void visitPyStarExpression(PyStarExpression node) {
super.visitPyStarExpression(node);
if (!(node.getExpression() instanceof PyTargetExpression)) {
getHolder().createErrorAnnotation(node, "can use starred expression only as assignment target");
}
}
}
@@ -0,0 +1 @@
y = (<error descr="can use starred expression only as assignment target">*()</error> for _ in ())
@@ -0,0 +1,10 @@
"""This is a docstring."""
from __future__ import print_function
#comment
from __future__ import absolute_import
class A:
pass
<warning descr="from __future__ imports must occur at the beginning of the file"><caret>from __future__ import with_statement</warning>
@@ -0,0 +1,10 @@
"""This is a docstring."""
from __future__ import with_statement
from __future__ import print_function
#comment
from __future__ import absolute_import
class A:
pass
@@ -42,7 +42,7 @@ f3(1, 2, <warning descr="Unexpected argument">3</warning>)
f3(b=2, a=1)
f3(b=1, <warning descr="Duplicate argument">b=2</warning>, a=1)
f3(1, b=2)
f3(a=1, <warning descr="Cannot appear past keyword arguments or *arg or **kwarg">2</warning><warning descr="Parameter 'b' unfilled">)</warning>
f3(a=1, <error descr="Cannot appear past keyword arguments or *arg or **kwarg">2</error><warning descr="Parameter 'b' unfilled">)</warning>
def f4(a, *b):
pass
@@ -52,4 +52,4 @@ f4(1, 2)
f4(1, 2, 3)
f4(1, *(2, 3))
f4(*(1,2,3))
f4(a=1, <warning descr="Cannot appear past keyword arguments or *arg or **kwarg">2</warning>, <warning descr="Cannot appear past keyword arguments or *arg or **kwarg">3</warning>)
f4(a=1, <error descr="Cannot appear past keyword arguments or *arg or **kwarg">2</error>, <error descr="Cannot appear past keyword arguments or *arg or **kwarg">3</error>)
@@ -0,0 +1,5 @@
def foo(**kwargs): pass
two = 0
kw = {}
foo(**kw, <error descr="Cannot appear past keyword arguments or *arg or **kwarg">two=1</error>)
@@ -0,0 +1,8 @@
kwargs = {'foo': 'bar'}
class Foo(object):
@classmethod
def test(cls):
cls(**kwargs, <error descr="Cannot appear past keyword arguments or *arg or **kwarg">foo=1</error>)
@@ -19,7 +19,7 @@ def f2(a, b, c=1, *d):
f2(c=3, *(1,2))
f2(1,2,3, *(1,2))
f2(*(1,2), c=20)
f2(*(1,2), <warning descr="Cannot appear past keyword arguments or *arg or **kwarg">20</warning>) # fail: positional past *
f2(*(1,2), <error descr="Cannot appear past keyword arguments or *arg or **kwarg">20</error>) # fail: positional past *
def f3(a=1, b=2, c=3, *d):
return a,b,c,d
@@ -13,7 +13,7 @@ namedpast(1,2,3, foo='a') # pass
namedpast(*args, foo='b') # pass
namedpast(foo='c') # pass
namedpast() # pass
namedpast(foo='1', <warning descr="Cannot appear past keyword arguments or *arg or **kwarg">2</warning>) # fail
namedpast(foo='1', <error descr="Cannot appear past keyword arguments or *arg or **kwarg">2</error>) # fail
def a23(a, *b, c=1):
pass
@@ -21,7 +21,7 @@ def a23(a, *b, c=1):
a23(1,2,3, c=10) # pass
a23(1,2,3, c=10, <warning descr="Duplicate argument">a=1</warning>) # fail
a23(c=10, a=1) # pass
a23(c=10, <warning descr="Cannot appear past keyword arguments or *arg or **kwarg">1</warning><warning descr="Parameter 'a' unfilled">)</warning> # fail
a23(c=10, <error descr="Cannot appear past keyword arguments or *arg or **kwarg">1</error><warning descr="Parameter 'a' unfilled">)</warning> # fail
a23(<warning descr="Multiple values resolve to positional parameter 'a'">*args</warning>, a=1) # fail
a23(*args, c=1) # pass
@@ -1,3 +1,4 @@
from __future__ import with_statement
import sys
import datetime
+1
View File
@@ -1,3 +1,4 @@
from __future__ import with_statement
import foo
import sys
from bar import *
+1
View File
@@ -0,0 +1 @@
x = (*)
+13
View File
@@ -0,0 +1,13 @@
PyFile:LoneStar.py
PyAssignmentStatement
PyTargetExpression: x
PsiElement(Py:IDENTIFIER)('x')
PsiWhiteSpace(' ')
PsiElement(Py:EQ)('=')
PsiWhiteSpace(' ')
PyParenthesizedExpression
PsiElement(Py:LPAR)('(')
PsiElement(Py:MULT)('*')
PsiErrorElement:expression expected
<empty list>
PsiElement(Py:RPAR)(')')
@@ -0,0 +1 @@
s = r'Hello\<selection>nWorld</selection>!'

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