Added local terminal plugin.

This commit is contained in:
Dmitry Trofimov
2013-05-06 20:21:06 +02:00
parent bcba80ea1f
commit 56eb583615
13 changed files with 629 additions and 0 deletions
+3
View File
@@ -255,6 +255,9 @@ libraryLicense(name: "Rhino JavaScript Engine", libraryName: "rhino-js-1_7R4", v
libraryLicense(name: "asm-4.0-all", libraryName: "asm-4.0-all", version: "4.0", attachedTo: "ByteCodeViewer", license: "BSD", url: "http://asm.objectweb.org/", licenseUrl: "http://asm.objectweb.org/license.html")
libraryLicense(name: "jsr305", libraryName: "jsr305", version: "snapshot", license: "BSD", url: "http://code.google.com/p/jsr-305/", licenseUrl: "http://code.google.com/p/jsr-305/source/browse/trunk/ri/LICENSE")
libraryLicense(name: "jzlib", libraryName: "jzlib", version: "1.1.1", license: "BSD", url: "http://www.jcraft.com/jzlib/", licenseUrl: "http://www.jcraft.com/jzlib/LICENSE.txt")
libraryLicense(name: "PureJavaComm", libraryName: "purejavacomm", version: "0.0.16", license: "BSD", url: "http://www.sparetimelabs.com/purejavacomm")
libraryLicense(name: "JPty", libraryName: "jpty", version: "git snapshot", license: "Apache 2.0", url: "https://github.com/jawi/JPty")
libraryLicense(name: "JediTerm", libraryName: "jediterm-pty", version: "0.2", license: "LGPL 2", url: "https://github.com/traff/jediterm", licenseUrl: "https://github.com/traff/jediterm/blob/master/COPYING")
jetbrainsLibrary("JPS")
jetbrainsLibrary("Maven Embedder")
jetbrainsLibrary("tcServiceMessages")
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,13 @@
<idea-plugin version="2" xmlns:xi="http://www.w3.org/2001/XInclude">
<name>Terminal</name>
<id>org.jetbrains.plugins.terminal</id>
<version>0.1</version>
<vendor>JetBrains</vendor>
<description>Embedded Terminal</description>
<xi:include href="/META-INF/terminal.xml" xpointer="xpointer(/idea-plugin/*)"/>
<extensions defaultExtensionNs="com.intellij">
<errorHandler implementation="com.intellij.diagnostic.ITNReporter"/>
</extensions>
</idea-plugin>
@@ -0,0 +1,9 @@
<idea-plugin version="2">
<actions>
<action id="org.jetbrains.plugins.terminal.RunLocalTerminalAction"
class="org.jetbrains.plugins.terminal.RunLocalTerminalAction"
text="Open Terminal..." description="Open terminal locally">
<add-to-group group-id="ToolsMenu" anchor="last"/>
</action>
</actions>
</idea-plugin>
@@ -0,0 +1,130 @@
package org.jetbrains.plugins.terminal;
import com.intellij.execution.ExecutionManager;
import com.intellij.execution.Executor;
import com.intellij.execution.ExecutorRegistry;
import com.intellij.execution.executors.DefaultRunExecutor;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.execution.ui.actions.CloseAction;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.util.ui.UIUtil;
import com.jediterm.emulator.TtyConnector;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.util.concurrent.ExecutionException;
/**
* @author traff
*/
public abstract class AbstractTerminalRunner<T extends Process> {
private static final Logger LOG = Logger.getInstance(AbstractTerminalRunner.class.getName());
@NotNull
protected final Project myProject;
public AbstractTerminalRunner(@NotNull Project project) {
myProject = project;
}
public void run() {
ProgressManager.getInstance().run(new Task.Backgroundable(myProject, "Connecting to terminal", false) {
public void run(@NotNull final ProgressIndicator indicator) {
indicator.setText("Connecting to terminal...");
try {
doRun();
}
catch (Exception e) {
LOG.warn("Error running terminal", e);
Messages.showErrorDialog(AbstractTerminalRunner.this.getProject(), getTitle(), e.getMessage());
}
}
});
}
private void doRun() {
// Create Server process
try {
final T process = createProcess();
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
initConsoleUI(process);
}
});
}
catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
protected abstract T createProcess() throws ExecutionException;
protected abstract ProcessHandler createProcessHandler(T process);
private void initConsoleUI(final T process) {
final Executor defaultExecutor = ExecutorRegistry.getInstance().getExecutorById(DefaultRunExecutor.EXECUTOR_ID);
final DefaultActionGroup toolbarActions = new DefaultActionGroup();
final ActionToolbar actionToolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, toolbarActions, false);
final JBTerminal term = new JBTerminal();
term.setTtyConnector(createTtyConnector(process));
final JPanel panel = new JPanel(new BorderLayout());
panel.add(actionToolbar.getComponent(), BorderLayout.WEST);
panel.add(term, BorderLayout.CENTER);
term.start();
actionToolbar.setTargetComponent(panel);
ProcessHandler processHandler = createProcessHandler(process);
final RunContentDescriptor contentDescriptor =
new RunContentDescriptor(null, processHandler, panel, getTerminalConnectionName(process));
toolbarActions.add(createCloseAction(defaultExecutor, contentDescriptor));
showConsole(defaultExecutor, contentDescriptor, term.getTermPanel());
processHandler.startNotify();
}
protected abstract String getTerminalConnectionName(T process);
protected abstract TtyConnector createTtyConnector(T process);
protected AnAction createCloseAction(final Executor defaultExecutor, final RunContentDescriptor myDescriptor) {
return new CloseAction(defaultExecutor, myDescriptor, myProject);
}
protected void showConsole(Executor defaultExecutor, RunContentDescriptor myDescriptor, final Component toFocus) {
// Show in run toolwindow
ExecutionManager.getInstance(myProject).getContentManager().showRunContent(defaultExecutor, myDescriptor);
// Request focus
final ToolWindow window = ToolWindowManager.getInstance(myProject).getToolWindow(defaultExecutor.getId());
window.activate(new Runnable() {
public void run() {
IdeFocusManager.getInstance(myProject).requestFocus(toFocus, true);
}
});
}
protected Project getProject() {
return myProject;
}
}
@@ -0,0 +1,269 @@
package org.jetbrains.plugins.terminal;
import com.intellij.application.options.OptionsConstants;
import com.intellij.openapi.editor.colors.*;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.options.FontSize;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.ui.components.JBScrollBar;
import com.intellij.util.containers.HashMap;
import com.jediterm.emulator.display.BackBuffer;
import com.jediterm.emulator.display.LinesBuffer;
import com.jediterm.emulator.display.StyleState;
import com.jediterm.emulator.ui.SwingJediTerminal;
import com.jediterm.emulator.ui.SwingTerminalPanel;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.EnumMap;
import java.util.Map;
public class JBTerminal extends SwingJediTerminal {
public JBTerminal() {
}
@Override
protected SwingTerminalPanel createTerminalPanel(StyleState styleState, BackBuffer backBuffer, LinesBuffer scrollBuffer) {
return new JBTerminalPanel(backBuffer, scrollBuffer, styleState, createBoundColorSchemeDelegate(null));
}
@Override
protected JScrollBar createScrollBar() {
return new JBScrollBar();
}
@NotNull
public EditorColorsScheme createBoundColorSchemeDelegate(@Nullable final EditorColorsScheme customGlobalScheme) {
return new MyColorSchemeDelegate(customGlobalScheme);
}
private static class MyColorSchemeDelegate implements EditorColorsScheme {
private final FontPreferences myFontPreferences = new FontPreferences();
private final HashMap<TextAttributesKey, TextAttributes> myOwnAttributes = new HashMap<TextAttributesKey, TextAttributes>();
private final HashMap<ColorKey, Color> myOwnColors = new HashMap<ColorKey, Color>();
private final EditorColorsScheme myCustomGlobalScheme;
private Map<EditorFontType, Font> myFontsMap = null;
private int myMaxFontSize = OptionsConstants.MAX_EDITOR_FONT_SIZE;
private int myFontSize = -1;
private String myFaceName = null;
private EditorColorsScheme myGlobalScheme;
private MyColorSchemeDelegate(@Nullable final EditorColorsScheme globalScheme) {
myCustomGlobalScheme = globalScheme;
updateGlobalScheme();
}
private EditorColorsScheme getGlobal() {
return myGlobalScheme;
}
@Override
public String getName() {
return getGlobal().getName();
}
protected void initFonts() {
String editorFontName = getEditorFontName();
int editorFontSize = getEditorFontSize();
myFontPreferences.clear();
myFontPreferences.register(editorFontName, editorFontSize);
myFontsMap = new EnumMap<EditorFontType, Font>(EditorFontType.class);
Font plainFont = new Font(editorFontName, Font.PLAIN, editorFontSize);
Font boldFont = new Font(editorFontName, Font.BOLD, editorFontSize);
Font italicFont = new Font(editorFontName, Font.ITALIC, editorFontSize);
Font boldItalicFont = new Font(editorFontName, Font.BOLD | Font.ITALIC, editorFontSize);
myFontsMap.put(EditorFontType.PLAIN, plainFont);
myFontsMap.put(EditorFontType.BOLD, boldFont);
myFontsMap.put(EditorFontType.ITALIC, italicFont);
myFontsMap.put(EditorFontType.BOLD_ITALIC, boldItalicFont);
}
@Override
public void setName(String name) {
getGlobal().setName(name);
}
@Override
public TextAttributes getAttributes(TextAttributesKey key) {
if (myOwnAttributes.containsKey(key)) return myOwnAttributes.get(key);
return getGlobal().getAttributes(key);
}
@Override
public void setAttributes(TextAttributesKey key, TextAttributes attributes) {
myOwnAttributes.put(key, attributes);
}
@NotNull
@Override
public Color getDefaultBackground() {
return getGlobal().getDefaultBackground();
}
@NotNull
@Override
public Color getDefaultForeground() {
return getGlobal().getDefaultForeground();
}
@Override
public Color getColor(ColorKey key) {
if (myOwnColors.containsKey(key)) return myOwnColors.get(key);
return getGlobal().getColor(key);
}
@Override
public void setColor(ColorKey key, Color color) {
myOwnColors.put(key, color);
}
@NotNull
@Override
public FontPreferences getFontPreferences() {
return myFontPreferences;
}
@Override
public void setFontPreferences(@NotNull FontPreferences preferences) {
preferences.copyTo(myFontPreferences);
initFonts();
}
@Override
public int getEditorFontSize() {
if (myFontSize == -1) {
return getGlobal().getEditorFontSize();
}
return myFontSize;
}
@Override
public void setEditorFontSize(int fontSize) {
if (fontSize < 8) fontSize = 8;
if (fontSize > myMaxFontSize) fontSize = myMaxFontSize;
myFontSize = fontSize;
initFonts();
}
@Override
public FontSize getQuickDocFontSize() {
return myGlobalScheme.getQuickDocFontSize();
}
@Override
public void setQuickDocFontSize(@NotNull FontSize fontSize) {
myGlobalScheme.setQuickDocFontSize(fontSize);
}
@Override
public String getEditorFontName() {
if (myFaceName == null) {
return getGlobal().getEditorFontName();
}
return myFaceName;
}
@Override
public void setEditorFontName(String fontName) {
myFaceName = fontName;
initFonts();
}
@Override
public Font getFont(EditorFontType key) {
if (myFontsMap != null) {
Font font = myFontsMap.get(key);
if (font != null) return font;
}
return getGlobal().getFont(key);
}
@Override
public void setFont(EditorFontType key, Font font) {
if (myFontsMap == null) {
initFonts();
}
myFontsMap.put(key, font);
}
@Override
public float getLineSpacing() {
return getGlobal().getLineSpacing();
}
@Override
public void setLineSpacing(float lineSpacing) {
getGlobal().setLineSpacing(lineSpacing);
}
@Override
@Nullable
public Object clone() {
return null;
}
@Override
public void readExternal(Element element) throws InvalidDataException {
}
@Override
public void writeExternal(Element element) throws WriteExternalException {
}
public void updateGlobalScheme() {
myGlobalScheme = myCustomGlobalScheme == null ? EditorColorsManager.getInstance().getGlobalScheme() : myCustomGlobalScheme;
int globalFontSize = getGlobal().getEditorFontSize();
myMaxFontSize = Math.max(OptionsConstants.MAX_EDITOR_FONT_SIZE, globalFontSize);
}
@NotNull
@Override
public FontPreferences getConsoleFontPreferences() {
return getGlobal().getConsoleFontPreferences();
}
@Override
public void setConsoleFontPreferences(@NotNull FontPreferences preferences) {
getGlobal().setConsoleFontPreferences(preferences);
}
@Override
public String getConsoleFontName() {
return getGlobal().getConsoleFontName();
}
@Override
public void setConsoleFontName(String fontName) {
getGlobal().setConsoleFontName(fontName);
}
@Override
public int getConsoleFontSize() {
return getGlobal().getConsoleFontSize();
}
@Override
public void setConsoleFontSize(int fontSize) {
getGlobal().setConsoleFontSize(fontSize);
}
@Override
public float getConsoleLineSpacing() {
return getGlobal().getConsoleLineSpacing();
}
@Override
public void setConsoleLineSpacing(float lineSpacing) {
getGlobal().setConsoleLineSpacing(lineSpacing);
}
}
}
@@ -0,0 +1,101 @@
/* -*-mode:java; c-basic-offset:2; -*- */
/* JCTerm
* Copyright (C) 2002-2004 ymnk, JCraft,Inc.
*
* Written by: 2002 ymnk<ymnk@jcaft.com>
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.jetbrains.plugins.terminal;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.ide.CopyPasteManager;
import com.intellij.util.ui.GraphicsUtil;
import com.intellij.util.ui.UIUtil;
import com.jediterm.emulator.TextStyle;
import com.jediterm.emulator.display.BackBuffer;
import com.jediterm.emulator.display.LinesBuffer;
import com.jediterm.emulator.display.StyleState;
import com.jediterm.emulator.ui.SwingTerminalPanel;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.image.BufferedImage;
import java.io.IOException;
public class JBTerminalPanel extends SwingTerminalPanel {
private final EditorColorsScheme myColorScheme;
public JBTerminalPanel(BackBuffer backBuffer, LinesBuffer scrollBuffer, StyleState styleState, EditorColorsScheme scheme) {
super(backBuffer, scrollBuffer, styleState);
myColorScheme = scheme;
styleState.setDefaultStyle(new TextStyle(myColorScheme.getDefaultForeground(), myColorScheme.getDefaultBackground()));
}
@Override
protected BufferedImage createBufferedImage(int width, int height) {
return UIUtil.createImage(width, height,
BufferedImage.TYPE_INT_RGB);
}
protected Font createFont() {
Font normalFont = Font.decode(myColorScheme.getConsoleFontName());
if (normalFont == null) {
return super.createFont();
}
return normalFont;
}
protected void setupAntialiasing(Graphics graphics, boolean antialiasing) {
GraphicsUtil.setupAntialiasing(graphics, antialiasing, false);
}
@Override
public Color getBackground() {
if (myColorScheme != null) {
return myColorScheme.getDefaultBackground();
}
return super.getBackground();
}
@Override
public Color getForeground() {
if (myColorScheme != null) {
return myColorScheme.getDefaultForeground();
}
return super.getBackground();
}
@Override
protected void setCopyContents(StringSelection selection) {
CopyPasteManager.getInstance().setContents(selection);
}
@Override
protected String getClipboardContent() throws IOException, UnsupportedFlavorException {
Transferable contents = CopyPasteManager.getInstance().getContents();
if (contents == null) {
return null;
}
return (String)contents.getTransferData(DataFlavor.stringFlavor);
}
}
@@ -0,0 +1,48 @@
package org.jetbrains.plugins.terminal;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.openapi.project.Project;
import com.jediterm.emulator.TtyConnector;
import com.jediterm.pty.PtyProcess;
import com.jediterm.pty.PtyProcessTtyConnector;
import java.nio.charset.Charset;
import java.util.concurrent.ExecutionException;
/**
* @author traff
*/
public class LocalTerminalDirectRunner extends AbstractTerminalRunner<PtyProcess> {
private final Charset myDefaultCharset;
private final String myCommand;
private final String[] myArguments;
public LocalTerminalDirectRunner(Project project, Charset charset, String command, String[] arguments) {
super(project);
myDefaultCharset = charset;
myCommand = command;
myArguments = arguments;
}
@Override
protected PtyProcess createProcess() throws ExecutionException {
return new PtyProcess(myCommand, myArguments);
}
@Override
protected ProcessHandler createProcessHandler(PtyProcess process) {
return new OSProcessHandler(process);
}
@Override
protected TtyConnector createTtyConnector(PtyProcess process) {
return new PtyProcessTtyConnector(process, myDefaultCharset);
}
@Override
protected String getTerminalConnectionName(PtyProcess process) {
return process.getCommandLineString();
}
}
@@ -0,0 +1,37 @@
package org.jetbrains.plugins.terminal;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import java.nio.charset.Charset;
/**
* @author traff
*/
public class RunLocalTerminalAction extends AnAction implements DumbAware {
public RunLocalTerminalAction() {
super();
}
@Override
public void update(final AnActionEvent e) {
e.getPresentation().setVisible(true);
e.getPresentation().setEnabled(true);
}
public void actionPerformed(final AnActionEvent e) {
runLocalTerminal(e);
}
public void runLocalTerminal(AnActionEvent event) {
final Project project = event.getData(PlatformDataKeys.PROJECT);
setupRemoteCredentialsAndRunTerminal(project);
}
public static void setupRemoteCredentialsAndRunTerminal(final Project project) {
new LocalTerminalDirectRunner(project, Charset.defaultCharset(), "/bin/bash", new String[]{"/bin/bash"}).run();
}
}
+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/resources" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="lang-api" />
<orderEntry type="library" name="jna" level="project" />
<orderEntry type="library" name="jediterm-pty" level="project" />
<orderEntry type="library" name="jpty" level="project" />
<orderEntry type="library" name="purejavacomm" level="project" />
<orderEntry type="module" module-name="platform-impl" />
</component>
</module>