Skip to content

Commit 0df4813

Browse files
committed
Use iface file to generate SciIFaceTable
1 parent e82cf8c commit 0df4813

File tree

6 files changed

+5371
-0
lines changed

6 files changed

+5371
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,4 @@ $RECYCLE.BIN/
157157
LuaDist
158158
gh-pages
159159
/docs_gen/Editor.lua
160+
*.pyc

scripts/Face.py

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# Face.py - module for reading and parsing Scintilla.iface file
2+
# Implemented 2000 by Neil Hodgson [email protected]
3+
# Released to the public domain.
4+
# Requires Python 2.5 or later
5+
6+
def sanitiseLine(line):
7+
if line[-1:] == '\n': line = line[:-1]
8+
if line.find("##") != -1:
9+
line = line[:line.find("##")]
10+
line = line.strip()
11+
return line
12+
13+
def decodeFunction(featureVal):
14+
retType, rest = featureVal.split(" ", 1)
15+
nameIdent, params = rest.split("(")
16+
name, value = nameIdent.split("=")
17+
params, rest = params.split(")")
18+
param1, param2 = params.split(",")
19+
return retType, name, value, param1, param2
20+
21+
def decodeEvent(featureVal):
22+
retType, rest = featureVal.split(" ", 1)
23+
nameIdent, params = rest.split("(")
24+
name, value = nameIdent.split("=")
25+
return retType, name, value
26+
27+
def decodeParam(p):
28+
param = p.strip()
29+
type = ""
30+
name = ""
31+
value = ""
32+
if " " in param:
33+
type, nv = param.split(" ")
34+
if "=" in nv:
35+
name, value = nv.split("=")
36+
else:
37+
name = nv
38+
return type, name, value
39+
40+
class Face:
41+
42+
def __init__(self):
43+
self.order = []
44+
self.features = {}
45+
self.values = {}
46+
self.events = {}
47+
48+
def ReadFromFile(self, name):
49+
currentCategory = ""
50+
currentComment = []
51+
currentCommentFinished = 0
52+
file = open(name)
53+
for line in file.readlines():
54+
line = sanitiseLine(line)
55+
if line:
56+
if line[0] == "#":
57+
if line[1] == " ":
58+
if currentCommentFinished:
59+
currentComment = []
60+
currentCommentFinished = 0
61+
currentComment.append(line[2:])
62+
else:
63+
currentCommentFinished = 1
64+
featureType, featureVal = line.split(" ", 1)
65+
if featureType in ["fun", "get", "set"]:
66+
try:
67+
retType, name, value, param1, param2 = decodeFunction(featureVal)
68+
except ValueError:
69+
print("Failed to decode %s" % line)
70+
raise
71+
p1 = decodeParam(param1)
72+
p2 = decodeParam(param2)
73+
self.features[name] = {
74+
"FeatureType": featureType,
75+
"ReturnType": retType,
76+
"Value": value,
77+
"Param1Type": p1[0], "Param1Name": p1[1], "Param1Value": p1[2],
78+
"Param2Type": p2[0], "Param2Name": p2[1], "Param2Value": p2[2],
79+
"Category": currentCategory, "Comment": currentComment
80+
}
81+
if value in self.values:
82+
raise Exception("Duplicate value " + value + " " + name)
83+
self.values[value] = 1
84+
self.order.append(name)
85+
currentComment = []
86+
elif featureType == "evt":
87+
retType, name, value = decodeEvent(featureVal)
88+
self.features[name] = {
89+
"FeatureType": featureType,
90+
"ReturnType": retType,
91+
"Value": value,
92+
"Category": currentCategory, "Comment": currentComment
93+
}
94+
if value in self.events:
95+
raise Exception("Duplicate event " + value + " " + name)
96+
self.events[value] = 1
97+
self.order.append(name)
98+
elif featureType == "cat":
99+
currentCategory = featureVal
100+
elif featureType == "val":
101+
try:
102+
name, value = featureVal.split("=", 1)
103+
except ValueError:
104+
print("Failure %s" % featureVal)
105+
raise Exception()
106+
self.features[name] = {
107+
"FeatureType": featureType,
108+
"Category": currentCategory,
109+
"Value": value }
110+
self.order.append(name)
111+
elif featureType == "enu" or featureType == "lex":
112+
name, value = featureVal.split("=", 1)
113+
self.features[name] = {
114+
"FeatureType": featureType,
115+
"Category": currentCategory,
116+
"Value": value,
117+
"Comment": currentComment }
118+
self.order.append(name)
119+
currentComment = []
120+

scripts/FileGenerator.py

+177
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
#!/usr/bin/env python
2+
# FileGenerator.py - implemented 2013 by Neil Hodgson [email protected]
3+
# Released to the public domain.
4+
5+
# Generate or regenerate source files based on comments in those files.
6+
# May be modified in-place or a template may be generated into a complete file.
7+
# Requires Python 2.5 or later
8+
# The files are copied to a string apart from sections between a
9+
# ++Autogenerated comment and a --Autogenerated comment which is
10+
# generated by the CopyWithInsertion function. After the whole string is
11+
# instantiated, it is compared with the target file and if different the file
12+
# is rewritten.
13+
14+
from __future__ import with_statement
15+
16+
import codecs, os, re, string, sys
17+
18+
lineEnd = "\r\n" if sys.platform == "win32" else "\n"
19+
20+
def UpdateFile(filename, updated):
21+
""" If the file contents are different to updated then copy updated into the
22+
file else leave alone so Mercurial and make don't treat it as modified. """
23+
newOrChanged = "Changed"
24+
try:
25+
with codecs.open(filename, "r", "utf-8") as infile:
26+
original = infile.read()
27+
if updated == original:
28+
# Same as before so don't write
29+
return
30+
os.unlink(filename)
31+
except IOError: # File is not there yet
32+
newOrChanged = "New"
33+
with codecs.open(filename, "w", "utf-8") as outfile:
34+
outfile.write(updated)
35+
print("%s %s" % (newOrChanged, filename))
36+
37+
# Automatically generated sections contain start and end comments,
38+
# a definition line and the results.
39+
# The results are replaced by regenerating based on the definition line.
40+
# The definition line is a comment prefix followed by "**".
41+
# If there is a digit after the ** then this indicates which list to use
42+
# and the digit and next character are not part of the definition
43+
# Backslash is used as an escape within the definition line.
44+
# The part between \( and \) is repeated for each item in the list.
45+
# \* is replaced by each list item. \t, and \n are tab and newline.
46+
# If there is no definition line than the first list is copied verbatim.
47+
# If retainDefs then the comments controlling generation are copied.
48+
def CopyWithInsertion(input, commentPrefix, retainDefs, lists):
49+
copying = 1
50+
generated = False
51+
listid = 0
52+
output = []
53+
for line in input.splitlines(0):
54+
isStartGenerated = line.lstrip().startswith(commentPrefix + "++Autogenerated")
55+
if copying and not isStartGenerated:
56+
output.append(line)
57+
if isStartGenerated:
58+
if retainDefs:
59+
output.append(line)
60+
copying = 0
61+
generated = False
62+
elif not copying and not generated:
63+
# Generating
64+
if line.startswith(commentPrefix + "**"):
65+
# Pattern to transform input data
66+
if retainDefs:
67+
output.append(line)
68+
definition = line[len(commentPrefix + "**"):]
69+
if (commentPrefix == "<!--") and (" -->" in definition):
70+
definition = definition.replace(" -->", "")
71+
listid = 0
72+
if definition[0] in string.digits:
73+
listid = int(definition[:1])
74+
definition = definition[2:]
75+
# Hide double slashes as a control character
76+
definition = definition.replace("\\\\", "\001")
77+
# Do some normal C style transforms
78+
definition = definition.replace("\\n", "\n")
79+
definition = definition.replace("\\t", "\t")
80+
# Get the doubled backslashes back as single backslashes
81+
definition = definition.replace("\001", "\\")
82+
startRepeat = definition.find("\\(")
83+
endRepeat = definition.find("\\)")
84+
intro = definition[:startRepeat]
85+
out = ""
86+
if intro.endswith("\n"):
87+
pos = 0
88+
else:
89+
pos = len(intro)
90+
out += intro
91+
middle = definition[startRepeat+2:endRepeat]
92+
for i in lists[listid]:
93+
item = middle.replace("\\*", i)
94+
if pos and (pos + len(item) >= 80):
95+
out += "\\\n"
96+
pos = 0
97+
out += item
98+
pos += len(item)
99+
if item.endswith("\n"):
100+
pos = 0
101+
outro = definition[endRepeat+2:]
102+
out += outro
103+
out = out.replace("\n", lineEnd) # correct EOLs in generated content
104+
output.append(out)
105+
else:
106+
# Simple form with no rule to transform input
107+
output.extend(lists[0])
108+
generated = True
109+
if line.lstrip().startswith(commentPrefix + "--Autogenerated") or \
110+
line.lstrip().startswith(commentPrefix + "~~Autogenerated"):
111+
copying = 1
112+
if retainDefs:
113+
output.append(line)
114+
#output = [line.rstrip(" \t") for line in output] # trim trailing whitespace
115+
return lineEnd.join(output) + lineEnd
116+
117+
def GenerateFile(inpath, outpath, commentPrefix, retainDefs, *lists):
118+
"""Generate 'outpath' from 'inpath'.
119+
"""
120+
121+
try:
122+
with codecs.open(inpath, "r", "UTF-8") as infile:
123+
original = infile.read()
124+
updated = CopyWithInsertion(original, commentPrefix,
125+
retainDefs, lists)
126+
UpdateFile(outpath, updated)
127+
except IOError:
128+
print("Can not open %s" % inpath)
129+
130+
def Generate(inpath, outpath, commentPrefix, *lists):
131+
"""Generate 'outpath' from 'inpath'.
132+
"""
133+
GenerateFile(inpath, outpath, commentPrefix, inpath == outpath, *lists)
134+
135+
def Regenerate(filename, commentPrefix, *lists):
136+
"""Regenerate the given file.
137+
"""
138+
Generate(filename, filename, commentPrefix, *lists)
139+
140+
def UpdateLineInPlistFile(path, key, value):
141+
"""Replace a single string value preceded by 'key' in an XML plist file.
142+
"""
143+
lines = []
144+
keyCurrent = ""
145+
with codecs.open(path, "rb", "utf-8") as f:
146+
for l in f.readlines():
147+
ls = l.strip()
148+
if ls.startswith("<key>"):
149+
keyCurrent = ls.replace("<key>", "").replace("</key>", "")
150+
elif ls.startswith("<string>"):
151+
if keyCurrent == key:
152+
start, tag, rest = l.partition("<string>")
153+
val, etag, end = rest.partition("</string>")
154+
l = start + tag + value + etag + end
155+
lines.append(l)
156+
contents = "".join(lines)
157+
UpdateFile(path, contents)
158+
159+
def UpdateLineInFile(path, linePrefix, lineReplace):
160+
lines = []
161+
updated = False
162+
with codecs.open(path, "r", "utf-8") as f:
163+
for l in f.readlines():
164+
l = l.rstrip()
165+
if not updated and l.startswith(linePrefix):
166+
lines.append(lineReplace)
167+
updated = True
168+
else:
169+
lines.append(l)
170+
contents = lineEnd.join(lines) + lineEnd
171+
UpdateFile(path, contents)
172+
173+
def ReplaceREInFile(path, match, replace):
174+
with codecs.open(path, "r", "utf-8") as f:
175+
contents = f.read()
176+
contents = re.sub(match, replace, contents)
177+
UpdateFile(path, contents)

0 commit comments

Comments
 (0)