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