bpo-23216: IDLE: Add docstrings to search modules (GH-12141) · python/cpython@0bb5e75 (original) (raw)

1

1

`"""Replace dialog for IDLE. Inherits SearchDialogBase for GUI.

`

2

``

`-

Uses idlelib.SearchEngine for search capability.

`

``

2

`+

Uses idlelib.searchengine.SearchEngine for search capability.

`

3

3

`Defines various replace related functions like replace, replace all,

`

4

``

`-

replace+find.

`

``

4

`+

and replace+find.

`

5

5

`"""

`

6

6

`import re

`

7

7

``

`@@ -10,9 +10,16 @@

`

10

10

`from idlelib.searchbase import SearchDialogBase

`

11

11

`from idlelib import searchengine

`

12

12

``

``

13

+

13

14

`def 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

`+

"""

`

16

23

`root = text._root()

`

17

24

`engine = searchengine.get(root)

`

18

25

`if not hasattr(engine, "_replacedialog"):

`

`@@ -22,16 +29,36 @@ def replace(text):

`

22

29

``

23

30

``

24

31

`class ReplaceDialog(SearchDialogBase):

`

``

32

`+

"Dialog for finding and replacing a pattern in text."

`

25

33

``

26

34

`title = "Replace Dialog"

`

27

35

`icon = "Replace"

`

28

36

``

29

37

`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)

`

31

51

`self.replvar = StringVar(root)

`

32

52

``

33

53

`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

`+

"""

`

35

62

`SearchDialogBase.open(self, text)

`

36

63

`try:

`

37

64

`first = text.index("sel.first")

`

`@@ -44,37 +71,50 @@ def open(self, text):

`

44

71

`first = first or text.index("insert")

`

45

72

`last = last or first

`

46

73

`self.show_hit(first, last)

`

47

``

`-

self.ok = 1

`

``

74

`+

self.ok = True

`

48

75

``

49

76

`def create_entries(self):

`

50

``

`-

"""Create label and text entry widgets"""

`

``

77

`+

"Create base and additional label and text entry widgets."

`

51

78

`SearchDialogBase.create_entries(self)

`

52

79

`self.replent = self.make_entry("Replace with:", self.replvar)[0]

`

53

80

``

54

81

`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

`+

"""

`

55

87

`SearchDialogBase.create_command_buttons(self)

`

56

88

`self.make_button("Find", self.find_it)

`

57

89

`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)

`

59

91

`self.make_button("Replace All", self.replace_all)

`

60

92

``

61

93

`def find_it(self, event=None):

`

62

``

`-

self.do_find(0)

`

``

94

`+

"Handle the Find button."

`

``

95

`+

self.do_find(False)

`

63

96

``

64

97

`def replace_it(self, event=None):

`

``

98

`+

"""Handle the Replace button.

`

``

99

+

``

100

`+

If the find is successful, then perform replace.

`

``

101

`+

"""

`

65

102

`if self.do_find(self.ok):

`

66

103

`self.do_replace()

`

67

104

``

68

105

`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

`+

"""

`

70

111

`if self.do_find(self.ok):

`

71

112

`if self.do_replace(): # Only find next match if replace succeeded.

`

72

113

`# A bad re can cause it to fail.

`

73

``

`-

self.do_find(0)

`

``

114

`+

self.do_find(False)

`

74

115

``

75

116

`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."

`

78

118

`if self.engine.isre():

`

79

119

`try:

`

80

120

`new = m.expand(repl)

`

`@@ -87,7 +127,15 @@ def _replace_expand(self, m, repl):

`

87

127

`return new

`

88

128

``

89

129

`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

`+

"""

`

91

139

`prog = self.engine.getprog()

`

92

140

`if not prog:

`

93

141

`return

`

`@@ -104,12 +152,13 @@ def replace_all(self, event=None):

`

104

152

`if self.engine.iswrap():

`

105

153

`line = 1

`

106

154

`col = 0

`

107

``

`-

ok = 1

`

``

155

`+

ok = True

`

108

156

`first = last = None

`

109

157

`# XXX ought to replace circular instead of top-to-bottom when wrapping

`

110

158

`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)

`

113

162

`if not res:

`

114

163

`break

`

115

164

`line, m = res

`

`@@ -130,13 +179,17 @@ def replace_all(self, event=None):

`

130

179

`if new:

`

131

180

`text.insert(first, new)

`

132

181

`col = i + len(new)

`

133

``

`-

ok = 0

`

``

182

`+

ok = False

`

134

183

`text.undo_block_stop()

`

135

184

`if first and last:

`

136

185

`self.show_hit(first, last)

`

137

186

`self.close()

`

138

187

``

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

`+

"""

`

140

193

`if not self.engine.getprog():

`

141

194

`return False

`

142

195

`text = self.text

`

`@@ -149,10 +202,11 @@ def do_find(self, ok=0):

`

149

202

`first = "%d.%d" % (line, i)

`

150

203

`last = "%d.%d" % (line, j)

`

151

204

`self.show_hit(first, last)

`

152

``

`-

self.ok = 1

`

``

205

`+

self.ok = True

`

153

206

`return True

`

154

207

``

155

208

`def do_replace(self):

`

``

209

`+

"Replace search pattern in text with replacement value."

`

156

210

`prog = self.engine.getprog()

`

157

211

`if not prog:

`

158

212

`return False

`

`@@ -180,12 +234,20 @@ def do_replace(self):

`

180

234

`text.insert(first, new)

`

181

235

`text.undo_block_stop()

`

182

236

`self.show_hit(first, text.index("insert"))

`

183

``

`-

self.ok = 0

`

``

237

`+

self.ok = False

`

184

238

`return True

`

185

239

``

186

240

`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

`+

"""

`

189

251

`text = self.text

`

190

252

`text.mark_set("insert", first)

`

191

253

`text.tag_remove("sel", "1.0", "end")

`

`@@ -199,6 +261,7 @@ def show_hit(self, first, last):

`

199

261

`text.update_idletasks()

`

200

262

``

201

263

`def close(self, event=None):

`

``

264

`+

"Close the dialog and remove hit tags."

`

202

265

`SearchDialogBase.close(self, event)

`

203

266

`self.text.tag_remove("hit", "1.0", "end")

`

204

267

``