]>
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 | ||
222 | PHPKEYWORDS = [ | |
223 | "and", "or", "xor", "__FILE__", "exception", "__LINE__", "array", "as", "break", "case", | |
224 | "class", "const", "continue", "declare", "default", "die", "do", "echo", "else", "elseif", | |
225 | "empty", "enddeclare", "endfor", "endforeach", "endif", "endswith", "endwhile", "eval", | |
226 | "exit", "extends", "for", "foreach", "function", "global", "if", "include", "include_once", | |
227 | "isset", "list", "new", "print", "require", "require_once", "return", "static", "switch", | |
228 | "unset", "use", "var", "while", "__FUNCTION__", "__CLASS__", "__METHOD__", "final", "php_user_filter", | |
229 | "interface", "implements", "extends", "public", "private", "protected", "abstract", "clone", "try", "catch", | |
230 | "throw", "cfunction", "old_function", | |
231 | "$_SERVER", "$_ENV", "$_COOKIE", "$_GET", "$_POST", "$_FILES", "$_REQUEST", "$_SESSION", "$GLOBALS", "$php_errormsg", | |
232 | "PHP_VERSION", "PHP_OS", "PHP_EOL", "DEFAULT_INCLUDE_PATH", "PEAR_INSTALL_DIR", "PEAR_EXTENSION_DIR", | |
233 | "PHP_EXTENSION_DIR", "PHP_BINDIR", "PHP_LIBDIR", "PHP_DATADIR", "PHP_SYSCONFDIR", "PHP_LOCALSTATEDIR", | |
234 | "PHP_CONFIG_FILE_PATH", "PHP_OUTPUT_HANDLER_START", "PHP_OUTPUT_HANDLER_CONT", "PHP_OUTPUT_HANDLER_END", | |
235 | "E_ERROR", "E_WARNING", "E_PARSE", "E_NOTICE", "E_CORE_ERROR", "E_CORE_WARNING", "E_COMPILE_ERROR", | |
236 | "E_COMPILE_WARNING", "E_USER_ERROR", "E_USER_WARNING", "E_USER_NOTICE", "E_ALL", "E_STRICT", | |
237 | "TRUE", "FALSE", "NULL", "ZEND_THREAD_SAFE", | |
238 | "EXTR_OVERWRITE", "EXTR_SKIP", "EXTR_PREFIX_SAME", "EXTR_PREFIX_ALL", "EXTR_PREFIX_INVALID", | |
239 | "EXTR_PREFIX_IF_EXISTS", "EXTR_IF_EXISTS", "SORT_ASC", "SORT_DESC", "SORT_REGULAR", "SORT_NUMERIC", | |
240 | "SORT_STRING", "CASE_LOWER", "CASE_UPPER", "COUNT_NORMAL", "COUNT_RECURSIVE", "ASSERT_ACTIVE", | |
241 | "ASSERT_CALLBACK", "ASSERT_BAIL", "ASSERT_WARNING", "ASSERT_QUIET_EVAL", "CONNECTION_ABORTED", | |
242 | "CONNECTION_NORMAL", "CONNECTION_TIMEOUT", "INI_USER", "INI_PERDIR", "INI_SYSTEM", "INI_ALL", | |
243 | "M_E", "M_LOG2E", "M_LOG10E", "M_LN2", "M_LN10", "M_PI", "M_PI_2", "M_PI_4", "M_1_PI", "M_2_PI", | |
244 | "M_2_SQRTPI", "M_SQRT2", "M_SQRT1_2", "CRYPT_SALT_LENGTH", "CRYPT_STD_DES", "CRYPT_EXT_DES", "CRYPT_MD5", | |
245 | "CRYPT_BLOWFISH", "DIRECTORY_SEPARATOR", "SEEK_SET", "SEEK_CUR", "SEEK_END", "LOCK_SH", "LOCK_EX", "LOCK_UN", | |
246 | "LOCK_NB", "HTML_SPECIALCHARS", "HTML_ENTITIES", "ENT_COMPAT", "ENT_QUOTES", "ENT_NOQUOTES", "INFO_GENERAL", | |
247 | "INFO_CREDITS", "INFO_CONFIGURATION", "INFO_MODULES", "INFO_ENVIRONMENT", "INFO_VARIABLES", "INFO_LICENSE", | |
248 | "INFO_ALL", "CREDITS_GROUP", "CREDITS_GENERAL", "CREDITS_SAPI", "CREDITS_MODULES", "CREDITS_DOCS", | |
249 | "CREDITS_FULLPAGE", "CREDITS_QA", "CREDITS_ALL", "STR_PAD_LEFT", "STR_PAD_RIGHT", "STR_PAD_BOTH", | |
250 | "PATHINFO_DIRNAME", "PATHINFO_BASENAME", "PATHINFO_EXTENSION", "PATH_SEPARATOR", "CHAR_MAX", "LC_CTYPE", | |
251 | "LC_NUMERIC", "LC_TIME", "LC_COLLATE", "LC_MONETARY", "LC_ALL", "LC_MESSAGES", "ABDAY_1", "ABDAY_2", | |
252 | "ABDAY_3", "ABDAY_4", "ABDAY_5", "ABDAY_6", "ABDAY_7", "DAY_1", "DAY_2", "DAY_3", "DAY_4", "DAY_5", | |
253 | "DAY_6", "DAY_7", "ABMON_1", "ABMON_2", "ABMON_3", "ABMON_4", "ABMON_5", "ABMON_6", "ABMON_7", "ABMON_8", | |
254 | "ABMON_9", "ABMON_10", "ABMON_11", "ABMON_12", "MON_1", "MON_2", "MON_3", "MON_4", "MON_5", "MON_6", "MON_7", | |
255 | "MON_8", "MON_9", "MON_10", "MON_11", "MON_12", "AM_STR", "PM_STR", "D_T_FMT", "D_FMT", "T_FMT", "T_FMT_AMPM", | |
256 | "ERA", "ERA_YEAR", "ERA_D_T_FMT", "ERA_D_FMT", "ERA_T_FMT", "ALT_DIGITS", "INT_CURR_SYMBOL", "CURRENCY_SYMBOL", | |
257 | "CRNCYSTR", "MON_DECIMAL_POINT", "MON_THOUSANDS_SEP", "MON_GROUPING", "POSITIVE_SIGN", "NEGATIVE_SIGN", | |
258 | "INT_FRAC_DIGITS", "FRAC_DIGITS", "P_CS_PRECEDES", "P_SEP_BY_SPACE", "N_CS_PRECEDES", "N_SEP_BY_SPACE", | |
259 | "P_SIGN_POSN", "N_SIGN_POSN", "DECIMAL_POINT", "RADIXCHAR", "THOUSANDS_SEP", "THOUSEP", "GROUPING", | |
260 | "YESEXPR", "NOEXPR", "YESSTR", "NOSTR", "CODESET", "LOG_EMERG", "LOG_ALERT", "LOG_CRIT", "LOG_ERR", | |
261 | "LOG_WARNING", "LOG_NOTICE", "LOG_INFO", "LOG_DEBUG", "LOG_KERN", "LOG_USER", "LOG_MAIL", "LOG_DAEMON", | |
262 | "LOG_AUTH", "LOG_SYSLOG", "LOG_LPR", "LOG_NEWS", "LOG_UUCP", "LOG_CRON", "LOG_AUTHPRIV", "LOG_LOCAL0", | |
263 | "LOG_LOCAL1", "LOG_LOCAL2", "LOG_LOCAL3", "LOG_LOCAL4", "LOG_LOCAL5", "LOG_LOCAL6", "LOG_LOCAL7", | |
264 | "LOG_PID", "LOG_CONS", "LOG_ODELAY", "LOG_NDELAY", "LOG_NOWAIT", "LOG_PERROR" | |
265 | ] | |
266 | ||
267 | ||
268 | #---------------------------------------------------------------------------- | |
269 | # Icon Bitmaps - generated by encode_bitmaps.py | |
270 | #---------------------------------------------------------------------------- | |
271 | from wx import ImageFromStream, BitmapFromImage | |
1f780e48 RD |
272 | import cStringIO |
273 | ||
274 | ||
275 | def getPHPData(): | |
276 | return \ | |
277 | '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ | |
278 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ | |
279 | \x00\x00{IDAT8\x8dclh8\xf0\x9f\x81\x02\xc0D\x89f\xaa\x18\xc0\x82M0<\\\x1c\ | |
280 | \xce^\xb9\xf2%y.\xd0\xd4\xd4$\xde\x05\xf8l\x0c\x0f\x17\x87\x8baS\xc7x\xfd\ | |
281 | \xfa\xf5\xff\xc8\xb6]\xbf~\x1d\xc3\x05\xf8\xc4\x98\x90\x05\xae_\xbf\x8e\xa1\ | |
282 | \x88\x90\xd8 \x8aF\x98\x93`~\xc3\x05\xd0\xd5\xc1\r\x80\t\xc0B\xf7\xfa\xf5\ | |
283 | \xeb(l\\\xeaP\xbc\x80\x1c\x85\xb8\xd8\xe8|&b\x9c\x8dn;2`\x1c\xf0\xdc\x08\x00\ | |
284 | \x8e\xf2S\xed\xb0\xbe\xaa\xbc\x00\x00\x00\x00IEND\xaeB`\x82' | |
285 | ||
286 | def getPHPBitmap(): | |
287 | return BitmapFromImage(getPHPImage()) | |
288 | ||
289 | def getPHPImage(): | |
290 | stream = cStringIO.StringIO(getPHPData()) | |
291 | return ImageFromStream(stream) | |
292 | ||
293 | def getPHPIcon(): | |
bbf7159c | 294 | return wx.IconFromBitmap(getPHPBitmap()) |