PluginSplitMergeCamelCase.py

branch
eric7
changeset 48
4f0e000eab79
parent 45
e12f7ab5f6c0
child 51
f862797030d1
equal deleted inserted replaced
47:0780a9985266 48:4f0e000eab79
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
44 """ 45 """
45 def __init__(self, ui): 46 def __init__(self, ui):
46 """ 47 """
47 Constructor 48 Constructor
48 49
49 @param ui reference to the user interface object (UI.UserInterface) 50 @param ui reference to the user interface object
51 @type UserInterface
50 """ 52 """
51 super().__init__(ui) 53 super().__init__(ui)
52 self.__ui = ui 54 self.__ui = ui
53 55
54 self.__translator = None 56 self.__translator = None
61 63
62 def activate(self): 64 def activate(self):
63 """ 65 """
64 Public method to activate this plugin. 66 Public method to activate this plugin.
65 67
66 @return tuple of None and activation status (boolean) 68 @return tuple of None and activation status
69 @rtype tuple of (None, bool)
67 """ 70 """
68 global error 71 global error
69 error = "" # clear previous error 72 error = "" # clear previous error
70 73
71 self.__ui.showMenu.connect(self.__populateMenu) 74 self.__ui.showMenu.connect(self.__populateMenu)
76 act = menu.addSeparator() 79 act = menu.addSeparator()
77 self.__mainActions.append(act) 80 self.__mainActions.append(act)
78 act = menu.addMenu(self.__menu) 81 act = menu.addMenu(self.__menu)
79 self.__mainActions.append(act) 82 self.__mainActions.append(act)
80 83
81 e5App().getObject("ViewManager").editorOpenedEd.connect( 84 ericApp().getObject("ViewManager").editorOpenedEd.connect(
82 self.__editorOpened) 85 self.__editorOpened)
83 e5App().getObject("ViewManager").editorClosedEd.connect( 86 ericApp().getObject("ViewManager").editorClosedEd.connect(
84 self.__editorClosed) 87 self.__editorClosed)
85 88
86 for editor in e5App().getObject("ViewManager").getOpenEditors(): 89 for editor in ericApp().getObject("ViewManager").getOpenEditors():
87 self.__editorOpened(editor) 90 self.__editorOpened(editor)
88 91
89 return None, True 92 return None, True
90 93
91 def deactivate(self): 94 def deactivate(self):
98 if menu is not None: 101 if menu is not None:
99 for act in self.__mainActions: 102 for act in self.__mainActions:
100 menu.removeAction(act) 103 menu.removeAction(act)
101 self.__mainActions = [] 104 self.__mainActions = []
102 105
103 e5App().getObject("ViewManager").editorOpenedEd.disconnect( 106 ericApp().getObject("ViewManager").editorOpenedEd.disconnect(
104 self.__editorOpened) 107 self.__editorOpened)
105 e5App().getObject("ViewManager").editorClosedEd.disconnect( 108 ericApp().getObject("ViewManager").editorClosedEd.disconnect(
106 self.__editorClosed) 109 self.__editorClosed)
107 110
108 for editor, acts in self.__editors.items(): 111 for editor, acts in self.__editors.items():
109 editor.showMenu.disconnect(self.__editorShowMenu) 112 editor.showMenu.disconnect(self.__editorShowMenu)
110 menu = editor.getMenu("Tools") 113 menu = editor.getMenu("Tools")
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)
173 193
174 def __editorOpened(self, editor): 194 def __editorOpened(self, editor):
175 """ 195 """
176 Private slot called, when a new editor was opened. 196 Private slot called, when a new editor was opened.
177 197
178 @param editor reference to the new editor (QScintilla.Editor) 198 @param editor reference to the new editor
199 @type Editor
179 """ 200 """
180 menu = editor.getMenu("Tools") 201 menu = editor.getMenu("Tools")
181 if menu is not None: 202 if menu is not None:
182 self.__editors[editor] = [] 203 self.__editors[editor] = []
183 if not menu.isEmpty(): 204 if not menu.isEmpty():
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

eric ide

mercurial