]>
Commit | Line | Data |
---|---|---|
1f780e48 RD |
1 | #---------------------------------------------------------------------------- |
2 | # Name: PHPEditor.py | |
3 | # Purpose: PHP Script Editor for pydocview tbat uses the Styled Text Control | |
4 | # | |
5 | # Author: Morgan Hua | |
6 | # | |
7 | # Created: 1/4/04 | |
8 | # CVS-ID: $Id$ | |
9 | # Copyright: (c) 2005 ActiveGrid, Inc. | |
10 | # License: wxWindows License | |
11 | #---------------------------------------------------------------------------- | |
12 | ||
13 | import wx | |
14 | import string | |
15 | import STCTextEditor | |
16 | import CodeEditor | |
17 | import OutlineService | |
18 | import os | |
19 | import re | |
20 | ||
21 | ||
22 | class PHPDocument(CodeEditor.CodeDocument): | |
23 | ||
24 | pass | |
25 | ||
26 | ||
27 | class PHPView(CodeEditor.CodeView): | |
28 | ||
29 | ||
30 | def GetCtrlClass(self): | |
31 | """ Used in split window to instantiate new instances """ | |
32 | return PHPCtrl | |
33 | ||
34 | ||
35 | def GetAutoCompleteHint(self): | |
36 | pos = self.GetCtrl().GetCurrentPos() | |
37 | if pos == 0: | |
38 | return None, None | |
39 | ||
40 | validLetters = string.letters + string.digits + '_$' | |
41 | word = '' | |
42 | while (True): | |
43 | pos = pos - 1 | |
44 | if pos < 0: | |
45 | break | |
46 | char = chr(self.GetCtrl().GetCharAt(pos)) | |
47 | if char not in validLetters: | |
48 | break | |
49 | word = char + word | |
50 | ||
51 | return None, word | |
52 | ||
53 | ||
54 | def GetAutoCompleteDefaultKeywords(self): | |
55 | return PHPKEYWORDS | |
56 | ||
57 | #---------------------------------------------------------------------------- | |
58 | # Methods for OutlineService | |
59 | #---------------------------------------------------------------------------- | |
60 | ||
61 | def DoLoadOutlineCallback(self, force=False): | |
62 | outlineService = wx.GetApp().GetService(OutlineService.OutlineService) | |
63 | if not outlineService: | |
64 | return False | |
65 | ||
66 | outlineView = outlineService.GetView() | |
67 | if not outlineView: | |
68 | return False | |
69 | ||
70 | treeCtrl = outlineView.GetTreeCtrl() | |
71 | if not treeCtrl: | |
72 | return False | |
73 | ||
74 | view = treeCtrl.GetCallbackView() | |
75 | newCheckSum = self.GenCheckSum() | |
76 | if not force: | |
77 | if view and view is self: | |
78 | if self._checkSum == newCheckSum: | |
79 | return False | |
80 | self._checkSum = newCheckSum | |
81 | ||
82 | treeCtrl.DeleteAllItems() | |
83 | ||
84 | document = self.GetDocument() | |
85 | if not document: | |
86 | return True | |
87 | ||
88 | filename = document.GetFilename() | |
89 | if filename: | |
90 | rootItem = treeCtrl.AddRoot(os.path.basename(filename)) | |
91 | treeCtrl.SetDoSelectCallback(rootItem, self, None) | |
92 | else: | |
93 | return True | |
94 | ||
95 | text = self.GetValue() | |
96 | if not text: | |
97 | return True | |
98 | ||
99 | INTERFACE_PATTERN = 'interface[ \t]+\w+' | |
100 | CLASS_PATTERN = '((final|abstract)[ \t]+)?((public|private|protected)[ \t]+)?(static[ \t]+)?class[ \t]+\w+((implements|extends)\w+)?' | |
101 | FUNCTION_PATTERN = '(abstract[ \t]+)?((public|private|protected)[ \t]+)?(static[ \t]+)?function[ \t]+?\w+\(.*?\)' | |
102 | interfacePat = re.compile(INTERFACE_PATTERN, re.M|re.S) | |
103 | classPat = re.compile(CLASS_PATTERN, re.M|re.S) | |
104 | funcPat= re.compile(FUNCTION_PATTERN, re.M|re.S) | |
105 | pattern = re.compile('^[ \t]*('+ CLASS_PATTERN + '.*?{|' + FUNCTION_PATTERN + '|' + INTERFACE_PATTERN +'\s*?{).*?$', re.M|re.S) | |
106 | ||
107 | iter = pattern.finditer(text) | |
108 | indentStack = [(0, rootItem)] | |
109 | for pattern in iter: | |
110 | line = pattern.string[pattern.start(0):pattern.end(0)] | |
111 | foundLine = classPat.search(line) | |
112 | if foundLine: | |
113 | indent = foundLine.start(0) | |
114 | itemStr = foundLine.string[foundLine.start(0):foundLine.end(0)] | |
115 | else: | |
116 | foundLine = funcPat.search(line) | |
117 | if foundLine: | |
118 | indent = foundLine.start(0) | |
119 | itemStr = foundLine.string[foundLine.start(0):foundLine.end(0)] | |
120 | else: | |
121 | foundLine = interfacePat.search(line) | |
122 | if foundLine: | |
123 | indent = foundLine.start(0) | |
124 | itemStr = foundLine.string[foundLine.start(0):foundLine.end(0)] | |
125 | ||
126 | if indent == 0: | |
127 | parentItem = rootItem | |
128 | else: | |
129 | lastItem = indentStack.pop() | |
130 | while lastItem[0] >= indent: | |
131 | lastItem = indentStack.pop() | |
132 | indentStack.append(lastItem) | |
133 | parentItem = lastItem[1] | |
134 | ||
135 | item = treeCtrl.AppendItem(parentItem, itemStr) | |
136 | treeCtrl.SetDoSelectCallback(item, self, (pattern.end(0), pattern.start(0) + indent)) # select in reverse order because we want the cursor to be at the start of the line so it wouldn't scroll to the right | |
137 | indentStack.append((indent, item)) | |
138 | ||
139 | treeCtrl.Expand(rootItem) | |
140 | ||
141 | return True | |
142 | ||
143 | ||
144 | class PHPService(CodeEditor.CodeService): | |
145 | ||
146 | ||
147 | def __init__(self): | |
148 | CodeEditor.CodeService.__init__(self) | |
149 | ||
150 | ||
151 | class PHPCtrl(CodeEditor.CodeCtrl): | |
152 | ||
153 | ||
26ee3a06 RD |
154 | def __init__(self, parent, id=-1, style=wx.NO_FULL_REPAINT_ON_RESIZE): |
155 | CodeEditor.CodeCtrl.__init__(self, parent, id, style) | |
6f1a3f9c | 156 | self.SetLexer(wx.stc.STC_LEX_PHP) |
1f780e48 RD |
157 | self.SetStyleBits(7) |
158 | self.SetKeyWords(4, string.join(PHPKEYWORDS)) | |
159 | self.SetProperty("fold.html", "1") | |
160 | ||
161 | ||
162 | def CanWordWrap(self): | |
163 | return True | |
164 | ||
165 | ||
166 | def SetViewDefaults(self): | |
167 | CodeEditor.CodeCtrl.SetViewDefaults(self, configPrefix = "PHP", hasWordWrap = True, hasTabs = True) | |
168 | ||
169 | ||
170 | def GetFontAndColorFromConfig(self): | |
171 | return CodeEditor.CodeCtrl.GetFontAndColorFromConfig(self, configPrefix = "PHP") | |
172 | ||
173 | ||
174 | def UpdateStyles(self): | |
175 | CodeEditor.CodeCtrl.UpdateStyles(self) | |
176 | ||
177 | if not self.GetFont(): | |
178 | return | |
179 | ||
180 | faces = { 'font' : self.GetFont().GetFaceName(), | |
181 | 'size' : self.GetFont().GetPointSize(), | |
182 | 'size2': self.GetFont().GetPointSize() - 2, | |
183 | 'color' : "%02x%02x%02x" % (self.GetFontColor().Red(), self.GetFontColor().Green(), self.GetFontColor().Blue()) | |
184 | } | |
185 | ||
186 | ||
187 | # HTML Styles | |
188 | # White space | |
189 | self.StyleSetSpec(wx.stc.STC_H_DEFAULT, "face:%(font)s,fore:#000000,face:%(font)s,size:%(size)d" % faces) | |
190 | # Comment | |
191 | self.StyleSetSpec(wx.stc.STC_H_COMMENT, "face:%(font)s,fore:#007F00,italic,face:%(font)s,size:%(size)d" % faces) | |
192 | # Number | |
193 | self.StyleSetSpec(wx.stc.STC_H_NUMBER, "face:%(font)s,fore:#007F7F,size:%(size)d" % faces) | |
194 | # String | |
195 | self.StyleSetSpec(wx.stc.STC_H_SINGLESTRING, "face:%(font)s,fore:#7F007F,face:%(font)s,size:%(size)d" % faces) | |
196 | self.StyleSetSpec(wx.stc.STC_H_DOUBLESTRING, "face:%(font)s,fore:#7F007F,face:%(font)s,size:%(size)d" % faces) | |
197 | # Tag | |
198 | self.StyleSetSpec(wx.stc.STC_H_TAG, "face:%(font)s,fore:#00007F,bold,size:%(size)d" % faces) | |
199 | # Attributes | |
200 | self.StyleSetSpec(wx.stc.STC_H_ATTRIBUTE, "face:%(font)s,fore:#00007F,bold,size:%(size)d" % faces) | |
201 | ||
202 | ||
203 | # PHP Styles | |
204 | self.StyleSetSpec(wx.stc.STC_HPHP_DEFAULT, "face:%(font)s,fore:#000000,face:%(font)s,size:%(size)d" % faces) | |
205 | self.StyleSetSpec(wx.stc.STC_HPHP_COMMENT, "face:%(font)s,fore:#007F00,italic,face:%(font)s,size:%(size)d" % faces) | |
206 | self.StyleSetSpec(wx.stc.STC_HPHP_COMMENTLINE, "face:%(font)s,fore:#007F00,italic,face:%(font)s,size:%(size)d" % faces) | |
207 | self.StyleSetSpec(wx.stc.STC_HPHP_NUMBER, "face:%(font)s,fore:#007F7F,size:%(size)d" % faces) | |
208 | self.StyleSetSpec(wx.stc.STC_HPHP_SIMPLESTRING, "face:%(font)s,fore:#7F007F,size:%(size)d" % faces) | |
209 | self.StyleSetSpec(wx.stc.STC_HPHP_HSTRING, "face:%(font)s,fore7F007F,face:%(font)s,size:%(size)d" % faces) | |
210 | self.StyleSetSpec(wx.stc.STC_HPHP_HSTRING_VARIABLE, "face:%(font)s,fore:#007F7F,italic,bold,face:%(font)s,size:%(size)d" % faces) | |
211 | self.StyleSetSpec(wx.stc.STC_HPHP_VARIABLE, "face:%(font)s,fore:#000000,face:%(font)s,size:%(size)d" % faces) | |
212 | self.StyleSetSpec(wx.stc.STC_HPHP_OPERATOR, "face:%(font)s,size:%(size)d" % faces) | |
213 | self.StyleSetSpec(wx.stc.STC_HPHP_WORD, "face:%(font)s,fore:#00007F,bold,size:%(size)d" % faces) # keyword | |
214 | ||
215 | ||
216 | class PHPOptionsPanel(STCTextEditor.TextOptionsPanel): | |
217 | ||
218 | def __init__(self, parent, id): | |
219 | STCTextEditor.TextOptionsPanel.__init__(self, parent, id, configPrefix = "PHP", label = "PHP", hasWordWrap = True, hasTabs = True) | |
220 | ||
221 | ||
02b800ce RD |
222 | def GetIcon(self): |
223 | return getPHPIcon() | |
224 | ||
225 | ||
1f780e48 RD |
226 | PHPKEYWORDS = [ |
227 | "and", "or", "xor", "__FILE__", "exception", "__LINE__", "array", "as", "break", "case", | |
228 | "class", "const", "continue", "declare", "default", "die", "do", "echo", "else", "elseif", | |
229 | "empty", "enddeclare", "endfor", "endforeach", "endif", "endswith", "endwhile", "eval", | |
230 | "exit", "extends", "for", "foreach", "function", "global", "if", "include", "include_once", | |
231 | "isset", "list", "new", "print", "require", "require_once", "return", "static", "switch", | |
232 | "unset", "use", "var", "while", "__FUNCTION__", "__CLASS__", "__METHOD__", "final", "php_user_filter", | |
233 | "interface", "implements", "extends", "public", "private", "protected", "abstract", "clone", "try", "catch", | |
234 | "throw", "cfunction", "old_function", | |
235 | "$_SERVER", "$_ENV", "$_COOKIE", "$_GET", "$_POST", "$_FILES", "$_REQUEST", "$_SESSION", "$GLOBALS", "$php_errormsg", | |
236 | "PHP_VERSION", "PHP_OS", "PHP_EOL", "DEFAULT_INCLUDE_PATH", "PEAR_INSTALL_DIR", "PEAR_EXTENSION_DIR", | |
237 | "PHP_EXTENSION_DIR", "PHP_BINDIR", "PHP_LIBDIR", "PHP_DATADIR", "PHP_SYSCONFDIR", "PHP_LOCALSTATEDIR", | |
238 | "PHP_CONFIG_FILE_PATH", "PHP_OUTPUT_HANDLER_START", "PHP_OUTPUT_HANDLER_CONT", "PHP_OUTPUT_HANDLER_END", | |
239 | "E_ERROR", "E_WARNING", "E_PARSE", "E_NOTICE", "E_CORE_ERROR", "E_CORE_WARNING", "E_COMPILE_ERROR", | |
240 | "E_COMPILE_WARNING", "E_USER_ERROR", "E_USER_WARNING", "E_USER_NOTICE", "E_ALL", "E_STRICT", | |
241 | "TRUE", "FALSE", "NULL", "ZEND_THREAD_SAFE", | |
242 | "EXTR_OVERWRITE", "EXTR_SKIP", "EXTR_PREFIX_SAME", "EXTR_PREFIX_ALL", "EXTR_PREFIX_INVALID", | |
243 | "EXTR_PREFIX_IF_EXISTS", "EXTR_IF_EXISTS", "SORT_ASC", "SORT_DESC", "SORT_REGULAR", "SORT_NUMERIC", | |
244 | "SORT_STRING", "CASE_LOWER", "CASE_UPPER", "COUNT_NORMAL", "COUNT_RECURSIVE", "ASSERT_ACTIVE", | |
245 | "ASSERT_CALLBACK", "ASSERT_BAIL", "ASSERT_WARNING", "ASSERT_QUIET_EVAL", "CONNECTION_ABORTED", | |
246 | "CONNECTION_NORMAL", "CONNECTION_TIMEOUT", "INI_USER", "INI_PERDIR", "INI_SYSTEM", "INI_ALL", | |
247 | "M_E", "M_LOG2E", "M_LOG10E", "M_LN2", "M_LN10", "M_PI", "M_PI_2", "M_PI_4", "M_1_PI", "M_2_PI", | |
248 | "M_2_SQRTPI", "M_SQRT2", "M_SQRT1_2", "CRYPT_SALT_LENGTH", "CRYPT_STD_DES", "CRYPT_EXT_DES", "CRYPT_MD5", | |
249 | "CRYPT_BLOWFISH", "DIRECTORY_SEPARATOR", "SEEK_SET", "SEEK_CUR", "SEEK_END", "LOCK_SH", "LOCK_EX", "LOCK_UN", | |
250 | "LOCK_NB", "HTML_SPECIALCHARS", "HTML_ENTITIES", "ENT_COMPAT", "ENT_QUOTES", "ENT_NOQUOTES", "INFO_GENERAL", | |
251 | "INFO_CREDITS", "INFO_CONFIGURATION", "INFO_MODULES", "INFO_ENVIRONMENT", "INFO_VARIABLES", "INFO_LICENSE", | |
252 | "INFO_ALL", "CREDITS_GROUP", "CREDITS_GENERAL", "CREDITS_SAPI", "CREDITS_MODULES", "CREDITS_DOCS", | |
253 | "CREDITS_FULLPAGE", "CREDITS_QA", "CREDITS_ALL", "STR_PAD_LEFT", "STR_PAD_RIGHT", "STR_PAD_BOTH", | |
254 | "PATHINFO_DIRNAME", "PATHINFO_BASENAME", "PATHINFO_EXTENSION", "PATH_SEPARATOR", "CHAR_MAX", "LC_CTYPE", | |
255 | "LC_NUMERIC", "LC_TIME", "LC_COLLATE", "LC_MONETARY", "LC_ALL", "LC_MESSAGES", "ABDAY_1", "ABDAY_2", | |
256 | "ABDAY_3", "ABDAY_4", "ABDAY_5", "ABDAY_6", "ABDAY_7", "DAY_1", "DAY_2", "DAY_3", "DAY_4", "DAY_5", | |
257 | "DAY_6", "DAY_7", "ABMON_1", "ABMON_2", "ABMON_3", "ABMON_4", "ABMON_5", "ABMON_6", "ABMON_7", "ABMON_8", | |
258 | "ABMON_9", "ABMON_10", "ABMON_11", "ABMON_12", "MON_1", "MON_2", "MON_3", "MON_4", "MON_5", "MON_6", "MON_7", | |
259 | "MON_8", "MON_9", "MON_10", "MON_11", "MON_12", "AM_STR", "PM_STR", "D_T_FMT", "D_FMT", "T_FMT", "T_FMT_AMPM", | |
260 | "ERA", "ERA_YEAR", "ERA_D_T_FMT", "ERA_D_FMT", "ERA_T_FMT", "ALT_DIGITS", "INT_CURR_SYMBOL", "CURRENCY_SYMBOL", | |
261 | "CRNCYSTR", "MON_DECIMAL_POINT", "MON_THOUSANDS_SEP", "MON_GROUPING", "POSITIVE_SIGN", "NEGATIVE_SIGN", | |
262 | "INT_FRAC_DIGITS", "FRAC_DIGITS", "P_CS_PRECEDES", "P_SEP_BY_SPACE", "N_CS_PRECEDES", "N_SEP_BY_SPACE", | |
263 | "P_SIGN_POSN", "N_SIGN_POSN", "DECIMAL_POINT", "RADIXCHAR", "THOUSANDS_SEP", "THOUSEP", "GROUPING", | |
264 | "YESEXPR", "NOEXPR", "YESSTR", "NOSTR", "CODESET", "LOG_EMERG", "LOG_ALERT", "LOG_CRIT", "LOG_ERR", | |
265 | "LOG_WARNING", "LOG_NOTICE", "LOG_INFO", "LOG_DEBUG", "LOG_KERN", "LOG_USER", "LOG_MAIL", "LOG_DAEMON", | |
266 | "LOG_AUTH", "LOG_SYSLOG", "LOG_LPR", "LOG_NEWS", "LOG_UUCP", "LOG_CRON", "LOG_AUTHPRIV", "LOG_LOCAL0", | |
267 | "LOG_LOCAL1", "LOG_LOCAL2", "LOG_LOCAL3", "LOG_LOCAL4", "LOG_LOCAL5", "LOG_LOCAL6", "LOG_LOCAL7", | |
268 | "LOG_PID", "LOG_CONS", "LOG_ODELAY", "LOG_NDELAY", "LOG_NOWAIT", "LOG_PERROR" | |
269 | ] | |
270 | ||
271 | ||
272 | #---------------------------------------------------------------------------- | |
273 | # Icon Bitmaps - generated by encode_bitmaps.py | |
274 | #---------------------------------------------------------------------------- | |
275 | from wx import ImageFromStream, BitmapFromImage | |
1f780e48 RD |
276 | import cStringIO |
277 | ||
278 | ||
279 | def getPHPData(): | |
280 | return \ | |
02b800ce | 281 | "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ |
1f780e48 | 282 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ |
02b800ce RD |
283 | \x00\x01GIDAT8\x8d\x8d\x931O\xc2@\x14\xc7\x7fW\xfa\x11\x1c\xe430\xb88\x18'\ |
284 | \x8c\x89\x0e\x0c\xc4\xd9\xdd\x85\xc9\xc5`\x82\x1b\t\x84\x98\x98\xe0\xa4_\x01\ | |
285 | cd`t$\xb8h\xd0\xb8\xabD0\xd4\xd0\xb4%H $\xe7P\x0e{@\xa9\xff\xe4\r\xf7\xee~\ | |
286 | \xff\xf7\xee^+\x1a\xcd\x8ed*\xab\xef\x02\xd0\xea\xda\x00\xb8\xce\x90\xb3\xa3\ | |
287 | }\xc1*5\x9a\x1d\xf9\xf6#g\xf1\xea\xf9qyS\x97\xf5o)\x8f\xcfo\xa50b\x84\x85\ | |
288 | \xb1\xca\xdc\x9b\xc0\xde\xe1\x01'\xa7U\x19v\xc6\xb4\xfa.\xeb\xc4\x01\x18L\ | |
289 | \xfc\xa4;\xf2\xdb\x7f\xac\xdd\xd3s<\xda\x03+\xb4\x88\x19\x04\x15\x0c\xb0\x93\ | |
290 | \xde\xc5\x9b\x80=\x86\xf6\xc5U\xa8\x81v\x05\x05\xab\xf6\xedq(\xf7\xd7A\xabk\ | |
291 | \xb36\xd2\x93A\xd8\x1aF\x18\xcc\x83\xb0\x08\x7f\xbc\xb7\xc2\r\\g8\x03\x97\ | |
292 | \xc1Q2{\x8e\xa7\x81/\xd7\xb5\x85C\xc9\xc46\xc9\x84>\xcaR!-`\xfa\x88\xab\xe0b\ | |
293 | >\xb5\xb4\xb2\xfa6\xcc\xf6\xa7\xc5f\x00V\xc0\xc3\xf3\x17w\x95\xa7YN\xad\x83\ | |
294 | \xfbP\x95\x06@un\xce\xd9\\\x8d\xad\x8d\xf8\xbf\xd6F\xa5\x9c\x11\x95rF\xfbaT\ | |
295 | \xc50\x15\xf3)\xb29\xbfc!\x8c\x98v\xaf\xe0f\x14\\*\xa4\x85f\x10|\x9c(\xa9)\ | |
296 | \xfc\x02?r\xb8\xfc~J.\xd0\x00\x00\x00\x00IEND\xaeB`\x82" | |
1f780e48 RD |
297 | |
298 | def getPHPBitmap(): | |
299 | return BitmapFromImage(getPHPImage()) | |
300 | ||
301 | def getPHPImage(): | |
302 | stream = cStringIO.StringIO(getPHPData()) | |
303 | return ImageFromStream(stream) | |
304 | ||
305 | def getPHPIcon(): | |
bbf7159c | 306 | return wx.IconFromBitmap(getPHPBitmap()) |