summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/asymptote/GUI/xasyFile.py
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/asymptote/GUI/xasyFile.py')
-rwxr-xr-xMaster/texmf-dist/asymptote/GUI/xasyFile.py364
1 files changed, 66 insertions, 298 deletions
diff --git a/Master/texmf-dist/asymptote/GUI/xasyFile.py b/Master/texmf-dist/asymptote/GUI/xasyFile.py
index 7516fc7d3b5..eee6d69a856 100755
--- a/Master/texmf-dist/asymptote/GUI/xasyFile.py
+++ b/Master/texmf-dist/asymptote/GUI/xasyFile.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
###########################################################################
#
# xasyFile implements the loading, parsing, and saving of an xasy file.
@@ -10,306 +10,74 @@
############################################################################
from string import *
-from xasy2asy import *
+import xasy2asy as x2a
+import io
import re
-class xasyParseError(Exception):
- """A parsing error"""
- pass
-
-class xasyFileError(Exception):
- """An i/o error or other error not related to parsing"""
- pass
-
-def parseFile(inFile):
- """Parse a file returning a list of xasyItems"""
- lines = inFile.read()
- lines = lines.splitlines()
- #lines = [line for line in lines.splitlines() if not line.startswith("//")]
- result = []
- if lines[0] != "initXasyMode();":
- raise xasyFileError("Invalid file format: First line must be \"initXasyMode();\"")
- lines.pop(0)
- lineCount = 2
- lineNum = len(lines)
- while lineNum > 0:
- line = lines[0]
- lines.pop(0)
- if not line.isspace() and len(line)>0:
- try:
- #print ("Line {:d}: {:s}".format(lineCount,line))
- lineResult = parseLine(line.strip(),lines)
- except:
- raise xasyParseError("Parsing error: line {:d} in {:s}\n{:s}".format(lineCount,inFile.name,line))
-
- if lineResult != None:
- result.append(lineResult)
- #print ("\tproduced: {:s}".format(str(lineResult)))
- lineCount += lineNum-len(lines)
- lineNum = len(lines)
- return result
-
-transformPrefix = "xformStack"
-scriptPrefix = "startScript(); {"
-scriptSuffix = "} endScript();"
-def extractScript(lines):
- """Find the code belonging to a script item"""
- theScript = ""
- line = lines.pop(0)
- level = 1
- while level > 0:
- check = line.lstrip()
- while check.endswith(scriptSuffix):
- level -= 1
- line = line[:len(line)-len(scriptSuffix)]
- check = line.lstrip()
- if check.startswith(scriptPrefix):
- level += 1
- theScript += line + "\n"
- if level > 0:
- line = lines.pop(0)
-
- global pendingTransformsD
- ts = pendingTransformsD[:]
- pendingTransformsD = []
- return xasyScript(None,script=theScript,transforms=ts[:])
-
-pendingTransforms = []
-pendingTransformsD = []
-def addTransform(index,t,active=1):
- """Place a transform in the list of transforms, expanding the list as needed"""
- while len(pendingTransformsD) < index+1:
- pendingTransformsD.append(identity())
- deleted = int(active==0)
- pendingTransformsD[index]=asyTransform(t,deleted)
-
-def parseIndexedTransforms(args):
- """Parse a list of indexedTransforms, adding them to the current list of transforms"""
- global pendingTransformsD
- pendingTransformsD = []
- args = args.replace("indexedTransform","")
- false = 0
- tList = [eval(a) for a in ")?(".join(args.split("),(")).split("?")]
- for a in tList:
- addTransform(*a)
-
-def parseTransformExpression(line):
- """Parse statements related to the xformStack
-
- Syntax:
- xformStack.push(transform)
- e.g.: xformStack.push((0,0,1,0,0,1)); //the identity
- xformStack.add(indexedTransform(index,transform)[,...])
- e.g.: xformStack.add(indexedTransform(1,(0,0,1,0,0,1));
- """
- global pendingTransforms
- stackCmd = line[len(transformPrefix)+1:line.find("(")]
- if line[-2:] != ");":
- raise xasyParseError("Invalid syntax")
- args = line[line.find("(")+1:-2]
- if stackCmd == "push":
- t = asyTransform(eval(args))
- pendingTransforms.append(t)
- elif stackCmd == "add":
- parseIndexedTransforms(args)
- else:
- raise xasyParseError("Invalid transform stack command.")
- return None
-
-def parseLabel(line):
- """Parse an asy Label statement, returning an xasyText item"""
- if not (line.startswith("Label(") and line.endswith(",align=SE)")):
- raise xasyParseError("Invalid syntax")
- args = line[6:-1]
- loc2 = args.rfind(",align=SE")
- loc1 = args.rfind(",",0,loc2-1)
- loc = args.rfind(",(",0,loc1-1)
- if loc < 2:
- raise xasyParseError("Invalid syntax")
- text = args[1:loc-1]
- location = eval(args[loc+1:args.find("),",loc)+1])
- pen = args[loc:loc2]
- pen = pen[pen.find(",")+1:]
- pen = pen[pen.find(",")+1:]
- pen = pen[pen.find(",")+1:]
- global pendingTransforms
- return xasyText(text,location,parsePen(pen),pendingTransforms.pop())
-
-def parseLabelCommand(line):
- """Parse a label command returning an xasyText object
-
- Syntax:
- label(Label(text,location,pen,align=SE));
- e.g.: label(Label("Hello world!",(0,0),rgb(0,0,0)+0.5,align=SE));
- """
- if line[-2:] != ");":
- raise xasyParseError("Invalid syntax")
- arguments = line[6:-2]
- return parseLabel(arguments)
-def parseDrawCommand(line):
- """Parse a draw command returning an xasyShape object
-
- Syntax:
- draw(path,pen);
- e.g.: draw((0,0)..controls(0.33,0.33)and(0.66,0.66)..(1,1),rgb(1,0,1)+1.5);
- """
- if line[-2:] != ");":
- raise xasyParseError("Invalid syntax")
- args = line[5:-2]
- loc = args.rfind(",rgb")
- path = args[:loc]
- pen = args[loc+1:]
- global pendingTransforms
- return xasyShape(parsePathExpression(path),parsePen(pen),pendingTransforms.pop())
+class xasyParseError(Exception):
+ """A parsing error"""
+ pass
-def parseFillCommand(line):
- """Parse a fill command returning an xasyFilledShape object
-
- Syntax:
- fill(cyclic path,pen);
- e.g.: fill((0,0)..controls(0.33,0.33)and(0.66,0.66)..(1,1)..controls(0.66,0)and(0.33,0)..cycle,rgb(1,0,1)+1.5);
- """
- if line[-2:] != ");":
- raise xasyParseError("Invalid syntax")
- args = line[5:-2]
- loc = args.rfind(",rgb")
- path = args[:loc]
- pen = args[loc+1:]
- global pendingTransforms
- return xasyFilledShape(parsePathExpression(path),parsePen(pen),pendingTransforms.pop())
-def parsePen(pen):
- """Parse a pen expression returning an asyPen
-
- Syntax:
- color+width[+options]
- e.g.: rgb(0,0,0)+1.5+evenodd
- e.g.: rgb(0,1,0)+1.23
- """
- try:
- tokens = pen.split("+")
- color = eval(tokens[0][3:])
- width = float(tokens[1])
- if len(tokens)>2:
- options = "+".join(tokens[2:])
+class xasyFileError(Exception):
+ """An i/o error or other error not related to parsing"""
+ pass
+
+
+def extractTransform(line):
+ """Returns key and the new transform."""
+ # see https://regex101.com/r/6DqkRJ/4 for info
+ mapString = x2a.xasyItem.mapString
+ testMatch = re.match(
+ r'^{0:s}\s*\(\s*\"([^\"]+)\"\s*,\s*\(([-\d, .]+)\)\s*\)'.format(mapString), line.strip())
+ if testMatch is None:
+ mapOnlyMatch = re.match(r'^{0:s}\s*\(\s *\"([^\"]+)\"\s*\)'.format(mapString), line.strip())
+ if mapOnlyMatch is None:
+ return None
+ else:
+ key = mapOnlyMatch.group(1)
+ return key, x2a.identity()
else:
- options = ""
- return asyPen(color,width,options)
- except:
- raise xasyParseError("Invalid pen")
-
-def parsePathExpression(expr):
- """Parse an asy path returning an asyPath()"""
- result = asyPath()
- expr = "".join(expr.split())
- #print (expr)
- if expr.find("controls") != -1:
- #parse a path with control points
- tokens = expr.split("..")
- nodes = [a for a in tokens if not a.startswith("controls")]
- for a in range(len(nodes)):
- if nodes[a] != "cycle":
- nodes[a] = eval(nodes[a])
- controls = [[eval(b) for b in a.replace("controls", "").split("and")] for a in tokens if a.startswith("controls")]
- result.initFromControls(nodes, controls)
- else:
- #parse a path without control points
- tokens = re.split(r"(::|--|\.\.)",expr)
- linkSet = re.findall("::|--|\.\.",expr)
- nodeSet = [a for a in tokens if not re.match(r"::|--|\.\.",a)]
- #print (nodeSet)
- for a in range(len(nodeSet)):
- if nodeSet[a] != "cycle":
- nodeSet[a] = eval(nodeSet[a])
- #print (nodeSet)
- result.initFromNodeList(nodeSet, linkSet)
- return result
-
-def takeUntilSemicolon(line,lines):
- """Read and concatenate lines until the collected lines end with a semicolon"""
- data = line
- while not data.endswith(";"):
- newline = lines.pop(0)
- data += newline
- return data
-
-def parseLine(line,lines):
- """Parse a line of the file"""
- if len(line)==0 or line.isspace() or line.startswith("//"):
- return None
- elif line.startswith(scriptPrefix):
- return extractScript(lines)
- elif line.startswith(transformPrefix):
- return parseTransformExpression(takeUntilSemicolon(line,lines))
- elif line.startswith("label("):
- return parseLabelCommand(takeUntilSemicolon(line,lines))
- elif line.startswith("draw("):
- return parseDrawCommand(takeUntilSemicolon(line,lines))
- elif line.startswith("fill("):
- return parseFillCommand(takeUntilSemicolon(line,lines))
- elif line.startswith("exitXasyMode();"):
- return None
- raise Exception("Could not parse the line")
-
-fileHeader = """initXasyMode();
-// This file was generated by xasy. It may be edited manually, however, a strict
-// syntax must be followed. It is advised that manually scripted items be added
-// in the form of a script either by using xasy or by mimicking the format of an
-// xasy-generated script item.
-// Please consult the documentation or the examples provided for details.
-"""
-
-fileFooter = """// This is the end of the file
-exitXasyMode();
-
-"""
-
-def saveFile(file,xasyItems):
- """Write a list of xasyItems to a file"""
- file.write(fileHeader)
- for item in xasyItems:
- file.write(item.getCode()+"\n\n")
- file.write(fileFooter)
-
-if __name__ == '__main__':
- root = Tk()
- try:
- name = raw_input("enter file name (\"../../xasyTest.asy\"):")
- if name == '':
- name = "../../xasyTest.asy"
- f = open(name,"rt")
- except:
- print ("Could not open file.")
- asy.quit()
- sys.exit(1)
-
- fileItems = []
- try:
- fileItems = parseFile(f)
- res = [str(a) for a in fileItems]
- print ("----------------------------------")
- print ("Objects in {:s}".format(f.name))
- print ("----------------------------------")
- for a in res:
- print (a)
- print ("----------------------------------")
- print ("successful parse")
- f.close()
- except:
- f.close()
- print ("parse failed")
- raise
-
- print ("making a file")
- f = open("testfile.asy","wt")
- saveFile(f,fileItems)
- f.close()
- root.configure(width=500,height=500)
- root.title("Results")
- canv = Canvas(root,width=500,height=500)
- canv.pack()
- for i in fileItems[1].imageList:
- canv.create_image(250+i.bbox[0],250-i.bbox[3],anchor = NW, image=i.image)
- Button(root,image=i.image).pack(side=LEFT)
- root.mainloop()
+ key = testMatch.group(1)
+ rawStr = testMatch.group(2)
+ rawStrArray = rawStr.split(',')
+
+ if len(rawStrArray) != 6:
+ return None
+ transf = [float(val.strip()) for val in rawStrArray]
+ return key, x2a.asyTransform(transf)
+
+
+def extractTransformsFromFile(fileStr):
+ transfDict = {}
+ maxItemCount = 0
+ with io.StringIO() as rawCode:
+ for line in fileStr.splitlines():
+ test_transf = extractTransform(line.rstrip())
+ if test_transf is None:
+ rawCode.write(line + '\n')
+ else:
+ key, transf = test_transf
+ if key not in transfDict.keys():
+ transfDict[key] = []
+ transfDict[key].append(transf)
+
+ # see https://regex101.com/r/RgeBVc/2 for regex
+
+ testNum = re.match(r'^x(\d+)($|:.*$)', key)
+ if testNum is not None:
+ maxItemCount = max(maxItemCount, int(testNum.group(1)))
+ final_str = rawCode.getvalue()
+ return final_str, transfDict, maxItemCount
+
+
+def saveFile(file, xasyItems, asy2psmap):
+ """Write a list of xasyItems to a file"""
+ for item in xasyItems:
+ file.write(item.getTransformCode(asy2psmap))
+
+ for item in xasyItems:
+ file.write(item.getObjectCode(asy2psmap))
+
+ file.write('size('+str(asy2psmap*x2a.yflip())+'); '+ x2a.xasyItem.resizeComment+'\n')