diff --git a/build/scripts/libLicenses.gant b/build/scripts/libLicenses.gant index 684faaa94a7d..12a784b47f1e 100644 --- a/build/scripts/libLicenses.gant +++ b/build/scripts/libLicenses.gant @@ -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") diff --git a/plugins/terminal/lib/JPty.jar b/plugins/terminal/lib/JPty.jar new file mode 100644 index 000000000000..1859fcfe3343 Binary files /dev/null and b/plugins/terminal/lib/JPty.jar differ diff --git a/plugins/terminal/lib/jediterm-pty-0.03.jar b/plugins/terminal/lib/jediterm-pty-0.03.jar new file mode 100644 index 000000000000..bd3fbb5990b7 Binary files /dev/null and b/plugins/terminal/lib/jediterm-pty-0.03.jar differ diff --git a/plugins/terminal/lib/jna.jar b/plugins/terminal/lib/jna.jar new file mode 100644 index 000000000000..4e05a4aba748 Binary files /dev/null and b/plugins/terminal/lib/jna.jar differ diff --git a/plugins/terminal/lib/purejavacomm-0.0.16.jar b/plugins/terminal/lib/purejavacomm-0.0.16.jar new file mode 100644 index 000000000000..dc41f6e444b8 Binary files /dev/null and b/plugins/terminal/lib/purejavacomm-0.0.16.jar differ diff --git a/plugins/terminal/resources/META-INF/plugin.xml b/plugins/terminal/resources/META-INF/plugin.xml new file mode 100644 index 000000000000..0d6ad053a0f9 --- /dev/null +++ b/plugins/terminal/resources/META-INF/plugin.xml @@ -0,0 +1,13 @@ + + Terminal + org.jetbrains.plugins.terminal + 0.1 + JetBrains + Embedded Terminal + + + + + + + diff --git a/plugins/terminal/resources/META-INF/terminal.xml b/plugins/terminal/resources/META-INF/terminal.xml new file mode 100644 index 000000000000..9e9addb6fe2a --- /dev/null +++ b/plugins/terminal/resources/META-INF/terminal.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/plugins/terminal/src/org/jetbrains/plugins/terminal/AbstractTerminalRunner.java b/plugins/terminal/src/org/jetbrains/plugins/terminal/AbstractTerminalRunner.java new file mode 100644 index 000000000000..4de14e4464d3 --- /dev/null +++ b/plugins/terminal/src/org/jetbrains/plugins/terminal/AbstractTerminalRunner.java @@ -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 { + 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; + } +} diff --git a/plugins/terminal/src/org/jetbrains/plugins/terminal/JBTerminal.java b/plugins/terminal/src/org/jetbrains/plugins/terminal/JBTerminal.java new file mode 100644 index 000000000000..982c06bd0f9f --- /dev/null +++ b/plugins/terminal/src/org/jetbrains/plugins/terminal/JBTerminal.java @@ -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 myOwnAttributes = new HashMap(); + private final HashMap myOwnColors = new HashMap(); + private final EditorColorsScheme myCustomGlobalScheme; + private Map 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.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); + } + } +} diff --git a/plugins/terminal/src/org/jetbrains/plugins/terminal/JBTerminalPanel.java b/plugins/terminal/src/org/jetbrains/plugins/terminal/JBTerminalPanel.java new file mode 100644 index 000000000000..0c8cfea1ab0c --- /dev/null +++ b/plugins/terminal/src/org/jetbrains/plugins/terminal/JBTerminalPanel.java @@ -0,0 +1,101 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* JCTerm + * Copyright (C) 2002-2004 ymnk, JCraft,Inc. + * + * Written by: 2002 ymnk + * + * + * 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); + } +} diff --git a/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java b/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java new file mode 100644 index 000000000000..05d120f15a8e --- /dev/null +++ b/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java @@ -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 { + + 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(); + } +} diff --git a/plugins/terminal/src/org/jetbrains/plugins/terminal/RunLocalTerminalAction.java b/plugins/terminal/src/org/jetbrains/plugins/terminal/RunLocalTerminalAction.java new file mode 100644 index 000000000000..b288c2e6cb5d --- /dev/null +++ b/plugins/terminal/src/org/jetbrains/plugins/terminal/RunLocalTerminalAction.java @@ -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(); + } +} diff --git a/plugins/terminal/terminal.iml b/plugins/terminal/terminal.iml new file mode 100644 index 000000000000..b1b2aa940a47 --- /dev/null +++ b/plugins/terminal/terminal.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + +