1+ """Grep dialog for Find in Files functionality.
2+
3+ Inherits from SearchDialogBase for GUI and uses searchengine
4+ to prepare search pattern.
5+ """
16import fnmatch
27import os
38import sys
1116# Importing OutputWindow here fails due to import loop
1217# EditorWindow -> GrepDialop -> OutputWindow -> EditorWindow
1318
19+
1420def grep (text , io = None , flist = None ):
21+ """Create or find singleton GrepDialog instance.
22+
23+ Args:
24+ text: Text widget that contains the selected text for
25+ default search phrase.
26+ io: iomenu.IOBinding instance with default path to search.
27+ flist: filelist.FileList instance for OutputWindow parent.
28+ """
29+
1530 root = text ._root ()
1631 engine = searchengine .get (root )
1732 if not hasattr (engine , "_grepdialog" ):
@@ -20,19 +35,32 @@ def grep(text, io=None, flist=None):
2035 searchphrase = text .get ("sel.first" , "sel.last" )
2136 dialog .open (text , searchphrase , io )
2237
38+
2339class GrepDialog (SearchDialogBase ):
40+ "Dialog for searching multiple files."
2441
2542 title = "Find in Files Dialog"
2643 icon = "Grep"
2744 needwrapbutton = 0
2845
2946 def __init__ (self , root , engine , flist ):
47+ """Create search dialog for searching for a phrase in the file system.
48+
49+ Uses SearchDialogBase as the basis for the GUI and a
50+ searchengine instance to prepare the search.
51+
52+ Attributes:
53+ globvar: Value of Text Entry widget for path to search.
54+ recvar: Boolean value of Checkbutton widget
55+ for traversing through subdirectories.
56+ """
3057 SearchDialogBase .__init__ (self , root , engine )
3158 self .flist = flist
3259 self .globvar = StringVar (root )
3360 self .recvar = BooleanVar (root )
3461
3562 def open (self , text , searchphrase , io = None ):
63+ "Make dialog visible on top of others and ready to use."
3664 SearchDialogBase .open (self , text , searchphrase )
3765 if io :
3866 path = io .filename or ""
@@ -45,20 +73,30 @@ def open(self, text, searchphrase, io=None):
4573 self .globvar .set (os .path .join (dir , "*" + tail ))
4674
4775 def create_entries (self ):
76+ "Create base entry widgets and add widget for search path."
4877 SearchDialogBase .create_entries (self )
4978 self .globent = self .make_entry ("In files:" , self .globvar )[0 ]
5079
5180 def create_other_buttons (self ):
81+ "Add check button to recurse down subdirectories."
5282 btn = Checkbutton (
5383 self .make_frame ()[0 ], variable = self .recvar ,
5484 text = "Recurse down subdirectories" )
5585 btn .pack (side = "top" , fill = "both" )
5686
5787 def create_command_buttons (self ):
88+ "Create base command buttons and add button for search."
5889 SearchDialogBase .create_command_buttons (self )
5990 self .make_button ("Search Files" , self .default_command , 1 )
6091
6192 def default_command (self , event = None ):
93+ """Grep for search pattern in file path. The default command is bound
94+ to <Return>.
95+
96+ If entry values are populated, set OutputWindow as stdout
97+ and perform search. The search dialog is closed automatically
98+ when the search begins.
99+ """
62100 prog = self .engine .getprog ()
63101 if not prog :
64102 return
@@ -75,12 +113,19 @@ def default_command(self, event=None):
75113 sys .stdout = save
76114
77115 def grep_it (self , prog , path ):
116+ """Search for prog within the lines of the files in path.
117+
118+ For the each file in the path directory, open the file and
119+ search each line for the matching pattern. If the pattern is
120+ found, write the file and line information to stdout (which
121+ is an OutputWindow).
122+ """
78123 dir , base = os .path .split (path )
79124 list = self .findfiles (dir , base , self .recvar .get ())
80125 list .sort ()
81126 self .close ()
82127 pat = self .engine .getpat ()
83- print ("Searching %r in %s ..." % ( pat , path ) )
128+ print (f "Searching { pat !r } in { path } ..." )
84129 hits = 0
85130 try :
86131 for fn in list :
@@ -90,20 +135,22 @@ def grep_it(self, prog, path):
90135 if line [- 1 :] == '\n ' :
91136 line = line [:- 1 ]
92137 if prog .search (line ):
93- sys .stdout .write ("%s: %s: %s\n " %
94- (fn , lineno , line ))
138+ sys .stdout .write (f"{ fn } : { lineno } : { line } \n " )
95139 hits += 1
96140 except OSError as msg :
97141 print (msg )
98- print (("Hits found: %s\n "
99- "(Hint: right-click to open locations.)"
100- % hits ) if hits else "No hits." )
142+ print (f"Hits found: { hits } \n (Hint: right-click to open locations.)"
143+ if hits else "No hits." )
101144 except AttributeError :
102145 # Tk window has been closed, OutputWindow.text = None,
103146 # so in OW.write, OW.text.insert fails.
104147 pass
105148
106149 def findfiles (self , dir , base , rec ):
150+ """Return list of files in the dir that match the base pattern.
151+
152+ If rec is True, recursively iterate through subdirectories.
153+ """
107154 try :
108155 names = os .listdir (dir or os .curdir )
109156 except OSError as msg :
@@ -123,11 +170,6 @@ def findfiles(self, dir, base, rec):
123170 list .extend (self .findfiles (subdir , base , rec ))
124171 return list
125172
126- def close (self , event = None ):
127- if self .top :
128- self .top .grab_release ()
129- self .top .withdraw ()
130-
131173
132174def _grep_dialog (parent ): # htest #
133175 from tkinter import Toplevel , Text , SEL , END
@@ -136,7 +178,7 @@ def _grep_dialog(parent): # htest #
136178 top = Toplevel (parent )
137179 top .title ("Test GrepDialog" )
138180 x , y = map (int , parent .geometry ().split ('+' )[1 :])
139- top .geometry ("+%d+%d" % ( x , y + 175 ) )
181+ top .geometry (f"+ { x } + { y + 175 } " )
140182
141183 flist = PyShellFileList (top )
142184 text = Text (top , height = 5 )
0 commit comments