mirror of
https://github.com/wassname/pyreadline.git
synced 2026-08-05 13:20:20 +08:00
Added the callback interface from the callback branch.
This commit is contained in:
@@ -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']
|
||||
|
||||
@@ -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()
|
||||
@@ -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 ''
|
||||
|
||||
@@ -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
@@ -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) ]
|
||||
|
||||
Reference in New Issue
Block a user