diff options
author | Cheryl Sabella <cheryl.sabella@gmail.com> | 2019-03-16 23:29:33 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-16 23:29:33 (GMT) |
commit | 0bb5e75cf8bc9b197ffb91cba6f30543ed502708 (patch) | |
tree | 8c7da5683bbc8651ba16841ab2468f4d47ddca99 /Lib | |
parent | 7c994549dcffd0d9d3bb37475e6374f356e7240e (diff) | |
download | cpython-0bb5e75cf8bc9b197ffb91cba6f30543ed502708.zip cpython-0bb5e75cf8bc9b197ffb91cba6f30543ed502708.tar.gz cpython-0bb5e75cf8bc9b197ffb91cba6f30543ed502708.tar.bz2 |
bpo-23216: IDLE: Add docstrings to search modules (GH-12141)
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/idlelib/grep.py | 46 | ||||
-rw-r--r-- | Lib/idlelib/replace.py | 111 | ||||
-rw-r--r-- | Lib/idlelib/search.py | 70 |
3 files changed, 188 insertions, 39 deletions
diff --git a/Lib/idlelib/grep.py b/Lib/idlelib/grep.py index 873233e..6068d7e 100644 --- a/Lib/idlelib/grep.py +++ b/Lib/idlelib/grep.py @@ -14,11 +14,16 @@ from idlelib.searchbase import SearchDialogBase from idlelib import searchengine # Importing OutputWindow here fails due to import loop -# EditorWindow -> GrepDialop -> OutputWindow -> EditorWindow +# EditorWindow -> GrepDialog -> OutputWindow -> EditorWindow def grep(text, io=None, flist=None): - """Create or find singleton GrepDialog instance. + """Open the Find in Files dialog. + + Module-level function to access the singleton GrepDialog + instance and open the dialog. If text is selected, it is + used as the search phrase; otherwise, the previous entry + is used. Args: text: Text widget that contains the selected text for @@ -26,7 +31,6 @@ def grep(text, io=None, flist=None): io: iomenu.IOBinding instance with default path to search. flist: filelist.FileList instance for OutputWindow parent. """ - root = text._root() engine = searchengine.get(root) if not hasattr(engine, "_grepdialog"): @@ -50,17 +54,29 @@ class GrepDialog(SearchDialogBase): searchengine instance to prepare the search. Attributes: - globvar: Value of Text Entry widget for path to search. - recvar: Boolean value of Checkbutton widget - for traversing through subdirectories. + flist: filelist.Filelist instance for OutputWindow parent. + globvar: String value of Entry widget for path to search. + globent: Entry widget for globvar. Created in + create_entries(). + recvar: Boolean value of Checkbutton widget for + traversing through subdirectories. """ - SearchDialogBase.__init__(self, root, engine) + super().__init__(root, engine) self.flist = flist self.globvar = StringVar(root) self.recvar = BooleanVar(root) def open(self, text, searchphrase, io=None): - "Make dialog visible on top of others and ready to use." + """Make dialog visible on top of others and ready to use. + + Extend the SearchDialogBase open() to set the initial value + for globvar. + + Args: + text: Multicall object containing the text information. + searchphrase: String phrase to search. + io: iomenu.IOBinding instance containing file path. + """ SearchDialogBase.open(self, text, searchphrase) if io: path = io.filename or "" @@ -85,9 +101,9 @@ class GrepDialog(SearchDialogBase): btn.pack(side="top", fill="both") def create_command_buttons(self): - "Create base command buttons and add button for search." + "Create base command buttons and add button for Search Files." SearchDialogBase.create_command_buttons(self) - self.make_button("Search Files", self.default_command, 1) + self.make_button("Search Files", self.default_command, isdef=True) def default_command(self, event=None): """Grep for search pattern in file path. The default command is bound @@ -119,6 +135,10 @@ class GrepDialog(SearchDialogBase): search each line for the matching pattern. If the pattern is found, write the file and line information to stdout (which is an OutputWindow). + + Args: + prog: The compiled, cooked search pattern. + path: String containing the search path. """ dir, base = os.path.split(path) list = self.findfiles(dir, base, self.recvar.get()) @@ -149,7 +169,13 @@ class GrepDialog(SearchDialogBase): def findfiles(self, dir, base, rec): """Return list of files in the dir that match the base pattern. + Use the current directory if dir has no value. If rec is True, recursively iterate through subdirectories. + + Args: + dir: Directory path to search. + base: File search pattern. + rec: Boolean for recursive search through subdirectories. """ try: names = os.listdir(dir or os.curdir) diff --git a/Lib/idlelib/replace.py b/Lib/idlelib/replace.py index 4a834eb..6be034a 100644 --- a/Lib/idlelib/replace.py +++ b/Lib/idlelib/replace.py @@ -1,7 +1,7 @@ """Replace dialog for IDLE. Inherits SearchDialogBase for GUI. -Uses idlelib.SearchEngine for search capability. +Uses idlelib.searchengine.SearchEngine for search capability. Defines various replace related functions like replace, replace all, -replace+find. +and replace+find. """ import re @@ -10,9 +10,16 @@ from tkinter import StringVar, TclError from idlelib.searchbase import SearchDialogBase from idlelib import searchengine + def replace(text): - """Returns a singleton ReplaceDialog instance.The single dialog - saves user entries and preferences across instances.""" + """Create or reuse a singleton ReplaceDialog instance. + + The singleton dialog saves user entries and preferences + across instances. + + Args: + text: Text widget containing the text to be searched. + """ root = text._root() engine = searchengine.get(root) if not hasattr(engine, "_replacedialog"): @@ -22,16 +29,36 @@ def replace(text): class ReplaceDialog(SearchDialogBase): + "Dialog for finding and replacing a pattern in text." title = "Replace Dialog" icon = "Replace" def __init__(self, root, engine): - SearchDialogBase.__init__(self, root, engine) + """Create search dialog for finding and replacing text. + + Uses SearchDialogBase as the basis for the GUI and a + searchengine instance to prepare the search. + + Attributes: + replvar: StringVar containing 'Replace with:' value. + replent: Entry widget for replvar. Created in + create_entries(). + ok: Boolean used in searchengine.search_text to indicate + whether the search includes the selection. + """ + super().__init__(root, engine) self.replvar = StringVar(root) def open(self, text): - """Display the replace dialog""" + """Make dialog visible on top of others and ready to use. + + Also, highlight the currently selected text and set the + search to include the current selection (self.ok). + + Args: + text: Text widget being searched. + """ SearchDialogBase.open(self, text) try: first = text.index("sel.first") @@ -44,37 +71,50 @@ class ReplaceDialog(SearchDialogBase): first = first or text.index("insert") last = last or first self.show_hit(first, last) - self.ok = 1 + self.ok = True def create_entries(self): - """Create label and text entry widgets""" + "Create base and additional label and text entry widgets." SearchDialogBase.create_entries(self) self.replent = self.make_entry("Replace with:", self.replvar)[0] def create_command_buttons(self): + """Create base and additional command buttons. + + The additional buttons are for Find, Replace, + Replace+Find, and Replace All. + """ SearchDialogBase.create_command_buttons(self) self.make_button("Find", self.find_it) self.make_button("Replace", self.replace_it) - self.make_button("Replace+Find", self.default_command, 1) + self.make_button("Replace+Find", self.default_command, isdef=True) self.make_button("Replace All", self.replace_all) def find_it(self, event=None): - self.do_find(0) + "Handle the Find button." + self.do_find(False) def replace_it(self, event=None): + """Handle the Replace button. + + If the find is successful, then perform replace. + """ if self.do_find(self.ok): self.do_replace() def default_command(self, event=None): - "Replace and find next." + """Handle the Replace+Find button as the default command. + + First performs a replace and then, if the replace was + successful, a find next. + """ if self.do_find(self.ok): if self.do_replace(): # Only find next match if replace succeeded. # A bad re can cause it to fail. - self.do_find(0) + self.do_find(False) def _replace_expand(self, m, repl): - """ Helper function for expanding a regular expression - in the replace field, if needed. """ + "Expand replacement text if regular expression." if self.engine.isre(): try: new = m.expand(repl) @@ -87,7 +127,15 @@ class ReplaceDialog(SearchDialogBase): return new def replace_all(self, event=None): - """Replace all instances of patvar with replvar in text""" + """Handle the Replace All button. + + Search text for occurrences of the Find value and replace + each of them. The 'wrap around' value controls the start + point for searching. If wrap isn't set, then the searching + starts at the first occurrence after the current selection; + if wrap is set, the replacement starts at the first line. + The replacement is always done top-to-bottom in the text. + """ prog = self.engine.getprog() if not prog: return @@ -104,12 +152,13 @@ class ReplaceDialog(SearchDialogBase): if self.engine.iswrap(): line = 1 col = 0 - ok = 1 + ok = True first = last = None # XXX ought to replace circular instead of top-to-bottom when wrapping text.undo_block_start() - while 1: - res = self.engine.search_forward(text, prog, line, col, 0, ok) + while True: + res = self.engine.search_forward(text, prog, line, col, + wrap=False, ok=ok) if not res: break line, m = res @@ -130,13 +179,17 @@ class ReplaceDialog(SearchDialogBase): if new: text.insert(first, new) col = i + len(new) - ok = 0 + ok = False text.undo_block_stop() if first and last: self.show_hit(first, last) self.close() - def do_find(self, ok=0): + def do_find(self, ok=False): + """Search for and highlight next occurrence of pattern in text. + + No text replacement is done with this option. + """ if not self.engine.getprog(): return False text = self.text @@ -149,10 +202,11 @@ class ReplaceDialog(SearchDialogBase): first = "%d.%d" % (line, i) last = "%d.%d" % (line, j) self.show_hit(first, last) - self.ok = 1 + self.ok = True return True def do_replace(self): + "Replace search pattern in text with replacement value." prog = self.engine.getprog() if not prog: return False @@ -180,12 +234,20 @@ class ReplaceDialog(SearchDialogBase): text.insert(first, new) text.undo_block_stop() self.show_hit(first, text.index("insert")) - self.ok = 0 + self.ok = False return True def show_hit(self, first, last): - """Highlight text from 'first' to 'last'. - 'first', 'last' - Text indices""" + """Highlight text between first and last indices. + + Text is highlighted via the 'hit' tag and the marked + section is brought into view. + + The colors from the 'hit' tag aren't currently shown + when the text is displayed. This is due to the 'sel' + tag being added first, so the colors in the 'sel' + config are seen instead of the colors for 'hit'. + """ text = self.text text.mark_set("insert", first) text.tag_remove("sel", "1.0", "end") @@ -199,6 +261,7 @@ class ReplaceDialog(SearchDialogBase): text.update_idletasks() def close(self, event=None): + "Close the dialog and remove hit tags." SearchDialogBase.close(self, event) self.text.tag_remove("hit", "1.0", "end") diff --git a/Lib/idlelib/search.py b/Lib/idlelib/search.py index 6e5a0c7..5bbe9d6 100644 --- a/Lib/idlelib/search.py +++ b/Lib/idlelib/search.py @@ -1,10 +1,23 @@ +"""Search dialog for Find, Find Again, and Find Selection + functionality. + + Inherits from SearchDialogBase for GUI and uses searchengine + to prepare search pattern. +""" from tkinter import TclError from idlelib import searchengine from idlelib.searchbase import SearchDialogBase def _setup(text): - "Create or find the singleton SearchDialog instance." + """Return the new or existing singleton SearchDialog instance. + + The singleton dialog saves user entries and preferences + across instances. + + Args: + text: Text widget containing the text to be searched. + """ root = text._root() engine = searchengine.get(root) if not hasattr(engine, "_searchdialog"): @@ -12,31 +25,71 @@ def _setup(text): return engine._searchdialog def find(text): - "Handle the editor edit menu item and corresponding event." + """Open the search dialog. + + Module-level function to access the singleton SearchDialog + instance and open the dialog. If text is selected, it is + used as the search phrase; otherwise, the previous entry + is used. No search is done with this command. + """ pat = text.get("sel.first", "sel.last") return _setup(text).open(text, pat) # Open is inherited from SDBase. def find_again(text): - "Handle the editor edit menu item and corresponding event." + """Repeat the search for the last pattern and preferences. + + Module-level function to access the singleton SearchDialog + instance to search again using the user entries and preferences + from the last dialog. If there was no prior search, open the + search dialog; otherwise, perform the search without showing the + dialog. + """ return _setup(text).find_again(text) def find_selection(text): - "Handle the editor edit menu item and corresponding event." + """Search for the selected pattern in the text. + + Module-level function to access the singleton SearchDialog + instance to search using the selected text. With a text + selection, perform the search without displaying the dialog. + Without a selection, use the prior entry as the search phrase + and don't display the dialog. If there has been no prior + search, open the search dialog. + """ return _setup(text).find_selection(text) class SearchDialog(SearchDialogBase): + "Dialog for finding a pattern in text." def create_widgets(self): + "Create the base search dialog and add a button for Find Next." SearchDialogBase.create_widgets(self) - self.make_button("Find Next", self.default_command, 1) + # TODO - why is this here and not in a create_command_buttons? + self.make_button("Find Next", self.default_command, isdef=True) def default_command(self, event=None): + "Handle the Find Next button as the default command." if not self.engine.getprog(): return self.find_again(self.text) def find_again(self, text): + """Repeat the last search. + + If no search was previously run, open a new search dialog. In + this case, no search is done. + + If a seach was previously run, the search dialog won't be + shown and the options from the previous search (including the + search pattern) will be used to find the next occurrence + of the pattern. Next is relative based on direction. + + Position the window to display the located occurrence in the + text. + + Return True if the search was successful and False otherwise. + """ if not self.engine.getpat(): self.open(text) return False @@ -66,6 +119,13 @@ class SearchDialog(SearchDialogBase): return False def find_selection(self, text): + """Search for selected text with previous dialog preferences. + + Instead of using the same pattern for searching (as Find + Again does), this first resets the pattern to the currently + selected text. If the selected text isn't changed, then use + the prior search phrase. + """ pat = text.get("sel.first", "sel.last") if pat: self.engine.setcookedpat(pat) |