From 802cab38faa9e9c6ace67699492986f5f29bae59 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Mon, 4 Nov 2013 17:23:41 +0100 Subject: [PATCH 01/11] make action event param Nullable --- .../com/intellij/ide/actions/GotoActionAction.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java index d6eccc0858b8..6aef4e82f420 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java @@ -32,6 +32,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.Pair; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.awt.*; import java.util.Collections; @@ -86,7 +87,7 @@ public class GotoActionAction extends GotoActionBase implements DumbAware { final String enteredText, final Project project, final Component component, - @NotNull final AnActionEvent e) { + @Nullable final AnActionEvent e) { if (element instanceof OptionDescription) { final String configurableId = ((OptionDescription)element).getConfigurableId(); ApplicationManager.getApplication().invokeLater(new Runnable() { @@ -108,10 +109,12 @@ public class GotoActionAction extends GotoActionBase implements DumbAware { } final Presentation presentation = action.getTemplatePresentation().clone(); final DataContext context = DataManager.getInstance().getDataContext(component); - final AnActionEvent event = new AnActionEvent(e.getInputEvent(), context, - e.getPlace(), presentation, + final AnActionEvent event = new AnActionEvent(e == null ? null : e.getInputEvent(), + context, + e == null ? ActionPlaces.UNKNOWN : e.getPlace(), + presentation, ActionManager.getInstance(), - e.getModifiers()); + e == null ? 0 : e.getModifiers()); if (ActionUtil.lastUpdateAndCheckDumb(action, event, true)) { if (action instanceof ActionGroup) { From a4da2060c8e0b029b9f414106d6846013b8cb2ee Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Mon, 4 Nov 2013 17:24:33 +0100 Subject: [PATCH 02/11] can't call actions by mouse --- .../intellij/ide/actions/SearchEverywhereAction.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index 89e2b11b4b75..c63edeb988c6 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -336,7 +336,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA private void initSearchField(final MySearchTextField search) { final JTextField editor = search.getTextEditor(); - onFocusLost(); +// onFocusLost(); editor.getDocument().addDocumentListener(new DocumentAdapter() { @Override protected void textChanged(DocumentEvent e) { @@ -379,7 +379,8 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA @Override public void focusLost(FocusEvent e) { - if ( myPopup instanceof AbstractPopup && myPopup.isVisible() && ((AbstractPopup)myPopup).getPopupWindow() == e.getOppositeComponent()) { + if ( myPopup instanceof AbstractPopup && myPopup.isVisible() + && ((myList == e.getOppositeComponent()) || ((AbstractPopup)myPopup).getPopupWindow() == e.getOppositeComponent())) { return; } onFocusLost(); @@ -491,7 +492,11 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA option.setOptionState(!option.isOptionEnabled()); } else { - GotoActionAction.openOptionOrPerformAction(value, pattern, project, comp, event); + Component c = comp; + if (c == null) { + c = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); + } + GotoActionAction.openOptionOrPerformAction(value, pattern, project, c, event); } } }); From 6afc6fc38c6b552859d695614df1e8cc97ad4c34 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 31 Oct 2013 12:19:51 +0100 Subject: [PATCH 03/11] Cleanup (code de-duplication) --- .../openapi/editor/impl/EditorImpl.java | 173 +++++++----------- 1 file changed, 63 insertions(+), 110 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index b73092aa3fb9..99f54696be4e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -5009,6 +5009,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi myDropHandler = dropHandler; } + private static class MyInputMethodHandleSwingThreadWrapper implements InputMethodRequests { private final InputMethodRequests myDelegate; @@ -5018,114 +5019,53 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi @Override public Rectangle getTextLocation(final TextHitInfo offset) { - if (ApplicationManager.getApplication().isDispatchThread()) return myDelegate.getTextLocation(offset); - - final Rectangle[] r = new Rectangle[1]; - try { - GuiUtils.invokeAndWait(new Runnable() { - @Override - public void run() { - r[0] = myDelegate.getTextLocation(offset); - } - }); - } - catch (InterruptedException e) { - LOG.error(e); - } - catch (InvocationTargetException e) { - LOG.error(e); - } - return r[0]; + return execute(new Computable() { + @Override + public Rectangle compute() { + return myDelegate.getTextLocation(offset); + } + }); } @Override public TextHitInfo getLocationOffset(final int x, final int y) { - if (ApplicationManager.getApplication().isDispatchThread()) return myDelegate.getLocationOffset(x, y); - - final TextHitInfo[] r = new TextHitInfo[1]; - try { - GuiUtils.invokeAndWait(new Runnable() { - @Override - public void run() { - r[0] = myDelegate.getLocationOffset(x, y); - } - }); - } - catch (InterruptedException e) { - LOG.error(e); - } - catch (InvocationTargetException e) { - LOG.error(e); - } - return r[0]; + return execute(new Computable() { + @Override + public TextHitInfo compute() { + return myDelegate.getLocationOffset(x, y); + } + }); } @Override public int getInsertPositionOffset() { - if (ApplicationManager.getApplication().isDispatchThread()) return myDelegate.getInsertPositionOffset(); - - final int[] r = new int[1]; - try { - GuiUtils.invokeAndWait(new Runnable() { - @Override - public void run() { - r[0] = myDelegate.getInsertPositionOffset(); - } - }); - } - catch (InterruptedException e) { - LOG.error(e); - } - catch (InvocationTargetException e) { - LOG.error(e); - } - return r[0]; + return execute(new Computable() { + @Override + public Integer compute() { + return myDelegate.getInsertPositionOffset(); + } + }); } @Override - public AttributedCharacterIterator getCommittedText(final int beginIndex, - final int endIndex, + public AttributedCharacterIterator getCommittedText(final int beginIndex, final int endIndex, final AttributedCharacterIterator.Attribute[] attributes) { - if (ApplicationManager.getApplication().isDispatchThread()) { - return myDelegate.getCommittedText(beginIndex, endIndex, attributes); - } - final AttributedCharacterIterator[] r = new AttributedCharacterIterator[1]; - try { - GuiUtils.invokeAndWait(new Runnable() { - @Override - public void run() { - r[0] = myDelegate.getCommittedText(beginIndex, endIndex, attributes); - } - }); - } - catch (InterruptedException e) { - LOG.error(e); - } - catch (InvocationTargetException e) { - LOG.error(e); - } - return r[0]; + return execute(new Computable() { + @Override + public AttributedCharacterIterator compute() { + return myDelegate.getCommittedText(beginIndex, endIndex, attributes); + } + }); } @Override public int getCommittedTextLength() { - if (ApplicationManager.getApplication().isDispatchThread()) return myDelegate.getCommittedTextLength(); - final int[] r = new int[1]; - try { - GuiUtils.invokeAndWait(new Runnable() { - @Override - public void run() { - r[0] = myDelegate.getCommittedTextLength(); - } - }); - } - catch (InterruptedException e) { - LOG.error(e); - } - catch (InvocationTargetException e) { - LOG.error(e); - } - return r[0]; + return execute(new Computable() { + @Override + public Integer compute() { + return myDelegate.getCommittedTextLength(); + } + }); } @Override @@ -5136,27 +5076,40 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi @Override public AttributedCharacterIterator getSelectedText(final AttributedCharacterIterator.Attribute[] attributes) { - if (ApplicationManager.getApplication().isDispatchThread()) return myDelegate.getSelectedText(attributes); + return execute(new Computable() { + @Override + public AttributedCharacterIterator compute() { + return myDelegate.getSelectedText(attributes); + } + }); + } - final AttributedCharacterIterator[] r = new AttributedCharacterIterator[1]; - try { - GuiUtils.invokeAndWait(new Runnable() { - @Override - public void run() { - r[0] = myDelegate.getSelectedText(attributes); - } - }); + private static T execute(final Computable computable) { + if (ApplicationManager.getApplication().isDispatchThread()) { + return computable.compute(); } - catch (InterruptedException e) { - LOG.error(e); + else { + final Ref ref = Ref.create(); + try { + GuiUtils.invokeAndWait(new Runnable() { + @Override + public void run() { + ref.set(computable.compute()); + } + }); + } + catch (InterruptedException e) { + LOG.error(e); + } + catch (InvocationTargetException e) { + LOG.error(e); + } + return ref.get(); } - catch (InvocationTargetException e) { - LOG.error(e); - } - return r[0]; } } + private class MyInputMethodHandler implements InputMethodRequests { private String composedText; private ProperTextRange composedTextRange; @@ -5357,8 +5310,8 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi } } - private class MyMouseAdapter extends MouseAdapter { + private class MyMouseAdapter extends MouseAdapter { private boolean mySelectionTweaked; @Override @@ -6160,14 +6113,14 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi @Override public void updateStarted(@NotNull Document doc) { if (doc != getDocument()) return; - + bulkUpdateStarted(); } @Override public void updateFinished(@NotNull Document doc) { if (doc != getDocument()) return; - + bulkUpdateFinished(); } } From df385ccbf168d40e544679c6ca485e21db78fe74 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 4 Nov 2013 17:17:43 +0100 Subject: [PATCH 04/11] EA-51567 (JRE bug - just catch and log) --- .../intellij/ide/ClipboardSynchronizer.java | 80 +++++++------------ 1 file changed, 28 insertions(+), 52 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/ClipboardSynchronizer.java b/platform/platform-impl/src/com/intellij/ide/ClipboardSynchronizer.java index e18c79a76b42..95795dd06a8f 100644 --- a/platform/platform-impl/src/com/intellij/ide/ClipboardSynchronizer.java +++ b/platform/platform-impl/src/com/intellij/ide/ClipboardSynchronizer.java @@ -36,8 +36,9 @@ import java.awt.datatransfer.*; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.*; -import java.util.List; +import java.util.Collection; +import java.util.Collections; +import java.util.Set; /** *

This class is used to workaround the problem with getting clipboard contents (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4818143). @@ -216,7 +217,7 @@ public class ClipboardSynchronizer implements ApplicationComponent { LOG.info(e); } } - + myFullTransferable = null; return transferable; } @@ -246,11 +247,11 @@ public class ClipboardSynchronizer implements ApplicationComponent { super.setContent(content, owner); } } - + @Nullable public static Transferable getContentsSafe() { final Ref result = new Ref(); - + Foundation.executeOnMainThread(new Runnable() { @Override public void run() { @@ -264,7 +265,7 @@ public class ClipboardSynchronizer implements ApplicationComponent { return result.get(); } } - + @Nullable private static Transferable getClipboardContentNatively() { String plainText = "public.utf8-plain-text"; @@ -285,9 +286,9 @@ public class ClipboardSynchronizer implements ApplicationComponent { } // will put string value even if we doesn't found java object. this is needed because java caches clipboard value internally and - // will reset it ONLY IF we'll put jvm-object into clipboard (see our setContent optimizations which avoids putting jvm-objects - // into clipboard) - + // will reset it ONLY IF we'll put jvm-object into clipboard (see our setContent optimizations which avoids putting jvm-objects + // into clipboard) + Transferable result = null; if (plainTextType != null) { ID text = Foundation.invoke(pasteboard, "stringForType:", plainTextType); @@ -299,7 +300,7 @@ public class ClipboardSynchronizer implements ApplicationComponent { result = new StringSelection(value); } } - + return result; } @@ -328,15 +329,19 @@ public class ClipboardSynchronizer implements ApplicationComponent { } try { - final Pair> contents = checkContentsQuick(); + final Collection contents = checkContentsQuick(); if (contents != null) { - return contents.second.contains(dataFlavor); + return contents.contains(dataFlavor); } return super.isDataFlavorAvailable(dataFlavor); } catch (NullPointerException e) { - LOG.warn("Sun bug #6322854", e); + LOG.warn("Java bug #6322854", e); + return false; + } + catch (IllegalArgumentException e) { + LOG.warn("Java bug #7173464", e); return false; } } @@ -349,49 +354,20 @@ public class ClipboardSynchronizer implements ApplicationComponent { } try { - final Pair> contents = checkContentsQuick(); - if (contents != null && contents.second.isEmpty()) { + final Collection contents = checkContentsQuick(); + if (contents != null && contents.isEmpty()) { return null; } - try { - return super.getContents(); - } - catch (IllegalArgumentException e) { - // todo[r.sh] to remove in IDEA 12.1 - if (contents != null && "Comparison method violates its general contract!".equals(e.getMessage())) { - LOG.error("Cannot sort: " + contents.second + ", atoms: " + atomNames(contents.first), e); - return null; - } - throw e; - } + return super.getContents(); } catch (NullPointerException e) { - LOG.warn("Sun bug #6322854", e); + LOG.warn("Java bug #6322854", e); return null; } - } - - private static List atomNames(long[] formats) { - try { - Class toolkit = Class.forName("sun.awt.X11.XToolkit"); - Method getDisplay = toolkit.getDeclaredMethod("getDisplay"); - getDisplay.setAccessible(true); - long display = (Long)getDisplay.invoke(null); - - Class wrapper = Class.forName("sun.awt.X11.XlibWrapper"); - Method getAtomName = wrapper.getDeclaredMethod("XGetAtomName", long.class, long.class); - getAtomName.setAccessible(true); - - List atoms = new ArrayList(); - for (long format : formats) { - String name = (String)getAtomName.invoke(null, display, format); - atoms.add(format + ":" + name); - } - return atoms; - } - catch (Throwable t) { - return Collections.emptyList(); + catch (IllegalArgumentException e) { + LOG.warn("Java bug #7173464", e); + return null; } } @@ -413,7 +389,7 @@ public class ClipboardSynchronizer implements ApplicationComponent { * collection of available data flavors otherwise. */ @Nullable - private static Pair> checkContentsQuick() { + private static Collection checkContentsQuick() { final Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); final Class aClass = clipboard.getClass(); if (!"sun.awt.X11.XClipboard".equals(aClass.getName())) return null; @@ -433,10 +409,10 @@ public class ClipboardSynchronizer implements ApplicationComponent { try { final long[] formats = (long[])getClipboardFormats.invoke(clipboard); if (formats == null || formats.length == 0) { - return Pair.create(formats, Collections.emptySet()); + return Collections.emptySet(); } @SuppressWarnings({"unchecked"}) final Set set = DataTransferer.getInstance().getFlavorsForFormats(formats, FLAVOR_MAP).keySet(); - return Pair.create(formats, set); + return set; } catch (IllegalAccessException ignore) { } catch (IllegalArgumentException ignore) { } From 95492f967ce37596272e86057261f6bfbd099998 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 4 Nov 2013 17:19:27 +0100 Subject: [PATCH 05/11] Cleanup (formatting) --- .../intellij/ide/ClipboardSynchronizer.java | 78 ++++++++++--------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/ClipboardSynchronizer.java b/platform/platform-impl/src/com/intellij/ide/ClipboardSynchronizer.java index 95795dd06a8f..d46b868f8d02 100644 --- a/platform/platform-impl/src/com/intellij/ide/ClipboardSynchronizer.java +++ b/platform/platform-impl/src/com/intellij/ide/ClipboardSynchronizer.java @@ -126,6 +126,7 @@ public class ClipboardSynchronizer implements ApplicationComponent { myClipboardHandler.resetContent(); } + private static class ClipboardHandler { public void init() { } @@ -179,6 +180,7 @@ public class ClipboardSynchronizer implements ApplicationComponent { } } + private static class MacClipboardHandler extends ClipboardHandler { private Pair myFullTransferable; @@ -264,45 +266,46 @@ public class ClipboardSynchronizer implements ApplicationComponent { return result.get(); } + + @Nullable + private static Transferable getClipboardContentNatively() { + String plainText = "public.utf8-plain-text"; + + ID pasteboard = Foundation.invoke("NSPasteboard", "generalPasteboard"); + ID types = Foundation.invoke(pasteboard, "types"); + IntegerType count = Foundation.invoke(types, "count"); + + ID plainTextType = null; + + for (int i = 0; i < count.intValue(); i++) { + ID each = Foundation.invoke(types, "objectAtIndex:", i); + String eachType = Foundation.toStringViaUTF8(each); + if (plainText.equals(eachType)) { + plainTextType = each; + break; + } + } + + // will put string value even if we doesn't found java object. this is needed because java caches clipboard value internally and + // will reset it ONLY IF we'll put jvm-object into clipboard (see our setContent optimizations which avoids putting jvm-objects + // into clipboard) + + Transferable result = null; + if (plainTextType != null) { + ID text = Foundation.invoke(pasteboard, "stringForType:", plainTextType); + String value = Foundation.toStringViaUTF8(text); + if (value == null) { + LOG.info(String.format("[Clipboard] Strange string value (null?) for type: %s", plainTextType)); + } + else { + result = new StringSelection(value); + } + } + + return result; + } } - @Nullable - private static Transferable getClipboardContentNatively() { - String plainText = "public.utf8-plain-text"; - - ID pasteboard = Foundation.invoke("NSPasteboard", "generalPasteboard"); - ID types = Foundation.invoke(pasteboard, "types"); - IntegerType count = Foundation.invoke(types, "count"); - - ID plainTextType = null; - - for (int i = 0; i < count.intValue(); i++) { - ID each = Foundation.invoke(types, "objectAtIndex:", i); - String eachType = Foundation.toStringViaUTF8(each); - if (plainText.equals(eachType)) { - plainTextType = each; - break; - } - } - - // will put string value even if we doesn't found java object. this is needed because java caches clipboard value internally and - // will reset it ONLY IF we'll put jvm-object into clipboard (see our setContent optimizations which avoids putting jvm-objects - // into clipboard) - - Transferable result = null; - if (plainTextType != null) { - ID text = Foundation.invoke(pasteboard, "stringForType:", plainTextType); - String value = Foundation.toStringViaUTF8(text); - if (value == null) { - LOG.info(String.format("[Clipboard] Strange string value (null?) for type: %s", plainTextType)); - } - else { - result = new StringSelection(value); - } - } - - return result; - } private static class XWinClipboardHandler extends ClipboardHandler { private static final FlavorTable FLAVOR_MAP = (FlavorTable)SystemFlavorMap.getDefaultFlavorMap(); @@ -430,6 +433,7 @@ public class ClipboardSynchronizer implements ApplicationComponent { } } + private static class HeadlessClipboardHandler extends ClipboardHandler { private volatile Transferable myContent = null; From 0f794b2884c666f5df2259fbb6b41da170ee0c34 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 4 Nov 2013 19:57:01 +0400 Subject: [PATCH 06/11] [log] defensive copying --- .../impl/src/com/intellij/vcs/log/impl/VcsCommitImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsCommitImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsCommitImpl.java index e1f075b014cd..3900dfc43c28 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsCommitImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsCommitImpl.java @@ -7,6 +7,7 @@ import com.intellij.vcs.log.Hash; import com.intellij.vcs.log.VcsCommit; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; import java.util.List; /** @@ -26,7 +27,7 @@ public class VcsCommitImpl implements VcsCommit { public VcsCommitImpl(@NotNull Hash hash, @NotNull List parents) { myHash = hash; - myParents = parents; + myParents = new ArrayList(parents); } @Override From 2c0d75439884154c0f67b73e03a3ac9aa0dd9af5 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 4 Nov 2013 20:24:05 +0400 Subject: [PATCH 07/11] [log] Don't display commit time if equal to author time --- .../com/intellij/vcs/log/ui/frame/DetailsPanel.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java index 22346edecdcd..c9fe1021e547 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java @@ -165,8 +165,14 @@ class DetailsPanel extends JPanel implements ListSelectionListener { String authorText = commit.getAuthorName() + " at " + DateFormatUtil.formatDateTime(commit.getAuthorTime()); if (!commit.getAuthorName().equals(commit.getCommitterName()) || !commit.getAuthorEmail().equals(commit.getCommitterEmail())) { - authorText += " (committed by " + commit.getCommitterName() + - " at " + DateFormatUtil.formatDateTime(commit.getCommitTime()) + ")"; + String commitTime; + if (commit.getCommitTime() != commit.getAuthorTime()) { + commitTime = " at " + DateFormatUtil.formatDateTime(commit.getCommitTime()); + } + else { + commitTime = ""; + } + authorText += " (committed by " + commit.getCommitterName() + commitTime + ")"; } myAuthor.setText(authorText); } From b23a9164eb7db6d9cb00c0a57a15d5a42b84d6c0 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 4 Nov 2013 20:25:13 +0400 Subject: [PATCH 08/11] [log] dispose the log structures on project dispose --- .../impl/src/com/intellij/vcs/log/impl/VcsLogManager.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogManager.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogManager.java index 5e7a0a809835..ab2eeccd5164 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogManager.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogManager.java @@ -39,7 +39,7 @@ import java.util.Set; /** * @author Kirill Likhodedov */ -public class VcsLogManager { +public class VcsLogManager implements Disposable { public static final ExtensionPointName LOG_PROVIDER_EP = ExtensionPointName.create("com.intellij.logProvider"); @@ -61,6 +61,7 @@ public class VcsLogManager { myLogObjectsFactory = logObjectsFactory; mySettings = settings; myUiProperties = uiProperties; + Disposer.register(myProject, this); } @NotNull @@ -71,6 +72,7 @@ public class VcsLogManager { VcsLogDataHolder.init(myProject, myLogObjectsFactory, logProviders, mySettings, new Consumer() { @Override public void consume(VcsLogDataHolder vcsLogDataHolder) { + Disposer.register(VcsLogManager.this, vcsLogDataHolder); VcsLogUI logUI = new VcsLogUI(vcsLogDataHolder, myProject, mySettings, new VcsLogColorManagerImpl(logProviders.keySet()), myUiProperties); myLogDataHolder = vcsLogDataHolder; @@ -119,6 +121,10 @@ public class VcsLogManager { return myUi; } + @Override + public void dispose() { + } + private static class VcsLogContainer extends JPanel { private final JBLoadingPanel myLoadingPanel; From ab339b8eac434043419bdd12c02d5aae1b5ee762 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 4 Nov 2013 20:40:18 +0400 Subject: [PATCH 09/11] [log] Consume less temporary memory When reading the whole log, don't read the whole output and then parse it. Instead read packs of 1000 commits and parse this parts of the log. --- .../src/git4idea/history/GitHistoryUtils.java | 88 ++++++++++++++++--- 1 file changed, 76 insertions(+), 12 deletions(-) diff --git a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java index 79f7223bc1ea..d51f4765abce 100644 --- a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java +++ b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java @@ -64,6 +64,7 @@ import java.io.*; import java.nio.charset.Charset; import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import static git4idea.history.GitLogParser.GitLogOption.*; @@ -535,8 +536,10 @@ public class GitHistoryUtils { @NotNull public static List readAllHashes(@NotNull Project project, @NotNull VirtualFile root) throws VcsException { - GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.LOG); - GitLogParser parser = new GitLogParser(project, GitLogParser.NameStatus.NONE, HASH, PARENTS, AUTHOR_TIME); + final int COMMIT_BUFFER = 1000; + + GitLineHandler h = new GitLineHandler(project, root, GitCommand.LOG); + final GitLogParser parser = new GitLogParser(project, GitLogParser.NameStatus.NONE, HASH, PARENTS, AUTHOR_TIME); h.setStdoutSuppressed(true); h.addParameters(parser.getPretty(), "--encoding=UTF-8"); h.addParameters("HEAD", "--branches", "--remotes", "--tags"); @@ -544,21 +547,82 @@ public class GitHistoryUtils { h.addParameters("--date-order"); h.endOptions(); - String output = h.run(); + final List commits = ContainerUtil.newArrayList(); - List records = parser.parse(output); - - return ContainerUtil.map(records, new Function() { + final StringBuilder record = new StringBuilder(); + final AtomicInteger records = new AtomicInteger(); + final Ref ex = new Ref(); + h.addLineListener(new GitLineHandlerListener() { @Override - public TimedVcsCommit fun(GitLogRecord record) { - List parents = new SmartList(); - for (String parent : record.getParentsHashes()) { - parents.add(HashImpl.build(parent)); + public void onLineAvailable(String line, Key outputType) { + try { + int recordEnd = line.indexOf(GitLogParser.RECORD_END); + String afterParseRemainder; + if (recordEnd == line.length() - 1) { // ends with + record.append(line); + afterParseRemainder = ""; + } + else if (recordEnd == -1) { // record doesn't end on this line => just appending, no parsing + record.append(line); + afterParseRemainder = null; + } + else { // record ends in the middle of this line + record.append(line.substring(0, recordEnd + 1)); + afterParseRemainder = line.substring(recordEnd + 1); + } + if (afterParseRemainder != null && records.incrementAndGet() > COMMIT_BUFFER) { // null means can't parse now + commits.addAll(parseCommit(parser, record)); + record.setLength(0); + record.append(afterParseRemainder); + } } - return ServiceManager.getService(VcsLogObjectsFactory.class).createTimedCommit(HashImpl.build(record.getHash()), - parents, record.getAuthorTimeStamp()); + catch (Exception e) { + ex.set(new VcsException(e)); + } + } + + @Override + public void processTerminated(int exitCode) { + try { + commits.addAll(parseCommit(parser, record)); + } + catch (Exception e) { + ex.set(new VcsException(e)); + } + } + + @Override + public void startFailed(Throwable exception) { + ex.set(new VcsException(exception)); } }); + h.runInCurrentThread(null); + if (!ex.isNull()) { + throw ex.get(); + } + return commits; + } + + private static List parseCommit(GitLogParser parser, StringBuilder record) { + List rec = parser.parse(record.toString()); + return ContainerUtil.mapNotNull(rec, new Function() { + @Override + public TimedVcsCommit fun(GitLogRecord record) { + return record == null ? null : convert(record); + } + }); + } + + @NotNull + private static TimedVcsCommit convert(GitLogRecord rec) { + VcsLogObjectsFactory factory = ServiceManager.getService(VcsLogObjectsFactory.class); + List parents = ContainerUtil.map(rec.getParentsHashes(), new Function() { + @Override + public Hash fun(String s) { + return HashImpl.build(s); + } + }); + return factory.createTimedCommit(HashImpl.build(rec.getHash()), parents, rec.getAuthorTimeStamp()); } private static class MyTokenAccumulator { From 28dee7ccf89116fc1e5fd4a36b7158ecf057d207 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 4 Nov 2013 16:20:32 +0100 Subject: [PATCH 10/11] add println to jetbrains.dic (IDEA-115852) --- spellchecker/src/com/intellij/spellchecker/jetbrains.dic | 1 + 1 file changed, 1 insertion(+) diff --git a/spellchecker/src/com/intellij/spellchecker/jetbrains.dic b/spellchecker/src/com/intellij/spellchecker/jetbrains.dic index 5db0eb8ee39e..637ca7510b83 100644 --- a/spellchecker/src/com/intellij/spellchecker/jetbrains.dic +++ b/spellchecker/src/com/intellij/spellchecker/jetbrains.dic @@ -361,6 +361,7 @@ prepended prepends preprocessor preprocessors +println processlist profiler progressbar From 3a224a11cefbe1e529d5d344561587ed2ef598cd Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 4 Nov 2013 17:43:07 +0100 Subject: [PATCH 11/11] just consider dash a part of word for hippie completion (IDEA-115762) --- .../completion/HippieCompletionTest.groovy | 15 +++++++++++ .../actions/HippieWordCompletionHandler.java | 25 +++++++------------ 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/HippieCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/HippieCompletionTest.groovy index 16ca708560a6..ab9ea13a425d 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/HippieCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/HippieCompletionTest.groovy @@ -113,6 +113,21 @@ class Foo { ''' } + public void "test complete variable name in string literal"() { + myFixture.configureByText "a.java", ''' +class Xoo { + String foobar = "foo"; +} +''' + complete() + myFixture.checkResult ''' +class Xoo { + String foobar = "foobar"; +} +''' + + } + private void complete() { myFixture.performEditorAction(IdeActions.ACTION_HIPPIE_COMPLETION) } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/HippieWordCompletionHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/HippieWordCompletionHandler.java index 4f273bb1cb90..19d4804efbe5 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/HippieWordCompletionHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/HippieWordCompletionHandler.java @@ -44,7 +44,6 @@ import java.util.*; */ public class HippieWordCompletionHandler implements CodeInsightActionHandler { private static final Key KEY_STATE = new Key("HIPPIE_COMPLETION_STATE"); - private static final String WHITESPACE_CHARS = " \t\n"; private final boolean myForward; public HippieWordCompletionHandler(boolean forward) { @@ -188,7 +187,7 @@ public class HippieWordCompletionHandler implements CodeInsightActionHandler { } } - private static boolean isWordLike(CharSequence seq, int start, int end) { + private static boolean containsLetters(CharSequence seq, int start, int end) { for (int i = start; i < end; i++) { if (Character.isLetter(seq.charAt(i))) { return true; @@ -256,7 +255,7 @@ public class HippieWordCompletionHandler implements CodeInsightActionHandler { @Override public boolean processToken(int start, int end) { if ((start > caretOffset || end < caretOffset) && //skip prefix itself - end - start > matcher.getPrefix().length() && isWordLike(chars, start, end)) { + end - start > matcher.getPrefix().length()) { final String word = chars.subSequence(start, end).toString(); if (matcher.isStartMatch(word)) { CompletionVariant v = new CompletionVariant(editor, word, start); @@ -280,25 +279,15 @@ public class HippieWordCompletionHandler implements CodeInsightActionHandler { while (!iterator.atEnd()) { int start = iterator.getStart(); int end = iterator.getEnd(); - if (StringUtil.indexOfAny(chars, WHITESPACE_CHARS, start, end) < 0) { - //a single token without whitespace, consider it one word, even if it's an identifier with '-' inside - if (isWordLike(chars, start, end) && !processor.processToken(start, end)) { - return; - } - iterator.advance(); - continue; - } - // a token with whitespace inside (a string literal or comment) - // use the default java-identifier notion of word while (start < end) { int wordStart = start; - while (wordStart < end && !Character.isJavaIdentifierPart(chars.charAt(wordStart))) wordStart++; + while (wordStart < end && !isWordPart(chars.charAt(wordStart))) wordStart++; int wordEnd = wordStart; - while (wordEnd < end && Character.isJavaIdentifierPart(chars.charAt(wordEnd))) wordEnd++; + while (wordEnd < end && isWordPart(chars.charAt(wordEnd))) wordEnd++; - if (!processor.processToken(wordStart, wordEnd)) { + if (wordEnd > wordStart && containsLetters(chars, wordStart, wordEnd) && !processor.processToken(wordStart, wordEnd)) { return; } start = wordEnd + 1; @@ -307,6 +296,10 @@ public class HippieWordCompletionHandler implements CodeInsightActionHandler { } } + private static boolean isWordPart(final char c) { + return Character.isJavaIdentifierPart(c) || c == '-' || c == '*' ; + } + private static CompletionData computeData(final Editor editor, final CharSequence charsSequence) { final int offset = editor.getCaretModel().getOffset();