mirror of
https://github.com/wassname/pyreadline.git
synced 2026-09-09 11:31:11 +08:00
pyreadline-refactor: Fixing clipboard bugs, adding some editing functions
This commit is contained in:
@@ -115,8 +115,10 @@ def make_KeyPress(char,state,keycode):
|
||||
control = (state & (4+8)) != 0
|
||||
meta = (state & (1+2)) != 0
|
||||
shift = (state & 0x10) != 0
|
||||
if control:
|
||||
if control and char !="\x00":
|
||||
char = chr(VkKeyScan(ord(char)) & 0xff)
|
||||
elif control:
|
||||
char=chr(keycode)
|
||||
try:
|
||||
keyname=code2sym_map[keycode]
|
||||
except KeyError:
|
||||
|
||||
@@ -9,7 +9,7 @@ import re,operator
|
||||
|
||||
import wordmatcher
|
||||
import pyreadline.clipboard as clipboard
|
||||
|
||||
from pyreadline.logger import log,log_sock
|
||||
class NotAWordError(IndexError):
|
||||
pass
|
||||
|
||||
@@ -292,7 +292,7 @@ class TextLine(object):
|
||||
stop=key.stop(self)
|
||||
else:
|
||||
stop=key.stop
|
||||
return TextLine(self.line_buffer[start:stop],point=0)
|
||||
return self.__class__(self.line_buffer[start:stop],point=0)
|
||||
elif isinstance(key,LinePositioner):
|
||||
return self.line_buffer[key(self)]
|
||||
elif isinstance(key,tuple):
|
||||
@@ -337,15 +337,15 @@ class TextLine(object):
|
||||
if isinstance(key,slice):
|
||||
start=key.start
|
||||
stop=key.stop
|
||||
prev=self.line_buffer[:start]
|
||||
rest=self.line_buffer[stop:]
|
||||
elif isinstance(key,LinePositioner):
|
||||
start=key(self)
|
||||
stop=start+1
|
||||
else:
|
||||
start=key
|
||||
stop=key+1
|
||||
value=TextLine(value).line_buffer
|
||||
prev=self.line_buffer[:start]
|
||||
value=self.__class__(value).line_buffer
|
||||
rest=self.line_buffer[stop:]
|
||||
out=prev+value+rest
|
||||
if len(out)>=len(self):
|
||||
self.point=len(self)
|
||||
@@ -356,10 +356,16 @@ class TextLine(object):
|
||||
|
||||
def upper(self):
|
||||
self.line_buffer=[x.upper() for x in self.line_buffer]
|
||||
return self
|
||||
|
||||
def lower(self):
|
||||
self.line_buffer=[x.lower() for x in self.line_buffer]
|
||||
|
||||
return self
|
||||
|
||||
def capitalize(self):
|
||||
self.set_line(self.get_line_text().capitalize(),self.point)
|
||||
return self
|
||||
|
||||
def startswith(self,txt):
|
||||
return self.get_line_text().startswith(txt)
|
||||
|
||||
@@ -390,12 +396,16 @@ class ReadLineTextBuffer(TextLine):
|
||||
def __repr__(self):
|
||||
return 'ReadLineTextBuffer("%s",point=%s,mark=%s,selection_mark=%s)'%(self.line_buffer,self.point,self.mark,self.selection_mark)
|
||||
|
||||
|
||||
|
||||
def insert_text(self,char):
|
||||
self.delete_selection()
|
||||
self.selection_mark=-1
|
||||
self._insert_text(char)
|
||||
|
||||
def to_clipboard(self):
|
||||
if self.enable_win32_clipboard:
|
||||
clipboard.set_clipboard_text(self.get_line_text())
|
||||
|
||||
######### Movement
|
||||
|
||||
def beginning_of_line(self):
|
||||
@@ -473,6 +483,7 @@ class ReadLineTextBuffer(TextLine):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
self.selection_mark=-1
|
||||
|
||||
def delete_char(self):
|
||||
if not self.delete_selection():
|
||||
@@ -492,93 +503,128 @@ class ReadLineTextBuffer(TextLine):
|
||||
del self[PrevWordStart:Point]
|
||||
self.selection_mark=-1
|
||||
|
||||
def forward_delete_word(self):
|
||||
if not self.delete_selection():
|
||||
#del self[PrevWordEnd:Point]
|
||||
del self[Point:NextWordStart]
|
||||
self.selection_mark=-1
|
||||
|
||||
def delete_current_word(self):
|
||||
if not self.delete_selection():
|
||||
del self[CurrentWord]
|
||||
self.selection_mark=-1
|
||||
|
||||
def delete_horizontal_space(self):
|
||||
if not self.delete_selection():
|
||||
pass
|
||||
if self[Point] in " \t":
|
||||
del self[PrevWordEnd:NextWordStart]
|
||||
self.selection_mark=-1
|
||||
######### Case
|
||||
|
||||
def upcase_word(self):
|
||||
p=self.point
|
||||
try:
|
||||
self[CurrentWord]=self[CurrentWord].line_buffer.upper()
|
||||
self[CurrentWord]=self[CurrentWord].upper()
|
||||
self.point=p
|
||||
except NotAWordError:
|
||||
pass
|
||||
|
||||
def downcase_word(self):
|
||||
p=self.point
|
||||
try:
|
||||
self[CurrentWord]=self[CurrentWord].line_buffer.lower()
|
||||
self[CurrentWord]=self[CurrentWord].lower()
|
||||
self.point=p
|
||||
except NotAWordError:
|
||||
pass
|
||||
|
||||
def capitalize_word(self):
|
||||
def capitalize_word(self):
|
||||
p=self.point
|
||||
try:
|
||||
self[CurrentWord]=self[CurrentWord].line_buffer.capitalize()
|
||||
self[CurrentWord]=self[CurrentWord].capitalize()
|
||||
self.point=p
|
||||
except NotAWordError:
|
||||
pass
|
||||
########### Transpose
|
||||
def transpose_chars(self):
|
||||
pass
|
||||
p2=Point(self)
|
||||
if p2==0:
|
||||
return
|
||||
elif p2==len(self):
|
||||
p2=p2-1
|
||||
p1=p2-1
|
||||
self[p2],self[p1]=self[p1],self[p2]
|
||||
self.point=p2+1
|
||||
|
||||
def transpose_words(self):
|
||||
pass
|
||||
word1=TextLine(self)
|
||||
word2=TextLine(self)
|
||||
if self.point==len(self):
|
||||
word2.point=PrevWordStart
|
||||
word1.point=PrevWordStart(word2)
|
||||
else:
|
||||
word1.point=PrevWordStart
|
||||
word2.point=NextWordStart
|
||||
stop1=NextWordEnd(word1)
|
||||
stop2=NextWordEnd(word2)
|
||||
start1=word1.point
|
||||
start2=word2.point
|
||||
self[start2:stop2]=word1[Point:NextWordEnd]
|
||||
self[start1:stop1]=word2[Point:NextWordEnd]
|
||||
self.point=stop2
|
||||
|
||||
|
||||
############ Kill
|
||||
|
||||
def kill_line(self):
|
||||
if self.enable_win32_clipboard:
|
||||
toclipboard="".join(self.line_buffer[self.point:])
|
||||
clipboard.set_clipboard_text(toclipboard)
|
||||
self[self.point:].to_clipboard()
|
||||
del self.line_buffer[self.point:]
|
||||
|
||||
def kill_whole_line(self):
|
||||
clipboard.set_clipboard_text()
|
||||
self[:].to_clipboard()
|
||||
del self[:]
|
||||
|
||||
def backward_kill_line(self):
|
||||
clipboard.set_clipboard_text()
|
||||
self[StartOfLine:Point].to_clipboard()
|
||||
del self[StartOfLine:Point]
|
||||
|
||||
def unix_line_discard(self):
|
||||
clipboard.set_clipboard_text(self[StartOfLine:Point])
|
||||
del self[StartOfLine:Point]
|
||||
pass
|
||||
|
||||
def kill_word(self):
|
||||
"""Kills to next word ending"""
|
||||
clipboard.set_clipboard_text(self[Point:NextWordEnd])
|
||||
self[Point:NextWordEnd].to_clipboard()
|
||||
del self[Point:NextWordEnd]
|
||||
|
||||
def backward_kill_word(self):
|
||||
"""Kills to next word ending"""
|
||||
clipboard.set_clipboard_text(self[PrevWordStart:Point])
|
||||
self[PrevWordStart:Point].to_clipboard()
|
||||
if not self.delete_selection():
|
||||
del self[PrevWordStart:Point]
|
||||
self.selection_mark=-1
|
||||
|
||||
def forward_kill_word(self):
|
||||
"""Kills to next word ending"""
|
||||
self[Point:NextWordEnd].to_clipboard()
|
||||
if not self.delete_selection():
|
||||
del self[Point:NextWordEnd]
|
||||
self.selection_mark=-1
|
||||
|
||||
def unix_word_rubout(self):
|
||||
clipboard.set_clipboard_text(self[PrevSpace:Point])
|
||||
self[PrevSpace:Point].to_clipboard()
|
||||
if not self.delete_selection():
|
||||
del self[PrevSpace:Point]
|
||||
self.selection_mark=-1
|
||||
|
||||
def kill_region(self):
|
||||
clipboard.set_clipboard_text()
|
||||
pass
|
||||
|
||||
def copy_region_as_kill(self):
|
||||
clipboard.set_clipboard_text()
|
||||
pass
|
||||
|
||||
def copy_backward_word(self):
|
||||
clipboard.set_clipboard_text()
|
||||
pass
|
||||
|
||||
def copy_forward_word(self):
|
||||
clipboard.set_clipboard_text()
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ host="localhost"
|
||||
port=8081
|
||||
logsocket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
|
||||
|
||||
show_event=["keypress","bound_function"]
|
||||
show_event=["keypress","bound_function","bind_key"]
|
||||
show_event=["bound_function"]
|
||||
|
||||
def log_sock(s,event_type=None):
|
||||
|
||||
@@ -84,6 +84,7 @@ class BaseMode(object):
|
||||
print "Trying to bind non method to keystroke:%s,%s"%(key,func)
|
||||
raise PyreadlineError("Trying to bind non method to keystroke:%s,%s,%s,%s"%(key,func,type(func),type(self._bind_key)))
|
||||
keyinfo = make_KeyPress_from_keydescr(key.lower()).tuple()
|
||||
log(">>>%s -> %s<<<"%(keyinfo,func.__name__))
|
||||
self.key_dispatch[keyinfo] = func
|
||||
|
||||
def _bind_exit_key(self, key):
|
||||
@@ -282,6 +283,21 @@ class BaseMode(object):
|
||||
self.l_buffer.backward_word_extend_selection()
|
||||
|
||||
|
||||
def upcase_word(self, e): # (M-u)
|
||||
'''Uppercase the current (or following) word. With a negative
|
||||
argument, uppercase the previous word, but do not move the cursor.'''
|
||||
self.l_buffer.upcase_word()
|
||||
|
||||
def downcase_word(self, e): # (M-l)
|
||||
'''Lowercase the current (or following) word. With a negative
|
||||
argument, lowercase the previous word, but do not move the cursor.'''
|
||||
self.l_buffer.downcase_word()
|
||||
|
||||
def capitalize_word(self, e): # (M-c)
|
||||
'''Capitalize the current (or following) word. With a negative
|
||||
argument, capitalize the previous word, but do not move the cursor.'''
|
||||
self.l_buffer.capitalize_word()
|
||||
|
||||
|
||||
|
||||
def clear_screen(self, e): # (C-l)
|
||||
@@ -312,11 +328,20 @@ class BaseMode(object):
|
||||
to kill the characters instead of deleting them.'''
|
||||
self.l_buffer.backward_delete_char()
|
||||
|
||||
def backward_delete_word(self, e): # (Rubout)
|
||||
def backward_delete_word(self, e): # (Control-Rubout)
|
||||
'''Delete the character behind the cursor. A numeric argument means
|
||||
to kill the characters instead of deleting them.'''
|
||||
self.l_buffer.backward_delete_word()
|
||||
|
||||
def forward_delete_word(self, e): # (Control-Delete)
|
||||
'''Delete the character behind the cursor. A numeric argument means
|
||||
to kill the characters instead of deleting them.'''
|
||||
self.l_buffer.forward_delete_word()
|
||||
|
||||
def delete_horizontal_space(self, e): # ()
|
||||
'''Delete all spaces and tabs around point. By default, this is unbound. '''
|
||||
self.l_buffer.delete_horizontal_space()
|
||||
|
||||
def self_insert(self, e): # (a, b, A, 1, !, ...)
|
||||
'''Insert yourself. '''
|
||||
if ord(e.char)!=0: #don't insert null character in buffer, can happen with dead keys.
|
||||
@@ -326,13 +351,17 @@ class BaseMode(object):
|
||||
# Paste from clipboard
|
||||
|
||||
def paste(self,e):
|
||||
'''Paste windows clipboard'''
|
||||
'''Paste windows clipboard.
|
||||
Assume single line strip other lines and end of line markers and trailing spaces''' #(Control-v)
|
||||
if self.enable_win32_clipboard:
|
||||
txt=clipboard.get_clipboard_text_and_convert(False)
|
||||
txt=txt.split("\n")[0].strip("\r").strip("\n")
|
||||
log("paste: >%s<"%map(ord,txt))
|
||||
self.insert_text(txt)
|
||||
|
||||
def paste_mulitline_code(self,e):
|
||||
'''Paste windows clipboard'''
|
||||
'''Paste windows clipboard as multiline code.
|
||||
Removes any empty lines in the code'''
|
||||
reg=re.compile("\r?\n")
|
||||
if self.enable_win32_clipboard:
|
||||
txt=clipboard.get_clipboard_text_and_convert(False)
|
||||
@@ -372,6 +401,20 @@ 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
|
||||
formatted in such a way that it can be made part of an inputrc
|
||||
file. This command is unbound by default.'''
|
||||
print
|
||||
txt="\n".join(self.rl_settings_to_string())
|
||||
print txt
|
||||
self._print_prompt()
|
||||
|
||||
|
||||
|
||||
|
||||
def commonprefix(m):
|
||||
"Given a list of pathnames, returns the longest common leading component"
|
||||
if not m: return ''
|
||||
|
||||
@@ -275,21 +275,6 @@ class EmacsMode(basemode.BaseMode):
|
||||
of the line, this transposes the last two words on the line.'''
|
||||
self.l_buffer.transpose_words()
|
||||
|
||||
def upcase_word(self, e): # (M-u)
|
||||
'''Uppercase the current (or following) word. With a negative
|
||||
argument, uppercase the previous word, but do not move the cursor.'''
|
||||
self.l_buffer.upcase_word()
|
||||
|
||||
def downcase_word(self, e): # (M-l)
|
||||
'''Lowercase the current (or following) word. With a negative
|
||||
argument, lowercase the previous word, but do not move the cursor.'''
|
||||
self.l_buffer.downcase_word()
|
||||
|
||||
def capitalize_word(self, e): # (M-c)
|
||||
'''Capitalize the current (or following) word. With a negative
|
||||
argument, capitalize the previous word, but do not move the cursor.'''
|
||||
self.l_buffer.capitalize_word()
|
||||
|
||||
def overwrite_mode(self, e): # ()
|
||||
'''Toggle overwrite mode. With an explicit positive numeric
|
||||
argument, switches to overwrite mode. With an explicit non-positive
|
||||
@@ -324,7 +309,8 @@ class EmacsMode(basemode.BaseMode):
|
||||
words, to the end of the next word. Word boundaries are the same as
|
||||
forward-word.'''
|
||||
self.l_buffer.kill_word()
|
||||
|
||||
forward_kill_word=kill_word
|
||||
|
||||
def backward_kill_word(self, e): # (M-DEL)
|
||||
'''Kill the word behind point. Word boundaries are the same as
|
||||
backward-word. '''
|
||||
@@ -335,10 +321,6 @@ class EmacsMode(basemode.BaseMode):
|
||||
boundary. The killed text is saved on the kill-ring.'''
|
||||
self.l_buffer.unix_word_rubout()
|
||||
|
||||
def delete_horizontal_space(self, e): # ()
|
||||
'''Delete all spaces and tabs around point. By default, this is unbound. '''
|
||||
pass
|
||||
|
||||
def kill_region(self, e): # ()
|
||||
'''Kill the text in the current region. By default, this command is unbound. '''
|
||||
pass
|
||||
@@ -476,13 +458,6 @@ class EmacsMode(basemode.BaseMode):
|
||||
case, the line is accepted as if a newline had been typed.'''
|
||||
pass
|
||||
|
||||
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
|
||||
formatted in such a way that it can be made part of an inputrc
|
||||
file. This command is unbound by default.'''
|
||||
pass
|
||||
|
||||
def dump_variables(self, e): # ()
|
||||
'''Print all of the settable variables and their values to the
|
||||
Readline output stream. If a numeric argument is supplied, the
|
||||
@@ -516,7 +491,7 @@ class EmacsMode(basemode.BaseMode):
|
||||
self._bind_key('Right', self.forward_char)
|
||||
self._bind_key('Control-f', self.forward_char)
|
||||
self._bind_key('BackSpace', self.backward_delete_char)
|
||||
self._bind_key('Control-BackSpace', self.backward_delete_word)
|
||||
self._bind_key('Control-BackSpace', self.backward_delete_word)
|
||||
|
||||
self._bind_key('Home', self.beginning_of_line)
|
||||
self._bind_key('End', self.end_of_line)
|
||||
@@ -576,6 +551,7 @@ class EmacsMode(basemode.BaseMode):
|
||||
self._bind_key("multiply", self.self_insert)
|
||||
self._bind_key("divide", self.self_insert)
|
||||
self._bind_key("vk_decimal", self.self_insert)
|
||||
log("RUNNING INIT EMACS")
|
||||
|
||||
# make it case insensitive
|
||||
def commonprefix(m):
|
||||
|
||||
@@ -19,7 +19,7 @@ import operator
|
||||
import exceptions
|
||||
|
||||
import clipboard,logger,console
|
||||
from logger import log
|
||||
from logger import log,log_sock
|
||||
from error import ReadlineError,GetSetError
|
||||
from pyreadline.keysyms.common import make_KeyPress_from_keydescr
|
||||
|
||||
@@ -241,7 +241,7 @@ class Readline(object):
|
||||
|
||||
## Internal functions
|
||||
|
||||
def rl_settings_to_string(self,e=None):
|
||||
def rl_settings_to_string(self):
|
||||
out=["%-20s: %s"%("show all if ambigous",self.show_all_if_ambiguous)]
|
||||
out.append("%-20s: %s"%("mark_directories",self.mark_directories))
|
||||
out.append("%-20s: %s"%("bell_style",self.bell_style))
|
||||
@@ -250,15 +250,9 @@ class Readline(object):
|
||||
tablepat="%-7s %-7s %-7s %-15s %-15s "
|
||||
out.append(tablepat%("Control","Meta","Shift","Keycode/char","Function"))
|
||||
bindings=[(k[0],k[1],k[2],k[3],v.__name__) for k,v in self.mode.key_dispatch.iteritems()]
|
||||
#print self.mode.key_dispatch
|
||||
#bindings=[str(v) for k,v in self.mode.key_dispatch.iteritems()]
|
||||
bindings.sort()
|
||||
for key in bindings:
|
||||
pass
|
||||
# out.append(str(key))
|
||||
out.append(tablepat%(key))
|
||||
if e:
|
||||
print "\n".join(out)
|
||||
return out
|
||||
|
||||
def _bell(self):
|
||||
@@ -334,10 +328,13 @@ class Readline(object):
|
||||
def setmode(name):
|
||||
self.mode=modes[name]
|
||||
def bind_key(key,name):
|
||||
# print "bind",key,name
|
||||
log("bind %s %s"%(key,name))
|
||||
log_sock("bindkey: %s %s"%(key,name),"bind_key")
|
||||
if hasattr(modes[mode],name):
|
||||
# print "can bind",key,name
|
||||
modes[mode]._bind_key(key,getattr(modes[mode],name))
|
||||
else:
|
||||
print "Trying to bind unknown command '%s' to key '%s'"%(name,key)
|
||||
def un_bind_key(key):
|
||||
keyinfo = make_KeyPress_from_keydescr(key).tuple()
|
||||
if keyinfo in modes[mode].key_dispatch:
|
||||
|
||||
Reference in New Issue
Block a user