diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgNameWithHashInfo.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgNameWithHashInfo.java index d7e09babe7a0..ccc87f690ac4 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgNameWithHashInfo.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgNameWithHashInfo.java @@ -38,11 +38,11 @@ public class HgNameWithHashInfo { } /** - *

Returns the hash on which this branch or bookmark or tag is reference to.

+ *

Returns the hash on which this bookmark or tag is reference to.

*/ @NotNull - public String getHash() { - return myHash.asString(); + public Hash getHash() { + return myHash; } @NotNull diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchPopupActions.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchPopupActions.java index 0e3142841f9f..4198069bad05 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchPopupActions.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchPopupActions.java @@ -16,11 +16,13 @@ package org.zmlx.hg4idea.action; import com.intellij.dvcs.DvcsUtil; +import com.intellij.dvcs.repo.Repository; import com.intellij.dvcs.ui.NewBranchAction; import com.intellij.openapi.actionSystem.ActionGroup; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DefaultActionGroup; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.DumbAwareAction; @@ -28,16 +30,18 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.update.UpdatedFiles; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.Function; import com.intellij.util.PlatformIcons; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.vcs.log.Hash; +import com.intellij.vcs.log.impl.HashImpl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.zmlx.hg4idea.HgNameWithHashInfo; import org.zmlx.hg4idea.HgRevisionNumber; import org.zmlx.hg4idea.HgVcs; import org.zmlx.hg4idea.HgVcsMessages; -import org.zmlx.hg4idea.command.HgBookmarkCreateCommand; -import org.zmlx.hg4idea.command.HgBranchCreateCommand; -import org.zmlx.hg4idea.command.HgMergeCommand; -import org.zmlx.hg4idea.command.HgUpdateCommand; +import org.zmlx.hg4idea.command.*; import org.zmlx.hg4idea.execution.HgCommandException; import org.zmlx.hg4idea.execution.HgCommandResult; import org.zmlx.hg4idea.execution.HgCommandResultHandler; @@ -48,8 +52,7 @@ import org.zmlx.hg4idea.ui.HgBookmarkDialog; import org.zmlx.hg4idea.util.HgErrorUtil; import org.zmlx.hg4idea.util.HgUtil; -import java.util.Collections; -import java.util.List; +import java.util.*; /** * @author Nadya Zabrodina @@ -68,7 +71,7 @@ public class HgBranchPopupActions { DefaultActionGroup popupGroup = new DefaultActionGroup(null, false); popupGroup.addAction(new HgNewBranchAction(myProject, Collections.singletonList(myRepository), myRepository.getRoot())); popupGroup.addAction(new HgNewBookmarkAction(myProject, Collections.singletonList(myRepository), myRepository.getRoot())); - + popupGroup.addAction(new HgShowUnnamedHeadsForCurrentBranchAction(myProject, myRepository)); if (toInsert != null) { popupGroup.addAll(toInsert); } @@ -86,9 +89,9 @@ public class HgBranchPopupActions { } popupGroup.addSeparator("Branches"); - List branchNames = HgUtil.getNamesWithoutHashes(myRepository.getBranches()); - Collections.sort(branchNames); - for (String branch : branchNames) { + List branchNamesList = new ArrayList(myRepository.getBranches().keySet()); + Collections.sort(branchNamesList); + for (String branch : branchNamesList) { if (!branch.equals(myRepository.getCurrentBranch())) { // don't show current branch in the list popupGroup.add(new BranchActions(myProject, branch, myRepository)); } @@ -175,6 +178,73 @@ public class HgBranchPopupActions { } } + static private class HgShowUnnamedHeadsForCurrentBranchAction extends ActionGroup { + @NotNull final Project myProject; + @NotNull final HgRepository myRepository; + @NotNull final String myCurrentBranchName; + @NotNull Collection myHeads = new HashSet(); + + public HgShowUnnamedHeadsForCurrentBranchAction(@NotNull Project project, + @NotNull HgRepository repository) { + super(null, true); + myProject = project; + myRepository = repository; + myCurrentBranchName = repository.getCurrentBranch(); + getTemplatePresentation().setText(String.format("Unnamed heads for %s", myCurrentBranchName)); + ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { + @Override + public void run() { + myHeads = filterUnnamedHeads(); + } + }); + } + + @NotNull + private Collection filterUnnamedHeads() { + Collection branchWithHashes = myRepository.getBranches().get(myCurrentBranchName); + if (branchWithHashes == null) { + // repository is fresh or branch is fresh. + return Collections.emptySet(); + } + else { + List parents = new HgWorkingCopyRevisionsCommand(myProject).parents(myRepository.getRoot()); + if (parents.size() == 1) { + Collection bookmarkHashes = ContainerUtil.map(myRepository.getBookmarks(), new Function() { + + @Override + public Hash fun(HgNameWithHashInfo info) { + return info.getHash(); + } + }); + branchWithHashes.removeAll(bookmarkHashes); + branchWithHashes.remove(HashImpl.build(parents.get(0).getChangeset())); + } + } + return branchWithHashes; + } + + @NotNull + @Override + public AnAction[] getChildren(@Nullable AnActionEvent e) { + List branchHeadActions = new ArrayList(); + for (Hash hash : myHeads) { + branchHeadActions.add(new BranchActions(myProject, hash.toShortString(), myRepository)); + } + return ContainerUtil.toArray(branchHeadActions, new AnAction[branchHeadActions.size()]); + } + + @Override + public void update(final AnActionEvent e) { + if (myRepository.isFresh()) { + e.getPresentation().setEnabled(false); + e.getPresentation().setDescription("Checkout of a new branch is not possible before the first commit."); + } + else if (Repository.State.MERGING.equals(myRepository.getState())) { + e.getPresentation().setEnabled(false); + } + } + } + /** * Actions available for branches. diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java b/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java index fb3f17d34a63..13d6e8c9edc1 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java @@ -103,18 +103,22 @@ public class HgLogProvider implements VcsLogProvider { } repository.update(); - Collection branches = repository.getBranches(); + Map> branches = repository.getBranches(); Collection bookmarks = repository.getBookmarks(); Collection tags = repository.getTags(); Collection localTags = repository.getLocalTags(); Collection refs = new ArrayList(branches.size() + bookmarks.size()); - for (HgNameWithHashInfo branchInfo : branches) { - refs.add(myVcsObjectsFactory.createRef(myVcsObjectsFactory.createHash(branchInfo.getHash()), branchInfo.getName(), HgRefManager.BRANCH, root)); + for (Map.Entry> entry : branches.entrySet()) { + String branchName = entry.getKey(); + for (Hash hash : entry.getValue()) { + refs.add(myVcsObjectsFactory.createRef(hash, branchName, HgRefManager.BRANCH, root)); + } } + for (HgNameWithHashInfo bookmarkInfo : bookmarks) { - refs.add(myVcsObjectsFactory.createRef(myVcsObjectsFactory.createHash(bookmarkInfo.getHash()), bookmarkInfo.getName(), + refs.add(myVcsObjectsFactory.createRef(bookmarkInfo.getHash(), bookmarkInfo.getName(), HgRefManager.BOOKMARK, root)); } String currentRevision = repository.getCurrentRevision(); @@ -122,10 +126,10 @@ public class HgLogProvider implements VcsLogProvider { refs.add(myVcsObjectsFactory.createRef(myVcsObjectsFactory.createHash(currentRevision), "tip", HgRefManager.HEAD, root)); } for (HgNameWithHashInfo tagInfo : tags) { - refs.add(myVcsObjectsFactory.createRef(myVcsObjectsFactory.createHash(tagInfo.getHash()), tagInfo.getName(), HgRefManager.TAG, root)); + refs.add(myVcsObjectsFactory.createRef(tagInfo.getHash(), tagInfo.getName(), HgRefManager.TAG, root)); } for (HgNameWithHashInfo localTagInfo : localTags) { - refs.add(myVcsObjectsFactory.createRef(myVcsObjectsFactory.createHash(localTagInfo.getHash()), localTagInfo.getName(), + refs.add(myVcsObjectsFactory.createRef(localTagInfo.getHash(), localTagInfo.getName(), HgRefManager.LOCAL_TAG, root)); } return refs; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepoInfo.java b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepoInfo.java index 90c59372dc8e..133bfc7ce869 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepoInfo.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepoInfo.java @@ -17,14 +17,12 @@ package org.zmlx.hg4idea.repo; import com.google.common.base.Objects; import com.intellij.dvcs.repo.Repository; +import com.intellij.vcs.log.Hash; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgNameWithHashInfo; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.Set; +import java.util.*; /** * @author Nadya Zabrodina @@ -34,7 +32,7 @@ public class HgRepoInfo { @Nullable private final String myCurrentRevision; @NotNull private final Repository.State myState; @Nullable private String myCurrentBookmark = null; - @NotNull private Set myBranches = Collections.emptySet(); + @NotNull private Map> myBranches = Collections.emptyMap(); @NotNull private Set myBookmarks = Collections.emptySet(); @NotNull private Set myTags = Collections.emptySet(); @NotNull private Set myLocalTags = Collections.emptySet(); @@ -42,7 +40,7 @@ public class HgRepoInfo { public HgRepoInfo(@NotNull String currentBranch, @Nullable String currentRevision, @NotNull Repository.State state, - @NotNull Collection branches, + @NotNull Map> branches, @NotNull Collection bookmarks, @Nullable String currentBookmark, @NotNull Collection tags, @@ -50,7 +48,7 @@ public class HgRepoInfo { myCurrentBranch = currentBranch; myCurrentRevision = currentRevision; myState = state; - myBranches = new LinkedHashSet(branches); + myBranches = branches; myBookmarks = new LinkedHashSet(bookmarks); myCurrentBookmark = currentBookmark; myTags = new LinkedHashSet(tags); @@ -63,7 +61,7 @@ public class HgRepoInfo { } @NotNull - public Collection getBranches() { + public Map> getBranches() { return myBranches; } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepository.java b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepository.java index fbaaa4f14a94..c698d50efaab 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepository.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepository.java @@ -18,11 +18,14 @@ package org.zmlx.hg4idea.repo; import com.intellij.dvcs.repo.Repository; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.vcs.log.Hash; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgNameWithHashInfo; import java.util.Collection; +import java.util.Map; +import java.util.Set; public interface HgRepository extends Repository { @@ -38,8 +41,11 @@ public interface HgRepository extends Repository { @NotNull String getCurrentBranch(); + /** + * @return map with heavy branch names and appropriate set of head hashes + */ @NotNull - Collection getBranches(); + Map> getBranches(); @NotNull Collection getBookmarks(); diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java index c95eb59a4449..db616ee6215c 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java @@ -22,6 +22,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.vcs.log.Hash; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgNameWithHashInfo; @@ -29,6 +30,8 @@ import org.zmlx.hg4idea.HgVcs; import org.zmlx.hg4idea.util.HgUtil; import java.util.Collection; +import java.util.Map; +import java.util.Set; /** @@ -96,7 +99,7 @@ public class HgRepositoryImpl extends RepositoryImpl implements HgRepository { @Override @NotNull - public Collection getBranches() { + public Map> getBranches() { return myInfo.getBranches(); } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryReader.java b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryReader.java index bed74806135c..1552b393a478 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryReader.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryReader.java @@ -20,6 +20,7 @@ import com.intellij.dvcs.repo.Repository; import com.intellij.dvcs.repo.RepositoryUtil; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; +import com.intellij.vcs.log.Hash; import com.intellij.vcs.log.VcsLogObjectsFactory; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -110,8 +111,8 @@ public class HgRepositoryReader { } @NotNull - public Collection readBranches() { - List branches = new ArrayList(); + public Map> readBranches() { + Map> branchesWithHashes = new HashMap>(); // Set branchNames = new HashSet(); if (isBranchInfoAvailable()) { String[] branchesWithHeads = RepositoryUtil.tryLoadFile(myBranchHeadsFile).split("\n"); @@ -120,13 +121,18 @@ public class HgRepositoryReader { Matcher matcher = HASH_NAME.matcher(branchesWithHeads[i]); if (matcher.matches()) { String name = matcher.group(2); - // if (branchNames.add(name)) { - branches.add(new HgNameWithHashInfo(name, myVcsObjectsFactory.createHash(matcher.group(1)))); - //} + if (branchesWithHashes.containsKey(name)) { + branchesWithHashes.get(name).add(myVcsObjectsFactory.createHash(matcher.group(1))); + } + else { + Set hashes = new HashSet(); + hashes.add(myVcsObjectsFactory.createHash(matcher.group(1))); + branchesWithHashes.put(name, hashes); + } } } } - return branches; + return branchesWithHashes; } public boolean isMergeInProgress() { diff --git a/plugins/hg4idea/testSrc/hg4idea/test/repo/HgRealRepositoryReaderTest.java b/plugins/hg4idea/testSrc/hg4idea/test/repo/HgRealRepositoryReaderTest.java index 306aade615ba..a1ec0c86a56f 100644 --- a/plugins/hg4idea/testSrc/hg4idea/test/repo/HgRealRepositoryReaderTest.java +++ b/plugins/hg4idea/testSrc/hg4idea/test/repo/HgRealRepositoryReaderTest.java @@ -19,7 +19,6 @@ import com.intellij.dvcs.repo.Repository; import com.intellij.openapi.vcs.VcsTestUtil; import hg4idea.test.HgPlatformTest; import org.jetbrains.annotations.NotNull; -import org.zmlx.hg4idea.HgVcs; import org.zmlx.hg4idea.repo.HgRepositoryReader; import org.zmlx.hg4idea.util.HgUtil; @@ -59,7 +58,7 @@ public class HgRealRepositoryReaderTest extends HgPlatformTest { } public void testBranches() { - VcsTestUtil.assertEqualCollections(HgUtil.getNamesWithoutHashes(myRepositoryReader.readBranches()), + VcsTestUtil.assertEqualCollections(myRepositoryReader.readBranches().keySet(), Arrays.asList("default", "branchA", "branchB")); } diff --git a/plugins/hg4idea/testSrc/hg4idea/test/repo/HgRepositoryReaderTest.java b/plugins/hg4idea/testSrc/hg4idea/test/repo/HgRepositoryReaderTest.java index bb94270fce05..dec100404c24 100644 --- a/plugins/hg4idea/testSrc/hg4idea/test/repo/HgRepositoryReaderTest.java +++ b/plugins/hg4idea/testSrc/hg4idea/test/repo/HgRepositoryReaderTest.java @@ -80,7 +80,7 @@ public class HgRepositoryReaderTest extends HgPlatformTest { } public void testBranches() { - Collection branches = HgUtil.getNamesWithoutHashes(myRepositoryReader.readBranches()); + Collection branches = myRepositoryReader.readBranches().keySet(); VcsTestUtil.assertEqualCollections(branches, myBranches); }