Update documentclass.

This commit is contained in:
Mikael Capelle 2018-02-26 19:23:34 +01:00
parent 154d8e1858
commit 758e99d5a7
5 changed files with 147 additions and 22 deletions

View File

@ -6,6 +6,7 @@ from .documentclass import *
from .figure import figure from .figure import figure
from .formatter import formatter from .formatter import formatter
from .input_element import input_element from .input_element import input_element
from .includegraphics import includegraphics
from .makebox import makebox from .makebox import makebox
from .resizebox import resizebox from .resizebox import resizebox
from .subfloat import subfloat from .subfloat import subfloat

View File

@ -3,20 +3,41 @@
from collections import Iterable from collections import Iterable
from .element import element from .element import element
import enum
import os
import subprocess import subprocess
class change_directory:
"""Context manager for changing the current working directory"""
def __init__(self, newPath):
self.newPath = os.path.expanduser(newPath)
def __enter__(self):
self.savedPath = os.getcwd()
os.chdir(self.newPath)
def __exit__(self, etype, value, traceback):
os.chdir(self.savedPath)
class CompileResult(enum.Enum):
ALREADY_EXISTS = 1
SUCCESS = 2
ERROR = 3
class documentclass(element): class documentclass(element):
packages = {}
preamble = []
options = []
classname = 'standalone' classname = 'standalone'
templates = { templates = {
'package': '\\usepackage{pkgoptions}{{{pkgname}}}', 'package': '\\usepackage{pkgoptions}{{{pkgname}}}',
'options': '[{content}]', 'options': '[{content}]',
'def': '\\def\\{name}#{nargs}{{{value}}}', 'def': '\\def\\{name}{nargs}{{{value}}}',
'content': """\\documentclass{options}{{{classname}}} 'content': """\\documentclass{options}{{{classname}}}
{packages} {packages}
{preamble} {preamble}
@ -26,11 +47,18 @@ class documentclass(element):
""" """
} }
def __init__(self, classname, childrens=[], options=[], packages=[]): output_aux_folder = '.pyltk'
auto_tex_folder = '{}/tex2pdf'.format(output_aux_folder)
def __init__(self, classname, childrens=[], options=[],
packages=[], preamble=[]):
super().__init__(parent=None, childrens=childrens) super().__init__(parent=None, childrens=childrens)
self.options = options self.options = options
self.classname = classname self.classname = classname
self.packages = {}
self.add_packages(packages) self.add_packages(packages)
self.preamble = []
self.add2preamble(preamble)
def add_packages(self, packages): def add_packages(self, packages):
if type(packages) is str: if type(packages) is str:
@ -49,19 +77,19 @@ class documentclass(element):
def add_def(self, name, nargs, value): def add_def(self, name, nargs, value):
self.preamble.append(self.fmt().format('def', { self.preamble.append(self.fmt().format('def', {
'name': name, 'name': name,
'nargs': nargs, 'nargs': '#{}'.format(nargs) if nargs > 0 else '',
'value': value 'value': value
})) }))
def format_preamble(self, defs): def format_preamble(self, defs):
return '\n'.join(self.preamble) return '\n'.join(str(p) for p in self.preamble)
def format_packages(self, pkgs): def format_packages(self, pkgs):
out = [] out = []
for pkg, opts in self.packages.items(): for pkg in sorted(pkgs):
options = '' options = ''
if opts is not True: if pkgs[pkg] is not True:
options = self.format_options(opts) options = self.format_options(pkgs[pkg])
out.append(self.fmt().format('package', { out.append(self.fmt().format('package', {
'pkgname': pkg, 'pkgname': pkg,
'pkgoptions': options 'pkgoptions': options
@ -77,12 +105,78 @@ class documentclass(element):
'content': super().content() 'content': super().content()
}) })
def compile(self, outfile, infile=None, outlog=None): def compile(self, outfile, infile='auto', outlog=None):
if infile is None: """ Compile the given document into a PDF file.
infile = '/tmp/pyltk-{}.tex'.format(id(self))
If infile is not None, and infile already exists, the document
will only be compiled if the content of infile is different
from this document or if infile is newer than the output
document.
Parameters:
- outfile Name of the output file (pdf extension may
be omitted).
- infile Name of the file to which latex code must be
written. If None, a temporary file will be created
and then erased. If 'auto', file will be saved in
an automatic folder for future use.
- outlog
"""
outdir = os.path.dirname(outfile)
outfile = os.path.basename(outfile)
res = CompileResult.ERROR
with change_directory(outdir):
os.makedirs(self.output_aux_folder, exist_ok=True)
if outfile.endswith('.pdf'):
outfile = outfile[:-4]
to_delete = False
if infile == 'auto':
os.makedirs(self.auto_tex_folder, exist_ok=True)
infile = '{}/{}.tex'.format(self.auto_tex_folder, outfile)
if infile is None:
to_delete = True
infile = '.pyltk-{}.tex'.format(outfile)
to_create = True
new_content = self.content()
# If the input file already exists...
if os.path.exists(infile):
with open(infile, 'r') as infd:
old_content = infd.read()
# Content has not changed
if old_content == new_content \
and os.path.exists('{}.pdf'.format(outfile)) \
and os.path.getctime(infile) <= \
os.path.getctime('{}.pdf'.format(outfile)):
to_create = False
if to_create:
with open(infile, 'w') as infd: with open(infile, 'w') as infd:
infd.write(self.content()) infd.write(self.content())
call = ['pdflatex', '-halt-on-error',
'-output-directory', self.output_aux_folder,
'-jobname', outfile, infile]
if subprocess.call(call, stdout=outlog) == 0:
os.rename('{}/{}.pdf'.format(
self.output_aux_folder, outfile),
'{}.pdf'.format(outfile))
res = CompileResult.SUCCESS
else:
res = CompileResult.ERROR
else:
res = CompileResult.ALREADY_EXISTS
call = ['pdflatex', '-halt-on-error', '-jobname', outfile, infile] if to_delete:
subprocess.call(call, stdout=outlog) os.remove(infile)
return res

View File

@ -26,7 +26,8 @@ class element:
# Do not wrap non-element in wrapper_element # Do not wrap non-element in wrapper_element
raw = False raw = False
def __init__(self, parent=None, childrens=[], label=None, raw=False): def __init__(self, parent=None, childrens=[], label=None,
raw=False, **kargs):
""" Create a new element with given parameters. """ Create a new element with given parameters.
Parameters: Parameters:
@ -34,7 +35,8 @@ class element:
- childrens Childrens of the element - Single element or list of - childrens Childrens of the element - Single element or list of
objects (element or not). objects (element or not).
- label Label of the element. - label Label of the element.
- raw Raw childrens (see description of `element`). """ - raw Raw childrens (see description of `element`).
- kargs Options for the element. """
self.parent = parent self.parent = parent
self.raw = raw self.raw = raw
if childrens is None: if childrens is None:
@ -44,6 +46,7 @@ class element:
self.childrens = [] self.childrens = []
self.add(childrens) self.add(childrens)
self.label = label self.label = label
self.options = kargs
def add(self, childrens): def add(self, childrens):
if not isinstance(childrens, Iterable): if not isinstance(childrens, Iterable):
@ -69,8 +72,9 @@ class element:
if not options: if not options:
return '' return ''
opts = [] opts = []
for k, v in options.items(): # Note: Sorted to have a guaranteed output
opts.append('{key} = {{{value}}}'.format(key=k, value=v)) for k in sorted(options):
opts.append('{key} = {{{value}}}'.format(key=k, value=options[k]))
return self.fmt().format('options', { return self.fmt().format('options', {
'content': ', '.join(opts) 'content': ', '.join(opts)
}) })

23
pyltk/includegraphics.py Normal file
View File

@ -0,0 +1,23 @@
# -*- encoding: utf-8 -*-
from .element import element
class includegraphics(element):
""" Class representing a latex includegrahics. """
templates = {
'element': '\\includegraphics[{options}]{{{filename}}}'
}
autolabel = False
def __init__(self, filename, parent=None, **kargs):
super().__init__(parent, **kargs)
self.filename = filename
def content(self):
return self.fmt().format('element', {
'filename': self.filename,
'options': self.format_options(self.options)
})

View File

@ -7,11 +7,13 @@ class subfloat(element):
""" Class representing a latex subfloat. """ """ Class representing a latex subfloat. """
templates = { templates = {
'content': """\\subfloat[{caption}]{{ 'content': """\\subfloat[{caption}{label}]{{
{inner} {inner}
}}""" }}"""
} }
autolabel = False
def __init__(self, caption, parent=None, childrens=None, label=None): def __init__(self, caption, parent=None, childrens=None, label=None):
super().__init__(parent, childrens, label=label) super().__init__(parent, childrens, label=label)
self.caption = caption self.caption = caption
@ -19,5 +21,6 @@ class subfloat(element):
def content(self): def content(self):
return self.fmt().format('content', { return self.fmt().format('content', {
'caption': self.caption, 'caption': self.caption,
'label': self.format_label(self.label),
'inner': super().content() 'inner': super().content()
}) })