PrEditor 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of PrEditor might be problematic. Click here for more details.

Files changed (158) hide show
  1. preditor/__init__.py +322 -0
  2. preditor/__main__.py +13 -0
  3. preditor/about_module.py +161 -0
  4. preditor/cli.py +192 -0
  5. preditor/config.py +302 -0
  6. preditor/contexts.py +119 -0
  7. preditor/cores/__init__.py +0 -0
  8. preditor/cores/core.py +20 -0
  9. preditor/dccs/maya/PrEditor_maya.mod +2 -0
  10. preditor/dccs/maya/plug-ins/PrEditor_maya.py +110 -0
  11. preditor/debug.py +144 -0
  12. preditor/delayable_engine/__init__.py +302 -0
  13. preditor/delayable_engine/delayables.py +85 -0
  14. preditor/enum.py +728 -0
  15. preditor/excepthooks.py +131 -0
  16. preditor/gui/__init__.py +93 -0
  17. preditor/gui/app.py +160 -0
  18. preditor/gui/codehighlighter.py +209 -0
  19. preditor/gui/completer.py +226 -0
  20. preditor/gui/console.py +867 -0
  21. preditor/gui/dialog.py +178 -0
  22. preditor/gui/drag_tab_bar.py +190 -0
  23. preditor/gui/editor_chooser.py +57 -0
  24. preditor/gui/errordialog.py +68 -0
  25. preditor/gui/find_files.py +125 -0
  26. preditor/gui/fuzzy_search/__init__.py +0 -0
  27. preditor/gui/fuzzy_search/fuzzy_search.py +93 -0
  28. preditor/gui/group_tab_widget/__init__.py +325 -0
  29. preditor/gui/group_tab_widget/grouped_tab_menu.py +35 -0
  30. preditor/gui/group_tab_widget/grouped_tab_models.py +108 -0
  31. preditor/gui/group_tab_widget/grouped_tab_widget.py +78 -0
  32. preditor/gui/group_tab_widget/one_tab_widget.py +54 -0
  33. preditor/gui/level_buttons.py +343 -0
  34. preditor/gui/logger_window_handler.py +48 -0
  35. preditor/gui/logger_window_plugin.py +32 -0
  36. preditor/gui/loggerwindow.py +1385 -0
  37. preditor/gui/newtabwidget.py +69 -0
  38. preditor/gui/set_text_editor_path_dialog.py +59 -0
  39. preditor/gui/status_label.py +99 -0
  40. preditor/gui/suggest_path_quotes_dialog.py +50 -0
  41. preditor/gui/ui/editor_chooser.ui +93 -0
  42. preditor/gui/ui/errordialog.ui +74 -0
  43. preditor/gui/ui/find_files.ui +140 -0
  44. preditor/gui/ui/loggerwindow.ui +1105 -0
  45. preditor/gui/ui/set_text_editor_path_dialog.ui +189 -0
  46. preditor/gui/ui/suggest_path_quotes_dialog.ui +225 -0
  47. preditor/gui/window.py +161 -0
  48. preditor/gui/workbox_mixin.py +389 -0
  49. preditor/gui/workbox_text_edit.py +137 -0
  50. preditor/gui/workboxwidget.py +298 -0
  51. preditor/logging_config.py +52 -0
  52. preditor/osystem.py +401 -0
  53. preditor/plugins.py +118 -0
  54. preditor/prefs.py +74 -0
  55. preditor/resource/environment_variables.html +26 -0
  56. preditor/resource/error_mail.html +85 -0
  57. preditor/resource/error_mail_inline.html +41 -0
  58. preditor/resource/img/README.md +17 -0
  59. preditor/resource/img/arrow_forward.png +0 -0
  60. preditor/resource/img/check-bold.png +0 -0
  61. preditor/resource/img/chevron-down.png +0 -0
  62. preditor/resource/img/chevron-up.png +0 -0
  63. preditor/resource/img/close-thick.png +0 -0
  64. preditor/resource/img/comment-edit.png +0 -0
  65. preditor/resource/img/content-copy.png +0 -0
  66. preditor/resource/img/content-cut.png +0 -0
  67. preditor/resource/img/content-duplicate.png +0 -0
  68. preditor/resource/img/content-paste.png +0 -0
  69. preditor/resource/img/content-save.png +0 -0
  70. preditor/resource/img/debug_disabled.png +0 -0
  71. preditor/resource/img/eye-check.png +0 -0
  72. preditor/resource/img/file-plus.png +0 -0
  73. preditor/resource/img/file-remove.png +0 -0
  74. preditor/resource/img/format-align-left.png +0 -0
  75. preditor/resource/img/format-letter-case-lower.png +0 -0
  76. preditor/resource/img/format-letter-case-upper.png +0 -0
  77. preditor/resource/img/format-letter-case.svg +1 -0
  78. preditor/resource/img/information.png +0 -0
  79. preditor/resource/img/logging_critical.png +0 -0
  80. preditor/resource/img/logging_custom.png +0 -0
  81. preditor/resource/img/logging_debug.png +0 -0
  82. preditor/resource/img/logging_error.png +0 -0
  83. preditor/resource/img/logging_info.png +0 -0
  84. preditor/resource/img/logging_not_set.png +0 -0
  85. preditor/resource/img/logging_warning.png +0 -0
  86. preditor/resource/img/marker.png +0 -0
  87. preditor/resource/img/play.png +0 -0
  88. preditor/resource/img/playlist-play.png +0 -0
  89. preditor/resource/img/plus-minus-variant.png +0 -0
  90. preditor/resource/img/preditor.ico +0 -0
  91. preditor/resource/img/preditor.png +0 -0
  92. preditor/resource/img/preditor.psd +0 -0
  93. preditor/resource/img/preditor.svg +44 -0
  94. preditor/resource/img/regex.svg +1 -0
  95. preditor/resource/img/restart.svg +1 -0
  96. preditor/resource/img/skip-forward-outline.png +0 -0
  97. preditor/resource/img/skip-next-outline.png +0 -0
  98. preditor/resource/img/skip-next.png +0 -0
  99. preditor/resource/img/skip-previous.png +0 -0
  100. preditor/resource/img/subdirectory-arrow-right.png +0 -0
  101. preditor/resource/img/text-search-variant.png +0 -0
  102. preditor/resource/img/warning-big.png +0 -0
  103. preditor/resource/lang/python.json +30 -0
  104. preditor/resource/settings.ini +25 -0
  105. preditor/resource/stylesheet/Bright.css +65 -0
  106. preditor/resource/stylesheet/Dark.css +199 -0
  107. preditor/scintilla/__init__.py +22 -0
  108. preditor/scintilla/delayables/__init__.py +11 -0
  109. preditor/scintilla/delayables/smart_highlight.py +94 -0
  110. preditor/scintilla/delayables/spell_check.py +173 -0
  111. preditor/scintilla/documenteditor.py +2038 -0
  112. preditor/scintilla/finddialog.py +68 -0
  113. preditor/scintilla/lang/__init__.py +80 -0
  114. preditor/scintilla/lang/config/bash.ini +15 -0
  115. preditor/scintilla/lang/config/batch.ini +14 -0
  116. preditor/scintilla/lang/config/cpp.ini +19 -0
  117. preditor/scintilla/lang/config/css.ini +19 -0
  118. preditor/scintilla/lang/config/eyeonscript.ini +17 -0
  119. preditor/scintilla/lang/config/html.ini +21 -0
  120. preditor/scintilla/lang/config/javascript.ini +24 -0
  121. preditor/scintilla/lang/config/lua.ini +16 -0
  122. preditor/scintilla/lang/config/maxscript.ini +20 -0
  123. preditor/scintilla/lang/config/mel.ini +18 -0
  124. preditor/scintilla/lang/config/mu.ini +22 -0
  125. preditor/scintilla/lang/config/nsi.ini +19 -0
  126. preditor/scintilla/lang/config/perl.ini +19 -0
  127. preditor/scintilla/lang/config/puppet.ini +19 -0
  128. preditor/scintilla/lang/config/python.ini +28 -0
  129. preditor/scintilla/lang/config/ruby.ini +19 -0
  130. preditor/scintilla/lang/config/sql.ini +7 -0
  131. preditor/scintilla/lang/config/xml.ini +21 -0
  132. preditor/scintilla/lang/config/yaml.ini +18 -0
  133. preditor/scintilla/lang/language.py +240 -0
  134. preditor/scintilla/lexers/__init__.py +0 -0
  135. preditor/scintilla/lexers/cpplexer.py +21 -0
  136. preditor/scintilla/lexers/javascriptlexer.py +25 -0
  137. preditor/scintilla/lexers/maxscriptlexer.py +234 -0
  138. preditor/scintilla/lexers/mellexer.py +368 -0
  139. preditor/scintilla/lexers/mulexer.py +32 -0
  140. preditor/scintilla/lexers/pythonlexer.py +41 -0
  141. preditor/scintilla/ui/finddialog.ui +160 -0
  142. preditor/settings.py +71 -0
  143. preditor/stream/__init__.py +80 -0
  144. preditor/stream/director.py +73 -0
  145. preditor/stream/manager.py +74 -0
  146. preditor/streamhandler_helper.py +46 -0
  147. preditor/utils/__init__.py +0 -0
  148. preditor/utils/cute.py +30 -0
  149. preditor/utils/stylesheets.py +54 -0
  150. preditor/utils/text_search.py +342 -0
  151. preditor/version.py +21 -0
  152. preditor/weakref.py +363 -0
  153. preditor-1.0.0.dist-info/METADATA +224 -0
  154. preditor-1.0.0.dist-info/RECORD +158 -0
  155. preditor-1.0.0.dist-info/WHEEL +5 -0
  156. preditor-1.0.0.dist-info/entry_points.txt +18 -0
  157. preditor-1.0.0.dist-info/licenses/LICENSE +165 -0
  158. preditor-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,298 @@
1
+ from __future__ import absolute_import, print_function
2
+
3
+ import io
4
+ import re
5
+ import time
6
+
7
+ from Qt.QtCore import Qt
8
+ from Qt.QtGui import QIcon
9
+ from Qt.QtWidgets import QAction
10
+
11
+ from .. import core, resourcePath
12
+ from ..gui.workbox_mixin import WorkboxMixin
13
+ from ..scintilla.documenteditor import DocumentEditor, SearchOptions
14
+ from ..scintilla.finddialog import FindDialog
15
+
16
+
17
+ class WorkboxWidget(WorkboxMixin, DocumentEditor):
18
+ def __init__(
19
+ self, parent=None, console=None, delayable_engine='default', core_name=None
20
+ ):
21
+ self.__set_console__(console)
22
+ self._searchFlags = 0
23
+ self._searchText = ''
24
+ self._searchDialog = None
25
+
26
+ # initialize the super class
27
+ super(WorkboxWidget, self).__init__(
28
+ parent, delayable_engine=delayable_engine, core_name=core_name
29
+ )
30
+
31
+ # Store the software name so we can handle custom keyboard shortcuts based on
32
+ # software
33
+ self._software = core.objectName()
34
+ # Used to remove any trailing whitespace when running selected text
35
+ self.regex = re.compile(r'\s+$')
36
+ self.initShortcuts()
37
+ self.setLanguage('Python')
38
+ # Default to unix newlines
39
+ self.setEolMode(self.EolUnix)
40
+ if hasattr(self.window(), "setWorkboxFontBasedOnConsole"):
41
+ self.window().setWorkboxFontBasedOnConsole()
42
+
43
+ def __auto_complete_enabled__(self):
44
+ return self.autoCompletionSource() == self.AcsAll
45
+
46
+ def __set_auto_complete_enabled__(self, state):
47
+ state = self.AcsAll if state else self.AcsNone
48
+ self.setAutoCompletionSource(state)
49
+
50
+ def __clear__(self):
51
+ self.clear()
52
+
53
+ def __comment_toggle__(self):
54
+ self.commentToggle()
55
+
56
+ def __copy_indents_as_spaces__(self):
57
+ return self.copyIndentsAsSpaces
58
+
59
+ def __set_copy_indents_as_spaces__(self, state):
60
+ self.copyIndentsAsSpaces = state
61
+
62
+ def __cursor_position__(self):
63
+ """Returns the line and index of the cursor."""
64
+ return self.getCursorPosition()
65
+
66
+ def __set_cursor_position__(self, line, index):
67
+ """Set the cursor to this line number and index"""
68
+ self.setCursorPosition(line, index)
69
+
70
+ def __exec_all__(self):
71
+ txt = self.__unix_end_lines__(self.text()).rstrip()
72
+ filename = self.__workbox_filename__()
73
+ self.__console__().executeString(txt, filename=filename)
74
+
75
+ def __file_monitoring_enabled__(self):
76
+ return self._fileMonitoringActive
77
+
78
+ def __set_file_monitoring_enabled__(self, state):
79
+ self.setAutoReloadOnChange(state)
80
+ self.enableFileWatching(state)
81
+
82
+ def __filename__(self):
83
+ return self.filename()
84
+
85
+ def __font__(self):
86
+ if self.lexer():
87
+ return self.lexer().font(0)
88
+ else:
89
+ self.font()
90
+
91
+ def __set_font__(self, font):
92
+ self.documentFont = font
93
+ if self.lexer():
94
+ self.lexer().setFont(font)
95
+ else:
96
+ self.setFont(font)
97
+
98
+ def __goto_line__(self, line):
99
+ self.goToLine(line)
100
+
101
+ def __indentations_use_tabs__(self):
102
+ return self.indentationsUseTabs()
103
+
104
+ def __set_indentations_use_tabs__(self, state):
105
+ self.setIndentationsUseTabs(state)
106
+
107
+ def __insert_text__(self, txt):
108
+ self.insert(txt)
109
+
110
+ def __load__(self, filename):
111
+ self.load(filename)
112
+
113
+ def __margins_font__(self):
114
+ return self.marginsFont()
115
+
116
+ def __set_margins_font__(self, font):
117
+ self.setMarginsFont(font)
118
+
119
+ def __marker_add__(self, line):
120
+ try:
121
+ marker = self._marker
122
+ except AttributeError:
123
+ self._marker = self.markerDefine(self.Circle)
124
+ marker = self._marker
125
+ self.markerAdd(line, marker)
126
+
127
+ def __marker_clear_all__(self):
128
+ try:
129
+ self.markerDeleteAll(self._marker)
130
+ except AttributeError:
131
+ # self._marker has not been created yet
132
+ pass
133
+
134
+ def __reload_file__(self):
135
+ # loading the file too quickly misses any changes
136
+ time.sleep(0.1)
137
+ font = self.__font__()
138
+ self.reloadChange()
139
+ self.__set_font__(font)
140
+
141
+ def __remove_selected_text__(self):
142
+ self.removeSelectedText()
143
+
144
+ def __save__(self):
145
+ self.save()
146
+
147
+ def __selected_text__(self, start_of_line=False, selectText=False):
148
+ line, s, end, e = self.getSelection()
149
+ if line == -1:
150
+ # Nothing is selected, return the current line of text
151
+ line, index = self.getCursorPosition()
152
+ txt = self.text(line)
153
+
154
+ lineLength = len(self.text(line).rstrip())
155
+ selectText = self.window().uiSelectTextACT.isChecked() or selectText
156
+
157
+ if selectText:
158
+ self.setSelection(line, 0, line, lineLength)
159
+
160
+ elif start_of_line:
161
+ ss = self.positionFromLineIndex(line, 0)
162
+ ee = self.positionFromLineIndex(end, e)
163
+ txt = self.text(ss, ee)
164
+ else:
165
+ txt = self.selectedText()
166
+ return self.regex.split(txt)[0], line
167
+
168
+ def __tab_width__(self):
169
+ return self.tabWidth()
170
+
171
+ def __set_tab_width__(self, width):
172
+ self.setTabWidth(width)
173
+
174
+ def __text__(self, line=None, start=None, end=None):
175
+ """Returns the text in this widget, possibly limited in scope.
176
+
177
+ Note: Only pass line, or (start and end) to this method.
178
+
179
+ Args:
180
+ line (int, optional): Limit the returned scope to just this line number.
181
+ start (int, optional): Limit the scope to text between this and end.
182
+ end (int, optional): Limit the scope to text between start and this.
183
+
184
+ Returns:
185
+ str: The requested text.
186
+ """
187
+ if line:
188
+ return self.text(line)
189
+ elif (start is None) != (end is None):
190
+ raise ValueError('You must pass start and end if you pass either.')
191
+ elif start is not None:
192
+ self.text(start, end)
193
+ return self.text()
194
+
195
+ def __set_text__(self, txt):
196
+ """Replace all of the current text with txt."""
197
+ self.setText(txt)
198
+
199
+ @classmethod
200
+ def __write_file__(cls, filename, txt):
201
+ with io.open(filename, 'w', newline='\n') as fle:
202
+ # Save unix newlines for simplicity
203
+ fle.write(cls.__unix_end_lines__(txt))
204
+
205
+ def keyPressEvent(self, event):
206
+ """Check for certain keyboard shortcuts, and handle them as needed,
207
+ otherwise pass the keyPress to the superclass.
208
+
209
+ NOTE! We handle the "shift+return" shortcut here, rather than the
210
+ QAction's shortcut, because the workbox will always intercept that
211
+ shortcut. So, we handle it here, and call the main window's
212
+ execSelected, which ultimately calls this workbox's __exec_selected__.
213
+
214
+ Also note, it would make sense to have ctrl+Enter also execute without
215
+ truncation, but no modifiers are registered when Enter is pressed (unlike
216
+ when Return is pressed), so this combination is not detectable.
217
+ """
218
+ if self._software == 'softimage':
219
+ DocumentEditor.keyPressEvent(self, event)
220
+ else:
221
+ if self.process_shortcut(event):
222
+ return
223
+ else:
224
+ # Send regular keystroke
225
+ DocumentEditor.keyPressEvent(self, event)
226
+
227
+ def initShortcuts(self):
228
+ """Use this to set up shortcuts when the DocumentEditor"""
229
+ icon = QIcon(resourcePath('img/text-search-variant.png'))
230
+ self.uiFindACT = QAction(icon, 'Find...', self)
231
+ self.uiFindACT.setShortcut("Ctrl+F")
232
+ self.addAction(self.uiFindACT)
233
+
234
+ icon = QIcon(resourcePath('img/skip-previous.png'))
235
+ self.uiFindPrevACT = QAction(icon, 'Find Prev', self)
236
+ self.uiFindPrevACT.setShortcut("Ctrl+F3")
237
+ self.addAction(self.uiFindPrevACT)
238
+
239
+ icon = QIcon(resourcePath('img/skip-next.png'))
240
+ self.uiFindNextACT = QAction(icon, 'Find Next', self)
241
+ self.uiFindNextACT.setShortcut("F3")
242
+ self.addAction(self.uiFindNextACT)
243
+
244
+ self.uiSelectCurrentLineACT = QAction(icon, 'Select Line', self)
245
+ self.uiSelectCurrentLineACT.triggered.connect(self.expandCursorToLineSelection)
246
+ self.uiSelectCurrentLineACT.setShortcut('Ctrl+L')
247
+ self.addAction(self.uiSelectCurrentLineACT)
248
+
249
+ # create the search dialog and connect actions
250
+ self._searchDialog = FindDialog(self)
251
+ self._searchDialog.setAttribute(Qt.WA_DeleteOnClose, False)
252
+ self.uiFindACT.triggered.connect(
253
+ lambda: self._searchDialog.search(self.searchText())
254
+ )
255
+ self.uiFindPrevACT.triggered.connect(
256
+ lambda: self.findPrev(self.searchText(), self.searchFlags())
257
+ )
258
+ self.uiFindNextACT.triggered.connect(
259
+ lambda: self.findNext(self.searchText(), self.searchFlags())
260
+ )
261
+
262
+ def searchFlags(self):
263
+ return self._searchFlags
264
+
265
+ def searchText(self):
266
+ if not self._searchDialog:
267
+ return ''
268
+ # refresh the search text unless we are using regular expressions
269
+ if (
270
+ not self._searchDialog.isVisible()
271
+ and not self._searchFlags & SearchOptions.QRegExp
272
+ ):
273
+ txt = self.selectedText()
274
+ if txt:
275
+ self._searchText = txt
276
+ return self._searchText
277
+
278
+ def setSearchFlags(self, flags):
279
+ self._searchFlags = flags
280
+
281
+ def setSearchText(self, txt):
282
+ self._searchText = txt
283
+
284
+ def showMenu(self, pos):
285
+ menu = super(WorkboxWidget, self).showMenu(pos, popup=False)
286
+ menu.addSeparator()
287
+ submenu = menu.addMenu('Options')
288
+ act = submenu.addAction('Toggle end line visibility')
289
+ act.setCheckable(True)
290
+ act.setChecked(self.eolVisibility())
291
+ act.triggered.connect(self.setEolVisibility)
292
+
293
+ act = submenu.addAction('Show Whitespace')
294
+ act.setCheckable(True)
295
+ act.setChecked(self.showWhitespaces())
296
+ act.triggered.connect(self.setShowWhitespaces)
297
+
298
+ menu.popup(self._clickPos)
@@ -0,0 +1,52 @@
1
+ from __future__ import absolute_import
2
+
3
+ import json
4
+ import logging
5
+ import logging.config
6
+ import os
7
+
8
+ from .prefs import prefs_path
9
+
10
+
11
+ class LoggingConfig(object):
12
+ def __init__(self, core_name, version=1):
13
+ self._filename = None
14
+ self.cfg = {'version': version}
15
+ self.core_name = core_name
16
+
17
+ def add_logger(self, name, logger):
18
+ if not logger.level:
19
+ # No need to record a logger that is inheriting its logging level
20
+ return
21
+
22
+ # Build the required dictionaries
23
+ loggers = self.cfg.setdefault('loggers', {})
24
+ log = loggers.setdefault(name, {})
25
+ log['level'] = logger.level
26
+
27
+ def build(self):
28
+ self.add_logger("", logging.root)
29
+ for name, logger in logging.root.manager.loggerDict.items():
30
+ if not isinstance(logger, logging.PlaceHolder):
31
+ self.add_logger(name, logger)
32
+
33
+ @property
34
+ def filename(self):
35
+ if self._filename:
36
+ return self._filename
37
+
38
+ self._filename = prefs_path('logging_prefs.json', core_name=self.core_name)
39
+ return self._filename
40
+
41
+ def load(self):
42
+ if not os.path.exists(self.filename):
43
+ return False
44
+
45
+ with open(self.filename) as fle:
46
+ self.cfg = json.load(fle)
47
+ logging.config.dictConfig(self.cfg)
48
+ return True
49
+
50
+ def save(self):
51
+ with open(self.filename, 'w') as fle:
52
+ json.dump(self.cfg, fle, indent=4)