From 380c99fb89ffb55bb604dd5ece87356ccf782d3a Mon Sep 17 00:00:00 2001 From: Vincent Ledda Date: Fri, 27 Nov 2020 21:08:29 +0100 Subject: [PATCH 1/2] makestatic is back --- .gitignore | 2 - makestatic.py | 80 +++++++++++++++ sagetexparse.py | 262 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 342 insertions(+), 2 deletions(-) create mode 100755 makestatic.py create mode 100644 sagetexparse.py diff --git a/.gitignore b/.gitignore index d6d709a..9d58d86 100644 --- a/.gitignore +++ b/.gitignore @@ -16,7 +16,6 @@ dist/ example.synctex.gz extractsagecode.py makecmds.sty -makestatic.py remote-sagetex.py run-sagetex-if-necessary.py sage-plots-for-*.tex/ @@ -28,7 +27,6 @@ sagetex.ind sagetex.py sagetex.pyc sagetex.sty -sagetexparse.py .*.sage-history .*.sage-chat MANIFEST diff --git a/makestatic.py b/makestatic.py new file mode 100755 index 0000000..e5199fd --- /dev/null +++ b/makestatic.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python +## +## This is file `makestatic.py', +## generated with the docstrip utility. +## +## The original source files were: +## +## scripts.dtx (with options: `staticscript') +## +## This is a generated file. It is part of the SageTeX package. +## +## Copyright (C) 2008--2015 by Dan Drake +## +## This program is free software: you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation, either version 2 of the License, or (at your +## option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +## Public License for more details. +## +## You should have received a copy of the GNU General Public License along +## with this program. If not, see . +## +import sys +import time +import getopt +import os.path +from sagetexparse import DeSageTex + +def usage(): + print("""Usage: %s [-h|--help] [-o|--overwrite] inputfile [outputfile] + +Removes SageTeX macros from `inputfile' and replaces them with the +Sage-computed results to make a "static" file. You'll need to have run +Sage on `inputfile' already. + +`inputfile' can include the .tex extension or not. If you provide +`outputfile', the results will be written to a file of that name. +Specify `-o' or `--overwrite' to overwrite the file if it exists. + +See the SageTeX documentation for more details.""" % sys.argv[0]) + +try: + opts, args = getopt.getopt(sys.argv[1:], 'ho', ['help', 'overwrite']) +except getopt.GetoptError as err: + print(str(err)) + usage() + sys.exit(2) + +overwrite = False +for o, a in opts: + if o in ('-h', '--help'): + usage() + sys.exit() + elif o in ('-o', '--overwrite'): + overwrite = True + +if len(args) == 0 or len(args) > 2: + print('Error: wrong number of arguments. Make sure to specify options first.\n') + usage() + sys.exit(2) + +if len(args) == 2 and (os.path.exists(args[1]) and not overwrite): + print('Error: %s exists and overwrite option not specified.' % args[1]) + sys.exit(1) + +src, ext = os.path.splitext(args[0]) +desagetexed = DeSageTex(src) +header = "%% SageTeX commands have been automatically removed from this file and\n%% replaced with plain LaTeX. Processed %s.\n" % time.strftime('%a %d %b %Y %H:%M:%S', time.localtime()) + +if len(args) == 2: + dest = open(args[1], 'w') +else: + dest = sys.stdout + +dest.write(header) +dest.write(desagetexed.result) diff --git a/sagetexparse.py b/sagetexparse.py new file mode 100644 index 0000000..e54a794 --- /dev/null +++ b/sagetexparse.py @@ -0,0 +1,262 @@ +## +## This is file `sagetexparse.py', +## generated with the docstrip utility. +## +## The original source files were: +## +## scripts.dtx (with options: `parsermod') +## +## This is a generated file. It is part of the SageTeX package. +## +## Copyright (C) 2008--2015 by Dan Drake +## +## This program is free software: you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation, either version 2 of the License, or (at your +## option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +## Public License for more details. +## +## You should have received a copy of the GNU General Public License along +## with this program. If not, see . +## +import sys + +from pyparsing import ( + Literal, + OneOrMore, + Optional, + ParseFatalException, + SkipTo, + Suppress, + Word, + lineno, + matchPreviousExpr, + nestedExpr, + nums, + oneOf, + originalTextFor, + replaceWith, + restOfLine, +) + + +def skipToMatching(opener, closer): + """ + + :param opener: opening token + :param closer: closing token + + """ + nest = nestedExpr(opener, closer) + return originalTextFor(nest) + + +curlybrackets = skipToMatching("{", "}") +squarebrackets = skipToMatching("[", "]") +sagemacroparser = r"\sage" + curlybrackets("code") +sageplotparser = ( + r"\sageplot" + + Optional(squarebrackets)("opts") + + Optional(squarebrackets)("format") + + curlybrackets("code") +) +sagetexpause = Literal(r"\sagetexpause") +sagetexunpause = Literal(r"\sagetexunpause") + + +class SoutParser: + """sout file parser""" + + def __init__(self, fn): + self.label = [] + parselabel = ( + r"\newlabel{@sageinline" + + Word(nums)("num") + + "}{" + + curlybrackets("result") + + "{}{}{}{}}" + ) + parselabel.ignore("%" + restOfLine) + parselabel.setParseAction(self.newlabel) + try: + OneOrMore(parselabel).parseFile(fn) + except IOError: + print("Error accessing {}; exiting. Does your .sout file exist?".format(fn)) + sys.exit(1) + + def newlabel(self, s, l, t): + """ + + :param s: string with newlabel + :param t: param l: + :param l: label content + + """ + self.label.append(t.result[1:-1]) + + +class DeSageTex: + """ """ + + def __init__(self, fn): + self.sagen = 0 + self.plotn = 0 + self.fn = fn + self.sout = SoutParser(fn + ".sagetex.sout") + smacro = sagemacroparser + smacro.setParseAction(self.sage) + usepackage = r"\usepackage" + Optional(squarebrackets) + "{sagetex}" + usepackage.setParseAction( + replaceWith( + r"""% "\usepackage{sagetex}" line was here: + \RequirePackage{verbatim} + \RequirePackage{graphicx} + \newcommand{\sagetexpause}{\relax} + \newcommand{\sagetexunpause}{\relax}""" + ) + ) + splot = sageplotparser + splot.setParseAction(self.plot) + beginorend = oneOf("begin end") + blockorverb = "sage" + oneOf("block verbatim") + blockorverb.setParseAction(replaceWith("verbatim")) + senv = "\\" + beginorend + "{" + blockorverb + "}" + silent = Literal("sagesilent") + silent.setParseAction(replaceWith("comment")) + ssilent = "\\" + beginorend + "{" + silent + "}" + stexindent = Suppress(r"\setlength{\sagetexindent}" + curlybrackets) + doit = smacro | senv | ssilent | usepackage | splot | stexindent + doit.ignore("%" + restOfLine) + doit.ignore(r"\begin{verbatim}" + SkipTo(r"\end{verbatim}")) + doit.ignore(r"\begin{comment}" + SkipTo(r"\end{comment}")) + doit.ignore(r"\sagetexpause" + SkipTo(r"\sagetexunpause")) + str = "".join(open(fn + ".tex", "r").readlines()) + self.result = doit.transformString(str) + + def sage(self, s, l, t): + """Return next sagelabel from sout file and increment sagen + + :param s: string + :param l: location in the string where matching started + :param t: token + :returns: next sagelabel from sout file + :rtype: string + + """ + self.sagen += 1 + return self.sout.label[self.sagen - 1] + + def plot(self, s, l, t): + """Replace sageplot by includegraphics and increment plotn + + :param s: string + :param l: loc + :param t: tok + + """ + self.plotn += 1 + if len(t.opts) == 0: + opts = r"[width=.75\textwidth]" + else: + opts = t.opts[0] + return r"\includegraphics%s{sage-plots-for-%s.tex/plot-%s}" % ( + opts, + self.fn, + self.plotn - 1, + ) + + +class SageCodeExtractor: + """ """ + + def __init__(self, fn): + smacro = sagemacroparser + smacro.setParseAction(self.macroout) + + splot = sageplotparser + splot.setParseAction(self.plotout) + env_names = oneOf("sageblock sageverbatim sagesilent") + senv = ( + r"\begin{" + + env_names("env") + + "}" + + SkipTo(r"\end{" + matchPreviousExpr(env_names) + "}")("code") + ) + senv.leaveWhitespace() + senv.setParseAction(self.envout) + + spause = sagetexpause + spause.setParseAction(self.pause) + + sunpause = sagetexunpause + sunpause.setParseAction(self.unpause) + + doit = smacro | splot | senv | spause | sunpause + + str = "".join(open(fn + ".tex", "r").readlines()) + self.result = "" + + doit.transformString(str) + + def macroout(self, s, l, t): + """ + + :param s: string + :param t: tok + :param l: + + """ + self.result += "# \\sage{} from line %s\n" % lineno(l, s) + self.result += t.code[1:-1] + "\n\n" + + def plotout(self, s, l, t): + """ + + :param s: string + :param t: tok + :param l: + + """ + self.result += "# \\sageplot{} from line %s:\n" % lineno(l, s) + if t.format is not "": + self.result += "# format: %s" % t.format[0][1:-1] + "\n" + self.result += t.code[1:-1] + "\n\n" + + def envout(self, s, l, t): + """ + + :param s: string + :param t: tok + :param l: + + """ + self.result += "# %s environment from line %s:" % (t.env, lineno(l, s)) + self.result += t.code[0] + "\n" + + def pause(self, s, l, t): + """ + + :param s: string + :param t: tok + :param l: + + """ + self.result += "# SageTeX (probably) paused on input line %s.\n\n" % ( + lineno(l, s) + ) + + def unpause(self, s, l, t): + """ + + :param s: string + :param l: loc + :param t: + + """ + self.result += "# SageTeX (probably) unpaused on input line %s.\n\n" % ( + lineno(l, s) + ) From c7fb3e11eec6618dc336b51965aca5dd4006e5f8 Mon Sep 17 00:00:00 2001 From: Vincent Ledda Date: Mon, 5 Apr 2021 12:46:41 +0200 Subject: [PATCH 2/2] =?UTF-8?q?Supression=20des=20fichiers=20autog=C3=A9n?= =?UTF-8?q?=C3=A9r=C3=A9s.=20gestion=20de=20sagestr.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- makestatic.py | 80 --------------- sagetexparse.py | 262 ------------------------------------------------ scripts.dtx | 10 +- 3 files changed, 6 insertions(+), 346 deletions(-) delete mode 100755 makestatic.py delete mode 100644 sagetexparse.py diff --git a/makestatic.py b/makestatic.py deleted file mode 100755 index e5199fd..0000000 --- a/makestatic.py +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env python -## -## This is file `makestatic.py', -## generated with the docstrip utility. -## -## The original source files were: -## -## scripts.dtx (with options: `staticscript') -## -## This is a generated file. It is part of the SageTeX package. -## -## Copyright (C) 2008--2015 by Dan Drake -## -## This program is free software: you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation, either version 2 of the License, or (at your -## option) any later version. -## -## This program is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -## Public License for more details. -## -## You should have received a copy of the GNU General Public License along -## with this program. If not, see . -## -import sys -import time -import getopt -import os.path -from sagetexparse import DeSageTex - -def usage(): - print("""Usage: %s [-h|--help] [-o|--overwrite] inputfile [outputfile] - -Removes SageTeX macros from `inputfile' and replaces them with the -Sage-computed results to make a "static" file. You'll need to have run -Sage on `inputfile' already. - -`inputfile' can include the .tex extension or not. If you provide -`outputfile', the results will be written to a file of that name. -Specify `-o' or `--overwrite' to overwrite the file if it exists. - -See the SageTeX documentation for more details.""" % sys.argv[0]) - -try: - opts, args = getopt.getopt(sys.argv[1:], 'ho', ['help', 'overwrite']) -except getopt.GetoptError as err: - print(str(err)) - usage() - sys.exit(2) - -overwrite = False -for o, a in opts: - if o in ('-h', '--help'): - usage() - sys.exit() - elif o in ('-o', '--overwrite'): - overwrite = True - -if len(args) == 0 or len(args) > 2: - print('Error: wrong number of arguments. Make sure to specify options first.\n') - usage() - sys.exit(2) - -if len(args) == 2 and (os.path.exists(args[1]) and not overwrite): - print('Error: %s exists and overwrite option not specified.' % args[1]) - sys.exit(1) - -src, ext = os.path.splitext(args[0]) -desagetexed = DeSageTex(src) -header = "%% SageTeX commands have been automatically removed from this file and\n%% replaced with plain LaTeX. Processed %s.\n" % time.strftime('%a %d %b %Y %H:%M:%S', time.localtime()) - -if len(args) == 2: - dest = open(args[1], 'w') -else: - dest = sys.stdout - -dest.write(header) -dest.write(desagetexed.result) diff --git a/sagetexparse.py b/sagetexparse.py deleted file mode 100644 index e54a794..0000000 --- a/sagetexparse.py +++ /dev/null @@ -1,262 +0,0 @@ -## -## This is file `sagetexparse.py', -## generated with the docstrip utility. -## -## The original source files were: -## -## scripts.dtx (with options: `parsermod') -## -## This is a generated file. It is part of the SageTeX package. -## -## Copyright (C) 2008--2015 by Dan Drake -## -## This program is free software: you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation, either version 2 of the License, or (at your -## option) any later version. -## -## This program is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -## Public License for more details. -## -## You should have received a copy of the GNU General Public License along -## with this program. If not, see . -## -import sys - -from pyparsing import ( - Literal, - OneOrMore, - Optional, - ParseFatalException, - SkipTo, - Suppress, - Word, - lineno, - matchPreviousExpr, - nestedExpr, - nums, - oneOf, - originalTextFor, - replaceWith, - restOfLine, -) - - -def skipToMatching(opener, closer): - """ - - :param opener: opening token - :param closer: closing token - - """ - nest = nestedExpr(opener, closer) - return originalTextFor(nest) - - -curlybrackets = skipToMatching("{", "}") -squarebrackets = skipToMatching("[", "]") -sagemacroparser = r"\sage" + curlybrackets("code") -sageplotparser = ( - r"\sageplot" - + Optional(squarebrackets)("opts") - + Optional(squarebrackets)("format") - + curlybrackets("code") -) -sagetexpause = Literal(r"\sagetexpause") -sagetexunpause = Literal(r"\sagetexunpause") - - -class SoutParser: - """sout file parser""" - - def __init__(self, fn): - self.label = [] - parselabel = ( - r"\newlabel{@sageinline" - + Word(nums)("num") - + "}{" - + curlybrackets("result") - + "{}{}{}{}}" - ) - parselabel.ignore("%" + restOfLine) - parselabel.setParseAction(self.newlabel) - try: - OneOrMore(parselabel).parseFile(fn) - except IOError: - print("Error accessing {}; exiting. Does your .sout file exist?".format(fn)) - sys.exit(1) - - def newlabel(self, s, l, t): - """ - - :param s: string with newlabel - :param t: param l: - :param l: label content - - """ - self.label.append(t.result[1:-1]) - - -class DeSageTex: - """ """ - - def __init__(self, fn): - self.sagen = 0 - self.plotn = 0 - self.fn = fn - self.sout = SoutParser(fn + ".sagetex.sout") - smacro = sagemacroparser - smacro.setParseAction(self.sage) - usepackage = r"\usepackage" + Optional(squarebrackets) + "{sagetex}" - usepackage.setParseAction( - replaceWith( - r"""% "\usepackage{sagetex}" line was here: - \RequirePackage{verbatim} - \RequirePackage{graphicx} - \newcommand{\sagetexpause}{\relax} - \newcommand{\sagetexunpause}{\relax}""" - ) - ) - splot = sageplotparser - splot.setParseAction(self.plot) - beginorend = oneOf("begin end") - blockorverb = "sage" + oneOf("block verbatim") - blockorverb.setParseAction(replaceWith("verbatim")) - senv = "\\" + beginorend + "{" + blockorverb + "}" - silent = Literal("sagesilent") - silent.setParseAction(replaceWith("comment")) - ssilent = "\\" + beginorend + "{" + silent + "}" - stexindent = Suppress(r"\setlength{\sagetexindent}" + curlybrackets) - doit = smacro | senv | ssilent | usepackage | splot | stexindent - doit.ignore("%" + restOfLine) - doit.ignore(r"\begin{verbatim}" + SkipTo(r"\end{verbatim}")) - doit.ignore(r"\begin{comment}" + SkipTo(r"\end{comment}")) - doit.ignore(r"\sagetexpause" + SkipTo(r"\sagetexunpause")) - str = "".join(open(fn + ".tex", "r").readlines()) - self.result = doit.transformString(str) - - def sage(self, s, l, t): - """Return next sagelabel from sout file and increment sagen - - :param s: string - :param l: location in the string where matching started - :param t: token - :returns: next sagelabel from sout file - :rtype: string - - """ - self.sagen += 1 - return self.sout.label[self.sagen - 1] - - def plot(self, s, l, t): - """Replace sageplot by includegraphics and increment plotn - - :param s: string - :param l: loc - :param t: tok - - """ - self.plotn += 1 - if len(t.opts) == 0: - opts = r"[width=.75\textwidth]" - else: - opts = t.opts[0] - return r"\includegraphics%s{sage-plots-for-%s.tex/plot-%s}" % ( - opts, - self.fn, - self.plotn - 1, - ) - - -class SageCodeExtractor: - """ """ - - def __init__(self, fn): - smacro = sagemacroparser - smacro.setParseAction(self.macroout) - - splot = sageplotparser - splot.setParseAction(self.plotout) - env_names = oneOf("sageblock sageverbatim sagesilent") - senv = ( - r"\begin{" - + env_names("env") - + "}" - + SkipTo(r"\end{" + matchPreviousExpr(env_names) + "}")("code") - ) - senv.leaveWhitespace() - senv.setParseAction(self.envout) - - spause = sagetexpause - spause.setParseAction(self.pause) - - sunpause = sagetexunpause - sunpause.setParseAction(self.unpause) - - doit = smacro | splot | senv | spause | sunpause - - str = "".join(open(fn + ".tex", "r").readlines()) - self.result = "" - - doit.transformString(str) - - def macroout(self, s, l, t): - """ - - :param s: string - :param t: tok - :param l: - - """ - self.result += "# \\sage{} from line %s\n" % lineno(l, s) - self.result += t.code[1:-1] + "\n\n" - - def plotout(self, s, l, t): - """ - - :param s: string - :param t: tok - :param l: - - """ - self.result += "# \\sageplot{} from line %s:\n" % lineno(l, s) - if t.format is not "": - self.result += "# format: %s" % t.format[0][1:-1] + "\n" - self.result += t.code[1:-1] + "\n\n" - - def envout(self, s, l, t): - """ - - :param s: string - :param t: tok - :param l: - - """ - self.result += "# %s environment from line %s:" % (t.env, lineno(l, s)) - self.result += t.code[0] + "\n" - - def pause(self, s, l, t): - """ - - :param s: string - :param t: tok - :param l: - - """ - self.result += "# SageTeX (probably) paused on input line %s.\n\n" % ( - lineno(l, s) - ) - - def unpause(self, s, l, t): - """ - - :param s: string - :param l: loc - :param t: - - """ - self.result += "# SageTeX (probably) unpaused on input line %s.\n\n" % ( - lineno(l, s) - ) diff --git a/scripts.dtx b/scripts.dtx index 8f7048d..b794104 100644 --- a/scripts.dtx +++ b/scripts.dtx @@ -281,8 +281,7 @@ from pyparsing import * % \begin{macrocode} def skipToMatching(opener, closer): nest = nestedExpr(opener, closer) - nest.setParseAction(lambda l, s, t: l[s:getTokensEndLoc()]) - return nest + return originalTextFor(nest) curlybrackets = skipToMatching('{', '}') squarebrackets = skipToMatching('[', ']') @@ -290,6 +289,7 @@ squarebrackets = skipToMatching('[', ']') % Next, parser for |\sage|, |\sageplot|, and pause/unpause calls: % \begin{macrocode} sagemacroparser = r'\sage' + curlybrackets('code') +sagestrmacroparser = r'\sagestr' + curlybrackets('code') sageplotparser = (r'\sageplot' + Optional(squarebrackets)('opts') + Optional(squarebrackets)('format') @@ -365,8 +365,10 @@ class DeSageTex(): % Parse |\sage| macros. We just need to pull in the result from the % |.sout| file and increment the counter---that's what |self.sage| does. % \begin{macrocode} + strmacro = sagestrmacroparser smacro = sagemacroparser smacro.setParseAction(self.sage) + strmacro.setParseAction(self.sage) % \end{macrocode} % Parse the |\usepackage{sagetex}| line. Right now we don't support % comma-separated lists of packages. @@ -410,7 +412,7 @@ class DeSageTex(): % looks for any one of the above bits, while ignoring anything that % should be ignored. % \begin{macrocode} - doit = smacro | senv | ssilent | usepackage | splot | stexindent + doit = smacro | senv | ssilent | usepackage | splot | stexindent |strmacro doit.ignore('%' + restOfLine) doit.ignore(r'\begin{verbatim}' + SkipTo(r'\end{verbatim}')) doit.ignore(r'\begin{comment}' + SkipTo(r'\end{comment}')) @@ -496,7 +498,7 @@ class SageCodeExtractor(): def plotout(self, s, l, t): self.result += '# \\sageplot{} from line %s:\n' % lineno(l, s) - if t.format is not '': + if t.format != '': self.result += '# format: %s' % t.format[0][1:-1] + '\n' self.result += t.code[1:-1] + '\n\n'