Hi,
I have been wanting something like this for GmatH for a while now!
Do you have any idea how you can create a canvas on which cells would
appear successively. One for input, then one for output, then one for
input and so on? And still have it work like the Interactive
interpreter attached!
This would mean a nice Interactive Interpreter a la Mathematica, and
attaching dynamically file_descriptors associated with those cells to
sys.stdin and sys.stdout!
Anyone that does that would get (not a million dollars) but, for it is
worth his name on the author list of GmatH that you might find at:
http://gmath.sourceforge.net
>>>>>>>>>>>>>>>>>> Original Message <<<<<<<<<<<<<<<<<<
On 1/11/00, 12:48:38 PM, Mirko Nasato <[EMAIL PROTECTED]> wrote
regarding [pygtk] [script] Interactive console:
> Hi everyone, I am new here.
> I have written a simple interactive console.
> The attempt is to overcome the line-by-line approach of other shells,
> allowing insertion and execution of multiple statements at once.
> You can think of it as a sort of compromise between a shell and an
> editor. Or, better, you can check it out; it's attached here.
> Bye!
> -- Mirko Nasato
# A generic class to build line-oriented command interpreters
#
# Interpreters constructed with this class obey the following conventions:
#
# 1. End of file on input is processed as the command 'EOF'.
# 2. A command is parsed out of each line by collecting the prefix composed
# of characters in the identchars member.
# 3. A command `foo' is dispatched to a method 'do_foo()'; the do_ method
# is passed a single argument consisting of the remainder of the line.
# 4. Typing an empty line repeats the last command. (Actually, it calls the
# method `emptyline', which may be overridden in a subclass.)
# 5. There is a predefined `help' method. Given an argument `topic', it
# calls the command `help_topic'. With no arguments, it lists all topics
# with defined help_ functions, broken into up to three topics; documented
# commands, miscellaneous help topics, and undocumented commands.
# 6. The command '?' is a synonym for `help'. The command '!' is a synonym
# for `shell', if a do_shell method exists.
#
# The `default' method may be overridden to intercept commands for which there
# is no do_ method.
#
# The data member `self.ruler' sets the character used to draw separator lines
# in the help messages. If empty, no ruler line is drawn. It defaults to "=".
#
# If the value of `self.intro' is nonempty when the cmdloop method is called,
# it is printed out on interpreter startup. This value may be overridden
# via an optional argument to the cmdloop() method.
#
# The data members `self.doc_header', `self.misc_header', and
# `self.undoc_header' set the headers used for the help function's
# listings of documented functions, miscellaneous topics, and undocumented
# functions respectively.
#
# These interpreters use raw_input; thus, if the readline module is loaded,
# they automatically support Emacs-like command history and editing features.
#
## 1999-2000: H. Aurag: I just modified, for now, the default behavior,
## and added by default emacs-like stuff, plus some mixing with Interactive
## Interpreter. Also added some history tracking for session Saving
import string, os, readline
import sys
import linecache
from code import InteractiveInterpreter
PROMPT = '(Cmd) '
IDENTCHARS = string.letters + string.digits + '_'
class Cmd(InteractiveInterpreter):
prompt = PROMPT
identchars = IDENTCHARS
ruler = '='
lastcmd = ''
cmdqueue = []
intro = None
doc_leader = ""
doc_header = "Documented commands (type help <topic>):"
misc_header = "Miscellaneous help topics:"
undoc_header = "Undocumented commands:"
nohelp = "*** No help on %s"
def __init__(self):
self.BUFFER = []
pass
def resetbuffer(self):
"""Reset the input buffer."""
self.buffer = []
def cmdloop(self, intro=None):
self.preloop()
if intro != None:
self.intro = intro
if self.intro:
print self.intro
stop = None
while not stop:
if self.cmdqueue:
line = self.cmdqueue[0]
del self.cmdqueue[0]
else:
try:
line = self.raw_input(self.prompt)
except EOFError:
line = 'EOF'
except KeyboardInterrupt:
print "\nKeyboardInterrupt\n"
self.resetbuffer()
line = "##"
line = self.precmd(line)
stop = self.onecmd(line)
stop = self.postcmd(stop, line)
self.postloop()
def precmd(self, line):
return line
def postcmd(self, stop, line):
if line:
self.history_index = self.history_index + 1
self.prompt = "\001\033[0;34m\002GIn["+str(self.history_index) +"]
:=\001\033[0m\002 "
print "\n"
return stop
def preloop(self):
pass
def postloop(self):
pass
def onecmd(self, line):
self.resetbuffer()
line = string.strip(line)
if line[:2] == "##":
return None
if line == '?':
line = 'help'
elif line == '!':
if hasattr(self, 'do_Shell'):
line = 'Shell'
else:
return self.default(line)
elif not line:
return self.emptyline()
self.lastcmd = line
i, n = 0, len(line)
while i < n and line[i] in self.identchars: i = i+1
cmd, arg = line[:i], string.strip(line[i:])
if cmd == '':
return self.default(line)
else:
try:
func = getattr(self, 'do_' + cmd)
self.BUFFER.append("\n## GIn[" +
str(self.history_index)+"]")
self.BUFFER.append(self.lastcmd)
except AttributeError:
return self.default(line)
return func(arg)
def emptyline(self):
return 0
if self.lastcmd:
return self.onecmd(self.lastcmd)
def push(self, line):
"""Push a line to the interpreter.
The line should not have a trailing newline; it may have
internal newlines. The line is appended to a buffer and the
interpreter's runsource() method is called with the
concatenated contents of the buffer as source. If this
indicates that the command was executed or invalid, the buffer
is reset; otherwise, the command is incomplete, and the buffer
is left as it was after the line was appended. The return
value is 1 if more input is required, 0 if the line was dealt
with in some way (this is the same as runsource()).
"""
self.buffer.append(line)
source = string.join(self.buffer, "\n")
more = self.runsource(source)
if not more:
self.BUFFER.append("\n## GIn[" + str(self.history_index)+"]")
self.BUFFER.append(source)
self.resetbuffer()
return more
def raw_input(self, prompt):
line = raw_input(self.prompt)
return line
def default(self, line):
line = string.strip(line)
more = 0
try:
more = self.push(line)
if more: print "Don't forget to indent!"
while more:
self.prompt = '....... '
line = self.raw_input(self.prompt)
more = self.push(line)
except:
print 'Error...\nType = ', sys.exc_type, ', Value = ',
sys.exc_value
def do_help(self, arg):
if arg:
# XXX check arg syntax
try:
func = getattr(self, 'help_' + arg)
except:
try:
doc=getattr(self, 'do_' + arg).__doc__
if doc:
print doc
return
except:
pass
print self.nohelp % (arg,)
return
func()
else:
# Inheritance says we have to look in class and
# base classes; order is not important.
names = []
classes = [self.__class__]
while classes:
aclass = classes[0]
if aclass.__bases__:
classes = classes + list(aclass.__bases__)
names = names + dir(aclass)
del classes[0]
cmds_doc = []
cmds_undoc = []
help = {}
for name in names:
if name[:5] == 'help_':
help[name[5:]]=1
names.sort()
# There can be duplicates if routines overridden
prevname = ''
for name in names:
if name[:3] == 'do_':
if name == prevname:
continue
prevname = name
cmd=name[3:]
if help.has_key(cmd):
cmds_doc.append(cmd)
del help[cmd]
elif getattr(self, name).__doc__:
cmds_doc.append(cmd)
else:
cmds_undoc.append(cmd)
print self.doc_leader
self.print_topics(self.doc_header, cmds_doc, 15,80)
self.print_topics(self.misc_header, help.keys(),15,80)
self.print_topics(self.undoc_header, cmds_undoc, 15,80)
def print_topics(self, header, cmds, cmdlen, maxcol):
if cmds:
print "\033[0;31m"+header+"\033[0;39m";
if self.ruler:
print "\033[0;31m"+(self.ruler * len(header))+"\033[0;39m"
(cmds_per_line,junk)=divmod(maxcol,cmdlen)
col=cmds_per_line
for cmd in cmds:
if col==0: print
print "\033[0;31m"+(("%-"+`cmdlen`+"s") %
cmd)+"\033[0;39m",
col = (col+1) % cmds_per_line
print "\n"