44and the cursor location
55based on http://www.bigsmoke.us/readline/shortcuts"""
66
7- import re
7+ from bpython . lazyre import LazyReCompile
88import inspect
99
1010INDENT = 4
@@ -73,6 +73,7 @@ def __delitem__(self, key):
7373 elif key in self .cut_buffer_edits : del self .cut_buffer_edits [key ]
7474 else : raise KeyError ("key %r not mapped" % (key ,))
7575
76+
7677class UnconfiguredEdits (AbstractEdits ):
7778 """Maps key to edit functions, and bins them by what parameters they take.
7879
@@ -114,6 +115,7 @@ def add_to_config(func):
114115 return func
115116 return add_to_config
116117
118+
117119class ConfiguredEdits (AbstractEdits ):
118120 def __init__ (self , simple_edits , cut_buffer_edits , awaiting_config , config , key_dispatch ):
119121 self .simple_edits = dict (simple_edits )
@@ -128,6 +130,7 @@ def add_config_attr(self, config_attr, func):
128130 def add (self , key , func ):
129131 raise NotImplementedError ("Config already set on this mapping" )
130132
133+
131134edit_keys = UnconfiguredEdits ()
132135
133136# Because the edits.on decorator runs the functions, functions which depend
@@ -161,19 +164,21 @@ def beginning_of_line(cursor_offset, line):
161164def end_of_line (cursor_offset , line ):
162165 return len (line ), line
163166
167+
168+ forward_word_re = LazyReCompile (r"\S\s" )
169+
170+
164171@edit_keys .on ('<Esc+f>' )
165172@edit_keys .on ('<Ctrl-RIGHT>' )
166173@edit_keys .on ('<Esc+RIGHT>' )
167174def forward_word (cursor_offset , line ):
168- patt = r"\S\s"
169- match = re .search (patt , line [cursor_offset :]+ ' ' )
175+ match = forward_word_re .search (line [cursor_offset :]+ ' ' )
170176 delta = match .end () - 1 if match else 0
171177 return (cursor_offset + delta , line )
172178
173179def last_word_pos (string ):
174180 """returns the start index of the last word of given string"""
175- patt = r'\S\s'
176- match = re .search (patt , string [::- 1 ])
181+ match = forward_word_re .search (string [::- 1 ])
177182 index = match and len (string ) - match .end () + 1
178183 return index or 0
179184
@@ -204,20 +209,29 @@ def backspace(cursor_offset, line):
204209def delete_from_cursor_back (cursor_offset , line ):
205210 return 0 , line [cursor_offset :]
206211
212+
213+ delete_rest_of_word_re = LazyReCompile (r'\w\b' )
214+
215+
207216@edit_keys .on ('<Esc+d>' ) # option-d
208217@kills_ahead
209218def delete_rest_of_word (cursor_offset , line ):
210- m = re .search (r'\w\b' , line [cursor_offset :])
219+ m = delete_rest_of_word_re .search (line [cursor_offset :])
211220 if not m :
212221 return cursor_offset , line , ''
213222 return (cursor_offset , line [:cursor_offset ] + line [m .start ()+ cursor_offset + 1 :],
214223 line [cursor_offset :m .start ()+ cursor_offset + 1 ])
215224
225+
226+ delete_word_to_cursor_re = LazyReCompile (r'\s\S' )
227+
228+
216229@edit_keys .on (config = 'clear_word_key' )
217230@kills_behind
218231def delete_word_to_cursor (cursor_offset , line ):
219- matches = list (re .finditer (r'\s\S' , line [:cursor_offset ]))
220- start = matches [- 1 ].start ()+ 1 if matches else 0
232+ start = 0
233+ for match in delete_word_to_cursor_re .finditer (line [:cursor_offset ]):
234+ start = match .start () + 1
221235 return start , line [:start ] + line [cursor_offset :], line [start :cursor_offset ]
222236
223237@edit_keys .on ('<Esc+y>' )
@@ -259,16 +273,22 @@ def delete_from_cursor_forward(cursor_offset, line):
259273def titlecase_next_word (cursor_offset , line ):
260274 return cursor_offset , line #TODO Not implemented
261275
276+
277+ delete_word_from_cursor_back_re = LazyReCompile (r'\b\w' )
278+
279+
262280@edit_keys .on ('<Esc+BACKSPACE>' )
263281@edit_keys .on ('<Meta-BACKSPACE>' )
264282@kills_behind
265283def delete_word_from_cursor_back (cursor_offset , line ):
266284 """Whatever my option-delete does in bash on my mac"""
267285 if not line :
268286 return cursor_offset , line , ''
269- starts = [m .start () for m in list (re .finditer (r'\b\w' , line )) if m .start () < cursor_offset ]
270- if starts :
271- return starts [- 1 ], line [:starts [- 1 ]] + line [cursor_offset :], line [starts [- 1 ]:cursor_offset ]
272- return cursor_offset , line , ''
273-
274-
287+ start = None
288+ for match in delete_word_from_cursor_back_re .finditer (line ):
289+ if match .start () < cursor_offset :
290+ start = match .start ()
291+ if start is not None :
292+ return start , line [:start ] + line [cursor_offset :], line [start :cursor_offset ]
293+ else :
294+ return cursor_offset , line , ''
0 commit comments