X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fjexer%2FTTerminalWindow.java;h=415a1a0a9fd1eb7ece35db9e3914ca9973b5124e;hb=051e29138b18fb4b731a72f8727475b10e4c74e4;hp=89280fd1d4d18d1b0a4ff0c05139dc916bb8c56a;hpb=1d99a38f2b0f1f6674a21ba8b17be28bc7a34035;p=fanfix.git diff --git a/src/jexer/TTerminalWindow.java b/src/jexer/TTerminalWindow.java index 89280fd..415a1a0 100644 --- a/src/jexer/TTerminalWindow.java +++ b/src/jexer/TTerminalWindow.java @@ -30,15 +30,19 @@ package jexer; import java.io.IOException; import java.lang.reflect.Field; +import java.text.MessageFormat; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.ResourceBundle; import jexer.bits.Cell; import jexer.bits.CellAttributes; import jexer.event.TKeypressEvent; +import jexer.event.TMenuEvent; import jexer.event.TMouseEvent; import jexer.event.TResizeEvent; +import jexer.menu.TMenu; import jexer.tterminal.DisplayLine; import jexer.tterminal.DisplayListener; import jexer.tterminal.ECMA48; @@ -50,6 +54,12 @@ import static jexer.TKeypress.*; public class TTerminalWindow extends TScrollableWindow implements DisplayListener { + + /** + * Translated strings. + */ + private static final ResourceBundle i18n = ResourceBundle.getBundle(TTerminalWindow.class.getName()); + /** * The emulator. */ @@ -138,17 +148,33 @@ public class TTerminalWindow extends TScrollableWindow } /** - * Public constructor spawns a shell. + * Convert a string array to a whitespace-separated string. * - * @param application TApplication that manages this window - * @param x column relative to parent - * @param y row relative to parent - * @param flags mask of CENTERED, MODAL, or RESIZABLE + * @param array the string array + * @return a single string */ - public TTerminalWindow(final TApplication application, final int x, - final int y, final int flags) { + private String stringArrayToString(final String [] array) { + StringBuilder sb = new StringBuilder(array[0].length()); + for (int i = 0; i < array.length; i++) { + sb.append(array[i]); + if (i < array.length - 1) { + sb.append(' '); + } + } + return sb.toString(); + } + + /** + * Spawn the shell. + * + * @param command the command line to execute + */ + private void spawnShell(final String [] command) { - super(application, "Terminal", x, y, 80 + 2, 24 + 2, flags); + /* + System.err.printf("spawnShell(): '%s'\n", + stringArrayToString(command)); + */ vScroller = new TVScroller(this, getWidth() - 2, 0, getHeight() - 2); setBottomValue(0); @@ -157,43 +183,7 @@ public class TTerminalWindow extends TScrollableWindow ECMA48.DeviceType deviceType = ECMA48.DeviceType.XTERM; try { - String [] cmdShellWindows = { - "cmd.exe" - }; - - // You cannot run a login shell in a bare Process interactively, - // due to libc's behavior of buffering when stdin/stdout aren't a - // tty. Use 'script' instead to run a shell in a pty. And - // because BSD and GNU differ on the '-f' vs '-F' flags, we need - // two different commands. Lovely. - String [] cmdShellGNU = { - "script", "-fqe", "/dev/null" - }; - String [] cmdShellBSD = { - "script", "-q", "-F", "/dev/null" - }; - String [] cmdShellPtypipe = { - "ptypipe", "/bin/bash", "--login" - }; - // Spawn a shell and pass its I/O to the other constructor. - - ProcessBuilder pb; - if ((System.getProperty("jexer.TTerminal.ptypipe") != null) - && (System.getProperty("jexer.TTerminal.ptypipe"). - equals("true")) - ) { - pb = new ProcessBuilder(cmdShellPtypipe); - ptypipe = true; - } else if (System.getProperty("os.name").startsWith("Windows")) { - pb = new ProcessBuilder(cmdShellWindows); - } else if (System.getProperty("os.name").startsWith("Mac")) { - pb = new ProcessBuilder(cmdShellBSD); - } else if (System.getProperty("os.name").startsWith("Linux")) { - pb = new ProcessBuilder(cmdShellGNU); - } else { - // When all else fails, assume GNU. - pb = new ProcessBuilder(cmdShellGNU); - } + ProcessBuilder pb = new ProcessBuilder(command); Map env = pb.environment(); env.put("TERM", ECMA48.deviceTypeTerm(deviceType)); env.put("LANG", ECMA48.deviceTypeLang(deviceType, "en")); @@ -202,10 +192,11 @@ public class TTerminalWindow extends TScrollableWindow pb.redirectErrorStream(true); shell = pb.start(); emulator = new ECMA48(deviceType, shell.getInputStream(), - shell.getOutputStream()); - emulator.setListener(this); + shell.getOutputStream(), this); } catch (IOException e) { - messageBox("Error", "Error launching shell: " + e.getMessage()); + messageBox(i18n.getString("errorLaunchingShellTitle"), + MessageFormat.format(i18n.getString("errorLaunchingShellText"), + e.getMessage())); } // Setup the scroll bars @@ -216,7 +207,118 @@ public class TTerminalWindow extends TScrollableWindow addShortcutKeys(); // Add shortcut text - newStatusBar("Terminal session executing..."); + newStatusBar(i18n.getString("statusBarRunning")); + } + + /** + * Public constructor spawns a custom command line. + * + * @param application TApplication that manages this window + * @param x column relative to parent + * @param y row relative to parent + * @param commandLine the command line to execute + */ + public TTerminalWindow(final TApplication application, final int x, + final int y, final String commandLine) { + + this(application, x, y, RESIZABLE, commandLine.split("\\s")); + } + + /** + * Public constructor spawns a custom command line. + * + * @param application TApplication that manages this window + * @param x column relative to parent + * @param y row relative to parent + * @param flags mask of CENTERED, MODAL, or RESIZABLE + * @param command the command line to execute + */ + public TTerminalWindow(final TApplication application, final int x, + final int y, final int flags, final String [] command) { + + super(application, i18n.getString("windowTitle"), x, y, + 80 + 2, 24 + 2, flags); + + String [] fullCommand; + + // Spawn a shell and pass its I/O to the other constructor. + if ((System.getProperty("jexer.TTerminal.ptypipe") != null) + && (System.getProperty("jexer.TTerminal.ptypipe"). + equals("true")) + ) { + ptypipe = true; + fullCommand = new String[command.length + 1]; + fullCommand[0] = "ptypipe"; + System.arraycopy(command, 0, fullCommand, 1, command.length); + } else if (System.getProperty("os.name").startsWith("Windows")) { + fullCommand = new String[3]; + fullCommand[0] = "cmd"; + fullCommand[1] = "/c"; + fullCommand[2] = stringArrayToString(command); + } else if (System.getProperty("os.name").startsWith("Mac")) { + fullCommand = new String[6]; + fullCommand[0] = "script"; + fullCommand[1] = "-q"; + fullCommand[2] = "-F"; + fullCommand[3] = "/dev/null"; + fullCommand[4] = "-c"; + fullCommand[5] = stringArrayToString(command); + } else { + // Default: behave like Linux + fullCommand = new String[5]; + fullCommand[0] = "script"; + fullCommand[1] = "-fqe"; + fullCommand[2] = "/dev/null"; + fullCommand[3] = "-c"; + fullCommand[4] = stringArrayToString(command); + } + spawnShell(fullCommand); + } + + /** + * Public constructor spawns a shell. + * + * @param application TApplication that manages this window + * @param x column relative to parent + * @param y row relative to parent + * @param flags mask of CENTERED, MODAL, or RESIZABLE + */ + public TTerminalWindow(final TApplication application, final int x, + final int y, final int flags) { + + super(application, i18n.getString("windowTitle"), x, y, + 80 + 2, 24 + 2, flags); + + String cmdShellWindows = "cmd.exe"; + + // You cannot run a login shell in a bare Process interactively, due + // to libc's behavior of buffering when stdin/stdout aren't a tty. + // Use 'script' instead to run a shell in a pty. And because BSD and + // GNU differ on the '-f' vs '-F' flags, we need two different + // commands. Lovely. + String cmdShellGNU = "script -fqe /dev/null"; + String cmdShellBSD = "script -q -F /dev/null"; + + // ptypipe is another solution that permits dynamic window resizing. + String cmdShellPtypipe = "ptypipe /bin/bash --login"; + + // Spawn a shell and pass its I/O to the other constructor. + if ((System.getProperty("jexer.TTerminal.ptypipe") != null) + && (System.getProperty("jexer.TTerminal.ptypipe"). + equals("true")) + ) { + ptypipe = true; + spawnShell(cmdShellPtypipe.split("\\s")); + } else if (System.getProperty("os.name").startsWith("Windows")) { + spawnShell(cmdShellWindows.split("\\s")); + } else if (System.getProperty("os.name").startsWith("Mac")) { + spawnShell(cmdShellBSD.split("\\s")); + } else if (System.getProperty("os.name").startsWith("Linux")) { + spawnShell(cmdShellGNU.split("\\s")); + } else { + // When all else fails, assume GNU. + spawnShell(cmdShellGNU.split("\\s")); + } } /** @@ -315,8 +417,18 @@ public class TTerminalWindow extends TScrollableWindow boolean reverse = line.isReverseColor() ^ ch.isReverse(); newCell.setReverse(false); if (reverse) { - newCell.setBackColor(ch.getForeColor()); - newCell.setForeColor(ch.getBackColor()); + if (ch.getForeColorRGB() < 0) { + newCell.setBackColor(ch.getForeColor()); + newCell.setBackColorRGB(-1); + } else { + newCell.setBackColorRGB(ch.getForeColorRGB()); + } + if (ch.getBackColorRGB() < 0) { + newCell.setForeColor(ch.getBackColor()); + newCell.setForeColorRGB(-1); + } else { + newCell.setForeColorRGB(ch.getBackColorRGB()); + } } if (line.isDoubleWidth()) { getScreen().putCharXY((i * 2) + 1, row, newCell); @@ -346,7 +458,31 @@ public class TTerminalWindow extends TScrollableWindow * Called by emulator when fresh data has come in. */ public void displayChanged() { - doRepaint(); + getApplication().postEvent(new TMenuEvent(TMenu.MID_REPAINT)); + } + + /** + * Function to call to obtain the display width. + * + * @return the number of columns in the display + */ + public int getDisplayWidth() { + if (ptypipe) { + return getWidth() - 2; + } + return 80; + } + + /** + * Function to call to obtain the display height. + * + * @return the number of rows in the display + */ + public int getDisplayHeight() { + if (ptypipe) { + return getHeight() - 2; + } + return 24; } /** @@ -362,6 +498,13 @@ public class TTerminalWindow extends TScrollableWindow } } + /** + * Hook for subclasses to be notified of the shell termination. + */ + public void onShellExit() { + getApplication().postEvent(new TMenuEvent(TMenu.MID_REPAINT)); + } + /** * Copy out variables from the emulator that TTerminal has to expose on * screen. @@ -394,13 +537,14 @@ public class TTerminalWindow extends TScrollableWindow try { int rc = shell.exitValue(); // The emulator exited on its own, all is fine - setTitle(String.format("%s [Completed - %d]", - getTitle(), rc)); + setTitle(MessageFormat.format(i18n. + getString("windowTitleCompleted"), getTitle(), rc)); shell = null; emulator.close(); clearShortcutKeypresses(); - statusBar.setText("Terminal session completed, exit " + - "code " + rc + "."); + statusBar.setText(MessageFormat.format(i18n. + getString("statusBarCompleted"), rc)); + onShellExit(); } catch (IllegalThreadStateException e) { // The emulator thread has exited, but the shell Process // hasn't figured that out yet. Do nothing, we will see @@ -411,13 +555,14 @@ public class TTerminalWindow extends TScrollableWindow try { int rc = shell.exitValue(); // If we got here, the shell died. - setTitle(String.format("%s [Completed - %d]", - getTitle(), rc)); + setTitle(MessageFormat.format(i18n. + getString("windowTitleCompleted"), getTitle(), rc)); shell = null; emulator.close(); clearShortcutKeypresses(); - statusBar.setText("Terminal session completed, exit " + - "code " + rc + "."); + statusBar.setText(MessageFormat.format(i18n. + getString("statusBarCompleted"), rc)); + onShellExit(); } catch (IllegalThreadStateException e) { // The shell is still running, do nothing. }