8000 [3.7] bpo-23216: IDLE: Add docstrings to search modules (GH-12141) by miss-islington · Pull Request #12376 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

[3.7] bpo-23216: IDLE: Add docstrings to search modules (GH-12141) #12376

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 36 additions & 10 deletions Lib/idlelib/grep.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,23 @@
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
default search phrase.
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"):
Expand All @@ -50,17 +54,29 @@ def __init__(self, root, engine, flist):
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 ""
Expand All @@ -85,9 +101,9 @@ def create_other_buttons(self):
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
Expand Down Expand Up @@ -119,6 +135,10 @@ def grep_it(self, prog, path):
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())
Expand Down Expand Up @@ -149,7 +169,13 @@ def grep_it(self, prog, path):
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)
Expand Down
111 changes: 87 additions & 24 deletions Lib/idlelib/replace.py
57AE
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -10,9 +10,16 @@
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"):
Expand All @@ -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")
Expand All @@ -44,37 +71,50 @@ def open(self, text):
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)
Expand All @@ -87,7 +127,15 @@ def _replace_expand(self, m, repl):
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
Expand All @@ -104,12 +152,13 @@ def replace_all(self, event=None):
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
Expand All @@ -130,13 +179,17 @@ def replace_all(self, event=None):
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):
""&q B41A uot;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
Expand All @@ -149,10 +202,11 @@ def do_find(self, ok=0):
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
Expand Down Expand Up @@ -180,12 +234,20 @@ def do_replace(self):
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")
Expand All @@ -199,6 +261,7 @@ def show_hit(self, first, last):
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")

Expand Down
Loading
0