PrEditor 2.1.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.
Files changed (179) hide show
  1. preditor/__init__.py +315 -0
  2. preditor/__main__.py +13 -0
  3. preditor/about_module.py +165 -0
  4. preditor/cli.py +192 -0
  5. preditor/config.py +318 -0
  6. preditor/constants.py +13 -0
  7. preditor/contexts.py +210 -0
  8. preditor/cores/__init__.py +0 -0
  9. preditor/cores/core.py +20 -0
  10. preditor/dccs/.hab.json +10 -0
  11. preditor/dccs/maya/PrEditor_maya.mod +1 -0
  12. preditor/dccs/maya/README.md +22 -0
  13. preditor/dccs/maya/plug-ins/PrEditor_maya.py +141 -0
  14. preditor/dccs/studiomax/PackageContents.xml +32 -0
  15. preditor/dccs/studiomax/PrEditor-PrEditor_Show.mcr +8 -0
  16. preditor/dccs/studiomax/README.md +17 -0
  17. preditor/dccs/studiomax/preditor.ms +16 -0
  18. preditor/dccs/studiomax/preditor_menu.mnx +7 -0
  19. preditor/debug.py +149 -0
  20. preditor/delayable_engine/__init__.py +302 -0
  21. preditor/delayable_engine/delayables.py +85 -0
  22. preditor/enum.py +728 -0
  23. preditor/excepthooks.py +165 -0
  24. preditor/gui/__init__.py +56 -0
  25. preditor/gui/app.py +163 -0
  26. preditor/gui/codehighlighter.py +289 -0
  27. preditor/gui/completer.py +237 -0
  28. preditor/gui/console.py +605 -0
  29. preditor/gui/console_base.py +911 -0
  30. preditor/gui/dialog.py +181 -0
  31. preditor/gui/drag_tab_bar.py +625 -0
  32. preditor/gui/editor_chooser.py +57 -0
  33. preditor/gui/errordialog.py +69 -0
  34. preditor/gui/find_files.py +137 -0
  35. preditor/gui/fuzzy_search/__init__.py +0 -0
  36. preditor/gui/fuzzy_search/fuzzy_search.py +97 -0
  37. preditor/gui/group_tab_widget/__init__.py +0 -0
  38. preditor/gui/group_tab_widget/group_tab_widget.py +528 -0
  39. preditor/gui/group_tab_widget/grouped_tab_menu.py +35 -0
  40. preditor/gui/group_tab_widget/grouped_tab_models.py +107 -0
  41. preditor/gui/group_tab_widget/grouped_tab_widget.py +223 -0
  42. preditor/gui/group_tab_widget/one_tab_widget.py +96 -0
  43. preditor/gui/level_buttons.py +358 -0
  44. preditor/gui/logger_window_handler.py +77 -0
  45. preditor/gui/logger_window_plugin.py +35 -0
  46. preditor/gui/loggerwindow.py +2405 -0
  47. preditor/gui/newtabwidget.py +69 -0
  48. preditor/gui/output_console.py +11 -0
  49. preditor/gui/qtdesigner/__init__.py +21 -0
  50. preditor/gui/qtdesigner/_log_plugin.py +29 -0
  51. preditor/gui/qtdesigner/console_base_plugin.py +48 -0
  52. preditor/gui/qtdesigner/console_predit_plugin.py +48 -0
  53. preditor/gui/set_text_editor_path_dialog.py +61 -0
  54. preditor/gui/status_label.py +99 -0
  55. preditor/gui/suggest_path_quotes_dialog.py +50 -0
  56. preditor/gui/ui/editor_chooser.ui +93 -0
  57. preditor/gui/ui/errordialog.ui +74 -0
  58. preditor/gui/ui/find_files.ui +140 -0
  59. preditor/gui/ui/loggerwindow.ui +1909 -0
  60. preditor/gui/ui/set_text_editor_path_dialog.ui +189 -0
  61. preditor/gui/ui/suggest_path_quotes_dialog.ui +225 -0
  62. preditor/gui/window.py +161 -0
  63. preditor/gui/workbox_mixin.py +1139 -0
  64. preditor/gui/workbox_text_edit.py +136 -0
  65. preditor/gui/workboxwidget.py +315 -0
  66. preditor/logging_config.py +55 -0
  67. preditor/osystem.py +401 -0
  68. preditor/plugins.py +118 -0
  69. preditor/prefs.py +381 -0
  70. preditor/resource/environment_variables.html +26 -0
  71. preditor/resource/error_mail.html +85 -0
  72. preditor/resource/error_mail_inline.html +41 -0
  73. preditor/resource/img/README.md +17 -0
  74. preditor/resource/img/arrow_forward.png +0 -0
  75. preditor/resource/img/check-bold.png +0 -0
  76. preditor/resource/img/chevron-down.png +0 -0
  77. preditor/resource/img/chevron-up.png +0 -0
  78. preditor/resource/img/close-thick.png +0 -0
  79. preditor/resource/img/comment-edit.png +0 -0
  80. preditor/resource/img/content-copy.png +0 -0
  81. preditor/resource/img/content-cut.png +0 -0
  82. preditor/resource/img/content-duplicate.png +0 -0
  83. preditor/resource/img/content-paste.png +0 -0
  84. preditor/resource/img/content-save.png +0 -0
  85. preditor/resource/img/debug_disabled.png +0 -0
  86. preditor/resource/img/eye-check.png +0 -0
  87. preditor/resource/img/file-plus.png +0 -0
  88. preditor/resource/img/file-remove.png +0 -0
  89. preditor/resource/img/format-align-left.png +0 -0
  90. preditor/resource/img/format-letter-case-lower.png +0 -0
  91. preditor/resource/img/format-letter-case-upper.png +0 -0
  92. preditor/resource/img/format-letter-case.svg +1 -0
  93. preditor/resource/img/information.png +0 -0
  94. preditor/resource/img/logging_critical.png +0 -0
  95. preditor/resource/img/logging_custom.png +0 -0
  96. preditor/resource/img/logging_debug.png +0 -0
  97. preditor/resource/img/logging_error.png +0 -0
  98. preditor/resource/img/logging_info.png +0 -0
  99. preditor/resource/img/logging_not_set.png +0 -0
  100. preditor/resource/img/logging_warning.png +0 -0
  101. preditor/resource/img/marker.png +0 -0
  102. preditor/resource/img/play.png +0 -0
  103. preditor/resource/img/playlist-play.png +0 -0
  104. preditor/resource/img/plus-minus-variant.png +0 -0
  105. preditor/resource/img/preditor.ico +0 -0
  106. preditor/resource/img/preditor.png +0 -0
  107. preditor/resource/img/preditor.psd +0 -0
  108. preditor/resource/img/preditor.svg +44 -0
  109. preditor/resource/img/regex.svg +1 -0
  110. preditor/resource/img/restart.svg +1 -0
  111. preditor/resource/img/skip-forward-outline.png +0 -0
  112. preditor/resource/img/skip-next-outline.png +0 -0
  113. preditor/resource/img/skip-next.png +0 -0
  114. preditor/resource/img/skip-previous.png +0 -0
  115. preditor/resource/img/subdirectory-arrow-right.png +0 -0
  116. preditor/resource/img/text-search-variant.png +0 -0
  117. preditor/resource/img/warning-big.png +0 -0
  118. preditor/resource/lang/python.json +30 -0
  119. preditor/resource/pref_updates/pref_updates.json +17 -0
  120. preditor/resource/settings.ini +25 -0
  121. preditor/resource/stylesheet/Bright.css +76 -0
  122. preditor/resource/stylesheet/Dark.css +210 -0
  123. preditor/scintilla/__init__.py +40 -0
  124. preditor/scintilla/delayables/__init__.py +11 -0
  125. preditor/scintilla/delayables/smart_highlight.py +97 -0
  126. preditor/scintilla/delayables/spell_check.py +174 -0
  127. preditor/scintilla/documenteditor.py +1924 -0
  128. preditor/scintilla/finddialog.py +68 -0
  129. preditor/scintilla/lang/__init__.py +80 -0
  130. preditor/scintilla/lang/config/bash.ini +15 -0
  131. preditor/scintilla/lang/config/batch.ini +14 -0
  132. preditor/scintilla/lang/config/cpp.ini +19 -0
  133. preditor/scintilla/lang/config/css.ini +19 -0
  134. preditor/scintilla/lang/config/eyeonscript.ini +17 -0
  135. preditor/scintilla/lang/config/html.ini +21 -0
  136. preditor/scintilla/lang/config/javascript.ini +24 -0
  137. preditor/scintilla/lang/config/lua.ini +16 -0
  138. preditor/scintilla/lang/config/maxscript.ini +20 -0
  139. preditor/scintilla/lang/config/mel.ini +18 -0
  140. preditor/scintilla/lang/config/mu.ini +22 -0
  141. preditor/scintilla/lang/config/nsi.ini +19 -0
  142. preditor/scintilla/lang/config/perl.ini +19 -0
  143. preditor/scintilla/lang/config/puppet.ini +19 -0
  144. preditor/scintilla/lang/config/python.ini +28 -0
  145. preditor/scintilla/lang/config/ruby.ini +19 -0
  146. preditor/scintilla/lang/config/sql.ini +7 -0
  147. preditor/scintilla/lang/config/xml.ini +21 -0
  148. preditor/scintilla/lang/config/yaml.ini +18 -0
  149. preditor/scintilla/lang/language.py +240 -0
  150. preditor/scintilla/lexers/__init__.py +0 -0
  151. preditor/scintilla/lexers/cpplexer.py +22 -0
  152. preditor/scintilla/lexers/javascriptlexer.py +27 -0
  153. preditor/scintilla/lexers/maxscriptlexer.py +235 -0
  154. preditor/scintilla/lexers/mellexer.py +369 -0
  155. preditor/scintilla/lexers/mulexer.py +33 -0
  156. preditor/scintilla/lexers/pythonlexer.py +42 -0
  157. preditor/scintilla/ui/finddialog.ui +160 -0
  158. preditor/settings.py +71 -0
  159. preditor/stream/__init__.py +72 -0
  160. preditor/stream/console_handler.py +169 -0
  161. preditor/stream/director.py +144 -0
  162. preditor/stream/manager.py +97 -0
  163. preditor/streamhandler_helper.py +46 -0
  164. preditor/utils/__init__.py +191 -0
  165. preditor/utils/call_stack.py +86 -0
  166. preditor/utils/cute.py +106 -0
  167. preditor/utils/stylesheets.py +54 -0
  168. preditor/utils/text_search.py +338 -0
  169. preditor/version.py +34 -0
  170. preditor/weakref.py +363 -0
  171. preditor-2.1.0.dist-info/METADATA +308 -0
  172. preditor-2.1.0.dist-info/RECORD +179 -0
  173. preditor-2.1.0.dist-info/WHEEL +5 -0
  174. preditor-2.1.0.dist-info/entry_points.txt +19 -0
  175. preditor-2.1.0.dist-info/licenses/LICENSE +165 -0
  176. preditor-2.1.0.dist-info/top_level.txt +3 -0
  177. tests/encodings/test_ecoding.py +33 -0
  178. tests/find_files/test_find_files.py +74 -0
  179. tests/ide/test_delayable_engine.py +171 -0
@@ -0,0 +1,240 @@
1
+ from __future__ import absolute_import, print_function
2
+
3
+ import re
4
+ import sys
5
+
6
+ try:
7
+ from configparser import ConfigParser
8
+ except ImportError:
9
+ from ConfigParser import ConfigParser
10
+
11
+ from .. import Qsci
12
+
13
+
14
+ class MethodDescriptor(object):
15
+ def __init__(self, dtype, expr):
16
+ self.dtype = dtype
17
+ self.exprText = expr
18
+ try:
19
+ self.expr = re.compile(expr, re.DOTALL | re.MULTILINE)
20
+ except Exception:
21
+ print('error generating expression', expr)
22
+ self.expr = None
23
+
24
+ def search(self, text, startpos=-1):
25
+ if not self.expr:
26
+ return None
27
+
28
+ if startpos != -1:
29
+ return self.expr.search(text, startpos)
30
+ else:
31
+ return self.expr.search(text)
32
+
33
+
34
+ class Language(object):
35
+ def __init__(self):
36
+ self._name = ''
37
+ self._fileTypes = []
38
+
39
+ # lexer class information
40
+ self._lexerClass = -1
41
+ self._lexerClassName = ''
42
+ self._lexerModule = ''
43
+ self._lexerColorTypes = {}
44
+ self._custom = False
45
+ self._sourcefile = ''
46
+
47
+ # comment information
48
+ self._lineComment = ''
49
+
50
+ # method descriptors
51
+ self._descriptors = []
52
+
53
+ def addDescriptor(self, type, expr):
54
+ self._descriptors.append(MethodDescriptor(type, expr))
55
+
56
+ def createLexer(self, parent=None):
57
+ # create an instance of the lexer
58
+ cls = self.lexerClass()
59
+ if not cls:
60
+ return None
61
+
62
+ output = cls(parent)
63
+ if output and parent:
64
+ output.setFont(parent.font())
65
+ return output
66
+
67
+ def descriptors(self):
68
+ return self._descriptors
69
+
70
+ def isCustom(self):
71
+ return self._custom
72
+
73
+ def name(self):
74
+ return self._name
75
+
76
+ def lexerColorTypes(self):
77
+ return self._lexerColorTypes
78
+
79
+ def lineComment(self):
80
+ return self._lineComment
81
+
82
+ def fileTypes(self):
83
+ return self._fileTypes
84
+
85
+ def lexerClass(self):
86
+ if self._lexerClass == -1:
87
+ # use a custom lexer module
88
+ if self._lexerModule:
89
+ # retrieve the lexer module
90
+ module = sys.modules.get(self._lexerModule)
91
+
92
+ # try to import the module
93
+ if not module:
94
+ try:
95
+ __import__(self._lexerModule)
96
+ module = sys.modules.get(self._lexerModule)
97
+ except Exception:
98
+ print(
99
+ (
100
+ '[preditor.scintilla.lexers.Language.createLexer() '
101
+ 'Error] Could not import %s module'
102
+ )
103
+ % self._lexerModule
104
+ )
105
+ self._lexerClass = None
106
+ return None
107
+
108
+ # otherwise, its in the Qsci module
109
+ else:
110
+ module = Qsci
111
+
112
+ # retrieve the lexer class
113
+ self._lexerClass = module.__dict__.get(self._lexerClassName)
114
+ if not self._lexerClass:
115
+ print(
116
+ (
117
+ '[preditor.scintilla.lexers.Language.createLexer() Error] '
118
+ 'No %s class in %s'
119
+ )
120
+ % (self._lexerClassName, module.__name__)
121
+ )
122
+
123
+ return self._lexerClass
124
+
125
+ def lexerClassName(self):
126
+ return self._lexerClassName
127
+
128
+ def lexerModule(self):
129
+ return self._lexerModule
130
+
131
+ def save(self, filename=''):
132
+ if not filename:
133
+ filename = self.filename()
134
+ if not filename:
135
+ return False
136
+
137
+ parser = ConfigParser()
138
+ parser.add_section('GLOBALS')
139
+ parser.set('GLOBALS', 'name', self.name())
140
+ parser.set('GLOBALS', 'filetypes', ';'.join(self.fileTypes()))
141
+ # quotes are to preserve spaces which configparser strips out
142
+ parser.set('GLOBALS', 'linecomment', '"{}"'.format(self.lineComment()))
143
+
144
+ parser.add_section('LEXER')
145
+ parser.set('LEXER', 'class', self.lexerClassName())
146
+ parser.set('LEXER', 'module', self.lexerModule())
147
+
148
+ parser.add_section('DESCRIPTORS')
149
+ for i, desc in enumerate(self._descriptors):
150
+ parser.set('DESCRIPTORS', '%s%i' % (desc.dtype, i), desc.exprText)
151
+
152
+ parser.add_section('COLOR_TYPES')
153
+ for key, value in self.lexerColorTypes().items():
154
+ parser.set('COLOR_TYPES', key, ','.join([str(val) for val in value]))
155
+
156
+ # save the language
157
+ f = open(filename, 'w')
158
+ parser.write(f)
159
+ f.close()
160
+
161
+ self._sourcefile = filename
162
+ return True
163
+
164
+ def setCustom(self, state):
165
+ self._custom = state
166
+
167
+ def setFileTypes(self, fileTypes):
168
+ self._fileTypes = fileTypes
169
+
170
+ def setLexerClassName(self, className):
171
+ self._lexerClassName = className
172
+
173
+ def setLexerModule(self, module):
174
+ self._lexerModule = module
175
+
176
+ def setLineComment(self, lineComment):
177
+ self._lineComment = lineComment
178
+
179
+ def setLexerColorTypes(self, lexerColorTypes):
180
+ self._lexerColorTypes = lexerColorTypes
181
+
182
+ def setName(self, name):
183
+ self._name = name
184
+
185
+ def sourcefile(self):
186
+ return self._sourcefile
187
+
188
+ @staticmethod
189
+ def fromConfig(filename):
190
+ parser = ConfigParser()
191
+
192
+ if not parser.read(filename):
193
+ return False
194
+
195
+ plugin = Language()
196
+ plugin._name = parser.get('GLOBALS', 'name')
197
+ plugin._fileTypes = parser.get('GLOBALS', 'filetypes').split(';')
198
+
199
+ # try to load the line comment information
200
+ try:
201
+ plugin._lineComment = parser.get('GLOBALS', 'linecomment').strip('"')
202
+ except Exception:
203
+ pass
204
+
205
+ # try to load the lexer information
206
+ try:
207
+ plugin._lexerClassName = parser.get('LEXER', 'class')
208
+ plugin._lexerModule = parser.get('LEXER', 'module')
209
+ except Exception:
210
+ pass
211
+
212
+ # load the different descriptor options
213
+ try:
214
+ options = parser.options('DESCRIPTORS')
215
+ except Exception:
216
+ options = []
217
+
218
+ for option in options:
219
+ expr = parser.get('DESCRIPTORS', option)
220
+ option = re.match(r'([^\d]*)\d*', option).groups()[0]
221
+ plugin._descriptors.append(MethodDescriptor(option, expr))
222
+
223
+ # load the different color map options
224
+ try:
225
+ options = parser.options('COLOR_TYPES')
226
+ except Exception:
227
+ options = []
228
+
229
+ for option in options:
230
+ vals = []
231
+ for val in parser.get('COLOR_TYPES', option).split(','):
232
+ try:
233
+ vals.append(int(val))
234
+ except Exception:
235
+ pass
236
+ plugin._lexerColorTypes[option] = vals
237
+
238
+ plugin._sourcefile = filename
239
+
240
+ return plugin
File without changes
@@ -0,0 +1,22 @@
1
+ from __future__ import absolute_import
2
+
3
+ from Qt.QtGui import QColor
4
+
5
+ from .. import Qsci
6
+
7
+
8
+ class CppLexer(Qsci.QsciLexerCPP):
9
+ # Items in this list will be highlighted using the color for self.KeywordSet2
10
+ highlightedKeywords = ''
11
+
12
+ def defaultPaper(self, style):
13
+ if style == self.CommentLine:
14
+ # Set the highlight color for this lexer
15
+ return QColor(155, 255, 155)
16
+ return super(CppLexer, self).defaultPaper(style)
17
+
18
+ def keywords(self, style):
19
+ # Words to be highlighted
20
+ if style == self.CommentLine and self.highlightedKeywords:
21
+ return self.highlightedKeywords
22
+ return super(CppLexer, self).keywords(style)
@@ -0,0 +1,27 @@
1
+ from __future__ import absolute_import
2
+
3
+ from Qt.QtGui import QColor
4
+
5
+ from .. import Qsci
6
+
7
+
8
+ class JavaScriptLexer(Qsci.QsciLexerJavaScript):
9
+ # Items in this list will be highlighted using the color for
10
+ # `Qsci.QsciLexerJavaScript.KeywordSet2`
11
+ highlightedKeywords = ''
12
+
13
+ def defaultFont(self, index):
14
+ # HACK: TODO: I should probably preserve the existing fonts
15
+ return self.font(0)
16
+
17
+ def defaultPaper(self, style):
18
+ if style == Qsci.QsciLexerJavaScript.KeywordSet2:
19
+ # Set the highlight color for this lexer
20
+ return QColor(155, 255, 155)
21
+ return super(JavaScriptLexer, self).defaultPaper(style)
22
+
23
+ def keywords(self, style):
24
+ # Words to be highlighted
25
+ if style == 2 and self.highlightedKeywords:
26
+ return self.highlightedKeywords
27
+ return super(JavaScriptLexer, self).keywords(style)
@@ -0,0 +1,235 @@
1
+ from __future__ import absolute_import
2
+
3
+ import re
4
+ from builtins import str as text
5
+
6
+ from future.utils import iteritems
7
+
8
+ from .. import Qsci, QsciScintilla
9
+
10
+ MS_KEYWORDS = """
11
+ if then else not and or key collect
12
+ do while for in with where
13
+ function fn rollout struct parameters attributes exit continue
14
+ local global
15
+ true false
16
+ ok undefined unsupplied return
17
+ filein open close flush include print
18
+ """
19
+
20
+
21
+ class MaxscriptLexer(Qsci.QsciLexerCustom):
22
+ # Items in this list will be highligheded using the color for self.SmartHighlight
23
+ highlightedKeywords = ''
24
+
25
+ def __init__(self, parent=None):
26
+ super(MaxscriptLexer, self).__init__(parent)
27
+ self._styles = {
28
+ 0: 'Default',
29
+ 1: 'Comment',
30
+ 2: 'CommentLine',
31
+ 3: 'Keyword',
32
+ 4: 'Operator',
33
+ 5: 'Number',
34
+ 6: 'String',
35
+ 7: 'SmartHighlight',
36
+ }
37
+
38
+ for key, value in iteritems(self._styles):
39
+ setattr(self, value, key)
40
+
41
+ def description(self, style):
42
+ return self._styles.get(style, '')
43
+
44
+ def defaultColor(self, style):
45
+ from Qt.QtCore import Qt
46
+ from Qt.QtGui import QColor
47
+
48
+ if style in (self.Comment, self.CommentLine):
49
+ return QColor(40, 160, 40)
50
+
51
+ elif style in (self.Keyword, self.Operator):
52
+ return QColor(Qt.GlobalColor.blue)
53
+
54
+ elif style == self.Number:
55
+ return QColor(Qt.GlobalColor.red)
56
+
57
+ elif style == self.String:
58
+ return QColor(180, 140, 30)
59
+
60
+ return super(MaxscriptLexer, self).defaultColor(style)
61
+
62
+ def defaultPaper(self, style):
63
+ if style == self.SmartHighlight:
64
+ from Qt.QtGui import QColor
65
+
66
+ # Set the highlight color for this lexer
67
+ return QColor(155, 255, 155)
68
+ return super(MaxscriptLexer, self).defaultPaper(style)
69
+
70
+ def font(self, style):
71
+ font = super(MaxscriptLexer, self).font(style)
72
+ if style in (self.Comment, self.CommentLine):
73
+ font.setFamily('Arial Bold')
74
+ return font
75
+
76
+ def keywords(self, style):
77
+ if style == self.Keyword:
78
+ return MS_KEYWORDS
79
+ if style == self.SmartHighlight:
80
+ return self.highlightedKeywords
81
+ return super(MaxscriptLexer, self).keywords(style)
82
+
83
+ def processChunk(self, chunk, lastState, keywords):
84
+ # process the length of the chunk
85
+ if isinstance(chunk, bytearray):
86
+ chunk = chunk.decode('utf8')
87
+ length = len(chunk)
88
+
89
+ # check to see if our last state was a block comment
90
+ if lastState == self.Comment:
91
+ pos = chunk.find('*/')
92
+ if pos != -1:
93
+ self.setStyling(pos + 2, self.Comment)
94
+ return self.processChunk(chunk[pos + 2 :], self.Default, keywords)
95
+ else:
96
+ self.setStyling(length, self.Comment)
97
+ return (self.Comment, 0)
98
+
99
+ # check to see if our last state was a string
100
+ elif lastState == self.String:
101
+ # remove special case backslashes
102
+ while r'\\' in chunk:
103
+ chunk = chunk.replace(r'\\', '||')
104
+
105
+ # remove special case strings
106
+ while r'\"' in chunk:
107
+ chunk = chunk.replace(r'\"', r"\'")
108
+
109
+ pos = chunk.find('"')
110
+ if pos != -1:
111
+ self.setStyling(pos + 1, self.String)
112
+ return self.processChunk(chunk[pos + 1 :], self.Default, keywords)
113
+ else:
114
+ self.setStyling(length, self.String)
115
+ return (self.String, 0)
116
+
117
+ # otherwise, process a default chunk
118
+ else:
119
+ blockpos = chunk.find('/*')
120
+ linepos = chunk.find('--')
121
+ strpos = chunk.find('"')
122
+ order = [blockpos, linepos, strpos]
123
+ order.sort()
124
+
125
+ # any of the above symbols will affect how a symbol following it is treated,
126
+ # so make sure we process in the proper order
127
+ for i in order:
128
+ if i == -1:
129
+ continue
130
+
131
+ # process a string
132
+ if i == strpos:
133
+ state, folding = self.processChunk(chunk[:i], lastState, keywords)
134
+ self.setStyling(1, self.String)
135
+ newstate, newfolding = self.processChunk(
136
+ chunk[i + 1 :], self.String, keywords
137
+ )
138
+ return (newstate, newfolding + folding)
139
+
140
+ # process a line comment
141
+ elif i == linepos:
142
+ state, folding = self.processChunk(chunk[:i], lastState, keywords)
143
+ self.setStyling(length - i, self.CommentLine)
144
+ return (self.Default, folding)
145
+
146
+ # process a block comment
147
+ elif i == blockpos:
148
+ state, folding = self.processChunk(chunk[:i], lastState, keywords)
149
+ self.setStyling(2, self.Comment)
150
+ newstate, newfolding = self.processChunk(
151
+ chunk[i + 2 :], self.Comment, keywords
152
+ )
153
+ return (newstate, newfolding + folding)
154
+
155
+ # otherwise, we are processing a default set of text whose syntaxing is
156
+ # irrelavent from the previous one TODO: this needs to handle QStrings.
157
+ # However I do not thing QStrings are the problem, its more likely a
158
+ # bytearray problem. the conversion at the start of this function may have
159
+ # resolved it.
160
+ results = self.chunkRegex.findall(chunk)
161
+ for space, kwd in results:
162
+ if not (space or kwd):
163
+ break
164
+
165
+ self.setStyling(len(space), self.Default)
166
+
167
+ if kwd.lower() in self.hlkwords:
168
+ self.setStyling(len(kwd), self.SmartHighlight)
169
+ elif kwd.lower() in keywords:
170
+ self.setStyling(len(kwd), self.Keyword)
171
+ else:
172
+ self.setStyling(len(kwd), self.Default)
173
+
174
+ # in this context, look for opening and closing parenthesis which will
175
+ # determine folding scope
176
+ return (self.Default, chunk.count('(') - chunk.count(')'))
177
+
178
+ def styleText(self, start, end):
179
+ editor = self.editor()
180
+ if not editor:
181
+ return
182
+
183
+ # scintilla works with encoded bytes, not decoded characters
184
+ # this matters if the source contains non-ascii characters and
185
+ # a multi-byte encoding is used (e.g. utf-8)
186
+ source = ''
187
+ if end > editor.length():
188
+ end = editor.length()
189
+
190
+ # define commonly used methods
191
+ SCI = editor.SendScintilla
192
+ SETFOLDLEVEL = QsciScintilla.SCI_SETFOLDLEVEL
193
+ HEADERFLAG = QsciScintilla.SC_FOLDLEVELHEADERFLAG
194
+ CURRFOLDLEVEL = QsciScintilla.SC_FOLDLEVELBASE
195
+
196
+ if end > start:
197
+ source = bytearray(end - start)
198
+ editor.SendScintilla(editor.SCI_GETTEXTRANGE, start, end, source)
199
+
200
+ if not source:
201
+ return
202
+ self.parent().blockSignals(True)
203
+
204
+ # the line index will also need to implement folding
205
+ index = editor.SendScintilla(editor.SCI_LINEFROMPOSITION, start)
206
+ if index > 0:
207
+ # the previous state may be needed for multi-line styling
208
+ pos = editor.SendScintilla(editor.SCI_GETLINEENDPOSITION, index - 1)
209
+ lastState = editor.SendScintilla(editor.SCI_GETSTYLEAT, pos)
210
+ else:
211
+ lastState = self.Default
212
+
213
+ self.startStyling(start, 0x1F)
214
+
215
+ # cache objects used by processChunk that do not need updated every time it is
216
+ # called
217
+ self.hlkwords = set(text(self.keywords(self.SmartHighlight)).lower().split())
218
+ self.chunkRegex = re.compile('([^A-Za-z0-9]*)([A-Za-z0-9]*)')
219
+ kwrds = set(MS_KEYWORDS.split())
220
+
221
+ # scintilla always asks to style whole lines
222
+ for line in source.splitlines(True):
223
+ lastState, folding = self.processChunk(line, lastState, kwrds)
224
+
225
+ # open folding levels
226
+ if folding > 0:
227
+ SCI(SETFOLDLEVEL, index, CURRFOLDLEVEL | HEADERFLAG)
228
+ CURRFOLDLEVEL += folding
229
+ else:
230
+ SCI(SETFOLDLEVEL, index, CURRFOLDLEVEL)
231
+ CURRFOLDLEVEL += folding
232
+
233
+ # folding implementation goes here
234
+ index += 1
235
+ self.parent().blockSignals(False)