11"""Replace dialog for IDLE. Inherits SearchDialogBase for GUI.
2- Uses idlelib.SearchEngine for search capability.
2+ Uses idlelib.searchengine. SearchEngine for search capability.
33Defines various replace related functions like replace, replace all,
4- replace+find.
4+ and replace+find.
55"""
66import re
77
1010from idlelib .searchbase import SearchDialogBase
1111from idlelib import searchengine
1212
13+
1314def replace (text ):
14- """Returns a singleton ReplaceDialog instance.The single dialog
15- saves user entries and preferences across instances."""
15+ """Create or reuse a singleton ReplaceDialog instance.
16+
17+ The singleton dialog saves user entries and preferences
18+ across instances.
19+
20+ Args:
21+ text: Text widget containing the text to be searched.
22+ """
1623 root = text ._root ()
1724 engine = searchengine .get (root )
1825 if not hasattr (engine , "_replacedialog" ):
@@ -22,16 +29,36 @@ def replace(text):
2229
2330
2431class ReplaceDialog (SearchDialogBase ):
32+ "Dialog for finding and replacing a pattern in text."
2533
2634 title = "Replace Dialog"
2735 icon = "Replace"
2836
2937 def __init__ (self , root , engine ):
30- SearchDialogBase .__init__ (self , root , engine )
38+ """Create search dialog for finding and replacing text.
39+
40+ Uses SearchDialogBase as the basis for the GUI and a
41+ searchengine instance to prepare the search.
42+
43+ Attributes:
44+ replvar: StringVar containing 'Replace with:' value.
45+ replent: Entry widget for replvar. Created in
46+ create_entries().
47+ ok: Boolean used in searchengine.search_text to indicate
48+ whether the search includes the selection.
49+ """
50+ super ().__init__ (root , engine )
3151 self .replvar = StringVar (root )
3252
3353 def open (self , text ):
34- """Display the replace dialog"""
54+ """Make dialog visible on top of others and ready to use.
55+
56+ Also, highlight the currently selected text and set the
57+ search to include the current selection (self.ok).
58+
59+ Args:
60+ text: Text widget being searched.
61+ """
3562 SearchDialogBase .open (self , text )
3663 try :
3764 first = text .index ("sel.first" )
@@ -44,37 +71,50 @@ def open(self, text):
4471 first = first or text .index ("insert" )
4572 last = last or first
4673 self .show_hit (first , last )
47- self .ok = 1
74+ self .ok = True
4875
4976 def create_entries (self ):
50- """ Create label and text entry widgets"" "
77+ "Create base and additional label and text entry widgets. "
5178 SearchDialogBase .create_entries (self )
5279 self .replent = self .make_entry ("Replace with:" , self .replvar )[0 ]
5380
5481 def create_command_buttons (self ):
82+ """Create base and additional command buttons.
83+
84+ The additional buttons are for Find, Replace,
85+ Replace+Find, and Replace All.
86+ """
5587 SearchDialogBase .create_command_buttons (self )
5688 self .make_button ("Find" , self .find_it )
5789 self .make_button ("Replace" , self .replace_it )
58- self .make_button ("Replace+Find" , self .default_command , 1 )
90+ self .make_button ("Replace+Find" , self .default_command , isdef = True )
5991 self .make_button ("Replace All" , self .replace_all )
6092
6193 def find_it (self , event = None ):
62- self .do_find (0 )
94+ "Handle the Find button."
95+ self .do_find (False )
6396
6497 def replace_it (self , event = None ):
98+ """Handle the Replace button.
99+
100+ If the find is successful, then perform replace.
101+ """
65102 if self .do_find (self .ok ):
66103 self .do_replace ()
67104
68105 def default_command (self , event = None ):
69- "Replace and find next."
106+ """Handle the Replace+Find button as the default command.
107+
108+ First performs a replace and then, if the replace was
109+ successful, a find next.
110+ """
70111 if self .do_find (self .ok ):
71112 if self .do_replace (): # Only find next match if replace succeeded.
72113 # A bad re can cause it to fail.
73- self .do_find (0 )
114+ self .do_find (False )
74115
75116 def _replace_expand (self , m , repl ):
76- """ Helper function for expanding a regular expression
77- in the replace field, if needed. """
117+ "Expand replacement text if regular expression."
78118 if self .engine .isre ():
79119 try :
80120 new = m .expand (repl )
@@ -87,7 +127,15 @@ def _replace_expand(self, m, repl):
87127 return new
88128
89129 def replace_all (self , event = None ):
90- """Replace all instances of patvar with replvar in text"""
130+ """Handle the Replace All button.
131+
132+ Search text for occurrences of the Find value and replace
133+ each of them. The 'wrap around' value controls the start
134+ point for searching. If wrap isn't set, then the searching
135+ starts at the first occurrence after the current selection;
136+ if wrap is set, the replacement starts at the first line.
137+ The replacement is always done top-to-bottom in the text.
138+ """
91139 prog = self .engine .getprog ()
92140 if not prog :
93141 return
@@ -104,12 +152,13 @@ def replace_all(self, event=None):
104152 if self .engine .iswrap ():
105153 line = 1
106154 col = 0
107- ok = 1
155+ ok = True
108156 first = last = None
109157 # XXX ought to replace circular instead of top-to-bottom when wrapping
110158 text .undo_block_start ()
111- while 1 :
112- res = self .engine .search_forward (text , prog , line , col , 0 , ok )
159+ while True :
160+ res = self .engine .search_forward (text , prog , line , col ,
161+ wrap = False , ok = ok )
113162 if not res :
114163 break
115164 line , m = res
@@ -130,13 +179,17 @@ def replace_all(self, event=None):
130179 if new :
131180 text .insert (first , new )
132181 col = i + len (new )
133- ok = 0
182+ ok = False
134183 text .undo_block_stop ()
135184 if first and last :
136185 self .show_hit (first , last )
137186 self .close ()
138187
139- def do_find (self , ok = 0 ):
188+ def do_find (self , ok = False ):
189+ """Search for and highlight next occurrence of pattern in text.
190+
191+ No text replacement is done with this option.
192+ """
140193 if not self .engine .getprog ():
141194 return False
142195 text = self .text
@@ -149,10 +202,11 @@ def do_find(self, ok=0):
149202 first = "%d.%d" % (line , i )
150203 last = "%d.%d" % (line , j )
151204 self .show_hit (first , last )
152- self .ok = 1
205+ self .ok = True
153206 return True
154207
155208 def do_replace (self ):
209+ "Replace search pattern in text with replacement value."
156210 prog = self .engine .getprog ()
157211 if not prog :
158212 return False
@@ -180,12 +234,20 @@ def do_replace(self):
180234 text .insert (first , new )
181235 text .undo_block_stop ()
182236 self .show_hit (first , text .index ("insert" ))
183- self .ok = 0
237+ self .ok = False
184238 return True
185239
186240 def show_hit (self , first , last ):
187- """Highlight text from 'first' to 'last'.
188- 'first', 'last' - Text indices"""
241+ """Highlight text between first and last indices.
242+
243+ Text is highlighted via the 'hit' tag and the marked
244+ section is brought into view.
245+
246+ The colors from the 'hit' tag aren't currently shown
247+ when the text is displayed. This is due to the 'sel'
248+ tag being added first, so the colors in the 'sel'
249+ config are seen instead of the colors for 'hit'.
250+ """
189251 text = self .text
190252 text .mark_set ("insert" , first )
191253 text .tag_remove ("sel" , "1.0" , "end" )
@@ -199,6 +261,7 @@ def show_hit(self, first, last):
199261 text .update_idletasks ()
200262
201263 def close (self , event = None ):
264+ "Close the dialog and remove hit tags."
202265 SearchDialogBase .close (self , event )
203266 self .text .tag_remove ("hit" , "1.0" , "end" )
204267
0 commit comments