38 LETTERS = ['_'] |
38 LETTERS = ['_'] |
39 for i in xrange(26): |
39 for i in xrange(26): |
40 LETTERS.append(chr(ord('a') + i)) |
40 LETTERS.append(chr(ord('a') + i)) |
41 LETTERS.append(chr(ord('A') + i)) |
41 LETTERS.append(chr(ord('A') + i)) |
42 |
42 |
43 [STC_PLC_WORD, STC_PLC_COMMENT, STC_PLC_NUMBER, STC_PLC_VARIABLE, |
43 [STC_PLC_WORD, STC_PLC_COMMENT, STC_PLC_NUMBER, STC_PLC_STRING, |
44 STC_PLC_FUNCTION, STC_PLC_JUMP, STC_PLC_ERROR] = range(7) |
44 STC_PLC_VARIABLE, STC_PLC_FUNCTION, STC_PLC_JUMP, STC_PLC_ERROR] = range(8) |
45 [SPACE, WORD, NUMBER, COMMENT] = range(4) |
45 [SPACE, WORD, NUMBER, STRING, WSTRING, COMMENT] = range(6) |
46 |
46 |
47 [ID_TEXTVIEWER, |
47 [ID_TEXTVIEWER, |
48 ] = [wx.NewId() for _init_ctrls in range(1)] |
48 ] = [wx.NewId() for _init_ctrls in range(1)] |
49 |
49 |
50 if wx.Platform == '__WXMSW__': |
50 if wx.Platform == '__WXMSW__': |
65 re_texts["letter"] = "[A-Za-z]" |
65 re_texts["letter"] = "[A-Za-z]" |
66 re_texts["digit"] = "[0-9]" |
66 re_texts["digit"] = "[0-9]" |
67 re_texts["identifier"] = "((?:%(letter)s|(?:_(?:%(letter)s|%(digit)s)))(?:_?(?:%(letter)s|%(digit)s))*)"%re_texts |
67 re_texts["identifier"] = "((?:%(letter)s|(?:_(?:%(letter)s|%(digit)s)))(?:_?(?:%(letter)s|%(digit)s))*)"%re_texts |
68 IDENTIFIER_MODEL = re.compile(re_texts["identifier"]) |
68 IDENTIFIER_MODEL = re.compile(re_texts["identifier"]) |
69 LABEL_MODEL = re.compile("[ \t\n]%(identifier)s:[ \t\n]"%re_texts) |
69 LABEL_MODEL = re.compile("[ \t\n]%(identifier)s:[ \t\n]"%re_texts) |
|
70 EXTENSIBLE_PARAMETER = re.compile("IN[1-9][0-9]*$") |
70 |
71 |
71 def GetCursorPos(old, new): |
72 def GetCursorPos(old, new): |
72 old_length = len(old) |
73 old_length = len(old) |
73 new_length = len(new) |
74 new_length = len(new) |
74 common_length = min(old_length, new_length) |
75 common_length = min(old_length, new_length) |
120 self.StyleSetSpec(STC_PLC_WORD, "fore:#00007F,bold,size:%(size)d" % faces) |
121 self.StyleSetSpec(STC_PLC_WORD, "fore:#00007F,bold,size:%(size)d" % faces) |
121 self.StyleSetSpec(STC_PLC_VARIABLE, "fore:#7F0000,size:%(size)d" % faces) |
122 self.StyleSetSpec(STC_PLC_VARIABLE, "fore:#7F0000,size:%(size)d" % faces) |
122 self.StyleSetSpec(STC_PLC_FUNCTION, "fore:#7F7F00,size:%(size)d" % faces) |
123 self.StyleSetSpec(STC_PLC_FUNCTION, "fore:#7F7F00,size:%(size)d" % faces) |
123 self.StyleSetSpec(STC_PLC_COMMENT, "fore:#7F7F7F,size:%(size)d" % faces) |
124 self.StyleSetSpec(STC_PLC_COMMENT, "fore:#7F7F7F,size:%(size)d" % faces) |
124 self.StyleSetSpec(STC_PLC_NUMBER, "fore:#007F7F,size:%(size)d" % faces) |
125 self.StyleSetSpec(STC_PLC_NUMBER, "fore:#007F7F,size:%(size)d" % faces) |
|
126 self.StyleSetSpec(STC_PLC_STRING, "fore:#7F007F,size:%(size)d" % faces) |
125 self.StyleSetSpec(STC_PLC_JUMP, "fore:#007F00,size:%(size)d" % faces) |
127 self.StyleSetSpec(STC_PLC_JUMP, "fore:#007F00,size:%(size)d" % faces) |
126 self.StyleSetSpec(STC_PLC_ERROR, "fore:#FF0000,back:#FFFF00,size:%(size)d" % faces) |
128 self.StyleSetSpec(STC_PLC_ERROR, "fore:#FF0000,back:#FFFF00,size:%(size)d" % faces) |
127 |
129 |
128 # Indicators styles |
130 # Indicators styles |
129 self.IndicatorSetStyle(0, wx.stc.STC_INDIC_SQUIGGLE) |
131 self.IndicatorSetStyle(0, wx.stc.STC_INDIC_SQUIGGLE) |
140 self.SetTabWidth(2) |
142 self.SetTabWidth(2) |
141 self.SetUseTabs(0) |
143 self.SetUseTabs(0) |
142 |
144 |
143 self.Keywords = [] |
145 self.Keywords = [] |
144 self.Variables = {} |
146 self.Variables = {} |
145 self.Functions = [] |
147 self.Functions = {} |
|
148 self.TypeNames = [] |
146 self.Jumps = [] |
149 self.Jumps = [] |
147 self.EnumeratedValues = [] |
150 self.EnumeratedValues = [] |
148 self.DisableEvents = True |
151 self.DisableEvents = True |
149 self.TextSyntax = "ST" |
152 self.TextSyntax = "ST" |
150 self.CurrentAction = None |
153 self.CurrentAction = None |
151 self.TagName = tagname |
154 self.TagName = tagname |
152 self.Errors = [] |
155 self.Errors = [] |
153 self.Debug = debug |
156 self.Debug = debug |
154 self.InstancePath = instancepath |
157 self.InstancePath = instancepath |
155 self.StructElementsStack = [] |
158 self.StructElementsStack = [] |
|
159 self.FunctionCallStack = [] |
156 |
160 |
157 self.ParentWindow = window |
161 self.ParentWindow = window |
158 self.Controler = controler |
162 self.Controler = controler |
159 |
163 |
160 self.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT| |
164 self.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT| |
284 def SetKeywords(self, keywords): |
288 def SetKeywords(self, keywords): |
285 self.Keywords = [keyword.upper() for keyword in keywords] |
289 self.Keywords = [keyword.upper() for keyword in keywords] |
286 self.Colourise(0, -1) |
290 self.Colourise(0, -1) |
287 |
291 |
288 def RefreshJumpList(self): |
292 def RefreshJumpList(self): |
289 self.Jumps = [jump.upper() for jump in LABEL_MODEL.findall(self.GetText())] |
293 if self.TextSyntax != "IL": |
290 self.Colourise(0, -1) |
294 self.Jumps = [jump.upper() for jump in LABEL_MODEL.findall(self.GetText())] |
|
295 self.Colourise(0, -1) |
291 |
296 |
292 # Buffer the last model state |
297 # Buffer the last model state |
293 def RefreshBuffer(self): |
298 def RefreshBuffer(self): |
294 self.Controler.BufferProject() |
299 self.Controler.BufferProject() |
295 if self.ParentWindow: |
300 if self.ParentWindow: |
326 self.EmptyUndoBuffer() |
331 self.EmptyUndoBuffer() |
327 self.DisableEvents = False |
332 self.DisableEvents = False |
328 |
333 |
329 self.RefreshVariableTree() |
334 self.RefreshVariableTree() |
330 |
335 |
331 self.Functions = [] |
336 self.TypeNames = [typename.upper() for typename in self.Controler.GetDataTypes(self.TagName, True, self.Debug)] |
|
337 self.EnumeratedValues = [value.upper() for value in self.Controler.GetEnumeratedDataValues()] |
|
338 |
|
339 self.Functions = {} |
332 for category in self.Controler.GetBlockTypes(self.TagName, self.Debug): |
340 for category in self.Controler.GetBlockTypes(self.TagName, self.Debug): |
333 for blocktype in category["list"]: |
341 for blocktype in category["list"]: |
334 if blocktype["type"] == "function" and blocktype["name"] not in self.Keywords and blocktype["name"] not in self.Variables.keys(): |
342 if blocktype["type"] == "function" and blocktype["name"] not in self.Keywords and blocktype["name"] not in self.Variables.keys(): |
335 self.Functions.append(blocktype["name"].upper()) |
343 if self.Functions.has_key(blocktype["name"]): |
336 |
344 for name, type, modifier in blocktype["inputs"]: |
337 self.EnumeratedValues = [] |
345 if name not in self.Functions[blocktype["name"]]["inputs"]: |
338 for value in self.Controler.GetEnumeratedDataValues(): |
346 self.Functions[blocktype["name"]]["inputs"].append(name) |
339 self.EnumeratedValues.append(value.upper()) |
347 for name, type, modifier in blocktype["outputs"]: |
|
348 if name not in self.Functions[blocktype["name"]]["outputs"]: |
|
349 self.Functions[blocktype["name"]]["outputs"].append(name) |
|
350 self.Functions[blocktype["name"]]["extensible"] |= blocktype["extensible"] |
|
351 else: |
|
352 self.Functions[blocktype["name"]] = {"inputs": [name for name, type, modifier in blocktype["inputs"]], |
|
353 "outputs": [name for name, type, modifier in blocktype["outputs"]], |
|
354 "extensible": blocktype["extensible"]} |
340 |
355 |
341 self.Colourise(0, -1) |
356 self.Colourise(0, -1) |
342 |
357 |
343 def RefreshVariableTree(self): |
358 def RefreshVariableTree(self): |
344 words = self.TagName.split("::") |
359 words = self.TagName.split("::") |
362 sub_tree = var_tree.get(name_list[0].upper(), None) |
377 sub_tree = var_tree.get(name_list[0].upper(), None) |
363 if sub_tree is not None: |
378 if sub_tree is not None: |
364 return self.IsValidVariable(name_list[1:], sub_tree) |
379 return self.IsValidVariable(name_list[1:], sub_tree) |
365 return False |
380 return False |
366 |
381 |
|
382 def IsFunctionParameter(self, param_name, func_name): |
|
383 if func_name is not None: |
|
384 func_decl = self.Functions.get(func_name, None) |
|
385 if func_decl is not None: |
|
386 return (param_name.upper() in func_decl["inputs"] or |
|
387 param_name.upper() in func_decl["outputs"] or |
|
388 func_decl["extensible"] and EXTENSIBLE_PARAMETER.match(param_name.upper()) is not None) |
|
389 return False |
|
390 |
367 def OnStyleNeeded(self, event): |
391 def OnStyleNeeded(self, event): |
368 self.TextChanged = True |
392 self.TextChanged = True |
369 line = self.LineFromPosition(self.GetEndStyled()) |
393 line = self.LineFromPosition(self.GetEndStyled()) |
370 if line == 0: |
394 if line == 0: |
371 start_pos = last_styled_pos = 0 |
395 start_pos = last_styled_pos = 0 |
373 start_pos = last_styled_pos = self.GetLineEndPosition(line - 1) + 1 |
397 start_pos = last_styled_pos = self.GetLineEndPosition(line - 1) + 1 |
374 end_pos = event.GetPosition() |
398 end_pos = event.GetPosition() |
375 self.StartStyling(start_pos, 0xff) |
399 self.StartStyling(start_pos, 0xff) |
376 |
400 |
377 struct_elements = [] |
401 struct_elements = [] |
|
402 current_function = None |
378 |
403 |
379 current_pos = last_styled_pos |
404 current_pos = last_styled_pos |
380 state = SPACE |
405 state = SPACE |
381 line = "" |
406 line = "" |
382 word = "" |
407 word = "" |
383 while current_pos < end_pos: |
408 while current_pos < end_pos: |
384 char = chr(self.GetCharAt(current_pos)).upper() |
409 char = chr(self.GetCharAt(current_pos)).upper() |
385 line += char |
410 line += char |
386 if char == NEWLINE: |
411 if char == NEWLINE: |
|
412 self.StructElementsStack = [] |
387 if state == COMMENT: |
413 if state == COMMENT: |
388 self.SetStyling(current_pos - last_styled_pos + 1, STC_PLC_COMMENT) |
414 self.SetStyling(current_pos - last_styled_pos + 1, STC_PLC_COMMENT) |
389 elif state == NUMBER: |
415 elif state == NUMBER: |
390 self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER) |
416 self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER) |
391 elif state == WORD: |
417 elif state == WORD: |
392 if word in self.Keywords: |
418 if word in self.Keywords or word in self.TypeNames: |
393 self.SetStyling(current_pos - last_styled_pos, STC_PLC_WORD) |
419 self.SetStyling(current_pos - last_styled_pos, STC_PLC_WORD) |
394 elif self.IsValidVariable(struct_elements + [word], self.Variables): |
420 elif self.IsValidVariable(struct_elements + [word], self.Variables) or self.IsFunctionParameter(word, current_function): |
395 self.SetStyling(current_pos - last_styled_pos, STC_PLC_VARIABLE) |
421 self.SetStyling(current_pos - last_styled_pos, STC_PLC_VARIABLE) |
396 elif word in self.Functions: |
422 elif word in self.Functions: |
397 self.SetStyling(current_pos - last_styled_pos, STC_PLC_FUNCTION) |
423 self.SetStyling(current_pos - last_styled_pos, STC_PLC_FUNCTION) |
398 elif word in self.Jumps: |
424 elif self.TextSyntax == "IL" and word in self.Jumps: |
399 self.SetStyling(current_pos - last_styled_pos, STC_PLC_JUMP) |
425 self.SetStyling(current_pos - last_styled_pos, STC_PLC_JUMP) |
400 elif word in self.EnumeratedValues: |
426 elif word in self.EnumeratedValues: |
401 self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER) |
427 self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER) |
402 else: |
428 else: |
403 self.SetStyling(current_pos - last_styled_pos, 31) |
429 self.SetStyling(current_pos - last_styled_pos, 31) |
420 elif state == COMMENT: |
446 elif state == COMMENT: |
421 if line.endswith("*)"): |
447 if line.endswith("*)"): |
422 self.SetStyling(current_pos - last_styled_pos + 2, STC_PLC_COMMENT) |
448 self.SetStyling(current_pos - last_styled_pos + 2, STC_PLC_COMMENT) |
423 last_styled_pos = current_pos + 1 |
449 last_styled_pos = current_pos + 1 |
424 state = SPACE |
450 state = SPACE |
|
451 elif (line.endswith("'") or line.endswith('"')) and state not in [COMMENT, STRING, WSTRING]: |
|
452 self.SetStyling(current_pos - last_styled_pos, 31) |
|
453 last_styled_pos = current_pos |
|
454 if state == WORD: |
|
455 struct_elements = [] |
|
456 if line.endswith("'"): |
|
457 state = STRING |
|
458 else: |
|
459 state = WSTRING |
|
460 elif state == STRING: |
|
461 if line.endswith("'") and not line.endswith("$'"): |
|
462 self.SetStyling(current_pos - last_styled_pos + 1, STC_PLC_STRING) |
|
463 last_styled_pos = current_pos + 1 |
|
464 state = SPACE |
|
465 elif state == WSTRING: |
|
466 if line.endswith('"') and not line.endswith('$"'): |
|
467 self.SetStyling(current_pos - last_styled_pos + 1, STC_PLC_STRING) |
|
468 last_styled_pos = current_pos + 1 |
|
469 state = SPACE |
425 elif char in LETTERS: |
470 elif char in LETTERS: |
426 if state == NUMBER: |
471 if state == NUMBER: |
427 word = "#" |
472 word = "#" |
428 state = WORD |
473 state = WORD |
429 elif state == SPACE: |
474 elif state == SPACE: |
438 self.SetStyling(current_pos - last_styled_pos, 31) |
483 self.SetStyling(current_pos - last_styled_pos, 31) |
439 last_styled_pos = current_pos |
484 last_styled_pos = current_pos |
440 state = NUMBER |
485 state = NUMBER |
441 if state == WORD and char != '.': |
486 if state == WORD and char != '.': |
442 word += char |
487 word += char |
|
488 elif char == '(' and state == SPACE: |
|
489 self.FunctionCallStack.append(current_function) |
|
490 current_function = None |
443 else: |
491 else: |
444 if state == WORD: |
492 if state == WORD: |
445 if word in self.Keywords: |
493 if word in self.Keywords or word in self.TypeNames: |
446 self.SetStyling(current_pos - last_styled_pos, STC_PLC_WORD) |
494 self.SetStyling(current_pos - last_styled_pos, STC_PLC_WORD) |
447 elif self.IsValidVariable(struct_elements + [word], self.Variables): |
495 elif self.IsValidVariable(struct_elements + [word], self.Variables) or self.IsFunctionParameter(word, current_function): |
448 self.SetStyling(current_pos - last_styled_pos, STC_PLC_VARIABLE) |
496 self.SetStyling(current_pos - last_styled_pos, STC_PLC_VARIABLE) |
449 elif word in self.Functions: |
497 elif word in self.Functions: |
450 self.SetStyling(current_pos - last_styled_pos, STC_PLC_FUNCTION) |
498 self.SetStyling(current_pos - last_styled_pos, STC_PLC_FUNCTION) |
451 elif word in self.Jumps: |
499 elif self.TextSyntax == "IL" and word in self.Jumps: |
452 self.SetStyling(current_pos - last_styled_pos, STC_PLC_JUMP) |
500 self.SetStyling(current_pos - last_styled_pos, STC_PLC_JUMP) |
453 elif word in self.EnumeratedValues: |
501 elif word in self.EnumeratedValues: |
454 self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER) |
502 self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER) |
455 else: |
503 else: |
456 self.SetStyling(current_pos - last_styled_pos, 31) |
504 self.SetStyling(current_pos - last_styled_pos, 31) |
459 self.SetStyling(current_pos - last_styled_pos, wx.stc.STC_INDIC0_MASK) |
507 self.SetStyling(current_pos - last_styled_pos, wx.stc.STC_INDIC0_MASK) |
460 self.StartStyling(current_pos, 0xff) |
508 self.StartStyling(current_pos, 0xff) |
461 if char == '.': |
509 if char == '.': |
462 if word != "]": |
510 if word != "]": |
463 struct_elements.append(word) |
511 struct_elements.append(word) |
|
512 elif char == '(': |
|
513 self.FunctionCallStack.append(current_function) |
|
514 if word in self.Functions: |
|
515 current_function = word |
|
516 struct_elements = [] |
|
517 else: |
|
518 if self.IsValidVariable(struct_elements + [word], self.Variables): |
|
519 struct_elements.append(word) |
|
520 current_function = None |
464 else: |
521 else: |
465 if char == '[': |
522 if char == '[': |
466 self.StructElementsStack.append(struct_elements + [word]) |
523 self.StructElementsStack.append(struct_elements + [word]) |
467 struct_elements = [] |
524 struct_elements = [] |
|
525 |
468 word = "" |
526 word = "" |
469 last_styled_pos = current_pos |
527 last_styled_pos = current_pos |
470 state = SPACE |
528 state = SPACE |
471 elif state == NUMBER: |
529 elif state == NUMBER: |
472 self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER) |
530 self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER) |
473 last_styled_pos = current_pos |
531 last_styled_pos = current_pos |
474 state = SPACE |
532 state = SPACE |
475 if char == ']': |
533 if char == ']': |
476 if len(self.StructElementsStack) > 0: |
534 if len(self.StructElementsStack) > 0: |
477 struct_elements = self.StructElementsStack.pop() |
535 struct_elements = self.StructElementsStack.pop() |
|
536 else: |
|
537 struct_elements = [] |
478 word = char |
538 word = char |
479 state = WORD |
539 state = WORD |
|
540 elif char == ')': |
|
541 struct_elements = [] |
|
542 if len(self.FunctionCallStack) > 0: |
|
543 current_function = self.FunctionCallStack.pop() |
|
544 else: |
|
545 current_function = None |
480 current_pos += 1 |
546 current_pos += 1 |
481 if state == COMMENT: |
547 if state == COMMENT: |
482 self.SetStyling(current_pos - last_styled_pos + 2, STC_PLC_COMMENT) |
548 self.SetStyling(current_pos - last_styled_pos + 2, STC_PLC_COMMENT) |
483 elif state == NUMBER: |
549 elif state == NUMBER: |
484 self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER) |
550 self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER) |
485 elif state == WORD: |
551 elif state == WORD: |
486 if word in self.Keywords: |
552 if word in self.Keywords or word in self.TypeNames: |
487 self.SetStyling(current_pos - last_styled_pos, STC_PLC_WORD) |
553 self.SetStyling(current_pos - last_styled_pos, STC_PLC_WORD) |
488 elif self.IsValidVariable(struct_elements + [word], self.Variables): |
554 elif self.IsValidVariable(struct_elements + [word], self.Variables) or self.IsFunctionParameter(word, current_function): |
489 self.SetStyling(current_pos - last_styled_pos, STC_PLC_VARIABLE) |
555 self.SetStyling(current_pos - last_styled_pos, STC_PLC_VARIABLE) |
490 elif word in self.Functions: |
556 elif self.TextSyntax == "IL" and word in self.Functions: |
491 self.SetStyling(current_pos - last_styled_pos, STC_PLC_FUNCTION) |
557 self.SetStyling(current_pos - last_styled_pos, STC_PLC_FUNCTION) |
492 elif word in self.Jumps: |
558 elif word in self.Jumps: |
493 self.SetStyling(current_pos - last_styled_pos, STC_PLC_JUMP) |
559 self.SetStyling(current_pos - last_styled_pos, STC_PLC_JUMP) |
494 elif word in self.EnumeratedValues: |
560 elif word in self.EnumeratedValues: |
495 self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER) |
561 self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER) |