252 lines
7.6 KiB
Python
252 lines
7.6 KiB
Python
|
#!/usr/bin/env python
|
||
|
# WidgetGen.py - regenerate the ScintillaWidgetCpp.cpp and ScintillaWidgetCpp.h files
|
||
|
# Check that API includes all gtkscintilla2 functions
|
||
|
|
||
|
import sys
|
||
|
import os
|
||
|
import getopt
|
||
|
|
||
|
scintillaDirectory = "../.."
|
||
|
scintillaScriptsDirectory = os.path.join(scintillaDirectory, "scripts")
|
||
|
sys.path.append(scintillaScriptsDirectory)
|
||
|
import Face
|
||
|
from FileGenerator import GenerateFile
|
||
|
|
||
|
def underscoreName(s):
|
||
|
# Name conversion fixes to match gtkscintilla2
|
||
|
irregular = ['WS', 'EOL', 'AutoC', 'KeyWords', 'BackSpace', 'UnIndents', 'RE', 'RGBA']
|
||
|
for word in irregular:
|
||
|
replacement = word[0] + word[1:].lower()
|
||
|
s = s.replace(word, replacement)
|
||
|
|
||
|
out = ""
|
||
|
for c in s:
|
||
|
if c.isupper():
|
||
|
if out:
|
||
|
out += "_"
|
||
|
out += c.lower()
|
||
|
else:
|
||
|
out += c
|
||
|
return out
|
||
|
|
||
|
def normalisedName(s, options, role=None):
|
||
|
if options["qtStyle"]:
|
||
|
if role == "get":
|
||
|
s = s.replace("Get", "")
|
||
|
return s[0].lower() + s[1:]
|
||
|
else:
|
||
|
return underscoreName(s)
|
||
|
|
||
|
typeAliases = {
|
||
|
"position": "int",
|
||
|
"colour": "int",
|
||
|
"keymod": "int",
|
||
|
"string": "const char *",
|
||
|
"stringresult": "const char *",
|
||
|
"cells": "const char *",
|
||
|
}
|
||
|
|
||
|
def cppAlias(s):
|
||
|
if s in typeAliases:
|
||
|
return typeAliases[s]
|
||
|
else:
|
||
|
return s
|
||
|
|
||
|
understoodTypes = ["", "void", "int", "bool", "position",
|
||
|
"colour", "keymod", "string", "stringresult", "cells"]
|
||
|
|
||
|
def checkTypes(name, v):
|
||
|
understandAllTypes = True
|
||
|
if v["ReturnType"] not in understoodTypes:
|
||
|
#~ print("Do not understand", v["ReturnType"], "for", name)
|
||
|
understandAllTypes = False
|
||
|
if v["Param1Type"] not in understoodTypes:
|
||
|
#~ print("Do not understand", v["Param1Type"], "for", name)
|
||
|
understandAllTypes = False
|
||
|
if v["Param2Type"] not in understoodTypes:
|
||
|
#~ print("Do not understand", v["Param2Type"], "for", name)
|
||
|
understandAllTypes = False
|
||
|
return understandAllTypes
|
||
|
|
||
|
def arguments(v, stringResult, options):
|
||
|
ret = ""
|
||
|
p1Type = cppAlias(v["Param1Type"])
|
||
|
if p1Type:
|
||
|
ret = ret + p1Type + " " + normalisedName(v["Param1Name"], options)
|
||
|
p2Type = cppAlias(v["Param2Type"])
|
||
|
if p2Type and not stringResult:
|
||
|
if p1Type:
|
||
|
ret = ret + ", "
|
||
|
ret = ret + p2Type + " " + normalisedName(v["Param2Name"], options)
|
||
|
return ret
|
||
|
|
||
|
def printPyFile(f, options):
|
||
|
out = []
|
||
|
for name in f.order:
|
||
|
v = f.features[name]
|
||
|
if v["Category"] != "Deprecated":
|
||
|
feat = v["FeatureType"]
|
||
|
if feat in ["val"]:
|
||
|
out.append(name + "=" + v["Value"])
|
||
|
if feat in ["evt"]:
|
||
|
out.append("SCN_" + name.upper() + "=" + v["Value"])
|
||
|
return out
|
||
|
|
||
|
def printHFile(f, options):
|
||
|
out = []
|
||
|
for name in f.order:
|
||
|
v = f.features[name]
|
||
|
if v["Category"] != "Deprecated":
|
||
|
feat = v["FeatureType"]
|
||
|
if feat in ["fun", "get", "set"]:
|
||
|
if checkTypes(name, v):
|
||
|
constDeclarator = " const" if feat == "get" else ""
|
||
|
returnType = cppAlias(v["ReturnType"])
|
||
|
stringResult = v["Param2Type"] == "stringresult"
|
||
|
if stringResult:
|
||
|
returnType = "QByteArray"
|
||
|
out.append("\t" + returnType + " " + normalisedName(name, options, feat) + "(" +
|
||
|
arguments(v, stringResult, options)+
|
||
|
")" + constDeclarator + ";")
|
||
|
return out
|
||
|
|
||
|
def methodNames(f, options):
|
||
|
for name in f.order:
|
||
|
v = f.features[name]
|
||
|
if v["Category"] != "Deprecated":
|
||
|
feat = v["FeatureType"]
|
||
|
if feat in ["fun", "get", "set"]:
|
||
|
if checkTypes(name, v):
|
||
|
yield normalisedName(name, options)
|
||
|
|
||
|
def printCPPFile(f, options):
|
||
|
out = []
|
||
|
for name in f.order:
|
||
|
v = f.features[name]
|
||
|
if v["Category"] != "Deprecated":
|
||
|
feat = v["FeatureType"]
|
||
|
if feat in ["fun", "get", "set"]:
|
||
|
if checkTypes(name, v):
|
||
|
constDeclarator = " const" if feat == "get" else ""
|
||
|
featureDefineName = "SCI_" + name.upper()
|
||
|
returnType = cppAlias(v["ReturnType"])
|
||
|
stringResult = v["Param2Type"] == "stringresult"
|
||
|
if stringResult:
|
||
|
returnType = "QByteArray"
|
||
|
returnStatement = ""
|
||
|
if returnType != "void":
|
||
|
returnStatement = "return "
|
||
|
out.append(returnType + " ScintillaEdit::" + normalisedName(name, options, feat) + "(" +
|
||
|
arguments(v, stringResult, options) +
|
||
|
")" + constDeclarator + " {")
|
||
|
returns = ""
|
||
|
if stringResult:
|
||
|
returns += " " + returnStatement + "TextReturner(" + featureDefineName + ", "
|
||
|
if "*" in cppAlias(v["Param1Type"]):
|
||
|
returns += "(uptr_t)"
|
||
|
if v["Param1Name"]:
|
||
|
returns += normalisedName(v["Param1Name"], options)
|
||
|
else:
|
||
|
returns += "0"
|
||
|
returns += ");"
|
||
|
else:
|
||
|
returns += " " + returnStatement + "send(" + featureDefineName + ", "
|
||
|
if "*" in cppAlias(v["Param1Type"]):
|
||
|
returns += "(uptr_t)"
|
||
|
if v["Param1Name"]:
|
||
|
returns += normalisedName(v["Param1Name"], options)
|
||
|
else:
|
||
|
returns += "0"
|
||
|
returns += ", "
|
||
|
if "*" in cppAlias(v["Param2Type"]):
|
||
|
returns += "(sptr_t)"
|
||
|
if v["Param2Name"]:
|
||
|
returns += normalisedName(v["Param2Name"], options)
|
||
|
else:
|
||
|
returns += "0"
|
||
|
returns += ");"
|
||
|
out.append(returns)
|
||
|
out.append("}")
|
||
|
out.append("")
|
||
|
return out
|
||
|
|
||
|
def gtkNames():
|
||
|
# The full path on my machine: should be altered for anyone else
|
||
|
p = "C:/Users/Neil/Downloads/wingide-source-4.0.1-1/wingide-source-4.0.1-1/external/gtkscintilla2/gtkscintilla.c"
|
||
|
with open(p) as f:
|
||
|
for l in f.readlines():
|
||
|
if "gtk_scintilla_" in l:
|
||
|
name = l.split()[1][14:]
|
||
|
if '(' in name:
|
||
|
name = name.split('(')[0]
|
||
|
yield name
|
||
|
|
||
|
def usage():
|
||
|
print("WidgetGen.py [-c|--clean][-h|--help][-u|--underscore-names]")
|
||
|
print("")
|
||
|
print("Generate full APIs for ScintillaEdit class and ScintillaConstants.py.")
|
||
|
print("")
|
||
|
print("options:")
|
||
|
print("")
|
||
|
print("-c --clean remove all generated code from files")
|
||
|
print("-h --help display this text")
|
||
|
print("-u --underscore-names use method_names consistent with GTK+ standards")
|
||
|
|
||
|
def readInterface(cleanGenerated):
|
||
|
f = Face.Face()
|
||
|
if not cleanGenerated:
|
||
|
f.ReadFromFile("../../include/Scintilla.iface")
|
||
|
return f
|
||
|
|
||
|
def main(argv):
|
||
|
# Using local path for gtkscintilla2 so don't default to checking
|
||
|
checkGTK = False
|
||
|
cleanGenerated = False
|
||
|
qtStyleInterface = True
|
||
|
# The --gtk-check option checks for full coverage of the gtkscintilla2 API but
|
||
|
# depends on a particular directory so is not mentioned in --help.
|
||
|
opts, args = getopt.getopt(argv, "hcgu", ["help", "clean", "gtk-check", "underscore-names"])
|
||
|
for opt, arg in opts:
|
||
|
if opt in ("-h", "--help"):
|
||
|
usage()
|
||
|
sys.exit()
|
||
|
elif opt in ("-c", "--clean"):
|
||
|
cleanGenerated = True
|
||
|
elif opt in ("-g", "--gtk-check"):
|
||
|
checkGTK = True
|
||
|
elif opt in ("-u", "--underscore-names"):
|
||
|
qtStyleInterface = False
|
||
|
|
||
|
options = {"qtStyle": qtStyleInterface}
|
||
|
f = readInterface(cleanGenerated)
|
||
|
try:
|
||
|
GenerateFile("ScintillaEdit.cpp.template", "ScintillaEdit.cpp",
|
||
|
"/* ", True, printCPPFile(f, options))
|
||
|
GenerateFile("ScintillaEdit.h.template", "ScintillaEdit.h",
|
||
|
"/* ", True, printHFile(f, options))
|
||
|
GenerateFile("../ScintillaEditPy/ScintillaConstants.py.template",
|
||
|
"../ScintillaEditPy/ScintillaConstants.py",
|
||
|
"# ", True, printPyFile(f, options))
|
||
|
if checkGTK:
|
||
|
names = set(methodNames(f))
|
||
|
#~ print("\n".join(names))
|
||
|
namesGtk = set(gtkNames())
|
||
|
for name in namesGtk:
|
||
|
if name not in names:
|
||
|
print(name, "not found in Qt version")
|
||
|
for name in names:
|
||
|
if name not in namesGtk:
|
||
|
print(name, "not found in GTK+ version")
|
||
|
except:
|
||
|
raise
|
||
|
|
||
|
if cleanGenerated:
|
||
|
for file in ["ScintillaEdit.cpp", "ScintillaEdit.h", "../ScintillaEditPy/ScintillaConstants.py"]:
|
||
|
try:
|
||
|
os.remove(file)
|
||
|
except OSError:
|
||
|
pass
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
main(sys.argv[1:])
|