Added the callback interface from the callback branch.

This commit is contained in:
Jorgen Stenarson
2008-06-24 20:08:32 +02:00
parent c5ce530293
commit 776d2141a8
5 changed files with 160 additions and 55 deletions
+3
View File
@@ -27,6 +27,9 @@ __all__ = [ 'parse_and_bind',
'set_completer_delims',
'get_completer_delims',
'add_history',
'callback_handler_install',
'callback_handler_remove',
'callback_read_char',
'GetOutputFile',
'rl',
'rlmain']
+53
View File
@@ -0,0 +1,53 @@
'''
Example script using the callback interface of readline.
:author: strank
'''
__docformat__ = "restructuredtext en"
import sys
import os
import time
import readline
import msvcrt
from pyreadline.rlmain import rl
prompting = True
count = 0
maxlines = 10
def main():
readline.callback_handler_install('Starting test, please do type:' + os.linesep, lineReceived)
index = 0
start = int(time.time())
while prompting:
# demonstrate that async stuff is possible:
if start + index < time.time():
rl.console.title("NON-BLOCKING: %d" % index)
index += 1
# ugly busy waiting/polling on windows, using 'select' on Unix: (or use twisted)
if msvcrt.kbhit():
readline.callback_read_char()
print "Done, index =", index
def lineReceived(line):
global count, prompting
count += 1
print "Got line: %s" % line
if count > maxlines:
prompting = False
readline.callback_handler_remove()
else:
readline.callback_handler_install('Got %s of %s, more typing please:' % (count, maxlines)
+ os.linesep, lineReceived)
if __name__ == '__main__':
main()
+58 -54
View File
@@ -55,10 +55,6 @@ class BaseMode(object):
return val
argument_reset=property(_argreset)
# _history=property(_g("_history"))
# l_buffer=property(*_gs("l_buffer"))
#used in readline
ctrl_c_tap_time_interval=property(*_gs("ctrl_c_tap_time_interval"))
allow_ctrl_c=property(*_gs("allow_ctrl_c"))
@@ -77,8 +73,6 @@ class BaseMode(object):
_bell=property(_g("_bell"))
bell_style=property(_g("bell_style"))
rl_settings_to_string=property(_g("rl_settings_to_string"))
#used in emacs
_clear_after=property(_g("_clear_after"))
_update_prompt_pos=property(_g("_update_prompt_pos"))
@@ -91,12 +85,65 @@ class BaseMode(object):
#not used in basemode or emacs
def readline_event_available(self):
return self.console.peek() or (len(self.paste_line_buffer)>0)
def _readline_from_keyboard(self):
raise NotImplementedError
while 1:
if self._readline_from_keyboard_poll():
break
def _readline_from_keyboard_poll(self):
if len(self.paste_line_buffer)>0:
#paste first line in multiline paste buffer
self.l_buffer=lineobj.ReadLineTextBuffer(self.paste_line_buffer[0])
self._update_line()
self.paste_line_buffer=self.paste_line_buffer[1:]
return True
c=self.console
def nop(e):
pass
try:
event = c.getkeypress()
except KeyboardInterrupt:
event=self.handle_ctrl_c()
if self.next_meta:
self.next_meta = False
control, meta, shift, code = event.keyinfo
event.keyinfo = (control, True, shift, code)
result=self.process_keyevent(event.keyinfo)
self._update_line()
return result
def readline(self, prompt=''):
'''Try to act like GNU readline.'''
# handle startup_hook
self.readline_setup(prompt)
self._readline_from_keyboard()
self.console.write('\r\n')
log('returning(%s)' % self.l_buffer.get_line_text())
return self.l_buffer.get_line_text() + '\n'
def handle_ctrl_c(self):
from pyreadline.keysyms.common import KeyPress
from pyreadline.console.event import Event
log_sock("KBDIRQ")
event=Event(0,0)
event.char="c"
event.keyinfo=KeyPress("c",shift=False,control=True,meta=False,keyname=None)
if self.allow_ctrl_c:
now=time.time()
if (now-self.ctrl_c_timeout)<self.ctrl_c_tap_time_interval:
log_sock("Raise KeyboardInterrupt")
raise KeyboardInterrupt
else:
self.ctrl_c_timeout=now
else:
raise KeyboardInterrupt
return event
def readline_setup(self, prompt=''):
self.ctrl_c_timeout=time.time()
self.l_buffer.selection_mark=-1
if self.first_prompt:
@@ -120,49 +167,10 @@ class BaseMode(object):
print 'pre_input_hook failed'
traceback.print_exc()
self.pre_input_hook = None
self._update_line()
log("in readline: %s"%self.paste_line_buffer)
if len(self.paste_line_buffer)>0:
self.l_buffer=lineobj.ReadLineTextBuffer(self.paste_line_buffer[0])
self._update_line()
self.paste_line_buffer=self.paste_line_buffer[1:]
c.write('\r\n')
else:
while 1:
self._update_line()
lbuf=self.l_buffer
log_sock("point:%d mark:%d selection_mark:%d"%(lbuf.point,lbuf.mark,lbuf.selection_mark))
try:
event = c.getkeypress()
log_sock(u">>%s"%event)
except KeyboardInterrupt:
from pyreadline.keysyms.common import KeyPress
from pyreadline.console.event import Event
event=Event(0,0)
event.char="c"
event.keyinfo=KeyPress("c",shift=False,control=True,meta=False,keyname=None)
log_sock("KBDIRQ")
if self.allow_ctrl_c:
now=time.time()
if (now-self.ctrl_c_timeout)<self.ctrl_c_tap_time_interval:
raise
else:
self.ctrl_c_timeout=now
pass
else:
raise
if self.next_meta:
self.next_meta = False
control, meta, shift, code = event.keyinfo
event.keyinfo = (control, True, shift, code)
if self.process_keyevent(event.keyinfo):
break
c.write('\r\n')
self.add_history(self.l_buffer.copy())
log('returning(%s)' % self.l_buffer.get_line_text())
return self.l_buffer.get_line_text() + '\n'
####################################
@@ -529,7 +537,6 @@ class BaseMode(object):
'''Copy the text in the region to the windows clipboard.'''
self.l_buffer.cut_selection_to_clipboard()
def dump_functions(self, e): # ()
'''Print all of the functions and their key bindings to the Readline
output stream. If a numeric argument is supplied, the output is
@@ -540,9 +547,6 @@ class BaseMode(object):
print txt
self._print_prompt()
def commonprefix(m):
"Given a list of pathnames, returns the longest common leading component"
if not m: return ''
+1
View File
@@ -76,6 +76,7 @@ class EmacsMode(basemode.BaseMode):
self.previous_func = dispatch_func
if r:
self._update_line()
self.add_history(self.l_buffer.copy())
return True
return False
+45 -1
View File
@@ -79,6 +79,7 @@ class Readline(object):
self.enable_win32_clipboard=True
self.paste_line_buffer=[]
self.callback = None
#Below is for refactoring, raise errors when using old style attributes
#that should be refactored out
@@ -135,7 +136,7 @@ class Readline(object):
def get_line_buffer(self):
'''Return the current contents of the line buffer.'''
return self.l_buffer.mode.get_line_text()
return self.mode.l_buffer.get_line_text()
def insert_text(self, string):
'''Insert text into the command line.'''
@@ -318,10 +319,50 @@ class Readline(object):
self._clear_after()
c.cursor(1) #Show cursor
self._set_cursor()
#
# Standard call
#
def readline(self, prompt=''):
return self.mode.readline(prompt)
#
# Callback interface
#
def event_available(self):
return self.mode.readline_event_available()
def setup(self,prompt=""):
return self.mode.readline_setup(prompt)
def keyboard_poll(self):
return self.mode._readline_from_keyboard_poll()
def callback_handler_install(self, prompt, callback):
'''bool readline_callback_handler_install ( string prompt, callback callback)
Initializes the readline callback interface and terminal, prints the prompt and returns immediately
'''
self.callback = callback
self.mode.readline_setup(prompt)
def callback_handler_remove(self):
'''Removes a previously installed callback handler and restores terminal settings'''
self.callback = None
def callback_read_char(self):
'''Reads a character and informs the readline callback interface when a line is received'''
if self.keyboard_poll():
line = self.get_line_buffer() + '\n'
self.console.write('\r\n') # this is the newline terminating input
# however there is another newline added by
# self.mode.readline_setup(prompt) which is called by callback_handler_install
# this differs from GNU readline
self.add_history(self.mode.l_buffer)
# TADA:
self.callback(line)
def read_inputrc(self,inputrcpath=os.path.expanduser("~/pyreadlineconfig.ini")):
modes=dict([(x.mode,x) for x in self.editingmodes])
mode=self.editingmodes[0].mode
@@ -451,6 +492,9 @@ set_completer_delims = rl.set_completer_delims
get_completer_delims = rl.get_completer_delims
set_startup_hook = rl.set_startup_hook
set_pre_input_hook = rl.set_pre_input_hook
callback_handler_install=rl.callback_handler_install
callback_handler_remove=rl.callback_handler_remove
callback_read_char=rl.callback_read_char
if __name__ == '__main__':
res = [ rl.readline('In[%d] ' % i) for i in range(3) ]