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 Show documentation
Show all versions of jython 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 jnr.constants.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;
}
}