mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'master' of git.labs.intellij.net:idea/community
This commit is contained in:
Generated
+2
-2
@@ -1,11 +1,11 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Guava">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/guava-r08.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/lib/guava-r09.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/src/guava-src-r08.zip!/" />
|
||||
<root url="jar://$PROJECT_DIR$/lib/src/guava-src-r09.zip!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
@@ -150,7 +150,7 @@ libraryLicense(name: "Apache Lucene", libraryName: "lucene-core-2.4.1.jar", vers
|
||||
libraryLicense(name: "Automaton", libraryName: "automaton.jar", version: "1.11", license: "BSD", url: "http://www.brics.dk/automaton/", licenseUrl: "http://www.opensource.org/licenses/bsd-license.php")
|
||||
libraryLicense(name: "DTDParser", version: "1.13", license: "LGPL", url: "http://sourceforge.net/projects/dtdparser/", licenseUrl: "http://www.opensource.org/licenses/lgpl-2.1")
|
||||
libraryLicense(name: "Ganymed", version: "bundled with SVNKit", libraryName: "svnkit.jar", license: "BSD", url: "http://www.ganymed.ethz.ch/ssh2/", licenseUrl: "http://www.ganymed.ethz.ch/ssh2/LICENSE.txt")
|
||||
libraryLicense(name: "Guava", version: "R6", license: "Apache 2.0", url: "http://code.google.com/p/guava-libraries/", licenseUrl: "http://ant.apache.org/license.html")
|
||||
libraryLicense(name: "Guava", version: "R8", license: "Apache 2.0", url: "http://code.google.com/p/guava-libraries/", licenseUrl: "http://ant.apache.org/license.html")
|
||||
libraryLicense(name: "Gradle API", libraryName: "gradle-open-api-0.8.jar", version: "0.8", license: "Apache 2.0", url: "http://www.gradle.org/")
|
||||
libraryLicense(name: "Groovy", version: "1.7.3", license: "Apache 2.0", url: "http://groovy.codehaus.org/")
|
||||
libraryLicense(name: "Gson", libraryName: "gson-1.3.jar", license: "Apache 2.0", url: "http://code.google.com/p/google-gson/")
|
||||
@@ -170,6 +170,7 @@ libraryLicense(name: "JUnit", libraryName: "JUnit4", version: "4.8", license: "C
|
||||
libraryLicense(name: "Log4j", libraryName: "Log4J", version: "1.2", license: "Apache 2.0", url: "http://logging.apache.org/log4j/1.2/index.html", licenseUrl: "http://logging.apache.org/license.html")
|
||||
libraryLicense(name: "Maven", version: "2.2.1", license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://maven.apache.org/license.html")
|
||||
libraryLicense(name: "Maven3", libraryNames: ["Maven3", "maven-dependency-tree-1.2.jar"], version: "3.0.3", license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://maven.apache.org/license.html")
|
||||
libraryLicense(name: "mercurial_prompthooks", attachedTo: "hg4idea", version: "", license: "GPLv2 (used as hg extension called from hg executable)", url: "https://github.com/willemv/mercurial_prompthooks", licenseUrl: "https://github.com/willemv/mercurial_prompthooks/blob/master/LICENSE.txt")
|
||||
libraryLicense(name: "Microba", libraryName: "microba", version: "0.4.2", license: "BSD", url: "http://microba.sourceforge.net/", licenseUrl: "http://microba.sourceforge.net/license.txt")
|
||||
libraryLicense(name: "NanoXML", version: "2.2.3", license: "zlib/libpng", url: "http://nanoxml.cyberelf.be/", licenseUrl: "http://devkix.com/nanoxml.php")
|
||||
libraryLicense(name: "Eclipse JDT Core", libraryName: "Eclipse", version: "3.3", license: "CPL 1.0", url: "http://www.eclipse.org/jdt/core/index.php")
|
||||
@@ -191,7 +192,7 @@ libraryLicense(name: "XML Commons (xml-apis.jar, resolver.jar)", version: "", li
|
||||
libraryLicense(name: "XMLBeans", libraryName: "XmlBeans", version: "2.3.0", license: "Apache 2.0", url: "http://xmlbeans.apache.org/", licenseUrl: "http://svn.jetbrains.org/idea/Trunk/bundled/WebServices/resources/lib/xmlbeans-2.3.0/xmlbeans.LICENSE")
|
||||
libraryLicense(name: "XML-RPC", libraryName: "XmlRPC", version: "2.0", license: "Apache 2.0", url: "http://ws.apache.org/xmlrpc/xmlrpc2/", licenseUrl: "http://ws.apache.org/xmlrpc/xmlrpc2/license.html")
|
||||
libraryLicense(name: "XStream", version: "1.2.1", license: "BSD", url: "http://xstream.codehaus.org/", licenseUrl: "http://xstream.codehaus.org/license.html")
|
||||
libraryLicense(name: "YourKit Java Profiler", libraryName: "yjp-controller-api-redist.jar", version: "7.0.2", license: "link (commercial license)", url: "http://yourkit.com/", licenseUrl: "http://www.yourkit.com/purchase/license.html")
|
||||
libraryLicense(name: "YourKit Java Profiler", libraryName: "yjp-controller-api-redist.jar", version: "8.0.x", license: "link (commercial license)", url: "http://yourkit.com/", licenseUrl: "http://www.yourkit.com/purchase/license.html")
|
||||
jetbrainsLibrary("JPS")
|
||||
jetbrainsLibrary("Maven Embedder")
|
||||
jetbrainsLibrary("tcServiceMessages")
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.packaging.impl.elements;
|
||||
|
||||
import com.intellij.facet.Facet;
|
||||
import com.intellij.packaging.elements.PackagingElementResolvingContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author nik
|
||||
*/
|
||||
public interface FacetBasedPackagingElement {
|
||||
@Nullable
|
||||
Facet findFacet(@NotNull PackagingElementResolvingContext context);
|
||||
}
|
||||
@@ -47,11 +47,6 @@ public class ArtifactElementPresentation extends TreeNodePresentation {
|
||||
return findArtifact() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSourceObject() {
|
||||
return myArtifactPointer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void navigateToSource() {
|
||||
final Artifact artifact = findArtifact();
|
||||
|
||||
-5
@@ -57,11 +57,6 @@ public class DelegatedPackagingElementPresentation extends PackagingElementPrese
|
||||
myDelegate.navigateToSource();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Object getSourceObject() {
|
||||
return myDelegate.getSourceObject();
|
||||
}
|
||||
|
||||
public int getWeight() {
|
||||
return myDelegate.getWeight();
|
||||
}
|
||||
|
||||
@@ -57,11 +57,6 @@ public class LibraryElementPresentation extends PackagingElementPresentation {
|
||||
return myLibrary != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSourceObject() {
|
||||
return myLibrary;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void navigateToSource() {
|
||||
myContext.selectLibrary(myLibrary);
|
||||
|
||||
@@ -51,11 +51,6 @@ public class ModuleElementPresentation extends TreeNodePresentation {
|
||||
return findModule() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSourceObject() {
|
||||
return findModule();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Module findModule() {
|
||||
return myModulePointer != null ? myModulePointer.getModule() : null;
|
||||
|
||||
@@ -45,6 +45,9 @@ public abstract class TreeNodePresentation {
|
||||
public void navigateToSource() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated this method is not used and will be removed in the future
|
||||
*/
|
||||
@Nullable
|
||||
public Object getSourceObject() {
|
||||
return null;
|
||||
|
||||
+38
-19
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.openapi.roots.ui.configuration.artifacts;
|
||||
|
||||
import com.intellij.facet.Facet;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.roots.libraries.Library;
|
||||
import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext;
|
||||
@@ -25,9 +26,11 @@ import com.intellij.packaging.impl.artifacts.ArtifactUtil;
|
||||
import com.intellij.packaging.impl.artifacts.PackagingElementPath;
|
||||
import com.intellij.packaging.impl.artifacts.PackagingElementProcessor;
|
||||
import com.intellij.packaging.impl.elements.ArtifactPackagingElement;
|
||||
import com.intellij.packaging.impl.elements.FacetBasedPackagingElement;
|
||||
import com.intellij.packaging.impl.elements.LibraryPackagingElement;
|
||||
import com.intellij.packaging.impl.elements.ModuleOutputPackagingElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -64,25 +67,10 @@ public class ArtifactProjectStructureElement extends ProjectStructureElement {
|
||||
ArtifactUtil.processPackagingElements(myArtifactsStructureContext.getRootElement(artifact), null, new PackagingElementProcessor<PackagingElement<?>>() {
|
||||
@Override
|
||||
public boolean process(@NotNull PackagingElement<?> packagingElement, @NotNull PackagingElementPath path) {
|
||||
if (packagingElement instanceof ModuleOutputPackagingElement) {
|
||||
final Module module = ((ModuleOutputPackagingElement)packagingElement).findModule(myArtifactsStructureContext);
|
||||
if (module != null) {
|
||||
usages.add(createUsage(packagingElement, path, new ModuleProjectStructureElement(myContext, module)));
|
||||
}
|
||||
}
|
||||
else if (packagingElement instanceof LibraryPackagingElement) {
|
||||
final Library library = ((LibraryPackagingElement)packagingElement).findLibrary(myArtifactsStructureContext);
|
||||
if (library != null) {
|
||||
usages.add(createUsage(packagingElement, path,
|
||||
new LibraryProjectStructureElement(ArtifactProjectStructureElement.this.myContext, library)));
|
||||
}
|
||||
}
|
||||
else if (packagingElement instanceof ArtifactPackagingElement) {
|
||||
final Artifact usedArtifact = ((ArtifactPackagingElement)packagingElement).findArtifact(myArtifactsStructureContext);
|
||||
if (usedArtifact != null) {
|
||||
final ArtifactProjectStructureElement artifactElement = myArtifactsStructureContext.getOrCreateArtifactElement(usedArtifact);
|
||||
usages.add(createUsage(packagingElement, path, artifactElement));
|
||||
}
|
||||
ProjectStructureElement element = getProjectStructureElementFor(packagingElement, ArtifactProjectStructureElement.this.myContext,
|
||||
ArtifactProjectStructureElement.this.myArtifactsStructureContext);
|
||||
if (element != null) {
|
||||
usages.add(createUsage(packagingElement, path, element));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -90,6 +78,37 @@ public class ArtifactProjectStructureElement extends ProjectStructureElement {
|
||||
return usages;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ProjectStructureElement getProjectStructureElementFor(PackagingElement<?> packagingElement,
|
||||
final StructureConfigurableContext context,
|
||||
final ArtifactsStructureConfigurableContext artifactsStructureContext) {
|
||||
if (packagingElement instanceof ModuleOutputPackagingElement) {
|
||||
final Module module = ((ModuleOutputPackagingElement)packagingElement).findModule(artifactsStructureContext);
|
||||
if (module != null) {
|
||||
return new ModuleProjectStructureElement(context, module);
|
||||
}
|
||||
}
|
||||
else if (packagingElement instanceof LibraryPackagingElement) {
|
||||
final Library library = ((LibraryPackagingElement)packagingElement).findLibrary(artifactsStructureContext);
|
||||
if (library != null) {
|
||||
return new LibraryProjectStructureElement(context, library);
|
||||
}
|
||||
}
|
||||
else if (packagingElement instanceof ArtifactPackagingElement) {
|
||||
final Artifact usedArtifact = ((ArtifactPackagingElement)packagingElement).findArtifact(artifactsStructureContext);
|
||||
if (usedArtifact != null) {
|
||||
return artifactsStructureContext.getOrCreateArtifactElement(usedArtifact);
|
||||
}
|
||||
}
|
||||
else if (packagingElement instanceof FacetBasedPackagingElement) {
|
||||
Facet facet = ((FacetBasedPackagingElement)packagingElement).findFacet(artifactsStructureContext);
|
||||
if (facet != null) {
|
||||
return new FacetProjectStructureElement(context, facet);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private UsageInArtifact createUsage(PackagingElement<?> packagingElement, PackagingElementPath path,
|
||||
final ProjectStructureElement element) {
|
||||
return new UsageInArtifact(myOriginalArtifact, myArtifactsStructureContext, element, this, path.getPathString(), packagingElement);
|
||||
|
||||
+2
-36
@@ -15,21 +15,11 @@
|
||||
*/
|
||||
package com.intellij.openapi.roots.ui.configuration.artifacts.actions;
|
||||
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.libraries.Library;
|
||||
import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable;
|
||||
import com.intellij.openapi.roots.ui.configuration.artifacts.ArtifactsStructureConfigurableContext;
|
||||
import com.intellij.openapi.roots.ui.configuration.artifacts.nodes.ArtifactsTreeNode;
|
||||
import com.intellij.openapi.roots.ui.configuration.projectRoot.FindUsagesInProjectStructureActionBase;
|
||||
import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext;
|
||||
import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.LibraryProjectStructureElement;
|
||||
import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ModuleProjectStructureElement;
|
||||
import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement;
|
||||
import com.intellij.packaging.artifacts.Artifact;
|
||||
import com.intellij.ui.awt.RelativePoint;
|
||||
import com.intellij.ui.treeStructure.Tree;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
@@ -38,7 +28,7 @@ import java.awt.*;
|
||||
*/
|
||||
public abstract class ArtifactEditorFindUsagesActionBase extends FindUsagesInProjectStructureActionBase {
|
||||
private final Tree myTree;
|
||||
private final ArtifactsStructureConfigurableContext myArtifactContext;
|
||||
protected final ArtifactsStructureConfigurableContext myArtifactContext;
|
||||
|
||||
public ArtifactEditorFindUsagesActionBase(Tree tree, Project project, ArtifactsStructureConfigurableContext artifactContext) {
|
||||
super(tree, project);
|
||||
@@ -47,33 +37,9 @@ public abstract class ArtifactEditorFindUsagesActionBase extends FindUsagesInPro
|
||||
}
|
||||
|
||||
protected boolean isEnabled() {
|
||||
ArtifactsTreeNode node = getSelectedNode();
|
||||
return node != null && node.getElementPresentation().getSourceObject() != null;
|
||||
return getSelectedElement() != null;
|
||||
}
|
||||
|
||||
protected ProjectStructureElement getSelectedElement() {
|
||||
ArtifactsTreeNode node = getSelectedNode();
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Object sourceObject = node.getElementPresentation().getSourceObject();
|
||||
final StructureConfigurableContext context = ProjectStructureConfigurable.getInstance(getContext().getProject()).getContext();
|
||||
if (sourceObject instanceof Module) {
|
||||
return new ModuleProjectStructureElement(context, (Module)sourceObject);
|
||||
}
|
||||
else if (sourceObject instanceof Library) {
|
||||
return new LibraryProjectStructureElement(context, (Library)sourceObject);
|
||||
}
|
||||
else if (sourceObject instanceof Artifact) {
|
||||
return myArtifactContext.getOrCreateArtifactElement((Artifact)sourceObject);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected abstract ArtifactsTreeNode getSelectedNode();
|
||||
|
||||
protected RelativePoint getPointToShowResults() {
|
||||
final int selectedRow = myTree.getSelectionRows()[0];
|
||||
final Rectangle rowBounds = myTree.getRowBounds(selectedRow);
|
||||
|
||||
+8
-7
@@ -16,10 +16,11 @@
|
||||
package com.intellij.openapi.roots.ui.configuration.artifacts.actions;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ui.configuration.artifacts.ArtifactProjectStructureElement;
|
||||
import com.intellij.openapi.roots.ui.configuration.artifacts.ArtifactsStructureConfigurableContext;
|
||||
import com.intellij.openapi.roots.ui.configuration.artifacts.LayoutTreeComponent;
|
||||
import com.intellij.openapi.roots.ui.configuration.artifacts.nodes.ArtifactsTreeNode;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement;
|
||||
import com.intellij.packaging.elements.PackagingElement;
|
||||
|
||||
/**
|
||||
* @author nik
|
||||
@@ -32,10 +33,10 @@ public class LayoutTreeFindUsagesAction extends ArtifactEditorFindUsagesActionBa
|
||||
myLayoutTreeComponent = layoutTreeComponent;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected ArtifactsTreeNode getSelectedNode() {
|
||||
return myLayoutTreeComponent.getSelection().getNodeIfSingle();
|
||||
}
|
||||
protected ProjectStructureElement getSelectedElement() {
|
||||
PackagingElement<?> packagingElement = myLayoutTreeComponent.getSelection().getElementIfSingle();
|
||||
if (packagingElement == null) return null;
|
||||
|
||||
return ArtifactProjectStructureElement.getProjectStructureElementFor(packagingElement, getContext(), myArtifactContext);
|
||||
}
|
||||
}
|
||||
|
||||
-5
@@ -57,11 +57,6 @@ public class DelegatedSourceItemPresentation extends SourceItemPresentation {
|
||||
myPresentation.navigateToSource();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Object getSourceObject() {
|
||||
return myPresentation.getSourceObject();
|
||||
}
|
||||
|
||||
public int getWeight() {
|
||||
return myPresentation.getWeight();
|
||||
}
|
||||
|
||||
-5
@@ -90,11 +90,6 @@ public class LibrarySourceItem extends PackagingSourceItem {
|
||||
myContext.selectLibrary(myLibrary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSourceObject() {
|
||||
return myLibrary;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPresentableName() {
|
||||
final String name = myLibrary.getName();
|
||||
|
||||
+4
@@ -38,6 +38,10 @@ public class ModuleOutputSourceItem extends PackagingSourceItem {
|
||||
myModule = module;
|
||||
}
|
||||
|
||||
public Module getModule() {
|
||||
return myModule;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof ModuleOutputSourceItem && myModule.equals(((ModuleOutputSourceItem)obj).myModule);
|
||||
}
|
||||
|
||||
-5
@@ -140,11 +140,6 @@ public class ModuleSourceItemGroup extends PackagingSourceItem {
|
||||
myContext.selectModule(myModule);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSourceObject() {
|
||||
return myModule;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWeight() {
|
||||
return SourceItemWeights.MODULE_WEIGHT;
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ public class SourceItemNode extends SourceItemNodeBase {
|
||||
}
|
||||
}
|
||||
|
||||
protected PackagingSourceItem getSourceItem() {
|
||||
public PackagingSourceItem getSourceItem() {
|
||||
return mySourceItem;
|
||||
}
|
||||
}
|
||||
|
||||
+27
-5
@@ -19,8 +19,12 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ui.configuration.artifacts.ArtifactsStructureConfigurableContext;
|
||||
import com.intellij.openapi.roots.ui.configuration.artifacts.actions.ArtifactEditorFindUsagesActionBase;
|
||||
import com.intellij.openapi.roots.ui.configuration.artifacts.nodes.ArtifactsTreeNode;
|
||||
import com.intellij.openapi.roots.ui.configuration.artifacts.sourceItems.SourceItemNode;
|
||||
import com.intellij.openapi.roots.ui.configuration.artifacts.sourceItems.SourceItemsTree;
|
||||
import com.intellij.openapi.roots.ui.configuration.artifacts.sourceItems.*;
|
||||
import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext;
|
||||
import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.LibraryProjectStructureElement;
|
||||
import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ModuleProjectStructureElement;
|
||||
import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement;
|
||||
import com.intellij.packaging.ui.PackagingSourceItem;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -35,9 +39,27 @@ public class SourceItemFindUsagesAction extends ArtifactEditorFindUsagesActionBa
|
||||
myTree = tree;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ArtifactsTreeNode getSelectedNode() {
|
||||
protected ProjectStructureElement getSelectedElement() {
|
||||
final List<SourceItemNode> nodes = myTree.getSelectedSourceItemNodes();
|
||||
return nodes.size() == 1 ? nodes.get(0) : null;
|
||||
if (nodes.size() != 1) return null;
|
||||
ArtifactsTreeNode node = nodes.get(0);
|
||||
if (!(node instanceof SourceItemNode)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PackagingSourceItem sourceItem = ((SourceItemNode)node).getSourceItem();
|
||||
if (sourceItem == null) return null;
|
||||
|
||||
final StructureConfigurableContext context = getContext();
|
||||
if (sourceItem instanceof ModuleOutputSourceItem) {
|
||||
return new ModuleProjectStructureElement(context, ((ModuleOutputSourceItem)sourceItem).getModule());
|
||||
}
|
||||
else if (sourceItem instanceof LibrarySourceItem) {
|
||||
return new LibraryProjectStructureElement(context, ((LibrarySourceItem)sourceItem).getLibrary());
|
||||
}
|
||||
else if (sourceItem instanceof ArtifactSourceItem) {
|
||||
return myArtifactContext.getOrCreateArtifactElement(((ArtifactSourceItem)sourceItem).getArtifact());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+12
-4
@@ -23,7 +23,8 @@ import com.intellij.facet.impl.ui.FacetEditorImpl;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.project.ProjectBundle;
|
||||
import com.intellij.openapi.roots.ui.configuration.ModulesConfigurator;
|
||||
import com.intellij.openapi.ui.NamedConfigurable;
|
||||
import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.FacetProjectStructureElement;
|
||||
import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -33,16 +34,18 @@ import javax.swing.*;
|
||||
/**
|
||||
* @author nik
|
||||
*/
|
||||
public class FacetConfigurable extends NamedConfigurable<Facet> {
|
||||
public class FacetConfigurable extends ProjectStructureElementConfigurable<Facet> {
|
||||
private final Facet myFacet;
|
||||
private final ModulesConfigurator myModulesConfigurator;
|
||||
private String myFacetName;
|
||||
private FacetProjectStructureElement myProjectStructureElement;
|
||||
|
||||
public FacetConfigurable(final Facet facet, final ModulesConfigurator modulesConfigurator, final Runnable updateTree) {
|
||||
public FacetConfigurable(final Facet facet, final StructureConfigurableContext context, final Runnable updateTree) {
|
||||
super(!facet.getType().isOnlyOneFacetAllowed() && !(facet instanceof InvalidFacet), updateTree);
|
||||
myFacet = facet;
|
||||
myModulesConfigurator = modulesConfigurator;
|
||||
myModulesConfigurator = context.getModulesConfigurator();
|
||||
myFacetName = myFacet.getName();
|
||||
myProjectStructureElement = new FacetProjectStructureElement(context, facet);
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +57,11 @@ public class FacetConfigurable extends NamedConfigurable<Facet> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectStructureElement getProjectStructureElement() {
|
||||
return myProjectStructureElement;
|
||||
}
|
||||
|
||||
private ProjectFacetsConfigurator getFacetsConfigurator() {
|
||||
return myModulesConfigurator.getFacetsConfigurator();
|
||||
}
|
||||
|
||||
+1
-1
@@ -87,7 +87,7 @@ public class FacetEditorFacadeImpl implements FacetEditorFacade {
|
||||
public FacetConfigurable getOrCreateConfigurable(final Facet facet) {
|
||||
FacetConfigurable configurable = myConfigurables.get(facet);
|
||||
if (configurable == null) {
|
||||
configurable = new FacetConfigurable(facet, myStructureConfigurable.getContext().getModulesConfigurator(), myTreeUpdater);
|
||||
configurable = new FacetConfigurable(facet, myStructureConfigurable.getContext(), myTreeUpdater);
|
||||
myConfigurables.put(facet, configurable);
|
||||
}
|
||||
return configurable;
|
||||
|
||||
+19
@@ -36,6 +36,8 @@ import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectBundle;
|
||||
import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable;
|
||||
import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.FacetProjectStructureElement;
|
||||
import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement;
|
||||
import com.intellij.openapi.ui.DetailsComponent;
|
||||
import com.intellij.openapi.ui.NamedConfigurable;
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
@@ -99,6 +101,19 @@ public class FacetStructureConfigurable extends BaseStructureConfigurable {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Collection<? extends ProjectStructureElement> getProjectStructureElements() {
|
||||
List<ProjectStructureElement> elements = new ArrayList<ProjectStructureElement>();
|
||||
for (Module module : myModuleManager.getModules()) {
|
||||
Facet[] facets = FacetManager.getInstance(module).getAllFacets();
|
||||
for (Facet facet : facets) {
|
||||
elements.add(new FacetProjectStructureElement(myContext, facet));
|
||||
}
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
|
||||
public MyNode findFacetTypeNode(FacetType facetType) {
|
||||
return findNodeByObject(myRoot, facetType);
|
||||
}
|
||||
@@ -106,6 +121,7 @@ public class FacetStructureConfigurable extends BaseStructureConfigurable {
|
||||
public void addFacetNode(@NotNull MyNode facetTypeNode, @NotNull Facet facet, @NotNull FacetEditorFacadeImpl editorFacade) {
|
||||
FacetConfigurable facetConfigurable = editorFacade.getOrCreateConfigurable(facet);
|
||||
addNode(new FacetConfigurableNode(facetConfigurable), facetTypeNode);
|
||||
myContext.getDaemonAnalyzer().queueUpdate(new FacetProjectStructureElement(myContext, facet));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -177,6 +193,9 @@ public class FacetStructureConfigurable extends BaseStructureConfigurable {
|
||||
protected List<Facet> removeFacet(final Facet facet) {
|
||||
List<Facet> removed = super.removeFacet(facet);
|
||||
ModuleStructureConfigurable.getInstance(myProject).removeFacetNodes(removed);
|
||||
for (Facet removedFacet : removed) {
|
||||
myContext.getDaemonAnalyzer().removeElement(new FacetProjectStructureElement(myContext, removedFacet));
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.roots.ui.configuration.projectRoot.daemon;
|
||||
|
||||
import com.intellij.facet.Facet;
|
||||
import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author nik
|
||||
*/
|
||||
public class FacetProjectStructureElement extends ProjectStructureElement {
|
||||
private final Facet myFacet;
|
||||
|
||||
public FacetProjectStructureElement(@NotNull StructureConfigurableContext context, @NotNull Facet facet) {
|
||||
super(context);
|
||||
myFacet = facet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void check(ProjectStructureProblemsHolder problemsHolder) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProjectStructureElementUsage> getUsagesInElement() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean highlightIfUnused() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof FacetProjectStructureElement && myFacet.equals(((FacetProjectStructureElement)obj).myFacet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return myFacet.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "facet:" + myFacet.getName() + " in " + myFacet.getModule().getName();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -74,7 +74,7 @@ public class NullableStuffInspection extends BaseLocalInspectionTool {
|
||||
final PsiParameterList parameterList = psiMethod.getParameterList();
|
||||
final PsiParameter[] parameters = parameterList.getParameters();
|
||||
final PsiExpression[] expressions = expression.getArgumentList().getExpressions();
|
||||
for (int i = 0, expressionsLength = expressions.length; i < Math.max(expressionsLength, parameters.length); i++) {
|
||||
for (int i = 0, expressionsLength = expressions.length; i < Math.min(expressionsLength, parameters.length); i++) {
|
||||
PsiExpression psiExpression = expressions[i];
|
||||
if (psiExpression.getType() == PsiType.NULL) {
|
||||
if (!AnnotationUtil.isNullable(parameters[i]) && !AnnotationUtil.isNotNull(parameters[i])) {
|
||||
|
||||
@@ -52,12 +52,12 @@ class AnchorElementInfo extends SelfElementInfo {
|
||||
@Nullable
|
||||
public PsiElement restoreElement() {
|
||||
if (stubId != -1) {
|
||||
PsiFile file = SelfElementInfo.restoreFileFromVirtual(myVirtualFile, myProject);
|
||||
PsiFile file = SelfElementInfo.restoreFileFromVirtual(getVirtualFile(), myProject);
|
||||
if (!(file instanceof PsiFileWithStubSupport)) return null;
|
||||
return PsiAnchor.restoreFromStubIndex((PsiFileWithStubSupport)file, stubId, myStubElementType);
|
||||
}
|
||||
if (!mySyncMarkerIsValid) return null;
|
||||
PsiFile file = SelfElementInfo.restoreFileFromVirtual(myVirtualFile, myProject);
|
||||
PsiFile file = SelfElementInfo.restoreFileFromVirtual(getVirtualFile(), myProject);
|
||||
if (file == null) return null;
|
||||
PsiElement anchor = file.findElementAt(getSyncStartOffset());
|
||||
if (anchor == null) return null;
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@ public class ImplicitVariableElementInfoFactory implements SmartPointerElementIn
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pointsToTheSameElementAs(SmartPointerElementInfo other) {
|
||||
public boolean pointsToTheSameElementAs(@NotNull SmartPointerElementInfo other) {
|
||||
if (other instanceof ImplicitVariableInfo) {
|
||||
return myVar == ((ImplicitVariableInfo)other).myVar;
|
||||
}
|
||||
|
||||
+105
-26
@@ -19,7 +19,13 @@ import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.codeInsight.intention.impl.TypeExpression;
|
||||
import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
|
||||
import com.intellij.codeInsight.template.impl.TemplateState;
|
||||
import com.intellij.ide.ui.ListCellRendererWrapper;
|
||||
import com.intellij.ide.ui.UISettings;
|
||||
import com.intellij.ide.util.PropertiesComponent;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CustomShortcutSet;
|
||||
import com.intellij.openapi.actionSystem.KeyboardShortcut;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
@@ -28,6 +34,7 @@ import com.intellij.openapi.editor.ScrollType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.wm.ToolWindowManager;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.VariableKind;
|
||||
@@ -42,11 +49,11 @@ import com.intellij.refactoring.ui.TypeSelectorManagerImpl;
|
||||
import com.intellij.refactoring.util.occurences.OccurenceManager;
|
||||
import com.intellij.ui.StateRestoringCheckBox;
|
||||
import com.intellij.ui.TitlePanel;
|
||||
import com.intellij.util.VisibilityUtil;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.awt.event.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
@@ -62,7 +69,7 @@ public class InplaceIntroduceConstantPopup {
|
||||
private PsiExpression myExpr;
|
||||
private final PsiLocalVariable myLocalVariable;
|
||||
private final PsiExpression[] myOccurrences;
|
||||
private final TypeSelectorManagerImpl myTypeSelectorManager;
|
||||
private TypeSelectorManagerImpl myTypeSelectorManager;
|
||||
private PsiElement myAnchorElement;
|
||||
private int myAnchorIdx = -1;
|
||||
private PsiElement myAnchorElementIfAll;
|
||||
@@ -83,7 +90,7 @@ public class InplaceIntroduceConstantPopup {
|
||||
|
||||
private JCheckBox myMoveToAnotherClassCb;
|
||||
|
||||
private JavaVisibilityPanel myVisibilityPanel;
|
||||
private JComboBox myVisibilityCombo;
|
||||
|
||||
private JPanel myWholePanel;
|
||||
|
||||
@@ -122,31 +129,36 @@ public class InplaceIntroduceConstantPopup {
|
||||
myLocalName = localVariable != null ? localVariable.getName() : null;
|
||||
|
||||
myWholePanel = new JPanel(new GridBagLayout());
|
||||
GridBagConstraints gc = new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0 , 0, 0), 0, 0);
|
||||
GridBagConstraints gc = new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0 , 0, 0), 0, 0);
|
||||
|
||||
final TitlePanel titlePanel = new TitlePanel();
|
||||
titlePanel.setBorder(null);
|
||||
titlePanel.setText(IntroduceConstantHandler.REFACTORING_NAME);
|
||||
|
||||
gc.gridwidth = 2;
|
||||
myWholePanel.add(titlePanel, gc);
|
||||
|
||||
gc.insets = new Insets(5, 5, 5, 5);
|
||||
gc.gridwidth = 1;
|
||||
gc.gridy = 1;
|
||||
myWholePanel.add(createLeftPanel(), gc);
|
||||
|
||||
myVisibilityPanel = new JavaVisibilityPanel(false, false);
|
||||
myVisibilityPanel.setVisibility(JavaRefactoringSettings.getInstance().INTRODUCE_CONSTANT_VISIBILITY);
|
||||
myWholePanel.add(myVisibilityPanel, gc);
|
||||
gc.gridx = 1;
|
||||
gc.insets.left = 6;
|
||||
myWholePanel.add(createRightPanel(), gc);
|
||||
|
||||
}
|
||||
|
||||
private JPanel createRightPanel() {
|
||||
final JPanel right = new JPanel(new GridBagLayout());
|
||||
final GridBagConstraints rgc = new GridBagConstraints(0, GridBagConstraints.RELATIVE,1,1,0,0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(1,0,0,0), 0, 0);
|
||||
myReplaceAllCb = new JCheckBox("Replace all occurrences");
|
||||
myReplaceAllCb.setMnemonic('a');
|
||||
myReplaceAllCb.setFocusable(false);
|
||||
myWholePanel.add(myReplaceAllCb, gc);
|
||||
myReplaceAllCb.setVisible(myOccurrences.length > 1);
|
||||
|
||||
right.add(myReplaceAllCb, rgc);
|
||||
|
||||
myCbDeleteVariable = new StateRestoringCheckBox("Delete variable declaration");
|
||||
myCbDeleteVariable.setMnemonic('d');
|
||||
myCbDeleteVariable.setFocusable(false);
|
||||
myWholePanel.add(myCbDeleteVariable, gc);
|
||||
if (myLocalVariable != null) {
|
||||
if (myReplaceAllCb != null) {
|
||||
myReplaceAllCb.setEnabled(false);
|
||||
@@ -157,15 +169,15 @@ public class InplaceIntroduceConstantPopup {
|
||||
} else {
|
||||
myCbDeleteVariable.setVisible(false);
|
||||
}
|
||||
right.add(myCbDeleteVariable, rgc);
|
||||
|
||||
myAnnotateNonNls = new JCheckBox("Annotate field as @NonNls");
|
||||
myAnnotateNonNls.setMnemonic('f');
|
||||
myAnnotateNonNls.setFocusable(false);
|
||||
myWholePanel.add(myAnnotateNonNls, gc);
|
||||
final PsiManager psiManager = PsiManager.getInstance(myProject);
|
||||
if ((myTypeSelectorManager.isSuggestedType("java.lang.String") || (myLocalVariable != null && AnnotationUtil.isAnnotated(myLocalVariable, AnnotationUtil.NON_NLS, false)))&&
|
||||
LanguageLevelProjectExtension.getInstance(psiManager.getProject()).getLanguageLevel().hasEnumKeywordAndAutoboxing() &&
|
||||
JavaPsiFacade.getInstance(psiManager.getProject()).findClass(AnnotationUtil.NON_NLS, myParentClass.getResolveScope()) != null) {
|
||||
if ((myTypeSelectorManager.isSuggestedType("java.lang.String") || (myLocalVariable != null && AnnotationUtil
|
||||
.isAnnotated(myLocalVariable, AnnotationUtil.NON_NLS, false)))&&
|
||||
LanguageLevelProjectExtension.getInstance(myProject).getLanguageLevel().hasEnumKeywordAndAutoboxing() &&
|
||||
JavaPsiFacade.getInstance(myProject).findClass(AnnotationUtil.NON_NLS, myParentClass.getResolveScope()) != null) {
|
||||
final PropertiesComponent component = PropertiesComponent.getInstance(myProject);
|
||||
myAnnotateNonNls.setSelected(component.isTrueValue(IntroduceConstantDialog.NONNLS_SELECTED_PROPERTY));
|
||||
myAnnotateNonNls.addItemListener(new ItemListener() {
|
||||
@@ -176,13 +188,69 @@ public class InplaceIntroduceConstantPopup {
|
||||
} else {
|
||||
myAnnotateNonNls.setVisible(false);
|
||||
}
|
||||
right.add(myAnnotateNonNls, rgc);
|
||||
return right;
|
||||
}
|
||||
|
||||
private JPanel createLeftPanel() {
|
||||
final JPanel left = new JPanel(new GridBagLayout());
|
||||
final GridBagConstraints lgc = new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(5,5,0,0), 0, 0);
|
||||
|
||||
final JLabel label = new JLabel("Visibility:");
|
||||
label.setDisplayedMnemonic('V');
|
||||
left.add(label, lgc);
|
||||
myVisibilityCombo = new JComboBox(new String[]{PsiModifier.PUBLIC, PsiModifier.PACKAGE_LOCAL, PsiModifier.PROTECTED, PsiModifier.PRIVATE});
|
||||
myVisibilityCombo.setRenderer(new ListCellRendererWrapper<String>(myVisibilityCombo.getRenderer()){
|
||||
@Override
|
||||
public void customize(JList list, String value, int index, boolean selected, boolean hasFocus) {
|
||||
setText(PsiBundle.visibilityPresentation(value));
|
||||
}
|
||||
});
|
||||
label.setLabelFor(myVisibilityCombo);
|
||||
myVisibilityCombo.setSelectedItem(JavaRefactoringSettings.getInstance().INTRODUCE_CONSTANT_VISIBILITY);
|
||||
myVisibilityCombo.addKeyListener(new KeyAdapter() {
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
|
||||
ToolWindowManager.getInstance(myProject).activateEditorComponent();
|
||||
}
|
||||
}
|
||||
});
|
||||
final AnAction arrow = new AnAction() {
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
if (e.getInputEvent() instanceof KeyEvent) {
|
||||
final int code = ((KeyEvent)e.getInputEvent()).getKeyCode();
|
||||
final int delta = code == KeyEvent.VK_DOWN ? 1 : code == KeyEvent.VK_UP ? -1 : 0;
|
||||
if (delta == 0) return;
|
||||
final int size = myVisibilityCombo.getModel().getSize();
|
||||
int next = myVisibilityCombo.getSelectedIndex() + delta;
|
||||
if (next < 0 || next >= size) {
|
||||
if (!UISettings.getInstance().CYCLE_SCROLLING) {
|
||||
return;
|
||||
}
|
||||
next = (next + size) % size;
|
||||
}
|
||||
myVisibilityCombo.setSelectedIndex(next);
|
||||
}
|
||||
}
|
||||
};
|
||||
arrow.registerCustomShortcutSet(new CustomShortcutSet(new KeyboardShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), null),
|
||||
new KeyboardShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), null)), myVisibilityCombo);
|
||||
lgc.gridx = 1;
|
||||
lgc.insets.top = 2;
|
||||
lgc.insets.left = 0;
|
||||
left.add(myVisibilityCombo, lgc);
|
||||
|
||||
myMoveToAnotherClassCb = new JCheckBox("Move to another class");
|
||||
myMoveToAnotherClassCb.setMnemonic('m');
|
||||
myMoveToAnotherClassCb.setFocusable(false);
|
||||
myWholePanel.add(myMoveToAnotherClassCb, gc);
|
||||
|
||||
|
||||
lgc.gridx = 0;
|
||||
lgc.gridy = 1;
|
||||
lgc.gridwidth = 2;
|
||||
lgc.insets.top = 0;
|
||||
left.add(myMoveToAnotherClassCb, lgc);
|
||||
return left;
|
||||
}
|
||||
|
||||
public void performInplaceIntroduce() {
|
||||
@@ -220,7 +288,7 @@ public class InplaceIntroduceConstantPopup {
|
||||
PsiField field = elementFactory.createFieldFromText(psiType.getCanonicalText() + " " + (myConstantName != null ? myConstantName : names[0]) + " = " + myExprText + ";", myParentClass);
|
||||
PsiUtil.setModifierProperty(field, PsiModifier.FINAL, true);
|
||||
PsiUtil.setModifierProperty(field, PsiModifier.STATIC, true);
|
||||
final String visibility = myVisibilityPanel.getVisibility();
|
||||
final String visibility = getSelectedVisibility();
|
||||
if (visibility != null) {
|
||||
PsiUtil.setModifierProperty(field, visibility, true);
|
||||
}
|
||||
@@ -230,6 +298,10 @@ public class InplaceIntroduceConstantPopup {
|
||||
});
|
||||
}
|
||||
|
||||
private String getSelectedVisibility() {
|
||||
return (String)myVisibilityCombo.getSelectedItem();
|
||||
}
|
||||
|
||||
public List<RangeMarker> getOccurrenceMarkers() {
|
||||
if (myOccurrenceMarkers == null) {
|
||||
myOccurrenceMarkers = new ArrayList<RangeMarker>();
|
||||
@@ -301,7 +373,7 @@ public class InplaceIntroduceConstantPopup {
|
||||
@Override
|
||||
protected void saveSettings(PsiVariable psiVariable) {
|
||||
TypeSelectorManagerImpl.typeSelected(psiVariable.getType(), myDefaultParameterTypePointer.getType());
|
||||
JavaRefactoringSettings.getInstance().INTRODUCE_CONSTANT_VISIBILITY = myVisibilityPanel.getVisibility();
|
||||
JavaRefactoringSettings.getInstance().INTRODUCE_CONSTANT_VISIBILITY = getSelectedVisibility();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -321,7 +393,7 @@ public class InplaceIntroduceConstantPopup {
|
||||
isReplaceAllOccurrences(), true,
|
||||
true,
|
||||
BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION,
|
||||
myVisibilityPanel.getVisibility(), myLocalVariable,
|
||||
getSelectedVisibility(), myLocalVariable,
|
||||
myFieldTypePointer.getType(),
|
||||
isDeleteVariable(),
|
||||
myParentClass, isAnnotateNonNls(), false);
|
||||
@@ -358,10 +430,16 @@ public class InplaceIntroduceConstantPopup {
|
||||
protected JComponent getComponent() {
|
||||
if (!myInitListeners) {
|
||||
myInitListeners = true;
|
||||
myVisibilityPanel.addListener(new VisibilityListener(myProject, myEditor){
|
||||
final VisibilityListener visibilityListener = new VisibilityListener(myProject, myEditor) {
|
||||
@Override
|
||||
protected String getVisibility() {
|
||||
return myVisibilityPanel.getVisibility();
|
||||
return getSelectedVisibility();
|
||||
}
|
||||
};
|
||||
myVisibilityCombo.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
visibilityListener.stateChanged(null);
|
||||
}
|
||||
});
|
||||
myReplaceAllCb.addItemListener(new ItemListener() {
|
||||
@@ -370,6 +448,7 @@ public class InplaceIntroduceConstantPopup {
|
||||
final TemplateState templateState = TemplateManagerImpl.getTemplateState(myEditor);
|
||||
if (templateState != null) {
|
||||
templateState.gotoEnd(true);
|
||||
myTypeSelectorManager = new TypeSelectorManagerImpl(myProject, myFieldTypePointer.getType(), null, myExpr, myOccurrences);
|
||||
startIntroduceTemplate(isReplaceAllOccurrences());
|
||||
}
|
||||
}
|
||||
|
||||
+13
-11
@@ -59,7 +59,7 @@ public class InplaceIntroduceFieldPopup {
|
||||
private final Editor myEditor;
|
||||
private Project myProject;
|
||||
|
||||
private final TypeSelectorManagerImpl myTypeSelectorManager;
|
||||
private TypeSelectorManagerImpl myTypeSelectorManager;
|
||||
private final PsiElement myAnchorElement;
|
||||
private int myAnchorIdx = -1;
|
||||
private final PsiElement myAnchorElementIfAll;
|
||||
@@ -136,16 +136,7 @@ public class InplaceIntroduceFieldPopup {
|
||||
|
||||
myWholePanel.add(myIntroduceFieldPanel.createCenterPanel(), gc);
|
||||
myIntroduceFieldPanel.initializeControls(initializerExpression, ourLastInitializerPlace);
|
||||
myIntroduceFieldPanel.addOccurrenceListener(new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
final TemplateState templateState = TemplateManagerImpl.getTemplateState(myEditor);
|
||||
if (templateState != null) {
|
||||
templateState.gotoEnd(true);
|
||||
startTemplate(myIntroduceFieldPanel.isReplaceAllOccurrences());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -298,6 +289,17 @@ public class InplaceIntroduceFieldPopup {
|
||||
finalListener.perform(myIntroduceFieldPanel.isDeclareFinal());
|
||||
}
|
||||
});
|
||||
myIntroduceFieldPanel.addOccurrenceListener(new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
final TemplateState templateState = TemplateManagerImpl.getTemplateState(myEditor);
|
||||
if (templateState != null) {
|
||||
templateState.gotoEnd(true);
|
||||
myTypeSelectorManager = new TypeSelectorManagerImpl(myProject, myFieldTypePointer.getType(), null, myInitializerExpression, myOccurrences);
|
||||
startTemplate(myIntroduceFieldPanel.isReplaceAllOccurrences());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return myWholePanel;
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -10,7 +10,7 @@ commons-logging-1.1.1.jar
|
||||
commons-net-2.0-patched.jar
|
||||
dtdparser113.jar
|
||||
groovy-all-1.7.3.jar
|
||||
guava-r08.jar
|
||||
guava-r09.jar
|
||||
jaxen-1.1.3.jar
|
||||
jcip-annotations.jar
|
||||
jdom.jar
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -16,6 +16,7 @@
|
||||
package com.intellij.psi;
|
||||
|
||||
import com.intellij.openapi.util.Segment;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* pointer to a PsiFile + range inside the file.
|
||||
@@ -25,5 +26,6 @@ public interface SmartPsiFileRange extends SmartPsiElementPointer<PsiFile> {
|
||||
/**
|
||||
* @return the range inside the PsiFile, or null if the range or PsiFile became invalid
|
||||
*/
|
||||
@Nullable
|
||||
Segment getRange();
|
||||
}
|
||||
|
||||
@@ -97,11 +97,11 @@ public abstract class ElementBase extends UserDataHolderBase implements Iconable
|
||||
baseIcon = myBaseIcon.get(flags);
|
||||
}
|
||||
|
||||
if (!psiElement.isValid()) return null;
|
||||
if (isToDeferIconLoading()) {
|
||||
return IconDeferrer.getInstance().defer(baseIcon, new ElementIconRequest(psiElement, flags), ICON_COMPUTE);
|
||||
}
|
||||
else {
|
||||
if (!psiElement.isValid()) return null;
|
||||
return computeIconNow(psiElement, flags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ public class IndentsPass extends TextEditorHighlightingPass implements DumbAware
|
||||
int newY = start.y;
|
||||
SoftWrapModel softWrapModel = editor.getSoftWrapModel();
|
||||
int lineHeight = editor.getLineHeight();
|
||||
for (int i = startLine + lineShift; i < endLine && newY < maxY; i++) {
|
||||
for (int i = Math.max(0, startLine + lineShift); i < endLine && newY < maxY; i++) {
|
||||
List<? extends SoftWrap> softWraps = softWrapModel.getSoftWrapsForLine(i);
|
||||
int logicalLineHeight = softWraps.size() * lineHeight;
|
||||
if (i > startLine + lineShift) {
|
||||
|
||||
+18
-2
@@ -28,6 +28,7 @@ import com.intellij.ide.DataManager;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.LogicalPosition;
|
||||
import com.intellij.openapi.editor.ScrollType;
|
||||
@@ -42,8 +43,10 @@ import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.impl.source.codeStyle.CodeEditUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.codeInsight.editorActions.JoinLinesHandlerDelegate.CANNOT_JOIN;
|
||||
|
||||
@@ -160,7 +163,7 @@ public class JoinLinesHandler extends EditorWriteActionHandler {
|
||||
if (rc != CANNOT_JOIN) break;
|
||||
}
|
||||
}
|
||||
docManager.doPostponedOperationsAndUnblockDocument(doc);
|
||||
doPostponedOperationsAndUnblockDocument(docManager, doc);
|
||||
|
||||
if (rc != CANNOT_JOIN) {
|
||||
if (caretRestoreOffset == CANNOT_JOIN) caretRestoreOffset = rc;
|
||||
@@ -209,7 +212,7 @@ public class JoinLinesHandler extends EditorWriteActionHandler {
|
||||
}
|
||||
|
||||
if (prevLineCount < doc.getLineCount()) {
|
||||
docManager.doPostponedOperationsAndUnblockDocument(doc);
|
||||
doPostponedOperationsAndUnblockDocument(docManager, doc);
|
||||
end = doc.getLineEndOffset(startLine) + doc.getLineSeparatorLength(startLine);
|
||||
start = end - doc.getLineSeparatorLength(startLine);
|
||||
int addedLinesCount = doc.getLineCount() - prevLineCount - 1;
|
||||
@@ -235,6 +238,19 @@ public class JoinLinesHandler extends EditorWriteActionHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private static void doPostponedOperationsAndUnblockDocument(@NotNull PsiDocumentManager docManager, @NotNull DocumentEx document) {
|
||||
boolean restore = CodeEditUtil.isSuspendedNodesReformattingAllowed();
|
||||
CodeEditUtil.setAllowSuspendNodesReformatting(false);
|
||||
try {
|
||||
docManager.doPostponedOperationsAndUnblockDocument(document);
|
||||
}
|
||||
finally {
|
||||
if (restore) {
|
||||
CodeEditUtil.setAllowSuspendNodesReformatting(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isCommentElement(final PsiElement element) {
|
||||
return element != null && PsiTreeUtil.getParentOfType(element, PsiComment.class, false) != null;
|
||||
}
|
||||
|
||||
@@ -45,8 +45,11 @@ class FoldingUtil {
|
||||
}
|
||||
|
||||
public static FoldRegion findFoldRegionStartingAtLine(Editor editor, int line){
|
||||
FoldRegion[] regions = editor.getFoldingModel().getAllFoldRegions();
|
||||
FoldRegion result = null;
|
||||
if (line >= editor.getDocument().getLineCount()) {
|
||||
return result;
|
||||
}
|
||||
FoldRegion[] regions = editor.getFoldingModel().getAllFoldRegions();
|
||||
for (FoldRegion region : regions) {
|
||||
if (region.getDocument().getLineNumber(region.getStartOffset()) == line) {
|
||||
if (result != null) return null;
|
||||
|
||||
@@ -0,0 +1,604 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.impl;
|
||||
|
||||
import com.intellij.execution.filters.HyperlinkInfo;
|
||||
import com.intellij.execution.ui.ConsoleViewContentType;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import gnu.trove.TIntArrayList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.execution.impl.ConsoleViewImpl.HyperlinkTokenInfo;
|
||||
import static com.intellij.execution.impl.ConsoleViewImpl.TokenInfo;
|
||||
|
||||
/**
|
||||
* IJ user may want the console to use cyclic buffer, i.e. don't keep more than particular amount of symbols. So, we need
|
||||
* to have a data structure that allow to achieve that. This class serves for that purpose.
|
||||
* <p/>
|
||||
* Not thread-safe.
|
||||
* <p/>
|
||||
* <b>Note:</b> basically this class consists of functionality that is cut from {@link ConsoleViewImpl} in order to make it possible
|
||||
* to cover it by tests.
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 4/5/11 5:26 PM
|
||||
*/
|
||||
public class ConsoleBuffer {
|
||||
|
||||
private static final int DEFAULT_CYCLIC_BUFFER_UNIT_SIZE = 256;
|
||||
|
||||
private static final boolean DEBUG_PROCESSING = false;
|
||||
|
||||
/**
|
||||
* Buffer for deferred stdout, stderr and stdin output.
|
||||
* <p/>
|
||||
* Feel free to check rationale for using this approach at {@link #myCyclicBufferSize} contract.
|
||||
*/
|
||||
private final Deque<StringBuilder> myDeferredOutput = new ArrayDeque<StringBuilder>();
|
||||
private final Set<ConsoleViewContentType> myContentTypesToNotStripOnCycling = new HashSet<ConsoleViewContentType>();
|
||||
|
||||
/**
|
||||
* Main console usage scenario assumes the following:
|
||||
* <pre>
|
||||
* <ul>
|
||||
* <li>
|
||||
* console may be {@link ConsoleViewImpl#print(String, ConsoleViewContentType) provided} with the new text from any thread
|
||||
* (e.g. separate thread is charged for reading output of java application launched under IJ. That output is provided
|
||||
* to the console);
|
||||
* </li>
|
||||
* <li>current class flushes provided text to {@link Editor editor} used for representing it to end-user from EDT;</li>
|
||||
* <li>
|
||||
* dedicated buffer is kept to hold console text between the moment when it's provided to the current class
|
||||
* and flush to the editor;</li>
|
||||
* </ul>
|
||||
* </pre>
|
||||
* <p/>
|
||||
* It's also possible to configure console to use cyclic buffer in order to avoid unnecessary memory consumption.
|
||||
* However, that implies possibility of the following situation - console user provides it with the great number
|
||||
* of small chunks of text (that is the case for junit processing). It's inappropriate to use single {@link StringBuilder} as
|
||||
* a buffer then because every time we see that cyclic buffer size is exceeded and we need to cut exceeding text from buffer
|
||||
* start, trailing part is moved to the zero offset. That produces extensive CPU usage in case of great number of small messages
|
||||
* where every such message exceeds cyclic buffer size.
|
||||
* <p/>
|
||||
* That is the reason why we use data structure similar to STL deque here - we hold number of string buffers of small size instead
|
||||
* of the single big buffer. That means that every 'cut at the start' operation requires much less number of trailing symbols
|
||||
* to be moved. Current constant defines default size of that small buffers.
|
||||
*/
|
||||
|
||||
private final int myCyclicBufferSize;
|
||||
private final int myCyclicBufferUnitSize;
|
||||
private final boolean myUseCyclicBuffer;
|
||||
|
||||
/**
|
||||
* Holds information about number of symbols stored at {@link #myDeferredOutput} collection.
|
||||
*/
|
||||
private int myDeferredOutputLength;
|
||||
|
||||
/** Buffer for deferred stdin and stderr output. */
|
||||
private StringBuffer myDeferredUserInput = new StringBuffer();
|
||||
|
||||
/**
|
||||
* Holds information about lexical division by offsets of the text that is not yet pushed to document.
|
||||
* <p/>
|
||||
* Target offsets are anchored to the {@link #myDeferredOutput deferred buffer}.
|
||||
*/
|
||||
private final List<TokenInfo> myDeferredTokens = new ArrayList<TokenInfo>();
|
||||
private final Set<ConsoleViewContentType> myDeferredTypes = new HashSet<ConsoleViewContentType>();
|
||||
|
||||
public ConsoleBuffer() {
|
||||
this(useCycleBuffer(), getCycleBufferSize(), DEFAULT_CYCLIC_BUFFER_UNIT_SIZE);
|
||||
}
|
||||
|
||||
public ConsoleBuffer(boolean useCyclicBuffer, int cyclicBufferSize, int cyclicBufferUnitSize) {
|
||||
myUseCyclicBuffer = useCyclicBuffer;
|
||||
myCyclicBufferSize = cyclicBufferSize;
|
||||
myCyclicBufferUnitSize = cyclicBufferUnitSize;
|
||||
myContentTypesToNotStripOnCycling.add(ConsoleViewContentType.USER_INPUT);
|
||||
}
|
||||
|
||||
private static boolean useCycleBuffer() {
|
||||
final String useCycleBufferProperty = System.getProperty("idea.cycle.buffer.size");
|
||||
return useCycleBufferProperty == null || !"disabled".equalsIgnoreCase(useCycleBufferProperty);
|
||||
}
|
||||
|
||||
private static int getCycleBufferSize() {
|
||||
final String cycleBufferSizeProperty = System.getProperty("idea.cycle.buffer.size");
|
||||
if (cycleBufferSizeProperty == null) return 1024 * 1024;
|
||||
try {
|
||||
return Integer.parseInt(cycleBufferSizeProperty) * 1024;
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
return 1024 * 1024;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isUseCyclicBuffer() {
|
||||
return myUseCyclicBuffer;
|
||||
}
|
||||
|
||||
public int getCyclicBufferSize() {
|
||||
return myCyclicBufferSize;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return myDeferredOutput.isEmpty() || (myDeferredOutput.size() == 1 && myDeferredOutput.getFirst().length() <= 0);
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
return myDeferredOutputLength;
|
||||
}
|
||||
|
||||
public int getUserInputLength() {
|
||||
return myDeferredUserInput.length();
|
||||
}
|
||||
|
||||
public String getUserInput() {
|
||||
return myDeferredUserInput.toString();
|
||||
}
|
||||
|
||||
public List<TokenInfo> getDeferredTokens() {
|
||||
return myDeferredTokens;
|
||||
}
|
||||
|
||||
public Set<ConsoleViewContentType> getDeferredTokenTypes() {
|
||||
return myDeferredTypes;
|
||||
}
|
||||
|
||||
public Deque<StringBuilder> getDeferredOutput() {
|
||||
return myDeferredOutput;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
if (myDeferredOutput.size() > 1) {
|
||||
final StringBuilder buffer = new StringBuilder();
|
||||
for (StringBuilder builder : myDeferredOutput) {
|
||||
buffer.append(builder);
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
else if (myDeferredOutput.size() == 1) {
|
||||
return myDeferredOutput.getFirst().substring(0);
|
||||
}
|
||||
else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This buffer automatically strips text that exceeds {@link #getCycleBufferSize() cyclic buffer size}. However, we may want
|
||||
* to avoid 'significant text' stripping, i.e. don't strip the text of particular type.
|
||||
* <p/>
|
||||
* {@link ConsoleViewContentType#USER_INPUT} is considered to be such a type by default, however, it's possible to overwrite that
|
||||
* via the current method.
|
||||
*
|
||||
* @param types content types that should not be stripped during the buffer's cycling
|
||||
*/
|
||||
public void setContentTypesToNotStripOnCycling(@NotNull Collection<ConsoleViewContentType> types) {
|
||||
myContentTypesToNotStripOnCycling.clear();
|
||||
myContentTypesToNotStripOnCycling.addAll(types);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
if (myUseCyclicBuffer) {
|
||||
myDeferredOutput.clear();
|
||||
myDeferredOutput.add(new StringBuilder(myCyclicBufferUnitSize));
|
||||
}
|
||||
else {
|
||||
for (StringBuilder builder : myDeferredOutput) {
|
||||
builder.setLength(0);
|
||||
}
|
||||
}
|
||||
myDeferredOutputLength = 0;
|
||||
myDeferredTypes.clear();
|
||||
myDeferredUserInput = new StringBuffer();
|
||||
myDeferredTokens.clear();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String cutFirstUserInputLine() {
|
||||
final String text = myDeferredUserInput.substring(0, myDeferredUserInput.length());
|
||||
final int index = Math.max(text.lastIndexOf('\n'), text.lastIndexOf('\r'));
|
||||
if (index < 0) {
|
||||
return null;
|
||||
}
|
||||
final String result = text.substring(0, index + 1);
|
||||
myDeferredUserInput.setLength(0);
|
||||
myDeferredUserInput.append(text.substring(index + 1));
|
||||
return result;
|
||||
}
|
||||
|
||||
public void addUserText(int offset, String text) {
|
||||
myDeferredUserInput.insert(offset, text);
|
||||
}
|
||||
|
||||
public void removeUserText(int startOffset, int endOffset) {
|
||||
myDeferredUserInput.delete(startOffset, endOffset);
|
||||
}
|
||||
|
||||
public void replaceUserText(int startOffset, int endOffset, String text) {
|
||||
myDeferredUserInput.replace(startOffset, endOffset, text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks current buffer to store given text of the given type.
|
||||
*
|
||||
* @param s text to store
|
||||
* @param contentType type of the given text
|
||||
* @param info hyperlink info for the given text (if any)
|
||||
* @return text that is actually stored (there is a possible case that the buffer is full and given text's type
|
||||
* is considered to have lower priority than the stored one, hence, it's better to drop given text completely
|
||||
* or partially) and number of existed symbols removed during storing the given data
|
||||
*/
|
||||
@NotNull
|
||||
public Pair<String, Integer> print(@NotNull String s, @NotNull ConsoleViewContentType contentType, @Nullable HyperlinkInfo info) {
|
||||
int numberOfSymbolsToProceed = s.length();
|
||||
int trimmedSymbolsNumber = myDeferredOutputLength;
|
||||
if (contentType != ConsoleViewContentType.USER_INPUT) {
|
||||
numberOfSymbolsToProceed = trimDeferredOutputIfNecessary(s.length());
|
||||
trimmedSymbolsNumber -= myDeferredOutputLength;
|
||||
}
|
||||
else {
|
||||
trimmedSymbolsNumber = 0;
|
||||
}
|
||||
|
||||
if (numberOfSymbolsToProceed <= 0) {
|
||||
return new Pair<String, Integer>("", 0);
|
||||
}
|
||||
|
||||
if (numberOfSymbolsToProceed < s.length()) {
|
||||
s = s.substring(s.length() - numberOfSymbolsToProceed);
|
||||
}
|
||||
|
||||
myDeferredTypes.add(contentType);
|
||||
|
||||
s = StringUtil.convertLineSeparators(s, !SystemInfo.isMac);
|
||||
|
||||
myDeferredOutputLength += s.length();
|
||||
StringBuilder bufferToUse;
|
||||
if (myDeferredOutput.isEmpty()) {
|
||||
myDeferredOutput.add(bufferToUse = new StringBuilder(myCyclicBufferUnitSize));
|
||||
}
|
||||
else {
|
||||
bufferToUse = myDeferredOutput.getLast();
|
||||
}
|
||||
int offset = 0;
|
||||
while (offset < s.length()) {
|
||||
if (bufferToUse.length() >= myCyclicBufferUnitSize) {
|
||||
myDeferredOutput.add(bufferToUse = new StringBuilder(myCyclicBufferUnitSize));
|
||||
}
|
||||
|
||||
if (bufferToUse.length() < myCyclicBufferUnitSize) {
|
||||
int numberOfSymbolsToAdd = Math.min(myCyclicBufferUnitSize - bufferToUse.length(), s.length() - offset);
|
||||
bufferToUse.append(s.substring(offset, offset + numberOfSymbolsToAdd));
|
||||
offset += numberOfSymbolsToAdd;
|
||||
}
|
||||
}
|
||||
|
||||
if (contentType == ConsoleViewContentType.USER_INPUT) {
|
||||
myDeferredUserInput.append(s);
|
||||
}
|
||||
|
||||
ConsoleUtil.addToken(s.length(), info, contentType, myDeferredTokens);
|
||||
return new Pair<String, Integer>(s, trimmedSymbolsNumber);
|
||||
}
|
||||
|
||||
//private void checkState() {
|
||||
// int bufferOffset = 0;
|
||||
// Iterator<StringBuilder> iterator = myDeferredOutput.iterator();
|
||||
// StringBuilder currentBuffer = null;
|
||||
// int prevTokenEnd = 0;
|
||||
// for (TokenInfo token : myDeferredTokens) {
|
||||
// if (prevTokenEnd != token.startOffset) {
|
||||
// try {
|
||||
// System.out.println("Problem detected!");
|
||||
// System.in.read();
|
||||
// }
|
||||
// catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// prevTokenEnd = token.endOffset;
|
||||
// char c = token.contentType == ConsoleViewContentType.ERROR_OUTPUT ? '2' : '1';
|
||||
// int length = token.getLength();
|
||||
// if (currentBuffer == null) {
|
||||
// currentBuffer = iterator.next();
|
||||
// }
|
||||
//
|
||||
// while (length > 0) {
|
||||
// if (bufferOffset == currentBuffer.length()) {
|
||||
// if (!iterator.hasNext()) {
|
||||
// try {
|
||||
// System.out.println("Problem detected!");
|
||||
// System.in.read();
|
||||
// }
|
||||
// catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// currentBuffer = iterator.next();
|
||||
// bufferOffset = 0;
|
||||
// }
|
||||
// else {
|
||||
// int endOffset = Math.min(bufferOffset + length, currentBuffer.length());
|
||||
// if (token.contentType == ConsoleViewContentType.NORMAL_OUTPUT || token.contentType == ConsoleViewContentType.ERROR_OUTPUT) {
|
||||
// for (int i = bufferOffset; i < endOffset; i++) {
|
||||
// char c1 = currentBuffer.charAt(i);
|
||||
// if (c1 != c && c1 != '\n') {
|
||||
// try {
|
||||
// System.out.println("Problem detected!");
|
||||
// System.in.read();
|
||||
// }
|
||||
// catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// length -= endOffset - bufferOffset;
|
||||
// bufferOffset = endOffset;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
/**
|
||||
* IJ console works as follows - it receives managed process outputs from dedicated thread that serves that process and
|
||||
* pushes it to the {@link Document document} of editor used to represent process console. Important point here is that process
|
||||
* output is received in a control flow of the thread over than EDT but push to the document is performed from EDT. Hence, we
|
||||
* have a potential situation when particular process outputs a lot and EDT is busy or push to the document is performed slowly.
|
||||
* <p/>
|
||||
* We don't want to keep too many information from the underlying process then and want to trim text buffer that holds text
|
||||
* to push to the document then. Current method serves exactly that purpose, i.e. it's expected to be called when new chunk of
|
||||
* text is received from the underlying process and trims existing text buffer if necessary.
|
||||
*
|
||||
* @param numberOfNewSymbols number of symbols read from the managed process output
|
||||
* @return number of newly read symbols that should be accepted
|
||||
*/
|
||||
@SuppressWarnings({"ForLoopReplaceableByForEach"})
|
||||
private int trimDeferredOutputIfNecessary(final int numberOfNewSymbols) {
|
||||
if (!myUseCyclicBuffer || myDeferredOutputLength + numberOfNewSymbols <= myCyclicBufferSize) {
|
||||
return numberOfNewSymbols;
|
||||
}
|
||||
|
||||
final int numberOfSymbolsToRemove = Math.min(myDeferredOutputLength, myDeferredOutputLength + numberOfNewSymbols - myCyclicBufferSize);
|
||||
myDeferredTypes.clear();
|
||||
|
||||
if (DEBUG_PROCESSING) {
|
||||
log("Starting console trimming. Need to delete %d symbols (deferred output length: %d, number of new symbols: %d, "
|
||||
+ "cyclic buffer size: %d). Current state:",
|
||||
numberOfSymbolsToRemove, myDeferredOutputLength, numberOfNewSymbols, myCyclicBufferSize
|
||||
);
|
||||
dumpDeferredOutput();
|
||||
}
|
||||
|
||||
Context context = new Context(numberOfSymbolsToRemove);
|
||||
|
||||
TIntArrayList indicesOfTokensToRemove = new TIntArrayList();
|
||||
for (int i = 0; i < myDeferredTokens.size(); i++) {
|
||||
TokenInfo tokenInfo = myDeferredTokens.get(i);
|
||||
tokenInfo.startOffset -= context.removedSymbolsNumber;
|
||||
tokenInfo.endOffset -= context.removedSymbolsNumber;
|
||||
|
||||
if (!context.canContinueProcessing()) {
|
||||
// Just update token offsets.
|
||||
myDeferredTypes.add(tokenInfo.contentType);
|
||||
if (context.removedSymbolsNumber == 0) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
int tokenLength = tokenInfo.getLength();
|
||||
|
||||
// Don't remove input text.
|
||||
if (myContentTypesToNotStripOnCycling.contains(tokenInfo.contentType)) {
|
||||
skip(context, tokenLength);
|
||||
myDeferredTypes.add(tokenInfo.contentType);
|
||||
continue;
|
||||
}
|
||||
|
||||
int removedTokenSymbolsNumber = remove(context, tokenLength);
|
||||
if (removedTokenSymbolsNumber == tokenLength) {
|
||||
indicesOfTokensToRemove.add(i);
|
||||
}
|
||||
else {
|
||||
tokenInfo.endOffset -= removedTokenSymbolsNumber;
|
||||
myDeferredTypes.add(tokenInfo.contentType);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = indicesOfTokensToRemove.size() - 1; i >= 0; i--) {
|
||||
myDeferredTokens.remove(indicesOfTokensToRemove.get(i));
|
||||
}
|
||||
|
||||
if (!myDeferredTokens.isEmpty()) {
|
||||
TokenInfo tokenInfo = myDeferredTokens.get(0);
|
||||
if (tokenInfo.startOffset > 0) {
|
||||
final HyperlinkInfo hyperlinkInfo = tokenInfo.getHyperlinkInfo();
|
||||
myDeferredTokens.add(0, hyperlinkInfo != null ? new HyperlinkTokenInfo(ConsoleViewContentType.USER_INPUT, 0, tokenInfo.startOffset, hyperlinkInfo)
|
||||
: new TokenInfo(ConsoleViewContentType.USER_INPUT, 0, tokenInfo.startOffset));
|
||||
myDeferredTypes.add(ConsoleViewContentType.USER_INPUT);
|
||||
}
|
||||
}
|
||||
|
||||
if (numberOfNewSymbols + myDeferredOutputLength > myCyclicBufferSize) {
|
||||
int result = myCyclicBufferSize - myDeferredOutputLength;
|
||||
if (result < 0) {
|
||||
return 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return numberOfNewSymbols;
|
||||
}
|
||||
|
||||
private static void skip(@NotNull Context context, int symbolsToSkipNumber) {
|
||||
int remainingNumberOfBufferSymbols = context.currentBuffer.length() - context.bufferOffset;
|
||||
if (remainingNumberOfBufferSymbols < symbolsToSkipNumber) {
|
||||
symbolsToSkipNumber -= remainingNumberOfBufferSymbols;
|
||||
while (context.iterator.hasNext()) {
|
||||
context.currentBuffer = context.iterator.next();
|
||||
context.bufferOffset = 0;
|
||||
if (DEBUG_PROCESSING) {
|
||||
log("Switching to the next buffer. Number of token symbols to skip: %d", symbolsToSkipNumber);
|
||||
}
|
||||
if (symbolsToSkipNumber <= 0) {
|
||||
break;
|
||||
}
|
||||
if (context.currentBuffer.length() > symbolsToSkipNumber) {
|
||||
context.bufferOffset = symbolsToSkipNumber;
|
||||
symbolsToSkipNumber = 0;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
symbolsToSkipNumber -= context.currentBuffer.length();
|
||||
}
|
||||
}
|
||||
assert symbolsToSkipNumber <= 0;
|
||||
}
|
||||
else {
|
||||
context.bufferOffset += symbolsToSkipNumber;
|
||||
if (DEBUG_PROCESSING) {
|
||||
log("All symbols to skip are processed. Current buffer offset is %d, text: '%s'", context.bufferOffset, context.currentBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int remove(@NotNull Context context, int tokenLength) {
|
||||
int removedSymbolsNumber = 0;
|
||||
int remainingTotalNumberOfSymbolsToRemove = context.numberOfSymbolsToRemove - context.removedSymbolsNumber;
|
||||
int numberOfTokenSymbolsToRemove = Math.min(remainingTotalNumberOfSymbolsToRemove, tokenLength);
|
||||
while (numberOfTokenSymbolsToRemove > 0 && context.currentBuffer != null) {
|
||||
int diff = numberOfTokenSymbolsToRemove - (context.currentBuffer.length() - context.bufferOffset);
|
||||
int endDeleteBufferOffset = Math.min(context.bufferOffset + numberOfTokenSymbolsToRemove, context.currentBuffer.length());
|
||||
int numberOfSymbolsRemovedFromCurrentBuffer = endDeleteBufferOffset - context.bufferOffset;
|
||||
if (DEBUG_PROCESSING) {
|
||||
log("About to delete %d symbols from the current buffer (offset is %d). Removed symbols number: %d. Current buffer: %d: '%s'",
|
||||
numberOfSymbolsRemovedFromCurrentBuffer, context.bufferOffset, context.removedSymbolsNumber, context.currentBuffer.length(),
|
||||
StringUtil.convertLineSeparators(context.currentBuffer.toString()));
|
||||
}
|
||||
numberOfTokenSymbolsToRemove -= numberOfSymbolsRemovedFromCurrentBuffer;
|
||||
removedSymbolsNumber += numberOfSymbolsRemovedFromCurrentBuffer;
|
||||
context.removedSymbolsNumber += numberOfSymbolsRemovedFromCurrentBuffer;
|
||||
myDeferredOutputLength -= numberOfSymbolsRemovedFromCurrentBuffer;
|
||||
|
||||
if (context.bufferOffset == 0 && (diff >= 0 || endDeleteBufferOffset == context.currentBuffer.length())) {
|
||||
context.iterator.remove();
|
||||
context.nextBuffer();
|
||||
}
|
||||
else {
|
||||
context.currentBuffer.delete(context.bufferOffset, endDeleteBufferOffset);
|
||||
if (DEBUG_PROCESSING) {
|
||||
log("Removed symbols at range [%d; %d). Buffer offset: %d, buffer length: %d, text: '%s'",
|
||||
context.bufferOffset, endDeleteBufferOffset, context.bufferOffset, context.currentBuffer.length(), context.currentBuffer);
|
||||
}
|
||||
if (context.bufferOffset == context.currentBuffer.length()) {
|
||||
context.nextBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
return removedSymbolsNumber;
|
||||
}
|
||||
|
||||
private final class Context {
|
||||
|
||||
public final int numberOfSymbolsToRemove;
|
||||
public StringBuilder currentBuffer;
|
||||
public Iterator<StringBuilder> iterator;
|
||||
public int bufferOffset;
|
||||
public int removedSymbolsNumber;
|
||||
|
||||
Context(int numberOfSymbolsToRemove) {
|
||||
this.numberOfSymbolsToRemove = numberOfSymbolsToRemove;
|
||||
iterator = myDeferredOutput.iterator();
|
||||
if (iterator.hasNext()) {
|
||||
currentBuffer = iterator.next();
|
||||
}
|
||||
else {
|
||||
currentBuffer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canContinueProcessing() {
|
||||
return removedSymbolsNumber < numberOfSymbolsToRemove && currentBuffer != null;
|
||||
}
|
||||
|
||||
public boolean nextBuffer() {
|
||||
if (iterator.hasNext()) {
|
||||
currentBuffer = iterator.next();
|
||||
bufferOffset = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"PointlessBooleanExpression", "ConstantConditions"})
|
||||
private void dumpDeferredOutput() {
|
||||
if (!DEBUG_PROCESSING) {
|
||||
return;
|
||||
}
|
||||
log("Tokens:");
|
||||
for (TokenInfo token : myDeferredTokens) {
|
||||
log("\t" + token);
|
||||
}
|
||||
log("Data:");
|
||||
for (StringBuilder buffer : myDeferredOutput) {
|
||||
log("\t%d: '%s'", buffer.length(), StringUtil.convertLineSeparators(buffer.toString()));
|
||||
}
|
||||
log("-----------------------------------------------------------------------------------------------------");
|
||||
}
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration", "CallToPrintStackTrace"})
|
||||
private static void log(Object o) {
|
||||
//try {
|
||||
// doLog(o);
|
||||
//}
|
||||
//catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
//}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration", "CallToPrintStackTrace"})
|
||||
private static void log(String message, Object... formatData) {
|
||||
//try {
|
||||
// doLog(String.format(message, formatData));
|
||||
//}
|
||||
//catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
//}
|
||||
}
|
||||
|
||||
//private static BufferedWriter myWriter;
|
||||
//private static void doLog(Object o) throws Exception {
|
||||
// if (!DEBUG_PROCESSING) {
|
||||
// return;
|
||||
// }
|
||||
// File file = new File("/home/denis/log/console.log");
|
||||
// if (myWriter == null || !file.exists()) {
|
||||
// myWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));
|
||||
// }
|
||||
// myWriter.write(o.toString());
|
||||
// myWriter.newLine();
|
||||
// myWriter.flush();
|
||||
//}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.impl;
|
||||
|
||||
import static com.intellij.execution.impl.ConsoleViewImpl.TokenInfo;
|
||||
import static com.intellij.execution.impl.ConsoleViewImpl.HyperlinkTokenInfo;
|
||||
|
||||
import com.intellij.execution.filters.HyperlinkInfo;
|
||||
import com.intellij.execution.ui.ConsoleViewContentType;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Holds utility methods for console processing.
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 4/6/11 3:50 PM
|
||||
*/
|
||||
public class ConsoleUtil {
|
||||
|
||||
private ConsoleUtil() {
|
||||
}
|
||||
|
||||
public static void addToken(int length, @Nullable HyperlinkInfo info, ConsoleViewContentType contentType, List<TokenInfo> tokens) {
|
||||
int startOffset = 0;
|
||||
if (!tokens.isEmpty()) {
|
||||
final TokenInfo lastToken = tokens.get(tokens.size() - 1);
|
||||
if (lastToken.contentType == contentType && info == lastToken.getHyperlinkInfo()) {
|
||||
lastToken.endOffset += length; // optimization
|
||||
return;
|
||||
}
|
||||
else {
|
||||
startOffset = lastToken.endOffset;
|
||||
}
|
||||
}
|
||||
|
||||
tokens.add(info != null ? new HyperlinkTokenInfo(contentType, startOffset, startOffset + length, info)
|
||||
: new TokenInfo(contentType, startOffset, startOffset + length));
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,7 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.LineTokenizer;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.pom.Navigatable;
|
||||
@@ -102,6 +102,7 @@ import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableConsoleView, DataProvider, OccurenceNavigator {
|
||||
|
||||
private @NonNls String CONSOLE_VIEW_POPUP_MENU = "ConsoleView.PopupMenu";
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.execution.impl.ConsoleViewImpl");
|
||||
|
||||
@@ -115,35 +116,6 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
typedAction.setupHandler(new MyTypedHandler(typedAction.getHandler()));
|
||||
}
|
||||
|
||||
private final int CYCLIC_BUFFER_SIZE = getCycleBufferSize();
|
||||
/**
|
||||
* Main console usage scenario assumes the following:
|
||||
* <pre>
|
||||
* <ul>
|
||||
* <li>
|
||||
* console may be {@link #print(String, ConsoleViewContentType) provided} with the new text from any thread
|
||||
* (e.g. separate thread is charged for reading output of java application launched under IJ. That output is provided
|
||||
* to the console);
|
||||
* </li>
|
||||
* <li>current class flushes provided text to {@link Editor editor} used for representing it to end-user from EDT;</li>
|
||||
* <li>
|
||||
* dedicated buffer is kept to hold console text between the moment when it's provided to the current class
|
||||
* and flush to the editor;</li>
|
||||
* </ul>
|
||||
* </pre>
|
||||
* <p/>
|
||||
* It's also possible to configure console to use cyclic buffer in order to avoid unnecessary memory consumption.
|
||||
* However, that implies possibility of the following situation - console user provides it with the great number
|
||||
* of small chunks of text (that is the case for junit processing). It's inappropriate to use single {@link StringBuilder} as
|
||||
* a buffer then because every time we see that cyclic buffer size is exceeded and we need to cut exceeding text from buffer
|
||||
* start, trailing part is moved to the zero offset. That produces extensive CPU usage in case of great number of small messages
|
||||
* where every such message exceeds cyclic buffer size.
|
||||
* <p/>
|
||||
* That is the reason why we use data structure similar to STL deque here - we hold number of string buffers of small size instead
|
||||
* of the single big buffer. That means that every 'cut at the start' operation requires much less number of trailing symbols
|
||||
* to be moved. Current constant defines desired size of that small buffers.
|
||||
*/
|
||||
private static final int CYCLIC_BUFFER_UNIT_SIZE = 256;
|
||||
private final CommandLineFolding myCommandLineFolding = new CommandLineFolding();
|
||||
|
||||
private final DisposedPsiManagerCheck myPsiDisposedCheck;
|
||||
@@ -153,30 +125,12 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
|
||||
private Computable<ModalityState> myStateForUpdate;
|
||||
|
||||
private static int getCycleBufferSize() {
|
||||
final String cycleBufferSizeProperty = System.getProperty("idea.cycle.buffer.size");
|
||||
if (cycleBufferSizeProperty == null) return 1024 * 1024;
|
||||
try {
|
||||
return Integer.parseInt(cycleBufferSizeProperty) * 1024;
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
return 1024 * 1024;
|
||||
}
|
||||
}
|
||||
|
||||
private final boolean USE_CYCLIC_BUFFER = useCycleBuffer();
|
||||
|
||||
private static boolean useCycleBuffer() {
|
||||
final String useCycleBufferProperty = System.getProperty("idea.cycle.buffer.size");
|
||||
return useCycleBufferProperty == null || !"disabled".equalsIgnoreCase(useCycleBufferProperty);
|
||||
}
|
||||
|
||||
private static final int HYPERLINK_LAYER = HighlighterLayer.SELECTION - 123;
|
||||
private final Alarm mySpareTimeAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, this);
|
||||
|
||||
private final CopyOnWriteArraySet<ChangeListener> myListeners = new CopyOnWriteArraySet<ChangeListener>();
|
||||
private final Set<ConsoleViewContentType> myDeferredTypes = new HashSet<ConsoleViewContentType>();
|
||||
private final ArrayList<AnAction> customActions = new ArrayList<AnAction>();
|
||||
private final ConsoleBuffer myBuffer = new ConsoleBuffer();
|
||||
|
||||
@TestOnly
|
||||
public Editor getEditor() {
|
||||
@@ -211,10 +165,10 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
updateFoldings(0, myEditor.getDocument().getLineCount() - 1, true);
|
||||
}
|
||||
|
||||
private static class TokenInfo {
|
||||
private final ConsoleViewContentType contentType;
|
||||
private int startOffset;
|
||||
private int endOffset;
|
||||
static class TokenInfo {
|
||||
final ConsoleViewContentType contentType;
|
||||
int startOffset;
|
||||
int endOffset;
|
||||
private final TextAttributes attributes;
|
||||
|
||||
TokenInfo(final ConsoleViewContentType contentType, final int startOffset, final int endOffset) {
|
||||
@@ -239,7 +193,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
}
|
||||
}
|
||||
|
||||
private static class HyperlinkTokenInfo extends TokenInfo {
|
||||
static class HyperlinkTokenInfo extends TokenInfo {
|
||||
private HyperlinkInfo myHyperlinkInfo;
|
||||
|
||||
HyperlinkTokenInfo(final ConsoleViewContentType contentType, final int startOffset, final int endOffset, HyperlinkInfo hyperlinkInfo) {
|
||||
@@ -268,21 +222,6 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
*/
|
||||
private int myContentSize;
|
||||
|
||||
/**
|
||||
* Buffer for deferred stdout, stderr and stdin output.
|
||||
* <p/>
|
||||
* Feel free to check rationale for using this approach at {@link #CYCLIC_BUFFER_UNIT_SIZE} contract.
|
||||
*/
|
||||
private final Deque<StringBuilder> myDeferredOutput = new ArrayDeque<StringBuilder>();
|
||||
|
||||
/**
|
||||
* Holds information about number of symbols stored at {@link #myDeferredOutput} collection.
|
||||
*/
|
||||
private int myDeferredOutputLength;
|
||||
|
||||
/** Buffer for deferred stdin and stderr output. */
|
||||
private StringBuffer myDeferredUserInput = new StringBuffer();
|
||||
|
||||
/**
|
||||
* Holds information about lexical division by offsets of the text already pushed to document.
|
||||
* <p/>
|
||||
@@ -290,13 +229,6 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
*/
|
||||
private ArrayList<TokenInfo> myTokens = new ArrayList<TokenInfo>();
|
||||
|
||||
/**
|
||||
* Holds information about lexical division by offsets of the text that is not yet pushed to document.
|
||||
* <p/>
|
||||
* Target offsets are anchored to the {@link #myDeferredOutput deferred buffer}.
|
||||
*/
|
||||
private final List<TokenInfo> myDeferredTokens = new ArrayList<TokenInfo>();
|
||||
|
||||
private final Hyperlinks myHyperlinks = new Hyperlinks();
|
||||
private final TIntObjectHashMap<ConsoleFolding> myFolding = new TIntObjectHashMap<ConsoleFolding>();
|
||||
|
||||
@@ -416,14 +348,8 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
// code and alarm clear request (in EDT) my occur print event in non-EDT thread
|
||||
// and unfortunately it is a real usecase and happens when switching active test in
|
||||
// tests console.
|
||||
myContentSize = Math.max(0, myContentSize - myDeferredOutputLength);
|
||||
|
||||
myDeferredOutput.clear();
|
||||
myDeferredOutput.add(new StringBuilder(CYCLIC_BUFFER_UNIT_SIZE));
|
||||
myDeferredOutputLength = 0;
|
||||
myDeferredTypes.clear();
|
||||
myDeferredUserInput = new StringBuffer();
|
||||
myDeferredTokens.clear();
|
||||
myContentSize = Math.max(0, myContentSize - myBuffer.getLength());
|
||||
myBuffer.clear();
|
||||
}
|
||||
myFlushAlarm.cancelAllRequests();
|
||||
myFlushAlarm.addRequest(myClearRequest, 0, getStateForUpdate());
|
||||
@@ -435,7 +361,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
flushDeferredText(false);
|
||||
if (myEditor == null) return;
|
||||
int moveOffset = offset;
|
||||
if (USE_CYCLIC_BUFFER && moveOffset >= myEditor.getDocument().getTextLength()) {
|
||||
if (myBuffer.isUseCyclicBuffer() && moveOffset >= myEditor.getDocument().getTextLength()) {
|
||||
moveOffset = 0;
|
||||
}
|
||||
myEditor.getCaretModel().moveToOffset(moveOffset);
|
||||
@@ -462,7 +388,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
|
||||
public boolean hasDeferredOutput() {
|
||||
synchronized (LOCK) {
|
||||
return myDeferredOutputLength > 0;
|
||||
return myBuffer.getLength() > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,9 +457,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
mySpareTimeAlarm.cancelAllRequests();
|
||||
disposeEditor();
|
||||
synchronized (LOCK) {
|
||||
myDeferredOutput.clear();
|
||||
myDeferredOutput.add(new StringBuilder());
|
||||
myDeferredOutputLength = 0;
|
||||
myBuffer.clear();
|
||||
}
|
||||
myEditor = null;
|
||||
}
|
||||
@@ -551,44 +475,9 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
|
||||
private void printHyperlink(String s, ConsoleViewContentType contentType, HyperlinkInfo info) {
|
||||
synchronized (LOCK) {
|
||||
int numberOfSymbolsToProceed = s.length();
|
||||
if (contentType != ConsoleViewContentType.USER_INPUT) {
|
||||
numberOfSymbolsToProceed = trimDeferredOutputIfNecessary(s.length());
|
||||
}
|
||||
|
||||
if (numberOfSymbolsToProceed <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (numberOfSymbolsToProceed < s.length()) {
|
||||
s = s.substring(s.length() - numberOfSymbolsToProceed);
|
||||
}
|
||||
|
||||
myDeferredTypes.add(contentType);
|
||||
|
||||
s = StringUtil.convertLineSeparators(s, !SystemInfo.isMac);
|
||||
myContentSize += s.length();
|
||||
myDeferredOutputLength += s.length();
|
||||
StringBuilder bufferToUse;
|
||||
if (myDeferredOutput.isEmpty()) {
|
||||
myDeferredOutput.add(bufferToUse = new StringBuilder(s.length()));
|
||||
}
|
||||
else {
|
||||
StringBuilder lastBuffer = myDeferredOutput.getLast();
|
||||
bufferToUse = lastBuffer;
|
||||
if (USE_CYCLIC_BUFFER) {
|
||||
if (lastBuffer.length() + s.length() > CYCLIC_BUFFER_UNIT_SIZE) {
|
||||
myDeferredOutput.addLast(bufferToUse = new StringBuilder(CYCLIC_BUFFER_UNIT_SIZE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bufferToUse.append(s);
|
||||
if (contentType == ConsoleViewContentType.USER_INPUT) {
|
||||
myDeferredUserInput.append(s);
|
||||
}
|
||||
|
||||
addToken(s.length(), info, contentType, myDeferredTokens);
|
||||
Pair<String,Integer> pair = myBuffer.print(s, contentType, info);
|
||||
s = pair.first;
|
||||
myContentSize += s.length() - pair.second;
|
||||
|
||||
if (s.indexOf('\n') >= 0 || s.indexOf('\r') >= 0) {
|
||||
if (contentType == ConsoleViewContentType.USER_INPUT) {
|
||||
@@ -596,146 +485,19 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
}
|
||||
}
|
||||
if (myFlushAlarm.getActiveRequestCount() == 0 && myEditor != null && !myFlushAlarm.isDisposed()) {
|
||||
final boolean shouldFlushNow = USE_CYCLIC_BUFFER && myDeferredOutputLength > CYCLIC_BUFFER_SIZE;
|
||||
final boolean shouldFlushNow = myBuffer.isUseCyclicBuffer() && myBuffer.getLength() >= myBuffer.getCyclicBufferSize();
|
||||
myFlushAlarm.addRequest(myFlushDeferredRunnable, shouldFlushNow ? 0 : FLUSH_DELAY, getStateForUpdate());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* IJ console works as follows - it receives managed process outputs from dedicated thread that serves that process and
|
||||
* pushes it to the {@link Document document} of editor used to represent process console. Important point here is that process
|
||||
* output is received in a control flow of the thread over than EDT but push to the document is performed from EDT. Hence, we
|
||||
* have a potential situation when particular process outputs a lot and EDT is busy or push to the document is performed slowly.
|
||||
* <p/>
|
||||
* We don't want to keep too many information from the underlying process then and want to trim text buffer that holds text
|
||||
* to push to the document then. Current method serves exactly that purpose, i.e. it's expected to be called when new chunk of
|
||||
* text is received from the underlying process and trims existing text buffer if necessary.
|
||||
*
|
||||
* @param numberOfNewSymbols number of symbols read from the managed process output
|
||||
* @return number of newly read symbols that should be accepted
|
||||
*/
|
||||
@SuppressWarnings({"ForLoopReplaceableByForEach"})
|
||||
private int trimDeferredOutputIfNecessary(final int numberOfNewSymbols) {
|
||||
if (!USE_CYCLIC_BUFFER || myDeferredOutputLength <= 0 || myDeferredOutputLength + numberOfNewSymbols <= CYCLIC_BUFFER_SIZE) {
|
||||
return numberOfNewSymbols;
|
||||
}
|
||||
|
||||
final int numberOfSymbolsToRemove = myDeferredOutputLength + numberOfNewSymbols - CYCLIC_BUFFER_SIZE;
|
||||
myDeferredTypes.clear();
|
||||
|
||||
int removedSymbolsNumber = 0;
|
||||
int endIndex = -1;
|
||||
Iterator<StringBuilder> iterator = myDeferredOutput.iterator();
|
||||
StringBuilder currentBuffer = iterator.next();
|
||||
int bufferOffset = 0;
|
||||
for (int i = 0; i < myDeferredTokens.size(); i++) {
|
||||
TokenInfo tokenInfo = myDeferredTokens.get(i);
|
||||
|
||||
if (removedSymbolsNumber < numberOfSymbolsToRemove) {
|
||||
int tokenLength = tokenInfo.getLength();
|
||||
|
||||
// Don't remove input text.
|
||||
if (tokenInfo.contentType == ConsoleViewContentType.USER_INPUT) {
|
||||
tokenInfo.startOffset -= removedSymbolsNumber;
|
||||
tokenInfo.endOffset -= removedSymbolsNumber;
|
||||
removedSymbolsNumber += tokenLength;
|
||||
bufferOffset += tokenLength;
|
||||
continue;
|
||||
}
|
||||
|
||||
int remainingNumberOfSymbolsToRemove = numberOfSymbolsToRemove - removedSymbolsNumber;
|
||||
int numberOfSymbolsToRemoveNow = Math.min(remainingNumberOfSymbolsToRemove, tokenLength);
|
||||
while (numberOfSymbolsToRemoveNow > 0) {
|
||||
int diff = numberOfSymbolsToRemoveNow - currentBuffer.length() - bufferOffset;
|
||||
int endDeleteOffset = Math.min(bufferOffset + numberOfSymbolsToRemoveNow, currentBuffer.length());
|
||||
int numberOfSymbolsRemovedFromCurrentBuffer = endDeleteOffset - bufferOffset;
|
||||
numberOfSymbolsToRemoveNow -= numberOfSymbolsRemovedFromCurrentBuffer;
|
||||
removedSymbolsNumber += numberOfSymbolsRemovedFromCurrentBuffer;
|
||||
myDeferredOutputLength -= numberOfSymbolsRemovedFromCurrentBuffer;
|
||||
currentBuffer.delete(bufferOffset, endDeleteOffset);
|
||||
if (diff >= 0) {
|
||||
iterator.remove();
|
||||
if (iterator.hasNext()) {
|
||||
currentBuffer = iterator.next();
|
||||
}
|
||||
else if (numberOfSymbolsToRemove > 0) {
|
||||
assert false;
|
||||
}
|
||||
|
||||
bufferOffset = 0;
|
||||
}
|
||||
}
|
||||
if (remainingNumberOfSymbolsToRemove < tokenLength) {
|
||||
tokenInfo.startOffset += remainingNumberOfSymbolsToRemove;
|
||||
endIndex = i;
|
||||
}
|
||||
else {
|
||||
endIndex = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (removedSymbolsNumber < numberOfSymbolsToRemove) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tokenInfo.startOffset -= numberOfSymbolsToRemove;
|
||||
tokenInfo.endOffset -= numberOfSymbolsToRemove;
|
||||
myDeferredTypes.add(tokenInfo.contentType);
|
||||
}
|
||||
|
||||
if (endIndex < 0) {
|
||||
myDeferredTokens.clear();
|
||||
}
|
||||
else if (endIndex > 0) {
|
||||
myDeferredTokens.subList(0, endIndex).clear();
|
||||
}
|
||||
|
||||
if (!myDeferredTokens.isEmpty()) {
|
||||
TokenInfo tokenInfo = myDeferredTokens.get(0);
|
||||
if (tokenInfo.startOffset > 0) {
|
||||
final HyperlinkInfo hyperlinkInfo = tokenInfo.getHyperlinkInfo();
|
||||
myDeferredTokens.add(0, hyperlinkInfo != null ? new HyperlinkTokenInfo(ConsoleViewContentType.USER_INPUT, 0, tokenInfo.startOffset, hyperlinkInfo)
|
||||
: new TokenInfo(ConsoleViewContentType.USER_INPUT, 0, tokenInfo.startOffset));
|
||||
myDeferredTypes.add(ConsoleViewContentType.USER_INPUT);
|
||||
}
|
||||
}
|
||||
|
||||
myContentSize -= removedSymbolsNumber;
|
||||
if (numberOfNewSymbols + myDeferredOutputLength > CYCLIC_BUFFER_SIZE) {
|
||||
int result = CYCLIC_BUFFER_SIZE - myDeferredOutputLength;
|
||||
if (result < 0) {
|
||||
return 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return numberOfNewSymbols;
|
||||
}
|
||||
|
||||
protected void beforeExternalAddContentToDocument(int length, ConsoleViewContentType contentType) {
|
||||
myContentSize+=length;
|
||||
addToken(length, null, contentType);
|
||||
}
|
||||
|
||||
private void addToken(int length, @Nullable HyperlinkInfo info, ConsoleViewContentType contentType) {
|
||||
addToken(length, info, contentType, myTokens);
|
||||
}
|
||||
|
||||
private static void addToken(int length, @Nullable HyperlinkInfo info, ConsoleViewContentType contentType, List<TokenInfo> tokens) {
|
||||
int startOffset = 0;
|
||||
if (!tokens.isEmpty()) {
|
||||
final TokenInfo lastToken = tokens.get(tokens.size() - 1);
|
||||
if (lastToken.contentType == contentType && info == lastToken.getHyperlinkInfo()) {
|
||||
lastToken.endOffset += length; // optimization
|
||||
return;
|
||||
}
|
||||
else {
|
||||
startOffset = lastToken.endOffset;
|
||||
}
|
||||
}
|
||||
|
||||
tokens.add(info != null ? new HyperlinkTokenInfo(contentType, startOffset, startOffset + length, info)
|
||||
: new TokenInfo(contentType, startOffset, startOffset + length));
|
||||
ConsoleUtil.addToken(length, info, contentType, myTokens);
|
||||
}
|
||||
|
||||
private ModalityState getStateForUpdate() {
|
||||
@@ -783,50 +545,29 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
}, null, DocCommandGroupId.noneGroupId(document));
|
||||
}
|
||||
|
||||
final StringBuilder buffer = new StringBuilder();
|
||||
|
||||
final String text;
|
||||
final Collection<ConsoleViewContentType> contentTypes;
|
||||
int deferredTokensSize;
|
||||
synchronized (LOCK) {
|
||||
if (myOutputPaused) return;
|
||||
if (myDeferredOutput.isEmpty() || (myDeferredOutput.size() == 1 && myDeferredOutput.getFirst().length() <= 0)) return;
|
||||
if (myBuffer.isEmpty()) return;
|
||||
if (myEditor == null) return;
|
||||
|
||||
if (myDeferredOutput.size() > 1) {
|
||||
for (StringBuilder builder : myDeferredOutput) {
|
||||
buffer.append(builder);
|
||||
}
|
||||
text = buffer.substring(0);
|
||||
}
|
||||
else if (myDeferredOutput.size() == 1) {
|
||||
text = myDeferredOutput.getFirst().substring(0);
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
text = myBuffer.getText();
|
||||
|
||||
contentTypes = Collections.unmodifiableCollection(new HashSet<ConsoleViewContentType>(myDeferredTypes));
|
||||
for (TokenInfo deferredToken : myDeferredTokens) {
|
||||
contentTypes = Collections.unmodifiableCollection(new HashSet<ConsoleViewContentType>(myBuffer.getDeferredTokenTypes()));
|
||||
List<TokenInfo> deferredTokens = myBuffer.getDeferredTokens();
|
||||
for (TokenInfo deferredToken : deferredTokens) {
|
||||
addToken(deferredToken.getLength(), deferredToken.getHyperlinkInfo(), deferredToken.contentType);
|
||||
}
|
||||
deferredTokensSize = myDeferredTokens.size();
|
||||
myDeferredTokens.clear();
|
||||
myDeferredTypes.clear();
|
||||
if (USE_CYCLIC_BUFFER) {
|
||||
myDeferredOutput.clear();
|
||||
myDeferredOutput.add(new StringBuilder(CYCLIC_BUFFER_SIZE));
|
||||
}
|
||||
else {
|
||||
for (StringBuilder builder : myDeferredOutput) {
|
||||
builder.setLength(0);
|
||||
}
|
||||
}
|
||||
myDeferredOutputLength = 0;
|
||||
deferredTokensSize = deferredTokens.size();
|
||||
myBuffer.clear();
|
||||
}
|
||||
final Document document = myEditor.getDocument();
|
||||
final int oldLineCount = document.getLineCount();
|
||||
final boolean isAtEndOfDocument = myEditor.getCaretModel().getOffset() == document.getTextLength();
|
||||
boolean cycleUsed = USE_CYCLIC_BUFFER && document.getTextLength() + text.length() > CYCLIC_BUFFER_SIZE;
|
||||
boolean cycleUsed = myBuffer.isUseCyclicBuffer() && document.getTextLength() + text.length() > myBuffer.getCyclicBufferSize();
|
||||
CommandProcessor.getInstance().executeCommand(myProject, new Runnable() {
|
||||
public void run() {
|
||||
int offset = myEditor.getCaretModel().getOffset();
|
||||
@@ -887,12 +628,10 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
}
|
||||
|
||||
private void flushDeferredUserInput() {
|
||||
final String text = myDeferredUserInput.substring(0, myDeferredUserInput.length());
|
||||
final int index = Math.max(text.lastIndexOf('\n'), text.lastIndexOf('\r'));
|
||||
if (index < 0) return;
|
||||
final String textToSend = text.substring(0, index + 1);
|
||||
myDeferredUserInput.setLength(0);
|
||||
myDeferredUserInput.append(text.substring(index + 1));
|
||||
final String textToSend = myBuffer.cutFirstUserInputLine();
|
||||
if (textToSend == null) {
|
||||
return;
|
||||
}
|
||||
myFlushUserInputAlarm.addRequest(new Runnable() {
|
||||
public void run() {
|
||||
if (myState.isRunning()) {
|
||||
@@ -980,7 +719,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
});
|
||||
|
||||
|
||||
final int bufferSize = USE_CYCLIC_BUFFER ? CYCLIC_BUFFER_SIZE : 0;
|
||||
final int bufferSize = myBuffer.isUseCyclicBuffer() ? myBuffer.getCyclicBufferSize() : 0;
|
||||
editor.getDocument().setCyclicBufferSize(bufferSize);
|
||||
|
||||
editor.putUserData(CONSOLE_VIEW_IN_EDITOR_VIEW, this);
|
||||
@@ -1589,7 +1328,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
public void execute(final ConsoleViewImpl consoleView, final DataContext context) {
|
||||
final int maxSize = UISettings.getInstance().CONSOLE_COMMAND_HISTORY_LIMIT;
|
||||
synchronized (consoleView.LOCK) {
|
||||
String str = consoleView.myDeferredUserInput.toString();
|
||||
String str = consoleView.myBuffer.getUserInput();
|
||||
if (StringUtil.isNotEmpty(str)) {
|
||||
consoleView.myHistory.remove(str);
|
||||
consoleView.myHistory.add(str);
|
||||
@@ -1917,6 +1656,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
*/
|
||||
private void insertUserText(final String s, int offset) {
|
||||
final ConsoleViewImpl consoleView = this;
|
||||
final ConsoleBuffer buffer = consoleView.myBuffer;
|
||||
final Editor editor = consoleView.myEditor;
|
||||
final Document document = editor.getDocument();
|
||||
final int startOffset;
|
||||
@@ -1938,7 +1678,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
return;
|
||||
}
|
||||
|
||||
final int deferredOffset = myContentSize - consoleView.myDeferredOutputLength - consoleView.myDeferredUserInput.length();
|
||||
final int deferredOffset = myContentSize - buffer.getLength() - buffer.getUserInputLength();
|
||||
if (offset > info.endOffset) {
|
||||
startOffset = info.endOffset;
|
||||
}
|
||||
@@ -1946,7 +1686,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
startOffset = Math.max(deferredOffset, Math.max(info.startOffset, offset));
|
||||
}
|
||||
|
||||
consoleView.myDeferredUserInput.insert(startOffset - deferredOffset, s);
|
||||
buffer.addUserText(startOffset - deferredOffset, s);
|
||||
|
||||
int charCountToAdd = s.length();
|
||||
info.endOffset += charCountToAdd;
|
||||
@@ -1972,6 +1712,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
return;
|
||||
}
|
||||
final ConsoleViewImpl consoleView = this;
|
||||
final ConsoleBuffer buffer = consoleView.myBuffer;
|
||||
final Editor editor = consoleView.myEditor;
|
||||
final Document document = editor.getDocument();
|
||||
final int startOffset;
|
||||
@@ -1987,9 +1728,9 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
editor.getSelectionModel().removeSelection();
|
||||
return;
|
||||
}
|
||||
if (consoleView.myDeferredUserInput.length() == 0) return;
|
||||
if (buffer.isEmpty()) return;
|
||||
|
||||
final int deferredOffset = myContentSize - consoleView.myDeferredOutputLength - consoleView.myDeferredUserInput.length();
|
||||
final int deferredOffset = myContentSize - buffer.getLength() - buffer.getUserInputLength();
|
||||
|
||||
startOffset = getStartOffset(start, info, deferredOffset);
|
||||
endOffset = getEndOffset(end, info);
|
||||
@@ -2003,7 +1744,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
}
|
||||
int charCountToReplace = s.length() - endOffset + startOffset;
|
||||
|
||||
consoleView.myDeferredUserInput.replace(startOffset - deferredOffset, endOffset - deferredOffset, s);
|
||||
buffer.replaceUserText(startOffset - deferredOffset, endOffset - deferredOffset, s);
|
||||
|
||||
info.endOffset += charCountToReplace;
|
||||
if (info.startOffset == info.endOffset) {
|
||||
@@ -2026,6 +1767,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
*/
|
||||
private void deleteUserText(int offset, int length) {
|
||||
ConsoleViewImpl consoleView = this;
|
||||
ConsoleBuffer buffer = consoleView.myBuffer;
|
||||
final Editor editor = consoleView.myEditor;
|
||||
final Document document = editor.getDocument();
|
||||
final int startOffset;
|
||||
@@ -2035,9 +1777,9 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
if (consoleView.myTokens.isEmpty()) return;
|
||||
final TokenInfo info = consoleView.myTokens.get(consoleView.myTokens.size() - 1);
|
||||
if (info.contentType != ConsoleViewContentType.USER_INPUT) return;
|
||||
if (consoleView.myDeferredUserInput.length() == 0) return;
|
||||
if (myBuffer.getUserInputLength() == 0) return;
|
||||
|
||||
final int deferredOffset = myContentSize - consoleView.myDeferredOutputLength - consoleView.myDeferredUserInput.length();
|
||||
final int deferredOffset = myContentSize - buffer.getLength() - buffer.getUserInputLength();
|
||||
startOffset = getStartOffset(offset, info, deferredOffset);
|
||||
endOffset = getEndOffset(offset + length, info);
|
||||
if (startOffset == -1 ||
|
||||
@@ -2049,7 +1791,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
return;
|
||||
}
|
||||
|
||||
consoleView.myDeferredUserInput.delete(startOffset - deferredOffset, endOffset - deferredOffset);
|
||||
buffer.removeUserText(startOffset - deferredOffset, endOffset - deferredOffset);
|
||||
int charCountToDelete = endOffset - startOffset;
|
||||
|
||||
info.endOffset -= charCountToDelete;
|
||||
|
||||
+4
-4
@@ -51,7 +51,7 @@ import java.util.List;
|
||||
* This class provides basic functionality for running consoles.
|
||||
* It launches external process and handles line input with history
|
||||
*/
|
||||
public abstract class AbstractConsoleRunnerWithHistory {
|
||||
public abstract class AbstractConsoleRunnerWithHistory<T extends LanguageConsoleViewImpl> {
|
||||
private final Project myProject;
|
||||
private final String myConsoleTitle;
|
||||
|
||||
@@ -59,7 +59,7 @@ public abstract class AbstractConsoleRunnerWithHistory {
|
||||
private final CommandLineArgumentsProvider myProvider;
|
||||
private final String myWorkingDir;
|
||||
|
||||
private LanguageConsoleViewImpl myConsoleView;
|
||||
private T myConsoleView;
|
||||
|
||||
private ConsoleExecuteActionHandler myConsoleExecuteActionHandler;
|
||||
|
||||
@@ -194,7 +194,7 @@ public abstract class AbstractConsoleRunnerWithHistory {
|
||||
myConsoleView.getConsole().setEditable(false);
|
||||
}
|
||||
|
||||
protected abstract LanguageConsoleViewImpl createConsoleView();
|
||||
protected abstract T createConsoleView();
|
||||
|
||||
@Nullable
|
||||
protected abstract Process createProcess(CommandLineArgumentsProvider provider) throws ExecutionException;
|
||||
@@ -288,7 +288,7 @@ public abstract class AbstractConsoleRunnerWithHistory {
|
||||
}
|
||||
}
|
||||
|
||||
public LanguageConsoleViewImpl getConsoleView() {
|
||||
public T getConsoleView() {
|
||||
return myConsoleView;
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -27,6 +27,7 @@ public abstract class EditorHeaderToggleAction extends CheckboxAction {
|
||||
public JComponent createCustomComponent(Presentation presentation) {
|
||||
final JComponent customComponent = super.createCustomComponent(presentation);
|
||||
getCheckBox().setFocusable(false);
|
||||
getCheckBox().setOpaque(false);
|
||||
return customComponent;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
package com.intellij.find.editorHeaderActions;
|
||||
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.ui.popup.JBPopup;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.ui.popup.PopupChooserBuilder;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
@@ -61,4 +66,20 @@ public class Utils {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean okToWrite(Editor e) {
|
||||
final PsiFile psiFile = PsiDocumentManager.getInstance(e.getProject()).getPsiFile(e.getDocument());
|
||||
boolean okWritable;
|
||||
if (psiFile != null) {
|
||||
final VirtualFile virtualFile = psiFile.getVirtualFile();
|
||||
if (virtualFile != null) {
|
||||
okWritable = ReadonlyStatusHandler.ensureFilesWritable(e.getProject(), virtualFile);
|
||||
} else {
|
||||
okWritable = psiFile.isWritable();
|
||||
}
|
||||
} else {
|
||||
okWritable = e.getDocument().isWritable();
|
||||
}
|
||||
return okWritable;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -3,6 +3,7 @@ package com.intellij.find.impl.livePreview;
|
||||
import com.intellij.find.FindManager;
|
||||
import com.intellij.find.FindModel;
|
||||
import com.intellij.find.FindUtil;
|
||||
import com.intellij.find.editorHeaderActions.Utils;
|
||||
import com.intellij.find.impl.FindResultImpl;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
@@ -194,7 +195,7 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil
|
||||
@Nullable
|
||||
@Override
|
||||
public TextRange performReplace(final LiveOccurrence occurrence, final String replacement, final Editor editor) {
|
||||
if (myReplaceDenied) return null;
|
||||
if (myReplaceDenied || !Utils.okToWrite(editor)) return null;
|
||||
TextRange range = occurrence.getPrimaryRange();
|
||||
FindModel findModel = mySearchResults.getFindModel();
|
||||
TextRange result = null;
|
||||
@@ -216,6 +217,7 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil
|
||||
|
||||
@Override
|
||||
public void performReplaceAll(Editor e) {
|
||||
if (!Utils.okToWrite(e)) return;
|
||||
if (mySearchResults.getFindModel() != null) {
|
||||
FindUtil.replace(e.getProject(), e,
|
||||
mySearchResults.getFindModel().isGlobal() ? 0 : mySearchResults.getEditor().getSelectionModel().getSelectionStart(),
|
||||
|
||||
+1
-1
@@ -362,7 +362,7 @@ public class ReplaceInProjectManager {
|
||||
for (final Usage usage : selectedUsages) {
|
||||
final VirtualFile file = ((UsageInFile)usage).getFile();
|
||||
|
||||
if (!file.isWritable()) {
|
||||
if (file != null && !file.isWritable()) {
|
||||
if (readOnlyFiles == null) readOnlyFiles = new HashSet<VirtualFile>();
|
||||
readOnlyFiles.add(file);
|
||||
}
|
||||
|
||||
+2
-1
@@ -20,6 +20,7 @@ import com.intellij.find.EditorSearchComponent;
|
||||
import com.intellij.find.FindManager;
|
||||
import com.intellij.find.FindModel;
|
||||
import com.intellij.find.FindUtil;
|
||||
import com.intellij.find.editorHeaderActions.Utils;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
@@ -69,7 +70,7 @@ public class IncrementalFindAction extends EditorAction {
|
||||
|
||||
public boolean isEnabled(Editor editor, DataContext dataContext) {
|
||||
Project project = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(editor.getComponent()));
|
||||
return project != null && !editor.isOneLineMode();
|
||||
return project != null && !editor.isOneLineMode() && (!myReplace || Utils.okToWrite(editor));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ class FileElementInfo implements SmartPointerElementInfo {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pointsToTheSameElementAs(SmartPointerElementInfo other) {
|
||||
public boolean pointsToTheSameElementAs(@NotNull SmartPointerElementInfo other) {
|
||||
if (other instanceof FileElementInfo) {
|
||||
return myVirtualFile == ((FileElementInfo)other).myVirtualFile;
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ class HardElementInfo implements SmartPointerElementInfo {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pointsToTheSameElementAs(SmartPointerElementInfo other) {
|
||||
public boolean pointsToTheSameElementAs(@NotNull SmartPointerElementInfo other) {
|
||||
return Comparing.equal(myElement, other.restoreElement());
|
||||
}
|
||||
|
||||
|
||||
+56
-7
@@ -17,24 +17,73 @@ package com.intellij.psi.impl.smartPointers;
|
||||
|
||||
import com.intellij.lang.injection.InjectedLanguageManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.Segment;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* User: cdr
|
||||
*/
|
||||
class InjectedSelfElementInfo extends SelfElementInfo {
|
||||
private final SmartPsiFileRange myPsiFileRangeInHostElement;
|
||||
private final Class<? extends PsiElement> myClass;
|
||||
|
||||
InjectedSelfElementInfo(@NotNull Project project,
|
||||
@NotNull PsiElement anchor,
|
||||
@NotNull PsiFile containingFile) {
|
||||
super(project, InjectedLanguageManager.getInstance(project).injectedToHost(anchor, anchor.getTextRange()), anchor.getClass(), InjectedLanguageUtil.getTopLevelFile(containingFile));
|
||||
assert containingFile.getContext() != null;
|
||||
@NotNull PsiElement context) {
|
||||
super(project, context);
|
||||
SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(project);
|
||||
myPsiFileRangeInHostElement = smartPointerManager.createSmartPsiFileRangePointer(context.getContainingFile(), InjectedLanguageManager.getInstance(
|
||||
project).injectedToHost(anchor, anchor.getTextRange()));
|
||||
myClass = anchor.getClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PsiElement findAnchorAt(@NotNull PsiFile file, int syncStartOffset) {
|
||||
return InjectedLanguageUtil.findInjectedElementNoCommitWithOffset(file, syncStartOffset);
|
||||
public VirtualFile getVirtualFile() {
|
||||
PsiElement element = restoreElement();
|
||||
if (element == null) return null;
|
||||
return element.getContainingFile().getVirtualFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement restoreElement() {
|
||||
PsiElement host = super.restoreElement();
|
||||
if (host == null) return null;
|
||||
|
||||
Segment segment = myPsiFileRangeInHostElement.getRange();
|
||||
if (segment == null) return null;
|
||||
final TextRange rangeInHostElement = TextRange.create(segment);
|
||||
final Ref<PsiElement> result = new Ref<PsiElement>();
|
||||
|
||||
InjectedLanguageUtil.enumerate(host, host.getContainingFile(), new PsiLanguageInjectionHost.InjectedPsiVisitor() {
|
||||
@Override
|
||||
public void visit(@NotNull PsiFile injectedPsi, @NotNull List<PsiLanguageInjectionHost.Shred> places) {
|
||||
if (result.get() != null) return;
|
||||
TextRange hostRange =
|
||||
InjectedLanguageManager.getInstance(getProject()).injectedToHost(injectedPsi, new TextRange(0, injectedPsi.getTextLength()));
|
||||
if (hostRange.contains(rangeInHostElement)) {
|
||||
TextRange rangeInside = rangeInHostElement.shiftRight(-hostRange.getStartOffset());
|
||||
PsiElement element = findElementInside(injectedPsi, rangeInside.getStartOffset(), rangeInside.getEndOffset(), myClass);
|
||||
result.set(element);
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
|
||||
return result.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pointsToTheSameElementAs(@NotNull SmartPointerElementInfo other) {
|
||||
if (getClass() != other.getClass()) return false;
|
||||
if (!super.pointsToTheSameElementAs(other)) return false;
|
||||
SmartPointerElementInfo myElementInfo = ((SmartPsiElementPointerImpl)myPsiFileRangeInHostElement).getElementInfo();
|
||||
SmartPointerElementInfo oElementInfo = ((SmartPsiElementPointerImpl)((InjectedSelfElementInfo)other).myPsiFileRangeInHostElement).getElementInfo();
|
||||
return myElementInfo.pointsToTheSameElementAs(oElementInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ import java.lang.ref.SoftReference;
|
||||
* User: cdr
|
||||
*/
|
||||
public class SelfElementInfo implements SmartPointerElementInfo {
|
||||
protected final VirtualFile myVirtualFile;
|
||||
private final VirtualFile myVirtualFile;
|
||||
private Reference<RangeMarker> myMarkerRef; // create marker only in case of live document
|
||||
private int mySyncStartOffset;
|
||||
private int mySyncEndOffset;
|
||||
@@ -44,6 +44,9 @@ public class SelfElementInfo implements SmartPointerElementInfo {
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
private RangeMarker myRangeMarker; //maintain hard reference during modification
|
||||
|
||||
protected SelfElementInfo(@NotNull Project project, @NotNull PsiElement anchor) {
|
||||
this(project, anchor.getTextRange(), anchor.getClass(), anchor.getContainingFile());
|
||||
}
|
||||
public SelfElementInfo(@NotNull Project project, @NotNull TextRange anchor, @NotNull Class anchorClass, @NotNull PsiFile containingFile) {
|
||||
myVirtualFile = containingFile.getVirtualFile();
|
||||
myType = anchorClass;
|
||||
@@ -154,7 +157,11 @@ public class SelfElementInfo implements SmartPointerElementInfo {
|
||||
final int syncStartOffset = getSyncStartOffset();
|
||||
final int syncEndOffset = getSyncEndOffset();
|
||||
|
||||
PsiElement anchor = findAnchorAt(file, syncStartOffset);
|
||||
return findElementInside(file, syncStartOffset, syncEndOffset, myType);
|
||||
}
|
||||
|
||||
protected static PsiElement findElementInside(PsiFile file, int syncStartOffset, int syncEndOffset, Class type) {
|
||||
PsiElement anchor = file.getViewProvider().findElementAt(syncStartOffset, file.getLanguage());
|
||||
if (anchor == null) return null;
|
||||
|
||||
TextRange range = anchor.getTextRange();
|
||||
@@ -166,7 +173,7 @@ public class SelfElementInfo implements SmartPointerElementInfo {
|
||||
range = anchor.getTextRange();
|
||||
}
|
||||
|
||||
while (range.getEndOffset() == syncEndOffset && anchor != null && !myType.equals(anchor.getClass())) {
|
||||
while (range.getEndOffset() == syncEndOffset && anchor != null && !type.equals(anchor.getClass())) {
|
||||
anchor = anchor.getParent();
|
||||
if (anchor == null || anchor.getTextRange() == null) break;
|
||||
range = anchor.getTextRange();
|
||||
@@ -176,10 +183,6 @@ public class SelfElementInfo implements SmartPointerElementInfo {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected PsiElement findAnchorAt(@NotNull PsiFile file, int syncStartOffset) {
|
||||
return file.getViewProvider().findElementAt(syncStartOffset, file.getLanguage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
RangeMarker marker = getMarker();
|
||||
@@ -251,7 +254,7 @@ public class SelfElementInfo implements SmartPointerElementInfo {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pointsToTheSameElementAs(SmartPointerElementInfo other) {
|
||||
public boolean pointsToTheSameElementAs(@NotNull SmartPointerElementInfo other) {
|
||||
if (other instanceof SelfElementInfo) {
|
||||
return myVirtualFile == ((SelfElementInfo)other).myVirtualFile
|
||||
&& myType == ((SelfElementInfo)other).myType
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ interface SmartPointerElementInfo {
|
||||
|
||||
void dispose();
|
||||
int elementHashCode(); // must be immutable
|
||||
boolean pointsToTheSameElementAs(SmartPointerElementInfo other);
|
||||
boolean pointsToTheSameElementAs(@NotNull SmartPointerElementInfo other);
|
||||
|
||||
VirtualFile getVirtualFile();
|
||||
|
||||
|
||||
+7
-9
@@ -85,7 +85,7 @@ class SmartPsiElementPointerImpl<E extends PsiElement> implements SmartPointerEx
|
||||
if (element != null && !element.isValid()) {
|
||||
element = null;
|
||||
}
|
||||
if (element == null && myElementInfo != null) {
|
||||
if (element == null) {
|
||||
element = (E)myElementInfo.restoreElement();
|
||||
if (element != null && (!element.getClass().equals(myElementClass) || !element.isValid())) {
|
||||
element = null;
|
||||
@@ -153,7 +153,8 @@ class SmartPsiElementPointerImpl<E extends PsiElement> implements SmartPointerEx
|
||||
|
||||
FileViewProvider viewProvider = containingFile.getViewProvider();
|
||||
if (viewProvider instanceof InjectedFileViewProvider) {
|
||||
return new InjectedSelfElementInfo(project, element, containingFile);
|
||||
PsiElement context = containingFile.getContext();
|
||||
if (context != null) return new InjectedSelfElementInfo(project, element, context);
|
||||
}
|
||||
|
||||
if (element instanceof PsiFile) {
|
||||
@@ -167,17 +168,13 @@ class SmartPsiElementPointerImpl<E extends PsiElement> implements SmartPointerEx
|
||||
}
|
||||
|
||||
public void documentAndPsiInSync() {
|
||||
if (myElementInfo != null) {
|
||||
myElementInfo.documentAndPsiInSync();
|
||||
}
|
||||
myElementInfo.documentAndPsiInSync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (myElementInfo != null) {
|
||||
myElementInfo.dispose();
|
||||
myElement = null;
|
||||
}
|
||||
myElementInfo.dispose();
|
||||
myElement = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -189,6 +186,7 @@ class SmartPsiElementPointerImpl<E extends PsiElement> implements SmartPointerEx
|
||||
myElementInfo.fastenBelt(offset);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
SmartPointerElementInfo getElementInfo() {
|
||||
return myElementInfo;
|
||||
}
|
||||
|
||||
+1
-1
@@ -221,7 +221,7 @@ public class PostprocessReformattingAspect implements PomModelAspect, Disposable
|
||||
LOG.error(e);
|
||||
}
|
||||
finally {
|
||||
LOG.assertTrue(myReformatElements.isEmpty());
|
||||
LOG.assertTrue(myReformatElements.isEmpty(), myReformatElements);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -22,13 +22,11 @@ import com.intellij.formatting.FormattingModelBuilder;
|
||||
import com.intellij.formatting.IndentInfo;
|
||||
import com.intellij.lang.*;
|
||||
import com.intellij.openapi.command.AbnormalCommandTerminationException;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.TokenType;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.psi.impl.source.tree.Factory;
|
||||
@@ -53,7 +51,13 @@ public class CodeEditUtil {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
};
|
||||
|
||||
private static final ThreadLocal<Boolean> ALLOW_NODES_REFORMATTING = new ThreadLocal<Boolean>() {
|
||||
@Override
|
||||
protected Boolean initialValue() {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
};
|
||||
|
||||
public static final Key<Boolean> OUTER_OK = new Key<Boolean>("OUTER_OK");
|
||||
|
||||
private CodeEditUtil() {
|
||||
@@ -425,7 +429,7 @@ public class CodeEditUtil {
|
||||
* @return <code>true</code> if given node is configured to be reformatted; <code>false</code> otherwise
|
||||
*/
|
||||
public static boolean isMarkedToReformat(final ASTNode node) {
|
||||
return node.getCopyableUserData(REFORMAT_KEY) != null;
|
||||
return node.getCopyableUserData(REFORMAT_KEY) != null && ALLOW_NODES_REFORMATTING.get();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,9 +458,9 @@ public class CodeEditUtil {
|
||||
* to {@link #markToReformat(ASTNode, boolean) mark node for postponed formatting} will have no effect until current method is
|
||||
* called with <code>'true'</code> as an argument. Hence, following usage scenario is expected:
|
||||
* <ol>
|
||||
* <li>this method is called with <code>'false'</code> argument;</li>
|
||||
* <li>formatting is performed at dedicated <code>'try'</code> block;</li>
|
||||
* <li>this method is called with <code>'false'</code> argument from <code>'finally'</code> section;</li>
|
||||
* <li>This method is called with <code>'false'</code> argument;</li>
|
||||
* <li>Formatting is performed at dedicated <code>'try'</code> block;</li>
|
||||
* <li>This method is called with <code>'false'</code> argument from <code>'finally'</code> section;</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param allow flag that defines if new reformat markers can be added from the current thread
|
||||
@@ -465,4 +469,32 @@ public class CodeEditUtil {
|
||||
public static void allowToMarkNodesForPostponedFormatting(boolean allow) {
|
||||
ALLOW_TO_MARK_NODES_TO_REFORMAT.set(allow);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>'allow suspended formatting'</code> flag value
|
||||
* @see #setAllowSuspendNodesReformatting(boolean)
|
||||
*/
|
||||
public static boolean isSuspendedNodesReformattingAllowed() {
|
||||
return ALLOW_NODES_REFORMATTING.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* There is a possible case that particular PSI tree node is {@link #markToReformat(ASTNode, boolean) marked for reformatting}.
|
||||
* That means that there is a big chance that the node will be re-formatted during corresponding document processing
|
||||
* (e.g. on call to {@link PsiDocumentManager#doPostponedOperationsAndUnblockDocument(Document)}).
|
||||
* <p/>
|
||||
* However, there is a possible case that particular activity that triggers such document processing is not ready to the
|
||||
* situation when the document is modified because of postponed formatting. Hence, it may ask to suspend postponed formatting
|
||||
* for a while. This method allows to do that at thread-local manner. I.e. it's expected to be called as follows:
|
||||
* <pre>
|
||||
* <ol>
|
||||
* <li>This method is called with <code>'false'</code> argument;</li>
|
||||
* <li>Document is processed at dedicated <code>'try'</code> block;</li>
|
||||
* <li>This method is called with <code>'false'</code> argument from <code>'finally'</code> section;</li>
|
||||
* </ol>
|
||||
</pre>
|
||||
*/
|
||||
public static void setAllowSuspendNodesReformatting(boolean allow) {
|
||||
ALLOW_NODES_REFORMATTING.set(allow);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -202,7 +202,7 @@ public class FileReference implements FileReferenceOwner, PsiPolyVariantReferenc
|
||||
|
||||
public boolean execute(PsiFileSystemItem element) {
|
||||
result.add(new PsiElementResolveResult(getOriginalFile(element)));
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
package com.intellij.execution.impl;
|
||||
|
||||
import com.intellij.execution.ui.ConsoleViewContentType;
|
||||
import com.intellij.openapi.editor.markup.TextAttributes;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.execution.impl.ConsoleViewImpl.TokenInfo;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Denis Zhdanov
|
||||
* @since 04/06/2011
|
||||
*/
|
||||
public class ConsoleBufferTest {
|
||||
|
||||
private static final ConsoleViewContentType IMPORTANT_OUTPUT = new ConsoleViewContentType("IMPORTANT_OUTPUT", (TextAttributes)null);
|
||||
private static final ConsoleViewContentType NORMAL_OUTPUT = new ConsoleViewContentType("NORMAL_OUTPUT", (TextAttributes)null);
|
||||
private static final ConsoleViewContentType BORING_OUTPUT = new ConsoleViewContentType("BORING_OUTPUT", (TextAttributes)null);
|
||||
|
||||
private ConsoleBuffer myBuffer;
|
||||
private int myBufferSize;
|
||||
private int myBufferUnitSize;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
myBufferSize = 10;
|
||||
myBufferUnitSize = 3;
|
||||
init();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonExceedingBufferSize() {
|
||||
myBuffer.print("a", NORMAL_OUTPUT, null);
|
||||
checkState(s("a"), new TokenInfo(NORMAL_OUTPUT, 0, 1));
|
||||
|
||||
myBuffer.print("b", BORING_OUTPUT, null);
|
||||
checkState(s("ab"), new TokenInfo(NORMAL_OUTPUT, 0, 1), new TokenInfo(BORING_OUTPUT, 1, 2));
|
||||
|
||||
myBuffer.print("cd", BORING_OUTPUT, null);
|
||||
checkState(s("abc", "d"), new TokenInfo(NORMAL_OUTPUT, 0, 1), new TokenInfo(BORING_OUTPUT, 1, 4));
|
||||
|
||||
myBuffer.print("ef", BORING_OUTPUT, null);
|
||||
checkState(s("abc", "def"), new TokenInfo(NORMAL_OUTPUT, 0, 1), new TokenInfo(BORING_OUTPUT, 1, 6));
|
||||
|
||||
myBuffer.print("ghij", NORMAL_OUTPUT, null);
|
||||
checkState(
|
||||
s("abc", "def", "ghi", "j"),
|
||||
new TokenInfo(NORMAL_OUTPUT, 0, 1), new TokenInfo(BORING_OUTPUT, 1, 6), new TokenInfo(NORMAL_OUTPUT, 6, 10)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cycling() {
|
||||
myBuffer.print("abcdefghi", NORMAL_OUTPUT, null);
|
||||
myBuffer.print("jklm", BORING_OUTPUT, null);
|
||||
checkState(s("def", "ghi", "jkl", "m"), new TokenInfo(NORMAL_OUTPUT, 0, 6), new TokenInfo(BORING_OUTPUT, 6, 10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removedTokenOnCyclingIsNotShownAtDeferredTypes() {
|
||||
myBuffer.print("a", BORING_OUTPUT, null);
|
||||
myBuffer.print("bcdefghijklmn", NORMAL_OUTPUT, null);
|
||||
checkState(s("efg", "hij", "klm", "n"), new TokenInfo(NORMAL_OUTPUT, 0, 10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tokenDataIsTrimmed() {
|
||||
myBuffer.print("1234567890", NORMAL_OUTPUT, null);
|
||||
myBuffer.print("123456789012", NORMAL_OUTPUT, null);
|
||||
checkState(s("345", "678", "901", "2"), new TokenInfo(NORMAL_OUTPUT, 0, 10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removingOfGreatNumberOfTokens() {
|
||||
myBuffer.print("a", NORMAL_OUTPUT, null);
|
||||
myBuffer.print("b", BORING_OUTPUT, null);
|
||||
myBuffer.print("a", NORMAL_OUTPUT, null);
|
||||
myBuffer.print("b", BORING_OUTPUT, null);
|
||||
myBuffer.print("a", NORMAL_OUTPUT, null);
|
||||
myBuffer.print("1234567890", BORING_OUTPUT, null);
|
||||
|
||||
checkState(s("123", "456", "789", "0"), new TokenInfo(BORING_OUTPUT, 0, 10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeFromBufferEnd() {
|
||||
myBuffer.print("1234567", IMPORTANT_OUTPUT, null);
|
||||
myBuffer.print("890", NORMAL_OUTPUT, null);
|
||||
myBuffer.print("abc", BORING_OUTPUT, null);
|
||||
|
||||
checkState(
|
||||
s("123", "456", "7ab", "c"),
|
||||
new TokenInfo(IMPORTANT_OUTPUT, 0, 7), new TokenInfo(BORING_OUTPUT, 7, 10)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void smallRemoveAtStart() {
|
||||
myBuffer.print("abc", NORMAL_OUTPUT, null);
|
||||
myBuffer.print("def", BORING_OUTPUT, null);
|
||||
myBuffer.print("ghi", NORMAL_OUTPUT, null);
|
||||
myBuffer.print("k", BORING_OUTPUT, null);
|
||||
myBuffer.print("l", NORMAL_OUTPUT, null);
|
||||
|
||||
checkState(
|
||||
s("bc", "def", "ghi", "kl"),
|
||||
new TokenInfo(NORMAL_OUTPUT, 0, 2), new TokenInfo(BORING_OUTPUT, 2, 5), new TokenInfo(NORMAL_OUTPUT, 5, 8),
|
||||
new TokenInfo(BORING_OUTPUT, 8, 9), new TokenInfo(NORMAL_OUTPUT, 9, 10)
|
||||
);
|
||||
}
|
||||
|
||||
private static List<String> s(String ... strings) {
|
||||
return Arrays.asList(strings);
|
||||
}
|
||||
|
||||
private void checkState(@NotNull List<String> expectedBuffers, @NotNull TokenInfo ... expectedTokens) {
|
||||
Deque<StringBuilder> actualBuffers = myBuffer.getDeferredOutput();
|
||||
assertEquals(expectedBuffers.size(), actualBuffers.size());
|
||||
int i = 0;
|
||||
for (StringBuilder actual : actualBuffers) {
|
||||
String expected = expectedBuffers.get(i++);
|
||||
assertEquals(expected, actual.toString());
|
||||
}
|
||||
|
||||
List<TokenInfo> actualTokens = myBuffer.getDeferredTokens();
|
||||
assertEquals(expectedTokens.length, actualTokens.size());
|
||||
i = 0;
|
||||
Set<ConsoleViewContentType> contentTypes = new HashSet<ConsoleViewContentType>();
|
||||
for (TokenInfo actual : actualTokens) {
|
||||
TokenInfo expected = expectedTokens[i++];
|
||||
assertEquals(expected.contentType, actual.contentType);
|
||||
assertEquals(expected.startOffset, actual.startOffset);
|
||||
assertEquals(expected.endOffset, actual.endOffset);
|
||||
contentTypes.add(expected.contentType);
|
||||
}
|
||||
|
||||
assertEquals(contentTypes, myBuffer.getDeferredTokenTypes());
|
||||
}
|
||||
|
||||
private void init() throws Exception {
|
||||
myBuffer = new ConsoleBuffer(true, myBufferSize, myBufferUnitSize);
|
||||
myBuffer.setContentTypesToNotStripOnCycling(Collections.singleton(IMPORTANT_OUTPUT));
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -71,7 +71,7 @@ public class GenericLineWrapPositionStrategy implements LineWrapPositionStrategy
|
||||
if (rule.condition == WrapCondition.BOTH || rule.condition == WrapCondition.AFTER) {
|
||||
int target = i+1;
|
||||
if (rule.symbol != ' ') {
|
||||
while(i < maxPreferredOffsetToUse && text.charAt(target) == ' ') {
|
||||
while(target < maxPreferredOffsetToUse && text.charAt(target) == ' ') {
|
||||
target++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ public abstract class FileDocumentManager {
|
||||
return ApplicationManager.getApplication().getComponent(FileDocumentManager.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public abstract Document getDocument(@NotNull VirtualFile file);
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -434,6 +434,9 @@ public class IdeEventQueue extends EventQueue {
|
||||
|
||||
if (e instanceof KeyEvent) {
|
||||
myKeyboardBusy = e.getID() != KeyEvent.KEY_RELEASED || ((KeyEvent)e).getModifiers() != 0;
|
||||
if (e.getID() == KeyEvent.KEY_RELEASED && ((KeyEvent)e).getKeyCode() == KeyEvent.VK_SHIFT) {
|
||||
myMouseEventDispatcher.resetHorScrollingTracker();
|
||||
}
|
||||
}
|
||||
|
||||
if (!typeaheadFlushing && typeAheadDispatchToFocusManager(e)) return;
|
||||
|
||||
@@ -30,12 +30,13 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class EditorUtil {
|
||||
private EditorUtil() { }
|
||||
|
||||
public static int getLastVisualLineColumnNumber(Editor editor, int line) {
|
||||
public static int getLastVisualLineColumnNumber(Editor editor, final int line) {
|
||||
Document document = editor.getDocument();
|
||||
int lastLine = document.getLineCount() - 1;
|
||||
if (lastLine < 0) {
|
||||
@@ -128,8 +129,9 @@ public class EditorUtil {
|
||||
|
||||
assert false : String.format(
|
||||
"Target visual line: %d, mapped logical line: %d, visual lines range for the mapped logical line: [%s]-[%s], soft wraps for "
|
||||
+ "the target logical line: %s%nDocument text: '%s'",
|
||||
line, resultLogLine, resVisStart, resVisEnd, softWraps, editor.getDocument().getText()
|
||||
+ "the target logical line: %s, all soft wraps: %s, fold regions: %s%nDocument text: '%s'",
|
||||
line, resultLogLine, resVisStart, resVisEnd, softWraps, editor.getSoftWrapModel().getSoftWrapsForRange(0, document.getTextLength()),
|
||||
Arrays.toString(editor.getFoldingModel().getAllFoldRegions()), editor.getDocument().getText()
|
||||
);
|
||||
return resVisEnd.column;
|
||||
}
|
||||
@@ -372,7 +374,9 @@ public class EditorUtil {
|
||||
|
||||
for (int i = start; i < offset; i++) {
|
||||
char c = text.charAt(i);
|
||||
assert c != '\n' && c != '\r';
|
||||
assert c != '\n' && c != '\r' :
|
||||
String.format("Symbol: %c, its index: %d, given start: %d, given offset: %d, given tab size: %d, text: '%s'",
|
||||
c, i, start, offset, tabSize, text);
|
||||
if (c == '\t') {
|
||||
shift += getTabLength(i + shift - start, tabSize) - 1;
|
||||
}
|
||||
|
||||
@@ -635,6 +635,7 @@ public class SoftWrapModelImpl implements SoftWrapModelEx, PrioritizedDocumentLi
|
||||
+ "%s%nDocument:%n%s%nFold regions: %s",
|
||||
task, myDataMapper, myEditor.getDocument().getText(), Arrays.toString(myEditor.getFoldingModel().fetchTopLevel())), e);
|
||||
}
|
||||
myEditor.getFoldingModel().rebuild();
|
||||
myDataMapper.release();
|
||||
myApplianceManager.reset();
|
||||
myStorage.removeAll();
|
||||
|
||||
+1
@@ -107,6 +107,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl
|
||||
public void disposeComponent() {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Document getDocument(@NotNull final VirtualFile file) {
|
||||
DocumentEx document = (DocumentEx)getCachedDocument(file);
|
||||
if (document == null) {
|
||||
|
||||
+10
-2
@@ -47,6 +47,7 @@ public final class IdeMouseEventDispatcher {
|
||||
private final PresentationFactory myPresentationFactory = new PresentationFactory();
|
||||
private final ArrayList<AnAction> myActions = new ArrayList<AnAction>(1);
|
||||
private final Map<Container, Integer> myRootPane2BlockedId = new HashMap<Container, Integer>();
|
||||
private int myLastHorScrolledComponentHash = 0;
|
||||
|
||||
public IdeMouseEventDispatcher() {
|
||||
}
|
||||
@@ -187,16 +188,23 @@ public final class IdeMouseEventDispatcher {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean doHorizontalScrolling(Component c, MouseWheelEvent me) {
|
||||
FeatureUsageTracker.getInstance().triggerFeatureUsed("ui.horizontal.scrolling");
|
||||
private boolean doHorizontalScrolling(Component c, MouseWheelEvent me) {
|
||||
final JScrollBar scrollBar = findHorizontalScrollBar(c);
|
||||
if (scrollBar != null) {
|
||||
if (scrollBar.hashCode() != myLastHorScrolledComponentHash) {
|
||||
FeatureUsageTracker.getInstance().triggerFeatureUsed("ui.horizontal.scrolling");
|
||||
myLastHorScrolledComponentHash = scrollBar.hashCode();
|
||||
}
|
||||
scrollBar.setValue(scrollBar.getValue() + getScrollAmount(c, me, scrollBar));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void resetHorScrollingTracker() {
|
||||
myLastHorScrolledComponentHash = 0;
|
||||
}
|
||||
|
||||
private static int getScrollAmount(Component c, MouseWheelEvent me, JScrollBar scrollBar) {
|
||||
final int ratio = Registry.is("ide.smart.horizontal.scrolling")
|
||||
? Math.max((int)Math.pow(c.getWidth() / scrollBar.getWidth() , 2), 10) : 10; // do annoying scrolling faster if smart scrolling is on
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<body style="font-family: Verdana; font-size: 13;" LEFTMARGIN="25" TOPMARGIN="25">
|
||||
<table cellpadding="15" width="98%" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
Version control annotations shows latest change of each line in one click!<br/>
|
||||
Use right-click on annotation and
|
||||
<font style="font-family: Verdana; font-weight:bold;" size="3" color="#005555">Show Diff</font> popup,
|
||||
in context menu.<br/><br/>
|
||||
<p><img hspace="20" src="images/annotationShowDiff.png"></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 94 KiB |
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.usages;
|
||||
|
||||
import com.intellij.injected.editor.DocumentWindow;
|
||||
import com.intellij.lexer.Lexer;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
@@ -26,6 +27,7 @@ import com.intellij.openapi.editor.markup.TextAttributes;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.PlainSyntaxHighlighter;
|
||||
import com.intellij.openapi.fileTypes.SyntaxHighlighter;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Segment;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
@@ -101,10 +103,11 @@ public class ChunkExtractor {
|
||||
private ChunkExtractor(@NotNull PsiFile file) {
|
||||
myColorsScheme = UsageTreeColorsScheme.getInstance().getScheme();
|
||||
|
||||
myDocument = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
|
||||
Project project = file.getProject();
|
||||
myDocument = PsiDocumentManager.getInstance(project).getDocument(file);
|
||||
LOG.assertTrue(myDocument != null);
|
||||
final FileType fileType = file.getFileType();
|
||||
final SyntaxHighlighter highlighter = SyntaxHighlighter.PROVIDER.create(fileType, file.getProject(), file.getVirtualFile());
|
||||
final SyntaxHighlighter highlighter = SyntaxHighlighter.PROVIDER.create(fileType, project, file.getVirtualFile());
|
||||
myHighlighter = highlighter == null ? new PlainSyntaxHighlighter() : highlighter;
|
||||
myLexer = myHighlighter.getHighlightingLexer();
|
||||
myLexer.start(myDocument.getCharsSequence());
|
||||
@@ -125,8 +128,15 @@ public class ChunkExtractor {
|
||||
int absoluteStartOffset = usageInfo2UsageAdapter.getNavigationOffset();
|
||||
if (absoluteStartOffset == -1) return TextChunk.EMPTY_ARRAY;
|
||||
|
||||
final int lineNumber = myDocument.getLineNumber(absoluteStartOffset);
|
||||
final int columnNumber = absoluteStartOffset - myDocument.getLineStartOffset(lineNumber);
|
||||
Document visibleDocument = myDocument instanceof DocumentWindow ? ((DocumentWindow)myDocument).getDelegate() : myDocument;
|
||||
int visibleStartOffset = myDocument instanceof DocumentWindow ? ((DocumentWindow)myDocument).injectedToHost(absoluteStartOffset) : absoluteStartOffset;
|
||||
|
||||
int lineNumber = myDocument.getLineNumber(absoluteStartOffset);
|
||||
//int columnNumber = absoluteStartOffset - myDocument.getLineStartOffset(lineNumber);
|
||||
int visibleLineNumber = visibleDocument.getLineNumber(visibleStartOffset);
|
||||
int visibleColumnNumber = visibleStartOffset - visibleDocument.getLineStartOffset(visibleLineNumber);
|
||||
final List<TextChunk> result = new ArrayList<TextChunk>();
|
||||
appendPrefix(result, visibleLineNumber, visibleColumnNumber);
|
||||
|
||||
int lineStartOffset = myDocument.getLineStartOffset(lineNumber);
|
||||
int lineEndOffset = lineStartOffset < myDocument.getTextLength() ? myDocument.getLineEndOffset(lineNumber) : 0;
|
||||
@@ -136,8 +146,6 @@ public class ChunkExtractor {
|
||||
if (myLexer.getTokenStart() > absoluteStartOffset) {
|
||||
myLexer.start(chars);
|
||||
}
|
||||
final List<TextChunk> result = new ArrayList<TextChunk>();
|
||||
appendPrefix(result, lineNumber, columnNumber);
|
||||
if (lineEndOffset - lineStartOffset > MAX_LINE_TO_SHOW) {
|
||||
lineStartOffset = Math.max(lineStartOffset, absoluteStartOffset - OFFSET_BEFORE_TO_SHOW_WHEN_LONG_LINE);
|
||||
lineEndOffset = Math.min(lineEndOffset, absoluteStartOffset + OFFSET_AFTER_TO_SHOW_WHEN_LONG_LINE);
|
||||
|
||||
@@ -41,7 +41,7 @@ public class UsageDataUtil {
|
||||
for (Usage usage : usages) {
|
||||
if (usage instanceof UsageInFile) {
|
||||
VirtualFile file = ((UsageInFile)usage).getFile();
|
||||
if (file.isValid()) {
|
||||
if (file != null && file.isValid()) {
|
||||
result.add(file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.intellij.usages;
|
||||
|
||||
import com.intellij.ide.SelectInEditorManager;
|
||||
import com.intellij.injected.editor.VirtualFileWindow;
|
||||
import com.intellij.openapi.actionSystem.DataKey;
|
||||
import com.intellij.openapi.actionSystem.DataSink;
|
||||
import com.intellij.openapi.actionSystem.TypeSafeDataProvider;
|
||||
@@ -79,7 +80,7 @@ public class UsageInfo2UsageAdapter implements UsageInModule,
|
||||
@Override
|
||||
public void run() {
|
||||
PsiElement element = getElement();
|
||||
Document document = getDocument();
|
||||
Document document = PsiDocumentManager.getInstance(getProject()).getDocument(element.getContainingFile());
|
||||
int startOffset = myUsageInfo.getNavigationOffset();
|
||||
|
||||
if (document != null) {
|
||||
@@ -197,7 +198,8 @@ public class UsageInfo2UsageAdapter implements UsageInModule,
|
||||
}
|
||||
|
||||
public boolean canNavigate() {
|
||||
return getFile().isValid();
|
||||
VirtualFile file = getFile();
|
||||
return file != null && file.isValid();
|
||||
}
|
||||
|
||||
public boolean canNavigateToSource() {
|
||||
@@ -218,7 +220,7 @@ public class UsageInfo2UsageAdapter implements UsageInModule,
|
||||
int offset = getUsageInfo().getNavigationOffset();
|
||||
if (offset == -1) offset = myOffset;
|
||||
if (offset >= document.getTextLength()) {
|
||||
int line = Math.max(0, Math.min(myLineNumber, document.getLineCount()));
|
||||
int line = Math.max(0, Math.min(myLineNumber, document.getLineCount() - 1));
|
||||
offset = document.getLineStartOffset(line);
|
||||
}
|
||||
return offset;
|
||||
@@ -323,16 +325,27 @@ public class UsageInfo2UsageAdapter implements UsageInModule,
|
||||
return myUsageInfo;
|
||||
}
|
||||
|
||||
// by start offset
|
||||
public int compareTo(final UsageInfo2UsageAdapter o) {
|
||||
VirtualFile containingFile = getFile();
|
||||
int shift1 = 0;
|
||||
if (containingFile instanceof VirtualFileWindow) {
|
||||
shift1 = ((VirtualFileWindow)containingFile).getDocumentWindow().injectedToHost(0);
|
||||
containingFile = ((VirtualFileWindow)containingFile).getDelegate();
|
||||
}
|
||||
VirtualFile oContainingFile = o.getFile();
|
||||
int shift2 = 0;
|
||||
if (oContainingFile instanceof VirtualFileWindow) {
|
||||
shift2 = ((VirtualFileWindow)oContainingFile).getDocumentWindow().injectedToHost(0);
|
||||
oContainingFile = ((VirtualFileWindow)oContainingFile).getDelegate();
|
||||
}
|
||||
if (containingFile == null && oContainingFile == null || !Comparing.equal(containingFile, oContainingFile)) {
|
||||
return 0;
|
||||
}
|
||||
Segment s1 = getFirstSegment();
|
||||
Segment s2 = o.getFirstSegment();
|
||||
if (s1 == null || s2 == null) return 0;
|
||||
return s1.getStartOffset() - s2.getStartOffset();
|
||||
return s1.getStartOffset() + shift1 - s2.getStartOffset() - shift2;
|
||||
}
|
||||
|
||||
public void rename(String newName) throws IncorrectOperationException {
|
||||
|
||||
@@ -909,7 +909,8 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra
|
||||
for (Usage usage : usages) {
|
||||
if (usage instanceof UsageInFile) {
|
||||
UsageInFile usageInFile = (UsageInFile)usage;
|
||||
result.add(usageInFile.getFile());
|
||||
VirtualFile file = usageInFile.getFile();
|
||||
if (file != null) result.add(file);
|
||||
}
|
||||
|
||||
if (usage instanceof UsageInFiles) {
|
||||
|
||||
@@ -889,7 +889,7 @@ public class ContainerUtil {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static <T, V> V getOrCreate(final Map<T, V> result, final T key, final Factory<V> factory) {
|
||||
public static <T, V> V getOrCreate(@NotNull Map<T, V> result, final T key, @NotNull Factory<V> factory) {
|
||||
V value = result.get(key);
|
||||
if (value == null) {
|
||||
result.put(key, value = factory.create());
|
||||
|
||||
@@ -28,6 +28,8 @@ import com.intellij.openapi.startup.StartupManager;
|
||||
import com.intellij.openapi.util.DefaultJDOMExternalizer;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -54,6 +56,10 @@ public final class VcsConfiguration implements PersistentStateComponent<Element>
|
||||
@NonNls private static final String VALUE_ATTR = "value";
|
||||
@NonNls private static final String CONFIRM_MOVE_TO_FAILED_COMMIT_ELEMENT = "confirmMoveToFailedCommit";
|
||||
@NonNls private static final String CONFIRM_REMOVE_EMPTY_CHANGELIST_ELEMENT = "confirmRemoveEmptyChangelist";
|
||||
|
||||
@NonNls public static final String PATCH = "patch";
|
||||
@NonNls public static final String DIFF = "diff";
|
||||
|
||||
private Project myProject;
|
||||
|
||||
public boolean OFFER_MOVE_TO_ANOTHER_CHANGELIST_ON_PARTIAL_COMMIT = true;
|
||||
@@ -73,6 +79,7 @@ public final class VcsConfiguration implements PersistentStateComponent<Element>
|
||||
public int CHANGED_ON_SERVER_INTERVAL = 60;
|
||||
public boolean SHOW_ONLY_CHANGED_IN_SELECTION_DIFF = true;
|
||||
public boolean CHECK_COMMIT_MESSAGE_SPELLING = true;
|
||||
public String DEFAULT_PATCH_EXTENSION = PATCH;
|
||||
|
||||
public enum StandardOption {
|
||||
ADD(VcsBundle.message("vcs.command.name.add")),
|
||||
@@ -346,4 +353,17 @@ public final class VcsConfiguration implements PersistentStateComponent<Element>
|
||||
|
||||
}
|
||||
|
||||
public String getPatchFileExtension() {
|
||||
return DEFAULT_PATCH_EXTENSION;
|
||||
}
|
||||
|
||||
public void acceptLastCreatedPatchName(final String string) {
|
||||
if (StringUtil.isEmptyOrSpaces(string)) return;
|
||||
final String extension = FileUtil.getExtension(string);
|
||||
if (DIFF.equalsIgnoreCase(extension)) {
|
||||
DEFAULT_PATCH_EXTENSION = DIFF;
|
||||
} else if (PATCH.equalsIgnoreCase(extension)) {
|
||||
DEFAULT_PATCH_EXTENSION = PATCH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,78 +47,6 @@ public interface ContinuationContext {
|
||||
void suspend();
|
||||
void ping();
|
||||
|
||||
class GatheringContinuationContext implements ContinuationContext {
|
||||
private final List<TaskDescriptor> myList;
|
||||
|
||||
public GatheringContinuationContext() {
|
||||
myList = new ArrayList<TaskDescriptor>();
|
||||
}
|
||||
|
||||
public List<TaskDescriptor> getList() {
|
||||
return myList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelEverything() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Exception> void addExceptionHandler(Class<T> clazz, Consumer<T> consumer) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleException(Exception e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void throwDisaster(Object disaster, final Object cure) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keepExisting(Object disaster, Object cure) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void next(TaskDescriptor... next) {
|
||||
myList.addAll(0, Arrays.asList(next));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void next(List<TaskDescriptor> next) {
|
||||
myList.addAll(0, next);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void last(TaskDescriptor... next) {
|
||||
myList.addAll(Arrays.asList(next));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void last(List<TaskDescriptor> next) {
|
||||
myList.addAll(next);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void after(@NotNull TaskDescriptor inQueue, TaskDescriptor... next) {
|
||||
int idx = -1;
|
||||
for (int i = 0; i < myList.size(); i++) {
|
||||
final TaskDescriptor descriptor = myList.get(i);
|
||||
if (inQueue == descriptor) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert idx != -1;
|
||||
myList.addAll(idx, Arrays.asList(next));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suspend() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ping() {
|
||||
}
|
||||
}
|
||||
}
|
||||
void removeNewTasksPatcher(@NotNull final Consumer<TaskDescriptor> consumer);
|
||||
void addNewTasksPatcher(@NotNull final Consumer<TaskDescriptor> consumer);
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.util.continuation;
|
||||
|
||||
import com.intellij.util.Consumer;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
* Date: 4/7/11
|
||||
* Time: 7:25 PM
|
||||
*/
|
||||
public class ContinuationFinalTasksInserter {
|
||||
private final ContinuationContext myContext;
|
||||
private final Consumer<TaskDescriptor> myPatcher;
|
||||
|
||||
public ContinuationFinalTasksInserter(ContinuationContext context) {
|
||||
myContext = context;
|
||||
myPatcher = new Consumer<TaskDescriptor>() {
|
||||
@Override
|
||||
public void consume(TaskDescriptor taskDescriptor) {
|
||||
taskDescriptor.setHaveMagicCure(true);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void allNextAreFinal() {
|
||||
myContext.addNewTasksPatcher(myPatcher);
|
||||
}
|
||||
|
||||
public void removeFinalPropertyAdder() {
|
||||
myContext.removeNewTasksPatcher(myPatcher);
|
||||
}
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.util.continuation;
|
||||
|
||||
import com.intellij.util.Consumer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
* Date: 4/7/11
|
||||
* Time: 6:43 PM
|
||||
*/
|
||||
public class GatheringContinuationContext implements ContinuationContext {
|
||||
private final List<TaskDescriptor> myList;
|
||||
|
||||
public GatheringContinuationContext() {
|
||||
myList = new ArrayList<TaskDescriptor>();
|
||||
}
|
||||
|
||||
public List<TaskDescriptor> getList() {
|
||||
return myList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelEverything() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Exception> void addExceptionHandler(Class<T> clazz, Consumer<T> consumer) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleException(Exception e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void throwDisaster(Object disaster, final Object cure) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keepExisting(Object disaster, Object cure) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void next(TaskDescriptor... next) {
|
||||
myList.addAll(0, Arrays.asList(next));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void next(List<TaskDescriptor> next) {
|
||||
myList.addAll(0, next);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void last(TaskDescriptor... next) {
|
||||
myList.addAll(Arrays.asList(next));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void last(List<TaskDescriptor> next) {
|
||||
myList.addAll(next);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void after(@NotNull TaskDescriptor inQueue, TaskDescriptor... next) {
|
||||
int idx = -1;
|
||||
for (int i = 0; i < myList.size(); i++) {
|
||||
final TaskDescriptor descriptor = myList.get(i);
|
||||
if (inQueue == descriptor) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert idx != -1;
|
||||
myList.addAll(idx, Arrays.asList(next));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suspend() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ping() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNewTasksPatcher(@NotNull Consumer<TaskDescriptor> consumer) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNewTasksPatcher(@NotNull Consumer<TaskDescriptor> consumer) {
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class TaskDescriptor {
|
||||
// this also means that it would be called in case of chain cancel()
|
||||
private boolean myHaveMagicCure;
|
||||
private final String myName;
|
||||
@NotNull
|
||||
|
||||
+4
-7
@@ -47,10 +47,7 @@ import com.intellij.openapi.vfs.newvfs.RefreshSession;
|
||||
import com.intellij.openapi.wm.ToolWindowManager;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.WaitForProgressToShow;
|
||||
import com.intellij.util.continuation.Continuation;
|
||||
import com.intellij.util.continuation.ContinuationContext;
|
||||
import com.intellij.util.continuation.TaskDescriptor;
|
||||
import com.intellij.util.continuation.Where;
|
||||
import com.intellij.util.continuation.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -111,9 +108,9 @@ public class PatchApplier<BinaryType extends FilePatch> {
|
||||
|
||||
@AsynchronousExecution
|
||||
public void execute(boolean showSuccessNotification) {
|
||||
final Continuation continuation = new Continuation(myProject, true);
|
||||
final ContinuationContext.GatheringContinuationContext initContext =
|
||||
new ContinuationContext.GatheringContinuationContext();
|
||||
final Continuation continuation = Continuation.createForCurrentProgress(myProject, true, "Apply patch");
|
||||
final GatheringContinuationContext initContext =
|
||||
new GatheringContinuationContext();
|
||||
scheduleSelf(showSuccessNotification, initContext);
|
||||
continuation.run(initContext.getList());
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.intellij.openapi.vcs.actions;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.Presentation;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.AbstractVcs;
|
||||
@@ -89,7 +90,10 @@ public abstract class AbstractShowDiffAction extends AbstractVcsAction{
|
||||
final Project project = vcsContext.getProject();
|
||||
final VirtualFile selectedFile = vcsContext.getSelectedFiles()[0];
|
||||
final FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
|
||||
fileDocumentManager.saveDocument(fileDocumentManager.getDocument(selectedFile));
|
||||
final Document document = fileDocumentManager.getDocument(selectedFile);
|
||||
if (document != null) {
|
||||
fileDocumentManager.saveDocument(document);
|
||||
}
|
||||
|
||||
final ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(project);
|
||||
final AbstractVcs vcs = vcsManager.getVcsFor(selectedFile);
|
||||
|
||||
+3
-1
@@ -29,6 +29,7 @@ import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.JDOMExternalizable;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.intellij.openapi.vcs.VcsBundle;
|
||||
import com.intellij.openapi.vcs.VcsConfiguration;
|
||||
import com.intellij.openapi.vcs.changes.*;
|
||||
import com.intellij.openapi.vcs.changes.shelf.ShelveChangesManager;
|
||||
import com.intellij.util.WaitForProgressToShow;
|
||||
@@ -118,7 +119,7 @@ public class CreatePatchCommitExecutor implements CommitExecutorWithHelp, Projec
|
||||
if (PATCH_PATH.length() == 0) {
|
||||
PATCH_PATH = myProject.getBaseDir().getPresentableUrl();
|
||||
}
|
||||
myPanel.setFileName(ShelveChangesManager.suggestPatchName(commitMessage, new File(PATCH_PATH)));
|
||||
myPanel.setFileName(ShelveChangesManager.suggestPatchName(myProject, commitMessage, new File(PATCH_PATH), null));
|
||||
myPanel.setReversePatch(REVERSE_PATCH);
|
||||
return myPanel.getPanel();
|
||||
}
|
||||
@@ -150,6 +151,7 @@ public class CreatePatchCommitExecutor implements CommitExecutorWithHelp, Projec
|
||||
try {
|
||||
final String fileName = myPanel.getFileName();
|
||||
final File file = new File(fileName).getAbsoluteFile();
|
||||
VcsConfiguration.getInstance(myProject).acceptLastCreatedPatchName(file.getName());
|
||||
PATCH_PATH = file.getParent();
|
||||
REVERSE_PATCH = myPanel.isReversePatch();
|
||||
|
||||
|
||||
+1
-1
@@ -141,7 +141,7 @@ public class CreatePatchConfigurationPanel {
|
||||
}
|
||||
|
||||
public boolean isOkToExecute() {
|
||||
return myErrorLabel.getText() == null || myErrorLabel.getText().length() == 0;
|
||||
return myErrorLabel.getText() == null || myErrorLabel.getText().length() == 0;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
|
||||
@@ -36,11 +36,12 @@ import org.jetbrains.annotations.Nullable;
|
||||
import javax.swing.*;
|
||||
|
||||
public class PatchFileType implements FileType {
|
||||
public static final String NAME = "PATCH";
|
||||
|
||||
@NotNull
|
||||
@NonNls
|
||||
public String getName() {
|
||||
return "PATCH";
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -21,8 +21,10 @@ public class PatchNameChecker {
|
||||
public final static int MAX = 100;
|
||||
private final String myName;
|
||||
private String myError;
|
||||
private final String myPath;
|
||||
|
||||
public PatchNameChecker(final String name) {
|
||||
myPath = name;
|
||||
myName = new File(name).getName();
|
||||
}
|
||||
|
||||
@@ -33,6 +35,9 @@ public class PatchNameChecker {
|
||||
} else if (myName.length() > MAX) {
|
||||
myError = "File name length cannot exceed " + MAX + " characters";
|
||||
return false;
|
||||
} else if (new File(myPath).exists()) {
|
||||
myError = "File with the same name already exists";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
+43
-20
@@ -24,7 +24,9 @@ import com.intellij.openapi.fileChooser.FileChooserFactory;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.ui.MessageType;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.vcs.AbstractVcsHelper;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
|
||||
@@ -60,28 +62,49 @@ public class ImportIntoShelfAction extends DumbAwareAction {
|
||||
@Override
|
||||
public void consume(final VirtualFile[] virtualFiles) {
|
||||
if (virtualFiles.length == 0) return;
|
||||
ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final List<VcsException> exceptions = new ArrayList<VcsException>();
|
||||
final List<ShelvedChangeList> lists =
|
||||
ShelveChangesManager.getInstance(project).importChangeLists(Arrays.asList(virtualFiles), new Consumer<VcsException>() {
|
||||
@Override
|
||||
public void consume(VcsException e) {
|
||||
exceptions.add(e);
|
||||
}
|
||||
});
|
||||
if (! lists.isEmpty()) {
|
||||
ShelvedChangesViewManager.getInstance(project).activateView(lists.get(lists.size() - 1));
|
||||
//gatherPatchFiles
|
||||
final ProgressManager pm = ProgressManager.getInstance();
|
||||
final ShelveChangesManager shelveChangesManager = ShelveChangesManager.getInstance(project);
|
||||
final List<VirtualFile> asList = Arrays.asList(virtualFiles);
|
||||
|
||||
final List<VirtualFile> patchTypeFiles = new ArrayList<VirtualFile>();
|
||||
final boolean filesFound = pm.runProcessWithProgressSynchronously(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
patchTypeFiles.addAll(shelveChangesManager.gatherPatchFiles(asList));
|
||||
}
|
||||
if (! exceptions.isEmpty()) {
|
||||
AbstractVcsHelper.getInstance(project).showErrors(exceptions, "Import patches into shelf");
|
||||
}, "Looking for patch files...", true, project);
|
||||
if (! filesFound || patchTypeFiles.isEmpty()) return;
|
||||
if (! patchTypeFiles.equals(asList)) {
|
||||
final int toImport = Messages.showYesNoDialog(project, "Found " +
|
||||
(patchTypeFiles.size() == 1
|
||||
? "one patch file (" + patchTypeFiles.get(0).getPath() + ")."
|
||||
: (patchTypeFiles.size() + " patch files.")) +
|
||||
"\nContinue with import?", "Import patches", Messages.getQuestionIcon());
|
||||
if (DialogWrapper.CANCEL_EXIT_CODE == toImport) return;
|
||||
}
|
||||
pm.runProcessWithProgressSynchronously(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final List<VcsException> exceptions = new ArrayList<VcsException>();
|
||||
final List<ShelvedChangeList> lists =
|
||||
shelveChangesManager.importChangeLists(patchTypeFiles, new Consumer<VcsException>() {
|
||||
@Override
|
||||
public void consume(VcsException e) {
|
||||
exceptions.add(e);
|
||||
}
|
||||
});
|
||||
if (!lists.isEmpty()) {
|
||||
ShelvedChangesViewManager.getInstance(project).activateView(lists.get(lists.size() - 1));
|
||||
}
|
||||
if (!exceptions.isEmpty()) {
|
||||
AbstractVcsHelper.getInstance(project).showErrors(exceptions, "Import patches into shelf");
|
||||
}
|
||||
if (lists.isEmpty() && exceptions.isEmpty()) {
|
||||
VcsBalloonProblemNotifier.showOverChangesView(project, "No patches found", MessageType.WARNING);
|
||||
}
|
||||
}
|
||||
if (lists.isEmpty() && exceptions.isEmpty()) {
|
||||
VcsBalloonProblemNotifier.showOverChangesView(project, "No patches found", MessageType.WARNING);
|
||||
}
|
||||
}
|
||||
}, "Import patches into shelf", true, project);
|
||||
}, "Import patches into shelf", true, project);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+31
-23
@@ -37,21 +37,17 @@ import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.FilePathImpl;
|
||||
import com.intellij.openapi.vcs.VcsBundle;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.*;
|
||||
import com.intellij.openapi.vcs.changes.*;
|
||||
import com.intellij.openapi.vcs.changes.patch.PatchFileType;
|
||||
import com.intellij.openapi.vcs.changes.patch.PatchNameChecker;
|
||||
import com.intellij.openapi.vcs.changes.ui.RollbackWorker;
|
||||
import com.intellij.openapi.vcs.impl.VcsFileTypeFactory;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.PathUtil;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.continuation.Continuation;
|
||||
import com.intellij.util.continuation.ContinuationContext;
|
||||
import com.intellij.util.continuation.TaskDescriptor;
|
||||
import com.intellij.util.continuation.Where;
|
||||
import com.intellij.util.continuation.*;
|
||||
import com.intellij.util.messages.MessageBus;
|
||||
import com.intellij.util.messages.Topic;
|
||||
import com.intellij.util.text.CharArrayCharSequence;
|
||||
@@ -68,8 +64,6 @@ import java.util.*;
|
||||
public class ShelveChangesManager implements ProjectComponent, JDOMExternalizable {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.shelf.ShelveChangesManager");
|
||||
|
||||
@NonNls private static final String PATCH_EXTENSION = "patch";
|
||||
|
||||
public static ShelveChangesManager getInstance(Project project) {
|
||||
return PeriodicalTasksCloser.getInstance().safeGetComponent(project, ShelveChangesManager.class);
|
||||
}
|
||||
@@ -221,17 +215,30 @@ public class ShelveChangesManager implements ProjectComponent, JDOMExternalizabl
|
||||
}
|
||||
}
|
||||
|
||||
public List<VirtualFile> gatherPatchFiles(final Collection<VirtualFile> files) {
|
||||
final List<VirtualFile> result = new ArrayList<VirtualFile>();
|
||||
|
||||
final LinkedList<VirtualFile> filesQueue = new LinkedList<VirtualFile>(files);
|
||||
while (! filesQueue.isEmpty()) {
|
||||
ProgressManager.checkCanceled();
|
||||
final VirtualFile file = filesQueue.removeFirst();
|
||||
if (file.isDirectory()) {
|
||||
filesQueue.addAll(Arrays.asList(file.getChildren()));
|
||||
continue;
|
||||
}
|
||||
if (PatchFileType.NAME.equals(file.getFileType().getName())) {
|
||||
result.add(file);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<ShelvedChangeList> importChangeLists(final Collection<VirtualFile> files, final Consumer<VcsException> exceptionConsumer) {
|
||||
final List<ShelvedChangeList> result = new ArrayList<ShelvedChangeList>(files.size());
|
||||
try {
|
||||
final LinkedList<VirtualFile> filesQueue = new LinkedList<VirtualFile>(files);
|
||||
while (! filesQueue.isEmpty()) {
|
||||
for (VirtualFile file : files) {
|
||||
ProgressManager.checkCanceled();
|
||||
final VirtualFile file = filesQueue.removeFirst();
|
||||
if (file.isDirectory()) {
|
||||
filesQueue.addAll(Arrays.asList(file.getChildren()));
|
||||
continue;
|
||||
}
|
||||
|
||||
final String description = file.getNameWithoutExtension().replace('_', ' ');
|
||||
final File patchPath = getPatchPath(description);
|
||||
@@ -289,16 +296,17 @@ public class ShelveChangesManager implements ProjectComponent, JDOMExternalizabl
|
||||
file.mkdirs();
|
||||
}
|
||||
|
||||
return suggestPatchName(commitMessage.length() > PatchNameChecker.MAX ? (commitMessage.substring(0, PatchNameChecker.MAX)) :
|
||||
commitMessage, file);
|
||||
return suggestPatchName(myProject, commitMessage.length() > PatchNameChecker.MAX ? (commitMessage.substring(0, PatchNameChecker.MAX)) :
|
||||
commitMessage, file, VcsConfiguration.PATCH);
|
||||
}
|
||||
|
||||
public static File suggestPatchName(final String commitMessage, final File file) {
|
||||
public static File suggestPatchName(Project project, final String commitMessage, final File file, String extension) {
|
||||
@NonNls String defaultPath = PathUtil.suggestFileName(commitMessage);
|
||||
if (defaultPath.length() == 0) {
|
||||
defaultPath = "unnamed";
|
||||
}
|
||||
return FileUtil.findSequentNonexistentFile(file, defaultPath, PATCH_EXTENSION);
|
||||
return FileUtil.findSequentNonexistentFile(file, defaultPath,
|
||||
extension == null ? VcsConfiguration.getInstance(project).getPatchFileExtension() : extension);
|
||||
}
|
||||
|
||||
public void unshelveChangeList(final ShelvedChangeList changeList, @Nullable final List<ShelvedChange> changes,
|
||||
@@ -312,8 +320,8 @@ public class ShelveChangesManager implements ProjectComponent, JDOMExternalizabl
|
||||
@Nullable final List<ShelvedBinaryFile> binaryFiles,
|
||||
@Nullable final LocalChangeList targetChangeList,
|
||||
boolean showSuccessNotification) {
|
||||
final Continuation continuation = new Continuation(myProject, true);
|
||||
final ContinuationContext.GatheringContinuationContext initContext = new ContinuationContext.GatheringContinuationContext();
|
||||
final Continuation continuation = Continuation.createForCurrentProgress(myProject, true, "Unshelve changes");
|
||||
final GatheringContinuationContext initContext = new GatheringContinuationContext();
|
||||
scheduleUnshelveChangeList(changeList, changes, binaryFiles, targetChangeList, showSuccessNotification, initContext);
|
||||
continuation.run(initContext.getList());
|
||||
}
|
||||
|
||||
+16
-4
@@ -27,11 +27,16 @@ import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.VcsBundle;
|
||||
import com.intellij.openapi.vcs.changes.BackgroundFromStartOption;
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManager;
|
||||
import com.intellij.openapi.vcs.changes.LocalChangeList;
|
||||
import com.intellij.openapi.vcs.changes.ui.ChangeListChooser;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -65,7 +70,7 @@ public class UnshelveChangesAction extends AnAction {
|
||||
}
|
||||
}
|
||||
defaultName = changeLists.length == 1 ? changeLists [0].DESCRIPTION : null;
|
||||
ChangeListChooser chooser = new ChangeListChooser(project, allChangeLists, list,
|
||||
final ChangeListChooser chooser = new ChangeListChooser(project, allChangeLists, list,
|
||||
VcsBundle.message("unshelve.changelist.chooser.title"), defaultName);
|
||||
chooser.show();
|
||||
if (!chooser.isOK()) {
|
||||
@@ -74,9 +79,16 @@ public class UnshelveChangesAction extends AnAction {
|
||||
|
||||
FileDocumentManager.getInstance().saveAllDocuments();
|
||||
|
||||
for(ShelvedChangeList changeList: changeLists) {
|
||||
ShelveChangesManager.getInstance(project).unshelveChangeList(changeList, changes, binaryFiles, chooser.getSelectedList());
|
||||
}
|
||||
final List<ShelvedBinaryFile> finalBinaryFiles = binaryFiles;
|
||||
final List<ShelvedChange> finalChanges = changes;
|
||||
ProgressManager.getInstance().run(new Task.Backgroundable(project, "Unshelve changes", true, BackgroundFromStartOption.getInstance()) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
for(ShelvedChangeList changeList: changeLists) {
|
||||
ShelveChangesManager.getInstance(project).unshelveChangeList(changeList, finalChanges, finalBinaryFiles, chooser.getSelectedList());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.intellij.openapi.vcs.impl;
|
||||
|
||||
import com.intellij.openapi.fileTypes.FileTypeFactory;
|
||||
import com.intellij.openapi.fileTypes.FileTypeConsumer;
|
||||
import com.intellij.openapi.vcs.VcsConfiguration;
|
||||
import com.intellij.openapi.vcs.changes.patch.PatchFileType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -25,6 +26,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
*/
|
||||
public class VcsFileTypeFactory extends FileTypeFactory {
|
||||
public void createFileTypes(@NotNull FileTypeConsumer consumer) {
|
||||
consumer.consume(new PatchFileType(), "patch;diff");
|
||||
consumer.consume(new PatchFileType(), VcsConfiguration.PATCH + ";" + VcsConfiguration.DIFF);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.vcs.update;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.progress.PerformInBackgroundOption;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.util.Icons;
|
||||
import com.intellij.util.continuation.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
* Date: 4/7/11
|
||||
* Time: 7:06 PM
|
||||
*/
|
||||
public class TestContinuationAction extends AnAction {
|
||||
public TestContinuationAction() {
|
||||
super("Test Continuation", "Test Continuation", Icons.ADVICE_ICON);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(final AnActionEvent e) {
|
||||
final Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext());
|
||||
if (project == null) return;
|
||||
|
||||
ProgressManager.getInstance().run(new Task.Backgroundable(project, "Test Continuation", true,
|
||||
new PerformInBackgroundOption() {
|
||||
@Override
|
||||
public boolean shouldStartInBackground() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processSentToBackground() {
|
||||
}
|
||||
}) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
final Continuation continuation = Continuation.createForCurrentProgress(project, true, e.getPresentation().getText());
|
||||
final ReportTask finalBlock = new ReportTask("I'm finally block!");
|
||||
finalBlock.setHaveMagicCure(true);
|
||||
continuation.run(new TaskDescriptor[] {new LongTaskDescriptor("First"), new ReportTask("First complete"),
|
||||
new TaskDescriptor("Adding task", Where.POOLED) {
|
||||
@Override
|
||||
public void run(final ContinuationContext context) {
|
||||
addMore(context);
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
}
|
||||
catch (InterruptedException e1) {
|
||||
//
|
||||
}
|
||||
}
|
||||
},
|
||||
new LongTaskDescriptor("Second"), new ReportTask("Second complete"),
|
||||
new TaskDescriptor("Adding task 2", Where.POOLED) {
|
||||
@Override
|
||||
public void run(final ContinuationContext context) {
|
||||
addMoreSurviving(context);
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
}
|
||||
catch (InterruptedException e1) {
|
||||
//
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
/*context.suspend();
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
context.ping();
|
||||
}
|
||||
}, ModalityState.NON_MODAL);*/
|
||||
}
|
||||
},
|
||||
new LongTaskDescriptor("Third"), new ReportTask("Third complete"),
|
||||
finalBlock});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
Messages.showInfoMessage("cancel!", myTitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
Messages.showInfoMessage("success!", myTitle);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void addMore(ContinuationContext context) {
|
||||
context.next(new LongTaskDescriptor("Inside killable"), new ReportTask("Inside killable complete"));
|
||||
}
|
||||
|
||||
private void addMoreSurviving(ContinuationContext context) {
|
||||
final ContinuationFinalTasksInserter finalTasksInserter = new ContinuationFinalTasksInserter(context);
|
||||
finalTasksInserter.allNextAreFinal();
|
||||
context.next(new LongTaskDescriptor("Inside surviving"), new ReportTask("Inside surviving complete"));
|
||||
finalTasksInserter.removeFinalPropertyAdder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
final Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext());
|
||||
e.getPresentation().setEnabled(project != null);
|
||||
}
|
||||
|
||||
private static class ReportTask extends TaskDescriptor {
|
||||
private ReportTask(String name) {
|
||||
super(name, Where.AWT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ContinuationContext context) {
|
||||
Messages.showInfoMessage(getName(), "Result");
|
||||
}
|
||||
}
|
||||
|
||||
private static class LongTaskDescriptor extends TaskDescriptor {
|
||||
private LongTaskDescriptor(final String name) {
|
||||
super(name, Where.POOLED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ContinuationContext context) {
|
||||
final ProgressIndicator pi = ProgressManager.getInstance().getProgressIndicator();
|
||||
pi.setText(getName());
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
//
|
||||
}
|
||||
pi.setText("");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,91 +15,50 @@
|
||||
*/
|
||||
package com.intellij.util.continuation;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.progress.EmptyProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator;
|
||||
import com.intellij.openapi.progress.impl.ProgressManagerImpl;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.CalledInAny;
|
||||
import com.intellij.openapi.vcs.CalledInAwt;
|
||||
import com.intellij.openapi.vcs.changes.BackgroundFromStartOption;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.WaitForProgressToShow;
|
||||
import com.intellij.util.concurrency.Semaphore;
|
||||
import com.sun.tools.javac.code.Attribute;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Continuation {
|
||||
private GeneralRunner myGeneralRunner;
|
||||
|
||||
public Continuation(final Project project, final boolean cancellable) {
|
||||
myGeneralRunner = new GeneralRunner(project, cancellable);
|
||||
private Continuation(GeneralRunner generalRunner) {
|
||||
myGeneralRunner = generalRunner;
|
||||
}
|
||||
|
||||
public static Continuation createForCurrentProgress(final Project project, final boolean cancellable, final String commonTitle) {
|
||||
return new Continuation(new SameProgressRunner(project, cancellable, commonTitle));
|
||||
}
|
||||
|
||||
public static Continuation createFragmented(final Project project, final boolean cancellable) {
|
||||
return new Continuation(new SeparatePiecesRunner(project, cancellable));
|
||||
}
|
||||
|
||||
public void run(final TaskDescriptor... tasks) {
|
||||
if (tasks.length == 0) return;
|
||||
myGeneralRunner.next(tasks);
|
||||
|
||||
pingRunnerInCorrectThread();
|
||||
myGeneralRunner.ping();
|
||||
}
|
||||
|
||||
public void run(final List<TaskDescriptor> tasks) {
|
||||
if (tasks.isEmpty()) return;
|
||||
myGeneralRunner.next(tasks);
|
||||
|
||||
pingRunnerInCorrectThread();
|
||||
}
|
||||
|
||||
public void runAndWait(final TaskDescriptor... tasks) {
|
||||
runAndWait(Arrays.asList(tasks));
|
||||
}
|
||||
|
||||
public void runAndWait(final List<TaskDescriptor> tasks) {
|
||||
final Semaphore semaphore = new Semaphore();
|
||||
semaphore.down();
|
||||
tasks.add(new TaskDescriptor("", Where.AWT) {
|
||||
@Override
|
||||
public void run(ContinuationContext context) {
|
||||
semaphore.up();
|
||||
}
|
||||
});
|
||||
run(tasks);
|
||||
semaphore.waitFor();
|
||||
myGeneralRunner.ping();
|
||||
}
|
||||
|
||||
public <T extends Exception> void addExceptionHandler(final Class<T> clazz, final Consumer<T> consumer) {
|
||||
myGeneralRunner.addExceptionHandler(clazz, consumer);
|
||||
}
|
||||
|
||||
public void runIndirect(final Consumer<ContinuationContext> consumer) {
|
||||
consumer.consume(myGeneralRunner);
|
||||
if (myGeneralRunner.isEmpty()) return;
|
||||
|
||||
pingRunnerInCorrectThread();
|
||||
}
|
||||
|
||||
public void resume() {
|
||||
myGeneralRunner.ping();
|
||||
}
|
||||
|
||||
private void pingRunnerInCorrectThread() {
|
||||
if (! ApplicationManager.getApplication().isDispatchThread()) {
|
||||
WaitForProgressToShow.runOrInvokeLaterAboveProgress(new Runnable() {
|
||||
public void run() {
|
||||
myGeneralRunner.ping();
|
||||
}
|
||||
}, null, myGeneralRunner.getProject());
|
||||
} else {
|
||||
myGeneralRunner.ping();
|
||||
}
|
||||
}
|
||||
|
||||
public void clearQueue() {
|
||||
myGeneralRunner.cancelEverything();
|
||||
}
|
||||
@@ -116,224 +75,7 @@ public class Continuation {
|
||||
return myGeneralRunner.isEmpty();
|
||||
}
|
||||
|
||||
private static class TaskWrapper extends Task.Backgroundable {
|
||||
private final TaskDescriptor myTaskDescriptor;
|
||||
private final GeneralRunner myGeneralRunner;
|
||||
|
||||
private TaskWrapper(@Nullable Project project,
|
||||
@NotNull String title,
|
||||
boolean canBeCancelled,
|
||||
TaskDescriptor taskDescriptor,
|
||||
GeneralRunner generalRunner) {
|
||||
super(project, title, canBeCancelled, BackgroundFromStartOption.getInstance());
|
||||
myTaskDescriptor = taskDescriptor;
|
||||
myGeneralRunner = generalRunner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
myTaskDescriptor.run(myGeneralRunner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
myGeneralRunner.ping();
|
||||
}
|
||||
}
|
||||
|
||||
private static class GeneralRunner implements ContinuationContext {
|
||||
private final Project myProject;
|
||||
private final boolean myCancellable;
|
||||
private final List<TaskDescriptor> myQueue;
|
||||
private final Object myQueueLock;
|
||||
private volatile boolean myTriggerSuspend;
|
||||
private ProgressIndicator myIndicator;
|
||||
private final Map<Object, Object> myDisasters;
|
||||
private final Map<Class<? extends Exception>, Consumer<Exception>> myHandlersMap;
|
||||
|
||||
private GeneralRunner(final Project project, boolean cancellable) {
|
||||
myProject = project;
|
||||
myCancellable = cancellable;
|
||||
myQueueLock = new Object();
|
||||
myQueue = new LinkedList<TaskDescriptor>();
|
||||
myDisasters = new HashMap<Object, Object>();
|
||||
myHandlersMap = new HashMap<Class<? extends Exception>, Consumer<Exception>>();
|
||||
}
|
||||
|
||||
public <T extends Exception> void addExceptionHandler(final Class<T> clazz, final Consumer<T> consumer) {
|
||||
synchronized (myQueueLock) {
|
||||
myHandlersMap.put(clazz, new Consumer<Exception>() {
|
||||
@Override
|
||||
public void consume(Exception e) {
|
||||
if (! clazz.isAssignableFrom(e.getClass())) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
consumer.consume((T) e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
return myProject;
|
||||
}
|
||||
|
||||
public void clearDisasters() {
|
||||
synchronized (myQueueLock) {
|
||||
myDisasters.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleException(Exception e) {
|
||||
synchronized (myQueueLock) {
|
||||
final Class<? extends Exception> aClass = e.getClass();
|
||||
Consumer<Exception> consumer = myHandlersMap.get(e.getClass());
|
||||
if (consumer != null) {
|
||||
consumer.consume(e);
|
||||
return true;
|
||||
}
|
||||
for (Map.Entry<Class<? extends Exception>, Consumer<Exception>> entry : myHandlersMap.entrySet()) {
|
||||
if (entry.getKey().isAssignableFrom(aClass)) {
|
||||
entry.getValue().consume(e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@CalledInAny
|
||||
public void cancelEverything() {
|
||||
synchronized (myQueueLock) {
|
||||
myQueue.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void cancelCurrent() {
|
||||
if (myIndicator != null) {
|
||||
myIndicator.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
public void suspend() {
|
||||
myTriggerSuspend = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keepExisting(Object disaster, Object cure) {
|
||||
synchronized (myQueueLock) {
|
||||
for (TaskDescriptor taskDescriptor : myQueue) {
|
||||
taskDescriptor.addCure(disaster, cure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void throwDisaster(@NotNull Object disaster, @NotNull final Object cure) {
|
||||
synchronized (myQueueLock) {
|
||||
final Iterator<TaskDescriptor> iterator = myQueue.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final TaskDescriptor taskDescriptor = iterator.next();
|
||||
if (taskDescriptor.isHaveMagicCure()) continue;
|
||||
final Object taskCure = taskDescriptor.hasCure(disaster);
|
||||
if (! cure.equals(taskCure)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
myDisasters.put(disaster, cure);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void after(@NotNull TaskDescriptor inQueue, TaskDescriptor... next) {
|
||||
synchronized (myQueueLock) {
|
||||
int idx = -1;
|
||||
int i = 0;
|
||||
for (TaskDescriptor descriptor : myQueue) {
|
||||
if (descriptor == inQueue) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
++ i;
|
||||
}
|
||||
assert idx != -1;
|
||||
myQueue.addAll(idx + 1, Arrays.asList(next));
|
||||
}
|
||||
}
|
||||
|
||||
@CalledInAny
|
||||
public void next(TaskDescriptor... next) {
|
||||
synchronized (myQueueLock) {
|
||||
myQueue.addAll(0, Arrays.asList(next));
|
||||
}
|
||||
}
|
||||
|
||||
public void next(List<TaskDescriptor> next) {
|
||||
synchronized (myQueueLock) {
|
||||
myQueue.addAll(0, next);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void last(List<TaskDescriptor> next) {
|
||||
synchronized (myQueueLock) {
|
||||
myQueue.addAll(next);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void last(TaskDescriptor... next) {
|
||||
synchronized (myQueueLock) {
|
||||
myQueue.addAll(Arrays.asList(next));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
synchronized (myQueueLock) {
|
||||
return myQueue.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
public void ping() {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
|
||||
while (true) {
|
||||
// stop if project is being disposed
|
||||
if (! myProject.isOpen()) return;
|
||||
|
||||
TaskDescriptor current;
|
||||
synchronized (myQueueLock) {
|
||||
if (myQueue.isEmpty()) return;
|
||||
if (myTriggerSuspend) {
|
||||
myTriggerSuspend = false;
|
||||
return;
|
||||
}
|
||||
current = myQueue.remove(0);
|
||||
// check if some tasks were scheduled after disaster was thrown, anyway, they should also be checked for cure
|
||||
if (! current.isHaveMagicCure()) {
|
||||
for (Map.Entry<Object, Object> entry : myDisasters.entrySet()) {
|
||||
if (! entry.getValue().equals(current.hasCure(entry.getKey()))) {
|
||||
current = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (current == null) continue;
|
||||
}
|
||||
|
||||
if (Where.AWT.equals(current.getWhere())) {
|
||||
myIndicator = null;
|
||||
current.run(this);
|
||||
} else {
|
||||
final TaskWrapper task = new TaskWrapper(myProject, current.getName(), myCancellable, current, this);
|
||||
myIndicator = ApplicationManager.getApplication().isUnitTestMode() ? new EmptyProgressIndicator() :
|
||||
new BackgroundableProcessIndicator(task);
|
||||
ProgressManagerImpl.runProcessWithProgressAsynchronously(task, myIndicator);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
public void onCancel() {
|
||||
myGeneralRunner.onCancel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.util.continuation;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.progress.EmptyProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator;
|
||||
import com.intellij.openapi.progress.impl.ProgressManagerImpl;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.CalledInAny;
|
||||
import com.intellij.openapi.vcs.CalledInAwt;
|
||||
import com.intellij.util.Consumer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
* Date: 4/7/11
|
||||
* Time: 2:44 PM
|
||||
*/
|
||||
abstract class GeneralRunner implements ContinuationContext {
|
||||
protected final Project myProject;
|
||||
protected final boolean myCancellable;
|
||||
protected final List<TaskDescriptor> myQueue;
|
||||
protected final Object myQueueLock;
|
||||
protected volatile boolean myTriggerSuspend;
|
||||
protected ProgressIndicator myIndicator;
|
||||
protected final Map<Object, Object> myDisasters;
|
||||
private final List<Consumer<TaskDescriptor>> myTasksPatchers;
|
||||
private final Map<Class<? extends Exception>, Consumer<Exception>> myHandlersMap;
|
||||
|
||||
GeneralRunner(final Project project, boolean cancellable) {
|
||||
myProject = project;
|
||||
myCancellable = cancellable;
|
||||
myQueueLock = new Object();
|
||||
myQueue = new LinkedList<TaskDescriptor>();
|
||||
myDisasters = new HashMap<Object, Object>();
|
||||
myHandlersMap = new HashMap<Class<? extends Exception>, Consumer<Exception>>();
|
||||
myTasksPatchers = new ArrayList<Consumer<TaskDescriptor>>();
|
||||
}
|
||||
|
||||
public <T extends Exception> void addExceptionHandler(final Class<T> clazz, final Consumer<T> consumer) {
|
||||
synchronized (myQueueLock) {
|
||||
myHandlersMap.put(clazz, new Consumer<Exception>() {
|
||||
@Override
|
||||
public void consume(Exception e) {
|
||||
if (!clazz.isAssignableFrom(e.getClass())) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
consumer.consume((T)e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
return myProject;
|
||||
}
|
||||
|
||||
public void clearDisasters() {
|
||||
synchronized (myQueueLock) {
|
||||
myDisasters.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleException(Exception e) {
|
||||
synchronized (myQueueLock) {
|
||||
final Class<? extends Exception> aClass = e.getClass();
|
||||
Consumer<Exception> consumer = myHandlersMap.get(e.getClass());
|
||||
if (consumer != null) {
|
||||
consumer.consume(e);
|
||||
return true;
|
||||
}
|
||||
for (Map.Entry<Class<? extends Exception>, Consumer<Exception>> entry : myHandlersMap.entrySet()) {
|
||||
if (entry.getKey().isAssignableFrom(aClass)) {
|
||||
entry.getValue().consume(e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@CalledInAny
|
||||
public void cancelEverything() {
|
||||
synchronized (myQueueLock) {
|
||||
myQueue.clear();
|
||||
myIndicator = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void cancelCurrent() {
|
||||
if (myIndicator != null) {
|
||||
myIndicator.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
public void suspend() {
|
||||
myTriggerSuspend = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keepExisting(Object disaster, Object cure) {
|
||||
synchronized (myQueueLock) {
|
||||
for (TaskDescriptor taskDescriptor : myQueue) {
|
||||
taskDescriptor.addCure(disaster, cure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void throwDisaster(@NotNull Object disaster, @NotNull final Object cure) {
|
||||
synchronized (myQueueLock) {
|
||||
final Iterator<TaskDescriptor> iterator = myQueue.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final TaskDescriptor taskDescriptor = iterator.next();
|
||||
if (taskDescriptor.isHaveMagicCure()) continue;
|
||||
final Object taskCure = taskDescriptor.hasCure(disaster);
|
||||
if (! cure.equals(taskCure)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
myDisasters.put(disaster, cure);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void after(@NotNull TaskDescriptor inQueue, TaskDescriptor... next) {
|
||||
synchronized (myQueueLock) {
|
||||
int idx = -1;
|
||||
int i = 0;
|
||||
for (TaskDescriptor descriptor : myQueue) {
|
||||
if (descriptor == inQueue) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
++ i;
|
||||
}
|
||||
assert idx != -1;
|
||||
final List<TaskDescriptor> asList = Arrays.asList(next);
|
||||
patchTasks(asList);
|
||||
myQueue.addAll(idx + 1, asList);
|
||||
}
|
||||
}
|
||||
|
||||
private void patchTasks(final List<TaskDescriptor> next) {
|
||||
for (TaskDescriptor descriptor : next) {
|
||||
for (Consumer<TaskDescriptor> tasksPatcher : myTasksPatchers) {
|
||||
tasksPatcher.consume(descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@CalledInAny
|
||||
public void next(TaskDescriptor... next) {
|
||||
synchronized (myQueueLock) {
|
||||
final List<TaskDescriptor> asList = Arrays.asList(next);
|
||||
patchTasks(asList);
|
||||
myQueue.addAll(0, asList);
|
||||
}
|
||||
}
|
||||
|
||||
public void next(List<TaskDescriptor> next) {
|
||||
synchronized (myQueueLock) {
|
||||
patchTasks(next);
|
||||
myQueue.addAll(0, next);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void last(List<TaskDescriptor> next) {
|
||||
synchronized (myQueueLock) {
|
||||
patchTasks(next);
|
||||
myQueue.addAll(next);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void last(TaskDescriptor... next) {
|
||||
synchronized (myQueueLock) {
|
||||
final List<TaskDescriptor> asList = Arrays.asList(next);
|
||||
patchTasks(asList);
|
||||
myQueue.addAll(asList);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
synchronized (myQueueLock) {
|
||||
return myQueue.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void ping();
|
||||
|
||||
@Override
|
||||
public void addNewTasksPatcher(@NotNull Consumer<TaskDescriptor> consumer) {
|
||||
synchronized (myQueueLock) {
|
||||
myTasksPatchers.add(consumer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNewTasksPatcher(@NotNull Consumer<TaskDescriptor> consumer) {
|
||||
synchronized (myQueueLock) {
|
||||
myTasksPatchers.remove(consumer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@CalledInAwt
|
||||
public void onCancel() {
|
||||
// left only "final" tasks
|
||||
synchronized (myQueueLock) {
|
||||
if (myQueue.isEmpty()) return;
|
||||
final Iterator<TaskDescriptor> iterator = myQueue.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final TaskDescriptor next = iterator.next();
|
||||
if (! next.isHaveMagicCure()) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ping();
|
||||
}
|
||||
|
||||
// null - no more tasks or suspend
|
||||
@Nullable
|
||||
protected TaskDescriptor getNextMatching() {
|
||||
while (true) {
|
||||
synchronized (myQueueLock) {
|
||||
if (myQueue.isEmpty()) return null;
|
||||
if (myTriggerSuspend) {
|
||||
return null;
|
||||
}
|
||||
TaskDescriptor current = myQueue.remove(0);
|
||||
// check if some tasks were scheduled after disaster was thrown, anyway, they should also be checked for cure
|
||||
if (! current.isHaveMagicCure()) {
|
||||
if (myIndicator != null && myIndicator.isCanceled()) {
|
||||
current = null;
|
||||
continue;
|
||||
} else {
|
||||
for (Map.Entry<Object, Object> entry : myDisasters.entrySet()) {
|
||||
if (! entry.getValue().equals(current.hasCure(entry.getKey()))) {
|
||||
current = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (current != null) return current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.util.continuation;
|
||||
|
||||
import com.intellij.CommonBundle;
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.EmptyProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.vcs.changes.BackgroundFromStartOption;
|
||||
import com.intellij.util.WaitForProgressToShow;
|
||||
import com.intellij.util.concurrency.Semaphore;
|
||||
import sun.util.LocaleServiceProviderPool;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
* Date: 4/7/11
|
||||
* Time: 2:54 PM
|
||||
*/
|
||||
public class SameProgressRunner extends GeneralRunner {
|
||||
private final Thread myInitThread;
|
||||
private final Semaphore mySemaphore;
|
||||
private final static Logger LOG = Logger.getInstance("#com.intellij.util.continuation.SameProgressRunner");
|
||||
|
||||
public SameProgressRunner(Project project, boolean cancellable, final String commonName) {
|
||||
super(project, cancellable);
|
||||
|
||||
final Application application = ApplicationManager.getApplication();
|
||||
if (! application.isUnitTestMode()) {
|
||||
assert ! application.isDispatchThread();
|
||||
}
|
||||
myIndicator = ProgressManager.getInstance().getProgressIndicator();
|
||||
if (myIndicator == null) {
|
||||
myIndicator = new EmptyProgressIndicator();
|
||||
}
|
||||
myInitThread = Thread.currentThread();
|
||||
mySemaphore = new Semaphore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ping() {
|
||||
myTriggerSuspend = false;
|
||||
if (Thread.currentThread().equals(myInitThread)) {
|
||||
pingInSourceThread();
|
||||
} else {
|
||||
mySemaphore.up();
|
||||
}
|
||||
}
|
||||
|
||||
private void pingInSourceThread() {
|
||||
while (true) {
|
||||
try {
|
||||
// stop if project is being disposed
|
||||
if (! myProject.isOpen()) return;
|
||||
|
||||
final TaskDescriptor current = getNextMatching();
|
||||
if (current == null) {
|
||||
synchronized (myQueueLock) {
|
||||
if (myTriggerSuspend) {
|
||||
mySemaphore.down();
|
||||
while (myTriggerSuspend) {
|
||||
mySemaphore.waitFor(500);
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Where.AWT.equals(current.getWhere())) {
|
||||
WaitForProgressToShow.runOrInvokeAndWaitAboveProgress(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
current.run(SameProgressRunner.this);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
current.run(this);
|
||||
}
|
||||
} catch (ProcessCanceledException ignored) {
|
||||
} catch (Throwable t) {
|
||||
LOG.error(t);
|
||||
myIndicator.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.util.continuation;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.progress.EmptyProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator;
|
||||
import com.intellij.openapi.progress.impl.ProgressManagerImpl;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.CalledInAwt;
|
||||
import com.intellij.openapi.vcs.changes.BackgroundFromStartOption;
|
||||
import com.intellij.util.WaitForProgressToShow;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
* Date: 4/7/11
|
||||
* Time: 2:46 PM
|
||||
*/
|
||||
public class SeparatePiecesRunner extends GeneralRunner {
|
||||
public SeparatePiecesRunner(Project project, boolean cancellable) {
|
||||
super(project, cancellable);
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
public void ping() {
|
||||
if (! ApplicationManager.getApplication().isDispatchThread()) {
|
||||
WaitForProgressToShow.runOrInvokeLaterAboveProgress(new Runnable() {
|
||||
public void run() {
|
||||
pingImpl();
|
||||
}
|
||||
}, null, myProject);
|
||||
} else {
|
||||
pingImpl();
|
||||
}
|
||||
}
|
||||
|
||||
private void pingImpl() {
|
||||
while (true) {
|
||||
// stop if project is being disposed
|
||||
if (! myProject.isOpen()) return;
|
||||
final TaskDescriptor current = getNextMatching();
|
||||
if (current == null) {
|
||||
synchronized (myQueueLock) {
|
||||
myTriggerSuspend = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (Where.AWT.equals(current.getWhere())) {
|
||||
myIndicator = null;
|
||||
current.run(this);
|
||||
} else {
|
||||
final TaskWrapper task = new TaskWrapper(myProject, current.getName(), myCancellable, current, this);
|
||||
myIndicator = ApplicationManager.getApplication().isUnitTestMode() ? new EmptyProgressIndicator() :
|
||||
new BackgroundableProcessIndicator(task);
|
||||
ProgressManagerImpl.runProcessWithProgressAsynchronously(task, myIndicator);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class TaskWrapper extends Task.Backgroundable {
|
||||
private final TaskDescriptor myTaskDescriptor;
|
||||
private final GeneralRunner myGeneralRunner;
|
||||
|
||||
TaskWrapper(@Nullable Project project,
|
||||
@NotNull String title,
|
||||
boolean canBeCancelled,
|
||||
TaskDescriptor taskDescriptor,
|
||||
GeneralRunner generalRunner) {
|
||||
super(project, title, canBeCancelled, BackgroundFromStartOption.getInstance());
|
||||
myTaskDescriptor = taskDescriptor;
|
||||
myGeneralRunner = generalRunner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
myTaskDescriptor.run(myGeneralRunner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
myGeneralRunner.ping();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
myGeneralRunner.onCancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@ import com.intellij.notification.NotificationType;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.progress.EmptyProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
@@ -37,7 +36,6 @@ import com.intellij.ui.CheckboxTree;
|
||||
import com.intellij.ui.CheckedTreeNode;
|
||||
import com.intellij.ui.ColoredTreeCellRenderer;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.continuation.ContinuationContext;
|
||||
import com.intellij.util.text.DateFormatUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
@@ -72,7 +70,8 @@ import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static git4idea.ui.GitUIUtil.*;
|
||||
import static git4idea.ui.GitUIUtil.notifyError;
|
||||
import static git4idea.ui.GitUIUtil.notifyMessage;
|
||||
|
||||
/**
|
||||
* The dialog that allows pushing active branches.
|
||||
@@ -304,8 +303,8 @@ public class GitPushActiveBranchesDialog extends DialogWrapper {
|
||||
final ArrayList<VcsException> errors = new ArrayList<VcsException>();
|
||||
for (Root r : rootsToPush) {
|
||||
GitLineHandler h = new GitLineHandler(myProject, r.root, GitCommand.PUSH);
|
||||
String src = r.commitToPush != null ? r.commitToPush : r.branch;
|
||||
h.addParameters("-v", r.remote, src + ":" + r.remoteBranch);
|
||||
String src = r.commitToPush != null ? r.commitToPush : r.currentBranch;
|
||||
h.addParameters("-v", r.remoteName, src + ":" + r.remoteBranch);
|
||||
GitPushUtils.trackPushRejectedAsError(h, "Rejected push (" + r.root.getPresentableUrl() + "): ");
|
||||
errors.addAll(GitHandlerUtil.doSynchronouslyWithExceptions(h));
|
||||
}
|
||||
@@ -321,7 +320,7 @@ public class GitPushActiveBranchesDialog extends DialogWrapper {
|
||||
for (int i = 0; i < myTreeRoot.getChildCount(); i++) {
|
||||
CheckedTreeNode node = (CheckedTreeNode) myTreeRoot.getChildAt(i);
|
||||
Root r = (Root)node.getUserObject();
|
||||
if (r.remote == null || r.commits.size() == 0) {
|
||||
if (r.remoteName == null || r.commits.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
boolean topCommit = true;
|
||||
@@ -646,7 +645,7 @@ public class GitPushActiveBranchesDialog extends DialogWrapper {
|
||||
for (Commit c : r.commits) {
|
||||
CheckedTreeNode child = new CheckedTreeNode(c);
|
||||
rootNode.add(child);
|
||||
child.setChecked(r.remote != null && !unchecked.contains(c.commitId()));
|
||||
child.setChecked(r.remoteName != null && !unchecked.contains(c.commitId()));
|
||||
}
|
||||
myTreeRoot.add(rootNode);
|
||||
}
|
||||
@@ -704,7 +703,7 @@ public class GitPushActiveBranchesDialog extends DialogWrapper {
|
||||
error = GitBundle.getString("push.active.error.reorder.needed");
|
||||
}
|
||||
}
|
||||
if (r.branch == null) {
|
||||
if (r.currentBranch == null) {
|
||||
if (error == null) {
|
||||
error = GitBundle.getString("push.active.error.no.branch");
|
||||
}
|
||||
@@ -770,20 +769,20 @@ public class GitPushActiveBranchesDialog extends DialogWrapper {
|
||||
r.root = root;
|
||||
GitBranch b = GitBranch.current(project, root);
|
||||
if (b != null) {
|
||||
r.branch = b.getFullName();
|
||||
r.remote = b.getTrackedRemoteName(project, root);
|
||||
r.currentBranch = b.getFullName();
|
||||
r.remoteName = b.getTrackedRemoteName(project, root);
|
||||
r.remoteBranch = b.getTrackedBranchName(project, root);
|
||||
if (r.remote != null) {
|
||||
if (fetchData && !r.remote.equals(".")) {
|
||||
if (r.remoteName != null) {
|
||||
if (fetchData && !r.remoteName.equals(".")) {
|
||||
GitLineHandler fetch = new GitLineHandler(project, root, GitCommand.FETCH);
|
||||
fetch.addParameters(r.remote, "-v");
|
||||
fetch.addParameters(r.remoteName, "-v");
|
||||
Collection<VcsException> exs = GitHandlerUtil.doSynchronouslyWithExceptions(fetch);
|
||||
exceptions.addAll(exs);
|
||||
}
|
||||
GitBranch tracked = b.tracked(project, root);
|
||||
assert tracked != null : "Tracked branch cannot be null here";
|
||||
GitSimpleHandler unmerged = new GitSimpleHandler(project, root, GitCommand.LOG);
|
||||
unmerged.addParameters("--pretty=format:%H", r.branch + ".." + tracked.getFullName());
|
||||
unmerged.addParameters("--pretty=format:%H", r.currentBranch + ".." + tracked.getFullName());
|
||||
unmerged.setNoSSH(true);
|
||||
unmerged.setStdoutSuppressed(true);
|
||||
StringScanner su = new StringScanner(unmerged.run());
|
||||
@@ -793,7 +792,7 @@ public class GitPushActiveBranchesDialog extends DialogWrapper {
|
||||
}
|
||||
}
|
||||
GitSimpleHandler toPush = new GitSimpleHandler(project, root, GitCommand.LOG);
|
||||
toPush.addParameters("--pretty=format:%H%x20%ct%x20%at%x20%s%n%P", tracked.getFullName() + ".." + r.branch);
|
||||
toPush.addParameters("--pretty=format:%H%x20%ct%x20%at%x20%s%n%P", tracked.getFullName() + ".." + r.currentBranch);
|
||||
toPush.setNoSSH(true);
|
||||
toPush.setStdoutSuppressed(true);
|
||||
StringScanner sp = new StringScanner(toPush.run());
|
||||
@@ -907,77 +906,59 @@ public class GitPushActiveBranchesDialog extends DialogWrapper {
|
||||
static abstract class Node {
|
||||
/**
|
||||
* Render the node text
|
||||
*
|
||||
* @param renderer the renderer to use
|
||||
*/
|
||||
protected abstract void render(ColoredTreeCellRenderer renderer);
|
||||
}
|
||||
|
||||
/**
|
||||
* The commit descriptor
|
||||
*/
|
||||
static class Status extends Node {
|
||||
/**
|
||||
* The root
|
||||
*/
|
||||
Root root;
|
||||
private String myMessage = "";
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected void render(ColoredTreeCellRenderer renderer) {
|
||||
renderer.append(GitBundle.getString("push.active.status.status"));
|
||||
if (root.branch == null) {
|
||||
renderer.append(GitBundle.message("push.active.status.no.branch"), SimpleTextAttributes.ERROR_ATTRIBUTES);
|
||||
if (root.currentBranch == null) {
|
||||
myMessage = GitBundle.message("push.active.status.no.branch");
|
||||
renderer.append(myMessage, SimpleTextAttributes.ERROR_ATTRIBUTES);
|
||||
}
|
||||
else if (root.remote == null) {
|
||||
renderer.append(GitBundle.message("push.active.status.no.tracked"), SimpleTextAttributes.GRAYED_BOLD_ATTRIBUTES);
|
||||
else if (root.remoteName == null) {
|
||||
myMessage = GitBundle.message("push.active.status.no.tracked");
|
||||
renderer.append(myMessage, SimpleTextAttributes.GRAYED_BOLD_ATTRIBUTES);
|
||||
}
|
||||
else if (root.remoteCommits != 0 && root.commits.size() == 0) {
|
||||
renderer.append(GitBundle.message("push.active.status.no.commits.behind", root.remoteCommits),
|
||||
SimpleTextAttributes.GRAYED_BOLD_ATTRIBUTES);
|
||||
myMessage = GitBundle.message("push.active.status.no.commits.behind", root.remoteCommits);
|
||||
renderer.append(myMessage, SimpleTextAttributes.GRAYED_BOLD_ATTRIBUTES);
|
||||
}
|
||||
else if (root.commits.size() == 0) {
|
||||
renderer.append(GitBundle.message("push.active.status.no.commits"), SimpleTextAttributes.GRAYED_BOLD_ATTRIBUTES);
|
||||
myMessage = GitBundle.message("push.active.status.no.commits");
|
||||
renderer.append(myMessage, SimpleTextAttributes.GRAYED_BOLD_ATTRIBUTES);
|
||||
}
|
||||
else if (root.remoteCommits != 0) {
|
||||
renderer.append(GitBundle.message("push.active.status.behind", root.remoteCommits), SimpleTextAttributes.ERROR_ATTRIBUTES);
|
||||
myMessage = GitBundle.message("push.active.status.behind", root.remoteCommits);
|
||||
renderer.append(myMessage, SimpleTextAttributes.ERROR_ATTRIBUTES);
|
||||
}
|
||||
else {
|
||||
renderer.append(GitBundle.message("push.active.status.push", root.commits.size()));
|
||||
myMessage = GitBundle.message("push.active.status.push", root.commits.size());
|
||||
renderer.append(myMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return GitBundle.getString("push.active.status.status") + myMessage;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The commit descriptor
|
||||
*/
|
||||
static class Commit extends Node {
|
||||
/**
|
||||
* The root
|
||||
*/
|
||||
Root root;
|
||||
/**
|
||||
* The revision
|
||||
*/
|
||||
GitRevisionNumber revision;
|
||||
/**
|
||||
* The message
|
||||
*/
|
||||
String message;
|
||||
/**
|
||||
* The author time
|
||||
*/
|
||||
String authorTime;
|
||||
/**
|
||||
* If true, the commit is a merge
|
||||
*/
|
||||
boolean isMerge;
|
||||
boolean isMerge; // true if this commit is a merge commit
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected void render(ColoredTreeCellRenderer renderer) {
|
||||
renderer.append(revision.asString().substring(0, HASH_PREFIX_SIZE), SimpleTextAttributes.GRAYED_ATTRIBUTES);
|
||||
@@ -994,53 +975,35 @@ public class GitPushActiveBranchesDialog extends DialogWrapper {
|
||||
String commitId() {
|
||||
return authorTime + ":" + message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String mergeCommitStr = isMerge ? " " + GitBundle.getString("push.active.commit.node.merge") : "";
|
||||
return revision.toShortString() + " " + message + mergeCommitStr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The root node
|
||||
*/
|
||||
static class Root extends Node {
|
||||
/**
|
||||
* if true, the update is required
|
||||
*/
|
||||
int remoteCommits;
|
||||
/**
|
||||
* the path to vcs root
|
||||
*/
|
||||
VirtualFile root;
|
||||
/**
|
||||
* the current branch
|
||||
*/
|
||||
String branch;
|
||||
/**
|
||||
* the remote name
|
||||
*/
|
||||
String remote;
|
||||
/**
|
||||
* the remote branch name
|
||||
*/
|
||||
String currentBranch;
|
||||
String remoteName;
|
||||
String remoteBranch;
|
||||
/**
|
||||
* The commit that will be actually pushed
|
||||
*/
|
||||
String commitToPush;
|
||||
/**
|
||||
* the commit
|
||||
*/
|
||||
String commitToPush; // The commit that will be actually pushed
|
||||
List<Commit> commits = new ArrayList<Commit>();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected void render(ColoredTreeCellRenderer renderer) {
|
||||
SimpleTextAttributes rootAttributes;
|
||||
SimpleTextAttributes branchAttributes;
|
||||
if (remote != null && commits.size() != 0 && remoteCommits != 0 || branch == null) {
|
||||
if (remoteName != null && commits.size() != 0 && remoteCommits != 0 || currentBranch == null) {
|
||||
rootAttributes = SimpleTextAttributes.ERROR_ATTRIBUTES.derive(SimpleTextAttributes.STYLE_BOLD, null, null, null);
|
||||
branchAttributes = SimpleTextAttributes.ERROR_ATTRIBUTES;
|
||||
}
|
||||
else if (remote == null || commits.size() == 0) {
|
||||
else if (remoteName == null || commits.size() == 0) {
|
||||
rootAttributes = SimpleTextAttributes.GRAYED_BOLD_ATTRIBUTES;
|
||||
branchAttributes = SimpleTextAttributes.GRAYED_ATTRIBUTES;
|
||||
}
|
||||
@@ -1049,13 +1012,27 @@ public class GitPushActiveBranchesDialog extends DialogWrapper {
|
||||
rootAttributes = SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES;
|
||||
}
|
||||
renderer.append(root.getPresentableUrl(), rootAttributes);
|
||||
if (branch != null) {
|
||||
renderer.append(" [" + branch, branchAttributes);
|
||||
if (remote != null) {
|
||||
renderer.append(" -> " + remote + "#" + remoteBranch, branchAttributes);
|
||||
if (currentBranch != null) {
|
||||
renderer.append(" [" + currentBranch, branchAttributes);
|
||||
if (remoteName != null) {
|
||||
renderer.append(" -> " + remoteName + "#" + remoteBranch, branchAttributes);
|
||||
}
|
||||
renderer.append("]", branchAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder string = new StringBuilder();
|
||||
string.append(root.getPresentableUrl());
|
||||
if (currentBranch != null) {
|
||||
string.append(" [").append(currentBranch);
|
||||
if (remoteName != null) {
|
||||
string.append(" -> ").append(remoteName).append("#").append(remoteBranch);
|
||||
}
|
||||
string.append("]");
|
||||
}
|
||||
return string.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.wm.ToolWindowManager;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.continuation.Continuation;
|
||||
import com.intellij.util.continuation.ContinuationContext;
|
||||
import com.intellij.util.continuation.GatheringContinuationContext;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import git4idea.GitRevisionNumber;
|
||||
import git4idea.GitUtil;
|
||||
@@ -578,7 +578,7 @@ public class GitCheckoutProcess {
|
||||
progress.setText("Refreshing files before restoring shelve: " + shelve.DESCRIPTION);
|
||||
final ShelvedChangeList finalShelve = shelve;
|
||||
|
||||
final Continuation continuation = new Continuation(myProject, true);
|
||||
final Continuation continuation = Continuation.createForCurrentProgress(myProject, true, "Git: restore changes");
|
||||
final Consumer<VcsException> exceptionConsumer = new Consumer<VcsException>() {
|
||||
@Override
|
||||
public void consume(VcsException e) {
|
||||
@@ -590,8 +590,7 @@ public class GitCheckoutProcess {
|
||||
}
|
||||
};
|
||||
continuation.addExceptionHandler(VcsException.class, exceptionConsumer);
|
||||
final ContinuationContext.GatheringContinuationContext initContext =
|
||||
new ContinuationContext.GatheringContinuationContext();
|
||||
final GatheringContinuationContext initContext = new GatheringContinuationContext();
|
||||
GitStashUtils.doSystemUnshelve(myProject, shelve, myShelveManager, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
@@ -15,10 +15,7 @@ package git4idea.history.wholeTree;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.CalledInAwt;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import com.intellij.util.continuation.Continuation;
|
||||
import com.intellij.util.continuation.ContinuationContext;
|
||||
import com.intellij.util.continuation.TaskDescriptor;
|
||||
import com.intellij.util.continuation.Where;
|
||||
import com.intellij.util.continuation.*;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
@@ -45,8 +42,7 @@ public class LoadAlgorithm {
|
||||
}
|
||||
|
||||
public void fillContinuation() {
|
||||
final ContinuationContext.GatheringContinuationContext initContext =
|
||||
new ContinuationContext.GatheringContinuationContext();
|
||||
final GatheringContinuationContext initContext = new GatheringContinuationContext();
|
||||
|
||||
for (LoaderAndRefresher<CommitHashPlusParents> loader : myLoaders) {
|
||||
final LoaderFactory factory = new LoaderFactory(loader);
|
||||
|
||||
@@ -86,7 +86,7 @@ public class LoadController implements Loader {
|
||||
continuation = myPreviousAlgorithm.getContinuation();
|
||||
continuation.clearQueue();
|
||||
} else {
|
||||
continuation = new Continuation(myProject, true);
|
||||
continuation = Continuation.createFragmented(myProject, true);
|
||||
}
|
||||
myPreviousAlgorithm = new LoadAlgorithm(myProject, list, shortLoaders, continuation);
|
||||
myPreviousAlgorithm.fillContinuation();
|
||||
|
||||
@@ -18,12 +18,10 @@ package git4idea.update;
|
||||
import com.intellij.ide.GeneralSettings;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ex.ProjectManagerEx;
|
||||
import com.intellij.util.continuation.Continuation;
|
||||
import com.intellij.util.continuation.ContinuationContext;
|
||||
import com.intellij.util.continuation.TaskDescriptor;
|
||||
import com.intellij.util.continuation.Where;
|
||||
import com.intellij.util.continuation.*;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
|
||||
/**
|
||||
@@ -32,6 +30,7 @@ import com.intellij.util.ui.UIUtil;
|
||||
* Time: 2:59 PM
|
||||
*/
|
||||
public abstract class GitUpdateLikeProcess {
|
||||
public static final String GIT_UPDATING = "Git: updating";
|
||||
private final Project myProject;
|
||||
private GeneralSettings myGeneralSettings;
|
||||
private ProjectManagerEx myProjectManager;
|
||||
@@ -60,22 +59,25 @@ public abstract class GitUpdateLikeProcess {
|
||||
}
|
||||
});
|
||||
|
||||
final Continuation continuation = new Continuation(myProject, true);
|
||||
final ContinuationContext.GatheringContinuationContext initContext = new ContinuationContext.GatheringContinuationContext();
|
||||
initContext.next(new TaskDescriptor("Git: updating", Where.POOLED) {
|
||||
@Override
|
||||
public void run(final ContinuationContext context) {
|
||||
runImpl(context);
|
||||
}
|
||||
}, new TaskDescriptor("", Where.AWT) {
|
||||
final Continuation continuation = Continuation.createForCurrentProgress(myProject, true, GIT_UPDATING);
|
||||
final GatheringContinuationContext initContext = new GatheringContinuationContext();
|
||||
final TaskDescriptor returnFlagsBack = new TaskDescriptor("", Where.AWT) {
|
||||
@Override
|
||||
public void run(ContinuationContext context) {
|
||||
myProjectManager.unblockReloadingProjectOnExternalChanges();
|
||||
myGeneralSettings.setSaveOnFrameDeactivation(saveOnFrameDeactivation);
|
||||
myGeneralSettings.setSyncOnFrameActivation(syncOnFrameDeactivation);
|
||||
}
|
||||
});
|
||||
continuation.runAndWait(initContext.getList());
|
||||
};
|
||||
final TaskDescriptor[] next = {new TaskDescriptor(GIT_UPDATING, Where.POOLED) {
|
||||
@Override
|
||||
public void run(final ContinuationContext context) {
|
||||
runImpl(context);
|
||||
}
|
||||
}, returnFlagsBack};
|
||||
returnFlagsBack.setHaveMagicCure(true);
|
||||
initContext.next(next);
|
||||
continuation.run(initContext.getList());
|
||||
}
|
||||
|
||||
protected abstract void runImpl(ContinuationContext context);
|
||||
|
||||
@@ -27,6 +27,8 @@ import com.intellij.openapi.vcs.update.UpdatedFiles;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.continuation.ContinuationContext;
|
||||
import com.intellij.util.continuation.ContinuationFinalTasksInserter;
|
||||
import com.intellij.util.continuation.TaskDescriptor;
|
||||
import com.intellij.util.text.DateFormatUtil;
|
||||
import git4idea.GitBranch;
|
||||
import git4idea.branch.GitBranchPair;
|
||||
@@ -189,7 +191,11 @@ public class GitUpdateProcess {
|
||||
"Restoring changes saved before update failed with an error.<br/>" + e.getLocalizedMessage());
|
||||
}
|
||||
});
|
||||
// try restore changes under all circumstances
|
||||
final ContinuationFinalTasksInserter finalTasksInserter = new ContinuationFinalTasksInserter(context);
|
||||
finalTasksInserter.allNextAreFinal();
|
||||
mySaver.restoreLocalChanges(context);
|
||||
finalTasksInserter.removeFinalPropertyAdder();
|
||||
}
|
||||
|
||||
// fetch all roots. If an error happens, return false and notify about errors.
|
||||
|
||||
@@ -116,5 +116,6 @@ hg4idea.merge.please-commit=Merged heads, please commit repository \"{0}\"
|
||||
hg4idea.error.invalidExecutable=\"{0}\" is not a valid mercurial executable
|
||||
hg4idea.integrate.other.head=Other head: {0}
|
||||
|
||||
hgidea.dialog.login.password.required=Login and password required
|
||||
hg4idea.dialog.login.password.required=Login and password required
|
||||
hg4idea.dialog.login.description=Login to {0}
|
||||
hg4idea.exception.file.not.under.hg=The file {0} is not under Mercurial.
|
||||
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
@@ -0,0 +1,8 @@
|
||||
This Mercurial extension is meant to provide robust integration with
|
||||
external tools.
|
||||
|
||||
Mercurial sometimes asks vital questions during several operations, for
|
||||
instance during merging. Automatically choosing the default answer
|
||||
for these questions is typically not what you want when working from,
|
||||
for instance, an IDE. This extension forwards the prompts to another
|
||||
process (i.e. the IDE) so that it can be answered by the user.
|
||||
@@ -1,24 +1,50 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from mercurial import filemerge, ui, util, dispatch
|
||||
from mercurial.node import short
|
||||
import sys, struct, socket
|
||||
#Mercurial extension to robustly integrate prompts with other processes
|
||||
#Copyright (C) 2010-2011 Willem Verstraeten
|
||||
#
|
||||
#This program is free software; you can redistribute it and/or
|
||||
#modify it under the terms of the GNU General Public License
|
||||
#as published by the Free Software Foundation; either version 2
|
||||
#of the License, or (at your option) any later version.
|
||||
#
|
||||
#This program is distributed in the hope that it will be useful,
|
||||
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
#GNU General Public License for more details.
|
||||
#
|
||||
#You should have received a copy of the GNU General Public License
|
||||
#along with this program; if not, write to the Free Software
|
||||
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
import urllib2
|
||||
from mercurial import ui, util
|
||||
import struct, socket
|
||||
from mercurial.i18n import _
|
||||
|
||||
try:
|
||||
from mercurial.url import passwordmgr
|
||||
except:
|
||||
from mercurial.httprepo import passwordmgr
|
||||
|
||||
def sendInt( client, number):
|
||||
length = struct.pack('>L', number)
|
||||
client.sendall( length )
|
||||
|
||||
def send( client, data ):
|
||||
sendInt(client, len(data))
|
||||
client.sendall( data )
|
||||
if data is None:
|
||||
sendInt(client, 0)
|
||||
else:
|
||||
sendInt(client, len(data))
|
||||
client.sendall( data )
|
||||
|
||||
def receiveInt(client):
|
||||
def receiveIntWithMessage(client, message):
|
||||
requiredLength = struct.calcsize('>L')
|
||||
buffer = ''
|
||||
while len(buffer)<requiredLength:
|
||||
chunk = client.recv(requiredLength-len(buffer))
|
||||
if chunk == '':
|
||||
raise RuntimeError, "socket connection broken"
|
||||
raise util.Abort( message )
|
||||
buffer = buffer + chunk
|
||||
|
||||
# struct.unpack always returns a tuple, even if that tuple only contains a single
|
||||
@@ -27,13 +53,20 @@ def receiveInt(client):
|
||||
|
||||
return intToReturn
|
||||
|
||||
|
||||
def receiveInt(client):
|
||||
return receiveIntWithMessage(client, "could not get information from server")
|
||||
|
||||
def receive( client ):
|
||||
length = receiveInt(client)
|
||||
receiveWithMessage(client, "could not get information from server")
|
||||
|
||||
def receiveWithMessage( client, message ):
|
||||
length = receiveIntWithMessage(client, message)
|
||||
buffer = ''
|
||||
while len(buffer) < length :
|
||||
chunk = client.recv(length - len(buffer))
|
||||
if chunk == '':
|
||||
raise RuntimeError, "socket connection broken"
|
||||
raise util.Abort( message)
|
||||
buffer = buffer+chunk
|
||||
|
||||
return buffer
|
||||
@@ -45,14 +78,14 @@ def monkeypatch_method(cls):
|
||||
return func
|
||||
return decorator
|
||||
|
||||
def sendchangestoidea(ui, msg, choices, default):
|
||||
def sendchoicestoidea(ui, msg, choices, default):
|
||||
port = int(ui.config( 'hg4ideaprompt', 'port', None, True))
|
||||
|
||||
if not port:
|
||||
raise util.Abort("No port was specified")
|
||||
|
||||
numOfChoices = len(choices)
|
||||
if numOfChoices == 0:
|
||||
if not numOfChoices:
|
||||
return default
|
||||
|
||||
client = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
|
||||
@@ -67,7 +100,6 @@ def sendchangestoidea(ui, msg, choices, default):
|
||||
sendInt( client, default )
|
||||
|
||||
answer = receiveInt( client )
|
||||
print "Received answer: %s" % answer
|
||||
if answer == -1:
|
||||
raise util.Abort("User cancelled")
|
||||
else:
|
||||
@@ -80,13 +112,13 @@ def sendchangestoidea(ui, msg, choices, default):
|
||||
if getattr(ui.ui, 'promptchoice', None):
|
||||
@monkeypatch_method(ui.ui)
|
||||
def promptchoice(self, msg, choices=None, default=0):
|
||||
return sendchangestoidea(self, msg, choices, default)
|
||||
return sendchoicestoidea(self, msg, choices, default)
|
||||
else:
|
||||
@monkeypatch_method(ui.ui)
|
||||
def prompt(self, msg, choices=None, default="y"):
|
||||
resps = [s[s.index('&')+1].lower() for s in choices]
|
||||
defaultIndex = resps.index( default )
|
||||
responseIndex = sendchangestoidea( self, msg, choices, defaultIndex)
|
||||
responseIndex = sendchoicestoidea( self, msg, choices, defaultIndex)
|
||||
return resps[responseIndex]
|
||||
|
||||
original_warn = ui.ui.warn
|
||||
@@ -110,3 +142,59 @@ def warn(self, *msg):
|
||||
sendInt( client, len(msg) )
|
||||
for message in msg:
|
||||
send( client, message )
|
||||
|
||||
|
||||
def retrieve_pass_from_server(ui, uri,path, proposed_user):
|
||||
port = int(ui.config('hg4ideapass', 'port', None, True))
|
||||
if port is None:
|
||||
raise util.Abort("No port was specified")
|
||||
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
ui.debug("connecting ...")
|
||||
client.connect(('127.0.0.1', port))
|
||||
ui.debug("connected, sending data ...")
|
||||
|
||||
send(client, "getpass")
|
||||
send(client, uri)
|
||||
send(client, path)
|
||||
send(client, proposed_user)
|
||||
user = receiveWithMessage(client, "http authorization required")
|
||||
password = receiveWithMessage(client, "http authorization required")
|
||||
return user, password
|
||||
|
||||
|
||||
original_retrievepass=passwordmgr.find_user_password
|
||||
@monkeypatch_method(passwordmgr)
|
||||
def find_user_password(self, realm, authuri):
|
||||
try:
|
||||
return original_retrievepass(self, realm, authuri)
|
||||
except util.Abort:
|
||||
|
||||
# In mercurial 1.8 the readauthtoken method was replaced with
|
||||
# the readauthforuri method, which has different semantics
|
||||
if getattr(self, 'readauthtoken', None):
|
||||
def read_hgrc_authtoken(ui, authuri):
|
||||
return self.readauthtoken(authuri)
|
||||
else:
|
||||
def read_hgrc_authtoken(ui, authuri):
|
||||
# hg 1.8
|
||||
from mercurial.url import readauthforuri
|
||||
res = readauthforuri(self.ui, authuri)
|
||||
if res:
|
||||
group, auth = res
|
||||
return auth
|
||||
else:
|
||||
return None
|
||||
|
||||
user, password = urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password(self, realm, authuri)
|
||||
if user is None:
|
||||
auth = read_hgrc_authtoken(self.ui, authuri)
|
||||
if auth:
|
||||
user = auth.get("username")
|
||||
|
||||
reduced_uri, path= self.reduce_uri(authuri, False)
|
||||
retrievedPass = retrieve_pass_from_server(self.ui, reduced_uri, path, user)
|
||||
if retrievedPass is None:
|
||||
raise util.Abort(_('http authorization required'))
|
||||
user, passwd = retrievedPass
|
||||
self.add_password(realm, authuri, user, passwd)
|
||||
return retrievedPass
|
||||
@@ -17,8 +17,6 @@
|
||||
serviceImplementation="org.zmlx.hg4idea.HgGlobalSettings"/>
|
||||
<projectService serviceInterface="org.zmlx.hg4idea.HgProjectSettings"
|
||||
serviceImplementation="org.zmlx.hg4idea.HgProjectSettings"/>
|
||||
<projectService serviceInterface="org.zmlx.hg4idea.command.HgCommandService"
|
||||
serviceImplementation="org.zmlx.hg4idea.command.HgCommandService"/>
|
||||
<projectService serviceInterface="org.zmlx.hg4idea.HgRootsHandler"
|
||||
serviceImplementation="org.zmlx.hg4idea.HgRootsHandler" />
|
||||
</extensions>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user