Welcome, guest | Sign In | My Account | Store | Cart

Applies python syntax highlighting to all the TextShapes (i.e. text boxes) in an OpenOffice document with the "code" graphic style applied. Typical usage is for highlighting code snippets in an Impress presentation. I have the "HighlightPython" function assigned to a menu item in my Tools menu for easy access.

Python, 108 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
import re
import keyword

###Following are some crude regexes which I use to tokenise a text object comprising python code
multiline_pat = "(\'\'\'|\"\"\")"+r"(.|\n)*?\1"
singleline_pat = "(\'|\")"+r".*?\1"
kw_pat = r"\b("+"|".join(keyword.kwlist)+r")\b"
number_pat = r"\b\d+\b"
def_pat = r"((?<=def )\w+)|((?<=class )\w+)"
comment_pat = r"#.*(\n|$)"

###Define some colors for each token type
kwcolor = RGB( 255, 0, 0 )
numberColor = RGB( 128, 50, 0)
defColor = RGB(0,0,255)
StrColor = RGB(125,125,0) 
CommentColor = RGB(128,128,128)
MultiStrColor = RGB(0,255,0)

def RGB( nRed, nGreen, nBlue ):
    """Return an integer which repsents a color.
    The color is specified in RGB notation.
    Each of nRed, nGreen and nBlue must be a number from 0 to 255.
    """
    return (int( nRed ) & 255) << 16 | (int( nGreen ) & 255) << 8 | (int( nBlue ) & 255) 

def HighlightPython():
    """
    Main function for highlighting python code in a document. Must be called 'in process'.
    """
    ctx = XSCRIPTCONTEXT
    doc = ctx.getDocument()
    HighlightAll(doc)

def _highlight(pat, data, csr, color):
    """
    Does the actual coloring of text
    
    @param pat: a regex to find patterns to highlight
    @param data: the source text to use, a string
    @param csr: a OOo TextCursor instance
    @param color: an integer representing a color. use the RGB() function above to calculate
    """
    pos=0
    csr.gotoStart(False)
    print "pattern:", pat
    for match in re.finditer(pat, data):
        start, end = match.span()
        print "match:", data[start:end]
        diff = start-pos
        csr.goRight(diff, False)
        csr.goRight(end-start,True)
        csr.CharColor = color
        pos=end
    
def ColourTextBox(txt):
    """
    Highlights a single TextShape item
    """
    data = txt.String
    csr = txt.createTextCursor()
    _highlight(kw_pat, data, csr, kwcolor)
    _highlight(number_pat, data, csr, numberColor)
    _highlight(def_pat, data, csr, defColor )
    _highlight(singleline_pat, data, csr, StrColor)
    _highlight(comment_pat, data, csr, CommentColor )
    _highlight(multiline_pat, data, csr, MultiStrColor )
    
    
def RemoteGetDoc():
    """
    Retrieve the document instance when accessing OOo 'out of process', using uno over a socket.
    """
    import uno
    localContext = uno.getComponentContext()
    resolver = localContext.ServiceManager.createInstanceWithContext(
                    "com.sun.star.bridge.UnoUrlResolver", localContext )
    ctx = resolver.resolve( "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext" )
    smgr = ctx.ServiceManager
    desktop = smgr.createInstanceWithContext( "com.sun.star.frame.Desktop",ctx)
    doc = desktop.getCurrentComponent()
    return doc
    
def HighlightAll(doc):
    """
    Apply syntax highlighting to all TextShapes in the document which have the "code"
    graphic style applied to them
    """
    styles = doc.StyleFamilies.getByName(u"graphics")
    code = styles.getByName(u"code")
    pages = doc.DrawPages
    count = pages.getCount()
    for idx in xrange(count):
        page = pages.getByIndex(idx)
        count = page.getCount()
        for item_idx in xrange(count):
            item = page.getByIndex(item_idx)
            if 'com.sun.star.drawing.TextShape' in item.SupportedServiceNames:
                style = item.Style
                if style==code:
                    ColourTextBox(item)
    
g_exportedScripts = (HighlightPython,)
    
if __name__=="__main__":
    #Script testing is easiest using remote uno over a socket
    doc = RemoteGetDoc()
    HighlightAll(doc)
    
    

To use this script, you need to define a graphic style named "code". I give this a monospaced font. You apply this to all text-frames containing python code. Then call the HighlightPython function from the OOo macros menu.

The script uses simple regexes to find each bit of text to color. A more robust method would be to exploit the Pygments library to tokenise the code instead (or learn more about regexes than I do).

The most useful aspect of the script is to demonstrate the OOo API used to find objects by their graphic-style, iterating over text with a Cursor object and coloring the text.

2 comments

virtueoftheabsurd 14 years, 9 months ago  # | flag

How do I get this script to work in OOo? I have it saved in ~/.openoffice.org/3/user/Scripts/python, but it comes up in the run macro dialog as a library with no macros. This shouldn't be--my understanding is that each function with no arguments should appear as a macro... Why might this be happening?

Bryan Cole (author) 14 years, 8 months ago  # | flag

The g_exportedScripts variable defines which functions should be made available in the macros menu.

I've run into problems with python scripts in User folders not appearing in the macros menu. This is a OOo bug. Try putting the script in the system macros folder (e.g. /usr/lib/openoffice.org/basis3.1/share/Scripts/python/ , in Fedora11 although it may be somewhere else on other OSs/distros. Obviously you need root access to do this). Upgrading OOo may also fix this.