syntax colorizer - ponyatov/orth GitHub Wiki

Any programmers editor must have two minimal functions:

  • syntax coloring
  • language element completion

We will do syntax coloring using ORTH syntax parser written with PLY library.

## word name or undefined
t_ANY = r'[a-zA-Z0-9_]+'
## compiler words
t_COMPILER = r'[\:\;]{1}'

## lexer error callback
def t_error(t): raise SyntaxError(t)

## FORTH coloring lexer
lexer = lex.lex()
  • wx.stc styling.
## get monospace font from system
font = wx.Font(14, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)
editor.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT,
                    "face:%s,size:%d" % (font.GetFaceName(), font.GetPointSize()))
## default style
style_DEFAULT = wx.stc.STC_STYLE_DEFAULT
editor.StyleSetSpec(style_DEFAULT,'fore:#000000')
## comment
style_COMMENT = 1
editor.StyleSetSpec(style_COMMENT,'fore:#0000FF,normal')
## number
style_NUMBER = 2
editor.StyleSetSpec(style_NUMBER,'fore:#008800')
## colon definition
style_COMPILER = 3
editor.StyleSetSpec(style_COMPILER,'fore:#FF0000,bold')

## colorer callback
def onStyle(event):
    # feed lexer
    text = editor.GetValue() ; lexer.input(text)
    # restart styles
#     editor.StartStyling(0,0xFF) ; editor.SetStyling(len(text),style_DEFAULT)
    # process source code via coloring lexer
    while True:
        token = lexer.token()
        if not token: break
        editor.StartStyling(token.lexpos,0xFF)
        if token.type == 'COMMENT':
            editor.SetStyling(len(token.value),style_COMMENT)
        elif token.type in ['NUMBER','INT','HEX','BIN']:
            editor.SetStyling(token.length,self.style_NUMBER)
        elif token.type == 'COMPILER':
            editor.SetStyling(len(token.value),style_COMPILER)
        else:
            editor.SetStyling(0,0)
            
editor.Bind(wx.stc.EVT_STC_STYLENEEDED,onStyle)

Debug

Variant of colorizer embedded into GUI Editor class

class Editor(wx.Frame):
    def initEditor(self):
        self.initColorizer()
    ## init colorizer styles & lexer
    def initColorizer(self):
        ## get monospace font from system
        self.font = wx.Font(14, wx.FONTFAMILY_MODERN,
            wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)
        ## load default editor style
        self.editor.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT,
            "face:%s,size:%d" % (
                self.font.GetFaceName(), self.font.GetPointSize()))

        # configure styles
        ## default style
        self.style_DEFAULT = wx.stc.STC_STYLE_DEFAULT
        self.editor.StyleSetSpec(self.style_DEFAULT,'fore:#000000')
        ## comment
        self.style_COMMENT = 1
        self.editor.StyleSetSpec(self.style_COMMENT,'fore:#0000FF,normal')
        ## number
        self.style_NUMBER = 2
        self.editor.StyleSetSpec(self.style_NUMBER,'fore:#008800')
        ## colon definition
        self.style_COMPILER = 3
        self.editor.StyleSetSpec(self.style_COMPILER,'fore:#FF0000,bold')
        # bind colorizer event
        self.editor.Bind(wx.stc.EVT_STC_STYLENEEDED,self.onStyle)
    ## colorizer  callback
    def onStyle(self,event):
        # feed lexer
        text = self.editor.GetValue() ; lexer.input(text)
        # restart styles
        # editor.StartStyling(0,0xFF) ; editor.SetStyling(len(text),style_DEFAULT)
        # process source code via coloring lexer
        while True:
            token = lexer.token()
            if not token: break
            self.editor.StartStyling(token.lexpos,0xFF)
            if token.type == 'COMMENT':
                self.editor.SetStyling(len(token.value),self.style_COMMENT)
            elif token.type in ['NUMBER','INT','HEX','BIN']:
                self.editor.SetStyling(token.length,self.style_NUMBER)
            elif token.type == 'COMPILER':
                self.editor.SetStyling(len(token.value),self.style_COMPILER)
            else:
                self.editor.SetStyling(0,0)