Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dmitry Trofimov
2011-11-17 17:04:49 +01:00
11 changed files with 435 additions and 53 deletions
@@ -619,4 +619,8 @@ public class GitUtil {
}
return null;
}
public static boolean repoContainsRemoteBranch(@NotNull GitRepository repository, @NotNull GitBranch dest) {
return repository.getBranches().getRemoteBranches().contains(dest);
}
}
@@ -113,7 +113,8 @@ public class DetailsCache {
myBranches.clear();
myStash.clear();
// will be cleared by itself; commits are not changed while they have same hash
//myCache.clear();
// uncommented because of reference caching
myCache.clear();
}
}
@@ -0,0 +1,226 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package git4idea.push;
import com.intellij.openapi.util.IconLoader;
import com.intellij.ui.components.JBLabel;
import com.intellij.util.ui.GridBag;
import com.intellij.util.ui.UIUtil;
import git4idea.repo.GitRemote;
import git4idea.repo.GitRepository;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import java.util.List;
/**
* @author Kirill Likhodedov
*/
class GitManualPushToBranch extends JPanel {
private final Collection<GitRepository> myRepositories;
private final JCheckBox myManualPush;
private final JTextField myDestBranchTextField;
private final JBLabel myComment;
private final JButton myRefreshButton;
private final RemoteSelector myRemoteSelector;
private final JComponent myRemoteSelectorComponent;
GitManualPushToBranch(@NotNull Collection<GitRepository> repositories,
@NotNull final Runnable performOnRefresh) {
super();
myRepositories = repositories;
myManualPush = new JCheckBox("Push current branch to: ", false);
myManualPush.setMnemonic('b');
myDestBranchTextField = new JTextField(15);
myComment = new JBLabel("This will apply to all selected repositories", UIUtil.ComponentStyle.SMALL);
myRefreshButton = new JButton(IconLoader.getIcon("/actions/sync.png"));
myRefreshButton.setToolTipText("Refresh commit list");
myRefreshButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
performOnRefresh.run();
}
});
myRemoteSelector = new RemoteSelector(getRemotesWithCommonNames(repositories));
myRemoteSelectorComponent = myRemoteSelector.createComponent();
setDefaultComponentsEnabledState(myManualPush.isSelected());
myManualPush.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
boolean isManualPushSelected = myManualPush.isSelected();
setDefaultComponentsEnabledState(isManualPushSelected);
}
});
layoutComponents();
}
private void setDefaultComponentsEnabledState(boolean selected) {
setComponentsEnabledState(selected, myRemoteSelectorComponent, myDestBranchTextField, myRefreshButton, myComment);
}
private void layoutComponents() {
JPanel panel = new JPanel();
GridBagLayout layout = new GridBagLayout();
panel.setLayout(layout);
GridBag g = new GridBag()
.setDefaultFill(GridBagConstraints.NONE)
.setDefaultAnchor(GridBagConstraints.LINE_START)
.setDefaultWeightX(1, 1);
panel.add(myManualPush, g.nextLine().next());
panel.add(myRemoteSelectorComponent, g.next());
panel.add(myDestBranchTextField, g.next());
panel.add(myRefreshButton, g.next());
g.nextLine();
if (myRepositories.size() > 1) {
GridBagConstraints constraints = new GridBagConstraints();
constraints.gridwidth = GridBagConstraints.REMAINDER;
constraints.anchor = GridBagConstraints.LINE_START;
constraints.gridx = 0;
constraints.gridy = 1;
constraints.insets = new Insets(0, 28, 0, 0);
//panel.add(myComment, g.insets(0, 20, 0, 0).coverLine().next());
panel.add(myComment, constraints);
}
setLayout(new BorderLayout());
add(panel, BorderLayout.WEST);
}
boolean canBeUsed() {
return myManualPush.isSelected() && !myDestBranchTextField.getText().isEmpty();
}
@NotNull
String getBranchToPush() {
return myDestBranchTextField.getText();
}
void setBranchToPushIfNotSet(@NotNull String text) {
if (myDestBranchTextField.getText().isEmpty()) {
myDestBranchTextField.setText(text);
}
}
@NotNull
GitRemote getSelectedRemote() {
return myRemoteSelector.getSelectedValue();
}
private static void setComponentsEnabledState(boolean enabled, JComponent... components) {
for (JComponent component : components) {
component.setEnabled(enabled);
}
}
@NotNull
private static Collection<GitRemote> getRemotesWithCommonNames(@NotNull Collection<GitRepository> repositories) {
if (repositories.isEmpty()) {
return Collections.emptyList();
}
Iterator<GitRepository> iterator = repositories.iterator();
List<GitRemote> commonRemotes = new ArrayList<GitRemote>(iterator.next().getRemotes());
while (iterator.hasNext()) {
GitRepository repository = iterator.next();
Collection<String> remoteNames = getRemoteNames(repository);
for (Iterator<GitRemote> commonIter = commonRemotes.iterator(); commonIter.hasNext(); ) {
GitRemote remote = commonIter.next();
if (!remoteNames.contains(remote.getName())) {
commonIter.remove();
}
}
}
return commonRemotes;
}
@NotNull
private static Collection<String> getRemoteNames(@NotNull GitRepository repository) {
Collection<String> names = new ArrayList<String>(repository.getRemotes().size());
for (GitRemote remote : repository.getRemotes()) {
names.add(remote.getName());
}
return names;
}
/**
* Component to select remotes.
* If there is only one remote, JLabel is used instead of JCombobox.
*/
private static class RemoteSelector {
private final Collection<GitRemote> myRemotes;
private JComboBox myRemoteCombobox;
private RemoteSelector(@NotNull Collection<GitRemote> remotes) {
myRemotes = remotes;
}
@NotNull
JComponent createComponent() {
//if (myRemotes.size() == 1) {
// JBLabel label = new JBLabel(myRemotes.iterator().next().getName());
// label.setToolTipText("Remote");
// return label;
//} else {
myRemoteCombobox = new JComboBox();
myRemoteCombobox.setRenderer(new RemoteCellRenderer());
for (GitRemote remote : myRemotes) {
myRemoteCombobox.addItem(remote);
}
myRemoteCombobox.setToolTipText("Select remote");
return myRemoteCombobox;
//}
}
@NotNull
GitRemote getSelectedValue() {
//if (myRemotes.size() == 1) {
// return myRemotes.iterator().next();
//}
return (GitRemote)myRemoteCombobox.getSelectedItem();
}
private static class RemoteCellRenderer implements ListCellRenderer {
public static final DefaultListCellRenderer DEFAULT_RENDERER = new DefaultListCellRenderer();
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Component renderer = DEFAULT_RENDERER.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value instanceof GitRemote) {
((JLabel) renderer).setText(((GitRemote)value).getName());
}
return renderer;
}
}
}
}
@@ -29,16 +29,24 @@ import java.util.List;
*/
final class GitPushBranchInfo {
private final GitBranch mySourceBranch;
private final GitBranch myDestBranch;
private final boolean myNewBranch;
private final List<GitCommit> myCommits;
GitPushBranchInfo(@NotNull GitBranch destBranch, @NotNull List<GitCommit> commits) {
GitPushBranchInfo(@NotNull GitBranch sourceBranch, @NotNull GitBranch destBranch, @NotNull List<GitCommit> commits, boolean newBranch) {
mySourceBranch = sourceBranch;
myCommits = commits;
myDestBranch = destBranch;
myNewBranch = newBranch;
}
GitPushBranchInfo(@NotNull GitPushBranchInfo pushBranchInfo) {
this(pushBranchInfo.getDestBranch(), pushBranchInfo.getCommits());
this(pushBranchInfo.getSourceBranch(), pushBranchInfo.getDestBranch(), pushBranchInfo.getCommits(), pushBranchInfo.isNewBranchCreated());
}
boolean isNewBranchCreated() {
return myNewBranch;
}
@NotNull
@@ -50,4 +58,9 @@ final class GitPushBranchInfo {
List<GitCommit> getCommits() {
return new ArrayList<GitCommit>(myCommits);
}
@NotNull
public GitBranch getSourceBranch() {
return mySourceBranch;
}
}
@@ -15,6 +15,9 @@
*/
package git4idea.push;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Result of pushing a single branch.
*
@@ -24,28 +27,35 @@ final class GitPushBranchResult {
private final Type myType;
private final int myNumberOfPushedCommits;
private final String myTargetBranchName;
enum Type {
SUCCESS,
NEW_BRANCH,
REJECTED,
ERROR
}
private GitPushBranchResult(Type type, int numberOfPushedCommits) {
private GitPushBranchResult(Type type, int numberOfPushedCommits, @Nullable String targetBranchName) {
myType = type;
myNumberOfPushedCommits = numberOfPushedCommits;
myTargetBranchName = targetBranchName;
}
static GitPushBranchResult success(int numberOfPushedCommits) {
return new GitPushBranchResult(Type.SUCCESS, numberOfPushedCommits);
return new GitPushBranchResult(Type.SUCCESS, numberOfPushedCommits, null);
}
static GitPushBranchResult newBranch(String targetBranchName) {
return new GitPushBranchResult(Type.NEW_BRANCH, 0, targetBranchName);
}
static GitPushBranchResult rejected() {
return new GitPushBranchResult(Type.REJECTED, 0);
return new GitPushBranchResult(Type.REJECTED, 0, null);
}
static GitPushBranchResult error() {
return new GitPushBranchResult(Type.ERROR, 0);
return new GitPushBranchResult(Type.ERROR, 0, null);
}
int getNumberOfPushedCommits() {
@@ -64,4 +74,13 @@ final class GitPushBranchResult {
return myType == Type.ERROR;
}
boolean isNewBranch() {
return myType == Type.NEW_BRANCH;
}
@NotNull
String getTargetBranchName() {
return myTargetBranchName != null ? myTargetBranchName : "";
}
}
@@ -59,6 +59,7 @@ public class GitPushDialog extends DialogWrapper {
private final JBLoadingPanel myLoadingPanel;
private final JCheckBox myPushAllCheckbox;
private final Object COMMITS_LOADING_LOCK = new Object();
private final GitManualPushToBranch myRefspecPanel;
public GitPushDialog(@NotNull Project project) {
super(project);
@@ -73,28 +74,16 @@ public class GitPushDialog extends DialogWrapper {
myPushAllCheckbox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
loadCommitsInBackground(myPushAllCheckbox.isSelected());
loadCommitsInBackground();
}
});
/* hidden: it may confuse users, the target is not clear, hidden until really needed,
not removed completely because it is default behavior for 'git push' in command line. */
myPushAllCheckbox.setVisible(false);
myListPanel = new GitPushLog(myProject, myRepositories, new Consumer<Boolean>() {
@Override public void consume(Boolean checked) {
if (checked) {
setOKActionEnabled(true);
} else {
Collection<GitRepository> repositories = myListPanel.getSelectedRepositories();
if (repositories.isEmpty()) {
setOKActionEnabled(false);
} else {
setOKActionEnabled(true);
}
}
}
});
myListPanel = new GitPushLog(myProject, myRepositories, new RepositoryCheckboxListener());
myRefspecPanel = new GitManualPushToBranch(myRepositories, new RefreshButtonListener());
init();
setOKButtonText("Push");
setTitle("Git Push");
@@ -103,31 +92,33 @@ public class GitPushDialog extends DialogWrapper {
@Override
protected JComponent createCenterPanel() {
JPanel optionsPanel = new JPanel(new BorderLayout());
optionsPanel.add(myPushAllCheckbox);
optionsPanel.add(myPushAllCheckbox, BorderLayout.NORTH);
optionsPanel.add(myRefspecPanel);
myRootPanel = new JPanel(new BorderLayout());
myRootPanel = new JPanel(new BorderLayout(0, 15));
myRootPanel.add(createCommitListPanel(), BorderLayout.CENTER);
myRootPanel.add(optionsPanel, BorderLayout.SOUTH);
return myRootPanel;
}
private JComponent createCommitListPanel() {
myLoadingPanel.add(myListPanel, BorderLayout.CENTER);
loadCommitsInBackground(false);
loadCommitsInBackground();
JPanel commitListPanel = new JPanel(new BorderLayout());
commitListPanel.add(myLoadingPanel, BorderLayout.CENTER);
return commitListPanel;
}
private void loadCommitsInBackground(final boolean pushAll) {
private void loadCommitsInBackground() {
myLoadingPanel.startLoading();
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
public void run() {
final AtomicReference<String> error = new AtomicReference<String>();
synchronized (COMMITS_LOADING_LOCK) {
error.set(collectInfoToPush(pushAll));
error.set(collectInfoToPush());
}
UIUtil.invokeLaterIfNeeded(new Runnable() {
@@ -138,17 +129,50 @@ public class GitPushDialog extends DialogWrapper {
} else {
myListPanel.setCommits(myGitCommitsToPush);
}
myRefspecPanel.setBranchToPushIfNotSet(getTrackedCurrentBranchName());
myLoadingPanel.stopLoading();
}
});
}
});
}
@NotNull
private String getTrackedCurrentBranchName() {
if (myGitCommitsToPush != null) {
Collection<GitRepository> repositories = myGitCommitsToPush.getRepositories();
if (!repositories.isEmpty()) {
GitRepository repository = repositories.iterator().next();
GitBranch currentBranch = repository.getCurrentBranch();
assert currentBranch != null;
return getNameWithoutRemote(myGitCommitsToPush.get(repository).get(currentBranch).getDestBranch());
}
}
return "";
}
@NotNull
private String getNameWithoutRemote(@NotNull GitBranch remoteBranch) {
String remoteName = myRefspecPanel.getSelectedRemote().getName() + "/";
String branchName = remoteBranch.getName();
if (branchName.startsWith(remoteName)) {
return branchName.substring(remoteName.length());
}
else {
// we are taking the current branch of the first repository
// it is possible (though unlikely), that this branch has other remote than the common remote selected in the refspec panel
// then we return the full branch name.
// the push won't work absolutely correct, if the remote doesn't have this branch, but it is not our problem in the case of
// several repositories with different remotes sets and different branches.
return remoteBranch.getFullName();
}
}
@Nullable
private String collectInfoToPush(boolean pushAll) {
private String collectInfoToPush() {
try {
myPushSpecs = pushAll ? pushSpecsForPushAll() : pushSpecsForCurrentBranches();
boolean pushAll = myPushAllCheckbox.isSelected();
myPushSpecs = pushAll ? pushSpecsForPushAll() : pushSpecsForCurrentOrEnteredBranches();
myGitCommitsToPush = myPusher.collectCommitsToPush(myPushSpecs);
return null;
}
@@ -159,7 +183,7 @@ public class GitPushDialog extends DialogWrapper {
}
}
private Map<GitRepository, GitPushSpec> pushSpecsForCurrentBranches() throws VcsException {
private Map<GitRepository, GitPushSpec> pushSpecsForCurrentOrEnteredBranches() throws VcsException {
Map<GitRepository, GitPushSpec> defaultSpecs = new HashMap<GitRepository, GitPushSpec>();
for (GitRepository repository : myRepositories) {
GitBranch currentBranch = repository.getCurrentBranch();
@@ -178,6 +202,19 @@ public class GitPushDialog extends DialogWrapper {
remote = remoteAndBranch.getFirst();
tracked = remoteAndBranch.getSecond();
}
if (myRefspecPanel.canBeUsed()) {
String manualBranchName = myRefspecPanel.getBranchToPush();
GitBranch manualBranch = findRemoteBranchByName(repository, remote, manualBranchName);
if (manualBranch == null) {
if (!manualBranchName.startsWith("refs/remotes/")) {
manualBranchName = myRefspecPanel.getSelectedRemote().getName() + "/" + manualBranchName;
}
manualBranch = new GitBranch(manualBranchName, false, true);
}
tracked = manualBranch;
}
GitPushSpec pushSpec = new GitPushSpec(remote, currentBranch, tracked);
defaultSpecs.put(repository, pushSpec);
}
@@ -227,7 +264,7 @@ public class GitPushDialog extends DialogWrapper {
synchronized (COMMITS_LOADING_LOCK) {
GitCommitsByRepoAndBranch selectedCommits;
if (myGitCommitsToPush == null) {
collectInfoToPush(myPushAllCheckbox.isSelected());
collectInfoToPush();
selectedCommits = myGitCommitsToPush;
} else {
Collection<GitRepository> selectedRepositories = myListPanel.getSelectedRepositories();
@@ -236,4 +273,27 @@ public class GitPushDialog extends DialogWrapper {
return new GitPushInfo(selectedCommits, myPushSpecs);
}
}
private class RepositoryCheckboxListener implements Consumer<Boolean> {
@Override public void consume(Boolean checked) {
if (checked) {
setOKActionEnabled(true);
} else {
Collection<GitRepository> repositories = myListPanel.getSelectedRepositories();
if (repositories.isEmpty()) {
setOKActionEnabled(false);
} else {
setOKActionEnabled(true);
}
}
}
}
private class RefreshButtonListener implements Runnable {
@Override
public void run() {
loadCommitsInBackground();
}
}
}
@@ -36,7 +36,6 @@ import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.tree.TreeUtil;
import git4idea.GitBranch;
import git4idea.GitUtil;
import git4idea.branch.GitBranchPair;
import git4idea.history.browser.GitCommit;
import git4idea.repo.GitRepository;
import org.jetbrains.annotations.NotNull;
@@ -208,7 +207,7 @@ class GitPushLog extends JPanel implements TypeSafeDataProvider {
}
private static DefaultMutableTreeNode createBranchNode(@NotNull GitBranch branch, @NotNull GitPushBranchInfo branchInfo) {
DefaultMutableTreeNode branchNode = new DefaultMutableTreeNode(new GitBranchPair(branch, branchInfo.getDestBranch()));
DefaultMutableTreeNode branchNode = new DefaultMutableTreeNode(branchInfo);
for (GitCommit commit : branchInfo.getCommits()) {
branchNode.add(new DefaultMutableTreeNode(commit));
}
@@ -290,10 +289,10 @@ class GitPushLog extends JPanel implements TypeSafeDataProvider {
Font font = EditorColorsManager.getInstance().getGlobalScheme().getFont(EditorFontType.PLAIN); // using probable monospace font to emulate table
renderer.setFont(font);
SimpleTextAttributes smallGrey = new SimpleTextAttributes(SimpleTextAttributes.STYLE_SMALLER, UIUtil.getInactiveTextColor());
if (userObject instanceof GitCommit) {
GitCommit commit = (GitCommit)userObject;
SimpleTextAttributes small = new SimpleTextAttributes(SimpleTextAttributes.STYLE_SMALLER, renderer.getForeground());
SimpleTextAttributes smallGrey = new SimpleTextAttributes(SimpleTextAttributes.STYLE_SMALLER, UIUtil.getInactiveTextColor());
renderer.append(commit.getShortHash().toString(), smallGrey);
renderer.append(String.format(" %" + myDateMaxWidth + "s ", getDateString(commit)), smallGrey);
renderer.append(commit.getSubject(), small);
@@ -302,13 +301,20 @@ class GitPushLog extends JPanel implements TypeSafeDataProvider {
String repositoryPath = calcRootPath((GitRepository)userObject);
renderer.append(repositoryPath, SimpleTextAttributes.GRAY_ATTRIBUTES);
}
else if (userObject instanceof GitBranchPair) {
GitBranchPair branchPair = (GitBranchPair) userObject;
GitBranch fromBranch = branchPair.getBranch();
GitBranch dest = branchPair.getDest();
assert dest != null : "Destination branch can't be null for branch " + fromBranch;
else if (userObject instanceof GitPushBranchInfo) {
GitPushBranchInfo branchInfo = (GitPushBranchInfo) userObject;
GitBranch fromBranch = branchInfo.getSourceBranch();
GitBranch dest = branchInfo.getDestBranch();
renderer.append(fromBranch.getName() + " -> " + dest.getName(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
String text = fromBranch.getName() + " -> ";
if (branchInfo.isNewBranchCreated()) {
text += "+";
}
text += dest.getName();
renderer.append(text, branchInfo.isNewBranchCreated() ? SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES : SimpleTextAttributes.REGULAR_ATTRIBUTES);
if (branchInfo.isNewBranchCreated()) {
renderer.append(" new branch will be created, showing last 10 commits on the current branch", smallGrey);
}
}
else if (userObject instanceof FakeCommit) {
int spaces = 6 + 15 + 3 + 30;
@@ -132,7 +132,7 @@ final class GitPushRepoResult {
}
@NotNull
String getPerBranchesReport() {
String getPerBranchesNonErrorReport() {
StringBuilder sb = new StringBuilder();
int i = 0;
for (Map.Entry<GitBranch, GitPushBranchResult> entry : myBranchResults.entrySet()) {
@@ -141,7 +141,11 @@ final class GitPushRepoResult {
if (branchResult.isSuccess()) {
sb.append(bold(branch.getName()) + ": pushed " + commits(branchResult.getNumberOfPushedCommits()));
} else {
}
else if (branchResult.isNewBranch()) {
sb.append(bold(branch.getName()) + " pushed to new branch " + bold(branchResult.getTargetBranchName()));
}
else {
sb.append(code(branch.getName())).append(": rejected");
}
@@ -225,8 +225,12 @@ class GitPushResult {
}
notificationType = NotificationType.WARNING;
} else {
title = "Pushed " + pushedCommitsNumber + " " + StringUtil.pluralize("commit", pushedCommitsNumber);
notificationType = NotificationType.INFORMATION;
if (pushedCommitsNumber == 0) { // happens on new branch creation
title = "Pushed successfully";
} else {
title = "Pushed " + pushedCommitsNumber + " " + StringUtil.pluralize("commit", pushedCommitsNumber);
}
}
String errorReport = reportForGroup(groupedResult.myErrorResults, GroupedResult.Type.ERROR);
@@ -291,7 +295,7 @@ class GitPushResult {
sb.append("<code>" + repository.getPresentableUrl() + "</code>:<br/>");
}
if (resultType == GroupedResult.Type.SUCCESS || resultType == GroupedResult.Type.REJECT) {
sb.append(result.getPerBranchesReport());
sb.append(result.getPerBranchesNonErrorReport());
} else {
sb.append(result.getOutput());
}
@@ -168,16 +168,28 @@ public final class GitPusher {
GitBranch dest = sourceDest.getDest();
assert dest != null : "Destination branch can't be null here for branch " + source;
List<GitCommit> commits = collectCommitsToPush(repository, source.getName(), dest.getName());
List<GitCommit> commits;
boolean newBranch;
if (GitUtil.repoContainsRemoteBranch(repository, dest)) {
commits = collectCommitsToPush(repository, source.getName(), dest.getName());
newBranch = false;
}
else {
commits = collectRecentCommitsOnBranch(repository, source);
newBranch = true;
}
if (!commits.isEmpty()) {
commitsByBranch.put(source, new GitPushBranchInfo(dest, commits));
commitsByBranch.put(source, new GitPushBranchInfo(source, dest, commits, newBranch));
}
}
return new GitCommitsByBranch(commitsByBranch);
}
private List<GitCommit> collectRecentCommitsOnBranch(GitRepository repository, GitBranch source) throws VcsException {
return GitHistoryUtils.history(myProject, repository.getRoot(), "--max-count=10", source.getName());
}
@NotNull
private List<GitCommit> collectCommitsToPush(@NotNull GitRepository repository, @NotNull String source, @NotNull String destination)
throws VcsException {
@@ -350,7 +362,11 @@ public final class GitPusher {
@NotNull
private static GitPushBranchResult successfulResultForBranch(@NotNull GitCommitsByBranch commitsByBranch, @NotNull GitBranch branch) {
return GitPushBranchResult.success(commitsByBranch.get(branch).getCommits().size());
GitPushBranchInfo branchInfo = commitsByBranch.get(branch);
if (branchInfo.isNewBranchCreated()) {
return GitPushBranchResult.newBranch(branchInfo.getDestBranch().getName());
}
return GitPushBranchResult.success(branchInfo.getCommits().size());
}
private static boolean branchInRejected(@NotNull GitBranch branch, @NotNull Collection<String> rejectedBranches) {
@@ -17,29 +17,36 @@ package com.intellij.codeInsight.editorActions;
import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegateAdapter;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.highlighter.EditorHighlighter;
import com.intellij.openapi.editor.highlighter.HighlighterIterator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.psi.xml.XmlTokenType;
import org.jetbrains.annotations.NotNull;
public class EnterBetweenXmlTagsHandler extends EnterHandlerDelegateAdapter {
public Result preprocessEnter(@NotNull final PsiFile file, @NotNull final Editor editor, @NotNull final Ref<Integer> caretOffset, @NotNull final Ref<Integer> caretAdvance,
@NotNull final DataContext dataContext, final EditorActionHandler originalHandler) {
if (file instanceof XmlFile && isBetweenXmlTags(editor, caretOffset.get().intValue())) {
final Project project = PlatformDataKeys.PROJECT.getData(dataContext);
if (file instanceof XmlFile && isBetweenXmlTags(project, editor, file, caretOffset.get().intValue())) {
originalHandler.execute(editor, dataContext);
return Result.DefaultForceIndent;
}
return Result.Continue;
}
private static boolean isBetweenXmlTags(Editor editor, int offset) {
private static boolean isBetweenXmlTags(Project project, Editor editor, PsiFile file, int offset) {
if (offset == 0) return false;
CharSequence chars = editor.getDocument().getCharsSequence();
if (chars.charAt(offset - 1) != '>') return false;
@@ -47,6 +54,11 @@ public class EnterBetweenXmlTagsHandler extends EnterHandlerDelegateAdapter {
EditorHighlighter highlighter = ((EditorEx)editor).getHighlighter();
HighlighterIterator iterator = highlighter.createIterator(offset - 1);
if (iterator.getTokenType() != XmlTokenType.XML_TAG_END) return false;
if (isAtTheEndOfEmptyTag(project, editor, file, iterator)) {
return false;
}
iterator.retreat();
int retrieveCount = 1;
@@ -62,4 +74,21 @@ public class EnterBetweenXmlTagsHandler extends EnterHandlerDelegateAdapter {
iterator.advance();
return !iterator.atEnd() && iterator.getTokenType() == XmlTokenType.XML_END_TAG_START;
}
private static boolean isAtTheEndOfEmptyTag(Project project, Editor editor, PsiFile file, HighlighterIterator iterator) {
if (iterator.getTokenType() != XmlTokenType.XML_TAG_END) {
return false;
}
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
final PsiElement element = file.findElementAt(iterator.getStart());
if (element == null) {
return false;
}
final PsiElement parent = element.getParent();
return parent instanceof XmlTag &&
parent.getTextRange().getEndOffset() == iterator.getEnd();
}
}