git4idea: refactored rebase editor service to support other types of rebase editors

This commit is contained in:
Constantine Plotnikov
2009-11-03 15:58:33 +03:00
parent 2bc7c28fd3
commit e7cabd4603
5 changed files with 191 additions and 157 deletions
@@ -21,9 +21,9 @@ import com.intellij.openapi.vfs.VirtualFile;
import git4idea.commands.GitHandler;
import git4idea.commands.GitLineHandler;
import git4idea.i18n.GitBundle;
import git4idea.rebase.GitInteractiveRebaseEditorHandler;
import git4idea.rebase.GitRebaseActionDialog;
import git4idea.rebase.GitRebaseUtils;
import git4idea.rebase.GitRebaseEditorHandler;
import org.jetbrains.annotations.NonNls;
import java.util.Iterator;
@@ -70,7 +70,7 @@ public abstract class GitAbstractRebaseResumeAction extends GitRebaseActionBase
* {@inheritDoc}
*/
@Override
protected void configureEditor(GitRebaseEditorHandler editor) {
protected void configureEditor(GitInteractiveRebaseEditorHandler editor) {
editor.setRebaseEditorShown();
}
@@ -19,12 +19,10 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
import git4idea.commands.GitHandler;
import git4idea.commands.GitHandlerUtil;
import git4idea.commands.GitLineHandler;
import git4idea.i18n.GitBundle;
import git4idea.rebase.GitRebaseEditorHandler;
import git4idea.rebase.GitRebaseEditorMain;
import git4idea.rebase.GitInteractiveRebaseEditorHandler;
import git4idea.rebase.GitRebaseEditorService;
import git4idea.rebase.GitRebaseLineListener;
import org.jetbrains.annotations.NotNull;
@@ -51,14 +49,13 @@ public abstract class GitRebaseActionBase extends GitRepositoryAction {
}
final VirtualFile root = h.workingDirectoryFile();
GitRebaseEditorService service = GitRebaseEditorService.getInstance();
GitRebaseEditorHandler editor = service.getHandler(project, root);
GitInteractiveRebaseEditorHandler editor = new GitInteractiveRebaseEditorHandler(service, project, root);
GitRebaseLineListener resultListener = new GitRebaseLineListener();
h.addLineListener(resultListener);
configureEditor(editor);
affectedRoots.add(root);
try {
h.setEnvironment(GitHandler.GIT_EDITOR_ENV, service.getEditorCommand());
h.setEnvironment(GitRebaseEditorMain.IDEA_REBASE_HANDER_NO, Integer.toString(editor.getHandlerNo()));
service.configureHandler(h, editor.getHandlerNo());
GitHandlerUtil.doSynchronously(h, GitBundle.getString("rebasing.title"), h.printableCommandLine());
}
finally {
@@ -105,7 +102,7 @@ public abstract class GitRebaseActionBase extends GitRepositoryAction {
*
* @param editor the editor to configure
*/
protected void configureEditor(GitRebaseEditorHandler editor) {
protected void configureEditor(GitInteractiveRebaseEditorHandler editor) {
}
/**
@@ -0,0 +1,155 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package git4idea.rebase;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ui.UIUtil;
import java.io.Closeable;
/**
* The handler for rebase editor request. The handler shows {@link git4idea.rebase.GitRebaseEditor}
* dialog with the specified file. If user accepts the changes, it saves file and returns 0,
* otherwise it just returns error code.
*/
public class GitInteractiveRebaseEditorHandler implements Closeable, GitRebaseEditorHandler {
/**
* The logger
*/
private final static Logger LOG = Logger.getInstance(GitInteractiveRebaseEditorHandler.class.getName());
/**
* The service object that has created this handler
*/
private final GitRebaseEditorService myService;
/**
* The context project
*/
private final Project myProject;
/**
* The git repository root
*/
private final VirtualFile myRoot;
/**
* The handler number
*/
private int myHandlerNo;
/**
* If true, the handler has been closed
*/
private boolean myIsClosed;
/**
* Set to true after rebase editor was shown
*/
protected boolean myRebaseEditorShown = false;
/**
* The constructor from fields that is expected to be
* accessed only from {@link git4idea.rebase.GitRebaseEditorService}.
*
* @param service the service object that has created this handler
* @param project the context project
* @param root the git repository root
*/
public GitInteractiveRebaseEditorHandler(final GitRebaseEditorService service, final Project project, final VirtualFile root) {
myService = service;
myProject = project;
myRoot = root;
myHandlerNo = service.registerHandler(this);
}
/**
* Edit commits request
*
* @param path the path to editing
* @return the exit code to be returned from editor
*/
public int editCommits(final String path) {
ensureOpen();
final Ref<Boolean> isSuccess = new Ref<Boolean>();
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
public void run() {
try {
if (myRebaseEditorShown) {
GitRebaseUnstructuredEditor editor = new GitRebaseUnstructuredEditor(myProject, myRoot, path);
editor.show();
if (editor.isOK()) {
editor.save();
isSuccess.set(true);
return;
}
else {
isSuccess.set(false);
}
}
else {
setRebaseEditorShown();
GitRebaseEditor editor = new GitRebaseEditor(myProject, myRoot, path);
editor.show();
if (editor.isOK()) {
editor.save();
isSuccess.set(true);
return;
}
else {
editor.cancel();
isSuccess.set(true);
}
}
}
catch (Exception e) {
LOG.error("Failed to edit the git rebase file: " + path, e);
}
isSuccess.set(false);
}
});
return (isSuccess.isNull() || !isSuccess.get().booleanValue()) ? GitRebaseEditorMain.ERROR_EXIT_CODE : 0;
}
/**
* This method is invoked to indicate that this editor will be invoked in the rebase continuation action.
*/
public void setRebaseEditorShown() {
myRebaseEditorShown = true;
}
/**
* Check that handler has not yet been closed
*/
private void ensureOpen() {
if (myIsClosed) {
throw new IllegalStateException("The handler was already closed");
}
}
/**
* Stop using the handler
*/
public void close() {
ensureOpen();
myIsClosed = true;
myService.unregisterHandler(myHandlerNo);
}
/**
* @return the handler number
*/
public int getHandlerNo() {
return myHandlerNo;
}
}
@@ -15,142 +15,15 @@
*/
package git4idea.rebase;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ui.UIUtil;
import java.io.Closeable;
/**
* The handler for rebase editor request. The handler shows {@link git4idea.rebase.GitRebaseEditor}
* dialog with the specified file. If user accepts the changes, it saves file and returns 0,
* otherwise it just returns error code.
* The interface
*/
public class GitRebaseEditorHandler implements Closeable {
/**
* The logger
*/
private final static Logger LOG = Logger.getInstance(GitRebaseEditorHandler.class.getName());
/**
* The service object that has created this handler
*/
private final GitRebaseEditorService myService;
/**
* The context project
*/
private final Project myProject;
/**
* The git repository root
*/
private final VirtualFile myRoot;
/**
* The handler number
*/
private final int myHandlerNo;
/**
* If true, the handler has been closed
*/
private boolean myIsClosed;
/**
* Set to true after rebase edior was shown
*/
private boolean myRebaseEditorShown = false;
/**
* The constructor from fields that is expected to be
* accessed only from {@link git4idea.rebase.GitRebaseEditorService}.
*
* @param service the service object that has created this handler
* @param project the context project
* @param root the git repository root
* @param handlerNo the handler no for this editor
*/
GitRebaseEditorHandler(final GitRebaseEditorService service, final Project project, final VirtualFile root, final int handlerNo) {
myService = service;
myProject = project;
myRoot = root;
myHandlerNo = handlerNo;
}
public interface GitRebaseEditorHandler {
/**
* Edit commits request
*
* @param path the path to eding
* @param path the path to editing
* @return the exit code to be returned from editor
*/
public int editCommits(final String path) {
ensureOpen();
final Ref<Boolean> isSuccess = new Ref<Boolean>();
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
public void run() {
try {
if (myRebaseEditorShown) {
GitRebaseUnstructuredEditor editor = new GitRebaseUnstructuredEditor(myProject, myRoot, path);
editor.show();
if (editor.isOK()) {
editor.save();
isSuccess.set(true);
return;
}
else {
isSuccess.set(false);
}
}
else {
setRebaseEditorShown();
GitRebaseEditor editor = new GitRebaseEditor(myProject, myRoot, path);
editor.show();
if (editor.isOK()) {
editor.save();
isSuccess.set(true);
return;
}
else {
editor.cancel();
isSuccess.set(true);
}
}
}
catch (Exception e) {
LOG.error("Failed to edit the git rebase file: " + path, e);
}
isSuccess.set(false);
}
});
return (isSuccess.isNull() || !isSuccess.get().booleanValue()) ? GitRebaseEditorMain.ERROR_EXIT_CODE : 0;
}
/**
* This method is invoked to indicate that this editor will be invoked in the rebase continuation action.
*/
public void setRebaseEditorShown() {
myRebaseEditorShown = true;
}
/**
* Check that handler has not yet been closed
*/
private void ensureOpen() {
if (myIsClosed) {
throw new IllegalStateException("The handler was already closed");
}
}
/**
* Stop using the handler
*/
public void close() {
ensureOpen();
myIsClosed = true;
myService.unregisterHandler(myHandlerNo);
}
/**
* @return the handler number
*/
public int getHandlerNo() {
return myHandlerNo;
}
int editCommits(String path);
}
@@ -18,9 +18,8 @@ package git4idea.rebase;
import com.intellij.ide.XmlRpcServer;
import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import git4idea.commands.GitHandler;
import git4idea.commands.GitLineHandler;
import git4idea.commands.ScriptGenerator;
import gnu.trove.THashMap;
import org.apache.commons.codec.DecoderException;
@@ -35,11 +34,6 @@ import java.util.Random;
* The service that generates editor script for
*/
public class GitRebaseEditorService implements ApplicationComponent {
/**
* the logger
*/
private static final Logger LOG = Logger.getInstance(GitRebaseEditorService.class.getName());
/**
* The editor command that is set to env variable
*/
@@ -65,7 +59,7 @@ public class GitRebaseEditorService implements ApplicationComponent {
*/
private final static Random oursRandom = new Random();
/**
* If true, the component has been intialized
* If true, the component has been initialized
*/
private boolean myInitialized = false;
/**
@@ -138,24 +132,27 @@ public class GitRebaseEditorService implements ApplicationComponent {
}
/**
* @return the handler instance
* Register the handler in the service
*
* @param handler the handler to register
* @return the handler identifier
*/
public GitRebaseEditorHandler getHandler(Project project, VirtualFile root) {
public int registerHandler(GitRebaseEditorHandler handler) {
initComponent();
GitRebaseEditorHandler rc = null;
Integer rc = null;
synchronized (myHandlersLock) {
for (int i = Integer.MAX_VALUE; i > 0; i--) {
int code = Math.abs(oursRandom.nextInt());
// note that code might still be negative at this point if it is Integer.MIN_VALUE.
if (code > 0 && !myHandlers.containsKey(code)) {
rc = new GitRebaseEditorHandler(this, project, root, code);
rc = code;
break;
}
}
if (rc == null) {
throw new IllegalStateException("There is a problem with random number allocation");
}
myHandlers.put(rc.getHandlerNo(), rc);
myHandlers.put(rc, handler);
}
return rc;
}
@@ -166,7 +163,7 @@ public class GitRebaseEditorService implements ApplicationComponent {
*
* @param handlerNo the handler number.
*/
void unregisterHandler(final int handlerNo) {
public void unregisterHandler(final int handlerNo) {
synchronized (myHandlersLock) {
if (myHandlers.remove(handlerNo) == null) {
throw new IllegalStateException("The handler " + handlerNo + " has been already remoted");
@@ -175,7 +172,7 @@ public class GitRebaseEditorService implements ApplicationComponent {
}
/**
* Unregister handler
* Get handler
*
* @param handlerNo the handler number.
*/
@@ -184,12 +181,23 @@ public class GitRebaseEditorService implements ApplicationComponent {
synchronized (myHandlersLock) {
GitRebaseEditorHandler h = myHandlers.get(handlerNo);
if (h == null) {
throw new IllegalStateException("The handler " + handlerNo + " has been already remoted");
throw new IllegalStateException("The handler " + handlerNo + " is not registered");
}
return h;
}
}
/**
* Configure handler with editor
*
* @param h the handler to configure
* @param editorNo the editor number
*/
public void configureHandler(GitLineHandler h, int editorNo) {
h.setEnvironment(GitHandler.GIT_EDITOR_ENV, getEditorCommand());
h.setEnvironment(GitRebaseEditorMain.IDEA_REBASE_HANDER_NO, Integer.toString(editorNo));
}
/**
* The internal xml rcp handler
@@ -202,6 +210,7 @@ public class GitRebaseEditorService implements ApplicationComponent {
* @param path the path to edit
* @return exit code
*/
@SuppressWarnings({"UnusedDeclaration"})
public int editCommits(int handlerNo, String path) {
return getHandler(handlerNo).editCommits(path);
}