Merge remote branch 'origin/master'

This commit is contained in:
Evgeny Zakrevsky
2011-11-25 19:19:35 +03:00
67 changed files with 727 additions and 118 deletions
@@ -50,9 +50,9 @@ public class CompilerUIConfigurable implements SearchableConfigurable, Configura
myCbUseCompileServer.setVisible(ApplicationManager.getApplication().isInternal());
myPatternLegendLabel.setText("<html>" +
"Use <b>;</b> to separate patterns and <b>!</b> to negate a pattern.<br/>" +
"Accepted wildcards: <b>?</b> - exactly one symbol; <b>*</b> - zero or more symbols;<br/>" +
"&nbsp;&nbsp;<b>/</b> - path separator; <b>/**/</b> - any number of directories;<br>" +
"&nbsp;&nbsp;<i>resources</i>:* - for everything under a source root named <i>resources</i>" +
"Accepted wildcards: <b>?</b> &mdash; exactly one symbol; <b>*</b> &mdash; zero or more symbols;<br/>" +
"&nbsp;&nbsp;<b>/</b> &mdash; path separator; <b>/**/</b> &mdash; any number of directories;<br>" +
"&nbsp;&nbsp;<i>&lt;dir_name&gt;</i>:&lt;pattern&gt; &mdash; restrict to source roots with the specified name" +
"</html>");
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,75 +15,33 @@
*/
package com.intellij.debugger.actions;
import com.intellij.debugger.DebuggerManagerEx;
import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.engine.RequestHint;
import com.intellij.debugger.engine.SuspendContextImpl;
import com.intellij.debugger.impl.DebuggerContextImpl;
import com.intellij.debugger.impl.DebuggerSession;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.TextEditor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.containers.OrderedSet;
import com.intellij.util.text.CharArrayUtil;
import com.intellij.xdebugger.impl.actions.DebuggerActionHandler;
import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
public class SmartStepIntoActionHandler extends DebuggerActionHandler {
public void perform(@NotNull final Project project, final AnActionEvent event) {
final DebuggerContextImpl debuggerContext = (DebuggerManagerEx.getInstanceEx(project)).getContext();
doStep(project, debuggerContext.getSourcePosition(), debuggerContext.getDebuggerSession());
/**
* User: Alexander Podkhalyuzin
* Date: 22.11.11
*/
public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler {
@Override
public boolean isAvailable(final SourcePosition position) {
final PsiFile file = position.getFile();
return file.getLanguage().isKindOf(JavaLanguage.INSTANCE);
}
private static void doStep(final @NotNull Project project, final @Nullable SourcePosition position, final @NotNull DebuggerSession session) {
final VirtualFile file = position != null ? position.getFile().getVirtualFile() : null;
final FileEditor fileEditor = file != null? FileEditorManager.getInstance(project).getSelectedEditor(file) : null;
if (fileEditor instanceof TextEditor) {
final List<PsiMethod> methods = findReferencedMethods(position);
if (methods.size() > 0) {
if (methods.size() == 1) {
session.stepInto(true, createSmartStepFilter(methods.get(0)));
}
else {
final PsiMethodListPopupStep popupStep = new PsiMethodListPopupStep(methods, new PsiMethodListPopupStep.OnChooseRunnable() {
public void execute(PsiMethod chosenMethod) {
session.stepInto(true, createSmartStepFilter(chosenMethod));
}
});
final ListPopup popup = JBPopupFactory.getInstance().createListPopup(popupStep);
final RelativePoint point = DebuggerUIUtil.calcPopupLocation(((TextEditor)fileEditor).getEditor(), position.getLine());
popup.show(point);
}
return;
}
}
session.stepInto(true, null);
}
@Nullable
private static RequestHint.SmartStepFilter createSmartStepFilter(final PsiMethod method) {
return new RequestHint.SmartStepFilter(method);
}
private static List<PsiMethod> findReferencedMethods(final SourcePosition position) {
@Override
public List<PsiMethod> findReferencedMethods(final SourcePosition position) {
final int line = position.getLine();
if (line < 0) {
return Collections.emptyList(); // the document has been changed
@@ -95,8 +53,9 @@ public class SmartStepIntoActionHandler extends DebuggerActionHandler {
// the file is not physical
return Collections.emptyList();
}
final Document doc = FileDocumentManager.getInstance().getDocument(vFile);
if (doc == null) return Collections.emptyList();
if (line >= doc.getLineCount()) {
return Collections.emptyList(); // the document has been changed
}
@@ -144,13 +103,4 @@ public class SmartStepIntoActionHandler extends DebuggerActionHandler {
}
return Collections.emptyList();
}
public boolean isEnabled(@NotNull final Project project, final AnActionEvent event) {
final DebuggerContextImpl context = (DebuggerManagerEx.getInstanceEx(project)).getContext();
DebuggerSession debuggerSession = context.getDebuggerSession();
final boolean isPaused = debuggerSession != null && debuggerSession.isPaused();
final SuspendContextImpl suspendContext = context.getSuspendContext();
final boolean hasCurrentThread = suspendContext != null && suspendContext.getThread() != null;
return isPaused && hasCurrentThread;
}
}
@@ -0,0 +1,74 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.debugger.actions;
import com.intellij.debugger.DebuggerManagerEx;
import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.engine.RequestHint;
import com.intellij.debugger.engine.SuspendContextImpl;
import com.intellij.debugger.impl.DebuggerContextImpl;
import com.intellij.debugger.impl.DebuggerSession;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.TextEditor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.containers.OrderedSet;
import com.intellij.util.text.CharArrayUtil;
import com.intellij.xdebugger.impl.actions.DebuggerActionHandler;
import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
public class JvmSmartStepIntoActionHandler extends DebuggerActionHandler {
public void perform(@NotNull final Project project, final AnActionEvent event) {
final DebuggerContextImpl debuggerContext = (DebuggerManagerEx.getInstanceEx(project)).getContext();
doStep(project, debuggerContext.getSourcePosition(), debuggerContext.getDebuggerSession());
}
private static void doStep(final @NotNull Project project, final @Nullable SourcePosition position, final @NotNull DebuggerSession session) {
final VirtualFile file = position != null ? position.getFile().getVirtualFile() : null;
final FileEditor fileEditor = file != null? FileEditorManager.getInstance(project).getSelectedEditor(file) : null;
if (fileEditor instanceof TextEditor) {
for (JvmSmartStepIntoHandler handler : Extensions.getExtensions(JvmSmartStepIntoHandler.EP_NAME)) {
if (handler.isAvailable(position) && handler.doSmartStep(position, session, (TextEditor)fileEditor)) return;
}
}
session.stepInto(true, null);
}
public boolean isEnabled(@NotNull final Project project, final AnActionEvent event) {
final DebuggerContextImpl context = (DebuggerManagerEx.getInstanceEx(project)).getContext();
DebuggerSession debuggerSession = context.getDebuggerSession();
final boolean isPaused = debuggerSession != null && debuggerSession.isPaused();
final SuspendContextImpl suspendContext = context.getSuspendContext();
final boolean hasCurrentThread = suspendContext != null && suspendContext.getThread() != null;
return isPaused && hasCurrentThread;
}
}
@@ -0,0 +1,79 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.debugger.actions;
import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.engine.RequestHint;
import com.intellij.debugger.impl.DebuggerSession;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.fileEditor.TextEditor;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.psi.PsiMethod;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* User: Alexander Podkhalyuzin
* Date: 22.11.11
*/
public abstract class JvmSmartStepIntoHandler {
public static ExtensionPointName<JvmSmartStepIntoHandler> EP_NAME = ExtensionPointName.create("com.intellij.debugger.jvmSmartStepIntoHandler");
public abstract List<PsiMethod> findReferencedMethods(SourcePosition position);
public abstract boolean isAvailable(SourcePosition position);
/**
* Override this if you haven't PsiMethod, like in Kotlin.
* @param position
* @param session
* @param fileEditor
* @return false to continue for another handler or for default action (step into)
*/
public boolean doSmartStep(SourcePosition position, final DebuggerSession session, TextEditor fileEditor) {
final List<PsiMethod> methods = findReferencedMethods(position);
if (methods.size() > 0) {
if (methods.size() == 1) {
session.stepInto(true, getSmartStepFilter(methods.get(0)));
}
else {
final PsiMethodListPopupStep popupStep = new PsiMethodListPopupStep(methods, new PsiMethodListPopupStep.OnChooseRunnable() {
public void execute(PsiMethod chosenMethod) {
session.stepInto(true, getSmartStepFilter(chosenMethod));
}
});
final ListPopup popup = JBPopupFactory.getInstance().createListPopup(popupStep);
final RelativePoint point = DebuggerUIUtil.calcPopupLocation(((TextEditor)fileEditor).getEditor(), position.getLine());
popup.show(point);
}
return true;
}
return false;
}
/**
* Override in case if your JVMNames slightly different then it can be provided by getJvmSignature method.
* @param method
* @return SmartStepFilter
*/
protected RequestHint.SmartStepFilter getSmartStepFilter(PsiMethod method) {
return new RequestHint.SmartStepFilter(method);
}
}
@@ -64,7 +64,7 @@ public class JavaDebuggerSupport extends DebuggerSupport {
private final QuickEvaluateActionHandler myQuickEvaluateHandler = new QuickEvaluateActionHandler();
private final JavaDebuggerSettingsPanelProvider myDebuggerSettingsPanelProvider = new JavaDebuggerSettingsPanelProvider();
private final MuteBreakpointsActionHandler myMuteBreakpointsHandler = new MuteBreakpointsActionHandler();
private final DebuggerActionHandler mySmartStepIntoHandler = new SmartStepIntoActionHandler();
private final DebuggerActionHandler mySmartStepIntoHandler = new JvmSmartStepIntoActionHandler();
private final DebuggerActionHandler myAddToWatchedActionHandler = new AddToWatchActionHandler();
private JavaMarkObjectActionHandler myMarkObjectActionHandler = new JavaMarkObjectActionHandler();
@@ -140,7 +140,7 @@ public class RootsDetectionStep extends AbstractStepWithProgress<List<DetectedRo
final Set<String> selectedTypes = new HashSet<String>();
for (DetectedRootData rootData : myDetectedRootsChooser.getMarkedElements()) {
for (ProjectStructureDetector detector : rootData.getSelectedDetectors()) {
selectedTypes.add(detector.getClass().getName());
selectedTypes.add(detector.getDetectorId());
}
}
mySequence.setTypes(selectedTypes);
@@ -68,7 +68,7 @@ public abstract class CreateFromSourcesMode extends WizardMode {
sequence.addCommonStep(new RootsDetectionStep(projectBuilder, context, sequence, icon, "reference.dialogs.new.project.fromCode.source"));
for (ProjectStructureDetector detector : ProjectStructureDetector.EP_NAME.getExtensions()) {
for (ModuleWizardStep step : detector.createWizardSteps(projectBuilder, projectBuilder.getProjectDescriptor(detector), icon)) {
sequence.addSpecificStep(detector.getClass().getName(), step);
sequence.addSpecificStep(detector.getDetectorId(), step);
}
}
@@ -52,6 +52,11 @@ public abstract class JavaSourceRootDetector extends ProjectStructureDetector {
return DirectoryProcessingResult.PROCESS_CHILDREN;
}
@Override
public String getDetectorId() {
return "Java";
}
@NotNull
protected abstract String getLanguageName();
@@ -68,6 +68,10 @@ public abstract class ProjectStructureDetector {
return Collections.emptyList();
}
public String getDetectorId() {
return getClass().getName();
}
/**
* Setup modules and libraries for the selected roots
*/
@@ -19,7 +19,8 @@ import com.intellij.codeInsight.AutoPopupController;
import com.intellij.codeInsight.ExpectedTypeInfo;
import com.intellij.codeInsight.ExpectedTypesProvider;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
import com.intellij.diagnostic.LogMessageEx;
import com.intellij.diagnostic.errordialog.Attachment;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
@@ -105,11 +106,8 @@ class JavaClassNameInsertHandler implements InsertHandler<JavaPsiClassReferenceE
String docText = context.getDocument().getText();
DefaultInsertHandler.addImportForItem(context, item);
if (context.getTailOffset() < 0) {
if (ApplicationManagerEx.getApplicationEx().isInternal()) {
LOG.error("Tail offset degraded: " + context.getStartOffset() + "; " + docText);
} else {
LOG.error("Tail offset degraded after insertion");
}
LOG.error(LogMessageEx.createEvent("Tail offset degraded after insertion", "start=" + context.getStartOffset(),
new Attachment(context.getFile().getViewProvider().getVirtualFile().getPath(), docText)));
}
@@ -173,6 +173,13 @@ public class JavaCompletionUtil {
public static boolean isInExcludedPackage(@NotNull final PsiMember member) {
final String name = StaticImportMethodFix.getMemberQualifiedName(member);
if (name == null) return false;
if (!member.hasModifierProperty(PsiModifier.STATIC)) {
if (member instanceof PsiMethod || member instanceof PsiField || member instanceof PsiClass && member.getContainingClass() != null) {
return false;
}
}
CodeInsightSettings cis = CodeInsightSettings.getInstance();
for (String excluded : cis.EXCLUDED_PACKAGES) {
if (name.equals(excluded) || name.startsWith(excluded + ".")) {
@@ -987,6 +987,7 @@ public class TemplateState implements Disposable {
for (TemplateOptionalProcessor optionalProcessor : Extensions.getExtensions(TemplateOptionalProcessor.EP_NAME)) {
optionalProcessor.processText(myProject, myTemplate, myDocument, myTemplateRange, myEditor);
}
PsiDocumentManager.getInstance(myProject).doPostponedOperationsAndUnblockDocument(myDocument);
// for Python, we need to indent the template even if reformatting is enabled, because otherwise indents would be broken
// and reformat wouldn't be able to fix them
if (myTemplate.isToIndent()) {
@@ -41,16 +41,7 @@ class NavBarBorder implements Border {
g.setColor(new Color(0, 0, 0, 50));
g.drawLine(x, y + 1, x + width, y + 1);
} else if (NavBarRootPaneExtension.runToolbarExists()) {
g.setColor(new Color(0, 0, 0, 50));
g.drawLine(x, y, x + width, y);
}
if (!UISettings.getInstance().SHOW_MAIN_TOOLBAR && NavBarRootPaneExtension.runToolbarExists()) {
g.drawLine(x + width - 1, y + 1, x + width - 1, y + height - 2);
g.drawLine(x, y + height - 1, x + width - 1, y + height - 1);
}
}
public Insets getBorderInsets(final Component c) {
@@ -77,7 +77,8 @@ public abstract class AbstractNavBarUI implements NavBarUI {
@Override
public void doPaintNavBarItem(Graphics2D g, NavBarItem item, NavBarPanel navbar) {
final boolean floating = navbar.isInFloatingMode();
boolean toolbar = UISettings.getInstance().SHOW_MAIN_TOOLBAR;
Icon icon = item.getIcon();
int w = item.getWidth();
int h = item.getHeight();
@@ -106,7 +107,7 @@ public abstract class AbstractNavBarUI implements NavBarUI {
endShape.lineTo(w, h / 2);
endShape.closePath();
if (bg != null) {
if (bg != null && toolbar) {
g2.setPaint(bg);
g2.fill(shape);
if (!item.isLastElement() || floating) {
@@ -115,17 +116,52 @@ public abstract class AbstractNavBarUI implements NavBarUI {
}
if (selected) {
Path2D.Double focusShape = new Path2D.Double();
if (toolbar || floating) {
focusShape.moveTo(w-getDecorationOffset(), 0);
} else {
focusShape.moveTo(0, 0);
focusShape.lineTo(w - getDecorationOffset(), 0);
}
focusShape.lineTo(w - 1, h / 2);
focusShape.lineTo(w - getDecorationOffset(), h - 1);
if (!toolbar && !floating) {
focusShape.lineTo(0, h - 1);
}
g2.setColor(selection);
if (floating && item.isLastElement()) {
g2.fillRect(0, 0, w, h);
} else {
g2.fill(shape);
g2.setColor(new Color(0, 0, 0, 70));
g2.draw(focusShape);
}
}
if (item.isNextSelected() && navbar.hasFocus()) {
g2.setColor(selection);
g2.fill(endShape);
Path2D.Double endFocusShape = new Path2D.Double();
if (toolbar || floating) {
endFocusShape.moveTo(w - getDecorationOffset(), 0);
} else {
endFocusShape.moveTo(w, 0);
endFocusShape.lineTo(w - getDecorationOffset(), 0);
}
endFocusShape.lineTo(w - 1, h / 2);
endFocusShape.lineTo(w - getDecorationOffset(), h - 1);
if (!toolbar && !floating) {
endFocusShape.lineTo(w, h - 1);
}
g2.setColor(new Color(0, 0, 0, 70));
g2.draw(endFocusShape);
}
final int offset = item.isFirstElement() ? getFirstElementLeftOffset() : 0;
@@ -138,20 +174,50 @@ public abstract class AbstractNavBarUI implements NavBarUI {
int off = getDecorationOffset() - 1;
if (!floating || !item.isLastElement()) {
g2.setColor(new Color(0, 0, 0, 70));
g2.drawLine(0, 0, off, h / 2 - 1);
g2.drawLine(off, h / 2 - 1, 0, h);
}
if (!selected && !floating) {
g2.translate(-1, 0);
g2.setColor(new SameColor(205));
g2.drawLine(0, 0, off, h / 2 - 1);
g2.drawLine(off, h / 2 - 1, 0, h);
if (toolbar || floating) {
if (!selected && (!navbar.hasFocus() | !item.isNextSelected())) {
drawArrow(g2, new Color(0, 0, 0, 70), new SameColor(205), off, h, !selected && !floating, false);
}
} else {
if (!selected && (!navbar.hasFocus() | !item.isNextSelected())) {
drawArrow(g2, new Color(0, 0, 0, 150), new Color(255, 255, 255, 200), off, h, !selected && !floating, true);
}
}
}
g2.dispose();
}
private static void drawArrow(Graphics2D g2d, Color c, Color light, int decorationOffset, int h, boolean highlight, boolean gradient) {
int off = decorationOffset - 1;
g2d.setColor(c);
if (gradient) {
g2d.setPaint(new GradientPaint(0, 0, new Color(c.getRed(), c.getGreen(), c.getBlue(), 10), 0, h / 2, c));
}
g2d.drawLine(0, 0, off, h / 2);
if (gradient) {
g2d.setPaint(new GradientPaint(0, h / 2, c, 0, h, new Color(c.getRed(), c.getGreen(), c.getBlue(), 10)));
}
g2d.drawLine(off, h / 2, 0, h);
if (highlight) {
g2d.translate(-1, 0);
g2d.setColor(light);
if (gradient) {
g2d.setPaint(new GradientPaint(0, 0, new Color(light.getRed(), light.getGreen(), light.getBlue(), 10), 0, h / 2, light));
}
g2d.drawLine(0, 0, off, h / 2);
if (gradient) {
g2d.setPaint(new GradientPaint(0, h / 2, light, 0, h, new Color(light.getRed(), light.getGreen(), light.getBlue(), 10)));
}
g2d.drawLine(off, h / 2, 0, h);
}
}
private int getDecorationOffset() {
return 8;
@@ -187,6 +253,8 @@ public abstract class AbstractNavBarUI implements NavBarUI {
@Override
public void doPaintNavBarPanel(Graphics2D g, Rectangle r, boolean mainToolbarVisible, boolean undocked) {
g.setColor(getBackgroundColor());
g.fillRect(0, 0, r.width, r.height);
if (mainToolbarVisible) {
g.fillRect(0, 0, r.width, r.height);
}
}
}
@@ -1178,8 +1178,14 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar {
setBorder(new EmptyBorder(0, 0, 0, 0));
setOpaque(false);
} else {
if (isInsideNavBar()) {
setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2));
}
else {
setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
}
setMinimumButtonSize(DEFAULT_MINIMUM_BUTTON_SIZE);
setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
setOpaque(true);
setLayoutPolicy(AUTO_LAYOUT_POLICY);
}
@@ -42,7 +42,6 @@ import com.intellij.ui.Gray;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.docking.DockManager;
import com.intellij.ui.tabs.JBTabs;
import com.intellij.ui.tabs.impl.JBTabsImpl;
import com.intellij.util.Alarm;
import com.intellij.util.ArrayUtil;
import com.intellij.util.PairFunction;
@@ -148,14 +147,19 @@ public class EditorsSplitters extends JPanel {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (myCurrentWindow == null || myCurrentWindow.getFiles().length == 0) {
g.setColor(new Color(0, 0, 0, 50));
g.drawLine(0, 0, getWidth(), 0);
}
if (showEmptyText()) {
final boolean darkerColors = UIUtil.isUnderAquaLookAndFeel() || UIUtil.isUnderGTKLookAndFeel();
UIUtil.applyRenderingHints(g);
g.setColor(darkerColors ? Gray._100 : Color.LIGHT_GRAY);
g.setColor(darkerColors ? Gray._100 : Color.DARK_GRAY);
g.setFont(UIUtil.getLabelFont().deriveFont(18f));
final UIUtil.TextPainter painter = new UIUtil.TextPainter(1.4f);
painter.appendLine("No files are open").underlined(darkerColors ? Gray._150 : Color.LIGHT_GRAY)
painter.appendLine("No files are open").underlined(darkerColors ? Gray._150 : Color.DARK_GRAY)
.appendLine("Open Project View with " + KeymapUtil.getShortcutText(new KeyboardShortcut(
KeyStroke.getKeyStroke((SystemInfo.isMac ? "meta" : "alt") + " 1"), null))).smaller().withBullet()
.appendLine("Open Recent files with " + getActionShortcutText("RecentFiles")).smaller().withBullet()
@@ -0,0 +1,66 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package git4idea.repo;
import org.jetbrains.annotations.NotNull;
/**
* @author Kirill Likhodedov
*/
public class GitBranchTrackInfo {
private final String myBranch;
private final GitRemote myRemote;
private final String myRemoteBranch;
private final boolean myMerge;
GitBranchTrackInfo(@NotNull String branch, @NotNull GitRemote remote, @NotNull String remoteBranch, boolean merge) {
myBranch = branch;
myMerge = merge;
myRemoteBranch = remoteBranch;
myRemote = remote;
}
@Override
public String toString() {
return String.format("%s %s %s %b", myBranch, myRemote, myRemoteBranch, myMerge);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GitBranchTrackInfo that = (GitBranchTrackInfo)o;
if (myMerge != that.myMerge) return false;
if (myBranch != null ? !myBranch.equals(that.myBranch) : that.myBranch != null) return false;
if (myRemote != null ? !myRemote.equals(that.myRemote) : that.myRemote != null) return false;
if (myRemoteBranch != null ? !myRemoteBranch.equals(that.myRemoteBranch) : that.myRemoteBranch != null) return false;
return true;
}
@Override
public int hashCode() {
int result = myBranch != null ? myBranch.hashCode() : 0;
result = 31 * result + (myRemote != null ? myRemote.hashCode() : 0);
result = 31 * result + (myRemoteBranch != null ? myRemoteBranch.hashCode() : 0);
result = 31 * result + (myMerge ? 1 : 0);
return result;
}
}
@@ -18,6 +18,7 @@ package git4idea.repo;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
import org.ini4j.Ini;
import org.ini4j.Profile;
import org.jetbrains.annotations.NotNull;
@@ -52,11 +53,14 @@ class GitConfig {
private static final Pattern REMOTE_SECTION = Pattern.compile("remote \"(.*)\"");
private static final Pattern URL_SECTION = Pattern.compile("url \"(.*)\"");
private static final Pattern BRANCH_SECTION = Pattern.compile("branch \"(.*)\"");
private final Collection<GitRemote> myRemotes;
private final Collection<GitBranchTrackInfo> myBranchTrackInfos;
private GitConfig(Collection<GitRemote> remotes) {
private GitConfig(Collection<GitRemote> remotes, @NotNull Collection<GitBranchTrackInfo> branchTrackInfos) {
myRemotes = remotes;
myBranchTrackInfos = branchTrackInfos;
}
/**
@@ -75,10 +79,19 @@ class GitConfig {
* </p>
* @return Git remotes defined in {@code .git/config}.
*/
@NotNull
Collection<GitRemote> getRemotes() {
return myRemotes;
}
/**
* @return branch tracking information defined in {@code .git/config}.
*/
@NotNull
public Collection<GitBranchTrackInfo> getBranchTrackInfos() {
return myBranchTrackInfos;
}
/**
* Creates an instance of GitConfig by reading information from the specified {@code .git/config} file.
* @param configFile
@@ -102,6 +115,76 @@ class GitConfig {
IdeaPluginDescriptor plugin = PluginManager.getPlugin(PluginManager.getPluginByClassName(GitConfig.class.getName()));
ClassLoader classLoader = plugin == null ? null : plugin.getPluginClassLoader(); // null if IDEA is started from IDEA
Collection<GitRemote> gitRemotes = parseRemotes(ini, classLoader);
Collection<GitBranchTrackInfo> trackedInfos = parseTrackedInfos(ini, classLoader, gitRemotes);
return new GitConfig(gitRemotes, trackedInfos);
}
private static Collection<GitBranchTrackInfo> parseTrackedInfos(Ini ini, ClassLoader classLoader, Collection<GitRemote> remotes) {
Collection<GitBranchTrackInfo> branchTrackInfos = new ArrayList<GitBranchTrackInfo>();
for (Map.Entry<String, Profile.Section> stringSectionEntry : ini.entrySet()) {
String sectionName = stringSectionEntry.getKey();
Profile.Section section = stringSectionEntry.getValue();
if (sectionName.startsWith("branch")) {
BranchConfig branchConfig = parseBranchSection(sectionName, section, classLoader);
GitBranchTrackInfo branchTrackInfo = convertBranchConfig(branchConfig, remotes);
if (branchTrackInfo != null) {
branchTrackInfos.add(branchTrackInfo);
}
}
}
return branchTrackInfos;
}
@Nullable
private static GitBranchTrackInfo convertBranchConfig(@Nullable BranchConfig branchConfig, @NotNull Collection<GitRemote> remotes) {
if (branchConfig == null) {
return null;
}
String branchName = branchConfig.getName();
String remoteName = branchConfig.getBean().getRemote();
String mergeName = branchConfig.getBean().getMerge();
String rebaseName = branchConfig.getBean().getRebase();
if (StringUtil.isEmptyOrSpaces(mergeName) && StringUtil.isEmptyOrSpaces(rebaseName)) {
LOG.info("No branch." + branchName + ".merge/rebase item in the .git/config");
return null;
}
if (StringUtil.isEmptyOrSpaces(remoteName)) {
LOG.info("No branch." + branchName + ".remote item in the .git/config");
return null;
}
boolean merge = mergeName != null;
String remoteBranch = (merge ? mergeName : rebaseName);
GitRemote branchRemote = null;
for (GitRemote remote : remotes) {
if (remote.getName().equals(remoteName)) {
branchRemote = remote;
break;
}
}
if (branchRemote == null) {
LOG.info("No remote found with name " + remoteName);
return null;
}
return new GitBranchTrackInfo(branchName, branchRemote, remoteBranch, merge);
}
@Nullable
private static BranchConfig parseBranchSection(String sectionName, Profile.Section section, ClassLoader classLoader) {
BranchBean branchBean = section.as(BranchBean.class, classLoader);
Matcher matcher = BRANCH_SECTION.matcher(sectionName);
if (matcher.matches()) {
return new BranchConfig(matcher.group(1), branchBean);
}
LOG.error(String.format("Invalid branch section format in .git/config. sectionName: %s section: %s", sectionName, section));
return null;
}
private static Collection<GitRemote> parseRemotes(Ini ini, ClassLoader classLoader) {
Collection<Remote> remotes = new ArrayList<Remote>();
Collection<Url> urls = new ArrayList<Url>();
for (Map.Entry<String, Profile.Section> stringSectionEntry : ini.entrySet()) {
@@ -122,9 +205,7 @@ class GitConfig {
}
}
Collection<GitRemote> gitRemotes = makeGitRemotes(remotes, urls);
return new GitConfig(gitRemotes);
return makeGitRemotes(remotes, urls);
}
// populate GitRemotes with substituting urls when needed
@@ -345,6 +426,30 @@ class GitConfig {
@Nullable String getInsteadOf();
@Nullable String getPushInsteadOf();
}
private static class BranchConfig {
private final String myName;
private final BranchBean myBean;
public BranchConfig(String name, BranchBean bean) {
myName = name;
myBean = bean;
}
public String getName() {
return myName;
}
public BranchBean getBean() {
return myBean;
}
}
private interface BranchBean {
@Nullable String getRemote();
@Nullable String getMerge();
@Nullable String getRebase();
}
@NotNull
private static String notNull(@Nullable String s) {
@@ -0,0 +1,6 @@
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
@@ -0,0 +1 @@
b0 No branches
@@ -0,0 +1,14 @@
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
[remote "origin"]
fetch = +refs/heads/*:refs/remotes/origin/*
url = /Users/loki/temp/parent.git
[branch "unexistant_remote"]
remote = unexistant
merge = refs/heads/master
[branch "no_merge_item"]
remote = origin
@@ -0,0 +1,2 @@
b1 No valid branches
One with incorrect remote, other without merge/rebase item
@@ -0,0 +1,12 @@
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
[remote "origin"]
fetch = +refs/heads/*:refs/remotes/origin/*
url = git@git.labs.intellij.net:idea/community
[branch "master"]
remote = origin
merge = refs/heads/master
@@ -0,0 +1 @@
b2 One branch
@@ -0,0 +1,6 @@
BRANCH
master
origin git@git.labs.intellij.net:idea/community git@git.labs.intellij.net:idea/community +refs/heads/*:refs/remotes/origin/* +refs/heads/*:refs/remotes/origin/*
refs/heads/master
origin/master
merge
@@ -0,0 +1,20 @@
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
[remote "origin"]
fetch = +refs/heads/*:refs/remotes/origin/*
url = git@git.labs.intellij.net:idea/community
[remote "github"]
fetch = +refs/heads/*:refs/remotes/github/*
url = https://github.com/JetBrains/intellij-community.git
[branch "master"]
remote = origin
merge = refs/heads/master
[branch "github_feature"]
remote = github
rebase = refs/heads/feature
@@ -0,0 +1,2 @@
b3 Two different branches
Two valid branches with 2 remotes. One merge, second rebase.
@@ -0,0 +1,12 @@
BRANCH
master
origin git@git.labs.intellij.net:idea/community git@git.labs.intellij.net:idea/community +refs/heads/*:refs/remotes/origin/* +refs/heads/*:refs/remotes/origin/*
refs/heads/master
origin/master
merge
BRANCH
github_feature
github https://github.com/JetBrains/intellij-community.git https://github.com/JetBrains/intellij-community.git +refs/heads/*:refs/remotes/github/* +refs/heads/*:refs/remotes/github/*
refs/heads/feature
github/feature
rebase
@@ -0,0 +1,13 @@
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
[remote "origin"]
fetch = +refs/heads/*:refs/remotes/origin/*
url = git@git.labs.intellij.net:idea/community
[branch "master"]
remote = origin
merge = refs/heads/master
rebase = refs/heads/master
@@ -0,0 +1,2 @@
b4 Branch with both merge and rebase
Then only merge is taken into consideration.
@@ -0,0 +1,6 @@
BRANCH
master
origin git@git.labs.intellij.net:idea/community git@git.labs.intellij.net:idea/community +refs/heads/*:refs/remotes/origin/* +refs/heads/*:refs/remotes/origin/*
refs/heads/master
origin/master
merge
@@ -23,6 +23,7 @@ import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.*;
@@ -33,11 +34,25 @@ import static org.testng.Assert.assertNotNull;
*/
public class GitConfigTest {
@DataProvider(name = "provider")
public Object[][] loadData() throws IOException {
@DataProvider(name = "remote")
public Object[][] loadRemotes() throws IOException {
return loadData("remote");
}
@DataProvider(name = "branch")
public Object[][] loadBranches() throws IOException {
return loadData("branch");
}
public static Object[][] loadData(String subfolder) throws IOException {
File pluginRoot = new File(PluginPathManager.getPluginHomePath("git4idea"));
File dataDir = new File(new File(pluginRoot, "testData"), "config");
File[] tests = dataDir.listFiles();
File dataDir = new File(new File(new File(pluginRoot, "testData"), "config"), subfolder);
File[] tests = dataDir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return !name.startsWith(".");
}
});
Object[][] data = new Object[tests.length][];
for (int i = 0; i < tests.length; i++) {
File testDir = tests[i];
@@ -67,13 +82,44 @@ public class GitConfigTest {
return data;
}
@Test(dataProvider = "provider")
public void test(String testName, File configFile, File resultFile) throws IOException {
@Test(dataProvider = "remote")
public void testRemotes(String testName, File configFile, File resultFile) throws IOException {
GitConfig config = GitConfig.read(configFile);
GitTestUtil.assertEqualCollections(config.getRemotes(), readResults(resultFile));
GitTestUtil.assertEqualCollections(config.getRemotes(), readRemoteResults(resultFile));
}
private static Set<GitRemote> readResults(File resultFile) throws IOException {
@Test(dataProvider = "branch")
public void testBranches(String testName, File configFile, File resultFile) throws IOException {
GitConfig config = GitConfig.read(configFile);
GitTestUtil.assertEqualCollections(config.getBranchTrackInfos(), readBranchResults(resultFile));
}
private static Collection<GitBranchTrackInfo> readBranchResults(File file) throws IOException {
String content = FileUtil.loadFile(file);
Collection<GitBranchTrackInfo> remotes = new ArrayList<GitBranchTrackInfo>();
String[] remStrings = content.split("BRANCH\n");
for (String remString : remStrings) {
if (StringUtil.isEmptyOrSpaces(remString)) {
continue;
}
String[] info = remString.split("\n");
String branch = info[0];
GitRemote remote = getRemote(info[1]);
String remoteSpec = info[2];
String remoteBranchName = info[3];
boolean merge = info[4].equals("merge");
remotes.add(new GitBranchTrackInfo(branch, remote, remoteSpec, merge));
}
return remotes;
}
private static GitRemote getRemote(String remoteString) {
String[] remoteInfo = remoteString.split(" ");
return new GitRemote(getOrEmpty(remoteInfo, 0), Collections.singletonList(getOrEmpty(remoteInfo, 1)),
Collections.singletonList(getOrEmpty(remoteInfo, 2)), getOrEmpty(remoteInfo, 3), getOrEmpty(remoteInfo, 4));
}
private static Set<GitRemote> readRemoteResults(File resultFile) throws IOException {
String content = FileUtil.loadFile(resultFile);
Set<GitRemote> remotes = new HashSet<GitRemote>();
String[] remStrings = content.split("REMOTE\n");
@@ -15,10 +15,17 @@
*/
package org.jetbrains.plugins.groovy;
import com.intellij.ide.util.projectWizard.importSources.JavaSourceRootDetectionUtil;
import com.intellij.ide.util.projectWizard.importSources.JavaSourceRootDetector;
import com.intellij.lexer.Lexer;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.NullableFunction;
import com.intellij.util.StringBuilderSpinAllocator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyLexer;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.lexer.TokenSets;
/**
* @author nik
@@ -41,9 +48,47 @@ public class GroovySourceRootDetector extends JavaSourceRootDetector {
return new NullableFunction<CharSequence, String>() {
@Override
public String fun(CharSequence charSequence) {
//todo[nik] implement groovy-specific package name parsing?
return JavaSourceRootDetectionUtil.getPackageName(charSequence);
return getPackageName(charSequence);
}
};
}
@Nullable
public static String getPackageName(CharSequence text) {
Lexer lexer = new GroovyLexer();
lexer.start(text);
skipWhitespacesAndComments(lexer);
final IElementType firstToken = lexer.getTokenType();
if (firstToken != GroovyTokenTypes.kPACKAGE) {
return "";
}
lexer.advance();
skipWhitespacesAndComments(lexer);
final StringBuilder buffer = StringBuilderSpinAllocator.alloc();
try {
while(true){
if (lexer.getTokenType() != GroovyTokenTypes.mIDENT) break;
buffer.append(text, lexer.getTokenStart(), lexer.getTokenEnd());
lexer.advance();
skipWhitespacesAndComments(lexer);
if (lexer.getTokenType() != GroovyTokenTypes.mDOT) break;
buffer.append('.');
lexer.advance();
skipWhitespacesAndComments(lexer);
}
String packageName = buffer.toString();
if (packageName.length() == 0 || StringUtil.endsWithChar(packageName, '.')) return null;
return packageName;
}
finally {
StringBuilderSpinAllocator.dispose(buffer);
}
}
private static void skipWhitespacesAndComments(Lexer lexer) {
while(TokenSets.ALL_COMMENT_TOKENS.contains(lexer.getTokenType()) || TokenSets.WHITE_SPACES_SET.contains(lexer.getTokenType())) {
lexer.advance();
}
}
}
@@ -0,0 +1,60 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.ide
import junit.framework.TestCase
import org.jetbrains.plugins.groovy.GroovySourceRootDetector
/**
* @author nik
*/
class GroovySourceRootDetectorTest extends TestCase {
public void testEmpty() {
doTest("", "")
}
public void testComment() {
doTest("//comment", "")
doTest(" /* comment */", "")
}
public void testStatement() {
doTest("def a = 0;", "")
}
public void testSimplePackage() {
doTest("package simple", "simple")
doTest("package simple;", "simple")
doTest("""//comment
package simple;""", "simple")
}
public void testComplexPackage() {
doTest("package com.simple", "com.simple")
doTest("package com.simple;", "com.simple")
doTest("""
package com.simple;""", "com.simple")
doTest("""/**
@author nik;
*/
package com.simple;""", "com.simple")
}
def doTest(String text, String expectedPackageName) {
assertEquals(expectedPackageName, GroovySourceRootDetector.getPackageName(text))
}
}
+3
View File
@@ -89,6 +89,8 @@
<extensionPoint name="debugger.positionManagerFactory"
interface="com.intellij.debugger.PositionManagerFactory"
area="IDEA_PROJECT"/>
<extensionPoint name="debugger.jvmSmartStepIntoHandler"
interface="com.intellij.debugger.actions.JvmSmartStepIntoHandler"/>
<extensionPoint name="allOverridingMethodsSearch" interface="com.intellij.util.QueryExecutor"/>
<extensionPoint name="annotatedElementsSearch" interface="com.intellij.util.QueryExecutor"/>
@@ -1160,6 +1162,7 @@
<debugger.breakpointFactory implementation="com.intellij.debugger.ui.breakpoints.AnyExceptionBreakpointFactory"/>
<debugger.breakpointFactory implementation="com.intellij.debugger.ui.breakpoints.FieldBreakpointFactory"/>
<debugger.breakpointFactory implementation="com.intellij.debugger.ui.breakpoints.MethodBreakpointFactory"/>
<debugger.jvmSmartStepIntoHandler implementation="com.intellij.debugger.actions.JavaSmartStepIntoHandler"/>
<dom.uiControlsProvider implementation="com.intellij.util.xml.impl.JavaDomApplicationComponent"/>