}
@Override
- public boolean dispatch(@NotNull AWTEvent e) {
+ public boolean dispatch(AWTEvent e) {
if (e instanceof KeyEvent && !skipKeyEvent((KeyEvent)e)) {
dispatchEvent(e);
return true;
@Override
protected BufferedImage createBufferedImage(int width, int height) {
- return UIUtil.createImage(this, width, height, BufferedImage.TYPE_INT_ARGB);
+ return UIUtil.createImage(width, height, BufferedImage.TYPE_INT_ARGB);
}
}
public FontInfo fontForChar(final char c, @JdkConstants.FontStyle int style) {
- return ComplementaryFontsRegistry.getFontAbleToDisplay(c, style, mySettingsProvider.getColorScheme().getConsoleFontPreferences(),
- null);
+ return ComplementaryFontsRegistry.getFontAbleToDisplay(c, style, mySettingsProvider.getColorScheme().getConsoleFontPreferences());
}
@Override
package com.intellij.terminal;
import com.google.common.base.Predicate;
-import com.intellij.execution.filters.Filter;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.jediterm.terminal.SubstringFinder;
import com.jediterm.terminal.TerminalStarter;
import com.jediterm.terminal.TtyConnector;
-import com.jediterm.terminal.model.HyperlinkFilter;
import com.jediterm.terminal.model.JediTerminal;
import com.jediterm.terminal.model.StyleState;
import com.jediterm.terminal.model.TerminalTextBuffer;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.List;
-import java.util.stream.Collectors;
public class JBTerminalWidget extends JediTermWidget implements Disposable {
Disposer.register(parent, this);
}
- public void addMessageFilter(Project project, Filter filter) {
- addHyperlinkFilter(new HyperlinkFilter() {
- @Override
- public Result apply(String line) {
- Filter.Result r = filter.applyFilter(line, line.length());
- if (r != null) {
- return new Result() {
-
- @Override
- public List<ResultItem> getResultItems() {
- return r.getResultItems().stream().map((item -> new ResultItem() {
- @Override
- public int getStartOffset() {
- return item.getHighlightStartOffset();
- }
-
- @Override
- public int getEndOffset() {
- return item.getHighlightEndOffset();
- }
-
- @Override
- public void navigate() {
- item.getHyperlinkInfo().navigate(project);
- }
- })).collect(Collectors.toList());
- }
- };
- }
- else {
- return null;
- }
- }
- });
- }
-
@Override
protected JBTerminalPanel createTerminalPanel(@NotNull SettingsProvider settingsProvider,
@NotNull StyleState styleState,
--- /dev/null
+/*
+ * Copyright 2000-2016 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 com.intellij.terminal;
+
+import com.intellij.execution.process.OSProcessHandler;
+import com.intellij.execution.process.ProcessHandler;
+import com.jediterm.terminal.Questioner;
+import com.jediterm.terminal.TtyConnector;
+import com.pty4j.PtyProcess;
+import com.pty4j.WinSize;
+import org.jetbrains.annotations.NotNull;
+
+import java.awt.*;
+import java.io.IOException;
+import java.nio.charset.Charset;
+
+/**
+ * @author traff
+ */
+public class ProcessHandlerTtyConnector implements TtyConnector {
+ private final OSProcessHandler myProcessHandler;
+ private final PtyProcess myPtyProcess;
+ protected Charset myCharset;
+
+ public ProcessHandlerTtyConnector(@NotNull ProcessHandler processHandler, @NotNull Charset charset) {
+ if (!(processHandler instanceof OSProcessHandler)) {
+ throw new IllegalArgumentException("Works currently only with OSProcessHandler");
+ }
+ else {
+ myProcessHandler = (OSProcessHandler)processHandler;
+ }
+ if (!(myProcessHandler.getProcess() instanceof PtyProcess)) {
+ throw new IllegalArgumentException("Should be a PTY based process");
+ }
+ else {
+ myPtyProcess = (PtyProcess)myProcessHandler.getProcess();
+ }
+ myCharset = charset;
+ }
+
+
+ @Override
+ public boolean init(Questioner q) {
+ return true;
+ }
+
+ @Override
+ public void close() {
+ myProcessHandler.destroyProcess();
+ }
+
+ @Override
+ public void resize(Dimension termSize, Dimension pixelSize) {
+ if (termSize != null && pixelSize != null) {
+ if (myPtyProcess.isRunning()) {
+ myPtyProcess.setWinSize(
+ new WinSize(termSize.width, termSize.height, pixelSize.width, pixelSize.height));
+ }
+ }
+ }
+
+ @Override
+ public String getName() {
+ return "TtyConnector:" + myProcessHandler.toString();
+ }
+
+ @Override
+ public int read(char[] buf, int offset, int length) throws IOException {
+ throw new IllegalStateException("all reads should be performed by ProcessHandler");
+ }
+
+ @Override
+ public void write(byte[] bytes) throws IOException {
+ myProcessHandler.getProcessInput().write(bytes);
+ }
+
+ @Override
+ public boolean isConnected() {
+ return false;
+ }
+
+ @Override
+ public void write(String string) throws IOException {
+ myProcessHandler.getProcessInput().write(string.getBytes(myCharset));
+ }
+
+ @Override
+ public int waitFor() throws InterruptedException {
+ return myPtyProcess.waitFor();
+ }
+}
--- /dev/null
+/*
+ * Copyright 2000-2016 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 com.intellij.terminal;
+
+import com.intellij.execution.filters.Filter;
+import com.intellij.execution.process.ProcessAdapter;
+import com.intellij.execution.process.ProcessEvent;
+import com.intellij.execution.process.ProcessHandler;
+import com.intellij.execution.process.ProcessOutputTypes;
+import com.intellij.execution.ui.ConsoleViewContentType;
+import com.intellij.execution.ui.ExecutionConsole;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Key;
+import com.jediterm.terminal.TerminalStarter;
+import com.jediterm.terminal.TtyConnector;
+import com.jediterm.terminal.model.HyperlinkFilter;
+import com.jediterm.terminal.model.JediTerminal;
+import com.jediterm.terminal.ui.TerminalSession;
+import com.jediterm.terminal.util.CharUtils;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.awt.*;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author traff
+ */
+public class TerminalExecutionConsole implements ExecutionConsole {
+ private JBTerminalWidget myTerminalWidget;
+
+ public TerminalExecutionConsole(@NotNull Project project, @NotNull ProcessHandler processHandler) {
+ final JBTerminalSystemSettingsProviderBase provider = new JBTerminalSystemSettingsProviderBase();
+ AppendableTerminalDataStream dataStream = new AppendableTerminalDataStream();
+
+
+ myTerminalWidget = new JBTerminalWidget(project, 200, 24, provider, this) {
+ @Override
+ protected TerminalStarter createTerminalStarter(JediTerminal terminal, TtyConnector connector) {
+ return new TerminalStarter(terminal, connector, dataStream);
+ }
+ };
+
+ TerminalSession session = myTerminalWidget
+ .createTerminalSession(new ProcessHandlerTtyConnector(processHandler, Charset.forName("UTF-8"))); //TODO: take charset from settings
+
+ processHandler.addProcessListener(new ProcessAdapter() {
+ @Override
+ public void startNotified(ProcessEvent event) {
+ session.start();
+ }
+
+ @Override
+ public void onTextAvailable(ProcessEvent event, Key outputType) {
+ try {
+ if (outputType != ProcessOutputTypes.STDOUT) {
+ ConsoleViewContentType contentType = ConsoleViewContentType.getConsoleViewType(outputType);
+ dataStream.append(encodeColor(contentType.getAttributes().getForegroundColor()));
+ }
+ dataStream.append(event.getText());
+ if (outputType != ProcessOutputTypes.STDOUT) {
+ dataStream.append((char)CharUtils.ESC + "[39m"); //restore color
+ }
+
+ if (outputType == ProcessOutputTypes.SYSTEM) {
+ dataStream.append('\r');
+ }
+ }
+ catch (IOException e) {
+ // pass
+ }
+ }
+
+ @Override
+ public void processTerminated(ProcessEvent event) {
+ myTerminalWidget.getTerminalPanel().setCursorVisible(false);
+ }
+ });
+ }
+
+ public void addMessageFilter(Project project, Filter filter) {
+ myTerminalWidget.addHyperlinkFilter(new HyperlinkFilter() {
+ @Override
+ public Result apply(String line) {
+ Filter.Result r = filter.applyFilter(line, line.length());
+ if (r != null) {
+ return new Result() {
+
+ @Override
+ public List<ResultItem> getResultItems() {
+ return r.getResultItems().stream().map((item -> new ResultItem() {
+ @Override
+ public int getStartOffset() {
+ return item.getHighlightStartOffset();
+ }
+
+ @Override
+ public int getEndOffset() {
+ return item.getHighlightEndOffset();
+ }
+
+ @Override
+ public void navigate() {
+ item.getHyperlinkInfo().navigate(project);
+ }
+ })).collect(Collectors.toList());
+ }
+ };
+ }
+ else {
+ return null;
+ }
+ }
+ });
+ }
+
+ private static String encodeColor(Color color) {
+ StringBuilder sb = new StringBuilder();
+ sb.append((char)CharUtils.ESC).append("[").append("38;2;").append(color.getRed()).append(";").append(color.getGreen()).append(";")
+ .append(color.getBlue()).append("m");
+ return sb.toString();
+ }
+
+ @Override
+ public JComponent getComponent() {
+ return myTerminalWidget.getComponent();
+ }
+
+ @Override
+ public JComponent getPreferredFocusableComponent() {
+ return myTerminalWidget.getComponent();
+ }
+
+ @Override
+ public void dispose() {
+ myTerminalWidget = null;
+ }
+}
boolean showCommandLineAfterwards();
void setShowCommandLineAfterwards(boolean showCommandLineAfterwards);
+
+ boolean emulateTerminal();
+ void setEmulateTerminal(boolean emulateTerminal);
}
private Boolean myMultiprocessDebug = null;
private boolean myRunWithPty = PtyCommandLine.isEnabled();
+ public boolean isRunWithPty() {
+ return myRunWithPty;
+ }
+
public boolean isDebug() {
return PyDebugRunner.PY_DEBUG_RUNNER.equals(getEnvironment().getRunner().getRunnerId());
}
import com.intellij.execution.Executor;
import com.intellij.execution.configurations.*;
import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.openapi.components.PathMacroManager;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizerUtil;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.io.FileUtil;
public static final String PARAMETERS = "PARAMETERS";
public static final String MULTIPROCESS = "MULTIPROCESS";
public static final String SHOW_COMMAND_LINE = "SHOW_COMMAND_LINE";
+ public static final String EMULATE_TERMINAL = "EMULATE_TERMINAL";
+
private String myScriptName;
private String myScriptParameters;
private boolean myShowCommandLineAfterwards = false;
+ private boolean myEmulateTerminal = false;
protected PythonRunConfiguration(Project project, ConfigurationFactory configurationFactory) {
super(project, configurationFactory);
myShowCommandLineAfterwards = showCommandLineAfterwards;
}
+ @Override
+ public boolean emulateTerminal() {
+ return myEmulateTerminal;
+ }
+
+ @Override
+ public void setEmulateTerminal(boolean emulateTerminal) {
+ myEmulateTerminal = emulateTerminal;
+ }
+
public void readExternal(Element element) {
super.readExternal(element);
myScriptName = JDOMExternalizerUtil.readField(element, SCRIPT_NAME);
myScriptParameters = JDOMExternalizerUtil.readField(element, PARAMETERS);
myShowCommandLineAfterwards = Boolean.parseBoolean(JDOMExternalizerUtil.readField(element, SHOW_COMMAND_LINE, "false"));
+ myEmulateTerminal = Boolean.parseBoolean(JDOMExternalizerUtil.readField(element, EMULATE_TERMINAL, "false"));
}
public void writeExternal(Element element) throws WriteExternalException {
JDOMExternalizerUtil.writeField(element, SCRIPT_NAME, myScriptName);
JDOMExternalizerUtil.writeField(element, PARAMETERS, myScriptParameters);
JDOMExternalizerUtil.writeField(element, SHOW_COMMAND_LINE, Boolean.toString(myShowCommandLineAfterwards));
+ JDOMExternalizerUtil.writeField(element, EMULATE_TERMINAL, Boolean.toString(myEmulateTerminal));
}
public AbstractPythonRunConfigurationParams getBaseParams() {
target.setScriptName(source.getScriptName());
target.setScriptParameters(source.getScriptParameters());
target.setShowCommandLineAfterwards(source.showCommandLineAfterwards());
+ target.setEmulateTerminal(source.emulateTerminal());
}
@Override
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.run.PythonRunConfigurationForm">
- <grid id="27dc6" binding="myRootPanel" layout-manager="GridLayoutManager" row-count="6" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+ <grid id="27dc6" binding="myRootPanel" layout-manager="GridLayoutManager" row-count="7" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="507" height="400"/>
</component>
<vspacer id="f8c96">
<constraints>
- <grid row="5" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+ <grid row="6" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
<grid id="9b4b8" binding="myCommonOptionsPlaceholder" layout-manager="BorderLayout" hgap="0" vgap="0">
</grid>
<component id="99b13" class="com.intellij.ui.components.JBCheckBox" binding="myShowCommandLineCheckbox">
<constraints>
- <grid row="4" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ <grid row="5" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<selected value="true"/>
<text value="Show command line afterwards"/>
</properties>
</component>
+ <component id="d70ad" class="com.intellij.ui.components.JBCheckBox" binding="myEmulateTerminalCheckbox">
+ <constraints>
+ <grid row="4" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <selected value="true"/>
+ <text value="Emulate terminal in output panel"/>
+ </properties>
+ </component>
</children>
</grid>
</form>
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
import java.awt.*;
/**
private JComponent anchor;
private final Project myProject;
private JBCheckBox myShowCommandLineCheckbox;
+ private JBCheckBox myEmulateTerminalCheckbox;
public PythonRunConfigurationForm(PythonRunConfiguration configuration) {
myCommonOptionsForm = PyCommonOptionsFormFactory.getInstance().createForm(configuration.getCommonOptionsFormData());
myScriptTextField.addActionListener(listener);
+ myEmulateTerminalCheckbox.addChangeListener(new ChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ boolean selected = !myEmulateTerminalCheckbox.isSelected();
+ myShowCommandLineCheckbox.setEnabled(selected);
+ }
+ });
+
setAnchor(myCommonOptionsForm.getAnchor());
}
myShowCommandLineCheckbox.setSelected(showCommandLineAfterwards);
}
+ @Override
+ public boolean emulateTerminal() {
+ return myEmulateTerminalCheckbox.isSelected();
+ }
+
+ @Override
+ public void setEmulateTerminal(boolean emulateTerminal) {
+ myEmulateTerminalCheckbox.setSelected(emulateTerminal);
+ }
+
@Override
public JComponent getAnchor() {
return anchor;
import com.intellij.execution.configurations.ParamsGroup;
import com.intellij.execution.console.ConsoleExecuteAction;
import com.intellij.execution.executors.DefaultDebugExecutor;
+import com.intellij.execution.filters.UrlFilter;
+import com.intellij.execution.process.OSProcessHandler;
+import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.terminal.TerminalExecutionConsole;
import com.intellij.util.ArrayUtil;
+import com.intellij.util.io.BaseDataReader;
+import com.intellij.util.io.BaseOutputReader;
import com.jetbrains.python.PythonHelper;
import com.jetbrains.python.console.PyConsoleOptions;
import com.jetbrains.python.console.PyConsoleType;
@Override
public ExecutionResult execute(Executor executor, final CommandLinePatcher... patchers) throws ExecutionException {
- if (myConfig.showCommandLineAfterwards()) {
+ if (myConfig.showCommandLineAfterwards() && !myConfig.emulateTerminal()) {
if (executor.getId() == DefaultDebugExecutor.EXECUTOR_ID) {
return super.execute(executor, ArrayUtil.append(patchers, new CommandLinePatcher() {
@Override
return new DefaultExecutionResult(runner.getConsoleView(), runner.getProcessHandler(), actions.toArray(new AnAction[actions.size()]));
}
+ else if (myConfig.emulateTerminal()) {
+ setRunWithPty(true);
+
+ final ProcessHandler processHandler = startProcess();
+
+ TerminalExecutionConsole executeConsole = new TerminalExecutionConsole(myConfig.getProject(), processHandler);
+
+ executeConsole.addMessageFilter(myConfig.getProject(), new PythonTracebackFilter(myConfig.getProject()));
+ executeConsole.addMessageFilter(myConfig.getProject(), new UrlFilter());
+
+ processHandler.startNotify();
+
+ return new DefaultExecutionResult(executeConsole, processHandler, AnAction.EMPTY_ARRAY);
+ }
else {
return super.execute(executor, patchers);
}
}
+ @Override
+ public void customizeEnvironmentVars(Map<String, String> envs, boolean passParentEnvs) {
+ if (myConfig.emulateTerminal()) {
+ if (!SystemInfo.isWindows) {
+ envs.put("TERM", "xterm-256color");
+ }
+ }
+ }
+
+ @Override
+ protected ProcessHandler doCreateProcess(GeneralCommandLine commandLine) throws ExecutionException {
+ if (myConfig.emulateTerminal()) {
+ return new OSProcessHandler(commandLine) {
+ @NotNull
+ @Override
+ protected BaseOutputReader.Options readerOptions() {
+ return new BaseOutputReader.Options() {
+ @Override
+ public BaseDataReader.SleepingPolicy policy() {
+ return BaseDataReader.SleepingPolicy.BLOCKING;
+ }
+
+ @Override
+ public boolean splitToLines() {
+ return false;
+ }
+
+ @Override
+ public boolean withSeparators() {
+ return true;
+ }
+ };
+ }
+ };
+ }
+ else {
+ return super.doCreateProcess(commandLine);
+ }
+ }
+
@Override
protected void buildCommandLineParameters(GeneralCommandLine commandLine) {
ParametersList parametersList = commandLine.getParametersList();
CommandLinePatcher[] patchers,
PyConsoleOptions.PyConsoleSettings consoleSettings,
String... statementsToExecute) {
- super(project, sdk, consoleType, workingDir, environmentVariables, consoleSettings, (s) -> {}, statementsToExecute);
+ super(project, sdk, consoleType, workingDir, environmentVariables, consoleSettings, (s) -> {
+ }, statementsToExecute);
myPatchers = patchers;
}