Coverage for search.py: 16%

79 statements  

« prev     ^ index     » next       coverage.py v7.2.5, created at 2023-05-11 13:22 -0700

1"""Search dialog for Find, Find Again, and Find Selection 

2 functionality. 

3 

4 Inherits from SearchDialogBase for GUI and uses searchengine 

5 to prepare search pattern. 

6""" 

7from tkinter import TclError 

8 

9from idlelib import searchengine 

10from idlelib.searchbase import SearchDialogBase 

11 

12def _setup(text): 

13 """Return the new or existing singleton SearchDialog instance. 

14 

15 The singleton dialog saves user entries and preferences 

16 across instances. 

17 

18 Args: 

19 text: Text widget containing the text to be searched. 

20 """ 

21 root = text._root() 

22 engine = searchengine.get(root) 

23 if not hasattr(engine, "_searchdialog"): 

24 engine._searchdialog = SearchDialog(root, engine) 

25 return engine._searchdialog 

26 

27def find(text): 

28 """Open the search dialog. 

29 

30 Module-level function to access the singleton SearchDialog 

31 instance and open the dialog. If text is selected, it is 

32 used as the search phrase; otherwise, the previous entry 

33 is used. No search is done with this command. 

34 """ 

35 pat = text.get("sel.first", "sel.last") 

36 return _setup(text).open(text, pat) # Open is inherited from SDBase. 

37 

38def find_again(text): 

39 """Repeat the search for the last pattern and preferences. 

40 

41 Module-level function to access the singleton SearchDialog 

42 instance to search again using the user entries and preferences 

43 from the last dialog. If there was no prior search, open the 

44 search dialog; otherwise, perform the search without showing the 

45 dialog. 

46 """ 

47 return _setup(text).find_again(text) 

48 

49def find_selection(text): 

50 """Search for the selected pattern in the text. 

51 

52 Module-level function to access the singleton SearchDialog 

53 instance to search using the selected text. With a text 

54 selection, perform the search without displaying the dialog. 

55 Without a selection, use the prior entry as the search phrase 

56 and don't display the dialog. If there has been no prior 

57 search, open the search dialog. 

58 """ 

59 return _setup(text).find_selection(text) 

60 

61 

62class SearchDialog(SearchDialogBase): 

63 "Dialog for finding a pattern in text." 

64 

65 def create_widgets(self): 

66 "Create the base search dialog and add a button for Find Next." 

67 SearchDialogBase.create_widgets(self) 

68 # TODO - why is this here and not in a create_command_buttons? 

69 self.make_button("Find Next", self.default_command, isdef=True) 

70 

71 def default_command(self, event=None): 

72 "Handle the Find Next button as the default command." 

73 if not self.engine.getprog(): 

74 return 

75 self.find_again(self.text) 

76 

77 def find_again(self, text): 

78 """Repeat the last search. 

79 

80 If no search was previously run, open a new search dialog. In 

81 this case, no search is done. 

82 

83 If a search was previously run, the search dialog won't be 

84 shown and the options from the previous search (including the 

85 search pattern) will be used to find the next occurrence 

86 of the pattern. Next is relative based on direction. 

87 

88 Position the window to display the located occurrence in the 

89 text. 

90 

91 Return True if the search was successful and False otherwise. 

92 """ 

93 if not self.engine.getpat(): 

94 self.open(text) 

95 return False 

96 if not self.engine.getprog(): 

97 return False 

98 res = self.engine.search_text(text) 

99 if res: 

100 line, m = res 

101 i, j = m.span() 

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

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

104 try: 

105 selfirst = text.index("sel.first") 

106 sellast = text.index("sel.last") 

107 if selfirst == first and sellast == last: 

108 self.bell() 

109 return False 

110 except TclError: 

111 pass 

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

113 text.tag_add("sel", first, last) 

114 text.mark_set("insert", self.engine.isback() and first or last) 

115 text.see("insert") 

116 return True 

117 else: 

118 self.bell() 

119 return False 

120 

121 def find_selection(self, text): 

122 """Search for selected text with previous dialog preferences. 

123 

124 Instead of using the same pattern for searching (as Find 

125 Again does), this first resets the pattern to the currently 

126 selected text. If the selected text isn't changed, then use 

127 the prior search phrase. 

128 """ 

129 pat = text.get("sel.first", "sel.last") 

130 if pat: 

131 self.engine.setcookedpat(pat) 

132 return self.find_again(text) 

133 

134 

135def _search_dialog(parent): # htest # 

136 "Display search test box." 

137 from tkinter import Toplevel, Text 

138 from tkinter.ttk import Frame, Button 

139 

140 top = Toplevel(parent) 

141 top.title("Test SearchDialog") 

142 x, y = map(int, parent.geometry().split('+')[1:]) 

143 top.geometry("+%d+%d" % (x, y + 175)) 

144 

145 frame = Frame(top) 

146 frame.pack() 

147 text = Text(frame, inactiveselectbackground='gray') 

148 text.pack() 

149 text.insert("insert","This is a sample string.\n"*5) 

150 

151 def show_find(): 

152 text.tag_add('sel', '1.0', 'end') 

153 _setup(text).open(text) 

154 text.tag_remove('sel', '1.0', 'end') 

155 

156 button = Button(frame, text="Search (selection ignored)", command=show_find) 

157 button.pack() 

158 

159if __name__ == '__main__': 159 ↛ 160line 159 didn't jump to line 160, because the condition on line 159 was never true

160 from unittest import main 

161 main('idlelib.idle_test.test_search', verbosity=2, exit=False) 

162 

163 from idlelib.idle_test.htest import run 

164 run(_search_dialog)