src.org.python.util.JLineConsole Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jython-standalone Show documentation
Show all versions of jython-standalone Show documentation
Jython is an implementation of the high-level, dynamic, object-oriented
language Python written in 100% Pure Java, and seamlessly integrated with
the Java platform. It thus allows you to run Python on any Java platform.
/* Copyright (c) Jython Developers */
package org.python.util;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Arrays;
import java.util.List;
import com.kenai.constantine.platform.Errno;
import jline.ConsoleReader;
import jline.Terminal;
import jline.WindowsTerminal;
import org.python.core.Py;
import org.python.core.PyObject;
/**
* This class uses JLine to provide
* readline like functionality to its console without requiring native readline
* support.
*/
public class JLineConsole extends InteractiveConsole {
/** Main interface to JLine. */
protected ConsoleReader reader;
/** Set by readline.set_startup_hook */
protected PyObject startup_hook;
protected PyObject pre_input_hook;
/** Whether reader is a WindowsTerminal. */
private boolean windows;
/** The ctrl-z character String. */
protected static final String CTRL_Z = "\u001a";
/**
* Errno strerrors possibly caused by a SIGSTP (ctrl-z). They may propagate up to
* IOException messages.
*/
private static final List SUSPENDED_STRERRORS =
Arrays.asList(Errno.EINTR.description(), Errno.EIO.description());
public JLineConsole() {
this(null);
}
public JLineConsole(PyObject locals) {
this(locals, CONSOLE_FILENAME);
try {
File historyFile = new File(System.getProperty("user.home"), ".jline-jython.history");
reader.getHistory().setHistoryFile(historyFile);
} catch (IOException e) {
// oh well, no history from file
}
}
public JLineConsole(PyObject locals, String filename) {
super(locals, filename, true);
// Disable JLine's unicode handling so it yields raw bytes
System.setProperty("jline.UnixTerminal.input.encoding", "ISO-8859-1");
System.setProperty("jline.WindowsTerminal.input.encoding", "ISO-8859-1");
Terminal.setupTerminal();
try {
InputStream input = new FileInputStream(FileDescriptor.in);
// Raw bytes in, so raw bytes out
Writer output = new OutputStreamWriter(new FileOutputStream(FileDescriptor.out),
"ISO-8859-1");
reader = new ConsoleReader(input, output, getBindings());
reader.setBellEnabled(false);
} catch (IOException e) {
throw new RuntimeException(e);
}
windows = reader.getTerminal() instanceof WindowsTerminal;
}
/**
* Return the JLine bindings file.
*
* This handles loading the user's custom keybindings (normally JLine does) so it can
* fallback to Jython's (which disable tab completition) when the user's are not
* available.
*
* @return an InputStream of the JLine bindings file.
*/
protected InputStream getBindings() {
String userBindings = new File(System.getProperty("user.home"),
".jlinebindings.properties").getAbsolutePath();
File bindingsFile = new File(System.getProperty("jline.keybindings", userBindings));
try {
if (bindingsFile.isFile()) {
try {
return new FileInputStream(bindingsFile);
} catch (FileNotFoundException fnfe) {
// Shouldn't really ever happen
fnfe.printStackTrace();
}
}
} catch (SecurityException se) {
// continue
}
return getClass().getResourceAsStream("jline-keybindings.properties");
}
@Override
public String raw_input(PyObject prompt) {
String line = null;
String promptString = prompt.toString();
while (true) {
try {
if (startup_hook != null) {
try {
startup_hook.__call__();
} catch (Exception ex) {
System.err.println(ex);
}
}
line = reader.readLine(promptString);
break;
} catch (IOException ioe) {
if (!fromSuspend(ioe)) {
throw Py.IOError(ioe);
}
// Hopefully an IOException caused by ctrl-z (seems only BSD throws this).
// Must reset jline to continue
try {
reader.getTerminal().initializeTerminal();
} catch (Exception e) {
throw Py.IOError(e.getMessage());
}
// Don't redisplay the prompt
promptString = "";
}
}
if (isEOF(line)) {
throw Py.EOFError("");
}
return line;
}
/**
* Determine if the IOException was likely caused by a SIGSTP (ctrl-z). Seems only
* applicable to BSD platforms.
*/
private boolean fromSuspend(IOException ioe) {
return !windows && SUSPENDED_STRERRORS.contains(ioe.getMessage());
}
/**
* Determine if line denotes an EOF.
*/
private boolean isEOF(String line) {
return line == null || (windows && CTRL_Z.equals(line));
}
/**
* @return the JLine console reader associated with this interpreter
*/
public ConsoleReader getReader() {
return reader;
}
/**
* @return the startup hook (called prior to each readline)
*/
public PyObject getStartupHook() {
return startup_hook;
}
/**
* Sets the startup hook (called prior to each readline)
*/
public void setStartupHook(PyObject hook) {
startup_hook = hook;
}
}