mirror of
https://github.com/wassname/pyreadline.git
synced 2026-06-27 16:10:38 +08:00
pyreadline-refactor: Added visible selection mode to emacs-mode.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
2006-03-16 Jörgen Stenarson <jorgen.stenarson -at- bostream.nu>
|
||||
* Added vi patch
|
||||
* Added visible selection mode to emacs mode
|
||||
|
||||
2006-03-16 Jörgen Stenarson <jorgen.stenarson -at- bostream.nu>
|
||||
* Refactored emacs mode
|
||||
|
||||
@@ -4,16 +4,21 @@ set_mode("emacs") #will cause following bind_keys to bind to emacs mode
|
||||
bind_exit_key("Control-d")
|
||||
bind_exit_key("Control-z")
|
||||
|
||||
|
||||
#Commands for moving
|
||||
bind_key("Home", "beginning_of_line")
|
||||
bind_key("End", "end_of_line")
|
||||
bind_key("Left", "backward_char")
|
||||
bind_key("Left", "backward_char")
|
||||
bind_key("Control-b", "backward_char")
|
||||
bind_key("Right", "forward_char")
|
||||
bind_key("Control-f", "forward_char")
|
||||
bind_key("Alt-f", "forward_word")
|
||||
bind_key("Control-Right", "forward_word")
|
||||
bind_key("Shift-Right", "forward_char_extend_selection")
|
||||
bind_key("Shift-Left", "backward_char_extend_selection")
|
||||
bind_key("Shift-Control-Right", "forward_word_extend_selection")
|
||||
bind_key("Shift-Control-Left", "backward_word_extend_selection")
|
||||
bind_key("Alt-b", "backward_word")
|
||||
bind_key("Control-Left", "backward_word")
|
||||
bind_key("Clear", "clear_screen")
|
||||
bind_key("Control-l", "clear_screen")
|
||||
bind_key("Control-a", "beginning_of_line")
|
||||
@@ -21,7 +26,7 @@ bind_key("Control-e", "end_of_line")
|
||||
#bind_key("Control-l", "redraw_current_line")
|
||||
|
||||
#Commands for Manipulating the History
|
||||
bind_key("Return", "accept_line")
|
||||
bind_key("Return", "accept_line")
|
||||
bind_key("Control-p", "previous_history")
|
||||
bind_key("Control-n", "next_history")
|
||||
bind_key("Up", "history_search_backward")
|
||||
@@ -37,12 +42,14 @@ bind_key("Alt-n", "non_incremental_forward_search_history")
|
||||
bind_key("Delete", "delete_char")
|
||||
bind_key("Control-d", "delete_char")
|
||||
bind_key("BackSpace", "backward_delete_char")
|
||||
bind_key("Control-Shift-v", "quoted_insert")
|
||||
bind_key("Control-BackSpace", "backward_delete_word")
|
||||
#bind_key("Control-Shift-v", "quoted_insert")
|
||||
bind_key("Control-space", "self_insert")
|
||||
|
||||
#Killing and Yanking
|
||||
bind_key("Control-k", "kill_line")
|
||||
bind_key("Control-shift-k", "kill_whole_line")
|
||||
bind_key("Escape", "kill_whole_line")
|
||||
bind_key("Meta-d", "kill_word")
|
||||
bind_key("Control-w", "unix_word_rubout")
|
||||
bind_key("Meta-Delete", "backward_kill_word")
|
||||
@@ -50,23 +57,25 @@ bind_key("Meta-Delete", "backward_kill_word")
|
||||
#Copy paste
|
||||
bind_key("Control-m", "set_mark")
|
||||
bind_key("Control-q", "copy_region_to_clipboard")
|
||||
bind_key("Control-x", "cut_selection_to_clipboard")
|
||||
bind_key("Control-Shift-x", "copy_selection_to_clipboard")
|
||||
bind_key("Control-v", "paste")
|
||||
bind_key("Alt-v", "ipython_paste")
|
||||
bind_key("Control-y", "paste")
|
||||
bind_key("Control-z", "undo")
|
||||
bind_key("Control-_", "undo")
|
||||
bind_key('Control-Shift-v', "paste_mulitline_code")
|
||||
|
||||
#Unbinding keys:
|
||||
#un_bind_key("Home")
|
||||
|
||||
|
||||
|
||||
#Other
|
||||
bell_style("none") #modes: none, audible, visible(not implemented)
|
||||
show_all_if_ambiguous("on")
|
||||
mark_directories("on")
|
||||
completer_delims(" \t\n\"\\'`@$><=;|&{(")
|
||||
completer_delims(" \t\n\"\\'`@$><=;|&{(?")
|
||||
debug_output("off")
|
||||
|
||||
history_filename("~/.pythonhistory")
|
||||
history_length(200) #value of -1 means no limit
|
||||
|
||||
|
||||
@@ -17,8 +17,6 @@ def quote_char(c):
|
||||
if ord(c)>0:
|
||||
return c
|
||||
|
||||
|
||||
|
||||
############## Line positioner ########################
|
||||
|
||||
class LinePositioner(object):
|
||||
@@ -358,44 +356,109 @@ class ReadLineTextBuffer(TextLine):
|
||||
def __init__(self,txtstr,point=None,mark=None):
|
||||
super(ReadLineTextBuffer,self).__init__(txtstr,point,mark)
|
||||
self.enable_win32_clipboard=True
|
||||
self.selection_mark=-1
|
||||
self.enable_selection=True
|
||||
|
||||
def insert_text(self,char):
|
||||
self.delete_selection()
|
||||
self.selection_mark=-1
|
||||
self._insert_text(char)
|
||||
|
||||
|
||||
######### Movement
|
||||
|
||||
def beginning_of_line(self):
|
||||
self.selection_mark=-1
|
||||
self.point=StartOfLine
|
||||
|
||||
def end_of_line(self):
|
||||
self.selection_mark=-1
|
||||
self.point=EndOfLine
|
||||
|
||||
def forward_char(self):
|
||||
self.selection_mark=-1
|
||||
self.point=NextChar
|
||||
|
||||
def backward_char(self):
|
||||
self.selection_mark=-1
|
||||
self.point=PrevChar
|
||||
|
||||
def forward_word(self):
|
||||
self.selection_mark=-1
|
||||
self.point=NextWordStart
|
||||
|
||||
def backward_word(self):
|
||||
self.selection_mark=-1
|
||||
self.point=PrevWordStart
|
||||
|
||||
######### Movement select
|
||||
def beginning_of_line_extend_selection(self):
|
||||
if self.enable_selection and self.selection_mark<0:
|
||||
self.selection_mark=self.point
|
||||
self.point=StartOfLine
|
||||
|
||||
def end_of_line_extend_selection(self):
|
||||
if self.enable_selection and self.selection_mark<0:
|
||||
self.selection_mark=self.point
|
||||
self.point=EndOfLine
|
||||
|
||||
def forward_char_extend_selection(self):
|
||||
if self.enable_selection and self.selection_mark<0:
|
||||
self.selection_mark=self.point
|
||||
self.point=NextChar
|
||||
|
||||
def backward_char_extend_selection(self):
|
||||
if self.enable_selection and self.selection_mark<0:
|
||||
self.selection_mark=self.point
|
||||
self.point=PrevChar
|
||||
|
||||
def forward_word_extend_selection(self):
|
||||
if self.enable_selection and self.selection_mark<0:
|
||||
self.selection_mark=self.point
|
||||
self.point=NextWordStart
|
||||
|
||||
def backward_word_extend_selection(self):
|
||||
if self.enable_selection and self.selection_mark<0:
|
||||
self.selection_mark=self.point
|
||||
self.point=PrevWordStart
|
||||
|
||||
######### delete
|
||||
|
||||
def delete_selection(self):
|
||||
if self.enable_selection and self.selection_mark>0:
|
||||
if self.selection_mark<self.point:
|
||||
del self[self.selection_mark:self.point]
|
||||
else:
|
||||
del self[self.point:self.selection_mark]
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def delete_char(self):
|
||||
del self[Point]
|
||||
if not self.delete_selection():
|
||||
del self[Point]
|
||||
self.selection_mark=-1
|
||||
|
||||
def backward_delete_char(self):
|
||||
self.backward_char()
|
||||
self.delete_char()
|
||||
if not self.delete_selection():
|
||||
if self.point>0:
|
||||
self.backward_char()
|
||||
self.delete_char()
|
||||
self.selection_mark=-1
|
||||
|
||||
def backward_delete_word(self):
|
||||
if not self.delete_selection():
|
||||
del self[PrevWordEnd:Point]
|
||||
self.selection_mark=-1
|
||||
|
||||
def delete_current_word(self):
|
||||
del self[CurrentWord]
|
||||
if not self.delete_selection():
|
||||
del self[CurrentWord]
|
||||
self.selection_mark=-1
|
||||
|
||||
def delete_horizontal_space(self):
|
||||
pass
|
||||
if not self.delete_selection():
|
||||
pass
|
||||
self.selection_mark=-1
|
||||
######### Case
|
||||
|
||||
def upcase_word(self):
|
||||
@@ -488,6 +551,22 @@ class ReadLineTextBuffer(TextLine):
|
||||
toclipboard="".join(self.line_buffer[begin:end])
|
||||
clipboard.SetClipboardText(str(toclipboard))
|
||||
|
||||
def copy_selection_to_clipboard(self): # ()
|
||||
'''Copy the text in the region to the windows clipboard.'''
|
||||
if self.enable_win32_clipboard and self.enable_selection and self.selection_mark>0:
|
||||
selection_mark=min(self.selection_mark,len(self.line_buffer))
|
||||
cursor=min(self.point,len(self.line_buffer))
|
||||
if self.selection_mark==-1:
|
||||
return
|
||||
begin=min(cursor,selection_mark)
|
||||
end=max(cursor,selection_mark)
|
||||
toclipboard="".join(self.line_buffer[begin:end])
|
||||
clipboard.SetClipboardText(str(toclipboard))
|
||||
|
||||
|
||||
def cut_selection_to_clipboard(self): # ()
|
||||
self.copy_selection_to_clipboard()
|
||||
self.delete_selection()
|
||||
############## Paste
|
||||
|
||||
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
# Distributed under the terms of the BSD License. The full license is in
|
||||
# the file COPYING, distributed as part of this software.
|
||||
#*****************************************************************************
|
||||
import os
|
||||
import os,re
|
||||
import pyreadline.logger as logger
|
||||
from pyreadline.logger import log
|
||||
from pyreadline.keysyms import key_text_to_keyinfo
|
||||
import pyreadline.lineeditor.lineobj as lineobj
|
||||
import pyreadline.lineeditor.history as history
|
||||
import pyreadline.clipboard as clipboard
|
||||
|
||||
class BaseMode(object):
|
||||
mode="base"
|
||||
@@ -41,11 +42,12 @@ class BaseMode(object):
|
||||
next_meta=property(*_gs("next_meta"))
|
||||
first_prompt=property(*_gs("first_prompt"))
|
||||
prompt=property(*_gs("prompt"))
|
||||
paste_line_buffer=property(*_gs("paste_line_buffer"))
|
||||
|
||||
console=property(_g("console"))
|
||||
insert_text=property(_g("insert_text"))
|
||||
_print_prompt=property(_g("_print_prompt"))
|
||||
_update_line=property(_g("_update_line"))
|
||||
paste_line_buffer=property(_g("paste_line_buffer"))
|
||||
add_history=property(_g("add_history"))
|
||||
_bell=property(_g("_bell"))
|
||||
_clear_after=property(_g("_clear_after"))
|
||||
@@ -54,9 +56,11 @@ class BaseMode(object):
|
||||
_update_prompt_pos=property(_g("_update_prompt_pos"))
|
||||
_update_line=property(_g("_update_line"))
|
||||
enable_win32_clipboard=property(_g("enable_win32_clipboard"))
|
||||
enable_ipython_paste_list_of_lists=property(_g("enable_ipython_paste_list_of_lists"))
|
||||
enable_ipython_paste_for_paths=property(_g("enable_ipython_paste_for_paths"))
|
||||
_bell=property(_g("_bell"))
|
||||
_history=property(_g("_history"))
|
||||
|
||||
|
||||
def _readline_from_keyboard(self):
|
||||
raise NotImplementedError
|
||||
|
||||
@@ -229,6 +233,37 @@ class BaseMode(object):
|
||||
composed of letters and digits.'''
|
||||
self.l_buffer.backward_word()
|
||||
|
||||
|
||||
|
||||
def beginning_of_line_extend_selection(self, e): #
|
||||
'''Move to the start of the current line. '''
|
||||
self.l_buffer.beginning_of_line_extend_selection()
|
||||
|
||||
def end_of_line_extend_selection(self, e): #
|
||||
'''Move to the end of the line. '''
|
||||
self.l_buffer.end_of_line_extend_selection()
|
||||
|
||||
def forward_char_extend_selection(self, e): #
|
||||
'''Move forward a character. '''
|
||||
self.l_buffer.forward_char_extend_selection()
|
||||
|
||||
def backward_char_extend_selection(self, e): #
|
||||
'''Move back a character. '''
|
||||
self.l_buffer.backward_char_extend_selection()
|
||||
|
||||
def forward_word_extend_selection(self, e): #
|
||||
'''Move forward to the end of the next word. Words are composed of
|
||||
letters and digits.'''
|
||||
self.l_buffer.forward_word_extend_selection()
|
||||
|
||||
def backward_word_extend_selection(self, e): #
|
||||
'''Move back to the start of the current or previous word. Words are
|
||||
composed of letters and digits.'''
|
||||
self.l_buffer.backward_word_extend_selection()
|
||||
|
||||
|
||||
|
||||
|
||||
def clear_screen(self, e): # (C-l)
|
||||
'''Clear the screen and redraw the current line, leaving the current
|
||||
line at the top of the screen.'''
|
||||
@@ -257,8 +292,63 @@ class BaseMode(object):
|
||||
to kill the characters instead of deleting them.'''
|
||||
self.l_buffer.backward_delete_char()
|
||||
|
||||
def backward_delete_word(self, e): # (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 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.
|
||||
self.insert_text(e.char)
|
||||
|
||||
|
||||
# Paste from clipboard
|
||||
|
||||
def paste(self,e):
|
||||
'''Paste windows clipboard'''
|
||||
if self.enable_win32_clipboard:
|
||||
txt=clipboard.get_clipboard_text_and_convert(False)
|
||||
self.insert_text(txt)
|
||||
|
||||
def paste_mulitline_code(self,e):
|
||||
'''Paste windows clipboard'''
|
||||
reg=re.compile("\r?\n")
|
||||
if self.enable_win32_clipboard:
|
||||
txt=clipboard.get_clipboard_text_and_convert(False)
|
||||
t=reg.split(txt)
|
||||
t=[row for row in t if row.strip()!=""] #remove empty lines
|
||||
if t!=[""]:
|
||||
self.insert_text(t[0])
|
||||
self.add_history(self.l_buffer.copy())
|
||||
self.paste_line_buffer=t[1:]
|
||||
log("multi: %s"%self.paste_line_buffer)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def ipython_paste(self,e):
|
||||
'''Paste windows clipboard. If enable_ipython_paste_list_of_lists is
|
||||
True then try to convert tabseparated data to repr of list of lists or
|
||||
repr of array'''
|
||||
if self.enable_win32_clipboard:
|
||||
txt=clipboard.get_clipboard_text_and_convert(
|
||||
self.enable_ipython_paste_list_of_lists)
|
||||
if self.enable_ipython_paste_for_paths:
|
||||
if len(txt)<300 and ("\t" not in txt) and ("\n" not in txt):
|
||||
txt=txt.replace("\\","/").replace(" ",r"\ ")
|
||||
self.insert_text(txt)
|
||||
|
||||
|
||||
def copy_region_to_clipboard(self, e): # ()
|
||||
'''Copy the text in the region to the windows clipboard.'''
|
||||
self.l_buffer.copy_region_to_clipboard()
|
||||
|
||||
def copy_selection_to_clipboard(self, e): # ()
|
||||
'''Copy the text in the region to the windows clipboard.'''
|
||||
self.l_buffer.copy_selection_to_clipboard()
|
||||
|
||||
def cut_selection_to_clipboard(self, e): # ()
|
||||
'''Copy the text in the region to the windows clipboard.'''
|
||||
self.l_buffer.cut_selection_to_clipboard()
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ class EmacsMode(basemode.BaseMode):
|
||||
def readline(self, prompt=''):
|
||||
'''Try to act like GNU readline.'''
|
||||
# handle startup_hook
|
||||
self.l_buffer.selection_mark=-1
|
||||
if self.first_prompt:
|
||||
self.first_prompt = False
|
||||
if self.startup_hook:
|
||||
@@ -76,7 +77,7 @@ class EmacsMode(basemode.BaseMode):
|
||||
|
||||
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.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')
|
||||
@@ -307,18 +308,6 @@ class EmacsMode(basemode.BaseMode):
|
||||
yanked right away. By default, this command is unbound.'''
|
||||
pass
|
||||
|
||||
def copy_region_to_clipboard(self, e): # ()
|
||||
'''Copy the text in the region to the windows clipboard.'''
|
||||
if self.enable_win32_clipboard:
|
||||
mark=min(self.l_buffer.mark,len(self.l_buffer.line_buffer))
|
||||
cursor=min(self.l_buffer.point,len(self.l_buffer.line_buffer))
|
||||
if self.l_buffer.mark==-1:
|
||||
return
|
||||
begin=min(cursor,mark)
|
||||
end=max(cursor,mark)
|
||||
toclipboard="".join(self.l_buffer.line_buffer[begin:end])
|
||||
clipboard.SetClipboardText(str(toclipboard))
|
||||
|
||||
def copy_backward_word(self, e): # ()
|
||||
'''Copy the word before point to the kill buffer. The word
|
||||
boundaries are the same as backward-word. By default, this command
|
||||
@@ -331,39 +320,6 @@ class EmacsMode(basemode.BaseMode):
|
||||
unbound.'''
|
||||
pass
|
||||
|
||||
def paste(self,e):
|
||||
'''Paste windows clipboard'''
|
||||
if self.enable_win32_clipboard:
|
||||
txt=clipboard.get_clipboard_text_and_convert(False)
|
||||
self.insert_text(txt)
|
||||
|
||||
def paste_mulitline_code(self,e):
|
||||
'''Paste windows clipboard'''
|
||||
reg=re.compile("\r?\n")
|
||||
if self.enable_win32_clipboard:
|
||||
txt=clipboard.get_clipboard_text_and_convert(False)
|
||||
t=reg.split(txt)
|
||||
t=[row for row in t if row.strip()!=""] #remove empty lines
|
||||
if t!=[""]:
|
||||
self.insert_text(t[0])
|
||||
self.add_history(self.l_buffer.copy())
|
||||
self.paste_line_buffer=t[1:]
|
||||
log("multi: %s"%self.paste_line_buffer)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def ipython_paste(self,e):
|
||||
'''Paste windows clipboard. If enable_ipython_paste_list_of_lists is
|
||||
True then try to convert tabseparated data to repr of list of lists or
|
||||
repr of array'''
|
||||
if self.enable_win32_clipboard:
|
||||
txt=clipboard.get_clipboard_text_and_convert(
|
||||
self.enable_ipython_paste_list_of_lists)
|
||||
if self.enable_ipython_paste_for_paths:
|
||||
if len(txt)<300 and ("\t" not in txt) and ("\n" not in txt):
|
||||
txt=txt.replace("\\","/").replace(" ",r"\ ")
|
||||
self.insert_text(txt)
|
||||
|
||||
def yank(self, e): # (C-y)
|
||||
'''Yank the top of the kill ring into the buffer at point. '''
|
||||
@@ -506,6 +462,7 @@ class EmacsMode(basemode.BaseMode):
|
||||
|
||||
def _bind_key(self, key, func):
|
||||
'''setup the mapping from key to call the function.'''
|
||||
# print key,func
|
||||
keyinfo = key_text_to_keyinfo(key)
|
||||
# print key,keyinfo,func.__name__
|
||||
self.key_dispatch[keyinfo] = func
|
||||
@@ -518,7 +475,6 @@ class EmacsMode(basemode.BaseMode):
|
||||
def init_editing_mode(self, e): # (C-e)
|
||||
'''When in vi command mode, this causes a switch to emacs editing
|
||||
mode.'''
|
||||
|
||||
self._bind_exit_key('Control-d')
|
||||
self._bind_exit_key('Control-z')
|
||||
|
||||
|
||||
@@ -95,7 +95,6 @@ class ViMode(basemode.BaseMode):
|
||||
|
||||
def init_editing_mode(self, e): # (M-C-j)
|
||||
'''Initialize vi editingmode'''
|
||||
print "initing vi"
|
||||
self.show_all_if_ambiguous = 'on'
|
||||
self.key_dispatch = {}
|
||||
self.__vi_insert_mode = None
|
||||
|
||||
+15
-4
@@ -53,6 +53,7 @@ class Readline(object):
|
||||
self.size = self.console.size()
|
||||
self.prompt_color = None
|
||||
self.command_color = None
|
||||
self.selection_color =0x00f0
|
||||
self.key_dispatch = {}
|
||||
self.previous_func = None
|
||||
self.first_prompt = True
|
||||
@@ -89,7 +90,6 @@ class Readline(object):
|
||||
self.paste_line_buffer=[]
|
||||
|
||||
|
||||
|
||||
#Below is for refactoring, raise errors when using old style attributes
|
||||
#that should be refactored out
|
||||
def _g(x):
|
||||
@@ -306,7 +306,17 @@ class Readline(object):
|
||||
c=self.console
|
||||
c.pos(*self.prompt_end_pos)
|
||||
ltext = self.l_buffer.quoted_text()
|
||||
n = c.write_scrolling(ltext, self.command_color)
|
||||
if self.l_buffer.enable_selection and self.l_buffer.selection_mark>0:
|
||||
start=len(self.l_buffer[:self.l_buffer.selection_mark].quoted_text())
|
||||
stop=len(self.l_buffer[:self.l_buffer.point].quoted_text())
|
||||
if start>stop:
|
||||
stop,start=start,stop
|
||||
n = c.write_scrolling(ltext[:start], self.command_color)
|
||||
n = c.write_scrolling(ltext[start:stop], self.selection_color)
|
||||
n = c.write_scrolling(ltext[stop:], self.command_color)
|
||||
else:
|
||||
n = c.write_scrolling(ltext, self.command_color)
|
||||
|
||||
self._update_prompt_pos(n)
|
||||
self._clear_after()
|
||||
self._set_cursor()
|
||||
@@ -321,8 +331,9 @@ class Readline(object):
|
||||
def setmode(name):
|
||||
self.mode=modes[name]
|
||||
def bind_key(key,name):
|
||||
if hasattr(self,name):
|
||||
modes[mode]._bind_key(key,getattr(self,name))
|
||||
if hasattr(modes[mode],name):
|
||||
#print key,name
|
||||
modes[mode]._bind_key(key,getattr(modes[mode],name))
|
||||
def un_bind_key(key):
|
||||
keyinfo = key_text_to_keyinfo(key)
|
||||
if keyinfo in modes[mode].key_dispatch:
|
||||
|
||||
Reference in New Issue
Block a user