From c08f2b01ce1b58431e37c34153eee36e4f501603 Mon Sep 17 00:00:00 2001 From: jstenar <> Date: Sun, 12 Mar 2006 14:52:00 +0000 Subject: [PATCH] pyreadline-refactor: Merged changes from trunk 1158-1201 to refactor branch. Did some rearranging of method order in Readline --- doc/ChangeLog | 4 + doc/manual_base.tex | 20 ++-- doc/update_manual.py | 62 +++++++--- eggsetup.py | 6 +- pyreadline/configuration/pyreadlineconfig.ini | 5 +- pyreadline/configuration/startup.py | 13 ++- pyreadline/console.py | 9 +- pyreadline/lineeditor/history.py | 18 +-- pyreadline/logger.py | 22 ++++ pyreadline/release.py | 36 +++--- pyreadline/rlmain.py | 110 ++++++++++-------- readline.py | 5 + setup.cfg | 3 + setup.py | 7 +- 14 files changed, 207 insertions(+), 113 deletions(-) create mode 100644 pyreadline/logger.py create mode 100644 readline.py create mode 100644 setup.cfg diff --git a/doc/ChangeLog b/doc/ChangeLog index 7bdaeff..0a33f86 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,7 @@ +2006-03-12 Jörgen Stenarson + * Merged changes from trunk 1158:1201 + * Did some rearranging of method order in Readline + 2006-02-14 Jörgen Stenarson * Started Refactor branch diff --git a/doc/manual_base.tex b/doc/manual_base.tex index d63f650..57b91d7 100644 --- a/doc/manual_base.tex +++ b/doc/manual_base.tex @@ -91,12 +91,18 @@ The pyreadline package is a python implementation of GNU readline. At the moment \item win32all \end{itemize} +\subsection{Conflicts} +Unfortunately the module rlcompleter, the module that provides tab completion, imports readline which means there must be an alias from readline to pyreadline for things to work properly. This means pyreadline install a file under the name readline.py in site-packages containing: +\lstinputlisting{../readline.py} + \section{Installation} +There are a few things that are not autmatically installed. For instance the configuration file and the startup code that makes sure pyreadline is activated when running python in interactive mode. + \subsection{Development version} -Use {\ttfamily easy\_install pyreadline==dev} to get development version. +Use {\ttfamily easy\_install pyreadline==dev} to get development version. Copy pyreadlineconfig.ini from pyreadline/configuration to your HOME directory (usually c:/documents and settings/YOURNAME) \subsection{Current release version} -Currently no release version available but will be: +\emph{Currently no release version available.} Use {\ttfamily easy\_install pyreadline} to get development version. \section{Usage} @@ -116,11 +122,11 @@ The configuration file is read from the users home directory and is named pyread \end{description} Here is the example config file shipped with pyreadline: -\lstinputlisting{pyreadlineconfig.ini} +\lstinputlisting{../pyreadline/configuration/pyreadlineconfig.ini} \subsection{pyreadline with python interpreter} -In your startup file add: -\lstinputlisting{startup.py} +In your startup file (pointed to by environment variable PYTHONSTARTUP) add: +\lstinputlisting{../pyreadline/configuration/startup.py} This file is included in the doc directory of the distribution. @@ -163,7 +169,7 @@ The pyreadline package now supports international characters. However using inte \appendix \section{Bindable commands} -This appendix will contain descriptions of all bindable commands. For now you have to look in the sourcecode check the readline class of the file rlmain.py +This appendix will contain descriptions of all bindable commands. For now you have to look in the sourcecode. Check the readline class of the file rlmain.py -\end{document} \ No newline at end of file +\end{document} diff --git a/doc/update_manual.py b/doc/update_manual.py index 23a4f89..8e5dc82 100644 --- a/doc/update_manual.py +++ b/doc/update_manual.py @@ -1,17 +1,45 @@ -# Must be launched with the build version of pyreadline on path -# -import re -import pyreadline.release as release - - -fil=open("manual_base.tex") -txt=fil.read() -fil.close() - -manualtext=re.sub("--version--",release.version,txt) -fil=open("manual.tex","w") -fil.write(manualtext) -fil.close() -print "Manual (magic.tex, manual.lyx) succesfully updated, exiting..." - - +# Must be launched with the build version of pyreadline on path +# +import re,os +import pyreadline.release as release + +def run_shell_command(command,path="",stdin=""): + """command= commandline, don't forget to qoute paths with spaces + path=path to change to before issuing command + stdin=string string to pass in as standard input + """ + oldpath=os.getcwd() + if path: + os.chdir(path) + (sin,sout,serr)=os.popen3(command) + if stdin: + sin.write(stdin) + sin.close() + txt=sout.read() + errtxt=serr.read() + sout.close() + serr.close() + os.chdir(oldpath) + return txt,errtxt + +def build_pdf_doc(): + print "latex pass 1" + t,err=run_shell_command("pdflatex -interaction=batchmode manual.tex") + print "latex pass 2" + t,err=run_shell_command("pdflatex -interaction=batchmode manual.tex") + print "removing tempfiles files" + for ext in ["aux","log","out","toc"]: + os.remove("manual.%s"%ext) + + +fil=open("manual_base.tex") +txt=fil.read() +fil.close() + +manualtext=re.sub("--version--",release.version,txt) +fil=open("manual.tex","w") +fil.write(manualtext) +fil.close() +print "Manual (manual.tex) succesfully updated, exiting..." +print "Run pdflatex manual.tex manually to see errors" +build_pdf_doc() diff --git a/eggsetup.py b/eggsetup.py index 590d559..b5bcf75 100644 --- a/eggsetup.py +++ b/eggsetup.py @@ -16,11 +16,15 @@ setup(name=name, long_description = long_description, author = authors["Jorgen"][0], author_email = authors["Jorgen"][1], + maintainer = authors["Jorgen"][0], + maintainer_email = authors["Jorgen"][1], license = license, + classifiers = classifiers, url = url, - download_url = download_url, +# download_url = download_url, platforms = platforms, keywords = keywords, + py_modules = ['readline'], packages = ['pyreadline'], data_files = [('doc', glob.glob("doc/*")), ], diff --git a/pyreadline/configuration/pyreadlineconfig.ini b/pyreadline/configuration/pyreadlineconfig.ini index f2d2042..3790b4d 100644 --- a/pyreadline/configuration/pyreadlineconfig.ini +++ b/pyreadline/configuration/pyreadlineconfig.ini @@ -64,5 +64,6 @@ bell_style("none") #modes: none, audible, visible(not implemented) show_all_if_ambiguous("on") mark_directories("on") completer_delims(" \t\n\"\\'`@$><=;|&{(") -#debug_output("on") #Not implemented yet - +debug_output("off") +history_filename("~/.pythonhistory") +history_length(200) #value of -1 means no limit diff --git a/pyreadline/configuration/startup.py b/pyreadline/configuration/startup.py index dbf30fc..47770a8 100644 --- a/pyreadline/configuration/startup.py +++ b/pyreadline/configuration/startup.py @@ -1,13 +1,14 @@ # -*- coding: UTF-8 -*- # Example snippet to use in a PYTHONSTARTUP file -# - try: - import pyreadline + import pyreadline,atexit except ImportError: - print "Module pyreadline not available." + print "Module readline not available." else: + #import tab completion functionality import rlcompleter + #activate tab completion pyreadline.parse_and_bind("tab: complete") - - + pyreadline.rl.read_history_file() + atexit.register(pyreadline.rl.write_history_file) + del pyreadline,rlcompleter,atexit diff --git a/pyreadline/console.py b/pyreadline/console.py index 82d5412..a5c8a4e 100644 --- a/pyreadline/console.py +++ b/pyreadline/console.py @@ -12,18 +12,11 @@ This was modeled after the C extension of the same name by Fredrik Lundh. ''' # primitive debug printing that won't interfere with the screen -if 1: - fp = open('debug.txt', 'w') - def log(s): - print >>fp, s - fp.flush() -else: - def log(s): - pass import sys import traceback import re +from logger import log try: # I developed this with ctypes 0.6 diff --git a/pyreadline/lineeditor/history.py b/pyreadline/lineeditor/history.py index 5fb8ebb..a37ac7a 100644 --- a/pyreadline/lineeditor/history.py +++ b/pyreadline/lineeditor/history.py @@ -5,7 +5,7 @@ # Distributed under the terms of the BSD License. The full license is in # the file COPYING, distributed as part of this software. #***************************************************************************** -import re,operator,string,sys +import re,operator,string,sys,os #import wordmatcher #import pyreadline.clipboard as clipboard @@ -24,8 +24,9 @@ class EscapeHistory(exceptions.Exception): class LineHistory(object): def __init__(self): self.history=[] - self.history_length=-1 + self.history_length=100 self.history_cursor=0 + self.history_filename=os.path.expanduser('~/.history') def get_history_length(self): return self.history_length @@ -33,20 +34,23 @@ class LineHistory(object): def set_history_length(self,value): self.history_length=value - def read_history_file(self, filename): + def read_history_file(self, filename=None): '''Load a readline history file.''' + if filename is None: + filename=self.history_filename try: for line in open(filename, 'rt'): self.add_history(lineobj.ReadLineTextBuffer(line.rstrip())) except IOError: self.history = [] self.history_cursor = 0 - raise IOError - def write_history_file(self, filename): + def write_history_file(self, filename=None): '''Save a readline history file.''' + if filename is None: + filename=self.history_filename fp = open(filename, 'wb') - for line in self.history: + for line in self.history[-self.history_length:]: fp.write(line.get_line_text()) fp.write('\n') fp.close() @@ -60,8 +64,6 @@ class LineHistory(object): pass else: self.history.append(line) - if self.history_length > 0 and len(self.history) > self.history_length: - self.history = self.history[-self.history_length:] self.history_cursor = len(self.history) def previous_history(self,current): # (C-p) diff --git a/pyreadline/logger.py b/pyreadline/logger.py new file mode 100644 index 0000000..286989f --- /dev/null +++ b/pyreadline/logger.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +#***************************************************************************** +# Copyright (C) 2006 Jorgen Stenarson. +# +# Distributed under the terms of the BSD License. The full license is in +# the file COPYING, distributed as part of this software. +#***************************************************************************** + + +_logfile=False + +def start_log(on,filename): + global _logfile + if on=="on": + _logfile=open(filename,"w") + else: + _logfile=False + +def log(s): + if _logfile: + print >>_logfile, s + _logfile.flush() diff --git a/pyreadline/release.py b/pyreadline/release.py index 3895e5e..0f4a708 100644 --- a/pyreadline/release.py +++ b/pyreadline/release.py @@ -29,26 +29,22 @@ description = "A python implmementation of GNU readline." long_description = \ """ -The pyreadline package is a python implementation of GNU readline functionality. -It is not complete and does not necessarily strive for complete -compatibilty but rather convenience in use on the windows platform. It has been -tested for use with windows 2000 and windows xp. - -There are currently no released version, only subversion access is possible. -use: easy_install pyreadline==dev - -features: -- Copy and paste using the clipboard -- Smart paste for convenient use with ipython. Converting tab separated data to - python list or numpy array. Converting file paths to use / and escaping any - spaces using \ . -- Configuration file +The pyreadline package is a python implementation of GNU readline functionality +it is based on the ctypes based UNC readline package by Gary Bishop. +It is not complete. It has been tested for use with windows 2000 and windows xp. +Features: + * Copy and paste using the clipboard + * Smart paste for convenient use with ipython. Converting tab separated data + to python list or numpy array. Converting file paths to use / and escaping + any spaces using \\\\ . + * Configuration file + The latest development version is always available at the IPython subversion repository_. .. _repository: http://ipython.scipy.org/svn/ipython/pyreadline/trunk#egg=pyreadline-dev -""" + """ license = 'BSD' @@ -57,10 +53,16 @@ authors = {'Jorgen' : ('Jorgen Stenarson','jorgen.stenarson@bostream.nu'), 'Jack': ('Jack Trainor', ''), } -url = 'http://ipython.scipy.org' +url = 'http://projects.scipy.org/ipython/ipython/wiki/PyReadline/Intro' -download_url = 'http://ipython.scipy.org/dist' +download_url = '' platforms = ['Windows XP/2000/NT','Windows 95/98/ME'] keywords = ['readline','pyreadline'] + +classifiers = ['Development Status :: 4 - Beta', + 'Environment :: Console', + 'Operating System :: Microsoft :: Windows',] + + diff --git a/pyreadline/rlmain.py b/pyreadline/rlmain.py index 8428e35..1a942b9 100644 --- a/pyreadline/rlmain.py +++ b/pyreadline/rlmain.py @@ -20,9 +20,8 @@ import exceptions import win32con as c32 -import console -import clipboard -from console import log +import clipboard,logger,console +from logger import log from keysyms import key_text_to_keyinfo import lineeditor.lineobj as lineobj @@ -48,7 +47,6 @@ class Readline(object): self.pre_input_hook = None self.completer = None self.completer_delims = " \t\n\"\\'`@$><=;|&{(" - self.console = console.Console() self.size = self.console.size() self.prompt_color = None @@ -69,6 +67,8 @@ class Readline(object): self.mark_directories = 'on' self.bell_style = 'none' self.mark=-1 + self.l_buffer=lineobj.ReadLineTextBuffer("") + self._history=history.LineHistory() self.read_inputrc() log("\n".join(self.rl_settings_to_string())) @@ -83,11 +83,8 @@ class Readline(object): self.paste_line_buffer=[] -# self.line_buffer = [] -# self.line_cursor = 0 - self.l_buffer=lineobj.ReadLineTextBuffer("") - self._history=history.LineHistory() - + #Below is for refactoring, raise errors when using old style attributes + #that should be refactored out def _g(x): def g(self): raise GetSetError("GET %s"%x) @@ -236,6 +233,29 @@ class Readline(object): log('returning(%s)' % self.l_buffer.get_line_text()) return self.l_buffer.get_line_text() + '\n' + def set_startup_hook(self, function=None): + '''Set or remove the startup_hook function. + + If function is specified, it will be used as the new startup_hook + function; if omitted or None, any hook function already installed is + removed. The startup_hook function is called with no arguments just + before readline prints the first prompt. + + ''' + self.startup_hook = function + + def set_pre_input_hook(self, function=None): + '''Set or remove the pre_input_hook function. + + If function is specified, it will be used as the new pre_input_hook + function; if omitted or None, any hook function already installed is + removed. The pre_input_hook function is called with no arguments + after the first prompt has been printed and just before readline + starts reading input characters. + + ''' + self.pre_input_hook = function + def parse_and_bind(self, string): '''Parse and execute single line of a readline init file.''' try: @@ -282,15 +302,13 @@ class Readline(object): '''Parse a readline initialization file. The default filename is the last filename used.''' log('read_init_file("%s")' % filename) - def read_history_file(self, filename=os.path.expanduser('~/.history')): - '''Load a readline history file. The default filename is ~/.history.''' - self._history.read_history_file(filename) + #History file book keeping methods (non-bindable) + + def add_history(self, line): + '''Append a line to the history buffer, as if it was the last line typed.''' + self._history.add_history(line) - def write_history_file(self, filename=os.path.expanduser('~/.history')): - '''Save a readline history file. The default filename is ~/.history.''' - self._history.write_history_file(filename) - - def get_history_length(self, ): + def get_history_length(self ): '''Return the desired length of the history file. Negative values imply unlimited history file size.''' @@ -304,28 +322,15 @@ class Readline(object): ''' self._history.set_history_length(length) - def set_startup_hook(self, function=None): - '''Set or remove the startup_hook function. + def read_history_file(self, filename=None): + '''Load a readline history file. The default filename is ~/.history.''' + self._history.read_history_file(filename) - If function is specified, it will be used as the new startup_hook - function; if omitted or None, any hook function already installed is - removed. The startup_hook function is called with no arguments just - before readline prints the first prompt. + def write_history_file(self, filename=None): + '''Save a readline history file. The default filename is ~/.history.''' + self._history.write_history_file(filename) - ''' - self.startup_hook = function - - def set_pre_input_hook(self, function=None): - '''Set or remove the pre_input_hook function. - - If function is specified, it will be used as the new pre_input_hook - function; if omitted or None, any hook function already installed is - removed. The pre_input_hook function is called with no arguments - after the first prompt has been printed and just before readline - starts reading input characters. - - ''' - self.pre_input_hook = function + #Completer functions def set_completer(self, function=None): '''Set or remove the completer function. @@ -363,10 +368,6 @@ class Readline(object): '''Get the readline word delimiters for tab-completion.''' return self.completer_delims - def add_history(self, line): - '''Append a line to the history buffer, as if it was the last line typed.''' - self._history.add_history(line) - ### Methods below here are bindable functions def beginning_of_line(self, e): # (C-a) @@ -410,6 +411,7 @@ class Readline(object): with add_history(). If this line is a modified history line, the history line is restored to its original state.''' return True + ######### History commands def previous_history(self, e): # (C-p) '''Move back through the history list, fetching the previous command. ''' @@ -955,6 +957,9 @@ class Readline(object): file. This command is unbound by default.''' pass + + #Create key bindings: + def _bind_key(self, key, func): '''setup the mapping from key to call the function.''' keyinfo = key_text_to_keyinfo(key) @@ -1040,8 +1045,13 @@ class Readline(object): if keyinfo in self.exit_dispatch: del self.exit_dispatch[keyinfo] + def sethistoryfilename(filename): + self._history.history_filename=os.path.expanduser(filename) def setbellstyle(mode): self.bell_style=mode + def sethistorylength(length): + self._history.history_length=int(length) + def setbellstyle(mode): self.bell_style=mode def show_all_if_ambiguous(mode): @@ -1050,6 +1060,9 @@ class Readline(object): self.mark_directories=mode def completer_delims(mode): self.completer_delims=mode + def debug_output(on,filename="pyreadline_debug_log.txt"): #Not implemented yet + logger.start_log(on,filename) + logger.log("STARTING LOG") loc={"bind_key":bind_key, "bind_exit_key":bind_exit_key, "un_bind_key":un_bind_key, @@ -1057,13 +1070,19 @@ class Readline(object): "bell_style":setbellstyle, "mark_directories":mark_directories, "show_all_if_ambiguous":show_all_if_ambiguous, - "completer_delims":completer_delims,} + "completer_delims":completer_delims, + "debug_output":debug_output, + "history_filename":sethistoryfilename, + "history_length":sethistorylength} if os.path.isfile(inputrcpath): try: execfile(inputrcpath,loc,loc) - except: - #Or should we force output otherwise python -v is necessary? - #print >>sys.stderr, "Error reading .pyinputrc" + except Exception,x: + import traceback + print >>sys.stderr, "Error reading .pyinputrc" + filepath,lineno=traceback.extract_tb(sys.exc_traceback)[1][:2] + print >>sys.stderr, "Line: %s in file %s"%(lineno,filepath) + print >>sys.stderr, x raise ReadlineError("Error reading .pyinputrc") @@ -1116,6 +1135,5 @@ if __name__ == '__main__': res = [ rl.readline('In[%d] ' % i) for i in range(3) ] print res else: - #import wingdbstub console.install_readline(rl.readline) pass diff --git a/readline.py b/readline.py new file mode 100644 index 0000000..0df5d61 --- /dev/null +++ b/readline.py @@ -0,0 +1,5 @@ +# -*- coding: UTF-8 -*- +#this file is needed in site-packages to emulate readline +#necessary for rlcompleter since it relies on the existance +#of a readline module +from pyreadline import * diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..865bffa --- /dev/null +++ b/setup.cfg @@ -0,0 +1,3 @@ +[egg_info] +tag_build=.dev +tag_svn_revision=1 \ No newline at end of file diff --git a/setup.py b/setup.py index 97b4490..e667309 100644 --- a/setup.py +++ b/setup.py @@ -18,12 +18,17 @@ setup(name=name, long_description = long_description, author = authors["Jorgen"][0], author_email = authors["Jorgen"][1], + maintainer = authors["Jorgen"][0], + maintainer_email = authors["Jorgen"][1], license = license, + classifiers = classifiers, url = url, - download_url = download_url, +# download_url = download_url, platforms = platforms, keywords = keywords, + py_modules = ['readline'], packages = ['pyreadline'], + package_data = {'pyreadline':['configuration/*']}, data_files = [('share/doc/pyreadline', glob.glob("doc/*")), ] )