Merge remote-tracking branch 'origin/master'

This commit is contained in:
Roman Shevchenko
2017-03-07 12:56:58 +01:00
272 changed files with 4727 additions and 5590 deletions
-1
View File
@@ -56,7 +56,6 @@
<module fileurl="file://$PROJECT_DIR$/platform/core-api/core-api.iml" filepath="$PROJECT_DIR$/platform/core-api/core-api.iml" group="platform" />
<module fileurl="file://$PROJECT_DIR$/platform/core-impl/core-impl.iml" filepath="$PROJECT_DIR$/platform/core-impl/core-impl.iml" group="platform" />
<module fileurl="file://$PROJECT_DIR$/python/educational-core/course-creator/course-creator.iml" filepath="$PROJECT_DIR$/python/educational-core/course-creator/course-creator.iml" group="python/educational/educational-core" />
<module fileurl="file://$PROJECT_DIR$/python/educational-python/course-creator-python/course-creator-python.iml" filepath="$PROJECT_DIR$/python/educational-python/course-creator-python/course-creator-python.iml" group="python/educational/educational-python" />
<module fileurl="file://$PROJECT_DIR$/plugins/coverage/coverage.iml" filepath="$PROJECT_DIR$/plugins/coverage/coverage.iml" group="plugins/coverage" />
<module fileurl="file://$PROJECT_DIR$/plugins/coverage-common/coverage-common.iml" filepath="$PROJECT_DIR$/plugins/coverage-common/coverage-common.iml" group="plugins/coverage" />
<module fileurl="file://$PROJECT_DIR$/plugins/coverage/coverage_rt/coverage_rt.iml" filepath="$PROJECT_DIR$/plugins/coverage/coverage_rt/coverage_rt.iml" group="plugins/coverage" />
+7 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -29,6 +29,12 @@ target(compile: "Compile project") {
loadProject()
prepareOutputFolder()
if (System.getProperty("tests.only")) {
ant.delete(dir: "$home/out")
ant.unzip(src: "$home/out.zip", dest: "$home/out")
return
}
if (!isDefined("avoid.project.rebuild")) {
clearBuildCaches()
projectBuilder.cleanOutput()
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -16,6 +16,7 @@
package com.intellij.debugger.engine.events;
import com.intellij.debugger.impl.DebuggerTaskImpl;
import org.jetbrains.annotations.Debugger;
/**
* @author lex
@@ -40,6 +41,7 @@ public abstract class DebuggerCommandImpl extends DebuggerTaskImpl {
}
}
@Debugger.Insert
public final void run() throws Exception{
try {
action();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -21,6 +21,7 @@ import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.sun.jdi.VMDisconnectedException;
import org.jetbrains.annotations.Debugger;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.*;
@@ -191,7 +192,7 @@ public abstract class InvokeThread<E extends PrioritizedTask> {
return request != null? request.getOwner() : null;
}
public boolean schedule(E r) {
public boolean schedule(@Debugger.Capture E r) {
if(LOG.isDebugEnabled()) {
LOG.debug("schedule " + r + " in " + this);
}
@@ -16,6 +16,9 @@
package com.intellij.debugger.settings;
import com.intellij.debugger.DebuggerBundle;
import com.intellij.debugger.engine.JVMNameUtil;
import com.intellij.debugger.jdi.DecompiledLocalVariable;
import com.intellij.debugger.ui.JavaDebuggerSupport;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.diagnostic.Logger;
@@ -27,10 +30,16 @@ import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileWrapper;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.AnnotatedElementsSearch;
import com.intellij.ui.*;
import com.intellij.ui.table.JBTable;
import com.intellij.util.PlatformIcons;
@@ -42,6 +51,7 @@ import one.util.streamex.IntStreamEx;
import one.util.streamex.StreamEx;
import org.jdom.Document;
import org.jdom.Element;
import org.jetbrains.annotations.Debugger;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -214,7 +224,92 @@ public class CaptureConfigurable implements SearchableConfigurable {
static final String[] COLUMN_NAMES =
new String[]{"", "Capture class name", "Capture method name", "Capture key expression", "Insert class name", "Insert method name", "Insert key expression"};
List<CapturePoint> myCapturePoints = DebuggerSettings.getInstance().cloneCapturePoints();
List<CapturePoint> myCapturePoints;
private MyTableModel() {
myCapturePoints = DebuggerSettings.getInstance().cloneCapturePoints();
scanPoints();
}
private void scanPoints() {
if (Registry.is("debugger.capture.points.annotations")) {
scanPointsInt(true);
scanPointsInt(false);
}
}
private void scanPointsInt(boolean capture) {
try {
String annotationName = (capture ? Debugger.Capture.class : Debugger.Insert.class).getName().replace("$", ".");
Project project = JavaDebuggerSupport.getContextProjectForEditorFieldsInDebuggerConfigurables();
GlobalSearchScope allScope = GlobalSearchScope.allScope(project);
PsiClass annotationClass = JavaPsiFacade.getInstance(project).findClass(annotationName, allScope);
if (annotationClass != null) {
AnnotatedElementsSearch.searchElements(annotationClass, allScope, PsiMethod.class, PsiParameter.class).forEach(e -> {
if (e instanceof PsiMethod) {
addCapturePointIfNeeded(e, (PsiMethod)e, annotationName, "this", capture);
}
else if (e instanceof PsiParameter) {
PsiParameter psiParameter = (PsiParameter)e;
PsiMethod psiMethod = (PsiMethod)psiParameter.getDeclarationScope();
addCapturePointIfNeeded(psiParameter, psiMethod, annotationName,
DecompiledLocalVariable.PARAM_PREFIX + psiMethod.getParameterList().getParameterIndex(psiParameter),
capture);
}
});
}
}
catch (Exception e) {
LOG.error(e);
}
}
private void addCapturePointIfNeeded(PsiModifierListOwner psiElement,
PsiMethod psiMethod,
String annotationName,
String defaultExpression,
boolean capture) {
CapturePoint capturePoint = new CapturePoint();
capturePoint.myEnabled = false;
if (capture) {
capturePoint.myClassName = JVMNameUtil.getNonAnonymousClassName(psiMethod.getContainingClass());
capturePoint.myMethodName = JVMNameUtil.getJVMMethodName(psiMethod);
}
else {
capturePoint.myInsertClassName = JVMNameUtil.getNonAnonymousClassName(psiMethod.getContainingClass());
capturePoint.myInsertMethodName = JVMNameUtil.getJVMMethodName(psiMethod);
}
PsiModifierList modifierList = psiElement.getModifierList();
if (modifierList != null) {
PsiAnnotation annotation = modifierList.findAnnotation(annotationName);
if (annotation != null) {
PsiAnnotationMemberValue attributeValue = annotation.findAttributeValue("keyExpression");
String keyExpression = attributeValue != null ? StringUtil.unquoteString(attributeValue.getText()) : null;
if (StringUtil.isEmpty(keyExpression)) {
keyExpression = defaultExpression;
}
if (capture) {
capturePoint.myCaptureKeyExpression = keyExpression;
}
else {
capturePoint.myInsertKeyExpression = keyExpression;
}
}
}
CapturePoint clone = capturePoint;
try {
clone = capturePoint.clone();
clone.myEnabled = !clone.myEnabled;
}
catch (CloneNotSupportedException e) {
LOG.error(e);
}
if (!myCapturePoints.contains(capturePoint) && !myCapturePoints.contains(clone)) {
myCapturePoints.add(capturePoint);
}
}
public String getColumnName(int column) {
return COLUMN_NAMES[column];
@@ -325,6 +420,7 @@ public class CaptureConfigurable implements SearchableConfigurable {
public void reset() {
myCaptureVariables.setSelected(DebuggerSettings.getInstance().CAPTURE_VARIABLES);
myTableModel.myCapturePoints = DebuggerSettings.getInstance().cloneCapturePoints();
myTableModel.scanPoints();
myTableModel.fireTableDataChanged();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -17,6 +17,10 @@ package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.AutoPopupController;
import com.intellij.codeInsight.completion.util.MethodParenthesesHandler;
import com.intellij.codeInsight.daemon.impl.ParameterHintsPresentationManager;
import com.intellij.codeInsight.hint.ParameterInfoController;
import com.intellij.codeInsight.hint.ShowParameterInfoContext;
import com.intellij.codeInsight.hint.api.impls.MethodParameterInfoHandler;
import com.intellij.codeInsight.lookup.*;
import com.intellij.codeInsight.lookup.impl.JavaElementLookupRenderer;
import com.intellij.codeInsight.template.*;
@@ -26,10 +30,13 @@ import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
import com.intellij.codeInsight.template.impl.TemplateState;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.CaretModel;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.Inlay;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ClassConditionKey;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Key;
@@ -44,6 +51,8 @@ import com.intellij.psi.util.TypeConversionUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -175,6 +184,7 @@ public class JavaMethodCallElement extends LookupItem<PsiMethod> implements Type
}
startArgumentLiveTemplate(context, method);
showParameterHints(context, method, methodCall);
}
static PsiCallExpression findCallAtOffset(InsertionContext context, int offset) {
@@ -270,6 +280,45 @@ public class JavaMethodCallElement extends LookupItem<PsiMethod> implements Type
return true;
}
public static void showParameterHints(InsertionContext context, PsiMethod method, PsiCallExpression methodCall) {
PsiParameterList parameterList = method.getParameterList();
int parametersCount = parameterList.getParametersCount();
if (methodCall == null ||
parametersCount == 0 ||
context.getCompletionChar() == Lookup.COMPLETE_STATEMENT_SELECT_CHAR ||
Registry.is("java.completion.argument.live.template") ||
!Registry.is("java.completion.argument.hints")) {
return;
}
Editor editor = context.getEditor();
CaretModel caretModel = editor.getCaretModel();
int offset = caretModel.getOffset();
caretModel.moveToOffset(offset - 1); // avoid caret impact on hints location
editor.getDocument().insertString(offset, StringUtil.repeat(", ", parametersCount - 1));
List<Inlay> addedHints = new ArrayList<>(parametersCount);
for (PsiParameter parameter : parameterList.getParameters()) {
String name = parameter.getName();
if (name != null) {
addedHints.add(ParameterHintsPresentationManager.getInstance().addHint(editor, offset, name + ":", false, true));
}
offset += 2;
}
int braceOffset = caretModel.getOffset();
caretModel.moveToLogicalPosition(editor.offsetToLogicalPosition(braceOffset + 1).leanForward(true));
Project project = context.getProject();
MethodParameterInfoHandler handler = new MethodParameterInfoHandler();
ShowParameterInfoContext infoContext = new ShowParameterInfoContext(editor, project, context.getFile(), braceOffset, braceOffset);
handler.findElementForParameterInfo(infoContext);
Disposer.register(new ParameterInfoController(project, editor, braceOffset, infoContext.getItemsToShow(), null, methodCall.getArgumentList(), handler, false, false), () -> {
for (Inlay inlay : addedHints) {
if (inlay != null) ParameterHintsPresentationManager.getInstance().unpin(inlay);
}
});
}
private static void setupNonFilledArgumentRemoving(final Editor editor, final TemplateState templateState) {
AtomicInteger maxEditedVariable = new AtomicInteger(-1);
editor.getDocument().addDocumentListener(new DocumentAdapter() {
@@ -0,0 +1,31 @@
/*
* Copyright 2000-2017 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.codeInsight.editorActions;
import com.intellij.openapi.actionSystem.ActionPromoter;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.util.containers.ContainerUtil;
import java.util.List;
public class JavaMethodOverloadSwitchActionPromoter implements ActionPromoter {
@Override
public List<AnAction> promote(List<AnAction> actions, DataContext context) {
return ContainerUtil.findAll(actions, a -> a instanceof JavaMethodOverloadSwitchUpAction ||
a instanceof JavaMethodOverloadSwitchDownAction);
}
}
@@ -0,0 +1,24 @@
/*
* Copyright 2000-2017 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.codeInsight.editorActions;
import com.intellij.openapi.editor.actionSystem.EditorAction;
public class JavaMethodOverloadSwitchDownAction extends EditorAction {
public JavaMethodOverloadSwitchDownAction() {
super(new JavaMethodOverloadSwitchHandler(false));
}
}
@@ -0,0 +1,149 @@
/*
* Copyright 2000-2017 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.codeInsight.editorActions;
import com.intellij.codeInsight.completion.CompletionMemory;
import com.intellij.codeInsight.daemon.impl.ParameterHintsPresentationManager;
import com.intellij.codeInsight.hint.ParameterInfoController;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Caret;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.Inlay;
import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.psi.*;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
public class JavaMethodOverloadSwitchHandler extends EditorWriteActionHandler {
private static final Key<Map<String, String>> ENTERED_PARAMETERS = Key.create("entered.parameters");
private final boolean mySwitchUp;
public JavaMethodOverloadSwitchHandler(boolean up) {
mySwitchUp = up;
}
@Override
protected boolean isEnabledForCaret(@NotNull Editor editor, @NotNull Caret caret, DataContext dataContext) {
if (!Registry.is("java.completion.argument.hints") || !ParameterInfoController.existsForEditor(editor)) return false;
Project project = CommonDataKeys.PROJECT.getData(dataContext);
if (project == null) return false;
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
PsiElement exprList = getExpressionList(editor, caret.getOffset(), project);
if (exprList == null) return false;
int lbraceOffset = exprList.getTextRange().getStartOffset();
return ParameterInfoController.findControllerAtOffset(editor, lbraceOffset) != null;
}
@Nullable
private static PsiElement getExpressionList(@NotNull Editor editor, int offset, @NotNull Project project) {
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
return file != null ? ParameterInfoController.findArgumentList(file, offset, -1) : null;
}
@Override
public void executeWriteAction(Editor editor, @Nullable Caret caret, DataContext dataContext) {
if (caret == null) caret = editor.getCaretModel().getPrimaryCaret();
Project project = CommonDataKeys.PROJECT.getData(dataContext);
if (project == null) return;
PsiDocumentManager.getInstance(project).commitAllDocuments();
PsiElement exprList = getExpressionList(editor, caret.getOffset(), project);
if (!(exprList instanceof PsiExpressionList)) return;
int lbraceOffset = exprList.getTextRange().getStartOffset();
ParameterInfoController controller = ParameterInfoController.findControllerAtOffset(editor, lbraceOffset);
if (controller == null) return;
Object[] objects = controller.getObjects();
Object highlighted = controller.getHighlighted();
if (objects == null || objects.length <= 1 || highlighted == null) return;
int currentIndex = ContainerUtil.indexOf(Arrays.asList(objects), highlighted);
if (currentIndex < 0) return;
PsiMethod currentMethod = (PsiMethod)((CandidateInfo)objects[currentIndex]).getElement();
Map<String, String> enteredParameters = exprList.getUserData(ENTERED_PARAMETERS);
if (enteredParameters == null) {
exprList.putUserData(ENTERED_PARAMETERS, enteredParameters = new HashMap<>());
}
PsiExpression[] enteredExpressions = ((PsiExpressionList)exprList).getExpressions();
assert enteredExpressions.length == 0 || enteredExpressions.length == currentMethod.getParameterList().getParametersCount();
for (int i = 0; i < enteredExpressions.length; i++) {
PsiExpression expression = enteredExpressions[i];
String value = expression.getText().trim();
if (!value.isEmpty()) {
String key = getParameterKey(currentMethod, i);
enteredParameters.put(key, value);
}
}
PsiMethod targetMethod = (PsiMethod)((CandidateInfo)objects[(currentIndex + (mySwitchUp ? -1 : 1) + objects.length) % objects.length]).getElement();
PsiParameterList parameterList = targetMethod.getParameterList();
int parametersCount = parameterList.getParametersCount();
caret.moveToOffset(lbraceOffset); // avoid caret impact on hints location
int offset = lbraceOffset + 1;
int endOffset = exprList.getTextRange().getEndOffset() - 1;
List<Inlay> oldInlays = editor.getInlayModel().getInlineElementsInRange(offset, endOffset);
for (Inlay inlay : oldInlays) {
Disposer.dispose(inlay);
}
editor.getDocument().deleteString(offset, endOffset);
int targetCaretPosition = -1;
List<Inlay> addedHints = new ArrayList<>(parametersCount);
for (int i = 0; i < parametersCount; i++) {
String key = getParameterKey(targetMethod, i);
String value = enteredParameters.getOrDefault(key, "");
if (value.isEmpty() && targetCaretPosition == -1) targetCaretPosition = offset;
if (i < parametersCount - 1) value += ", ";
editor.getDocument().insertString(offset, value);
String name = parameterList.getParameters()[i].getName();
if (name != null) {
addedHints.add(ParameterHintsPresentationManager.getInstance().addHint(editor, offset, name + ":", false, true));
}
offset += value.length();
}
if (targetCaretPosition == -1) targetCaretPosition = offset;
caret.moveToLogicalPosition(editor.offsetToLogicalPosition(targetCaretPosition).leanForward(true));
Disposer.register(controller, () -> {
for (Inlay hint : addedHints) {
if (hint != null) ParameterHintsPresentationManager.getInstance().unpin(hint);
}
});
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
CompletionMemory.registerChosenMethod(targetMethod, (PsiCall)exprList.getParent());
controller.updateComponent(); // update popup immediately (otherwise, it will be updated only after delay)
}
private static String getParameterKey(PsiMethod method, int parameterIndex) {
PsiParameter parameter = method.getParameterList().getParameters()[parameterIndex];
return parameter.getName() + ":" + parameter.getType().getCanonicalText();
}
}
@@ -0,0 +1,24 @@
/*
* Copyright 2000-2017 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.codeInsight.editorActions;
import com.intellij.openapi.editor.actionSystem.EditorAction;
public class JavaMethodOverloadSwitchUpAction extends EditorAction {
public JavaMethodOverloadSwitchUpAction() {
super(new JavaMethodOverloadSwitchHandler(true));
}
}
@@ -107,13 +107,6 @@ public class PsiMethodReferenceUtil {
return false;
}
PsiClass qContainingClass = getQualifierResolveResult(expression).getContainingClass();
if (qContainingClass != null && containingClass != null &&
isReceiverType(getFirstParameterType(functionalInterfaceType, expression), qContainingClass, subst)) {
subst = TypeConversionUtil.getClassSubstitutor(containingClass, qContainingClass, subst);
LOG.assertTrue(subst != null);
}
methodReturnType = subst.substitute(methodReturnType);
}
}
@@ -26,7 +26,7 @@ import org.jetbrains.annotations.NotNull;
public class JavaReadWriteAccessDetector extends ReadWriteAccessDetector {
@Override
public boolean isReadWriteAccessible(@NotNull final PsiElement element) {
return element instanceof PsiVariable && !(element instanceof ImplicitVariable) || element instanceof PsiClass;
return element instanceof PsiVariable && !(element instanceof ImplicitVariable) || element instanceof PsiClass || element instanceof PsiAnnotationMethod && !(element instanceof PsiCompiledElement);
}
@Override
@@ -49,7 +49,12 @@ public class JavaReadWriteAccessDetector extends ReadWriteAccessDetector {
@NotNull
@Override
public Access getExpressionAccess(@NotNull final PsiElement expression) {
if (!(expression instanceof PsiExpression)) return Access.Read;
if (!(expression instanceof PsiExpression)) {
if (expression instanceof PsiNameValuePair || expression instanceof PsiIdentifier) {
return Access.Write;
}
return Access.Read;
}
PsiExpression expr = (PsiExpression) expression;
boolean readAccess = PsiUtil.isAccessedForReading(expr);
boolean writeAccess = PsiUtil.isAccessedForWriting(expr);
@@ -1607,7 +1607,8 @@ public class InferenceSession {
if (receiverSubstitutor != null) {
if (!method.hasTypeParameters()) {
if (signature.getParameterTypes().length == 1 || PsiUtil.isRawSubstitutor(containingClass, receiverSubstitutor)) {
return receiverSubstitutor;
return methodContainingClass != null ? JavaClassSupers.getInstance().getSuperClassSubstitutor(methodContainingClass, containingClass, reference.getResolveScope(), receiverSubstitutor)
: receiverSubstitutor;
}
}
mySiteSubstitutor = mySiteSubstitutor.putAll(receiverSubstitutor);
@@ -185,6 +185,13 @@ public class StrictSubtypingConstraint implements ConstraintFormula {
return true;
}
if (myT instanceof PsiCapturedWildcardType) {
PsiType lowerBound = ((PsiCapturedWildcardType)myT).getLowerBound();
if (lowerBound != PsiType.NULL) {
constraints.add(new StrictSubtypingConstraint(lowerBound, myS));
}
}
return true;
}
@@ -0,0 +1,17 @@
import java.util.Collections;
import java.util.List;
interface Processor<P> {
void process(P t);
}
class Test {
void foo(Processor<? super List<String>> p) {
p.process(Collections.emptyList());
}
void bar(Processor<? extends List<String>> p) {
p.process<error descr="'process(capture<? extends java.util.List<java.lang.String>>)' in 'Processor' cannot be applied to '(java.util.List<java.lang.Object>)'">(Collections.emptyList())</error>;
}
}
@@ -0,0 +1,15 @@
import java.util.function.BiFunction;
import java.util.function.Function;
class Test {
interface MyBaseStream<T, S extends MyBaseStream<T, S>> {
<R> MyStream<R> map(Function<? super T, ? extends R> mapper);
}
interface MyStream<T> extends MyBaseStream<T, MyStream<T>> {}
{
BiFunction<MyStream<Integer>, Function<Integer, Integer>, MyStream<Integer>> streamMapper = MyStream::map;
}
}
@@ -0,0 +1,130 @@
/*
* Copyright 2000-2017 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.codeInsight.completion;
import com.intellij.codeInsight.daemon.impl.ParameterHintsPresentationManager;
import com.intellij.codeInsight.hint.ParameterInfoController;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementPresentation;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.registry.RegistryValue;
import com.intellij.util.ui.UIUtil;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
public class CompletionHintsTest extends LightFixtureCompletionTestCase {
private RegistryValue myRegistryValue = Registry.get("java.completion.argument.hints");
private boolean myStoredRegistryValue;
@Override
protected void setUp() throws Exception {
super.setUp();
myStoredRegistryValue = myRegistryValue.asBoolean();
myRegistryValue.setValue(true);
}
@Override
protected void tearDown() throws Exception {
try {
myRegistryValue.setValue(myStoredRegistryValue);
}
finally {
super.tearDown();
}
}
public void testBasicScenario() throws Exception {
// check hints appearance on completion
myFixture.configureByText(JavaFileType.INSTANCE, "class C { void m() { System.setPro<caret> } }");
complete("setProperty");
myFixture.checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>, <hint text=\"value:\"/>) } }");
// check that hints don't disappear after daemon highlighting passes
myFixture.doHighlighting();
myFixture.checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>, <hint text=\"value:\"/>) } }");
// test Tab/Shift+Tab navigation
myFixture.checkResult("class C { void m() { System.setProperty(<caret>, ) } }");
assertTrue(myFixture.getEditor().getCaretModel().getLogicalPosition().leansForward);
myFixture.performEditorAction("NextParameter");
myFixture.checkResult("class C { void m() { System.setProperty(, <caret>) } }");
assertTrue(myFixture.getEditor().getCaretModel().getLogicalPosition().leansForward);
myFixture.performEditorAction("PrevParameter");
myFixture.checkResult("class C { void m() { System.setProperty(<caret>, ) } }");
assertTrue(myFixture.getEditor().getCaretModel().getLogicalPosition().leansForward);
// test hints remain shown while entering parameter values
myFixture.type("\"a");
myFixture.performEditorAction("NextParameter");
myFixture.type("\"b");
myFixture.doHighlighting();
myFixture.checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>\"a\", <hint text=\"value:\"/>\"b\") } }");
// test hints disappearance when caret moves out of parameter list
myFixture.performEditorAction("EditorRight");
myFixture.performEditorAction("EditorRight");
ParameterInfoController.waitForDelayedActions(getEditor(), 10, TimeUnit.SECONDS);
myFixture.doHighlighting();
waitTillAnimationCompletes();
myFixture.checkResultWithInlays("class C { void m() { System.setProperty(\"a\", \"b\") } }");
}
public void testSwitchingOverloads() {
myFixture.configureByText(JavaFileType.INSTANCE, "class C { void m() { Character.to<caret> } }");
complete("toChars(int codePoint)");
myFixture.checkResultWithInlays("class C { void m() { Character.toChars(<hint text=\"codePoint:\"/>) } }");
showParameterInfo();
myFixture.performEditorAction("MethodOverloadSwitchDown");
myFixture.checkResultWithInlays("class C { void m() { Character.toChars(<hint text=\"codePoint:\"/>, <hint text=\"dst:\"/>, <hint text=\"dstIndex:\"/>) } }");
}
public void testSwitchingOverloadsWithParameterFilled() {
myFixture.configureByText(JavaFileType.INSTANCE, "class C { void m() { Character.to<caret> } }");
complete("toChars(int codePoint)");
type("123");
myFixture.checkResultWithInlays("class C { void m() { Character.toChars(<hint text=\"codePoint:\"/>123) } }");
showParameterInfo();
myFixture.performEditorAction("MethodOverloadSwitchDown");
myFixture.checkResultWithInlays("class C { void m() { Character.toChars(<hint text=\"codePoint:\"/>123, <hint text=\"dst:\"/>, <hint text=\"dstIndex:\"/>) } }");
myFixture.checkResult("class C { void m() { Character.toChars(123, <caret>, ) } }");
}
private void showParameterInfo() {
myFixture.performEditorAction("ParameterInfo");
UIUtil.dispatchAllInvocationEvents();
}
private void complete(String partOfItemText) {
LookupElement[] elements = myFixture.completeBasic();
LookupElement element = Stream.of(elements).filter(e -> {
LookupElementPresentation p = new LookupElementPresentation();
e.renderElement(p);
return (p.getItemText() + p.getTailText()).contains(partOfItemText);
}).findAny().get();
selectItem(element);
}
private void waitTillAnimationCompletes() {
long deadline = System.currentTimeMillis() + 60_000;
while (ParameterHintsPresentationManager.getInstance().isAnimationInProgress(getEditor())) {
if (System.currentTimeMillis() > deadline) fail("Too long waiting for animation to finish");
UIUtil.dispatchAllInvocationEvents();
}
}
}
@@ -1005,6 +1005,10 @@ public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase {
doTest(true);
}
public void testLowerBoundOfCapturedWildcardInSubtypingConstraint() throws Exception {
doTest(true);
}
public void testMembersContainedInCapturedWildcardType() throws Exception {
doTest();
}
@@ -537,6 +537,10 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testMethodInInheritorFoundBySecondSearch() throws Exception {
doTest();
}
public void testNonExactMethodReferenceOnRawClassType() throws Exception {
doTest();
}
@@ -39,7 +39,7 @@ import java.util.*;
/**
* @author Irina.Chernushina on 8/31/2015.
*/
class JsonBySchemaObjectAnnotator implements Annotator {
public class JsonBySchemaObjectAnnotator implements Annotator {
private final static Logger LOG = Logger.getInstance("#com.jetbrains.jsonSchema.JsonBySchemaAnnotator");
private static final Key<Set<PsiElement>> ANNOTATED_PROPERTIES = Key.create("JsonSchema.Properties.Annotated");
@NotNull private final VirtualFile mySchemaFile;
@@ -15,8 +15,10 @@
*/
package com.intellij.ide;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
public interface HelpIdProvider {
@Nullable String getHelpId();
@Nullable @NonNls
String getHelpId();
}
@@ -53,7 +53,7 @@ class UISettings : BaseState(), PersistentStateComponent<UISettings> {
@get:Property(filter = FontFilter::class)
@get:OptionTag("FONT_SIZE")
var fontSize by storedProperty(10)
var fontSize by storedProperty(12)
@get:Property(filter = FontFilter::class)
@get:OptionTag("FONT_SCALE")
@@ -29,6 +29,9 @@ public interface FontPreferences {
int DEFAULT_FONT_SIZE = FontSize.SMALL.getSize();
float DEFAULT_LINE_SPACING = 1.0f;
String MAC_OS_DEFAULT_FONT_FAMILY = "Menlo";
String LINUX_DEFAULT_FONT_FAMILY = "DejaVu Sans Mono";
String WINDOWS_DEFAULT_FONT_FAMILY = "Monospaced";
@NotNull
List<String> getEffectiveFontFamilies();
@@ -74,14 +77,14 @@ public interface FontPreferences {
}
static String getDefaultFontName() {
if (SystemInfo.isMacOSSnowLeopard) return "Menlo";
if (SystemInfo.isMacOSSnowLeopard) return MAC_OS_DEFAULT_FONT_FAMILY;
if (SystemInfo.isXWindow && !GraphicsEnvironment.isHeadless()) {
for (Font font : GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts()) {
if ("DejaVu Sans Mono".equals(font.getName())) {
if (LINUX_DEFAULT_FONT_FAMILY.equals(font.getName())) {
return font.getFontName();
}
}
}
return "Monospaced";
return WINDOWS_DEFAULT_FONT_FAMILY;
}
}
@@ -35,7 +35,6 @@ import com.intellij.util.PlatformUtils;
import com.intellij.util.containers.ContainerUtilRt;
import com.intellij.util.containers.HashMap;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import gnu.trove.THashMap;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
@@ -54,6 +53,7 @@ import static com.intellij.openapi.editor.markup.TextAttributes.USE_INHERITED_MA
import static com.intellij.openapi.util.Couple.of;
import static com.intellij.ui.ColorUtil.fromHex;
@SuppressWarnings("UseJBColor")
public abstract class AbstractColorsScheme implements EditorColorsScheme, SerializableScheme {
private static final int CURR_VERSION = 142;
@@ -422,10 +422,11 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
}
continue;
}
TextAttributes attr = myValueReader.read(TextAttributes.class, valueElement);
myAttributesMap.put(key, attr);
migrateErrorStripeColorFrom14(key, attr);
if (attr != null) {
myAttributesMap.put(key, attr);
migrateErrorStripeColorFrom14(key, attr);
}
}
}
@@ -522,10 +523,11 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
}
private int readFontSize(Element element, boolean isDefault, Float fontScale) {
Float size = (float)myValueReader.read(Integer.class, element);
if (size == null) {
Integer intSize = myValueReader.read(Integer.class, element);
if (intSize == null) {
return -1;
}
Float size = (float)intSize;
if (!isDefault) {
size = (fontScale != null) ? size / fontScale : DEFAULT_FONT_SIZE.getSize();
}
@@ -562,7 +564,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
parentNode.setAttribute(NAME_ATTR, getName());
parentNode.setAttribute(VERSION_ATTR, Integer.toString(myVersion));
/**
/*
* FONT_SCALE is used to correctly identify the font size in both the JRE-managed HiDPI mode and
* the IDE-managed HiDPI mode: {@link UIUtil#isJreHiDPIEnabled()}. Also, it helps to distinguish
* the "hidpi-aware" scheme version from the previous one. Namely, the absence of the FONT_SCALE
@@ -20,6 +20,7 @@ import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.text.StringUtil;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import java.awt.Color;
@@ -32,6 +33,7 @@ import java.awt.Color;
*
* @author Sergey.Malenkov
*/
@SuppressWarnings("UseJBColor")
class ValueElementReader {
@NonNls private static final String VALUE = "value";
@NonNls private static final String MAC = "mac";
@@ -60,6 +62,7 @@ class ValueElementReader {
* @param <T> the result type
* @return a value or {@code null} if it cannot be read
*/
@Nullable
public <T> T read(Class<T> type, Element element) {
T value = null;
if (element != null) {
@@ -20,11 +20,12 @@ import com.intellij.execution.actions.ConfigurationContext;
import com.intellij.execution.actions.ConfigurationFromContext;
import com.intellij.execution.actions.RunConfigurationProducer;
import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings;
import com.intellij.openapi.externalSystem.model.execution.ExternalTaskExecutionInfo;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Vladislav.Soroka
@@ -37,7 +38,7 @@ public abstract class AbstractExternalSystemRunConfigurationProducer extends Run
}
@Override
public boolean shouldReplace(ConfigurationFromContext self, ConfigurationFromContext other) {
public boolean shouldReplace(@NotNull ConfigurationFromContext self, @NotNull ConfigurationFromContext other) {
return true;
}
@@ -45,34 +46,33 @@ public abstract class AbstractExternalSystemRunConfigurationProducer extends Run
protected boolean setupConfigurationFromContext(ExternalSystemRunConfiguration configuration,
ConfigurationContext context,
Ref<PsiElement> sourceElement) {
Location location = context.getLocation();
if (!(location instanceof ExternalSystemTaskLocation)) {
Project project = getProjectFromContext(context);
if (project == null) return false;
ExternalSystemTaskExecutionSettings contextTaskExecutionSettings = getTaskSettingsFromContext(context);
if (contextTaskExecutionSettings == null) return false;
ExternalSystemTaskExecutionSettings taskExecutionSettings = configuration.getSettings();
if (!contextTaskExecutionSettings.getExternalSystemId().equals(taskExecutionSettings.getExternalSystemId())) {
return false;
}
ExternalSystemTaskLocation taskLocation = (ExternalSystemTaskLocation)location;
ExternalSystemTaskExecutionSettings taskExecutionSettings = configuration.getSettings();
ExternalTaskExecutionInfo task = taskLocation.getTaskInfo();
taskExecutionSettings.setExternalProjectPath(task.getSettings().getExternalProjectPath());
taskExecutionSettings.setTaskNames(task.getSettings().getTaskNames());
configuration.setName(AbstractExternalSystemTaskConfigurationType.generateName(location.getProject(), taskExecutionSettings));
taskExecutionSettings.setExternalProjectPath(contextTaskExecutionSettings.getExternalProjectPath());
taskExecutionSettings.setTaskNames(contextTaskExecutionSettings.getTaskNames());
configuration.setName(AbstractExternalSystemTaskConfigurationType.generateName(project, taskExecutionSettings));
return true;
}
@Override
public boolean isConfigurationFromContext(ExternalSystemRunConfiguration configuration, ConfigurationContext context) {
final Location contextLocation = context.getLocation();
if (contextLocation == null) return false;
Project project = getProjectFromContext(context);
if (project == null) return false;
if (!(contextLocation instanceof ExternalSystemTaskLocation)) {
return false;
}
ExternalSystemTaskExecutionSettings contextTaskExecutionSettings = getTaskSettingsFromContext(context);
if (contextTaskExecutionSettings == null) return false;
ExternalSystemTaskLocation taskLocation = (ExternalSystemTaskLocation)contextLocation;
ExternalSystemTaskExecutionSettings contextTaskExecutionSettings = taskLocation.getTaskInfo().getSettings();
ExternalSystemTaskExecutionSettings taskExecutionSettings = configuration.getSettings();
if(!contextTaskExecutionSettings.getExternalSystemId().equals(taskExecutionSettings.getExternalSystemId())) {
if (!contextTaskExecutionSettings.getExternalSystemId().equals(taskExecutionSettings.getExternalSystemId())) {
return false;
}
if (!StringUtil.equals(contextTaskExecutionSettings.getExternalProjectPath(), taskExecutionSettings.getExternalProjectPath())) {
@@ -81,4 +81,22 @@ public abstract class AbstractExternalSystemRunConfigurationProducer extends Run
if (!contextTaskExecutionSettings.getTaskNames().equals(taskExecutionSettings.getTaskNames())) return false;
return true;
}
@Nullable
private static ExternalSystemTaskExecutionSettings getTaskSettingsFromContext(ConfigurationContext context) {
final Location contextLocation = context.getLocation();
if (!(contextLocation instanceof ExternalSystemTaskLocation)) {
return null;
}
return ((ExternalSystemTaskLocation)contextLocation).getTaskInfo().getSettings();
}
@Nullable
private static Project getProjectFromContext(ConfigurationContext context) {
final Location contextLocation = context.getLocation();
if (!(contextLocation instanceof ExternalSystemTaskLocation)) {
return null;
}
return contextLocation.getProject();
}
}
@@ -15,7 +15,6 @@
*/
package com.intellij.openapi.externalSystem.service.project;
import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys;
import com.intellij.openapi.externalSystem.model.project.*;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleGrouperKt;
@@ -103,11 +102,9 @@ public class IdeModelsProviderImpl implements IdeModelsProvider {
}
private static boolean isApplicableIdeModule(@NotNull ModuleData moduleData, @NotNull Module ideModule) {
if (ideModule.getProject().getUserData(ExternalSystemDataKeys.NEWLY_CREATED_PROJECT) == Boolean.TRUE) {
for (VirtualFile root : ModuleRootManager.getInstance(ideModule).getContentRoots()) {
if (pathsEqual(root.getPath(), moduleData.getLinkedExternalProjectPath())) {
return true;
}
for (VirtualFile root : ModuleRootManager.getInstance(ideModule).getContentRoots()) {
if (pathsEqual(root.getPath(), moduleData.getLinkedExternalProjectPath())) {
return true;
}
}
return isExternalSystemAwareModule(moduleData.getOwner(), ideModule) &&
@@ -17,6 +17,7 @@ package com.intellij.lang.findUsages;
import com.intellij.lang.cacheBuilder.WordsScanner;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -54,7 +55,7 @@ public interface FindUsagesProvider {
* @param psiElement the element for which the help topic is requested.
* @return the help topic ID, or null if no help is available.
*/
@Nullable
@Nullable @NonNls
String getHelpId(@NotNull PsiElement psiElement);
/**
@@ -15,6 +15,7 @@
*/
package com.intellij.ide.util.gotoByName;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -59,7 +60,7 @@ public interface ChooseByNameModel {
@Nullable
String getFullName(Object element);
@Nullable
@Nullable @NonNls
String getHelpId();
boolean willOpenEditor();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -53,7 +53,7 @@ public class InlineElementData extends HighlightData {
@Override
public void addHighlToView(Editor view, EditorColorsScheme scheme, Map<TextAttributesKey, String> displayText) {
int offset = getStartOffset();
ParameterHintsPresentationManager.getInstance().addHint(view, offset, myText, false);
ParameterHintsPresentationManager.getInstance().addHint(view, offset, myText, false, false);
List<Inlay> inlays = view.getInlayModel().getInlineElementsInRange(offset, offset);
for (Inlay inlay : inlays) {
EditorCustomElementRenderer renderer = inlay.getRenderer();
@@ -863,8 +863,12 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzerEx implements Pers
public void run() {
ApplicationManager.getApplication().assertIsDispatchThread();
Project project = myProject;
DaemonCodeAnalyzerImpl daemonCodeAnalyzer = (DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(project);
if (project == null || !project.isInitialized() || project.isDisposed() || PowerSaveMode.isEnabled() || daemonCodeAnalyzer.myDisposed) {
DaemonCodeAnalyzerImpl daemonCodeAnalyzer;
if (project == null ||
!project.isInitialized() ||
project.isDisposed() ||
PowerSaveMode.isEnabled() ||
(daemonCodeAnalyzer = (DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(project)).myDisposed) {
return;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -33,6 +33,7 @@ import com.intellij.util.Alarm;
import com.intellij.util.ui.GraphicsUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import javax.swing.*;
import java.awt.*;
@@ -42,6 +43,7 @@ import java.util.Iterator;
import java.util.Set;
public class ParameterHintsPresentationManager implements Disposable {
private static final Key<Boolean> PINNED = Key.create("parameter.hint.pinned");
private static final Key<MyFontMetrics> HINT_FONT_METRICS = Key.create("ParameterHintFontMetrics");
private static final Key<AnimationStep> ANIMATION_STEP = Key.create("ParameterHintAnimationStep");
@@ -62,17 +64,27 @@ public class ParameterHintsPresentationManager implements Disposable {
return inlay.getRenderer() instanceof MyRenderer;
}
public boolean isPinned(@NotNull Inlay inlay) {
return Boolean.TRUE.equals(inlay.getUserData(PINNED));
}
public void unpin(@NotNull Inlay inlay) {
inlay.putUserData(PINNED, null);
}
public String getHintText(@NotNull Inlay inlay) {
EditorCustomElementRenderer renderer = inlay.getRenderer();
return renderer instanceof MyRenderer ? ((MyRenderer)renderer).getText() : null;
}
public void addHint(@NotNull Editor editor, int offset, @NotNull String hintText, boolean useAnimation) {
public Inlay addHint(@NotNull Editor editor, int offset, @NotNull String hintText, boolean useAnimation, boolean pinned) {
MyRenderer renderer = new MyRenderer(editor, hintText, useAnimation);
Inlay inlay = editor.getInlayModel().addInlineElement(offset, renderer);
if (useAnimation && inlay != null) {
scheduleRendererUpdate(editor, inlay);
if (inlay != null) {
if (pinned) inlay.putUserData(PINNED, Boolean.TRUE);
if (useAnimation) scheduleRendererUpdate(editor, inlay);
}
return inlay;
}
public void deleteHint(@NotNull Editor editor, @NotNull Inlay hint) {
@@ -109,6 +121,12 @@ public class ParameterHintsPresentationManager implements Disposable {
myAlarm.addRequest(step, ANIMATION_STEP_MS, ModalityState.any());
}
@TestOnly
public boolean isAnimationInProgress(@NotNull Editor editor) {
ApplicationManager.getApplication().assertIsDispatchThread();
return editor.getUserData(ANIMATION_STEP) != null;
}
private static Font getFont(@NotNull Editor editor) {
return getFontMetrics(editor).getFont();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -140,10 +140,6 @@ public class ParameterInfoComponent extends JPanel {
return myHighlighted;
}
public void setRequestFocus(boolean requestFocus) {
myRequestFocus = requestFocus;
}
public boolean isRequestFocus() {
return myRequestFocus;
}
@@ -16,18 +16,19 @@
package com.intellij.codeInsight.hint;
import com.intellij.codeInsight.daemon.impl.ParameterHintsPresentationManager;
import com.intellij.codeInsight.lookup.Lookup;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.ide.IdeTooltip;
import com.intellij.injected.editor.EditorWindow;
import com.intellij.lang.parameterInfo.ParameterInfoHandler;
import com.intellij.lang.parameterInfo.ParameterInfoHandlerWithTabActionSupport;
import com.intellij.lang.parameterInfo.ParameterInfoUtils;
import com.intellij.lang.parameterInfo.UpdateParameterInfoContext;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.event.*;
import com.intellij.openapi.editor.impl.EditorImpl;
import com.intellij.openapi.project.DumbService;
@@ -36,19 +37,21 @@ import com.intellij.openapi.ui.popup.Balloon.Position;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.TokenType;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.HintHint;
import com.intellij.ui.LightweightHint;
import com.intellij.util.Alarm;
import com.intellij.util.containers.JBIterable;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.text.CharArrayUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import javax.swing.*;
import java.awt.*;
@@ -56,6 +59,8 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class ParameterInfoController implements Disposable {
private final Project myProject;
@@ -64,15 +69,16 @@ public class ParameterInfoController implements Disposable {
private final RangeMarker myLbraceMarker;
private final LightweightHint myHint;
private final ParameterInfoComponent myComponent;
private final boolean myKeepOnHintHidden;
private final CaretListener myEditorCaretListener;
@NotNull private final ParameterInfoHandler<Object, Object> myHandler;
private final ShowParameterInfoHandler.BestLocationPointProvider myProvider;
private final MyBestLocationPointProvider myProvider;
private final Alarm myAlarm = new Alarm();
private static final int DELAY = 200;
private boolean myDisposed = false;
private boolean myDisposed;
/**
* Keeps Vector of ParameterInfoController's in Editor
@@ -85,7 +91,7 @@ public class ParameterInfoController implements Disposable {
ParameterInfoController controller = allControllers.get(i);
if (controller.myLbraceMarker.getStartOffset() == offset) {
if (controller.myHint.isVisible()) return controller;
if (controller.myKeepOnHintHidden || controller.myHint.isVisible()) return controller;
Disposer.dispose(controller);
--i;
}
@@ -103,27 +109,40 @@ public class ParameterInfoController implements Disposable {
return array;
}
public static boolean isShownForEditor(@NotNull Editor editor) {
public static boolean existsForEditor(@NotNull Editor editor) {
return !getAllControllers(editor).isEmpty();
}
public static boolean isAlreadyShown(Editor editor, int lbraceOffset) {
return findControllerAtOffset(editor, lbraceOffset) != null;
ParameterInfoController controller = findControllerAtOffset(editor, lbraceOffset);
return controller != null && controller.myHint.isVisible();
}
public ParameterInfoController(@NotNull Project project,
@NotNull Editor editor,
int lbraceOffset,
@NotNull LightweightHint hint,
Object[] descriptors,
Object highlighted,
PsiElement parameterOwner,
@NotNull ParameterInfoHandler handler,
@NotNull ShowParameterInfoHandler.BestLocationPointProvider provider) {
boolean showHint,
boolean requestFocus) {
myProject = project;
myEditor = editor;
myHandler = handler;
myProvider = provider;
myProvider = new MyBestLocationPointProvider(editor);
myLbraceMarker = editor.getDocument().createRangeMarker(lbraceOffset, lbraceOffset);
myHint = hint;
myComponent = (ParameterInfoComponent)myHint.getComponent();
myComponent = new ParameterInfoComponent(descriptors, editor, handler, requestFocus);
myHint = new LightweightHint(myComponent);
myKeepOnHintHidden = !showHint;
myHint.setSelectingHint(true);
myComponent.setParameterOwner(parameterOwner);
myComponent.setHighlightedParameter(highlighted);
myComponent.update(); // to have correct preferred size
if (showHint) {
showHint(requestFocus);
}
List<ParameterInfoController> allControllers = getAllControllers(myEditor);
allControllers.add(this);
@@ -175,12 +194,26 @@ public class ParameterInfoController implements Disposable {
public void dispose(){
if (myDisposed) return;
myDisposed = true;
myHint.hide();
List<ParameterInfoController> allControllers = getAllControllers(myEditor);
allControllers.remove(this);
myEditor.getCaretModel().removeCaretListener(myEditorCaretListener);
}
public void showHint(boolean requestFocus) {
Pair<Point, Short> pos = myProvider.getBestPointPosition(myHint, myComponent.getParameterOwner(), myLbraceMarker.getStartOffset(), true, HintManager.UNDER);
HintHint hintHint = HintManagerImpl.createHintHint(myEditor, pos.getFirst(), myHint, pos.getSecond());
hintHint.setExplicitClose(true);
hintHint.setRequestFocus(requestFocus);
Editor editorToShow = myEditor instanceof EditorWindow ? ((EditorWindow)myEditor).getDelegate() : myEditor;
// is case of injection we need to calculate position for EditorWindow
// also we need to show the hint in the main editor because of intention bulb
HintManagerImpl.getInstanceImpl().showEditorHint(myHint, editorToShow, pos.getFirst(), HintManager.HIDE_BY_ESCAPE | HintManager.UPDATE_BY_SCROLLING, 0, false, hintHint);
updateComponent();
}
private void adjustPositionForLookup(@NotNull Lookup lookup) {
if (!myHint.isVisible() || myEditor.isDisposed()) {
Disposer.dispose(this);
@@ -221,8 +254,34 @@ public class ParameterInfoController implements Disposable {
myAlarm.addRequest(request, DELAY, ModalityState.stateForComponent(myEditor.getComponent()));
}
private void updateComponent(){
if (!myHint.isVisible()){
public void updateComponent(){
if (myKeepOnHintHidden) {
boolean removeHints = true;
PsiElement owner = myComponent.getParameterOwner();
if (owner != null && owner.isValid()) {
int caretOffset = myEditor.getCaretModel().getOffset();
TextRange ownerTextRange = owner.getTextRange();
if (ownerTextRange != null) {
if (caretOffset > ownerTextRange.getStartOffset() && caretOffset < ownerTextRange.getEndOffset()) {
removeHints = false;
}
else {
for (PsiElement element : owner.getChildren()) {
if (element instanceof PsiErrorElement) {
removeHints = false;
break;
}
}
}
}
}
if (removeHints) {
Disposer.dispose(this);
return;
}
}
if (!myHint.isVisible() && !myKeepOnHintHidden && !ApplicationManager.getApplication().isUnitTestMode()) {
Disposer.dispose(this);
return;
}
@@ -290,12 +349,26 @@ public class ParameterInfoController implements Disposable {
PsiElement argsList = findArgumentList(file, offset, -1);
if (argsList == null) return;
myEditor.getCaretModel().moveToOffset(offset);
offset = adjustOffsetToInlay(offset);
myEditor.getCaretModel().moveToLogicalPosition(myEditor.offsetToLogicalPosition(offset).leanForward(true));
myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
myEditor.getSelectionModel().removeSelection();
myHandler.updateParameterInfo(argsList, new MyUpdateParameterInfoContext(offset, file));
}
private int adjustOffsetToInlay(int offset) {
CharSequence text = myEditor.getDocument().getImmutableCharSequence();
String whitespaceChars = " \t";
int whitespaceStart = CharArrayUtil.shiftBackward(text, offset, whitespaceChars) + 1;
int whitespaceEnd = CharArrayUtil.shiftForward(text, offset, whitespaceChars);
List<Inlay> inlays = myEditor.getInlayModel().getInlineElementsInRange(whitespaceStart, whitespaceEnd);
for (Inlay inlay : inlays) {
if (ParameterHintsPresentationManager.getInstance().isParameterHint(inlay)) return inlay.getOffset();
}
return offset;
}
private int getPrevOrNextParameterOffset(boolean isNext) {
if (!(myHandler instanceof ParameterInfoHandlerWithTabActionSupport)) return -1;
ParameterInfoHandlerWithTabActionSupport handler = (ParameterInfoHandlerWithTabActionSupport)myHandler;
@@ -338,7 +411,93 @@ public class ParameterInfoController implements Disposable {
return null;
}
private class MyUpdateParameterInfoContext implements UpdateParameterInfoContext {
public Object[] getObjects() {
return myComponent.getObjects();
}
public Object getHighlighted() {
return myComponent.getHighlighted();
}
@TestOnly
public static void waitForDelayedActions(@NotNull Editor editor, long timeout, @NotNull TimeUnit unit) throws TimeoutException {
long deadline = System.currentTimeMillis() + unit.toMillis(timeout);
while (System.currentTimeMillis() < deadline) {
List<ParameterInfoController> controllers = getAllControllers(editor);
boolean hasPendingRequests = false;
for (ParameterInfoController controller : controllers) {
if (!controller.myAlarm.isEmpty()) {
hasPendingRequests = true;
break;
}
}
if (hasPendingRequests) UIUtil.dispatchAllInvocationEvents();
else return;
}
throw new TimeoutException();
}
/**
* @return Point in layered pane coordinate system
*/
static Pair<Point, Short> chooseBestHintPosition(Project project,
Editor editor,
LogicalPosition pos,
LightweightHint hint,
boolean awtTooltip, short preferredPosition) {
if (ApplicationManager.getApplication().isUnitTestMode()) return Pair.pair(new Point(), HintManager.DEFAULT);
HintManagerImpl hintManager = HintManagerImpl.getInstanceImpl();
Dimension hintSize = hint.getComponent().getPreferredSize();
JComponent editorComponent = editor.getComponent();
JLayeredPane layeredPane = editorComponent.getRootPane().getLayeredPane();
Point p1;
Point p2;
boolean isLookupShown = LookupManager.getInstance(project).getActiveLookup() != null;
if (isLookupShown) {
p1 = hintManager.getHintPosition(hint, editor, HintManager.UNDER);
p2 = hintManager.getHintPosition(hint, editor, HintManager.ABOVE);
}
else {
p1 = HintManagerImpl.getHintPosition(hint, editor, pos, HintManager.UNDER);
p2 = HintManagerImpl.getHintPosition(hint, editor, pos, HintManager.ABOVE);
}
if (!awtTooltip) {
p1.x = Math.min(p1.x, layeredPane.getWidth() - hintSize.width);
p1.x = Math.max(p1.x, 0);
p2.x = Math.min(p2.x, layeredPane.getWidth() - hintSize.width);
p2.x = Math.max(p2.x, 0);
}
boolean p1Ok = p1.y + hintSize.height < layeredPane.getHeight();
boolean p2Ok = p2.y >= 0;
if (isLookupShown) {
if (p1Ok) return new Pair<>(p1, HintManager.UNDER);
if (p2Ok) return new Pair<>(p2, HintManager.ABOVE);
}
else {
if (preferredPosition != HintManager.DEFAULT) {
if (preferredPosition == HintManager.ABOVE) {
if (p2Ok) return new Pair<>(p2, HintManager.ABOVE);
} else if (preferredPosition == HintManager.UNDER) {
if (p1Ok) return new Pair<>(p1, HintManager.UNDER);
}
}
if (p1Ok) return new Pair<>(p1, HintManager.UNDER);
if (p2Ok) return new Pair<>(p2, HintManager.ABOVE);
}
int underSpace = layeredPane.getHeight() - p1.y;
int aboveSpace = p2.y;
return aboveSpace > underSpace ? new Pair<>(new Point(p2.x, 0), HintManager.UNDER) : new Pair<>(p1,
HintManager.ABOVE);
}
public class MyUpdateParameterInfoContext implements UpdateParameterInfoContext {
private final int myOffset;
private final PsiFile myFile;
@@ -415,4 +574,46 @@ public class ParameterInfoController implements Disposable {
}
}
private static class MyBestLocationPointProvider {
private final Editor myEditor;
private int previousOffset = -1;
private Point previousBestPoint;
private Short previousBestPosition;
public MyBestLocationPointProvider(final Editor editor) {
myEditor = editor;
}
@NotNull
public Pair<Point, Short> getBestPointPosition(LightweightHint hint,
final PsiElement list,
int offset,
final boolean awtTooltip,
short preferredPosition) {
if (list != null) {
TextRange range = list.getTextRange();
if (!range.contains(offset)) {
offset = range.getStartOffset() + 1;
}
}
if (previousOffset == offset) return Pair.create(previousBestPoint, previousBestPosition);
final boolean isMultiline = list != null && StringUtil.containsAnyChar(list.getText(), "\n\r");
final LogicalPosition pos = myEditor.offsetToLogicalPosition(offset).leanForward(true);
Pair<Point, Short> position;
if (!isMultiline) {
position = chooseBestHintPosition(myEditor.getProject(), myEditor, pos, hint, awtTooltip, preferredPosition);
}
else {
Point p = HintManagerImpl.getHintPosition(hint, myEditor, pos, HintManager.ABOVE);
position = new Pair<>(p, HintManager.ABOVE);
}
previousBestPoint = position.getFirst();
previousBestPosition = position.getSecond();
previousOffset = offset;
return position;
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -40,7 +40,7 @@ public class PrevNextParameterHandler extends EditorActionHandler {
@Override
protected boolean isEnabledForCaret(@NotNull Editor editor, @NotNull Caret caret, DataContext dataContext) {
if (!ParameterInfoController.isShownForEditor(editor)) return false;
if (!ParameterInfoController.existsForEditor(editor)) return false;
Project project = CommonDataKeys.PROJECT.getData(dataContext);
if (project == null) return false;
@@ -49,7 +49,7 @@ public class PrevNextParameterHandler extends EditorActionHandler {
if (exprList == null) return false;
int lbraceOffset = exprList.getTextRange().getStartOffset();
return ParameterInfoController.isAlreadyShown(editor, lbraceOffset) &&
return ParameterInfoController.findControllerAtOffset(editor, lbraceOffset) != null &&
ParameterInfoController.hasPrevOrNextParameter(editor, lbraceOffset, myIsNextParameterHandler);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -15,29 +15,18 @@
*/
package com.intellij.codeInsight.hint;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.injected.editor.EditorWindow;
import com.intellij.lang.parameterInfo.CreateParameterInfoContext;
import com.intellij.lang.parameterInfo.ParameterInfoHandler;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.ui.HintHint;
import com.intellij.ui.LightweightHint;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
/**
* @author peter
*/
@@ -131,20 +120,6 @@ public class ShowParameterInfoContext implements CreateParameterInfoContext {
if (ParameterInfoController.isAlreadyShown(editor, elementStart)) return;
if (editor.isDisposed() || !editor.getComponent().isVisible()) return;
final ParameterInfoComponent component = new ParameterInfoComponent(descriptors, editor,handler,requestFocus);
component.setParameterOwner(element);
component.setRequestFocus(requestFocus);
if (highlighted != null) {
component.setHighlightedParameter(highlighted);
}
component.update(); // to have correct preferred size
final LightweightHint hint = new LightweightHint(component);
hint.setSelectingHint(true);
final HintManagerImpl hintManager = HintManagerImpl.getInstanceImpl();
final ShowParameterInfoHandler.BestLocationPointProvider provider = new MyBestLocationPointProvider(editor);
final Pair<Point, Short> pos = provider.getBestPointPosition(hint, element, elementStart, true, HintManager.UNDER);
PsiDocumentManager.getInstance(project).performLaterWhenAllCommitted(() -> {
if (editor.isDisposed() || DumbService.isDumb(project)) return;
@@ -152,15 +127,13 @@ public class ShowParameterInfoContext implements CreateParameterInfoContext {
final Document document = editor.getDocument();
if (document.getTextLength() < elementStart) return;
HintHint hintHint = HintManagerImpl.createHintHint(editor, pos.getFirst(), hint, pos.getSecond());
hintHint.setExplicitClose(true);
hintHint.setRequestFocus(requestFocus);
Editor editorToShow = editor instanceof EditorWindow ? ((EditorWindow)editor).getDelegate() : editor;
// is case of injection we need to calculate position for EditorWindow
// also we need to show the hint in the main editor because of intention bulb
hintManager.showEditorHint(hint, editorToShow, pos.getFirst(), HintManager.HIDE_BY_ESCAPE | HintManager.UPDATE_BY_SCROLLING, 0, false, hintHint);
new ParameterInfoController(project, editor, elementStart, hint, handler, provider);
ParameterInfoController controller = ParameterInfoController.findControllerAtOffset(editor, elementStart);
if (controller == null) {
new ParameterInfoController(project, editor, elementStart, descriptors, highlighted, element, handler, true, requestFocus);
}
else {
controller.showHint(requestFocus);
}
});
}
@@ -175,66 +148,6 @@ public class ShowParameterInfoContext implements CreateParameterInfoContext {
showParameterHint(list, editor, candidates, project, candidates.length > 1 ? highlighted : null, offset, handler, requestFocus);
}
/**
* @return Point in layered pane coordinate system
*/
static Pair<Point, Short> chooseBestHintPosition(Project project,
Editor editor,
int line,
int col,
LightweightHint hint,
boolean awtTooltip, short preferredPosition) {
HintManagerImpl hintManager = HintManagerImpl.getInstanceImpl();
Dimension hintSize = hint.getComponent().getPreferredSize();
JComponent editorComponent = editor.getComponent();
JLayeredPane layeredPane = editorComponent.getRootPane().getLayeredPane();
Point p1;
Point p2;
boolean isLookupShown = LookupManager.getInstance(project).getActiveLookup() != null;
if (isLookupShown) {
p1 = hintManager.getHintPosition(hint, editor, HintManager.UNDER);
p2 = hintManager.getHintPosition(hint, editor, HintManager.ABOVE);
}
else {
LogicalPosition pos = new LogicalPosition(line, col);
p1 = HintManagerImpl.getHintPosition(hint, editor, pos, HintManager.UNDER);
p2 = HintManagerImpl.getHintPosition(hint, editor, pos, HintManager.ABOVE);
}
if (!awtTooltip) {
p1.x = Math.min(p1.x, layeredPane.getWidth() - hintSize.width);
p1.x = Math.max(p1.x, 0);
p2.x = Math.min(p2.x, layeredPane.getWidth() - hintSize.width);
p2.x = Math.max(p2.x, 0);
}
boolean p1Ok = p1.y + hintSize.height < layeredPane.getHeight();
boolean p2Ok = p2.y >= 0;
if (isLookupShown) {
if (p1Ok) return new Pair<>(p1, HintManager.UNDER);
if (p2Ok) return new Pair<>(p2, HintManager.ABOVE);
}
else {
if (preferredPosition != HintManager.DEFAULT) {
if (preferredPosition == HintManager.ABOVE) {
if (p2Ok) return new Pair<>(p2, HintManager.ABOVE);
} else if (preferredPosition == HintManager.UNDER) {
if (p1Ok) return new Pair<>(p1, HintManager.UNDER);
}
}
if (p1Ok) return new Pair<>(p1, HintManager.UNDER);
if (p2Ok) return new Pair<>(p2, HintManager.ABOVE);
}
int underSpace = layeredPane.getHeight() - p1.y;
int aboveSpace = p2.y;
return aboveSpace > underSpace ? new Pair<>(new Point(p2.x, 0), HintManager.UNDER) : new Pair<>(p1,
HintManager.ABOVE);
}
public void setRequestFocus(boolean requestFocus) {
myRequestFocus = requestFocus;
}
@@ -242,47 +155,4 @@ public class ShowParameterInfoContext implements CreateParameterInfoContext {
public boolean isRequestFocus() {
return myRequestFocus;
}
static class MyBestLocationPointProvider implements ShowParameterInfoHandler.BestLocationPointProvider {
private final Editor myEditor;
private int previousOffset = -1;
private Point previousBestPoint;
private Short previousBestPosition;
public MyBestLocationPointProvider(final Editor editor) {
myEditor = editor;
}
@Override
@NotNull
public Pair<Point, Short> getBestPointPosition(LightweightHint hint,
final PsiElement list,
int offset,
final boolean awtTooltip,
short preferredPosition) {
if (list != null) {
TextRange range = list.getTextRange();
if (!range.contains(offset)) {
offset = range.getStartOffset() + 1;
}
}
if (previousOffset == offset) return Pair.create(previousBestPoint, previousBestPosition);
final boolean isMultiline = list != null && StringUtil.containsAnyChar(list.getText(), "\n\r");
final LogicalPosition pos = myEditor.offsetToLogicalPosition(offset);
Pair<Point, Short> position;
if (!isMultiline) {
position = chooseBestHintPosition(myEditor.getProject(), myEditor, pos.line, pos.column, hint, awtTooltip, preferredPosition);
}
else {
Point p = HintManagerImpl.getHintPosition(hint, myEditor, pos, HintManager.ABOVE);
position = new Pair<>(p, HintManager.ABOVE);
}
previousBestPoint = position.getFirst();
previousBestPosition = position.getSecond();
previousOffset = offset;
return position;
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -142,7 +142,7 @@ public class ShowParameterInfoHandler implements CodeInsightActionHandler {
final LightweightHint hint = new LightweightHint(component);
hint.setSelectingHint(true);
final HintManagerImpl hintManager = HintManagerImpl.getInstanceImpl();
final Pair<Point, Short> pos = ShowParameterInfoContext.chooseBestHintPosition(project, editor, -1, -1, hint, true, HintManager.DEFAULT);
final Pair<Point, Short> pos = ParameterInfoController.chooseBestHintPosition(project, editor, null, hint, true, HintManager.DEFAULT);
ApplicationManager.getApplication().invokeLater(() -> {
if (!editor.getComponent().isShowing()) return;
hintManager.showEditorHint(hint, editor, pos.getFirst(),
@@ -160,15 +160,5 @@ public class ShowParameterInfoHandler implements CodeInsightActionHandler {
if (handlers.isEmpty()) return null;
return handlers.toArray(new ParameterInfoHandler[handlers.size()]);
}
interface BestLocationPointProvider {
@NotNull
Pair<Point, Short> getBestPointPosition(LightweightHint hint,
final PsiElement list,
int offset,
final boolean awtTooltip,
short preferredPosition);
}
}
@@ -146,7 +146,7 @@ public class ParameterHintsPassFactory extends AbstractProjectComponent implemen
String newText = myAnnotations.remove(offset);
String oldText = presentationManager.getHintText(inlay);
if (delayRemoval(inlay, caretMap)) continue;
if (delayRemoval(inlay, caretMap) || presentationManager.isPinned(inlay)) continue;
if (!Objects.equals(newText, oldText)) {
if (newText == null) {
removedHints.add(oldText);
@@ -160,7 +160,7 @@ public class ParameterHintsPassFactory extends AbstractProjectComponent implemen
for (Map.Entry<Integer, String> e : myAnnotations.entrySet()) {
int offset = e.getKey();
String text = e.getValue();
presentationManager.addHint(myEditor, offset, text, !firstTime && !removedHints.contains(text));
presentationManager.addHint(myEditor, offset, text, !firstTime && !removedHints.contains(text), false);
}
keeper.restoreOriginalLocation();
myEditor.putUserData(REPEATED_PASS, Boolean.TRUE);
@@ -46,13 +46,13 @@ public class FileUndoProvider extends VirtualFileAdapter implements UndoProvider
private long myLastChangeId;
@SuppressWarnings({"UnusedDeclaration"})
@SuppressWarnings("UnusedDeclaration")
public FileUndoProvider() {
this(null);
}
public FileUndoProvider(Project project) {
myProject = project;
private FileUndoProvider(Project project) {
myProject = project;
if (myProject == null) return;
LocalHistoryImpl localHistory = LocalHistoryImpl.getInstanceImpl();
@@ -99,7 +99,7 @@ public class FileUndoProvider extends VirtualFileAdapter implements UndoProvider
}
private void processEvent(VirtualFileEvent e) {
if (shouldNotProcess(e)) return;
if (!shouldProcess(e)) return;
if (isUndoable(e)) {
registerUndoableAction(e);
}
@@ -110,14 +110,14 @@ public class FileUndoProvider extends VirtualFileAdapter implements UndoProvider
@Override
public void beforeContentsChange(@NotNull VirtualFileEvent e) {
if (shouldNotProcess(e)) return;
if (!shouldProcess(e)) return;
if (isUndoable(e)) return;
registerNonUndoableAction(e);
}
@Override
public void beforeFileDeletion(@NotNull VirtualFileEvent e) {
if (shouldNotProcess(e)) {
if (!shouldProcess(e)) {
invalidateActionsFor(e);
return;
}
@@ -132,6 +132,7 @@ public class FileUndoProvider extends VirtualFileAdapter implements UndoProvider
@Override
public void fileDeleted(@NotNull VirtualFileEvent e) {
if (!shouldProcess(e)) return;
VirtualFile f = e.getFile();
DocumentReference ref = f.getUserData(DELETION_WAS_UNDOABLE);
@@ -141,13 +142,11 @@ public class FileUndoProvider extends VirtualFileAdapter implements UndoProvider
}
}
private boolean shouldNotProcess(VirtualFileEvent e) {
return isProjectClosed() || !LocalHistory.getInstance().isUnderControl(e.getFile()) || !myIsInsideCommand
|| FileContentUtilCore.FORCE_RELOAD_REQUESTOR.equals(e.getRequestor());
}
private boolean isProjectClosed() {
return myProject.isDisposed();
private boolean shouldProcess(VirtualFileEvent e) {
return !myProject.isDisposed() &&
LocalHistory.getInstance().isUnderControl(e.getFile()) &&
myIsInsideCommand &&
!FileContentUtilCore.FORCE_RELOAD_REQUESTOR.equals(e.getRequestor());
}
private static boolean isUndoable(VirtualFileEvent e) {
@@ -167,7 +166,9 @@ public class FileUndoProvider extends VirtualFileAdapter implements UndoProvider
}
private void invalidateActionsFor(VirtualFileEvent e) {
getUndoManager().invalidateActionsFor(createDocumentReference(e));
if (myProject == null || !myProject.isDisposed()) {
getUndoManager().invalidateActionsFor(createDocumentReference(e));
}
}
private static DocumentReference createDocumentReference(VirtualFileEvent e) {
@@ -185,7 +186,7 @@ public class FileUndoProvider extends VirtualFileAdapter implements UndoProvider
private ChangeRange myActionChangeRange;
private ChangeRange myUndoChangeRange;
public MyUndoableAction(DocumentReference r) {
MyUndoableAction(DocumentReference r) {
super(r);
myActionChangeRange = new ChangeRange(myGateway, myLocalHistory, myLastChangeId);
}
@@ -18,6 +18,7 @@ package com.intellij.ide.wizard;
import com.intellij.openapi.Disposable;
import com.intellij.util.EventDispatcher;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -97,6 +98,7 @@ public abstract class AbstractWizardStepEx implements Step, Disposable {
@Nullable
public abstract JComponent getPreferredFocusedComponent();
@NonNls
public String getHelpId() {
return null;
}
@@ -1526,7 +1526,7 @@ public abstract class DialogWrapper {
/**
* @return the help identifier or null if no help is available.
*/
@Nullable
@Nullable @NonNls
protected String getHelpId() {
return null;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -654,23 +654,19 @@ public class HintManagerImpl extends HintManager implements Disposable {
@PositionFlags short constraint,
boolean showByBalloon) {
Dimension hintSize = hint.getComponent().getPreferredSize();
int line1 = pos1.line;
int col1 = pos1.column;
int line2 = pos2.line;
int col2 = pos2.column;
Point location;
JComponent externalComponent = getExternalComponent(editor);
JComponent internalComponent = editor.getContentComponent();
if (constraint == RIGHT_UNDER) {
Point p = editor.logicalPositionToXY(new LogicalPosition(line2, col2));
Point p = editor.logicalPositionToXY(pos2);
if (!showByBalloon) {
p.y += editor.getLineHeight();
}
location = SwingUtilities.convertPoint(internalComponent, p, externalComponent);
}
else {
Point p = editor.logicalPositionToXY(new LogicalPosition(line1, col1));
Point p = editor.logicalPositionToXY(pos1);
if (constraint == UNDER) {
p.y += editor.getLineHeight();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -36,10 +36,7 @@ import com.intellij.util.containers.Stack;
import com.intellij.util.containers.WeakHashMap;
import com.intellij.util.ui.UIUtil;
import io.netty.util.internal.SystemPropertyUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.annotations.*;
import javax.swing.*;
import java.awt.*;
@@ -63,6 +60,7 @@ public class LaterInvocator {
@NotNull private final Condition<?> expired;
@NotNull private final ActionCallback callback;
@Debugger.Capture
RunnableInfo(@NotNull Runnable runnable,
@NotNull ModalityState modalityState,
@NotNull Condition<?> expired,
@@ -401,6 +399,7 @@ public class LaterInvocator {
}
}
@Debugger.Insert(keyExpression = "lastInfo")
private boolean runNextEvent() {
final RunnableInfo lastInfo = getNextEvent(true);
myLastInfo = lastInfo;
@@ -62,7 +62,7 @@ public class DocumentUndoProvider implements Disposable {
@Override
public void beforeDocumentChange(DocumentEvent e) {
Document document = e.getDocument();
if (shouldBeIgnored(document)) return;
if (!shouldProcess(document)) return;
UndoManagerImpl undoManager = getUndoManager();
if (undoManager.isActive() && isUndoable(document) && (undoManager.isUndoInProgress() || undoManager.isRedoInProgress()) &&
@@ -74,7 +74,7 @@ public class DocumentUndoProvider implements Disposable {
@Override
public void documentChanged(final DocumentEvent e) {
Document document = e.getDocument();
if (shouldBeIgnored(document)) return;
if (!shouldProcess(document)) return;
UndoManagerImpl undoManager = getUndoManager();
if (undoManager.isActive() && isUndoable(document)) {
@@ -85,11 +85,12 @@ public class DocumentUndoProvider implements Disposable {
}
}
private boolean shouldBeIgnored(Document document) {
return UndoManagerImpl.isCopy(document) // if we don't ignore copy's events, we will receive notification
// for the same event twice (from original document too)
// and undo will work incorrectly
|| !shouldRecordActions(document);
private boolean shouldProcess(Document document) {
if (myProject != null && myProject.isDisposed()) return false;
return !UndoManagerImpl.isCopy(document) // if we don't ignore copy's events, we will receive notification
// for the same event twice (from original document too)
// and undo will work incorrectly
&& shouldRecordActions(document);
}
private boolean shouldRecordActions(final Document document) {
@@ -116,11 +117,7 @@ public class DocumentUndoProvider implements Disposable {
if (file != null && file.getUserData(UndoConstants.FORCE_RECORD_UNDO) == Boolean.TRUE) {
return true;
}
else {
if (!UndoManagerImpl.isRefresh()) return true;
}
return getUndoManager().isUndoOrRedoAvailable(ref);
return !UndoManagerImpl.isRefresh() || getUndoManager().isUndoOrRedoAvailable(ref);
}
}
}
@@ -79,10 +79,8 @@ public class UndoManagerImpl extends UndoManager implements Disposable {
private int myCommandTimestamp = 1;
private int myCommandLevel;
private static final int NONE = 0;
private static final int UNDO = 1;
private static final int REDO = 2;
private int myCurrentOperationState = NONE;
private enum OperationState { NONE, UNDO, REDO }
private OperationState myCurrentOperationState = OperationState.NONE;
private DocumentReference myOriginatorReference;
@@ -129,16 +127,19 @@ public class UndoManagerImpl extends UndoManager implements Disposable {
@Override
public void commandStarted(CommandEvent event) {
if (myProject != null && myProject.isDisposed()) return;
onCommandStarted(event.getProject(), event.getUndoConfirmationPolicy(), event.shouldRecordActionForOriginalDocument());
}
@Override
public void commandFinished(CommandEvent event) {
if (myProject != null && myProject.isDisposed()) return;
onCommandFinished(event.getProject(), event.getCommandName(), event.getCommandGroupId());
}
@Override
public void undoTransparentActionStarted() {
if (myProject != null && myProject.isDisposed()) return;
if (!isInsideCommand()) {
myStarted = true;
onCommandStarted(myProject, UndoConfirmationPolicy.DEFAULT, true);
@@ -147,6 +148,7 @@ public class UndoManagerImpl extends UndoManager implements Disposable {
@Override
public void undoTransparentActionFinished() {
if (myProject != null && myProject.isDisposed()) return;
if (myStarted) {
myStarted = false;
onCommandFinished(myProject, "", null);
@@ -277,14 +279,16 @@ public class UndoManagerImpl extends UndoManager implements Disposable {
@Override
public void nonundoableActionPerformed(@NotNull final DocumentReference ref, final boolean isGlobal) {
ApplicationManager.getApplication().assertIsDispatchThread();
if (myProject != null && myProject.isDisposed()) return;
undoableActionPerformed(new NonUndoableAction(ref, isGlobal));
}
@Override
public void undoableActionPerformed(@NotNull UndoableAction action) {
ApplicationManager.getApplication().assertIsDispatchThread();
if (myProject != null && myProject.isDisposed()) return;
if (myCurrentOperationState != NONE) return;
if (myCurrentOperationState != OperationState.NONE) return;
if (myCommandLevel == 0) {
LOG.assertTrue(action instanceof NonUndoableAction,
@@ -355,7 +359,7 @@ public class UndoManagerImpl extends UndoManager implements Disposable {
}
private void undoOrRedo(final FileEditor editor, final boolean isUndo) {
myCurrentOperationState = isUndo ? UNDO : REDO;
myCurrentOperationState = isUndo ? OperationState.UNDO : OperationState.REDO;
final RuntimeException[] exception = new RuntimeException[1];
Runnable executeUndoOrRedoAction = () -> {
@@ -370,7 +374,7 @@ public class UndoManagerImpl extends UndoManager implements Disposable {
exception[0] = ex;
}
finally {
myCurrentOperationState = NONE;
myCurrentOperationState = OperationState.NONE;
}
};
@@ -382,12 +386,12 @@ public class UndoManagerImpl extends UndoManager implements Disposable {
@Override
public boolean isUndoInProgress() {
return myCurrentOperationState == UNDO;
return myCurrentOperationState == OperationState.UNDO;
}
@Override
public boolean isRedoInProgress() {
return myCurrentOperationState == REDO;
return myCurrentOperationState == OperationState.REDO;
}
@Override
@@ -518,7 +522,7 @@ public class UndoManagerImpl extends UndoManager implements Disposable {
}
protected void compact() {
if (myCurrentOperationState == NONE && myCommandTimestamp % COMMAND_TO_RUN_COMPACT == 0) {
if (myCurrentOperationState == OperationState.NONE && myCommandTimestamp % COMMAND_TO_RUN_COMPACT == 0) {
doCompact();
}
}
@@ -597,6 +601,7 @@ public class UndoManagerImpl extends UndoManager implements Disposable {
@TestOnly
private void flushMergers() {
assert myProject == null || !myProject.isDisposed();
// Run dummy command in order to flush all mergers...
CommandProcessor.getInstance().executeCommand(myProject, EmptyRunnable.getInstance(), CommonBundle.message("drop.undo.history.command.name"), null);
}
@@ -22,6 +22,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ValidationInfo;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -47,7 +48,7 @@ public abstract class WebProjectGenerator<T> implements DirectoryProjectGenerato
return null;
}
@Nullable
@Nullable @NonNls
public String getHelpId() {
return null;
}
@@ -15,6 +15,7 @@
*/
package com.intellij.ui.wizard;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -48,7 +49,7 @@ public abstract class WizardStep<T extends WizardModel> {
myIcon = icon;
}
public WizardStep(String title, String explanation, Icon icon, String helpId) {
public WizardStep(String title, String explanation, Icon icon, @NonNls String helpId) {
myTitle = title;
myExplanation = explanation;
myIcon = icon;
@@ -90,6 +91,7 @@ public abstract class WizardStep<T extends WizardModel> {
return myIcon;
}
@NonNls
public String getHelpId() {
return myHelpId;
}
@@ -1578,4 +1578,7 @@ action.ToggleDistractionFreeMode.exit=Exit Distraction Free Mode
action.TogglePresentationMode.exit=Exit Presentation Mode
action.TogglePresentationMode.enter=Enter Presentation Mode
action.EmojiAndSymbols.description=Input special characters using macOS system palette
action.EmojiAndSymbols.description=Input special characters using macOS system palette
action.MethodOverloadSwitchUp.text=Previous Method Overload
action.MethodOverloadSwitchDown.text=Next Method Overload
@@ -80,6 +80,9 @@
<action id="EditorLookupUp"><keyboard-shortcut first-keystroke="control UP"/></action>
<action id="EditorLookupDown"><keyboard-shortcut first-keystroke="control DOWN"/></action>
<action id="MethodOverloadSwitchUp"><keyboard-shortcut first-keystroke="control UP"/></action>
<action id="MethodOverloadSwitchDown"><keyboard-shortcut first-keystroke="control DOWN"/></action>
<action id="ReformatCode">
<keyboard-shortcut first-keystroke="control alt L"/>
</action>
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -94,7 +94,7 @@ public abstract class KeymapsTestCase extends PlatformTestCase {
{ "control 3", "GotoBookmark3", "FileChooser.GotoModule"},
{ "control ADD", "ExpandAll", "ExpandRegion"},
{ "control DIVIDE", "CommentByLineComment", "Images.Editor.ActualSize"},
{ "control DOWN", "EditorScrollDown", "EditorLookupDown"},
{ "control DOWN", "EditorScrollDown", "EditorLookupDown", "MethodOverloadSwitchDown"},
{ "control ENTER", "EditorSplitLine", "ViewSource", "Console.Execute.Multiline"},
{ "control EQUALS", "ExpandAll", "ExpandRegion"},
{ "control F5", "Refresh", "Rerun"},
@@ -106,7 +106,7 @@ public abstract class KeymapsTestCase extends PlatformTestCase {
{ "control R", "Replace", "Console.TableResult.Reload", "org.jetbrains.plugins.ruby.rails.console.ReloadSources"},
{ "control SLASH", "CommentByLineComment", "Images.Editor.ActualSize"},
{ "control U", "GotoSuperMethod", "CommanderSwapPanels"},
{ "control UP", "EditorScrollUp", "EditorLookupUp"},
{ "control UP", "EditorScrollUp", "EditorLookupUp", "MethodOverloadSwitchUp"},
{ "control alt A", "ChangesView.AddUnversioned", "Diagram.DeselectAll"},
{ "control alt E", "PerforceDirect.Edit", "Console.History.Browse"},
{ "control alt DOWN", "NextOccurence", "Console.TableResult.NextPage"},
@@ -162,6 +162,8 @@ public abstract class KeymapsTestCase extends PlatformTestCase {
{ "meta 3", "ActivateFindToolWindow", "FileChooser.GotoModule"},
{ "meta N", "FileChooser.NewFolder", "Generate", "NewElement"},
{ "meta O", "GotoClass", "GotoChangedFile"},
{ "meta UP", "ShowNavBar", "MethodOverloadSwitchUp"},
{ "meta DOWN", "EditSource", "MethodOverloadSwitchDown"},
{ "shift meta G", "ClassTemplateNavigation", "GoToClass", "FindPrevious"},
{ "shift meta LEFT", "EditorLineStartWithSelection", "ResizeToolWindowLeft", },
{ "shift meta RIGHT", "EditorLineEndWithSelection", "ResizeToolWindowRight", },
@@ -211,8 +213,8 @@ public abstract class KeymapsTestCase extends PlatformTestCase {
{ "control X", "GotoFile", "SaveAll", "NextTab", "PreviousTab", "CloseContent", "CloseAllEditors", "NextSplitter",
"GotoNextError", "NextProjectWindow", "EditorSwapSelectionBoundaries", "SplitVertically",
"SplitHorizontally", "UnsplitAll", "Switcher", "$SelectAll"},
{ "control UP", "EditorBackwardParagraph", "EditorLookupUp"},
{ "control DOWN", "EditorForwardParagraph", "EditorLookupDown"},
{ "control UP", "EditorBackwardParagraph", "EditorLookupUp", "MethodOverloadSwitchUp"},
{ "control DOWN", "EditorForwardParagraph", "EditorLookupDown", "MethodOverloadSwitchDown"},
{ "control alt A", "MethodUp", "ChangesView.AddUnversioned", "Diagram.DeselectAll"},
{ "control alt E", "MethodDown", "PerforceDirect.Edit", "Console.History.Browse"},
{ "control alt G", "GotoDeclaration", "org.jetbrains.plugins.ruby.rails.actions.generators.GeneratorsPopupAction", "Mvc.RunTarget"},
@@ -423,10 +423,10 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da
append(() -> ((UndoManagerImpl)UndoManager.getInstance(project)).dropHistoryInTests()).
append(() -> ((DocumentReferenceManagerImpl)DocumentReferenceManager.getInstance()).cleanupForNextTest()).
append(() -> TemplateDataLanguageMappings.getInstance(project).cleanupForNextTest()).
append(() -> ((PsiManagerImpl)PsiManager.getInstance(project)).cleanupForNextTest()).
append(() -> ProjectManagerEx.getInstanceEx().closeTestProject(project)).
append(() -> application.setDataProvider(null)).
append(() -> ourTestCase = null).
append(() -> ((PsiManagerImpl)PsiManager.getInstance(project)).cleanupForNextTest()).
append(() -> CompletionProgressIndicator.cleanupForNextTest()).
append(() -> UIUtil.dispatchAllInvocationEvents()).
append(() -> {
@@ -542,6 +542,8 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
void testInlays();
void checkResultWithInlays(String text);
void assertPreferredCompletionItems(int selected, @NotNull String... expected);
/**
@@ -27,6 +27,7 @@ import com.intellij.codeInsight.daemon.GutterMark;
import com.intellij.codeInsight.daemon.impl.*;
import com.intellij.codeInsight.folding.CodeFoldingManager;
import com.intellij.codeInsight.highlighting.actions.HighlightUsagesAction;
import com.intellij.codeInsight.hints.InlayInfo;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.impl.IntentionListStep;
import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler;
@@ -1705,6 +1706,15 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
}
}
@Override
public void checkResultWithInlays(String text) {
Document checkDocument = new DocumentImpl(text);
InlayHintsChecker checker = new InlayHintsChecker(this);
List<InlayInfo> inlayInfos = checker.extractInlays(checkDocument);
checkResult(checkDocument.getText());
checker.verifyInlays(inlayInfos, text);
}
@Override
public void assertPreferredCompletionItems(final int selected, @NotNull final String... expected) {
final LookupImpl lookup = getLookup();
@@ -17,7 +17,6 @@ package com.intellij.testFramework.utils.inlays
import com.intellij.codeInsight.daemon.impl.ParameterHintsPresentationManager
import com.intellij.codeInsight.hints.InlayInfo
import com.intellij.codeInsight.hints.InlayParameterHintsExtension
import com.intellij.codeInsight.hints.settings.ParameterNameHintsSettings
import com.intellij.openapi.command.WriteCommandAction
import com.intellij.openapi.editor.Document
@@ -57,10 +56,17 @@ class InlayHintsChecker(private val myFixture: CodeInsightTestFixture) {
val document = myFixture.getDocument(file)
val originalText = document.text
val expectedInlays: List<InlayInfo> = extractInlays(document)
myFixture.doHighlighting();
verifyInlays(expectedInlays, originalText)
}
fun verifyInlays(expectedInlays : List<InlayInfo>, originalText: String) {
val file = myFixture.file
val document = myFixture.getDocument(file)
val actual: List<Pair<Int, String>> = getActualInlays()
val expected = expectedInlays.map { Pair(it.offset, it.text) }
if (expectedInlays.size != actual.size || actual.zip(expected).any { it.first != it.second }) {
val proposedText = StringBuilder(document.text)
actual.asReversed().forEach { proposedText.insert(it.first, "<hint text=\"${it.second}\" />") }
@@ -70,9 +76,8 @@ class InlayHintsChecker(private val myFixture: CodeInsightTestFixture) {
} ?: throw ComparisonFailure("Hints differ", originalText, proposedText.toString())
}
}
private fun getActualInlays(): List<Pair<Int, String>> {
myFixture.doHighlighting()
val editor = myFixture.editor
val allInlays = editor.inlayModel.getInlineElementsInRange(0, editor.document.textLength)
@@ -259,6 +259,7 @@ debugger.emulate.method.breakpoints.description=Emulate method breakpoints with
debugger.intern.string.literals=false
debugger.intern.string.literals.description=Make string literal refer to the same instance of class String
debugger.capture.points=true
debugger.capture.points.annotations=false
analyze.exceptions.on.the.fly=false
analyze.exceptions.on.the.fly.description=Automatically analyze clipboard on frame activation,\
@@ -369,6 +370,9 @@ show.live.templates.in.completion.description=Show live templates in completion
java.completion.make.outer.variables.final=true
java.completion.make.outer.variables.final.description=Make variables accessed from inner class final automatically
java.completion.argument.hints=false
java.completion.argument.hints.description=When completing a method call, show hints in place of all arguments
java.completion.argument.live.template=false
java.completion.argument.live.template.description=When completing a method call, start a live template with all arguments
@@ -0,0 +1,51 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
/**
* @author egor
*/
public class Debugger {
/**
* Advise IDEA Debugger to capture stack frames and use as a key:
* <ul>
* <li>{@code keyExpression} (if specified)</li>
* <li>annotated parameter value</li>
* <li>{@code this} value (if used on a method)</li>
* </ul>
*/
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
public @interface Capture {
String keyExpression() default "";
}
/**
* Advise IDEA Debugger to replace the stack frames with the captured information and use as a key:
* <ul>
* <li>{@code keyExpression} (if specified)</li>
* <li>annotated parameter value</li>
* <li>{@code this} value (if used on a method)</li>
* </ul>
*/
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
public @interface Insert {
String keyExpression() default "";
}
}
@@ -15,9 +15,12 @@
*/
package com.intellij.openapi.vcs.changes;
import org.jetbrains.annotations.NonNls;
/**
* @author irengrig
*/
public interface CommitExecutorWithHelp extends CommitExecutor {
@NonNls
String getHelpId();
}
@@ -18,6 +18,7 @@ package com.intellij.openapi.vcs.changes;
import com.intellij.openapi.ui.ValidationInfo;
import org.jetbrains.annotations.CalledInAwt;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -69,6 +70,7 @@ public interface CommitSession {
* @return the ID of the help topic to show for the dialog
* @since 10.5
*/
@NonNls
String getHelpId();
@CalledInAwt
@@ -110,7 +110,10 @@ public class JavaFxModuleUtil {
}
private static ModificationTracker getModificationTracker(@NotNull Project project) {
return project.getUserData(KEY);
return () -> {
final ModificationTracker tracker = project.getUserData(KEY);
return tracker != null ? tracker.getModificationCount() + 1 : 0;
};
}
@Override
@@ -32,24 +32,20 @@ import org.tmatesoft.svn.core.SVNException;
public abstract class RepeatSvnActionThroughBusy {
public static final int REPEAT = 10;
public static final Processor<Exception> ourBusyExceptionProcessor = new Processor<Exception>() {
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
@Override
public boolean process(Exception e) {
if (e instanceof SVNException) {
final SVNErrorCode errorCode = ((SVNException)e).getErrorMessage().getErrorCode();
if (SVNErrorCode.WC_LOCKED.equals(errorCode)) {
return true;
}
else if (SVNErrorCode.SQLITE_ERROR.equals(errorCode)) {
Throwable cause = ((SVNException)e).getErrorMessage().getCause();
if (cause instanceof SqlJetException) {
return SqlJetErrorCode.BUSY.equals(((SqlJetException)cause).getErrorCode());
}
public static final Processor<Exception> ourBusyExceptionProcessor = e -> {
if (e instanceof SVNException) {
final SVNErrorCode errorCode = ((SVNException)e).getErrorMessage().getErrorCode();
if (SVNErrorCode.WC_LOCKED.equals(errorCode)) {
return true;
}
else if (SVNErrorCode.SQLITE_ERROR.equals(errorCode)) {
Throwable cause = ((SVNException)e).getErrorMessage().getCause();
if (cause instanceof SqlJetException) {
return SqlJetErrorCode.BUSY.equals(((SqlJetException)cause).getErrorCode());
}
}
return false;
}
return false;
};
protected int myCnt = REPEAT;
@@ -57,14 +57,12 @@ public class RootsToWorkingCopies implements VcsListener {
myRootMapping = new HashMap<>();
myUnversioned = new HashSet<>();
myVcs = vcs;
myRechecker = new Runnable() {
public void run() {
final VirtualFile[] roots = ProjectLevelVcsManager.getInstance(myProject).getRootsUnderVcs(myVcs);
synchronized (myLock) {
clear();
for (VirtualFile root : roots) {
addRoot(root);
}
myRechecker = () -> {
final VirtualFile[] roots = ProjectLevelVcsManager.getInstance(myProject).getRootsUnderVcs(myVcs);
synchronized (myLock) {
clear();
for (VirtualFile root : roots) {
addRoot(root);
}
}
};
@@ -1,145 +0,0 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.idea.svn;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.vcs.changes.FilePathsHelper;
import com.intellij.util.TimeoutUtil;
import org.jetbrains.annotations.Nullable;
import org.tmatesoft.sqljet.core.SqlJetException;
import org.tmatesoft.sqljet.core.table.ISqlJetBusyHandler;
import org.tmatesoft.sqljet.core.table.ISqlJetTransaction;
import org.tmatesoft.sqljet.core.table.SqlJetDb;
import org.tmatesoft.svn.core.SVNException;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created with IntelliJ IDEA.
* User: Irina.Chernushina
* Date: 10/19/12
* Time: 12:09 PM
*/
// TODO: Such locking functionality is not required anymore. Likely to be removed (together with SvnProxies).
public abstract class SvnAbstractWriteOperationLocks {
private final long myTimeout;
private final static Map<String, Lock> myLockMap = new HashMap<>();
private final static Object myLock = new Object();
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnAbstractWriteOperationLocks");
private ISqlJetBusyHandler ourBusyHandler;
private volatile boolean myDisposed;
protected SvnAbstractWriteOperationLocks(long timeout) {
myTimeout = timeout;
ourBusyHandler = new ISqlJetBusyHandler() {
@Override
public boolean call(int i) {
if (myDisposed) return false;
TimeoutUtil.sleep(myTimeout);
return true;
}
};
}
public void dispose() {
myDisposed = true;
}
// null if not 1.7+ copy
@Nullable
private Lock getLockObject(File file) throws SVNException {
final boolean directory = file.isDirectory();
final WorkingCopy wcRoot = getCopy(file, directory);
if (! wcRoot.is17Copy()) return null;
Lock lock;
final String path = FilePathsHelper.convertPath(wcRoot.getFile().getPath());
synchronized (myLock) {
lock = myLockMap.get(path);
if (lock == null) {
lock = new ReentrantLock();
myLockMap.put(path, lock);
}
}
return lock;
}
protected abstract WorkingCopy getCopy(File file, boolean directory) throws SVNException;
public void lockWrite(final File file) throws SVNException {
final Lock lock = getLockObject(file);
if (lock != null) {
lock.lock();
}
}
public void unlockWrite(final File file) throws SVNException {
final Lock lock = getLockObject(file);
if (lock != null) {
lock.unlock();
}
}
// would wait until read is available
public void wrapRead(final File file, final Runnable runnable) throws SVNException {
final WorkingCopy copy = getCopy(file, file.isDirectory());
if (! copy.is17Copy()) {
runnable.run();
return;
}
final File root = copy.getFile();
SqlJetDb open = null;
final boolean run[] = new boolean[1];
run[0] = false;
try {
open = SqlJetDb.open(SvnUtil.getWcDb(root), false);
open.setBusyHandler(ourBusyHandler);
try {
final SqlJetDb finalOpen = open;
open.runReadTransaction(new ISqlJetTransaction() {
@Override
public Object run(SqlJetDb db) throws SqlJetException {
run[0] = true;
runnable.run();
return null;
}
});
} finally {
open.rollback();
}
}
catch (SqlJetException e) {
LOG.info(e);
if (! run[0]) {
runnable.run();
}
}
finally {
if (open != null) {
try {
open.close();
}
catch (SqlJetException e) {
LOG.info(e);
}
}
}
}
}
@@ -59,13 +59,7 @@ public class SvnChangeProvider implements ChangeProvider {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnChangeProvider");
public static final String PROPERTY_LAYER = "Property";
private static final NotNullFactory<Map<String, File>> NAME_TO_FILE_MAP_FACTORY = new NotNullFactory<Map<String, File>>() {
@NotNull
@Override
public Map<String, File> create() {
return ContainerUtil.newHashMap();
}
};
private static final NotNullFactory<Map<String, File>> NAME_TO_FILE_MAP_FACTORY = () -> ContainerUtil.newHashMap();
@NotNull private final SvnVcs myVcs;
@NotNull private final VcsContextFactory myFactory;
@@ -176,12 +170,7 @@ public class SvnChangeProvider implements ChangeProvider {
}
}
return new ISVNStatusFileProvider() {
@Override
public Map<String, File> getChildrenFiles(File parent) {
return result.get(parent.getAbsolutePath());
}
};
return parent -> result.get(parent.getAbsolutePath());
}
private void processCopiedAndDeleted(@NotNull SvnChangeProviderContext context, @Nullable VcsDirtyScope dirtyScope) throws SVNException {
@@ -285,12 +274,10 @@ public class SvnChangeProvider implements ChangeProvider {
final Change change = context
.createMovedChange(createBeforeRevision(deletedFile, true), CurrentContentRevision.create(oldPath), copiedStatus,
deletedFile.getStatus());
final boolean isUnder = dirtyScope == null ? true : ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
@Override
public Boolean compute() {
return ChangeListManagerImpl.isUnder(change, dirtyScope);
}
});
final boolean isUnder = dirtyScope == null
? true
: ApplicationManager.getApplication()
.runReadAction((Computable<Boolean>)() -> ChangeListManagerImpl.isUnder(change, dirtyScope));
if (isUnder) {
context.getBuilder().removeRegisteredChangeFor(oldPath);
context.getBuilder().processChangeInList(change, clName, SvnVcs.getKey());
@@ -44,12 +44,9 @@ public class SvnChangelistListener implements ChangeListListener {
public SvnChangelistListener(@NotNull SvnVcs vcs) {
myVcs = vcs;
myUnderSvnCondition = new Condition<FilePath>() {
@Override
public boolean value(@NotNull FilePath path) {
final AbstractVcs vcs = ProjectLevelVcsManager.getInstance(myVcs.getProject()).getVcsFor(path);
return vcs != null && SvnVcs.VCS_NAME.equals(vcs.getName());
}
myUnderSvnCondition = path -> {
final AbstractVcs vcs1 = ProjectLevelVcsManager.getInstance(myVcs.getProject()).getVcsFor(path);
return vcs1 != null && SvnVcs.VCS_NAME.equals(vcs1.getName());
};
}
@@ -20,7 +20,6 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
import com.intellij.openapi.vfs.VirtualFile;
@@ -55,30 +54,21 @@ public class SvnCompatibilityChecker {
myCounter = 0;
++ myInvocationCounter;
final Application application = ApplicationManager.getApplication();
application.executeOnPooledThread(new Runnable() {
public void run() {
final List<VirtualFile> suspicious = new ArrayList<>();
for (VirtualFile vf : result) {
if (SvnUtil.seemsLikeVersionedDir(vf)) {
suspicious.add(vf);
}
}
if (! suspicious.isEmpty()) {
final String message = (suspicious.size() == 1) ?
"Root '" + suspicious.get(0).getPresentableName() + "' is likely to be of unsupported Subversion format" :
"Some roots are likely to be of unsupported Subversion format";
application.invokeLater(new Runnable() {
public void run() {
new VcsBalloonProblemNotifier(myProject, message, MessageType.WARNING).run();
}
}, ModalityState.NON_MODAL, new Condition() {
@Override
public boolean value(Object o) {
return (! myProject.isOpen()) || myProject.isDisposed();
}
});
application.executeOnPooledThread(() -> {
final List<VirtualFile> suspicious = new ArrayList<>();
for (VirtualFile vf : result) {
if (SvnUtil.seemsLikeVersionedDir(vf)) {
suspicious.add(vf);
}
}
if (!suspicious.isEmpty()) {
final String message = (suspicious.size() == 1)
? "Root '" + suspicious.get(0).getPresentableName() + "' is likely to be of unsupported Subversion format"
: "Some roots are likely to be of unsupported Subversion format";
application
.invokeLater(() -> new VcsBalloonProblemNotifier(myProject, message, MessageType.WARNING).run(), ModalityState.NON_MODAL,
o -> (!myProject.isOpen()) || myProject.isDisposed());
}
});
}
}
@@ -37,7 +37,6 @@ import com.intellij.ui.MultiLineTooltipUI;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBRadioButton;
import com.intellij.ui.components.labels.LinkLabel;
import com.intellij.ui.components.labels.LinkListener;
import com.intellij.util.Consumer;
import com.intellij.util.net.HttpProxyConfigurable;
import com.intellij.util.ui.UIUtil;
@@ -51,10 +50,6 @@ import org.jetbrains.idea.svn.svnkit.SvnKitManager;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
public class SvnConfigurable implements Configurable {
@@ -96,79 +91,52 @@ public class SvnConfigurable implements Configurable {
public SvnConfigurable(Project project) {
myProject = project;
myWithCommandLineClient.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
enableCommandLineClientOptions();
}
});
myWithCommandLineClient.addItemListener(e -> enableCommandLineClientOptions());
enableCommandLineClientOptions();
myUseDefaultCheckBox.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
boolean enabled = !myUseDefaultCheckBox.isSelected();
myConfigurationDirectoryText.setEnabled(enabled);
myConfigurationDirectoryText.setEditable(enabled);
myConfigurationDirectoryLabel.setEnabled(enabled);
SvnConfiguration configuration = SvnConfiguration.getInstance(myProject);
String path = configuration.getConfigurationDirectory();
if (!enabled || path == null) {
myConfigurationDirectoryText.setText(IdeaSubversionConfigurationDirectory.getPath());
}
else {
myConfigurationDirectoryText.setText(path);
}
myUseDefaultCheckBox.addActionListener(e -> {
boolean enabled = !myUseDefaultCheckBox.isSelected();
myConfigurationDirectoryText.setEnabled(enabled);
myConfigurationDirectoryText.setEditable(enabled);
myConfigurationDirectoryLabel.setEnabled(enabled);
SvnConfiguration configuration = SvnConfiguration.getInstance(myProject);
String path = configuration.getConfigurationDirectory();
if (!enabled || path == null) {
myConfigurationDirectoryText.setText(IdeaSubversionConfigurationDirectory.getPath());
}
else {
myConfigurationDirectoryText.setText(path);
}
});
myCommandLineClient.addBrowseFolderListener("Subversion", "Select path to Subversion executable (1.7+)", project,
FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor());
myClearAuthButton.addActionListener(new ActionListener(){
public void actionPerformed(final ActionEvent e) {
SvnAuthenticationNotifier.clearAuthenticationCache(myProject, myComponent, myConfigurationDirectoryText.getText());
}
});
myClearAuthButton.addActionListener(
e -> SvnAuthenticationNotifier.clearAuthenticationCache(myProject, myComponent, myConfigurationDirectoryText.getText()));
myConfigurationDirectoryText.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
@NonNls String path = myConfigurationDirectoryText.getText().trim();
selectConfigurationDirectory(path, new Consumer<String>() {
@Override
public void consume(String s) {
myConfigurationDirectoryText.setText(s);
}
}, myProject, myComponent);
}
myConfigurationDirectoryText.addActionListener(e -> {
@NonNls String path = myConfigurationDirectoryText.getText().trim();
selectConfigurationDirectory(path, s -> myConfigurationDirectoryText.setText(s), myProject, myComponent);
});
myConfigurationDirectoryLabel.setLabelFor(myConfigurationDirectoryText);
myUseCommonProxy.setText(SvnBundle.message("use.idea.proxy.as.default", ApplicationNamesInfo.getInstance().getProductName()));
myNavigateToCommonProxyLink.setListener(new LinkListener<Object>() {
@Override
public void linkSelected(LinkLabel aSource, Object aLinkData) {
Settings settings = Settings.KEY.getData(DataManager.getInstance().getDataContext(myComponent));
myNavigateToCommonProxyLink.setListener((aSource, aLinkData) -> {
Settings settings = Settings.KEY.getData(DataManager.getInstance().getDataContext(myComponent));
if (settings != null) {
settings.select(settings.find(HttpProxyConfigurable.class));
}
if (settings != null) {
settings.select(settings.find(HttpProxyConfigurable.class));
}
}, null);
myEditProxiesButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
final SvnConfigureProxiesDialog dialog = new SvnConfigureProxiesDialog(myProject);
dialog.show();
myHttpTimeout.setValue(Long.valueOf(SvnConfiguration.getInstance(myProject).getHttpTimeout() / 1000));
}
myEditProxiesButton.addActionListener(e -> {
final SvnConfigureProxiesDialog dialog = new SvnConfigureProxiesDialog(myProject);
dialog.show();
myHttpTimeout.setValue(Long.valueOf(SvnConfiguration.getInstance(myProject).getHttpTimeout() / 1000));
});
myMaximumNumberOfRevisionsCheckBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
myNumRevsInAnnotations.setEnabled(myMaximumNumberOfRevisionsCheckBox.isSelected());
}
});
myMaximumNumberOfRevisionsCheckBox
.addActionListener(e -> myNumRevsInAnnotations.setEnabled(myMaximumNumberOfRevisionsCheckBox.isSelected()));
myNumRevsInAnnotations.setEnabled(myMaximumNumberOfRevisionsCheckBox.isSelected());
final ButtonGroup bg = new ButtonGroup();
@@ -17,7 +17,6 @@
package org.jetbrains.idea.svn;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.components.*;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
@@ -374,12 +373,7 @@ public class SvnConfiguration implements PersistentStateComponent<SvnConfigurati
if (myAuthManager == null) {
// reloaded when configuration directory changes
myAuthManager = new SvnAuthenticationManager(svnVcs, new File(getConfigurationDirectory()));
Disposer.register(svnVcs.getProject(), new Disposable() {
@Override
public void dispose() {
myAuthManager = null;
}
});
Disposer.register(svnVcs.getProject(), () -> myAuthManager = null);
getInteractiveManager(svnVcs);
// to init
myAuthManager.setAuthenticationProvider(new SvnAuthenticationProvider(svnVcs, myInteractiveProvider, myAuthManager));
@@ -17,7 +17,6 @@ package org.jetbrains.idea.svn;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.RequestsMerger;
import com.intellij.util.Consumer;
import com.intellij.util.concurrency.Semaphore;
public class SvnCopiesRefreshManager {
@@ -28,24 +27,12 @@ public class SvnCopiesRefreshManager {
public SvnCopiesRefreshManager(final SvnFileUrlMappingImpl mapping) {
mySemaphore = new Semaphore();
// svn mappings refresh inside also uses asynchronous pass -> we need to pass callback that will ping our "single-threaded" executor here
myMappingCallback = new Runnable() {
@Override
public void run() {
mySemaphore.up();
}
};
myRequestsMerger = new RequestsMerger(new Runnable() {
@Override
public void run() {
mySemaphore.down();
mapping.realRefresh(myMappingCallback);
mySemaphore.waitFor();
}
}, new Consumer<Runnable>() {
public void consume(final Runnable runnable) {
ApplicationManager.getApplication().executeOnPooledThread(runnable);
}
});
myMappingCallback = () -> mySemaphore.up();
myRequestsMerger = new RequestsMerger(() -> {
mySemaphore.down();
mapping.realRefresh(myMappingCallback);
mySemaphore.waitFor();
}, runnable -> ApplicationManager.getApplication().executeOnPooledThread(runnable));
}
public void asynchRequest() {
@@ -40,7 +40,6 @@ import org.jetbrains.idea.svn.info.InfoConsumer;
import org.jetbrains.idea.svn.properties.PropertyValue;
import org.jetbrains.idea.svn.status.Status;
import org.jetbrains.idea.svn.status.StatusType;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc2.SvnTarget;
@@ -118,18 +117,15 @@ public class SvnDiffProvider extends DiffProviderEx implements DiffProvider, Dif
@NotNull
private static InfoConsumer createInfoHandler(@NotNull final Map<VirtualFile, VcsRevisionNumber> revisionMap,
@NotNull final Map<String, VirtualFile> fileMap) {
return new InfoConsumer() {
@Override
public void consume(Info info) throws SVNException {
if (info != null) {
VirtualFile file = fileMap.get(info.getFile().getAbsolutePath());
return info -> {
if (info != null) {
VirtualFile file = fileMap.get(info.getFile().getAbsolutePath());
if (file != null) {
revisionMap.put(file, getRevision(info));
}
else {
LOG.info("Could not find virtual file for path " + info.getFile().getAbsolutePath());
}
if (file != null) {
revisionMap.put(file, getRevision(info));
}
else {
LOG.info("Could not find virtual file for path " + info.getFile().getAbsolutePath());
}
}
};
@@ -40,7 +40,6 @@ import com.intellij.openapi.vfs.LocalFileOperationsHandler;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.RefreshQueue;
import com.intellij.util.Processor;
import com.intellij.util.ThrowableConsumer;
import com.intellij.util.containers.Convertor;
import com.intellij.util.containers.MultiMap;
@@ -359,22 +358,19 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
private static void copyUnversionedMembersOfDirectory(final File src, final File dst) throws SvnBindException {
if (src.isDirectory()) {
final SvnBindException[] exc = new SvnBindException[1];
FileUtil.processFilesRecursively(src, new Processor<File>() {
@Override
public boolean process(File file) {
String relativePath = FileUtil.getRelativePath(src, file);
File newFile = new File(dst, relativePath);
if (!newFile.exists()) {
try {
FileUtil.copyFileOrDir(src, dst);
}
catch (IOException e) {
exc[0] = new SvnBindException(e);
return false;
}
FileUtil.processFilesRecursively(src, file -> {
String relativePath = FileUtil.getRelativePath(src, file);
File newFile = new File(dst, relativePath);
if (!newFile.exists()) {
try {
FileUtil.copyFileOrDir(src, dst);
}
catch (IOException e) {
exc[0] = new SvnBindException(e);
return false;
}
return true;
}
return true;
});
if (exc[0] != null) {
throw exc[0];
@@ -709,15 +705,13 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
// if refresh asynchronously, local changes would also be notified that they are dirty asynchronously,
// and commit could be executed while not all changes are visible
filterOutInvalid(myFilesToRefresh);
RefreshQueue.getInstance().refresh(true, true, new Runnable() {
public void run() {
if (project.isDisposed()) return;
filterOutInvalid(toRefreshFiles);
filterOutInvalid(toRefreshDirs);
RefreshQueue.getInstance().refresh(true, true, () -> {
if (project.isDisposed()) return;
filterOutInvalid(toRefreshFiles);
filterOutInvalid(toRefreshDirs);
final VcsDirtyScopeManager vcsDirtyScopeManager = VcsDirtyScopeManager.getInstance(project);
vcsDirtyScopeManager.filesDirty(toRefreshFiles, toRefreshDirs);
}
final VcsDirtyScopeManager vcsDirtyScopeManager = VcsDirtyScopeManager.getInstance(project);
vcsDirtyScopeManager.filesDirty(toRefreshFiles, toRefreshDirs);
}, myFilesToRefresh);
myFilesToRefresh.clear();
}
@@ -748,18 +742,15 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
// Current method could be invoked under write action (for instance, during project import). So we explicitly use
// Application.invokeLater() in such cases to prevent deadlocks (while accessing vcs root mappings) and also not to show dialog under
// write action.
runNotUnderWriteAction(project, new Runnable() {
@Override
public void run() {
final AbstractVcsHelper vcsHelper = AbstractVcsHelper.getInstance(project);
final Collection<VirtualFile> filesToProcess = promptAboutAddition(vcs, addedVFiles, value, vcsHelper);
if (filesToProcess != null && !filesToProcess.isEmpty()) {
final List<VcsException> exceptions = new ArrayList<>();
runInBackground(project, "Adding files to Subversion",
createAdditionRunnable(project, vcs, copyFromMap, filesToProcess, exceptions));
if (!exceptions.isEmpty()) {
vcsHelper.showErrors(exceptions, SvnBundle.message("add.files.errors.title"));
}
runNotUnderWriteAction(project, () -> {
final AbstractVcsHelper vcsHelper = AbstractVcsHelper.getInstance(project);
final Collection<VirtualFile> filesToProcess = promptAboutAddition(vcs, addedVFiles, value, vcsHelper);
if (filesToProcess != null && !filesToProcess.isEmpty()) {
final List<VcsException> exceptions = new ArrayList<>();
runInBackground(project, "Adding files to Subversion",
createAdditionRunnable(project, vcs, copyFromMap, filesToProcess, exceptions));
if (!exceptions.isEmpty()) {
vcsHelper.showErrors(exceptions, SvnBundle.message("add.files.errors.title"));
}
}
});
@@ -789,44 +780,41 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
final Map<VirtualFile, File> copyFromMap,
final Collection<VirtualFile> filesToProcess,
final List<VcsException> exceptions) {
return new Runnable() {
@Override
public void run() {
for(VirtualFile file: filesToProcess) {
final File ioFile = new File(file.getPath());
try {
final File copyFrom = copyFromMap.get(file);
if (copyFrom != null) {
try {
new ActionWithTempFile(ioFile) {
protected void executeInternal() throws VcsException {
// not recursive
new RepeatSvnActionThroughBusy() {
@Override
protected void executeImpl() throws VcsException {
vcs.getFactory(copyFrom).createCopyMoveClient().copy(copyFrom, ioFile, true, false);
}
}.execute();
}
}.execute();
}
catch (VcsException e) {
exceptions.add(e);
}
}
else {
new RepeatSvnActionThroughBusy() {
@Override
protected void executeImpl() throws VcsException {
vcs.getFactory(ioFile).createAddClient().add(ioFile, null, false, false, true, null);
return () -> {
for (VirtualFile file : filesToProcess) {
final File ioFile = new File(file.getPath());
try {
final File copyFrom = copyFromMap.get(file);
if (copyFrom != null) {
try {
new ActionWithTempFile(ioFile) {
protected void executeInternal() throws VcsException {
// not recursive
new RepeatSvnActionThroughBusy() {
@Override
protected void executeImpl() throws VcsException {
vcs.getFactory(copyFrom).createCopyMoveClient().copy(copyFrom, ioFile, true, false);
}
}.execute();
}
}.execute();
}
VcsDirtyScopeManager.getInstance(project).fileDirty(file);
catch (VcsException e) {
exceptions.add(e);
}
}
catch (VcsException e) {
exceptions.add(e);
else {
new RepeatSvnActionThroughBusy() {
@Override
protected void executeImpl() throws VcsException {
vcs.getFactory(ioFile).createAddClient().add(ioFile, null, false, false, true, null);
}
}.execute();
}
VcsDirtyScopeManager.getInstance(project).fileDirty(file);
}
catch (VcsException e) {
exceptions.add(e);
}
}
};
@@ -907,12 +895,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
if (!filesToProcess.isEmpty()) {
runInBackground(project, "Deleting files from Subversion", createDeleteRunnable(project, vcs, filesToProcess, exceptions));
}
final List<FilePath> deletedFilesFiles = ObjectsConvertor.convert(deletedFiles, new Convertor<Pair<FilePath, WorkingCopyFormat>, FilePath>() {
@Override
public FilePath convert(Pair<FilePath, WorkingCopyFormat> o) {
return o.getFirst();
}
});
final List<FilePath> deletedFilesFiles = ObjectsConvertor.convert(deletedFiles, o -> o.getFirst());
for (FilePath file : deletedFilesFiles) {
final FilePath parent = file.getParentPath();
if (parent != null) {
@@ -936,25 +919,23 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
final SvnVcs vcs,
final Collection<FilePath> filesToProcess,
final List<VcsException> exceptions) {
return new Runnable() {
public void run() {
for(FilePath file: filesToProcess) {
VirtualFile vFile = file.getVirtualFile(); // for deleted directories
final File ioFile = new File(file.getPath());
try {
createDeleteAction(vcs, ioFile, true).execute();
if (vFile != null && vFile.isValid() && vFile.isDirectory()) {
vFile.refresh(true, true);
VcsDirtyScopeManager.getInstance(project).dirDirtyRecursively(vFile);
}
else {
VcsDirtyScopeManager.getInstance(project).fileDirty(file);
}
return () -> {
for (FilePath file : filesToProcess) {
VirtualFile vFile = file.getVirtualFile(); // for deleted directories
final File ioFile = new File(file.getPath());
try {
createDeleteAction(vcs, ioFile, true).execute();
if (vFile != null && vFile.isValid() && vFile.isDirectory()) {
vFile.refresh(true, true);
VcsDirtyScopeManager.getInstance(project).dirDirtyRecursively(vFile);
}
catch (VcsException e) {
exceptions.add(e);
else {
VcsDirtyScopeManager.getInstance(project).fileDirty(file);
}
}
catch (VcsException e) {
exceptions.add(e);
}
}
};
}
@@ -963,13 +944,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
SvnVcs vcs,
VcsShowConfirmationOption.Value value,
AbstractVcsHelper vcsHelper) {
final Convertor<Pair<FilePath, WorkingCopyFormat>, FilePath> convertor =
new Convertor<Pair<FilePath, WorkingCopyFormat>, FilePath>() {
@Override
public FilePath convert(Pair<FilePath, WorkingCopyFormat> o) {
return o.getFirst();
}
};
final Convertor<Pair<FilePath, WorkingCopyFormat>, FilePath> convertor = o -> o.getFirst();
Collection<FilePath> filesToProcess;
if (value == VcsShowConfirmationOption.Value.DO_ACTION_SILENTLY) {
filesToProcess = ObjectsConvertor.convert(deletedFiles, convertor);
@@ -1016,14 +991,12 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
private void processMovedFiles(final Project project) {
if (myMovedFiles.isEmpty()) return;
final Runnable runnable = new Runnable() {
public void run() {
for (Iterator<MovedFileInfo> iterator = myMovedFiles.iterator(); iterator.hasNext();) {
MovedFileInfo movedFileInfo = iterator.next();
if (movedFileInfo.myProject == project) {
doMove(SvnVcs.getInstance(project), movedFileInfo.mySrc, movedFileInfo.myDst);
iterator.remove();
}
final Runnable runnable = () -> {
for (Iterator<MovedFileInfo> iterator = myMovedFiles.iterator(); iterator.hasNext(); ) {
MovedFileInfo movedFileInfo = iterator.next();
if (movedFileInfo.myProject == project) {
doMove(SvnVcs.getInstance(project), movedFileInfo.mySrc, movedFileInfo.myDst);
iterator.remove();
}
}
};
@@ -165,18 +165,16 @@ public class SvnNativeCallsTranslator {
}
static {
ourAdvices.put(-25293, new Convertor<NativeLogReader.CallInfo, String>() {
@Override
public String convert(NativeLogReader.CallInfo callInfo) {
if (! SystemInfo.isMac) return null;
final Trinity<String, String, String> trinity = MacParser.macMessages.get(callInfo.getResultCode());
if (trinity == null) return null;
return MessageFormat.format(ourGenericAdvice, callInfo.getFunctionName(),
new StringBuilder().append(callInfo.getResultCode()).append(" ( ").append(trinity.getFirst())
.append(" - ").append(trinity.getSecond()).append(")").append("\nYou are likely to have modified ")
.append(ApplicationInfo.getInstance().getVersionName()).append(" bundle.\n")
.append("Please try to reinstall ").append(ApplicationInfo.getInstance().getVersionName()).toString());
}
ourAdvices.put(-25293, callInfo -> {
if (!SystemInfo.isMac) return null;
final Trinity<String, String, String> trinity = MacParser.macMessages.get(callInfo.getResultCode());
if (trinity == null) return null;
return MessageFormat.format(ourGenericAdvice, callInfo.getFunctionName(),
new StringBuilder().append(callInfo.getResultCode()).append(" ( ").append(trinity.getFirst())
.append(" - ").append(trinity.getSecond()).append(")").append("\nYou are likely to have modified ")
.append(ApplicationInfo.getInstance().getVersionName()).append(" bundle.\n")
.append("Please try to reinstall ").append(ApplicationInfo.getInstance().getVersionName())
.toString());
});
}
@@ -20,17 +20,14 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Processor;
import com.intellij.openapi.vfs.VirtualFileVisitor;
import com.intellij.vcsUtil.VcsUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -45,13 +42,17 @@ import org.jetbrains.idea.svn.status.StatusType;
import org.tmatesoft.svn.core.SVNCancelException;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
import org.tmatesoft.svn.core.wc.ISVNStatusFileProvider;
import org.tmatesoft.svn.core.wc.SVNRevision;
import java.io.File;
import java.util.LinkedList;
import static com.intellij.openapi.vfs.VfsUtilCore.visitChildrenRecursively;
import static com.intellij.openapi.vfs.VirtualFileVisitor.ONE_LEVEL_DEEP;
import static com.intellij.openapi.vfs.VirtualFileVisitor.SKIP_ROOT;
import static com.intellij.util.containers.ContainerUtil.ar;
public class SvnRecursiveStatusWalker {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnRecursiveStatusWalker");
@@ -129,12 +130,9 @@ public class SvnRecursiveStatusWalker {
}
public boolean isIgnoredByVcs(@NotNull final VirtualFile vFile) {
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
@Override
public Boolean compute() {
if (myVcs.getProject().isDisposed()) throw new ProcessCanceledException();
return myVcsManager.isIgnored(vFile);
}
return ApplicationManager.getApplication().runReadAction((Computable<Boolean>)() -> {
if (myVcs.getProject().isDisposed()) throw new ProcessCanceledException();
return myVcsManager.isIgnored(vFile);
});
}
@@ -198,57 +196,28 @@ public class SvnRecursiveStatusWalker {
myReceiver.processIgnored(vFile);
return;
}
final Depth newDepth = Depth.INFINITY.equals(prevDepth) ? Depth.INFINITY : Depth.EMPTY;
final File ioFile = new File(vFile.getPath());
final Processor<File> processor;
final Processor<File> directoryFilter;
final Ref<File> lastIgnored = new Ref<>();
final Processor<File> checkDirProcessor = new Processor<File>() {
Depth newDepth = Depth.INFINITY.equals(prevDepth) ? Depth.INFINITY : Depth.EMPTY;
VirtualFileVisitor.Option[] options = newDepth.equals(Depth.EMPTY) ? ar(SKIP_ROOT, ONE_LEVEL_DEEP) : new VirtualFileVisitor.Option[0];
visitChildrenRecursively(vFile, new VirtualFileVisitor(options) {
@NotNull
@Override
public boolean process(File file) {
FilePath path = VcsUtil.getFilePath(file, true);
VirtualFile vf = VfsUtil.findFileByIoFile(file, true);
if (vf != null && isIgnoredIdeaLevel(vf)) {
lastIgnored.set(file);
myReceiver.processIgnored(vf);
public Result visitFileEx(@NotNull VirtualFile file) {
if (isIgnoredIdeaLevel(file)) {
myReceiver.processIgnored(file);
return SKIP_CHILDREN;
}
else if (file.isDirectory() && new File(file, SVNFileUtil.getAdminDirectoryName()).exists()) {
myQueue.add(createItem(path, newDepth, true));
else if (file.isDirectory() && file.findChild(SvnUtil.SVN_ADMIN_DIR_NAME) != null) {
myQueue.add(createItem(VcsUtil.getFilePath(file), newDepth, true));
return SKIP_CHILDREN;
}
else if (vf != null) {
myReceiver.processUnversioned(vf);
else {
myReceiver.processUnversioned(file);
return CONTINUE;
}
return true;
}
};
if (Depth.EMPTY.equals(newDepth)) {
// just process immediate children - so only root directory itself should satisfy filter
directoryFilter = new Processor<File>() {
@Override
public boolean process(File file) {
return FileUtil.filesEqual(ioFile, file);
}
};
processor = new Processor<File>() {
@Override
public boolean process(File file) {
// TODO: check if we should still call checkDirProcessor() here - or we really could not check ignore settings but just call
// TODO: myReceiver.processUnversioned() for all immediate children
// here we deal only with immediate children - so ignored on IDEA level for children is not important
return FileUtil.filesEqual(ioFile, file) || checkDirProcessor.process(file);
}
};
} else {
directoryFilter = new Processor<File>() {
@Override
public boolean process(File file) {
return ! Comparing.equal(lastIgnored, file) && (myQueue.isEmpty() || ! FileUtil.filesEqual(myQueue.getLast().getPath().getIOFile(), file));
}
};
processor = checkDirProcessor;
}
FileUtil.processFilesRecursively(ioFile, processor, directoryFilter);
});
}
@NotNull
@@ -16,17 +16,13 @@
package org.jetbrains.idea.svn;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vcs.ObjectsConvertor;
import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vcs.changes.InvokeAfterUpdateMode;
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Convertor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.status.Status;
@@ -94,11 +90,7 @@ public class SvnRootsDetector {
}
private void addNestedRoots(final boolean clearState, final Runnable callback) {
final List<VirtualFile> basicVfRoots = ObjectsConvertor.convert(myResult.myTopRoots, new Convertor<RootUrlInfo, VirtualFile>() {
public VirtualFile convert(final RootUrlInfo real) {
return real.getVirtualFile();
}
});
final List<VirtualFile> basicVfRoots = ObjectsConvertor.convert(myResult.myTopRoots, real -> real.getVirtualFile());
final ChangeListManager clManager = ChangeListManager.getInstance(myVcs.getProject());
@@ -106,38 +98,34 @@ public class SvnRootsDetector {
// clear what was reported before (could be for currently-not-existing roots)
myNestedCopiesHolder.getAndClear();
}
clManager.invokeAfterUpdate(new Runnable() {
public void run() {
final List<RootUrlInfo> nestedRoots = new ArrayList<>();
clManager.invokeAfterUpdate(() -> {
final List<RootUrlInfo> nestedRoots = new ArrayList<>();
for (NestedCopyInfo info : myNestedCopiesHolder.getAndClear()) {
if (NestedCopyType.external.equals(info.getType()) || NestedCopyType.switched.equals(info.getType())) {
RootUrlInfo topRoot = findTopRoot(VfsUtilCore.virtualToIoFile(info.getFile()));
for (NestedCopyInfo info : myNestedCopiesHolder.getAndClear()) {
if (NestedCopyType.external.equals(info.getType()) || NestedCopyType.switched.equals(info.getType())) {
RootUrlInfo topRoot = findTopRoot(VfsUtilCore.virtualToIoFile(info.getFile()));
if (topRoot != null) {
// TODO: Seems that type is not set in ForNestedRootChecker as we could not determine it for sure. Probably, for the case
// TODO: (or some other cases) when vcs root from settings belongs is in externals of some other working copy upper
// TODO: the tree (I did not check this). Leave this setter for now.
topRoot.setType(info.getType());
continue;
}
if (!refreshPointInfo(info)) {
continue;
}
if (topRoot != null) {
// TODO: Seems that type is not set in ForNestedRootChecker as we could not determine it for sure. Probably, for the case
// TODO: (or some other cases) when vcs root from settings belongs is in externals of some other working copy upper
// TODO: the tree (I did not check this). Leave this setter for now.
topRoot.setType(info.getType());
continue;
}
if (!refreshPointInfo(info)) {
continue;
}
registerRootUrlFromNestedPoint(info, nestedRoots);
}
myResult.myTopRoots.addAll(nestedRoots);
myMapping.applyDetectionResult(myResult);
callback.run();
registerRootUrlFromNestedPoint(info, nestedRoots);
}
}, InvokeAfterUpdateMode.SILENT_CALLBACK_POOLED, null, new Consumer<VcsDirtyScopeManager>() {
public void consume(VcsDirtyScopeManager vcsDirtyScopeManager) {
if (clearState) {
vcsDirtyScopeManager.filesDirty(null, basicVfRoots);
}
myResult.myTopRoots.addAll(nestedRoots);
myMapping.applyDetectionResult(myResult);
callback.run();
}, InvokeAfterUpdateMode.SILENT_CALLBACK_POOLED, null, vcsDirtyScopeManager -> {
if (clearState) {
vcsDirtyScopeManager.filesDirty(null, basicVfRoots);
}
}, null);
}
@@ -185,22 +173,12 @@ public class SvnRootsDetector {
@Nullable
private RootUrlInfo findTopRoot(@NotNull final File file) {
return ContainerUtil.find(myResult.myTopRoots, new Condition<RootUrlInfo>() {
@Override
public boolean value(RootUrlInfo topRoot) {
return FileUtil.filesEqual(topRoot.getIoFile(), file);
}
});
return ContainerUtil.find(myResult.myTopRoots, topRoot -> FileUtil.filesEqual(topRoot.getIoFile(), file));
}
@Nullable
private RootUrlInfo findAncestorTopRoot(@NotNull final VirtualFile file) {
return ContainerUtil.find(myResult.myTopRoots, new Condition<RootUrlInfo>() {
@Override
public boolean value(RootUrlInfo topRoot) {
return VfsUtilCore.isAncestor(topRoot.getVirtualFile(), file, true);
}
});
return ContainerUtil.find(myResult.myTopRoots, topRoot -> VfsUtilCore.isAncestor(topRoot.getVirtualFile(), file, true));
}
private static class RepositoryRoots {
@@ -1,41 +0,0 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.idea.svn;
import org.tmatesoft.svn.core.SVNException;
import java.io.File;
/**
* Created with IntelliJ IDEA.
* User: Irina.Chernushina
* Date: 10/23/12
* Time: 2:31 PM
*/
// TODO: Used only in SvnLockingTest which is not required anymore. Likely to be removed.
public class SvnTestWriteOperationLocks extends SvnAbstractWriteOperationLocks {
private final WorkingCopy myWorkingCopy;
public SvnTestWriteOperationLocks(WorkingCopy copy) {
super(10);
myWorkingCopy = copy;
}
@Override
protected WorkingCopy getCopy(File file, boolean directory) throws SVNException {
return myWorkingCopy;
}
}
@@ -41,7 +41,6 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.wm.impl.status.StatusBarUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.NotNullFunction;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Convertor;
import com.intellij.util.containers.MultiMap;
@@ -55,7 +54,6 @@ import org.jetbrains.idea.svn.api.ProgressEvent;
import org.jetbrains.idea.svn.api.ProgressTracker;
import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationManager;
import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew;
import org.jetbrains.idea.svn.browse.DirectoryEntry;
import org.jetbrains.idea.svn.browse.DirectoryEntryConsumer;
import org.jetbrains.idea.svn.commandLine.SvnBindException;
import org.jetbrains.idea.svn.dialogs.LockDialog;
@@ -67,7 +65,6 @@ import org.tmatesoft.sqljet.core.internal.table.ISqlJetBtreeSchemaTable;
import org.tmatesoft.sqljet.core.internal.table.SqlJetBtreeSchemaTable;
import org.tmatesoft.sqljet.core.table.ISqlJetOptions;
import org.tmatesoft.sqljet.core.table.SqlJetDb;
import org.tmatesoft.sqljet.core.table.engine.ISqlJetEngineSynchronized;
import org.tmatesoft.sqljet.core.table.engine.SqlJetEngine;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
@@ -224,27 +221,25 @@ public class SvnUtil {
}
};
Runnable command = new Runnable() {
public void run() {
ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
Runnable command = () -> {
ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
try {
try {
if (progress != null) {
progress.setText(SvnBundle.message("progress.text.locking.files"));
}
for (File ioFile : ioFiles) {
if (progress != null) {
progress.setText(SvnBundle.message("progress.text.locking.files"));
progress.checkCanceled();
}
for (File ioFile : ioFiles) {
if (progress != null) {
progress.checkCanceled();
}
if (progress != null) {
progress.setText2(SvnBundle.message("progress.text2.processing.file", ioFile.getName()));
}
activeVcs.getFactory(ioFile).createLockClient().lock(ioFile, force, lockMessage, eventHandler);
if (progress != null) {
progress.setText2(SvnBundle.message("progress.text2.processing.file", ioFile.getName()));
}
activeVcs.getFactory(ioFile).createLockClient().lock(ioFile, force, lockMessage, eventHandler);
}
catch (VcsException e) {
exception[0] = e;
}
}
catch (VcsException e) {
exception[0] = e;
}
};
@@ -289,27 +284,25 @@ public class SvnUtil {
}
};
Runnable command = new Runnable() {
public void run() {
ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
Runnable command = () -> {
ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
try {
try {
if (progress != null) {
progress.setText(SvnBundle.message("progress.text.unlocking.files"));
}
for (File ioFile : ioFiles) {
if (progress != null) {
progress.setText(SvnBundle.message("progress.text.unlocking.files"));
progress.checkCanceled();
}
for (File ioFile : ioFiles) {
if (progress != null) {
progress.checkCanceled();
}
if (progress != null) {
progress.setText2(SvnBundle.message("progress.text2.processing.file", ioFile.getName()));
}
activeVcs.getFactory(ioFile).createLockClient().unlock(ioFile, force, eventHandler);
if (progress != null) {
progress.setText2(SvnBundle.message("progress.text2.processing.file", ioFile.getName()));
}
activeVcs.getFactory(ioFile).createLockClient().unlock(ioFile, force, eventHandler);
}
catch (VcsException e) {
exception[0] = e;
}
}
catch (VcsException e) {
exception[0] = e;
}
};
@@ -332,26 +325,17 @@ public class SvnUtil {
@NotNull
public static MultiMap<Pair<SVNURL, WorkingCopyFormat>, Change> splitChangesIntoWc(@NotNull SvnVcs vcs, @NotNull List<Change> changes) {
return splitIntoRepositoriesMap(vcs, changes, new Convertor<Change, FilePath>() {
@Override
public FilePath convert(@NotNull Change change) {
return ChangesUtil.getFilePath(change);
}
});
return splitIntoRepositoriesMap(vcs, changes, change -> ChangesUtil.getFilePath(change));
}
@NotNull
public static <T> MultiMap<Pair<SVNURL, WorkingCopyFormat>, T> splitIntoRepositoriesMap(@NotNull final SvnVcs vcs,
@NotNull Collection<T> items,
@NotNull final Convertor<T, FilePath> converter) {
return ContainerUtil.groupBy(items, new NotNullFunction<T, Pair<SVNURL, WorkingCopyFormat>>() {
@NotNull
@Override
public Pair<SVNURL, WorkingCopyFormat> fun(@NotNull T item) {
RootUrlInfo path = vcs.getSvnFileUrlMapping().getWcRootForFilePath(converter.convert(item).getIOFile());
return ContainerUtil.groupBy(items, item -> {
RootUrlInfo path = vcs.getSvnFileUrlMapping().getWcRootForFilePath(converter.convert(item).getIOFile());
return path == null ? UNKNOWN_REPOSITORY_AND_FORMAT : Pair.create(path.getRepositoryUrlUrl(), path.getFormat());
}
return path == null ? UNKNOWN_REPOSITORY_AND_FORMAT : Pair.create(path.getRepositoryUrlUrl(), path.getFormat());
});
}
@@ -487,12 +471,8 @@ public class SvnUtil {
public static VirtualFile getVirtualFile(final String filePath) {
@NonNls final String path = VfsUtilCore.pathToUrl(filePath.replace(File.separatorChar, '/'));
return ApplicationManager.getApplication().runReadAction(new Computable<VirtualFile>() {
@Nullable
public VirtualFile compute() {
return VirtualFileManager.getInstance().findFileByUrl(path);
}
});
return ApplicationManager.getApplication()
.runReadAction((Computable<VirtualFile>)() -> VirtualFileManager.getInstance().findFileByUrl(path));
}
@Nullable
@@ -597,13 +577,9 @@ public class SvnUtil {
public static boolean remoteFolderIsEmpty(@NotNull SvnVcs vcs, @NotNull String url) throws VcsException {
SvnTarget target = SvnTarget.fromURL(createUrl(url));
Ref<Boolean> result = new Ref<>(true);
DirectoryEntryConsumer handler = new DirectoryEntryConsumer() {
@Override
public void consume(final DirectoryEntry entry) throws SVNException {
if (entry != null) {
result.set(false);
}
DirectoryEntryConsumer handler = entry -> {
if (entry != null) {
result.set(false);
}
};
@@ -990,15 +966,13 @@ public class SvnUtil {
String result = "";
try {
result = (String)runSynchronized(new ISqlJetEngineSynchronized() {
public Object runSynchronized(SqlJetEngine engine) throws SqlJetException {
btree.enter();
try {
return readDbSchema();
}
finally {
btree.leave();
}
result = (String)runSynchronized(engine -> {
btree.enter();
try {
return readDbSchema();
}
finally {
btree.leave();
}
});
}
@@ -185,12 +185,7 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
myChangeListListener = new SvnChangelistListener(this);
myVcsListener = new VcsListener() {
@Override
public void directoryMappingChanged() {
invokeRefreshSvnRoots();
}
};
myVcsListener = () -> invokeRefreshSvnRoots();
}
myFrameStateListener = project.isDefault() ? null : new MyFrameStateListener(ChangeListManager.getInstance(project),
@@ -205,12 +200,9 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
if (myProject.isDefault()) return;
myCopiesRefreshManager = new SvnCopiesRefreshManager((SvnFileUrlMappingImpl)getSvnFileUrlMapping());
if (!myConfiguration.isCleanupRun()) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
cleanup17copies();
myConfiguration.setCleanupRun(true);
}
ApplicationManager.getApplication().invokeLater(() -> {
cleanup17copies();
myConfiguration.setCleanupRun(true);
}, ModalityState.NON_MODAL, myProject.getDisposed());
}
else {
@@ -261,26 +253,23 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
private void upgradeIfNeeded(final MessageBus bus) {
final MessageBusConnection connection = bus.connect();
connection.subscribe(ChangeListManagerImpl.LISTS_LOADED, new LocalChangeListsLoadedListener() {
@Override
public void processLoadedLists(final List<LocalChangeList> lists) {
if (lists.isEmpty()) return;
try {
ChangeListManager.getInstance(myProject).setReadOnly(LocalChangeList.DEFAULT_NAME, true);
connection.subscribe(ChangeListManagerImpl.LISTS_LOADED, lists -> {
if (lists.isEmpty()) return;
try {
ChangeListManager.getInstance(myProject).setReadOnly(LocalChangeList.DEFAULT_NAME, true);
if (!myConfiguration.changeListsSynchronized()) {
processChangeLists(lists);
}
if (!myConfiguration.changeListsSynchronized()) {
processChangeLists(lists);
}
catch (ProcessCanceledException e) {
//
}
finally {
myConfiguration.upgrade();
}
connection.disconnect();
}
catch (ProcessCanceledException e) {
//
}
finally {
myConfiguration.upgrade();
}
connection.disconnect();
});
}
@@ -301,12 +290,7 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
finally {
final Application appManager = ApplicationManager.getApplication();
if (appManager.isDispatchThread()) {
appManager.executeOnPooledThread(new Runnable() {
@Override
public void run() {
plVcsManager.stopBackgroundVcsOperation();
}
});
appManager.executeOnPooledThread(() -> plVcsManager.stopBackgroundVcsOperation());
}
else {
plVcsManager.stopBackgroundVcsOperation();
@@ -356,24 +340,21 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
}
// do one time after project loaded
StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new DumbAwareRunnable() {
@Override
public void run() {
postStartup();
StartupManager.getInstance(myProject).runWhenProjectIsInitialized((DumbAwareRunnable)() -> {
postStartup();
// for IDEA, it takes 2 minutes - and anyway this can be done in background, no sense...
// once it could be mistaken about copies for 2 minutes on start...
// for IDEA, it takes 2 minutes - and anyway this can be done in background, no sense...
// once it could be mistaken about copies for 2 minutes on start...
/*if (! myMapping.getAllWcInfos().isEmpty()) {
invokeRefreshSvnRoots();
return;
}
ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
public void run() {
myCopiesRefreshManager.getCopiesRefresh().ensureInit();
}
}, SvnBundle.message("refreshing.working.copies.roots.progress.text"), true, myProject);*/
/*if (! myMapping.getAllWcInfos().isEmpty()) {
invokeRefreshSvnRoots();
return;
}
ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
public void run() {
myCopiesRefreshManager.getCopiesRefresh().ensureInit();
}
}, SvnBundle.message("refreshing.working.copies.roots.progress.text"), true, myProject);*/
});
myProject.getMessageBus().connect().subscribe(ProjectLevelVcsManager.VCS_CONFIGURATION_CHANGED, myRootsToWorkingCopies);
@@ -818,12 +799,7 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
infos.add(new MyPair<>(vf, url.toString(), s));
}
final List<MyPair<S>> filtered = new UniqueRootsFilter().filter(infos);
final List<S> converted = ObjectsConvertor.convert(filtered, new Convertor<MyPair<S>, S>() {
@Override
public S convert(final MyPair<S> o) {
return o.getSrc();
}
});
final List<S> converted = ObjectsConvertor.convert(filtered, o -> o.getSrc());
if (!notMatched.isEmpty()) {
// potential bug is here: order is not kept. but seems it only occurs for cases where result is sorted after filtering so ok
converted.addAll(notMatched);
@@ -917,10 +893,10 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
/**
* Detects appropriate client factory based on project root directory working copy format.
*
* <p>
* Try to avoid usages of this method (for now) as it could not correctly for all cases
* detect svn 1.8 working copy format to guarantee command line client.
*
* <p>
* For instance, when working copies of several formats are presented in project
* (though it seems to be rather unlikely case).
*
@@ -1,51 +0,0 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.idea.svn;
import com.intellij.openapi.vcs.changes.ChangesUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.vcsUtil.VcsUtil;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import java.io.File;
/**
* Created with IntelliJ IDEA.
* User: Irina.Chernushina
* Date: 10/23/12
* Time: 2:29 PM
*/
// TODO: Such locking functionality is not required anymore. Likely to be removed.
public class SvnWriteOperationLocks extends SvnAbstractWriteOperationLocks {
private final RootsToWorkingCopies myRootsToWorkingCopies;
public SvnWriteOperationLocks(RootsToWorkingCopies rootsToWorkingCopies) {
super(1000);
myRootsToWorkingCopies = rootsToWorkingCopies;
}
protected WorkingCopy getCopy(File file, boolean directory) throws SVNException {
final VirtualFile parentOrSelf = ChangesUtil.findValidParentAccurately(VcsUtil.getFilePath(file, directory));
final WorkingCopy wcRoot = myRootsToWorkingCopies.getWcRoot(parentOrSelf);
if (wcRoot == null) {
throw new SVNException(SVNErrorMessage.create(directory ? SVNErrorCode.WC_NOT_WORKING_COPY : SVNErrorCode.WC_NOT_FILE));
}
// todo check about externals!
return wcRoot;
}
}
@@ -15,7 +15,6 @@
*/
package org.jetbrains.idea.svn;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
@@ -24,7 +23,6 @@ import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
@@ -46,20 +44,11 @@ public class UniqueRootsFilter {
}
private static <T extends RootUrlPair> void sort(List<T> list) {
Collections.sort(list, new Comparator<RootUrlPair>() {
public int compare(final RootUrlPair o1, final RootUrlPair o2) {
return o1.getVirtualFile().getPath().compareTo(o2.getVirtualFile().getPath());
}
});
Collections.sort(list, (o1, o2) -> o1.getVirtualFile().getPath().compareTo(o2.getVirtualFile().getPath()));
}
private static <T extends RootUrlPair> boolean alreadyRegistered(@NotNull final T child, @NotNull List<T> registered) {
return ContainerUtil.exists(registered, new Condition<T>() {
@Override
public boolean value(T parent) {
return isSamePath(child, parent) || isSameSupposedUrl(child, parent);
}
});
return ContainerUtil.exists(registered, parent -> isSamePath(child, parent) || isSameSupposedUrl(child, parent));
}
private static <T extends RootUrlPair> boolean isSamePath(@NotNull T child, @NotNull T parent) {
@@ -27,7 +27,6 @@ import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.AbstractVcsHelper;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.TransactionRunnable;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
import com.intellij.openapi.vfs.VirtualFile;
@@ -59,24 +58,22 @@ public abstract class BasicAction extends AnAction implements DumbAware {
AbstractVcsHelper helper = AbstractVcsHelper.getInstance(project);
try {
List<VcsException> exceptions = helper.runTransactionRunnable(vcs, new TransactionRunnable() {
public void run(List<VcsException> exceptions) {
VirtualFile badFile = null;
try {
if (isBatchAction()) {
batchExecute(vcs, files, e.getDataContext());
}
else {
for (VirtualFile file : files) {
badFile = file;
execute(vcs, file, e.getDataContext());
}
List<VcsException> exceptions = helper.runTransactionRunnable(vcs, exceptionList -> {
VirtualFile badFile = null;
try {
if (isBatchAction()) {
batchExecute(vcs, files, e.getDataContext());
}
else {
for (VirtualFile file : files) {
badFile = file;
execute(vcs, file, e.getDataContext());
}
}
catch (VcsException ex) {
ex.setVirtualFile(badFile);
exceptions.add(ex);
}
}
catch (VcsException ex) {
ex.setVirtualFile(badFile);
exceptionList.add(ex);
}
}, null);
@@ -32,11 +32,7 @@ public class ExclusiveBackgroundVcsAction {
} finally {
final Application application = ApplicationManager.getApplication();
if (application.isDispatchThread()) {
application.executeOnPooledThread(new Runnable() {
public void run() {
plVcsManager.stopBackgroundVcsOperation();
}
});
application.executeOnPooledThread(() -> plVcsManager.stopBackgroundVcsOperation());
} else {
plVcsManager.stopBackgroundVcsOperation();
}
@@ -35,9 +35,7 @@ import org.jetbrains.idea.svn.api.Depth;
import org.jetbrains.idea.svn.commandLine.SvnBindException;
import org.jetbrains.idea.svn.conflict.ConflictClient;
import org.jetbrains.idea.svn.dialogs.SelectFilesDialog;
import org.jetbrains.idea.svn.status.Status;
import org.jetbrains.idea.svn.status.StatusClient;
import org.jetbrains.idea.svn.status.StatusConsumer;
import org.jetbrains.idea.svn.status.StatusType;
import org.tmatesoft.svn.core.wc.SVNRevision;
@@ -127,13 +125,10 @@ public class MarkResolvedAction extends BasicAction {
File path = VfsUtilCore.virtualToIoFile(file);
StatusClient client = vcs.getFactory(path).createStatusClient();
client.doStatus(path, SVNRevision.UNDEFINED, Depth.INFINITY, false, false, false, false, new StatusConsumer() {
@Override
public void consume(@NotNull Status status) {
if (status.getContentsStatus() == StatusType.STATUS_CONFLICTED ||
status.getPropertiesStatus() == StatusType.STATUS_CONFLICTED) {
result.add(status.getFile().getAbsolutePath());
}
client.doStatus(path, SVNRevision.UNDEFINED, Depth.INFINITY, false, false, false, false, status -> {
if (status.getContentsStatus() == StatusType.STATUS_CONFLICTED ||
status.getPropertiesStatus() == StatusType.STATUS_CONFLICTED) {
result.add(status.getFile().getAbsolutePath());
}
}, null);
}
@@ -42,7 +42,7 @@ public class ShareWholeProject extends AnAction implements DumbAware {
final Presentation presentation = e.getPresentation();
presentation.setEnabled(checker.isEnabled());
presentation.setVisible(checker.isVisible());
if (checker.isEnabled()) {
presentation.setText(SvnBundle.message("action.share.whole.project.text"));
@@ -73,19 +73,20 @@ public class ShareWholeProject extends AnAction implements DumbAware {
myHadNoMappings = MyCheckResult.notMapped.equals(result);
if (MyCheckResult.notMapped.equals(result)) {
// no change list manager working
if(SvnUtil.seemsLikeVersionedDir(baseDir)) return;
} else if (SvnStatusUtil.isUnderControl(myProject, baseDir)) {
if (SvnUtil.seemsLikeVersionedDir(baseDir)) return;
}
else if (SvnStatusUtil.isUnderControl(myProject, baseDir)) {
return;
}
if ((! myHadNoMappings) && (! SvnVcs.getInstance(myProject).getSvnFileUrlMapping().isEmpty())) {
if ((!myHadNoMappings) && (!SvnVcs.getInstance(myProject).getSvnFileUrlMapping().isEmpty())) {
// there are some versioned dirs under project dir
return;
}
// visible: already checked above
myVisible = true;
myEnabled = (! vcsManager.isBackgroundVcsOperationRunning());
myEnabled = (!vcsManager.isBackgroundVcsOperationRunning());
}
private static enum MyCheckResult {
@@ -137,7 +138,7 @@ public class ShareWholeProject extends AnAction implements DumbAware {
public void actionPerformed(AnActionEvent e) {
final MyChecker checker = new MyChecker();
checker.execute(e);
if (! checker.isEnabled()) return;
if (!checker.isEnabled()) return;
final Project project = checker.getProject();
final VirtualFile baseDir = project.getBaseDir();
@@ -146,26 +147,21 @@ public class ShareWholeProject extends AnAction implements DumbAware {
boolean excThrown = false;
try {
success = ShareProjectAction.share(project, baseDir);
} catch (VcsException exc) {
}
catch (VcsException exc) {
AbstractVcsHelper.getInstance(project).showError(exc, "Failed to Share Project");
excThrown = true;
} finally {
}
finally {
// if success = false -> either action was cancelled or exception was thrown, so also check for exception
if (success || excThrown) {
baseDir.refresh(true, true, new Runnable() {
public void run() {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
VcsDirtyScopeManager.getInstance(project).dirDirtyRecursively(project.getBaseDir());
if (checker.isHadNoMappings() && SvnUtil.seemsLikeVersionedDir(baseDir)) {
final ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(project);
vcsManager.setDirectoryMappings(Arrays.asList(new VcsDirectoryMapping("", SvnVcs.VCS_NAME)));
}
}
}, ModalityState.NON_MODAL, project.getDisposed());
baseDir.refresh(true, true, () -> ApplicationManager.getApplication().invokeLater(() -> {
VcsDirtyScopeManager.getInstance(project).dirDirtyRecursively(project.getBaseDir());
if (checker.isHadNoMappings() && SvnUtil.seemsLikeVersionedDir(baseDir)) {
final ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(project);
vcsManager.setDirectoryMappings(Arrays.asList(new VcsDirectoryMapping("", SvnVcs.VCS_NAME)));
}
});
}, ModalityState.NON_MODAL, project.getDisposed()));
}
}
}
@@ -67,12 +67,7 @@ public class SvnExcludingIgnoredOperation {
}
private boolean isIgnoredByVcs(final VirtualFile file) {
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
@Override
public Boolean compute() {
return myVcsManager.isIgnored(file);
}
});
return ApplicationManager.getApplication().runReadAction((Computable<Boolean>)() -> myVcsManager.isIgnored(file));
}
}
@@ -58,53 +58,53 @@ public class SvnMergeProvider implements MergeProvider {
@NotNull
public MergeData loadRevisions(@NotNull final VirtualFile file) throws VcsException {
final MergeData data = new MergeData();
VcsRunnable runnable = new VcsRunnable() {
public void run() throws VcsException {
File oldFile = null;
File newFile = null;
File workingFile = null;
boolean mergeCase = false;
SvnVcs vcs = SvnVcs.getInstance(myProject);
Info info = vcs.getInfo(file);
VcsRunnable runnable = () -> {
File oldFile = null;
File newFile = null;
File workingFile = null;
boolean mergeCase = false;
SvnVcs vcs = SvnVcs.getInstance(myProject);
Info info = vcs.getInfo(file);
if (info != null) {
oldFile = info.getConflictOldFile();
newFile = info.getConflictNewFile();
workingFile = info.getConflictWrkFile();
mergeCase = workingFile == null || workingFile.getName().contains("working");
// for debug
if (workingFile == null) {
LOG.info("Null working file when merging text conflict for " + file.getPath() + " old file: " + oldFile + " new file: " + newFile);
}
if (mergeCase) {
// this is merge case
oldFile = info.getConflictNewFile();
newFile = info.getConflictOldFile();
workingFile = info.getConflictWrkFile();
}
data.LAST_REVISION_NUMBER = new SvnRevisionNumber(info.getRevision());
} else {
throw new VcsException("Could not get info for " + file.getPath());
}
if (oldFile == null || newFile == null || workingFile == null) {
ByteArrayOutputStream bos = getBaseRevisionContents(vcs, file);
data.ORIGINAL = bos.toByteArray();
data.LAST = bos.toByteArray();
data.CURRENT = readFile(new File(file.getPath()));
}
else {
data.ORIGINAL = readFile(oldFile);
data.LAST = readFile(newFile);
data.CURRENT = readFile(workingFile);
if (info != null) {
oldFile = info.getConflictOldFile();
newFile = info.getConflictNewFile();
workingFile = info.getConflictWrkFile();
mergeCase = workingFile == null || workingFile.getName().contains("working");
// for debug
if (workingFile == null) {
LOG
.info("Null working file when merging text conflict for " + file.getPath() + " old file: " + oldFile + " new file: " + newFile);
}
if (mergeCase) {
final ByteArrayOutputStream contents = getBaseRevisionContents(vcs, file);
if (! Arrays.equals(contents.toByteArray(), data.ORIGINAL)) {
// swap base and server: another order of merge arguments
byte[] original = data.ORIGINAL;
data.ORIGINAL = data.LAST;
data.LAST = original;
}
// this is merge case
oldFile = info.getConflictNewFile();
newFile = info.getConflictOldFile();
workingFile = info.getConflictWrkFile();
}
data.LAST_REVISION_NUMBER = new SvnRevisionNumber(info.getRevision());
}
else {
throw new VcsException("Could not get info for " + file.getPath());
}
if (oldFile == null || newFile == null || workingFile == null) {
ByteArrayOutputStream bos = getBaseRevisionContents(vcs, file);
data.ORIGINAL = bos.toByteArray();
data.LAST = bos.toByteArray();
data.CURRENT = readFile(new File(file.getPath()));
}
else {
data.ORIGINAL = readFile(oldFile);
data.LAST = readFile(newFile);
data.CURRENT = readFile(workingFile);
}
if (mergeCase) {
final ByteArrayOutputStream contents = getBaseRevisionContents(vcs, file);
if (!Arrays.equals(contents.toByteArray(), data.ORIGINAL)) {
// swap base and server: another order of merge arguments
byte[] original = data.ORIGINAL;
data.ORIGINAL = data.LAST;
data.LAST = original;
}
}
};
@@ -176,11 +176,7 @@ public abstract class BaseSvnFileAnnotation extends FileAnnotation {
public List<VcsFileRevision> getRevisions() {
final List<VcsFileRevision> result = new ArrayList<>(myRevisionMap.values());
Collections.sort(result, new Comparator<VcsFileRevision>() {
public int compare(final VcsFileRevision o1, final VcsFileRevision o2) {
return o2.getRevisionNumber().compareTo(o1.getRevisionNumber());
}
});
Collections.sort(result, (o1, o2) -> o2.getRevisionNumber().compareTo(o1.getRevisionNumber()));
return result;
}
@@ -35,9 +35,10 @@ import com.intellij.vcsUtil.VcsUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.*;
import org.jetbrains.idea.svn.checkin.CommitInfo;
import org.jetbrains.idea.svn.diff.DiffOptions;
import org.jetbrains.idea.svn.history.*;
import org.jetbrains.idea.svn.history.HistoryClient;
import org.jetbrains.idea.svn.history.SvnChangeList;
import org.jetbrains.idea.svn.history.SvnFileRevision;
import org.jetbrains.idea.svn.info.Info;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
@@ -70,8 +71,9 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
throw new VcsException("Can not get current revision for file " + file.getPath());
}
final SVNRevision svnRevision = ((SvnRevisionNumber)lastChangedRevision.getRevisionNumber()).getRevision();
if (! svnRevision.isValid()) {
throw new VcsException("Can not get last changed revision for file: " + file.getPath() + "\nPlease run svn info for this file and file an issue.");
if (!svnRevision.isValid()) {
throw new VcsException(
"Can not get last changed revision for file: " + file.getPath() + "\nPlease run svn info for this file and file an issue.");
}
return annotate(file, new SvnFileRevision(myVcs, currentRevision, currentRevision, null, null, null, null, null),
lastChangedRevision.getRevisionNumber(), true);
@@ -89,78 +91,80 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
final FileAnnotation[] annotation = new FileAnnotation[1];
final VcsException[] exception = new VcsException[1];
Runnable command = new Runnable() {
public void run() {
final ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
final File ioFile = new File(file.getPath()).getAbsoluteFile();
Info info = null;
try {
Runnable command = () -> {
final ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
final File ioFile = new File(file.getPath()).getAbsoluteFile();
Info info = null;
try {
final String contents;
if (loadExternally) {
byte[] data = SvnUtil.getFileContents(myVcs, SvnTarget.fromFile(ioFile), SVNRevision.BASE, SVNRevision.UNDEFINED);
contents = LoadTextUtil.getTextByBinaryPresentation(data, file, false, false).toString();
} else {
final byte[] bytes = VcsHistoryUtil.loadRevisionContent(revision);
contents = LoadTextUtil.getTextByBinaryPresentation(bytes, file, false, false).toString();
}
final SvnFileAnnotation result = new SvnFileAnnotation(myVcs, file, contents, lastChangedRevision);
info = myVcs.getInfo(ioFile);
if (info == null) {
exception[0] = new VcsException(new SVNException(SVNErrorMessage.create(SVNErrorCode.UNKNOWN, "File ''{0}'' is not under version control", ioFile)));
return;
}
final String url = info.getURL() == null ? null : info.getURL().toString();
SVNRevision endRevision = ((SvnFileRevision) revision).getRevision();
if (SVNRevision.WORKING.equals(endRevision)) {
endRevision = info.getRevision();
}
if (progress != null) {
progress.setText(SvnBundle.message("progress.text.computing.annotation", file.getName()));
}
// ignore mime type=true : IDEA-19562
final AnnotationConsumer annotateHandler = createAnnotationHandler(progress, result);
boolean calculateMergeinfo =
myVcs.getSvnConfiguration().isShowMergeSourcesInAnnotate() && SvnUtil.checkRepositoryVersion15(myVcs, url);
final MySteppedLogGetter logGetter = new MySteppedLogGetter(
myVcs, ioFile, progress,
myVcs.getFactory(ioFile).createHistoryClient(), endRevision, result,
url, calculateMergeinfo, file.getCharset());
logGetter.go();
final LinkedList<SVNRevision> rp = logGetter.getRevisionPoints();
// TODO: only 2 elements will be in rp and for loop will be executed only once - probably rewrite with Pair
AnnotateClient annotateClient = myVcs.getFactory(ioFile).createAnnotateClient();
for (int i = 0; i < rp.size() - 1; i++) {
annotateClient.annotate(SvnTarget.fromFile(ioFile), rp.get(i + 1), rp.get(i), calculateMergeinfo, getLogClientOptions(myVcs),
annotateHandler);
}
if (rp.get(1).getNumber() > 0) {
result.setFirstRevision(rp.get(1));
}
annotation[0] = result;
final String contents;
if (loadExternally) {
byte[] data = SvnUtil.getFileContents(myVcs, SvnTarget.fromFile(ioFile), SVNRevision.BASE, SVNRevision.UNDEFINED);
contents = LoadTextUtil.getTextByBinaryPresentation(data, file, false, false).toString();
}
catch (IOException e) {
exception[0] = new VcsException(e);
} catch (VcsException e) {
if (e.getCause() instanceof SVNException) {
handleSvnException(ioFile, info, (SVNException)e.getCause(), file, revision, annotation, exception);
}
else {
exception[0] = e;
}
else {
final byte[] bytes = VcsHistoryUtil.loadRevisionContent(revision);
contents = LoadTextUtil.getTextByBinaryPresentation(bytes, file, false, false).toString();
}
final SvnFileAnnotation result = new SvnFileAnnotation(myVcs, file, contents, lastChangedRevision);
info = myVcs.getInfo(ioFile);
if (info == null) {
exception[0] = new VcsException(
new SVNException(SVNErrorMessage.create(SVNErrorCode.UNKNOWN, "File ''{0}'' is not under version control", ioFile)));
return;
}
final String url = info.getURL() == null ? null : info.getURL().toString();
SVNRevision endRevision = ((SvnFileRevision)revision).getRevision();
if (SVNRevision.WORKING.equals(endRevision)) {
endRevision = info.getRevision();
}
if (progress != null) {
progress.setText(SvnBundle.message("progress.text.computing.annotation", file.getName()));
}
// ignore mime type=true : IDEA-19562
final AnnotationConsumer annotateHandler = createAnnotationHandler(progress, result);
boolean calculateMergeinfo =
myVcs.getSvnConfiguration().isShowMergeSourcesInAnnotate() && SvnUtil.checkRepositoryVersion15(myVcs, url);
final MySteppedLogGetter logGetter = new MySteppedLogGetter(
myVcs, ioFile, progress,
myVcs.getFactory(ioFile).createHistoryClient(), endRevision, result,
url, calculateMergeinfo, file.getCharset());
logGetter.go();
final LinkedList<SVNRevision> rp = logGetter.getRevisionPoints();
// TODO: only 2 elements will be in rp and for loop will be executed only once - probably rewrite with Pair
AnnotateClient annotateClient = myVcs.getFactory(ioFile).createAnnotateClient();
for (int i = 0; i < rp.size() - 1; i++) {
annotateClient.annotate(SvnTarget.fromFile(ioFile), rp.get(i + 1), rp.get(i), calculateMergeinfo, getLogClientOptions(myVcs),
annotateHandler);
}
if (rp.get(1).getNumber() > 0) {
result.setFirstRevision(rp.get(1));
}
annotation[0] = result;
}
catch (IOException e) {
exception[0] = new VcsException(e);
}
catch (VcsException e) {
if (e.getCause() instanceof SVNException) {
handleSvnException(ioFile, info, (SVNException)e.getCause(), file, revision, annotation, exception);
}
else {
exception[0] = e;
}
}
};
if (ApplicationManager.getApplication().isDispatchThread()) {
ProgressManager.getInstance().runProcessWithProgressSynchronously(command, SvnBundle.message("action.text.annotate"), false, myVcs.getProject());
ProgressManager.getInstance()
.runProcessWithProgressSynchronously(command, SvnBundle.message("action.text.annotate"), false, myVcs.getProject());
}
else {
command.run();
@@ -179,10 +183,10 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
FileAnnotation[] annotation, VcsException[] exception) {
// TODO: Check how this scenario could be reproduced by user and what changes needs to be done for command line client
if (SVNErrorCode.FS_NOT_FOUND.equals(e.getErrorMessage().getErrorCode())) {
final CommittedChangesProvider<SvnChangeList,ChangeBrowserSettings> provider = myVcs.getCommittedChangesProvider();
final CommittedChangesProvider<SvnChangeList, ChangeBrowserSettings> provider = myVcs.getCommittedChangesProvider();
try {
final Pair<SvnChangeList, FilePath> pair = provider.getOneList(file, revision.getRevisionNumber());
if (pair != null && info != null && pair.getSecond() != null && ! Comparing.equal(pair.getSecond().getIOFile(), ioFile)) {
if (pair != null && info != null && pair.getSecond() != null && !Comparing.equal(pair.getSecond().getIOFile(), ioFile)) {
annotation[0] = annotateNonExisting(pair, revision, info, file.getCharset(), file);
return;
}
@@ -205,19 +209,21 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
final List<String> parts2 = StringUtil.split(can2.getPath(), File.separator, true);
int cnt = 0;
while (parts1.size() > cnt && parts2.size() > cnt) {
if (! parts1.get(cnt).equals(parts2.get(cnt))) {
if (!parts1.get(cnt).equals(parts2.get(cnt))) {
if (cnt > 0) {
return new File(StringUtil.join(parts1.subList(0, cnt), File.separator));
} else {
}
else {
return null;
}
}
++ cnt;
++cnt;
}
//shorter one
if (parts1.size() > parts2.size()) {
return file2;
} else {
}
else {
return file1;
}
}
@@ -225,28 +231,34 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
private SvnRemoteFileAnnotation annotateNonExisting(Pair<SvnChangeList, FilePath> pair,
VcsFileRevision revision,
Info info,
Charset charset, final VirtualFile current) throws VcsException, SVNException, IOException {
Charset charset, final VirtualFile current)
throws VcsException, SVNException, IOException {
final File wasFile = pair.getSecond().getIOFile();
final File root = getCommonAncestor(wasFile, info.getFile());
if (root == null) throw new VcsException("Can not find relative path for " + wasFile.getPath() + "@" + revision.getRevisionNumber().asString());
if (root == null) {
throw new VcsException("Can not find relative path for " + wasFile.getPath() + "@" + revision.getRevisionNumber().asString());
}
final String relativePath = FileUtil.getRelativePath(root.getPath(), wasFile.getPath(), File.separatorChar);
if (relativePath == null) throw new VcsException("Can not find relative path for " + wasFile.getPath() + "@" + revision.getRevisionNumber().asString());
if (relativePath == null) {
throw new VcsException("Can not find relative path for " + wasFile.getPath() + "@" + revision.getRevisionNumber().asString());
}
Info wcRootInfo = myVcs.getInfo(root);
if (wcRootInfo == null || wcRootInfo.getURL() == null) {
throw new VcsException("Can not find relative path for " + wasFile.getPath() + "@" + revision.getRevisionNumber().asString());
throw new VcsException("Can not find relative path for " + wasFile.getPath() + "@" + revision.getRevisionNumber().asString());
}
SVNURL wasUrl = wcRootInfo.getURL();
final String[] strings = relativePath.replace('\\','/').split("/");
final String[] strings = relativePath.replace('\\', '/').split("/");
for (String string : strings) {
wasUrl = wasUrl.appendPath(string, true);
}
final SVNRevision svnRevision = ((SvnRevisionNumber)revision.getRevisionNumber()).getRevision();
byte[] data = SvnUtil.getFileContents(myVcs, SvnTarget.fromURL(wasUrl), svnRevision, svnRevision);
final String contents = LoadTextUtil.getTextByBinaryPresentation(data, charset == null ? CharsetToolkit.UTF8_CHARSET : charset).toString();
final String contents =
LoadTextUtil.getTextByBinaryPresentation(data, charset == null ? CharsetToolkit.UTF8_CHARSET : charset).toString();
final SvnRemoteFileAnnotation result = new SvnRemoteFileAnnotation(myVcs, contents, revision.getRevisionNumber(), current);
final AnnotationConsumer annotateHandler = createAnnotationHandler(ProgressManager.getInstance().getProgressIndicator(), result);
@@ -262,23 +274,19 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
@NotNull
private static AnnotationConsumer createAnnotationHandler(@Nullable final ProgressIndicator progress,
@NotNull final BaseSvnFileAnnotation result) {
return new AnnotationConsumer() {
@Override
public void consume(int lineNumber, @NotNull CommitInfo info, @Nullable CommitInfo mergeInfo) throws SVNException {
if (progress != null) {
progress.checkCanceled();
}
result.setLineInfo(lineNumber, info, mergeInfo != null && info.getRevision() > mergeInfo.getRevision() ? mergeInfo : null);
return (lineNumber, info, mergeInfo) -> {
if (progress != null) {
progress.checkCanceled();
}
result.setLineInfo(lineNumber, info, mergeInfo != null && info.getRevision() > mergeInfo.getRevision() ? mergeInfo : null);
};
}
@Override
public VcsAnnotation createCacheable(FileAnnotation fileAnnotation) {
if (! (fileAnnotation instanceof SvnFileAnnotation)) return null;
final SvnFileAnnotation svnFileAnnotation = (SvnFileAnnotation) fileAnnotation;
if (!(fileAnnotation instanceof SvnFileAnnotation)) return null;
final SvnFileAnnotation svnFileAnnotation = (SvnFileAnnotation)fileAnnotation;
final AnnotationSourceSwitcher annotationSourceSwitcher = svnFileAnnotation.getAnnotationSourceSwitcher();
if (annotationSourceSwitcher != null) {
annotationSourceSwitcher.switchTo(AnnotationSource.LOCAL);
@@ -288,7 +296,7 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
final VcsUsualLineAnnotationData lineAnnotationData = new VcsUsualLineAnnotationData(size);
for (int i = 0; i < size; i++) {
final VcsRevisionNumber revisionNumber = svnFileAnnotation.getLineRevisionNumber(i);
lineAnnotationData.put(i, revisionNumber);
lineAnnotationData.put(i, revisionNumber);
}
final VcsAnnotation vcsAnnotation = new VcsAnnotation(VcsUtil.getFilePath(svnFileAnnotation.getFile()), lineAnnotationData,
@@ -304,10 +312,10 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
final VcsRevisionNumber number = svnFileAnnotation.getLineRevisionNumber(i);
if (number == null) continue;
merged.put(i, number);
addMap.put(number, svnFileAnnotation.getRevision(((SvnRevisionNumber) number).getRevision().getNumber()));
addMap.put(number, svnFileAnnotation.getRevision(((SvnRevisionNumber)number).getRevision().getNumber()));
}
}
if (! merged.isEmpty()) {
if (!merged.isEmpty()) {
vcsAnnotation.addAnnotation(MERGED_KEY, merged);
vcsAnnotation.addCachedOtherRevisions(addMap);
}
@@ -326,7 +334,7 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
new SvnFileAnnotation(myVcs, vcsAnnotation.getFilePath().getVirtualFile(), annotatedContent, revisionNumber);
final VcsLineAnnotationData basicAnnotation = vcsAnnotation.getBasicAnnotation();
final VcsLineAnnotationData data = vcsAnnotation.getAdditionalAnnotations().get(MERGED_KEY);
final Map<VcsRevisionNumber,VcsFileRevision> historyAsMap = session.getHistoryAsMap();
final Map<VcsRevisionNumber, VcsFileRevision> historyAsMap = session.getHistoryAsMap();
final Map<VcsRevisionNumber, VcsFileRevision> cachedOtherRevisions = vcsAnnotation.getCachedOtherRevisions();
for (int i = 0; i < basicAnnotation.getNumLines(); i++) {
@@ -337,17 +345,18 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
if (mergedData == null) {
annotation.setLineInfo(i, fileRevision.getCommitInfo(), null);
} else {
}
else {
final SvnFileRevision mergedRevision = (SvnFileRevision)cachedOtherRevisions.get(mergedData);
if (mergedRevision == null) return null;
annotation.setLineInfo(i, fileRevision.getCommitInfo(), mergedRevision.getCommitInfo());
}
}
if (vcsAnnotation.getFirstRevision() != null) {
annotation.setFirstRevision(((SvnRevisionNumber) vcsAnnotation.getFirstRevision()).getRevision());
annotation.setFirstRevision(((SvnRevisionNumber)vcsAnnotation.getFirstRevision()).getRevision());
}
for (VcsFileRevision revision : session.getRevisionList()) {
annotation.setRevision(((SvnRevisionNumber) revision.getRevisionNumber()).getRevision().getNumber(), (SvnFileRevision)revision);
annotation.setRevision(((SvnRevisionNumber)revision.getRevisionNumber()).getRevision().getNumber(), (SvnFileRevision)revision);
}
return annotation;
}
@@ -387,16 +396,18 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
boolean longHistory = true;
if (maxAnnotateRevisions == -1) {
longHistory = false;
} else {
}
else {
if (myEndRevision.getNumber() < maxAnnotateRevisions) {
longHistory = false;
}
}
if (! longHistory) {
if (!longHistory) {
doLog(myCalculateMergeinfo, null, 0);
putDefaultBounds();
} else {
}
else {
doLog(false, null, 0);
final List<VcsFileRevision> fileRevisionList = myResult.getRevisions();
if (fileRevisionList.size() < maxAnnotateRevisions) {
@@ -407,7 +418,7 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
return;
}
myRevisionPoints.add(((SvnRevisionNumber) fileRevisionList.get(0).getRevisionNumber()).getRevision());
myRevisionPoints.add(((SvnRevisionNumber)fileRevisionList.get(0).getRevisionNumber()).getRevision());
final SVNRevision truncateTo =
((SvnRevisionNumber)fileRevisionList.get(maxAnnotateRevisions - 1).getRevisionNumber()).getRevision();
myRevisionPoints.add(truncateTo);
@@ -427,19 +438,17 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
private void doLog(final boolean includeMerged, final SVNRevision truncateTo, final int max) throws VcsException {
myClient.doLog(SvnTarget.fromFile(myIoFile), myEndRevision, truncateTo == null ? SVNRevision.create(1L) : truncateTo,
false, false, includeMerged, max, null,
new LogEntryConsumer() {
@Override
public void consume(LogEntry logEntry) {
if (SVNRevision.UNDEFINED.getNumber() == logEntry.getRevision()) {
return;
}
if (myProgress != null) {
myProgress.checkCanceled();
myProgress.setText2(SvnBundle.message("progress.text2.revision.processed", logEntry.getRevision()));
}
myResult.setRevision(logEntry.getRevision(), new SvnFileRevision(myVcs, SVNRevision.UNDEFINED, logEntry, myUrl, ""));
logEntry -> {
if (SVNRevision.UNDEFINED.getNumber() == logEntry.getRevision()) {
return;
}
if (myProgress != null) {
myProgress.checkCanceled();
myProgress.setText2(SvnBundle.message("progress.text2.revision.processed", logEntry.getRevision()));
}
myResult
.setRevision(logEntry.getRevision(), new SvnFileRevision(myVcs, SVNRevision.UNDEFINED, logEntry, myUrl, ""));
});
}
@@ -105,13 +105,8 @@ public class AuthenticationService {
if (repositoryUrl != null) {
final String realm = repositoryUrl.toDecodedString();
authentication = requestCredentials(realm, type, new Getter<SVNAuthentication>() {
@Override
public SVNAuthentication get() {
return myConfiguration.getInteractiveManager(myVcs).getInnerProvider()
.requestClientAuthentication(type, repositoryUrl, realm, null, null, true);
}
});
authentication = requestCredentials(realm, type, () -> myConfiguration.getInteractiveManager(myVcs).getInnerProvider()
.requestClientAuthentication(type, repositoryUrl, realm, null, null, true));
}
if (authentication == null) {
@@ -154,30 +149,25 @@ public class AuthenticationService {
public String requestSshCredentials(@NotNull final String realm,
@NotNull final SimpleCredentialsDialog.Mode mode,
@NotNull final String key) {
return requestCredentials(realm, StringUtil.toLowerCase(mode.toString()), new Getter<String>() {
@Override
public String get() {
final Ref<String> answer = new Ref<>();
return requestCredentials(realm, StringUtil.toLowerCase(mode.toString()), () -> {
final Ref<String> answer = new Ref<>();
Runnable command = new Runnable() {
public void run() {
SimpleCredentialsDialog dialog = new SimpleCredentialsDialog(myVcs.getProject());
Runnable command = () -> {
SimpleCredentialsDialog dialog = new SimpleCredentialsDialog(myVcs.getProject());
dialog.setup(mode, realm, key, true);
dialog.setTitle(SvnBundle.message("dialog.title.authentication.required"));
dialog.setSaveEnabled(false);
if (dialog.showAndGet()) {
answer.set(dialog.getPassword());
}
}
};
dialog.setup(mode, realm, key, true);
dialog.setTitle(SvnBundle.message("dialog.title.authentication.required"));
dialog.setSaveEnabled(false);
if (dialog.showAndGet()) {
answer.set(dialog.getPassword());
}
};
// Use ModalityState.any() as currently ssh credentials in terminal mode are requested in the thread that reads output and not in
// the thread that started progress
WaitForProgressToShow.runOrInvokeAndWaitAboveProgress(command, ModalityState.any());
// Use ModalityState.any() as currently ssh credentials in terminal mode are requested in the thread that reads output and not in
// the thread that started progress
WaitForProgressToShow.runOrInvokeAndWaitAboveProgress(command, ModalityState.any());
return answer.get();
}
return answer.get();
});
}
@@ -15,7 +15,6 @@
*/
package org.jetbrains.idea.svn.auth;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.Logger;
@@ -63,7 +62,8 @@ import static com.intellij.util.WaitForProgressToShow.runOrInvokeLaterAboveProgr
/**
* @author alex
*/
public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager implements SvnAuthenticationListener, ISVNAuthenticationManagerExt {
public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager
implements SvnAuthenticationListener, ISVNAuthenticationManagerExt {
private static final Logger LOG = Logger.getInstance(SvnAuthenticationManager.class);
// while Mac storage not working for IDEA, we use this key to check whether to prompt abt plaintext or just store
public static final String SVN_SSH = "svn+ssh";
@@ -104,26 +104,22 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
myPersistentAuthenticationProviderProxy.setProject(myProject);
}
myInteraction = new MySvnAuthenticationInteraction(myProject);
Disposer.register(myProject, new Disposable() {
@Override
public void dispose() {
myVcs = null;
myProject = null;
if (myPersistentAuthenticationProviderProxy != null) {
myPersistentAuthenticationProviderProxy.myProject = null;
((MyKeyringMasterKeyProvider) myPersistentAuthenticationProviderProxy.myISVNGnomeKeyringPasswordProvider).myProject = null;
myPersistentAuthenticationProviderProxy = null;
}
if (myInteraction instanceof MySvnAuthenticationInteraction) {
((MySvnAuthenticationInteraction) myInteraction).myProject = null;
}
if (myConfig != null) {
myConfig.clear();
myConfig = null;
}
myInteraction = null;
Disposer.register(myProject, () -> {
myVcs = null;
myProject = null;
if (myPersistentAuthenticationProviderProxy != null) {
myPersistentAuthenticationProviderProxy.myProject = null;
((MyKeyringMasterKeyProvider)myPersistentAuthenticationProviderProxy.myISVNGnomeKeyringPasswordProvider).myProject = null;
myPersistentAuthenticationProviderProxy = null;
}
if (myInteraction instanceof MySvnAuthenticationInteraction) {
((MySvnAuthenticationInteraction)myInteraction).myProject = null;
}
if (myConfig != null) {
myConfig.clear();
myConfig = null;
}
myInteraction = null;
});
// This is not the same instance as DefaultSVNAuthenticationManager.myProviders[1], but currently
// DefaultSVNAuthenticationManager.CacheAuthenticationProvider uses only its outer class state - so we utilize necessary logic with
@@ -189,7 +185,7 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
SVNAuthentication previousAuth, boolean authMayBeStored) {
final SVNAuthentication authentication =
myDelegate.requestClientAuthentication(kind, url, realm, errorMessage, previousAuth, authMayBeStored);
if (myProject != null && ! myProject.isDisposed()) {
if (myProject != null && !myProject.isDisposed()) {
myProject.getMessageBus().syncPublisher(AUTHENTICATION_PROVIDER_LISTENER)
.requestClientAuthentication(kind, url, realm, errorMessage, previousAuth, authMayBeStored, authentication);
}
@@ -202,7 +198,7 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
Object certificate,
boolean resultMayBeStored) {
final int result = myDelegate.acceptServerAuthentication(url, realm, certificate, resultMayBeStored);
if (myProject != null && ! myProject.isDisposed()) {
if (myProject != null && !myProject.isDisposed()) {
myProject.getMessageBus().syncPublisher(AUTHENTICATION_PROVIDER_LISTENER)
.acceptServerAuthentication(url, realm, certificate, resultMayBeStored, result);
}
@@ -212,14 +208,19 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
public interface ISVNAuthenticationProviderListener {
void requestClientAuthentication(String kind, SVNURL url, String realm, SVNErrorMessage errorMessage,
SVNAuthentication previousAuth, boolean authMayBeStored, SVNAuthentication authentication);
void acceptServerAuthentication(SVNURL url, String realm, Object certificate, boolean resultMayBeStored, @MagicConstant int acceptResult);
SVNAuthentication previousAuth, boolean authMayBeStored, SVNAuthentication authentication);
void acceptServerAuthentication(SVNURL url,
String realm,
Object certificate,
boolean resultMayBeStored,
@MagicConstant int acceptResult);
}
@Override
public void setAuthenticationProvider(ISVNAuthenticationProvider provider) {
ISVNAuthenticationProvider useProvider = provider;
if (! (provider instanceof AuthenticationProviderProxy)) {
if (!(provider instanceof AuthenticationProviderProxy)) {
useProvider = new AuthenticationProviderProxy(provider);
}
myProvider = useProvider;
@@ -234,13 +235,13 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
/**
* Gets authentication provider without looking into thread local storage for providers.
*
* <p>
* TODO:
* Thread local storage is used "for some interaction with SVNKit" and is not always cleared correctly. So some threads contain
* "passive provider" in thread local storage - and getProvider() returns this "passive provider". This occurs, for instance when
* RemoteRevisionsCache is refreshed in background - after its execution, corresponding thread has "passive provider" in thread local
* storage.
*
* <p>
* As a result authentication fails in such cases (at least for command line implementation). To fix this, command line implementation is
* updated not to check thread local storage at all.
*
@@ -305,7 +306,7 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
@Override
public void requested(ProviderType type, SVNURL url, String realm, String kind, boolean canceled) {
if (ProviderType.interactive.equals(type) && (! canceled)) {
if (ProviderType.interactive.equals(type) && (!canceled)) {
ourJustEntered.set(true);
}
myListener.getMulticaster().requested(type, url, realm, kind, canceled);
@@ -347,7 +348,8 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
}
};
ensureListenerCreated();
myDelegate = new DefaultSVNPersistentAuthenticationProvider(authDir, userName, delegatingOptions, getDefaultOptions(), getHostOptionsProvider()) {
myDelegate = new DefaultSVNPersistentAuthenticationProvider(authDir, userName, delegatingOptions, getDefaultOptions(),
getHostOptionsProvider()) {
@Override
protected IPasswordStorage[] createPasswordStorages(DefaultSVNOptions options) {
final IPasswordStorage[] passwordStorages = super.createPasswordStorages(options);
@@ -366,17 +368,18 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
myProject = project;
}
public SVNAuthentication requestClientAuthentication(final String kind, final SVNURL url, final String realm, final SVNErrorMessage errorMessage,
final SVNAuthentication previousAuth, final boolean authMayBeStored) {
public SVNAuthentication requestClientAuthentication(final String kind,
final SVNURL url,
final String realm,
final SVNErrorMessage errorMessage,
final SVNAuthentication previousAuth,
final boolean authMayBeStored) {
try {
return wrapNativeCall(new ThrowableComputable<SVNAuthentication, SVNException>() {
@Override
public SVNAuthentication compute() throws SVNException {
final SVNAuthentication svnAuthentication =
myDelegate.requestClientAuthentication(kind, url, realm, errorMessage, previousAuth, authMayBeStored);
myListener.getMulticaster().requested(ProviderType.persistent, url, realm, kind, svnAuthentication == null);
return svnAuthentication;
}
return wrapNativeCall(() -> {
final SVNAuthentication svnAuthentication =
myDelegate.requestClientAuthentication(kind, url, realm, errorMessage, previousAuth, authMayBeStored);
myListener.getMulticaster().requested(ProviderType.persistent, url, realm, kind, svnAuthentication == null);
return svnAuthentication;
});
}
catch (SVNException e) {
@@ -391,41 +394,39 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
private void actualSavePermissions(String realm, SVNAuthentication auth) {
final String actualKind = auth.getKind();
File dir = new File(myAuthDir, actualKind);
String fileName = SVNFileUtil.computeChecksum(realm);
File authFile = new File(dir, fileName);
File dir = new File(myAuthDir, actualKind);
String fileName = SVNFileUtil.computeChecksum(realm);
File authFile = new File(dir, fileName);
try {
((ISVNPersistentAuthenticationProvider) myDelegate).saveAuthentication(auth, actualKind, realm);
}
catch (SVNException e) {
if (myProject != null) {
ApplicationManager.getApplication().invokeLater(new VcsBalloonProblemNotifier(myProject,
"<b>Problem when storing Subversion credentials:</b>&nbsp;" + e.getMessage(), MessageType.ERROR));
}
}
finally {
// do not make password file readonly
setWriteable(authFile);
}
try {
((ISVNPersistentAuthenticationProvider)myDelegate).saveAuthentication(auth, actualKind, realm);
}
catch (SVNException e) {
if (myProject != null) {
ApplicationManager.getApplication().invokeLater(new VcsBalloonProblemNotifier(myProject,
"<b>Problem when storing Subversion credentials:</b>&nbsp;" +
e.getMessage(), MessageType.ERROR));
}
}
finally {
// do not make password file readonly
setWriteable(authFile);
}
}
public void saveAuthentication(final SVNAuthentication auth, final String kind, final String realm) throws SVNException {
try {
wrapNativeCall(new ThrowableComputable<Void, SVNException>() {
@Override
public Void compute() throws SVNException {
final Boolean fromInteractive = ourJustEntered.get();
ourJustEntered.set(null);
if (! myArtificialSaving && ! Boolean.TRUE.equals(fromInteractive)) {
// not what user entered
return null;
}
myListener.getMulticaster().saveAttemptStarted(ProviderType.persistent, auth.getURL(), realm, auth.getKind());
((ISVNPersistentAuthenticationProvider) myDelegate).saveAuthentication(auth, kind, realm);
myListener.getMulticaster().saveAttemptFinished(ProviderType.persistent, auth.getURL(), realm, auth.getKind());
wrapNativeCall(() -> {
final Boolean fromInteractive = ourJustEntered.get();
ourJustEntered.set(null);
if (!myArtificialSaving && !Boolean.TRUE.equals(fromInteractive)) {
// not what user entered
return null;
}
myListener.getMulticaster().saveAttemptStarted(ProviderType.persistent, auth.getURL(), realm, auth.getKind());
((ISVNPersistentAuthenticationProvider)myDelegate).saveAuthentication(auth, kind, realm);
myListener.getMulticaster().saveAttemptFinished(ProviderType.persistent, auth.getURL(), realm, auth.getKind());
return null;
});
}
catch (SVNException e) {
@@ -437,12 +438,9 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
@Override
public void saveFingerprints(final String realm, final byte[] fingerprints) {
try {
wrapNativeCall(new ThrowableComputable<Void, SVNException>() {
@Override
public Void compute() throws SVNException {
((ISVNPersistentAuthenticationProvider) myDelegate).saveFingerprints(realm, fingerprints);
return null;
}
wrapNativeCall(() -> {
((ISVNPersistentAuthenticationProvider)myDelegate).saveFingerprints(realm, fingerprints);
return null;
});
}
catch (SVNException e) {
@@ -454,12 +452,7 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
@Override
public byte[] loadFingerprints(final String realm) {
try {
return wrapNativeCall(new ThrowableComputable<byte[], SVNException>() {
@Override
public byte[] compute() throws SVNException {
return ((ISVNPersistentAuthenticationProvider) myDelegate).loadFingerprints(realm);
}
});
return wrapNativeCall(() -> ((ISVNPersistentAuthenticationProvider)myDelegate).loadFingerprints(realm));
}
catch (SVNException e) {
LOG.info(e);
@@ -468,8 +461,9 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
}
private final static int maxAttempts = 10;
private void setWriteable(final File file) {
if (! file.exists()) return;
if (!file.exists()) return;
if (file.getParentFile() == null) {
return;
}
@@ -478,8 +472,8 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
try {
final File tempFile = FileUtil.createTempFile(parent, "123", "1", true);
FileUtil.delete(tempFile);
if (! file.renameTo(tempFile)) continue;
if (! file.createNewFile()) continue;
if (!file.renameTo(tempFile)) continue;
if (!file.createNewFile()) continue;
FileUtil.copy(tempFile, file);
FileUtil.delete(tempFile);
return;
@@ -496,7 +490,8 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
myKeyAlgorithm.put(Thread.currentThread(), keyAlgorithm);
try {
super.verifyHostKey(hostName, port, keyAlgorithm, hostKey);
} finally {
}
finally {
myKeyAlgorithm.remove(Thread.currentThread());
}
}
@@ -543,7 +538,8 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
final SVNAuthentication proxy = ProxySvnAuthentication.proxy(authentication, authStorageEnabled, myArtificialSaving);
super.acknowledgeAuthentication(accepted, kind, realm, errorMessage, proxy);
successSaving = true;
} finally {
}
finally {
mySavePermissions.remove();
if (myArtificialSaving) {
myArtificialSaving = false;
@@ -569,7 +565,7 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
}
public void acknowledgeForSSL(boolean accepted, SVNAuthentication proxy) {
if (accepted && proxy instanceof SVNSSLAuthentication && (((SVNSSLAuthentication) proxy).getCertificateFile() != null)) {
if (accepted && proxy instanceof SVNSSLAuthentication && (((SVNSSLAuthentication)proxy).getCertificateFile() != null)) {
final SVNSSLAuthentication svnsslAuthentication = (SVNSSLAuthentication)proxy;
final SVNURL url = svnsslAuthentication.getURL();
@@ -603,7 +599,7 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
// ! use common proxy if it is set
try {
final List<Proxy> proxies = HttpConfigurable.getInstance().getOnlyBySettingsSelector().select(new URI(url.toString()));
if (proxies != null && ! proxies.isEmpty()) {
if (proxies != null && !proxies.isEmpty()) {
for (Proxy proxy : proxies) {
if (HttpConfigurable.isRealProxy(proxy) && Proxy.Type.HTTP.equals(proxy.type())) {
final SocketAddress address = proxy.address();
@@ -624,15 +620,15 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
String proxyExceptions = getServersPropertyIdea(host, "http-proxy-exceptions");
String proxyExceptionsSeparator = ",";
if (proxyExceptions == null) {
proxyExceptions = System.getProperty("http.nonProxyHosts");
proxyExceptionsSeparator = "|";
proxyExceptions = System.getProperty("http.nonProxyHosts");
proxyExceptionsSeparator = "|";
}
if (proxyExceptions != null) {
for(StringTokenizer exceptions = new StringTokenizer(proxyExceptions, proxyExceptionsSeparator); exceptions.hasMoreTokens();) {
String exception = exceptions.nextToken().trim();
if (DefaultSVNOptions.matches(exception, host)) {
return null;
}
for (StringTokenizer exceptions = new StringTokenizer(proxyExceptions, proxyExceptionsSeparator); exceptions.hasMoreTokens(); ) {
String exception = exceptions.nextToken().trim();
if (DefaultSVNOptions.matches(exception, host)) {
return null;
}
}
}
String proxyPort = getServersPropertyIdea(host, HTTP_PROXY_PORT);
@@ -687,41 +683,42 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
}
private static class MySimpleProxyManager implements ISVNProxyManager {
protected String myProxyHost;
private final String myProxyPort;
protected String myProxyUser;
protected String myProxyPassword;
protected String myProxyHost;
private final String myProxyPort;
protected String myProxyUser;
protected String myProxyPassword;
public MySimpleProxyManager(String host, String port, String user, String password) {
myProxyHost = host;
myProxyPort = port == null ? "3128" : port;
myProxyUser = user;
myProxyPassword = password;
}
public MySimpleProxyManager(String host, String port, String user, String password) {
myProxyHost = host;
myProxyPort = port == null ? "3128" : port;
myProxyUser = user;
myProxyPassword = password;
}
public String getProxyHost() {
return myProxyHost;
}
public String getProxyHost() {
return myProxyHost;
}
public int getProxyPort() {
try {
return Integer.parseInt(myProxyPort);
} catch (NumberFormatException nfe) {
//
}
return 3128;
public int getProxyPort() {
try {
return Integer.parseInt(myProxyPort);
}
catch (NumberFormatException nfe) {
//
}
return 3128;
}
public String getProxyUserName() {
return myProxyUser;
}
public String getProxyUserName() {
return myProxyUser;
}
public String getProxyPassword() {
return myProxyPassword;
}
public String getProxyPassword() {
return myProxyPassword;
}
public void acknowledgeProxyContext(boolean accepted, SVNErrorMessage errorMessage) {
}
public void acknowledgeProxyContext(boolean accepted, SVNErrorMessage errorMessage) {
}
}
// 30 seconds
@@ -786,7 +783,7 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
}
}
Map globalProps = serversFile.getProperties("global");
return (String) globalProps.get(name);
return (String)globalProps.get(name);
}
public static boolean checkHostGroup(final String url, final String patterns, final String exceptions) {
@@ -799,15 +796,15 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
}
final String host = svnurl.getHost();
return matches(patterns, host) && (! matches(exceptions, host));
return matches(patterns, host) && (!matches(exceptions, host));
}
private static boolean matches(final String pattern, final String host) {
final StringTokenizer tokenizer = new StringTokenizer(pattern, ",");
while(tokenizer.hasMoreTokens()) {
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
if (DefaultSVNOptions.matches(token, host)) {
return true;
return true;
}
}
return false;
@@ -815,7 +812,7 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
@Nullable
public static String getGroupForHost(final String host, final IdeaSVNConfigFile serversFile) {
final Map<String,ProxyGroup> groups = serversFile.getAllGroups();
final Map<String, ProxyGroup> groups = serversFile.getAllGroups();
for (Map.Entry<String, ProxyGroup> entry : groups.entrySet()) {
if (matchesGroupPattern(host, entry.getValue().getPatterns())) return entry.getKey();
}
@@ -825,19 +822,19 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
// taken from default manager as is
private static String getGroupName(Map groups, String host) {
for (Object o : groups.keySet()) {
final String name = (String) o;
final String pattern = (String) groups.get(name);
final String name = (String)o;
final String pattern = (String)groups.get(name);
if (matchesGroupPattern(host, pattern)) return name;
}
return null;
return null;
}
private static boolean matchesGroupPattern(String host, String pattern) {
for(StringTokenizer tokens = new StringTokenizer(pattern, ","); tokens.hasMoreTokens();) {
String token = tokens.nextToken();
if (DefaultSVNOptions.matches(token, host)) {
return true;
}
for (StringTokenizer tokens = new StringTokenizer(pattern, ","); tokens.hasMoreTokens(); ) {
String token = tokens.nextToken();
if (DefaultSVNOptions.matches(token, host)) {
return true;
}
}
return false;
}
@@ -871,24 +868,28 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
@Override
public void warnOnAuthStorageDisabled(SVNURL url) {
VcsBalloonProblemNotifier.showOverChangesView(myProject, "Cannot store credentials: forbidden by \"store-auth-creds=no\"", MessageType.ERROR);
VcsBalloonProblemNotifier
.showOverChangesView(myProject, "Cannot store credentials: forbidden by \"store-auth-creds=no\"", MessageType.ERROR);
}
@Override
public void warnOnPasswordStorageDisabled(SVNURL url) {
VcsBalloonProblemNotifier.showOverChangesView(myProject, "Cannot store password: forbidden by \"store-passwords=no\"", MessageType.ERROR);
VcsBalloonProblemNotifier
.showOverChangesView(myProject, "Cannot store password: forbidden by \"store-passwords=no\"", MessageType.ERROR);
}
@Override
public void warnOnSSLPassphraseStorageDisabled(SVNURL url) {
VcsBalloonProblemNotifier.showOverChangesView(myProject, "Cannot store passphrase: forbidden by \"store-ssl-client-cert-pp=no\"", MessageType.ERROR);
VcsBalloonProblemNotifier
.showOverChangesView(myProject, "Cannot store passphrase: forbidden by \"store-ssl-client-cert-pp=no\"", MessageType.ERROR);
}
@Override
public boolean promptForPlaintextPasswordSaving(SVNURL url, String realm) {
final int answer = Messages.showYesNoDialog(myProject, String.format("Your password for authentication realm:\n" +
"%s\ncan only be stored to disk unencrypted. Would you like to store it in plaintext?", realm),
"Store the password in plaintext?", Messages.getQuestionIcon());
"%s\ncan only be stored to disk unencrypted. Would you like to store it in plaintext?",
realm),
"Store the password in plaintext?", Messages.getQuestionIcon());
return answer == Messages.YES;
}
@@ -900,9 +901,11 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
@Override
public boolean promptForSSLPlaintextPassphraseSaving(SVNURL url, String realm, File certificateFile, String certificateName) {
final int answer = Messages.showYesNoDialog(myProject,
String.format("Your passphrase for " + certificateName + ":\n%s\ncan only be stored to disk unencrypted. Would you like to store it in plaintext?",
certificateFile.getPath()),
"Store the passphrase in plaintext?", Messages.getQuestionIcon());
String.format("Your passphrase for " +
certificateName +
":\n%s\ncan only be stored to disk unencrypted. Would you like to store it in plaintext?",
certificateFile.getPath()),
"Store the passphrase in plaintext?", Messages.getQuestionIcon());
return answer == Messages.YES;
}
@@ -967,13 +970,8 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
final boolean superValue = super.isStorePlainTextPasswords(realm, auth);
final boolean value = mySavePermissions.allowed() || superValue;
if ((! value) && (! mySavePermissions.have())) {
promptAndSaveWhenWeLackEncryption(realm, auth, new Getter<Boolean>() {
@Override
public Boolean get() {
return myInteraction.promptForPlaintextPasswordSaving(myUrl, realm);
}
});
if ((!value) && (!mySavePermissions.have())) {
promptAndSaveWhenWeLackEncryption(realm, auth, () -> myInteraction.promptForPlaintextPasswordSaving(myUrl, realm));
}
return value;
}
@@ -983,25 +981,24 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
if (USERNAME.equals(auth.getKind())) return true;
final boolean value = mySavePermissions.allowed() || super.isStorePlainTextPassphrases(realm, auth);
if ((! value) && (! mySavePermissions.have())) {
promptAndSaveWhenWeLackEncryption(realm, auth, new Getter<Boolean>() {
@Override
public Boolean get() {
File file = null;
String certificateName = null;
if (auth instanceof SVNSSLAuthentication) {
file = ((SVNSSLAuthentication) auth).getCertificateFile();
certificateName = "client certificate";
} else if (auth instanceof SVNSSHAuthentication) {
file = ((SVNSSHAuthentication) auth).getPrivateKeyFile();
certificateName = "private key file";
} else {
assert false;
}
return myInteraction.promptForSSLPlaintextPassphraseSaving(myUrl, realm,
file, certificateName);
}
});
if ((!value) && (!mySavePermissions.have())) {
promptAndSaveWhenWeLackEncryption(realm, auth, () -> {
File file = null;
String certificateName = null;
if (auth instanceof SVNSSLAuthentication) {
file = ((SVNSSLAuthentication)auth).getCertificateFile();
certificateName = "client certificate";
}
else if (auth instanceof SVNSSHAuthentication) {
file = ((SVNSSHAuthentication)auth).getPrivateKeyFile();
certificateName = "private key file";
}
else {
assert false;
}
return myInteraction.promptForSSLPlaintextPassphraseSaving(myUrl, realm,
file, certificateName);
});
}
return value;
}
@@ -1011,10 +1008,11 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
final boolean value;
if (hasAuthStorageEnabledOption()) {
value = super.isAuthStorageEnabled();
} else {
}
else {
value = isTurned(getConfigFile().getPropertyValue("auth", "store-auth-creds"));
}
if (! value) {
if (!value) {
myInteraction.warnOnAuthStorageDisabled(myUrl);
}
return value;
@@ -1026,11 +1024,12 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
final boolean value;
if (storePasswords != null) {
value = isTurned(storePasswords);
} else {
}
else {
final String configValue = getConfigFile().getPropertyValue("auth", "store-passwords");
value = isTurned(configValue);
}
if (! value) {
if (!value) {
myInteraction.warnOnPasswordStorageDisabled(myUrl);
}
return value;
@@ -1039,7 +1038,7 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
@Override
public boolean isStoreSSLClientCertificatePassphrases() {
final boolean value = super.isStoreSSLClientCertificatePassphrases();
if (! value) {
if (!value) {
myInteraction.warnOnSSLPassphraseStorageDisabled(myUrl);
}
return value;
@@ -1062,16 +1061,13 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
private void promptAndSaveWhenWeLackEncryption(final String realm, final SVNAuthentication auth, final Getter<Boolean> prompt) {
final Boolean[] saveOnce = new Boolean[1];
final Runnable actualSave = new Runnable() {
@Override
public void run() {
mySavePermissions.put(Boolean.TRUE.equals(saveOnce[0]));
try {
myPersistentAuthenticationProviderProxy.actualSavePermissions(realm, auth);
}
finally {
mySavePermissions.remove();
}
final Runnable actualSave = () -> {
mySavePermissions.put(Boolean.TRUE.equals(saveOnce[0]));
try {
myPersistentAuthenticationProviderProxy.actualSavePermissions(realm, auth);
}
finally {
mySavePermissions.remove();
}
};
@@ -1080,7 +1076,8 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
saveOnce[0] = Boolean.TRUE.equals(prompt.get());
ApplicationManager.getApplication().executeOnPooledThread(actualSave);
}, getCurrent(), myProject);
} else {
}
else {
saveOnce[0] = Boolean.TRUE.equals(prompt.get());
actualSave.run();
}
@@ -1152,7 +1149,8 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
LOG.info(sb.toString());
}
return t;
} finally {
}
finally {
NativeLogReader.clear();
NativeLogReader.endTracking();
}
@@ -1170,12 +1168,8 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
final String message = keyringName != null ? SvnBundle.message("gnome.keyring.prompt.named", keyringName)
: SvnBundle.message("gnome.keyring.prompt.nameless");
final Ref<String> result = Ref.create();
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
result.set(Messages.showPasswordDialog(myProject, message, SvnBundle.message("subversion.name"), Messages.getQuestionIcon()));
}
});
UIUtil.invokeAndWaitIfNeeded((Runnable)() -> result
.set(Messages.showPasswordDialog(myProject, message, SvnBundle.message("subversion.name"), Messages.getQuestionIcon())));
return !result.isNull() ? result.get().toCharArray() : null;
}
}
@@ -38,7 +38,6 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.IdeFrame;
import com.intellij.openapi.wm.ex.WindowManagerEx;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.Consumer;
import com.intellij.util.ThreeState;
import com.intellij.util.net.HttpConfigurable;
import com.intellij.util.proxy.CommonProxy;
@@ -62,7 +61,6 @@ import org.tmatesoft.svn.core.wc2.SvnTarget;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.io.FilenameFilter;
import java.net.*;
import java.util.*;
import java.util.List;
@@ -112,22 +110,19 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl<SvnAuthentica
final Ref<Boolean> resultRef = new Ref<>();
final Runnable checker = new Runnable() {
@Override
public void run() {
try {
final boolean result =
interactiveValidation(obj.myProject, obj.getUrl(), obj.getRealm(), obj.getKind());
log("ask result for: " + obj.getUrl() + " is: " + result);
resultRef.set(result);
if (result) {
onStateChangedToSuccess(obj);
}
}
finally {
myVerificationInProgress = false;
final Runnable checker = () -> {
try {
final boolean result =
interactiveValidation(obj.myProject, obj.getUrl(), obj.getRealm(), obj.getKind());
log("ask result for: " + obj.getUrl() + " is: " + result);
resultRef.set(result);
if (result) {
onStateChangedToSuccess(obj);
}
}
finally {
myVerificationInProgress = false;
}
};
final Application application = ApplicationManager.getApplication();
// also do not show auth if thread does not have progress indicator
@@ -173,12 +168,9 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl<SvnAuthentica
}
}
log("on state changed ");
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
for (SVNURL key : outdatedRequests) {
removeLazyNotificationByKey(key);
}
ApplicationManager.getApplication().invokeLater(() -> {
for (SVNURL key : outdatedRequests) {
removeLazyNotificationByKey(key);
}
}, ModalityState.NON_MODAL);
}
@@ -428,35 +420,23 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl<SvnAuthentica
private static void showAuthenticationFailedWithHotFixes(final Project project,
final SvnConfiguration configuration,
final SVNException e) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
VcsBalloonProblemNotifier.showOverChangesView(project, "Authentication failed: " + e.getMessage(), MessageType.ERROR,
new NamedRunnable(
SvnBundle.message("confirmation.title.clear.authentication.cache")) {
@Override
public void run() {
clearAuthenticationCache(project, null, configuration
.getConfigurationDirectory());
}
},
new NamedRunnable(SvnBundle.message("action.title.select.configuration.directory")) {
@Override
public void run() {
SvnConfigurable
.selectConfigurationDirectory(configuration.getConfigurationDirectory(),
new Consumer<String>() {
@Override
public void consume(String s) {
configuration
.setConfigurationDirParameters(false, s);
}
}, project, null);
}
}
);
}
}, ModalityState.NON_MODAL, project.getDisposed());
ApplicationManager.getApplication().invokeLater(() -> VcsBalloonProblemNotifier
.showOverChangesView(project, "Authentication failed: " + e.getMessage(), MessageType.ERROR, new NamedRunnable(
SvnBundle.message("confirmation.title.clear.authentication.cache")) {
@Override
public void run() {
clearAuthenticationCache(project, null, configuration
.getConfigurationDirectory());
}
}, new NamedRunnable(
SvnBundle.message("action.title.select.configuration.directory")) {
@Override
public void run() {
SvnConfigurable.selectConfigurationDirectory(configuration.getConfigurationDirectory(),
s -> configuration.setConfigurationDirParameters(false, s), project, null);
}
}
), ModalityState.NON_MODAL, project.getDisposed());
}
public static void clearAuthenticationCache(@NotNull final Project project, final Component component, final String configDirPath) {
@@ -481,27 +461,19 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl<SvnAuthentica
public static void clearAuthenticationDirectory(@NotNull SvnConfiguration configuration) {
final File authDir = new File(configuration.getConfigurationDirectory(), "auth");
if (authDir.exists()) {
final Runnable process = new Runnable() {
@Override
public void run() {
final ProgressIndicator ind = ProgressManager.getInstance().getProgressIndicator();
if (ind != null) {
ind.setIndeterminate(true);
ind.setText("Clearing stored credentials in " + authDir.getAbsolutePath());
}
final File[] files = authDir.listFiles(new FilenameFilter() {
@Override
public boolean accept(@NotNull File dir, @NotNull String name) {
return ourAuthKinds.contains(name);
}
});
final Runnable process = () -> {
final ProgressIndicator ind = ProgressManager.getInstance().getProgressIndicator();
if (ind != null) {
ind.setIndeterminate(true);
ind.setText("Clearing stored credentials in " + authDir.getAbsolutePath());
}
final File[] files = authDir.listFiles((dir, name) -> ourAuthKinds.contains(name));
for (File dir : files) {
if (ind != null) {
ind.setText("Deleting " + dir.getAbsolutePath());
}
FileUtil.delete(dir);
for (File dir : files) {
if (ind != null) {
ind.setText("Deleting " + dir.getAbsolutePath());
}
FileUtil.delete(dir);
}
};
final Application application = ApplicationManager.getApplication();
@@ -85,14 +85,12 @@ public class SvnInteractiveAuthenticationProvider implements ISVNAuthenticationP
final String userName =
previousAuth != null && previousAuth.getUserName() != null ? previousAuth.getUserName() : myManager.getDefaultUsername(kind, url);
if (ISVNAuthenticationManager.PASSWORD.equals(kind)) {// || ISVNAuthenticationManager.USERNAME.equals(kind)) {
command = new Runnable() {
public void run() {
SimpleCredentialsDialog dialog = new SimpleCredentialsDialog(myProject);
dialog.setup(realm, userName, authCredsOn);
setTitle(dialog, errorMessage);
if (dialog.showAndGet()) {
result[0] = new SVNPasswordAuthentication(dialog.getUserName(), dialog.getPassword(), dialog.isSaveAllowed(), url, false);
}
command = () -> {
SimpleCredentialsDialog dialog = new SimpleCredentialsDialog(myProject);
dialog.setup(realm, userName, authCredsOn);
setTitle(dialog, errorMessage);
if (dialog.showAndGet()) {
result[0] = new SVNPasswordAuthentication(dialog.getUserName(), dialog.getPassword(), dialog.isSaveAllowed(), url, false);
}
};
}
@@ -100,14 +98,12 @@ public class SvnInteractiveAuthenticationProvider implements ISVNAuthenticationP
if (ApplicationManager.getApplication().isUnitTestMode()) {
return new SVNUserNameAuthentication(userName, false);
}
command = new Runnable() {
public void run() {
UserNameCredentialsDialog dialog = new UserNameCredentialsDialog(myProject);
dialog.setup(realm, userName, authCredsOn);
setTitle(dialog, errorMessage);
if (dialog.showAndGet()) {
result[0] = new SVNUserNameAuthentication(dialog.getUserName(), dialog.isSaveAllowed(), url, false);
}
command = () -> {
UserNameCredentialsDialog dialog = new UserNameCredentialsDialog(myProject);
dialog.setup(realm, userName, authCredsOn);
setTitle(dialog, errorMessage);
if (dialog.showAndGet()) {
result[0] = new SVNUserNameAuthentication(dialog.getUserName(), dialog.isSaveAllowed(), url, false);
}
};
}
@@ -117,47 +113,43 @@ public class SvnInteractiveAuthenticationProvider implements ISVNAuthenticationP
final Connector agentConnector = createSshAgentConnector();
final boolean isAgentAvailable = agentConnector != null && agentConnector.isAvailable();
command = new Runnable() {
public void run() {
SSHCredentialsDialog dialog = new SSHCredentialsDialog(myProject, realm, userName, authCredsOn, url.getPort(), isAgentAvailable);
setTitle(dialog, errorMessage);
if (dialog.showAndGet()) {
int port = dialog.getPortNumber();
if (dialog.isSshAgentSelected()) {
if (agentConnector != null) {
result[0] =
new SVNSSHAuthentication(dialog.getUserName(), new TrileadAgentProxy(agentConnector), port, url, false);
}
}
else if (dialog.getKeyFile() != null && dialog.getKeyFile().trim().length() > 0) {
String passphrase = dialog.getPassphrase();
if (passphrase != null && passphrase.length() == 0) {
passphrase = null;
}
command = () -> {
SSHCredentialsDialog dialog = new SSHCredentialsDialog(myProject, realm, userName, authCredsOn, url.getPort(), isAgentAvailable);
setTitle(dialog, errorMessage);
if (dialog.showAndGet()) {
int port = dialog.getPortNumber();
if (dialog.isSshAgentSelected()) {
if (agentConnector != null) {
result[0] =
new SVNSSHAuthentication(dialog.getUserName(), new File(dialog.getKeyFile()), passphrase, port, dialog.isSaveAllowed(), url,
false);
new SVNSSHAuthentication(dialog.getUserName(), new TrileadAgentProxy(agentConnector), port, url, false);
}
else {
result[0] = new SVNSSHAuthentication(dialog.getUserName(), dialog.getPassword(), port, dialog.isSaveAllowed(), url, false);
}
else if (dialog.getKeyFile() != null && dialog.getKeyFile().trim().length() > 0) {
String passphrase = dialog.getPassphrase();
if (passphrase != null && passphrase.length() == 0) {
passphrase = null;
}
result[0] =
new SVNSSHAuthentication(dialog.getUserName(), new File(dialog.getKeyFile()), passphrase, port, dialog.isSaveAllowed(), url,
false);
}
else {
result[0] = new SVNSSHAuthentication(dialog.getUserName(), dialog.getPassword(), port, dialog.isSaveAllowed(), url, false);
}
}
};
} else if (ISVNAuthenticationManager.SSL.equals(kind)) {
command = new Runnable() {
public void run() {
final ISVNHostOptions options = myManager.getHostOptionsProvider().getHostOptions(url);
final String file = options.getSSLClientCertFile();
final SSLCredentialsDialog dialog = new SSLCredentialsDialog(myProject, realm, authCredsOn);
if (!StringUtil.isEmptyOrSpaces(file)) {
dialog.setFile(file);
}
setTitle(dialog, errorMessage);
if (dialog.showAndGet()) {
result[0] = new SVNSSLAuthentication(new File(dialog.getCertificatePath()), String.valueOf(dialog.getCertificatePassword()),
dialog.getSaveAuth(), url, false);
}
command = () -> {
final ISVNHostOptions options = myManager.getHostOptionsProvider().getHostOptions(url);
final String file = options.getSSLClientCertFile();
final SSLCredentialsDialog dialog = new SSLCredentialsDialog(myProject, realm, authCredsOn);
if (!StringUtil.isEmptyOrSpaces(file)) {
dialog.setFile(file);
}
setTitle(dialog, errorMessage);
if (dialog.showAndGet()) {
result[0] = new SVNSSLAuthentication(new File(dialog.getCertificatePath()), String.valueOf(dialog.getCertificatePassword()),
dialog.getSaveAuth(), url, false);
}
};
}
@@ -197,25 +189,20 @@ public class SvnInteractiveAuthenticationProvider implements ISVNAuthenticationP
final int[] result = new int[1];
Runnable command;
if (certificate instanceof X509Certificate || certificate instanceof String) {
command = new Runnable() {
public void run() {
ServerSSLDialog dialog = certificate instanceof X509Certificate
? new ServerSSLDialog(myProject, (X509Certificate)certificate, resultMayBeStored)
: new ServerSSLDialog(myProject, (String)certificate, resultMayBeStored);
dialog.show();
result[0] = dialog.getResult();
}
command = () -> {
ServerSSLDialog dialog = certificate instanceof X509Certificate
? new ServerSSLDialog(myProject, (X509Certificate)certificate, resultMayBeStored)
: new ServerSSLDialog(myProject, (String)certificate, resultMayBeStored);
dialog.show();
result[0] = dialog.getResult();
};
} else if (certificate instanceof byte[]) {
final String sshKeyAlgorithm = myManager.getSSHKeyAlgorithm();
command = new Runnable() {
@Override
public void run() {
final ServerSSHDialog serverSSHDialog =
new ServerSSHDialog(myProject, resultMayBeStored, url.toDecodedString(), sshKeyAlgorithm, (byte[])certificate);
serverSSHDialog.show();
result[0] = serverSSHDialog.getResult();
}
command = () -> {
final ServerSSHDialog serverSSHDialog =
new ServerSSHDialog(myProject, resultMayBeStored, url.toDecodedString(), sshKeyAlgorithm, (byte[])certificate);
serverSSHDialog.show();
result[0] = serverSSHDialog.getResult();
};
} else {
VcsBalloonProblemNotifier.showOverChangesView(myProject, "Subversion: unknown certificate type from " + url.toDecodedString(),
@@ -122,19 +122,16 @@ public class BranchConfigurationDialog extends DialogWrapper {
}
}
})
.setRemoveAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
int selectedIndex = myBranchLocationsList.getSelectedIndex();
for (String url : myBranchLocationsList.getSelectedValuesList()) {
int index = myBranchLocationsModel.getConfiguration().getBranchUrls().indexOf(url);
myBranchLocationsModel.getConfiguration().removeBranch(url);
myBranchLocationsModel.fireItemRemoved(index);
}
if (myBranchLocationsModel.getSize() > 0) {
selectedIndex = min(selectedIndex, myBranchLocationsModel.getSize() - 1);
myBranchLocationsList.setSelectedIndex(selectedIndex);
}
.setRemoveAction(button -> {
int selectedIndex = myBranchLocationsList.getSelectedIndex();
for (String url : myBranchLocationsList.getSelectedValuesList()) {
int index = myBranchLocationsModel.getConfiguration().getBranchUrls().indexOf(url);
myBranchLocationsModel.getConfiguration().removeBranch(url);
myBranchLocationsModel.fireItemRemoved(index);
}
if (myBranchLocationsModel.getSize() > 0) {
selectedIndex = min(selectedIndex, myBranchLocationsModel.getSize() - 1);
myBranchLocationsList.setSelectedIndex(selectedIndex);
}
})
.disableUpDownActions()
@@ -24,7 +24,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.api.Depth;
import org.jetbrains.idea.svn.browse.BrowseClient;
import org.jetbrains.idea.svn.browse.DirectoryEntry;
import org.jetbrains.idea.svn.browse.DirectoryEntryConsumer;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
@@ -93,13 +92,9 @@ public class BranchesLoader implements Runnable {
@NotNull
private static DirectoryEntryConsumer createConsumer(@NotNull final List<SvnBranchItem> result) {
return new DirectoryEntryConsumer() {
@Override
public void consume(final DirectoryEntry entry) throws SVNException {
if (entry.getDate() != null) {
result.add(new SvnBranchItem(entry.getUrl().toDecodedString(), entry.getDate(), entry.getRevision()));
}
return entry -> {
if (entry.getDate() != null) {
result.add(new SvnBranchItem(entry.getUrl().toDecodedString(), entry.getDate(), entry.getRevision()));
}
};
}
@@ -45,11 +45,8 @@ import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.wc.SVNRevision;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
@@ -109,12 +106,10 @@ public class CreateBranchOrTagDialog extends DialogWrapper {
updateControls();
}
});
myRepositoryField.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
SVNURL url = SelectLocationDialog.selectLocation(project, mySrcURL);
if (url != null) {
myRepositoryField.setText(url.toString());
}
myRepositoryField.addActionListener(e -> {
SVNURL url = SelectLocationDialog.selectLocation(project, mySrcURL);
if (url != null) {
myRepositoryField.setText(url.toString());
}
});
myRepositoryField.getTextField().getDocument().addDocumentListener(new DocumentAdapter() {
@@ -122,16 +117,14 @@ public class CreateBranchOrTagDialog extends DialogWrapper {
updateToURL();
}
});
myToURLText.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
String url = myToURLText.getText();
String dstName = SVNPathUtil.tail(mySrcURL);
dstName = SVNEncodingUtil.uriDecode(dstName);
url = SelectLocationDialog.selectCopyDestination(myProject, SVNPathUtil.removeTail(url),
SvnBundle.message("label.copy.select.location.dialog.copy.as"), dstName, false);
if (url != null) {
myToURLText.setText(url);
}
myToURLText.addActionListener(e -> {
String url = myToURLText.getText();
String dstName = SVNPathUtil.tail(mySrcURL);
dstName = SVNEncodingUtil.uriDecode(dstName);
url = SelectLocationDialog.selectCopyDestination(myProject, SVNPathUtil.removeTail(url),
SvnBundle.message("label.copy.select.location.dialog.copy.as"), dstName, false);
if (url != null) {
myToURLText.setText(url);
}
});
@@ -149,25 +142,13 @@ public class CreateBranchOrTagDialog extends DialogWrapper {
myRevisionPanel.setRoot(mySrcVirtualFile);
myRevisionPanel.setProject(myProject);
myRevisionPanel.setUrlProvider(new SvnRevisionPanel.UrlProvider() {
public String getUrl() {
return mySrcURL;
}
});
myRevisionPanel.setUrlProvider(() -> mySrcURL);
updateBranchTagBases();
myRevisionPanel.addChangeListener(new ChangeListener() {
public void stateChanged(final ChangeEvent e) {
getOKAction().setEnabled(isOKActionEnabled());
}
});
myRevisionPanel.addChangeListener(e -> getOKAction().setEnabled(isOKActionEnabled()));
init();
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
updateControls();
}
};
ActionListener listener = e -> updateControls();
myWorkingCopyRadioButton.addActionListener(listener);
myRepositoryRadioButton.addActionListener(listener);
myBranchOrTagRadioButton.addActionListener(listener);
@@ -179,23 +160,15 @@ public class CreateBranchOrTagDialog extends DialogWrapper {
}
});
updateToURL();
myProjectButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
myRepositoryField.setText(myWcRootUrl);
}
myProjectButton.addActionListener(e -> myRepositoryField.setText(myWcRootUrl));
myBranchTagBaseComboBox.addActionListener(e -> {
BranchConfigurationDialog.configureBranches(project, mySrcVirtualFile);
updateBranchTagBases();
updateControls();
});
myBranchTagBaseComboBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
BranchConfigurationDialog.configureBranches(project, mySrcVirtualFile);
updateBranchTagBases();
updateControls();
}
});
myBranchTagBaseComboBox.getComboBox().addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
updateToURL();
updateControls();
}
myBranchTagBaseComboBox.getComboBox().addActionListener(e -> {
updateToURL();
updateControls();
});
}
@@ -27,7 +27,6 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.SvnUtil;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.api.Depth;
import org.jetbrains.idea.svn.browse.DirectoryEntry;
import org.jetbrains.idea.svn.browse.DirectoryEntryConsumer;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
@@ -130,20 +129,16 @@ public class DefaultBranchConfigInitializer implements Runnable {
@NotNull
private static DirectoryEntryConsumer createHandler(@NotNull final SvnBranchConfigurationNew result, @NotNull final SVNURL rootPath) {
return new DirectoryEntryConsumer() {
return entry -> {
if (entry.isDirectory()) {
SVNURL childUrl = rootPath.appendPath(entry.getName(), false);
@Override
public void consume(final DirectoryEntry entry) throws SVNException {
if (entry.isDirectory()) {
SVNURL childUrl = rootPath.appendPath(entry.getName(), false);
if (StringUtil.endsWithIgnoreCase(entry.getName(), DEFAULT_TRUNK_NAME)) {
result.setTrunkUrl(childUrl.toString());
}
else {
result.addBranches(childUrl.toString(),
new InfoStorage<>(new ArrayList<>(0), InfoReliability.defaultValues));
}
if (StringUtil.endsWithIgnoreCase(entry.getName(), DEFAULT_TRUNK_NAME)) {
result.setTrunkUrl(childUrl.toString());
}
else {
result.addBranches(childUrl.toString(),
new InfoStorage<>(new ArrayList<>(0), InfoReliability.defaultValues));
}
}
};
@@ -17,10 +17,10 @@ package org.jetbrains.idea.svn.branchConfig;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.vcs.ProgressManagerQueue;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.CalledInBackground;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.vcs.ProgressManagerQueue;
import org.jetbrains.annotations.CalledInBackground;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.SvnVcs;
@@ -62,12 +62,7 @@ public class NewRootBunch {
}
if (reload && override) {
myBranchesLoader.run(new Runnable() {
@Override
public void run() {
reloadBranches(root, previous, config.getValue());
}
});
myBranchesLoader.run(() -> reloadBranches(root, previous, config.getValue()));
}
}
}
@@ -104,16 +99,11 @@ public class NewRootBunch {
public void reloadBranchesAsync(@NotNull final VirtualFile root,
@NotNull final String branchLocation,
@NotNull final InfoReliability reliability) {
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@Override
public void run() {
reloadBranches(root, branchLocation, reliability, true);
}
});
ApplicationManager.getApplication().executeOnPooledThread(() -> reloadBranches(root, branchLocation, reliability, true));
}
public void reloadBranches(@NotNull VirtualFile root, @Nullable SvnBranchConfigurationNew prev, @NotNull SvnBranchConfigurationNew next) {
final Set<String> oldUrls = (prev == null) ? Collections.<String>emptySet() : new HashSet<>(prev.getBranchUrls());
final Set<String> oldUrls = (prev == null) ? Collections.emptySet() : new HashSet<>(prev.getBranchUrls());
final SvnVcs vcs = SvnVcs.getInstance(myProject);
if (!vcs.isVcsBackgroundOperationsAllowed(root)) return;
@@ -168,25 +168,13 @@ public class SelectBranchPopup {
@Override
public PopupStep onChosen(final String selectedValue, final boolean finalChoice) {
if (CONFIGURE_MESSAGE.equals(selectedValue)) {
return doFinalStep(new Runnable() {
public void run() {
BranchConfigurationDialog.configureBranches(myProject, myVcsRoot);
}
});
return doFinalStep(() -> BranchConfigurationDialog.configureBranches(myProject, myVcsRoot));
}
else if (myTrunkString.equals(selectedValue)) {
return doFinalStep(new Runnable() {
public void run() {
myCallback.branchSelected(myProject, myConfiguration, myConfiguration.getTrunkUrl(), -1);
}
});
return doFinalStep(() -> myCallback.branchSelected(myProject, myConfiguration, myConfiguration.getTrunkUrl(), -1));
}
else if (!myTopLevel || selectedValue.equals(myConfiguration.getTrunkUrl())) {
return doFinalStep(new Runnable() {
public void run() {
myCallback.branchSelected(myProject, myConfiguration, selectedValue, -1);
}
});
return doFinalStep(() -> myCallback.branchSelected(myProject, myConfiguration, selectedValue, -1));
}
else {
showBranchPopup(selectedValue);
@@ -238,35 +226,18 @@ public class SelectBranchPopup {
.setTitle(SVNPathUtil.tail(selectedValue))
.setResizable(true)
//.setDimensionServiceKey("Svn.CompareWithBranchPopup")
.setItemChoosenCallback(new Runnable() {
public void run() {
if (REFRESH_MESSAGE.equals(branchList.getSelectedValue())) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
loadBranches(selectedValue, new Runnable() {
@Override
public void run() {
showBranchPopup(selectedValue);
}
});
}
});
return;
}
SvnBranchItem item = (SvnBranchItem)branchList.getSelectedValue();
if (item != null) {
myCallback.branchSelected(myProject, myConfiguration, item.getUrl(), item.getRevision());
}
.setItemChoosenCallback(() -> {
if (REFRESH_MESSAGE.equals(branchList.getSelectedValue())) {
SwingUtilities.invokeLater(() -> loadBranches(selectedValue, () -> showBranchPopup(selectedValue)));
return;
}
})
.setFilteringEnabled(new NullableFunction<Object, String>() {
@Nullable
@Override
public String fun(Object item) {
return item instanceof SvnBranchItem ? getBranchName((SvnBranchItem)item) : null;
SvnBranchItem item = (SvnBranchItem)branchList.getSelectedValue();
if (item != null) {
myCallback.branchSelected(myProject, myConfiguration, item.getUrl(), item.getRevision());
}
})
.setFilteringEnabled(
(NullableFunction<Object, String>)item -> item instanceof SvnBranchItem ? getBranchName((SvnBranchItem)item) : null)
.createPopup();
showPopupAt(popup);
}
@@ -62,18 +62,11 @@ public class SvnBranchConfigurationManager implements PersistentStateComponent<S
// TODO: for DefaultConfigLoader it would be better to run modal cancellable task - so branches structure could be detected and
// TODO: shown in dialog. Currently when "Configure Branches" is invoked for the first time - no branches are shown.
// TODO: If "Cancel" is pressed and "Configure Branches" invoked once again - already detected (in background) branches are shown.
((ProjectLevelVcsManagerImpl) vcsManager).addInitializationRequest(VcsInitObject.BRANCHES, new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
if (myProject.isDisposed()) return;
myBranchesLoader.start();
}
});
}
});
((ProjectLevelVcsManagerImpl)vcsManager)
.addInitializationRequest(VcsInitObject.BRANCHES, () -> ApplicationManager.getApplication().runReadAction(() -> {
if (myProject.isDisposed()) return;
myBranchesLoader.start();
}));
myBunch = new NewRootBunch(project, myBranchesLoader);
}
@@ -189,22 +182,17 @@ public class SvnBranchConfigurationManager implements PersistentStateComponent<S
}
private void preloadBranches(@NotNull final Collection<Pair<VirtualFile, SvnBranchConfigurationNew>> branchPoints) {
((ProjectLevelVcsManagerImpl) myVcsManager).addInitializationRequest(VcsInitObject.BRANCHES, new Runnable() {
public void run() {
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
public void run() {
try {
for (Pair<VirtualFile, SvnBranchConfigurationNew> pair : branchPoints) {
myBunch.reloadBranches(pair.getFirst(), null, pair.getSecond());
}
}
catch (ProcessCanceledException e) {
//
}
((ProjectLevelVcsManagerImpl)myVcsManager)
.addInitializationRequest(VcsInitObject.BRANCHES, () -> ApplicationManager.getApplication().executeOnPooledThread(() -> {
try {
for (Pair<VirtualFile, SvnBranchConfigurationNew> pair : branchPoints) {
myBunch.reloadBranches(pair.getFirst(), null, pair.getSecond());
}
});
}
});
}
catch (ProcessCanceledException e) {
//
}
}));
}
private List<SvnBranchItem> getStored(String branchUrl) {
@@ -19,7 +19,6 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.ObjectsConvertor;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.Convertor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.SvnUtil;
@@ -64,12 +63,7 @@ public class SvnBranchConfigurationNew {
public List<String> getBranchUrls() {
final ArrayList<String> result = new ArrayList<>(myBranchMap.keySet());
final List<String> cutList = ObjectsConvertor.convert(result, new Convertor<String, String>() {
@Override
public String convert(String s) {
return cutEndSlash(s);
}
});
final List<String> cutList = ObjectsConvertor.convert(result, s -> cutEndSlash(s));
Collections.sort(cutList);
return cutList;
}
@@ -121,12 +121,8 @@ public class IdeaCommitHandler implements CommitEventHandler, ProgressTracker {
private void trackDeletedFile(@NotNull ProgressEvent event) {
@NonNls final String filePath = "file://" + event.getFile().getAbsolutePath().replace(File.separatorChar, '/');
VirtualFile virtualFile = ApplicationManager.getApplication().runReadAction(new Computable<VirtualFile>() {
@Nullable
public VirtualFile compute() {
return VirtualFileManager.getInstance().findFileByUrl(filePath);
}
});
VirtualFile virtualFile = ApplicationManager.getApplication()
.runReadAction((Computable<VirtualFile>)() -> VirtualFileManager.getInstance().findFileByUrl(filePath));
if (virtualFile != null) {
myDeletedFiles.add(virtualFile);
@@ -22,7 +22,6 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vcs.CheckinProjectPanel;
import com.intellij.openapi.vcs.FilePath;
@@ -135,16 +134,8 @@ public class SvnCheckinEnvironment implements CheckinEnvironment {
final Project project = mySvnVcs.getProject();
final String message = SvnBundle.message("status.text.comitted.revision", committedRevisions);
if (feedback == null) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
new VcsBalloonProblemNotifier(project, message, MessageType.INFO).run();
}
}, new Condition<Object>() {
@Override
public boolean value(Object o) {
return (! project.isOpen()) || project.isDisposed();
}
});
ApplicationManager.getApplication().invokeLater(() -> new VcsBalloonProblemNotifier(project, message, MessageType.INFO).run(),
o -> (!project.isOpen()) || project.isDisposed());
} else {
feedback.add("Subversion: " + message);
}
@@ -207,11 +198,9 @@ public class SvnCheckinEnvironment implements CheckinEnvironment {
doCommit(committables, preparedComment, exception, feedback);
}
else if (ApplicationManager.getApplication().isDispatchThread()) {
ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
public void run() {
doCommit(committables, preparedComment, exception, feedback);
}
}, SvnBundle.message("progress.title.commit"), false, mySvnVcs.getProject());
ProgressManager.getInstance().runProcessWithProgressSynchronously(
() -> doCommit(committables, preparedComment, exception, feedback), SvnBundle.message("progress.title.commit"), false,
mySvnVcs.getProject());
}
else {
doCommit(committables, preparedComment, exception, feedback);

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