#!/usr/bin/env python """ Convert scintilla/include/Scintilla.iface to an HTML document. ./iface-to-doc.py \ scintilla/include/Scintilla.iface \ > ScintillaLua.html """ import re def Parse_comment(line): return line def Parse_cat(line): return line Parse_fun_reLine = re.compile(r'(\S+)\s+(\S+?)\s*=\s*\d+\s*\(\s*(.*?)\s*\)') def Parse_fun(line): ret,name,args = Parse_fun_reLine.match(line).groups() if ret == 'void': ret = [] else: ret = [ret] args = [ i.strip() for i in args.split(',') ] args = [ i.split() for i in args if i and i != 'void' ] temp = args args = [] for i in temp: if i == ["int", "length"]: continue if i and i[0] == "stringresult": ret.insert(0, "string") continue args.append(i) return ret, name, args def Parse_get(line): return Parse_fun(line) def Parse_set(line): return Parse_fun(line) Parse_val_reLine = re.compile(r'(\S+?)\s*=\s*(.+)') def Parse_val(line): name, value = Parse_val_reLine.match(line).groups() return name, value def Parse_evt(line): return Parse_fun(line) def Parse_enu(line): name, prefixes = Parse_val_reLine.match(line).groups() return name, prefixes.split() def Parse_lex(line): name, prefixes = Parse_val_reLine.match(line).groups() prefixes = prefixes.split() value = prefixes[0] ; prefixes = prefixes[1:] return name, value, prefixes Parse = \ { "#" : Parse_comment , "cat": Parse_cat , "fun": Parse_fun , "get": Parse_get , "set": Parse_set , "val": Parse_val , "evt": Parse_evt , "enu": Parse_enu , "lex": Parse_lex } def Phase1(sFileIn): """ Load a file and parse each line """ lines = dict() reLine = re.compile(r'(\S+)\s+(.*)') iLine = 0 for line in open(sFileIn): line = line.strip() iLine += 1 if not line: lines[iLine] = ["", None] continue if line.startswith('##' ): continue if line.startswith('#!' ): continue type, line = reLine.match(line).groups() lines[iLine] = [type, Parse[type](line)] return lines def Phase2(input): """ Attribute comments to their next line `Commented' null lines will remain """ lines = dict() currentComment = [] for line in sorted(input): type, contents = input[line] if type == '#': currentComment.append(contents) continue if not currentComment and not type: continue theComment = ' '.join(currentComment) currentComment = [] lines[line] = [type, contents, theComment] return lines def Phase3(input): """ Getters and Setters are united Impossible getters and setters are re-marked as 'fun' """ getsets = dict() for line, (type, contents, comment) in input.items(): if type == "get": prop = contents[1].replace('Get', '', 1) index = 0 elif type == "set": prop = contents[1].replace('Set', '', 1) index = 1 else: continue if prop not in getsets: getsets[prop] = [None, None] getsets[prop][index] = (line, contents, comment) properties = dict() for prop, (g,s) in getsets.items(): bOK = True if g: gline, (gret, gname, gargs), gcomment = g if len(gret) != 1 or gargs: bOK = False if s: sline, (sret, sname, sargs), scomment = s if sret or len(sargs) != 1: bOK = False if g and s and bOK: if gret[0] != sargs[0][0]: print >> sys.stderr, "Warning: property getter and setter has different type:", gname formline = min(gline, sline) lattline = max(gline, sline) comment = [] if gcomment: comment.append('R: ' + gcomment) if scomment: comment.append('W: ' + scomment) comment = '\n'.join(comment) input[formline] = ["get", ('RW', ' '.join(sargs[0]), prop), comment] del input[lattline] continue if g and bOK: input[gline] = ["get", ('R', gret[0], prop), gcomment] continue if s and bOK: input[sline] = ["get", ('W', ' '.join(sargs[0]), prop), scomment] continue if g: input[gline][0] = "fun" if s: input[sline][0] = "fun" return input def Phase4(input): """ Unite val to enu and lex """ vals = dict() enus = [] lexs = [] for line, (type, contents, comment) in input.items(): if type == "val": vals[line] = (contents, comment) elif type == "enu": enus.append((line, contents, comment)) elif type == "lex": lexs.append((line, contents, comment)) deletedLines = set() for line, (name, prefixes), comment in enus: members = dict() for vline, ((vname, vvalue), vcomment) in vals.items(): if any(vname.startswith(p) for p in prefixes): members[vline] = (vname, vvalue, vcomment) deletedLines.add(vline) members = [members[k] for k in sorted(members)] input[line] = ["enu", (name, members), comment] for line, (name, value, prefixes), comment in lexs: members = dict() for vline, ((vname, vvalue), vcomment) in vals.items(): if any(vname.startswith(p) for p in prefixes): members[vline] = (vname, vvalue, vcomment) deletedLines.add(vline) members = [members[k] for k in sorted(members)] input[line] = ["lex", (name, value, members), comment] for line in deletedLines: del input[line] return input EscapeHTML_re = re.compile(r'[<>&\n]') EscapeHTML_dict = {'<': '<', '>': '>', '&': '&', '\n': '
\n'} def EscapeHTML(text): """ \n ->
<>& -> <>& """ return EscapeHTML_re.sub \ ( lambda m: EscapeHTML_dict[m.group()] , text ) def ToHTML_comment(contents, comment): return '

%s

' % EscapeHTML(comment) def ToHTML_cat(contents, comment): header = '

%s

' % contents if comment: header += '\n

%s

' % EscapeHTML(comment) return header def ToHTML_fun(contents, comment): ret, name, args = contents if ret: ret = ' : ' + ', '.join(ret) else: ret = '' args = [' '.join(i) for i in args] args = ', '.join(args) return '\n'.join \ ([ '
' , '\t
%s(%s)%s
' % (name, args, ret) , '\t
%s
' % EscapeHTML(comment) , '
' ]) def ToHTML_get(contents, comment): type, args, name = contents if args: args = ' : ' + args return '\n'.join \ ([ '
' , '\t
%s [%s]%s
' % (name, type, args) , '\t
%s
' % EscapeHTML(comment) , '
' ]) def ToHTML_val(contents, comment): name, val = contents return '\n'.join \ ([ '
' , '\t
%s = %s
' % (name, val) , '\t
%s
' % EscapeHTML(comment) , '
' ]) def ToHTML_evt(contents, comment): ret, name, args = contents if ret: ret = ' : ' + ', '.join(ret) else: ret = '' args = [' '.join(i) for i in args] args = ', '.join(args) return '\n'.join \ ([ '
' , '\t
%s(%s)%s
' % (name, args, ret) , '\t
%s
' % EscapeHTML(comment) , '
' ]) def ToHTML_enu(contents, comment): enuname, members = contents lines = \ [ '
' , '\t
%s
' % enuname , '\t
' ] if comment: lines.append('\t\t' + EscapeHTML(comment)) lines.append('\t\t
') return '\n'.join(lines) def ToHTML_lex(contents, comment): lexname, lexvalue, members = contents lines = \ [ '
' , '\t
%s = %s
' % (lexname, lexvalue) , '\t
' ] if comment: lines.append('\t\t' + EscapeHTML(comment)) lines.append('\t\t
') return '\n'.join(lines) def ToHTML_HIDE(contents, comment): return "" ToHTML = \ { "" : ToHTML_comment , "cat": ToHTML_cat , "fun": ToHTML_fun , "get": ToHTML_get , "val": ToHTML_val , "evt": ToHTML_HIDE , "enu": ToHTML_enu , "lex": ToHTML_HIDE } ToHTML_header = \ """ Spurious manual of SciTE Lua

SciTE/Scintilla functions for Lua

Those reddish are constants. They are global.

Those bluish are methods of the objects 'editor' and 'output'. They are called like 'editor:AddText("_")'

Those greenish are properties of 'editor' and 'output'; either 'R' (readable) or 'W' (writable) or both. They are accessed like 'editor.TabWidth = 20'


""" ToHTML_footer = \ """

This document is a simple conversion of Scintilla's interface file, the license of which is noted in Scintilla License.

""" def Phase5(input): """ lines to to Html elements """ htmls = [] for line in sorted(input): type, contents, comment = input[line] elem = ToHTML[type](contents, comment) if elem: htmls.append(elem) return htmls def main(): import os import sys sSrcTopDir = sys.argv[1] sIFaceFile = os.path.join\ ( sSrcTopDir, "scintilla", "include", "Scintilla.iface" ) lines = Phase1(sIFaceFile) lines = Phase2(lines) lines = Phase3(lines) lines = Phase4(lines) htmls = Phase5(lines) print ToHTML_header for elem in htmls: print elem print ToHTML_footer main()