Coverage for C:\Repos\leo-editor\leo\commands\rectangleCommands.py: 89%

145 statements  

« prev     ^ index     » next       coverage.py v6.4, created at 2022-05-24 10:21 -0500

1# -*- coding: utf-8 -*- 

2#@+leo-ver=5-thin 

3#@+node:ekr.20150514040146.1: * @file ../commands/rectangleCommands.py 

4#@@first 

5"""Leo's rectangle commands.""" 

6#@+<< imports >> 

7#@+node:ekr.20150514050446.1: ** << imports >> (rectangleCommands.py) 

8from leo.core import leoGlobals as g 

9from leo.commands.baseCommands import BaseEditCommandsClass 

10#@-<< imports >> 

11 

12def cmd(name): 

13 """Command decorator for the RectangleCommandsClass class.""" 

14 return g.new_cmd_decorator(name, ['c', 'rectangleCommands',]) 

15 

16#@+others 

17#@+node:ekr.20160514120751.1: ** class RectangleCommandsClass 

18class RectangleCommandsClass(BaseEditCommandsClass): 

19 #@+others 

20 #@+node:ekr.20150514063305.448: *3* rectangle.ctor 

21 def __init__(self, c): 

22 """Ctor for RectangleCommandsClass.""" 

23 # pylint: disable=super-init-not-called 

24 self.c = c 

25 self.theKillRectangle = [] # Do not re-init this! 

26 self.stringRect = None 

27 self.commandsDict = { 

28 'c': ('clear-rectangle', self.clearRectangle), 

29 'd': ('delete-rectangle', self.deleteRectangle), 

30 'k': ('kill-rectangle', self.killRectangle), 

31 'o': ('open-rectangle', self.openRectangle), 

32 # 'r': ('copy-rectangle-to-register', self.copyRectangleToRegister), 

33 't': ('string-rectangle', self.stringRectangle), 

34 'y': ('yank-rectangle', self.yankRectangle), 

35 } 

36 #@+node:ekr.20150514063305.451: *3* check 

37 def check(self, event, warning='No rectangle selected'): 

38 """ 

39 Return True if there is a selection. 

40 Otherwise, return False and issue a warning. 

41 """ 

42 return self._chckSel(event, warning) 

43 #@+node:ekr.20150514063305.453: *3* rectangle.Entries 

44 #@+node:ekr.20150514063305.454: *4* clearRectangle 

45 @cmd('rectangle-clear') 

46 def clearRectangle(self, event): 

47 """Clear the rectangle defined by the start and end of selected text.""" 

48 w = self.editWidget(event) 

49 if not w or not self.check(event): 

50 return 

51 self.beginCommand(w, 'clear-rectangle') 

52 r1, r2, r3, r4 = self.getRectanglePoints(w) 

53 # Change the text. 

54 fill = ' ' * (r4 - r2) 

55 for r in range(r1, r3 + 1): 

56 w.delete(f"{r}.{r2}", f"{r}.{r4}") 

57 w.insert(f"{r}.{r2}", fill) 

58 w.setSelectionRange(f"{r1}.{r2}", f"{r3}.{r2 + len(fill)}") 

59 self.endCommand() 

60 #@+node:ekr.20150514063305.455: *4* closeRectangle 

61 @cmd('rectangle-close') 

62 def closeRectangle(self, event): 

63 """Delete the rectangle if it contains nothing but whitespace..""" 

64 w = self.editWidget(event) 

65 if not w or not self.check(event): 

66 return 

67 self.beginCommand(w, 'close-rectangle') 

68 r1, r2, r3, r4 = self.getRectanglePoints(w) 

69 # Return if any part of the selection contains something other than whitespace. 

70 for r in range(r1, r3 + 1): 

71 s = w.get(f"{r}.{r2}", f"{r}.{r4}") 

72 if s.strip(): 

73 return 

74 # Change the text. 

75 for r in range(r1, r3 + 1): 

76 w.delete(f"{r}.{r2}", f"{r}.{r4}") 

77 i = f"{r1}.{r2}" 

78 j = f"{r3}.{r2}" 

79 w.setSelectionRange(i, j, insert=j) 

80 self.endCommand() 

81 #@+node:ekr.20150514063305.456: *4* deleteRectangle 

82 @cmd('rectangle-delete') 

83 def deleteRectangle(self, event): 

84 """Delete the rectangle defined by the start and end of selected text.""" 

85 w = self.editWidget(event) 

86 if not w or not self.check(event): 

87 return 

88 self.beginCommand(w, 'delete-rectangle') 

89 r1, r2, r3, r4 = self.getRectanglePoints(w) 

90 for r in range(r1, r3 + 1): 

91 w.delete(f"{r}.{r2}", f"{r}.{r4}") 

92 i = f"{r1}.{r2}" 

93 j = f"{r3}.{r2}" 

94 w.setSelectionRange(i, j, insert=j) 

95 self.endCommand() 

96 #@+node:ekr.20150514063305.457: *4* killRectangle 

97 @cmd('rectangle-kill') 

98 def killRectangle(self, event): 

99 """Kill the rectangle defined by the start and end of selected text.""" 

100 w = self.editWidget(event) 

101 if not w or not self.check(event): 

102 return 

103 self.beginCommand(w, 'kill-rectangle') 

104 r1, r2, r3, r4 = self.getRectanglePoints(w) 

105 self.theKillRectangle = [] 

106 r = 0 

107 for r in range(r1, r3 + 1): 

108 s = w.get(f"{r}.{r2}", f"{r}.{r4}") 

109 self.theKillRectangle.append(s) 

110 w.delete(f"{r}.{r2}", f"{r}.{r4}") 

111 if self.theKillRectangle: 

112 ins = f"{r}.{r2}" 

113 w.setSelectionRange(ins, ins, insert=ins) 

114 self.endCommand() 

115 #@+node:ekr.20150514063305.458: *4* openRectangle 

116 @cmd('rectangle-open') 

117 def openRectangle(self, event): 

118 """ 

119 Insert blanks in the rectangle defined by the start and end of selected 

120 text. This pushes the previous contents of the rectangle rightward. 

121 """ 

122 w = self.editWidget(event) 

123 if not w or not self.check(event): 

124 return 

125 self.beginCommand(w, 'open-rectangle') 

126 r1, r2, r3, r4 = self.getRectanglePoints(w) 

127 fill = ' ' * (r4 - r2) 

128 for r in range(r1, r3 + 1): 

129 w.insert(f"{r}.{r2}", fill) 

130 i = f"{r1}.{r2}" 

131 j = f"{r3}.{r2 + len(fill)}" 

132 w.setSelectionRange(i, j, insert=j) 

133 self.endCommand() 

134 #@+node:ekr.20150514063305.459: *4* stringRectangle 

135 @cmd('rectangle-string') 

136 def stringRectangle(self, event): 

137 """ 

138 Prompt for a string, then replace the contents of a rectangle 

139 with a string on each line. 

140 """ 

141 k = self.c.k 

142 if g.unitTesting: 

143 k.arg = 's...s' # This string is known to the unit test. 

144 self.w = self.editWidget(event) 

145 self.stringRect = self.getRectanglePoints(self.w) 

146 self.stringRectangle1(event) 

147 return 

148 self.w = self.editWidget(event) 

149 if self.w and self.check(event): 

150 self.stringRect = self.getRectanglePoints(self.w) 

151 k.setLabelBlue('String rectangle: ') 

152 k.get1Arg(event, handler=self.stringRectangle1) 

153 

154 def stringRectangle1(self, event): 

155 c, k = self.c, self.c.k 

156 k.clearState() 

157 k.resetLabel() 

158 c.bodyWantsFocus() 

159 w = self.w 

160 self.beginCommand(w, 'string-rectangle') 

161 # pylint: disable=unpacking-non-sequence 

162 r1, r2, r3, r4 = self.stringRect 

163 s = w.getAllText() 

164 for r in range(r1, r3 + 1): 

165 i = g.convertRowColToPythonIndex(s, r - 1, r2) 

166 j = g.convertRowColToPythonIndex(s, r - 1, r4) 

167 s = s[:i] + k.arg + s[j:] 

168 w.setAllText(s) 

169 i = g.convertRowColToPythonIndex(s, r1 - 1, r2) 

170 j = g.convertRowColToPythonIndex(s, r3 - 1, r2 + len(k.arg)) 

171 w.setSelectionRange(i, j) 

172 self.endCommand() 

173 # 2010/1/1: Fix bug 480422: 

174 # string-rectangle kills syntax highlighting. 

175 c.frame.body.recolor(c.p) 

176 #@+node:ekr.20150514063305.460: *4* yankRectangle 

177 @cmd('rectangle-yank') 

178 def yankRectangle(self, event): 

179 """Yank into the rectangle defined by the start and end of selected text.""" 

180 # c = self.c 

181 k = self.c.k 

182 w = self.editWidget(event) 

183 if not w: 

184 return 

185 killRect = self.theKillRectangle 

186 if g.unitTesting: 

187 # This value is used by the unit test. 

188 killRect = ['Y1Y', 'Y2Y', 'Y3Y', 'Y4Y'] 

189 elif not killRect: 

190 k.setLabelGrey('No kill rect') 

191 return 

192 self.beginCommand(w, 'yank-rectangle') 

193 r1, r2, r3, r4 = self.getRectanglePoints(w) 

194 n = 0 

195 for r in range(r1, r3 + 1): 

196 if n >= len(killRect): 

197 break 

198 w.delete(f"{r}.{r2}", f"{r}.{r4}") 

199 w.insert(f"{r}.{r2}", killRect[n]) 

200 n += 1 

201 i = f"{r1}.{r2}" 

202 j = f"{r3}.{r2 + len(killRect[n - 1])}" 

203 w.setSelectionRange(i, j, insert=j) 

204 self.endCommand() 

205 #@-others 

206#@-others 

207#@-leo