/******************************************************************************* * Copyright (c) 2016 Ericsson and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.internal.ui.console; import java.io.IOException; import org.eclipse.cdt.debug.ui.debuggerconsole.IDebuggerConsoleView; import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants; import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin; import org.eclipse.cdt.dsf.gdb.service.IGDBBackend; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.ui.DebugUITools; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.console.IConsoleView; import org.eclipse.ui.console.IOConsole; import org.eclipse.ui.console.IOConsoleOutputStream; import org.eclipse.ui.part.IPageBookViewPage; /** * A GDB CLI console. * This console simply provides an IOConsole to perform CLI commands * towards GDB. It is used whenever {@link IGDBBackend#isFullGdbConsoleSupported()} * returns false. */ public class GdbBasicCliConsole extends IOConsole implements IGDBDebuggerConsole { /** * A conversion factor used to resolve number of characters from number of lines */ private final static int CHARS_PER_LINE_AVG = 80; private final static int HIGH_WATERMARK_OFFSET_CHARS = 8000; private final ILaunch fLaunch; private final String fLabel; private final Process fProcess; private final IOConsoleOutputStream fOutputStream; private final IOConsoleOutputStream fErrorStream; private GdbAbstractConsolePreferenceListener fPreferenceListener = new GdbAbstractConsolePreferenceListener() { @Override protected void handleAutoTerminatePref(boolean enabled) { // Nothing to do for this class } @Override protected void handleInvertColorsPref(boolean enabled) { setInvertedColors(enabled); } @Override protected void handleBufferLinesPref(int bufferLines) { setBufferLineLimit(bufferLines); } }; public GdbBasicCliConsole(ILaunch launch, String label, Process process) { super("", "GdbBasicCliConsole", null, false); //$NON-NLS-1$ //$NON-NLS-2$ fLaunch = launch; fLabel = label; fProcess = process; fOutputStream = newOutputStream(); fErrorStream = newOutputStream(); assert(process != null); // Create a lifecycle listener to call init() and dispose() new GdbConsoleLifecycleListener(this); GdbUIPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(fPreferenceListener); resetName(); setDefaults(); new InputReadJob().schedule(); new OutputReadJob().schedule(); new ErrorReadJob().schedule(); } @Override protected void dispose() { try { fOutputStream.close(); } catch (IOException e) { } try { fErrorStream.close(); } catch (IOException e) { } GdbUIPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(fPreferenceListener); super.dispose(); } private void setDefaults() { IPreferenceStore store = GdbUIPlugin.getDefault().getPreferenceStore(); boolean enabled = store.getBoolean(IGdbDebugPreferenceConstants.PREF_CONSOLE_INVERTED_COLORS); int bufferLines = store.getInt(IGdbDebugPreferenceConstants.PREF_CONSOLE_BUFFERLINES); Display.getDefault().asyncExec(() -> { getInputStream().setColor(Display.getDefault().getSystemColor(SWT.COLOR_GREEN)); fErrorStream.setColor(Display.getDefault().getSystemColor(SWT.COLOR_RED)); setInvertedColors(enabled); setBufferLineLimit(bufferLines); }); } @Override public ILaunch getLaunch() { return fLaunch; } @Override public void resetName() { String newName = computeName(); String name = getName(); if (!name.equals(newName)) { PlatformUI.getWorkbench().getDisplay().asyncExec(() -> setName(newName)); } } protected String computeName() { if (fLaunch == null) { return ""; //$NON-NLS-1$ } String label = fLabel; ILaunchConfiguration config = fLaunch.getLaunchConfiguration(); if (config != null && !DebugUITools.isPrivate(config)) { String type = null; try { type = config.getType().getName(); } catch (CoreException e) { } StringBuffer buffer = new StringBuffer(); buffer.append(config.getName()); if (type != null) { buffer.append(" ["); //$NON-NLS-1$ buffer.append(type); buffer.append("] "); //$NON-NLS-1$ } buffer.append(label); label = buffer.toString(); } if (fLaunch.isTerminated()) { return ConsoleMessages.ConsoleMessages_console_terminated + label; } return label; } @Override public IPageBookViewPage createPage(IConsoleView view) { return new GdbBasicCliConsolePage(this, view); } @Override public IPageBookViewPage createDebuggerPage(IDebuggerConsoleView view) { if (view instanceof IConsoleView) { return createPage((IConsoleView)view); } return null; } private void setInvertedColors(boolean enable) { if (enable) { setBackground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); fOutputStream.setColor(Display.getDefault().getSystemColor(SWT.COLOR_WHITE)); } else { setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE)); fOutputStream.setColor(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); } } private void setBufferLineLimit(int bufferLines) { int chars = bufferLines * CHARS_PER_LINE_AVG; // The buffer will be allowed to grow up-to the high watermark. // When high watermark is passed, it will be trimmed-down to the low watermark. // So here add an extra buffer for high watermark. setWaterMarks(chars, chars + HIGH_WATERMARK_OFFSET_CHARS); } private class InputReadJob extends Job { { setSystem(true); } InputReadJob() { super("GDB CLI Input Job"); //$NON-NLS-1$ } @Override protected IStatus run(IProgressMonitor monitor) { try { byte[] b = new byte[1024]; int read = 0; do { read = getInputStream().read(b); if (read > 0) { fProcess.getOutputStream().write(b, 0, read); } } while (read >= 0); } catch (IOException e) { } return Status.OK_STATUS; } } private class OutputReadJob extends Job { { setSystem(true); } OutputReadJob() { super("GDB CLI output Job"); //$NON-NLS-1$ } @Override protected IStatus run(IProgressMonitor monitor) { try { byte[] b = new byte[1024]; int read = 0; do { read = fProcess.getInputStream().read(b); if (read > 0) { fOutputStream.write(b, 0, read); } } while (read >= 0); } catch (IOException e) { } return Status.OK_STATUS; } } private class ErrorReadJob extends Job { { setSystem(true); } ErrorReadJob() { super("GDB CLI error output Job"); //$NON-NLS-1$ } @Override protected IStatus run(IProgressMonitor monitor) { try { byte[] b = new byte[1024]; int read = 0; do { read = fProcess.getErrorStream().read(b); if (read > 0) { fErrorStream.write(b, 0, read); } } while (read >= 0); } catch (IOException e) { } return Status.OK_STATUS; } } }