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

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

145 statements  

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 = [] 

26 # Do not re-init this! 

27 self.stringRect = None 

28 self.commandsDict = { 

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

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

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

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

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

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

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

36 } 

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

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

39 """ 

40 Return True if there is a selection. 

41 Otherwise, return False and issue a warning. 

42 """ 

43 return self._chckSel(event, warning) 

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

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

46 @cmd('rectangle-clear') 

47 def clearRectangle(self, event): 

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

49 w = self.editWidget(event) 

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

51 return 

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

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

54 # Change the text. 

55 fill = ' ' * (r4 - r2) 

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

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

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

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

60 self.endCommand() 

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

62 @cmd('rectangle-close') 

63 def closeRectangle(self, event): 

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

65 w = self.editWidget(event) 

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

67 return 

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

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

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

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

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

73 if s.strip(): 

74 return 

75 # Change the text. 

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

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

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

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

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

81 self.endCommand() 

82 #@+node:ekr.20150515060613.1: *4* copyRectangleToRegister (no longer used) 

83 # @cmd('rectangle-copy-to-register') 

84 # def copyRectangleToRegister(self, event): 

85 # self.c.registerCommands.copyRectangleToRegister(event) 

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

87 @cmd('rectangle-delete') 

88 def deleteRectangle(self, event): 

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

90 w = self.editWidget(event) 

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

92 return 

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

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

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

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

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

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

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

100 self.endCommand() 

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

102 @cmd('rectangle-kill') 

103 def killRectangle(self, event): 

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

105 w = self.editWidget(event) 

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

107 return 

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

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

110 self.theKillRectangle = [] 

111 r = 0 

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

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

114 self.theKillRectangle.append(s) 

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

116 if self.theKillRectangle: 

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

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

119 self.endCommand() 

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

121 @cmd('rectangle-open') 

122 def openRectangle(self, event): 

123 """ 

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

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

126 """ 

127 w = self.editWidget(event) 

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

129 return 

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

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

132 fill = ' ' * (r4 - r2) 

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

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

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

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

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

138 self.endCommand() 

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

140 @cmd('rectangle-string') 

141 def stringRectangle(self, event): 

142 """ 

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

144 with a string on each line. 

145 """ 

146 k = self.c.k 

147 if g.unitTesting: 

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

149 self.w = self.editWidget(event) 

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

151 self.stringRectangle1(event) 

152 return 

153 self.w = self.editWidget(event) 

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

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

156 k.setLabelBlue('String rectangle: ') 

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

158 

159 def stringRectangle1(self, event): 

160 c, k = self.c, self.c.k 

161 k.clearState() 

162 k.resetLabel() 

163 c.bodyWantsFocus() 

164 w = self.w 

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

166 # pylint: disable=unpacking-non-sequence 

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

168 s = w.getAllText() 

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

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

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

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

173 w.setAllText(s) 

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

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

176 w.setSelectionRange(i, j) 

177 self.endCommand() 

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

179 # string-rectangle kills syntax highlighting. 

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

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

182 @cmd('rectangle-yank') 

183 def yankRectangle(self, event): 

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

185 # c = self.c 

186 k = self.c.k 

187 w = self.editWidget(event) 

188 if not w: 

189 return 

190 killRect = self.theKillRectangle 

191 if g.unitTesting: 

192 # This value is used by the unit test. 

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

194 elif not killRect: 

195 k.setLabelGrey('No kill rect') 

196 return 

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

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

199 n = 0 

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

201 if n >= len(killRect): 

202 break 

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

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

205 n += 1 

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

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

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

209 self.endCommand() 

210 #@-others 

211#@-others 

212#@-leo