summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/pythontex
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2017-07-21 22:00:53 +0000
committerKarl Berry <karl@freefriends.org>2017-07-21 22:00:53 +0000
commit26f8c60d721bcd3fe6a0183b9f5ea076f9018293 (patch)
treefbfd09188328236e0c4b2a6e91210b4a690fde90 /Master/texmf-dist/scripts/pythontex
parent2a74b4e85b56e76205237f78b9b87db928cb1143 (diff)
pythontex (21jul17)
git-svn-id: svn://tug.org/texlive/trunk@44860 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/scripts/pythontex')
-rwxr-xr-xMaster/texmf-dist/scripts/pythontex/depythontex.py2
-rwxr-xr-xMaster/texmf-dist/scripts/pythontex/depythontex2.py4
-rwxr-xr-xMaster/texmf-dist/scripts/pythontex/depythontex3.py4
-rwxr-xr-xMaster/texmf-dist/scripts/pythontex/pythontex.py2
-rwxr-xr-xMaster/texmf-dist/scripts/pythontex/pythontex2.py54
-rwxr-xr-xMaster/texmf-dist/scripts/pythontex/pythontex3.py54
-rwxr-xr-xMaster/texmf-dist/scripts/pythontex/pythontex_2to3.py38
-rwxr-xr-xMaster/texmf-dist/scripts/pythontex/pythontex_engines.py259
8 files changed, 305 insertions, 112 deletions
diff --git a/Master/texmf-dist/scripts/pythontex/depythontex.py b/Master/texmf-dist/scripts/pythontex/depythontex.py
index 30256c6d1c3..3d48e3b1daa 100755
--- a/Master/texmf-dist/scripts/pythontex/depythontex.py
+++ b/Master/texmf-dist/scripts/pythontex/depythontex.py
@@ -9,7 +9,7 @@ on your system. If you wish to use a different version of Python, you could
launch depythontex2.py or depythontex3.py directly. The version of Python
does not matter for depythontex, since no code is executed.
-Copyright (c) 2013-2016, Geoffrey M. Poore
+Copyright (c) 2013-2017, Geoffrey M. Poore
All rights reserved.
Licensed under the BSD 3-Clause License:
http://www.opensource.org/licenses/BSD-3-Clause
diff --git a/Master/texmf-dist/scripts/pythontex/depythontex2.py b/Master/texmf-dist/scripts/pythontex/depythontex2.py
index 0975b9b8ca4..7687e0e7244 100755
--- a/Master/texmf-dist/scripts/pythontex/depythontex2.py
+++ b/Master/texmf-dist/scripts/pythontex/depythontex2.py
@@ -47,7 +47,7 @@ example, typeset code may have a different appearance or layout when it is
typeset with a different package.
-Copyright (c) 2013-2016, Geoffrey M. Poore
+Copyright (c) 2013-2017, Geoffrey M. Poore
All rights reserved.
Licensed under the BSD 3-Clause License:
http://www.opensource.org/licenses/BSD-3-Clause
@@ -86,7 +86,7 @@ import codecs
# Script parameters
# Version
-__version__ = '0.15'
+__version__ = '0.16'
# Functions and parameters for customizing the script output
diff --git a/Master/texmf-dist/scripts/pythontex/depythontex3.py b/Master/texmf-dist/scripts/pythontex/depythontex3.py
index 567363eeaa0..bdcea2185e0 100755
--- a/Master/texmf-dist/scripts/pythontex/depythontex3.py
+++ b/Master/texmf-dist/scripts/pythontex/depythontex3.py
@@ -47,7 +47,7 @@ example, typeset code may have a different appearance or layout when it is
typeset with a different package.
-Copyright (c) 2013-2016, Geoffrey M. Poore
+Copyright (c) 2013-2017, Geoffrey M. Poore
All rights reserved.
Licensed under the BSD 3-Clause License:
http://www.opensource.org/licenses/BSD-3-Clause
@@ -86,7 +86,7 @@ import codecs
# Script parameters
# Version
-__version__ = '0.15'
+__version__ = '0.16'
# Functions and parameters for customizing the script output
diff --git a/Master/texmf-dist/scripts/pythontex/pythontex.py b/Master/texmf-dist/scripts/pythontex/pythontex.py
index 0c6e5c70bb1..2fe6de902a2 100755
--- a/Master/texmf-dist/scripts/pythontex/pythontex.py
+++ b/Master/texmf-dist/scripts/pythontex/pythontex.py
@@ -16,7 +16,7 @@ under which your code is actually executed.
Licensed under the BSD 3-Clause License:
-Copyright (c) 2012-2016, Geoffrey M. Poore
+Copyright (c) 2012-2017, Geoffrey M. Poore
All rights reserved.
diff --git a/Master/texmf-dist/scripts/pythontex/pythontex2.py b/Master/texmf-dist/scripts/pythontex/pythontex2.py
index 519b36f3066..871d394e375 100755
--- a/Master/texmf-dist/scripts/pythontex/pythontex2.py
+++ b/Master/texmf-dist/scripts/pythontex/pythontex2.py
@@ -13,7 +13,7 @@ should be in the same directory.
Licensed under the BSD 3-Clause License:
-Copyright (c) 2012-2016, Geoffrey M. Poore
+Copyright (c) 2012-2017, Geoffrey M. Poore
All rights reserved.
@@ -77,7 +77,7 @@ else:
# Script parameters
# Version
-__version__ = '0.15'
+__version__ = '0.16'
@@ -1286,7 +1286,8 @@ def do_multiprocessing(data, temp_data, old_data, engine_dict):
engine_dict[family].warnings,
engine_dict[family].linenumbers,
engine_dict[family].lookbehind,
- keeptemps, hashdependencies)'''
+ keeptemps, hashdependencies,
+ pygments_settings)'''
tasks.append(pool.apply_async(run_code, [encoding, outputdir,
workingdir, code_dict[key],
engine_dict[family].language,
@@ -1299,7 +1300,8 @@ def do_multiprocessing(data, temp_data, old_data, engine_dict):
engine_dict[family].warnings,
engine_dict[family].linenumbers,
engine_dict[family].lookbehind,
- keeptemps, hashdependencies]))
+ keeptemps, hashdependencies,
+ pygments_settings]))
if verbose:
print(' - Code process ' + key.replace('#', ':'))
@@ -1475,7 +1477,7 @@ def do_multiprocessing(data, temp_data, old_data, engine_dict):
def run_code(encoding, outputdir, workingdir, code_list, language, commands,
command_created, extension, makestderr, stderrfilename,
code_index, errorsig, warningsig, linesig, stderrlookbehind,
- keeptemps, hashdependencies):
+ keeptemps, hashdependencies, pygments_settings):
'''
Function for multiprocessing code files
'''
@@ -1526,7 +1528,10 @@ def run_code(encoding, outputdir, workingdir, code_list, language, commands,
exec_cmd = shlex.split(bytes(command.format(file=script.replace('\\', '\\\\'), File=script_full.replace('\\', '\\\\'), workingdir=workingdir.replace('\\', '\\\\'))))
exec_cmd = [unicode(elem) for elem in exec_cmd]
else:
- exec_cmd = shlex.split(command.format(file=script.replace('\\', '\\\\'), File=script_full.replace('\\', '\\\\'), workingdir=workingdir.replace('\\', '\\\\')))
+ if family != 'juliacon':
+ exec_cmd = shlex.split(command.format(file=script.replace('\\', '\\\\'), File=script_full.replace('\\', '\\\\'), workingdir=workingdir.replace('\\', '\\\\')))
+ else:
+ exec_cmd = shlex.split(command.format(file=script.replace('\\', '/'), File=script_full.replace('\\', '/'), workingdir=workingdir.replace('\\', '/')))
# Add any created files due to the command
# This needs to be done before attempts to execute, to prevent orphans
try:
@@ -1563,6 +1568,22 @@ def run_code(encoding, outputdir, workingdir, code_list, language, commands,
messages.append(' Missing output file for ' + key_run.replace('#', ':'))
errors += 1
else:
+ if family == 'juliacon':
+ with open(out_file_name.rsplit('.', 1)[0] + '.tex', 'r', encoding=encoding) as f:
+ tex_data_lines = f.readlines()
+ inst = 0
+ for n, line in enumerate(tex_data_lines):
+ if line.rstrip() == '\\begin{juliaterm}':
+ tex_data_lines[n] = '=>PYTHONTEX:STDOUT#{0}#code#\n'.format(inst)
+ inst += 1
+ if n != 0:
+ tex_data_lines[n-1] = ''
+ if line.rstrip() == '\\end{juliaterm}':
+ tex_data_lines[n] = ''
+ tex_data_lines.append('=>PYTHONTEX:DEPENDENCIES#\n=>PYTHONTEX:CREATED#\n')
+ with open(out_file_name, 'w', encoding=encoding) as f:
+ f.write(''.join(tex_data_lines))
+
f = open(out_file_name, 'r', encoding=encoding)
out = f.read()
f.close()
@@ -1619,6 +1640,18 @@ def run_code(encoding, outputdir, workingdir, code_list, language, commands,
else:
dependencies[dep] = (os.path.getmtime(dep_file), '')
+ if family == 'juliacon':
+ from pygments import highlight
+ from pygments.lexers import get_lexer_by_name
+ from pygments.formatters import LatexFormatter
+ formatter = dict()
+ lexer = dict()
+ for codetype in pygments_settings:
+ if codetype != ':GLOBAL':
+ p = pygments_settings[codetype]['formatter_options'].copy()
+ p['commandprefix'] = 'PYG'
+ formatter[codetype] = LatexFormatter(**p)
+ lexer[codetype] = get_lexer_by_name(pygments_settings[codetype]['lexer'], **p)
for block in out.split('=>PYTHONTEX:STDOUT#')[1:]:
if block:
delims, content = block.split('#\n', 1)
@@ -1649,6 +1682,8 @@ def run_code(encoding, outputdir, workingdir, code_list, language, commands,
# Remove newline added by printing, prevent
# LaTeX from adding a space after content
content = content.rsplit('\n', 1)[0] + '\\endinput\n'
+ if family == 'juliacon':
+ content = highlight(content, lexer[family], formatter[family])
f.write(content)
f.close()
files.append(fname)
@@ -1658,6 +1693,8 @@ def run_code(encoding, outputdir, workingdir, code_list, language, commands,
messages.append('* PythonTeX error')
messages.append(' Missing stderr file for ' + key_run.replace('#', ':'))
errors += 1
+ elif family == 'juliacon':
+ pass
else:
# Open error and code files.
f = open(err_file_name, encoding=encoding)
@@ -2408,7 +2445,10 @@ def python_console(jobname, encoding, outputdir, workingdir, fvextfile,
sys.excepthook = sys.__excepthook__
old_stdout = sys.stdout
sys.stdout = self.iostdout
- self.interact(self.banner)
+ if sys.version_info.major == 3 and sys.version_info.minor >= 6:
+ self.interact(self.banner, exitmsg='')
+ else:
+ self.interact(self.banner)
sys.stdout = old_stdout
self.session_log = self.iostdout.getvalue()
diff --git a/Master/texmf-dist/scripts/pythontex/pythontex3.py b/Master/texmf-dist/scripts/pythontex/pythontex3.py
index b872dbaa2c4..cb96f97d336 100755
--- a/Master/texmf-dist/scripts/pythontex/pythontex3.py
+++ b/Master/texmf-dist/scripts/pythontex/pythontex3.py
@@ -13,7 +13,7 @@ should be in the same directory.
Licensed under the BSD 3-Clause License:
-Copyright (c) 2012-2016, Geoffrey M. Poore
+Copyright (c) 2012-2017, Geoffrey M. Poore
All rights reserved.
@@ -77,7 +77,7 @@ else:
# Script parameters
# Version
-__version__ = '0.15'
+__version__ = '0.16'
@@ -1286,7 +1286,8 @@ def do_multiprocessing(data, temp_data, old_data, engine_dict):
engine_dict[family].warnings,
engine_dict[family].linenumbers,
engine_dict[family].lookbehind,
- keeptemps, hashdependencies)'''
+ keeptemps, hashdependencies,
+ pygments_settings)'''
tasks.append(pool.apply_async(run_code, [encoding, outputdir,
workingdir, code_dict[key],
engine_dict[family].language,
@@ -1299,7 +1300,8 @@ def do_multiprocessing(data, temp_data, old_data, engine_dict):
engine_dict[family].warnings,
engine_dict[family].linenumbers,
engine_dict[family].lookbehind,
- keeptemps, hashdependencies]))
+ keeptemps, hashdependencies,
+ pygments_settings]))
if verbose:
print(' - Code process ' + key.replace('#', ':'))
@@ -1475,7 +1477,7 @@ def do_multiprocessing(data, temp_data, old_data, engine_dict):
def run_code(encoding, outputdir, workingdir, code_list, language, commands,
command_created, extension, makestderr, stderrfilename,
code_index, errorsig, warningsig, linesig, stderrlookbehind,
- keeptemps, hashdependencies):
+ keeptemps, hashdependencies, pygments_settings):
'''
Function for multiprocessing code files
'''
@@ -1526,7 +1528,10 @@ def run_code(encoding, outputdir, workingdir, code_list, language, commands,
exec_cmd = shlex.split(bytes(command.format(file=script.replace('\\', '\\\\'), File=script_full.replace('\\', '\\\\'), workingdir=workingdir.replace('\\', '\\\\'))))
exec_cmd = [unicode(elem) for elem in exec_cmd]
else:
- exec_cmd = shlex.split(command.format(file=script.replace('\\', '\\\\'), File=script_full.replace('\\', '\\\\'), workingdir=workingdir.replace('\\', '\\\\')))
+ if family != 'juliacon':
+ exec_cmd = shlex.split(command.format(file=script.replace('\\', '\\\\'), File=script_full.replace('\\', '\\\\'), workingdir=workingdir.replace('\\', '\\\\')))
+ else:
+ exec_cmd = shlex.split(command.format(file=script.replace('\\', '/'), File=script_full.replace('\\', '/'), workingdir=workingdir.replace('\\', '/')))
# Add any created files due to the command
# This needs to be done before attempts to execute, to prevent orphans
try:
@@ -1563,6 +1568,22 @@ def run_code(encoding, outputdir, workingdir, code_list, language, commands,
messages.append(' Missing output file for ' + key_run.replace('#', ':'))
errors += 1
else:
+ if family == 'juliacon':
+ with open(out_file_name.rsplit('.', 1)[0] + '.tex', 'r', encoding=encoding) as f:
+ tex_data_lines = f.readlines()
+ inst = 0
+ for n, line in enumerate(tex_data_lines):
+ if line.rstrip() == '\\begin{juliaterm}':
+ tex_data_lines[n] = '=>PYTHONTEX:STDOUT#{0}#code#\n'.format(inst)
+ inst += 1
+ if n != 0:
+ tex_data_lines[n-1] = ''
+ if line.rstrip() == '\\end{juliaterm}':
+ tex_data_lines[n] = ''
+ tex_data_lines.append('=>PYTHONTEX:DEPENDENCIES#\n=>PYTHONTEX:CREATED#\n')
+ with open(out_file_name, 'w', encoding=encoding) as f:
+ f.write(''.join(tex_data_lines))
+
f = open(out_file_name, 'r', encoding=encoding)
out = f.read()
f.close()
@@ -1619,6 +1640,18 @@ def run_code(encoding, outputdir, workingdir, code_list, language, commands,
else:
dependencies[dep] = (os.path.getmtime(dep_file), '')
+ if family == 'juliacon':
+ from pygments import highlight
+ from pygments.lexers import get_lexer_by_name
+ from pygments.formatters import LatexFormatter
+ formatter = dict()
+ lexer = dict()
+ for codetype in pygments_settings:
+ if codetype != ':GLOBAL':
+ p = pygments_settings[codetype]['formatter_options'].copy()
+ p['commandprefix'] = 'PYG'
+ formatter[codetype] = LatexFormatter(**p)
+ lexer[codetype] = get_lexer_by_name(pygments_settings[codetype]['lexer'], **p)
for block in out.split('=>PYTHONTEX:STDOUT#')[1:]:
if block:
delims, content = block.split('#\n', 1)
@@ -1649,6 +1682,8 @@ def run_code(encoding, outputdir, workingdir, code_list, language, commands,
# Remove newline added by printing, prevent
# LaTeX from adding a space after content
content = content.rsplit('\n', 1)[0] + '\\endinput\n'
+ if family == 'juliacon':
+ content = highlight(content, lexer[family], formatter[family])
f.write(content)
f.close()
files.append(fname)
@@ -1658,6 +1693,8 @@ def run_code(encoding, outputdir, workingdir, code_list, language, commands,
messages.append('* PythonTeX error')
messages.append(' Missing stderr file for ' + key_run.replace('#', ':'))
errors += 1
+ elif family == 'juliacon':
+ pass
else:
# Open error and code files.
f = open(err_file_name, encoding=encoding)
@@ -2408,7 +2445,10 @@ def python_console(jobname, encoding, outputdir, workingdir, fvextfile,
sys.excepthook = sys.__excepthook__
old_stdout = sys.stdout
sys.stdout = self.iostdout
- self.interact(self.banner)
+ if sys.version_info.major == 3 and sys.version_info.minor >= 6:
+ self.interact(self.banner, exitmsg='')
+ else:
+ self.interact(self.banner)
sys.stdout = old_stdout
self.session_log = self.iostdout.getvalue()
diff --git a/Master/texmf-dist/scripts/pythontex/pythontex_2to3.py b/Master/texmf-dist/scripts/pythontex/pythontex_2to3.py
index 166e6784676..442309c86b1 100755
--- a/Master/texmf-dist/scripts/pythontex/pythontex_2to3.py
+++ b/Master/texmf-dist/scripts/pythontex/pythontex_2to3.py
@@ -4,30 +4,30 @@
'''
Convert PythonTeX scripts from Python 2 to Python 3
-It isn't possible to have a single PythonTeX code base, since unicode text
-needs to be supported. Under Python 2, this means importing unicode_literals
+It isn't possible to have a single PythonTeX code base, since unicode text
+needs to be supported. Under Python 2, this means importing unicode_literals
from __future__, or using the unicode function or "u" prefix. Under Python 3,
all strings are automatically unicode.
-At the same time, the differences between the Python 2 and 3 versions are
+At the same time, the differences between the Python 2 and 3 versions are
usually very small, involving only a few lines of code. To keep the code base
-unified, while simultaneously fully supporting both Python 2 and 3, the
-following scheme was devised. The code is written for Python 2. Whenever
-code is not compatible with Python 3, it is enclosed with the tags
-"#// Python 2" and "#\\ End Python 2" (each on its own line, by itself). If
-a Python 3 version of the code is needed, it is included between analogous
-tags "#// Python 3" and "#\\ End Python 2". The Python 3 code is commented
+unified, while simultaneously fully supporting both Python 2 and 3, the
+following scheme was devised. The code is written for Python 2. Whenever
+code is not compatible with Python 3, it is enclosed with the tags
+"#// Python 2" and "#\\ End Python 2" (each on its own line, by itself). If
+a Python 3 version of the code is needed, it is included between analogous
+tags "#// Python 3" and "#\\ End Python 2". The Python 3 code is commented
out with "#", at the same indentation level as the Python 3 tags.
-This script creates Python 3 scripts from the original Python 2 scripts
-by commenting out everything between the Python 2 tags, and uncommenting
-everything between the Python 3 tags. In this way, full compatibility is
-maintained with both Python 2 and 3 while keeping the code base essentially
-unified. This approach also allows greater customization of version-specific
-code than would be possible if automatic translation with a tool like 2to3
+This script creates Python 3 scripts from the original Python 2 scripts
+by commenting out everything between the Python 2 tags, and uncommenting
+everything between the Python 3 tags. In this way, full compatibility is
+maintained with both Python 2 and 3 while keeping the code base essentially
+unified. This approach also allows greater customization of version-specific
+code than would be possible if automatic translation with a tool like 2to3
was required.
-Copyright (c) 2012-2014, Geoffrey M. Poore
+Copyright (c) 2012-2017, Geoffrey M. Poore
All rights reserved.
Licensed under the BSD 3-Clause License:
http://www.opensource.org/licenses/BSD-3-Clause
@@ -50,7 +50,7 @@ def from2to3(list_of_code):
in_2 = False
in_3 = False
indent = ''
-
+
for line in list_of_code:
if r'#// Python 2' in line:
in_2 = True
@@ -70,8 +70,8 @@ def from2to3(list_of_code):
if fixed[0].startswith('#!/usr/bin/env python2'):
fixed[0] = fixed[0].replace('python2', 'python3')
return fixed
-
-
+
+
for file in files_to_process:
f = open(file, 'r', encoding=encoding)
converted_code = from2to3(f.readlines())
diff --git a/Master/texmf-dist/scripts/pythontex/pythontex_engines.py b/Master/texmf-dist/scripts/pythontex/pythontex_engines.py
index 6bcbd1690db..38fea5efc43 100755
--- a/Master/texmf-dist/scripts/pythontex/pythontex_engines.py
+++ b/Master/texmf-dist/scripts/pythontex/pythontex_engines.py
@@ -17,7 +17,7 @@ document (script for execution).
-Copyright (c) 2012-2016, Geoffrey M. Poore
+Copyright (c) 2012-2017, Geoffrey M. Poore
All rights reserved.
Licensed under the BSD 3-Clause License:
http://www.opensource.org/licenses/BSD-3-Clause
@@ -1113,6 +1113,12 @@ CodeEngine('julia', 'julia', '.jl', '{julia} "{file}.jl"', julia_template,
SubCodeEngine('julia', 'jl')
+CodeEngine('juliacon', 'julia', '.jl', '{julia} -e "using Weave; weave(\\"{File}.jl\\", \\"tex\\")"', '{body}\n',
+ '#+ term=true\n{code}\n', '', '',
+ 'ERROR:', 'WARNING:', ':{number}', True, created='{File}.tex')
+
+
+
octave_template = '''
@@ -1285,42 +1291,133 @@ CodeEngine('bash', 'bash', '.sh',
rust_template = '''
// -*- coding: utf-8 -*-
- #![allow(dead_code)]
- #![allow(unused_imports)]
-
-
+ #![allow(dead_code, unused_imports)]
+ #[warn(unused_imports)]
mod rust_tex_utils {{
- use std::fmt;
- use std::collections;
- use std::io::prelude::*;
-
- pub struct RustTeXUtils {{
- _formatter: Box<FnMut(&fmt::Display) -> String>,
- _before: Box<FnMut()>,
- _after: Box<FnMut()>,
- pub family: &'static str,
- pub session: &'static str,
- pub restart: &'static str,
- pub dependencies: Vec<String>,
- pub created: Vec<String>,
- pub command: &'static str,
- pub context: collections::HashMap<&'static str, &'static str>,
- pub args: collections::HashMap<&'static str, &'static str>,
- pub instance: &'static str,
- pub line: &'static str,
+ use std::{{borrow, collections, fmt, fs, io, iter, ops, path}};
+ use self::OpenMode::{{ReadMode, WriteMode, AppendMode, TruncateMode, CreateMode, CreateNewMode}};
+ pub struct UserAction<'u> {{
+ _act: Box<FnMut() + 'u>
}}
-
- impl RustTeXUtils {{
+ impl<'u> UserAction<'u> {{
+ pub fn new() -> Self {{
+ Self::from(|| {{}})
+ }}
+ pub fn act(&mut self) {{
+ (self._act)();
+ }}
+ pub fn set<F: FnMut() + 'u>(&mut self, f: F) {{
+ self._act = Box::new(f);
+ }}
+ }}
+ impl<'u> Default for UserAction<'u> {{
+ fn default() -> Self {{
+ Self::new()
+ }}
+ }}
+ impl<'u, F: FnMut() + 'u> From<F> for UserAction<'u> {{
+ fn from(f: F) -> Self {{
+ UserAction {{ _act: Box::new(f) }}
+ }}
+ }}
+ impl<'u, U: Into<UserAction<'u>> + 'u> ops::Add<U> for UserAction<'u> {{
+ type Output = UserAction<'u>;
+ fn add(self, f: U) -> Self::Output {{
+ let mut self_act: Box<FnMut() + 'u> = self._act;
+ let mut other_act: Box<FnMut() + 'u> = f.into()._act;
+ Self::from(move || {{ self_act.as_mut()(); other_act.as_mut()(); }})
+ }}
+ }}
+ impl<'u, F: Into<UserAction<'u>> + 'u> iter::FromIterator<F> for UserAction<'u> {{
+ fn from_iter<T>(iter: T) -> Self where T: IntoIterator<Item = F> {{
+ let mut others: Vec<Self> = iter.into_iter().map(F::into).collect();
+ Self::from(move || {{ for other in others.iter_mut() {{ other.act(); }} }})
+ }}
+ }}
+ impl<'u> ops::Deref for UserAction<'u> {{
+ type Target = FnMut() + 'u;
+ fn deref(&self) -> &Self::Target {{
+ &*self._act
+ }}
+ }}
+ impl<'u> ops::DerefMut for UserAction<'u> {{
+ fn deref_mut(&mut self) -> &mut Self::Target {{
+ &mut *self._act
+ }}
+ }}
+ pub struct RustTeXUtils<'u> {{
+ _formatter: Box<FnMut(&fmt::Display) -> String + 'u>,
+ pub before: UserAction<'u>,
+ pub after: UserAction<'u>,
+ pub family: &'u str,
+ pub session: &'u str,
+ pub restart: &'u str,
+ pub dependencies: collections::HashSet<borrow::Cow<'u, path::Path>>,
+ pub created: collections::HashSet<borrow::Cow<'u, path::Path>>,
+ pub command: &'u str,
+ pub context: collections::HashMap<&'u str, borrow::Cow<'u, str>>,
+ pub args: collections::HashMap<&'u str, borrow::Cow<'u, str>>,
+ pub instance: &'u str,
+ pub line: &'u str,
+ }}
+ #[derive(Clone,Copy,Debug,Hash,PartialEq,Eq)]
+ pub enum OpenMode {{
+ /// Open the file for reading
+ ReadMode,
+ /// Open the file for writing
+ WriteMode,
+ /// Open the file for appending
+ AppendMode,
+ /// Truncate the file before opening
+ TruncateMode,
+ /// Create the file before opening if necessary
+ CreateMode,
+ /// Always create the file before opening
+ CreateNewMode,
+ }}
+ pub mod open_mode {{
+ pub use super::OpenMode::{{self, ReadMode, WriteMode, AppendMode, TruncateMode, CreateMode, CreateNewMode}};
+ pub const R: &'static [OpenMode] = &[ReadMode];
+ pub const W: &'static [OpenMode] = &[WriteMode];
+ pub const A: &'static [OpenMode] = &[AppendMode];
+ pub const WC: &'static [OpenMode] = &[WriteMode, CreateMode];
+ pub const CW: &'static [OpenMode] = WC;
+ pub const AC: &'static [OpenMode] = &[AppendMode, CreateMode];
+ pub const CA: &'static [OpenMode] = AC;
+ pub const WT: &'static [OpenMode] = &[WriteMode, TruncateMode];
+ pub const TW: &'static [OpenMode] = WT;
+ pub const WCT: &'static [OpenMode] = &[WriteMode, CreateMode, TruncateMode];
+ pub const WTC: &'static [OpenMode] = WCT;
+ pub const CWT: &'static [OpenMode] = WCT;
+ pub const CTW: &'static [OpenMode] = WCT;
+ pub const TWC: &'static [OpenMode] = WCT;
+ pub const TCW: &'static [OpenMode] = WCT;
+ pub const WN: &'static [OpenMode] = &[WriteMode, CreateNewMode];
+ pub const NW: &'static [OpenMode] = WN;
+ pub const AN: &'static [OpenMode] = &[AppendMode, CreateNewMode];
+ pub const NA: &'static [OpenMode] = AN;
+ }}
+ impl OpenMode {{
+ /// The same options as `fs::File::open`.
+ pub fn open() -> &'static [OpenMode] {{
+ open_mode::R
+ }}
+ /// The same options as `fs::File::create`.
+ pub fn create() -> &'static [OpenMode] {{
+ open_mode::WCT
+ }}
+ }}
+ impl<'u> RustTeXUtils<'u> {{
pub fn new() -> Self {{
RustTeXUtils {{
_formatter: Box::new(|x: &fmt::Display| format!("{{}}", x)),
- _before: Box::new(|| {{}}),
- _after: Box::new(|| {{}}),
+ before: UserAction::new(),
+ after: UserAction::new(),
family: "{family}",
session: "{session}",
restart: "{restart}",
- dependencies: Vec::new(),
- created: Vec::new(),
+ dependencies: collections::HashSet::new(),
+ created: collections::HashSet::new(),
command: "",
context: collections::HashMap::new(),
args: collections::HashMap::new(),
@@ -1328,53 +1425,69 @@ rust_template = '''
line: "",
}}
}}
-
-
pub fn formatter<A: fmt::Display>(&mut self, x: A) -> String {{
- (*self._formatter)(&x)
+ (self._formatter)(&x)
}}
- pub fn set_formatter<F: FnMut(&fmt::Display) -> String + 'static>(&mut self, f: F) {{
+ pub fn set_formatter<F: FnMut(&fmt::Display) -> String + 'u>(&mut self, f: F) {{
self._formatter = Box::new(f);
}}
-
- pub fn before(&mut self) {{
- (*self._before)();
- }}
- pub fn set_before<F: FnMut() + 'static>(&mut self, f: F) {{
- self._before = Box::new(f);
+ pub fn add_dependencies<SS: IntoIterator>(&mut self, deps: SS)
+ where SS::Item: Into<borrow::Cow<'u, path::Path>>
+ {{
+ self.dependencies.extend(deps.into_iter().map(SS::Item::into));
}}
-
- pub fn after(&mut self) {{
- (*self._after)();
- }}
- pub fn set_after<F: FnMut() + 'static>(&mut self, f: F) {{
- self._after = Box::new(f);
- }}
-
- pub fn add_dependencies<SS: IntoIterator>(&mut self, deps: SS) where SS::Item: Into<String> {{
- self.dependencies.append(&mut deps.into_iter().map(|x| x.into()).collect());
+ pub fn add_created<SS: IntoIterator>(&mut self, crts: SS)
+ where SS::Item: Into<borrow::Cow<'u, path::Path>>
+ {{
+ self.created.extend(crts.into_iter().map(SS::Item::into));
}}
-
- pub fn add_created<SS: IntoIterator>(&mut self, crts: SS) where SS::Item: Into<String> {{
- self.created.append(&mut crts.into_iter().map(|x| x.into()).collect());
+ pub fn open<P: 'u, O>(&mut self, name: P, options: O) -> io::Result<fs::File>
+ where P: AsRef<path::Path>,
+ O: IntoIterator,
+ O::Item: borrow::Borrow<OpenMode>
+ {{
+ let opts = options.into_iter()
+ .map(|x| *<O::Item as borrow::Borrow<OpenMode>>::borrow(&x))
+ .collect::<collections::HashSet<OpenMode>>();
+ let mut options = fs::OpenOptions::new();
+ if opts.contains(&ReadMode) {{
+ options.read(true);
+ self.add_dependencies(iter::once(name.as_ref().to_owned()));
+ }}
+ if opts.contains(&WriteMode) {{
+ options.write(true);
+ }}
+ if opts.contains(&AppendMode) {{
+ options.append(true);
+ }}
+ if opts.contains(&TruncateMode) {{
+ options.truncate(true);
+ }}
+ if opts.contains(&CreateMode) {{
+ options.create(true);
+ self.add_created(iter::once(name.as_ref().to_owned()));
+ }}
+ if opts.contains(&CreateNewMode) {{
+ options.create_new(true);
+ self.add_created(iter::once(name.as_ref().to_owned()));
+ }}
+ options.open(name)
}}
-
pub fn cleanup(self) {{
println!("{{}}", "{dependencies_delim}");
for x in self.dependencies {{
- println!("{{}}", x);
+ println!("{{}}", x.to_str().expect(&format!("could not properly display path ({{:?}})", x)));
}}
println!("{{}}", "{created_delim}");
for x in self.created {{
- println!("{{}}", x);
+ println!("{{}}", x.to_str().expect(&format!("could not properly display path ({{:?}})", x)));
}}
}}
-
- pub fn setup_wrapper(&mut self, cmd: &'static str, cxt: &'static str, ags: &'static str, ist: &'static str, lne: &'static str) {{
- fn parse_map(kvs: &'static str) -> collections::HashMap<&'static str, &'static str> {{
+ pub fn setup_wrapper(&mut self, cmd: &'u str, cxt: &'u str, ags: &'u str, ist: &'u str, lne: &'u str) {{
+ fn parse_map<'w>(kvs: &'w str) -> collections::HashMap<&'w str, borrow::Cow<'w, str>> {{
kvs.split(',').filter(|s| !s.is_empty()).map(|kv| {{
let (k, v) = kv.split_at(kv.find('=').expect(&format!("Error parsing supposed key-value pair ({{}})", kv)));
- (k.trim(), v[1..].trim())
+ (k.trim(), v[1..].trim().into())
}}).collect()
}}
self.command = cmd;
@@ -1384,24 +1497,23 @@ rust_template = '''
self.line = lne;
}}
}}
+ impl<'u> Default for RustTeXUtils<'u> {{
+ fn default() -> Self {{
+ Self::new()
+ }}
+ }}
}}
-
-
- use std::{{io, fmt, env, path, ffi, collections}};
+ use std::{{borrow, collections, env, ffi, fmt, fs, hash, io, iter, ops, path}};
use std::io::prelude::*;
-
-
+ use rust_tex_utils::open_mode;
#[allow(unused_mut)]
fn main() {{
let mut rstex = rust_tex_utils::RustTeXUtils::new();
if env::set_current_dir(ffi::OsString::from("{workingdir}".to_string())).is_err() && env::args().all(|x| x != "--manual") {{
panic!("Could not change to the specified working directory ({workingdir})");
}}
-
{extend}
-
{body}
-
rstex.cleanup();
}}
'''
@@ -1410,20 +1522,21 @@ rust_wrapper = '''
rstex.setup_wrapper("{command}", "{context}", "{args}", "{instance}", "{line}");
println!("{stdoutdelim}");
writeln!(io::stderr(), "{stderrdelim}").unwrap();
- rstex.before();
-
+ rstex.before.act();
{code}
-
- rstex.after();
+ rstex.after.act();
'''
-rust_sub = '''println!("{field_delim}");\nprintln!("{{}}", {field});\n'''
+rust_sub = '''
+ println!("{field_delim}");
+ println!("{{}}", {field});
+ '''
CodeEngine('rust', 'rust', '.rs',
# The full script name has to be used in order to make Windows and Unix behave nicely
# together when naming executables. Despite appearances, using `.exe` works on Unix too.
['{rustc} --crate-type bin -o {File}.exe -L {workingdir} {file}.rs', '{File}.exe'],
- rust_template, rust_wrapper, 'println!("{{}}", rstex.formatter({code}));', rust_sub,
+ rust_template, rust_wrapper, '{{ let val = {{ {code} }}; println!("{{}}", rstex.formatter(val)); }}', rust_sub,
errors='error:', warnings='warning:', linenumbers='.rs:{number}',
created='{File}.exe')