9 |
9 |
10 import contextlib |
10 import contextlib |
11 import os |
11 import os |
12 import re |
12 import re |
13 |
13 |
14 from PyQt5.QtCore import QObject, QTranslator |
14 from PyQt6.QtCore import QObject, QTranslator |
15 from PyQt5.QtWidgets import QMenu |
15 from PyQt6.QtWidgets import QMenu |
16 |
16 |
17 from E5Gui.E5Application import e5App |
17 from EricWidgets.EricApplication import ericApp |
18 |
18 |
19 # Start-Of-Header |
19 # Start-Of-Header |
20 name = "Camel Case Handling Plug-in" |
20 name = "Camel Case Handling Plug-in" |
21 author = "Detlev Offenbach <detlev@die-offenbachs.de>" |
21 author = "Detlev Offenbach <detlev@die-offenbachs.de>" |
22 autoactivate = True |
22 autoactivate = True |
23 deactivateable = True |
23 deactivateable = True |
24 version = "3.1.0" |
24 version = "1.0.0" |
25 className = "SplitMergeCamelCasePlugin" |
25 className = "SplitMergeCamelCasePlugin" |
26 packageName = "SplitMergeCamelCase" |
26 packageName = "SplitMergeCamelCase" |
27 shortDescription = "Split, merge or convert camel case text" |
27 shortDescription = "Split, merge or convert camel/snake case text" |
28 longDescription = ( |
28 longDescription = ( |
29 """This plug-in implements a tool to split, merge or convert""" |
29 """This plug-in implements a tool to split or merge camel case """ |
30 """ camel case text. It works with the text of the current""" |
30 """or snake case text. It also offers the capability to convert""" |
31 """ editor. The menu entries will only be selectable, if the""" |
31 """ text between these case variants. It works with the text of""" |
32 """ current editor has some selected text.""" |
32 """ the current editor. The menu entries will only be enabled,""" |
|
33 """ if the current editor has some selected text.""" |
33 ) |
34 ) |
34 needsRestart = False |
35 needsRestart = False |
35 pyqtApi = 2 |
36 pyqtApi = 2 |
36 # End-Of-Header |
37 # End-Of-Header |
37 |
38 |
125 translation = "splitmergecamelcase_{0}".format(loc) |
128 translation = "splitmergecamelcase_{0}".format(loc) |
126 translator = QTranslator(None) |
129 translator = QTranslator(None) |
127 loaded = translator.load(translation, locale_dir) |
130 loaded = translator.load(translation, locale_dir) |
128 if loaded: |
131 if loaded: |
129 self.__translator = translator |
132 self.__translator = translator |
130 e5App().installTranslator(self.__translator) |
133 ericApp().installTranslator(self.__translator) |
131 else: |
134 else: |
132 print("Warning: translation file '{0}' could not be" |
135 print("Warning: translation file '{0}' could not be" |
133 " loaded.".format(translation)) |
136 " loaded.".format(translation)) |
134 print("Using default.") |
137 print("Using default.") |
135 |
138 |
136 def __initMenu(self): |
139 def __initMenu(self): |
137 """ |
140 """ |
138 Private method to initialize the camel case handling menu. |
141 Private method to initialize the camel case handling menu. |
139 """ |
142 """ |
140 self.__menu = QMenu(self.tr("CamelCase Handling")) |
143 self.__menu = QMenu(self.tr("Camel/Snake Case Handling")) |
141 self.__menu.addAction(self.tr("Split from CamelCase"), |
144 self.__menu.addAction( |
142 self.__splitCamelCase) |
145 self.tr("Split from Camel Case"), |
143 self.__menu.addAction(self.tr("Merge to CamelCase"), |
146 self.__splitCamelCase) |
144 self.__mergeCamelCase) |
147 self.__menu.addAction( |
145 self.__menu.addAction(self.tr("CamelCase to under_score"), |
148 self.tr("Merge to Camel Case"), |
146 self.__camelCaseToUnderscore) |
149 self.__mergeCamelCase) |
147 self.__menu.addAction(self.tr("under_score to CamelCase"), |
150 self.__menu.addAction( |
148 self.__underscoreToCamelCase) |
151 self.tr("Merge to Camel Case (upper case first)"), |
149 self.__menu.addAction( |
152 self.__mergeCamelCaseUppercaseFirst) |
150 self.tr("under_score to CamelCase (upper case first)"), |
153 self.__menu.addSeparator() |
151 self.__underscoreToCamelCaseUppercaseFirst) |
154 self.__menu.addAction( |
|
155 self.tr("Split from Snake Case"), |
|
156 self.__splitSnakeCase) |
|
157 self.__menu.addAction( |
|
158 self.tr("Merge to Snake Case"), |
|
159 self.__mergeSnakeCase) |
|
160 self.__menu.addSeparator() |
|
161 self.__menu.addAction( |
|
162 self.tr("Camel Case to Snake Case"), |
|
163 self.__camelCaseToSnakeCase) |
|
164 self.__menu.addAction( |
|
165 self.tr("Snake Case to Camel Case"), |
|
166 self.__snakeCaseToCamelCase) |
|
167 self.__menu.addAction( |
|
168 self.tr("Snake Case to Camel Case (upper case first)"), |
|
169 self.__snakeCaseToCamelCaseUppercaseFirst) |
152 |
170 |
153 def __populateMenu(self, name, menu): |
171 def __populateMenu(self, name, menu): |
154 """ |
172 """ |
155 Private slot to populate the tools menu with our entries. |
173 Private slot to populate the tools menu with our entries. |
156 |
174 |
157 @param name name of the menu (string) |
175 @param name name of the menu |
158 @param menu reference to the menu to be populated (QMenu) |
176 @type str |
|
177 @param menu reference to the menu to be populated |
|
178 @type QMenu |
159 """ |
179 """ |
160 if name not in ["Tools", "PluginTools"]: |
180 if name not in ["Tools", "PluginTools"]: |
161 return |
181 return |
162 |
182 |
163 editor = e5App().getObject("ViewManager").activeWindow() |
183 editor = ericApp().getObject("ViewManager").activeWindow() |
164 |
184 |
165 if name == "Tools": |
185 if name == "Tools": |
166 if not menu.isEmpty(): |
186 if not menu.isEmpty(): |
167 menu.addSeparator() |
187 menu.addSeparator() |
168 act = menu.addMenu(self.__menu) |
188 act = menu.addMenu(self.__menu) |
189 |
210 |
190 def __editorClosed(self, editor): |
211 def __editorClosed(self, editor): |
191 """ |
212 """ |
192 Private slot called, when an editor was closed. |
213 Private slot called, when an editor was closed. |
193 |
214 |
194 @param editor reference to the editor (QScintilla.Editor) |
215 @param editor reference to the editor |
|
216 @type Editor |
195 """ |
217 """ |
196 with contextlib.suppress(KeyError): |
218 with contextlib.suppress(KeyError): |
197 del self.__editors[editor] |
219 del self.__editors[editor] |
198 |
220 |
199 def __editorShowMenu(self, menuName, menu, editor): |
221 def __editorShowMenu(self, menuName, menu, editor): |
200 """ |
222 """ |
201 Private slot called, when the the editor context menu or a submenu is |
223 Private slot called, when the the editor context menu or a submenu is |
202 about to be shown. |
224 about to be shown. |
203 |
225 |
204 @param menuName name of the menu to be shown (string) |
226 @param menuName name of the menu to be shown |
205 @param menu reference to the menu (QMenu) |
227 @type str |
|
228 @param menu reference to the menu |
|
229 @type QMenu |
206 @param editor reference to the editor |
230 @param editor reference to the editor |
|
231 @type Editor |
207 """ |
232 """ |
208 if menuName == "Tools": |
233 if menuName == "Tools": |
209 if self.__menu.menuAction() not in menu.actions(): |
234 if self.__menu.menuAction() not in menu.actions(): |
210 # Re-add our menu |
235 # Re-add our menu |
211 self.__editors[editor] = [] |
236 self.__editors[editor] = [] |
219 |
244 |
220 def __applyChange(self, newText, editor): |
245 def __applyChange(self, newText, editor): |
221 """ |
246 """ |
222 Private method to change the selected text. |
247 Private method to change the selected text. |
223 |
248 |
224 @param newText new (converted) text (string) |
249 @param newText new (converted) text |
|
250 @type str |
225 @param editor reference to the editor to apply the text |
251 @param editor reference to the editor to apply the text |
226 change to (Editor) |
252 change to |
|
253 @type Editor |
227 """ |
254 """ |
228 editor.beginUndoAction() |
255 editor.beginUndoAction() |
229 editor.replaceSelectedText(newText) |
256 editor.replaceSelectedText(newText) |
230 editor.endUndoAction() |
257 editor.endUndoAction() |
231 |
258 |
232 def __splitCamelCase(self): |
259 def __splitCamelCase(self): |
233 """ |
260 """ |
234 Private slot to split the selected camel case text. |
261 Private slot to split the selected camel case text. |
235 """ |
262 """ |
236 editor = e5App().getObject("ViewManager").activeWindow() |
263 editor = ericApp().getObject("ViewManager").activeWindow() |
237 if editor is None: |
264 if editor is None: |
238 return |
265 return |
239 |
266 |
240 text = editor.selectedText() |
267 text = editor.selectedText() |
241 if text: |
268 if text: |
242 newText = re.sub(r"([A-Z])", r" \1", text) |
269 newText = re.sub(r"([A-Z])", r" \1", text).lstrip(" ") |
243 if newText.startswith(" "): |
270 if newText != text: |
244 newText = newText[1:] |
271 self.__applyChange(newText, editor) |
245 if newText != text: |
272 |
246 self.__applyChange(newText, editor) |
273 def __mergeCamelCase(self, uppercaseFirst=False): |
247 |
|
248 def __mergeCamelCase(self): |
|
249 """ |
274 """ |
250 Private slot to merge the selected text to camel case. |
275 Private slot to merge the selected text to camel case. |
251 """ |
|
252 editor = e5App().getObject("ViewManager").activeWindow() |
|
253 if editor is None: |
|
254 return |
|
255 |
|
256 text = editor.selectedText() |
|
257 if text: |
|
258 newText = "".join(text.split()) |
|
259 if newText != text: |
|
260 self.__applyChange(newText, editor) |
|
261 |
|
262 def __camelCaseToUnderscore(self): |
|
263 """ |
|
264 Private slot to convert camel case text to underscore separated text. |
|
265 """ |
|
266 editor = e5App().getObject("ViewManager").activeWindow() |
|
267 if editor is None: |
|
268 return |
|
269 |
|
270 text = editor.selectedText() |
|
271 if text: |
|
272 newText = re.sub(r"([A-Z])", r"_\1", text).lower() |
|
273 if newText.startswith("_"): |
|
274 newText = newText[1:] |
|
275 if newText != text: |
|
276 self.__applyChange(newText, editor) |
|
277 |
|
278 def __underscoreToCamelCase(self, uppercaseFirst=False): |
|
279 """ |
|
280 Private slot to convert underscore separated text to camel case. |
|
281 |
276 |
282 @param uppercaseFirst flag indicating to upper case the |
277 @param uppercaseFirst flag indicating to upper case the |
283 first character (boolean) |
278 first character |
284 """ |
279 @type bool |
285 editor = e5App().getObject("ViewManager").activeWindow() |
280 """ |
286 if editor is None: |
281 editor = ericApp().getObject("ViewManager").activeWindow() |
287 return |
282 if editor is None: |
288 |
283 return |
289 text = editor.selectedText() |
284 |
290 if text: |
285 text = editor.selectedText() |
291 newText = "".join([s.capitalize() for s in text.split("_")]) |
286 if text: |
|
287 newText = "".join(w[0].upper() + w[1:] for w in text.split()) |
292 if not uppercaseFirst: |
288 if not uppercaseFirst: |
293 newText = newText[0].lower() + newText[1:] |
289 newText = newText[0].lower() + newText[1:] |
294 if newText != text: |
290 if newText != text: |
295 self.__applyChange(newText, editor) |
291 self.__applyChange(newText, editor) |
296 |
292 |
297 def __underscoreToCamelCaseUppercaseFirst(self): |
293 def __mergeCamelCaseUppercaseFirst(self): |
|
294 """ |
|
295 Private slot to merge the selected text to camel case upper casing |
|
296 the first character. |
|
297 """ |
|
298 self.__mergeCamelCase(True) |
|
299 |
|
300 def __splitSnakeCase(self): |
|
301 """ |
|
302 Private slot to split the selected snake case text. |
|
303 """ |
|
304 editor = ericApp().getObject("ViewManager").activeWindow() |
|
305 if editor is None: |
|
306 return |
|
307 |
|
308 text = editor.selectedText() |
|
309 if text: |
|
310 newText = text.replace("_", " ").lstrip(" ") |
|
311 if newText != text: |
|
312 self.__applyChange(newText, editor) |
|
313 |
|
314 def __mergeSnakeCase(self): |
|
315 """ |
|
316 Private slot to merge the selected text to snake case. |
|
317 """ |
|
318 editor = ericApp().getObject("ViewManager").activeWindow() |
|
319 if editor is None: |
|
320 return |
|
321 |
|
322 text = editor.selectedText() |
|
323 if text: |
|
324 newText = "_".join(w.lower() for w in text.split()) |
|
325 if newText != text: |
|
326 self.__applyChange(newText, editor) |
|
327 |
|
328 def __camelCaseToSnakeCase(self): |
|
329 """ |
|
330 Private slot to convert camel case text to underscore separated text. |
|
331 """ |
|
332 editor = ericApp().getObject("ViewManager").activeWindow() |
|
333 if editor is None: |
|
334 return |
|
335 |
|
336 text = editor.selectedText() |
|
337 if text: |
|
338 newText = re.sub(r"([A-Z])", r"_\1", text).lower().lstrip("_") |
|
339 if text.startswith("__"): |
|
340 newText = "__" + newText |
|
341 elif text.startswith("_"): |
|
342 newText = "_" + newText |
|
343 if newText != text: |
|
344 self.__applyChange(newText, editor) |
|
345 |
|
346 def __snakeCaseToCamelCase(self, uppercaseFirst=False): |
|
347 """ |
|
348 Private slot to convert underscore separated text to camel case. |
|
349 |
|
350 @param uppercaseFirst flag indicating to upper case the |
|
351 first character |
|
352 @type bool |
|
353 """ |
|
354 editor = ericApp().getObject("ViewManager").activeWindow() |
|
355 if editor is None: |
|
356 return |
|
357 |
|
358 text = editor.selectedText() |
|
359 if text: |
|
360 newText = "".join(s.capitalize() for s in text.split("_")) |
|
361 if not uppercaseFirst: |
|
362 newText = newText[0].lower() + newText[1:] |
|
363 if text.startswith("__"): |
|
364 newText = "__" + newText |
|
365 elif text.startswith("_"): |
|
366 newText = "_" + newText |
|
367 if newText != text: |
|
368 self.__applyChange(newText, editor) |
|
369 |
|
370 def __snakeCaseToCamelCaseUppercaseFirst(self): |
298 """ |
371 """ |
299 Private slot to convert underscore separated text to camel case |
372 Private slot to convert underscore separated text to camel case |
300 upper casing the first character. |
373 upper casing the first character. |
301 """ |
374 """ |
302 self.__underscoreToCamelCase(True) |
375 self.__snakeCaseToCamelCase(True) |
303 |
376 |
304 # |
377 # |
305 # eflag: noqa = M801 |
378 # eflag: noqa = M801 |