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
« 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 >>
12def cmd(name):
13 """Command decorator for the RectangleCommandsClass class."""
14 return g.new_cmd_decorator(name, ['c', 'rectangleCommands',])
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)
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