summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1997-09-26 21:51:21 (GMT)
committerGuido van Rossum <guido@python.org>1997-09-26 21:51:21 (GMT)
commit290900a5d76a5d9763bc1d1bb228845cda5754fa (patch)
treed72b60287b654bc5d4187f3ea78a3792616fa8e7
parentee81af89779d8ea189f23fddca1d96a4eb49751e (diff)
downloadcpython-290900a5d76a5d9763bc1d1bb228845cda5754fa.zip
cpython-290900a5d76a5d9763bc1d1bb228845cda5754fa.tar.gz
cpython-290900a5d76a5d9763bc1d1bb228845cda5754fa.tar.bz2
Reordered and reformatted, and added some cool new features:
set_completer(function) parse_and_bind(string) read_init_file(filename) The first is the most exciting feature: with an appropriate Python completer function, it can do dynamic completion based on the contents of your namespace!
-rw-r--r--Modules/readline.c245
1 files changed, 183 insertions, 62 deletions
diff --git a/Modules/readline.c b/Modules/readline.c
index a1ba13d..851378d 100644
--- a/Modules/readline.c
+++ b/Modules/readline.c
@@ -1,89 +1,195 @@
-/* The readline module makes GNU readline available to Python. It
- * has ideas contributed by Lee Busby, LLNL, and William Magro,
- * Cornell Theory Center.
+/* This module makes GNU readline available to Python. It has ideas
+ * contributed by Lee Busby, LLNL, and William Magro, Cornell Theory
+ * Center. The completer interface was inspired by Lele Gaifax.
+ *
+ * More recently, it was largely rewritten by Guido van Rossum who is
+ * now maintaining it.
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
+/* Standard definitions */
#include "Python.h"
#include <setjmp.h>
#include <signal.h>
+#include <errno.h>
-/* Routines needed from outside (but not declared in a header file). */
+/* GNU readline definitions */
+#include <readline/readline.h> /* You may need to add an -I option to Setup */
+
+/* Pointers needed from outside (but not declared in a header file). */
extern int (*PyOS_InputHook)();
-extern char *readline();
-extern int rl_initialize();
-extern int rl_insert();
-extern int rl_bind_key();
-extern void add_history();
-extern char *rl_readline_name;
-extern int (*rl_event_hook)();
extern char *(*PyOS_ReadlineFunctionPointer) Py_PROTO((char *));
-/* This module's initialization routine */
-void initreadline (void);
-static void PyOS_ReadlineInit();
-static RETSIGTYPE onintr();
-static char *PyOS_GnuReadline();
-static jmp_buf jbuf;
-static PyObject *ReadlineError;
-static int already_initialized = 0;
-static char readline_module_documentation[] =
-"Readline Module, version0.0"
-;
+/* Exported function to send one line to readline's init file parser */
+
+static PyObject *
+parse_and_bind(self, args)
+ PyObject *self;
+ PyObject *args;
+{
+ char *s;
+ if (!PyArg_ParseTuple(args, "s", &s))
+ return NULL;
+ rl_parse_and_bind(s);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char doc_parse_and_bind[] = "\
+parse_and_bind(string) -> None\n\
+Parse and execute single line of a readline init file.\
+";
+
+
+/* Exported function to parse a readline init file */
+
+static PyObject *
+read_init_file(self, args)
+ PyObject *self;
+ PyObject *args;
+{
+ char *s = NULL;
+ if (!PyArg_ParseTuple(args, "|z", &s))
+ return NULL;
+ errno = rl_read_init_file(s);
+ if (errno)
+ return PyErr_SetFromErrno(PyExc_IOError);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char doc_read_init_file[] = "\
+read_init_file([filename]) -> None\n\
+Parse a readline initialization file.\n\
+The default filename is the last filename used.\
+";
+
+
+/* Exported function to specify a word completer in Python */
+
+static PyObject *completer = NULL;
+static PyThreadState *tstate = NULL;
+
+static PyObject *
+set_completer(self, args)
+ PyObject *self;
+ PyObject *args;
+{
+ PyObject *function = Py_None;
+ if (!PyArg_ParseTuple(args, "|O", &function))
+ return NULL;
+ if (function == Py_None) {
+ Py_XDECREF(completer);
+ completer = NULL;
+ tstate = NULL;
+ }
+ else if (PyCallable_Check(function)) {
+ PyObject *tmp = completer;
+ Py_INCREF(function);
+ completer = function;
+ Py_XDECREF(tmp);
+ tstate = PyThreadState_Get();
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "set_completer(func): argument not callable");
+ return NULL;
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char doc_set_completer[] = "\
+set_completer([function]) -> None\n\
+Set or remove the completer function.\n\
+The function is called as function(text, state),\n\
+for i in [0, 1, 2, ...] until it returns a non-string.\n\
+It should return the next possible completion starting with 'text'.\
+";
+
+
+/* Table of functions exported by the module */
static struct PyMethodDef readline_methods[] =
-{
- { 0, 0 }
+{
+ {"parse_and_bind", parse_and_bind, 1, doc_parse_and_bind},
+ {"read_init_file", read_init_file, 1, doc_read_init_file},
+ {"set_completer", set_completer, 1, doc_set_completer},
+ {0, 0}
};
-/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
+/* C function to call the Python completer. */
+
+static char *
+on_completion(text, state)
+ char *text;
+ int state;
+{
+ char *result = NULL;
+ if (completer != NULL) {
+ PyObject *r;
+ /* Note that readline is called with the interpreter
+ lock released! */
+ PyEval_RestoreThread(tstate);
+ r = PyObject_CallFunction(completer, "si", text, state);
+ if (r == NULL)
+ goto error;
+ if (r == Py_None) {
+ result = NULL;
+ }
+ else {
+ char *s = PyString_AsString(r);
+ if (s == NULL)
+ goto error;
+ result = strdup(s);
+ }
+ Py_DECREF(r);
+ goto done;
+ error:
+ PyErr_Clear();
+ Py_XDECREF(r);
+ done:
+ PyEval_SaveThread();
+ }
+ return result;
+}
+
+
+/* Helper to initialize GNU readline properly. */
-/* Initialize the module. Actually, that's all you can or need to do. */
-void initreadline (void)
+static void
+setup_readline()
{
- PyObject *m, *d;
-
- if (already_initialized)
- return;
- m = Py_InitModule4 ("readline", readline_methods,
- readline_module_documentation,
- (PyObject *) 0, PYTHON_API_VERSION);
- d = PyModule_GetDict (m);
- ReadlineError = PyString_FromString ("Readline.error");
- PyDict_SetItemString (d, "error", ReadlineError);
- if (PyErr_Occurred ()) {
- Py_FatalError ("Cannot initialize module readline");
- }
- if (isatty(fileno(stdin))){
- PyOS_ReadlineFunctionPointer = PyOS_GnuReadline;
- PyOS_ReadlineInit();
- }
- already_initialized = 1;
+ rl_readline_name = "python";
+ /* Force rebind of TAB to insert-tab */
+ rl_bind_key('\t', rl_insert);
+ /* Bind both ESC-TAB and ESC-ESC to the completion function */
+ rl_bind_key_in_map ('\t', rl_complete, emacs_meta_keymap);
+ rl_bind_key_in_map ('\033', rl_complete, emacs_meta_keymap);
+ /* Set our completion function */
+ rl_completion_entry_function = (Function *) on_completion;
+ /* Initialize (allows .inputrc to override) */
+ rl_initialize();
}
+
+/* Interrupt handler */
+
+static jmp_buf jbuf;
+
/* ARGSUSED */
static RETSIGTYPE
onintr(sig)
- int sig;
+ int sig;
{
- longjmp(jbuf, 1);
+ longjmp(jbuf, 1);
}
-static void
-PyOS_ReadlineInit()
-{
- /* Force rebind of TAB to insert-tab */
- rl_readline_name = "python";
- rl_initialize();
- rl_bind_key('\t', rl_insert);
-}
+
+/* Wrapper around GNU readline that handles signals differently. */
static char *
-PyOS_GnuReadline(prompt)
+call_readline(prompt)
char *prompt;
{
int n;
@@ -117,6 +223,21 @@ PyOS_GnuReadline(prompt)
return p;
}
-#ifdef __cplusplus
+
+/* Initialize the module */
+
+static char doc_module[] =
+"Importing this module enables command line editing using GNU readline.";
+
+void
+initreadline()
+{
+ PyObject *m;
+
+ m = Py_InitModule4("readline", readline_methods, doc_module,
+ (PyObject *)NULL, PYTHON_API_VERSION);
+ if (isatty(fileno(stdin))) {
+ PyOS_ReadlineFunctionPointer = call_readline;
+ setup_readline();
+ }
}
-#endif