From 1b40be5b1dfe64cc86035528c355f1d20434ec28 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Mon, 19 Jan 2015 13:22:57 +0100 Subject: [PATCH 01/77] revert my previous temp fix 0c90cc01992c2c3a19391c5199a9f85eeae7dac2 --- .../editorActions/CompletionAutoPopupHandler.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java index 0c618e515248..8010e76335bb 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java @@ -32,8 +32,6 @@ import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiPlainText; -import com.intellij.psi.PsiPlainTextFile; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import org.jetbrains.annotations.NotNull; @@ -67,9 +65,7 @@ public class CompletionAutoPopupHandler extends TypedHandlerDelegate { return Result.STOP; } - if ((Character.isLetter(charTyped) || charTyped == '_') && - !(file instanceof PsiPlainTextFile) // todo [maxim, peter] why we start autopopup when editing text files ? it cancels find preview - ) { + if (Character.isLetter(charTyped) || charTyped == '_') { AutoPopupController.getInstance(project).scheduleAutoPopup(editor); return Result.STOP; } From 4d457b8f270273bd09655040c3c890f75aeb1403 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Mon, 19 Jan 2015 14:07:05 +0100 Subject: [PATCH 02/77] [performance optimization] avoid calling VirtualFile.getPath() for files that doesn't have "scratches" as parent file name --- .../com/intellij/ide/scratch/ScratchFileServiceImpl.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/ide/scratch/ScratchFileServiceImpl.java b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchFileServiceImpl.java index 5352b24cb5ec..e2e264a8e86c 100644 --- a/platform/lang-impl/src/com/intellij/ide/scratch/ScratchFileServiceImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchFileServiceImpl.java @@ -36,7 +36,9 @@ import com.intellij.openapi.fileTypes.*; import com.intellij.openapi.fileTypes.ex.FileTypeIdentifiableByVirtualFile; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Iconable; +import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.ThrowableComputable; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; @@ -305,8 +307,13 @@ public abstract class ScratchFileServiceImpl extends ScratchFileService { } private static boolean isFileInRootImpl(@NotNull VirtualFile file, RootId scratches) { + // files are created under scratches.getId() directory, quickly check parent name to avoid calling getPath() + VirtualFile parent = file.getParent(); + if (parent == null) return false; + if (!Comparing.equal(parent.getNameSequence(), scratches.getId(), SystemInfo.isFileSystemCaseSensitive)) return false; + String rootPath = ScratchFileService.getInstance().getRootPath(scratches); - return file.getPath().startsWith(rootPath); + return FileUtil.startsWith(file.getPath(), rootPath); } private static class MyFileType extends LanguageFileType implements FileTypeIdentifiableByVirtualFile, InternalFileType { From 89335d7a78bfd18297acdee3ccbbc50d383ac84f Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Mon, 19 Jan 2015 16:51:04 +0100 Subject: [PATCH 03/77] smartly restart find in file on write action --- .../com/intellij/find/impl/FindDialog.java | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java b/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java index 6db6bfe0e4db..25f1e631ca9e 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java @@ -61,6 +61,7 @@ import com.intellij.ui.table.JBTable; import com.intellij.usageView.UsageInfo; import com.intellij.usages.*; import com.intellij.usages.impl.UsagePreviewPanel; +import com.intellij.util.Alarm; import com.intellij.util.ArrayUtil; import com.intellij.util.Consumer; import com.intellij.util.Processor; @@ -128,6 +129,7 @@ public class FindDialog extends DialogWrapper { private JBTable myResultsPreviewTable; private UsagePreviewPanel myUsagePreviewPanel; private TabbedPane myContent; + private Alarm mySearchRescheduleOnCancellationsAlarm; private volatile ProgressIndicatorBase myResultsPreviewSearchProgress; public FindDialog(@NotNull Project project, @NotNull FindModel model, @NotNull Consumer myOkHandler){ @@ -176,6 +178,7 @@ public class FindDialog extends DialogWrapper { @Override protected void dispose() { finishPreviousPreviewSearch(); + if (mySearchRescheduleOnCancellationsAlarm != null) Disposer.dispose(mySearchRescheduleOnCancellationsAlarm); if (myUsagePreviewPanel != null) Disposer.dispose(myUsagePreviewPanel); for(Map.Entry e: myComboBoxListeners.entrySet()) { e.getKey().removeDocumentListener(e.getValue()); @@ -324,6 +327,7 @@ public class FindDialog extends DialogWrapper { if (state == ModalityState.NON_MODAL) return; // skip initial changes finishPreviousPreviewSearch(); + mySearchRescheduleOnCancellationsAlarm.cancelAllRequests(); final DefaultTableModel model = new DefaultTableModel() { @Override public boolean isCellEditable(int row, int column) { @@ -337,7 +341,6 @@ public class FindDialog extends DialogWrapper { applyTo(modelClone, false); ValidationInfo result = getValidationInfo(modelClone); - if (result != null) return; // todo final PsiDirectory psiDirectory = FindInProjectUtil.getPsiDirectory(modelClone, myProject); @@ -345,6 +348,12 @@ public class FindDialog extends DialogWrapper { myResultsPreviewSearchProgress = progressIndicatorWhenSearchStarted; myResultsPreviewTable.setModel(model); + + if (result != null) { + myResultsPreviewTable.getEmptyText().setText(UIBundle.message("message.nothingToShow")); + return; + } + myResultsPreviewTable.getColumnModel().getColumn(0).setCellRenderer(new UsageTableCellRenderer()); myResultsPreviewTable.getEmptyText().setText("Searching..."); @@ -375,7 +384,7 @@ public class FindDialog extends DialogWrapper { return resultsCount.incrementAndGet() < ShowUsagesAction.USAGES_PAGE_SIZE; } }, processPresentation); - if (resultsCount.get() == 0) { + if (resultsCount.get() == 0 && !progressIndicatorWhenSearchStarted.isCanceled()) { ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { @@ -389,8 +398,14 @@ public class FindDialog extends DialogWrapper { @Override public void onCanceled(@NotNull ProgressIndicator indicator) { - if (progressIndicatorWhenSearchStarted == myResultsPreviewSearchProgress && resultsCount.get() == 0) { - myResultsPreviewTable.getEmptyText().setText("Cancelled"); + if (isShowing() && progressIndicatorWhenSearchStarted == myResultsPreviewSearchProgress) { + mySearchRescheduleOnCancellationsAlarm.cancelAllRequests(); + mySearchRescheduleOnCancellationsAlarm.addRequest(new Runnable() { + @Override + public void run() { + findSettingsChanged(); + } + }, 100); } } }); @@ -513,6 +528,7 @@ public class FindDialog extends DialogWrapper { } } }); + mySearchRescheduleOnCancellationsAlarm = new Alarm(); previewSplitter.setFirstComponent(new JBScrollPane(myResultsPreviewTable)); previewSplitter.setSecondComponent(myUsagePreviewPanel.createComponent()); myPreviewSplitter = previewSplitter; From f7b4d9724dc2ad1b6c1335a43085be33f04c0bcc Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Mon, 19 Jan 2015 16:53:13 +0100 Subject: [PATCH 04/77] introduced getVirtualFilesWithWord: same as getFilesWithWord but without PsiFile --- .../com/intellij/psi/impl/cache/CacheManager.java | 4 ++++ .../psi/impl/cache/impl/IndexCacheManagerImpl.java | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/cache/CacheManager.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/CacheManager.java index e403f60c8777..fb4a272361dc 100644 --- a/platform/indexing-impl/src/com/intellij/psi/impl/cache/CacheManager.java +++ b/platform/indexing-impl/src/com/intellij/psi/impl/cache/CacheManager.java @@ -18,6 +18,7 @@ package com.intellij.psi.impl.cache; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.UsageSearchContext; @@ -38,6 +39,9 @@ public interface CacheManager { @NotNull PsiFile[] getFilesWithWord(@NotNull String word, short occurenceMask, @NotNull GlobalSearchScope scope, final boolean caseSensitively); + @NotNull + VirtualFile[] getVirtualFilesWithWord(@NotNull String word, short occurenceMask, @NotNull GlobalSearchScope scope, final boolean caseSensitively); + boolean processFilesWithWord(@NotNull Processor processor, @NotNull String word, @MagicConstant(flagsFromClass = UsageSearchContext.class) short occurenceMask, diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/IndexCacheManagerImpl.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/IndexCacheManagerImpl.java index 1a44cf491b54..d2027575121a 100644 --- a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/IndexCacheManagerImpl.java +++ b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/IndexCacheManagerImpl.java @@ -65,6 +65,18 @@ public class IndexCacheManagerImpl implements CacheManager{ return processor.getResults().isEmpty() ? PsiFile.EMPTY_ARRAY : processor.toArray(PsiFile.EMPTY_ARRAY); } + @Override + @NotNull + public VirtualFile[] getVirtualFilesWithWord(@NotNull final String word, final short occurenceMask, @NotNull final GlobalSearchScope scope, final boolean caseSensitively) { + if (myProject.isDefault()) { + return VirtualFile.EMPTY_ARRAY; + } + + final List vFiles = new ArrayList(5); + collectVirtualFilesWithWord(new CommonProcessors.CollectProcessor(vFiles), word, occurenceMask, scope, caseSensitively); + return vFiles.isEmpty() ? VirtualFile.EMPTY_ARRAY : vFiles.toArray(new VirtualFile[vFiles.size()]); + } + // IMPORTANT!!! // Since implementation of virtualFileProcessor.process() may call indices directly or indirectly, // we cannot call it inside FileBasedIndex.processValues() method except in collecting form From aa915b2f7d274c1d1aa37978f3051179550694ce Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Mon, 19 Jan 2015 17:43:24 +0100 Subject: [PATCH 05/77] javadoc for javadoc psi --- .../intellij/psi/javadoc/PsiDocComment.java | 22 +++++++++++++- .../com/intellij/psi/javadoc/PsiDocTag.java | 29 +++++++++++++++++-- .../com/intellij/psi/javadoc/PsiDocToken.java | 7 ++++- .../intellij/psi/javadoc/PsiInlineDocTag.java | 5 +++- 4 files changed, 58 insertions(+), 5 deletions(-) diff --git a/java/java-psi-api/src/com/intellij/psi/javadoc/PsiDocComment.java b/java/java-psi-api/src/com/intellij/psi/javadoc/PsiDocComment.java index 081d0ce90206..b727ec7f3806 100644 --- a/java/java-psi-api/src/com/intellij/psi/javadoc/PsiDocComment.java +++ b/java/java-psi-api/src/com/intellij/psi/javadoc/PsiDocComment.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -23,20 +23,40 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +/** + * Represents a JavaDoc comment. + */ public interface PsiDocComment extends PsiComment, PsiDocCommentBase { + /** + * Returns the class, method or field described by the comment. + */ @Override @Nullable PsiDocCommentOwner getOwner(); + /** + * Returns the PSI elements containing the description of the element being documented + * (all significant tokens up to the first doc comment tag). + */ @NotNull PsiElement[] getDescriptionElements(); + /** + * Returns the list of JavaDoc tags in the comment. + */ @NotNull PsiDocTag[] getTags(); + /** + * Finds the first JavaDoc tag with the specified name. + * @return the tag with the specified name, or null if not found. + */ @Nullable PsiDocTag findTagByName(@NonNls String name); + /** + * Finds all JavaDoc tags with the specified name. + */ @NotNull PsiDocTag[] findTagsByName(@NonNls String name); } \ No newline at end of file diff --git a/java/java-psi-api/src/com/intellij/psi/javadoc/PsiDocTag.java b/java/java-psi-api/src/com/intellij/psi/javadoc/PsiDocTag.java index f2dfe9165036..6ae7d1321ebb 100644 --- a/java/java-psi-api/src/com/intellij/psi/javadoc/PsiDocTag.java +++ b/java/java-psi-api/src/com/intellij/psi/javadoc/PsiDocTag.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -22,13 +22,38 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public interface PsiDocTag extends PsiElement, PsiNamedElement{ +/** + * Represents a JavaDoc tag (either an inline tag or a block tag). + */ +public interface PsiDocTag extends PsiElement, PsiNamedElement { PsiDocTag[] EMPTY_ARRAY = new PsiDocTag[0]; + /** + * Returns the doc comment in which the tag is conained. + */ PsiDocComment getContainingComment(); + + /** + * Returns the token representing the name of this JavaDoc tag. + */ PsiElement getNameElement(); + + /** + * Returns the name of this JavaDoc tag. + */ @Override @NonNls @NotNull String getName(); + + /** + * Returns the list of all elements representing the contents of a tag. + */ PsiElement[] getDataElements(); + + /** + * Returns the element specifying what exactly is being documented by this tag + * (for example, the parameter name for a param tag or the exception name for a throws tag). + * + * @return the element, or null if the tag structure does not include such an element. + */ @Nullable PsiDocTagValue getValueElement(); } \ No newline at end of file diff --git a/java/java-psi-api/src/com/intellij/psi/javadoc/PsiDocToken.java b/java/java-psi-api/src/com/intellij/psi/javadoc/PsiDocToken.java index c515bbd58d79..f44565286d81 100644 --- a/java/java-psi-api/src/com/intellij/psi/javadoc/PsiDocToken.java +++ b/java/java-psi-api/src/com/intellij/psi/javadoc/PsiDocToken.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -19,8 +19,13 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; /** + * Represents a token inside a JavaDoc comment. + * * @author Mike */ public interface PsiDocToken extends PsiElement { + /** + * Returns the element type of this token. + */ IElementType getTokenType(); } diff --git a/java/java-psi-api/src/com/intellij/psi/javadoc/PsiInlineDocTag.java b/java/java-psi-api/src/com/intellij/psi/javadoc/PsiInlineDocTag.java index 535868cc0b1c..b22b44bd4cf3 100644 --- a/java/java-psi-api/src/com/intellij/psi/javadoc/PsiInlineDocTag.java +++ b/java/java-psi-api/src/com/intellij/psi/javadoc/PsiInlineDocTag.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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,5 +15,8 @@ */ package com.intellij.psi.javadoc; +/** + * Represents an inline JavaDoc tag. + */ public interface PsiInlineDocTag extends PsiDocTag { } \ No newline at end of file From a3fe80e2d1820dbc2294c90c0b2af01177a4b75d Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 19 Jan 2015 17:11:51 +0100 Subject: [PATCH 06/77] API to select UI elements the same way as speed search would do --- .../template/impl/TemplateListPanel.java | 16 ++-------------- .../ui/speedSearch/SpeedSearchSupply.java | 6 ++++++ .../src/com/intellij/ui/SpeedSearchBase.java | 7 ++++++- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateListPanel.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateListPanel.java index d310851b8965..24efa6e9dd93 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateListPanel.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateListPanel.java @@ -33,6 +33,7 @@ import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.EmptyRunnable; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.*; +import com.intellij.ui.speedSearch.SpeedSearchSupply; import com.intellij.util.Alarm; import com.intellij.util.NullableFunction; import com.intellij.util.ObjectUtils; @@ -947,20 +948,7 @@ public class TemplateListPanel extends JPanel implements Disposable { } void selectNode(@NotNull String searchQuery) { - for (TemplateGroup group : myTemplateGroups) { - for (TemplateImpl template : group.getElements()) { - if (StringUtil.startsWithIgnoreCase(template.getKey(), searchQuery)) { - selectTemplate(group.getName(), template.getKey()); - return; - } - } - } - for (TemplateGroup group : myTemplateGroups) { - if (StringUtil.startsWithIgnoreCase(group.getName(), searchQuery)) { - selectTemplate(group.getName(), null); - return; - } - } + ObjectUtils.assertNotNull(SpeedSearchSupply.getSupply(myTree, true)).findAndSelectElement(searchQuery); } private void selectTemplate(@Nullable final String groupName, @Nullable final String templateKey) { diff --git a/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchSupply.java b/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchSupply.java index 736c4db0b677..75ffa534737e 100644 --- a/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchSupply.java +++ b/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchSupply.java @@ -80,4 +80,10 @@ public abstract class SpeedSearchSupply { public abstract void addChangeListener(@NotNull PropertyChangeListener listener); public abstract void removeChangeListener(@NotNull PropertyChangeListener listener); + + /** + * Find an element matching the searching query in the underlying component and select it there. Speed-search popup is not affected. + * @param searchQuery text that the selected element should match + */ + public abstract void findAndSelectElement(@NotNull String searchQuery); } diff --git a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java index 6ee1ded56642..7170e20b9d7f 100644 --- a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java +++ b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java @@ -338,6 +338,11 @@ public abstract class SpeedSearchBase extends SpeedSear if ( mySearchPopup != null ) mySearchPopup.refreshSelection(); } + @Override + public void findAndSelectElement(@NotNull String searchQuery) { + selectElement(findElement(searchQuery), searchQuery); + } + private class SearchPopup extends JPanel { private final SearchField mySearchField; @@ -425,7 +430,7 @@ public abstract class SpeedSearchBase extends SpeedSear } public void refreshSelection () { - updateSelection(findElement(mySearchField.getText())); + findAndSelectElement(mySearchField.getText()); } private void updateSelection(Object element) { From b8ab7e2bc79b742dd48bcca79abcc5745fc45944 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 19 Jan 2015 17:14:13 +0100 Subject: [PATCH 07/77] IDEA-117143 quick search in settings does not search in "Notifications" --- ...tificationSearchableOptionContributor.java | 32 +++++++++++++++++++ .../impl/NotificationsConfigurable.java | 10 ++++-- .../ui/NotificationsConfigurablePanel.java | 6 ++++ .../src/META-INF/PlatformExtensions.xml | 1 + 4 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 platform/platform-impl/src/com/intellij/notification/impl/NotificationSearchableOptionContributor.java diff --git a/platform/platform-impl/src/com/intellij/notification/impl/NotificationSearchableOptionContributor.java b/platform/platform-impl/src/com/intellij/notification/impl/NotificationSearchableOptionContributor.java new file mode 100644 index 000000000000..b08890a14d61 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/notification/impl/NotificationSearchableOptionContributor.java @@ -0,0 +1,32 @@ +/* + * Copyright 2000-2015 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.notification.impl; + +import com.intellij.ide.ui.search.SearchableOptionContributor; +import com.intellij.ide.ui.search.SearchableOptionProcessor; +import org.jetbrains.annotations.NotNull; + +/** + * @author peter + */ +public class NotificationSearchableOptionContributor extends SearchableOptionContributor { + @Override + public void processOptions(@NotNull SearchableOptionProcessor processor) { + for (NotificationSettings settings : NotificationsConfigurationImpl.getInstanceImpl().getAllSettings()) { + processor.addOptions(settings.getGroupId(), null, settings.getGroupId() + " notifications", NotificationsConfigurable.ID, NotificationsConfigurable.DISPLAY_NAME, true); + } + } +} diff --git a/platform/platform-impl/src/com/intellij/notification/impl/NotificationsConfigurable.java b/platform/platform-impl/src/com/intellij/notification/impl/NotificationsConfigurable.java index 17f6f42cb4df..99871d163225 100644 --- a/platform/platform-impl/src/com/intellij/notification/impl/NotificationsConfigurable.java +++ b/platform/platform-impl/src/com/intellij/notification/impl/NotificationsConfigurable.java @@ -30,6 +30,7 @@ import javax.swing.*; */ public class NotificationsConfigurable implements Configurable, SearchableConfigurable, Configurable.NoScroll { public static final String DISPLAY_NAME = "Notifications"; + static final String ID = "reference.settings.ide.settings.notifications"; private NotificationsConfigurablePanel myComponent; @Override @@ -41,7 +42,7 @@ public class NotificationsConfigurable implements Configurable, SearchableConfig @Override @NotNull public String getHelpTopic() { - return "reference.settings.ide.settings.notifications"; + return ID; } @Override @@ -82,6 +83,11 @@ public class NotificationsConfigurable implements Configurable, SearchableConfig @Override public Runnable enableSearch(final String option) { - return null; + return new Runnable() { + @Override + public void run() { + myComponent.selectGroup(option); + } + }; } } diff --git a/platform/platform-impl/src/com/intellij/notification/impl/ui/NotificationsConfigurablePanel.java b/platform/platform-impl/src/com/intellij/notification/impl/ui/NotificationsConfigurablePanel.java index 7931606053e5..1706376cc8e0 100644 --- a/platform/platform-impl/src/com/intellij/notification/impl/ui/NotificationsConfigurablePanel.java +++ b/platform/platform-impl/src/com/intellij/notification/impl/ui/NotificationsConfigurablePanel.java @@ -23,6 +23,8 @@ import com.intellij.openapi.ui.ComboBoxTableRenderer; import com.intellij.openapi.ui.StripeTable; import com.intellij.openapi.util.SystemInfo; import com.intellij.ui.*; +import com.intellij.ui.speedSearch.SpeedSearchSupply; +import com.intellij.util.ObjectUtils; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; @@ -427,4 +429,8 @@ public class NotificationsConfigurablePanel extends JPanel implements Disposable return result; } } + + public void selectGroup(String searchQuery) { + ObjectUtils.assertNotNull(SpeedSearchSupply.getSupply(myTable, true)).findAndSelectElement(searchQuery); + } } diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index d383db2838f0..5bd41b391f08 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -241,6 +241,7 @@ displayName="Notifications" id="reference.settings.ide.settings.notifications" provider="com.intellij.notification.impl.NotificationsConfigurableProvider"/> + Date: Mon, 19 Jan 2015 17:31:22 +0100 Subject: [PATCH 08/77] Cleanup (formatting; unneeded assertions) --- .../navigation/NavigationUtil.java | 3 +- .../intellij/ide/actions/GotoClassAction.java | 49 ++++++++++--------- .../intellij/ide/actions/GotoFileAction.java | 27 +++++----- .../fileEditor/OpenFileDescriptor.java | 23 +++------ .../src/messages/IdeBundle.properties | 4 ++ 5 files changed, 56 insertions(+), 50 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/NavigationUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/NavigationUtil.java index e8774cedeeb8..2bbbd2ca8869 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/NavigationUtil.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/NavigationUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -175,7 +175,6 @@ public final class NavigationUtil { return false; } - private static boolean activatePsiElementIfOpen(@NotNull PsiElement elt, boolean searchForOpen, boolean requestFocus) { if (!elt.isValid()) return false; elt = elt.getNavigationElement(); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java index 24d7a09942df..33163b76381f 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.ide.actions; import com.intellij.codeInsight.navigation.NavigationUtil; import com.intellij.featureStatistics.FeatureUsageTracker; +import com.intellij.ide.IdeBundle; import com.intellij.ide.structureView.StructureView; import com.intellij.ide.structureView.StructureViewBuilder; import com.intellij.ide.structureView.StructureViewTreeElement; @@ -29,7 +29,6 @@ import com.intellij.lang.LanguageStructureViewBuilder; import com.intellij.lang.PsiStructureViewFactory; import com.intellij.navigation.AnonymousElementProvider; import com.intellij.navigation.ChooseByNameRegistry; -import com.intellij.navigation.ItemPresentation; import com.intellij.navigation.NavigationItem; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.AccessToken; @@ -53,34 +52,38 @@ import com.intellij.psi.util.PsiUtilCore; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.awt.*; +import java.awt.event.InputEvent; import java.util.ArrayList; import java.util.List; public class GotoClassAction extends GotoActionBase implements DumbAware { @Override - public void actionPerformed(@NotNull final AnActionEvent e) { - final Project project = e.getData(CommonDataKeys.PROJECT); - assert project != null; + public void actionPerformed(@NotNull AnActionEvent e) { + Project project = e.getProject(); + if (project == null) return; + if (!DumbService.getInstance(project).isDumb()) { super.actionPerformed(e); } else { - DumbService.getInstance(project) - .showDumbModeNotification("Goto Class action is not available until indices are built, using Goto File instead"); - ActionManager.getInstance() - .tryToExecute(ActionManager.getInstance().getAction(GotoFileAction.ID), ActionCommand.getInputEvent(GotoFileAction.ID), - e.getData(PlatformDataKeys.CONTEXT_COMPONENT), e.getPlace(), true); + DumbService.getInstance(project).showDumbModeNotification(IdeBundle.message("go.to.class.dumb.mode.message")); + AnAction action = ActionManager.getInstance().getAction(GotoFileAction.ID); + InputEvent event = ActionCommand.getInputEvent(GotoFileAction.ID); + Component component = e.getData(PlatformDataKeys.CONTEXT_COMPONENT); + ActionManager.getInstance().tryToExecute(action, event, component, e.getPlace(), true); } } @Override - public void gotoActionPerformed(AnActionEvent e) { - final Project project = e.getData(CommonDataKeys.PROJECT); - assert project != null; + public void gotoActionPerformed(@NotNull AnActionEvent e) { + final Project project = e.getProject(); + if (project == null) return; + + FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.popup.class"); PsiDocumentManager.getInstance(project).commitAllDocuments(); - FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.popup.class"); final GotoClassModel2 model = new GotoClassModel2(project); showNavigationPopup(e, model, new GotoActionCallback() { @Override @@ -95,14 +98,16 @@ public class GotoClassAction extends GotoActionBase implements DumbAware { if (element instanceof PsiElement) { final PsiElement psiElement = getElement(((PsiElement)element), popup); final VirtualFile file = PsiUtilCore.getVirtualFile(psiElement); - if (popup.getLinePosition() != -1 && file != null) { - Navigatable n = new OpenFileDescriptor(project, file, popup.getLinePosition(), popup.getColumnPosition()).setUseCurrentWindow( - popup.isOpenInCurrentWindowRequested()); + + if (file != null && popup.getLinePosition() != -1) { + OpenFileDescriptor descriptor = new OpenFileDescriptor(project, file, popup.getLinePosition(), popup.getColumnPosition()); + Navigatable n = descriptor.setUseCurrentWindow(popup.isOpenInCurrentWindowRequested()); if (n.canNavigate()) { n.navigate(true); return; } } + if (psiElement != null && file != null && popup.getMemberPattern() != null) { NavigationUtil.activateFileWithPsiElement(psiElement, !popup.isOpenInCurrentWindowRequested()); Navigatable member = findMember(popup.getMemberPattern(), psiElement, file); @@ -121,10 +126,11 @@ public class GotoClassAction extends GotoActionBase implements DumbAware { token.finish(); } } - }, "Classes matching pattern", true); + }, IdeBundle.message("go.to.class.toolwindow.title"), true); } - @Nullable private static Navigatable findMember(String pattern, PsiElement psiElement, VirtualFile file) { + @Nullable + private static Navigatable findMember(String pattern, PsiElement psiElement, VirtualFile file) { final PsiStructureViewFactory factory = LanguageStructureViewBuilder.INSTANCE.forLanguage(psiElement.getLanguage()); final StructureViewBuilder builder = factory == null ? null : factory.getStructureViewBuilder(psiElement.getContainingFile()); final FileEditor[] editors = FileEditorManager.getInstance(psiElement.getProject()).getEditors(file); @@ -144,8 +150,7 @@ public class GotoClassAction extends GotoActionBase implements DumbAware { Object target = null; for (TreeElement treeElement : element.getChildren()) { if (treeElement instanceof StructureViewTreeElement) { - final ItemPresentation presentation = treeElement.getPresentation(); - String presentableText = presentation == null ? null : presentation.getPresentableText(); + String presentableText = treeElement.getPresentation().getPresentableText(); if (presentableText != null) { final int degree = matcher.matchingDegree(presentableText); if (degree > max) { diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java index 280e4c7736b1..e43d45ada6d8 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -13,11 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.ide.actions; import com.intellij.featureStatistics.FeatureUsageTracker; -import com.intellij.ide.util.gotoByName.*; +import com.intellij.ide.IdeBundle; +import com.intellij.ide.util.gotoByName.ChooseByNameFilter; +import com.intellij.ide.util.gotoByName.ChooseByNamePopup; +import com.intellij.ide.util.gotoByName.GotoFileConfiguration; +import com.intellij.ide.util.gotoByName.GotoFileModel; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.application.ApplicationManager; @@ -30,7 +33,6 @@ import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.Navigatable; -import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; @@ -52,8 +54,11 @@ public class GotoFileAction extends GotoActionBase implements DumbAware { @Override public void gotoActionPerformed(AnActionEvent e) { - FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.popup.file"); final Project project = e.getData(CommonDataKeys.PROJECT); + if (project == null) return; + + FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.popup.file"); + final GotoFileModel gotoFileModel = new GotoFileModel(project); GotoActionCallback callback = new GotoActionCallback() { @Override @@ -71,9 +76,10 @@ public class GotoFileAction extends GotoActionBase implements DumbAware { //this is for better cursor position if (element instanceof PsiFile) { - VirtualFile vfile = ((PsiFile)element).getVirtualFile(); - if (vfile == null) return; - n = new OpenFileDescriptor(project, vfile, popup.getLinePosition(), popup.getColumnPosition()).setUseCurrentWindow(popup.isOpenInCurrentWindowRequested()); + VirtualFile file = ((PsiFile)element).getVirtualFile(); + if (file == null) return; + OpenFileDescriptor descriptor = new OpenFileDescriptor(project, file, popup.getLinePosition(), popup.getColumnPosition()); + n = descriptor.setUseCurrentWindow(popup.isOpenInCurrentWindowRequested()); } if (!n.canNavigate()) return; @@ -82,8 +88,8 @@ public class GotoFileAction extends GotoActionBase implements DumbAware { }, ModalityState.NON_MODAL); } }; - PsiElement context = getPsiContext(e); - showNavigationPopup(e, gotoFileModel, callback, "Files matching pattern", true, true, new GotoFileItemProvider(project, context)); + GotoFileItemProvider provider = new GotoFileItemProvider(project, getPsiContext(e)); + showNavigationPopup(e, gotoFileModel, callback, IdeBundle.message("go.to.file.toolwindow.title"), true, true, provider); } protected static class GotoFileFilter extends ChooseByNameFilter { @@ -148,5 +154,4 @@ public class GotoFileAction extends GotoActionBase implements DumbAware { return o1.getName().compareToIgnoreCase(o2.getName()); } } - } diff --git a/platform/platform-api/src/com/intellij/openapi/fileEditor/OpenFileDescriptor.java b/platform/platform-api/src/com/intellij/openapi/fileEditor/OpenFileDescriptor.java index fbf057f50acc..654490929110 100644 --- a/platform/platform-api/src/com/intellij/openapi/fileEditor/OpenFileDescriptor.java +++ b/platform/platform-api/src/com/intellij/openapi/fileEditor/OpenFileDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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,21 +36,17 @@ import java.util.List; public class OpenFileDescriptor implements Navigatable { /** - * Tells descriptor to navigate in specific editor rather than file editor - * in main IDEA window. - * For example if you want to navigate in editor embedded into modal dialog, - * you should provide this data. + * Tells descriptor to navigate in specific editor rather than file editor in main IDEA window. + * For example if you want to navigate in editor embedded into modal dialog, you should provide this data. */ public static final DataKey NAVIGATE_IN_EDITOR = DataKey.create("NAVIGATE_IN_EDITOR"); - @NotNull + private final Project myProject; private final VirtualFile myFile; - private final int myOffset; private final int myLogicalLine; private final int myLogicalColumn; + private final int myOffset; private final RangeMarker myRangeMarker; - @NotNull - private final Project myProject; private boolean myUseCurrentWindow = false; @@ -62,8 +58,7 @@ public class OpenFileDescriptor implements Navigatable { this(project, file, logicalLine, logicalColumn, -1, false); } - public OpenFileDescriptor(@NotNull Project project, @NotNull VirtualFile file, - int logicalLine, int logicalColumn, boolean persistent) { + public OpenFileDescriptor(@NotNull Project project, @NotNull VirtualFile file, int logicalLine, int logicalColumn, boolean persistent) { this(project, file, logicalLine, logicalColumn, -1, persistent); } @@ -71,10 +66,8 @@ public class OpenFileDescriptor implements Navigatable { this(project, file, -1, -1, -1, false); } - private OpenFileDescriptor(@NotNull Project project, @NotNull VirtualFile file, - int logicalLine, int logicalColumn, int offset, boolean persistent) { + private OpenFileDescriptor(@NotNull Project project, @NotNull VirtualFile file, int logicalLine, int logicalColumn, int offset, boolean persistent) { myProject = project; - myFile = file; myLogicalLine = logicalLine; myLogicalColumn = logicalColumn; @@ -139,7 +132,7 @@ public class OpenFileDescriptor implements Navigatable { } private boolean navigateInRequestedEditor() { - DataContext ctx = DataManager.getInstance().getDataContext(); + @SuppressWarnings("deprecation") DataContext ctx = DataManager.getInstance().getDataContext(); Editor e = NAVIGATE_IN_EDITOR.getData(ctx); if (e == null) return false; if (!Comparing.equal(FileDocumentManager.getInstance().getFile(e.getDocument()), myFile)) return false; diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index 7af9239acdc0..49dede6c95ca 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -1166,3 +1166,7 @@ new.dir.project.chooser.title=Select Location for Project Directory new.dir.project.default.generator=Empty project new.dir.project.error.empty=Project name can't be empty new.dir.project.error.buck=Project directory name must not contain the ''$'' character + +go.to.file.toolwindow.title=Files matching pattern +go.to.class.toolwindow.title=Classes matching pattern +go.to.class.dumb.mode.message=Go To Class action is not available until indices are built, using Go To File instead From 8ff01473052c916bbfffbe2db574a787aaa0b13a Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 19 Jan 2015 18:15:47 +0100 Subject: [PATCH 09/77] IDEA-108519, IDEA-135363 (obtain target navigation element first) --- .../src/com/intellij/ide/actions/GotoClassAction.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java index 33163b76381f..a6c296bba9f4 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java @@ -96,8 +96,9 @@ public class GotoClassAction extends GotoActionBase implements DumbAware { AccessToken token = ReadAction.start(); try { if (element instanceof PsiElement) { - final PsiElement psiElement = getElement(((PsiElement)element), popup); - final VirtualFile file = PsiUtilCore.getVirtualFile(psiElement); + PsiElement psiElement = getElement(((PsiElement)element), popup); + psiElement = psiElement.getNavigationElement(); + VirtualFile file = PsiUtilCore.getVirtualFile(psiElement); if (file != null && popup.getLinePosition() != -1) { OpenFileDescriptor descriptor = new OpenFileDescriptor(project, file, popup.getLinePosition(), popup.getColumnPosition()); @@ -108,7 +109,7 @@ public class GotoClassAction extends GotoActionBase implements DumbAware { } } - if (psiElement != null && file != null && popup.getMemberPattern() != null) { + if (file != null && popup.getMemberPattern() != null) { NavigationUtil.activateFileWithPsiElement(psiElement, !popup.isOpenInCurrentWindowRequested()); Navigatable member = findMember(popup.getMemberPattern(), psiElement, file); if (member != null) { @@ -186,6 +187,7 @@ public class GotoClassAction extends GotoActionBase implements DumbAware { return null; } + @NotNull private static PsiElement getElement(@NotNull PsiElement element, ChooseByNamePopup popup) { final String path = popup.getPathToAnonymous(); if (path != null) { From aacf30ab0b44256290ec0faf70f8e93ff67c1580 Mon Sep 17 00:00:00 2001 From: Anton Makeev Date: Mon, 19 Jan 2015 18:27:55 +0100 Subject: [PATCH 10/77] KeymapsTest: more detailed error message for reassigned shortcuts --- .../openapi/keymap/KeymapsTestCase.java | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java b/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java index 284c8edabb92..5e552ec0002e 100644 --- a/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java +++ b/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java @@ -565,16 +565,16 @@ public abstract class KeymapsTestCase extends PlatformTestCase { ); @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") - Map> reassignedShortcuts = new FactoryMap>() { + Map> reassignedShortcuts = new FactoryMap>() { @Override - protected Map> createMap() { - return new LinkedHashMap>(); + protected Map> createMap() { + return new LinkedHashMap>(); } @Nullable @Override - protected List create(String key) { - return new ArrayList(); + protected List create(Keymap key) { + return new ArrayList(); } }; for (String name : duplicates.keySet()) { @@ -597,7 +597,7 @@ public abstract class KeymapsTestCase extends PlatformTestCase { Set expectedSc = new HashSet(shortcutMappings.getValue()); for (String s : actualSc) { if (!expectedSc.contains(s)) { - reassignedShortcuts.get(keymap.getName()).add(getText(shortcut)); + reassignedShortcuts.get(keymap).add(shortcut); } } for (String s : expectedSc) { @@ -610,11 +610,19 @@ public abstract class KeymapsTestCase extends PlatformTestCase { } if (!reassignedShortcuts.isEmpty()) { StringBuilder message = new StringBuilder(); - for (Map.Entry> keymapToShortcuts : reassignedShortcuts.entrySet()) { - message.append("The following shortcuts was reassigned in keymap ").append(keymapToShortcuts.getKey()) + for (Map.Entry> keymapToShortcuts : reassignedShortcuts.entrySet()) { + Keymap keymap = keymapToShortcuts.getKey(); + message.append("The following shortcuts was reassigned in keymap ").append(keymap.getName()) .append(". Please modify known duplicates list:\n"); - for (String eachShortcut : keymapToShortcuts.getValue()) { - message.append(eachShortcut).append("\n"); + for (Shortcut eachShortcut : keymapToShortcuts.getValue()) { + message.append(" { ").append(StringUtil.wrapWithDoubleQuote(getText(eachShortcut))).append(",\t") + .append(StringUtil.join(keymap.getActionIds(eachShortcut), new Function() { + @Override + public String fun(String s) { + return StringUtil.wrapWithDoubleQuote(s); + } + }, ", ")) + .append("},\n"); } } TestCase.fail("\n" + message.toString()); From 26f389b07acfd7531c9039957c252d0e512e4ded Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Mon, 19 Jan 2015 18:22:03 +0100 Subject: [PATCH 11/77] discovering proxy settings for jetprofile network connection --- lib/src/proxy-vole-20131209-src.zip | Bin 0 -> 90740 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 lib/src/proxy-vole-20131209-src.zip diff --git a/lib/src/proxy-vole-20131209-src.zip b/lib/src/proxy-vole-20131209-src.zip new file mode 100644 index 0000000000000000000000000000000000000000..e7455560863d291db3fa3074a82f53a2013e6468 GIT binary patch literal 90740 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 Date: Mon, 19 Jan 2015 16:22:12 +0100 Subject: [PATCH 12/77] generate equals/hashCode: generate deepHashCode for IntelliJ template; do not use deep equals for Objects template as Objects.hash doesn't support it anyway (IDEA-135313) --- .../intellij/codeInsight/generation/defaultHashCode.vm | 9 +++++---- .../com/intellij/codeInsight/generation/objectsEquals.vm | 8 -------- .../generateEquals/afterArraysFromJava15.java | 3 +-- .../codeInsight/generateEquals/afterDifferentTypes.java | 9 +++------ .../generateEquals/afterDifferentTypesAllNotNull.java | 9 +++------ .../generateEquals/afterDifferentTypesGetters.java | 9 +++------ .../generateEquals/afterDifferentTypesNoDouble.java | 9 +++------ .../afterDifferentTypesSuperEqualsAndHashCode.java | 9 +++------ .../codeInsight/generateEquals/afterNameConflicts.java | 9 +++------ 9 files changed, 24 insertions(+), 50 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/defaultHashCode.vm b/java/java-impl/src/com/intellij/codeInsight/generation/defaultHashCode.vm index e4c51becd08c..a37759ce7bd8 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/defaultHashCode.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/defaultHashCode.vm @@ -78,11 +78,12 @@ public int hashCode() { #end ## #macro(adjustHashCodeToArrays $field) -#if ($field.array && $java_version > 4) -#if ($field.nestedArray) -// Probably incorrect - hashCode for high dimension arrays with Arrays.hashCode + #if ($field.array && $java_version > 4) + #if ($field.nestedArray) + java.util.Arrays.deepHashCode($field.accessor)## + #else + java.util.Arrays.hashCode($field.accessor)## #end - java.util.Arrays.hashCode($field.accessor)## #else ${field.accessor}.hashCode()## #end diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/objectsEquals.vm b/java/java-impl/src/com/intellij/codeInsight/generation/objectsEquals.vm index 5e240f9f73d2..f87075daf08e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/objectsEquals.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/objectsEquals.vm @@ -13,15 +13,7 @@ Object $paramName){ && #end #set($i = $i + 1) - #if ($field.array) - #if ($field.nestedArray) -java.util.Arrays.deepEquals($field.accessor, ${classInstanceName}.$field.accessor)## - #else -java.util.Arrays.equals($field.accessor, ${classInstanceName}.$field.accessor)## - #end - #else java.util.Objects.equals($field.accessor, ${classInstanceName}.$field.accessor)## - #end #end ; } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterArraysFromJava15.java b/java/java-tests/testData/codeInsight/generateEquals/afterArraysFromJava15.java index c97281035edd..dca0073b3c7b 100644 --- a/java/java-tests/testData/codeInsight/generateEquals/afterArraysFromJava15.java +++ b/java/java-tests/testData/codeInsight/generateEquals/afterArraysFromJava15.java @@ -21,8 +21,7 @@ class Test { public int hashCode() { int result = myOs != null ? Arrays.hashCode(myOs) : 0; - result = 31 * result + (myIIs != null ? // Probably incorrect - hashCode for high dimension arrays with Arrays.hashCode - Arrays.hashCode(myIIs) : 0); + result = 31 * result + (myIIs != null ? Arrays.deepHashCode(myIIs) : 0); result = 31 * result + (myIs != null ? Arrays.hashCode(myIs) : 0); return result; } diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypes.java b/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypes.java index fc6c3314aeff..b81281d9e49b 100644 --- a/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypes.java +++ b/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypes.java @@ -51,14 +51,11 @@ class A { int result; long temp; result = a1 != null ? Arrays.hashCode(a1) : 0; - result = 31 * result + (a2 != null ? // Probably incorrect - hashCode for high dimension arrays with Arrays.hashCode - Arrays.hashCode(a2) : 0); + result = 31 * result + (a2 != null ? Arrays.deepHashCode(a2) : 0); result = 31 * result + (a3 != null ? Arrays.hashCode(a3) : 0); - result = 31 * result + (a4 != null ? // Probably incorrect - hashCode for high dimension arrays with Arrays.hashCode - Arrays.hashCode(a4) : 0); + result = 31 * result + (a4 != null ? Arrays.deepHashCode(a4) : 0); result = 31 * result + (a5 != null ? Arrays.hashCode(a5) : 0); - result = 31 * result + (a6 != null ? // Probably incorrect - hashCode for high dimension arrays with Arrays.hashCode - Arrays.hashCode(a6) : 0); + result = 31 * result + (a6 != null ? Arrays.deepHashCode(a6) : 0); result = 31 * result + (int) a7; result = 31 * result + (int) a8; result = 31 * result + a9; diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesAllNotNull.java b/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesAllNotNull.java index 6465e3455ad8..98a7fa6c18bf 100644 --- a/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesAllNotNull.java +++ b/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesAllNotNull.java @@ -51,14 +51,11 @@ class A { int result; long temp; result = Arrays.hashCode(a1); - result = 31 * result + // Probably incorrect - hashCode for high dimension arrays with Arrays.hashCode - Arrays.hashCode(a2); + result = 31 * result + Arrays.deepHashCode(a2); result = 31 * result + Arrays.hashCode(a3); - result = 31 * result + // Probably incorrect - hashCode for high dimension arrays with Arrays.hashCode - Arrays.hashCode(a4); + result = 31 * result + Arrays.deepHashCode(a4); result = 31 * result + Arrays.hashCode(a5); - result = 31 * result + // Probably incorrect - hashCode for high dimension arrays with Arrays.hashCode - Arrays.hashCode(a6); + result = 31 * result + Arrays.deepHashCode(a6); result = 31 * result + (int) a7; result = 31 * result + (int) a8; result = 31 * result + a9; diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesGetters.java b/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesGetters.java index c807dcf489de..69bf70d1ec08 100644 --- a/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesGetters.java +++ b/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesGetters.java @@ -99,14 +99,11 @@ class A { int result; long temp; result = getA1() != null ? Arrays.hashCode(getA1()) : 0; - result = 31 * result + (getA2() != null ? // Probably incorrect - hashCode for high dimension arrays with Arrays.hashCode - Arrays.hashCode(getA2()) : 0); + result = 31 * result + (getA2() != null ? Arrays.deepHashCode(getA2()) : 0); result = 31 * result + (getA3() != null ? Arrays.hashCode(getA3()) : 0); - result = 31 * result + (getA4() != null ? // Probably incorrect - hashCode for high dimension arrays with Arrays.hashCode - Arrays.hashCode(getA4()) : 0); + result = 31 * result + (getA4() != null ? Arrays.deepHashCode(getA4()) : 0); result = 31 * result + (getA5() != null ? Arrays.hashCode(getA5()) : 0); - result = 31 * result + (getA6() != null ? // Probably incorrect - hashCode for high dimension arrays with Arrays.hashCode - Arrays.hashCode(getA6()) : 0); + result = 31 * result + (getA6() != null ? Arrays.deepHashCode(getA6()) : 0); result = 31 * result + (int) getA7(); result = 31 * result + (int) getA8(); result = 31 * result + getA9(); diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesNoDouble.java b/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesNoDouble.java index 29b89feff7d2..5a3e505e01e8 100644 --- a/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesNoDouble.java +++ b/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesNoDouble.java @@ -47,14 +47,11 @@ class A { @Override public int hashCode() { int result = Arrays.hashCode(a1); - result = 31 * result + // Probably incorrect - hashCode for high dimension arrays with Arrays.hashCode - Arrays.hashCode(a2); + result = 31 * result + Arrays.deepHashCode(a2); result = 31 * result + Arrays.hashCode(a3); - result = 31 * result + // Probably incorrect - hashCode for high dimension arrays with Arrays.hashCode - Arrays.hashCode(a4); + result = 31 * result + Arrays.deepHashCode(a4); result = 31 * result + Arrays.hashCode(a5); - result = 31 * result + // Probably incorrect - hashCode for high dimension arrays with Arrays.hashCode - Arrays.hashCode(a6); + result = 31 * result + Arrays.deepHashCode(a6); result = 31 * result + (int) a7; result = 31 * result + (int) a8; result = 31 * result + a9; diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesSuperEqualsAndHashCode.java b/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesSuperEqualsAndHashCode.java index 5ce0416adf60..629408b134ca 100644 --- a/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesSuperEqualsAndHashCode.java +++ b/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesSuperEqualsAndHashCode.java @@ -63,14 +63,11 @@ class A extends B { int result = super.hashCode(); long temp; result = 31 * result + Arrays.hashCode(a1); - result = 31 * result + // Probably incorrect - hashCode for high dimension arrays with Arrays.hashCode - Arrays.hashCode(a2); + result = 31 * result + Arrays.deepHashCode(a2); result = 31 * result + Arrays.hashCode(a3); - result = 31 * result + // Probably incorrect - hashCode for high dimension arrays with Arrays.hashCode - Arrays.hashCode(a4); + result = 31 * result + Arrays.deepHashCode(a4); result = 31 * result + Arrays.hashCode(a5); - result = 31 * result + // Probably incorrect - hashCode for high dimension arrays with Arrays.hashCode - Arrays.hashCode(a6); + result = 31 * result + Arrays.deepHashCode(a6); result = 31 * result + (int) a7; result = 31 * result + (int) a8; result = 31 * result + a9; diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterNameConflicts.java b/java/java-tests/testData/codeInsight/generateEquals/afterNameConflicts.java index ff36c08a04e0..37194104a2ed 100644 --- a/java/java-tests/testData/codeInsight/generateEquals/afterNameConflicts.java +++ b/java/java-tests/testData/codeInsight/generateEquals/afterNameConflicts.java @@ -51,14 +51,11 @@ class A { int result1; long temp1; result1 = Arrays.hashCode(a1); - result1 = 31 * result1 + // Probably incorrect - hashCode for high dimension arrays with Arrays.hashCode - Arrays.hashCode(a2); + result1 = 31 * result1 + Arrays.deepHashCode(a2); result1 = 31 * result1 + Arrays.hashCode(a3); - result1 = 31 * result1 + // Probably incorrect - hashCode for high dimension arrays with Arrays.hashCode - Arrays.hashCode(a4); + result1 = 31 * result1 + Arrays.deepHashCode(a4); result1 = 31 * result1 + Arrays.hashCode(a5); - result1 = 31 * result1 + // Probably incorrect - hashCode for high dimension arrays with Arrays.hashCode - Arrays.hashCode(a6); + result1 = 31 * result1 + Arrays.deepHashCode(a6); result1 = 31 * result1 + (int) a7; result1 = 31 * result1 + (int) a8; result1 = 31 * result1 + a9; From 2fcc03f31ff3d2b8ad65cdef8b192689371f63b2 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 19 Jan 2015 17:18:43 +0100 Subject: [PATCH 13/77] make use of PropertyUtil --- .../src/com/intellij/uiDesigner/wizard/Generator.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/Generator.java b/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/Generator.java index 72f278390514..771a10dec6e9 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/Generator.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/Generator.java @@ -572,14 +572,7 @@ public final class Generator { @SuppressWarnings({"HardCodedStringLiteral"}) private static String suggestGetterName(final String propertyName, final String propertyType) { - final StringBuffer name = new StringBuffer(StringUtil.capitalize(propertyName)); - if ("boolean".equals(propertyType)) { - name.insert(0, "is"); - } - else { - name.insert(0, "get"); - } - return name.toString(); + return PropertyUtil.suggestGetterName(propertyName, "boolean".equals(propertyType) ? PsiType.BOOLEAN : null); } public static void prepareWizardData(final WizardData data, PsiClass boundClass) throws MyException { From d879e82ff11dcdf32e55934840bbffe34f1724af Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 19 Jan 2015 18:17:08 +0100 Subject: [PATCH 14/77] redundant cast: ensure only one cast from 2 same but equals casts is suggested as redundant (IDEA-135043) --- .../src/com/intellij/psi/util/RedundantCastUtil.java | 9 ++++++++- .../inspection/redundantCast/DoubleCast3/expected.xml | 11 ++++++++--- .../redundantCast/DoubleCast3/src/DoubleCast3.java | 2 ++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java b/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java index 02566166fa28..d11b4a9cf984 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java @@ -204,7 +204,14 @@ public class RedundantCastUtil { if (rExpr instanceof PsiTypeCastExpression) { PsiExpression castOperand = ((PsiTypeCastExpression)rExpr).getOperand(); if (castOperand != null) { - PsiType operandType = castOperand.getType(); + PsiType operandType; + if (castOperand instanceof PsiTypeCastExpression) { + final PsiExpression nestedCastOperand = ((PsiTypeCastExpression)castOperand).getOperand(); + operandType = nestedCastOperand != null ? nestedCastOperand.getType() : null; + } + else { + operandType = castOperand.getType(); + } if (operandType != null) { if (lType != null && TypeConversionUtil.isAssignable(lType, operandType, false)) { addToResults((PsiTypeCastExpression)rExpr); diff --git a/java/java-tests/testData/inspection/redundantCast/DoubleCast3/expected.xml b/java/java-tests/testData/inspection/redundantCast/DoubleCast3/expected.xml index e8c201ce3315..49a614757885 100644 --- a/java/java-tests/testData/inspection/redundantCast/DoubleCast3/expected.xml +++ b/java/java-tests/testData/inspection/redundantCast/DoubleCast3/expected.xml @@ -3,12 +3,17 @@ DoubleCast3.java 4 - Casting '(String) o' to String is redundant + Casting 'o' to String is redundant DoubleCast3.java - 4 - Casting 'o' to String is redundant + 6 + Casting '(String) s' to String is redundant + + + DoubleCast3.java + 6 + Casting 's' to String is redundant diff --git a/java/java-tests/testData/inspection/redundantCast/DoubleCast3/src/DoubleCast3.java b/java/java-tests/testData/inspection/redundantCast/DoubleCast3/src/DoubleCast3.java index 36da9cba2007..a4bcb59f55b0 100644 --- a/java/java-tests/testData/inspection/redundantCast/DoubleCast3/src/DoubleCast3.java +++ b/java/java-tests/testData/inspection/redundantCast/DoubleCast3/src/DoubleCast3.java @@ -2,5 +2,7 @@ class Test{ static f(){ Object o; String s = (String) (String) o; + + String s2 = (String) (String) s; } } From 65cc6f3fbf2adf80f5279559146d2432aca78355 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Thu, 15 Jan 2015 13:24:45 +0300 Subject: [PATCH 15/77] PY-12861 Remove whitespaces before/after parenthesis in Python formatter --- .../python/formatter/PythonFormattingModelBuilder.java | 1 + .../testData/formatter/spacesInsideParenthesisAreStripped.py | 4 ++++ .../formatter/spacesInsideParenthesisAreStripped_after.py | 4 ++++ python/testSrc/com/jetbrains/python/PyFormatterTest.java | 5 +++++ 4 files changed, 14 insertions(+) create mode 100644 python/testData/formatter/spacesInsideParenthesisAreStripped.py create mode 100644 python/testData/formatter/spacesInsideParenthesisAreStripped_after.py diff --git a/python/src/com/jetbrains/python/formatter/PythonFormattingModelBuilder.java b/python/src/com/jetbrains/python/formatter/PythonFormattingModelBuilder.java index 595213c7b833..c468290a8514 100644 --- a/python/src/com/jetbrains/python/formatter/PythonFormattingModelBuilder.java +++ b/python/src/com/jetbrains/python/formatter/PythonFormattingModelBuilder.java @@ -113,6 +113,7 @@ public class PythonFormattingModelBuilder implements FormattingModelBuilderEx, C .withinPairInside(LPAR, RPAR, PARAMETER_LIST).spaceIf(commonSettings.SPACE_WITHIN_METHOD_PARENTHESES) .withinPairInside(LPAR, RPAR, FROM_IMPORT_STATEMENT).spaces(0) .withinPairInside(LPAR, RPAR, GENERATOR_EXPRESSION).spaces(0) + .withinPairInside(LPAR, RPAR, PARENTHESIZED_EXPRESSION).spaces(0) .before(LBRACKET).spaceIf(pySettings.SPACE_BEFORE_LBRACKET) .withinPair(LBRACE, RBRACE).spaceIf(pySettings.SPACE_WITHIN_BRACES) diff --git a/python/testData/formatter/spacesInsideParenthesisAreStripped.py b/python/testData/formatter/spacesInsideParenthesisAreStripped.py new file mode 100644 index 000000000000..e8998d6360a0 --- /dev/null +++ b/python/testData/formatter/spacesInsideParenthesisAreStripped.py @@ -0,0 +1,4 @@ +def crap( self ): + foo = ( 'bar' for bar in [ 1, 2,3,4 ] ) + if ( 'a' and 'b' ): + blah( '123' ) \ No newline at end of file diff --git a/python/testData/formatter/spacesInsideParenthesisAreStripped_after.py b/python/testData/formatter/spacesInsideParenthesisAreStripped_after.py new file mode 100644 index 000000000000..56282e7d9b5a --- /dev/null +++ b/python/testData/formatter/spacesInsideParenthesisAreStripped_after.py @@ -0,0 +1,4 @@ +def crap(self): + foo = ('bar' for bar in [1, 2, 3, 4]) + if ('a' and 'b'): + blah('123') \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyFormatterTest.java b/python/testSrc/com/jetbrains/python/PyFormatterTest.java index 4c6e3fd22e7a..a6b5e7c2b465 100644 --- a/python/testSrc/com/jetbrains/python/PyFormatterTest.java +++ b/python/testSrc/com/jetbrains/python/PyFormatterTest.java @@ -430,6 +430,11 @@ public class PyFormatterTest extends PyTestCase { myFixture.checkResultByFile("formatter/" + getTestName(true) + "_after.py"); } + // PY-12861 + public void testSpacesInsideParenthesisAreStripped() { + doTest(); + } + /** * This test merely checks that call to {@link com.intellij.psi.codeStyle.CodeStyleManager#reformat(com.intellij.psi.PsiElement)} * is possible for Python sources. From 697afe15ecb52c6b6c7c447baaed27a1dfc0ae4e Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Thu, 15 Jan 2015 20:28:52 +0300 Subject: [PATCH 16/77] PY-14838, PY-13955 Do not align function arguments when first of them contains "hanging indent" Regardless of option "Align multiline call arguments", alignment should take place only when there is no, so called, "hanging indent" in function call (see PEP-8). In accordance to behavior of 'pep8' utility several such indents at the end of line are collapsed into one. E.g. fragment 'func([{\n' is considered as having "hanging indent" both for function call, list and dict literals. --- .../jetbrains/python/formatter/PyBlock.java | 44 ++++++++++++++++--- ...entAfterDictHangingIndentInFunctionCall.py | 10 +++++ ...DictHangingIndentInFunctionCallOnTyping.py | 3 ++ ...ngingIndentInFunctionCallOnTyping_after.py | 4 ++ ...erDictHangingIndentInFunctionCall_after.py | 11 +++++ .../com/jetbrains/python/PyFormatterTest.java | 39 +++++++++++++++- 6 files changed, 102 insertions(+), 9 deletions(-) create mode 100644 python/testData/formatter/noAlignmentAfterDictHangingIndentInFunctionCall.py create mode 100644 python/testData/formatter/noAlignmentAfterDictHangingIndentInFunctionCallOnTyping.py create mode 100644 python/testData/formatter/noAlignmentAfterDictHangingIndentInFunctionCallOnTyping_after.py create mode 100644 python/testData/formatter/noAlignmentAfterDictHangingIndentInFunctionCall_after.py diff --git a/python/src/com/jetbrains/python/formatter/PyBlock.java b/python/src/com/jetbrains/python/formatter/PyBlock.java index f0a81efaacdf..fdcd46b6bbdd 100644 --- a/python/src/com/jetbrains/python/formatter/PyBlock.java +++ b/python/src/com/jetbrains/python/formatter/PyBlock.java @@ -243,12 +243,13 @@ public class PyBlock implements ASTBlock { } } //Align elements vertically if there is an argument in the first line of parenthesized expression - else if (((parentType == PyElementTypes.PARENTHESIZED_EXPRESSION && myContext.getSettings().ALIGN_MULTILINE_PARENTHESIZED_EXPRESSION) - || (parentType == PyElementTypes.ARGUMENT_LIST && myContext.getSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS) - || (parentType == PyElementTypes.PARAMETER_LIST && myContext.getSettings().ALIGN_MULTILINE_PARAMETERS)) && + else if (!hasHangingIndent(_node.getPsi()) && + ((parentType == PyElementTypes.PARENTHESIZED_EXPRESSION && myContext.getSettings().ALIGN_MULTILINE_PARENTHESIZED_EXPRESSION) || + (parentType == PyElementTypes.ARGUMENT_LIST && myContext.getSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS) || + (parentType == PyElementTypes.PARAMETER_LIST && myContext.getSettings().ALIGN_MULTILINE_PARAMETERS)) && !isIndentNext(child) && - !hasLineBreaksBefore(_node.getFirstChildNode(), 1) - && !ourListElementTypes.contains(childType)) { + !hasLineBreaksBefore(_node.getFirstChildNode(), 1) && + !ourListElementTypes.contains(childType)) { if (!ourBrackets.contains(childType)) { childAlignment = getAlignmentForChildren(); @@ -325,6 +326,35 @@ public class PyBlock implements ASTBlock { return new PyBlock(this, child, childAlignment, childIndent, wrap, myContext); } + // Check https://www.python.org/dev/peps/pep-0008/#indentation + private boolean hasHangingIndent(@NotNull PsiElement elem) { + final PsiElement[] items; + if (elem instanceof PyCallExpression) { + final PyArgumentList argumentList = ((PyCallExpression)elem).getArgumentList(); + return argumentList != null && hasHangingIndent(argumentList); + } + else if (elem instanceof PyFunction) { + return hasHangingIndent(((PyFunction)elem).getParameterList()); + } + else if (elem instanceof PySequenceExpression) { + items = ((PySequenceExpression)elem).getElements(); + } + else if (elem instanceof PyParameterList) { + items = ((PyParameterList)elem).getParameters(); + } + else if (elem instanceof PyArgumentList) { + items = ((PyArgumentList)elem).getArguments(); + } + else { + return false; + } + if (items.length == 0) { + return true; + } + final PsiElement firstItem = items[0]; + return hasLineBreaksBefore(firstItem.getNode(), 1) || hasHangingIndent(firstItem); + } + private static boolean breaksAlignment(IElementType type) { return type != PyElementTypes.BINARY_EXPRESSION; } @@ -412,7 +442,7 @@ public class PyBlock implements ASTBlock { return false; } if (_node.getElementType() == PyElementTypes.ARGUMENT_LIST) { - if (!myContext.getSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS) { + if (!myContext.getSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS || hasHangingIndent(_node.getPsi())) { return false; } if (child.getElementType() == PyTokenTypes.COMMA) { @@ -427,7 +457,7 @@ public class PyBlock implements ASTBlock { return false; } if (_node.getElementType() == PyElementTypes.PARAMETER_LIST) { - return myContext.getSettings().ALIGN_MULTILINE_PARAMETERS; + return !hasHangingIndent(_node.getPsi()) && myContext.getSettings().ALIGN_MULTILINE_PARAMETERS; } if (_node.getElementType() == PyElementTypes.SUBSCRIPTION_EXPRESSION) { return false; diff --git a/python/testData/formatter/noAlignmentAfterDictHangingIndentInFunctionCall.py b/python/testData/formatter/noAlignmentAfterDictHangingIndentInFunctionCall.py new file mode 100644 index 000000000000..107888673836 --- /dev/null +++ b/python/testData/formatter/noAlignmentAfterDictHangingIndentInFunctionCall.py @@ -0,0 +1,10 @@ +def test_function(*args): + pass + +test_function({ + 'a': 'b', +}, 5) + +test_function(1, + 2, + 3) \ No newline at end of file diff --git a/python/testData/formatter/noAlignmentAfterDictHangingIndentInFunctionCallOnTyping.py b/python/testData/formatter/noAlignmentAfterDictHangingIndentInFunctionCallOnTyping.py new file mode 100644 index 000000000000..5132384a86b5 --- /dev/null +++ b/python/testData/formatter/noAlignmentAfterDictHangingIndentInFunctionCallOnTyping.py @@ -0,0 +1,3 @@ +handler = webapp2.WSGIApplication([ + ('/', UserHandler), +], debug=True) diff --git a/python/testData/formatter/noAlignmentAfterDictHangingIndentInFunctionCallOnTyping_after.py b/python/testData/formatter/noAlignmentAfterDictHangingIndentInFunctionCallOnTyping_after.py new file mode 100644 index 000000000000..9e3811c7a380 --- /dev/null +++ b/python/testData/formatter/noAlignmentAfterDictHangingIndentInFunctionCallOnTyping_after.py @@ -0,0 +1,4 @@ +handler = webapp2.WSGIApplication([ + ('/', UserHandler), + () +], debug=True) diff --git a/python/testData/formatter/noAlignmentAfterDictHangingIndentInFunctionCall_after.py b/python/testData/formatter/noAlignmentAfterDictHangingIndentInFunctionCall_after.py new file mode 100644 index 000000000000..f8fbb2f5c06b --- /dev/null +++ b/python/testData/formatter/noAlignmentAfterDictHangingIndentInFunctionCall_after.py @@ -0,0 +1,11 @@ +def test_function(*args): + pass + + +test_function({ + 'a': 'b', +}, 5) + +test_function(1, + 2, + 3) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyFormatterTest.java b/python/testSrc/com/jetbrains/python/PyFormatterTest.java index a6b5e7c2b465..a1f5cc860347 100644 --- a/python/testSrc/com/jetbrains/python/PyFormatterTest.java +++ b/python/testSrc/com/jetbrains/python/PyFormatterTest.java @@ -21,6 +21,7 @@ import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.python.fixtures.PyTestCase; import com.jetbrains.python.formatter.PyCodeStyleSettings; @@ -159,7 +160,7 @@ public class PyFormatterTest extends PyTestCase { } public void testNoAlignForMethodArguments() { // PY-3995 - settings().getCommonSettings(PythonLanguage.getInstance()).ALIGN_MULTILINE_PARAMETERS_IN_CALLS = false; + getCommonSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = false; doTest(); } @@ -435,6 +436,36 @@ public class PyFormatterTest extends PyTestCase { doTest(); } + // PY-14838 + public void testNoAlignmentAfterDictHangingIndentInFunctionCall() { + getCommonSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true; + try { + doTest(); + } + finally { + settings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = false; + } + } + + // PY-13955 + public void testNoAlignmentAfterDictHangingIndentInFunctionCallOnTyping() { + settings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true; + try { + final String testName = "formatter/" + getTestName(true); + myFixture.configureByFile(testName + ".py"); + WriteCommandAction.runWriteCommandAction(null, new Runnable() { + @Override + public void run() { + myFixture.type("\n("); + } + }); + myFixture.checkResultByFile(testName + "_after.py"); + } + finally { + settings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = false; + } + } + /** * This test merely checks that call to {@link com.intellij.psi.codeStyle.CodeStyleManager#reformat(com.intellij.psi.PsiElement)} * is possible for Python sources. @@ -455,7 +486,11 @@ public class PyFormatterTest extends PyTestCase { myFixture.checkResultByFile("formatter/" + getTestName(true) + "_after.py"); } + private CommonCodeStyleSettings getCommonSettings() { + return settings().getCommonSettings(PythonLanguage.getInstance()); + } + private CodeStyleSettings settings() { - return CodeStyleSettingsManager.getInstance().getSettings(myFixture.getProject()); + return CodeStyleSettingsManager.getSettings(myFixture.getProject()); } } From 4ced2f94f723d4ed56a5cc47097f4b18e7f5f951 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Fri, 16 Jan 2015 18:24:32 +0300 Subject: [PATCH 17/77] PY-12145 Align closing brace when there is no hanging indent in parental expression Also update expected test data in a couple of existing tests to be PEP8 complaint --- .../jetbrains/python/formatter/PyBlock.java | 36 ++++++++++++++----- .../alignInParenthesizedExpression_after.py | 2 +- ...ngBraceInDictLiteralWhenNoHangingIndent.py | 8 +++++ ...eInDictLiteralWhenNoHangingIndent_after.py | 8 +++++ .../formatter/tupleInArgList_after.py | 2 +- .../com/jetbrains/python/PyFormatterTest.java | 5 +++ 6 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 python/testData/formatter/alignmentOfClosingBraceInDictLiteralWhenNoHangingIndent.py create mode 100644 python/testData/formatter/alignmentOfClosingBraceInDictLiteralWhenNoHangingIndent_after.py diff --git a/python/src/com/jetbrains/python/formatter/PyBlock.java b/python/src/com/jetbrains/python/formatter/PyBlock.java index fdcd46b6bbdd..4a76a487de6d 100644 --- a/python/src/com/jetbrains/python/formatter/PyBlock.java +++ b/python/src/com/jetbrains/python/formatter/PyBlock.java @@ -336,7 +336,16 @@ public class PyBlock implements ASTBlock { else if (elem instanceof PyFunction) { return hasHangingIndent(((PyFunction)elem).getParameterList()); } - else if (elem instanceof PySequenceExpression) { + + final PsiElement firstChild = elem.getFirstChild(); + if (firstChild == null) { + return false; + } + if (PyTokenTypes.OPEN_BRACES.contains(firstChild.getNode().getElementType()) && hasLineBreaksAfter(firstChild.getNode(), 1)) { + return true; + } + + if (elem instanceof PySequenceExpression) { items = ((PySequenceExpression)elem).getElements(); } else if (elem instanceof PyParameterList) { @@ -345,14 +354,19 @@ public class PyBlock implements ASTBlock { else if (elem instanceof PyArgumentList) { items = ((PyArgumentList)elem).getArguments(); } + else if (elem instanceof PyParenthesizedExpression) { + final PyParenthesizedExpression parenthesizedExpr = (PyParenthesizedExpression)elem; + if (parenthesizedExpr.getContainedExpression() instanceof PyTupleExpression) { + items = (((PyTupleExpression)parenthesizedExpr.getContainedExpression()).getElements()); + } + else { + items = new PsiElement[]{parenthesizedExpr.getContainedExpression()}; + } + } else { return false; } - if (items.length == 0) { - return true; - } - final PsiElement firstItem = items[0]; - return hasLineBreaksBefore(firstItem.getNode(), 1) || hasHangingIndent(firstItem); + return items.length == 0 || hasHangingIndent(items[0]); } private static boolean breaksAlignment(IElementType type) { @@ -439,7 +453,7 @@ public class PyBlock implements ASTBlock { myContext.getMode() == FormattingMode.ADJUST_INDENT) { return true; } - return false; + return !hasHangingIndent(_node.getPsi()); } if (_node.getElementType() == PyElementTypes.ARGUMENT_LIST) { if (!myContext.getSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS || hasHangingIndent(_node.getPsi())) { @@ -477,12 +491,18 @@ public class PyBlock implements ASTBlock { return node; } - private static boolean hasLineBreaksBefore(ASTNode child, int minCount) { + private static boolean hasLineBreaksBefore(@NotNull ASTNode child, int minCount) { final ASTNode treePrev = child.getTreePrev(); return (treePrev != null && isWhitespaceWithLineBreaks(TreeUtil.findLastLeaf(treePrev), minCount)) || isWhitespaceWithLineBreaks(child.getFirstChildNode(), minCount); } + private static boolean hasLineBreaksAfter(@NotNull ASTNode child, int minCount) { + final ASTNode treeNext = child.getTreeNext(); + return (treeNext != null && isWhitespaceWithLineBreaks(TreeUtil.findLastLeaf(treeNext), minCount)) || + isWhitespaceWithLineBreaks(child.getLastChildNode(), minCount); + } + private static boolean isWhitespaceWithLineBreaks(ASTNode node, int minCount) { if (node != null && node.getElementType() == TokenType.WHITE_SPACE) { String prevNodeText = node.getText(); diff --git a/python/testData/formatter/alignInParenthesizedExpression_after.py b/python/testData/formatter/alignInParenthesizedExpression_after.py index 868557ca748f..9e619c4e8013 100644 --- a/python/testData/formatter/alignInParenthesizedExpression_after.py +++ b/python/testData/formatter/alignInParenthesizedExpression_after.py @@ -5,4 +5,4 @@ print(1 + (1 + (1 + x. calc() -)) \ No newline at end of file + )) \ No newline at end of file diff --git a/python/testData/formatter/alignmentOfClosingBraceInDictLiteralWhenNoHangingIndent.py b/python/testData/formatter/alignmentOfClosingBraceInDictLiteralWhenNoHangingIndent.py new file mode 100644 index 000000000000..af427d022905 --- /dev/null +++ b/python/testData/formatter/alignmentOfClosingBraceInDictLiteralWhenNoHangingIndent.py @@ -0,0 +1,8 @@ +class Checkpoints(webapp2.RequestHandler): + def get(self): + self.response.write(json.dumps({"meta": {"code": 400, + "errorType": "paramError", + "errorDetail": "Parameter 'api_key' is missing" + }, + "response": {} + })) \ No newline at end of file diff --git a/python/testData/formatter/alignmentOfClosingBraceInDictLiteralWhenNoHangingIndent_after.py b/python/testData/formatter/alignmentOfClosingBraceInDictLiteralWhenNoHangingIndent_after.py new file mode 100644 index 000000000000..d7df54a76338 --- /dev/null +++ b/python/testData/formatter/alignmentOfClosingBraceInDictLiteralWhenNoHangingIndent_after.py @@ -0,0 +1,8 @@ +class Checkpoints(webapp2.RequestHandler): + def get(self): + self.response.write(json.dumps({"meta": {"code": 400, + "errorType": "paramError", + "errorDetail": "Parameter 'api_key' is missing" + }, + "response": {} + })) \ No newline at end of file diff --git a/python/testData/formatter/tupleInArgList_after.py b/python/testData/formatter/tupleInArgList_after.py index ff31f6bd51cc..72dce723faab 100644 --- a/python/testData/formatter/tupleInArgList_after.py +++ b/python/testData/formatter/tupleInArgList_after.py @@ -1,4 +1,4 @@ urlpatterns = patterns('', (r'^admin/', include(admin.site.urls)), url(r'^', include('cms.urls')), -) + ) diff --git a/python/testSrc/com/jetbrains/python/PyFormatterTest.java b/python/testSrc/com/jetbrains/python/PyFormatterTest.java index a1f5cc860347..96e2c7e86ee7 100644 --- a/python/testSrc/com/jetbrains/python/PyFormatterTest.java +++ b/python/testSrc/com/jetbrains/python/PyFormatterTest.java @@ -466,6 +466,11 @@ public class PyFormatterTest extends PyTestCase { } } + // PY-12145 + public void testAlignmentOfClosingBraceInDictLiteralWhenNoHangingIndent() { + doTest(); + } + /** * This test merely checks that call to {@link com.intellij.psi.codeStyle.CodeStyleManager#reformat(com.intellij.psi.PsiElement)} * is possible for Python sources. From 29f261213c5a4585580e26eae89faec90a995705 Mon Sep 17 00:00:00 2001 From: Sergey Savenko Date: Mon, 19 Jan 2015 21:58:59 +0300 Subject: [PATCH 18/77] fix ContentManagerUtil#getContentManagerFromContext Return a content manager from context if a visible toolwindow is not required --- .../intellij/ui/content/ContentManagerUtil.java | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ui/content/ContentManagerUtil.java b/platform/platform-impl/src/com/intellij/ui/content/ContentManagerUtil.java index b1a1a2f8a2eb..9129f3c3bb73 100644 --- a/platform/platform-impl/src/com/intellij/ui/content/ContentManagerUtil.java +++ b/platform/platform-impl/src/com/intellij/ui/content/ContentManagerUtil.java @@ -21,6 +21,7 @@ import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.project.Project; import com.intellij.openapi.wm.ex.ToolWindowEx; import com.intellij.openapi.wm.ex.ToolWindowManagerEx; +import com.intellij.util.ObjectUtils; public class ContentManagerUtil { private ContentManagerUtil() { @@ -43,18 +44,14 @@ public class ContentManagerUtil { id = mgr.getLastActiveToolWindowId(); } } - if(id == null){ + + ToolWindowEx toolWindow = id != null ? (ToolWindowEx)mgr.getToolWindow(id) : null; + if (requiresVisibleToolWindow && (toolWindow == null || !toolWindow.isVisible())) { return null; } - ToolWindowEx toolWindow = (ToolWindowEx)mgr.getToolWindow(id); - if (requiresVisibleToolWindow && !toolWindow.isVisible()) { - return null; - } - - final ContentManager fromContext = PlatformDataKeys.CONTENT_MANAGER.getData(dataContext); - if (fromContext != null) return fromContext; - - return toolWindow != null ? toolWindow.getContentManager() : null; + ContentManager fromToolWindow = toolWindow != null ? toolWindow.getContentManager() : null; + ContentManager fromContext = PlatformDataKeys.CONTENT_MANAGER.getData(dataContext); + return ObjectUtils.chooseNotNull(fromContext, fromToolWindow); } } From 880dd54504d3818b4fbd7b0c9cafc0a537cd68c0 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Mon, 19 Jan 2015 20:03:31 +0100 Subject: [PATCH 19/77] [performance optimization] use VirtualFile.getNameSequence() instead of VirtualFile.getName() --- .../openapi/vfs/newvfs/persistent/PersistentFSImpl.java | 2 +- .../src/com/intellij/openapi/vcs/changes/IgnoredFileBean.java | 3 ++- .../jetbrains/python/psi/stubs/PySetuptoolsNamespaceIndex.java | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java index b1c3d90a8aed..bf91a747b948 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java @@ -1323,7 +1323,7 @@ public class PersistentFSImpl extends PersistentFS implements ApplicationCompone @NotNull @Override public CharSequence getNameSequence() { - return myParentLocalFile.getName(); + return myParentLocalFile.getNameSequence(); } @Override diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/changes/IgnoredFileBean.java b/platform/vcs-api/src/com/intellij/openapi/vcs/changes/IgnoredFileBean.java index 1091f908b600..2245b5eae90b 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/changes/IgnoredFileBean.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/changes/IgnoredFileBean.java @@ -25,6 +25,7 @@ package com.intellij.openapi.vcs.changes; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; @@ -119,7 +120,7 @@ public class IgnoredFileBean { } else { // quick check for 'file' == exact match pattern - if (IgnoreSettingsType.FILE.equals(myType) && !myFilenameIfFile.equals(file.getName())) return false; + if (IgnoreSettingsType.FILE.equals(myType) && !StringUtil.equals(myFilenameIfFile, file.getNameSequence())) return false; VirtualFile selector = resolve(); if (Comparing.equal(selector, NullVirtualFile.INSTANCE)) return false; diff --git a/python/src/com/jetbrains/python/psi/stubs/PySetuptoolsNamespaceIndex.java b/python/src/com/jetbrains/python/psi/stubs/PySetuptoolsNamespaceIndex.java index 2988922415d2..a0bf1cceb943 100644 --- a/python/src/com/jetbrains/python/psi/stubs/PySetuptoolsNamespaceIndex.java +++ b/python/src/com/jetbrains/python/psi/stubs/PySetuptoolsNamespaceIndex.java @@ -16,6 +16,7 @@ package com.jetbrains.python.psi.stubs; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.indexing.*; @@ -58,7 +59,7 @@ public class PySetuptoolsNamespaceIndex extends ScalarIndexExtension { private FileBasedIndex.InputFilter myInputFilter = new FileBasedIndex.InputFilter() { @Override public boolean acceptInput(@NotNull VirtualFile file) { - return file.getName().endsWith(NAMESPACE_FILE_SUFFIX); + return StringUtil.endsWith(file.getNameSequence(), NAMESPACE_FILE_SUFFIX); } }; From ad345ace46c219789ef014520f66b7dd91484192 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Mon, 19 Jan 2015 20:11:22 +0100 Subject: [PATCH 20/77] add inline debugger colors to debugger colors page --- .../src/com/intellij/xdebugger/ui/DebuggerColors.java | 5 ++++- .../com/intellij/xdebugger/impl/ui/DebuggerColorsPage.java | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/ui/DebuggerColors.java b/platform/xdebugger-api/src/com/intellij/xdebugger/ui/DebuggerColors.java index f71f8b0cf1bb..8322ff735434 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/ui/DebuggerColors.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/ui/DebuggerColors.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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,4 +36,7 @@ public interface DebuggerColors { Key BREAKPOINT_HIGHLIGHTER_KEY = Key.create("BREAKPOINT_HIGHLIGHTER_KEY"); int EXECUTION_LINE_HIGHLIGHTERLAYER = HighlighterLayer.SELECTION - 1; + TextAttributesKey INLINED_VALUES = TextAttributesKey.createTextAttributesKey("DEBUGGER_INLINED_VALUES"); + TextAttributesKey INLINED_VALUES_MODIFIED = TextAttributesKey.createTextAttributesKey("DEBUGGER_INLINED_VALUES_MODIFIED"); + TextAttributesKey INLINED_VALUES_EXECUTION_LINE = TextAttributesKey.createTextAttributesKey("DEBUGGER_INLINED_VALUES_EXECUTION_LINE"); } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerColorsPage.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerColorsPage.java index 6314a6b9f97b..143e95fbc16b 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerColorsPage.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerColorsPage.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -54,6 +54,9 @@ public class DebuggerColorsPage implements ColorSettingsPage, DisplayPrioritySor new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.breakpoint.line"), DebuggerColors.BREAKPOINT_ATTRIBUTES), new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.execution.point"), DebuggerColors.EXECUTIONPOINT_ATTRIBUTES), new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.not.top.frame"), DebuggerColors.NOT_TOP_FRAME_ATTRIBUTES), + new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.inlined.values"), DebuggerColors.INLINED_VALUES), + new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.inlined.values.modified"), DebuggerColors.INLINED_VALUES_MODIFIED), + new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.inlined.values.execution.line"), DebuggerColors.INLINED_VALUES_EXECUTION_LINE), }; } From e9e46749f9a652d540f58bb0bfd8b2c734b8c37e Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Mon, 19 Jan 2015 20:12:20 +0100 Subject: [PATCH 21/77] create LineExtensionInfo from TextAttributes --- .../com/intellij/openapi/editor/LineExtensionInfo.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/LineExtensionInfo.java b/platform/platform-impl/src/com/intellij/openapi/editor/LineExtensionInfo.java index f84502097b10..86a80c702585 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/LineExtensionInfo.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/LineExtensionInfo.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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.openapi.editor; import com.intellij.openapi.editor.markup.EffectType; +import com.intellij.openapi.editor.markup.TextAttributes; import org.intellij.lang.annotations.JdkConstants; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -43,6 +44,13 @@ public class LineExtensionInfo { myEffectColor = effectColor; myFontType = fontType; } + public LineExtensionInfo(@NotNull String text, @NotNull TextAttributes attr) { + myText = text; + myColor = attr.getForegroundColor(); + myEffectType = attr.getEffectType(); + myEffectColor = attr.getEffectColor(); + myFontType = attr.getFontType(); + } @NotNull public String getText() { From 4821c9bc8a22fe61c8b92a8b3b8dd8afa504535b Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Mon, 19 Jan 2015 20:13:32 +0100 Subject: [PATCH 22/77] add inline debugger color settings labels to options bundle --- .../src/messages/OptionsBundle.properties | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform/platform-resources-en/src/messages/OptionsBundle.properties b/platform/platform-resources-en/src/messages/OptionsBundle.properties index cb27a90f5dd7..b51a7a78bb5b 100644 --- a/platform/platform-resources-en/src/messages/OptionsBundle.properties +++ b/platform/platform-resources-en/src/messages/OptionsBundle.properties @@ -95,6 +95,9 @@ options.java.attribute.descriptor.bad.character=Bad character options.java.attribute.descriptor.breakpoint.line=Breakpoint line options.java.attribute.descriptor.execution.point=Execution point options.java.attribute.descriptor.not.top.frame=Not top frame +options.java.attribute.descriptor.inlined.values=Inlined values +options.java.attribute.descriptor.inlined.values.modified=Inlined modified values +options.java.attribute.descriptor.inlined.values.execution.line=Inlined values for breakpoint line options.java.attribute.descriptor.recursive.call=Recursive calls highlighting options.java.attribute.descriptor.annotation.name=Annotation name options.java.attribute.descriptor.annotation.attribute.name=Annotation attribute name From 3b6253d998b59b5a940ba9325691c38b7a3935c4 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Mon, 19 Jan 2015 20:14:24 +0100 Subject: [PATCH 23/77] use global color scheme for inline debugger colors --- .../evaluate/XDebuggerEditorLinePainter.java | 78 ++++++++++++------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEditorLinePainter.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEditorLinePainter.java index 047cbb1831b2..a2beefaedadb 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEditorLinePainter.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEditorLinePainter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -19,6 +19,7 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.EditorLinePainter; import com.intellij.openapi.editor.LineExtensionInfo; import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; @@ -40,6 +41,7 @@ import com.intellij.xdebugger.impl.frame.XDebugView; import com.intellij.xdebugger.impl.frame.XVariablesView; import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl; import com.intellij.xdebugger.impl.ui.tree.nodes.XValueTextRendererImpl; +import com.intellij.xdebugger.ui.DebuggerColors; import org.jetbrains.annotations.NotNull; import java.awt.*; @@ -102,7 +104,7 @@ public class XDebuggerEditorLinePainter extends EditorLinePainter { } XDebugSession session = XDebugView.getSession(values.iterator().next().getTree()); boolean isTopFrame = session instanceof XDebugSessionImpl && ((XDebugSessionImpl)session).isTopFrameSelected(); - final Color color = bpLine == lineNumber && isTopFrame ? new JBColor(new Color(0, 255, 86), new Color(255, 235, 9)) : getForeground(); + final TextAttributes attributes = bpLine == lineNumber && isTopFrame ? getTopFrameSelectedAttributes() : getNormalAttributes(); final String name = value.getName(); if (StringUtil.isEmpty(text.toString())) { @@ -110,7 +112,7 @@ public class XDebuggerEditorLinePainter extends EditorLinePainter { } final VariableText res = new VariableText(); result.add(res); - res.add(new LineExtensionInfo(" " + name + ": ", color, null, null, Font.ITALIC)); + res.add(new LineExtensionInfo(" " + name + ": ", attributes)); Variable var = new Variable(name, lineNumber); VariableValue variableValue = oldValues.get(var); @@ -126,7 +128,7 @@ public class XDebuggerEditorLinePainter extends EditorLinePainter { if (!variableValue.isChanged()) { for (String s : text.getTexts()) { - res.add(new LineExtensionInfo(s, color, null, null, Font.ITALIC)); + res.add(new LineExtensionInfo(s, attributes)); } } else { @@ -167,28 +169,44 @@ public class XDebuggerEditorLinePainter extends EditorLinePainter { return ColorUtil.isDark(bg); } - public static JBColor getForeground() { - return new JBColor(new NotNullProducer() { - @SuppressWarnings("UseJBColor") - @NotNull - @Override - public Color produce() { - return isDarkEditor() ? Registry.getColor("ide.debugger.inline.dark.fg.color", new Color(0x3d8065)) - : Registry.getColor("ide.debugger.inline.fg.color", new Color(0x3d8065)); - } - }); + public static TextAttributes getNormalAttributes() { + TextAttributes attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(DebuggerColors.INLINED_VALUES); + if (attributes == null || attributes.getForegroundColor() == null) { + return new TextAttributes(new JBColor(new NotNullProducer() { + @SuppressWarnings("UseJBColor") + @NotNull + @Override + public Color produce() { + return Registry.getColor(isDarkEditor() ? "ide.debugger.inline.dark.fg.color" : "ide.debugger.inline.fg.color", new Color(0x3d8065)); + } + }), null, null, null, Font.ITALIC); + } + return attributes; } - public static JBColor getChangedForeground() { - return new JBColor(new NotNullProducer() { - @SuppressWarnings("UseJBColor") - @NotNull - @Override - public Color produce() { - return isDarkEditor() ? Registry.getColor("ide.debugger.inline.dark.fg.modified.color", new Color(0xa1830a)) - : Registry.getColor("ide.debugger.inline.fg.modified.color", new Color(0xca8021)); - } - }); + public static TextAttributes getChangedAttributes() { + TextAttributes attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(DebuggerColors.INLINED_VALUES_MODIFIED); + if (attributes == null || attributes.getForegroundColor() == null) { + return new TextAttributes(new JBColor(new NotNullProducer() { + @SuppressWarnings("UseJBColor") + @NotNull + @Override + public Color produce() { + return isDarkEditor() ? Registry.getColor("ide.debugger.inline.dark.fg.modified.color", new Color(0xa1830a)) + : Registry.getColor("ide.debugger.inline.fg.modified.color", new Color(0xca8021)); + } + }), null, null, null, Font.ITALIC); + } + return attributes; + } + + private static TextAttributes getTopFrameSelectedAttributes() { + TextAttributes attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(DebuggerColors.INLINED_VALUES_EXECUTION_LINE); + if (attributes == null || attributes.getForegroundColor() == null) { + //noinspection UseJBColor + return new TextAttributes(isDarkEditor() ? new Color(255, 235, 9) : new Color(0, 255, 86), null, null, null, Font.ITALIC); + } + return attributes; } static class Variable { @@ -240,22 +258,22 @@ public class XDebuggerEditorLinePainter extends EditorLinePainter { if (isArray(actual) && isArray(old)) { List actualParts = getArrayParts(actual); List oldParts = getArrayParts(old); - result.add(new LineExtensionInfo("{", getForeground(), null, null, Font.ITALIC)); + result.add(new LineExtensionInfo("{", getNormalAttributes())); for (int i = 0; i < actualParts.size(); i++) { if (i < oldParts.size() && StringUtil.equals(actualParts.get(i), oldParts.get(i))) { - result.add(new LineExtensionInfo(actualParts.get(i), getForeground(), null, null, Font.ITALIC)); + result.add(new LineExtensionInfo(actualParts.get(i), getNormalAttributes())); } else { - result.add(new LineExtensionInfo(actualParts.get(i), getChangedForeground(), null, null, Font.ITALIC)); + result.add(new LineExtensionInfo(actualParts.get(i), getChangedAttributes())); } if (i != actualParts.size() - 1) { - result.add(new LineExtensionInfo(", ", getForeground(), null, null, Font.ITALIC)); + result.add(new LineExtensionInfo(", ", getNormalAttributes())); } } - result.add(new LineExtensionInfo("}", getForeground(), null, null, Font.ITALIC)); + result.add(new LineExtensionInfo("}", getNormalAttributes())); return; } - result.add(new LineExtensionInfo(actual, getChangedForeground(), null, null, Font.ITALIC)); + result.add(new LineExtensionInfo(actual, getChangedAttributes())); } private static boolean isArray(String s) { From c6aaf7b49113e54ea728bba3e26767cee0ad8751 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Mon, 19 Jan 2015 20:15:12 +0100 Subject: [PATCH 24/77] Default Color Scheme: add inline debugger colors --- .../src/DefaultColorSchemesManager.xml | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/platform/platform-resources/src/DefaultColorSchemesManager.xml b/platform/platform-resources/src/DefaultColorSchemesManager.xml index 06e6feb837d9..83962be2446e 100644 --- a/platform/platform-resources/src/DefaultColorSchemesManager.xml +++ b/platform/platform-resources/src/DefaultColorSchemesManager.xml @@ -33,6 +33,27 @@ + + +