# HG changeset patch # User laurent # Date 1319414794 -7200 # Node ID aa41547baa2ae25a6655b737ce6cce4b3df0bb57 # Parent c2d96ea9c14a8ac2ea8dfdb4a2d6499dd55859e6 Adding support for folding/unfolding and auto-indentation in ST code editor diff -r c2d96ea9c14a -r aa41547baa2a TextViewer.py --- a/TextViewer.py Mon Oct 24 02:03:42 2011 +0200 +++ b/TextViewer.py Mon Oct 24 02:06:34 2011 +0200 @@ -29,6 +29,7 @@ import re from graphics.GraphicCommons import ERROR_HIGHLIGHT, SEARCH_RESULT_HIGHLIGHT, REFRESH_HIGHLIGHT_PERIOD +from plcopen.structures import ST_BLOCK_START_KEYWORDS, ST_BLOCK_END_KEYWORDS #------------------------------------------------------------------------------- # Textual programs Viewer class @@ -98,6 +99,8 @@ else: return None +def LineStartswith(line, symbols): + return reduce(lambda x, y: x or y, map(lambda x: line.startswith(x), symbols), False) class TextViewer(wx.stc.StyledTextCtrl): @@ -148,6 +151,15 @@ self.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER) self.SetMarginWidth(1, 50) + # Folding + self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPEN, wx.stc.STC_MARK_BOXMINUS, "white", "#808080") + self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDER, wx.stc.STC_MARK_BOXPLUS, "white", "#808080") + self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERSUB, wx.stc.STC_MARK_VLINE, "white", "#808080") + self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERTAIL, wx.stc.STC_MARK_LCORNER, "white", "#808080") + self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEREND, wx.stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080") + self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPENMID, wx.stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080") + self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERMIDTAIL, wx.stc.STC_MARK_TCORNER, "white", "#808080") + # Indentation size self.SetTabWidth(2) self.SetUseTabs(0) @@ -179,6 +191,7 @@ wx.stc.STC_PERFORMED_USER) self.Bind(wx.stc.EVT_STC_STYLENEEDED, self.OnStyleNeeded, id=ID_TEXTVIEWER) + self.Bind(wx.stc.EVT_STC_MARGINCLICK, self.OnMarginClick) if controler: self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) self.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop, id=ID_TEXTVIEWER) @@ -300,6 +313,11 @@ def SetTextSyntax(self, syntax): self.TextSyntax = syntax + if syntax == "ST": + self.SetMarginType(2, wx.stc.STC_MARGIN_SYMBOL) + self.SetMarginMask(2, wx.stc.STC_MASK_FOLDERS) + self.SetMarginSensitive(2, 1) + self.SetMarginWidth(2, 12) def SetKeywords(self, keywords): self.Keywords = [keyword.upper() for keyword in keywords] @@ -368,7 +386,7 @@ self.Functions[blockname] = {"interface": interface, "extensible": blocktype["extensible"]} self.Colourise(0, -1) - + def RefreshVariableTree(self): words = self.TagName.split("::") self.Variables = self.GenerateVariableTree([(variable["Name"], variable["Type"], variable["Tree"]) for variable in self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)]) @@ -397,14 +415,36 @@ return (call["interface"].get(name.upper(), None) is not None or call["extensible"] and EXTENSIBLE_PARAMETER.match(name.upper()) is not None) return False - + + def RefreshLineFolding(self, line_number): + if self.TextSyntax == "ST": + level = wx.stc.STC_FOLDLEVELBASE + self.GetLineIndentation(line_number) + line = self.GetLine(line_number).strip() + if line == "": + if line_number > 0: + if LineStartswith(self.GetLine(line_number - 1).strip(), ST_BLOCK_END_KEYWORDS): + level = self.GetFoldLevel(self.GetFoldParent(line_number - 1)) & wx.stc.STC_FOLDLEVELNUMBERMASK + else: + level = self.GetFoldLevel(line_number - 1) & wx.stc.STC_FOLDLEVELNUMBERMASK + if level != wx.stc.STC_FOLDLEVELBASE: + level |= wx.stc.STC_FOLDLEVELWHITEFLAG + elif LineStartswith(line, ST_BLOCK_START_KEYWORDS): + level |= wx.stc.STC_FOLDLEVELHEADERFLAG + elif LineStartswith(line, ST_BLOCK_END_KEYWORDS): + if LineStartswith(self.GetLine(line_number - 1).strip(), ST_BLOCK_END_KEYWORDS): + level = self.GetFoldLevel(self.GetFoldParent(line_number - 1)) & wx.stc.STC_FOLDLEVELNUMBERMASK + else: + level = self.GetFoldLevel(line_number - 1) & wx.stc.STC_FOLDLEVELNUMBERMASK + self.SetFoldLevel(line_number, level) + def OnStyleNeeded(self, event): self.TextChanged = True - line = self.LineFromPosition(self.GetEndStyled()) - if line == 0: + line_number = self.LineFromPosition(self.GetEndStyled()) + if line_number == 0: start_pos = last_styled_pos = 0 else: - start_pos = last_styled_pos = self.GetLineEndPosition(line - 1) + 1 + start_pos = last_styled_pos = self.GetLineEndPosition(line_number - 1) + 1 + self.RefreshLineFolding(line_number) end_pos = event.GetPosition() self.StartStyling(start_pos, 0xff) @@ -449,6 +489,8 @@ last_styled_pos = current_pos state = SPACE line = "" + line_number += 1 + self.RefreshLineFolding(line_number) elif line.endswith("(*") and state != COMMENT: self.SetStyling(current_pos - last_styled_pos - 1, 31) last_styled_pos = current_pos @@ -585,6 +627,11 @@ self.ShowHighlights(start_pos, end_pos) event.Skip() + def OnMarginClick(self, event): + if event.GetMargin() == 2: + self.ToggleFold(self.LineFromPosition(event.GetPosition())) + event.Skip() + def Cut(self): self.ResetBuffer() self.CmdKeyExecute(wx.stc.STC_CMD_CUT) @@ -608,7 +655,8 @@ if self.CallTipActive(): self.CallTipCancel() key = event.GetKeyCode() - + key_handled = False + # Code completion if key == wx.WXK_SPACE and event.ControlDown(): @@ -643,7 +691,24 @@ kw.sort() self.AutoCompSetIgnoreCase(True) self.AutoCompShow(len(words[-1]), " ".join(kw)) - else: + key_handled = True + elif key == wx.WXK_RETURN or key == wx.WXK_NUMPAD_ENTER: + if self.TextSyntax == "ST": + line = self.GetCurrentLine() + indent = self.GetLineIndentation(line) + if LineStartswith(self.GetLine(line).strip(), ST_BLOCK_START_KEYWORDS): + indent += 2 + self.AddText("\n" + " " * indent) + key_handled = True + elif key == wx.WXK_BACK: + if self.TextSyntax == "ST": + line = self.GetCurrentLine() + indent = self.GetLineIndentation(line) + if self.GetLine(line).strip() == "" and indent > 0: + self.DelLineLeft() + self.AddText(" " * max(0, indent - 2)) + key_handled = True + if not key_handled: event.Skip() def OnKillFocus(self, event): diff -r c2d96ea9c14a -r aa41547baa2a plcopen/structures.py --- a/plcopen/structures.py Mon Oct 24 02:03:42 2011 +0200 +++ b/plcopen/structures.py Mon Oct 24 02:06:34 2011 +0200 @@ -639,10 +639,10 @@ # Keywords for Structured Text -ST_KEYWORDS = ["TRUE", "FALSE", "IF", "THEN", "ELSIF", "ELSE", "END_IF", "CASE", "OF", "END_CASE", - "FOR", "TO", "BY", "DO", "END_FOR", "WHILE", "DO", "END_WHILE", "REPEAT", "UNTIL", - "END_REPEAT", "EXIT", "RETURN", "NOT", "MOD", "AND", "XOR", "OR"] - +ST_BLOCK_START_KEYWORDS = ["IF", "ELSIF", "ELSE", "CASE", "FOR", "WHILE", "REPEAT"] +ST_BLOCK_END_KEYWORDS = ["END_IF", "END_CASE", "END_FOR", "END_WHILE", "END_REPEAT"] +ST_KEYWORDS = ["TRUE", "FALSE", "THEN", "OF", "TO", "BY", "DO", "DO", "UNTIL", "EXIT", + "RETURN", "NOT", "MOD", "AND", "XOR", "OR"] + ST_BLOCK_START_KEYWORDS + ST_BLOCK_END_KEYWORDS # All the keywords of IEC IEC_KEYWORDS = ["E", "TRUE", "FALSE"]